Пример #1
0
class GanttConfigure(QDialog):
    def __init__(self, sim, start, end):
        QDialog.__init__(self)
        #self.setCaption("Gantt configuration")
        self.layout = QVBoxLayout(self)

#        self._slider = QxtSpanSliderWidget(
#            sim.observe_window[0] // sim.cycles_per_ms,
#            min(sim.now(), sim.observe_window[1]) // sim.cycles_per_ms,
#            self)
        self._slider = QxtSpanSliderWidget(
            0,
            min(sim.now(), sim.duration) // sim.cycles_per_ms,
            self)
        self._slider.setSpan(start, end)
        self.layout.addWidget(self._slider)

        self._list_elements = QListWidget(self)
        for processor in sim.processors:
            item = QListWidgetItem(processor.name, self._list_elements)
            item.setData(Qt.UserRole, processor)
            self._list_elements.addItem(item)
        for task in sim.task_list:
            item = QListWidgetItem(task.name, self._list_elements)
            item.setData(Qt.UserRole, task)
            self._list_elements.addItem(item)
        #self._list_elements.setDragDropMode(QListWidget.InternalMove)
        for row in range(0, self._list_elements.count()):
            self._list_elements.item(row).setCheckState(Qt.Checked)
        self.layout.addWidget(self._list_elements)

        buttons = QWidget(self)
        buttons_layout = QHBoxLayout()
        buttons.setLayout(buttons_layout)
        buttons_layout.addStretch()
        ok_button = QPushButton("Ok")
        cancel_button = QPushButton("Cancel")
        ok_button.clicked.connect(self.accept)
        cancel_button.clicked.connect(self.reject)
        buttons_layout.addWidget(ok_button)
        buttons_layout.addWidget(cancel_button)
        self.layout.addWidget(buttons)

    def get_start_date(self):
        return self._slider.lowerValue

    def get_end_date(self):
        return self._slider.upperValue

    def get_selected_items(self):
        res = []
        for row in range(0, self._list_elements.count()):
            if self._list_elements.item(row).checkState() == Qt.Checked:
                data = self._list_elements.item(row).data(Qt.UserRole)
                res.append(data)
        return res
Пример #2
0
class MetricsWindowTab(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.name = self.tr("Metrics Window")

        self.inputTextLabel = QLabel(self.tr("Default text:"), self)
        self.inputTextList = QListWidget(self)
        self.inputTextList.setDragDropMode(QAbstractItemView.InternalMove)
        self.addItemButton = QPushButton("+", self)
        self.addItemButton.clicked.connect(self.addItem)
        self.removeItemButton = QPushButton("−", self)
        self.removeItemButton.clicked.connect(self.removeItem)

        layout = QGridLayout(self)
        l = 0
        layout.addWidget(self.inputTextLabel, l, 0, 1, 3)
        l += 1
        layout.addWidget(self.inputTextList, l, 0, 1, 3)
        l += 1
        layout.addWidget(self.addItemButton, l, 0)
        layout.addWidget(self.removeItemButton, l, 1)
        self.setLayout(layout)

        self.readSettings()

    def addItem(self):
        item = QListWidgetItem(self.inputTextList)
        item.setFlags(item.flags() | Qt.ItemIsEditable)
        self.inputTextList.setCurrentItem(item)
        self.inputTextList.editItem(item)
        self.removeItemButton.setEnabled(True)

    def removeItem(self):
        i = self.inputTextList.currentRow()
        self.inputTextList.takeItem(i)
        if not self.inputTextList.count():
            self.removeItemButton.setEnabled(False)

    def readSettings(self):
        self.inputTextList.clear()
        entries = settings.metricsWindowComboBoxItems()
        for entry in entries:
            item = QListWidgetItem(entry, self.inputTextList)
            item.setFlags(item.flags() | Qt.ItemIsEditable)
        if not len(entries):
            self.removeItemButton.setEnabled(False)

    def writeSettings(self):
        entries = []
        for i in range(self.inputTextList.count()):
            item = self.inputTextList.item(i)
            entries.append(item.text())
        settings.setMetricsWindowComboBoxItems(entries)
Пример #3
0
class PatchesPage(QtWidgets.QWizardPage):
    def __init__(self, Wizard, parent=None):
        super(PatchesPage, self).__init__(parent)

        self.base = Wizard.base

        self.setTitle(self.tr("Patches page"))
        self.setSubTitle(self.tr("Select patches"))

        self.addButton = QPushButton("+")
        self.removeButton = QPushButton("-")
        patchesLabel = QLabel("Patches")
        self.listPatches = QListWidget()
        self.addButton.setMaximumWidth(68)
        self.addButton.setMaximumHeight(60)
        self.addButton.clicked.connect(self.openPatchesPageFileDialog)
        self.removeButton.setMaximumWidth(68)
        self.removeButton.setMaximumHeight(60)
        self.removeButton.clicked.connect(self.removeItemFromListWidget)

        grid = QGridLayout()
        grid.addWidget(patchesLabel, 0, 0)
        grid.addWidget(self.addButton, 0, 1,)
        grid.addWidget(self.removeButton, 0, 2)
        grid.addWidget(self.listPatches, 1, 0, 1, 0)

        self.setLayout(grid)

    def removeItemFromListWidget(self):
        self.item = self.listPatches.takeItem(self.listPatches.currentRow())
        self.item = None

    def openPatchesPageFileDialog(self):
        brows = QFileDialog()
        self.getPath = brows.getOpenFileName(self,
                                             "Choose patches",
                                             "/home",
                                             "All files (*)")
        self.newPath = self.getPath[0]
        self.listPatches.addItem(self.newPath)

    def validatePage(self):
        self.itemsCount = self.listPatches.count()
        self.pathes = []
        for i in range(0, self.itemsCount):
            self.pathes.append(self.listPatches.item(i).text())

        self.base.apply_patches(self.pathes)
        self.base.run_patched_sources_analysis()
        return True

    def nextId(self):
        return Wizard.PageScripts
Пример #4
0
class JavaScriptExceptionsPanel(SettingsPanel):
    def __init__(self, parent=None):
        super(JavaScriptExceptionsPanel, self).__init__(parent)

        domainEntryRow = custom_widgets.LineEditRow(tr("Add domain:"), self)
        self.domainEntry = domainEntryRow.lineEdit
        self.domainEntry.returnPressed.connect(self.addDomain)
        self.layout().addWidget(domainEntryRow)

        self.addDomainButton = QPushButton(tr("Add"))
        self.addDomainButton.clicked.connect(self.addDomain)
        domainEntryRow.layout().addWidget(self.addDomainButton)

        self.domainList = QListWidget(self)
        self.layout().addWidget(self.domainList)

        self.removeDomainButton = QPushButton(tr("Remove"))
        self.removeDomainButton.clicked.connect(lambda: self.removeDomain(True))
        self.layout().addWidget(self.removeDomainButton)

        self.removeAction = QAction(self)
        self.removeAction.setShortcut("Del")
        self.removeAction.triggered.connect(self.removeDomain)
        self.addAction(self.removeAction)

    def removeDomain(self, forceFocus=False):
        if self.domainList.hasFocus() or forceFocus:
            self.domainList.takeItem(self.domainList.row(self.domainList.currentItem()))

    def addDomain(self):
        self.domainList.addItem(self.domainEntry.text())
        self.domainEntry.clear()

    def loadSettings(self):
        settings.js_exceptions = settings.setting_to_list("content/JavaScriptExceptions")
        self.domainList.clear()
        for f in settings.js_exceptions:
            self.domainList.addItem(f)

    def saveSettings(self):
        settings.js_exceptions = [self.domainList.item(f).text() for f in range(0, self.domainList.count())]
        settings.settings.setValue("content/JavaScriptExceptions", settings.js_exceptions)
        settings.settings.sync()
Пример #5
0
class AdremoverSettingsPanel(SettingsPanel):
    def __init__(self, parent=None):
        super(AdremoverSettingsPanel, self).__init__(parent)

        filterEntryRow = custom_widgets.LineEditRow(tr("Add filter:"), self)
        self.filterEntry = filterEntryRow.lineEdit
        self.filterEntry.returnPressed.connect(self.addFilter)
        self.layout().addWidget(filterEntryRow)

        self.addFilterButton = QPushButton(tr("Add"))
        self.addFilterButton.clicked.connect(self.addFilter)
        filterEntryRow.layout().addWidget(self.addFilterButton)

        # Ad Remover filter list.
        self.filterList = QListWidget(self)
        self.layout().addWidget(self.filterList)

        self.removeFilterButton = QPushButton(tr("Remove"))
        self.removeFilterButton.clicked.connect(lambda: self.removeFilter(True))
        self.layout().addWidget(self.removeFilterButton)

        self.removeAction = QAction(self)
        self.removeAction.setShortcut("Del")
        self.removeAction.triggered.connect(self.removeFilter)
        self.addAction(self.removeAction)

    def removeFilter(self, forceFocus=False):
        if self.filterList.hasFocus() or forceFocus:
            self.filterList.takeItem(self.filterList.row(self.filterList.currentItem()))

    def addFilter(self):
        self.filterList.addItem(self.filterEntry.text())
        self.filterEntry.clear()

    def loadSettings(self):
        settings.load_adremover_filters()
        self.filterList.clear()
        for f in settings.adremover_filters:
            self.filterList.addItem(f)

    def saveSettings(self):
        settings.adremover_filters = [self.filterList.item(f).text() for f in range(0, self.filterList.count())]
        settings.save_adremover_filters()
Пример #6
0
class SelectedLinesWidget(QWidget):
    """ Widget to show and enable lines to be selected
    inp : LineList
      Input LineList
    init_select : str or list of indices
      str -- 'All'

    """
    def __init__(self, inp, parent=None, init_select=None, plot_widget=None):
        """
        """
        super(SelectedLinesWidget, self).__init__(parent)

        self.parent = parent

        # Line list Table
        if isinstance(inp, LineList):
            self.lines = inp._data
            self.llst = inp
        elif isinstance(inp, Table):
            raise ValueError('SelectedLineWidget: DEPRECATED')
        else:
            raise ValueError('SelectedLineWidget: Wrong type of input')

        self.plot_widget = plot_widget

        # Create the line list
        line_label = QLabel('Lines:')
        self.lines_widget = QListWidget(self)
        self.lines_widget.setSelectionMode(QAbstractItemView.MultiSelection)

        # Initialize list
        self.item_flg = 0
        self.init_list()

        # Initial selection
        if init_select is None:
            self.selected = [0]
        elif init_select == 'All':
            self.selected = []
            for ii in range(self.lines_widget.count()):
                self.lines_widget.item(ii).setSelected(True)
                self.selected.append(ii)
        else:
            self.selected = init_select
            if len(self.selected) == 0:
                self.selected = [0]

        for iselect in self.selected:
            self.lines_widget.item(iselect).setSelected(True)

        self.lines_widget.scrollToItem(self.lines_widget.item(
            self.selected[0]))

        # Events
        self.lines_widget.itemSelectionChanged.connect(self.on_item_change)

        # Layout
        vbox = QVBoxLayout()
        vbox.addWidget(line_label)
        vbox.addWidget(self.lines_widget)

        self.setLayout(vbox)

    def init_list(self):
        nlin = len(self.lines['wrest'])
        for ii in range(nlin):
            self.lines_widget.addItem('{:s} :: {:.3f} :: {}'.format(
                self.lines['name'][ii], self.lines['wrest'][ii],
                self.lines['f'][ii]))

    def on_item_change(self):  #,item):
        # For big changes
        if self.item_flg == 1:
            return
        all_items = [
            self.lines_widget.item(ii)
            for ii in range(self.lines_widget.count())
        ]
        sel_items = self.lines_widget.selectedItems()
        self.selected = [all_items.index(isel) for isel in sel_items]
        self.selected.sort()

        #QtCore.pyqtRemoveInputHook()
        #xdb.set_trace()
        #QtCore.pyqtRestoreInputHook()

        # Update llist
        try:
            self.plot_widget.llist['show_line'] = self.selected
        except AttributeError:
            if self.parent is not None:
                self.parent.updated_slines(self.selected)
            return
        else:
            self.plot_widget.on_draw()

    def on_list_change(self, llist):
        # Clear
        if not isinstance(llist, LineList):
            raise ValueError('Expecting LineList!!')
        self.item_flg = 1
        self.lines = llist._data
        self.llst = llist
        self.lines_widget.clear()
        # Initialize
        self.init_list()
        # Set selected
        for iselect in self.selected:
            self.lines_widget.item(iselect).setSelected(True)
        self.lines_widget.scrollToItem(self.lines_widget.item(
            self.selected[0]))
        self.item_flg = 0
Пример #7
0
class Scheduler:
    def showDialog(self, currentCard=None):
        if currentCard:
            self.did = currentCard.did
        elif mw._selectedDeck():
            self.did = mw._selectedDeck()['id']
        else:
            return

        if not self._getCardInfo(self.did):
            showInfo('Please select an Incremental Reading deck.')
            return

        dialog = QDialog(mw)
        layout = QVBoxLayout()
        self.cardListWidget = QListWidget()
        self.cardListWidget.setAlternatingRowColors(True)
        self.cardListWidget.setSelectionMode(
            QAbstractItemView.ExtendedSelection)
        self.cardListWidget.setWordWrap(True)
        self.cardListWidget.itemDoubleClicked.connect(lambda: self.showBrowser(
            self.cardListWidget.currentItem().data(Qt.UserRole)['nid']))

        self._updateListItems()

        upButton = QPushButton('Up')
        upButton.clicked.connect(self._moveUp)
        downButton = QPushButton('Down')
        downButton.clicked.connect(self._moveDown)
        topButton = QPushButton('Top')
        topButton.clicked.connect(self._moveToTop)
        bottomButton = QPushButton('Bottom')
        bottomButton.clicked.connect(self._moveToBottom)
        randomizeButton = QPushButton('Randomize')
        randomizeButton.clicked.connect(self._randomize)

        controlsLayout = QHBoxLayout()
        controlsLayout.addWidget(topButton)
        controlsLayout.addWidget(upButton)
        controlsLayout.addWidget(downButton)
        controlsLayout.addWidget(bottomButton)
        controlsLayout.addStretch()
        controlsLayout.addWidget(randomizeButton)

        buttonBox = QDialogButtonBox(QDialogButtonBox.Close
                                     | QDialogButtonBox.Save)
        buttonBox.accepted.connect(dialog.accept)
        buttonBox.rejected.connect(dialog.reject)
        buttonBox.setOrientation(Qt.Horizontal)

        layout.addLayout(controlsLayout)
        layout.addWidget(self.cardListWidget)
        layout.addWidget(buttonBox)

        dialog.setLayout(layout)
        dialog.setWindowModality(Qt.WindowModal)
        dialog.resize(500, 500)
        choice = dialog.exec_()

        if choice == 1:
            cids = []
            for i in range(self.cardListWidget.count()):
                card = self.cardListWidget.item(i).data(Qt.UserRole)
                cids.append(card['id'])

            self.reorder(cids)

    def _updateListItems(self):
        cardInfo = self._getCardInfo(self.did)
        self.cardListWidget.clear()
        posWidth = len(str(len(cardInfo) + 1))
        for i, card in enumerate(cardInfo, start=1):
            if self.settings['prioEnabled']:
                info = card['priority']
            else:
                info = str(i).zfill(posWidth)
            title = sub('\s+', ' ', stripHTML(card['title']))
            text = self.settings['organizerFormat'].format(info=info,
                                                           title=title)
            item = QListWidgetItem(text)
            item.setData(Qt.UserRole, card)
            self.cardListWidget.addItem(item)

    def _moveToTop(self):
        selected = self._getSelected()
        if not selected:
            showInfo('Please select one or several items.')
            return

        selected.reverse()
        for item in selected:
            self.cardListWidget.takeItem(self.cardListWidget.row(item))
            self.cardListWidget.insertItem(0, item)
            item.setSelected(True)

        self.cardListWidget.scrollToTop()

    def _moveUp(self):
        selected = self._getSelected()
        if not selected:
            showInfo('Please select one or several items.')
            return

        if self.cardListWidget.row(selected[0]) == 0:
            return

        for item in selected:
            row = self.cardListWidget.row(item)
            self.cardListWidget.takeItem(row)
            self.cardListWidget.insertItem(row - 1, item)
            item.setSelected(True)
            self.cardListWidget.scrollToItem(item)

    def _moveDown(self):
        selected = self._getSelected()
        if not selected:
            showInfo('Please select one or several items.')
            return

        selected.reverse()

        if (self.cardListWidget.row(
                selected[0]) == self.cardListWidget.count() - 1):
            return

        for item in selected:
            row = self.cardListWidget.row(item)
            self.cardListWidget.takeItem(row)
            self.cardListWidget.insertItem(row + 1, item)
            item.setSelected(True)
            self.cardListWidget.scrollToItem(item)

    def _moveToBottom(self):
        selected = self._getSelected()
        if not selected:
            showInfo('Please select one or several items.')
            return

        for item in selected:
            self.cardListWidget.takeItem(self.cardListWidget.row(item))
            self.cardListWidget.insertItem(self.cardListWidget.count(), item)
            item.setSelected(True)

        self.cardListWidget.scrollToBottom()

    def _getSelected(self):
        return [
            self.cardListWidget.item(i)
            for i in range(self.cardListWidget.count())
            if self.cardListWidget.item(i).isSelected()
        ]

    def _randomize(self):
        allItems = [
            self.cardListWidget.takeItem(0)
            for _ in range(self.cardListWidget.count())
        ]
        if self.settings['prioEnabled']:
            maxPrio = len(self.settings['priorities']) - 1
            for item in allItems:
                priority = item.data(Qt.UserRole)['priority']
                if priority != '':
                    item.contNewPos = gauss(maxPrio - int(priority),
                                            maxPrio / 20)
                else:
                    item.contNewPos = float('inf')
            allItems.sort(key=lambda item: item.contNewPos)

        else:
            shuffle(allItems)

        for item in allItems:
            self.cardListWidget.addItem(item)

    def answer(self, card, ease):
        if self.settings['prioEnabled']:
            # reposition the card at the end of the organizer
            cardCount = len(self._getCardInfo(card.did))
            self.reposition(card, cardCount)
            return

        if ease == SCHEDULE_EXTRACT:
            value = self.settings['extractValue']
            randomize = self.settings['extractRandom']
            method = self.settings['extractMethod']
        elif ease == SCHEDULE_SOON:
            value = self.settings['soonValue']
            randomize = self.settings['soonRandom']
            method = self.settings['soonMethod']
        elif ease == SCHEDULE_LATER:
            value = self.settings['laterValue']
            randomize = self.settings['laterRandom']
            method = self.settings['laterMethod']
        elif ease == SCHEDULE_CUSTOM:
            self.reposition(card, 1)
            self.showDialog(card)
            return

        if method == 'percent':
            totalCards = len([c['id'] for c in self._getCardInfo(card.did)])
            newPos = totalCards * (value / 100)
        elif method == 'count':
            newPos = value

        if randomize:
            newPos = gauss(newPos, newPos / 10)

        newPos = max(1, round(newPos))
        self.reposition(card, newPos)

        if ease != SCHEDULE_EXTRACT:
            tooltip('Card moved to position {}'.format(newPos))

    def reposition(self, card, newPos):
        cids = [c['id'] for c in self._getCardInfo(card.did)]
        mw.col.sched.forgetCards(cids)
        cids.remove(card.id)
        newOrder = cids[:newPos - 1] + [card.id] + cids[newPos - 1:]
        mw.col.sched.sortCards(newOrder)

    def reorder(self, cids):
        mw.col.sched.forgetCards(cids)
        mw.col.sched.sortCards(cids)

    def _getCardInfo(self, did):
        cardInfo = []

        for cid, nid in mw.col.db.execute(
                'select id, nid from cards where did = ?', did):
            note = mw.col.getNote(nid)
            if note.model()['name'] == self.settings['modelName']:
                if self.settings['prioEnabled']:
                    prio = note[self.settings['prioField']]
                else:
                    prio = None

                cardInfo.append({
                    'id': cid,
                    'nid': nid,
                    'title': note[self.settings['titleField']],
                    'priority': prio
                })

        return cardInfo

    def showBrowser(self, nid):
        browser = dialogs.open('Browser', mw)
        browser.form.searchEdit.lineEdit().setText('nid:' + str(nid))
        browser.onSearchActivated()
Пример #8
0
class GridControl(QGroupBox):
    """
    Widget for controlling grids in Main Window.
    """
    """Signals"""
    sig_place_grid = pyqtSignal()
    sig_crop_region = pyqtSignal(list, float, str)
    sig_generate_rotated_image = pyqtSignal(float)

    def __init__(self, parent, title, num_rows, num_cols):
        super().__init__(parent=parent, title=title)

        # self.gc_box = QGroupBox(parent=self, title='Grid control')
        self.layout = QGridLayout()
        self.label_checkbox = QCheckBox('Toggle labels', parent=self)
        self.col_label = QLabel('Columns:', parent=self)
        self.row_label = QLabel('Rows: ', parent=self)
        self.col_spinbox = QSpinBox(parent=self,
                                    value=num_cols,
                                    maximum=26,
                                    minimum=1)
        self.row_spinbox = QSpinBox(parent=self,
                                    value=num_rows,
                                    maximum=40,
                                    minimum=1)
        self.btn_like_grid = QPushButton('I like this grid!', parent=self)
        self.grid_list = QListWidget(parent=self)
        self.btn_crop_grid = QPushButton('Crop', parent=self)
        self.btn_del_grid = QPushButton('Delete', parent=self)

        self.parent = self.parentWidget()

        self.configure_gui()
        self.configure_signals()

    def configure_gui(self):
        """
            Configure grid control
        """
        """Layout"""
        self.layout.addWidget(self.row_label, 0, 0)
        self.layout.addWidget(self.col_label, 0, 1)
        self.layout.addWidget(self.col_spinbox, 1, 1)
        self.layout.addWidget(self.row_spinbox, 1, 0)
        self.layout.addWidget(self.label_checkbox, 2, 0, 1, 2)
        self.layout.addWidget(self.btn_like_grid, 3, 0, 1, 2)
        self.layout.addWidget(self.grid_list, 4, 0, 1, 2)
        self.layout.addWidget(self.btn_crop_grid, 5, 0)
        self.layout.addWidget(self.btn_del_grid, 5, 1)
        self.setLayout(self.layout)
        self.setGeometry(0, 0, 150, 400)
        self.move(520, 90)
        """Checkbox"""
        self.label_checkbox.resize(self.label_checkbox.sizeHint())
        self.label_checkbox.setCheckState(Qt.Unchecked)
        self.label_checkbox.stateChanged.connect(self.label_checkbox_checked)
        self.label_checkbox_checked()  # update grid to default settings
        """Row/column spinboxes"""
        self.row_spinbox.valueChanged.connect(self.parent.set_num_rows)
        self.col_spinbox.valueChanged.connect(self.parent.set_num_cols)
        """I like this grid! button"""
        self.btn_like_grid.resize(self.btn_like_grid.sizeHint())
        self.btn_like_grid.setEnabled(False)
        self.btn_like_grid.clicked.connect(self.like_grid_button_clicked)
        """Grid list"""
        self.grid_list.setSelectionMode(QAbstractItemView.SingleSelection)
        self.grid_list.itemSelectionChanged.connect(self.change_selected_grid)
        self.grid_list.itemDoubleClicked.connect(self.change_grid_name)
        """Crop and del button"""
        self.btn_crop_grid.setEnabled(False)
        self.btn_crop_grid.clicked.connect(self.crop_grid_button_clicked)
        self.btn_del_grid.setEnabled(False)
        self.btn_del_grid.clicked.connect(self.del_grid_button_clicked)

    def configure_signals(self):
        self.sig_place_grid.connect(self.parent.place_grid)
        self.sig_generate_rotated_image.connect(self.parent.rotate_image)

    @pyqtSlot()
    def change_selected_grid(self):
        """
        Call when selected grid in `GridList` changes.
        `Crop` and `Del` are enabled, and selected grid
        changes def_color.

        Returns
        -------

        """
        grid_list = []
        for i in range(self.grid_list.count()):
            grid_list.append(self.grid_list.item(i))

        grid_list_selected = self.grid_list.selectedItems()

        for grid_item in grid_list:
            grid_item.grid.set_color_and_thickness(color=Qt.blue)

        for grid_item in grid_list_selected:
            grid_item.grid.set_color_and_thickness(color=Qt.red, thickness=3.)

        if len(grid_list_selected) > 0:
            self.btn_crop_grid.setEnabled(True)
            self.btn_del_grid.setEnabled(True)
        else:
            self.btn_crop_grid.setEnabled(False)
            self.btn_del_grid.setEnabled(False)

    @pyqtSlot()
    def change_grid_name(self):
        item = self.grid_list.selectedItems()[0]
        self.grid_list.editItem(item)

    @pyqtSlot()
    def crop_grid_button_clicked(self):
        """
        Crop images using the selected grid in `GridList`.
        For each grid square, emit signal `sig_crop_region`,
        passing `QRectF` scaled coordinates of region to crop.

        Returns
        -------

        """
        """Collect grid information"""
        grid_item = self.grid_list.selectedItems()[0]
        image_coordinates = grid_item.grid.image_coordinates
        num_rows = grid_item.grid.num_rows
        num_cols = grid_item.grid.num_cols
        angle = grid_item.grid.phi
        alphabet = string.ascii_uppercase
        """Create directory and crop images"""
        directory = grid_item.text()
        if not os.path.exists(directory):
            os.makedirs(directory)
            """generate counter-rotated_image for cropping"""
            self.sig_generate_rotated_image.emit(-angle)
            """Crop images"""
            for ix, image_coordinate in enumerate(image_coordinates):
                """Get bg_image coordinate"""
                tl_x, tl_y = image_coordinate[0, 0]
                tl = QPointF(tl_x, tl_y)  # top left
                bl_x, bl_y = image_coordinate[0, 1]
                bl = QPointF(bl_x, bl_y)  # top right
                tr_x, tr_y = image_coordinate[1, 0]
                tr = QPointF(tr_x, tr_y)  # bottom left
                br_x, br_y = image_coordinate[1, 1]
                br = QPointF(br_x, br_y)  # bottom right
                """Find polygon to be cropped"""
                coords = [tl, bl, br, tr]
                # pol = QPolygonF(coords)
                """Determine file name"""
                col = (ix // num_rows)
                row = (ix % num_rows) + 1
                file_name = str(alphabet[col]) + str(row)
                full_path = os.path.join(directory, file_name)
                self.sig_crop_region.emit(coords, angle, full_path)
        else:
            print('Can\'t crop bg_image: folder already exist')

    @pyqtSlot()
    def del_grid_button_clicked(self):
        """
        Delete grid from `GridList`.
        Returns
        -------

        """
        """Find selected GridListItemWidget """
        grid_item = self.grid_list.selectedItems()[0]
        """Remove from GridList"""
        item_ix = self.grid_list.row(grid_item)
        self.grid_list.takeItem(item_ix)
        """Remove from scene"""
        grid_item.grid.clear_grid()

    @pyqtSlot()
    def like_grid_button_clicked(self):
        """
        Add grid to `grid_list` and emit `sig_place_grid`.

        Returns
        -------

        """

        self.btn_like_grid.setEnabled(False)
        """Add grid to placed grid widget"""
        item = GridListWidgetItem(parent=self.grid_list)
        item.set_grid(self.parent.view.current_grid)
        # TODO ItemIsEditable does not work
        # item.setFlags(Qt.ItemIsEditable)
        # item.setFlags(Qt.ItemIsSelectable)

        self.sig_place_grid.emit()

    @pyqtSlot()
    def label_checkbox_checked(self):
        """
        Enable/disable labels "A1,..,etc." in current grid.
        :return:
        """
        check_state = self.label_checkbox.checkState()
        grid = self.parent.view.current_grid

        if check_state == Qt.Checked:
            grid.label_enabled = True
        elif check_state == Qt.Unchecked:
            grid.label_enabled = False
        """Redraw grid"""
        try:
            tl, br = grid.tl_br_qpointf
        except ValueError:
            pass
        else:
            tl_x = tl.x()
            tl_y = tl.y()
            br_x = br.x()
            br_y = br.y()
            angle = grid.phi
            grid.draw_grid(tl_x, tl_y, br_x, br_y, angle)
Пример #9
0
class GstPipeEdit(QDialog):

    def __init__(self, pipe, preferences_mode=False, **kwargs):
        super().__init__(**kwargs)

        self.setWindowTitle('Edit Pipeline')
        self.setWindowModality(Qt.ApplicationModal)
        self.setLayout(QGridLayout())
        self.setMaximumSize(500, 400)
        self.setMinimumSize(500, 400)
        self.resize(500, 400)

        self._preferences_mode = preferences_mode

        # Input selection
        self.inputBox = QComboBox(self)
        self.layout().addWidget(self.inputBox, 0, 0, 1, 3)
        self.init_inputs(pipe)

        # Current plugins list
        self.currentList = QListWidget(self)
        self.currentList.setDragEnabled(True)
        self.currentList.setDragDropMode(QAbstractItemView.InternalMove)
        self.layout().addWidget(self.currentList, 1, 0, 3, 1)
        self.init_current_plugins(pipe)

        # Add/Remove plugins buttons
        self.pluginsLayout = QVBoxLayout(self)
        self.layout().addLayout(self.pluginsLayout, 2, 1)

        self.addButton = QPushButton(self)
        self.addButton.setIcon(QIcon.fromTheme('go-previous'))
        self.addButton.clicked.connect(self.__add_plugin)
        self.pluginsLayout.addWidget(self.addButton)
        self.pluginsLayout.setAlignment(self.addButton, Qt.AlignHCenter)

        self.delButton = QPushButton(self)
        self.delButton.setIcon(QIcon.fromTheme('go-next'))
        self.delButton.clicked.connect(self.__remove_plugin)
        self.pluginsLayout.addWidget(self.delButton)
        self.pluginsLayout.setAlignment(self.delButton, Qt.AlignHCenter)

        # Available plugins list
        self.availableList = QListWidget(self)
        self.layout().addWidget(self.availableList, 1, 2, 3, 1)
        self.init_available_plugins(pipe)

        # Output selection
        self.outputBox = QComboBox(self)
        self.layout().addWidget(self.outputBox, 4, 0, 1, 3)
        self.init_outputs(pipe)

        # Confirm/Cancel buttons
        self.dialogButtons = QDialogButtonBox(self)
        self.dialogButtons.setStandardButtons(QDialogButtonBox.Cancel |
                                              QDialogButtonBox.Ok)
        self.layout().addWidget(self.dialogButtons, 5, 0, 1, 3)

        self.dialogButtons.accepted.connect(self.accept)
        self.dialogButtons.rejected.connect(self.reject)

    def init_inputs(self, pipe):
        if self._preferences_mode:
            self.inputBox.setEnabled(False)
        else:
            inputs = sorted(elements.inputs())
            self.inputBox.addItems(inputs)
            self.inputBox.setEnabled(len(inputs) > 1)
            if pipe != '':
                self.inputBox.setCurrentIndex(inputs.index(pipe.split('!')[0]))

    def init_outputs(self, pipe):
        outputs = sorted(elements.outputs())
        self.outputBox.addItems(outputs)
        self.outputBox.setEnabled(len(outputs) > 1)
        if pipe != '':
            self.outputBox.setCurrentIndex(outputs.index(pipe.split('!')[-1]))

    def init_current_plugins(self, pipe):
        start = 0 if self._preferences_mode else 1
        for plugin in pipe.split('!')[start:-1]:
            self.currentList.addItem(plugin)

    def init_available_plugins(self, pipe):
        currents = pipe.split('!')
        for plugin in elements.plugins().values():
            if plugin.Name not in currents:
                self.availableList.addItem(plugin.Name)

    def get_pipe(self):
        pipe = [] if self._preferences_mode else [self.inputBox.currentText()]
        for n in range(self.currentList.count()):
            pipe.append(self.currentList.item(n).text())
        pipe.append(self.outputBox.currentText())

        return '!'.join(pipe)

    def __add_plugin(self):
        item = self.availableList.takeItem(self.availableList.currentRow())
        self.currentList.addItem(item)

    def __remove_plugin(self):
        item = self.currentList.takeItem(self.currentList.currentRow())
        self.availableList.addItem(item)
Пример #10
0
class GalleryListView(QWidget):
	SERIES = pyqtSignal(list)
	def __init__(self, parent=None, modal=False):
		super().__init__(parent)
		self.setWindowFlags(Qt.Dialog)

		layout = QVBoxLayout()
		self.setLayout(layout)

		if modal:
			frame = QFrame()
			frame.setFrameShape(frame.StyledPanel)
			modal_layout = QHBoxLayout()
			frame.setLayout(modal_layout)
			layout.addWidget(frame)
			info = QLabel('This mode let\'s you add galleries from ' +
				 'different folders.')
			f_folder = QPushButton('Add folders')
			f_folder.clicked.connect(self.from_folder)
			f_files = QPushButton('Add files')
			f_files.clicked.connect(self.from_files)
			modal_layout.addWidget(info, 3, Qt.AlignLeft)
			modal_layout.addWidget(f_folder, 0, Qt.AlignRight)
			modal_layout.addWidget(f_files, 0, Qt.AlignRight)

		check_layout = QHBoxLayout()
		layout.addLayout(check_layout)
		if modal:
			check_layout.addWidget(QLabel('Please uncheck galleries you do' +
							  ' not want to add. (Exisiting galleries won\'t be added'),
							 3)
		else:
			check_layout.addWidget(QLabel('Please uncheck galleries you do' +
							  ' not want to add. (Existing galleries are hidden)'),
							 3)
		self.check_all = QCheckBox('Check/Uncheck All', self)
		self.check_all.setChecked(True)
		self.check_all.stateChanged.connect(self.all_check_state)

		check_layout.addWidget(self.check_all)
		self.view_list = QListWidget()
		self.view_list.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
		self.view_list.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
		layout.addWidget(self.view_list)
		
		add_btn = QPushButton('Add checked')
		add_btn.clicked.connect(self.return_gallery)

		cancel_btn = QPushButton('Cancel')
		cancel_btn.clicked.connect(self.close_window)
		btn_layout = QHBoxLayout()

		spacer = QWidget()
		spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
		btn_layout.addWidget(spacer)
		btn_layout.addWidget(add_btn)
		btn_layout.addWidget(cancel_btn)
		layout.addLayout(btn_layout)

		self.resize(500,550)
		frect = self.frameGeometry()
		frect.moveCenter(QDesktopWidget().availableGeometry().center())
		self.move(frect.topLeft())
		self.setWindowTitle('Gallery List')

	def all_check_state(self, new_state):
		row = 0
		done = False
		while not done:
			item = self.view_list.item(row)
			if item:
				row += 1
				if new_state == Qt.Unchecked:
					item.setCheckState(Qt.Unchecked)
				else:
					item.setCheckState(Qt.Checked)
			else:
				done = True

	def add_gallery(self, item, name):
		"""
		Constructs an widgetitem to hold the provided item,
		and adds it to the view_list
		"""
		assert isinstance(name, str)
		gallery_item = GalleryListItem(item)
		gallery_item.setText(name)
		gallery_item.setFlags(gallery_item.flags() | Qt.ItemIsUserCheckable)
		gallery_item.setCheckState(Qt.Checked)
		self.view_list.addItem(gallery_item)

	def return_gallery(self):
		gallery_list = []
		row = 0
		done = False
		while not done:
			item = self.view_list.item(row)
			if not item:
				done = True
			else:
				if item.checkState() == Qt.Checked:
					gallery_list.append(item.gallery)
				row += 1

		self.SERIES.emit(gallery_list)
		self.close()

	def from_folder(self):
		file_dialog = QFileDialog()
		file_dialog.setFileMode(QFileDialog.DirectoryOnly)
		file_dialog.setOption(QFileDialog.DontUseNativeDialog, True)
		file_view = file_dialog.findChild(QListView, 'listView')
		if file_view:
			file_view.setSelectionMode(QAbstractItemView.MultiSelection)
		f_tree_view = file_dialog.findChild(QTreeView)
		if f_tree_view:
			f_tree_view.setSelectionMode(QAbstractItemView.MultiSelection)

		if file_dialog.exec():
			for path in file_dialog.selectedFiles():
				self.add_gallery(path, os.path.split(path)[1])


	def from_files(self):
		gallery_list = QFileDialog.getOpenFileNames(self,
											 'Select 1 or more gallery to add',
											 filter='Archives (*.zip *.cbz)')
		for path in gallery_list[0]:
			#Warning: will break when you add more filters
			if len(path) != 0:
				self.add_gallery(path, os.path.split(path)[1])

	def close_window(self):
		msgbox = QMessageBox()
		msgbox.setText('Are you sure you want to cancel?')
		msgbox.setStandardButtons(msgbox.Yes | msgbox.No)
		msgbox.setDefaultButton(msgbox.No)
		msgbox.setIcon(msgbox.Question)
		if msgbox.exec() == QMessageBox.Yes:
			self.close()
Пример #11
0
class GrubList(QDialog):
    """Classe représentant la liste des répertoires GRUB"""
    
    scanner = Scanner("/", "*/grub/grub.cfg")
    newCurrentItem = pyqtSignal(str)
    
    def __init__(self, parent=None, text="Choisissez un répertoire GRUB", allowNone=True):
        QDialog.__init__(self, parent)
        
        # Création des éléments
        # Labels
        label = QLabel(text)
        label.setAlignment(Qt.AlignHCenter)
        self.scanText = QLabel("No scan running")
        self.scanText.setAlignment(Qt.AlignHCenter)
        # List View
        self.grub_list = QListWidget()
        self.grub_list.setSelectionMode(QAbstractItemView.SingleSelection)
        # Buttons
        self.scanButton = QPushButton("Scanner")
        self.add = QPushButton("Ajouter")
        self.scanButton.clicked.connect(self.scan)
        self.add.clicked.connect(self.openSelectionDialog)
        self.scanButton.setToolTip("Cette opération peut être <b>très</b> longue !")
        if allowNone:
            buttonBox = QDialogButtonBox(QDialogButtonBox.Cancel | QDialogButtonBox.Ok)
            buttonBox.rejected.connect(self.reject)
        else:
            buttonBox = QDialogButtonBox(QDialogButtonBox.Ok)
        buttonBox.accepted.connect(self.accept)
        # Progressbar
        self.progressbar = QProgressBar()
        self.progressbar.setEnabled(False)
        
        # Création des Layouts
        # Horizontal
        hbox = QHBoxLayout()
        hbox.addWidget(self.scanButton)
        hbox.addWidget(self.add)
        # Vertical
        vbox = QVBoxLayout()
        vbox.addWidget(label)
        vbox.addWidget(self.grub_list)
        vbox.addLayout(hbox)
        vbox.addWidget(self.scanText)
        vbox.addWidget(self.progressbar)
        vbox.addWidget(buttonBox)
        
        # Affichage de l'interface
        self.setLayout(vbox)
        
        #Signals
        self.scanner.found_rep.connect(self.add_items)
        self.scanner.started.connect(self._scan_started)
        self.scanner.finished.connect(self._scan_finished)
        self.scanner.max_changed.connect(self.progressbar.setMaximum)
        self.scanner.value_changed.connect(self.progressbar.setValue)
        self.scanner.dir_scanned.connect(self._setScanText)
        
        # Ajout de /boot/grub s'il existe
        if path.Path("/boot/grub/grub.cfg").exists():
            self.add_item("/boot/grub")
    
    def selectGrubRep(self):
        self.setModal(True)
        result = self.exec_()
        if result == QDialog.Accepted:
            grubRep = self.getGrubRep()
            return grubRep
        else:
            return False
    
    def scan(self):
        warning = QMessageBox(self)
        msg =  ("Cette opération peut être très longue.\n"
                "Le logiciel va analyser toute votre arborescence de fichier "
                "pour chercher un éventuel dossier contenant la configuration de GRUB.")
        warning.setText(msg)
        warning.setInformativeText("Êtes-vous sûr de vouloir continuer ?")
        warning.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        warning.setDefaultButton(QMessageBox.No)
        warning.setWindowTitle("Attention")
        answer = warning.exec_()
        if answer == QMessageBox.Yes:
            self.scanner.start()
    
    def openSelectionDialog(self):
        dir = QFileDialog.getExistingDirectory(self,
                                               "Sélectionner un répertoire GRUB",
                                               expanduser('~'))
        if (path.Path(dir) / "grub.cfg").exists():
            self.add_item(dir)
        elif dir:
            error = QMessageBox(self)
            msg = "{} n'est pas un répertoire GRUB valide !".format(dir)
            error.setText(msg)
            error.setWindowTitle("Répertoire non valide")
            error.exec_()
    
    def getGrubRep(self):
        dir = self.grub_list.selectedItems()
        try:
            dir = dir[0].text()
        except IndexError:
            return False
        else:
            return dir
    
    @pyqtSlot(list)
    def add_items(self, items):
        for item in items:
            self.add_item(item)
        self.grub_list.setCurrentRow(0)
    
    @pyqtSlot(str)
    def add_item(self, dir):
        item = None
        for i in range(self.grub_list.count()):
            if self.grub_list.item(i).text() == dir:
                item = self.grub_list.item(i)
        if not item:
            item = QListWidgetItem(dir, self.grub_list)
        self.grub_list.setCurrentItem(item)
    
    @pyqtSlot()
    def _scan_started(self):
        self.progressbar.setEnabled(True)
        self.progressbar.setMinimum(0)
        self.scanButton.setEnabled(False)
        self.add.setEnabled(False)
    
    @pyqtSlot()
    def _scan_finished(self):
        self.progressbar.reset()
        self.progressbar.setEnabled(False)
        self.scanText.setText("No scan running")
        self.scanButton.setEnabled(True)
        self.add.setEnabled(True)
    
    @pyqtSlot(str)
    def _setScanText(self, text):
        self.scanText.setText("Scanning {}...".format(text))
Пример #12
0
class SelectedLinesWidget(QWidget):
    """ Widget to show and enable lines to be selected
    inp : LineList
      Input LineList
    init_select : str or list of indices
      str -- 'All'

    """
    def __init__(self, inp, parent=None, init_select=None, plot_widget=None):
        """
        """
        super(SelectedLinesWidget, self).__init__(parent)

        self.parent=parent

        # Line list Table
        if isinstance(inp, LineList):
            self.lines = inp._data
            self.llst = inp
        elif isinstance(inp,Table):
            raise ValueError('SelectedLineWidget: DEPRECATED')
        else:
            raise ValueError('SelectedLineWidget: Wrong type of input')

        self.plot_widget = plot_widget

        # Create the line list
        line_label = QLabel('Lines:')
        self.lines_widget = QListWidget(self)
        self.lines_widget.setSelectionMode(QAbstractItemView.MultiSelection)

        # Initialize list
        self.item_flg = 0
        self.init_list()

        # Initial selection
        if init_select is None:
            self.selected = [0]
        elif init_select == 'All':
            self.selected = []
            for ii in range(self.lines_widget.count()):
                self.lines_widget.item(ii).setSelected(True)
                self.selected.append(ii)
        else:
            self.selected = init_select
            if len(self.selected) == 0:
                self.selected = [0]

        for iselect in self.selected:
            self.lines_widget.item(iselect).setSelected(True)

        self.lines_widget.scrollToItem( self.lines_widget.item( self.selected[0] ) )

        # Events
        self.lines_widget.itemSelectionChanged.connect(self.on_item_change)

        # Layout
        vbox = QVBoxLayout()
        vbox.addWidget(line_label)
        vbox.addWidget(self.lines_widget)

        self.setLayout(vbox)

    def init_list(self):
        nlin = len(self.lines['wrest'])
        for ii in range(nlin):
            self.lines_widget.addItem('{:s} :: {:.3f} :: {}'.format(self.lines['name'][ii],
                                                         self.lines['wrest'][ii].value,
                                                         self.lines['f'][ii]))

    def on_item_change(self): #,item):
        # For big changes
        if self.item_flg == 1:
            return
        all_items = [self.lines_widget.item(ii) for ii in range(self.lines_widget.count())]
        sel_items = self.lines_widget.selectedItems()
        self.selected = [all_items.index(isel) for isel in sel_items]
        self.selected.sort()

        #QtCore.pyqtRemoveInputHook()
        #xdb.set_trace()
        #QtCore.pyqtRestoreInputHook()

        # Update llist
        try:
            self.plot_widget.llist['show_line'] = self.selected
        except AttributeError:
            if self.parent is not None:
                self.parent.updated_slines(self.selected)
            return
        else:
            self.plot_widget.on_draw()

    def on_list_change(self, llist):
        # Clear
        if not isinstance(llist, LineList):
            raise ValueError('Expecting LineList!!')
        self.item_flg = 1
        self.lines = llist._data
        self.llst = llist
        self.lines_widget.clear()
        # Initialize
        self.init_list()
        # Set selected
        for iselect in self.selected:
            self.lines_widget.item(iselect).setSelected(True)
        self.lines_widget.scrollToItem(self.lines_widget.item(self.selected[0]))
        self.item_flg = 0
Пример #13
0
class TriggersSettings(SettingsSection):

    Name = 'Triggers'
    Dialog = CueListDialog()

    def __init__(self, size, cue=None, **kwargs):
        super().__init__(size, cue=None, **kwargs)
        self.setLayout(QVBoxLayout(self))

        self.list = QListWidget(self)
        self.list.setAlternatingRowColors(True)
        self.layout().addWidget(self.list)

        self.buttons = QDialogButtonBox(self)
        self.buttons.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        self.layout().addWidget(self.buttons)

        self.addButton = self.buttons.addButton('Add',
                                                QDialogButtonBox.ActionRole)
        self.delButton = self.buttons.addButton('Remove',
                                                QDialogButtonBox.ActionRole)

        self.addButton.clicked.connect(self._add_trigger_dialog)
        self.delButton.clicked.connect(self._remove_trigger)

        self.Dialog.reset()
        self.Dialog.add_cues(Application().layout.get_cues())

        self.duration = -1

    def _add_new_trigger(self, cue_id, action, name):
        item = QListWidgetItem()
        item.setSizeHint(QSize(200, 30))
        widget = TriggerWidget(item)
        widget.timeEdit.editingFinished.connect(self.list.sortItems)
        widget.load_trigger(cue_id, action, self.duration, name)

        self.list.addItem(item)
        self.list.setItemWidget(item, widget)

    def _add_trigger_dialog(self):
        cue = self.cue_select_dialog()
        if cue is not None:
            self._add_new_trigger(cue['id'], 'play', cue['name'])

    def _remove_trigger(self):
        widget = self.list.itemWidget(self.list.item(self.list.currentRow()))
        widget.timeEdit.editingFinished.disconnect()
        self.list.takeItem(self.list.currentRow())

    @classmethod
    def cue_select_dialog(cls):
        if cls.Dialog.exec_() == QDialog.Accepted:
            return cls.Dialog.selected_cues()[0]

    def set_configuration(self, conf):
        if conf is not None:
            self.duration = conf.get('media', {}).get('duration', -1)

            if 'triggers' in conf:
                for action, ids in conf['triggers'].items():
                    for cue_id in ids:
                        cue = Application().layout.get_cue_by_id(cue_id)
                        if cue is not None:
                            self._add_new_trigger(cue_id, action, cue['name'])

    def get_configuration(self):
        triggers = {}

        for n in range(self.list.count()):
            trigger = self.list.itemWidget(self.list.item(n))
            action, target = trigger.get_trigger()

            if action not in triggers:
                triggers[action] = [target]
            else:
                triggers[action].append(target)

        return {'triggers': triggers}
Пример #14
0
class MyApp(QMainWindow):
    def __init__(self):
        super(MyApp, self).__init__()
        self.mainUI()
        self.setLayout()
        self.setWindowTitle("List App")
        self.setFixedSize(500, 300)
        self.setCentralWidget(self.setWidget)

    def mainUI(self):
        self.list = QListWidget()
        self.buttonAddItem = QPushButton("Add Item")
        self.buttonRemoveItem = QPushButton("Remove Item")
        self.buttonUpdateItem = QPushButton("update Item")
        self.buttonClearAllItem = QPushButton("clear all Item")
        self.buttonDuplicateItem = QPushButton("duplicate Item")

        # logic for progresss Bar
        self.buttonAddItem.clicked.connect(self.setInput)
        self.buttonRemoveItem.clicked.connect(self.setRemove)
        self.buttonClearAllItem.clicked.connect(self.setClear)
        self.buttonUpdateItem.clicked.connect(self.setUpdate)

        # logic for slider
        self.buttonDuplicateItem.clicked.connect(self.setDuplicate)

        self.slider = QSlider(Qt.Horizontal)
        self.progressbar = QProgressBar()

    def setLayout(self):
        self.layoutList = QVBoxLayout()
        self.layoutList.addWidget(self.list)
        self.layoutList.addWidget(self.buttonAddItem)
        self.layoutList.addWidget(self.buttonRemoveItem)
        self.layoutList.addWidget(self.buttonUpdateItem)
        self.layoutList.addWidget(self.buttonClearAllItem)
        self.layoutList.addWidget(self.buttonDuplicateItem)
        self.layoutList.addWidget(self.slider)
        self.layoutList.addWidget(self.progressbar)

        self.setWidget = QWidget()
        self.setWidget.setLayout(self.layoutList)

    def setDialog(self):

        self.dialog = QDialog()
        self.dialog.setFixedSize(400, 200)
        self.dialog.setWindowTitle("Custom Dialog Box")

        self.labelDialog = QLabel("custom label")
        self.button = QDialogButtonBox.Ok
        self.buttonBox = QDialogButtonBox(self.button)
        self.buttonBox.accepted.connect(self.dialog.accept)

        self.layoutDialog = QVBoxLayout()
        self.layoutDialog.addWidget(self.labelDialog)
        self.layoutDialog.addWidget(self.buttonBox)

        self.dialog.setLayout(self.layoutDialog)
        self.dialog.exec_()

    # logic dialog

    def setInput(self):
        self.inputDialog, ok = QInputDialog.getText(self, "Add to List Item",
                                                    "Enter Input")
        if ok == True:
            if self.inputDialog != "":
                self.add = QListWidgetItem(self.inputDialog, self.list)
                self.list.addItem(self.add)
                self.progressbar.setValue(self.list.count())
                print(f"check input dialog : {self.inputDialog}")
        print(ok)

    def setRemove(self):
        listdata_items = self.list.selectedItems()
        if not listdata_items:
            return
        for item in listdata_items:
            self.list.takeItem(self.list.row(item))
            self.progressbar.setValue(self.list.count())

    def setClear(self):
        self.list.clear()
        self.progressbar.setValue(self.list.count())

    def setUpdate(self):
        dialog_update = QInputDialog()
        listdata_selected = self.list.selectedItems()
        index = ['%s' % (i.text()) for i in listdata_selected]

        result, ok = dialog_update.getText(self,
                                           "Update List Item",
                                           "Update List",
                                           text=index[0])

        if ok == True and result != "":
            for item in listdata_selected:
                self.list.item(self.list.row(item)).setText(result)
        self.progressbar.setValue(self.list.count())

    def setDuplicate(self):
        range_itemselected = self.valuesitem_slider()
        listdata_selected = [
            '%s' % (i.text()) for i in self.list.selectedItems()
        ]
        for x in range(range_itemselected):
            QListWidgetItem(listdata_selected[0], self.list)
            self.progressbar.setValue(self.list.count())
        self.progressbar.setValue(self.list.count())

    def valuesitem_slider(self):
        return self.slider.value()
Пример #15
0
class DataSettingsPanel(SettingsPanel):
    def __init__(self, parent=None):
        super(DataSettingsPanel, self).__init__(parent)

        # Clear history dialog.
        self.clearHistoryDialog = clear_history_dialog.ClearHistoryDialog(self)
        self.clearHistoryDialog.hide()

        self.showClearHistoryDialogButton = QPushButton(tr("Clear Data"), self)
        self.showClearHistoryDialogButton.clicked.connect(self.clearHistoryDialog.exec_)
        self.layout().addWidget(self.showClearHistoryDialogButton)

        # Remember history checkbox.
        self.rememberHistoryToggle = QCheckBox(tr("Remember &history"), self)
        self.layout().addWidget(self.rememberHistoryToggle)

        # Maximum URL length spinbox.
        self.maximumURLLengthRow = custom_widgets.SpinBoxRow(tr("Maximum URL length:"), self)
        self.maximumURLLengthRow.expander.setText(tr("characters"))
        self.maximumURLLength = self.maximumURLLengthRow.spinBox
        self.maximumURLLength.setMaximum(9999)
        self.layout().addWidget(self.maximumURLLengthRow)

        # Maximum cache size spinbox.
        # The cache is gone because it f***s Nimbus with a chainsaw.
        #self.maximumCacheSizeRow = custom_widgets.SpinBoxRow(tr("Maximum cache size:"), self)
        #self.maximumCacheSizeRow.expander.setText(tr("MB"))
        #self.maximumCacheSize = self.maximumCacheSizeRow.spinBox
        #self.maximumCacheSize.setMaximum(20000)
        #self.layout().addWidget(self.maximumCacheSizeRow)

        # Checkbox to toggle geolocation.
        self.geolocationToggle = QCheckBox(tr("Enable geo&location"), self)
        self.layout().addWidget(self.geolocationToggle)

        self.geolocationPermissionsRow = custom_widgets.Row(self)
        self.layout().addWidget(self.geolocationPermissionsRow)

        self.geolocationWhitelistColumn = custom_widgets.Column(self)
        self.geolocationPermissionsRow.addWidget(self.geolocationWhitelistColumn)

        self.geolocationWhitelistLabel = QLabel(tr("Allow these sites to track my location:"), self)
        self.geolocationWhitelistColumn.addWidget(self.geolocationWhitelistLabel)

        self.geolocationWhitelist = QListWidget(self)
        self.geolocationWhitelistColumn.addWidget(self.geolocationWhitelist)

        self.removeFromWhitelistButton = QPushButton(tr("Remove"))
        self.removeFromWhitelistButton.clicked.connect(lambda: self.geolocationWhitelist.takeItem(self.geolocationWhitelist.row(self.geolocationWhitelist.currentItem())))
        self.geolocationWhitelistColumn.addWidget(self.removeFromWhitelistButton)

        self.geolocationBlacklistColumn = custom_widgets.Column(self)
        self.geolocationPermissionsRow.addWidget(self.geolocationBlacklistColumn)

        self.geolocationBlacklistLabel = QLabel(tr("Prevent these sites from tracking my location:"), self)
        self.geolocationBlacklistColumn.addWidget(self.geolocationBlacklistLabel)

        self.geolocationBlacklist = QListWidget(self)
        self.geolocationBlacklistColumn.addWidget(self.geolocationBlacklist)

        self.removeFromBlacklistButton = QPushButton(tr("Remove"))
        self.removeFromBlacklistButton.clicked.connect(lambda: self.geolocationBlacklist.takeItem(self.geolocationBlacklist.row(self.geolocationBlacklist.currentItem())))
        self.geolocationBlacklistColumn.addWidget(self.removeFromBlacklistButton)

        self.removeAction = QAction(self)
        self.removeAction.setShortcut("Del")
        self.removeAction.triggered.connect(lambda: self.geolocationWhitelist.takeItem(self.geolocationWhitelist.row(self.geolocationWhitelist.currentItem())) if self.geolocationWhitelist.hasFocus() else self.geolocationBlacklist.takeItem(self.geolocationBlacklist.row(self.geolocationBlacklist.currentItem())))
        self.addAction(self.removeAction)

        self.layout().addWidget(custom_widgets.Expander(self))
    def loadSettings(self):
        self.maximumURLLength.setValue(settings.setting_to_int("data/MaximumURLLength"))
        #self.maximumCacheSize.setValue(settings.setting_to_int("data/MaximumCacheSize"))
        self.rememberHistoryToggle.setChecked(settings.setting_to_bool("data/RememberHistory"))
        self.geolocationToggle.setChecked(settings.setting_to_bool("network/GeolocationEnabled"))
        self.geolocationWhitelist.clear()
        for url in data.geolocation_whitelist:
            self.geolocationWhitelist.addItem(url)
        self.geolocationBlacklist.clear()
        for url in data.geolocation_blacklist:
            self.geolocationBlacklist.addItem(url)
    def saveSettings(self):
        settings.settings.setValue("data/MaximumURLLength", self.maximumURLLength.value())
        #settings.settings.setValue("data/MaximumCacheSize", self.maximumCacheSize.value())
        settings.settings.setValue("data/RememberHistory", self.rememberHistoryToggle.isChecked())
        settings.settings.setValue("network/GeolocationEnabled", self.geolocationToggle.isChecked())
        data.geolocation_whitelist = [self.geolocationWhitelist.item(authority).text() for authority in range(0, self.geolocationWhitelist.count())]
        data.geolocation_blacklist = [self.geolocationBlacklist.item(authority).text() for authority in range(0, self.geolocationBlacklist.count())]
        data.saveData()
Пример #16
0
class CityListDlg(QDialog):
    citieslist_signal = pyqtSignal([list])
    citiesdict_signal = pyqtSignal([dict])

    def __init__(self,
                 citylist,
                 accurate_url,
                 appid,
                 trans_cities_dict,
                 parent=None):
        super(CityListDlg, self).__init__(parent)
        self.settings = QSettings()
        self.citylist = citylist
        self.trans_cities_dict = trans_cities_dict
        self.accurate_url = accurate_url
        self.appid = appid
        self.listWidget = QListWidget()
        self.listWidget.itemDoubleClicked.connect(self.translate)
        cities_list = []
        for i in self.citylist:
            cities_list.append(self.trans_cities_dict.get(i, i))
        self.listWidget.addItems(cities_list)
        buttonLayout = QVBoxLayout()
        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Ok
                                          | QDialogButtonBox.Cancel)
        self.buttonBox.rejected.connect(self.reject)
        self.buttonBox.accepted.connect(self.accept)
        layoutT = QVBoxLayout()
        layout = QHBoxLayout()
        layout.addWidget(self.listWidget)
        layout.addLayout(buttonLayout)
        for text, slot in ((self.tr("&Add..."),
                            self.add), (self.tr("&Remove..."), self.remove),
                           (self.tr("&Up"), self.up),
                           (self.tr("&Down"), self.down), (self.tr("De&fault"),
                                                           self.default),
                           (self.tr("&Sort"), self.listWidget.sortItems)):
            button = QPushButton(text)
            buttonLayout.addWidget(button)
            button.clicked.connect(slot)
        self.translate_button = QPushButton(
            QCoreApplication.translate('Button', '&Translate',
                                       'Edit cities name'))
        buttonLayout.addWidget(self.translate_button)
        self.translate_button.clicked.connect(self.translate)
        buttonLayout.addWidget(self.buttonBox)
        self.status = QLabel()
        layoutT.addLayout(layout)
        layoutT.addWidget(self.status)
        self.setLayout(layoutT)
        self.setWindowTitle(
            QCoreApplication.translate('Window title', 'Cities',
                                       'Cities list dialogue'))
        self.checklength()

    def add(self):
        self.status.setText('')
        lista = []
        newitem = ''
        self.citytoadd = ''
        self.countrytoadd = ''
        self._idtoadd = ''
        dialog = searchcity.SearchCity(self.accurate_url, self.appid, self)
        dialog.id_signal.connect(self.addcity)
        dialog.city_signal.connect(self.addcity)
        dialog.country_signal.connect(self.addcity)
        if dialog.exec_() == 1:
            newitem = (self.citytoadd + '_' + self.countrytoadd + '_' +
                       self._idtoadd)
            for row in range(self.listWidget.count()):
                lista.append(self.listWidget.item(row).text())
            if newitem in lista:
                self.status.setText(
                    QCoreApplication.translate(
                        'Status bar message',
                        'The city already exists in the list',
                        'Cities list dialogue'))
                return
            else:
                self.listWidget.addItem(newitem)
                self.checklength()
                self.status.setText('ℹ ' + QCoreApplication.translate(
                    'Status bar message',
                    'Toggle cities with mouse scroll on the weather window',
                    'Cities list dialogue'))

    def addcity(self, what):
        self.status.setText('')
        if what[0] == 'ID':
            self._idtoadd = what[1]
        elif what[0] == 'City':
            self.citytoadd = what[1]
        elif what[0] == 'Country':
            self.countrytoadd = what[1]

    def remove(self):
        self.status.setText('')
        if self.listWidget.count() == 1:
            self.status.setText(
                QCoreApplication.translate(
                    'Message when trying to remove the'
                    'last and unique city in the list',
                    'This is the default city!', 'Cities list dialogue'))
            return
        row = self.listWidget.currentRow()
        item = self.listWidget.item(row)
        if item is None:
            return
        message = self.tr('The city "{0}" has been removed').format(
            self.listWidget.item(row).text())
        item = self.listWidget.takeItem(row)
        del item
        self.status.setText(message)

    def up(self):
        self.status.setText('')
        row = self.listWidget.currentRow()
        if row >= 1:
            item = self.listWidget.takeItem(row)
            self.listWidget.insertItem(row - 1, item)
            self.listWidget.setCurrentItem(item)

    def down(self):
        self.status.setText('')
        row = self.listWidget.currentRow()
        if row < self.listWidget.count() - 1:
            item = self.listWidget.takeItem(row)
            self.listWidget.insertItem(row + 1, item)
            self.listWidget.setCurrentItem(item)

    def default(self):
        self.status.setText('')
        row = self.listWidget.currentRow()
        if row >= 1:
            item = self.listWidget.takeItem(row)
            self.listWidget.insertItem(0, item)
            self.listWidget.setCurrentItem(item)

    def checklength(self):
        if self.listWidget.count() == 1:
            # After adding the first city the entry is not activated
            self.listWidget.setCurrentRow(0)
        if self.listWidget.count() > 0:
            self.translate_button.setEnabled(True)
            self.listWidget.setMinimumWidth(
                self.listWidget.sizeHintForColumn(0))
        else:
            self.translate_button.setEnabled(False)

    def translate(self):
        city = self.listWidget.currentItem().text()
        dialog = citytranslate.CityTranslate(city, self.trans_cities_dict,
                                             self)
        dialog.city_signal.connect(self.current_translation)
        if dialog.exec_() == 1:
            row = self.listWidget.currentRow()
            item = self.listWidget.takeItem(row)
            del item
            self.listWidget.insertItem(row, self.current_translated_city)
            self.listWidget.setCurrentRow(row)

    def current_translation(self, translated_city):
        for city, translated in translated_city.items():
            if translated == '':
                translated = city
            self.trans_cities_dict[city] = translated
            self.current_translated_city = translated

    def accept(self):
        listtosend = []
        for row in range(self.listWidget.count()):
            city = self.find_city_key(self.listWidget.item(row).text())
            listtosend.append(city)
        if self.listWidget.count() == 0:
            return
        self.citieslist_signal[list].emit(listtosend)
        self.citiesdict_signal[dict].emit(self.trans_cities_dict)
        QDialog.accept(self)

    def find_city_key(self, city):
        for key, value in self.trans_cities_dict.items():
            if value == city:
                return key
        return city
Пример #17
0
class SettingsTab(QWidget):
    def __init__(self, elder):
        super().__init__()
        self.elder = elder
        self.layout = QGridLayout(self)
        self.settings = elder.settings
        self.listener = elder.listener

        paths = QGroupBox(self)
        paths.setTitle('Paths')
        paths_layout = QGridLayout(paths)
        self.layout.addWidget(paths)

        label = QLabel(paths)
        label.setText('Fiddler')
        paths_layout.addWidget(label, 0, 0, 1, 1)

        self.fiddler_path = QLineEdit(paths)
        self.fiddler_path.setText(self.settings.paths['Fiddler'])
        self.fiddler_path.setDisabled(True)
        paths_layout.addWidget(self.fiddler_path, 0, 1, 1, 1)

        button = QPushButton(paths)
        button.setText('...')
        button.clicked.connect(lambda: self.set_path('fiddler'))
        paths_layout.addWidget(button, 0, 2, 1, 1)

        label = QLabel(paths)
        label.setText('TurboHUD')
        paths_layout.addWidget(label, 1, 0, 1, 1)

        self.turbohud_path = QLineEdit(paths)
        self.turbohud_path.setText(self.settings.paths['TurboHUD'])
        self.turbohud_path.setDisabled(True)
        paths_layout.addWidget(self.turbohud_path, 1, 1, 1, 1)

        button = QPushButton(paths)
        button.setText('...')
        button.clicked.connect(lambda: self.set_path('turbohud'))
        paths_layout.addWidget(button, 1, 2, 1, 1)

        label = QLabel(paths)
        label.setText('pHelper')
        paths_layout.addWidget(label, 2, 0, 1, 1)

        self.phelper_path = QLineEdit(paths)
        self.phelper_path.setText(self.settings.paths['pHelper'])
        self.phelper_path.setDisabled(True)
        paths_layout.addWidget(self.phelper_path, 2, 1, 1, 1)

        button = QPushButton(paths)
        button.setText('...')
        button.clicked.connect(lambda: self.set_path('phelper'))
        paths_layout.addWidget(button, 2, 2, 1, 1)

        image_recognition = QGroupBox(self)
        image_recognition.setTitle('Auto Stuff (Image Recognition)')
        image_recognition_layout = QGridLayout(image_recognition)
        self.layout.addWidget(image_recognition, 0, 1)

        checkbox = QCheckBox(image_recognition)
        checkbox.setText('Auto start Game')
        checkbox.setChecked(self.settings.special['auto_start'])
        checkbox.clicked.connect(lambda: self.checkbox_clicked('auto_start'))
        image_recognition_layout.addWidget(checkbox, 0, 0)

        checkbox = QCheckBox(image_recognition)
        checkbox.setText('Auto open Rift / Grift')
        checkbox.setChecked(self.settings.special['auto_open'])
        checkbox.clicked.connect(lambda: self.checkbox_clicked('auto_open'))
        image_recognition_layout.addWidget(checkbox, 1, 0)

        radio = QRadioButton(image_recognition)
        radio.setText('Rift')
        radio.setChecked(self.settings.special['auto_open_option'] == 'rift')
        radio.clicked.connect(lambda: self.radio_clicked('rift'))
        image_recognition_layout.addWidget(radio, 2, 0)

        radio = QRadioButton(image_recognition)
        radio.setText('Grift')
        radio.setChecked(self.settings.special['auto_open_option'] == 'grift')
        radio.clicked.connect(lambda: self.radio_clicked('grift'))
        image_recognition_layout.addWidget(radio, 2, 1)

        checkbox = QCheckBox(image_recognition)
        checkbox.setText('Auto accept Grift')
        checkbox.setChecked(self.settings.special['auto_accept_gr'])
        checkbox.clicked.connect(
            lambda: self.checkbox_clicked('auto_accept_gr'))
        image_recognition_layout.addWidget(checkbox, 3, 0)

        checkbox = QCheckBox(image_recognition)
        checkbox.setText('Auto upgrade Gem')
        checkbox.setChecked(self.settings.special['auto_upgrade_gem'])
        checkbox.clicked.connect(
            lambda: self.checkbox_clicked('auto_upgrade_gem'))
        image_recognition_layout.addWidget(checkbox, 4, 0)

        checkbox = QCheckBox(image_recognition)
        checkbox.setText('Auto gamble')
        checkbox.setChecked(self.settings.special['auto_gamble'])
        checkbox.clicked.connect(lambda: self.checkbox_clicked('auto_gamble'))
        image_recognition_layout.addWidget(checkbox, 5, 0)

        poolspots = QGroupBox(self)
        poolspots.setTitle('Poolspots')
        poolspots_layout = QGridLayout(poolspots)
        self.layout.addWidget(poolspots, 1, 0)

        self.poolspot_list = QListWidget(poolspots)
        self.poolspot_list.setSelectionMode(QListWidget.MultiSelection)
        for act, ps in ressources.poolspots().items():
            for poolspot in ps:
                item = QListWidgetItem(self.poolspot_list)
                item.setText(
                    f'Act {act}: {string.capwords(poolspot.replace("_", " "))}'
                )
                item.poolspot = poolspot
                if poolspot in self.settings.poolspots:
                    item.setSelected(True)
        self.poolspot_list.itemSelectionChanged.connect(self.update_poolspots)
        poolspots_layout.addWidget(self.poolspot_list)

        # button = QPushButton(poolspots)
        # button.setText('Save')
        # button.clicked.connect(self.update_poolspots)
        # poolspots_layout.addWidget(button)

        gamble_item = QGroupBox(self)
        gamble_item.setTitle('Gamble Item')
        gamble_item_layout = QGridLayout(gamble_item)
        self.layout.addWidget(gamble_item, 1, 1)

        self.gamble_item_list = QListWidget(gamble_item)
        self.gamble_item_list.setSelectionMode(QListWidget.SingleSelection)
        for _item in ressources.items():
            item = QListWidgetItem(self.gamble_item_list)
            item.setText(string.capwords(_item.replace('_', ' ')))
            item.item = _item
            if _item == self.settings.special['gamble_item']:
                item.setSelected(True)
        self.gamble_item_list.itemSelectionChanged.connect(
            self.update_gamble_item)
        gamble_item_layout.addWidget(self.gamble_item_list)

        self.setLayout(self.layout)

    def set_path(self, path):
        exe = str(
            QFileDialog.getOpenFileName(self, 'Select Executables', '',
                                        'Executables (*.exe)')[0])
        if exe:
            if path == 'fiddler':
                self.settings.paths['Fiddler'] = exe
                self.fiddler_path.setText(exe)
            elif path == 'turbohud':
                self.settings.paths['TurboHUD'] = exe
                self.turbohud_path.setText(exe)
            elif path == 'phelper':
                self.settings.paths['pHelper'] = exe
                self.phelper_path.setText(exe)

    def update_poolspots(self):
        self.listener.stop()

        selected_spots = []
        for i in range(self.poolspot_list.count()):
            item = self.poolspot_list.item(i)
            if item.isSelected():
                selected_spots.append(item.poolspot)
        self.settings.poolspots = selected_spots

        if not self.listener.paused:
            self.listener.start()
        # TODO: Wenn man seinen Pause key deleted
        elif self.settings.hotkeys['pause']:
            keyboard.add_hotkey(self.settings.hotkeys['pause'],
                                self.listener.pause)

    def update_gamble_item(self):
        self.listener.stop()

        selected_item = self.gamble_item_list.selectedItems()[0]
        self.settings.special['gamble_item'] = selected_item.item

        if not self.listener.paused:
            self.listener.start()
        # TODO: Wenn man seinen Pause key deleted
        elif self.settings.hotkeys['pause']:
            keyboard.add_hotkey(self.settings.hotkeys['pause'],
                                self.listener.pause)

    def checkbox_clicked(self, value):
        sender = self.sender()
        self.settings.special[value] = sender.isChecked()

    def radio_clicked(self, value):
        self.settings.special['auto_open_option'] = value
Пример #18
0
class AbbrevationTab(QWidget):
    def __init__(self, elder):
        super().__init__()
        self.elder = elder
        self.layout = QGridLayout(self)
        self.settings = elder.settings
        self.listener = elder.listener

        checkbox = QCheckBox(self)
        checkbox.setText('Abbrevations enabled')
        checkbox.setChecked(self.settings.special['abbrevations_enabled'])
        checkbox.clicked.connect(self.checkbox_clicked)
        self.layout.addWidget(checkbox)

        abbrevations = QGroupBox(self)
        abbrevations.setTitle('Current Abbrevations')
        abbrevations_layout = QGridLayout(abbrevations)
        self.layout.addWidget(abbrevations)

        self.abbrevations_list = QListWidget(abbrevations)
        self.abbrevations_list.setSelectionMode(QListWidget.SingleSelection)
        for abbrevation, msg in self.settings.abbrevations.items():
            # Add the new Item to QListWidget
            custom_widget = CustomListWidget(abbrevation, msg)
            item = QListWidgetItem(self.abbrevations_list)
            item.abbrevation = abbrevation
            item.msg_line_edit = custom_widget.msg_edit

            self.abbrevations_list.addItem(item)
            item.setSizeHint(custom_widget.minimumSizeHint())
            self.abbrevations_list.setItemWidget(item, custom_widget)
        abbrevations_layout.addWidget(self.abbrevations_list, 0, 0, 1, 0)

        button = QPushButton(abbrevations)
        button.setText('Save')
        button.clicked.connect(self.update_abbrevations)
        abbrevations_layout.addWidget(button, 1, 0)

        button = QPushButton(abbrevations)
        button.setText('Add new')
        button.clicked.connect(self.add_item)
        abbrevations_layout.addWidget(button, 1, 1)

        button = QPushButton(abbrevations)
        button.setText('Remove selected')
        button.clicked.connect(self.remove_selected_item)
        abbrevations_layout.addWidget(button, 1, 2)

        self.layout.addWidget(abbrevations)

        self.setLayout(self.layout)

    def checkbox_clicked(self):
        self.listener.stop()
        sender = self.sender()

        self.settings.special['abbrevations_enabled'] = sender.isChecked()

        if not self.listener.paused:
            self.listener.start()
        # TODO: Wenn man seinen Pause key deleted
        elif self.settings.hotkeys['pause']:
            keyboard.add_hotkey(self.settings.hotkeys['pause'],
                                self.listener.pause)

    def update_abbrevations(self):
        self.listener.stop()

        new_abbrevations = {}
        for i in range(self.abbrevations_list.count()):
            item = self.abbrevations_list.item(i)
            abbrevation = item.abbrevation
            msg = item.msg_line_edit.text()
            new_abbrevations[abbrevation] = msg
        self.settings.abbrevations = new_abbrevations

        if not self.listener.paused:
            self.listener.start()
        # TODO: Wenn man seinen Pause key deleted
        elif self.settings.hotkeys['pause']:
            keyboard.add_hotkey(self.settings.hotkeys['pause'],
                                self.listener.pause)

    def remove_selected_item(self):
        if self.abbrevations_list.selectedItems():
            item = self.abbrevations_list.selectedItems()[0]
            self.abbrevations_list.takeItem(self.abbrevations_list.row(item))

    def add_item(self):
        dlg = AddItemDialog(self)
        if dlg.exec_():
            abbrevation = dlg.abbrevation_edit.text()
            msg = dlg.msg_edit.text()

            # Add the new Item to QListWidget
            custom_widget = CustomListWidget(abbrevation, msg)
            item = QListWidgetItem(self.abbrevations_list)
            item.abbrevation = abbrevation
            item.msg_line_edit = custom_widget.msg_edit

            self.abbrevations_list.addItem(item)
            item.setSizeHint(custom_widget.minimumSizeHint())
            self.abbrevations_list.setItemWidget(item, custom_widget)
Пример #19
0
class ContactCards(QWidget):
    def __init__(self, context: ListContext, parent: Any = None) -> None:
        super().__init__(parent)

        self._context = context

        self._layout = QVBoxLayout()
        self._layout.setContentsMargins(0, 0, 0, 0)
        self._layout.setSpacing(0)

        self._empty_label = None
        self._list = None

        contact_identities = self._context.wallet_api.get_identities()
        if len(contact_identities) > 0:
            for contact, identity in sorted(contact_identities,
                                            key=lambda t: t[0].label):
                self._add_identity(contact, identity)
        else:
            self._add_empty_label()

        self.setLayout(self._layout)

        self._context.wallet_api.contact_changed.connect(
            self._on_contact_changed)

    def _add_identity(self, contact: ContactEntry,
                      identity: ContactIdentity) -> None:
        self._remove_empty_label()
        if self._list is None:
            self._list = QListWidget(self)
            self._list.setSortingEnabled(True)
            self._layout.addWidget(self._list)

        test_card = ContactCard(self._context, contact, identity)
        test_card.setSizePolicy(QSizePolicy.MinimumExpanding,
                                QSizePolicy.Minimum)

        list_item = QListWidgetItem()
        list_item.setText(contact.label)
        # The item won't display unless it gets a size hint. It seems to resize horizontally
        # but unless the height is a minimal amount it won't do anything proactive..
        list_item.setSizeHint(QSize(256, 130))
        self._list.addItem(list_item)
        self._list.setItemWidget(list_item, test_card)

    def _remove_identity(self, contact: ContactEntry,
                         identity: ContactIdentity) -> None:
        removal_entries = []
        for i in range(self._list.count() - 1, -1, -1):
            item = self._list.item(i)
            widget = self._list.itemWidget(item)
            if identity is None and widget._contact.contact_id == contact.contact_id:
                self._list.takeItem(i)
            elif widget._identity.identity_id == identity.identity_id:
                self._list.takeItem(i)

        if self._list.count() == 0:
            # Remove the list.
            self._list.setParent(None)
            self._list = None

            # Replace it with the placeholder label.
            self._add_empty_label()

    def _on_contact_changed(self, added: bool, contact: ContactEntry,
                            identity: ContactIdentity) -> None:
        if added:
            self._add_identity(contact, identity)
        else:
            self._remove_identity(contact, identity)

    def _add_empty_label(self) -> None:
        self._empty_label = QLabel(
            _("You do not currently have any contacts."))
        self._empty_label.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        self._layout.addWidget(self._empty_label)

    def _remove_empty_label(self) -> None:
        if self._empty_label is not None:
            self._empty_label.setParent(None)
            self._empty_label = None
Пример #20
0
class window(QtWidgets.QMainWindow):   
   def __init__(self):
      super(window,self).__init__()
      self.currentlocal=0
      self.data=None
      self.checker=0
      self.lastcolored=0
      self.photo = QLabel(self)
      self.port=0
      self.pixmap = QPixmap('photo.png')
      self.pixmap = self.pixmap.scaled(600, 300, QtCore.Qt.KeepAspectRatio)
      self.photo.setPixmap(self.pixmap)

      self.labelgif=QLabel(self)      
      self.labelgif.setStyleSheet("QLabel { background-color : white;}");
      self.labelgif.setGeometry(100,50,500,430)
      self.movie = QtGui.QMovie('data.gif', QtCore.QByteArray(),self.labelgif)
      self.movie.setSpeed(100)
      self.labelgif.setMovie(self.movie) 
      self.movie.start()
      self.labelgif.setVisible(False)

      self.labelyazi=QLabel(self)
      self.labelgif1=QLabel(self)      
      self.labelgif1.setStyleSheet("QLabel { background-color : white;}")
      self.labelyazi.setText('G'+"\u00F6"+"zl"+"\u0259"+"yin..")
      font1=QtGui.QFont('Times',17)
      self.labelyazi.setFont(font1)
      self.labelyazi.setVisible(False)
      self.labelyazi.setGeometry(350,150,150,60)
      self.labelgif1.setGeometry(150,100,489,289)
      self.movie1 = QtGui.QMovie('wait.gif', QtCore.QByteArray(),self.labelgif1)
      self.movie1.setSpeed(100)
      self.labelgif1.setMovie(self.movie1) 
      self.movie1.start()
      self.labelgif1.setVisible(False)

      
      self.setWindowTitle("Diplom i\u015Fi v1")      
      self.setWindowIcon(QtGui.QIcon('pyicon.png'))
      self.button = QPushButton('PyQt5 button', self)#button yaradildi
      self.listw=QListWidget(self)#listWidget yaradildi
      self.button1=QPushButton(self)
      self.buttonlocal=QPushButton(self)
      self.buttonlocal.setText('Qo\u015F')
      self.button1.setText("Temperaturu"+" " +"\u00F6"+"l"+"\u00E7")
      self.dial=QDial(self)
      self.lcd=QLCDNumber(self)
      self.label=QLabel(self)
      self.labelrefresh=QLabel(self)
      self.obj=[]
   
      
      self.listCOM=QListWidget(self)
      self.spin=QSpinBox(self)
      self.radiosan=QRadioButton(self)
      self.radiosan.setText("Saniy"+"\u0259")
      self.radiodeq=QRadioButton(self)
      self.radiodeq.setText("D"+"\u0259"+"qiq"+"\u0259")
      self.starting()
      self.initUI()

      
   def initUI(self):                  
        self.setFixedSize(700,500)
        self.dial.setNotchesVisible(True)
        self.labelrefresh.setText('Yenil\u0259m\u0259k \u00FC\u00E7\u00FCn F5 d\u00FCym\u0259sini s\u0131x\u0131n ')
        self.labelrefresh.setStyleSheet("QLabel{background-color: yellow; }")
        font=QtGui.QFont('Times',10,QtGui.QFont.Bold)
        self.labelrefresh.setFont(font)
        self.lcd.setVisible(False)
        self.photo.setVisible(False)
        self.photo.raise_()            
        self.labelgif.raise_()
        self.labelgif1.raise_()
        self.labelyazi.raise_()
        self.spin.setRange(1,60)
        self.dial.setRange(1,60)
        self.button.setText("\u015E"+"\u0259"+"b\u0259k\u0259ni yoxla")
        self.button1.setEnabled(False)
        self.button.setEnabled(False)
        self.spin.setEnabled(False)
        self.dial.setEnabled(False)
        self.radiosan.setEnabled(False)
        self.radiodeq.setEnabled(False)
        self.label.setText('Qo\u015Fulmu'+'\u015F cihaz yoxdur')
        self.label.setStyleSheet("QLabel { background-color : #e20000; color : black; }");
        newfont = QtGui.QFont('Times',11) 
        self.label.setFont(newfont)        
        

        
        #geometries
        self.setGeometry(40,50,700,500)
        self.button.setGeometry(20,40,120,50)
        self.listw.setGeometry(380,160,300,200)
        self.button1.setGeometry(575,40,120,50)
        self.dial.setGeometry(40,400,75,70)
        self.spin.setGeometry(150,425,50,25)
        self.radiosan.setGeometry(150,400,75,25)
        self.radiodeq.setGeometry(150,380,75,25)
        self.lcd.setGeometry(300,40,100,50)
        self.buttonlocal.setGeometry(150,40,125,50)
        self.label.setGeometry(520,440,155,30)
        self.listCOM.setGeometry(20,160,300,200)
        self.labelrefresh.setGeometry(20,100,220,30)
        self.photo.setGeometry(50,100,600,300)
        
    
        #events
        self.buttonlocal.clicked.connect(self.checklocal)
        self.button.clicked.connect(self.thread1)
        self.button.clicked.connect(self.threadnetwork)
        self.dial.valueChanged.connect(self.spin.setValue)
        self.spin.valueChanged.connect(self.dial.setValue)
        self.listCOM.doubleClicked.connect(self.showdialog)
        self.listw.doubleClicked.connect(self.showdialogremote)
        self.button1.clicked.connect(self.thread) # communication
        self.radiodeq.clicked.connect(self.spinvalue)
        self.radiosan.clicked.connect(self.dialvalue)
        self.button1.clicked.connect(self.threadback)


    
   def threadback(self):
      if  self.radiodeq.isChecked() or self.radiosan.isChecked():
         self.thread1=threading.Thread(target=self.send)
         self.thread1.start()
      else:
         pass
   def loading(self):
      m=loading()
      

      
   def send(self):
      try:    
         self.currentlocal.open()
         remotestr=self.listw.currentItem().text()
         li=remotestr.split("-")
         xbee_network=self.currentlocal.get_network()         
         remote=xbee_network.get_device_by_64(XBee64BitAddress.from_hex_string(li[0]))
         arr_64=self.currentlocal.get_64bit_addr()
         NEW_TIMEOUT_FOR_SYNC_OPERATIONS = 1
         self.currentlocal.set_sync_ops_timeout(NEW_TIMEOUT_FOR_SYNC_OPERATIONS)
         if self.radiosan.isChecked():
            self.currentlocal.send_data(remote,str(arr_64)+"-"+str(self.spin.value()))
         else:
            self.currentlocal.send_data(remote,str(arr_64)+"-"+str(self.spin.value()*60))
         self.labelgif1.setVisible(False)     
         
                   
         self.labelgif1.setVisible(True)
         self.labelyazi.setVisible(True)
         while(True):
            self.data=self.currentlocal.read_data()
            if(self.data!=None):
               self.data=self.data.data.decode()
               self.labelgif1.setVisible(False)
               self.labelyazi.setVisible(False)
               break 
             
         self.currentlocal.close()
         
         data_list=self.data.split(',')
         self.labelgif.setVisible(True)
         
         objects = []
         performance=[]
         for i in range(1,len(data_list)):
            objects.append(i)
         for i in range(len(data_list)-1):
            li=data_list[i]
            li=li.split('-')
            performance.append(li[1])
         
         y_pos = np.arange(len(objects))
         objects=tuple(objects)
         plt.figure("Qrafik")
         plt.xticks(y_pos, objects)
         plt.ylabel('Temperatur')
         plt.xlabel('Zaman')
         plt.plot(y_pos,performance)
         self.labelgif.setVisible(False)
         plt.show()
         self.data=None
         
      except:
         print('salam')
         self.currentlocal.close()
      
         

         
   def showdialog(self): 
      try:
         li=self.listCOM.currentItem().text().split('-')
         local=XBeeDevice(li[2],9600)
         local.open()
         arr_64=local.get_64bit_addr()
         arr_16=local.get_16bit_addr()
         arr_node=local.get_node_id()
         arr_pro=local.get_protocol()
         arr_hard=local.get_hardware_version()
         local.close()
         dlg=dialog(arr_64,arr_16,arr_node,arr_pro,arr_hard)
      except:
         pass    #exception

      
   def showdialogremote(self): 
      li=self.listw.currentItem().text().split('-')
      if self.checker !=0:
         self.lastcolored.setBackground(QtGui.QColor(255,255,255))
         
      self.lastcolored=self.listw.currentItem()
      self.listw.currentItem().setBackground(QtGui.QColor(239, 255, 25))
      try:
         self.currentlocal.open()
         
         xbee_network=self.currentlocal.get_network()
         
         remote=xbee_network.get_device_by_64(XBee64BitAddress.from_hex_string(li[0]))
         
         arr_64=remote.get_64bit_addr()
         
         arr_16=remote.get_16bit_addr()
         arr_node=remote.get_node_id()
         arr_pro=remote.get_protocol()
         arr_hard=remote.get_hardware_version()
         self.currentlocal.close()
         dlg=dialog(arr_64,arr_16,arr_node,arr_pro,arr_hard)
         self.checker=1
      except:
         pass # exception
      

   def spinvalue(self):
      self.dial.setRange(1,60)
      self.spin.setRange(1,60)
      self.dial.setValue(1)
   def dialvalue(self):
      self.dial.setRange(4,60)
      self.spin.setRange(4,60)
      self.dial.setValue(4)
      
        
   def keyPressEvent(self, event):
      key = event.key()
      if key == QtCore.Qt.Key_F5:
         self.threadrefresh()


      

   def checklocal(self):                                               
      try:         
         if (self.currentlocal !=0):
            for i in range(0,self.listCOM.count()):
                 self.listCOM.item(i).setBackground(QtGui.QColor(255, 255, 255))
         self.listCOM.currentItem().setBackground(QtGui.QColor(97, 255, 66))
         li=self.listCOM.currentItem().text().split('-')
         self.currentlocal = XBeeDevice(li[2], 9600)
         self.port=li[2]        
         self.currentCOM=self.listCOM.currentItem().text()
         self.currentlocal.open()
         self.currentlocal.close()
         self.listw.clear()
         self.button1.setEnabled(True)
         self.button.setEnabled(True)
         self.spin.setEnabled(True)
         self.dial.setEnabled(True)     
         self.radiosan.setEnabled(True)
         self.radiodeq.setEnabled(True)
         if platform.system()=='Linux':
            self.label.setGeometry(500,440,180,30)
         self.label.setText('Qo\u015Fulmu'+'\u015F port: '+str(li[2]))
         self.checker=0  
         self.label.setStyleSheet("QLabel { background-color : #22ce00; color : white; }")
         
         
         
         
      except:
         QMessageBox.about(self, 'Yanl\u0131\u015F', 'Lokal cihaz\u0131n portu do\u011Fru deyil')

   def refresh(self):                                                                  
      self.listCOM.clear()
      index=0
      if platform.system()=='Windows':
         for i in range(0,257):
               try:               
                  local_xbee = XBeeDevice('COM'+str(i), 9600)
                  local_xbee.open()
                  addr64=local_xbee.get_64bit_addr()
                  noid=local_xbee.get_node_id()
                  local_xbee.close()
                  self.listCOM.addItem(str(addr64)+"-"+str(noid)+"-"+'COM'+str(i))
                  if(self.port=='COM'+str(i)):               
                     self.listCOM.item(index).setBackground(QtGui.QColor(97, 255, 66))
                  index+=1
               except:
                  pass
      elif platform.system()=='Linux':
         for i in range(257):
            try:               
               local_xbee = XBeeDevice('/dev/ttyUSB'+str(i), 9600)
               local_xbee.open()
               addr64=local_xbee.get_64bit_addr()
               noid=local_xbee.get_node_id()
               local_xbee.close()
               self.listCOM.addItem(str(addr64)+"-"+str(noid)+"-"+'/dev/ttyUSB'+str(i))
               if(self.port=='/dev/ttyUSB'+str(i)):               
                  self.listCOM.item(index).setBackground(QtGui.QColor(97, 255, 66))
               index+=1
            except:
               pass
      self.checker=0
         
      
      

         
        
   def thread(self):                                               
      if  self.radiodeq.isChecked() or self.radiosan.isChecked():
         self.thread=threading.Thread(target=self.timing)
         self.thread.start()
      else:
         QMessageBox.about(self, 'Yanl\u0131\u015F', 'Zaman vahidini se\u00E7in')

         
            
            
   def thread1(self):                                                          
      if  self.radiodeq.isChecked() or self.radiosan.isChecked():
         self.thread1=threading.Thread(target=self.scan)
         self.thread1.start()
      else:
         QMessageBox.about(self, 'Yanl\u0131\u015F', 'Zaman vahidini se\u00E7in')

   def threadnetwork(self):
      if  self.radiodeq.isChecked() or self.radiosan.isChecked():
         self.thread1=threading.Thread(target=self.network)
         self.thread1.start()
      else:
         pass


   def network(self):
      try:
         self.button1.setEnabled(False)
         self.buttonlocal.setEnabled(False)
         self.button.setEnabled(False)
         self.button1.setEnabled(False)
         self.spin.setEnabled(False)
         self.dial.setEnabled(False)    
         self.radiosan.setEnabled(False)
         self.radiodeq.setEnabled(False)
         self.listw.clear()
         self.currentlocal.open()
         xbee_network=self.currentlocal.get_network()
         xbee_network.clear()
         listdev=[]
         def callback_device_discovered(remote):
            listdev.append(str(remote))
         if self.radiosan.isChecked():
            if(self.spin.value()>25):
               defe=int((self.spin.value())/25)
               qaliqsan=(self.spin.value())%25
               for i in range(0,defe):
                  xbee_network.set_discovery_timeout(22)  
                  xbee_network.add_device_discovered_callback(callback_device_discovered)
                  xbee_network.start_discovery_process()
                  while xbee_network.is_discovery_running():
                     QtCore.QThread.msleep(100)
               if(qaliqsan<4):
                  add=q=4-qaliqsan
                  xbee_network.set_discovery_timeout(qaliqsan+add)  
                  xbee_network.add_device_discovered_callback(callback_device_discovered)
                  xbee_network.start_discovery_process()
                  while xbee_network.is_discovery_running():
                     QtCore.QThread.msleep(100)
               else:
                  xbee_network.set_discovery_timeout(qaliqsan) 
                  xbee_network.add_device_discovered_callback(callback_device_discovered)
                  xbee_network.start_discovery_process()
                  while xbee_network.is_discovery_running():
                     QtCore.QThread.msleep(100)
                     
               
               self.currentlocal.close()
            else:
               
               xbee_network.set_discovery_timeout(self.spin.value())   
               xbee_network.add_device_discovered_callback(callback_device_discovered)
               xbee_network.start_discovery_process()
               while xbee_network.is_discovery_running():
                  QtCore.QThread.msleep(100)
               self.currentlocal.close()
               
           
            self.photo.setVisible(True)
            listdev=list(set(listdev))
            for i in range(0,len(listdev)):
               self.listw.addItem(listdev[i])
            QtCore.QThread.msleep(1000)
            self.photo.setEnabled(True)
            self.buttonlocal.setEnabled(True)
            self.button1.setEnabled(True)
            self.button.setEnabled(True)
            self.spin.setEnabled(True)
            self.dial.setEnabled(True)     
            self.radiosan.setEnabled(True)
            self.radiodeq.setEnabled(True)
            self.photo.setVisible(False)
            
            

         if self.radiodeq.isChecked():
         
            defe=int((self.spin.value()*60)/25)
            qaliqsan=(self.spin.value()*60)%25
            for i in range(0,defe):
               xbee_network.set_discovery_timeout(22)  # 24 seconds + saniye elave.
               xbee_network.add_device_discovered_callback(callback_device_discovered)
               xbee_network.start_discovery_process()
               while xbee_network.is_discovery_running():
                  QtCore.QThread.msleep(100)
            xbee_network.set_discovery_timeout(qaliqsan)  # qaliq saniye.
            xbee_network.add_device_discovered_callback(callback_device_discovered)
            xbee_network.start_discovery_process()
            while xbee_network.is_discovery_running():
               QtCore.QThread.msleep(100)
            self.currentlocal.close()
         else:
            xbee_network.set_discovery_timeout(self.spin.value())  # qaliq saniye 
            xbee_network.add_device_discovered_callback(callback_device_discovered)
            xbee_network.start_discovery_process()
            while xbee_network.is_discovery_running():
               QtCore.QThread.msleep(100)
            self.currentlocal.close()
            
         self.photo.setVisible(True)  
         listdev=list(set(listdev))
         for i in range(0,len(listdev)):
            self.listw.addItem(listdev[i])
         QtCore.QThread.msleep(2000)
         self.buttonlocal.setEnabled(True)
         self.button1.setEnabled(True)
         self.button.setEnabled(True)
         self.spin.setEnabled(True)
         self.dial.setEnabled(True)
         self.radiosan.setEnabled(True)
         self.radiodeq.setEnabled(True)
         self.photo.setVisible(False)
         
      except:
         self.currentlocal.close()





   def threadrefresh(self):
      t=threading.Thread(target=self.refresh)
      t.start()
      


   #UI has been finished
      
   def timing(self):
      QtCore.QThread.msleep(1000)
      self.button1.setEnabled(False)
      if(self.radiodeq.isChecked()):
         self.lcd.setVisible(True)
         j=self.spin.value()*60
         k=self.spin.value()
         if(k<10):
            self.lcd.display("0{}:00".format(k))
            QtCore.QThread.msleep(1000)
         else:
            self.lcd.display("{}:00".format(k))
            QtCore.QThread.msleep(1000)
            
         j-=1
         k-=1
         while(j>-1):
            if(k<10):
               if(j%60<10):
                  if(j%60 is 0):                     
                     self.lcd.display("0{}:0{}".format(k,j%60))
                     k-=1
                     j-=1
                     QtCore.QThread.msleep(1000)
                     continue
                  self.lcd.display("0{}:0{}".format(k,j%60))
                  app.processEvents()
                  QtCore.QThread.msleep(1000)                     
                  j-=1
               else:
                  self.lcd.display("0{}:{}".format(k,j%60))
                  QtCore.QThread.msleep(1000)                     
                  j-=1
            else:
               if(j%60 is 0):
                  self.lcd.display("0{}:0{}".format(k,j%60))
                  k-=1
                  j-=1
                  QtCore.QThread.msleep(1000)
                  continue
               if(j%60<10):
                  self.lcd.display("{}:0{}".format(k,j%60))
                  QtCore.QThread.msleep(1000)
                  j-=1
               else:
                  self.lcd.display("{}:{}".format(k,j%60))
                  QtCore.QThread.msleep(1000)                     
                  j-=1
         self.lcd.setVisible(False)
         self.button1.setEnabled(True)

      elif (self.radiosan.isChecked()):
         self.lcd.setVisible(True)
         timing=self.spin.value()
         for i in range(timing,-1,-1):                     
            if(i<10):
               self.lcd.display("00:0{}".format(i))
               QtCore.QThread.msleep(1000)
               
            else:
               self.lcd.display("00:{}".format(i))
               QtCore.QThread.msleep(1000)
         self.lcd.setVisible(False)
         self.button1.setEnabled(True)

   def starting(self):
      splash=QtWidgets.QSplashScreen(QtGui.QPixmap('splash.jpg'),QtCore.Qt.WindowStaysOnTopHint)
      splash.show()
      for i in range(0,257):
         app.processEvents()
         if (i is 50):
               splash.showMessage("<h1><font color=#608fdb>Proqram başladılır!</font></h1>", QtCore.Qt.AlignTop)
               QtCore.QThread.msleep(1000)
         try:
            if (platform.system() == 'Windows'):
               local_xbee = XBeeDevice('COM'+str(i), 9600)
               local_xbee.open()
               addr64=local_xbee.get_64bit_addr()
               noid=local_xbee.get_node_id()
               local_xbee.close()
               self.listCOM.addItem(str(addr64)+"-"+str(noid)+"-"+'COM'+str(i))
            elif (platform.system() == 'Linux'):
               local_xbee = XBeeDevice('/dev/ttyUSB'+str(i), 9600)
               local_xbee.open()
               addr64=local_xbee.get_64bit_addr()
               noid=local_xbee.get_node_id()
               local_xbee.close()
               self.listCOM.addItem(str(addr64)+"-"+str(noid)+"-"+'/dev/ttyUSB'+str(i))         
         except:
            pass
      splash.close()

         
         
         



   def createlistw(self):
       self.listw.clear()
       for i in range(0,9):
          self.obj.append(i)
          self.obj[i]=elements()
          self.obj[i].t=[10,20,30,40,2,3,4,5,6]
          self.obj[i].s=[5,6,7,8,9,1,2,3,4,5,88]
          self.listw.addItem(str(self.obj[i].t[i]))

            
           

   def scan(self):
      self.button.setEnabled(False)

      if(self.radiodeq.isChecked()):
         self.lcd.setVisible(True)
         j=self.spin.value()*60
         k=self.spin.value()
         if(k<10):
            self.lcd.display("0{}:00".format(k))
            QtCore.QThread.msleep(1000)
         else:
            self.lcd.display("{}:00".format(k))
            QtCore.QThread.msleep(1000)
            
         j-=1
         k-=1
         while(j>-1):
            if(k<10):
               if(j%60<10):
                  if(j%60 is 0):
                     self.lcd.display("0{}:0{}".format(k,j%60))
                     k-=1
                     j-=1
                     QtCore.QThread.msleep(1000)
                     continue
                  self.lcd.display("0{}:0{}".format(k,j%60))
                  app.processEvents()
                  QtCore.QThread.msleep(1000)                     
                  j-=1
               else:
                  self.lcd.display("0{}:{}".format(k,j%60))
                  QtCore.QThread.msleep(1000)                     
                  j-=1
            else:
               if(j%60 is 0):
                  self.lcd.display("0{}:0{}".format(k,j%60))
                  k-=1
                  j-=1
                  QtCore.QThread.msleep(1000)
                  continue
               if(j%60<10):
                  self.lcd.display("{}:0{}".format(k,j%60))
                  QtCore.QThread.msleep(1000)
                  j-=1
               else:
                  self.lcd.display("{}:{}".format(k,j%60))
                  QtCore.QThread.msleep(1000)                     
                  j-=1
         self.lcd.setVisible(False)
         self.button.setEnabled(True)
      elif (self.radiosan.isChecked()):
         self.lcd.setVisible(True)
         timing=self.spin.value()
         for i in range(timing,-1,-1):
            if(i<10):
               self.lcd.display("00:0{}".format(i))
               QtCore.QThread.msleep(1000)                     
            else:
               self.lcd.display("00:{}".format(i))
               QtCore.QThread.msleep(1000)
         self.lcd.setVisible(False)
         self.button.setEnabled(True)
Пример #21
0
class SimulationGui(QMainWindow):
    """
    class for the graphical user interface
    """
    # TODO enable closing plot docks by right-clicking their name

    runSimulation = pyqtSignal()
    stopSimulation = pyqtSignal()
    playbackTimeChanged = pyqtSignal()
    regimeFinished = pyqtSignal()
    finishedRegimeBatch = pyqtSignal(bool)

    def __init__(self):
        # constructor of the base class
        QMainWindow.__init__(self)

        QCoreApplication.setOrganizationName("RST")
        QCoreApplication.setOrganizationDomain("https://tu-dresden.de/rst")
        QCoreApplication.setApplicationVersion(
            pkg_resources.require("PyMoskito")[0].version)
        QCoreApplication.setApplicationName(globals()["__package__"])

        # load settings
        self._settings = QSettings()
        self._read_settings()

        # initialize logger
        self._logger = logging.getLogger(self.__class__.__name__)

        # Create Simulation Backend
        self.guiProgress = None
        self.cmdProgress = None
        self.sim = SimulatorInteractor(self)
        self.runSimulation.connect(self.sim.run_simulation)
        self.stopSimulation.connect(self.sim.stop_simulation)
        self.sim.simulation_finalized.connect(self.new_simulation_data)
        self.currentDataset = None
        self.interpolator = None

        # sim setup viewer
        self.targetView = SimulatorView(self)
        self.targetView.setModel(self.sim.target_model)
        self.targetView.expanded.connect(self.target_view_changed)
        self.targetView.collapsed.connect(self.target_view_changed)

        # sim results viewer
        self.result_view = QTreeView()

        # the docking area allows to rearrange the user interface at runtime
        self.area = pg.dockarea.DockArea()

        # Window properties
        icon_size = QSize(25, 25)
        self.setCentralWidget(self.area)
        self.resize(1000, 700)
        self.setWindowTitle("PyMoskito")
        res_path = get_resource("mosquito.png")
        icon = QIcon(res_path)
        self.setWindowIcon(icon)

        # create docks
        self.propertyDock = pg.dockarea.Dock("Properties")
        self.animationDock = pg.dockarea.Dock("Animation")
        self.regimeDock = pg.dockarea.Dock("Regimes")
        self.dataDock = pg.dockarea.Dock("Data")
        self.logDock = pg.dockarea.Dock("Log")
        self.plotDockPlaceholder = pg.dockarea.Dock("Placeholder")

        # arrange docks
        self.area.addDock(self.animationDock, "right")
        self.area.addDock(self.regimeDock, "left", self.animationDock)
        self.area.addDock(self.propertyDock, "bottom", self.regimeDock)
        self.area.addDock(self.dataDock, "bottom", self.propertyDock)
        self.area.addDock(self.plotDockPlaceholder, "bottom", self.animationDock)
        self.area.addDock(self.logDock, "bottom", self.dataDock)
        self.non_plotting_docks = list(self.area.findAll()[1].keys())

        # add widgets to the docks
        self.propertyDock.addWidget(self.targetView)

        if not vtk_available:
            self._logger.error("loading vtk failed with:{}".format(vtk_error_msg))

        # check if there is a registered visualizer
        available_vis = get_registered_visualizers()
        self._logger.info("found visualizers: {}".format(
            [name for cls, name in available_vis]))
        if available_vis:
            # instantiate the first visualizer
            self._logger.info("loading visualizer '{}'".format(available_vis[0][1]))
            self.animationLayout = QVBoxLayout()

            if issubclass(available_vis[0][0], MplVisualizer):
                self.animationWidget = QWidget()
                self.visualizer = available_vis[0][0](self.animationWidget,
                                                      self.animationLayout)
                self.animationDock.addWidget(self.animationWidget)
            elif issubclass(available_vis[0][0], VtkVisualizer):
                if vtk_available:
                    # vtk window
                    self.animationFrame = QFrame()
                    self.vtkWidget = QVTKRenderWindowInteractor(
                        self.animationFrame)
                    self.animationLayout.addWidget(self.vtkWidget)
                    self.animationFrame.setLayout(self.animationLayout)
                    self.animationDock.addWidget(self.animationFrame)
                    self.vtk_renderer = vtkRenderer()
                    self.vtkWidget.GetRenderWindow().AddRenderer(
                        self.vtk_renderer)
                    self.visualizer = available_vis[0][0](self.vtk_renderer)
                    self.vtkWidget.Initialize()
                else:
                    self._logger.warning("visualizer depends on vtk which is "
                                         "not available on this system!")
            elif available_vis:
                raise NotImplementedError
        else:
            self.visualizer = None

        # regime window
        self.regime_list = QListWidget(self)
        self.regime_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.regimeDock.addWidget(self.regime_list)
        self.regime_list.itemDoubleClicked.connect(self.regime_dclicked)
        self._regimes = []
        self.regime_file_name = ""

        self.actDeleteRegimes = QAction(self.regime_list)
        self.actDeleteRegimes.setText("&Delete Selected Regimes")
        # TODO shortcut works always, not only with focus on the regime list
        # self.actDeleteRegimes.setShortcutContext(Qt.WindowShortcut)
        self.actDeleteRegimes.setShortcut(QKeySequence(Qt.Key_Delete))
        self.actDeleteRegimes.triggered.connect(self.remove_regime_items)

        self.actSave = QAction(self)
        self.actSave.setText('Save Results As')
        self.actSave.setIcon(QIcon(get_resource("save.png")))
        self.actSave.setDisabled(True)
        self.actSave.setShortcut(QKeySequence.Save)
        self.actSave.triggered.connect(self.export_simulation_data)

        self.actLoadRegimes = QAction(self)
        self.actLoadRegimes.setText("Load Regimes from File")
        self.actLoadRegimes.setIcon(QIcon(get_resource("load.png")))
        self.actLoadRegimes.setDisabled(False)
        self.actLoadRegimes.setShortcut(QKeySequence.Open)
        self.actLoadRegimes.triggered.connect(self.load_regime_dialog)

        self.actExitOnBatchCompletion = QAction(self)
        self.actExitOnBatchCompletion.setText("&Exit On Batch Completion")
        self.actExitOnBatchCompletion.setCheckable(True)
        self.actExitOnBatchCompletion.setChecked(
            self._settings.value("control/exit_on_batch_completion") == "True"
        )
        self.actExitOnBatchCompletion.changed.connect(
            self.update_exit_on_batch_completion_setting)

        # regime management
        self.runningBatch = False
        self._current_regime_index = None
        self._current_regime_name = None
        self._regimes = []

        self.regimeFinished.connect(self.run_next_regime)
        self.finishedRegimeBatch.connect(self.regime_batch_finished)

        # data window
        self.dataList = QListWidget(self)
        self.dataDock.addWidget(self.dataList)
        self.dataList.itemDoubleClicked.connect(self.create_plot)

        # actions for simulation control
        self.actSimulateCurrent = QAction(self)
        self.actSimulateCurrent.setText("&Simulate Current Regime")
        self.actSimulateCurrent.setIcon(QIcon(get_resource("simulate.png")))
        self.actSimulateCurrent.setShortcut(QKeySequence("F5"))
        self.actSimulateCurrent.triggered.connect(self.start_simulation)

        self.actSimulateAll = QAction(self)
        self.actSimulateAll.setText("Simulate &All Regimes")
        self.actSimulateAll.setIcon(QIcon(get_resource("execute_regimes.png")))
        self.actSimulateAll.setShortcut(QKeySequence("F6"))
        self.actSimulateAll.setDisabled(True)
        self.actSimulateAll.triggered.connect(self.start_regime_execution)

        # actions for animation control
        self.actAutoPlay = QAction(self)
        self.actAutoPlay.setText("&Autoplay Simulation")
        self.actAutoPlay.setCheckable(True)
        self.actAutoPlay.setChecked(
            self._settings.value("control/autoplay_animation") == "True"
        )
        self.actAutoPlay.changed.connect(self.update_autoplay_setting)

        self.actPlayPause = QAction(self)
        self.actPlayPause.setText("Play Animation")
        self.actPlayPause.setIcon(QIcon(get_resource("play.png")))
        self.actPlayPause.setDisabled(True)
        self.actPlayPause.setShortcut(QKeySequence(Qt.Key_Space))
        self.actPlayPause.triggered.connect(self.play_animation)

        self.actStop = QAction(self)
        self.actStop.setText("Stop")
        self.actStop.setIcon(QIcon(get_resource("stop.png")))
        self.actStop.setDisabled(True)
        self.actStop.triggered.connect(self.stop_animation)

        self.actSlow = QAction(self)
        self.actSlow.setText("Slowest")
        self.actSlow.setIcon(QIcon(get_resource("slow.png")))
        self.actSlow.setDisabled(False)
        self.actSlow.triggered.connect(self.set_slowest_playback_speed)

        self.actFast = QAction(self)
        self.actFast.setText("Fastest")
        self.actFast.setIcon(QIcon(get_resource("fast.png")))
        self.actFast.setDisabled(False)
        self.actFast.triggered.connect(self.set_fastest_playback_speed)

        self.speedControl = QSlider(Qt.Horizontal, self)
        self.speedControl.setMaximumSize(200, 25)
        self.speedControl.setTickPosition(QSlider.TicksBothSides)
        self.speedControl.setDisabled(False)
        self.speedControl.setMinimum(0)
        self.speedControl.setMaximum(12)
        self.speedControl.setValue(6)
        self.speedControl.setTickInterval(6)
        self.speedControl.setSingleStep(2)
        self.speedControl.setPageStep(3)
        self.speedControl.valueChanged.connect(self.update_playback_speed)

        self.timeSlider = QSlider(Qt.Horizontal, self)
        self.timeSlider.setMinimum(0)
        self.timeSliderRange = 1000
        self.timeSlider.setMaximum(self.timeSliderRange)
        self.timeSlider.setTickInterval(1)
        self.timeSlider.setTracking(True)
        self.timeSlider.setDisabled(True)
        self.timeSlider.valueChanged.connect(self.update_playback_time)

        self.playbackTime = .0
        self.playbackGain = 1
        self.currentStepSize = .0
        self.currentEndTime = .0
        self.playbackTimer = QTimer()
        self.playbackTimer.timeout.connect(self.increment_playback_time)
        self.playbackTimeChanged.connect(self.update_gui)
        self.playbackTimeout = 33  # in [ms] -> 30 fps

        self.actResetCamera = QAction(self)
        self.actResetCamera.setText("Reset Camera")
        self.actResetCamera.setIcon(QIcon(get_resource("reset_camera.png")))
        self.actResetCamera.setDisabled(True)
        if available_vis:
            self.actResetCamera.setEnabled(self.visualizer.can_reset_view)
        self.actResetCamera.triggered.connect(self.reset_camera_clicked)

        # postprocessing
        self.actPostprocessing = QAction(self)
        self.actPostprocessing.setText("Launch Postprocessor")
        self.actPostprocessing.setIcon(QIcon(get_resource("processing.png")))
        self.actPostprocessing.setDisabled(False)
        self.actPostprocessing.triggered.connect(self.postprocessing_clicked)
        self.actPostprocessing.setShortcut(QKeySequence("F7"))

        self.postprocessor = None

        # toolbar
        self.toolbarSim = QToolBar("Simulation")
        self.toolbarSim.setContextMenuPolicy(Qt.PreventContextMenu)
        self.toolbarSim.setMovable(False)
        self.toolbarSim.setIconSize(icon_size)
        self.addToolBar(self.toolbarSim)
        self.toolbarSim.addAction(self.actLoadRegimes)
        self.toolbarSim.addAction(self.actSave)
        self.toolbarSim.addSeparator()
        self.toolbarSim.addAction(self.actSimulateCurrent)
        self.toolbarSim.addAction(self.actSimulateAll)
        self.toolbarSim.addSeparator()
        self.toolbarSim.addAction(self.actPlayPause)
        self.toolbarSim.addAction(self.actStop)
        self.toolbarSim.addWidget(self.timeSlider)
        self.toolbarSim.addSeparator()
        self.toolbarSim.addAction(self.actSlow)
        self.toolbarSim.addWidget(self.speedControl)
        self.toolbarSim.addAction(self.actFast)
        self.toolbarSim.addSeparator()
        self.toolbarSim.addAction(self.actPostprocessing)
        self.toolbarSim.addAction(self.actResetCamera)
        self.postprocessor = None

        # log dock
        self.logBox = QPlainTextEdit(self)
        self.logBox.setReadOnly(True)
        self.logDock.addWidget(self.logBox)

        # init logger for logging box
        self.textLogger = PlainTextLogger(logging.INFO)
        self.textLogger.set_target_cb(self.logBox.appendPlainText)
        logging.getLogger().addHandler(self.textLogger)

        # menu bar
        fileMenu = self.menuBar().addMenu("&File")
        fileMenu.addAction(self.actLoadRegimes)
        fileMenu.addAction(self.actSave)
        fileMenu.addAction("&Quit", self.close)

        editMenu = self.menuBar().addMenu("&Edit")
        editMenu.addAction(self.actDeleteRegimes)

        simMenu = self.menuBar().addMenu("&Simulation")
        simMenu.addAction(self.actSimulateCurrent)
        simMenu.addAction(self.actSimulateAll)
        simMenu.addAction(self.actExitOnBatchCompletion)
        simMenu.addAction(self.actPostprocessing)

        animMenu = self.menuBar().addMenu("&Animation")
        animMenu.addAction(self.actPlayPause)
        animMenu.addAction("&Increase Playback Speed",
                           self.increment_playback_speed,
                           QKeySequence(Qt.CTRL + Qt.Key_Plus))
        animMenu.addAction("&Decrease Playback Speed",
                           self.decrement_playback_speed,
                           QKeySequence(Qt.CTRL + Qt.Key_Minus))
        animMenu.addAction("&Reset Playback Speed",
                           self.reset_playback_speed,
                           QKeySequence(Qt.CTRL + Qt.Key_0))
        animMenu.addAction(self.actAutoPlay)
        animMenu.addAction(self.actResetCamera)

        helpMenu = self.menuBar().addMenu("&Help")
        helpMenu.addAction("&Online Documentation", self.show_online_docs)
        helpMenu.addAction("&About", self.show_info)

        # status bar
        self.status = QStatusBar(self)
        self.setStatusBar(self.status)
        self.statusLabel = QLabel("Ready.")
        self.statusBar().addPermanentWidget(self.statusLabel)
        self.timeLabel = QLabel("current time: 0.0")
        self.statusBar().addPermanentWidget(self.timeLabel)

        self._logger.info("Simulation GUI is up and running.")

    def _read_settings(self):

        # add default settings if none are present
        if not self._settings.contains("path/simulation_results"):
            self._settings.setValue("path/simulation_results",
                                    os.path.join(os.path.curdir,
                                                 "results",
                                                 "simulation"))
        if not self._settings.contains("path/postprocessing_results"):
            self._settings.setValue("path/postprocessing_results",
                                    os.path.join(os.path.curdir,
                                                 "results",
                                                 "postprocessing"))
        if not self._settings.contains("path/metaprocessing_results"):
            self._settings.setValue("path/metaprocessing_results",
                                    os.path.join(os.path.curdir,
                                                 "results",
                                                 "metaprocessing"))

        if not self._settings.contains("control/autoplay_animation"):
            self._settings.setValue("control/autoplay_animation", "False")

        if not self._settings.contains("control/exit_on_batch_completion"):
            self._settings.setValue("control/exit_on_batch_completion", "False")

    def _write_settings(self):
        """ Store the application state. """
        pass

    @pyqtSlot()
    def update_autoplay_setting(self):
        self._settings.setValue("control/autoplay_animation",
                                str(self.actAutoPlay.isChecked()))

    @pyqtSlot()
    def update_exit_on_batch_completion_setting(self, state=None):
        if state is None:
            state = self.actExitOnBatchCompletion.isChecked()
        self._settings.setValue("control/exit_on_batch_completion", str(state))

    def set_visualizer(self, vis):
        self.visualizer = vis
        self.vtkWidget.Initialize()

    @pyqtSlot()
    def play_animation(self):
        """
        play the animation
        """
        self._logger.debug("Starting Playback")

        # if we are at the end, start from the beginning
        if self.playbackTime == self.currentEndTime:
            self.timeSlider.setValue(0)

        self.actPlayPause.setText("Pause Animation")
        self.actPlayPause.setIcon(QIcon(get_resource("pause.png")))
        self.actPlayPause.triggered.disconnect(self.play_animation)
        self.actPlayPause.triggered.connect(self.pause_animation)
        self.playbackTimer.start(self.playbackTimeout)

    @pyqtSlot()
    def pause_animation(self):
        """
        pause the animation
        """
        self._logger.debug("Pausing Playback")
        self.playbackTimer.stop()
        self.actPlayPause.setText("Play Animation")
        self.actPlayPause.setIcon(QIcon(get_resource("play.png")))
        self.actPlayPause.triggered.disconnect(self.pause_animation)
        self.actPlayPause.triggered.connect(self.play_animation)

    def stop_animation(self):
        """
        Stop the animation if it is running and reset the playback time.
        """
        self._logger.debug("Stopping Playback")
        if self.actPlayPause.text() == "Pause Animation":
            # animation is playing -> stop it
            self.playbackTimer.stop()
            self.actPlayPause.setText("Play Animation")
            self.actPlayPause.setIcon(QIcon(get_resource("play.png")))
            self.actPlayPause.triggered.disconnect(self.pause_animation)
            self.actPlayPause.triggered.connect(self.play_animation)

        self.timeSlider.setValue(0)

    @pyqtSlot()
    def start_simulation(self):
        """
        start the simulation and disable start button
        """
        if self._current_regime_index is None:
            regime_name = ""
        else:
            regime_name = str(self.regime_list.item(
                self._current_regime_index).text())

        self.statusLabel.setText("simulating {}".format(regime_name))
        self._logger.info("Simulating: {}".format(regime_name))

        self.actSimulateCurrent.setIcon(QIcon(
            get_resource("stop_simulation.png")))
        self.actSimulateCurrent.setText("Abort &Simulation")
        self.actSimulateCurrent.triggered.disconnect(self.start_simulation)
        self.actSimulateCurrent.triggered.connect(self.stop_simulation)

        if not self.runningBatch:
            self.actSimulateAll.setDisabled(True)

        self.guiProgress = QProgressBar(self)
        self.sim.simulationProgressChanged.connect(self.guiProgress.setValue)
        self.statusBar().addWidget(self.guiProgress)
        self.runSimulation.emit()

    @pyqtSlot()
    def stop_simulation(self):
        self.stopSimulation.emit()

    def export_simulation_data(self, ok):
        """
        Query the user for a custom name and export the current simulation
        results.

        :param ok: unused parameter from QAction.triggered() Signal
        """
        self._save_data()

    def _save_data(self, file_path=None):
        """
        Save the current simulation results.

        If *fie_name* is given, the result will be saved to the specified
        location, making automated exporting easier.

        Args:
            file_path(str): Absolute path of the target file. If `None` the
                use will be asked for a storage location.
        """
        regime_name = self._regimes[self._current_regime_index]["Name"]

        if file_path is None:
            # get default path
            path = self._settings.value("path/simulation_results")

            # create canonic file name
            suggestion = self._simfile_name(regime_name)
        else:
            path = os.path.dirname(file_path)
            suggestion = os.path.basename(file_path)

        # check if path exists otherwise create it
        if not os.path.isdir(path):
            box = QMessageBox()
            box.setText("Export Folder does not exist yet.")
            box.setInformativeText("Do you want to create it? \n"
                                   "{}".format(os.path.abspath(path)))
            box.setStandardButtons(QMessageBox.Ok | QMessageBox.No)
            box.setDefaultButton(QMessageBox.Ok)
            ret = box.exec_()
            if ret == QMessageBox.Ok:
                os.makedirs(path)
            else:
                path = os.path.abspath(os.path.curdir)
                file_path = None

        # If no path was given, present the default and let the user choose
        if file_path is None:
            dialog = QFileDialog(self)
            dialog.setAcceptMode(QFileDialog.AcceptSave)
            dialog.setFileMode(QFileDialog.AnyFile)
            dialog.setDirectory(path)
            dialog.setNameFilter("PyMoskito Results (*.pmr)")
            dialog.selectFile(suggestion)

            if dialog.exec_():
                file_path = dialog.selectedFiles()[0]
            else:
                self._logger.warning("Export Aborted")
                return -1

        # ask whether this should act as new default
        path = os.path.abspath(os.path.dirname(file_path))
        if path != self._settings.value("path/simulation_results"):
            box = QMessageBox()
            box.setText("Use this path as new default?")
            box.setInformativeText("{}".format(path))
            box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            box.setDefaultButton(QMessageBox.Yes)
            ret = box.exec_()
            if ret == QMessageBox.Yes:
                self._settings.setValue("path/simulation_results", path)

        self.currentDataset.update({"regime name": regime_name})
        with open(file_path, "wb") as f:
            pickle.dump(self.currentDataset, f, protocol=4)

        self.statusLabel.setText("results saved to {}".format(file_path))
        self._logger.info("results saved to {}".format(file_path))

    def _simfile_name(self, regime_name):
        """ Create a canonical name for a simulation result file
        """
        suggestion = (time.strftime("%Y%m%d-%H%M%S")
                      + "_" + regime_name + ".pmr")
        return suggestion

    def load_regime_dialog(self):
        regime_path = os.path.join(os.curdir)

        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.ExistingFile)
        dialog.setDirectory(regime_path)
        dialog.setNameFilter("Simulation Regime files (*.sreg)")

        if dialog.exec_():
            file = dialog.selectedFiles()[0]
            self.load_regimes_from_file(file)

    def load_regimes_from_file(self, file_name):
        """
        load simulation regime from file
        :param file_name:
        """
        self.regime_file_name = os.path.split(file_name)[-1][:-5]
        self._logger.info("loading regime file: {0}".format(self.regime_file_name))
        with open(file_name.encode(), "r") as f:
            self._regimes += yaml.load(f)

        self._update_regime_list()

        if self._regimes:
            self.actSimulateAll.setDisabled(False)

        self._logger.info("loaded {} regimes".format(len(self._regimes)))
        self.statusBar().showMessage("loaded {} regimes.".format(len(self._regimes)), 1000)
        return

    def _update_regime_list(self):
        self.regime_list.clear()
        for reg in self._regimes:
            self._logger.debug("adding '{}' to regime list".format(reg["Name"]))
            self.regime_list.addItem(reg["Name"])

    def remove_regime_items(self):
        if self.regime_list.currentRow() >= 0:
            # flag all selected files as invalid
            items = self.regime_list.selectedItems()
            for item in items:
                del self._regimes[self.regime_list.row(item)]
                self.regime_list.takeItem(self.regime_list.row(item))

    @pyqtSlot(QListWidgetItem)
    def regime_dclicked(self, item):
        """
        Apply the selected regime to the current target.
        """
        self.apply_regime_by_name(str(item.text()))

    def apply_regime_by_name(self, regime_name):
        """
        Apply the regime given by `regime_name` und update the regime index.

        Returns:
            bool: `True` if successful, `False` if errors occurred.
        """
        # get regime idx
        try:
            idx = list(map(itemgetter("Name"), self._regimes)).index(regime_name)
        except ValueError as e:
            self._logger.error("apply_regime_by_name(): Error no regime called "
                               "'{0}'".format(regime_name))
            return False

        # apply
        return self._apply_regime_by_idx(idx)

    def _apply_regime_by_idx(self, index=0):
        """
        Apply the given regime.

        Args:
            index(int): Index of the regime in the `RegimeList` .

        Returns:
            bool: `True` if successful, `False` if errors occurred.
        """
        if index >= len(self._regimes):
            self._logger.error("applyRegime: index error! ({})".format(index))
            return False

        reg_name = self._regimes[index]["Name"]
        self.statusBar().showMessage("regime {} applied.".format(reg_name),
                                     1000)
        self._logger.info("applying regime '{}'".format(reg_name))

        self._current_regime_index = index
        self._current_regime_name = reg_name

        return self.sim.set_regime(self._regimes[index])

    @pyqtSlot()
    def start_regime_execution(self):
        """
        Simulate all regimes in the regime list.
        """
        self.actSimulateAll.setText("Stop Simulating &All Regimes")
        self.actSimulateAll.setIcon(QIcon(get_resource("stop_batch.png")))
        self.actSimulateAll.triggered.disconnect(self.start_regime_execution)
        self.actSimulateAll.triggered.connect(self.stop_regime_excecution)

        self.runningBatch = True
        self._current_regime_index = -1
        self.regimeFinished.emit()

    def run_next_regime(self):
        """
        Execute the next regime in the regime batch.
        """
        # are we finished?
        if self._current_regime_index == len(self._regimes) - 1:
            self.finishedRegimeBatch.emit(True)
            return

        suc = self._apply_regime_by_idx(self._current_regime_index + 1)
        if not suc:
            self.finishedRegimeBatch.emit(False)
            return

        self.start_simulation()

    @pyqtSlot()
    def stop_regime_excecution(self):
        """ Stop the batch process.
        """
        self.stopSimulation.emit()
        self.finishedRegimeBatch.emit(False)

    def regime_batch_finished(self, status):
        self.runningBatch = False
        self.actSimulateAll.setDisabled(False)
        self.actSave.setDisabled(True)

        self.actSimulateAll.setText("Simulate &All Regimes")
        self.actSimulateAll.setIcon(QIcon(get_resource("execute_regimes.png")))
        self.actSimulateAll.triggered.disconnect(self.stop_regime_excecution)
        self.actSimulateAll.triggered.connect(self.start_regime_execution)

        if status:
            self.statusLabel.setText("All regimes have been simulated")
            self._logger.info("All Regimes have been simulated")
        else:
            self._logger.error("Batch simulation has been aborted")

        if self._settings.value("control/exit_on_batch_completion") == "True":
            self._logger.info("Shutting down SimulationGUI")
            self.close()

    @pyqtSlot(str, dict, name="new_simulation_data")
    def new_simulation_data(self, status, data):
        """
        Slot to be called when the simulation interface has completed the
        current job and new data is available.

        Args:
            status (str): Status of the simulation, either
                - `finished` : Simulation has been finished successfully or
                - `failed` : Simulation has failed.
            data (dict): Dictionary, holding the simulation data.
        """
        self._logger.info("Simulation {}".format(status))
        self.statusLabel.setText("Simulation {}".format(status))

        self.actSimulateCurrent.setText("&Simulate Current Regime")
        self.actSimulateCurrent.setIcon(QIcon(get_resource("simulate.png")))
        self.actSimulateCurrent.triggered.disconnect(self.stop_simulation)
        self.actSimulateCurrent.triggered.connect(self.start_simulation)

        self.actPlayPause.setDisabled(False)
        self.actStop.setDisabled(False)
        self.actSave.setDisabled(False)
        self.speedControl.setDisabled(False)
        self.timeSlider.setDisabled(False)

        self.sim.simulationProgressChanged.disconnect(self.guiProgress.setValue)
        self.statusBar().removeWidget(self.guiProgress)

        self.stop_animation()

        self.currentDataset = data
        if data:
            self._read_results()
            self._update_data_list()
            self._update_plots()

        if self._settings.value("control/autoplay_animation") == "True":
            self.actPlayPause.trigger()

        if self.runningBatch:
            regime_name = self._regimes[self._current_regime_index]["Name"]
            file_name = self._simfile_name(regime_name)
            self._save_data(os.path.join(
                self._settings.value("path/simulation_results"),
                file_name))
            self.regimeFinished.emit()
        else:
            self.actSimulateAll.setDisabled(False)

    def _read_results(self):
        state = self.currentDataset["results"]["Solver"]
        self.interpolator = interp1d(self.currentDataset["results"]["time"],
                                     state,
                                     axis=0,
                                     bounds_error=False,
                                     fill_value=(state[0], state[-1]))
        self.currentStepSize = 1.0/self.currentDataset["simulation"][
            "measure rate"]
        self.currentEndTime = self.currentDataset["simulation"]["end time"]
        self.validData = True

    def increment_playback_speed(self):
        self.speedControl.setValue(self.speedControl.value()
                                   + self.speedControl.singleStep())

    def decrement_playback_speed(self):
        self.speedControl.setValue(self.speedControl.value()
                                   - self.speedControl.singleStep())

    def reset_playback_speed(self):
        self.speedControl.setValue((self.speedControl.maximum()
                                    - self.speedControl.minimum())/2)

    def set_slowest_playback_speed(self):
        self.speedControl.setValue(self.speedControl.minimum())

    def set_fastest_playback_speed(self):
        self.speedControl.setValue(self.speedControl.maximum())

    def update_playback_speed(self, val):
        """
        adjust playback time to slider value

        :param val:
        """
        maximum = self.speedControl.maximum()
        self.playbackGain = 10**(3.0 * (val - maximum / 2) / maximum)

    @pyqtSlot()
    def increment_playback_time(self):
        """
        go one time step forward in playback
        """
        if self.playbackTime == self.currentEndTime:
            self.pause_animation()
            return

        increment = self.playbackGain * self.playbackTimeout / 1000
        self.playbackTime = min(self.currentEndTime,
                                self.playbackTime + increment)
        pos = int(self.playbackTime / self.currentEndTime
                  * self.timeSliderRange)
        self.timeSlider.blockSignals(True)
        self.timeSlider.setValue(pos)
        self.timeSlider.blockSignals(False)
        self.playbackTimeChanged.emit()

    def update_playback_time(self):
        """
        adjust playback time to slider value
        """
        self.playbackTime = self.timeSlider.value()/self.timeSliderRange*self.currentEndTime
        self.playbackTimeChanged.emit()
        return

    def update_gui(self):
        """
        updates the graphical user interface, including:
            - timestamp
            - visualisation
            - time cursor in diagrams
        """
        if not self.validData:
            return

        self.timeLabel.setText("current time: %4f" % self.playbackTime)

        # update time cursor in plots
        self._update_time_cursors()

        # update state of rendering
        if self.visualizer:
            state = self.interpolator(self.playbackTime)
            self.visualizer.update_scene(state)
            if isinstance(self.visualizer, MplVisualizer):
                pass
            elif isinstance(self.visualizer, VtkVisualizer):
                self.vtkWidget.GetRenderWindow().Render()

    def _update_data_list(self):
        self.dataList.clear()
        for module_name, results in self.currentDataset["results"].items():
            if not isinstance(results, np.ndarray):
                continue
            if len(results.shape) == 1:
                self.dataList.insertItem(0, module_name)
            elif len(results.shape) == 2:
                for col in range(results.shape[1]):
                    self.dataList.insertItem(
                        0,
                        self._build_entry_name(module_name, (col, ))
                    )
            elif len(results.shape) == 3:
                for col in range(results.shape[1]):
                    for der in range(results.shape[2]):
                        self.dataList.insertItem(
                            0,
                            self._build_entry_name(module_name, (col, der))
                        )

    def _build_entry_name(self, module_name, idx):
        """
        Construct an identifier for a given entry of a module.
        Args:
            module_name (str): name of the module the entry belongs to.
            idx (tuple): Index of the entry.

        Returns:
            str: Identifier to use for display.
        """
        # save the user from defining 1d entries via tuples
        if len(idx) == 1:
            m_idx = idx[0]
        else:
            m_idx = idx

        mod_settings = self.currentDataset["modules"]
        info = mod_settings.get(module_name, {}).get("output_info", None)
        if info:
            if m_idx in info:
                return ".".join([module_name, info[m_idx]["Name"]])

        return ".".join([module_name] + [str(i) for i in idx])

    def _get_index_from_suffix(self, module_name, suffix):
        info = self.currentDataset["modules"].get(module_name, {}).get(
            "output_info", None)
        idx = next((i for i in info if info[i]["Name"] == suffix), None)
        return idx

    def _get_units(self, entry):
        """
        Return the unit that corresponds to a given entry.

        If no information is available, None is returned.

        Args:
            entry (str): Name of the entry. This can either be "Model.a.b" where
                a and b are numbers or if information is available "Model.Signal"
                where signal is the name of that part.

        Returns:

        """
        args = entry.split(".")
        module_name = args.pop(0)
        info = self.currentDataset["modules"].get(module_name, {}).get(
            "output_info", None)
        if info is None:
            return None

        if len(args) == 1:
            try:
                idx = int(args[0])
            except ValueError:
                idx = next((i for i in info if info[i]["Name"] == args[0]),
                           None)
        else:
            idx = (int(a) for a in args)

        return info[idx]["Unit"]

    def create_plot(self, item):
        """
        Creates a plot widget based on the given item.

        If a plot for this item is already open no new plot is created but the
        existing one is raised up again.

        Args:
            item(Qt.ListItem): Item to plot.
        """
        title = str(item.text())
        if title in self.non_plotting_docks:
            self._logger.error("Title '{}' not allowed for a plot window since"
                               "it would shadow on of the reserved "
                               "names".format(title))

        # check if plot has already been opened
        if title in self.area.findAll()[1]:
            self.area.docks[title].raiseDock()
            return

        # collect data
        data = self._get_data_by_name(title)
        t = self.currentDataset["results"]["time"]
        unit = self._get_units(title)
        if "." in title:
            name = title.split(".")[1]
        else:
            name = title

        # create plot widget
        widget = pg.PlotWidget(title=title)
        widget.showGrid(True, True)
        widget.plot(x=t, y=data)
        widget.getPlotItem().getAxis("bottom").setLabel(text="Time", units="s")
        widget.getPlotItem().getAxis("left").setLabel(text=name, units=unit)

        # add a time line
        time_line = pg.InfiniteLine(self.playbackTime,
                                    angle=90,
                                    movable=False,
                                    pen=pg.mkPen("#FF0000", width=2.0))
        widget.getPlotItem().addItem(time_line)

        # create dock container and add it to dock area
        dock = pg.dockarea.Dock(title, closable=True)
        dock.addWidget(widget)
        self.area.addDock(dock, "above", self.plotDockPlaceholder)

    def _get_data_by_name(self, name):
        tmp = name.split(".")
        module_name = tmp[0]
        if len(tmp) == 1:
            data = np.array(self.currentDataset["results"][module_name])
        elif len(tmp) == 2:
            try:
                idx = int(tmp[1])
            except ValueError:
                idx = self._get_index_from_suffix(module_name, tmp[1])
            finally:
                data = self.currentDataset["results"][module_name][..., idx]
        elif len(tmp) == 3:
            idx = int(tmp[1])
            der = int(tmp[2])
            data = self.currentDataset["results"][module_name][..., idx, der]
        else:
            raise ValueError("Format not supported")

        return data

    def _update_time_cursors(self):
        """
        Update the time lines of all plot windows
        """
        for title, dock in self.area.findAll()[1].items():
            if title in self.non_plotting_docks:
                continue
            for widget in dock.widgets:
                for item in widget.getPlotItem().items:
                    if isinstance(item, pg.InfiniteLine):
                        item.setValue(self.playbackTime)

    def _update_plots(self):
        """
        Update the data in all plot windows
        """
        for title, dock in self.area.findAll()[1].items():
            if title in self.non_plotting_docks:
                continue

            if not self.dataList.findItems(dock.name(), Qt.MatchExactly):
                # no data for this plot -> remove it
                dock.close()
                continue

            for widget in dock.widgets:
                for item in widget.getPlotItem().items:
                    if isinstance(item, pg.PlotDataItem):
                        x_data = self.currentDataset["results"]["time"]
                        y_data = self._get_data_by_name(dock.name())
                        item.setData(x=x_data, y=y_data)

    @pyqtSlot(QModelIndex)
    def target_view_changed(self, index):
        self.targetView.resizeColumnToContents(0)

    def postprocessing_clicked(self):
        """
        starts the post- and metaprocessing application
        """
        self._logger.info("launching postprocessor")
        self.statusBar().showMessage("launching postprocessor", 1000)
        if self.postprocessor is None:
            self.postprocessor = PostProcessor()

        self.postprocessor.show()

    def reset_camera_clicked(self):
        """
        reset camera in vtk window
        """
        self.visualizer.reset_camera()
        self.vtkWidget.GetRenderWindow().Render()

    def show_info(self):
        icon_lic = open(get_resource("license.txt"), "r").read()
        text = "This application was build using PyMoskito ver. {} .<br />" \
               "PyMoskito is free software distributed under GPLv3. <br />" \
               "It is developed by members of the " \
               "<a href=\'https://tu-dresden.de/ing/elektrotechnik/rst'>" \
               "Institute of Control Theory</a>" \
               " at the <a href=\'https://tu-dresden.de'>" \
               "Dresden University of Technology</a>. <br />" \
               "".format(pkg_resources.require("PyMoskito")[0].version) \
               + "<br />" + icon_lic
        box = QMessageBox.about(self, "PyMoskito", text)

    def show_online_docs(self):
        webbrowser.open("https://pymoskito.readthedocs.org")

    def closeEvent(self, QCloseEvent):
        self._logger.info("Close Event received, shutting down.")
        logging.getLogger().removeHandler(self.textLogger)
        super().closeEvent(QCloseEvent)
Пример #22
0
class PostProcessor(QMainWindow):

    sim_results_changed = pyqtSignal()
    post_results_changed = pyqtSignal()

    figures_changed = pyqtSignal(list, str)

    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self._settings = QSettings()
        self._logger = logging.getLogger(self.__class__.__name__)

        self.setWindowTitle("Processing")
        self.setWindowIcon(QIcon(get_resource("processing.png")))
        self.mainFrame = QWidget(self)
        self.resize(1000, 600)

        # toolbar
        self.toolBar = QToolBar("file control")
        self.toolBar.setIconSize(QSize(24, 24))
        self.addToolBar(self.toolBar)

        self.actLoad = QAction(self)
        self.actLoad.setText("load result file")
        self.actLoad.setIcon(QIcon(get_resource("load.png")))
        self.actLoad.setDisabled(False)
        self.actLoad.triggered.connect(self.load_result_files)

        self.actPostLoad = QAction(self)
        self.actPostLoad.setText("load post-result file")
        self.actPostLoad.setIcon(QIcon(get_resource("load.png")))
        self.actPostLoad.setDisabled(False)
        self.actPostLoad.triggered.connect(self.load_post_result_files)

        self.actSwitch = QAction(self)
        self.actSwitch.setText("switch display mode")
        self.actSwitch.setIcon(QIcon(get_resource("left_mode.png")))
        self.actSwitch.setDisabled(False)
        self.actSwitch.triggered.connect(self.switch_sides)
        self.displayLeft = True

        self.spacer1 = QWidget()
        self.spacer2 = QWidget()
        self.spacer1.setSizePolicy(QSizePolicy.Expanding,
                                   QSizePolicy.Expanding)
        self.spacer2.setSizePolicy(QSizePolicy.Expanding,
                                   QSizePolicy.Expanding)

        self.actReloadMethods = QAction(self)
        self.actReloadMethods.setText("reload methods")
        self.actReloadMethods.setIcon(QIcon(get_resource("reload.png")))
        self.actReloadMethods.setDisabled(False)
        self.actReloadMethods.triggered.connect(self.update_post_method_list)

        self.actReloadMetaMethods = QAction(self)
        self.actReloadMetaMethods.setText("reload meta methods")
        self.actReloadMetaMethods.setIcon(QIcon(get_resource("reload.png")))
        self.actReloadMetaMethods.setDisabled(False)
        self.actReloadMetaMethods.triggered.connect(
            self.update_meta_method_list)

        self.toolBar.addAction(self.actLoad)
        self.toolBar.addAction(self.actReloadMethods)

        self.toolBar.addWidget(self.spacer1)
        self.toolBar.addAction(self.actSwitch)
        self.toolBar.addWidget(self.spacer2)

        self.toolBar.addAction(self.actReloadMetaMethods)
        self.toolBar.addAction(self.actPostLoad)

        # main window
        self.grid = QGridLayout(self.mainFrame)
        self.grid.setColumnMinimumWidth(0, 70)
        self.grid.setColumnStretch(0, 0)
        self.grid.setColumnStretch(1, 1)

        self.methodList = QListWidget(self)
        self.methodList.itemDoubleClicked.connect(self.post_processor_clicked)
        self.update_post_method_list()
        self.metaMethodList = QListWidget(self)
        self.metaMethodList.itemDoubleClicked.connect(
            self.meta_processor_clicked)
        self.update_meta_method_list()

        self.sim_result_list = QListWidget(self)
        self.sim_results_changed.connect(self.update_result_list)
        self.results = []

        self.delShort = QShortcut(QKeySequence(Qt.Key_Delete),
                                  self.sim_result_list)
        self.delShort.activated.connect(self.remove_result_item)

        # figures
        self._figure_dict = {}
        self.figures_changed.connect(self.update_figure_lists)

        self.post_figure_list = QListWidget(self)
        self.post_figure_list.currentItemChanged.connect(
            self.current_figure_changed)
        self.meta_figure_list = QListWidget(self)
        self.meta_figure_list.currentItemChanged.connect(
            self.current_figure_changed)

        self.plotView = QWidget()
        self.lastFigure = None

        self.post_result_list = QListWidget(self)
        self.post_results_changed.connect(self.update_post_result_list)
        self.post_results = []
        self.delShortPost = QShortcut(QKeySequence(Qt.Key_Backspace),
                                      self.post_result_list)
        self.delShortPost.activated.connect(self.remove_post_result_item)

        # log dock
        self.logBox = QPlainTextEdit(self)
        self.logBox.setReadOnly(True)

        # init logger for logging box
        self.textLogger = PlainTextLogger(logging.INFO)
        self.textLogger.set_target_cb(self.logBox.appendPlainText)
        logging.getLogger().addHandler(self.textLogger)

        self.grid.addWidget(QLabel("Result Files:"), 0, 0)
        self.grid.addWidget(self.sim_result_list, 1, 0)
        self.grid.addWidget(QLabel("Postprocessors:"), 2, 0)
        self.grid.addWidget(self.methodList, 3, 0)
        self.grid.addWidget(QLabel("Figures:"), 4, 0)
        self.grid.addWidget(self.post_figure_list, 5, 0)
        self.grid.addWidget(QLabel("Selected Figure:"), 0, 1)
        self.grid.addWidget(QLabel("Postprocessor Files:"), 0, 2)
        self.grid.addWidget(self.post_result_list, 1, 2)
        self.grid.addWidget(QLabel("Metaprocessors:"), 2, 2)
        self.grid.addWidget(self.metaMethodList, 3, 2)
        self.grid.addWidget(QLabel("Figures:"), 4, 2)
        self.grid.addWidget(self.meta_figure_list, 5, 2)
        self.grid.addWidget(self.logBox, 6, 0, 1, 3)

        self.mainFrame.setLayout(self.grid)
        self.setCentralWidget(self.mainFrame)

        # status bar
        self.statusBar = QStatusBar(self)
        self.setStatusBar(self.statusBar)

    def load_result_files(self):
        path = self._settings.value("path/simulation_results")

        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.ExistingFiles)
        dialog.setDirectory(path)
        dialog.setNameFilter("PyMoskito Result files (*.pmr)")

        if dialog.exec_():
            files = dialog.selectedFiles()
            for single_file in files:
                if single_file:
                    self._load_result_file(single_file)

    def _load_result_file(self, file_name):
        """
        loads a result file
        """
        self._logger.info("loading result file {}".format(file_name))
        with open(file_name.encode(), "rb") as f:
            self.results.append(pickle.load(f))

        self.sim_results_changed.emit()

    def update_result_list(self):
        self.sim_result_list.clear()
        for res in self.results:
            name = res["regime name"]
            self.sim_result_list.addItem(name)

    def remove_result_item(self):
        if self.sim_result_list.currentRow() >= 0:
            del self.results[self.sim_result_list.currentRow()]
            self.sim_result_list.takeItem(self.sim_result_list.currentRow())

    def load_post_result_files(self):
        path = self._settings.value("path/processing_results")

        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.ExistingFiles)
        dialog.setDirectory(path)
        dialog.setNameFilter("Postprocessing Output files (*.pof)")

        if dialog.exec_():
            files = dialog.selectedFiles()
            for single_file in files:
                if single_file:
                    self._load_post_result_file(single_file)

    def _load_post_result_file(self, file_name):
        """
        loads a post-result file (.pof)
        """
        name = os.path.split(file_name)[-1][:-4]
        self._logger.info("loading result file {}".format(file_name))
        with open(file_name.encode(), "rb") as f:
            results = pickle.load(f)
            results.update({"name": name})
            self.post_results.append(results)

        self.post_results_changed.emit()

    def update_post_result_list(self):
        self.post_result_list.clear()
        for res in self.post_results:
            name = res["name"]
            self.post_result_list.addItem(name)

    def remove_post_result_item(self):
        if self.post_result_list.currentRow() >= 0:
            del self.post_results[self.post_result_list.currentRow()]
            self.post_result_list.takeItem(self.post_result_list.currentRow())

    def update_post_method_list(self):
        self.methodList.clear()
        modules = pm.get_registered_processing_modules(PostProcessingModule)
        for mod in modules:
            self.methodList.addItem(mod[1])

    def update_meta_method_list(self):
        self.metaMethodList.clear()
        modules = pm.get_registered_processing_modules(MetaProcessingModule)
        for mod in modules:
            self.metaMethodList.addItem(mod[1])

    def post_processor_clicked(self, item):
        self.run_processor(str(item.text()), "post")

    def meta_processor_clicked(self, item):
        self.run_processor(str(item.text()), "meta")

    def run_processor(self, name, processor_type):
        if processor_type == "post":
            result_files = self.results
            base_cls = PostProcessingModule
        elif processor_type == "meta":
            result_files = self.post_results
            base_cls = MetaProcessingModule
        else:
            self._logger.error(
                "unknown processor type {0}".format(processor_type))
            raise ValueError(
                "unknown processor type {0}".format(processor_type))

        if not result_files:
            self._logger.warning(
                "run_processor() Error: no result file loaded")
            return

        processor_cls = pm.get_processing_module_class_by_name(base_cls, name)
        processor = processor_cls()

        figs = []
        try:
            self._logger.info("executing processor '{0}'".format(name))
            figs = processor.process(result_files)
        except Exception as err:
            self._logger.exception("Error in processor")

        self.figures_changed.emit(figs, processor_type)
        self._logger.info("finished postprocessing")

    def update_figure_lists(self, figures, target_type):
        # remove no longer needed elements
        for item, fig in [(key, val[0])
                          for key, val in self._figure_dict.items()
                          if val[1] == target_type]:
            if fig not in [new_fig["figure"] for new_fig in figures]:
                if target_type == "post":
                    old_item = self.post_figure_list.takeItem(
                        self.post_figure_list.row(item))
                    del old_item
                elif target_type == "meta":
                    old_item = self.meta_figure_list.takeItem(
                        self.meta_figure_list.row(item))
                    del old_item

                del self._figure_dict[item]

        # add new ones to internal storage
        for fig in figures:
            if fig["figure"] not in self._figure_dict.values():
                new_entry = [(fig["name"], (QListWidgetItem(fig["name"]),
                                            fig["figure"], target_type))]
                self._figure_dict.update(new_entry)

        # add to display
        for key, val in self._figure_dict.items():
            if val[2] == "post":
                self.post_figure_list.addItem(val[0])
            elif val[2] == "meta":
                self.meta_figure_list.addItem(val[0])

        self.post_figure_list.setCurrentItem(self.post_figure_list.item(0))
        self.meta_figure_list.setCurrentItem(self.meta_figure_list.item(0))

    def current_figure_changed(self, current_item, last_item=None):
        if current_item is None:
            return

        figures = self._figure_dict

        if self.lastFigure:
            self.grid.removeWidget(self.lastFigure)
            self.lastFigure.setVisible(False)

        if current_item.text() in figures:
            figure_widget = figures[current_item.text()][1]
            self.grid.addWidget(figure_widget, 1, 1, 5, 1)
            figure_widget.setVisible(True)
            self.lastFigure = figure_widget

    def switch_sides(self):
        self.displayLeft = not self.displayLeft
        if self.displayLeft:
            self.actSwitch.setIcon(QIcon(get_resource("left_mode.png")))
            self.post_figure_list.setFocus()
            self.current_figure_changed(self.post_figure_list.currentItem())
        else:
            self.actSwitch.setIcon(QIcon(get_resource("right_mode.png")))
            self.meta_figure_list.setFocus()
            self.current_figure_changed(self.meta_figure_list.currentItem())
Пример #23
0
class PageWidget(QWidget):

    ITEMCLICKED = pyqtSignal(CustomPageItem)

    RES_PATH = "uilib/img"    # 图片资源的路径

    STYLE = """
QPushButton#_previous_btn,QPushButton#_next_btn {{
    max-width: 49px;
    max-height: 39px;
    min-width: 49px;
    min-height: 39px;
    width: 49px;
    height: 39px;
    border-color: #E4E7EA;
    
}}
QPushButton#_previous_btn:hover,QPushButton#_next_btn:hover {{
    border-color: #1ABC9C;
    background-color: #1ABC9C;
    
}}
QPushButton#_previous_btn:pressed,QPushButton#_next_btn:pressed {{
    border-color: #1ABC9C;
    background-color: #1ABC9C;
    
}}
QPushButton#_previous_btn {{
    padding-right: 1px;
    border-top-left-radius: 6px;
    border-top-right-radius: 0px;
    border-bottom-left-radius: 6px;
    border-bottom-right-radius: 0px;
    background: #E4E7EA url({RES_PATH}/arrow_left_white.png) no-repeat center center;
}}
QPushButton#_next_btn {{
    padding-left: 1px;
    border-top-left-radius: 0px;
    border-top-right-radius: 6px;
    border-bottom-left-radius: 0px;
    border-bottom-right-radius: 6px;
    background: #E4E7EA url({RES_PATH}/arrow_right_white.png) no-repeat center center;
}}

QListView#_page_list_widget {{
    max-height: 40px;
    background-color: rgba(0,0,0,0);
}}
QListView#_page_list_widget::item {{
    margin: 1px;
    color: white;
    background-color: #E4E7EA;
    height: 40px;
}}

QListView#_page_list_widget::item:selected {{
    background-color: #1ABC9C;
}}
QListView#_page_list_widget::item:focus {{
    background-color: #1ABC9C;
}}

QListView#_page_list_widget::item:hover {{
    background-color: #1ABC9C;
}}"""

    def __init__(self, parent = None, pages = 0):
        super(PageWidget, self).__init__(parent)
        self.setObjectName("_page_widget")
        self.pages = pages    # 页数
        self.cpage = 0

        # 左边按钮
        self._previous_btn = BothSidesItem(self, which = "left")
        self._previous_btn.clicked.connect(self._previous)
        self._previous_btn.setToolTip("上一页")
        # 右边按钮
        self._next_btn = BothSidesItem(self, which = "right")
        self._next_btn.clicked.connect(self._next)
        self._next_btn.setToolTip("下一页")

        self._page_list_widget = QListWidget(self)
        self._page_list_widget.setObjectName("_page_list_widget")
        # 无边框
        self._page_list_widget.setFrameShape(QFrame.NoFrame)
        # 无滑动条
        self._page_list_widget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self._page_list_widget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        # 禁止自动滚动
        self._page_list_widget.setAutoScroll(False)
        # tab切换
        self._page_list_widget.setTabKeyNavigation(True)
        # 设置为横向
        self._page_list_widget.setFlow(QListView.LeftToRight)
        # 设置字体
        font = QFont()
        font.setPointSize(14)
        self._page_list_widget.setFont(font)
        # item点击事件
        self._page_list_widget.itemClicked.connect(self.ITEMCLICKED.emit)

        # 布局
        hLayout = QHBoxLayout(self)
        hLayout.setSpacing(0)
        hLayout.setContentsMargins(0, 0, 0, 0)
        spacerItem = QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Minimum)
        hLayout.addItem(spacerItem)
        hLayout.addWidget(self._previous_btn)
        hLayout.addWidget(self._page_list_widget)
        hLayout.addWidget(self._next_btn)
        hLayout.addItem(spacerItem)

        self._refresh(pages)

        self.updateStyle()    # 设置样式

    def _refresh(self, pages):
        # 动态调整宽度
        if pages == 0:
            self.resize(100, 40)
        elif pages >= 8:
            self._page_list_widget.setMinimumSize(320, 40)
            self._page_list_widget.resize(320, 40)
            self.resize(420, 40)
        self._page_list_widget.clear()
        # 中间
        for i in range(1, pages + 1):
            CustomPageItem(i, self._page_list_widget)

    def _previous(self, clicked):
        '''上一页'''
        num = int(self.pages / 8)
        if num == 0:
            return
        self.cpage -= 1
        if self.cpage >= 0:
            print("_previous: ", self.cpage)
            if self.cpage == 0:
                previousItem = self._page_list_widget.item(0)
            else:
                previousItem = self._page_list_widget.item(self.cpage * 8 - 4)
            self._page_list_widget.scrollTo(self._page_list_widget.indexFromItem(previousItem))
        else:
            self.cpage += 1

    def _next(self, clicked):
        '''下一页'''
        num = int(self.pages / 8)
        if num == 0:
            return
        self.cpage += 1
        if self.cpage <= num:
            print("_next: ", self.cpage)
            remainder = self.pages - self.cpage * 8
            if remainder > 8:
                nextItem = self._page_list_widget.item(self.cpage * 8 + 7)
            else:
                nextItem = self._page_list_widget.item(self.pages - 1)
            self._page_list_widget.scrollTo(self._page_list_widget.indexFromItem(nextItem))
        else:
            self.cpage -= 1

    def setResPath(self, resPath):
        '''设置资源路径'''
        self.RES_PATH = resPath

    def getResPath(self):
        return self.RES_PATH

    def updateStyle(self):
        '''刷新样式'''
        self.setStyleSheet(self.STYLE.format(RES_PATH = self.RES_PATH))

    def setPages(self, pages):
        '''设置页数'''
        self.pages = pages
        self._refresh(pages)

    def getPages(self):
        '''得到当前总的页数'''
        return self.pages
Пример #24
0
class MainWindow(QMainWindow):
    def __init__(self, *args):
        QMainWindow.__init__(self)
        self.current_image = None
        self.createComponents()
        self.loadFromBufferMemory()
        #print("Input file type", type(input_file))
        self.createMenu()
        self.createLayout()
        self.createConnects()
        self.setWindowTitle('Micrograph Selection Tool')

    def createComponents(self):
        self.buttonLoad = QPushButton('Load')
        self.buttonSave = QPushButton('Save')
        self.buttonKeep = QPushButton('Keep (Right arrow key)')
        self.buttonKeep.setStyleSheet('QPushButton {color: green;}')
        self.buttonDiscard = QPushButton('Discard (Left arrow key)')
        self.buttonDiscard.setStyleSheet('QPushButton {color: red;}')
        self.fileList = QListWidget()
        self.micrograph = emimage2d.EMImage2DWidget(image=EMAN2.EMData(
            700, 700),
                                                    application=app,
                                                    parent=self)
        self.powerSpectrum = emimage2d.EMImage2DWidget(image=EMAN2.EMData(
            700, 700),
                                                       application=app,
                                                       parent=self)
        self.all_items = []

    def loadFromBufferMemory(self):
        """loads the content from the buffer database"""
        image_list = []
        buffer_lines = []
        self.buffer_path = "/home/turi/Schreibtisch/buffermemory.txt"

        with open(self.buffer_path) as buffer:
            buffer = buffer.read()
            if len(buffer) > 0:
                buffer_lines = buffer.split(',')
                print("buffer", buffer_lines)
            else:
                print("Buffer is empty")

        for image_index in range(len(buffer_lines)):
            # cleans the image name and status to add them in the GUI
            image_path = str(buffer_lines[image_index].split(':')[0])
            print("imagepath", image_path)
            image_status = str(buffer_lines[image_index].split(':')[1])
            print("imagestatus", image_status)

            # remove symbols from the image_name string
            if "(u'" in image_path:
                image_path = image_path.replace("(u'", "")
            if "',)" in image_path:
                image_path = image_path.replace("',)", "")
            if "\n" in image_path:
                image_path = image_path.replace("\n", "")
            if "'" in image_path:
                image_path = image_path.replace("'", "")
            if "\"" in image_path:
                image_path = image_path.replace("\"", "")
            if "[" in image_path:
                image_path = image_path.replace("[", "")
            if "]" in image_path:
                image_path = image_path.replace("]", "")
            if "\\" in image_path:
                image_path = image_path.replace("\\", "")

            image_name = QFileInfo(image_path).fileName()
            image_list.append(image_path)  # adds the name
            item = QListWidgetItem(image_name)

            # remove symbols from the status string
            if "(u'" in image_status:
                image_status = image_status.replace("(u'", "")
            if "',)" in image_status:
                image_status = image_status.replace("',)", "")
            if "\n" in image_status:
                image_status = image_status.replace("\n", "")
            if "'" in image_status:
                image_status = image_status.replace("'", "")
            if "[" in image_status:
                image_status = image_status.replace("[", "")
            if "]" in image_status:
                image_status = image_status.replace("]", "")

            if image_status == "checked":
                item.setCheckState(Qt.Checked)
            if image_status == "unchecked":
                item.setCheckState(Qt.Unchecked)

            self.fileList.addItem(item)

        if len(image_list) > 0:
            self.uploadMicrographs(image_list=image_list,
                                   upload_from_buffer=True)
        else:
            pass

    def createLayout(self):
        """layout: left, middle, right layouts, all three are vertically structured"""
        layoutMain = QHBoxLayout()

        layoutLeft = QVBoxLayout()
        layoutLeft.addWidget(self.buttonLoad)
        layoutLeft.addWidget(self.fileList)
        layoutLeft.addWidget(self.buttonSave)

        layoutMiddle = QVBoxLayout()
        layoutMiddle.addWidget(self.micrograph)
        layoutMiddle.addWidget(self.buttonKeep)

        layoutRight = QVBoxLayout()
        layoutRight.addWidget(self.powerSpectrum)
        layoutRight.addWidget(self.buttonDiscard)

        layoutMain.addLayout(layoutLeft, stretch=1)
        layoutMain.addLayout(layoutMiddle, stretch=2)
        layoutMain.addLayout(layoutRight, stretch=2)

        widgetMain = QWidget()
        widgetMain.setLayout(layoutMain)
        self.setCentralWidget(widgetMain)

    def createMenu(self):
        self.actionOpenData = QAction(("Open file.."), self)
        self.actionSaveData = QAction(("Save"), self)
        self.actionSelectAll = QAction(("Select all"), self)
        self.actionDeselectAll = QAction(("Deselect all"), self)
        self.actionSetCheck_fromKeepFile = QAction("Upload Keep/Discard Files",
                                                   self)
        self.actionQuit = QAction(("Quit"), self)
        self.actionQuit.setMenuRole(QAction.QuitRole)

        menu_file = self.menuBar().addMenu("File")
        menu_file.addAction(self.actionOpenData)
        menu_file.addAction(self.actionSaveData)
        menu_file.addAction(self.actionSelectAll)
        menu_file.addAction(self.actionDeselectAll)
        menu_file.addAction(self.actionSetCheck_fromKeepFile)
        menu_file.addSeparator()
        menu_file.addAction(self.actionQuit)

        self.menuBar().addMenu("Help")

    def createConnects(self):
        self.buttonLoad.clicked.connect(
            self.buttonLoad_clicked)  # function call without ()-sign
        self.buttonSave.clicked.connect(self.buttonSave_clicked)
        self.buttonKeep.clicked.connect(self.buttonKeep_clicked)
        self.buttonDiscard.clicked.connect(self.buttonDiscard_clicked)
        self.fileList.clicked.connect(self.changeImageByMouse)
        self.fileList.keyPressEvent = self.myKeyPressEvent
        self.micrograph.keyPressEvent = self.myKeyPressEvent
        self.powerSpectrum.keyPressEvent = self.myKeyPressEvent
        self.actionSelectAll.triggered.connect(self.selectAll)
        self.actionDeselectAll.triggered.connect(self.deselectAll)
        self.actionSetCheck_fromKeepFile.triggered.connect(
            self.setCheck_fromKeepFile)

    def myKeyPressEvent(self, buttonSignal):
        if self.fileList.count() > 0:
            if buttonSignal.key() == Qt.Key_Right:
                print
                "Right"
                self.arrowKeyRight_clicked()
            elif buttonSignal.key() == Qt.Key_Left:
                print
                "Left"
                self.arrowKeyLeft_clicked()
            elif buttonSignal.key() == Qt.Key_Up:
                print
                "Up"
                self.arrowKeyUp_clicked()
            elif buttonSignal.key() == Qt.Key_Down:
                print
                "Down!"
                self.arrowKeyDown_clicked()

    def loadMicrographsFromItemList(self, image_index):
        """creates an EMImage-Widget"""
        if self.current_image is None:
            image_path = self.all_items[image_index]  #
            self.current_image = EMAN2.EMData(image_path)
        self.micrograph.set_data(
            self.current_image
        )  # in project description as 'aaa' instead of 'micrograph'

    def loadPowerSpectrumFromItemList(self, image_index):
        """creates power spectrum of a micrograph"""
        # Try to load image from buffer
        # If buffer is empty, wait the image appears
        while True:
            load_successfull = False
            try:
                preload_image_path, preload_image_index, img, fft_img = img_buffer.popleft(
                )
                if preload_image_index == image_index:
                    load_successfull = True
            except IndexError as e:
                print("Index error", e)
                time.sleep(1)

            if load_successfull:
                break

        self.current_image = img
        self.powerSpectrum.set_data(fft_img)

    def preload_images(self, micrograph_list, img_buffer):
        """
        Preloads IMG_BUFFER_SIZE number of images into the memory.

        :param micrograph_list: list of all micrographs ######## mistake --> here it gets just a string not a list
        :param img_buffer: deque as buffer for images
        :return: None
        """
        print("preload_images micrograph_list", micrograph_list)
        offset = 0
        last_index = -1
        while True:
            index = self.fileList.row(self.fileList.currentItem())
            if last_index != -1:
                if index - last_index == 1:
                    offset = offset - 1
                elif index - last_index != 0:
                    offset = 0

            if len(img_buffer) < IMG_BUFFER_SIZE and (
                    index + offset) < len(micrograph_list):
                start = time.time()
                print("in", index + offset)
                print("micrograph_list", micrograph_list)
                filename = str(micrograph_list[index + offset])

                print("filename", filename)
                image = EMAN2.EMData(filename)

                fft_img = image.do_fft()

                fft_img.set_value_at(0, 0, 0, 0)
                fft_img.set_value_at(1, 0, 0, 0)
                fft_img.process_inplace("xform.phaseorigin.tocorner")
                fft_img.process_inplace("xform.fourierorigin.tocenter")
                fft_img = fft_img.get_fft_amplitude()

                img_buffer.append((filename, index + offset, image, fft_img))
                end = time.time()
                print("Put new image:", filename, "Current index", index,
                      "Image+offset:", index + offset, "offset", offset,
                      "time", end - start)
                offset = offset + 1
            else:
                time.sleep(1)

            last_index = index

    def buttonLoad_clicked(self):
        """"opens dialog for folder selection, """

        image_dir = QFileDialog.getExistingDirectory(parent=None,
                                                     caption=u"Open directory")
        image_dir = str(image_dir)

        image_list = []
        for root, dirs, files in os.walk(image_dir):
            for file in files:
                if (".mrc" or ".tiff" or ".tif" or ".hdf" or ".png") in file:
                    image_list.append(image_dir + "/" + file)
        #if no micrograph loaded
        if len(image_list) == 0:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Information)
            msg.setInformativeText("No images in the selected folder")
            msg.setStandardButtons(QMessageBox.Ok)
            msg.exec_()

        if len(image_list) > 0:
            self.uploadMicrographs(image_list=image_list,
                                   upload_from_buffer=False)
        else:
            pass

    def buttonSave_clicked(self):
        """the keep and discard image names are added to two independent text files one for keep one for discard"""

        save_dir = QFileDialog.getExistingDirectory(
            parent=None,
            caption="Directory of selected and discarded file with image names"
        )
        path_selected = str(save_dir) + "/" + "selected_images.txt"
        path_discarded = str(save_dir) + "/" + "discarded_images.txt"

        try:
            file_selected = open(path_selected, "w+")
            file_discarded = open(path_discarded, "w+")
        except IOError:
            return

        number_of_items = self.fileList.count()
        for index in range(number_of_items):  # as often as number of files
            if (self.fileList.item(index).checkState()) == Qt.Checked:
                file_selected.write(
                    os.path.basename(self.all_items[index]) + "\n")
            else:
                file_discarded.write(
                    os.path.basename(self.all_items[index]) + "\n")
        file_selected.close()
        file_discarded.close()

    def uploadMicrographs(self, image_list, upload_from_buffer):
        """loads the micrograph into the GUI and saves their path and status in buffer memory"""
        #global all_items  # maybe problematic?
        #all_items = []
        self.all_items = []
        image_path_and_status = []

        if upload_from_buffer == True:
            for image_path in image_list:
                # loads the micrograph names and status into the GUI
                self.all_items.append(image_path)

        if upload_from_buffer == False:
            self.fileList.clear()
            # add a try except tree
            for image_path in image_list:
                print
                "Path", image_path
                image_name = QFileInfo(image_path).fileName()
                item = QListWidgetItem(image_name)
                image_path = str(
                    image_path)  # contains the path and the name of the image
                self.all_items.append(image_path)

                image_path_and_status.append(image_path + ":" + "checked")

                item.setCheckState(Qt.Checked)
                self.fileList.addItem(item)

            # remove symbols from the list
            image_path_and_status = str(image_path_and_status)
            if "'" in image_path_and_status:
                image_path_and_status = image_path_and_status.replace("'", "")
            if "[" in image_path_and_status:
                image_path_and_status = image_path_and_status.replace("[", "")
            if "]" in image_path_and_status:
                image_path_and_status = image_path_and_status.replace("]", "")
            if " " in image_path_and_status:
                image_path_and_status = image_path_and_status.replace(" ", "")

            with open(self.buffer_path, "w") as buffer:
                buffer.write(image_path_and_status)

        if len(image_list) > 0:
            # loads the micrographs into the GUI
            self.fileList.setCurrentRow(0)
            thread.start_new_thread(self.preload_images, (
                image_list,
                img_buffer,
            ))
            self.loadPowerSpectrumFromItemList(0)
            self.loadMicrographsFromItemList(0)
            last_loaded_image = 0

    def writeToBuffer_check(self):
        """the status of the image is written to the buffer"""
        row_index = self.fileList.row(self.fileList.currentItem())

        with open(self.buffer_path, "r") as buffer:
            buffer_lines = buffer.read().split(",")
            buffer_line = buffer_lines[row_index].split(":")
            print(buffer_line)
            image_path = buffer_line[0]
            image_status = buffer_line[1]
            # order of checking importance: checked is included in unchecked !!!
            if "unchecked" in image_status:
                image_status = image_status.replace("unchecked", "checked")
            elif "checked" in image_status:
                pass
            buffer_lines[row_index] = str(image_path + ":" + image_status)

        buffer_lines = str(buffer_lines)
        if "'" in buffer_lines:
            buffer_lines = buffer_lines.replace("'", "")
        if "\"" in buffer_lines:
            buffer_lines = buffer_lines.replace("\"", "")
        if "[" in buffer_lines:
            buffer_lines = buffer_lines.replace("[", "")
        if "]" in buffer_lines:
            buffer_lines = buffer_lines.replace("]", "")
        if " " in buffer_lines:
            buffer_lines = buffer_lines.replace(" ", "")
        if "\\" in buffer_lines:
            buffer_lines = buffer_lines.replace("\\", "")

        print("Bufferline", str(buffer_lines))
        with open(self.buffer_path, "w") as buffer:
            buffer.write(str(buffer_lines))

    def writeToBuffer_uncheck(self):
        """the status of the image is written to the buffer"""
        row_index = self.fileList.row(self.fileList.currentItem())

        with open(self.buffer_path, "r") as buffer:
            buffer_lines = buffer.read().split(",")
            buffer_line = buffer_lines[row_index].split(":")
            image_path = buffer_line[0]
            image_status = buffer_line[1]
            # order of checking importance: checked is included in unchecked !!!
            if "unchecked" in image_status:
                pass
            elif "checked" in image_status:
                image_status = image_status.replace("checked", "unchecked")
            buffer_lines[row_index] = str(image_path + ":" + image_status)
            print("Puffer", buffer_lines)

        buffer_lines = str(buffer_lines)
        if "'" in buffer_lines:
            buffer_lines = buffer_lines.replace("'", "")
        if "\"" in buffer_lines:
            buffer_lines = buffer_lines.replace("\"", "")
        if "[" in buffer_lines:
            buffer_lines = buffer_lines.replace("[", "")
        if "]" in buffer_lines:
            buffer_lines = buffer_lines.replace("]", "")
        if " " in buffer_lines:
            buffer_lines = buffer_lines.replace(" ", "")
        if "\\" in buffer_lines:
            buffer_lines = buffer_lines.replace("\\", "")

        print("Bufferline", str(buffer_lines))
        with open(self.buffer_path, "w") as buffer:
            buffer.write(str(buffer_lines))

    def setCheck_fromKeepFile(self):
        """images are automatically selected or discarded according to saved keep files"""
        file_dirs = QFileDialog.getExistingDirectory(parent=None,
                                                     caption=u"Open files")

        file_list = []
        files_selected = []
        for root, dirs, files in os.walk(file_dirs):
            for file in files:
                if ("selected_images.txt") in file:
                    file_list.append(file_dirs + "/" + file)
                    files_selected.append(file_dirs + "/" + file)
                if ("discarded_images.txt") in file:
                    file_list.append(file_dirs + "/" + file)

        # if no micrograph loaded
        if len(file_list) == 0:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Information)
            msg.setInformativeText("No textfile in the selected folder")
            msg.setStandardButtons(QMessageBox.Ok)
            msg.exec_()

        else:
            for index in range(len(files_selected)):

                with open(files_selected[index], "r") as file:
                    selected_images = file.readlines()

                if len(selected_images) > 0:

                    if self.fileList.currentItem() is not None:
                        self.fileList.setCurrentRow(0)

                        for uploaded_image in self.all_items:
                            # image contains name and path
                            # all_items has the same order like self.fileList
                            uploaded_image = str(uploaded_image)
                            uploaded_image = uploaded_image.split("/")[
                                -1]  # removes the path, extracts the name

                            for index in range(len(selected_images)):
                                if "\n" in selected_images[index]:
                                    selected_images[index] = selected_images[
                                        index].replace("\n", "")

                            if uploaded_image in selected_images:
                                self.setCheck()
                                self.moveToNextItem()
                            else:
                                self.setUncheck()
                                self.moveToNextItem()

                    else:
                        pass

    def buttonKeep_clicked(self):
        if self.fileList.currentItem() is not None:
            self.setCheck()
            self.moveToNextItem()
            self.showImageOfCurrentRow()

    def buttonDiscard_clicked(self):
        if self.fileList.currentItem() is not None:
            self.setUncheck()
            self.moveToNextItem()
            self.showImageOfCurrentRow()

    def arrowKeyRight_clicked(self):
        self.setCheck()
        self.moveToNextItem()
        self.showImageOfCurrentRow()

    def arrowKeyLeft_clicked(self):
        self.setUncheck()
        self.moveToNextItem()
        self.showImageOfCurrentRow()

    def arrowKeyUp_clicked(self):
        self.moveToPrevItem()
        self.showImageOfCurrentRow()

    def arrowKeyDown_clicked(self):
        self.moveToNextItem()
        self.showImageOfCurrentRow()

    def setCheck(self):
        self.fileList.currentItem().setCheckState(Qt.Checked)
        self.writeToBuffer_check()

    def setUncheck(self):
        self.fileList.currentItem().setCheckState(Qt.Unchecked)
        self.writeToBuffer_uncheck()

    def selectAll(self):
        """all images get the checked status"""
        print("bbb")
        self.fileList.setCurrentRow(0)
        self.loadPowerSpectrumFromItemList(0)
        self.loadMicrographsFromItemList(0)
        print(len(self.all_items))

        for row_index in range(len(self.all_items)):
            print("bbbbb")
            self.setCheck()
            self.moveToNextItem()

    def deselectAll(self):
        """all images get the unchecked status"""
        print("ccc")
        self.fileList.setCurrentRow(0)
        self.loadPowerSpectrumFromItemList(0)
        self.loadMicrographsFromItemList(0)
        print(len(self.all_items))

        for row_index in range(len(self.all_items)):
            print("ccccc")
            self.setUncheck()
            self.moveToNextItem()

    def moveToNextItem(self):
        row_index = self.fileList.row(self.fileList.currentItem())
        self.fileList.setCurrentRow(row_index + 1)
        if row_index >= (self.fileList.count()) - 1:
            self.fileList.setCurrentRow(0)

    def moveToPrevItem(self):
        row_index = self.fileList.row(self.fileList.currentItem())
        self.fileList.setCurrentRow(row_index - 1)
        if row_index >= (self.fileList.count()) - 1:
            self.fileList.setCurrentRow(0)

    def changeImageByMouse(self):
        self.showImageOfCurrentRow()

    def showImageOfCurrentRow(self):
        """the image of current row is shown"""
        global last_loaded_image  # maybe problematic?
        row_index = self.fileList.row(self.fileList.currentItem())
        if last_loaded_image - row_index != 0:
            self.loadPowerSpectrumFromItemList(row_index)
            self.loadMicrographsFromItemList(row_index)
            last_loaded_image = row_index
Пример #25
0
class DebuggerMainWindow(object):
    def __init__(self, comm):
        self.comm = comm
        self.follow_state = True
        self.init_instances()
        self.init_widgets()
        self.init_actions()
        self.window.closeEvent = self.close_handler
        self.window.showMaximized()

    def run(self):
        self.poll_timer = QTimer()
        self.poll_timer.timeout.connect(self.poll_handler)
        self.comm.start_worker()
        self.poll_timer.start(1000)

    def poll_handler(self):
        self.comm.put_job(self.comm.get_agent_track)
        data = self.comm.take_data()
        for location_info, state in data:
            file_name, node_id = location_info
            i = self.get_instance(file_name)

            if i is None:
                text = "%s:%s" % (str(location_info), state)
            else:
                node = i.model.get_node(node_id)
                if node is not None:
                    text = "%s: %s: %s" % (file_name, node.get_display_text(), state)
                else:
                    text = "%s:%s" % (str(location_info), state)
            self.add_to_history_list(location_info, text)
        if self.follow_state:
            self.focus_last()

    def init_widgets(self):
        self.window = loadUi(MAIN_UI_PATH)
        self.mdi = self.window.mdiArea
        self.mdi.setViewMode(QMdiArea.TabbedView)
        self.mdi.setTabsMovable(True)
        self.mdi.setTabsClosable(True)
        self.mdi.setTabShape(QTabWidget.Rounded)
        self.dock_anchor = self.window.dockAnchor
        self.dock_anchor.layout().setAlignment(Qt.AlignTop)

        self.history_list = QListWidget()
        self.history_list.itemSelectionChanged.connect(self.list_item_selected)
        self.add_dock_content(self.history_list)

    def list_item_selected(self):
        citem = self.history_list.currentItem()
        self.focus_on_location(citem.location_info)

    def init_instances(self):
        self.instances = {}

    def remove_instance(self, ins):
        file_name = ins.file_name
        self.instances.pop(file_name)

    def add_instance(self, ins):
        file_name = ins.file_name
        self.instances[file_name] = ins

    def get_instance(self, file_name):
        if file_name in self.instances:
            return self.instances[file_name]
        else:
            full_path = GraphInstanceVM.get_full_path(file_name)
            model = GraphInstanceVM.get_model(full_path)
            if model is None:
                return None
            ins = GraphInstanceVM(model, self, file_name)
            return ins

    def init_actions(self):
        self.window.actionResume.triggered.connect(self.action_resume_handler)
        self.window.actionStop.triggered.connect(self.action_stop_handler)
        self.window.actionFollow.triggered.connect(self.action_follow_handler)
        self.window.actionHold.triggered.connect(self.action_hold_handler)

    def action_resume_handler(self):
        self.clear_list()
        self.comm.put_job(functools.partial(self.comm.track_agent, True))

    def action_stop_handler(self):
        self.comm.put_job(functools.partial(self.comm.track_agent, False))

    def action_follow_handler(self):
        self.follow_state = True

    def action_hold_handler(self):
        self.follow_state = False

    def close_handler(self, ev):
        # disable tracking for some agents
        self.poll_timer.stop()
        self.comm.put_job(self.comm.finish)
        self.comm.shutdown()

    def add_dock_content(self, widget):
        self.clear_dock_contents()
        self.dock_anchor.layout().addWidget(widget)

    def get_dock_contents(self):
        l = self.dock_anchor.layout()
        ret = []
        for i in range(l.count()):
            ret.append(l.itemAt(i).widget())
        return ret

    def clear_dock_contents(self):
        ws = self.get_dock_contents()
        for w in ws:
            w.deleteLater()

    def focus_on_location(self, location):
        file_name, node_id = location
        instance = self.get_instance(file_name)
        if instance is None:
            logger.fatal("can not find src file for %s" % file_name)
            return False
        ret = instance.focus_on(node_id)
        if ret is False:
            logger.fatal("can not find node %s for %s" % (node_id, file_name))
            return False
        return True

    def add_to_history_list(self, location, text):
        item = HistoryListItem(location, text)
        self.history_list.addItem(item)

    def clear_list(self):
        self.history_list.clear()

    def focus_last(self):
        c = self.history_list.count()
        if c > 0:
            item = self.history_list.item(c-1)
            self.history_list.setCurrentItem(item)
            self.focus_on_location(item.location_info)
Пример #26
0
class SubSheet(SimpleBlackbox):
    author = "DrLuke"
    name = "Subsheet"
    modulename = "subsheet"

    Category = ["Builtin"]

    placeable = True

    implementation = SubSheetImplementation

    def __init__(self, *args, **kwargs):
        self.ownsheet = None
        self.sheets = None
        self.selectedSheet = None
        self.listSheetItems = {}

        super(SubSheet, self).__init__(*args, **kwargs)

        self.propertiesWidget = QWidget()

        self.vlayout = QVBoxLayout()

        self.listWidget = QListWidget()
        self.listWidget.itemClicked.connect(self.listClicked)
        self.vlayout.addWidget(self.listWidget)

        self.vlayout.addItem(
            QSpacerItem(40, 20, QSizePolicy.Minimum, QSizePolicy.Expanding))

        self.propertiesWidget.setLayout(self.vlayout)

    def getPropertiesWidget(self):
        return self.propertiesWidget

    def updateSheets(self):
        if self.sheets is not None and self.ownsheet is not None:
            self.listSheetItems = {}
            self.listWidget.clear()
            for sheetId in self.sheets:
                if not sheetId == self.ownsheet:
                    newItem = QListWidgetItem(self.sheets[sheetId])
                    newItem.setToolTip(str(sheetId))
                    newItem.setData(Qt.UserRole, sheetId)
                    self.listSheetItems[sheetId] = newItem
                    self.listWidget.addItem(newItem)

                    if sheetId == self.selectedSheet:
                        boldFont = QFont()
                        boldFont.setBold(True)
                        newItem.setFont(boldFont)

    def listClicked(self, item):
        normalFont = QFont()
        boldFont = QFont()
        boldFont.setBold(True)

        for i in range(self.listWidget.count()):
            itemnormal = self.listWidget.item(i)
            itemnormal.setFont(normalFont)

        self.selectedSheet = item.data(Qt.UserRole)
        self.sendDataToImplementations({"subsheetid": self.selectedSheet})
        item.setFont(boldFont)

    def serialize(self):
        return {"subsheetid": self.selectedSheet}

    def deserialize(self, data):
        if data is not None:
            if "subsheetid" in data:
                self.selectedSheet = data["subsheetid"]
                self.sendDataToImplementations(
                    {"subsheetid": self.selectedSheet})

    def selectedChanged(self, state):
        if state:
            self.mainRect.setPen(QPen(Qt.red))
        else:
            self.mainRect.setPen(QPen(Qt.blue))

    def defineIO(self):
        self.addInput(execType, "execInit", "Execute Init")
        self.addInput(execType, "execLoop", "Execute Loop")

        self.addOutput(execType, "ExecInitOut", "Init Done")
        self.addOutput(execType, "ExecLoopOut", "Loop Done")
Пример #27
0
class CollectionCueSettings(SettingsPage):
    Name = 'Edit Collection'

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.setLayout(QVBoxLayout(self))

        self.cuesWidget = QListWidget(self)
        self.cuesWidget.setAlternatingRowColors(True)
        self.layout().addWidget(self.cuesWidget)

        # Buttons
        self.dialogButtons = QDialogButtonBox(self)
        self.dialogButtons.setSizePolicy(QSizePolicy.Minimum,
                                         QSizePolicy.Minimum)
        self.layout().addWidget(self.dialogButtons)

        self.addButton = self.dialogButtons.addButton('Add', QDialogButtonBox.ActionRole)
        self.addButton.clicked.connect(self._add_dialog)

        self.delButton = self.dialogButtons.addButton('Remove', QDialogButtonBox.ActionRole)
        self.delButton.clicked.connect(self._remove_selected)

        self.cue_dialog = CueListDialog(cues=Application().cue_model)
        self.cue_dialog.list.setSelectionMode(QAbstractItemView.ExtendedSelection)

    def load_settings(self, settings):
        for target_id, action in settings.get('targets', []):
            target = Application().cue_model.get(target_id)
            if target is not None:
                self._add_cue(target, action)

    def get_settings(self):
        targets = []
        for n in range(self.cuesWidget.count()):
            widget = self.cuesWidget.itemWidget(self.cuesWidget.item(n))
            target_id, action = widget.get_target()
            targets.append((target_id, action))

        return {'targets': targets}

    def _add_cue(self, cue, action):
        item = QListWidgetItem()
        item.setSizeHint(QSize(200, 30))

        widget = CueItemWidget(cue, action, self.cue_dialog)

        self.cuesWidget.addItem(item)
        self.cuesWidget.setItemWidget(item, widget)
        self.cue_dialog.remove_cue(cue)

    def _add_dialog(self):
        if self.cue_dialog.exec_() == QDialog.Accepted:
            for target in self.cue_dialog.selected_cues():
                self._add_cue(target, tuple(target.CueActions)[0].name)

    def _remove_selected(self):
        cue = self.cuesWidget.itemWidget(self.cuesWidget.currentItem()).target

        self.cuesWidget.takeItem(self.cuesWidget.currentRow())
        self.cue_dialog.add_cue(cue)
Пример #28
0
class ChatSetter(QWidget):
    """..."""
    saved = pyqtSignal(str, bool, list)

    def __init__(self, name_):
        super(ChatSetter, self).__init__()
        self._name = name_
        self._setup_ui()

    def enable(self, enable_):
        """..."""
        self._enable.setChecked(enable_)

    def display_filter(self, filter_list_):
        """..."""
        self._filter.clear()
        for _name in filter_list_:
            _item = QListWidgetItem(_name)
            _item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable)
            self._filter.addItem(_item)

    def _on_clicked(self, item_):
        self._filter.setCurrentItem(item_)
        for _index in range(self._filter.count()):
            self._filter.item(_index).setBackground(QColor('white'))
            self._filter.item(_index).setForeground(QColor('black'))
        item_.setBackground(QColor(0, 105, 217))
        item_.setForeground(QColor('white'))

    def _setup_ui(self):
        _vbox = QVBoxLayout()
        self._enable = QCheckBox(self._name)
        self._filter = QListWidget()
        self._filter.itemClicked.connect(self._on_clicked)
        self._filter.itemChanged.connect(self._save_filter)
        self._filter.setSelectionMode(QAbstractItemView.SingleSelection)
        _vbox.addWidget(self._enable)
        _vbox.addWidget(self._filter)
        _vbox.addLayout(self._gen_filter_btn_group())
        self.setLayout(_vbox)

    def _gen_filter_btn_group(self):
        _add = QPushButton('Add')
        _add.clicked.connect(self._add_filter)
        _delete = QPushButton('Delete')
        _delete.clicked.connect(self._delete_filter)

        _btn_group = QHBoxLayout()
        _btn_group.addWidget(_add)
        _btn_group.addWidget(_delete)
        _btn_group.setSpacing(0)
        return _btn_group

    def _add_filter(self):
        _name = GuiUtils.input_dialog(self, 'Filter', 'Add filter:')
        if _name:
            _item = QListWidgetItem(_name)
            _item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable)
            self._filter.addItem(_item)
            self._save_filter()

    def _delete_filter(self):
        try:
            _item = self._filter.currentItem()
            if GuiUtils.question_dialog(self, 'Filter',
                                        'Delete filter: ' + _item.text()):
                _item = self._filter.takeItem(self._filter.currentRow())
                del _item
                self._save_filter()
        except Exception as e:
            _msg = 'Choose one item before deleting.'
            print(_msg)

    def _save_filter(self):
        self.saved.emit(self._name, self._enable.isChecked(), [
            self._filter.item(_index).text()
            for _index in range(self._filter.count())
        ])
Пример #29
0
class PostProcessor(QMainWindow):

    sim_results_changed = pyqtSignal()
    post_results_changed = pyqtSignal()

    figures_changed = pyqtSignal(list, str)

    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self._settings = QSettings()
        self._logger = logging.getLogger(self.__class__.__name__)

        self.setWindowTitle("Processing")
        self.setWindowIcon(QIcon(get_resource("processing.png")))
        self.mainFrame = QWidget(self)
        self.resize(1000, 600)

        # toolbar
        self.toolBar = QToolBar("file control")
        self.toolBar.setIconSize(QSize(24, 24))
        self.addToolBar(self.toolBar)

        self.actLoad = QAction(self)
        self.actLoad.setText("load result file")
        self.actLoad.setIcon(QIcon(get_resource("load.png")))
        self.actLoad.setDisabled(False)
        self.actLoad.triggered.connect(self.load_result_files)

        self.actPostLoad = QAction(self)
        self.actPostLoad.setText("load post-result file")
        self.actPostLoad.setIcon(QIcon(get_resource("load.png")))
        self.actPostLoad.setDisabled(False)
        self.actPostLoad.triggered.connect(self.load_post_result_files)

        self.actSwitch = QAction(self)
        self.actSwitch.setText("switch display mode")
        self.actSwitch.setIcon(QIcon(get_resource("left_mode.png")))
        self.actSwitch.setDisabled(False)
        self.actSwitch.triggered.connect(self.switch_sides)
        self.displayLeft = True

        self.spacer1 = QWidget()
        self.spacer2 = QWidget()
        self.spacer1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.actReloadMethods = QAction(self)
        self.actReloadMethods.setText("reload methods")
        self.actReloadMethods.setIcon(QIcon(get_resource("reload.png")))
        self.actReloadMethods.setDisabled(False)
        self.actReloadMethods.triggered.connect(self.update_post_method_list)

        self.actReloadMetaMethods = QAction(self)
        self.actReloadMetaMethods.setText("reload meta methods")
        self.actReloadMetaMethods.setIcon(QIcon(get_resource("reload.png")))
        self.actReloadMetaMethods.setDisabled(False)
        self.actReloadMetaMethods.triggered.connect(
            self.update_meta_method_list)
        
        self.toolBar.addAction(self.actLoad)
        self.toolBar.addAction(self.actReloadMethods)
        
        self.toolBar.addWidget(self.spacer1)
        self.toolBar.addAction(self.actSwitch)
        self.toolBar.addWidget(self.spacer2)

        self.toolBar.addAction(self.actReloadMetaMethods)
        self.toolBar.addAction(self.actPostLoad)

        # main window
        self.grid = QGridLayout(self.mainFrame)
        self.grid.setColumnMinimumWidth(0, 70)
        self.grid.setColumnStretch(0, 0)
        self.grid.setColumnStretch(1, 1)

        self.methodList = QListWidget(self)
        self.methodList.itemDoubleClicked.connect(
            self.post_processor_clicked)
        self.update_post_method_list()
        self.metaMethodList = QListWidget(self)
        self.metaMethodList.itemDoubleClicked.connect(
            self.meta_processor_clicked)
        self.update_meta_method_list()

        self.sim_result_list = QListWidget(self)
        self.sim_results_changed.connect(self.update_result_list)
        self.results = []

        self.delShort = QShortcut(QKeySequence(Qt.Key_Delete),
                                  self.sim_result_list)
        self.delShort.activated.connect(self.remove_result_item)

        # figures
        self._figure_dict = {}
        self.figures_changed.connect(self.update_figure_lists)

        self.post_figure_list = QListWidget(self)
        self.post_figure_list.currentItemChanged.connect(
            self.current_figure_changed)
        self.meta_figure_list = QListWidget(self)
        self.meta_figure_list.currentItemChanged.connect(
            self.current_figure_changed)

        self.plotView = QWidget()
        self.lastFigure = None

        self.post_result_list = QListWidget(self)
        self.post_results_changed.connect(self.update_post_result_list)
        self.post_results = []
        self.delShortPost = QShortcut(QKeySequence(Qt.Key_Backspace),
                                      self.post_result_list)
        self.delShortPost.activated.connect(self.remove_post_result_item)

        # log dock
        self.logBox = QPlainTextEdit(self)
        self.logBox.setReadOnly(True)

        # init logger for logging box
        self.textLogger = PlainTextLogger(logging.INFO)
        self.textLogger.set_target_cb(self.logBox.appendPlainText)
        logging.getLogger().addHandler(self.textLogger)

        self.grid.addWidget(QLabel("Result Files:"), 0, 0)
        self.grid.addWidget(self.sim_result_list, 1, 0)
        self.grid.addWidget(QLabel("Postprocessors:"), 2, 0)
        self.grid.addWidget(self.methodList, 3, 0)
        self.grid.addWidget(QLabel("Figures:"), 4, 0)
        self.grid.addWidget(self.post_figure_list, 5, 0)
        self.grid.addWidget(QLabel("Selected Figure:"), 0, 1)
        self.grid.addWidget(QLabel("Postprocessor Files:"), 0, 2)
        self.grid.addWidget(self.post_result_list, 1, 2)
        self.grid.addWidget(QLabel("Metaprocessors:"), 2, 2)
        self.grid.addWidget(self.metaMethodList, 3, 2)
        self.grid.addWidget(QLabel("Figures:"), 4, 2)
        self.grid.addWidget(self.meta_figure_list, 5, 2)
        self.grid.addWidget(self.logBox, 6, 0, 1, 3)

        self.mainFrame.setLayout(self.grid)
        self.setCentralWidget(self.mainFrame)

        # status bar
        self.statusBar = QStatusBar(self)
        self.setStatusBar(self.statusBar)

    def load_result_files(self):
        path = self._settings.value("path/simulation_results")

        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.ExistingFiles)
        dialog.setDirectory(path)
        dialog.setNameFilter("PyMoskito Result files (*.pmr)")

        if dialog.exec_():
            files = dialog.selectedFiles()
            for single_file in files:
                if single_file:
                    self._load_result_file(single_file)

    def _load_result_file(self, file_name):
        """
        loads a result file
        """
        self._logger.info("loading result file {}".format(file_name))
        with open(file_name.encode(), "rb") as f:
            self.results.append(pickle.load(f))

        self.sim_results_changed.emit()

    def update_result_list(self):
        self.sim_result_list.clear()
        for res in self.results:
            name = res["regime name"]
            self.sim_result_list.addItem(name)

    def remove_result_item(self):
        if self.sim_result_list.currentRow() >= 0:
            del self.results[self.sim_result_list.currentRow()]
            self.sim_result_list.takeItem(self.sim_result_list.currentRow())

    def load_post_result_files(self):
        path = self._settings.value("path/processing_results")

        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.ExistingFiles)
        dialog.setDirectory(path)
        dialog.setNameFilter("Postprocessing Output files (*.pof)")

        if dialog.exec_():
            files = dialog.selectedFiles()
            for single_file in files:
                if single_file:
                    self._load_post_result_file(single_file)

    def _load_post_result_file(self, file_name):
        """
        loads a post-result file (.pof)
        """
        name = os.path.split(file_name)[-1][:-4]
        self._logger.info("loading result file {}".format(file_name))
        with open(file_name.encode(), "rb") as f:
            results = pickle.load(f)
            results.update({"name": name})
            self.post_results.append(results)

        self.post_results_changed.emit()

    def update_post_result_list(self):
        self.post_result_list.clear()
        for res in self.post_results:
            name = res["name"]
            self.post_result_list.addItem(name)

    def remove_post_result_item(self):
        if self.post_result_list.currentRow() >= 0:
            del self.post_results[self.post_result_list.currentRow()]
            self.post_result_list.takeItem(self.post_result_list.currentRow())

    def update_post_method_list(self):
        self.methodList.clear()
        modules = pm.get_registered_processing_modules(PostProcessingModule)
        for mod in modules:
            self.methodList.addItem(mod[1])

    def update_meta_method_list(self):
        self.metaMethodList.clear()
        modules = pm.get_registered_processing_modules(MetaProcessingModule)
        for mod in modules:
            self.metaMethodList.addItem(mod[1])

    def post_processor_clicked(self, item):
        self.run_processor(str(item.text()), "post")

    def meta_processor_clicked(self, item):
        self.run_processor(str(item.text()), "meta")

    def run_processor(self, name, processor_type):
        if processor_type == "post":
            result_files = self.results
            base_cls = PostProcessingModule
        elif processor_type == "meta":
            result_files = self.post_results
            base_cls = MetaProcessingModule
        else:
            self._logger.error("unknown processor type {0}".format(
                processor_type))
            raise ValueError("unknown processor type {0}".format(
                processor_type))

        if not result_files:
            self._logger.warning("run_processor() Error: no result file loaded")
            return

        processor_cls = pm.get_processing_module_class_by_name(base_cls, name)
        processor = processor_cls()

        figs = []
        try:
            self._logger.info("executing processor '{0}'".format(name))
            figs = processor.process(result_files)
        except Exception as err:
            self._logger.exception("Error in processor")

        self.figures_changed.emit(figs, processor_type)
        self._logger.info("finished postprocessing")

    def update_figure_lists(self, figures, target_type):
        # remove no longer needed elements
        for item, fig in [(key, val[0])
                          for key, val in self._figure_dict.items()
                          if val[1] == target_type]:
            if fig not in [new_fig["figure"] for new_fig in figures]:
                if target_type == "post":
                    old_item = self.post_figure_list.takeItem(
                        self.post_figure_list.row(item))
                    del old_item
                elif target_type == "meta":
                    old_item = self.meta_figure_list.takeItem(
                        self.meta_figure_list.row(item))
                    del old_item

                del self._figure_dict[item]

        # add new ones to internal storage
        for fig in figures:
            if fig["figure"] not in self._figure_dict.values():
                new_entry = [(fig["name"],
                              (QListWidgetItem(fig["name"]),
                               fig["figure"], target_type)
                              )]
                self._figure_dict.update(new_entry)

        # add to display
        for key, val in self._figure_dict.items():
            if val[2] == "post":
                self.post_figure_list.addItem(val[0])
            elif val[2] == "meta":
                self.meta_figure_list.addItem(val[0])

        self.post_figure_list.setCurrentItem(self.post_figure_list.item(0))
        self.meta_figure_list.setCurrentItem(self.meta_figure_list.item(0))

    def current_figure_changed(self, current_item, last_item=None):
        if current_item is None:
            return

        figures = self._figure_dict

        if self.lastFigure:
            self.grid.removeWidget(self.lastFigure)
            self.lastFigure.setVisible(False)

        if current_item.text() in figures:
            figure_widget = figures[current_item.text()][1]
            self.grid.addWidget(figure_widget, 1, 1, 5, 1)
            figure_widget.setVisible(True)
            self.lastFigure = figure_widget
        
    def switch_sides(self):
        self.displayLeft = not self.displayLeft
        if self.displayLeft:
            self.actSwitch.setIcon(QIcon(get_resource("left_mode.png")))
            self.post_figure_list.setFocus()
            self.current_figure_changed(self.post_figure_list.currentItem())
        else:
            self.actSwitch.setIcon(QIcon(get_resource("right_mode.png")))
            self.meta_figure_list.setFocus()
            self.current_figure_changed(self.meta_figure_list.currentItem())
class MultiSelectComboBox(QComboBox):
    search_bar_index = 0

    updated = pyqtSignal()

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

        self.list_widget = QListWidget(self)
        self.line_edit = QLineEdit(self)
        self.search_bar = QLineEdit(self)

        current_item = QListWidgetItem(self.list_widget)
        self.search_bar.setPlaceholderText("Search...")
        self.search_bar.setClearButtonEnabled(True)
        # First item in the list is the SEARCH BAR
        self.list_widget.addItem(current_item)
        self.list_widget.setItemWidget(current_item, self.search_bar)

        self.line_edit.setReadOnly(True)
        self.line_edit.installEventFilter(self)

        self.setModel(self.list_widget.model())
        self.setView(self.list_widget)
        self.setLineEdit(self.line_edit)

        self.search_bar.textChanged.connect(self.onSearch)
        self.activated.connect(self.itemClicked)

    def hidePopup(self):
        width = self.width()
        height = self.list_widget.height()
        x = QCursor.pos().x() - self.mapToGlobal(
            self.geometry().topLeft()).x() + self.geometry().x()
        y = QCursor.pos().y() - self.mapToGlobal(
            self.geometry().topLeft()).y() + self.geometry().y()

        if x >= 0 and x <= width and y >= self.height(
        ) and y <= height + self.height():
            pass  # Item was clicked do not hide popup
        else:
            super().hidePopup()

    def stateChanged(self, state=None):
        # state is unused
        selected_data = []
        count = self.list_widget.count()

        for i in range(1, count):
            check_box = self.list_widget.itemWidget(self.list_widget.item(i))
            if check_box.isChecked():
                selected_data.append(check_box.text())

        if selected_data:
            self.line_edit.setText(', '.join(selected_data))
        else:
            self.line_edit.clear()
        self.updated.emit()

    def addItem(self, text, user_data=None):
        # user_data is unused
        list_widget_item = QListWidgetItem(self.list_widget)
        check_box = QCheckBox(self)
        check_box.setText(text)
        self.list_widget.addItem(list_widget_item)
        self.list_widget.setItemWidget(list_widget_item, check_box)
        check_box.stateChanged.connect(self.stateChanged)

    def currentText(self):
        if self.line_edit.text():
            return [_.strip() for _ in self.line_edit.text().split(",")]
        return []

    def addItems(self, texts):
        for s in texts:
            self.addItem(s)

    def count(self):
        return max(0,
                   self.list_widget.count() - 1)  # Do not count the search bar

    def onSearch(self, s):
        for i in range(self.list_widget.count()):
            check_box = self.list_widget.itemWidget(self.list_widget.item(i))
            if s.lower() in check_box.text().lower():
                self.list_widget.item(i).setHidden(False)
            else:
                self.list_widget.item(i).setHidden(True)

    def itemClicked(self, index):
        if index != self.search_bar_index:
            check_box = self.list_widget.itemWidget(
                self.list_widget.item(index))
            check_box.setChecked(not check_box.isChecked())

    def setSearchBarPlaceholderText(self, placeholder_text):
        self.search_bar.setPlaceholderText(placeholder_text)

    def setPlaceholderText(self, placeholder_text):
        self.line_edit.setPlaceholderText(placeholder_text)

    def clear(self):
        self.list_widget.clear()
        current_item = QListWidgetItem(self.list_widget)
        self.search_bar = QLineEdit(self)
        self.search_bar.setPlaceholderText("Search...")
        self.search_bar.setClearButtonEnabled(True)
        self.list_widget.addItem(current_item)
        self.list_widget.setItemWidget(current_item, self.search_bar)

        self.search_bar.textChanged.connect(self.onSearch)

    def wheelEvent(self, wheel_event):
        pass  # Do not handle the wheel event

    def setCurrentText(self, text):
        pass

    def setCurrentTexts(self, texts):
        count = self.list_widget.count()

        for i in range(1, count):
            check_box = self.list_widget.itemWidget(self.list_widget.item(i))
            check_box_string = check_box.text()
            if check_box_string in texts:
                check_box.setChecked(True)

    def ResetSelection(self):
        count = self.list_widget.count()

        for i in range(1, count):
            check_box = self.list_widget.itemWidget(self.list_widget.item(i))
            check_box.setChecked(False)
Пример #31
0
class RmExplorerWindow(QMainWindow):

    def __init__(self):

        super().__init__()

        self.settings = Settings()
        self.updateFromSettings()

        self.statusBar()
        self.makeMenus()

        self.dirsList = QListWidget(self)
        self.dirsList.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.dirsList.itemDoubleClicked.connect(self.dirsListItemDoubleClicked)
        self.dirsList.setContextMenuPolicy(Qt.CustomContextMenu)
        self.dirsList.customContextMenuRequested.connect(self.dirsListContextMenuRequested)

        self.filesList = QListWidget(self)
        self.filesList.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.filesList.itemDoubleClicked.connect(self.filesListItemDoubleClicked)
        self.filesList.setContextMenuPolicy(Qt.CustomContextMenu)
        self.filesList.customContextMenuRequested.connect(self.filesListContextMenuRequested)

        self.curDirLabel = QLabel(self)

        browserLayout = QGridLayout()
        browserLayout.addWidget(QLabel('Folders:'), 0, 0)
        browserLayout.addWidget(QLabel('Files:'), 0, 1)
        browserLayout.addWidget(self.dirsList, 1, 0)
        browserLayout.addWidget(self.filesList, 1, 1)

        mainLayout = QVBoxLayout()
        mainLayout.addLayout(browserLayout)
        mainLayout.addWidget(self.curDirLabel)

        centralWidget = QWidget(self)
        centralWidget.setLayout(mainLayout)
        self.setCentralWidget(centralWidget)

        self.curDir = ''
        self.curDirName = ''
        self.curDirParents = []
        self.curDirParentsNames = []
        self.dirIds = []
        self.dirNames = []
        self.fileIds = []
        self.goToDir('', '')

        self.currentWarning = ''
        self.hasRaised = None

        self.progressWindow = None
        self.downloadFilesWorker = None
        self.uploadDocsWorker = None
        self.backupDocsWorker = None
        self.restoreDocsWorker = None
        self.taskThread = None

        self._masterKey = None

        self.setWindowTitle(constants.AppName)


    ###################
    # General methods #
    ###################

    def updateFromSettings(self):
        """Call this whenever settings are changed"""

        socket.setdefaulttimeout(self.settings.value('HTTPShortTimeout', type=float))


    def makeMenus(self):

        menubar = self.menuBar()

        # Explorer menu
        uploadDocsAct = QAction('&Upload documents', self)
        uploadDocsAct.setShortcut('Ctrl+U')
        uploadDocsAct.setStatusTip('Upload documents from the computer to the tablet.')
        uploadDocsAct.triggered.connect(self.uploadDocs)
        #
        dlAllAct = QAction('&Download all', self)
        dlAllAct.setShortcut('Ctrl+D')
        dlAllAct.setStatusTip('Download all files to a local folder.')
        dlAllAct.triggered.connect(self.downloadAll)
        #
        refreshAct = QAction('&Refresh', self)
        refreshAct.setShortcut('Ctrl+R')
        refreshAct.setStatusTip('Refresh folders and files lists.')
        refreshAct.triggered.connect(self.refreshLists)
        #
        settingsAct = QAction('&Settings', self)
        settingsAct.setShortcut('Ctrl+S')
        settingsAct.setStatusTip('%s settings' % constants.AppName)
        settingsAct.triggered.connect(self.editSettings)
        #
        exitAct = QAction('&Exit', self)
        exitAct.setShortcut('Ctrl+Q')
        exitAct.setStatusTip('Exit %s.' % constants.AppName)
        exitAct.triggered.connect(qApp.quit)
        #
        explorerMenu = menubar.addMenu('&Explorer')
        explorerMenu.addAction(uploadDocsAct)
        explorerMenu.addAction(dlAllAct)
        explorerMenu.addAction(refreshAct)
        explorerMenu.addSeparator()
        explorerMenu.addAction(settingsAct)
        explorerMenu.addSeparator()
        explorerMenu.addAction(exitAct)

        # SSH menu
        backupDocsAct = QAction('&Backup documents', self)
        backupDocsAct.setStatusTip('Backup all notebooks, documents, ebooks and bookmarks to a folder on this computer.')
        backupDocsAct.triggered.connect(self.backupDocs)
        #
        restoreDocsAct = QAction('&Restore documents', self)
        restoreDocsAct.setStatusTip('Restore documents on the tablet from a backup on this computer.')
        restoreDocsAct.triggered.connect(self.restoreDocs)
        #
        sshMenu = menubar.addMenu('&SSH')
        sshMenu.addAction(backupDocsAct)
        sshMenu.addAction(restoreDocsAct)

        # About menu
        aboutAct = QAction(constants.AppName, self)
        aboutAct.setStatusTip("Show %s's About box." % constants.AppName)
        aboutAct.triggered.connect(self.about)
        #
        aboutQtAct = QAction('Qt', self)
        aboutQtAct.setStatusTip("Show Qt's About box.")
        aboutQtAct.triggered.connect(qApp.aboutQt)
        #
        explorerMenu = menubar.addMenu('&About')
        explorerMenu.addAction(aboutAct)
        explorerMenu.addAction(aboutQtAct)

        # Context menu of the directories QListWidget
        self.dirsListContextMenu = QMenu(self)
        downloadDirsAct = self.dirsListContextMenu.addAction('&Download')
        downloadDirsAct.triggered.connect(self.downloadDirsClicked)

        # Context menu of the files QListWidget
        self.filesListContextMenu = QMenu(self)
        downloadFilesAct = self.filesListContextMenu.addAction('&Download')
        downloadFilesAct.triggered.connect(self.downloadFilesClicked)


    def goToDir(self, dirId, dirName):

        try:
            collections, docs = tools.listDir(dirId, self.settings)
        except (urllib.error.URLError, socket.timeout) as e:
            msg = getattr(e, 'reason', 'timeout')
            QMessageBox.critical(self, constants.AppName,
                                 'Could not go to directory "%s": URL error:\n%s' % (dirId, msg))
            return

        if dirId != self.curDir:
            # We are either moving up or down one level
            if len(self.curDirParents) == 0 or self.curDirParents[-1] != dirId:
                # Moving down
                self.curDirParents.append(self.curDir)
                self.curDirParentsNames.append(self.curDirName)
            else:
                # Moving up
                self.curDirParents.pop()
                self.curDirParentsNames.pop()
            self.curDir = dirId
            self.curDirName = dirName
        if self.curDirParents:
            path = '%s/%s' % ('/'.join(self.curDirParentsNames), self.curDirName)
        else:
            path = '/'
        self.curDirLabel.setText(path)

        # Update dirsList and filesList
        self.dirsList.clear()
        self.filesList.clear()

        if dirId != '':
            self.dirIds = [self.curDirParents[-1]]
            self.dirNames = [self.curDirParentsNames[-1]]
            self.dirsList.addItem('..')
        else:
            self.dirIds = []
            self.dirNames = []
        self.fileIds = []

        for id_, name in collections:
            self.dirIds.append(id_)
            self.dirNames.append(name)
            self.dirsList.addItem(name)
        for id_, name in docs:
            self.fileIds.append(id_)
            self.filesList.addItem(name)


    def downloadFile(self, basePath, fileDesc, mode):

        if not os.path.isdir(basePath):
            raise OSError('Not a directory: %s' % basePath)

        fid, destRelPath = fileDesc
        self.statusBar().showMessage('Downloading %s...' % os.path.split(destRelPath)[1])
        try:
            tools.downloadFile(fid, basePath, destRelPath, mode, self.settings)
        except (urllib.error.URLError, socket.timeout) as e:
            msg = getattr(e, 'reason', 'timeout')
            QMessageBox.error(self, constants.AppName,
                                'URL error: %s. Aborted.' % msg)
            self.statusBar().showMessage('Download error.',
                                         constants.StatusBarMsgDisplayDuration)
        else:
            self.statusBar().showMessage('Download finished.',
                                         constants.StatusBarMsgDisplayDuration)


    def downloadDirs(self, dirs):

        def listFiles(ext, baseFolderId, baseFolderPath, filesList):
            url = self.settings.value('listFolderURL', type=str) % baseFolderId
            try:
                res = urllib.request.urlopen(url)
                data = res.read().decode(constants.HttpJsonEncoding)
            except (urllib.error.URLError, socket.timeout) as e:
                warningBox = QMessageBox(self)
                msg = getattr(e, 'reason', 'timeout')
                warningBox.setText('URL error: %s. Aborted.' % msg)
                warningBox.setIcon(QMessageBox.Warning)
                warningBox.exec()
                self.statusBar().showMessage('Download error.',
                                             constants.StatusBarMsgDisplayDuration)
                return
            data = json.loads(data)
            for elem in data:
                if elem['Type'] == 'DocumentType':
                    path = '%s.%s' % (os.path.join(baseFolderPath, elem['VissibleName']), ext) # yes, "Vissible"
                    filesList.append((elem['ID'], path))
                elif elem['Type'] == 'CollectionType':
                    listFiles(ext, elem['ID'],
                              os.path.join(baseFolderPath, elem['VissibleName']),
                              filesList)

        dialog = SaveOptsDialog(self.settings, self)
        if dialog.exec() == QDialog.Accepted:
            mode = dialog.getSaveMode()
            ext = mode
            # Ask for destination folder
            folder = QFileDialog.getExistingDirectory(self,
                                                      'Save directory',
                                                      self.settings.value('lastDir', type=str),
                                                      QFileDialog.ShowDirsOnly
                                                      | QFileDialog.DontResolveSymlinks)
            if folder:
                self.settings.setValue('lastDir', os.path.split(folder)[0])
                # Construct files list
                dlList = []
                for dir_id, dir_name in dirs:
                    listFiles(ext, dir_id, dir_name, dlList)

                self.progressWindow = ProgressWindow(self)
                self.progressWindow.setWindowTitle("Downloading...")
                self.progressWindow.nSteps = len(dlList)
                self.progressWindow.open()

                self.settings.sync()
                self.currentWarning = ''
                self.downloadFilesWorker = DownloadFilesWorker(folder,
                                                               dlList,
                                                               mode)
                self.taskThread = QThread()
                self.downloadFilesWorker.moveToThread(self.taskThread)
                self.taskThread.started.connect(self.downloadFilesWorker.start)
                self.downloadFilesWorker.notifyProgress.connect(self.progressWindow.updateStep)
                self.downloadFilesWorker.finished.connect(self.onDownloadFilesFinished)
                self.downloadFilesWorker.warning.connect(self.warningRaised)
                self.taskThread.start()
            else:
                self.statusBar().showMessage('Cancelled.',
                                             constants.StatusBarMsgDisplayDuration)


    def downloadFiles(self, files):

        dialog = SaveOptsDialog(self.settings, self)
        if dialog.exec() == QDialog.Accepted:
            mode = dialog.getSaveMode()
            ext = mode
            # Ask for destination folder
            folder = QFileDialog.getExistingDirectory(self,
                                                      'Save directory',
                                                      self.settings.value('lastDir', type=str),
                                                      QFileDialog.ShowDirsOnly
                                                      | QFileDialog.DontResolveSymlinks)
            if folder:
                self.settings.setValue('lastDir', os.path.split(folder)[0])
                # Construct files list
                dlList = tuple((id_, os.path.join(folder, '%s.%s' % (name, ext)))
                               for id_, name in files)

                self.progressWindow = ProgressWindow(self)
                self.progressWindow.setWindowTitle("Downloading...")
                self.progressWindow.nSteps = len(dlList)
                self.progressWindow.open()

                self.settings.sync()
                self.currentWarning = ''
                self.downloadFilesWorker = DownloadFilesWorker(folder,
                                                               dlList,
                                                               mode)
                self.taskThread = QThread()
                self.downloadFilesWorker.moveToThread(self.taskThread)
                self.taskThread.started.connect(self.downloadFilesWorker.start)
                self.downloadFilesWorker.notifyProgress.connect(self.progressWindow.updateStep)
                self.downloadFilesWorker.finished.connect(self.onDownloadFilesFinished)
                self.downloadFilesWorker.warning.connect(self.warningRaised)
                self.taskThread.start()
            else:
                self.statusBar().showMessage('Cancelled.',
                                             constants.StatusBarMsgDisplayDuration)


    def backupDocs(self):

        # Destination folder
        defaultDir = (self.settings.value('lastSSHBackupDir', type=str)
                      or self.settings.value('lastDir', type=str))
        folder = QFileDialog.getExistingDirectory(self,
                                                  'Save directory',
                                                  defaultDir,
                                                  QFileDialog.ShowDirsOnly
                                                  | QFileDialog.DontResolveSymlinks)
        if not folder:
            self.statusBar().showMessage('Cancelled.',
                                         constants.StatusBarMsgDisplayDuration)
            return

        self.settings.setValue('lastSSHBackupDir', os.path.split(folder)[0])

        if not self.settings.unlockMasterKeyInteractive(self):
            self.statusBar().showMessage('Cancelled.',
                                         constants.StatusBarMsgDisplayDuration)
            return

        self.progressWindow = ProgressWindow(self)
        self.progressWindow.setWindowTitle("Downloading backup...")
        self.progressWindow.open()

        self.settings.sync()
        self.currentWarning = ''
        self.backupDocsWorker = BackupDocsWorker(folder, self.settings._masterKey)

        self.taskThread = QThread()
        self.backupDocsWorker.moveToThread(self.taskThread)
        self.taskThread.started.connect(self.backupDocsWorker.start)
        self.backupDocsWorker.notifyNSteps.connect(self.progressWindow.updateNSteps)
        self.backupDocsWorker.notifyProgress.connect(self.progressWindow.updateStep)
        self.backupDocsWorker.finished.connect(self.onBackupDocsFinished)
        self.backupDocsWorker.warning.connect(self.warningRaised)
        self.taskThread.start()


    def restoreDocs(self):

        # Confirm user has a backup folder
        tabletDir = self.settings.value('TabletDocumentsDir')
        msg = "To restore a backup, you need a previous copy on your computer of the tablet's \"%s\" folder. Ensure the backup you select was made with a tablet having the same software version as the device on which you want to restore the files.\n\n" % tabletDir
        msg += "Do you have such a backup and want to proceed to the restoration?"
        reply = QMessageBox.question(self, constants.AppName, msg)
        if reply == QMessageBox.No:
            self.statusBar().showMessage('Cancelled.',
                                         constants.StatusBarMsgDisplayDuration)
            return

        # Source folder
        defaultDir = (self.settings.value('lastSSHBackupDir', type=str)
                      or self.settings.value('lastDir', type=str))
        folder = QFileDialog.getExistingDirectory(self,
                                                  'Backup directory',
                                                  defaultDir,
                                                  QFileDialog.ShowDirsOnly
                                                  | QFileDialog.DontResolveSymlinks)
        if not folder:
            self.statusBar().showMessage('Cancelled.',
                                         constants.StatusBarMsgDisplayDuration)
            return
        self.settings.setValue('lastSSHBackupDir', os.path.split(folder)[0])

        # Basic check that the folder contents looks like a backup
        success, msg = tools.isValidBackupDir(folder)
        if not success:
            QMessageBox.warning(self, constants.AppName, '%s\nAborting.' % msg)
            self.statusBar().showMessage('Cancelled.',
                                         constants.StatusBarMsgDisplayDuration)
            return

        if not self.settings.unlockMasterKeyInteractive(self):
            self.statusBar().showMessage('Cancelled.',
                                         constants.StatusBarMsgDisplayDuration)
            return

        # Last chance to cancel!
        msg = "%s is now ready to restore the documents. Please check that the tablet is turned on, unlocked and that Wifi is enabled. Make sure no file is open and do not use the tablet during the upload.\n\n" % constants.AppName
        msg += "When the upload finishes, please reboot the tablet.\n\n"
        msg += "To restore documents, contents on the tablet will first be deleted. By continuing, you acknowledge that you take the sole responsibility for any possible data loss or damage caused to the tablet that may result from using %s.\n\n" % constants.AppName
        msg += "Do you want to continue?"
        reply = QMessageBox.question(self, constants.AppName, msg)
        if reply == QMessageBox.No:
            self.statusBar().showMessage('Cancelled.',
                                         constants.StatusBarMsgDisplayDuration)
            return

        self.progressWindow = ProgressWindow(self)
        self.progressWindow.setWindowTitle("Restoring backup...")
        self.progressWindow.open()

        self.settings.sync()
        self.hasRaised = False
        self.restoreDocsWorker = RestoreDocsWorker(folder, self.settings._masterKey)

        self.taskThread = QThread()
        self.restoreDocsWorker.moveToThread(self.taskThread)
        self.taskThread.started.connect(self.restoreDocsWorker.start)
        self.restoreDocsWorker.notifyNSteps.connect(self.progressWindow.updateNSteps)
        self.restoreDocsWorker.notifyProgress.connect(self.progressWindow.updateStep)
        self.restoreDocsWorker.finished.connect(self.onRestoreDocsFinished)
        self.restoreDocsWorker.error.connect(self.errorRaised)
        self.taskThread.start()


    #########
    # Slots #
    #########

    def refreshLists(self):

        self.goToDir(self.curDir, self.curDirName)


    def dirsListItemDoubleClicked(self, item):

        idx = self.dirsList.currentRow()
        self.goToDir(self.dirIds[idx], self.dirNames[idx])


    def dirsListContextMenuRequested(self, pos):

        if len(self.dirsList.selectedItems()) > 0:
            self.dirsListContextMenu.exec(self.dirsList.mapToGlobal(pos))


    def filesListContextMenuRequested(self, pos):

        if len(self.filesList.selectedItems()) > 0:
            self.filesListContextMenu.exec(self.filesList.mapToGlobal(pos))


    def filesListItemDoubleClicked(self, item):

        fid = self.fileIds[self.filesList.currentRow()]
        dialog = SaveOptsDialog(self.settings, self)
        if dialog.exec() == QDialog.Accepted:
            mode = dialog.getSaveMode()
            ext = mode
            filename = '%s.%s' % (item.text(), ext)

            # Ask for file destination
            result = QFileDialog.getSaveFileName(self,
                                                 'Save %s' % ext.upper(),
                                                 os.path.join(self.settings.value('lastDir', type=str),
                                                              filename),
                                                 '%s file (*.%s)' % (ext.upper(), ext))
            if result[0]:
                dest_path = result[0] if result[0].endswith('.%s' % ext) else '%s.%s' % (result[0], ext)
                parts = os.path.split(dest_path)
                self.settings.setValue('lastDir', parts[0])
                self.downloadFile(parts[0], (fid, parts[1]), ext)
            else:
                self.statusBar().showMessage('Cancelled.',
                                             constants.StatusBarMsgDisplayDuration)
        else:
            self.statusBar().showMessage('Cancelled.',
                                         constants.StatusBarMsgDisplayDuration)


    def downloadFilesClicked(self):

        items = self.filesList.selectionModel().selectedIndexes()
        files = tuple((self.fileIds[i.row()],
                       self.filesList.item(i.row()).text()) for i in items)
        self.downloadFiles(files)


    def downloadDirsClicked(self):

        items = self.dirsList.selectionModel().selectedIndexes()
        dirs = tuple((self.dirIds[i.row()], self.dirNames[i.row()]) for i in items)
        self.downloadDirs(dirs)


    def downloadAll(self):

        self.downloadDirs((('', ''),))


    def uploadDocs(self):

        defaultDir = (self.settings.value('lastDir', type=str))
        paths = QFileDialog.getOpenFileNames(self,
                                             'Select files to upload',
                                             defaultDir,
                                             'Documents (*.pdf *.epub)')[0]
        nFiles = len(paths)
        if nFiles == 0:
            self.statusBar().showMessage('Cancelled.',
                                         constants.StatusBarMsgDisplayDuration)
            return

        self.settings.setValue('lastDir', os.path.split(paths[0])[0])

        self.progressWindow = ProgressWindow(self)
        self.progressWindow.setWindowTitle("Uploading documents...")
        self.progressWindow.nSteps = nFiles
        self.progressWindow.open()

        self.settings.sync()
        self.currentWarning = ''
        self.uploadDocsWorker = UploadDocsWorker(paths)

        self.taskThread = QThread()
        self.uploadDocsWorker.moveToThread(self.taskThread)
        self.taskThread.started.connect(self.uploadDocsWorker.start)
        self.uploadDocsWorker.notifyNSteps.connect(self.progressWindow.updateNSteps)
        self.uploadDocsWorker.notifyProgress.connect(self.progressWindow.updateStep)
        self.uploadDocsWorker.finished.connect(self.onUploadDocsFinished)
        self.uploadDocsWorker.warning.connect(self.warningRaised)
        self.taskThread.start()


    def warningRaised(self, msg):

        self.currentWarning = msg


    def errorRaised(self, msg):

        self.hasRaised = True
        QMessageBox.critical(self, constants.AppName,
                             'Error:\n%s\nAborted.' % msg)


    def onDownloadFilesFinished(self):

        self.progressWindow.hide()

        self.taskThread.started.disconnect(self.downloadFilesWorker.start)
        self.downloadFilesWorker.notifyProgress.disconnect(self.progressWindow.updateStep)
        self.downloadFilesWorker.warning.disconnect(self.warningRaised)
        self.downloadFilesWorker.finished.disconnect(self.onDownloadFilesFinished)

        self.progressWindow.deleteLater()

        # Not sure that the following is entirely safe.  For example, what if a
        # new thread is created before the old objects are actually deleted?
        self.taskThread.quit()
        self.downloadFilesWorker.deleteLater()
        self.taskThread.deleteLater()
        self.taskThread.wait()

        if self.currentWarning:
            QMessageBox.warning(self, constants.AppName,
                                'Errors were encountered:\n%s' % self.currentWarning)
        self.statusBar().showMessage('Finished downloading files.',
                                     constants.StatusBarMsgDisplayDuration)


    def onUploadDocsFinished(self):

        self.progressWindow.hide()

        self.taskThread.started.disconnect(self.uploadDocsWorker.start)
        self.uploadDocsWorker.notifyNSteps.disconnect(self.progressWindow.updateNSteps)
        self.uploadDocsWorker.notifyProgress.disconnect(self.progressWindow.updateStep)
        self.uploadDocsWorker.warning.disconnect(self.warningRaised)
        self.uploadDocsWorker.finished.disconnect(self.onUploadDocsFinished)

        self.progressWindow.deleteLater()

        # Not sure that the following is entirely safe.  For example, what if a
        # new thread is created before the old objects are actually deleted?
        self.taskThread.quit()
        self.uploadDocsWorker.deleteLater()
        self.taskThread.deleteLater()
        self.taskThread.wait()

        if self.currentWarning:
            QMessageBox.warning(self, constants.AppName,
                                'Errors were encountered:\n%s' % self.currentWarning)
        self.refreshLists()
        self.statusBar().showMessage('Finished uploading files.',
                                     constants.StatusBarMsgDisplayDuration)


    def editSettings(self):

        dialog = SettingsDialog(self.settings, self)
        if dialog.exec() == QDialog.Accepted:
            self.updateFromSettings()
            self.statusBar().showMessage('Settings updated.',
                                         constants.StatusBarMsgDisplayDuration)


    def onBackupDocsFinished(self):

        self.progressWindow.hide()

        self.taskThread.started.disconnect(self.backupDocsWorker.start)
        self.backupDocsWorker.warning.disconnect(self.warningRaised)
        self.backupDocsWorker.finished.disconnect(self.onBackupDocsFinished)
        self.backupDocsWorker.notifyNSteps.disconnect(self.progressWindow.updateNSteps)
        self.backupDocsWorker.notifyProgress.disconnect(self.progressWindow.updateStep)

        self.progressWindow.deleteLater()

        self.taskThread.quit()
        self.backupDocsWorker.deleteLater()
        self.taskThread.deleteLater()
        self.taskThread.wait()

        if self.currentWarning:
            QMessageBox.warning(self, constants.AppName,
                                'Errors were encountered:\n%s' % self.currentWarning)
        else:
            QMessageBox.information(self, constants.AppName,
                                    'Backup was created successfully!')
        self.statusBar().showMessage('Finished downloading backup.',
                                     constants.StatusBarMsgDisplayDuration)


    def onRestoreDocsFinished(self):

        self.progressWindow.hide()

        self.taskThread.started.disconnect(self.restoreDocsWorker.start)
        self.restoreDocsWorker.error.disconnect(self.errorRaised)
        self.restoreDocsWorker.finished.disconnect(self.onRestoreDocsFinished)
        self.restoreDocsWorker.notifyNSteps.disconnect(self.progressWindow.updateNSteps)
        self.restoreDocsWorker.notifyProgress.disconnect(self.progressWindow.updateStep)

        self.progressWindow.deleteLater()

        self.taskThread.quit()
        self.restoreDocsWorker.deleteLater()
        self.taskThread.deleteLater()
        self.taskThread.wait()

        if not self.hasRaised:
            QMessageBox.information(self, constants.AppName,
                                    'Backup was restored successfully! Please reboot the tablet now.')

            self.statusBar().showMessage('Finished restoring backup.',
                                         constants.StatusBarMsgDisplayDuration)


    def about(self):

        msg = """<b>pyrmexplorer: Explorer for Remarkable tablets</b><br/><br/>
Version %s<br/><br/>
Copyright (C) 2019 Nicolas Bruot (<a href="https://www.bruot.org/hp/">https://www.bruot.org/hp/</a>)<br/><br/>

Some parts of this software are copyright other contributors. Refer to the individual source files for details.<br/><br/>

pyrmexplorer is released under the terms of the GNU General Public License (GPL) v3.<br/><br/>

The source code is available at <a href=\"https://github.com/bruot/pyrmexplorer/\">https://github.com/bruot/pyrmexplorer/</a>.<br/><br/>
"""
        msg = msg % __version__
        msgBox = QMessageBox(self)
        msgBox.setText(msg)
        msgBox.exec()
Пример #32
0
class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.filenames = json_files()

        if type(self.filenames) is list:
            self.curr_file = self.filenames[0]
        else:
            self.curr_file = self.filenames

        self.initUI()

    def initUI(self):

        self.num = -1  # index for search bar query
        self.show_save = False  # bool for showing unsaved changes dialog
        self.temp_file = ".temp.csv"
        self.refresh_file = False  # failsafe 1 for itemChanged trigger

        self.list_1 = QListWidget()

        lister(file=self.curr_file, target=self.list_1, index=0, mode=0)
        self.list_1.clicked.connect(self.clear_selection)
        self.list_1.installEventFilter(self)

        self.list_items = self.list_1.count(
        )  # failsafe 2 for itemChanged trigger
        self.list_1.itemChanged.connect(self.edit_next_item)
        self.list_1.verticalScrollBar().valueChanged.connect(self.sync_scroll)

        self.list_2 = QListWidget()
        lister(file=self.curr_file, target=self.list_2, index=1, mode=0)
        self.list_2.clicked.connect(self.clear_selection)

        self.list_3 = QListWidget()
        lister(file=self.curr_file, target=self.list_3, index=2, mode=0)
        self.list_3.clicked.connect(self.clear_selection)

        self.all_lists = [self.list_1, self.list_2, self.list_3]

        self.menubar = QMenuBar()
        self.menubar.setNativeMenuBar(False)

        exit_event = QAction('Exit', self)
        exit_event.setShortcut('Ctrl+W')
        exit_event.triggered.connect(app.quit)

        showAct = QAction('Show extras', self, checkable=True)
        showAct.setChecked(False)
        showAct.setShortcut('Ctrl+E')
        showAct.triggered.connect(self.hide_notes)

        addAct = QAction('Fields', self)
        addAct.setShortcut('Ctrl+N')
        addAct.triggered.connect(self.add_item)

        fileOpen = QAction('Open file', self)
        fileOpen.triggered.connect(self.fileDialog)
        fileOpen.setShortcut('Ctrl+O')

        fileSave = QAction('Save file', self)
        fileSave.triggered.connect(self.save)
        fileSave.triggered.connect(self.refresh_recents)
        fileSave.setShortcut('Ctrl+S')

        self.fileRecents = QMenu('Recent file', self)
        self.refresh_recents()

        self.toggle_theme = QAction('Toggle theme', self, checkable=True)
        self.toggle_theme.setChecked(json_theme())
        self.toggle_theme.triggered.connect(self.theme)
        self.toggle_theme.setShortcut('Ctrl+T')

        self.col_sort_index = QMenu('Sorting column index', self)
        self.col_sort_index.addAction(QAction(str(0), self))
        self.col_sort_index.addAction(QAction(str(1), self))
        self.col_sort_index.addAction(QAction(str(2), self))
        self.col_sort_index.triggered.connect(self.sort_col_choice)

        self.col_search_index = QMenu('Searching column index', self)
        self.col_search_index.addAction(QAction(str(0), self))
        self.col_search_index.addAction(QAction(str(1), self))
        self.col_search_index.addAction(QAction(str(2), self))
        self.col_search_index.triggered.connect(self.search_col_choice)

        self.sort = QAction('Sort entries', self, checkable=True)
        self.curr_col = 0
        self.search_col = 0
        self.sort.triggered.connect(self.refresh_list)
        self.sort.setShortcut('Ctrl+R')

        self.addFields = self.menubar.addMenu('Add')
        self.addFields.addAction(addAct)

        self.optionMenu = self.menubar.addMenu('Options')
        self.optionMenu.addAction(exit_event)
        self.optionMenu.addAction(showAct)
        self.optionMenu.addAction(self.toggle_theme)
        self.optionMenu.addMenu(self.col_sort_index)
        self.optionMenu.addMenu(self.col_search_index)
        self.optionMenu.addAction(self.sort)

        self.fileMenu = self.menubar.addMenu('File')
        self.fileMenu.addAction(fileOpen)
        self.fileMenu.addAction(fileSave)
        self.fileMenu.addMenu(self.fileRecents)

        self.search_bar = QLineEdit()
        self.search_bar.setPlaceholderText('Search vocab')
        self.search_bar.setClearButtonEnabled(True)
        self.search_bar.setMaxLength(10)
        self.search_bar.returnPressed.connect(self.search_item)

        self.status_bar = QStatusBar()
        status(self.status_bar, self.list_1)

        grid = QGridLayout()
        grid.setSpacing(10)
        grid.addWidget(self.menubar, 0, 0)
        grid.addWidget(self.list_1, 1, 0)
        grid.addWidget(self.list_2, 1, 1)
        grid.addWidget(self.list_3, 1, 2)
        grid.addWidget(self.search_bar, 0, 1)
        grid.addWidget(self.status_bar)

        self.theme()
        self.setLayout(grid)
        self.setGeometry(*json_window_size())
        self.setWindowTitle(f'{split_name(self.curr_file)}')
        self.show()

        self.list_1.scrollToBottom()
        self.list_2.verticalScrollBar().setHidden(True)
        self.list_3.verticalScrollBar().setHidden(True)
        self.list_3.setHidden(True)

    def sync_scroll(self):

        scroll_location = self.list_1.verticalScrollBar().value()

        self.list_2.verticalScrollBar().setValue(scroll_location)
        self.list_3.verticalScrollBar().setValue(scroll_location)

    def edit_next_item(self, event):
        """When an item is added and edited on the first col, starts editing its counterpart on the next col"""

        if self.list_items == self.list_1.count(
        ) - 2 or self.list_items != self.list_1.count(
        ) and self.refresh_file == False:

            item = self.list_2.item(self.list_2.count() - 1)
            self.list_2.editItem(item)

            self.list_items = self.list_1.count()

    def closeEvent(self, event):
        """Triggered upon program exit, shows a dialog for unsaved changes using a bool"""

        if self.show_save == True:

            reply = QMessageBox.question(
                self, 'Message',
                "You may have unsaved changes, are you sure you want to quit?",
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

            if reply == QMessageBox.Yes:
                try:
                    remove(self.temp_file)
                except:
                    pass

                event.accept()
            else:
                event.ignore()

        else:
            pass

    def sort_col_choice(self, action):
        self.curr_col = int(action.text())

    def search_col_choice(self, action):
        self.search_col = int(action.text())

    def refresh_list(self):
        """Refreshes the contents of the lists, when sorting is used"""

        self.save(
            mode=1
        )  # saves a temp copy, with changes, but irreversable sorting introduced

        clear_lists(self.all_lists)

        if self.sort.isChecked() == True:
            mode = 2
        else:
            mode = 0

        try:
            lister(file=self.temp_file,
                   target=self.list_1,
                   index=0,
                   mode=mode,
                   column=self.curr_col)
            lister(file=self.temp_file,
                   target=self.list_2,
                   index=1,
                   mode=mode,
                   column=self.curr_col)
            lister(file=self.temp_file,
                   target=self.list_3,
                   index=2,
                   mode=mode,
                   column=self.curr_col)

        except:
            lister(file=self.curr_file,
                   target=self.list_1,
                   index=0,
                   mode=mode,
                   column=self.curr_col)
            lister(file=self.curr_file,
                   target=self.list_2,
                   index=1,
                   mode=mode,
                   column=self.curr_col)
            lister(file=self.curr_file,
                   target=self.list_3,
                   index=2,
                   mode=mode,
                   column=self.curr_col)

    def refresh_recents(self):

        try:

            file_1 = QAction(self.curr_file, self)
            self.fileRecents.addAction(file_1)
            file_1.triggered.connect(self.clickedFileAct)

            if type(self.filenames) is list:

                if self.filenames[1] != None:
                    file_2 = QAction(self.filenames[1], self)
                    self.fileRecents.addAction(file_2)
                    file_2.triggered.connect(self.clickedFileAct)

                if self.filenames[2] != None:
                    file_3 = QAction(self.filenames[2], self)
                    self.fileRecents.addAction(file_3)
                    file_3.triggered.connect(self.clickedFileAct)

        except:
            pass

    def clickedFileAct(self):

        self.refresh_file = True

        file = self.sender().text()
        self.curr_file = file
        self.setWindowTitle(f'{split_name(self.curr_file)}')

        clear_lists(self.all_lists)

        lister(file=self.curr_file, target=self.list_1, index=0)
        lister(file=self.curr_file, target=self.list_2, index=1)
        lister(file=self.curr_file, target=self.list_3, index=2)

        status(self.status_bar, self.list_1)
        self.theme()

        self.list_1.scrollToBottom()
        self.list_3.setHidden(True)

        self.refresh_file = False

    def eventFilter(self, source, event):
        """Item (row) deletion"""

        if (event.type() == QEvent.ContextMenu and source is self.list_1):
            menu = QMenu()
            menu.addAction("Delete row")
            if menu.exec_(event.globalPos()):
                item = source.itemAt(event.pos())
                try:
                    model = self.list_1.indexFromItem(item)
                    row = model.row()

                    self.show_save = True

                    self.list_1.takeItem(row)
                    self.list_2.takeItem(row)
                    self.list_3.takeItem(row)

                    status(self.status_bar, self.list_1,
                           f'Deleted row number: {row+1}.')
                    self.clearSelection()

                except:
                    pass

            return True
        return super(Example, self).eventFilter(source, event)

    def hide_notes(self):
        """Toggles showing the note column and stretches the window for clearer reading of it"""

        self.list_3.setHidden(not self.list_3.isHidden())

    def theme(self):
        """Sets the theme for the window and its widgets"""

        palette = QPalette()

        # dark theme
        if self.toggle_theme.isChecked() == True:

            palette.setColor(QPalette.Window, QColor(0, 0, 0))
            dark = "background-color: rgb(0, 0, 0); color: rgb(255, 255, 255);"

            self.menubar.setStyleSheet(dark)
            self.addFields.setStyleSheet(dark)
            self.optionMenu.setStyleSheet(dark)
            self.fileMenu.setStyleSheet(dark)
            self.search_bar.setStyleSheet(
                "background-color: rgb(0, 0, 0); color: rgb(255, 255, 255)"
            )  # border: 0px; for transparency
            self.status_bar.setStyleSheet(dark)

            style_items(self.all_lists, dark_theme=True)

        # light theme
        elif self.toggle_theme.isChecked() == False:

            palette.setColor(QPalette.Window, QColor(255, 255, 255))
            light = "background-color: rgb(255, 255, 255); color: rgb(0, 0, 0)"

            self.menubar.setStyleSheet(light)
            self.addFields.setStyleSheet(light)
            self.optionMenu.setStyleSheet(light)
            self.fileMenu.setStyleSheet(light)
            self.search_bar.setStyleSheet(light)
            self.status_bar.setStyleSheet(light)

            style_items(self.all_lists, dark_theme=False)

        self.setPalette(palette)

        self.theme_bool = self.toggle_theme.isChecked(
        )  # used in the save func

    def search_item(self):
        """Takes input from the search bar and matches with an item, 
		gets index and scrolls to it, more reusults being qued with the num class var
		"""

        query = self.search_bar.text()
        search = self.all_lists[self.search_col].findItems(
            query, Qt.MatchContains)
        status(self.status_bar, self.list_1, f'Found {len(search)} results.')
        self.clear_selection()

        # testing search in all column

        # search_list =[]
        # for x in range(3):
        # 	search_list.append(self.all_lists[x].findItems(query, Qt.MatchContains))

        # parent_list = []
        # for x in range(3):
        # 	for y in range(len(search_list[x])):
        # 		parent_list.append(self.all_lists[x]) # replace with x

        # import itertools
        # merged = list(itertools.chain.from_iterable(search_list))

        # search_dict = dict(zip(parent_list, merged))
        # print(search_dict)
        # print()
        # print(len(merged))
        # print(len(parent_list))

        self.num += 1
        for i in search:

            try:
                model_index = self.all_lists[self.search_col].indexFromItem(
                    search[self.num])

            except:
                self.num = 0
                model_index = self.all_lists[self.search_col].indexFromItem(
                    search[self.num])

            item_index = model_index.row()

            self.all_lists[self.search_col].item(item_index).setSelected(True)
            self.list_1.scrollToItem(self.list_1.item(item_index),
                                     QAbstractItemView.PositionAtCenter)

    def add_item(self):

        self.show_save = True

        for x in range(3):
            if x == 0:
                lister(file=self.curr_file,
                       target=self.list_1,
                       index=x,
                       mode=1)

            elif x == 1:
                lister(file=self.curr_file,
                       target=self.list_2,
                       index=x,
                       mode=1)

            elif x == 2:
                lister(file=self.curr_file,
                       target=self.list_3,
                       index=x,
                       mode=1)

        item = self.list_1.item(self.list_1.count() - 1)
        self.list_1.editItem(item)
        status(self.status_bar, self.list_1)

        self.list_1.scrollToBottom()
        self.list_2.scrollToBottom()
        self.list_3.scrollToBottom()

    def clear_selection(self):
        """Clears all item slections for aesthetical purposes, but only single clicks"""

        self.list_1.clearSelection()
        self.list_2.clearSelection()
        self.list_3.clearSelection()

    def fileDialog(self):

        fname = QFileDialog()
        path = fname.getOpenFileName(self,
                                     'Open file',
                                     getcwd(),
                                     filter='csv (*.csv);;')
        if path[0] == '':  # failsafe for canceling the dialog
            return self.curr_file

        self.curr_file = path[0]
        self.setWindowTitle(f'{split_name(self.curr_file)}')

        clear_lists(self.all_lists)

        lister(file=self.curr_file, target=self.list_1, index=0)
        lister(file=self.curr_file, target=self.list_2, index=1)
        lister(file=self.curr_file, target=self.list_3, index=2)

        status(self.status_bar, self.list_1)
        self.theme()

    def save(self, mode=0):

        self.show_save = False

        list1_items = items_text(self.list_1)
        list2_items = items_text(self.list_2)
        list3_items = items_text(self.list_3)

        total_dicts = []
        for (a, b, c) in zip(list1_items, list2_items,
                             list3_items):  # each letter is a column
            dictionary = {'word_1': a, 'word_2': b, 'notes': c}
            total_dicts.append(dictionary)

        if mode == 0:

            writer(file=self.curr_file, data=total_dicts)
            status(self.status_bar, self.list_1, ('Saved current changes.'))

            try:
                json_template(theme=self.theme_bool,
                              files=[self.curr_file, None, None],
                              window_size=self.geometry().getRect()
                              )  # current size values of the window

            except:
                json_template(
                )  # bug cannot be avoided, even though used setChecked at the beggining

        elif mode == 1:

            self.show_save = True
            writer(file=self.temp_file, data=total_dicts)

        # avoids stacking and refreshes recent file actions
        actions = self.fileRecents.actions()
        for action in actions:
            self.fileRecents.removeAction(action)
Пример #33
0
class MainWindow(QMainWindow):

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

        self._suggester = suggester.Suggester()
        self._pickedfiles = []
        self._targetmidi = []
        self.inputlistview = None
        self.suggestionlistview = None
        self.target_lbl = None
        self.initUI()

    def initUI(self):

        targetButton = QPushButton('Select Target', self)
        targetButton.setToolTip('Select midi you want suggestions for')
        targetButton.resize(targetButton.sizeHint())
        targetButton.clicked.connect(self.picktargetmidi)

        self.inputlistview = QListWidget()
        self.inputlistview.itemPressed.connect(self.showmidi)

        inputlistview_lbl = QLabel(self)
        inputlistview_lbl.setText("Input MIDIs")
        inputlistview_lbl.adjustSize()

        suggestionlistview_lbl = QLabel(self)
        suggestionlistview_lbl.setText("Suggested segments")
        suggestionlistview_lbl.adjustSize()

        self.target_lbl = QLabel(self)
        self.target_lbl.setText("Please select target midi")
        self.target_lbl.adjustSize()

        self.suggestionlistview = QListWidget()

        suggestButton = QPushButton("Suggest", self)
        suggestButton.setToolTip('Suggest a continuation to target midi')
        suggestButton.clicked.connect(self.suggestmidi)
        saveButton = QPushButton("Save Suggestions", self)

        importAction = QAction(self.tr('Add MIDI file(s)'), self)
        importAction.setShortcut('Ctrl+O')
        importAction.setStatusTip('Add MIDI files to pool')
        importAction.triggered.connect(self.pickfiles)

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(self.target_lbl)
        hbox.addWidget(targetButton)
        hbox.addWidget(suggestButton)
        hbox.addWidget(saveButton)

        vbox = QVBoxLayout()
        vbox.addStretch(1)
        vbox.addWidget(inputlistview_lbl)
        vbox.addWidget(self.inputlistview)
        vbox.addLayout(hbox)
        vbox.addWidget(suggestionlistview_lbl)
        vbox.addWidget(self.suggestionlistview)


        cwidget = QWidget()
        cwidget.setLayout(vbox)

        self.setCentralWidget(cwidget)
        self.statusBar().showMessage('Ready')

        self.statusBar()

        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(importAction)

        self.center()
        self.setGeometry(150,20,100,100)
        self.setWindowTitle('Gnotestic')
        self.show()

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

    def pickfiles(self, point):
        dialog_result = QFileDialog.getOpenFileNames(self,
                                                     self.tr("Import Midi"), "", self.tr("Midi Files (*.mid *.midi)"))
        self._pickedfiles.extend(dialog_result[0])
        self.updatemidilist(dialog_result[0])

    def picktargetmidi(self, point):
        dialog_result = QFileDialog.getOpenFileName(self,
                                                    self.tr("Select Target Midi"), "", self.tr("Midi Files (*.mid *.midi)"))
        self._targetmidi = dialog_result[0]

    def updatemidilist(self, items):
        for item in items:
            witem = QListWidgetItem(item)
            self.inputlistview.addItem(witem)

    def showmidi(self, item):
        path = item.text()
        ms = converter.parse(path)
        ms.plot('pianoroll')

    def suggestmidi(self, point):
        #add midis to suggester
        if self._targetmidi and self.inputlistview.count():
            self._suggester.set_target_piece(self._targetmidi)
            for i in range(self.inputlistview.count()):
                self._suggester.add_midi(self.inputlistview.item(i).text())
        #update suggestion list
        self.suggestionlistview.clear()
        for suggestion in self._suggester.get_suggestions():
            self.suggestionlistview.addItem(QListWidgetItem(repr(suggestion)))
Пример #34
0
class NameMan(QWidget):
    def __init__(self, parent=None):
        super(NameMan, self).__init__(parent)

        self.createTop()
        self.createInfo()
        mainLayout = QVBoxLayout()
        mainLayout.addLayout(self.searchLayout)
        mainLayout.addWidget(self.infoBox)
        self.setFixedSize(440, 260)
        self.setLayout(mainLayout)

    def createTop(self):
        self.searchLayout = QHBoxLayout()
        self.searchLine = QLineEdit()
        search = QPushButton("搜索")
        search.clicked.connect(self.updateInfoList)
        self.searchLayout.addWidget(self.searchLine)
        self.searchLayout.addWidget(search)

    def updateShow(self):
        pass

    def createInfo(self):
        self.infoBox = QGroupBox("匹配到的域文件")
        self.infoBox.setFixedSize(430, 200)
        self.listWidget = QListWidget()
        layout = QVBoxLayout()
        self.ok = QPushButton("修改")
        self.cancel = QPushButton("删除")
        self.ok.setEnabled(False)
        self.cancel.setEnabled(False)
        self.ok.clicked.connect(self.modifi)
        self.cancel.clicked.connect(self.delete)
        button = QHBoxLayout()
        button.addWidget(self.ok)
        button.addWidget(self.cancel)
        layout.addWidget(self.listWidget)
        layout.addLayout(button)
        self.infoBox.setLayout(layout)

    def updateInfoList(self):
        self.listWidget.clear()
        par = self.searchLine.text()
        if not par:
            QMessageBox.about(self, "Error", "没有检索内容!!!")
            return
        view = [
            i for i in os.listdir("/var/cache/bind/")
            if os.path.isdir("/var/cache/bind/" + i)
        ]
        self.result = []
        for i in view:
            lis = os.listdir("/var/cache/bind/" + i)
            ret = ["%s-->%s" % (i, a) for a in lis if par in a]
            self.result.extend(ret)
        if not self.result:
            QMessageBox.about(self, "Warn", "没有你想要检索的内容!!!")
            self.checkButton()
            return
        self.addListItem()
        self.selected = self.listWidget.item(0).text()
        self.listWidget.currentItemChanged.connect(self.getSelected)
        #print(self.selected)
        self.checkButton()

    def checkButton(self):
        if not self.result:
            self.ok.setEnabled(False)
            self.cancel.setEnabled(False)
        else:
            self.ok.setEnabled(True)
            self.cancel.setEnabled(True)

    def addListItem(self):
        lis = self.result
        for i in lis:
            item = QListWidgetItem(self.listWidget)
            item.setText(i)
            item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)

    def getSelected(self, current, previous):
        if not current:
            current = previous
        self.selected = self.listWidget.item(
            self.listWidget.row(current)).text()
        print(self.selected)

    def modifi(self):
        flag = self.selected.split("-->")
        path = "/var/cache/bind/" + flag[0] + "/" + flag[1]
        self.notepad = Notepad()
        self.notepad.openFile(path)


#        self.notepad.show()

    def delete(self):
        flag = self.selected.split("-->")
        conf = "/etc/bind/named.conf." + flag[0] + "-views"
        path1 = "/var/cache/bind/" + flag[0] + "/" + flag[1]
        path2 = "/var/cache/bind/" + flag[1]
        print(conf)
        psutil.os.popen("rm -f " + path1)
        psutil.os.popen("rm -f " + path2)
        psutil.os.popen('sed -i "/' + self.searchLine.text() +
                        '\"/,/\b;};/d" ' + conf)
        n1 = self.result
        self.updateInfoList()
        n2 = self.result
        if n1 != n2:
            QMessageBox.about(self, "Succree", "删除文件成功!!!")
        else:
            QMessageBox.about(self, "Fail", "发生未知错误导致删除文件失败!!!")
Пример #35
0
class EgimDownloaderFrame(QFrame):
    """Frame to download data from EMSODEV servers"""

    # Signals
    msg2Statusbar = pyqtSignal(str)
    wf2plotSplitter = pyqtSignal(WaterFrame)

    class DownloadParameterThread(QThread):
        """
        The process to download data from the API is very slow.
        We are going to use this thread to download data without block the app.
        """
        def __init__(self, downloader):
            QThread.__init__(self)

            self.downloader = downloader

        def __del__(self):
            self.wait()

        def run(self):
            """Thread main function"""

            if self.downloader.instrument_list.currentItem().text() \
               == "icListen-1636":
                date = datetime.datetime.strptime(
                    self.downloader.date_list.currentItem().text(),
                    "%Y-%m-%d").strftime("%d/%m/%Y")
                self.downloader.download_acoustic(
                    date,
                    self.downloader.hour_minute_list.currentItem().text())
            else:
                parameters = [
                    item.text()
                    for item in self.downloader.parameter_list.selectedItems()
                ]
                for parameter in parameters:
                    self.downloader.download_parameter(parameter)

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

        # Instance variables
        self.downloader = EGIM()
        self.wf = WaterFrame()  # pylint: disable=C0103
        self.metadata = dict()
        self.dates = []
        self.my_thread = None
        # Save the login of the EMSODEV API
        self.downloader.login = "******"
        self.downloader.password = ""

        self.init_ui()

    def init_ui(self):
        """Layout and main functionalities"""

        # Buttons
        download_button = QPushButton("Download", self)
        download_button.clicked.connect(self.download_click)
        download_button.setEnabled(False)
        close_button = QPushButton("Close", self)
        close_button.clicked.connect(self.hide)

        # Lists
        self.egim_list = QListWidget(self)
        self.egim_list.itemClicked.connect(self.load_instruments)
        self.egim_list.setMaximumWidth(200)

        self.instrument_list = QListWidget(self)
        self.instrument_list.itemClicked.connect(self.load_parameters)
        self.instrument_list.setMaximumWidth(290)

        self.metadata_list = QListWidget(self)

        self.parameter_list = QListWidget(self)
        self.parameter_list.setSelectionMode(
            QAbstractItemView.ExtendedSelection)
        self.parameter_list.itemClicked.connect(
            lambda: download_button.setEnabled(True))

        self.date_list = QListWidget(self)
        self.date_list.itemClicked.connect(self.load_times)
        self.date_list.setMaximumWidth(150)
        self.hour_minute_list = QListWidget(self)
        self.hour_minute_list.itemClicked.connect(
            lambda: download_button.setEnabled(True))
        self.hour_minute_list.setMaximumWidth(150)

        # Labels
        egim_label = QLabel("EGIM", self)
        instrument_label = QLabel("Instrument", self)
        metadata_label = QLabel("Metadata", self)
        parameter_label = QLabel("Parameter", self)
        start_date_label = QLabel("Start date", self)
        end_date_label = QLabel("End date", self)
        limit_label = QLabel("Get last X values", self)
        hour_label = QLabel("Hour and minute (HHmm)", self)
        date_label = QLabel("Available dates", self)

        # Date edit
        self.start_date_edit = QDateEdit(self)
        self.start_date_edit.setCalendarPopup(True)
        self.start_date_edit.setDateTime(
            QDateTime(QDate(2017, 1, 27), QTime(0, 0, 0)))
        self.start_date_edit.setMinimumDateTime(
            QDateTime(QDate(2017, 1, 27), QTime(0, 0, 0)))
        self.end_date_edit = QDateEdit(self)
        self.end_date_edit.setCalendarPopup(True)
        self.end_date_edit.setDateTime(
            QDateTime(QDate(2017, 1, 27), QTime(0, 0, 0)))
        self.end_date_edit.setMinimumDateTime(
            QDateTime(QDate(2017, 1, 27), QTime(0, 0, 0)))

        # Spin box
        self.limit_spin_box = QSpinBox(self)
        self.limit_spin_box.setMinimum(0)
        self.limit_spin_box.setMaximum(9999999999)
        self.limit_spin_box.setSingleStep(100)
        self.limit_spin_box.valueChanged.connect(self.enable_date)

        # Custom Widgets

        # Widget for dates of the acoustic data
        self.acoustic_date_widget = QWidget(self)
        # - Layout
        v_acoustic_date = QVBoxLayout()
        v_acoustic_date.addWidget(date_label)
        v_acoustic_date.addWidget(self.date_list)
        v_acoustic_date.addWidget(hour_label)
        v_acoustic_date.addWidget(self.hour_minute_list)
        self.acoustic_date_widget.setLayout(v_acoustic_date)
        self.acoustic_date_widget.setMaximumWidth(175)
        self.acoustic_date_widget.setEnabled(False)

        # Widget for dates of parameters
        self.parameter_date_widget = QWidget(self)
        # - Layout
        v_parameter_date = QVBoxLayout()
        v_parameter_date.addWidget(start_date_label)
        v_parameter_date.addWidget(self.start_date_edit)
        v_parameter_date.addWidget(end_date_label)
        v_parameter_date.addWidget(self.end_date_edit)
        v_parameter_date.addWidget(limit_label)
        v_parameter_date.addWidget(self.limit_spin_box)
        v_parameter_date.addStretch()
        self.parameter_date_widget.setLayout(v_parameter_date)
        self.parameter_date_widget.setEnabled(False)

        # Layout
        # - Vertical layout for EGIM --
        v_egim = QVBoxLayout()
        v_egim.addWidget(egim_label)
        v_egim.addWidget(self.egim_list)
        # -- Vertical layout for instruments -
        v_instrument = QVBoxLayout()
        v_instrument.addWidget(instrument_label)
        v_instrument.addWidget(self.instrument_list)
        # - Vertical layout for parameters -
        v_parameter = QVBoxLayout()
        v_parameter.addWidget(metadata_label)
        v_parameter.addWidget(self.metadata_list)
        v_parameter.addWidget(parameter_label)
        v_parameter.addWidget(self.parameter_list)
        # - Vertical layout for dates and buttons
        v_button = QVBoxLayout()
        v_button.addWidget(download_button)
        v_button.addWidget(close_button)
        v_button.addStretch()
        # - Layout of the frame -
        h_frame = QHBoxLayout()
        h_frame.addLayout(v_egim)
        h_frame.addLayout(v_instrument)
        h_frame.addLayout(v_parameter)
        h_frame.addWidget(self.parameter_date_widget)
        h_frame.addWidget(self.acoustic_date_widget)
        h_frame.addLayout(v_button)

        self.setLayout(h_frame)

    def load_observatories(self):
        """
        It asks for the available EGIM observatories and write its names into
        self.egim_list
        """
        debug = True  # For print debug info

        if debug:
            print("- In EgimDownloaderFrame.load_observatory() -")

        # Send a message for the statusbar
        self.msg2Statusbar.emit("Loading observatories")
        # Clear self.egim_list
        self.egim_list.clear()
        # Ask for the observatories
        code, observatory_list = self.downloader.observatories()

        if debug:
            print("code:", code)
            print("observatory_list:", observatory_list)

        if code:
            if code == 200:
                # It means that you are going good
                self.egim_list.addItems(observatory_list)
                # Send a message for the statusbar
                self.msg2Statusbar.emit("Ready")
            elif code == 401:

                if debug:
                    print(
                        "msg2Statusbar: Unauthorized to use the EMSODEV DMP API",
                        code)

                self.msg2Statusbar.emit(
                    "Unauthorized to use the EMSODEV DMP API")
                self.downloader.password = None
                self.reload()
            elif code == 404:
                self.msg2Statusbar.emit("Not Found")
            elif code == 403:
                self.msg2Statusbar.emit("Forbidden")
            elif code == 500:
                self.msg2Statusbar.emit("EMSODEV API internal error")
            elif code == 504:
                self.msg2Statusbar.emit("EMSODEV DMP error: Gateway Time Out")
            else:
                self.msg2Statusbar.emit("Unknown EMSODEV DMP API error")
        else:
            self.msg2Statusbar.emit(
                "Impossible to connect to the EMSODEV DMP API")

    def load_instruments(self, observatory):
        """
        It asks for the available instruments and write its names into
        self.instrument_list

        Parameters
        ----------
            observatory: item
                item from self.observatory_list
        """
        # Send a message for the statusbar
        self.msg2Statusbar.emit("Loading instruments")
        # Clear self.instrument_list
        self.instrument_list.clear()
        # Ask for instruments
        code, instrument_list_ = self.downloader.instruments(
            observatory.text())
        if code:
            if code == 200:
                # It means that you are going good
                # Obtain all sensor names of instrument_list_
                sensor_type = [
                    instrument['name'] for instrument in instrument_list_
                ]
                self.instrument_list.addItems(sensor_type)
                # Add tooltip
                for i in range(self.instrument_list.count()):
                    self.instrument_list.item(i).setToolTip(
                        '<p><b>Sensor Type</b><br>' +
                        '{}</p><p>'.format(instrument_list_[i]['sensorType']) +
                        '<b>Long Name</b><br>' + '{}</p>'.format(
                            instrument_list_[i]['sensorLongName']) +
                        '<p></p><p><b>S/N</b><br>' +
                        '{}</p>'.format(instrument_list_[i]['sn']))
                # Send a message for the statusbar
                self.msg2Statusbar.emit("Ready")
            elif code == 401:
                self.msg2Statusbar.emit(
                    "Unauthorized to use the EMSODEV DMP API")
                self.downloader.password = None
                self.reload()
            elif code == 404:
                self.msg2Statusbar.emit("Not Found")
            elif code == 403:
                self.msg2Statusbar.emit("Forbidden")
            elif code == 500:
                self.msg2Statusbar.emit("EMSODEV API internal error")
            else:
                self.msg2Statusbar.emit("Unknown EMSODEV DMP API error")
        else:
            self.msg2Statusbar.emit(
                "Impossible to connect to the EMSODEV DMP API")

    def load_parameters(self, instrument):
        """
        It asks for the available parameters and metadata and write them into
        self.parameter_list and self.metadata_list
        """
        # Send a message for the statusbar
        self.msg2Statusbar.emit("Loading parameters")
        # Clear self.parameter_list and self.metadata_list
        self.parameter_list.clear()
        self.metadata_list.clear()
        self.parameter_date_widget.setEnabled(False)
        self.acoustic_date_widget.setEnabled(False)

        # If instrument is an icListener, check times
        if instrument.text() == "icListen-1636":
            self.acoustic_date_widget.setEnabled(True)
            # Ask for dates
            code, self.dates = self.downloader.acoustic_date(
                self.egim_list.currentItem().text(), instrument.text())
            if code == 200:
                date_list = [
                    date['acousticObservationDate'] for date in self.dates
                ]
                self.date_list.addItems(date_list)

            else:
                self.msg2Statusbar.emit(
                    "Impossible to connect to the EMSODEV DMP API")
                return
            return

        self.parameter_date_widget.setEnabled(True)

        # Ask for metadata
        code, self.metadata = self.downloader.metadata(
            self.egim_list.currentItem().text(), instrument.text())
        if code == 200:
            items = []
            for key, value in self.metadata.items():
                items.append("{}: {}".format(key, value))
            self.metadata_list.addItems(items)
        else:
            self.msg2Statusbar.emit(
                "Impossible to connect to the EMSODEV DMP API")
            return

        # Ask for parameters
        code, parameter_list_ = self.downloader.parameters(
            self.egim_list.currentItem().text(), instrument.text())
        if code:
            if code == 200:
                # It means that you are going good
                # Obtain all parameter names of parameter_list_
                names = [parameter['name'] for parameter in parameter_list_]
                self.parameter_list.addItems(names)
                self.parameter_list.sortItems()
                # Add tooltip
                for i in range(self.parameter_list.count()):
                    self.parameter_list.item(i).setToolTip(
                        '<b>Units:</b> {}'.format(parameter_list_[i]['uom']))
                # Send a message for the statusbar
                self.msg2Statusbar.emit("Ready")
            elif code == 401:
                self.msg2Statusbar.emit(
                    "Unauthorized to use the EMSODEV DMP API")
                self.downloader.password = None
                self.reload()
            elif code == 404:
                self.msg2Statusbar.emit("Not Found")
            elif code == 403:
                self.msg2Statusbar.emit("Forbidden")
            elif code == 500:
                self.msg2Statusbar.emit("EMSODEV API internal error")
            else:
                self.msg2Statusbar.emit("Unknown EMSODEV DMP API error")
        else:
            self.msg2Statusbar.emit(
                "Impossible to connect to the EMSODEV DMP API")

    def load_times(self, date_item):
        """
        Write items into self.hour_minute_list QListWidget
        """
        for date in self.dates:
            if date['acousticObservationDate'] == date_item.text():
                time_list = []
                for time in date['observationsHourMinuteList']:
                    time_list.append(time['acousticObservationHourMinute'])
                self.hour_minute_list.addItems(time_list)

    def reload(self):
        """It clear all lists and load again the observatories."""
        debug = True

        if debug:
            print("- In EgimDownloaderFrame.reload() -")
            print("self.downloader.password:"******"Password is required to download data from EMSODEV")

            # pylint: disable=C0103
            text, ok = QInputDialog.getText(None, "Attention", "Password",
                                            QLineEdit.Password)

            if debug:
                print("Request for password")
                print("text:", text)
                print("ok:", ok)

            if ok:
                self.downloader.password = text
            else:
                return
        self.load_observatories()

    def download_click(self):
        """Function when user click download"""

        self.my_thread = self.DownloadParameterThread(self)
        self.my_thread.start()

    def download_parameter(self, parameter):
        """It download data with the observation function of EGIM"""

        # Send a message for the statusbar
        self.msg2Statusbar.emit("Downloading {}".format(parameter))

        code, df = self.downloader.observation(  # pylint: disable=C0103
            observatory=self.egim_list.currentItem().text(),
            instrument=self.instrument_list.currentItem().text(),
            parameter=parameter,
            startDate=self.start_date_edit.text(),
            endDate=self.end_date_edit.text(),
            limit=self.limit_spin_box.text())
        if code:
            if code == 200:
                self.msg2Statusbar.emit("Waterframe creation")
                # It means that you are going good
                # pylint: disable=C0103
                wf = self.downloader.to_waterframe(data=df,
                                                   metadata=self.metadata)
                # print(wf.data.head())
                # Send a signal with the new WaterFrame
                self.wf2plotSplitter.emit(wf)
                self.msg2Statusbar.emit("Ready")
            elif code == 401:
                self.msg2Statusbar.emit(
                    "Unauthorized to use the EMSODEV DMP API")
                self.downloader.password = None
                self.reload()
            elif code == 404:
                self.msg2Statusbar.emit("Not Found")
            elif code == 403:
                self.msg2Statusbar.emit("Forbidden")
            elif code == 500:
                self.msg2Statusbar.emit("EMSODEV API internal error")
            else:
                self.msg2Statusbar.emit("Unknown EMSODEV DMP API error")
        else:
            self.msg2Statusbar.emit(
                "Impossible to connect to the EMSODEV DMP API")

    def download_acoustic(self, date, time):
        """Download acoustic data from EMSO"""
        # Send a message for the statusbar
        self.msg2Statusbar.emit("Downloading acoustic file from {}, {}".format(
            date, time))

        code, df, metadata = self.downloader.acoustic_observation(  # pylint: disable=C0103
            observatory=self.egim_list.currentItem().text(),
            instrument=self.instrument_list.currentItem().text(),
            date=date,
            hour_minute=time)
        if code:
            if code == 200:
                self.msg2Statusbar.emit("Waterframe creation")
                # It means that you are going good
                # pylint: disable=C0103
                wf = self.downloader.to_waterframe(data=df, metadata=metadata)
                # Send a signal with the new WaterFrame
                self.wf2plotSplitter.emit(wf)
                self.msg2Statusbar.emit("Ready")
            elif code == 401:
                self.msg2Statusbar.emit(
                    "Unauthorized to use the EMSODEV DMP API")
                self.downloader.password = None
                self.reload()
            elif code == 404:
                self.msg2Statusbar.emit("Not Found")
            elif code == 403:
                self.msg2Statusbar.emit("Forbidden")
            elif code == 500:
                self.msg2Statusbar.emit("EMSODEV API internal error")
            else:
                self.msg2Statusbar.emit("Unknown EMSODEV DMP API error")
        else:
            self.msg2Statusbar.emit(
                "Impossible to connect to the EMSODEV DMP API")

    def enable_date(self):
        """Enable or disable date elements"""
        if int(self.limit_spin_box.text()) > 0:
            self.start_date_edit.setEnabled(False)
            self.end_date_edit.setEnabled(False)
        else:
            self.start_date_edit.setEnabled(True)
            self.end_date_edit.setEnabled(True)
Пример #36
0
class MainWindow(QMainWindow):
    """This is the main window of the ERCreator app.
    Args:
        manager (ERmanager): The class which handles organization of the Extra reflectance database locally an online."""
    def __init__(self, manager: ERManager):
        super().__init__()
        self.explorerWindow = manager.createManagerWindow(self)
        self.setWindowTitle("Extra Reflectance Creator")
        self.setWindowIcon(QtGui.QIcon(os.path.join(resources,
                                                    'cellLogo.png')))

        widg = QWidget()
        layout = QGridLayout()
        self.listWidg = QListWidget(self)
        self.selListWidg = QListWidget(self)
        self.binningCombo = QComboBox()
        self.binningCombo.addItems(['Auto', '1x1', '2x2', '3x3'])
        self.parallelCheckBox = QCheckBox("Parallel Process", self)
        self.parallelCheckBox.setToolTip(
            "Uses significantly more ram but may be significantly faster")
        self.compareDatesButton = QPushButton("Compare Dates")
        self.plotButton = QPushButton("Plot Details")
        self.saveButton = QPushButton("Save Checked Dates")
        self.deleteFigsButton = QPushButton("Close Figures")
        self.viewFilesButton = QPushButton("View Files")
        self.viewFilesButton.released.connect(self.viewFiles)
        self.numericalAperture = QDoubleSpinBox()
        self.numericalAperture.setRange(0, 2)
        self.numericalAperture.setSingleStep(0.01)
        self.numericalAperture.setValue(0.52)
        row = 0
        layout.addWidget(self.listWidg, row, 0, 4, 4)
        layout.addWidget(self.selListWidg, row, 4, 4, 4)
        row += 4
        layout.addWidget(self.compareDatesButton, row, 0, 1, 1)
        layout.addWidget(self.plotButton, row, 1, 1, 1)
        layout.addWidget(self.deleteFigsButton, row, 2, 1, 1)
        layout.addWidget(QLabel("Binning"), row, 4, 1, 1)
        layout.addWidget(self.binningCombo, row, 5, 1, 1)
        layout.addWidget(self.parallelCheckBox, row, 6, 1, 1)
        row += 1
        layout.addWidget(self.saveButton, row, 0, 1, 1)
        layout.addWidget(self.viewFilesButton, row, 1, 1, 1)
        layout.addWidget(QLabel("NA"), row, 4, 1, 1)
        layout.addWidget(self.numericalAperture, row, 5, 1, 1)
        widg.setLayout(layout)
        self.setCentralWidget(widg)
        self.buttons = [
            self.compareDatesButton, self.plotButton, self.saveButton
        ]
        self.show()

    @property
    def binning(self) -> int:
        num = self.binningCombo.currentIndex()
        return num if num != 0 else None

    @property
    def parallelProcessing(self) -> bool:
        return self.parallelCheckBox.isChecked()

    @property
    def checkedSettings(self):
        dateItems = [
            self.selListWidg.item(i) for i in range(self.selListWidg.count())
        ]
        return [i.text() for i in dateItems if i.checkState()]

    def setEnabled(self, en: bool):
        [
            i.setEnabled(en) for i in [
                self.binningCombo, self.saveButton, self.compareDatesButton,
                self.plotButton
            ]
        ]

    def viewFiles(self):
        self.explorerWindow.refresh()
        self.explorerWindow.show()
Пример #37
0
class cronotipy(QMainWindow, QDialog):
    def __init__(self):
        super(cronotipy, self).__init__()

        # Get Window attributes from ui file
        self.cronotipy_ui = Ui_cronotipy_mw()
        self.cronotipy_ui.setupUi(self)
        self.setWindowIcon(QIcon(path_logo))

        cronotipy.initUI(self)  #Another init, this makes code clean

        self.title_and_time = {}  #get titles names and yours respectively time
        self.titles_typed = []

        self.unfreeze = QGuiApplication.processEvents  #unfreeze

        self.startcronotipy = True  #bool to while in start (start/stop)
        self.isOnOff_Notify = True  #state of notify checkable menu
        self.isOnOff_Sound = True  #state of sound checkable menu
        self.isOnOff_loop = False

    def initUI(self):

        #Create the QListWidget
        self.listwd = QListWidget()
        self.listwd.setSelectionMode(
            QAbstractItemView.ExtendedSelection
        )  #This Method enable ctrl and click selection
        self.listwd.doubleClicked.connect(self.renameActualize)

        #Buttons
        self.cronotipy_ui.btn_create.clicked.connect(self.addLines)
        self.cronotipy_ui.btn_create.setStyleSheet(style_buttons)
        self.cronotipy_ui.btn_remove.clicked.connect(self.removeLines)
        self.cronotipy_ui.btn_remove.setStyleSheet(style_buttons)
        self.btn_start = QPushButton('Start')
        self.btn_start.setStyleSheet(style_buttons)
        self.btn_stop = QPushButton('Stop')
        self.btn_stop.setStyleSheet(style_buttons)
        self.btn_start.clicked.connect(self.start)
        self.btn_stop.clicked.connect(self.stop)

        #Create widget inside QDockWidget
        self.dock = cronotipy.createDockwidget(self)
        self.dock.layout().addWidget(self.cronotipy_ui.btn_create,
                                     alignment=Qt.AlignCenter)  #align button
        self.dock.layout().addWidget(self.cronotipy_ui.btn_remove,
                                     alignment=Qt.AlignCenter)  #align button
        self.dock.layout().addWidget(self.btn_start, alignment=Qt.AlignCenter)
        self.dock.layout().addWidget(self.btn_stop, alignment=Qt.AlignCenter)
        self.dock.layout().addWidget(self.listwd)  #QList stay below buttons

        #QScrollBar
        self.vbox_top = QFormLayout()  #vbox, but the true is formbox lol
        self.cronotipy_ui.scrollAWD_top.setLayout(
            self.vbox_top)  #put the vbox layout inside scrollbars widget
        self.cronotipy_ui.scrollA_top.setStyleSheet(style_scrollbar)
        self.vbox_bot = QFormLayout()
        self.cronotipy_ui.scrollAWD_bot.setLayout(
            self.vbox_bot)  #put the vbox layout inside scrollbars widget
        self.cronotipy_ui.scrollA_bot.setStyleSheet(style_scrollbar)

        #MenuBar
        self.cronotipy_ui.menu_Notify_On_Off.triggered.connect(
            self.turnOnOffnotify)
        self.cronotipy_ui.menu_Sound_On_Off.triggered.connect(
            self.turnOnOffsound)
        self.cronotipy_ui.menu_Loop_On_Off.triggered.connect(
            self.turnOnOffloop)
        self.cronotipy_ui.menu_Quit.triggered.connect(self.quitMenu)
        self.cronotipy_ui.menu_Save.triggered.connect(self.saveProfile)
        self.cronotipy_ui.menu_Open.triggered.connect(self.openProfile)

    def createDockwidget(self):
        #create widget Inside QDock
        self.layoutdock = QVBoxLayout()
        self.dockedwidget = QWidget()

        self.cronotipy_ui.dockwd.setWidget(self.dockedwidget)
        self.cronotipy_ui.dockwd.setStyleSheet(style)  #change appearance
        self.dockedwidget.setLayout(self.layoutdock)

        return self.dockedwidget

    def start(self):
        self.startcronotipy = True  #for while

        if self.cronotipy_ui.menu_Loop_On_Off.isChecked():  #for loop
            self.isOnOff_loop = True

        get_titles = [
            self.listwd.item(item).text()
            for item in range(self.listwd.count())
        ]
        title_message = {}

        for title in get_titles:
            title_message[title] = self.findChild(QLineEdit, title).text()
            #timeinseconds = cronotipy.time2seconds(self, self.title_and_time[title])
            #print(timeinseconds)

        seconds_title = {}
        cnt = 0
        cnt_finish = 0
        while self.startcronotipy:  #start counts
            cnt += 1
            try:  #try for when to delete the title at the time of counting
                for i, title in enumerate(get_titles):
                    time = cronotipy.time2seconds(
                        self,
                        self.title_and_time[title])  #calc time in seconds

                    if cnt == 1:  #get dictionary just in first iteration
                        seconds_title[time] = title

                    self.findChild(QProgressBar, get_titles[i]).setMaximum(
                        time)  #set max value of progbar
                    self.findChild(QProgressBar,
                                   get_titles[i]).setTextVisible(True)
                    self.findChild(QProgressBar, get_titles[i]).setValue(
                        cnt)  #change value of progbar
            except KeyError:
                #QUANDO DELETAMOS UM TITULO ENQUANTO A CONTAGEM TA ROLANDO DA ESSE KEYERROR
                #ESSE TRY RESOLVE ISSO, MAS PRECISO TIRAR ESSE TITULO DO DICIONARIO PARA NAO APARECER NOTIFICAÇÃO
                pass

            if cnt in seconds_title.keys():  #when cnt pass through time
                if self.isOnOff_Notify:
                    Notify.Notification.new(seconds_title[cnt],
                                            title_message[seconds_title[cnt]],
                                            path_logo).show()

                if self.isOnOff_Sound:
                    subprocess.run('play {} &'.format(path_sound_notify),
                                   shell=True)

                cnt_finish += 1

            elif cnt_finish == len(
                    seconds_title):  #when the last notify finish
                self.startcronotipy = False

                if self.isOnOff_Notify:
                    Notify.Notification.new('Done!',
                                            'All notifications are over.',
                                            path_logo).show()

            QTest.qWait(1000)
        #loop
        if self.isOnOff_loop:
            self.startcronotipy = True
            cronotipy.start(self)

    def stop(self):
        self.startcronotipy = False
        self.isOnOff_loop = False

    def renameActualize(self):
        #cronotipy.actualizeEditables(self)
        dialog = AddNotifiy()
        dialog.setWindowTitle('Titles Rename')
        dialog.setStyleSheet("background-color: rgba(84, 84, 84, 0.5);")
        state = dialog.exec_()

        time = [
            dialog.spinbox_hours.value(),
            dialog.spinbox_minutes.value(),
            dialog.spinbox_seconds.value()
        ]

        get_title = dialog.edit.text()  #get the typed
        #get_title = cronotipy._testTitle(self, title=get_title)

        if get_title == '' or state == 0:
            pass
        else:
            cronotipy.removeLines(self)
            self.listwd.addItem(get_title)  #add a item in QList "title - left"
            cronotipy.addText2ScrollBar(
                self,
                title=get_title)  #add a QLine in QScroll "message - right"
            cronotipy.addProgressbar2ScrollBar(
                self, title=get_title,
                time=time)  #add a QProgressBar in QSCROLL bot

            self.title_and_time[
                get_title] = time  #update title and time in dictionary

    def addLines(self):
        get = AddNotifiy()  #instancing dialog
        get.setWindowTitle('Add a notifier')
        get.setStyleSheet("background-color: rgba(84, 84, 84, 0.5);")
        state = get.exec_()  # show dialog

        #get time from spinboxes
        time = [
            get.spinbox_hours.value(),
            get.spinbox_minutes.value(),
            get.spinbox_seconds.value()
        ]
        get_title = get.edit.text()  #get the typed
        self.titles_typed.append(
            get_title)  #store titles to check equal titles

        get_title = cronotipy._testTitle(self, title=get_title)

        if get_title == '' or state == 0:
            pass
        else:
            self.listwd.addItem(get_title)  #add a item in QList "title - left"
            cronotipy.addText2ScrollBar(
                self,
                title=get_title)  #add a QLine in QScroll "message - right"
            cronotipy.addProgressbar2ScrollBar(
                self, title=get_title,
                time=time)  #add a QProgressBar in QSCROLL bot

            self.title_and_time[get_title] = time

    def removeLines(self):
        getselected = self.listwd.selectedItems()  #take the selected items

        for i in getselected:
            item2remove = self.listwd.takeItem(self.listwd.row(i)).text(
            )  #str, name of object selected is the same name of QLine ObjectName
            #child = self.findChild(QLineEdit, item2remove.text()).objectName() #this lines returns the objectName of QLine
            child = self.findChild(QLineEdit, item2remove).deleteLater(
            )  #remove the QLine with objectname "item2remove"
            self.findChild(QProgressBar, item2remove).deleteLater()
            self.findChild(QLabel, item2remove).deleteLater()
            try:  #this is for rename and next remove item
                self.titles_typed.remove(item2remove)
            except:
                pass
            self.title_and_time.pop(item2remove)

    def addText2ScrollBar(self, title):
        #Add QLine in TOP SCROLLBAR
        line = QLineEdit(self)
        line.setPlaceholderText('Type a message for {}'.format(title))
        line.setObjectName(title)

        self.vbox_top.addWidget(line)  #put line object inside vbox

    def addProgressbar2ScrollBar(self, title, time=[]):
        #Add progressbar in BOT SCROLLBAR
        progressbar = QProgressBar(self)
        progressbar.setObjectName(title)
        progressbar.setValue(100)
        progressbar.setTextVisible(False)
        progressbar.setStyleSheet(style_progbar)

        progresslabel = QLabel(
            title +
            '  ({:02d}:{:02d}:{:02d}):'.format(time[0], time[1], time[2]))
        progresslabel.setObjectName(title)

        self.vbox_bot.addRow(progresslabel, progressbar)

    def time2seconds(self, time=[]):
        hour2seconds = time[0] * 3600
        min2seconds = time[1] * 60
        seconds = time[2] * 1
        return hour2seconds + min2seconds + seconds

    def turnOnOffnotify(self):
        if self.cronotipy_ui.menu_Notify_On_Off.isChecked():
            self.isOnOff_Notify = True

        if not self.cronotipy_ui.menu_Notify_On_Off.isChecked():
            self.isOnOff_Notify = False

    def turnOnOffsound(self):
        if self.cronotipy_ui.menu_Sound_On_Off.isChecked():
            self.isOnOff_Sound = True

        if not self.cronotipy_ui.menu_Sound_On_Off.isChecked():
            self.isOnOff_Sound = False

    def turnOnOffloop(self):
        if self.cronotipy_ui.menu_Loop_On_Off.isChecked():
            self.isOnOff_loop = True

        if not self.cronotipy_ui.menu_Loop_On_Off.isChecked():
            self.isOnOff_loop = False

        print(self.cronotipy_ui.menu_Loop_On_Off.isChecked())

    def quitMenu(self):
        cronotipy.stop(self)
        self.close()

    def closeEvent(self, event):
        reply = QMessageBox.question(
            self, 'Closing Window',
            'Do you really want to close this application?',
            QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            cronotipy.stop(self)
            event.accept()

        else:
            event.ignore()

    def _testTitle(self, title):
        n_titles_contained = self.titles_typed.count(
            title)  #number of times that title appears

        if n_titles_contained == 1:
            return title
        elif title in self.titles_typed:
            self.titles_typed.append(title + '{}'.format(n_titles_contained))
            return title + '{}'.format(n_titles_contained)

    def openProfile(self):
        get_dir, _ = QFileDialog.getOpenFileName(
            self, 'Open Profile for Cronotipy', '',
            '(*.cnp) ;; all*')  #open dir/namefile as a string
        with open(get_dir, 'r') as fileopen:
            get_filetext = fileopen.readlines()
            #print(get_filetext)

            time = []
            for i in get_filetext:  #each iterations have the three information
                title_time_text = i.split('-')
                print(type(title_time_text[1]))
                for t in title_time_text[1].split(','):  #geting time
                    time.append(int(t.replace('[', '').replace(
                        ']', '')))  #formating time's list str to int and store

                cronotipy._addLinesFromOpen(
                    self, title_time_text[0], time,
                    title_time_text[2])  #Add this lines
                time = []

    def _addLinesFromOpen(self, title, times, text):
        #get time from spinboxes
        time = times
        get_title = title  #get the typed
        self.titles_typed.append(
            get_title)  #store titles to check equal titles

        get_title = cronotipy._testTitle(self, title=get_title)

        if get_title == '':
            pass
        else:
            self.listwd.addItem(get_title)  #add a item in QList "title - left"
            cronotipy.addText2ScrollBar(
                self,
                title=get_title)  #add a QLine in QScroll "message - right"
            self.findChild(QLineEdit, get_title).setText(text)
            cronotipy.addProgressbar2ScrollBar(
                self, title=get_title,
                time=time)  #add a QProgressBar in QSCROLL bot

            self.title_and_time[get_title] = time

    def saveProfile(self):
        get_dir, _ = QFileDialog.getSaveFileName(
            self, 'Save Profile', '')  #open a Dir with files name
        if get_dir.endswith('.cnp'):
            with open(get_dir, 'w') as filesave:
                for key, value in self.title_and_time.items():
                    get_text = self.findChild(QLineEdit, key).text()
                    filesave.write(
                        str(key) + '-' + str(value) + '-' + get_text + '\n')
        else:
            with open(get_dir + '.cnp', 'w') as filesave:
                for key, value in self.title_and_time.items():
                    get_text = self.findChild(QLineEdit, key).text()
                    filesave.write(
                        str(key) + '-' + str(value) + '-' + get_text + '\n')
Пример #38
0
class EditUsersWindow(QWidget):
    def __init__(self, userDetails):
        super().__init__()
        self.setGeometry(200, 50, 500, 500)
        self.setWindowTitle("Edit User")
        self.userDetails = userDetails
        self.layouts()
        self.widgets()

    def layouts(self):
        self.mainLayout = QVBoxLayout()
        self.topLayout = QVBoxLayout()
        self.middleLayout = QHBoxLayout()
        self.topLayout.setContentsMargins(20, 20, 20, 20)
        self.bottomLayout = QHBoxLayout()

        self.text = QLabel('')
        self.progeesBar = QProgressBar()
        self.progeesBar.setHidden(True)
        self.submitBtn = QPushButton("Submit")
        self.submitBtn.clicked.connect(self.submitAction)
        self.cancelBtn = QPushButton("Cancel")
        self.cancelBtn.clicked.connect(self.cancelAction)
        self.okBtn = QPushButton("Ok")
        self.okBtn.clicked.connect(self.okAction)
        self.okBtn.setHidden(True)
        self.submitBtn.setFixedHeight(30)
        self.cancelBtn.setFixedHeight(30)
        self.okBtn.setFixedHeight(30)
        self.submitBtn.setStyleSheet(
            "color: #ecf0f1; background-color: #27ae60 ; border: 0px")
        self.okBtn.setStyleSheet(
            "color: #ecf0f1; background-color: #27ae60 ; border: 0px")
        self.cancelBtn.setStyleSheet(
            "color: #ecf0f1; background-color: #e74c3c; border: 0px")

        self.bottomLayout.addWidget(self.submitBtn)
        self.bottomLayout.addWidget(self.cancelBtn)
        self.bottomLayout.addWidget(self.okBtn)
        self.mainLayout.addLayout(self.topLayout)
        self.mainLayout.addStretch()
        self.mainLayout.addLayout(self.bottomLayout)
        self.setLayout(self.mainLayout)

    def widgets(self):
        self.form = QFormLayout()

        print(self.userDetails)
        self.username = QLineEdit(self.userDetails[0])
        self.form.addRow(QLabel('Username :'******'User ID :'), self.id)

        self.primaryGroup = self.userDetails[2].split('(')[1].split(')')[0]
        self.priGroup = QLineEdit(self.primaryGroup)
        self.form.addRow(QLabel('Primary Group :'), self.priGroup)

        self.comment = QLineEdit(self.userDetails[4])
        self.form.addRow(QLabel('Comment :'), self.comment)
        self.homeDir = QLineEdit(self.userDetails[5])
        self.form.addRow(QLabel('Home Directory :'), self.homeDir)
        self.shell = QLineEdit(self.userDetails[6])
        self.form.addRow(QLabel('Shell :'), self.shell)

        if self.userDetails[7] == 'never':
            self.expirationDate = QLineEdit()
        else:
            import dateutil.parser as parser
            self.expirationDate_adapted = datetime.strptime(
                self.userDetails[7], '%b %d, %Y').strftime('%Y-%m-%d')
            date = parser.parse(self.expirationDate_adapted)
            self.expirationDate = QLineEdit(date.isoformat().split('T')[0])
        self.form.addRow(QLabel('Expiration Date :'), self.expirationDate)

        self.groupsBtns = QVBoxLayout()
        self.lineEditAddGroup = QLineEdit()
        self.lineEditAddGroup.setPlaceholderText('enter group name')
        self.addGroupBtn = QPushButton('Add')
        self.addGroupBtn.clicked.connect(self.addGroup)
        self.deleteGroupBtn = QPushButton('Delete')
        self.deleteGroupBtn.clicked.connect(self.deleteGroup)
        self.deleteAllGroupsBtn = QPushButton('Delete All')
        self.deleteAllGroupsBtn.clicked.connect(self.deleteAllGroups)
        self.groupsBtns.addWidget(self.lineEditAddGroup)
        self.groupsBtns.addWidget(self.addGroupBtn)
        self.groupsBtns.addWidget(self.deleteGroupBtn)
        self.groupsBtns.addWidget(self.deleteAllGroupsBtn)
        self.groupsBtns.addStretch()
        self.listGroups = QListWidget()

        self.form.addRow(QLabel('Groups :'), self.middleLayout)

        groups = self.userDetails[3].split(',')
        for group in groups:
            grp = group.split('(')[1].split(')')[0]
            if grp == self.primaryGroup:
                continue
            else:
                self.listGroups.addItem(grp)

        self.middleLayout.addWidget(self.listGroups)
        self.middleLayout.addLayout(self.groupsBtns)
        self.topLayout.addLayout(self.form)
        self.topLayout.addWidget(self.text)
        self.topLayout.addWidget(self.progeesBar)

    def addGroup(self):
        group = self.lineEditAddGroup.text()
        if group == "":
            pass
        else:
            self.listGroups.addItem(group)

    def deleteGroup(self):
        listGroups = self.listGroups.selectedItems()
        if not listGroups: return
        for group in listGroups:
            self.listGroups.takeItem(self.listGroups.row(group))

    def deleteAllGroups(self):
        self.listGroups.clear()

    def submitAction(self):
        try:
            self.setCursor(Qt.WaitCursor)
            self.progeesBar.setHidden(False)
            self.progeesBar.setMaximum(1)
            self.progeesBar.setValue(0)
            self.edituser()
        except subprocess.CalledProcessError:
            QMessageBox.warning(self, 'warning',
                                f"error occured during editing this user\n")
        else:
            self.setCursor(Qt.ArrowCursor)
            self.submitBtn.setHidden(True)
            self.cancelBtn.setHidden(True)
            self.okBtn.setHidden(False)

    def okAction(self):
        self.close()

    def edituser(self):
        usernamee = self.username.text()
        idd = self.id.text()
        priGroupp = self.priGroup.text()
        commentt = self.comment.text()
        homeDirr = self.homeDir.text()
        shelll = self.shell.text()
        expirationDatee = self.expirationDate.text()
        txt = ''

        groupsitems = []
        for index in range(self.listGroups.count()):
            groupsitems.append(str(self.listGroups.item(index).text()))
        groupsitemsstring = ",".join(groupsitems)
        print(groupsitemsstring)
        if expirationDatee == "never":
            QMessageBox.warning(self, 'expiration field error',
                                "expiration field can't be 'never' ")
            return 0
        elif expirationDatee == '':
            pass
        else:
            try:
                subprocess.run(
                    f'usermod -e {expirationDatee} {self.userDetails[0]}',
                    stdout=subprocess.DEVNULL,
                    stderr=subprocess.DEVNULL,
                    check=True,
                    shell=True)
            except subprocess.CalledProcessError:
                txt = txt + "error occured during editing expiration date for this user\n"
                self.text.setText(txt)
            else:
                txt = txt + "expiration date edited succesfully\n"
                self.text.setText(txt)
        try:
            subprocess.run(f'usermod -g {priGroupp} {self.userDetails[0]}',
                           stdout=subprocess.DEVNULL,
                           stderr=subprocess.DEVNULL,
                           check=True,
                           shell=True)
        except subprocess.CalledProcessError:
            txt = txt + "error occured during editing primary group for this user\n"
            self.text.setText(txt)
        else:
            txt = txt + "primary group edited succesfully\n"
            self.text.setText(txt)

        try:
            subprocess.run(
                f'usermod -G {groupsitemsstring} {self.userDetails[0]}',
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,
                check=True,
                shell=True)
        except subprocess.CalledProcessError:
            txt = txt + "error occured during editing supplementary groups for this user\n"
            self.text.setText(txt)
        else:
            txt = txt + "supplementary groups edited succesfully\n"
            self.text.setText(txt)

        try:
            subprocess.run(f'usermod -s {shelll} {self.userDetails[0]}',
                           stdout=subprocess.DEVNULL,
                           stderr=subprocess.DEVNULL,
                           check=True,
                           shell=True)
        except subprocess.CalledProcessError:
            txt = txt + "error occured during editing shell for this user\n"
            self.text.setText(txt)
        else:
            txt = txt + "shell edited succesfully\n"
            self.text.setText(txt)

        try:
            subprocess.run(f'usermod -d {homeDirr} {self.userDetails[0]}',
                           stdout=subprocess.DEVNULL,
                           stderr=subprocess.DEVNULL,
                           check=True,
                           shell=True)
        except subprocess.CalledProcessError:
            txt = txt + "error occured during editing home directory for this user\n"
            self.text.setText(txt)
        else:
            txt = txt + "home directory edited succesfully\n"
            self.text.setText(txt)

        try:
            subprocess.run(f"usermod -c '{commentt}' {self.userDetails[0]}",
                           stdout=subprocess.DEVNULL,
                           stderr=subprocess.DEVNULL,
                           check=True,
                           shell=True)
        except subprocess.CalledProcessError:
            txt = txt + "error occured during editing comment for this user\n"
            self.text.setText(txt)
        else:
            txt = txt + "comment edited succesfully\n"
            self.text.setText(txt)

        try:
            subprocess.run(f"usermod -u {idd} {self.userDetails[0]}",
                           stdout=subprocess.DEVNULL,
                           stderr=subprocess.DEVNULL,
                           check=True,
                           shell=True)
        except subprocess.CalledProcessError:
            txt = txt + "error occured during editing user id for this user\n"
            self.text.setText(txt)
        else:
            txt = txt + "user id edited succesfully\n"
            self.text.setText(txt)

        try:
            subprocess.run(f'usermod -l {usernamee} {self.userDetails[0]}',
                           stdout=subprocess.DEVNULL,
                           stderr=subprocess.DEVNULL,
                           check=True,
                           shell=True)
        except subprocess.CalledProcessError:
            txt = txt + "error occured during editing username for this user\n"
            self.text.setText(txt)
        else:
            txt = txt + "username edited succesfully\n"
            self.text.setText(txt)

        self.progeesBar.setValue(1)

    def cancelAction(self):
        self.close()
Пример #39
0
class ExtensionsSettingsPanel(SettingsPanel):
    def __init__(self, parent=None):
        super(ExtensionsSettingsPanel, self).__init__(parent)

        self.thread = ExtensionsUpdateThread(self)
        self.thread.finished.connect(self.notifyFinish)
        self.thread.finished.connect(self.loadSettings)

        # List row
        listRow = custom_widgets.Row(self)
        self.layout().addWidget(listRow)

        # Extensions whitelist.
        whitelistColumn = custom_widgets.Column(self)
        listRow.addWidget(whitelistColumn)
        whitelistColumn.addWidget(QLabel(tr("Enabled extensions:"), self))
        self.whitelist = QListWidget(self)
        self.whitelist.currentTextChanged.connect(self.changeAboutText)
        self.whitelist.itemActivated.connect(self.disableExtension)
        whitelistColumn.addWidget(self.whitelist)

        # Extensions blacklist.
        blacklistColumn = custom_widgets.Column(self)
        listRow.addWidget(blacklistColumn)
        blacklistColumn.addWidget(QLabel(tr("Disabled extensions:"), self))
        self.blacklist = QListWidget(self)
        self.blacklist.currentTextChanged.connect(self.changeAboutText)
        self.blacklist.itemActivated.connect(self.enableExtension)
        blacklistColumn.addWidget(self.blacklist)

        # About text
        self.aboutText = custom_widgets.ReadOnlyTextEdit(self)
        self.aboutText.setMaximumHeight(92)
        self.layout().addWidget(self.aboutText)

        updateExtensionsButton = QPushButton(tr("&Update extensions"), self)
        updateExtensionsButton.clicked.connect(self.updateExtensions)
        self.layout().addWidget(updateExtensionsButton)

    def changeAboutText(self, name):
        aboutpath = os.path.join(settings.extensions_folder, name, "about.txt")
        try: f = open(aboutpath, "r")
        except:
            self.aboutText.setText(tr("This extension has no description."))
            return
        aboutText = f.read().replace("\n", "")
        f.close()
        self.aboutText.setText(aboutText)

    def disableExtension(self, item):
        name = item.text()
        self.blacklist.addItem(name)
        self.blacklist.sortItems(Qt.AscendingOrder)
        self.whitelist.takeItem(self.whitelist.row(item))
        self.whitelist.sortItems(Qt.AscendingOrder)

    def enableExtension(self, item):
        name = item.text()
        self.whitelist.addItem(name)
        self.whitelist.sortItems(Qt.AscendingOrder)
        self.blacklist.takeItem(self.blacklist.row(item))
        self.blacklist.sortItems(Qt.AscendingOrder)

    def notifyFinish(self):
        common.trayIcon.showMessage(tr("Extensions updated"), tr("All extensions are up to date."))

    def updateExtensions(self):
        if not self.thread.isRunning():
            common.trayIcon.showMessage(tr("Updating extensions"), tr("This may take some time."))
            self.thread.start()
        else:
            common.trayIcon.dontBeImpatient()

    def loadSettings(self):
        settings.reload_extensions()
        self.whitelist.clear()
        for extension in settings.extensions_whitelist:
            self.whitelist.addItem(extension)
        self.blacklist.clear()
        for extension in settings.extensions_blacklist:
            self.blacklist.addItem(extension)
        self.whitelist.sortItems(Qt.AscendingOrder)
        self.blacklist.sortItems(Qt.AscendingOrder)

    def saveSettings(self):
        settings.settings.setValue("extensions/Whitelist", json.dumps([self.whitelist.item(extension).text() for extension in range(0, self.whitelist.count())]))
        settings.reload_extensions()
        settings.settings.sync()
Пример #40
0
class GstPipeEdit(QWidget):

    def __init__(self, pipe, app_mode=False, **kwargs):
        super().__init__(**kwargs)
        self.setLayout(QGridLayout())
        self.layout().setAlignment(Qt.AlignTop)

        self._app_mode = app_mode

        # Input selection
        self.inputBox = QComboBox(self)
        self.layout().addWidget(self.inputBox, 0, 0, 1, 3)
        self.__init_inputs()

        # Current plugins list
        self.currentList = QListWidget(self)
        self.currentList.setDragEnabled(True)
        self.currentList.setDragDropMode(QAbstractItemView.InternalMove)
        self.layout().addWidget(self.currentList, 1, 0)

        # Available plugins list
        self.availableList = QListWidget(self)
        self.layout().addWidget(self.availableList, 1, 2)

        # Output selection
        self.outputBox = QComboBox(self)
        self.layout().addWidget(self.outputBox, 4, 0, 1, 3)
        self.__init_outputs()

        # Add/Remove plugins buttons
        self.buttonsLayout = QVBoxLayout()
        self.layout().addLayout(self.buttonsLayout, 1, 1)
        self.layout().setAlignment(self.buttonsLayout, Qt.AlignHCenter)

        self.addButton = QPushButton(self)
        self.addButton.setIcon(QIcon.fromTheme('go-previous'))
        self.addButton.clicked.connect(self.__add_plugin)
        self.buttonsLayout.addWidget(self.addButton)
        self.buttonsLayout.setAlignment(self.addButton, Qt.AlignHCenter)

        self.delButton = QPushButton(self)
        self.delButton.setIcon(QIcon.fromTheme('go-next'))
        self.delButton.clicked.connect(self.__remove_plugin)
        self.buttonsLayout.addWidget(self.delButton)
        self.buttonsLayout.setAlignment(self.delButton, Qt.AlignHCenter)

        # Load the pipeline
        self.set_pipe(pipe)

    def set_pipe(self, pipe):
        if pipe:
            if not self._app_mode:
                inputs = sorted(elements.inputs())
                self.inputBox.setCurrentIndex(inputs.index(pipe[0]))

            outputs = sorted(elements.outputs())
            self.outputBox.setCurrentIndex(outputs.index(pipe[-1]))

        self.__init_current_plugins(pipe)
        self.__init_available_plugins(pipe)

    def get_pipe(self):
        pipe = [] if self._app_mode else [self.inputBox.currentText()]
        for n in range(self.currentList.count()):
            pipe.append(self.currentList.item(n).text())
        pipe.append(self.outputBox.currentText())

        return tuple(pipe)

    def __init_inputs(self):
        if self._app_mode:
            self.inputBox.setEnabled(False)
        else:
            inputs = sorted(elements.inputs())
            self.inputBox.addItems(inputs)
            self.inputBox.setEnabled(len(inputs) > 1)

    def __init_outputs(self):
        outputs = sorted(elements.outputs())
        self.outputBox.addItems(outputs)
        self.outputBox.setEnabled(len(outputs) > 1)

    def __init_current_plugins(self, pipe):
        self.currentList.clear()

        start = 0 if self._app_mode else 1
        for plugin in pipe[start:-1]:
            self.currentList.addItem(plugin)

    def __init_available_plugins(self, pipe):
        self.availableList.clear()

        for plugin in elements.plugins().values():
            if plugin.Name not in pipe:
                self.availableList.addItem(plugin.Name)

    def __add_plugin(self):
        item = self.availableList.takeItem(self.availableList.currentRow())
        self.currentList.addItem(item)

    def __remove_plugin(self):
        item = self.currentList.takeItem(self.currentList.currentRow())
        self.availableList.addItem(item)
Пример #41
0
class Form(QWidget):
    def __init__(self, parent=None):
        super(Form, self).__init__(parent)
 
        # Set up the first list (elements that can be used)
        elements = QListWidget()
        elements.viewport().setAcceptDrops(True)
        elements.setDragEnabled(True)
        elements.setDefaultDropAction(Qt.MoveAction)
        elements.setSelectionMode(QAbstractItemView.ExtendedSelection)
        elements.addItem(u"Last Name")
        elements.addItem(u"First Name")
        elements.addItem(u"Middle Initial")
        elements.addItem(u"Full Name")
        elements.addItem(u"DMIS ID")
        elements.addItem(u"SPIN Number")
        elements.addItem(u"SSN Prefix")
        elements.addItem(u"Social Security Number")
        elements.addItem(u"Date of Birth")
        elements.addItem(u"Gender")
        elements.addItem(u"Accession")
        elements.addItem(u"Isolation Date")
        elements.addItem(u"Culture Type")
        elements.addItem(u"Source")
        elements.addItem(u"Location Type")
        elements.addItem(u"Location")
        elements.addItem(u"Isolate Number")
        elements.addItem(u"Organism Name")
        elements.addItem(u"Alternate Organism Name")
        elements.addItem(u"Equipment")
        elements.addItem(u"Drug Info")
        elements.addItem(u"ESBL")
        elements.addItem(u"AMPC")


        # Set up the second list (elements to generate a config file from)
        self.selected_elements = QListWidget()
        self.selected_elements.viewport().setAcceptDrops(True)
        self.selected_elements.setDragEnabled(True)
        self.selected_elements.setDefaultDropAction(Qt.MoveAction)
        self.selected_elements.setSelectionMode(QAbstractItemView.ExtendedSelection)

        ok_button = QPushButton(u"OK")
        cancel_button = QPushButton(u"Cancel")
        about_button = QPushButton(u"About")
        insert_blank_line_button = QPushButton(u"Insert blank line")
        drug_validator = QIntValidator(1, 999)
        self.drugs = QLineEdit("1")
        self.drugs.setValidator(drug_validator)
        drugs_label = QLabel("Number of drugs per line")
        self.drugformat = QLineEdit("MIC,Call")
        drugformat_label = QLabel("Format of the drug information")
        self.date = QLineEdit("MM/dd/yyyy")
        date_label = QLabel("Date format")
        self.machine = QLineEdit("Machine name")
        machine_label = QLabel("Machine the file is from")
        buttons = QHBoxLayout()

        ok_button.clicked.connect(self.export_parser)
        cancel_button.clicked.connect(self.close_program)
        about_button.clicked.connect(self.about)
        insert_blank_line_button.clicked.connect(self.insert_blank_line)
        self.drugs.setMaxLength(3)

        buttons.addWidget(ok_button)
        buttons.addWidget(cancel_button)
        buttons.addWidget(about_button)
        buttons.addWidget(insert_blank_line_button)
 
        mainLayout = QGridLayout()
        mainLayout.addWidget(elements, 0, 0)
        mainLayout.addWidget(self.selected_elements, 0, 1)
        mainLayout.addLayout(buttons, 1, 0)
        mainLayout.addWidget(self.drugs, 2, 0)
        mainLayout.addWidget(drugs_label, 2, 1)
        mainLayout.addWidget(self.drugformat, 3, 0)
        mainLayout.addWidget(drugformat_label, 3, 1)
        mainLayout.addWidget(self.date, 4, 0)
        mainLayout.addWidget(date_label, 4, 1)
        mainLayout.addWidget(self.machine, 5, 0)
        mainLayout.addWidget(machine_label, 5, 1)
 
        self.setLayout(mainLayout)
        self.setWindowTitle(u"RevealerParserWizard")
        
    def export_parser(self):
        u'''
        Extract the text of the elements in selected_elements, then pass them
        to write_output so they can be fully converted and written to a parser
        file.
        '''
        extracted_elements = []
        element_num = self.selected_elements.count()
        if element_num < 1:
            no_entries = QMessageBox()
            no_entries.setIcon(QMessageBox.Warning)
            no_entries.setText(u"No elements selected!")
            no_entries.exec_()
            return
        for i in xrange(0, element_num):
            extracted_elements.append(self.selected_elements.item(i).text() + 1)
        
        # Act like a clown and get knocked down
        if int(self.drugs.text()) < 1:
            too_small = QMessageBox()
            too_small.setIcon(QMessageBox.Warning)
            too_small.setText(u"'Drugs per line' must be between 1 and 999")
            too_small.exec_()
            return
        else:
            extracted_elements.append("Drugs per line" + '\t' + self.drugs.text())
            
        if (len(self.drugformat.text()) < 1):
            too_small = QMessageBox()
            too_small.setIcon(QMessageBox.Warning)
            too_small.setText(u"'Drug Info Format' must not be empty")
            too_small.exec_()
            return
        else:
            extracted_elements.append("Drug Info Format" + '\t' + self.drugformat.text())

        extracted_elements.append("Date Format" + '\t' + self.date.text())
            
        
        if os.path.isfile(u"my_parser.txt"):
            output_exists = QMessageBox()
            output_exists.setIcon(QMessageBox.Warning)
            output_exists.setText(u"my_parser.txt already exists! Overwrite?")
            output_exists.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            overwrite = output_exists.exec_()
            if overwrite == QMessageBox.Yes:
                with open(u"my_parser.txt", u'w') as output:
                    self.write_output(output, extracted_elements)
                    return
            else:
                sys.exit()
        else:
            with open(u"my_parser.txt", u'w') as output:
                self.write_output(output, extracted_elements)
                return
            
    def write_output(self, output, elements):
        u'''
        Given a List of strings, convert them into an MDRevealer custom parser
        file and write them to my_parser.txt.
        '''
        i = 0
        for e in elements:
            if not "Drugs per" in e:
                output.write(e + u'\t' + unicode(i) + u'\n')
            else:
                output.write(e + u'\n')
            i += 1
        success = QMessageBox()
        success.setText(u"my_parser.txt written successfully.")
        success.exec_()
        sys.exit()
                
    
    def close_program(self):
        u'''
        Close the program.
        '''
        sys.exit()
        
    def about(self):
        u'''
        Provide information about the program in a QMessageBox.
        '''
        QMessageBox.information(self, u"About RevealerParserWizard", u"RevealerParserWizard 1.0b" +
         "\n" + u"A program to generate custom parser files for MDRevealer" + "\n" +
         u"Copyright (C) 2015 Sean Clifford" + "\n" + "Available under GPLv3+")
        
        
    def insert_blank_line(self):
        u'''
        Adds a blank line to selected_elements, for handling fields in the file
        to parse that Revealer doesn't read.
        '''
        self.selected_elements.addItem(u"(skip)")
Пример #42
0
class HeaderEditDialog(QDialog):

    # name of the current preset, whether to set this preset as default, list of Columns
    header_changed = pyqtSignal(str, bool, list)

    def __init__(self, parent, table_header):
        super().__init__(parent)

        self.table_header = table_header
        self.default_preset_name = None
        self.preset_name = table_header.preset_name
        self.columns = copy.deepcopy(table_header.columns)
        self.setupUi()

    def setupUi(self):
        self.resize(200, 400)
        self.vbox = QVBoxLayout(self)
        self.presetLabel = QLabel("Preset: {}".format(self.preset_name), self)
        self.columnList = QListWidget(self)
        self.setAsDefaultCheckbox = QCheckBox("Set as default preset", self)
        self.vbox.addWidget(self.presetLabel)
        self.vbox.addWidget(self.columnList)
        self.vbox.addWidget(self.setAsDefaultCheckbox)

        self.columnList.setDragDropMode(QListWidget.InternalMove)
        self.columnList.setDefaultDropAction(Qt.MoveAction)
        self.columnList.setSelectionMode(QListWidget.ExtendedSelection)
        self.columnList.setAlternatingRowColors(True)
        self.columnList.installEventFilter(self)
        self.columnList.setContextMenuPolicy(Qt.CustomContextMenu)
        self.columnList.customContextMenuRequested.connect(self.open_menu)
        self.columnList.model().rowsMoved.connect(self.read_columns_from_list)

        # for a dumb qss hack to make selected checkboxes not white on a light theme
        self.columnList.setObjectName("ColumnList")

        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Cancel, self)
        self.vbox.addWidget(self.buttonBox)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        self.fill_column_list()
        self.set_default_checkbox()

    def eventFilter(self, object, event):
        if event.type() == QEvent.KeyPress:
            if event.key() == Qt.Key_Space or event.key() == Qt.Key_Return:
                self.toggle_selected_columns()
                return True
        return False

    def fill_column_list(self):
        self.columnList.clear()
        for column in self.columns:
            ColumnListItem(self.columnList, column)

    def accept(self):
        self.read_columns_from_list()
        self.header_changed.emit(self.preset_name,
                                 self.setAsDefaultCheckbox.isChecked(),
                                 self.columns)
        self.done(0)

    def reject(self):
        self.done(0)

    def read_columns_from_list(self):
        new_columns = []
        for i in range(self.columnList.count()):
            item = self.columnList.item(i)
            new_columns.append(item.column)
        self.columns = new_columns

    def toggle_selected_columns(self):
        selected = self.columnList.selectedItems()
        for item in selected:
            value_now = item.data(Qt.CheckStateRole)
            item.setData(Qt.CheckStateRole, not value_now)
        self.columnList.reset()  # @Improvement: is there a better way to update QListWidget?

    def open_menu(self, position):
        menu = QMenu(self)

        preset_menu = menu.addMenu('Presets')
        preset_menu.addAction('New preset', self.new_preset_dialog)
        preset_menu.addSeparator()

        preset_names = CONFIG.get_header_presets()

        if len(preset_names) == 0:
            action = preset_menu.addAction('No presets')
            action.setEnabled(False)
        else:
            delete_menu = menu.addMenu('Delete preset')
            for name in preset_names:
                preset_menu.addAction(name, partial(self.load_preset, name))
                delete_menu.addAction(name, partial(self.delete_preset, name))

        menu.addSeparator()
        menu.addAction('New column...', self.create_new_column_dialog)

        if len(self.columnList.selectedIndexes()) > 0:
            menu.addAction('Delete selected', self.delete_selected)

        menu.popup(self.columnList.viewport().mapToGlobal(position))

    def load_preset(self, name):
        new_columns = CONFIG.load_header_preset(name)
        if not new_columns:
            return

        self.columns = new_columns
        self.preset_name = name
        self.fill_column_list()
        self.presetLabel.setText("Preset: {}".format(name))
        self.set_default_checkbox()

    def new_preset_dialog(self):
        d = QInputDialog(self)
        d.setLabelText('Enter the new name for the new preset:')
        d.setWindowTitle('Create new preset')
        d.textValueSelected.connect(self.create_new_preset)
        d.open()

    def create_new_preset(self, name):
        if name in CONFIG.get_header_presets():
            show_warning_dialog(self, "Preset creation error",
                                'Preset named "{}" already exists.'.format(name))
            return
        if len(name.strip()) == 0:
            show_warning_dialog(self, "Preset creation error",
                                'This preset name is not allowed.'.format(name))
            return

        self.preset_name = name
        self.presetLabel.setText("Preset: {}".format(name))
        CONFIG.save_header_preset(name, self.columns)
        self.setAsDefaultCheckbox.setChecked(False)

    def delete_preset(self, name):
        CONFIG.delete_header_preset(name)
        if name == self.preset_name:
            self.columns = copy.deepcopy(DEFAULT_COLUMNS)
            self.fill_column_list()

    def create_new_column_dialog(self):
        d = CreateNewColumnDialog(self)
        d.add_new_column.connect(self.add_new_column)
        d.setWindowTitle('Create new column')
        d.open()

    def add_new_column(self, name, title):
        new_column = Column(name, title)
        # if the last column is message, insert this column before it (i think it makes sense?)
        if self.columns[-1].name == 'message':
            self.columns.insert(-1, new_column)
        else:
            self.columns.append(new_column)
        self.fill_column_list()

    def set_default_checkbox(self):
        self.setAsDefaultCheckbox.setChecked(CONFIG['default_header_preset'] == self.preset_name)

    def delete_selected(self):
        selected = self.columnList.selectedItems()
        for item in selected:
            self.columnList.takeItem(self.columnList.row(item))
        self.read_columns_from_list()
        self.fill_column_list()
Пример #43
0
class StringListDlg(QDialog):

    def __init__(self, name, stringlist=None, parent=None):
        super(StringListDlg, self).__init__(parent)

        self.name = name

        self.listWidget = QListWidget()
        if stringlist is not None:
            self.listWidget.addItems(stringlist)
            self.listWidget.setCurrentRow(0)
        buttonLayout = QVBoxLayout()
        for text, slot in (("&Add...", self.add),
                           ("&Edit...", self.edit),
                           ("&Remove...", self.remove),
                           ("&Up", self.up),
                           ("&Down", self.down),
                           ("&Sort", self.listWidget.sortItems),
                           ("Close", self.accept)):
            button = QPushButton(text)
            if not MAC:
                button.setFocusPolicy(Qt.NoFocus)
            if text == "Close":
                buttonLayout.addStretch()
            buttonLayout.addWidget(button)
            button.clicked.connect(slot)
#            self.connect(button, SIGNAL("clicked()"), slot)
        layout = QHBoxLayout()
        layout.addWidget(self.listWidget)
        layout.addLayout(buttonLayout)
        self.setLayout(layout)
        self.setWindowTitle("Edit {0} List".format(self.name))


    def add(self):
        row = self.listWidget.currentRow()
        title = "Add {0}".format(self.name)
        string, ok = QInputDialog.getText(self, title, title)
        if ok and string is not None:
            self.listWidget.insertItem(row, string)


    def edit(self):
        row = self.listWidget.currentRow()
        item = self.listWidget.item(row)
        if item is not None:
            title = "Edit {0}".format(self.name)
            string, ok = QInputDialog.getText(self, title, title,
                    QLineEdit.Normal, item.text())
            if ok and string is not None:
                item.setText(string)


    def remove(self):
        row = self.listWidget.currentRow()
        item = self.listWidget.item(row)
        if item is None:
            return
        reply = QMessageBox.question(self, "Remove {0}".format(
                self.name), "Remove {0} `{1}'?".format(
                self.name, unicode(item.text())),
                QMessageBox.Yes|QMessageBox.No)
        if reply == QMessageBox.Yes:
            item = self.listWidget.takeItem(row)
            del item


    def up(self):
        row = self.listWidget.currentRow()
        if row >= 1:
            item = self.listWidget.takeItem(row)
            self.listWidget.insertItem(row - 1, item)
            self.listWidget.setCurrentItem(item)


    def down(self):
        row = self.listWidget.currentRow()
        if row < self.listWidget.count() - 1:
            item = self.listWidget.takeItem(row)
            self.listWidget.insertItem(row + 1, item)
            self.listWidget.setCurrentItem(item)


    def reject(self):
        self.accept()


    def accept(self):
        self.stringlist = QStringListModel().stringList()
        for row in range(self.listWidget.count()):
            self.stringlist.append(self.listWidget.item(row).text())
        #self.stringlist.acceptedList.emit(self.stringlist)
        QDialog.accept(self)
Пример #44
0
class SubwindowMisc(QWidget):
    """Show subwindow with miscellaneous settings."""
    def createWindow(self, mainWindow, tab=''):
        """Create subwindow with miscellaneous settings."""
        try:
            parent = None
            super().__init__(parent)
            # self.setWindowFlags(Qt.WindowStaysOnTopHint)

            self.setWindowIcon(
                QIcon(scctool.settings.getResFile('settings.png')))
            self.setWindowModality(Qt.ApplicationModal)
            self.mainWindow = mainWindow
            self.passEvent = False
            self.controller = mainWindow.controller
            self.__dataChanged = False

            self.createButtonGroup()
            self.createTabs(tab)

            mainLayout = QVBoxLayout()

            mainLayout.addWidget(self.tabs)
            mainLayout.addLayout(self.buttonGroup)

            self.setLayout(mainLayout)

            self.resize(
                QSize(mainWindow.size().width() * .80,
                      self.sizeHint().height()))
            relativeChange = QPoint(mainWindow.size().width() / 2,
                                    mainWindow.size().height() / 3)\
                - QPoint(self.size().width() / 2,
                         self.size().height() / 3)
            self.move(mainWindow.pos() + relativeChange)

            self.setWindowTitle(_("Miscellaneous Settings"))

        except Exception as e:
            module_logger.exception("message")

    def createTabs(self, tab=''):
        """Create tabs."""
        self.tabs = QTabWidget()

        self.createMapsBox()
        self.createFavBox()
        self.createAliasBox()
        self.createOcrBox()
        self.createAlphaBox()

        # Add tabs
        self.tabs.addTab(self.mapsBox, _("Map Manager"))
        self.tabs.addTab(self.favBox, _("Favorites"))
        self.tabs.addTab(self.aliasBox, _("Alias"))
        self.tabs.addTab(self.ocrBox, _("OCR"))
        self.tabs.addTab(self.alphaBox, _("AlphaTL && Ingame Score"))

        table = dict()
        table['mapmanager'] = 0
        table['favorites'] = 1
        table['alias'] = 2
        table['ocr'] = 3
        table['alphatl'] = 4
        self.tabs.setCurrentIndex(table.get(tab, -1))

    def changed(self):
        """Handle changes."""
        self.__dataChanged = True

    def createAlphaBox(self):
        """Create Alpha QWidget."""
        self.alphaBox = QWidget()
        mainLayout = QVBoxLayout()

        box = QGroupBox(_("AlphaTL"))
        layout = QHBoxLayout()

        self.cb_trans_banner = QCheckBox(
            " " + _("Download transparent Banner of the Match"))
        self.cb_trans_banner.setChecked(
            scctool.settings.config.parser.getboolean(
                "SCT", "transparent_match_banner"))
        self.cb_trans_banner.stateChanged.connect(self.changed)

        layout.addWidget(self.cb_trans_banner)
        box.setLayout(layout)

        mainLayout.addWidget(box)

        box = QGroupBox(_("Set Ingame Score Task"))
        layout = QVBoxLayout()

        self.cb_ctrlx = QCheckBox(" " +
                                  _('Automatically press Ctrl+X to apply the'
                                    ' correct player order ingame'))
        self.cb_ctrlx.setToolTip(
            _("This will ensure that the player of the first team is always"
              " on the left/top in the ingame Observer UI."))
        self.cb_ctrlx.setChecked(
            scctool.settings.config.parser.getboolean("SCT", "CtrlX"))
        self.cb_ctrlx.stateChanged.connect(self.changed)
        layout.addWidget(self.cb_ctrlx)

        self.cb_ctrln = QCheckBox(" " + _('Automatically press Ctrl+N before'
                                          ' OCR to display player names'))
        self.cb_ctrln.setToolTip(
            _("This is recommended for Standard and Gawliq Observer UI."))
        self.cb_ctrln.setChecked(
            scctool.settings.config.parser.getboolean("SCT", "CtrlN"))
        self.cb_ctrln.stateChanged.connect(self.changed)
        layout.addWidget(self.cb_ctrln)

        self.cb_ctrlshifts = QCheckBox(
            " " + _('Automatically press Ctrl+Shift+S to display'
                    ' the ingame score'))
        self.cb_ctrlshifts.setToolTip(
            _("Ctrl+Shift+S is needed for the WCS-Gameheart Oberserver"
              " Overlay, but disables the sound for other overlays."))
        self.cb_ctrlshifts.setChecked(
            scctool.settings.config.parser.getboolean("SCT", "CtrlShiftS"))
        self.cb_ctrlshifts.stateChanged.connect(self.changed)
        layout.addWidget(self.cb_ctrlshifts)

        self.cb_ctrlshiftc = QCheckBox(
            " " + _('Automatically press Ctrl+Shift+C to toogle the clan tag'))
        self.cb_ctrlshiftc.setChecked(
            scctool.settings.config.parser.getboolean("SCT", "CtrlShiftC"))
        self.cb_ctrlshiftc.stateChanged.connect(self.changed)
        layout.addWidget(self.cb_ctrlshiftc)

        container = QHBoxLayout()
        self.cb_ctrlshiftr = QComboBox()
        self.cb_ctrlshiftr.addItem("0")
        self.cb_ctrlshiftr.addItem("1")
        self.cb_ctrlshiftr.addItem("2")
        try:
            self.cb_ctrlshiftr.setCurrentIndex(
                scctool.settings.config.parser.getint("SCT", "CtrlShiftR"))
        except Exception:
            self.cb_ctrlshiftr.setCurrentIndex(0)
        self.cb_ctrlshiftr.setMaximumWidth(40)
        self.cb_ctrlshiftr.currentIndexChanged.connect(self.changed)
        container.addWidget(
            QLabel(
                _('Automatically press Ctrl+Shift+R to toogle the race icon '))
        )
        container.addWidget(self.cb_ctrlshiftr)
        container.addWidget(QLabel(_(' time(s)')))
        layout.addLayout(container)

        self.cb_blacklist = QCheckBox(" " + _('Activate Blacklist for'
                                              ' Ingame Score'))
        self.cb_blacklist.setChecked(
            scctool.settings.config.parser.getboolean("SCT", "blacklist_on"))
        self.cb_blacklist.stateChanged.connect(self.changed)
        layout.addWidget(self.cb_blacklist)

        box.setLayout(layout)

        mainLayout.addWidget(box)

        box = QGroupBox(_("Blacklist for Ingame Score"))
        layout = QVBoxLayout()

        blacklistDesc = _("Enter your SC2 client usernames to deactivate"
                          " automatically setting the ingame score and"
                          " toogling the production tab when you are playing"
                          " yourself. Replays are exempt.")
        label = QLabel(blacklistDesc)
        label.setAlignment(Qt.AlignJustify)
        label.setWordWrap(True)
        layout.addWidget(label)

        self.list_blacklist = ListTable(4,
                                        scctool.settings.config.getBlacklist())
        self.list_blacklist.dataModified.connect(self.changed)
        self.list_blacklist.setFixedHeight(50)
        layout.addWidget(self.list_blacklist)
        box.setLayout(layout)

        mainLayout.addWidget(box)

        mainLayout.addItem(
            QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding))

        self.alphaBox.setLayout(mainLayout)

    def createFavBox(self):
        """Create favorites box."""
        self.favBox = QWidget()
        mainLayout = QVBoxLayout()

        box = QGroupBox(_("Players"))
        layout = QHBoxLayout()

        self.list_favPlayers = ListTable(
            4, scctool.settings.config.getMyPlayers())
        self.list_favPlayers.dataModified.connect(self.changed)
        self.list_favPlayers.setFixedHeight(150)
        layout.addWidget(self.list_favPlayers)
        box.setLayout(layout)

        mainLayout.addWidget(box)

        box = QGroupBox(_("Teams"))
        layout = QVBoxLayout()

        self.list_favTeams = ListTable(3, scctool.settings.config.getMyTeams())
        self.list_favTeams.dataModified.connect(self.changed)
        self.list_favTeams.setFixedHeight(100)
        layout.addWidget(self.list_favTeams)
        self.cb_swapTeams = QCheckBox(
            _('Swap my favorite team always to the left'))
        self.cb_swapTeams.setChecked(
            scctool.settings.config.parser.getboolean("SCT", "swap_myteam"))
        self.cb_swapTeams.stateChanged.connect(self.changed)
        layout.addWidget(self.cb_swapTeams)
        box.setLayout(layout)
        mainLayout.addWidget(box)

        mainLayout.addItem(
            QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding))

        self.favBox.setLayout(mainLayout)

    def createAliasBox(self):
        """Create favorites box."""
        self.aliasBox = QWidget()
        mainLayout = QGridLayout()

        aliasDesc = _(
            'Player and team aliases are replaced by the actual name when' +
            ' encountered by the match grabber. Additionally, SC2 player' +
            ' names listed as aliases are replaced in the intros' +
            ' and used to identify players by the automatic' +
            ' background tasks "Auto Score Update" and "Set Ingame Score".')
        label = QLabel(aliasDesc)
        label.setAlignment(Qt.AlignJustify)
        label.setWordWrap(True)

        mainLayout.addWidget(label, 1, 0, 1, 2)

        box = QGroupBox(_("Player Aliases"))
        layout = QVBoxLayout()
        self.list_aliasPlayers = AliasTreeView(self)
        self.list_aliasPlayers.aliasRemoved.connect(
            self.controller.aliasManager.removePlayerAlias)
        layout.addWidget(self.list_aliasPlayers)
        addButton = QPushButton(_("Add Alias"))
        addButton.clicked.connect(
            lambda: self.addAlias(self.list_aliasPlayers, _('Player Name')))
        layout.addWidget(addButton)
        box.setLayout(layout)
        mainLayout.addWidget(box, 0, 0)

        box = QGroupBox(_("Team Aliases"))
        layout = QVBoxLayout()
        self.list_aliasTeams = AliasTreeView(self)
        self.list_aliasTeams.aliasRemoved.connect(
            self.controller.aliasManager.removeTeamAlias)
        layout.addWidget(self.list_aliasTeams)
        addButton = QPushButton(_("Add Alias"))
        addButton.clicked.connect(
            lambda: self.addAlias(self.list_aliasTeams, _('Team Name')))
        layout.addWidget(addButton)
        box.setLayout(layout)
        mainLayout.addWidget(box, 0, 1)

        list = self.controller.aliasManager.playerAliasList()
        for player, aliases in list.items():
            self.list_aliasPlayers.insertAliasList(player, aliases)

        list = self.controller.aliasManager.teamAliasList()
        for team, aliases in list.items():
            self.list_aliasTeams.insertAliasList(team, aliases)

        self.aliasBox.setLayout(mainLayout)

    def addAlias(self, widget, scope, name=""):

        name, ok = QInputDialog.getText(self, scope, scope + ':', text=name)
        if not ok:
            return

        name = name.strip()
        alias, ok = QInputDialog.getText(self,
                                         _('Alias'),
                                         _('Alias of {}').format(name) + ':',
                                         text="")

        alias = alias.strip()
        if not ok:
            return

        try:
            if widget == self.list_aliasPlayers:
                self.controller.aliasManager.addPlayerAlias(name, alias)
            elif widget == self.list_aliasTeams:
                self.controller.aliasManager.addTeamAlias(name, alias)
            widget.insertAlias(name, alias, True)
        except Exception as e:
            module_logger.exception("message")
            QMessageBox.critical(self, _("Error"), str(e))

    def createOcrBox(self):
        """Create forms for OCR."""
        self.ocrBox = QWidget()

        mainLayout = QVBoxLayout()

        box = QGroupBox(
            _("Optical Character Recognition for"
              " Automatic Setting of Ingame Score"))

        layout = QGridLayout()

        self.cb_useocr = QCheckBox(" " +
                                   _("Activate Optical Character Recognition"))
        self.cb_useocr.setChecked(
            scctool.settings.config.parser.getboolean("SCT", "use_ocr"))
        self.cb_useocr.stateChanged.connect(self.changed)

        self.tesseract = MonitoredLineEdit()
        self.tesseract.setText(
            scctool.settings.config.parser.get("SCT", "tesseract"))
        self.tesseract.textModified.connect(self.changed)
        # self.tesseract.setAlignment(Qt.AlignCenter)
        self.tesseract.setPlaceholderText(
            "C:\\Program Files (x86)\\Tesseract-OCR\\tesseract")
        self.tesseract.setReadOnly(True)
        self.tesseract.setToolTip(_('Tesseract-OCR Executable'))

        self.browse = QPushButton(_("Browse..."))
        self.browse.clicked.connect(self.selectTesseract)

        text = _(
            "Sometimes the order of players given by the SC2-Client-API"
            " differs from the order in the Observer-UI resulting in a"
            " swapped match score. To correct this via Optical Character"
            " Recognition you have to download {} and install and select the"
            " exectuable below, if it is not detected automatically.")
        url = 'https://github.com/UB-Mannheim/tesseract' + \
            '/wiki#tesseract-at-ub-mannheim'
        href = "<a href='{}'>" + "Tesseract-OCR" + "</a>"
        href = href.format(url)

        label = QLabel(text.format(href))
        label.setAlignment(Qt.AlignJustify)
        label.setOpenExternalLinks(True)
        label.setWordWrap(True)
        label.setMargin(5)
        layout.addWidget(label, 1, 0, 1, 2)

        layout.addWidget(self.cb_useocr, 0, 0, 1, 2)
        layout.addWidget(QLabel(_("Tesseract-OCR Executable") + ":"), 2, 0)
        layout.addWidget(self.tesseract, 3, 0)
        layout.addWidget(self.browse, 3, 1)

        box.setLayout(layout)
        mainLayout.addWidget(box)
        mainLayout.addItem(
            QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding))
        self.ocrBox.setLayout(mainLayout)

        if (not scctool.settings.windows):
            self.cb_useocr.setEnabled(False)
            self.cb_useocr.setAttribute(Qt.WA_AlwaysShowToolTips)
            self.cb_useocr.setToolTip(
                _("This feature is only available in Windows."))
            self.tesseract.setEnabled(False)
            self.tesseract.setAttribute(Qt.WA_AlwaysShowToolTips)
            self.tesseract.setToolTip(
                _("This feature is only available in Windows."))
            self.browse.setEnabled(False)
            self.browse.setAttribute(Qt.WA_AlwaysShowToolTips)
            self.browse.setToolTip(
                _("This feature is only available in Windows."))

    def selectTesseract(self):
        """Create forms for tesseract."""
        old_exe = self.tesseract.text()
        default = scctool.settings.config.findTesserAct(old_exe)
        exe, ok = QFileDialog.getOpenFileName(
            self, _("Select Tesseract-OCR Executable"), default,
            _("Tesseract-OCR Executable") + " (tesseract.exe);; " +
            _("Executable") + " (*.exe);; " + _("All files") + " (*)")
        if (ok and exe != old_exe):
            self.tesseract.setText(exe)
            self.changed()

    def createMapsBox(self):
        """Create box for map manager."""
        self.mapsize = 300

        self.mapsBox = QWidget()

        layout = QGridLayout()

        self.maplist = QListWidget()
        self.maplist.setSortingEnabled(True)
        for map in scctool.settings.maps:
            self.maplist.addItem(QListWidgetItem(map))
        self.maplist.setCurrentItem(self.maplist.item(0))
        self.maplist.currentItemChanged.connect(self.changePreview)
        # self.maplist.setFixedHeight(self.mapsize)
        self.maplist.setMinimumWidth(150)

        layout.addWidget(self.maplist, 0, 1, 2, 1)
        self.mapPreview = QLabel()
        self.mapPreview.setFixedWidth(self.mapsize)
        self.mapPreview.setFixedHeight(self.mapsize)
        self.mapPreview.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.mapPreview, 0, 0)
        self.mapInfo = QLabel()
        self.mapInfo.setIndent(10)
        layout.addWidget(self.mapInfo, 1, 0)

        self.pb_addMapLiquipedia = QPushButton(_("Add from Liquipedia"))
        self.pb_addMapLiquipedia.clicked.connect(self.addFromLquipedia)
        self.pb_addMap = QPushButton(_("Add from File"))
        self.pb_addMap.clicked.connect(self.addMap)
        self.pb_renameMap = QPushButton(_("Rename"))
        self.pb_renameMap.clicked.connect(self.renameMap)
        self.pb_changeMap = QPushButton(_("Change Image"))
        self.pb_changeMap.clicked.connect(self.changeMap)
        self.pb_removeMap = QPushButton(_("Remove"))
        self.pb_removeMap.clicked.connect(self.deleteMap)

        self.sc_removeMap = QShortcut(QKeySequence("Del"), self)
        self.sc_removeMap.setAutoRepeat(False)
        self.sc_removeMap.activated.connect(self.deleteMap)

        box = QWidget()
        container = QHBoxLayout()

        container.addWidget(self.pb_addMapLiquipedia, 0)
        container.addWidget(self.pb_addMap, 0)
        container.addWidget(QLabel(), 4)
        container.addWidget(self.pb_renameMap, 0)
        container.addWidget(self.pb_changeMap, 0)
        container.addWidget(self.pb_removeMap, 0)
        box.setLayout(container)

        layout.addWidget(box, 2, 0, 1, 2)

        layout.addItem(
            QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding), 3,
            0, 1, 2)

        self.changePreview()
        self.mapsBox.setLayout(layout)

    def renameMap(self):
        """Rename maps."""
        item = self.maplist.currentItem()
        map = item.text()
        text, ok = QInputDialog.getText(self,
                                        _('Map Name'),
                                        _('Map Name') + ':',
                                        text=map)
        if not ok:
            return
        text = text.strip()
        if (text == map):
            return
        if text.lower() == 'tbd':
            QMessageBox.critical(
                self, _("Error"),
                _('"{}" is not a valid map name.').format(text))
            return
        if (text in scctool.settings.maps):
            buttonReply = QMessageBox.warning(
                self, _("Duplicate Entry"),
                _("Map is already in list! Overwrite?"),
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
            if buttonReply == QMessageBox.No:
                return

        self.controller.addMap(self.controller.getMapImg(map, True), text)
        self.controller.deleteMap(map)
        item.setText(text)

    def changeMap(self):
        """Change a map."""
        map = self.maplist.currentItem().text()
        fileName, ok = QFileDialog.getOpenFileName(
            self, _("Select Map Image (> 500x500px recommended)"), "",
            _("Supported Images") + " (*.png *.jpg)")
        if ok:
            base = os.path.basename(fileName)
            name, ext = os.path.splitext(base)
            name = name.replace("_", " ")
            self.controller.deleteMap(map)
            self.controller.addMap(fileName, map)
            self.changePreview()

    def addMap(self):
        """Add a map."""
        fileName, ok = QFileDialog.getOpenFileName(
            self, _("Select Map Image (> 500x500px recommended)"), "",
            _("Supported Images") + " (*.png *.jpg)")
        if ok:
            base = os.path.basename(fileName)
            name, ext = os.path.splitext(base)
            name = name.replace("_", " ")
            map_name, ok = QInputDialog.getText(self,
                                                _('Map Name'),
                                                _('Map Name') + ':',
                                                text=name)
            map_name = map_name.strip()
            if ok:
                if map_name.lower() == 'tbd':
                    QMessageBox.critical(
                        self, _("Error"),
                        _('"{}" is not a valid map name.').format(map_name))
                    return

                if (map_name in scctool.settings.maps):
                    buttonReply = QMessageBox.warning(
                        self, _("Duplicate Entry"),
                        _("Map is already in list! Overwrite?"),
                        QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                    if buttonReply == QMessageBox.No:
                        return
                    else:
                        self.controller.deleteMap(map_name)

                self.controller.addMap(fileName, map_name)
                items = self.maplist.findItems(map_name, Qt.MatchExactly)
                if len(items) == 0:
                    item = QListWidgetItem(map_name)
                    self.maplist.addItem(item)
                    self.maplist.setCurrentItem(item)
                else:
                    self.maplist.setCurrentItem(items[0])
                self.changePreview()

    def addFromLquipedia(self):
        grabber = LiquipediaGrabber()
        search_str = ''
        while True:
            search_str, ok = QInputDialog.getText(self,
                                                  _('Map Name'),
                                                  _('Map Name') + ':',
                                                  text=search_str)
            search_str.strip()
            try:
                if ok and search_str:
                    if search_str.lower() == 'tbd':
                        QMessageBox.critical(
                            self, _("Error"),
                            _('"{}" is not a valid map name.').format(
                                search_str))
                        continue
                    try:
                        map = grabber.get_map(search_str)
                    except MapNotFound:
                        QMessageBox.critical(
                            self, _("Map not found"),
                            _('"{}" was not found on Liquipedia.').format(
                                search_str))
                        continue
                    map_name = map.get_name()

                    if (map_name in scctool.settings.maps):
                        buttonReply = QMessageBox.warning(
                            self, _("Duplicate Entry"),
                            _("Map {} is already in list! Overwrite?".format(
                                map_name)), QMessageBox.Yes | QMessageBox.No,
                            QMessageBox.No)
                        if buttonReply == QMessageBox.No:
                            break
                        else:
                            self.controller.deleteMap(map_name)

                    images = grabber.get_images(map.get_map_images())
                    image = ""
                    for size in sorted(images):
                        if not image or size <= 2500 * 2500:
                            image = images[size]
                    url = grabber._base_url + image

                    downloader = MapDownloader(self, map_name, url)
                    downloader.download()
                    if map_name not in scctool.settings.maps:
                        scctool.settings.maps.append(map_name)
                    items = self.maplist.findItems(map_name, Qt.MatchExactly)
                    if len(items) == 0:
                        item = QListWidgetItem(map_name)
                        self.maplist.addItem(item)
                        self.maplist.setCurrentItem(item)
                    else:
                        self.maplist.setCurrentItem(items[0])
                    self.changePreview()
            except Exception as e:
                module_logger.exception("message")
                QMessageBox.critical(self, _("Error"), str(e))
            finally:
                break

    def deleteMap(self):
        """Delete a map."""
        item = self.maplist.currentItem()
        map = item.text()
        buttonReply = QMessageBox.question(
            self, _('Delete map?'),
            _("Delete '{}' permanently?").format(map),
            QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if buttonReply == QMessageBox.Yes:
            self.controller.deleteMap(map)
            self.maplist.takeItem(self.maplist.currentRow())

    def changePreview(self):
        """Change the map preview."""
        if self.maplist.count() < 1:
            return

        map = self.maplist.currentItem().text()
        if (map == "TBD"):
            self.pb_renameMap.setEnabled(False)
            self.pb_removeMap.setEnabled(False)
            self.sc_removeMap.setEnabled(False)
        else:
            self.pb_removeMap.setEnabled(True)
            self.pb_renameMap.setEnabled(True)
            self.sc_removeMap.setEnabled(True)

        file = self.controller.getMapImg(map, True)
        map = QPixmap(file)
        width = map.height()
        height = map.width()
        ext = os.path.splitext(file)[1].replace(".", "").upper()
        size = humanize.naturalsize(os.path.getsize(file))
        map = QPixmap(file).scaled(self.mapsize, self.mapsize,
                                   Qt.KeepAspectRatio)
        self.mapPreview.setPixmap(map)
        text = "{}x{}px, {}, {}".format(width, height, str(size), ext)
        self.mapInfo.setText(text)

    def createButtonGroup(self):
        """Create buttons."""
        try:
            layout = QHBoxLayout()

            layout.addWidget(QLabel(""))

            buttonCancel = QPushButton(_('Cancel'))
            buttonCancel.clicked.connect(self.closeWindow)
            layout.addWidget(buttonCancel)

            buttonSave = QPushButton(_('&Save && Close'))
            buttonSave.setToolTip(_("Shortcut: {}").format("Ctrl+S"))
            self.shortcut = QShortcut(QKeySequence("Ctrl+S"), self)
            self.shortcut.setAutoRepeat(False)
            self.shortcut.activated.connect(self.saveCloseWindow)
            buttonSave.clicked.connect(self.saveCloseWindow)
            layout.addWidget(buttonSave)

            self.buttonGroup = layout
        except Exception as e:
            module_logger.exception("message")

    def saveData(self):
        """Save the data."""
        if (self.__dataChanged):
            scctool.settings.config.parser.set(
                "SCT", "myteams", ", ".join(self.list_favTeams.getData()))
            scctool.settings.config.parser.set(
                "SCT", "commonplayers",
                ", ".join(self.list_favPlayers.getData()))
            scctool.settings.config.parser.set("SCT", "tesseract",
                                               self.tesseract.text().strip())
            scctool.settings.config.parser.set("SCT", "use_ocr",
                                               str(self.cb_useocr.isChecked()))
            scctool.settings.config.parser.set(
                "SCT", "transparent_match_banner",
                str(self.cb_trans_banner.isChecked()))
            scctool.settings.config.parser.set(
                "SCT", "CtrlShiftS", str(self.cb_ctrlshifts.isChecked()))
            scctool.settings.config.parser.set(
                "SCT", "CtrlShiftC", str(self.cb_ctrlshiftc.isChecked()))
            scctool.settings.config.parser.set(
                "SCT", "swap_myteam", str(self.cb_swapTeams.isChecked()))
            scctool.settings.config.parser.set("SCT", "CtrlN",
                                               str(self.cb_ctrln.isChecked()))
            scctool.settings.config.parser.set("SCT", "CtrlX",
                                               str(self.cb_ctrlx.isChecked()))
            scctool.settings.config.parser.set(
                "SCT", "CtrlShiftR", str(self.cb_ctrlshiftr.currentText()))
            scctool.settings.config.parser.set(
                "SCT", "blacklist_on", str(self.cb_blacklist.isChecked()))
            scctool.settings.config.parser.set(
                "SCT", "blacklist", ", ".join(self.list_blacklist.getData()))

            self.__dataChanged = False

    def saveCloseWindow(self):
        """Save and close window."""
        self.saveData()
        self.passEvent = True
        self.close()

    def closeWindow(self):
        """Close window."""
        self.passEvent = True
        self.close()

    def closeEvent(self, event):
        """Handle close event."""
        try:
            self.mainWindow.updateMapCompleters()
            if (not self.__dataChanged):
                event.accept()
                return
            if (not self.passEvent):
                if (self.isMinimized()):
                    self.showNormal()
                buttonReply = QMessageBox.question(
                    self, _('Save data?'), _("Save data?"),
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                if buttonReply == QMessageBox.Yes:
                    self.saveData()
            event.accept()
        except Exception as e:
            module_logger.exception("message")
Пример #45
0
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        self.defaultError = "Welcome to EZ Audio! Expand your audio library by entering a valid Youtube URL above."
        self.defaultURL = "Enter URL Here..."
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(421, 500)
        font = QtGui.QFont()
        font.setFamily("Leelawadee UI Semilight")
        font.setPointSize(9)
        MainWindow.setFont(font)
        MainWindow.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu)
        MainWindow.setStyleSheet("background-color: rgb(74, 74, 74);")
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.centralwidget)
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.PrimaryLayout = QtWidgets.QVBoxLayout()
        self.PrimaryLayout.setContentsMargins(10, 10, 10, 90)
        self.PrimaryLayout.setSpacing(30)
        self.PrimaryLayout.setObjectName("PrimaryLayout")
        self.TopLayout = QtWidgets.QHBoxLayout()
        self.TopLayout.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
        self.TopLayout.setContentsMargins(0, -1, 0, 0)
        self.TopLayout.setSpacing(0)
        self.TopLayout.setObjectName("TopLayout")
        self.TitleLayout = QtWidgets.QVBoxLayout()
        self.TitleLayout.setContentsMargins(0, 0, 0, -1)
        self.TitleLayout.setSpacing(0)
        self.TitleLayout.setObjectName("TitleLayout")
        self.EZAudioLogo = QtWidgets.QLabel(self.centralwidget)
        self.EZAudioLogo.setMinimumSize(QtCore.QSize(20, 100))
        font = QtGui.QFont()
        font.setFamily("Poor Richard")
        font.setPointSize(26)
        font.setBold(False)
        font.setWeight(50)
        self.EZAudioLogo.setFont(font)
        self.EZAudioLogo.setStyleSheet("color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255));\n"
"color: rgb(255, 255, 255);")
        self.EZAudioLogo.setObjectName("EZAudioLogo")
        self.TitleLayout.addWidget(self.EZAudioLogo, 0, QtCore.Qt.AlignHCenter|QtCore.Qt.AlignVCenter)
        self.TopLayout.addLayout(self.TitleLayout)
        self.QueueLayout = QtWidgets.QVBoxLayout()
        self.QueueLayout.setSizeConstraint(QtWidgets.QLayout.SetMinAndMaxSize)
        self.QueueLayout.setContentsMargins(0, 0, 0, 0)
        self.QueueLayout.setSpacing(0)
        self.QueueLayout.setObjectName("QueueLayout")
        self.LibraryButton = QtWidgets.QPushButton(self.centralwidget)
        font = QtGui.QFont()
        font.setFamily("Bookman Old Style")
        font.setPointSize(11)
        self.LibraryButton.setFont(font)
        self.LibraryButton.setStyleSheet("color: rgb(255, 255, 255);\n"
"background-color: rgb(103, 103, 103);")
        self.LibraryButton.setObjectName("LibraryButton")
        self.QueueLayout.addWidget(self.LibraryButton)
        self.QueueButton = QtWidgets.QPushButton(self.centralwidget)
        font = QtGui.QFont()
        font.setFamily("Bookman Old Style")
        font.setPointSize(11)
        self.QueueButton.setFont(font)
        self.QueueButton.setStyleSheet("color: rgb(255, 255, 255);\n"
"background-color: rgb(103, 103, 103);")
        self.QueueButton.setObjectName("QueueButton")
        self.QueueLayout.addWidget(self.QueueButton)
        self.TopLayout.addLayout(self.QueueLayout)
        self.TopLayout.setStretch(0, 1)
        self.PrimaryLayout.addLayout(self.TopLayout)
        self.BottomLayout = QtWidgets.QVBoxLayout()
        self.BottomLayout.setSpacing(30)
        self.BottomLayout.setObjectName("BottomLayout")
        self.ConvertLayout = QtWidgets.QHBoxLayout()
        self.ConvertLayout.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
        self.ConvertLayout.setContentsMargins(-1, -1, 0, 0)
        self.ConvertLayout.setSpacing(5)
        self.ConvertLayout.setObjectName("ConvertLayout")
        self.URLBox = QtWidgets.QLineEdit(self.centralwidget)
        font = QtGui.QFont()
        font.setFamily("Leelawadee UI Semilight")
        font.setPointSize(12)
        self.URLBox.setFont(font)
        self.URLBox.setStyleSheet("background-color: rgb(168, 168, 168);")
        self.URLBox.setObjectName("URLBox")
        self.ConvertLayout.addWidget(self.URLBox)
        self.ConvertButton = QtWidgets.QToolButton(self.centralwidget)
        self.ConvertButton.setMinimumSize(QtCore.QSize(101, 0))
        font = QtGui.QFont()
        font.setFamily("Bookman Old Style")
        font.setPointSize(10)
        font.setUnderline(False)
        self.ConvertButton.setFont(font)
        self.ConvertButton.setStyleSheet("color: rgb(255, 255, 255);\n"
"background-color: rgb(103, 103, 103);")
        self.ConvertButton.setObjectName("ConvertButton")
        self.ConvertLayout.addWidget(self.ConvertButton)
        self.BottomLayout.addLayout(self.ConvertLayout)
        self.ErrorBox = QtWidgets.QLabel(self.centralwidget)
        self.ErrorBox.setMinimumSize(QtCore.QSize(361, 61))
        font = QtGui.QFont()
        font.setFamily("Leelawadee UI Semilight")
        # self.ErrorBox.setFont(font)
        # self.ErrorBox.setStyleSheet("background-color: rgb(168, 168, 168);")
        # self.ErrorBox.setFrameShape(QtWidgets.QFrame.NoFrame)
        # self.ErrorBox.setFrameShadow(QtWidgets.QFrame.Raised)
        # self.ErrorBox.setLineWidth(0)
        # self.ErrorBox.setMidLineWidth(0)
        # self.ErrorBox.setTextFormat(QtCore.Qt.AutoText)
        # self.ErrorBox.setScaledContents(False)
        # self.ErrorBox.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
        # self.ErrorBox.setWordWrap(True)
        # self.ErrorBox.setObjectName("ErrorBox")
        self.BottomLayout.addWidget(self.ErrorBox)
        self.PrimaryLayout.addLayout(self.BottomLayout)
        self.horizontalLayout_3.addLayout(self.PrimaryLayout)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 401, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.formatCombo = QtWidgets.QComboBox(self.centralwidget)
        self.formatCombo.setGeometry(QtCore.QRect(19, 190, 70, 20))
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        sizePolicy.setHorizontalStretch(15)
        sizePolicy.setVerticalStretch(32)
        sizePolicy.setHeightForWidth(self.formatCombo.sizePolicy().hasHeightForWidth())
        self.formatCombo.setSizePolicy(sizePolicy)
        self.formatCombo.setMinimumSize(QtCore.QSize(70, 25))
        self.formatCombo.setMaximumSize(QtCore.QSize(70, 25))
        self.formatCombo.setStyleSheet("background-color: rgb(168, 168, 168);")
        font = QtGui.QFont()
        font.setFamily("Leelawadee UI Semilight")
        self.formatCombo.setFont(font)
        self.formatCombo.setObjectName("formatCombo")
        self.formatCombo.addItem("")
        self.formatCombo.addItem("")
        self.bitRateCombo = QtWidgets.QComboBox(self.centralwidget)
        self.bitRateCombo.setGeometry(QtCore.QRect(100, 190, 70, 20))
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        sizePolicy.setHorizontalStretch(15)
        sizePolicy.setVerticalStretch(32)
        sizePolicy.setHeightForWidth(self.bitRateCombo.sizePolicy().hasHeightForWidth())
        self.bitRateCombo.setSizePolicy(sizePolicy)
        self.bitRateCombo.setMinimumSize(QtCore.QSize(70, 25))
        self.bitRateCombo.setMaximumSize(QtCore.QSize(70, 25))
        self.bitRateCombo.setStyleSheet("background-color: rgb(168, 168, 168);")
        font = QtGui.QFont()
        font.setFamily("Leelawadee UI Semilight")
        self.bitRateCombo.setFont(font)
        self.bitRateCombo.setObjectName("bitRateCombo")
        self.bitRateCombo.addItem("")
        self.bitRateCombo.addItem("")
        self.bitRateCombo.addItem("")

        self.convert_Button = QPushButton('Convert', MainWindow)
        font = QtGui.QFont()
        font.setFamily("Bookman Old Style")
        font.setPointSize(10)
        font.setUnderline(False)
        self.convert_Button.setFont(font)
        self.convert_Button.setStyleSheet("color: rgb(255, 255, 255);\n" "background-color: rgb(103, 103, 103);")
        self.convert_Button.resize(100, 25)
        self.convert_Button.move(299, 190)


        self.initUI()

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)



    def changeError(self):
        self.inputURL = self.URLBox.text()
        _translate = QtCore.QCoreApplication.translate
        self.ErrorBox.setText(_translate("MainWindow", "Hold on..."))
        conversionEngine.converter.transcodeURL(self.inputURL)

        self.ErrorBox.setText(_translate("MainWindow", "Download done!"))

    def openLibrary(self):
        self.ex = List()
        self.ex.show()

    def openQueue(self): #Cloud Function
        self.cal = Window()
        self.cal.show()


    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "EZ Audio"))
        self.URLBox.setText(_translate("MainWindow", self.defaultURL))
        self.EZAudioLogo.setText(_translate("MainWindow", "<html><head/><body><p>EZ Audio</p><p><span style=\" font-size:11pt;\">By Yousif, Omar, Jack, and Khaled</span></p></body></html>"))
        self.LibraryButton.setText(_translate("MainWindow", "Library"))
        self.QueueButton.setText(_translate("MainWindow", "Cloud"))
        self.ConvertButton.setText(_translate("MainWindow", "Add Url"))
        # self.ErrorBox.setText(_translate("MainWindow", self.defaultError))
        # self.ConvertButton.clicked.connect(self.changeError)
        self.ConvertButton.clicked.connect(self.addUrl)
        self.URL_List.clicked.connect(self.removeURL)

        self.formatCombo.setItemText(0, _translate("MainWindow", "mp3"))
        self.formatCombo.setItemText(1, _translate("MainWindow", "m4a"))
        self.bitRateCombo.setItemText(0, _translate("MainWindow", "48"))
        self.bitRateCombo.setItemText(1, _translate("MainWindow", "96"))
        self.bitRateCombo.setItemText(2, _translate("MainWindow", "128"))

        self.convert_Button.clicked.connect(self.covertURL)

        self.LibraryButton.clicked.connect(self.openLibrary)
        self.QueueButton.clicked.connect(self.openQueue)

    @pyqtSlot()
    def initUI(self):
        self.textbox = QLineEdit(MainWindow)
        self.textbox.move(19, 460)
        self.textbox.resize(200, 20)
        self.textbox.setStyleSheet("background-color: rgb(168, 168, 168);")
        self.textbox.setText("(To delete a URL double click on it)")
        font = QtGui.QFont()
        font.setFamily("Leelawadee UI Semilight")
        self.textbox.setFont(font)
        #self.textbox.fornt.setPointSize(50)

        self.URL_List = QListWidget(MainWindow)
        self.URL_List.move(19, 230)
        self.URL_List.resize(350, 220)
        self.URL_List.setStyleSheet("""QListWidget{ background: rgb(168, 168, 168); }""")

    def addUrl(self):
        textboxValue = self.URLBox.text()
        subString = textboxValue[0:23]
        print(subString)

        if subString == "https://www.youtube.com":
            self.URL_List.addItem(textboxValue)
        else:
            # self.message = QMessageBox(MainWindow)
            QMessageBox(MainWindow).question(MainWindow, 'Error', "The Url you entered is not a valid ",
                                             QMessageBox.Ok,
                                             QMessageBox.Ok)
            print(subString)


    def removeURL(self):
        index = self.URL_List.row(self.URL_List.currentItem())

        buttonReply = QMessageBox(MainWindow).question(MainWindow, 'Message', "Do you want to delete?",
                                           QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if buttonReply == QMessageBox.Yes:
            self.URL_List.takeItem(index)
        else:
            return

    def covertURL(self):

        index = self.URL_List.item(0)
        if index is None:
            QMessageBox(MainWindow).question(MainWindow, 'Message', "No Url to convert ",
                                             QMessageBox.Ok,
                                             QMessageBox.Ok)
        else:
            while index is not None:
                # print(self.URL_List.item(0).text())
                self.inputURL = self.URL_List.item(0).text()
                x = str(self.formatCombo.currentText())
                y = int(self.bitRateCombo.currentText())
                conversionEngine.ytdlExec(self.inputURL, y, x)
                self.URL_List.takeItem(0)
                index = self.URL_List.item(0)
            QMessageBox(MainWindow).question(MainWindow, 'Message', "All url have been converted ",
                                         QMessageBox.Ok,
                                         QMessageBox.Ok)
Пример #46
0
class ListEdit(QWidget):
    """A widget to edit a list of items (e.g. a list of directories)."""

    # emitted when anything changed in the listbox.
    changed = pyqtSignal()

    def __init__(self, *args, **kwargs):
        QWidget.__init__(self, *args, **kwargs)
        layout = QGridLayout(self)
        self.setLayout(layout)

        self.addButton = QPushButton(icons.get('list-add'), '')
        self.editButton = QPushButton(icons.get('document-edit'), '')
        self.removeButton = QPushButton(icons.get('list-remove'), '')
        self.listBox = QListWidget()

        layout.setContentsMargins(1, 1, 1, 1)
        layout.setSpacing(0)
        layout.addWidget(self.listBox, 0, 0, 8, 1)
        layout.addWidget(self.addButton, 0, 1)
        layout.addWidget(self.editButton, 1, 1)
        layout.addWidget(self.removeButton, 2, 1)

        self.changed.connect(self.updateSelection)
        self.listBox.itemSelectionChanged.connect(self.updateSelection)
        self.updateSelection()
        self.connectSlots()
        app.translateUI(self)

    def connectSlots(self):
        self.addButton.clicked.connect(self.addClicked)
        self.editButton.clicked.connect(self.editClicked)
        self.removeButton.clicked.connect(self.removeClicked)
        self.listBox.itemDoubleClicked.connect(self.itemDoubleClicked)
        self.listBox.model().layoutChanged.connect(self.changed)

    def translateUI(self):
        self.addButton.setText(_("&Add..."))
        self.editButton.setText(_("&Edit..."))
        self.removeButton.setText(_("&Remove"))

    def addClicked(self, button):
        item = self.createItem()
        if self.openEditor(item):
            self.addItem(item)

    def editClicked(self, button):
        item = self.listBox.currentItem()
        item and self.editItem(item)

    def removeClicked(self, button):
        item = self.listBox.currentItem()
        if item:
            self.removeItem(item)
            
    def updateSelection(self):
        selected = bool(self.listBox.currentItem())
        self.editButton.setEnabled(selected)
        self.removeButton.setEnabled(selected)

    def itemDoubleClicked(self, item):
        item and self.editItem(item)

    def createItem(self):
        return QListWidgetItem()

    def addItem(self, item):
        self.listBox.addItem(item)
        self.itemChanged(item)
        self.changed.emit()

    def removeItem(self, item):
        self.listBox.takeItem(self.listBox.row(item))
        self.changed.emit()

    def editItem(self, item):
        if self.openEditor(item):
            self.itemChanged(item)
            self.changed.emit()

    def setCurrentItem(self, item):
        self.listBox.setCurrentItem(item)

    def setCurrentRow(self, row):
        self.listBox.setCurrentRow(row)

    def openEditor(self, item):
        """Opens an editor (dialog) for the item.

        Returns True if the dialog was accepted and the item edited.
        Returns False if the dialog was cancelled (the item must be left
        unedited).
        """
        pass

    def itemChanged(self, item):
        """Called after an item has been added or edited.

        Re-implement to do something at this moment if needed, e.g. alter the
        text or display of other items.
        """
        pass

    def setValue(self, strings):
        """Sets the listbox to a list of strings."""
        self.listBox.clear()
        self.listBox.addItems(strings)
        self.changed.emit()

    def value(self):
        """Returns the list of paths in the listbox."""
        return [self.listBox.item(i).text()
            for i in range(self.listBox.count())]

    def setItems(self, items):
        """Sets the listbox to a list of items."""
        self.listBox.clear()
        for item in items:
            self.listBox.addItem(item)
            self.itemChanged(item)
        self.changed.emit()

    def items(self):
        """Returns the list of items in the listbox."""
        return [self.listBox.item(i)
            for i in range(self.listBox.count())]

    def clear(self):
        """Clears the listbox."""
        self.listBox.clear()
        self.changed.emit()
Пример #47
0
class plotWidget(QWidget):
    NextId = 1

    FONT_MAX_SIZE = 30
    FONT_MIN_SIZE = 10

    TEXTCHANGED = 0

    customDataChanged = pyqtSignal()

    def __init__(self, filename=None, parent=None):
        """
        Creates an Instance of QWidget

         Args:
             filename (str): for opening a parameter file
             parent  (object)

        """
        super(plotWidget, self).__init__(parent)
        self.parent = parent

        self.setAttribute(Qt.WA_DeleteOnClose)

        self.filename = filename  # VIT
        self.save_title = ''

        self.setWindowTitle(QFileInfo(self.filename).fileName())

        hbox = QHBoxLayout(self)
        self.plotToolWidget = showPlot(self, width=5, height=4, dpi=100)

        self.listWidget = QListWidget(self)
        self.listWidget.currentRowChanged.connect(self.updatePlot)
        # self.listWidget.setMinimumWidth(200)
        self.listWidget.setMaximumWidth(200)

        self.splitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal)  # This is Yeah
        self.splitter.addWidget(self.plotToolWidget)  # This is Yeah
        self.splitter.addWidget(self.listWidget)  # This is Yeah

        hbox.addWidget(self.splitter)
        # hbox.addWidget(listWidget)

        self.readData()

    def updatePlot(self):
        print("Update Plot Yahooooo ")
        row = self.listWidget.currentRow()
        self.title = self.listWidget.item(row).text()
        print('Row ', row)
        print('----------------------------')
        x, y = self.edrObject.dataExtractFromRow(row)
        unit = self.edrObject.getUnits(row)
        print('Unit is ', unit)
        # print('x ',len(x))
        # print('y ',len(y))

        self.plotToolWidget.plotFigure(x, y, 'ps', unit, self.title)

    def readData(self):
        self.edrObject = EdrIO(self.filename, 'float')  # for now
        print('edrObject ', self.edrObject)
        self.populateList()

    def populateList(self):
        self.props = self.edrObject.read('avail quantities')
        print('props ', self.props)
        index = 0
        for i in self.props:
            self.listWidget.addItem(str(index) + '. ' + i)
            index += 1

    def save(self):
        #: So self.title has to be modified
        self.save_title = self.title.split(' ')[1] + '.png'
        print('save_title is ', self.save_title)

        if "edr" in self.filename:
            filename = QFileDialog.getSaveFileName(self,
                                                   "G.R.O.M. Editor -- Save File As", self.save_title,
                                                   "png (*.png  *.*)")
            print('filename is ', filename)
            if len(filename[0]) == 0:
                return
            self.filenameSave = filename[0]
            print('Save graph ', self.filenameSave)
        # self.setWindowTitle(QFileInfo(self.filename).fileName())
        exception = None
        fh = None
        try:
            # fh = QFile(self.filenameSave)
            # if not fh.open(QIODevice.WriteOnly):
            # raise IOError(str(fh.errorString()))
            self.plotToolWidget.saveFig(self.filenameSave)
        except EnvironmentError as e:
            exception = e
            print('error in saving ', e)
Пример #48
0
class VariableSettingWindowDemo(QDialog):
    def __init__(self, data_list):
        super(VariableSettingWindowDemo, self).__init__()
        self.initUI(data_list)

    def initUI(self, data_list):
        self.resize(800, 800)
        self.setWindowTitle('变量设置')
        self.signal = MySignal()
        icon = QIcon()
        icon.addPixmap(QPixmap('./image/设置.png'))
        self.setWindowIcon(icon)
        self.label1 = QLabel('变量')
        self.label2 = QLabel('自变量')
        self.label3 = QLabel('因变量')

        self.list_widget1 = QListWidget()
        self.list_widget2 = QListWidget()
        self.list_widget3 = QListWidget()

        self.list_widget1.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.list_widget2.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.list_widget3.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.list_widget1.addItems(data_list)

        self.button12 = QPushButton('-->')
        self.button21 = QPushButton('<--')

        self.button13 = QPushButton('-->')
        self.button31 = QPushButton('<--')

        self.button1 = QPushButton('确认')
        self.button2 = QPushButton('取消')

        vlayout1 = QVBoxLayout()
        vlayout1.addWidget(self.button12)
        vlayout1.addWidget(self.button21)

        hlayout1 = QHBoxLayout()
        hlayout1.addItem(vlayout1)
        vlayout = QVBoxLayout()
        # vlayout.addWidget(QLabel(''))
        vlayout.addWidget(self.label2)
        vlayout.addWidget(self.list_widget2)
        vlayout.setSpacing(10)
        hlayout1.addItem(vlayout)

        vlayout2 = QVBoxLayout()
        vlayout2.addWidget(self.button13)
        vlayout2.addWidget(self.button31)

        hlayout2 = QHBoxLayout()
        hlayout2.addItem(vlayout2)
        vlayout = QVBoxLayout()
        # vlayout.addWidget(QLabel(''))
        vlayout.addWidget(self.label3)
        vlayout.addWidget(self.list_widget3)
        vlayout.setSpacing(10)
        hlayout2.addItem(vlayout)

        gridlayout = QGridLayout()
        hlayout = QHBoxLayout()
        # hlayout.addWidget(self.button1)
        # hlayout.addWidget(self.button2)
        hlayout.setSpacing(20)

        vlayout = QVBoxLayout()
        vlayout.addItem(hlayout)
        vlayout.addWidget(self.label1)
        vlayout.addWidget(self.list_widget1)
        vlayout.setSpacing(10)

        gridlayout.addItem(vlayout, 1, 0, 2, 1)
        hlayout1.setSpacing(10)
        hlayout2.setSpacing(10)
        gridlayout.addItem(hlayout1, 1, 1, 1, 1)
        gridlayout.addItem(hlayout2, 2, 1, 1, 1)
        hlayout = QHBoxLayout()
        hlayout.addWidget(self.button1)
        hlayout.addWidget(self.button2)
        hlayout.setSpacing(10)
        gridlayout.addItem(hlayout, 3, 0, 1, 1)
        self.setLayout(gridlayout)

        #绑定信号
        self.button12.clicked.connect(
            lambda: self.onClickButton(self.list_widget1, self.list_widget2))
        self.button21.clicked.connect(
            lambda: self.onClickButton(self.list_widget2, self.list_widget1))
        self.button13.clicked.connect(
            lambda: self.onClickButton(self.list_widget1, self.list_widget3))
        self.button31.clicked.connect(
            lambda: self.onClickButton(self.list_widget3, self.list_widget1))
        self.button1.clicked.connect(self.sendSignal)
        self.button2.clicked.connect(self.close)

    def onClickButton(self, sender, reciever):
        try:
            item_list = sender.selectedItems()
            for item in item_list:
                reciever.addItem(item.text())
                sender.takeItem(sender.row(item))
        except Exception as e:
            print(e)

    def sendSignal(self):
        count1 = self.list_widget2.count()
        count2 = self.list_widget3.count()
        independ_var = [
            self.list_widget2.item(i).text() for i in range(count1)
        ]
        depend_var = [self.list_widget3.item(i).text() for i in range(count2)]
        var_list = [independ_var, depend_var]
        self.signal.send(var_list)
        self.close()
Пример #49
0
class UnsavedFilesDialog(QDialog):

    def __init__(self, unsaved_files, parent=None):
        super().__init__(parent)
        self._ninja = parent
        self.setWindowTitle(translations.TR_IDE_CONFIRM_EXIT_TITLE)
        vbox = QVBoxLayout(self)

        self._unsave_files_list = QListWidget()
        self._unsave_files_list.setSelectionMode(QListWidget.ExtendedSelection)
        vbox.addWidget(QLabel(translations.TR_IDE_CONFIRM_EXIT_BODY))
        vbox.addWidget(self._unsave_files_list)
        button_box = QDialogButtonBox(self)

        standard_icon = self.style().standardIcon

        btn = button_box.addButton(
            translations.TR_CANCEL, QDialogButtonBox.RejectRole)
        btn.setIcon(standard_icon(self.style().SP_DialogCloseButton))
        self._btn_save_selected = button_box.addButton(
            translations.TR_SAVE_SELECTED, QDialogButtonBox.AcceptRole)
        self._btn_save_selected.setIcon(
            standard_icon(self.style().SP_DialogSaveButton))
        btn_save_all = button_box.addButton(
            translations.TR_SAVE_ALL, QDialogButtonBox.AcceptRole)
        btn_save_all.setIcon(standard_icon(self.style().SP_DialogApplyButton))
        btn_donot_save = button_box.addButton(
            translations.TR_DONOT_SAVE, QDialogButtonBox.DestructiveRole)
        btn_donot_save.setIcon(standard_icon(self.style().SP_DialogNoButton))

        vbox.addWidget(button_box)

        for nfile in unsaved_files:
            item = QListWidgetItem(nfile.display_name)
            item.setData(Qt.UserRole, nfile)
            item.setToolTip(nfile.file_path)
            self._unsave_files_list.addItem(item)

        # Connections
        button_box.rejected.connect(self.reject)
        button_box.accepted.connect(self._save_selected)
        btn_donot_save.clicked.connect(self._discard)
        btn_save_all.clicked.connect(self._save_all)
        self._unsave_files_list.itemSelectionChanged.connect(
            self._on_selection_changed)

        self._unsave_files_list.selectAll()

    def _on_selection_changed(self):
        value = True
        if not self._unsave_files_list.selectedItems():
            value = False
        self._btn_save_selected.setEnabled(value)

    def _save_selected(self):
        logger.debug("Saving selected unsaved files")
        self.__save()

    def __save(self):
        """Collect all selected items and save"""

        items_to_save = []
        for item in self._unsave_files_list.selectedItems():
            nfile = item.data(Qt.UserRole)
            items_to_save.append(nfile)
        self._ninja._save_unsaved_files(items_to_save)
        self.accept()

    def _save_all(self):
        """Select all items in the list and save"""
        logger.debug("Saving all unsaved files")
        for index in range(self._unsave_files_list.count()):
            item = self._unsave_files_list.item(index)
            item.setSelected(True)
        self.__save()

    def _discard(self):
        logger.debug("Discarding all unsaved files")
        self.accept()
Пример #50
0
class CityListDlg(QDialog):
    citieslist_signal = pyqtSignal([list])
    citiesdict_signal = pyqtSignal([dict])

    def __init__(
        self, citylist, accurate_url, appid, trans_cities_dict, parent=None
    ):
        super(CityListDlg, self).__init__(parent)
        self.settings = QSettings()
        self.citylist = citylist
        self.trans_cities_dict = trans_cities_dict
        self.accurate_url = accurate_url
        self.appid = appid
        self.listWidget = QListWidget()
        self.listWidget.itemDoubleClicked.connect(self.translate)
        cities_list = []
        for i in self.citylist:
            cities_list.append(self.trans_cities_dict.get(i, i))
        self.listWidget.addItems(cities_list)
        buttonLayout = QVBoxLayout()
        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel
        )
        self.buttonBox.rejected.connect(self.reject)
        self.buttonBox.accepted.connect(self.accept)
        layoutT = QVBoxLayout()
        layout = QHBoxLayout()
        layout.addWidget(self.listWidget)
        layout.addLayout(buttonLayout)
        for text, slot in ((self.tr("&Add..."), self.add),
                           (self.tr("&Remove..."), self.remove),
                           (self.tr("&Up"), self.up),
                           (self.tr("&Down"), self.down),
                           (self.tr("De&fault"), self.default),
                           (self.tr("&Sort"), self.listWidget.sortItems)):
            button = QPushButton(text)
            buttonLayout.addWidget(button)
            button.clicked.connect(slot)
        self.translate_button = QPushButton(
            QCoreApplication.translate(
                'Button',
                '&Translate',
                'Edit cities name'
            )
        )
        buttonLayout.addWidget(self.translate_button)
        self.translate_button.clicked.connect(self.translate)
        buttonLayout.addWidget(self.buttonBox)
        self.status = QLabel()
        layoutT.addLayout(layout)
        layoutT.addWidget(self.status)
        self.setLayout(layoutT)
        self.setWindowTitle(
            QCoreApplication.translate(
                'Window title',
                'Cities',
                'Cities list dialogue'
            )
        )
        self.checklength()

    def add(self):
        self.status.setText('')
        lista = []
        newitem = ''
        self.citytoadd = ''
        self.countrytoadd = ''
        self._idtoadd = ''
        dialog = searchcity.SearchCity(self.accurate_url, self.appid, self)
        dialog.id_signal.connect(self.addcity)
        dialog.city_signal.connect(self.addcity)
        dialog.country_signal.connect(self.addcity)
        if dialog.exec_() == 1:
            newitem = (
                self.citytoadd + '_' + self.countrytoadd
                + '_' + self._idtoadd
            )
            for row in range(self.listWidget.count()):
                lista.append(self.listWidget.item(row).text())
            if newitem in lista:
                self.status.setText(
                    QCoreApplication.translate(
                        'Status bar message',
                        'The city already exists in the list',
                        'Cities list dialogue'
                    )
                )
                return
            else:
                self.listWidget.addItem(newitem)
                self.checklength()
                self.status.setText(
                    'ℹ ' + QCoreApplication.translate(
                        'Status bar message',
                        'Toggle cities with mouse scroll on the weather window',
                        'Cities list dialogue'
                    )
                )

    def addcity(self, what):
        self.status.setText('')
        if what[0] == 'ID':
            self._idtoadd = what[1]
        elif what[0] == 'City':
            self.citytoadd = what[1]
        elif what[0] == 'Country':
            self.countrytoadd = what[1]

    def remove(self):
        self.status.setText('')
        if self.listWidget.count() == 1:
            self.status.setText(
                QCoreApplication.translate(
                    'Message when trying to remove the'
                    'last and unique city in the list',
                    'This is the default city !',
                    'Cities list dialogue'
                )
            )
            return
        row = self.listWidget.currentRow()
        item = self.listWidget.item(row)
        if item is None:
            return
        message = self.tr('The city "{0}" has been removed').format(
            self.listWidget.item(row).text())
        item = self.listWidget.takeItem(row)
        del item
        self.status.setText(message)

    def up(self):
        self.status.setText('')
        row = self.listWidget.currentRow()
        if row >= 1:
            item = self.listWidget.takeItem(row)
            self.listWidget.insertItem(row - 1, item)
            self.listWidget.setCurrentItem(item)

    def down(self):
        self.status.setText('')
        row = self.listWidget.currentRow()
        if row < self.listWidget.count() - 1:
            item = self.listWidget.takeItem(row)
            self.listWidget.insertItem(row + 1, item)
            self.listWidget.setCurrentItem(item)

    def default(self):
        self.status.setText('')
        row = self.listWidget.currentRow()
        if row >= 1:
            item = self.listWidget.takeItem(row)
            self.listWidget.insertItem(0, item)
            self.listWidget.setCurrentItem(item)

    def checklength(self):
        if self.listWidget.count() == 1:
            # After adding the first city the entry is not activated
            self.listWidget.setCurrentRow(0)
        if self.listWidget.count() > 0:
            self.translate_button.setEnabled(True)
            self.listWidget.setMinimumWidth(
                self.listWidget.sizeHintForColumn(0)
            )
        else:
            self.translate_button.setEnabled(False)

    def translate(self):
        city = self.listWidget.currentItem().text()
        dialog = citytranslate.CityTranslate(
            city, self.trans_cities_dict, self
        )
        dialog.city_signal.connect(self.current_translation)
        if dialog.exec_() == 1:
            row = self.listWidget.currentRow()
            item = self.listWidget.takeItem(row)
            del item
            self.listWidget.insertItem(row, self.current_translated_city)
            self.listWidget.setCurrentRow(row)

    def current_translation(self, translated_city):
        for city, translated in translated_city.items():
            if translated == '':
                translated = city
            self.trans_cities_dict[city] = translated
            self.current_translated_city = translated

    def accept(self):
        listtosend = []
        for row in range(self.listWidget.count()):
            city = self.find_city_key(self.listWidget.item(row).text())
            listtosend.append(city)
        if self.listWidget.count() == 0:
            return
        self.citieslist_signal[list].emit(listtosend)
        self.citiesdict_signal[dict].emit(self.trans_cities_dict)
        QDialog.accept(self)

    def find_city_key(self, city):
        for key, value in self.trans_cities_dict.items():
            if value == city:
                return key
        return city
Пример #51
0
class SubSheet(SimpleBlackbox):
    author = "DrLuke"
    name = "Subsheet"
    modulename = "subsheet"

    Category = ["Builtin"]

    placeable = True

    implementation = SubSheetImplementation

    def __init__(self, *args, **kwargs):
        self.ownsheet = None
        self.sheets = None
        self.selectedSheet = None
        self.listSheetItems = {}

        super(SubSheet, self).__init__(*args, **kwargs)

        self.propertiesWidget = QWidget()

        self.vlayout = QVBoxLayout()

        self.listWidget = QListWidget()
        self.listWidget.itemClicked.connect(self.listClicked)
        self.vlayout.addWidget(self.listWidget)

        self.vlayout.addItem(QSpacerItem(40, 20, QSizePolicy.Minimum, QSizePolicy.Expanding))

        self.propertiesWidget.setLayout(self.vlayout)

    def getPropertiesWidget(self):
        return self.propertiesWidget

    def updateSheets(self):
        if self.sheets is not None and self.ownsheet is not None:
            self.listSheetItems = {}
            self.listWidget.clear()
            for sheetId in self.sheets:
                if not sheetId == self.ownsheet:
                    newItem = QListWidgetItem(self.sheets[sheetId])
                    newItem.setToolTip(str(sheetId))
                    newItem.setData(Qt.UserRole, sheetId)
                    self.listSheetItems[sheetId] = newItem
                    self.listWidget.addItem(newItem)

                    if sheetId == self.selectedSheet:
                        boldFont = QFont()
                        boldFont.setBold(True)
                        newItem.setFont(boldFont)

    def listClicked(self, item):
        normalFont = QFont()
        boldFont = QFont()
        boldFont.setBold(True)

        for i in range(self.listWidget.count()):
            itemnormal = self.listWidget.item(i)
            itemnormal.setFont(normalFont)

        self.selectedSheet = item.data(Qt.UserRole)
        self.sendDataToImplementations({"subsheetid": self.selectedSheet})
        item.setFont(boldFont)

    def serialize(self):
        return {"subsheetid": self.selectedSheet}

    def deserialize(self, data):
        if data is not None:
            if "subsheetid" in data:
                self.selectedSheet = data["subsheetid"]
                self.sendDataToImplementations({"subsheetid": self.selectedSheet})

    def selectedChanged(self, state):
        if state:
            self.mainRect.setPen(QPen(Qt.red))
        else:
            self.mainRect.setPen(QPen(Qt.blue))

    def defineIO(self):
        self.addInput(execType, "execInit", "Execute Init")
        self.addInput(execType, "execLoop", "Execute Loop")

        self.addOutput(execType, "ExecInitOut", "Init Done")
        self.addOutput(execType, "ExecLoopOut", "Loop Done")
Пример #52
0
class ListEntry(BaseParamWidget):
    def __init__(self, layout_dir: str, title: str,
                 initial_value: List[List[str]], new_id_func: Callable):
        super().__init__(layout_dir)
        self.choices = []
        self.text_list = []
        lab_title = QLabel(text=title)
        layout = QHBoxLayout()
        self.central_layout.addWidget(lab_title)
        self.on_check_callback = None
        self.list_widget = QListWidget()
        self.set_value(initial_value)
        layout_tools = QVBoxLayout()
        self.button_add_item = QPushButton('+')
        self.button_delete_item = QPushButton('-')
        self.button_delete_item.clicked.connect(self.delete_row)
        self.button_add_item.clicked.connect(self.add_row)
        self.button_add_item.setMaximumWidth(20)
        self.button_delete_item.setMaximumWidth(20)
        layout_tools.addWidget(self.button_add_item)
        layout_tools.addWidget(self.button_delete_item)
        layout.addLayout(layout_tools)
        layout.addWidget(self.list_widget)
        self.central_layout.addLayout(layout)
        self.data = initial_value
        self.new_id_func = new_id_func

    def new_id(self):
        if callable(self.new_id_func):
            return self.new_id_func()
        else:
            return None

    def add_row(self):
        self.data[0].append(self.new_id())
        self.data[1].append('Unnamed')
        self.set_value(self.data)

    def delete_row(self):
        # item = self.list_widget.currentItem()
        index = self.list_widget.currentIndex().row()
        self.data[0].pop(index)
        self.data[1].pop(index)
        self.set_value(self.data)

    def on_listwidget_double_cicked(self):
        print('edit')
        item = self.list_widget.currentItem()
        self.list_widget.editItem(item)

    def get_value(self):
        text = []
        for i in range(self.list_widget.count()):
            text.append(self.list_widget.item(i).text())
        self.data[1] = text
        return self.data

    def set_value(self, data: List[List[str]]):
        self.list_widget.clear()
        self.list_widget.addItems(data[1])
        self.data = data
        for index in range(self.list_widget.count()):
            item = self.list_widget.item(index)
            item.setFlags(item.flags() | Qt.ItemIsEditable)
Пример #53
0
class ApplicationWindow(QtWidgets.QMainWindow):
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        self.setWindowTitle("application main window")

        self.file_menu = QtWidgets.QMenu('&File', self)
        self.file_menu.addAction('&Quit', self.fileQuit,
                                 QtCore.Qt.CTRL + QtCore.Qt.Key_Q)
        self.menuBar().addMenu(self.file_menu)

        self.help_menu = QtWidgets.QMenu('&Help', self)
        self.menuBar().addSeparator()
        self.menuBar().addMenu(self.help_menu)

        self.help_menu.addAction('&About', self.about)

        self.main_widget = QtWidgets.QWidget(self)

        mainLayout = QtWidgets.QVBoxLayout(self.main_widget)

        # convas
        # dc = MyDynamicMplCanvas(self.main_widget, width=8, height=4, dpi=100)
        # mainLayout.addWidget(dc)


        hBoxLayout = QtWidgets.QHBoxLayout()

        # self.tableWidget = QTableWidget(self)
        # self.tableWidget.setRowCount(1)
        # self.tableWidget.setColumnCount(100)
        # self.tableWidget.resizeRowToContents(0)
        #self.tableWidget.setItem(0,0, QTableWidgetItem("aa"))
        #self.tableWidget.insertRow(1)

        self.listWidget = QListWidget(self)
        # self.listWidget.addItem(QListWidgetItem("3"))


        self.factorValue = QLineEdit(self)
        self.factorValue.setText("0.98")
        self.factorValue.setFixedSize(100, 30)

        self.factorButton = QPushButton(self)
        self.factorButton.setText('Change emissivity')
        self.factorButton.clicked.connect(self.factorButtonOnClicked)
        self.factorButton.setFixedSize(150, 30)

        self.stopButton = QPushButton(self)
        self.stopButton.setText('Stop')
        self.stopButton.clicked.connect(self.stopButtonOnClicked)
        self.stopButton.setFixedSize(100, 30)

        self.copyData = QPushButton(self)
        self.copyData.setText('Copy')
        self.copyData.clicked.connect(self.onCopyButtonCliced)


        self.oneMeasureButton = QPushButton(self)
        self.oneMeasureButton.setText('One Measure')
        self.oneMeasureButton.clicked.connect(self.onMeasureButtonOnClicked)


        # self.oneMeasureButton.setFixedSize(5,5)

        # self.factorMenu = QMenu(self)
        # self.factorMenu.frameSize()
        # self.factorSubMenu = self.factorMenu.addMenu("material")
        # self.factorSubMenu.addAction("new")
        # self.factorSubMenu.addAction("new2")


        spacer = QSpacerItem(500, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        hBoxLayout.addItem(spacer)
        # hBoxLayout.addWidget(self.factorMenu)

        mainLayout.addWidget(self.listWidget)
        # mainLayout.addWidget(self.tableWidget)

        hBoxLayout.addWidget(self.copyData)
        hBoxLayout.addWidget(self.factorValue)
        hBoxLayout.addWidget(self.factorButton)
        hBoxLayout.addWidget(self.stopButton)
        hBoxLayout.addWidget(self.oneMeasureButton)

        mainLayout.addLayout(hBoxLayout)



        self.main_widget.setFocus()
        self.setCentralWidget(self.main_widget)

        #self.statusBar().showMessage("All hail matplotlib!", 2000)

    def stopButtonOnClicked(self):
        print("\tStop button clicked")
        connMan = PirConnManager()
        connMan.sendStopCommand()



    def factorButtonOnClicked(self):
        print("\tChange emissivity factor button clicked")

        e = float(self.factorValue.text())

        # save only when e is in range
        if e >= 0.1 and e <= 1.0:
            connMan = PirConnManager()
            if True == connMan.saveEmissivity(e):
                print("Emmisivity changed to ", e)
            else:
                print("Error whiel saving emmisivity")
        else:
            print("Aborting. Wrong emmisivity value!")


    def onMeasureButtonOnClicked(self):
        print("\tOne Measuere button clicked")
        connMan = PirConnManager()
        temp = connMan.readOneSample("object")
        self.listWidget.addItem(str(round(temp[0],2))+ " °C")
        self.listWidget.setCurrentRow( self.listWidget.count() - 1 )

        # copy to clipboard
        # cl =  QApplication.clipboard()
        # cl.setText("TestTest")

        print(temp)

    def onCopyButtonCliced(self):
        # copy to clipboard
        cl =  QApplication.clipboard()

        items = []
        for index in range( self.listWidget.count()):
            items.append( self.listWidget.item(index).text())
            # print(self.listWidget.item(index).text())

        cl.setText(str(items))


        #cl.setText("TestTest")

    def fileQuit(self):
        self.close()

    def closeEvent(self, ce):
        print("exiting")
        self.fileQuit()

    def about(self):
        QtWidgets.QMessageBox.about(self, "")
Пример #54
0
class CityListDlg(QDialog):
    citieslist_signal = pyqtSignal([list])

    def __init__(self, citylist, accurate_url, appid, parent=None):
        super(CityListDlg, self).__init__(parent)
        self.citylist = citylist
        self.accurate_url = accurate_url
        self.appid = appid
        self.listWidget = QListWidget()
        self.listWidget.addItems(self.citylist)
        buttonLayout = QVBoxLayout()
        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        self.buttonBox.rejected.connect(self.reject)
        self.buttonBox.accepted.connect(self.accept)
        layoutT = QVBoxLayout()
        layout = QHBoxLayout()
        layout.addWidget(self.listWidget)
        layout.addLayout(buttonLayout)
        for text, slot in ((self.tr("&Add..."), self.add),
                           (self.tr("&Remove..."), self.remove),
                           (self.tr("&Up"), self.up),
                           (self.tr("&Down"), self.down),
                           (self.tr("De&fault"), self.default),
                           (self.tr("&Sort"), self.listWidget.sortItems)):
            button = QPushButton(text)
            buttonLayout.addWidget(button)
            button.clicked.connect(slot)
        buttonLayout.addWidget(self.buttonBox)
        self.status = QLabel()
        layoutT.addLayout(layout)
        layoutT.addWidget(self.status)
        self.setLayout(layoutT)
        self.checklength()

    def add(self):
        self.status.setText('')
        lista = []
        newitem = ''
        self.citytoadd = ''
        self.countrytoadd = ''
        self._idtoadd = ''
        dialog = searchcity.SearchCity(self.accurate_url, self.appid, self)
        dialog.id_signal.connect(self.addcity)
        dialog.city_signal.connect(self.addcity)
        dialog.country_signal.connect(self.addcity)
        if dialog.exec_() == 1:
            newitem = (self.citytoadd + '_' + self.countrytoadd + '_' +
                       self._idtoadd)
            for row in range(self.listWidget.count()):
                lista.append(self.listWidget.item(row).text())
            if newitem in lista:
                self.status.setText(QCoreApplication.translate('Status bar message',
                                    'The city already exists in the list', 'Cities list dialogue'))
                return
            else:
                self.listWidget.addItem(newitem)
                self.checklength()

    def addcity(self, what):
        self.status.setText('')
        if what[0] == 'ID':
            self._idtoadd = what[1]
        elif what[0] == 'City':
            self.citytoadd = what[1]
        elif what[0] == 'Country':
            self.countrytoadd = what[1]

    def remove(self):
        self.status.setText('')
        if self.listWidget.count() == 0:
            self.status.setText(self.tr('The list is empty'))
            return
        row = self.listWidget.currentRow()
        item = self.listWidget.item(row)
        if item is None:
            return
        message = self.tr('The city "{0}" has been removed').format(
            self.listWidget.item(row).text())
        item = self.listWidget.takeItem(row)
        del item
        self.status.setText(message)

    def up(self):
        self.status.setText('')
        row = self.listWidget.currentRow()
        if row >= 1:
            item = self.listWidget.takeItem(row)
            self.listWidget.insertItem(row - 1, item)
            self.listWidget.setCurrentItem(item)

    def down(self):
        self.status.setText('')
        row = self.listWidget.currentRow()
        if row < self.listWidget.count() - 1:
            item = self.listWidget.takeItem(row)
            self.listWidget.insertItem(row + 1, item)
            self.listWidget.setCurrentItem(item)

    def default(self):
        self.status.setText('')
        row = self.listWidget.currentRow()
        if row >= 1:
            item = self.listWidget.takeItem(row)
            self.listWidget.insertItem(0, item)
            self.listWidget.setCurrentItem(item)

    def checklength(self):
        listtosend = []
        for row in range(self.listWidget.count()):
            listtosend.append(self.listWidget.item(row).text())
        if len(listtosend) == 0:
            return
        self.listWidget.setMinimumWidth(self.listWidget.sizeHintForColumn(0))

    def accept(self):
        listtosend = []
        for row in range(self.listWidget.count()):
            listtosend.append(self.listWidget.item(row).text())
        self.citieslist_signal[list].emit(listtosend)
        QDialog.accept(self)
Пример #55
0
class CreateChatDialog(QDialog):
   def __init__(self):
      super().__init__()
      self.initUI()
      self.created_chat = False
      self.participants = []
      self.chat_name = None

      for friend in config.friends:
         self.unadded_friends.addItem(QListWidgetItem(friend))

   def initUI(self):
      self.setWindowModality(Qt.ApplicationModal)
      self.setWindowTitle("Create Chat")

      self.grid = QGridLayout(self)

      self.chat_name_label = QLabel("Chat Name:")
      self.grid.addWidget(self.chat_name_label, 0, 0, 1, 1)
      self.chat_name_field = QLineEdit()
      self.grid.addWidget(self.chat_name_field, 0, 1, 1, 3)

      self.unadded_friends = QListWidget()
      self.unadded_friends.setSortingEnabled(True)
      self.grid.addWidget(self.unadded_friends, 1, 0, 4, 2)

      self.added_friends = QListWidget()
      self.added_friends.setSortingEnabled(True)
      self.grid.addWidget(self.added_friends, 1, 3, 4, 1)

      self.add_friend_button = QPushButton(">>")
      self.add_friend_button.pressed.connect(self.addFriend)
      self.grid.addWidget(self.add_friend_button, 2, 2, 1, 1)

      self.remove_friend_button = QPushButton("<<")
      self.remove_friend_button.pressed.connect(self.removeFriend)
      self.grid.addWidget(self.remove_friend_button, 3, 2, 1, 1)

      self.create_button = QPushButton("Create")
      self.create_button.pressed.connect(self.createChat)
      self.grid.addWidget(self.create_button, 5, 0, 1, 4)

      self.cancel_button = QPushButton("Cancel")
      self.cancel_button.pressed.connect(self.cancel)
      self.grid.addWidget(self.cancel_button, 6, 0, 1, 4)

   def addFriend(self):
      selected_friends = self.unadded_friends.selectedItems()
      for friend in selected_friends:
         self.unadded_friends.takeItem(self.unadded_friends.row(friend))
         self.added_friends.addItem(friend)

   def removeFriend(self):
      selected_friends = self.added_friends.selectedItems()
      for friend in selected_friends:
         self.added_friends.takeItem(self.added_friends.row(friend))
         self.unadded_friends.addItem(friend)

   def createChat(self):
      self.created_chat = True
      self.chat_name = self.chat_name_field.text()
      for i in range(self.added_friends.count()):
         self.participants.append(self.added_friends.item(i).text())
      config.chats[self.chat_name] = {"participants": self.participants}
      self.close()

   def cancel(self):
      self.close()
Пример #56
0
class MainScreen(QMainWindow):
    """The Main GUI layout and callbacks.
    """
    def __init__(self) -> None:

        logging.info("Initialize MainScreen")
        super().__init__(parent=None)

        self._traffic: Optional[Traffic] = None
        self._tview: Optional[Traffic] = None
        self.decoder: Optional[ModeS_Decoder] = None
        self.updateTraffic: Optional[UpdateTraffic] = None
        self.airspace_ready: bool = False
        self.last_interact: datetime = datetime.now()

        airspace_init = AirspaceInitCache(self)
        airspace_init.start()

        self.setWindowTitle("traffic")
        self.setGeometry(10, 10, 920, 720)

        self.set_icons()
        self.set_layout()
        self.set_design()
        self.set_callbacks()

    def __del__(self) -> None:
        if self.updateTraffic is not None:
            self.updateTraffic.terminate()
        if self.decoder is not None:
            self.decoder.stop()

    @property
    def traffic(self) -> Optional[Traffic]:
        self.last_interact = datetime.now()
        if self.decoder is not None:
            self._traffic = self.decoder.traffic
            if self._traffic is None:
                return None
            self.set_time_range()
            # self.set_float_columns()
        #            max_alt = 100 * self.altitude_slider.value()
        #            max_time = self.dates[self.time_slider.value()]
        #            self.on_filter(max_alt, max_time)
        return self._traffic

    def set_callbacks(self) -> None:
        self.airport_button.clicked.connect(self.on_plot_airport)
        self.altitude_slider.sliderMoved.connect(self.on_altitude_moved)
        self.altitude_slider.sliderReleased.connect(self.on_select)
        self.area_input.textEdited.connect(self.on_area_input)
        self.area_select.itemSelectionChanged.connect(self.on_area_select)
        self.extent_button.clicked.connect(self.on_extent_button)
        self.identifier_input.textEdited.connect(self.on_id_input)
        self.identifier_select.itemSelectionChanged.connect(self.on_id_change)
        self.open_dropdown.activated.connect(self.on_open)
        self.plot_button.clicked.connect(self.on_plot_button)
        self.projection_dropdown.activated.connect(self.make_map)
        self.reset_button.clicked.connect(self.on_clear_button)
        self.time_slider.sliderMoved.connect(self.on_time_moved)
        self.time_slider.sliderReleased.connect(self.on_select)
        self.y_selector.itemSelectionChanged.connect(self.on_id_change)
        self.sec_y_selector.itemSelectionChanged.connect(self.on_id_change)

    def set_design(self) -> None:
        self.open_dropdown.setMaximumWidth(400)
        self.projection_dropdown.setMaximumWidth(400)
        self.altitude_description.setMinimumWidth(100)
        self.altitude_description.setMaximumWidth(100)
        self.altitude_slider_info.setMinimumWidth(50)
        self.altitude_slider_info.setMaximumWidth(50)
        self.altitude_slider.setMaximumWidth(240)
        self.area_input_description.setMinimumWidth(100)
        self.area_input_description.setMaximumWidth(100)
        self.area_input.setMaximumWidth(290)
        self.area_select.setMaximumHeight(100)
        self.area_select.setMaximumWidth(400)
        self.identifier_description.setMinimumWidth(100)
        self.identifier_description.setMaximumWidth(100)
        self.identifier_input.setMaximumWidth(290)
        self.identifier_select.setMaximumWidth(400)
        self.time_description.setMinimumWidth(100)
        self.time_description.setMaximumWidth(100)
        self.time_slider_info.setMinimumWidth(50)
        self.time_slider_info.setMaximumWidth(50)
        self.time_slider.setMaximumWidth(240)
        self.y_selector.setMaximumHeight(100)
        self.sec_y_selector.setMaximumHeight(100)

    def set_layout(self) -> None:

        self.plot_tabs = QTabWidget()
        map_tab = QWidget()
        map_layout = QVBoxLayout()
        map_tab.setLayout(map_layout)

        self.map_plot = MapCanvas(parent=self, width=5, height=4)
        self.map_plot.move(0, 0)
        self.time_plot = TimeCanvas(parent=self, width=5, height=4)
        self.time_plot.move(0, 0)

        map_toolbar = NavigationToolbar2QT(self.map_plot, map_tab)
        map_toolbar.setVisible(False)
        map_layout.addWidget(map_toolbar)
        map_layout.addWidget(self.map_plot)
        map_toolbar.pan()

        time_tab = QWidget()
        time_layout = QVBoxLayout()
        time_tab.setLayout(time_layout)

        self.y_selector = QListWidget()
        self.sec_y_selector = QListWidget()
        self.y_selector.setSelectionMode(3)  # extended selection
        self.sec_y_selector.setSelectionMode(3)  # extended selection
        selector = QHBoxLayout()
        selector.addWidget(self.y_selector)
        selector.addWidget(self.sec_y_selector)

        time_layout.addLayout(selector)
        time_layout.addWidget(self.time_plot)

        self.plot_tabs.addTab(map_tab, "Map")
        self.plot_tabs.addTab(time_tab, "Plots")

        plot_column = QVBoxLayout()
        plot_column.addWidget(self.plot_tabs)

        self.interact_column = QVBoxLayout()

        self.open_options = ["Open file", "dump1090"]
        if "decoders" in config:
            self.open_options += list(config["decoders"])
        self.open_dropdown = QComboBox()
        for option in self.open_options:
            self.open_dropdown.addItem(option)
        self.interact_column.addWidget(self.open_dropdown)

        self.projections = ["EuroPP", "Lambert93", "Mercator"]
        self.projection_dropdown = QComboBox()
        more_projs = config.get("projections", "extra", fallback="")
        if more_projs != "":
            proj_list = more_projs.split(";")
            self.projections += list(x.strip() for x in proj_list)
        for proj in self.projections:
            self.projection_dropdown.addItem(proj)
        self.interact_column.addWidget(self.projection_dropdown)

        button_grid = QGridLayout()

        self.extent_button = QPushButton("Extent")
        button_grid.addWidget(self.extent_button, 0, 0)
        self.plot_button = QPushButton("Plot")
        button_grid.addWidget(self.plot_button, 0, 1)
        self.airport_button = QPushButton("Airport")
        button_grid.addWidget(self.airport_button, 1, 0)
        self.reset_button = QPushButton("Reset")
        button_grid.addWidget(self.reset_button, 1, 1)

        self.interact_column.addLayout(button_grid)

        self.area_input_description = QLabel("Area")
        self.area_input = QLineEdit()
        area_input_layout = QHBoxLayout()
        area_input_layout.addWidget(self.area_input_description)
        area_input_layout.addWidget(self.area_input)
        self.interact_column.addLayout(area_input_layout)

        self.area_select = QListWidget()
        self.interact_column.addWidget(self.area_select)

        self.time_slider = QSlider(QtCore.Qt.Horizontal)
        self.time_description = QLabel("Date max.")
        self.time_slider_info = QLabel()
        time_layout = QHBoxLayout()
        time_layout.addWidget(self.time_description)
        time_layout.addWidget(self.time_slider)
        time_layout.addWidget(self.time_slider_info)
        self.time_slider.setMinimum(0)
        self.time_slider.setMaximum(99)
        self.time_slider.setValue(99)
        self.time_slider.setEnabled(False)
        self.interact_column.addLayout(time_layout)

        self.altitude_slider = QSlider(QtCore.Qt.Horizontal)
        self.altitude_description = QLabel("Altitude max.")
        self.altitude_slider_info = QLabel("60000")
        self.altitude_slider.setSingleStep(5)
        self.altitude_slider.setPageStep(100)
        self.altitude_slider.setMinimum(0)
        self.altitude_slider.setMaximum(600)
        self.altitude_slider.setValue(600)
        altitude_layout = QHBoxLayout()
        altitude_layout.addWidget(self.altitude_description)
        altitude_layout.addWidget(self.altitude_slider)
        altitude_layout.addWidget(self.altitude_slider_info)
        self.interact_column.addLayout(altitude_layout)

        self.identifier_description = QLabel("Callsign/ID")
        self.identifier_input = QLineEdit()

        identifier_layout = QHBoxLayout()
        identifier_layout.addWidget(self.identifier_description)
        identifier_layout.addWidget(self.identifier_input)
        self.interact_column.addLayout(identifier_layout)

        self.identifier_select = QListWidget()
        self.identifier_select.setSelectionMode(3)  # extended selection
        self.interact_column.addWidget(self.identifier_select)

        mainLayout = QGridLayout()
        mainLayout.addLayout(plot_column, 0, 0)
        mainLayout.addLayout(self.interact_column, 0, 1)

        mainWidget = QWidget()
        mainWidget.setLayout(mainLayout)
        self.setCentralWidget(mainWidget)

    # -- Callbacks --

    @dont_crash
    def on_time_moved(self, value: int, *args, **kwargs) -> None:
        self.last_interact = datetime.now()
        self.time_slider_info.setText(self.date_options[value])

    @dont_crash
    def on_altitude_moved(self, value: int, *args, **kwargs) -> None:
        self.last_interact = datetime.now()
        self.altitude_slider_info.setText(f"{100*value}")

    @dont_crash
    def on_select(self, *args, **kwargs) -> None:
        self.last_interact = datetime.now()
        if self.traffic is not None:
            max_alt = 100 * self.altitude_slider.value()
            max_time = self.dates[self.time_slider.value()]
            self.on_filter(max_alt, max_time)

    @dont_crash
    def on_filter(self, max_alt: int, max_time: datetime) -> None:

        assert self._traffic is not None

        west, east, south, north = self.map_plot.ax.get_extent(
            crs=PlateCarree())

        self._tview = self._traffic.before(max_time).sort_values("timestamp")

        if self._tview is None:
            return

        filtered = Traffic.from_flights(
            Flight(f.data.ffill().bfill()) for f in self._tview)
        if "altitude" in filtered.data.columns:
            filtered = filtered.query(
                f"altitude != altitude or altitude <= {max_alt}")
        if "latitude" in self._tview.data.columns:
            filtered = filtered.query("latitude != latitude or "
                                      f"({west} <= longitude <= {east} and "
                                      f"{south} <= latitude <= {north})")

        self.identifier_select.clear()
        text = self.identifier_input.text()
        # cast is necessary because of the @lru_cache on callsigns which hides
        # the type annotation
        for callsign in sorted(cast(Set[str], filtered.callsigns)):
            if re.match(text, callsign, flags=re.IGNORECASE):
                self.identifier_select.addItem(callsign)

        callsigns = cast(Set[str], filtered.callsigns)
        self.map_plot.default_plot(self._tview[callsigns])
        self.set_float_columns()

    @dont_crash
    def on_extent_button(self, *args, **kwargs) -> None:
        self.last_interact = datetime.now()
        if self.area_select.count() == 0:
            if len(self.area_input.text()) == 0:
                self.map_plot.ax.set_global()
            else:
                self.map_plot.ax.set_extent(location(self.area_input.text()))
        else:
            if self.airspace_ready:
                self.map_plot.ax.set_extent(
                    aixm_airspaces[self.area_select.item(0).text()])

        self.map_plot.draw()

        if self.traffic is not None:
            max_alt = 100 * self.altitude_slider.value()
            max_time = self.dates[self.time_slider.value()]
            self.on_filter(max_alt, max_time)

    @dont_crash
    def on_id_change(self, *args, **kwargs) -> None:
        assert self._tview is not None
        self.last_interact = datetime.now()

        list_callsigns = list(
            item.text() for item in self.identifier_select.selectedItems())
        selected_y = list(item.text()
                          for item in self.y_selector.selectedItems())
        selected_sec_y = list(item.text()
                              for item in self.sec_y_selector.selectedItems())
        self.map_plot.plot_callsigns(self._tview, list_callsigns)
        self.time_plot.create_plot()
        self.time_plot.plot_callsigns(
            self._tview,
            list_callsigns,
            y=selected_y + selected_sec_y,
            secondary_y=selected_sec_y,
        )

    @dont_crash
    def on_id_input(self, text, *args, **kwargs) -> None:
        assert self._tview is not None
        self.last_interact = datetime.now()
        # segfault prone when interactive (decoder)
        # selected = list(
        #     item.text() for item in self.identifier_select.selectedItems()
        # )
        self.identifier_select.clear()
        for callsign in sorted(cast(Set[str], self._tview.callsigns)):
            if re.match(text, callsign, flags=re.IGNORECASE):
                self.identifier_select.addItem(callsign)
                # if callsign in selected:
                #     curItem = self.identifier_select.item(
                #         self.identifier_select.count() - 1
                #     )
                #     self.identifier_select.setItemSelected(curItem, True)

    @dont_crash
    def on_plot_button(self, *args, **kwargs) -> None:
        assert self._tview is not None
        self.last_interact = datetime.now()
        if self.area_select.count() == 0:
            if len(self.area_input.text()) == 0:
                self.map_plot.default_plot(self._tview)
            else:
                location(self.area_input.text()).plot(
                    self.map_plot.ax,
                    color="#524c50",
                    linestyle="dotted",
                    linewidth=0.5,
                )
        else:
            if self.airspace_ready:
                selected = self.area_select.selectedItems()
                if len(selected) == 0:
                    return
                airspace = aixm_airspaces[selected[0].text()]
                if airspace is not None:
                    airspace.plot(self.map_plot.ax)

        self.map_plot.draw()

    @dont_crash
    def on_area_input(self, text: str, *args, **kwargs) -> None:
        self.last_interact = datetime.now()
        self.area_select.clear()
        if len(text) > 0 and self.airspace_ready:
            for airspace_info in aixm_airspaces.parse(text):
                self.area_select.addItem(airspace_info.name)

    @dont_crash
    def on_area_select(self, *args, **kwargs) -> None:
        self.last_interact = datetime.now()
        selected = self.area_select.selectedItems()
        if len(selected) == 0:
            return
        if self.airspace_ready:
            airspace = aixm_airspaces[selected[0].text()]
            if airspace is not None:
                self.map_plot.ax.set_extent(airspace)
                self.map_plot.draw()

    @dont_crash
    def on_plot_airport(self, *args, **kwargs) -> None:
        self.last_interact = datetime.now()
        if len(self.area_input.text()) == 0:
            from cartotools.osm import request, tags

            west, east, south, north = self.map_plot.ax.get_extent(
                crs=PlateCarree())
            if abs(east - west) > 1 or abs(north - south) > 1:
                # that would be a too big request
                return
            request((west, south, east, north),
                    **tags.airport).plot(self.map_plot.ax)
        else:
            from traffic.data import airports

            airport = airports[self.area_input.text()]
            if airport is not None:
                airport.plot(self.map_plot.ax)
        self.map_plot.draw()

    @dont_crash
    def on_clear_button(self, *args, **kwargs) -> None:
        self.last_interact = datetime.now()
        if self.traffic is not None:
            assert self._traffic is not None
            self._tview = self._traffic.sort_values("timestamp")
            self.altitude_slider.setValue(600)
            self.make_map(self.projection_dropdown.currentIndex())
            self.time_plot.create_plot()
            self.set_float_columns()

    @dont_crash
    def make_map(self, index_projection: int, *args, **kwargs) -> None:
        self.last_interact = datetime.now()
        self.map_plot.create_map(self.projections[index_projection])
        if self._tview is not None:
            self.map_plot.default_plot(self._tview)

    @dont_crash
    def on_open(self, index: int, *args, **kwargs) -> None:
        if self.decoder is not None and self.updateTraffic is not None:
            self.updateTraffic.terminate()
            self.decoder.stop()
        if index == 0:
            self.openFile()
        elif index == 1:
            self.openDump1090()
        else:
            address = config.get("decoders", self.open_options[index])
            host_port, reference = address.split("/")
            host, port = host_port.split(":")
            self.decoder = ModeS_Decoder.from_address(host, int(port),
                                                      reference)
            refresh_time = config.getint("decoders",
                                         "refresh_time",
                                         fallback=30)
            self.updateTraffic = UpdateTraffic(self, refresh_time)
            self.updateTraffic.start()

    # -- Basic setters --

    def set_icons(self) -> None:

        logging.info("Setting options")
        icon_path = Path(traffic.__file__).absolute().parent.parent / "icons"
        if sys.platform == "linux":
            icon_full = QtGui.QIcon(
                (icon_path / "travel-beige.svg").as_posix())
        elif sys.platform == "darwin":
            icon_full = QtGui.QIcon((icon_path / "travel-grey.svg").as_posix())
        else:
            icon_full = QtGui.QIcon(
                (icon_path / "travel-orange.svg").as_posix())

        self.setWindowIcon(icon_full)

    def set_time_range(self) -> None:
        assert self._traffic is not None
        self.time_slider.setEnabled(True)
        start_time = cast(pd.Timestamp, self._traffic.start_time)
        end_time = cast(pd.Timestamp, self._traffic.end_time)
        self.dates = [
            start_time + i * (end_time - start_time) / 99 for i in range(100)
        ]

        tz_now = datetime.now().astimezone().tzinfo
        if cast(pd.Timestamp, self._traffic.start_time).tzinfo is not None:
            self.date_options = [
                t.tz_convert("utc").strftime("%H:%M") for t in self.dates
            ]
        else:
            self.date_options = [
                t.tz_localize(tz_now).tz_convert("utc").strftime("%H:%M")
                for t in self.dates
            ]
        self.time_slider_info.setText(self.date_options[-1])

    def set_float_columns(self) -> None:
        assert self._traffic is not None
        self.y_selector.clear()
        self.sec_y_selector.clear()
        for column, dtype in self._traffic.data.dtypes.items():
            if column not in ("latitude", "longitude"):
                if dtype in ["float64", "int64"]:
                    self.y_selector.addItem(column)
                    self.sec_y_selector.addItem(column)

    def openDump1090(self) -> None:
        reference, ok = QInputDialog.getText(self, "dump1090 reference",
                                             "Reference airport:")

        if ok:
            self.open_dropdown.setItemText(1, f"dump1090 ({reference})")
            self.decoder = ModeS_Decoder.from_dump1090(reference)
            refresh_time = config.getint("decoders",
                                         "refresh_time",
                                         fallback=30)
            self.updateTraffic = UpdateTraffic(self, refresh_time)
            self.updateTraffic.start()

    @dont_crash
    def openFile(self, *args, **kwargs) -> None:
        options = {
            "caption":
            "Open file",
            "filter": ("Pandas DataFrame (*.pkl);;"
                       "CSV files (*.csv);;"
                       "Sqlite3 files (*.db)"),
            #             "filter": "Data files (*.csv *.pkl)",
            "directory":
            os.path.expanduser("~"),
        }

        self.filename = QFileDialog.getOpenFileName(self, **options)[0]
        if self.filename == "":
            return
        self.filename = Path(self.filename)
        self._traffic = Traffic.from_file(self.filename)

        assert self._traffic is not None
        self._tview = self._traffic.sort_values("timestamp")
        assert self._tview is not None
        self.open_dropdown.setItemText(0, self.filename.name)
        self.map_plot.default_plot(self._tview)

        self.identifier_select.clear()
        for callsign in sorted(cast(Set[str], self._tview.callsigns)):
            self.identifier_select.addItem(callsign)

        self.set_time_range()
        self.set_float_columns()
Пример #57
0
class SettingsDialog(QDialog):
    worker = None
    config = None
    configfile = None

    saved = QtCore.pyqtSignal()

    def __init__(self, parent, worker, config, configfile):
        QDialog.__init__(self, parent)

        self.worker = worker
        self.config = config
        self.configfile = configfile
        self.setStyleSheet("QGroupBox { font-weight: bold; } ")
        self.setWindowTitle('Settings')
        layout = QGridLayout()

        # Categories
        self.category_list = QListWidget()
        category_media = QListWidgetItem(getIcon('media-playback-start'), 'Media', self.category_list)
        category_sync = QListWidgetItem(getIcon('view-refresh'), 'Sync', self.category_list)
        category_ui = QListWidgetItem(getIcon('window-new'), 'User Interface', self.category_list)
        category_theme = QListWidgetItem(getIcon('applications-graphics'), 'Theme', self.category_list)
        self.category_list.setSelectionMode(QAbstractItemView.SingleSelection)
        self.category_list.setCurrentRow(0)
        self.category_list.setMaximumWidth(self.category_list.sizeHintForColumn(0) + 15)
        self.category_list.setFocus()
        self.category_list.currentItemChanged.connect(self.s_switch_page)

        # Media tab
        page_media = QWidget()
        page_media_layout = QVBoxLayout()
        page_media_layout.setAlignment(QtCore.Qt.AlignTop)

        # Group: Media settings
        g_media = QGroupBox('Media settings')
        g_media.setFlat(True)
        g_media_layout = QFormLayout()
        self.tracker_enabled = QCheckBox()
        self.tracker_enabled.toggled.connect(self.tracker_type_change)

        self.tracker_type = QComboBox()
        for (n, label) in utils.available_trackers:
            self.tracker_type.addItem(label, n)
        self.tracker_type.currentIndexChanged.connect(self.tracker_type_change)

        self.tracker_interval = QSpinBox()
        self.tracker_interval.setRange(5, 1000)
        self.tracker_interval.setMaximumWidth(60)
        self.tracker_process = QLineEdit()
        self.tracker_update_wait = QSpinBox()
        self.tracker_update_wait.setRange(0, 1000)
        self.tracker_update_wait.setMaximumWidth(60)
        self.tracker_update_close = QCheckBox()
        self.tracker_update_prompt = QCheckBox()
        self.tracker_not_found_prompt = QCheckBox()

        g_media_layout.addRow('Enable tracker', self.tracker_enabled)
        g_media_layout.addRow('Tracker type', self.tracker_type)
        g_media_layout.addRow('Tracker interval (seconds)', self.tracker_interval)
        g_media_layout.addRow('Process name (regex)', self.tracker_process)
        g_media_layout.addRow('Wait before updating (seconds)', self.tracker_update_wait)
        g_media_layout.addRow('Wait until the player is closed', self.tracker_update_close)
        g_media_layout.addRow('Ask before updating', self.tracker_update_prompt)
        g_media_layout.addRow('Ask to add new shows', self.tracker_not_found_prompt)

        g_media.setLayout(g_media_layout)

        # Group: Plex settings
        g_plex = QGroupBox('Plex Media Server')
        g_plex.setFlat(True)
        self.plex_host = QLineEdit()
        self.plex_port = QLineEdit()
        self.plex_user = QLineEdit()
        self.plex_passw = QLineEdit()
        self.plex_passw.setEchoMode(QLineEdit.Password)
        self.plex_obey_wait = QCheckBox()

        g_plex_layout = QGridLayout()
        g_plex_layout.addWidget(QLabel('Host and Port'),                   0, 0, 1, 1)
        g_plex_layout.addWidget(self.plex_host,                            0, 1, 1, 1)
        g_plex_layout.addWidget(self.plex_port,                            0, 2, 1, 2)
        g_plex_layout.addWidget(QLabel('Use "wait before updating" time'), 1, 0, 1, 1)
        g_plex_layout.addWidget(self.plex_obey_wait,                       1, 2, 1, 1)
        g_plex_layout.addWidget(QLabel('myPlex login (claimed server)'),   2, 0, 1, 1)
        g_plex_layout.addWidget(self.plex_user,                            2, 1, 1, 1)
        g_plex_layout.addWidget(self.plex_passw,                           2, 2, 1, 2)

        g_plex.setLayout(g_plex_layout)

        # Group: Library
        g_playnext = QGroupBox('Library')
        g_playnext.setFlat(True)
        self.player = QLineEdit()
        self.player_browse = QPushButton('Browse...')
        self.player_browse.clicked.connect(self.s_player_browse)
        lbl_searchdirs = QLabel('Media directories')
        lbl_searchdirs.setAlignment(QtCore.Qt.AlignTop)
        self.searchdirs = QListWidget()
        self.searchdirs_add = QPushButton('Add...')
        self.searchdirs_add.clicked.connect(self.s_searchdirs_add)
        self.searchdirs_remove = QPushButton('Remove')
        self.searchdirs_remove.clicked.connect(self.s_searchdirs_remove)
        self.searchdirs_buttons = QVBoxLayout()
        self.searchdirs_buttons.setAlignment(QtCore.Qt.AlignTop)
        self.searchdirs_buttons.addWidget(self.searchdirs_add)
        self.searchdirs_buttons.addWidget(self.searchdirs_remove)
        self.searchdirs_buttons.addWidget(QSplitter())
        self.library_autoscan = QCheckBox()
        self.scan_whole_list = QCheckBox()
        self.library_full_path = QCheckBox()


        g_playnext_layout = QGridLayout()
        g_playnext_layout.addWidget(QLabel('Player'),                    0, 0, 1, 1)
        g_playnext_layout.addWidget(self.player,                         0, 1, 1, 1)
        g_playnext_layout.addWidget(self.player_browse,                  0, 2, 1, 1)
        g_playnext_layout.addWidget(lbl_searchdirs,                      1, 0, 1, 1)
        g_playnext_layout.addWidget(self.searchdirs,                     1, 1, 1, 1)
        g_playnext_layout.addLayout(self.searchdirs_buttons,             1, 2, 1, 1)
        g_playnext_layout.addWidget(QLabel('Rescan Library at startup'), 2, 0, 1, 2)
        g_playnext_layout.addWidget(self.library_autoscan,               2, 2, 1, 1)
        g_playnext_layout.addWidget(QLabel('Scan through whole list'),   3, 0, 1, 2)
        g_playnext_layout.addWidget(self.scan_whole_list,                3, 2, 1, 1)
        g_playnext_layout.addWidget(QLabel('Take subdirectory name into account'), 4, 0, 1, 2)
        g_playnext_layout.addWidget(self.library_full_path,              4, 2, 1, 1)

        g_playnext.setLayout(g_playnext_layout)

        # Media form
        page_media_layout.addWidget(g_media)
        page_media_layout.addWidget(g_plex)
        page_media_layout.addWidget(g_playnext)
        page_media.setLayout(page_media_layout)

        # Sync tab
        page_sync = QWidget()
        page_sync_layout = QVBoxLayout()
        page_sync_layout.setAlignment(QtCore.Qt.AlignTop)

        # Group: Autoretrieve
        g_autoretrieve = QGroupBox('Autoretrieve')
        g_autoretrieve.setFlat(True)
        self.autoretrieve_off = QRadioButton('Disabled')
        self.autoretrieve_always = QRadioButton('Always at start')
        self.autoretrieve_days = QRadioButton('After n days')
        self.autoretrieve_days.toggled.connect(self.s_autoretrieve_days)
        self.autoretrieve_days_n = QSpinBox()
        self.autoretrieve_days_n.setRange(1, 100)
        g_autoretrieve_layout = QGridLayout()
        g_autoretrieve_layout.setColumnStretch(0, 1)
        g_autoretrieve_layout.addWidget(self.autoretrieve_off,    0, 0, 1, 1)
        g_autoretrieve_layout.addWidget(self.autoretrieve_always, 1, 0, 1, 1)
        g_autoretrieve_layout.addWidget(self.autoretrieve_days,   2, 0, 1, 1)
        g_autoretrieve_layout.addWidget(self.autoretrieve_days_n, 2, 1, 1, 1)
        g_autoretrieve.setLayout(g_autoretrieve_layout)

        # Group: Autosend
        g_autosend = QGroupBox('Autosend')
        g_autosend.setFlat(True)
        self.autosend_off = QRadioButton('Disabled')
        self.autosend_always = QRadioButton('Immediately after every change')
        self.autosend_minutes = QRadioButton('After n minutes')
        self.autosend_minutes.toggled.connect(self.s_autosend_minutes)
        self.autosend_minutes_n = QSpinBox()
        self.autosend_minutes_n.setRange(1, 1000)
        self.autosend_size = QRadioButton('After the queue reaches n items')
        self.autosend_size.toggled.connect(self.s_autosend_size)
        self.autosend_size_n = QSpinBox()
        self.autosend_size_n.setRange(2, 20)
        self.autosend_at_exit = QCheckBox('At exit')
        g_autosend_layout = QGridLayout()
        g_autosend_layout.setColumnStretch(0, 1)
        g_autosend_layout.addWidget(self.autosend_off,      0, 0, 1, 1)
        g_autosend_layout.addWidget(self.autosend_always,   1, 0, 1, 1)
        g_autosend_layout.addWidget(self.autosend_minutes,    2, 0, 1, 1)
        g_autosend_layout.addWidget(self.autosend_minutes_n,  2, 1, 1, 1)
        g_autosend_layout.addWidget(self.autosend_size,     3, 0, 1, 1)
        g_autosend_layout.addWidget(self.autosend_size_n,   3, 1, 1, 1)
        g_autosend_layout.addWidget(self.autosend_at_exit,  4, 0, 1, 1)
        g_autosend.setLayout(g_autosend_layout)

        # Group: Extra
        g_extra = QGroupBox('Additional options')
        g_extra.setFlat(True)
        self.auto_status_change = QCheckBox('Change status automatically')
        self.auto_status_change.toggled.connect(self.s_auto_status_change)
        self.auto_status_change_if_scored = QCheckBox('Change status automatically only if scored')
        self.auto_date_change = QCheckBox('Change start and finish dates automatically')
        g_extra_layout = QVBoxLayout()
        g_extra_layout.addWidget(self.auto_status_change)
        g_extra_layout.addWidget(self.auto_status_change_if_scored)
        g_extra_layout.addWidget(self.auto_date_change)
        g_extra.setLayout(g_extra_layout)

        # Sync layout
        page_sync_layout.addWidget(g_autoretrieve)
        page_sync_layout.addWidget(g_autosend)
        page_sync_layout.addWidget(g_extra)
        page_sync.setLayout(page_sync_layout)

        # UI tab
        page_ui = QWidget()
        page_ui_layout = QFormLayout()
        page_ui_layout.setAlignment(QtCore.Qt.AlignTop)

        # Group: Icon
        g_icon = QGroupBox('Notification Icon')
        g_icon.setFlat(True)
        self.tray_icon = QCheckBox('Show tray icon')
        self.tray_icon.toggled.connect(self.s_tray_icon)
        self.close_to_tray = QCheckBox('Close to tray')
        self.start_in_tray = QCheckBox('Start minimized to tray')
        self.tray_api_icon = QCheckBox('Use API icon as tray icon')
        self.notifications = QCheckBox('Show notification when tracker detects new media')
        g_icon_layout = QVBoxLayout()
        g_icon_layout.addWidget(self.tray_icon)
        g_icon_layout.addWidget(self.close_to_tray)
        g_icon_layout.addWidget(self.start_in_tray)
        g_icon_layout.addWidget(self.tray_api_icon)
        g_icon_layout.addWidget(self.notifications)
        g_icon.setLayout(g_icon_layout)

        # Group: Window
        g_window = QGroupBox('Window')
        g_window.setFlat(True)
        self.remember_geometry = QCheckBox('Remember window size and position')
        self.remember_columns = QCheckBox('Remember column layouts and widths')
        self.columns_per_api = QCheckBox('Use different visible columns per API')
        g_window_layout = QVBoxLayout()
        g_window_layout.addWidget(self.remember_geometry)
        g_window_layout.addWidget(self.remember_columns)
        g_window_layout.addWidget(self.columns_per_api)
        g_window.setLayout(g_window_layout)

        # Group: Lists
        g_lists = QGroupBox('Lists')
        g_lists.setFlat(True)
        self.filter_bar_position = QComboBox()
        filter_bar_positions = [(FilterBar.PositionHidden,     'Hidden'),
                                (FilterBar.PositionAboveLists, 'Above lists'),
                                (FilterBar.PositionBelowLists, 'Below lists')]
        for (n, label) in filter_bar_positions:
            self.filter_bar_position.addItem(label, n)
        self.inline_edit = QCheckBox('Enable in-line editing')
        g_lists_layout = QFormLayout()
        g_lists_layout.addRow('Filter bar position:', self.filter_bar_position)
        g_lists_layout.addRow(self.inline_edit)
        g_lists.setLayout(g_lists_layout)

        # UI layout
        page_ui_layout.addWidget(g_icon)
        page_ui_layout.addWidget(g_window)
        page_ui_layout.addWidget(g_lists)
        page_ui.setLayout(page_ui_layout)

        # Theming tab
        page_theme = QWidget()
        page_theme_layout = QFormLayout()
        page_theme_layout.setAlignment(QtCore.Qt.AlignTop)

        # Group: Episode Bar
        g_ep_bar = QGroupBox('Episode Bar')
        g_ep_bar.setFlat(True)
        self.ep_bar_style = QComboBox()
        ep_bar_styles = [(ShowsTableDelegate.BarStyleBasic,  'Basic'),
                         (ShowsTableDelegate.BarStyle04,     'Trackma'),
                         (ShowsTableDelegate.BarStyleHybrid, 'Hybrid')]
        for (n, label) in ep_bar_styles:
            self.ep_bar_style.addItem(label, n)
        self.ep_bar_style.currentIndexChanged.connect(self.s_ep_bar_style)
        self.ep_bar_text = QCheckBox('Show text label')
        g_ep_bar_layout = QFormLayout()
        g_ep_bar_layout.addRow('Style:', self.ep_bar_style)
        g_ep_bar_layout.addRow(self.ep_bar_text)
        g_ep_bar.setLayout(g_ep_bar_layout)

        # Group: Colour scheme
        g_scheme = QGroupBox('Color Scheme')
        g_scheme.setFlat(True)
        col_tabs = [('rows',     '&Row highlights'),
                    ('progress', '&Progress widget')]
        self.colors = {}
        self.colors['rows'] = [('is_playing',  'Playing'),
                               ('is_queued',   'Queued'),
                               ('new_episode', 'New Episode'),
                               ('is_airing',   'Airing'),
                               ('not_aired',   'Unaired')]
        self.colors['progress'] = [('progress_bg',       'Background'),
                                   ('progress_fg',       'Watched bar'),
                                   ('progress_sub_bg',   'Aired episodes'),
                                   ('progress_sub_fg',   'Stored episodes'),
                                   ('progress_complete', 'Complete')]
        self.color_buttons = []
        self.syscolor_buttons = []
        g_scheme_layout = QGridLayout()
        tw_scheme = QTabWidget()
        for (key, tab_title) in col_tabs:
            page = QFrame()
            page_layout = QGridLayout()
            col = 0
            # Generate widgets from the keys and values
            for (key, label) in self.colors[key]:
                self.color_buttons.append(QPushButton())
                # self.color_buttons[-1].setStyleSheet('background-color: ' + getColor(self.config['colors'][key]).name())
                self.color_buttons[-1].setFocusPolicy(QtCore.Qt.NoFocus)
                self.color_buttons[-1].clicked.connect(self.s_color_picker(key, False))
                self.syscolor_buttons.append(QPushButton('System Colors'))
                self.syscolor_buttons[-1].clicked.connect(self.s_color_picker(key, True))
                page_layout.addWidget(QLabel(label),             col, 0, 1, 1)
                page_layout.addWidget(self.color_buttons[-1],    col, 1, 1, 1)
                page_layout.addWidget(self.syscolor_buttons[-1], col, 2, 1, 1)
                col += 1
            page.setLayout(page_layout)
            tw_scheme.addTab(page, tab_title)
        g_scheme_layout.addWidget(tw_scheme)
        g_scheme.setLayout(g_scheme_layout)

        # UI layout
        page_theme_layout.addWidget(g_ep_bar)
        page_theme_layout.addWidget(g_scheme)
        page_theme.setLayout(page_theme_layout)

        # Content
        self.contents = QStackedWidget()
        self.contents.addWidget(page_media)
        self.contents.addWidget(page_sync)
        self.contents.addWidget(page_ui)
        self.contents.addWidget(page_theme)
        if pyqt_version is not 5:
            self.contents.layout().setMargin(0)

        # Bottom buttons
        bottombox = QDialogButtonBox(
            QDialogButtonBox.Ok
            | QDialogButtonBox.Apply
            | QDialogButtonBox.Cancel
        )
        bottombox.accepted.connect(self.s_save)
        bottombox.button(QDialogButtonBox.Apply).clicked.connect(self._save)
        bottombox.rejected.connect(self.reject)

        # Main layout finish
        layout.addWidget(self.category_list,  0, 0, 1, 1)
        layout.addWidget(self.contents,       0, 1, 1, 1)
        layout.addWidget(bottombox,           1, 0, 1, 2)
        layout.setColumnStretch(1, 1)

        self._load()
        self.update_colors()

        self.setLayout(layout)

    def _add_dir(self, path):
        self.searchdirs.addItem(path)

    def _load(self):
        engine = self.worker.engine
        tracker_type = self.tracker_type.findData(engine.get_config('tracker_type'))
        autoretrieve = engine.get_config('autoretrieve')
        autosend = engine.get_config('autosend')

        self.tracker_enabled.setChecked(engine.get_config('tracker_enabled'))
        self.tracker_type.setCurrentIndex(max(0, tracker_type))
        self.tracker_interval.setValue(engine.get_config('tracker_interval'))
        self.tracker_process.setText(engine.get_config('tracker_process'))
        self.tracker_update_wait.setValue(engine.get_config('tracker_update_wait_s'))
        self.tracker_update_close.setChecked(engine.get_config('tracker_update_close'))
        self.tracker_update_prompt.setChecked(engine.get_config('tracker_update_prompt'))
        self.tracker_not_found_prompt.setChecked(engine.get_config('tracker_not_found_prompt'))

        self.player.setText(engine.get_config('player'))
        self.library_autoscan.setChecked(engine.get_config('library_autoscan'))
        self.scan_whole_list.setChecked(engine.get_config('scan_whole_list'))
        self.library_full_path.setChecked(engine.get_config('library_full_path'))
        self.plex_host.setText(engine.get_config('plex_host'))
        self.plex_port.setText(engine.get_config('plex_port'))
        self.plex_obey_wait.setChecked(engine.get_config('plex_obey_update_wait_s'))
        self.plex_user.setText(engine.get_config('plex_user'))
        self.plex_passw.setText(engine.get_config('plex_passwd'))

        for path in engine.get_config('searchdir'):
            self._add_dir(path)

        if autoretrieve == 'always':
            self.autoretrieve_always.setChecked(True)
        elif autoretrieve == 'days':
            self.autoretrieve_days.setChecked(True)
        else:
            self.autoretrieve_off.setChecked(True)

        self.autoretrieve_days_n.setValue(engine.get_config('autoretrieve_days'))

        if autosend == 'always':
            self.autosend_always.setChecked(True)
        elif autosend in ('minutes', 'hours'):
            self.autosend_minutes.setChecked(True)
        elif autosend == 'size':
            self.autosend_size.setChecked(True)
        else:
            self.autosend_off.setChecked(True)

        self.autosend_minutes_n.setValue(engine.get_config('autosend_minutes'))
        self.autosend_size_n.setValue(engine.get_config('autosend_size'))

        self.autosend_at_exit.setChecked(engine.get_config('autosend_at_exit'))
        self.auto_status_change.setChecked(engine.get_config('auto_status_change'))
        self.auto_status_change_if_scored.setChecked(engine.get_config('auto_status_change_if_scored'))
        self.auto_date_change.setChecked(engine.get_config('auto_date_change'))

        self.tray_icon.setChecked(self.config['show_tray'])
        self.close_to_tray.setChecked(self.config['close_to_tray'])
        self.start_in_tray.setChecked(self.config['start_in_tray'])
        self.tray_api_icon.setChecked(self.config['tray_api_icon'])
        self.notifications.setChecked(self.config['notifications'])
        self.remember_geometry.setChecked(self.config['remember_geometry'])
        self.remember_columns.setChecked(self.config['remember_columns'])
        self.columns_per_api.setChecked(self.config['columns_per_api'])
        self.filter_bar_position.setCurrentIndex(self.filter_bar_position.findData(self.config['filter_bar_position']))
        self.inline_edit.setChecked(self.config['inline_edit'])

        self.ep_bar_style.setCurrentIndex(self.ep_bar_style.findData(self.config['episodebar_style']))
        self.ep_bar_text.setChecked(self.config['episodebar_text'])

        self.autoretrieve_days_n.setEnabled(self.autoretrieve_days.isChecked())
        self.autosend_minutes_n.setEnabled(self.autosend_minutes.isChecked())
        self.autosend_size_n.setEnabled(self.autosend_size.isChecked())
        self.close_to_tray.setEnabled(self.tray_icon.isChecked())
        self.start_in_tray.setEnabled(self.tray_icon.isChecked())
        self.notifications.setEnabled(self.tray_icon.isChecked())

        self.color_values = self.config['colors'].copy()

        self.tracker_type_change(None)

    def _save(self):
        engine = self.worker.engine

        engine.set_config('tracker_enabled',       self.tracker_enabled.isChecked())
        engine.set_config('tracker_type',          self.tracker_type.itemData(self.tracker_type.currentIndex()))
        engine.set_config('tracker_interval',      self.tracker_interval.value())
        engine.set_config('tracker_process',       str(self.tracker_process.text()))
        engine.set_config('tracker_update_wait_s', self.tracker_update_wait.value())
        engine.set_config('tracker_update_close',  self.tracker_update_close.isChecked())
        engine.set_config('tracker_update_prompt', self.tracker_update_prompt.isChecked())
        engine.set_config('tracker_not_found_prompt', self.tracker_not_found_prompt.isChecked())

        engine.set_config('player',            self.player.text())
        engine.set_config('library_autoscan',  self.library_autoscan.isChecked())
        engine.set_config('scan_whole_list', self.scan_whole_list.isChecked())
        engine.set_config('library_full_path', self.library_full_path.isChecked())
        engine.set_config('plex_host',         self.plex_host.text())
        engine.set_config('plex_port',         self.plex_port.text())
        engine.set_config('plex_obey_update_wait_s', self.plex_obey_wait.isChecked())
        engine.set_config('plex_user',         self.plex_user.text())
        engine.set_config('plex_passwd',       self.plex_passw.text())

        engine.set_config('searchdir',         [self.searchdirs.item(i).text() for i in range(self.searchdirs.count())])

        if self.autoretrieve_always.isChecked():
            engine.set_config('autoretrieve', 'always')
        elif self.autoretrieve_days.isChecked():
            engine.set_config('autoretrieve', 'days')
        else:
            engine.set_config('autoretrieve', 'off')

        engine.set_config('autoretrieve_days',   self.autoretrieve_days_n.value())

        if self.autosend_always.isChecked():
            engine.set_config('autosend', 'always')
        elif self.autosend_minutes.isChecked():
            engine.set_config('autosend', 'minutes')
        elif self.autosend_size.isChecked():
            engine.set_config('autosend', 'size')
        else:
            engine.set_config('autosend', 'off')

        engine.set_config('autosend_minutes', self.autosend_minutes_n.value())
        engine.set_config('autosend_size',  self.autosend_size_n.value())

        engine.set_config('autosend_at_exit',   self.autosend_at_exit.isChecked())
        engine.set_config('auto_status_change', self.auto_status_change.isChecked())
        engine.set_config('auto_status_change_if_scored', self.auto_status_change_if_scored.isChecked())
        engine.set_config('auto_date_change',   self.auto_date_change.isChecked())

        engine.save_config()

        self.config['show_tray'] = self.tray_icon.isChecked()
        self.config['close_to_tray'] = self.close_to_tray.isChecked()
        self.config['start_in_tray'] = self.start_in_tray.isChecked()
        self.config['tray_api_icon'] = self.tray_api_icon.isChecked()
        self.config['notifications'] = self.notifications.isChecked()
        self.config['remember_geometry'] = self.remember_geometry.isChecked()
        self.config['remember_columns'] = self.remember_columns.isChecked()
        self.config['columns_per_api'] = self.columns_per_api.isChecked()
        self.config['filter_bar_position'] = self.filter_bar_position.itemData(self.filter_bar_position.currentIndex())
        self.config['inline_edit'] = self.inline_edit.isChecked()

        self.config['episodebar_style'] = self.ep_bar_style.itemData(self.ep_bar_style.currentIndex())
        self.config['episodebar_text'] = self.ep_bar_text.isChecked()

        self.config['colors'] = self.color_values

        utils.save_config(self.config, self.configfile)

        self.saved.emit()

    def s_save(self):
        self._save()
        self.accept()

    def tracker_type_change(self, checked):
        if self.tracker_enabled.isChecked():
            self.tracker_interval.setEnabled(True)
            self.tracker_update_wait.setEnabled(True)
            self.tracker_type.setEnabled(True)
            if self.tracker_type.itemData(self.tracker_type.currentIndex()) == 'plex':
                self.plex_host.setEnabled(True)
                self.plex_port.setEnabled(True)
                self.plex_obey_wait.setEnabled(True)
                self.plex_user.setEnabled(True)
                self.plex_passw.setEnabled(True)
                self.tracker_process.setEnabled(False)
            else:
                self.tracker_process.setEnabled(True)
                self.plex_host.setEnabled(False)
                self.plex_port.setEnabled(False)
                self.plex_user.setEnabled(False)
                self.plex_passw.setEnabled(False)
                self.plex_obey_wait.setEnabled(False)
        else:
            self.tracker_type.setEnabled(False)
            self.plex_host.setEnabled(False)
            self.plex_port.setEnabled(False)
            self.plex_user.setEnabled(False)
            self.plex_passw.setEnabled(False)
            self.plex_obey_wait.setEnabled(False)
            self.tracker_process.setEnabled(False)
            self.tracker_interval.setEnabled(False)
            self.tracker_update_wait.setEnabled(False)

    def s_autoretrieve_days(self, checked):
        self.autoretrieve_days_n.setEnabled(checked)

    def s_autosend_minutes(self, checked):
        self.autosend_minutes_n.setEnabled(checked)

    def s_autosend_size(self, checked):
        self.autosend_size_n.setEnabled(checked)

    def s_tray_icon(self, checked):
        self.close_to_tray.setEnabled(checked)
        self.start_in_tray.setEnabled(checked)
        self.tray_api_icon.setEnabled(checked)
        self.notifications.setEnabled(checked)

    def s_ep_bar_style(self, index):
        if self.ep_bar_style.itemData(index) == ShowsTableDelegate.BarStyle04:
            self.ep_bar_text.setEnabled(False)
        else:
            self.ep_bar_text.setEnabled(True)

    def s_auto_status_change(self, checked):
        self.auto_status_change_if_scored.setEnabled(checked)

    def s_player_browse(self):
        if pyqt_version is 5:
            self.player.setText(QFileDialog.getOpenFileName(caption='Choose player executable')[0])
        else:
            self.player.setText(QFileDialog.getOpenFileName(caption='Choose player executable'))

    def s_searchdirs_add(self):
        self._add_dir(QFileDialog.getExistingDirectory(caption='Choose media directory'))

    def s_searchdirs_remove(self):
        row = self.searchdirs.currentRow()
        if row != -1:
            self.searchdirs.takeItem(row)

    def s_switch_page(self, new, old):
        if not new:
            new = old

        self.contents.setCurrentIndex(self.category_list.row(new))

    def s_color_picker(self, key, system):
        return lambda: self.color_picker(key, system)

    def color_picker(self, key, system):
        if system is True:
            current = self.color_values[key]
            result = ThemedColorPicker.do()
            if result is not None and result is not current:
                self.color_values[key] = result
                self.update_colors()
        else:
            current = getColor(self.color_values[key])
            result = QColorDialog.getColor(current)
            if result.isValid() and result is not current:
                self.color_values[key] = str(result.name())
                self.update_colors()

    def update_colors(self):
        for ((key, label), color) in zip(self.colors['rows']+self.colors['progress'], self.color_buttons):
            color.setStyleSheet('background-color: ' + getColor(self.color_values[key]).name())
Пример #58
0
class _HistoryDialog:

    record_label = "Save..."
    execute_label = "Execute"

    def __init__(self, controller, typed_only):
        # make dialog hidden initially
        self.controller = controller
        self.typed_only = typed_only

        self.window = controller.tool_window.create_child_window(
            "Command History", close_destroys=False)
        self.window.fill_context_menu = self.fill_context_menu

        parent = self.window.ui_area
        from PyQt5.QtWidgets import QListWidget, QVBoxLayout, QFrame, QHBoxLayout, QPushButton, QLabel
        self.listbox = QListWidget(parent)
        self.listbox.setSelectionMode(QListWidget.ExtendedSelection)
        self.listbox.itemSelectionChanged.connect(self.select)
        main_layout = QVBoxLayout(parent)
        main_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.addWidget(self.listbox)
        num_cmd_frame = QFrame(parent)
        main_layout.addWidget(num_cmd_frame)
        num_cmd_layout = QHBoxLayout(num_cmd_frame)
        num_cmd_layout.setContentsMargins(0, 0, 0, 0)
        remem_label = QLabel("Remember")
        from PyQt5.QtCore import Qt
        remem_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        num_cmd_layout.addWidget(remem_label, 1)
        from PyQt5.QtWidgets import QSpinBox, QSizePolicy

        class ShorterQSpinBox(QSpinBox):
            max_val = 1000000

            def textFromValue(self, val):
                # kludge to make the damn entry field shorter
                if val == self.max_val:
                    return "1 mil"
                return str(val)

        spin_box = ShorterQSpinBox()
        spin_box.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        spin_box.setRange(100, spin_box.max_val)
        spin_box.setSingleStep(100)
        spin_box.setValue(controller.settings.num_remembered)
        spin_box.valueChanged.connect(self._num_remembered_changed)
        num_cmd_layout.addWidget(spin_box, 0)
        num_cmd_layout.addWidget(QLabel("commands"), 1)
        num_cmd_frame.setLayout(num_cmd_layout)
        button_frame = QFrame(parent)
        main_layout.addWidget(button_frame)
        button_layout = QHBoxLayout(button_frame)
        button_layout.setContentsMargins(0, 0, 0, 0)
        for but_name in [
                self.record_label, self.execute_label, "Delete", "Copy", "Help"
        ]:
            but = QPushButton(but_name, button_frame)
            but.setAutoDefault(False)
            but.clicked.connect(
                lambda arg, txt=but_name: self.button_clicked(txt))
            button_layout.addWidget(but)
        button_frame.setLayout(button_layout)
        self.window.manage(placement=None, initially_hidden=True)
        from chimerax.core.history import FIFOHistory
        self._history = FIFOHistory(controller.settings.num_remembered,
                                    controller.session, "commands")
        self._record_dialog = None
        self._search_cache = (False, None)

    def add(self, item, *, typed=False):
        if len(self._history) >= self.controller.settings.num_remembered:
            if not self.typed_only or self._history[0][1]:
                self.listbox.takeItem(0)
        if typed or not self.typed_only:
            self.listbox.addItem(item)
        self._history.enqueue((item, typed))
        # 'if typed:' to avoid clearing any partially entered command text
        if typed:
            self.listbox.clearSelection()
            self.listbox.setCurrentRow(len(self.history()) - 1)
            self.update_list()

    def button_clicked(self, label):
        session = self.controller.session
        if label == self.record_label:
            from chimerax.ui.open_save import SaveDialog
            if self._record_dialog is None:
                fmt = session.data_formats["ChimeraX commands"]
                self._record_dialog = dlg = SaveDialog(session,
                                                       self.window.ui_area,
                                                       "Save Commands",
                                                       data_formats=[fmt])
                from PyQt5.QtWidgets import QFrame, QLabel, QHBoxLayout, QVBoxLayout, QComboBox
                from PyQt5.QtWidgets import QCheckBox
                from PyQt5.QtCore import Qt
                options_frame = dlg.custom_area
                options_layout = QVBoxLayout(options_frame)
                options_frame.setLayout(options_layout)
                amount_frame = QFrame(options_frame)
                options_layout.addWidget(amount_frame, Qt.AlignCenter)
                amount_layout = QHBoxLayout(amount_frame)
                amount_layout.addWidget(QLabel("Save", amount_frame))
                self.save_amount_widget = saw = QComboBox(amount_frame)
                saw.addItems(["all", "selected"])
                amount_layout.addWidget(saw)
                amount_layout.addWidget(QLabel("commands", amount_frame))
                amount_frame.setLayout(amount_layout)
                self.append_checkbox = QCheckBox("Append to file",
                                                 options_frame)
                self.append_checkbox.stateChanged.connect(self.append_changed)
                options_layout.addWidget(self.append_checkbox, Qt.AlignCenter)
                self.overwrite_disclaimer = disclaimer = QLabel(
                    "<small><i>(ignore overwrite warning)</i></small>",
                    options_frame)
                options_layout.addWidget(disclaimer, Qt.AlignCenter)
                disclaimer.hide()
            else:
                dlg = self._record_dialog
            if not dlg.exec():
                return
            path = dlg.selectedFiles()[0]
            if not path:
                from chimerax.core.errors import UserError
                raise UserError("No file specified for saving command history")
            if self.save_amount_widget.currentText() == "all":
                cmds = [cmd for cmd in self.history()]
            else:
                # listbox.selectedItems() may not be in order, so...
                items = [
                    self.listbox.item(i) for i in range(self.listbox.count())
                    if self.listbox.item(i).isSelected()
                ]
                cmds = [item.text() for item in items]
            from chimerax.io import open_output
            f = open_output(path,
                            encoding='utf-8',
                            append=self.append_checkbox.isChecked())
            for cmd in cmds:
                print(cmd, file=f)
            f.close()
            return
        if label == self.execute_label:
            for item in self.listbox.selectedItems():
                self.controller.cmd_replace(item.text())
                self.controller.execute()
            return
        if label == "Delete":
            retain = []
            listbox_index = 0
            for h_item in self._history:
                if self.typed_only and not h_item[1]:
                    retain.append(h_item)
                    continue
                if not self.listbox.item(listbox_index).isSelected():
                    # not selected for deletion
                    retain.append(h_item)
                listbox_index += 1
            self._history.replace(retain)
            self.populate()
            return
        if label == "Copy":
            clipboard = session.ui.clipboard()
            clipboard.setText("\n".join(
                [item.text() for item in self.listbox.selectedItems()]))
            return
        if label == "Help":
            from chimerax.core.commands import run
            run(session, 'help help:user/tools/cli.html#history')
            return

    def down(self, shifted):
        sels = self.listbox.selectedIndexes()
        if len(sels) != 1:
            self._search_cache = (False, None)
            return
        sel = sels[0].row()
        orig_text = self.controller.text.currentText()
        match_against = None
        if shifted:
            was_searching, prev_search = self._search_cache
            if was_searching:
                match_against = prev_search
            else:
                words = orig_text.strip().split()
                if words:
                    match_against = words[0]
                    self._search_cache = (True, match_against)
                else:
                    self._search_cache = (False, None)
        else:
            self._search_cache = (False, None)
        if match_against:
            last = self.listbox.count() - 1
            while sel < last:
                if self.listbox.item(sel + 1).text().startswith(match_against):
                    break
                sel += 1
        if sel == self.listbox.count() - 1:
            return
        self.listbox.clearSelection()
        self.listbox.setCurrentRow(sel + 1)
        new_text = self.listbox.item(sel + 1).text()
        self.controller.cmd_replace(new_text)
        if orig_text == new_text:
            self.down(shifted)

    def fill_context_menu(self, menu, x, y):
        # avoid having actions destroyed when this routine returns
        # by stowing a reference in the menu itself
        from PyQt5.QtWidgets import QAction
        filter_action = QAction("Typed commands only", menu)
        filter_action.setCheckable(True)
        filter_action.setChecked(self.controller.settings.typed_only)
        filter_action.toggled.connect(
            lambda arg, f=self.controller._set_typed_only: f(arg))
        menu.addAction(filter_action)

    def on_append_change(self, event):
        self.overwrite_disclaimer.Show(self.save_append_CheckBox.Value)

    def append_changed(self, append):
        if append:
            self.overwrite_disclaimer.show()
        else:
            self.overwrite_disclaimer.hide()

    def on_listbox(self, event):
        self.select()

    def populate(self):
        self.listbox.clear()
        history = self.history()
        self.listbox.addItems([cmd for cmd in history])
        self.listbox.setCurrentRow(len(history) - 1)
        self.update_list()
        self.select()
        self.controller.text.lineEdit().setFocus()
        self.controller.text.lineEdit().selectAll()
        cursels = self.listbox.scrollToBottom()

    def search_reset(self):
        searching, target = self._search_cache
        if searching:
            self._search_cache = (False, None)
            self.listbox.blockSignals(True)
            self.listbox.clearSelection()
            self.listbox.setCurrentRow(self.listbox.count() - 1)
            self.listbox.blockSignals(False)

    def select(self):
        sels = self.listbox.selectedItems()
        if len(sels) != 1:
            return
        self.controller.cmd_replace(sels[0].text())

    def up(self, shifted):
        sels = self.listbox.selectedIndexes()
        if len(sels) != 1:
            self._search_cache = (False, None)
            return
        sel = sels[0].row()
        orig_text = self.controller.text.currentText()
        match_against = None
        if shifted:
            was_searching, prev_search = self._search_cache
            if was_searching:
                match_against = prev_search
            else:
                words = orig_text.strip().split()
                if words:
                    match_against = words[0]
                    self._search_cache = (True, match_against)
                else:
                    self._search_cache = (False, None)
        else:
            self._search_cache = (False, None)
        if match_against:
            while sel > 0:
                if self.listbox.item(sel - 1).text().startswith(match_against):
                    break
                sel -= 1
        if sel == 0:
            return
        self.listbox.clearSelection()
        self.listbox.setCurrentRow(sel - 1)
        new_text = self.listbox.item(sel - 1).text()
        self.controller.cmd_replace(new_text)
        if orig_text == new_text:
            self.up(shifted)

    def update_list(self):
        c = self.controller
        last8 = list(reversed(self.history()[-8:]))
        # without blocking signals, if the command list is empty then
        # "Command History" (the first entry) will execute...
        c.text.blockSignals(True)
        c.text.clear()
        c.text.addItems(last8 + [c.show_history_label, c.compact_label])
        if not last8:
            c.text.lineEdit().setText("")
        c.text.blockSignals(False)

    def history(self):
        if self.typed_only:
            return [h[0] for h in self._history if h[1]]
        return [h[0] for h in self._history]

    def set_typed_only(self, typed_only):
        self.typed_only = typed_only
        self.populate()

    def _num_remembered_changed(self, new_hist_len):
        if len(self._history) > new_hist_len:
            self._history.replace(self._history[-new_hist_len:])
            self.populate()
        self.controller.settings.num_remembered = new_hist_len
Пример #59
0
class ListEdit(QWidget):
    """A widget to edit a list of items (e.g. a list of directories)."""
    
    # emitted when anything changed in the listbox.
    changed = pyqtSignal()
    
    def __init__(self, *args, **kwargs):
        QWidget.__init__(self, *args, **kwargs)
        layout = QGridLayout(self)
        self.setLayout(layout)
        
        self.addButton = QPushButton(icons.get('list-add'), '')
        self.editButton = QPushButton(icons.get('document-edit'), '')
        self.removeButton = QPushButton(icons.get('list-remove'), '')
        self.listBox = QListWidget()
        
        layout.setContentsMargins(1, 1, 1, 1)
        layout.setSpacing(0)
        layout.addWidget(self.listBox, 0, 0, 8, 1)
        layout.addWidget(self.addButton, 0, 1)
        layout.addWidget(self.editButton, 1, 1)
        layout.addWidget(self.removeButton, 2, 1)
        
        @self.addButton.clicked.connect
        def addClicked():
            item = self.createItem()
            if self.openEditor(item):
                self.addItem(item)
                
        @self.editButton.clicked.connect
        def editClicked():
            item = self.listBox.currentItem()
            item and self.editItem(item)
        
        @self.removeButton.clicked.connect
        def removeClicked():
            item = self.listBox.currentItem()
            if item:
                self.removeItem(item)
        
        @self.listBox.itemDoubleClicked.connect
        def itemDoubleClicked(item):
            item and self.editItem(item)
            
        self.listBox.model().layoutChanged.connect(self.changed)
    
        def updateSelection():
            selected = bool(self.listBox.currentItem())
            self.editButton.setEnabled(selected)
            self.removeButton.setEnabled(selected)
        
        self.changed.connect(updateSelection)
        self.listBox.itemSelectionChanged.connect(updateSelection)
        updateSelection()
        app.translateUI(self)
    
    def translateUI(self):
        self.addButton.setText(_("&Add..."))
        self.editButton.setText(_("&Edit..."))
        self.removeButton.setText(_("&Remove"))
    
    def createItem(self):
        return QListWidgetItem()
        
    def addItem(self, item):
        self.listBox.addItem(item)
        self.itemChanged(item)
        self.changed.emit()
        
    def removeItem(self, item):
        self.listBox.takeItem(self.listBox.row(item))
        self.changed.emit()
        
    def editItem(self, item):
        if self.openEditor(item):
            self.itemChanged(item)
            self.changed.emit()
            
    def setCurrentItem(self, item):
        self.listBox.setCurrentItem(item)
        
    def setCurrentRow(self, row):
        self.listBox.setCurrentRow(row)
        
    def openEditor(self, item):
        """Opens an editor (dialog) for the item.
        
        Returns True if the dialog was accepted and the item edited.
        Returns False if the dialog was cancelled (the item must be left
        unedited).
        """
        pass
    
    def itemChanged(self, item):
        """Called after an item has been added or edited.
        
        Re-implement to do something at this moment if needed, e.g. alter the
        text or display of other items.
        """
        pass
    
    def setValue(self, strings):
        """Sets the listbox to a list of strings."""
        self.listBox.clear()
        self.listBox.addItems(strings)
        self.changed.emit()
        
    def value(self):
        """Returns the list of paths in the listbox."""
        return [self.listBox.item(i).text()
            for i in range(self.listBox.count())]
    
    def setItems(self, items):
        """Sets the listbox to a list of items."""
        self.listBox.clear()
        for item in items:
            self.listBox.addItem(item)
            self.itemChanged(item)
        self.changed.emit()
    
    def items(self):
        """Returns the list of items in the listbox."""
        return [self.listBox.item(i)
            for i in range(self.listBox.count())]
        
    def clear(self):
        """Clears the listbox."""
        self.listBox.clear()
        self.changed.emit()
Пример #60
0
class Checkers(QMainWindow):
    def __init__(self, share_dir):
        QMainWindow.__init__(self)
        self.share_dir = share_dir
        self.setWindowTitle(_("HCheckers client"))
        self.settings = QSettings("hcheckers", "hcheckers")
        self._board_setup_mode = False
        self._game_active = False
        self._connection_failed = False
        self._poll_try_number = 0
        self.splashscreen = None
        self._show_splashcreen(_("Starting HCheckers..."))
        self.server_url = self.settings.value("server_url", DEFAULT_SERVER_URL)
        self._start_server()
        self._prepare()
        self._gui_setup()
        self._setup_actions()
        self._default_new_game()

    def get_board_setup_mode(self):
        return self._board_setup_mode

    def set_board_setup_mode(self, mode):
        self._board_setup_mode = mode
        self.run_action.setEnabled(mode)
        self.put_first_action.setEnabled(mode)
        self.put_second_action.setEnabled(mode)
        self.erase_action.setEnabled(mode)

    board_setup_mode = property(get_board_setup_mode, set_board_setup_mode)

    def get_my_turn(self):
        return self.board.my_turn

    def set_my_turn(self, value):
        self.board.my_turn = value
        if value:
            self.statusBar().showMessage(_("Your turn."))
            self.board.text_message = None
            #self.board.repaint()
        else:
            self.statusBar().showMessage(
                _("Awaiting a turn from another side."))
            #self.board.text_message = _("Waiting for another side turn")

    my_turn = property(get_my_turn, set_my_turn)

    def get_game_active(self):
        return self._game_active

    def set_game_active(self, value):
        self._game_active = value
        self.board.locked = not value

    game_active = property(get_game_active, set_game_active)

    def _start_server(self):
        server_running = Game.check_server(self.server_url)
        use_local_server = self.settings.value("use_local_server", type=bool)
        self.local_server_used = False
        if server_running:
            if use_local_server:
                logging.info(
                    _("Server appears to be already running, do not start a local server"
                      ))
        else:
            if use_local_server:
                self.splashscreen.showMessage(_("Starting local server..."))
                QApplication.processEvents()
                server_path = self.settings.value("local_server_path")
                logging.info(_("Running local server: {}").format(server_path))
                server = subprocess.Popen(server_path,
                                          shell=True,
                                          stdout=subprocess.PIPE,
                                          stderr=subprocess.STDOUT)
                time.sleep(1)
                server.poll()
                if server.returncode is not None and server.returncode != 0:
                    output = server.stdout.read()
                    message = _(
                        "Could not start local server; exit code: {}; message:\n{}"
                    ).format(server.returncode, output.decode('utf-8'))
                    logging.error(message)
                    QMessageBox.critical(self, _("Exception"), message)
                else:
                    self.local_server_used = True

    def _prepare(self):
        if self.share_dir is None:
            raise Exception("Cant locate share directory")
        theme_name = self.settings.value("theme", "default")
        self.theme = Theme(join(self.share_dir, "themes", theme_name), None)
        self.theme.enable_sound = self.settings.value("enable_sound",
                                                      type=bool)
        self.game = Game(self.server_url)
        self.poll_timer = self.startTimer(500)
        self.setup_fields_on_poll = False

    def _icon(self, name):
        return QIcon(join(self.share_dir, "icons", name))

    @handling_error
    def _gui_setup(self):
        widget = QWidget(self)
        layout = QVBoxLayout()
        self.board = Board(self.theme, self.settings, self.game, self)
        self.board.message.connect(self._on_board_message)
        self.board.field_clicked.connect(self._on_field_clicked)
        #self.board.show()
        self.toolbar = QToolBar(self)
        self.message = QLabel(self)
        layout.addWidget(self.toolbar)
        layout.addWidget(self.message)
        layout.addWidget(self.board, stretch=1)
        widget.setLayout(layout)
        self.setCentralWidget(widget)

        self.status_info = QLabel(self)
        self.statusBar().addPermanentWidget(self.status_info)
        self.rules_info = QLabel(self)
        self.rules_info.setFrameStyle(QFrame.Sunken | QFrame.Panel)
        #self.rules_info.setLineWidth(3)
        self.statusBar().addPermanentWidget(self.rules_info)
        self.opponent_info = QLabel(self)
        self.opponent_info.setFrameStyle(QFrame.Sunken | QFrame.Panel)
        #self.opponent_info.setLineWidth(3)
        self.statusBar().addPermanentWidget(self.opponent_info)

        self.history = HistoryWidget(self.game, self.board, self)
        self.history_dock = QDockWidget(_("History"), self)
        self.history_dock.setAllowedAreas(Qt.AllDockWidgetAreas)
        self.history_dock.setWidget(self.history)
        self.history_dock.setObjectName("history")
        self.addDockWidget(Qt.RightDockWidgetArea, self.history_dock)

        self.log = QListWidget(self)
        self.log.setContextMenuPolicy(Qt.CustomContextMenu)
        self.log.customContextMenuRequested.connect(self._on_log_context_menu)
        self.log_dock = QDockWidget(_("Log"), self)
        self.log_dock.setAllowedAreas(Qt.AllDockWidgetAreas)
        self.log_dock.setWidget(self.log)
        self.log_dock.setObjectName("log")
        self.addDockWidget(Qt.BottomDockWidgetArea, self.log_dock)

        console_handler = logging.getLogger().handlers[0]
        logging.getLogger().removeHandler(console_handler)
        log_handler = UiLogHandler(self.log)
        level = self.settings.value("log_level", logging.INFO, type=int)
        logging.getLogger().setLevel(level)
        logging.getLogger().addHandler(log_handler)
        for logger in lowered_loggers:
            logging.getLogger(logger).addFilter(
                LogFilter(lowered_regexps=lowered_regexps))

        self.board.server_log.connect(self._on_server_log)

        geometry = self.settings.value("UI/geometry")
        if geometry is not None:
            self.restoreGeometry(geometry)
        state = self.settings.value("UI/windowState")
        if state is not None:
            self.restoreState(state)

    def _create_action(self,
                       icon,
                       title,
                       menu,
                       handler=None,
                       group=None,
                       toggle=False,
                       toolbar=True,
                       key=None):
        if group is None:
            parent = self
        else:
            parent = group
        action = QAction(title, parent)
        if icon is not None:
            action.setIcon(icon)
        if key is not None:
            action.setShortcut(key)
        if toggle:
            action.setCheckable(True)
        if toolbar:
            self.toolbar.addAction(action)
        menu.addAction(action)
        if handler:
            action.triggered.connect(handler)
        return action

    def _setup_actions(self):
        menu = self.menuBar().addMenu(_("&Game"))
        self._create_action(QIcon.fromTheme("document-new"),
                            _("&New Game"),
                            menu,
                            self._on_new_game,
                            key="Ctrl+N")
        self._create_action(QIcon.fromTheme("document-open"),
                            _("&Open Game..."),
                            menu,
                            self._on_open_game,
                            key="Ctrl+O")
        self._create_action(QIcon.fromTheme("document-save"),
                            _("&Save Position"),
                            menu,
                            self._on_save_game,
                            key="Ctrl+S")
        self._create_action(QIcon.fromTheme("edit-undo"),
                            _("&Undo"),
                            menu,
                            self._on_undo,
                            key="Ctrl+Z")
        self.request_draw_action = self._create_action(
            self._icon("draw_offer.svg"), _("Offer a &draw"), menu,
            self._on_draw_rq)
        self.capitulate_action = self._create_action(self._icon("handsup.svg"),
                                                     _("Capitulate"), menu,
                                                     self._on_capitulate)

        menu.addSeparator()

        self.clear_log_action = self._create_action(
            QIcon.fromTheme("edit-clear"),
            _("&Clear log"),
            menu,
            self._on_clear_log,
            toolbar=False)
        self.copy_log_action = self._create_action(
            QIcon.fromTheme("edit-copy"),
            _("Copy selected log record"),
            menu,
            self._on_copy_log,
            toolbar=False)
        self.save_log_action = self._create_action(
            QIcon.fromTheme("document-save"),
            _("Save &log..."),
            menu,
            self._on_save_log,
            toolbar=False)

        menu.addSeparator()
        self.toolbar.addSeparator()

        self.run_action = self._create_action(
            QIcon.fromTheme("media-playback-start"),
            _("Start &Game"),
            menu,
            self._on_run_game,
            key="Ctrl+R")
        menu.addSeparator()
        self._create_action(QIcon.fromTheme("preferences-system"),
                            _("Se&ttings"),
                            menu,
                            self._on_settings,
                            toolbar=False)
        menu.addSeparator()
        self._create_action(QIcon.fromTheme("application-exit"),
                            _("E&xit"),
                            menu,
                            self._on_exit,
                            toolbar=False,
                            key="Ctrl+Q")

        menu = self.menuBar().addMenu(_("&Position"))
        setup = QActionGroup(self)
        setup.setExclusive(True)
        self.put_first_action = self._create_action(self._icon("manwhite.svg"),
                                                    _("Put &white piece"),
                                                    menu,
                                                    group=setup,
                                                    toggle=True)
        self.put_second_action = self._create_action(
            self._icon("manblack.svg"),
            _("Put &black piece"),
            menu,
            group=setup,
            toggle=True)
        self.erase_action = self._create_action(QIcon.fromTheme("list-remove"),
                                                _("&Remove piece"),
                                                menu,
                                                group=setup,
                                                toggle=True)
        self.board_setup_mode = False
        menu.addSeparator()
        self.toolbar.addSeparator()

        menu = self.menuBar().addMenu(_("&View"))
        self.flip_action = self._create_action(
            QIcon.fromTheme("object-flip-vertical"),
            _("&Flip board"),
            menu,
            self._on_flip_board,
            toggle=True,
            key="Ctrl+T")
        flip = self.settings.value("flip_board", False, type=bool)
        self.flip_action.setChecked(flip)
        self._set_flip_board(flip)
        menu.addAction(self.history_dock.toggleViewAction())
        menu.addAction(self.log_dock.toggleViewAction())

    @handling_error
    def _on_run_game(self, checked=None):
        self.board_setup_mode = False
        board = self.board.json()
        self.game.start_new_game(
            self.game_settings.user_name,
            rules=self.game_settings.rules,
            user_turn_first=self.game_settings.user_turn_first,
            ai=self.game_settings.ai,
            board=board)
        self.board.text_message = None
        self.board.fields_setup()

    @handling_error
    def _on_field_clicked(self, row, col):
        if not self.board_setup_mode:
            return

        field = self.board.fields[(row, col)]
        if not field.usable:
            logging.debug("You cant put piece at this field")
            return

        first = self.put_first_action.isChecked()
        second = self.put_second_action.isChecked()
        erase = self.erase_action.isChecked()

        if not first and not second and not erase:
            return
        if first:
            side = FIRST
        elif second:
            side = SECOND

        piece = field.piece
        if not erase:
            if piece and piece.side == side:
                if piece.kind == MAN:
                    piece.kind = KING
                else:
                    piece.kind = MAN
            else:
                piece = Piece(MAN, side)
        else:
            piece = None
        self.board.fields[(row, col)].piece = piece

    @handling_error
    def _default_new_game(self):
        self.splashscreen.finish(self)
        if len(sys.argv) == 2:
            path = sys.argv[1]
            if path.endswith(".pdn"):
                mask = PDN_MASK
            elif path.endswith(".fen"):
                mask = FEN_MASK
            else:
                mask = None
        else:
            path, mask = None, None
        self._on_new_game(show_exit=True, open_file=(path, mask))

    @handling_error
    def _on_exit(self, *args):
        self.close()

    def _screen_size(self):
        rect = QApplication.desktop().availableGeometry(self)
        return min(rect.width(), rect.height())

    def _splashscreen_size(self):
        screen_size = self._screen_size()
        return screen_size / 2

    def _show_splashcreen(self, message=None):
        splash_size = self._splashscreen_size()
        splash_pix = self._icon("splashscreen.svg").pixmap(
            QSize(splash_size, splash_size))
        self.splashscreen = QSplashScreen(splash_pix, Qt.WindowStaysOnTopHint)
        self.splashscreen.show()
        QApplication.processEvents()
        if message is not None:
            self.splashscreen.showMessage(message)
            QApplication.processEvents()

    def _new_game(self, dialog):
        # Show splashcreen after user pressed Ok in the "new game" dialog
        self._show_splashcreen(_("Starting new game..."))

        if self.game.is_active():
            self.game.capitulate()
        self.board.text_message = None
        self.game_active = True
        self.game.game_id = None

        self.request_draw_action.setEnabled(True)
        self.capitulate_action.setEnabled(True)

        self.game_settings = game = dialog.get_settings()
        if game.action == START_AI_GAME:
            if game.board_setup:
                self.board.empty()
                self.board_setup_mode = True
                self.game.rules = game.rules
            else:
                self.game.start_new_game(
                    game.user_name,
                    rules=game.rules,
                    user_turn_first=game.user_turn_first,
                    ai=game.ai,
                    fen_path=game.fen_path,
                    pdn_path=game.pdn_path,
                    previous_board_game=game.previous_board_game)
                state = self.game.get_state()
                my_side = 'First' if self.game.user_side == FIRST else 'Second'
                self.my_turn = state["side"] == my_side
                self.rules_info.setText(
                    _("Rules: {}").format(rules_dict[game.rules]))
                self.opponent_info.setText(_("AI: {}").format(game.ai.title))
                self.status_info.setText("")
        elif game.action == START_HUMAN_GAME:
            game_id = self.game.new_game(game.rules)
            logging.info(_("New game ID: {}").format(game_id))
            if game.user_turn_first:
                self.game.register_user(game.user_name, FIRST)
            else:
                self.game.register_user(game.user_name, SECOND)
            self.setup_fields_on_poll = True
            self.rules_info.setText(_("Rules: {}").format(game.rules))
            self.opponent_info.setText("")
            self.status_info.setText("")
            self.game_active = False
            message = _("Waiting for another side to join the game.")
            self.statusBar().showMessage(message)
            self.board.text_message = message
        elif game.action == JOIN_HUMAN_GAME:
            self.game.game_id = dialog.lobby.get_game_id()
            self.game.user_side = side = dialog.lobby.get_free_side()
            self.game.rules = dialog.lobby.get_rules()
            #used_name = dialog.lobby.get_used_name()
            self.game.register_user(game.user_name, side)
            self.game.run_game()
            self.setup_fields_on_poll = True
            self.my_turn = side == FIRST
            self.rules_info.setText(_("Rules: {}").format(game.rules))
            self.opponent_info.setText("")
            self.status_info.setText("")

        size, invert, notation = self.game.get_notation(game.rules)
        self.board.invert_colors = invert
        self.board.topology = self.game.get_topology(game.rules)
        self.board.set_notation(size, notation)

        self.board.theme = self.board.theme
        #self.board.repaint()
        self.history.fill()

    @handling_error
    def _on_new_game(self,
                     checked=None,
                     show_exit=False,
                     open_file=(None, None)):
        dialog = NewGameDialog(self.settings,
                               self.game,
                               self.share_dir,
                               show_exit,
                               open_file=open_file,
                               parent=self)
        result = dialog.exec_()

        if result == QDialog.Accepted:
            self._new_game(dialog)

        if self.splashscreen:
            self.splashscreen.finish(self)

        if result == EXIT:
            print("Exit!")
            #QApplication.quit()
            QTimer.singleShot(0, lambda: self.close())

    @handling_error
    def _on_open_game(self, checked=None):
        path, mask = select_game_file(self)
        if path:
            dialog = NewGameDialog(self.settings,
                                   self.game,
                                   self.share_dir,
                                   show_exit=False,
                                   open_file=(path, mask),
                                   parent=self)
            result = dialog.exec_()

            if result == QDialog.Accepted:
                self._new_game(dialog)

            if self.splashscreen:
                self.splashscreen.finish(self)

    @handling_error
    def _on_save_game(self, checked=None):
        (path, mask) = QFileDialog.getSaveFileName(self.board, _("Save file"),
                                                   ".",
                                                   FEN_MASK + ";;" + PDN_MASK)
        if path:
            if mask == FEN_MASK:
                fen = self.game.get_fen()
                with open(path, 'w') as f:
                    f.write(fen)
            elif mask == PDN_MASK:
                pdn = self.game.get_pdn()
                with open(path, 'w') as f:
                    f.write(pdn)

    @handling_error
    def _on_undo(self, checked=None):
        try:
            prev_board = self.game.undo()
            self.board.fields_setup(prev_board)
            self.board.repaint()
            self.history.fill()
        except RequestError as e:
            error = e.rs.json().get("error", None)
            if error == "NothingToUndo":
                logging.warning(_("Nothing to undo."))
            else:
                raise e

    @handling_error
    def _on_draw_rq(self, checked=None):
        messages = self.game.request_draw()
        for message in messages:
            self.board.process_message(message)
        self.request_draw_action.setEnabled(False)
        self.capitulate_action.setEnabled(False)

    @handling_error
    def _on_accept_draw(self, checked=None):
        messages = self.game.accept_draw(True)
        for message in messages:
            self.board.process_message(message)

    @handling_error
    def _on_decline_draw(self, checked=None):
        messages = self.game.accept_draw(False)
        for message in messages:
            self.board.process_message(message)

    @handling_error
    def _on_capitulate(self, checked=None):
        messages = self.game.capitulate()
        for message in messages:
            self.board.process_message(message)
        #self.my_turn = False

    @handling_error
    def get_result_str(self, result):
        first, second = self.game.get_colors(self.game.rules)
        if result == 'FirstWin':
            return _("{} win").format(first)
        elif result == 'SecondWin':
            return _("{} win").format(second)
        else:
            return _("Draw")

    def _on_board_message(self, message):
        if isinstance(message, GameResultMessage):
            self.game_active = False
            result = self.get_result_str(message.result)
            result_text = _("Game result: {}").format(result)
            self.status_info.setText(result_text)
            self.board.setCursor(Qt.ArrowCursor)
            game_over = _("Game over.")
            self.statusBar().showMessage(game_over)
            self.board.text_message = game_over + " " + result_text
            self.history.fill()
            self.request_draw_action.setEnabled(False)
            self.capitulate_action.setEnabled(False)
        elif isinstance(message, OtherSideMove):
            self.message.setText(str(message))
            self.history.fill()
            self.my_turn = True
            self.board.text_message = None
            self.board.repaint()
        elif isinstance(message, WaitingMove):
            text = str(message)
            self.statusBar().showMessage(text)
            self.board.text_message = text
        elif isinstance(message, DrawRequestedMessage):
            ok = QMessageBox.question(
                self, _("Accept the draw?"),
                _("Another side have offered you a draw. Do you wish to accept it?"
                  ))
            if ok == QMessageBox.Yes:
                self._on_accept_draw()
            else:
                self._on_decline_draw()
        elif isinstance(message, DrawResponseMessage):
            text = str(message)
            self.message.setText(text)
            self.board.text_message = text
            self.board.repaint()
            if not message.result:
                self.request_draw_action.setEnabled(True)
                self.capitulate_action.setEnabled(True)

    def _on_server_log(self, level, message):
        if level == "DEBUG":
            logging.debug(message)
        elif level == "INFO":
            logging.info(message)
        elif level == "WARNING":
            logging.warning(message)
        elif level == "ERROR":
            logging.error(message)
#        item = QListWidgetItem(self.log)
#        item.setText(message)
#        icon = None
#        if level == "DEBUG":
#            icon = QIcon.fromTheme("document-properties")
#        elif level == "INFO":
#            icon = QIcon.fromTheme("dialog-information")
#        elif level == "ERROR":
#            icon = QIcon.fromTheme("dialog-error")
#        elif level == "WARNING":
#            icon = QIcon.fromTheme("dialog-warning")
#        if icon is not None:
#            item.setIcon(icon)
#        self.log.update()
#        self.log.scrollToBottom()

    def _log_context_menu(self):
        menu = QMenu(self)
        menu.addAction(self.clear_log_action)
        menu.addAction(self.copy_log_action)
        menu.addAction(self.save_log_action)
        return menu

    def _on_log_context_menu(self, pos):
        menu = self._log_context_menu()
        menu.exec_(self.log.mapToGlobal(pos))

    def _on_clear_log(self, checked):
        self.log.clear()
        logging.info(_("Log has been cleared."))

    def _on_save_log(self, checked):
        text = ""
        for row in range(self.log.count()):
            text = text + self.log.item(row).text() + "\n"
        (path, mask) = QFileDialog.getSaveFileName(self, _("Save file"), ".",
                                                   LOG_MASK)
        if path:
            with open(path, 'w') as f:
                f.write(text)  #.encode("utf-8"))

    def _on_copy_log(self, checked):
        items = self.log.selectedItems()
        if not items:
            return
        text = items[0].text()
        QApplication.clipboard().setText(text)

    def _set_flip_board(self, value):
        self.board.flip = value
        self.settings.setValue("flip_board", self.board.flip)

    def _on_flip_board(self):
        self._set_flip_board(self.flip_action.isChecked())

    def _on_settings(self):
        dialog = SettingsDialog(self.settings, self.share_dir, self)
        result = dialog.exec_()
        if result == QDialog.Accepted:
            self.board.show_possible_moves = dialog.get_show_possible_moves()
            self.board.show_notation = dialog.get_show_notation()
            self.board.theme = dialog.get_theme()
            self.board.theme.enable_sound = dialog.get_enable_sound()
            level = self.settings.value("log_level", logging.INFO, type=int)
            logging.getLogger().setLevel(level)
            self.settings.sync()
            logging.info(_("Settings have been updated."))

    def _handle_game_error(self, rs):
        try:
            json = rs.json()
        except:
            json = None

        message_format = _(
            "Unexpected response received from the server.\nRequest URL: {}\nResponse code: {}\nResponse message: {}"
        )
        if json is None:
            message = message_format.format(rs.url, rs.status_code, rs.text)
        else:
            err_msg = json.get("error", "Unspecified")
            if err_msg == "no such move":
                move = json.get("move", "?")
                #board = Game.parse_board(json["board"])
                #board = self.board
                #possible = json.get("possible", [])
                #possible = [board.show_move(Move.fromJson(m)) for m in possible]
                message = _("No such move: {}").format(move)
            elif err_msg == "invalid game status":
                expected = json.get("expected", "?")
                actual = json.get("actual", "?")
                message = _(
                    "Status of current game is unsuitable for this operation. Game status is {}; required status is {}"
                ).format(expected, actual)
            else:
                message = message_format.format(rs.url, rs.status_code,
                                                err_msg)

        QMessageBox.critical(self, _("Exception"), message)
        logging.exception(message)

    def _handle_connection_error(self, url, e):
        message = _(
            "An exception occured while connecting to the server.\nRequest URL: {}\nException text: {}"
        ).format(url, e)
        QMessageBox.critical(self, _("Exception"), message)
        logging.exception(message)
        self._connection_failed = True

    def closeEvent(self, ev):

        if self.game.is_active():
            try:
                self.game.capitulate()
            except Exception as e:
                logging.exception(e)
                print(e)

        use_local_server = self.settings.value("use_local_server", type=bool)
        if use_local_server and self.local_server_used:
            try:
                self.game.shutdown()
            except RequestError as e:
                self._handle_game_error(e.rs)
            except Exception as e:
                logging.exception(e)
                print(e)

        self.settings.setValue("UI/geometry", self.saveGeometry())
        self.settings.setValue("UI/windowState", self.saveState())
        QMainWindow.closeEvent(self, ev)

    @handling_error
    def timerEvent(self, e):
        if e.timerId() != self.poll_timer:
            return

        if self._connection_failed:
            self._poll_try_number = self._poll_try_number + 1
            if self._poll_try_number < 10:
                return

        if self.setup_fields_on_poll and not self.game_active:
            state = self.game.get_state()
            if state["status"] == 'Running':
                self.game_active = True
                my_side = 'First' if self.game.user_side == FIRST else 'Second'
                self.my_turn = state['side'] == my_side
                #self.statusBar().clearMessage()

        if not self.game.is_active():
            return

        self._poll_try_number = 0

        board, messages = self.game.poll()
        for message in messages:
            self.board.process_message(message)
            if "move" in message:
                self.my_turn = True
        if self.setup_fields_on_poll:
            self.board.fields_setup(board)