Ejemplo n.º 1
0
    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        icon_path = "frontend/icons/wow.png"
        icon_nn_path = "frontend/icons/nn_.png"
        icon_click_path = "frontend/icons/point.png"
        self.add_action(
            icon_path,
            text=self.tr("Set neural network (F6)"),
            callback=self.gui_dialog,
            parent=self.iface.mainWindow(),
            shortcut="F6",
        )
        self.add_action(
            icon_nn_path,
            text=self.tr("Inference (F4)"),
            callback=self.infer_only,
            parent=self.iface.mainWindow(),
            shortcut="F4",
        )
        self.add_action(
            icon_click_path,
            text=self.tr("Clicky click (F3)"),
            callback=self.clicky,
            parent=self.iface.mainWindow(),
        )

        short = QShortcut("F3", self.iface.mainWindow())
        short.setContext(Qt.ApplicationShortcut)
        short.activated.connect(partial(self._set_class_annot))
Ejemplo n.º 2
0
 def _setupUi(self):
     self.resize(400, 300)
     self.gridLayout = QGridLayout(self)
     self.label = QLabel(tr("Choose a type for this tab:"))
     self.label.setAlignment(Qt.AlignCenter)
     self.gridLayout.addWidget(self.label, 0, 0, 1, 3)
     self.gridLayout.addItem(horizontalSpacer(), 1, 0, 1, 1)
     self.verticalLayout = QVBoxLayout()
     BUTTONS = [
         ('networthButton', tr("1. Net Worth"), 'balance_sheet_16'),
         ('profitButton', tr("2. Profit && Loss"), 'income_statement_16'),
         ('transactionButton', tr("3. Transactions"),
          'transaction_table_16'),
         ('gledgerButton', tr("4. General Ledger"), 'gledger_16'),
         ('scheduleButton', tr("5. Schedules"), 'schedules_16'),
         ('budgetButton', tr("6. Budgets"), 'budget_16'),
         ('docpropsButton', tr("7. Document Properties"), 'gledger_16'),
     ]
     for i, (name, label, icon) in enumerate(BUTTONS, start=1):
         button = QPushButton(label)
         if icon:
             button.setIcon(QIcon(QPixmap(':/{}'.format(icon))))
         self.verticalLayout.addWidget(button)
         setattr(self, name, button)
         shortcut = QShortcut(self)
         shortcut.setKey(QKeySequence(str(i)))
         shortcut.setContext(Qt.WidgetShortcut)
         setattr(self, 'shortcut{}'.format(i), shortcut)
     self.gridLayout.addLayout(self.verticalLayout, 1, 1, 1, 1)
     self.gridLayout.addItem(horizontalSpacer(), 1, 2, 1, 1)
     self.gridLayout.addItem(verticalSpacer(), 2, 1, 1, 1)
Ejemplo n.º 3
0
def bind_all_standard_keys(standard_key,
                           handler_cb,
                           parent=None,
                           context=Qt.WindowShortcut):
    """Workaround for Qt apparently only binding the first StandardKey
    when it's fed into QShortcut

    @type standard_key: C{QtGui.QKeySequence.StandardKey}
    @type handler_cb: C{function}
    @type parent: C{QObject}
    @type context: C{QtCore.Qt.ShortcutContext}

    @rtype: C{[QtWidgets.QShortcut]}
    """

    results = []
    if isinstance(standard_key, QKeySequence.StandardKey):
        hotkeys = QKeySequence.keyBindings(standard_key)
    else:
        hotkeys = [standard_key]

    for hotkey in hotkeys:
        shortcut = QShortcut(hotkey, parent)
        shortcut.setContext(context)
        shortcut.activated.connect(handler_cb)
        results.append(shortcut)
    return results
Ejemplo n.º 4
0
    def __init__(self, items=None, parent=None, status=None):
        self.emits = ['patternchanged']
        self.receives = [('patterns', self.setItems)]
        self.settingsdialog = SettingsWin
        QComboBox.__init__(self, parent)
        self._status = status
        status['patterns'] = self.items
        status['patterntext'] = lambda: str(self.currentText())

        self.setEditable(True)
        if items:
            self.addItems(items)
        pchange = lambda text: self.patternchanged.emit(str(text))
        self.editTextChanged.connect(pchange)

        shortcut = QShortcut(self)
        shortcut.setKey('F8')
        shortcut.setContext(Qt.ApplicationShortcut)

        def set_focus():
            if self.hasFocus():
                status['table'].setFocus()
            else:
                self.lineEdit().selectAll()
                self.setFocus()

        shortcut.activated.connect(set_focus)
Ejemplo n.º 5
0
 def _setupUi(self):
     self.resize(400, 300)
     self.gridLayout = QGridLayout(self)
     self.label = QLabel(tr("Choose a type for this tab:"))
     self.label.setAlignment(Qt.AlignCenter)
     self.gridLayout.addWidget(self.label, 0, 0, 1, 3)
     self.gridLayout.addItem(horizontalSpacer(), 1, 0, 1, 1)
     self.verticalLayout = QVBoxLayout()
     BUTTONS = [
         ('networthButton', tr("1. Net Worth"), 'balance_sheet_16'),
         ('profitButton', tr("2. Profit && Loss"), 'income_statement_16'),
         ('transactionButton', tr("3. Transactions"), 'transaction_table_16'),
         ('gledgerButton', tr("4. General Ledger"), 'gledger_16'),
         ('scheduleButton', tr("5. Schedules"), 'schedules_16'),
         ('budgetButton', tr("6. Budgets"), 'budget_16'),
         ('docpropsButton', tr("7. Document Properties"), 'gledger_16'),
     ]
     for i, (name, label, icon) in enumerate(BUTTONS, start=1):
         button = QPushButton(label)
         if icon:
             button.setIcon(QIcon(QPixmap(':/{}'.format(icon))))
         self.verticalLayout.addWidget(button)
         setattr(self, name, button)
         shortcut = QShortcut(self)
         shortcut.setKey(QKeySequence(str(i)))
         shortcut.setContext(Qt.WidgetShortcut)
         setattr(self, 'shortcut{}'.format(i), shortcut)
     self.gridLayout.addLayout(self.verticalLayout, 1, 1, 1, 1)
     self.gridLayout.addItem(horizontalSpacer(), 1, 2, 1, 1)
     self.gridLayout.addItem(verticalSpacer(), 2, 1, 1, 1)
Ejemplo n.º 6
0
def install_shortcuts(obj, actions, ide):
    short = resources.get_shortcut
    for action in actions:
        short_key = action.get("shortcut", None)
        action_data = action.get("action", None)
        connect = action.get("connect", None)
        if connect == "open_project_properties":
            print("\nregistrando ::open_project_properties;  obj:", obj)

        shortcut = None
        item_ui = None
        func = None
        if connect:
            func = getattr(obj, connect, None)

        if short_key and not action_data:
            if isinstance(short_key, QKeySequence):
                shortcut = QShortcut(short_key, ide)
            else:
                shortcut = QShortcut(short(short_key), ide)
            shortcut.setContext(Qt.ApplicationShortcut)
            if isinstance(func, collections.Callable):
                shortcut.activated.connect(func)
        if action_data:
            is_menu = action_data.get('is_menu', False)
            if is_menu:
                item_ui = QMenu(action_data['text'], ide)
            else:
                item_ui = QAction(action_data['text'], ide)
                object_name = "%s.%s" % (obj.__class__.__name__, connect)
                item_ui.setObjectName(object_name)
            image_name = action_data.get('image', None)
            section = action_data.get('section', None)
            weight = action_data.get('weight', None)
            keysequence = action_data.get('keysequence', None)
            if image_name:
                if isinstance(image_name, int):
                    icon = ide.style().standardIcon(image_name)
                    item_ui.setIcon(icon)
                elif isinstance(image_name, str):
                    icon = QIcon(":img/" + image_name)
                    item_ui.setIcon(icon)
            if short_key and not is_menu:
                item_ui.setShortcut(short(short_key))
                item_ui.setShortcutContext(Qt.ApplicationShortcut)
            elif keysequence and not is_menu:
                item_ui.setShortcut(short(keysequence))
                item_ui.setShortcutContext(Qt.ApplicationShortcut)
            if isinstance(func, collections.Callable) and not is_menu:
                item_ui.triggered['bool'].connect(lambda s, f=func: f())
            if section and section[0] is not None and weight:
                ide.register_menuitem(item_ui, section, weight)
                if image_name and not is_menu:
                    ide.register_toolbar(item_ui, section, weight)

        if short_key and shortcut:
            ide.register_shortcut(short_key, shortcut, item_ui)
Ejemplo n.º 7
0
def install_shortcuts(obj, actions, ide):
    short = resources.get_shortcut
    for action in actions:
        short_key = action.get("shortcut", None)
        action_data = action.get("action", None)
        connect = action.get("connect", None)
        if connect == "open_project_properties":
            print("\nregistrando ::open_project_properties;  obj:", obj)

        shortcut = None
        item_ui = None
        func = None
        if connect:
            func = getattr(obj, connect, None)

        if short_key and not action_data:
            if isinstance(short_key, QKeySequence):
                shortcut = QShortcut(short_key, ide)
            else:
                shortcut = QShortcut(short(short_key), ide)
            shortcut.setContext(Qt.ApplicationShortcut)
            if isinstance(func, collections.Callable):
                shortcut.activated.connect(func)
        if action_data:
            is_menu = action_data.get('is_menu', False)
            if is_menu:
                item_ui = QMenu(action_data['text'], ide)
            else:
                item_ui = QAction(action_data['text'], ide)
                object_name = "%s.%s" % (obj.__class__.__name__, connect)
                item_ui.setObjectName(object_name)
            image_name = action_data.get('image', None)
            section = action_data.get('section', None)
            weight = action_data.get('weight', None)
            keysequence = action_data.get('keysequence', None)
            if image_name:
                if isinstance(image_name, int):
                    icon = ide.style().standardIcon(image_name)
                    item_ui.setIcon(icon)
                elif isinstance(image_name, str):
                    icon = QIcon(":img/" + image_name)
                    item_ui.setIcon(icon)
            if short_key and not is_menu:
                item_ui.setShortcut(short(short_key))
                item_ui.setShortcutContext(Qt.ApplicationShortcut)
            elif keysequence and not is_menu:
                item_ui.setShortcut(short(keysequence))
                item_ui.setShortcutContext(Qt.ApplicationShortcut)
            if isinstance(func, collections.Callable) and not is_menu:
                item_ui.triggered['bool'].connect(lambda s, f=func: f())
            if section and section[0] is not None and weight:
                ide.register_menuitem(item_ui, section, weight)
                if image_name and not is_menu:
                    ide.register_toolbar(item_ui, section, weight)

        if short_key and shortcut:
            ide.register_shortcut(short_key, shortcut, item_ui)
Ejemplo n.º 8
0
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        Ui_PlaylistsWidget.setupUi(self, self)

        self.view.doubleClicked.connect(self.playlistClicked)

        deletePlaylistShortcut = QShortcut(QKeySequence('Del'), self.view)
        deletePlaylistShortcut.setContext(Qt.WidgetShortcut)
        deletePlaylistShortcut.activated.connect(self.onDeletePlaylist)
Ejemplo n.º 9
0
class UI(QWidget):
    def __init__(self, *args):
        super().__init__(*args)

        self.factory = ObjectFactory()
        self.factory_shortcut = QShortcut(QKeySequence("Ctrl+n"), self)
        self.factory_shortcut.setContext(QtCore.Qt.ApplicationShortcut)
        self.factory_shortcut.activated.connect(self.on_factory)

        self.selector = ObjectSelector()
        self.selector_shortcut = QShortcut(QKeySequence("Ctrl+s"), self)
        self.selector_shortcut.setContext(QtCore.Qt.ApplicationShortcut)
        self.selector_shortcut.activated.connect(self.on_selector)

        flags = QtCore.Qt.WindowFlags(QtCore.Qt.WindowStaysOnBottomHint)
        self.setWindowFlags(flags)

        self.showFullScreen()
        return

    def contextMenuEvent(self, event):
        m = QMenu()
        new_action = m.addAction("New ...")
        find_action = m.addAction("Find ...")
        m.addSeparator()
        logout_action = m.addAction("Logout")
        quit_action = m.addAction("Shutdown")

        action = m.exec_(self.mapToGlobal(event.pos()))
        if action == new_action:
            self.on_factory()
        elif action == find_action:
            self.on_selector()
        elif action == quit_action:
            qApp.quit()

    def on_factory(self, *args):
        """Display a panel enabling creation of new type instances."""
        print("Factory: " + str(args))
        if self.factory.isVisible():
            self.factory.hide()
        else:
            self.factory.show()
        return

    def on_selector(self, *args):
        """Display a panel enabling a search of existing objects."""
        print("Selector: " + str(args))
        self.selector.toggle_visibility()
        return
Ejemplo n.º 10
0
    def __init__(self, controller: 'Controller') -> None:
        super().__init__()
        self.controller = controller
        self.is_unused = True
        self.set_unused_text()
        self.returnPressed.connect(self.on_return_pressed)
        self.history: List[str] = []
        self.history_idx = 0

        action = self.addAction(QIcon.fromTheme("window-close"), QLineEdit.TrailingPosition)
        action.triggered.connect(self._on_reset)
        action.setToolTip("Close the Search")

        shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_G), self)
        shortcut.setContext(Qt.WidgetShortcut)
        shortcut.activated.connect(self._on_reset)

        shortcut = QShortcut(QKeySequence(Qt.Key_Escape), self)
        shortcut.setContext(Qt.WidgetShortcut)
        shortcut.activated.connect(self._on_reset)

        shortcut = QShortcut(QKeySequence(Qt.Key_Up), self)
        shortcut.setContext(Qt.WidgetShortcut)
        shortcut.activated.connect(self.history_up)

        shortcut = QShortcut(QKeySequence(Qt.Key_Down), self)
        shortcut.setContext(Qt.WidgetShortcut)
        shortcut.activated.connect(self.history_down)
Ejemplo n.º 11
0
    def initPlaylist(self):
        """Initialize song playlist."""
        self.playlistTable = QTableWidget()

        self.playlistTable.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.playlistTable.setSelectionMode(
            QAbstractItemView.ExtendedSelection)
        self.playlistTable.setSortingEnabled(True)

        self.playlistTable.setTabKeyNavigation(False)
        self.playlistTable.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.playlistTable.setAlternatingRowColors(True)

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

        self.playlistTable.itemDoubleClicked.connect(self.doubleClicked)
        self.doubleClicked = False
        self.lastPlayed = -1
        self.currentPlaying = -1
        delete = QShortcut(
            QKeySequence.Delete, self.playlistTable, self.deleteSongs)
        delete.setContext(Qt.WidgetShortcut)

        self.playlistTable.setColumnCount(4)
        self.playlistTable.setHorizontalHeaderLabels(
            ['Artist', 'Title', 'Album', 'Duration'])

        # False - ascending order, True - descending
        self.descendingOrder = [False] * 4
        self.playlistTable.horizontalHeader().sectionClicked.connect(
            self.toSort)

        self.windows = []

        names = []
        for index in range(self.playlist.mediaCount()):
            names.append(self.playlist.media(index).canonicalUrl().path())
        self.addClicked(names)

        self.grid.addWidget(self.playlistTable, 2, 0, 1, 4)
        self.grid.setRowStretch(2, 1)
Ejemplo n.º 12
0
    def __init__(self, parent):
        """Init table list."""
        super().__init__()
        self.parent = parent
        self.items = dict()
        self.header().hide()
        self.setAnimated(True)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.openMenu)

        shortcut = QShortcut(QKeySequence("DEL"), self)
        shortcut.setAutoRepeat(False)
        shortcut.setContext(Qt.WidgetWithChildrenShortcut)
        shortcut.activated.connect(self.delClicked)

        shortcut = QShortcut(QKeySequence("Enter"), self)
        shortcut.setAutoRepeat(False)
        shortcut.setContext(Qt.WidgetWithChildrenShortcut)
        shortcut.activated.connect(self.enterClicked)
Ejemplo n.º 13
0
    def __init__(self, main_window, shortcut):
        self.shortcut = shortcut
        self.main_window = main_window
        shortcut_ = QShortcut(self.shortcut, main_window)
        shortcut_.setContext(Qt.ApplicationShortcut)

        def ShowStyleSheetEditor():
            style_sheet_inspector_class = GetStyleSheetInspectorClass()
            style_sheet_inspector = [
                c for c in self.main_window.children()
                if isinstance(c, style_sheet_inspector_class)
            ]
            if style_sheet_inspector:
                style_sheet_inspector = style_sheet_inspector[0]
            else:
                style_sheet_inspector = style_sheet_inspector_class(
                    self.main_window)
                style_sheet_inspector.setFixedSize(800, 600)
            style_sheet_inspector.show()

        shortcut_.activated.connect(ShowStyleSheetEditor)
Ejemplo n.º 14
0
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        Ui_LibraryWidget.setupUi(self, self)

        self.rescanButton.show()
        self.scanProgressBar.hide()

        self.libraryModel = LibraryModel()
        self.treeView.setModel(self.libraryModel)

        self.libraryModel.toggleRow.connect(self.onToggleRow)
        self.rescanButton.clicked.connect(self.rescanClicked)
        self.treeView.doubleClicked.connect(self.onTreeViewDoubleClicked)

        self.querySearchBox.textChanged.connect(self.onQueryChanged)
        self.clearSearchButton.clicked.connect(self.onQueryClear)

        # shortcuts
        releaseSearchboxShortcut = QShortcut(QKeySequence('Esc'), self.querySearchBox)
        releaseSearchboxShortcut.setContext(Qt.WidgetShortcut)
        releaseSearchboxShortcut.activated.connect(self.onReleaseSearchbox)
        scrollLibraryShortcut = QShortcut(QKeySequence(Qt.Key_Down), self.querySearchBox)
        scrollLibraryShortcut.setContext(Qt.WidgetShortcut)
        scrollLibraryShortcut.activated.connect(self.onScrollLibrary)
        activateTracksShortcut = QShortcut(QKeySequence(Qt.Key_Return), self.treeView)
        activateTracksShortcut.setContext(Qt.WidgetShortcut)
        activateTracksShortcut.activated.connect(self.onActivateTracks)
Ejemplo n.º 15
0
 def init(self):
     self.setUtf8(True)
     lexer = QsciLexerJSON(self)
     self.setLexer(lexer)
     self.setAutoCompletionCaseSensitivity(False)  # 忽略大小写
     self.setAutoCompletionSource(self.AcsAll)
     self.setAutoCompletionThreshold(1)  # 一个字符就弹出补全
     self.setAutoIndent(True)  # 自动缩进
     self.setBackspaceUnindents(True)
     self.setBraceMatching(self.StrictBraceMatch)
     self.setIndentationGuides(True)
     self.setIndentationsUseTabs(False)
     self.setIndentationWidth(4)
     self.setTabIndents(True)
     self.setTabWidth(4)
     self.setWhitespaceSize(1)
     self.setWhitespaceVisibility(self.WsVisible)
     self.setWhitespaceForegroundColor(Qt.gray)
     self.setWrapIndentMode(self.WrapIndentFixed)
     self.setWrapMode(self.WrapWord)
     # 折叠
     self.setFolding(self.BoxedTreeFoldStyle, 2)
     self.setFoldMarginColors(QColor("#676A6C"), QColor("#676A6D"))
     font = self.font() or QFont()
     font.setFamily("Consolas")
     font.setFixedPitch(True)
     font.setPointSize(13)
     self.setFont(font)
     self.setMarginsFont(font)
     self.fontmetrics = QFontMetrics(font)
     lexer.setFont(font)
     self.setMarginWidth(0, self.fontmetrics.width(str(self.lines())) + 6)
     self.setMarginLineNumbers(0, True)
     self.setMarginsBackgroundColor(QColor("gainsboro"))
     self.setMarginWidth(1, 0)
     self.setMarginWidth(2, 14)  # 折叠区域
     # 绑定自动补齐热键Alt+/
     completeKey = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Slash), self)
     completeKey.setContext(Qt.WidgetShortcut)
     completeKey.activated.connect(self.autoCompleteFromAll)
Ejemplo n.º 16
0
    def _setupInspector(self):
        """
        F12키를 누르면 "개발자 도구"가 노출됨
        """
        # webinspector
        self.settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
        self.webInspector = QWebInspector(self)
        self.webInspector.setPage(self.page())

        # shortcut
        shortcut = QShortcut(self)
        shortcut.setContext(Qt.ApplicationShortcut)
        shortcut.setKey(Qt.Key_F12)
        shortcut.activated.connect(self._toggleInspector)

        # Devtools
        self.webInspector.setVisible(True)
        self.devTool = QDialog(self)
        self.devTool.setWindowTitle("Development Tool")
        self.devTool.resize(950, 400)
        layout = QGridLayout()
        layout.setContentsMargins(0,0,0,0)
        layout.addWidget(self.webInspector)
        self.devTool.setLayout(layout)
Ejemplo n.º 17
0
    def __init__(self, parent):
        super().__init__(parent)

        self.mModel = CommandDataModel(self)

        self.setModel(self.mModel)
        self.setRootIsDecorated(False)
        # Setup resizing so the command column stretches
        self.setColumnWidth(0, 200)
        h = self.header()
        h.setStretchLastSection(False)

        h.setSectionResizeMode(CommandDataModel.NameColumn,
                               QHeaderView.Interactive)
        h.setSectionResizeMode(CommandDataModel.CommandColumn,
                               QHeaderView.Stretch)
        h.setSectionResizeMode(CommandDataModel.EnabledColumn,
                               QHeaderView.ResizeToContents)

        # Allow deletion via keyboard
        d = QShortcut(QKeySequence.Delete, self)
        d.setContext(Qt.WidgetShortcut)
        d.activated.connect(self.removeSelectedCommands)
        self.mModel.rowsRemoved.connect(self.handleRowsRemoved)
Ejemplo n.º 18
0
    def __init__(self, controller: 'Controller') -> None:
        super().__init__()

        self._controller = controller
        self.is_unused = True
        self._show_completion_selection = True

        self.returnPressed.connect(self.on_return_pressed)
        self.textEdited.connect(self.on_text_edited)

        self.bookmark_act = self.addAction(QIcon.fromTheme("user-bookmarks"),
                                           QLineEdit.TrailingPosition)
        self.bookmark_act.setCheckable(True)
        self.bookmark_act.triggered.connect(self._on_bookmark_triggered)
        self.bookmark_act.setToolTip("Toggle bookmark for this location")

        self._controller.sig_location_changed.connect(
            self._on_location_changed)
        self._controller.sig_location_changed_to_none.connect(
            lambda: self._on_location_changed(None))

        self._popup = LocationLineEditPopup(self)

        shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_G), self)
        shortcut.setContext(Qt.WidgetShortcut)
        shortcut.activated.connect(self._on_escape_press)

        shortcut = QShortcut(QKeySequence(Qt.Key_Escape), self)
        shortcut.setContext(Qt.WidgetShortcut)
        shortcut.activated.connect(self._on_escape_press)

        shortcut = QShortcut(QKeySequence(Qt.Key_Up), self)
        shortcut.setContext(Qt.WidgetShortcut)
        shortcut.activated.connect(self._popup.on_key_up)

        shortcut = QShortcut(QKeySequence(Qt.Key_Down), self)
        shortcut.setContext(Qt.WidgetShortcut)
        shortcut.activated.connect(self._popup.on_key_down)
Ejemplo n.º 19
0
class SubwindowMisc(QWidget):
    """Show subwindow with miscellaneous settings."""

    current_tab = -1

    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(int(mainWindow.size().width() * 0.9),
                      self.sizeHint().height()))
            relativeChange = QPoint(int(mainWindow.size().width() / 2),
                                    int(mainWindow.size().height() / 3))\
                - QPoint(int(self.size().width() / 2),
                         int(self.size().height() / 3))
            self.move(mainWindow.pos() + relativeChange)

            self.setWindowTitle(_("Miscellaneous Settings"))

        except Exception:
            module_logger.exception("message")

    def createTabs(self, tab=''):
        """Create tabs."""
        self.tabs = QTabWidget()

        self.createMapsBox()
        self.createFavBox()
        self.createAliasBox()
        self.createOcrBox()
        self.createAlphaBox()
        self.createSC2ClientAPIBox()
        self.createAligulacTab()
        self.createCounterTab()

        # 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"))
        self.tabs.addTab(self.clientapiBox, _("SC2 Client API"))
        self.tabs.addTab(self.aligulacTab, _("Aligulac"))
        self.tabs.addTab(self.counterTab, _("Countdown && Ticker"))

        table = dict()
        table['mapmanager'] = 0
        table['favorites'] = 1
        table['alias'] = 2
        table['ocr'] = 3
        table['alphatl'] = 4
        table['sc2clientapi'] = 5
        table['aligulac'] = 6
        table['counter'] = 7
        self.tabs.setCurrentIndex(table.get(tab, SubwindowMisc.current_tab))
        self.tabs.currentChanged.connect(self.tabChanged)

    @classmethod
    def tabChanged(cls, idx):
        """Save the current tab index."""
        SubwindowMisc.current_tab = idx

    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, team, and league 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, 3)

        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)

        box = QGroupBox(_("League Aliases"))
        layout = QVBoxLayout()
        self.list_aliasLeagues = AliasTreeView(self)
        self.list_aliasLeagues.aliasRemoved.connect(
            self.controller.aliasManager.removeLeagueAlias)
        layout.addWidget(self.list_aliasLeagues)
        addButton = QPushButton(_("Add Alias"))
        addButton.clicked.connect(
            lambda: self.addAlias(self.list_aliasLeagues, _('League Name')))
        layout.addWidget(addButton)
        box.setLayout(layout)
        mainLayout.addWidget(box, 0, 2)

        alias_list = self.controller.aliasManager.playerAliasList()
        for player, aliases in alias_list.items():
            self.list_aliasPlayers.insertAliasList(player, aliases)

        alias_list = self.controller.aliasManager.teamAliasList()
        for league, aliases in alias_list.items():
            self.list_aliasTeams.insertAliasList(league, aliases)

        alias_list = self.controller.aliasManager.leagueAliasList()
        for league, aliases in alias_list.items():
            self.list_aliasLeagues.insertAliasList(league, aliases)

        self.aliasBox.setLayout(mainLayout)

    def addAlias(self, widget, scope, name=""):
        """Add an alias."""
        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)
            elif widget == self.list_aliasLeagues:
                self.controller.aliasManager.addLeagueAlias(name, alias)
            widget.insertAlias(name, alias, True)
        except Exception as e:
            module_logger.exception("message")
            QMessageBox.critical(self, _("Error"), str(e))

    def createSC2ClientAPIBox(self):
        """Create form for SC2 Client API config."""
        self.clientapiBox = QWidget()

        mainLayout = QVBoxLayout()

        box = QGroupBox(_("SC2 Client API Address"))

        layout = QGridLayout()

        self.cb_usesc2listener = QCheckBox(
            " " + _("Listen to SC2 Client API running"
                    " on a different PC in the network."))
        self.cb_usesc2listener.setChecked(
            scctool.settings.config.parser.getboolean(
                "SCT", "sc2_network_listener_enabled"))
        self.cb_usesc2listener.stateChanged.connect(self.changed)

        self.listener_address = MonitoredLineEdit()
        self.listener_address.setAlignment(Qt.AlignCenter)
        self.listener_address.setText(
            scctool.settings.config.parser.get("SCT",
                                               "sc2_network_listener_address"))
        self.listener_address.textModified.connect(self.changed)
        # self.tesseract.setAlignment(Qt.AlignCenter)
        self.listener_address.setPlaceholderText("[Your SC2 PC IP]:6119")
        self.listener_address.setToolTip(
            _('IP address and port of machine running SC2.'))
        ip_port = (
            r"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)" +
            r"{3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]):[0-9]+$")
        self.listener_address.setValidator(QRegExpValidator(QRegExp(ip_port)))

        self.test_listener = QPushButton(" " +
                                         _("Test SC2 Client API Connection") +
                                         " ")
        self.test_listener.clicked.connect(self.testClientAPI)

        text = _("Activate this option if you are using a two computer "
                 "setup with StarCraft Casting Tool running on a different"
                 " PC than your SC2 client. Open the Battle.net launcher "
                 "on the latter PC, click 'Options', 'Game Settings', and "
                 "under SC2, check 'Additional Command Line Arguments', and "
                 "enter '-clientapi 6119'. Finally set as network"
                 " address below: '[Your SC2 PC IP]:6119'.")

        label = QLabel(text)
        label.setAlignment(Qt.AlignJustify)
        label.setOpenExternalLinks(True)
        label.setWordWrap(True)
        label.setMargin(5)
        layout.addWidget(label, 1, 0, 1, 3)

        layout.addWidget(self.cb_usesc2listener, 0, 0, 1, 3)
        layout.addWidget(QLabel(_("Network Address") + ": "), 3, 0)
        layout.addWidget(self.listener_address, 3, 1)
        layout.addWidget(self.test_listener, 3, 2)

        box.setLayout(layout)
        mainLayout.addWidget(box)
        mainLayout.addItem(
            QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding))
        self.clientapiBox.setLayout(mainLayout)

    def testClientAPI(self):
        """Test for connection to sc2 client api."""
        QApplication.setOverrideCursor(Qt.WaitCursor)
        address = self.listener_address.text().strip()
        url = "http://{}/ui".format(address)
        try:
            r = requests.get(url, timeout=10)
            r.raise_for_status()
            successfull = True
        except Exception:
            successfull = False
            module_logger.error("message")
        finally:
            QApplication.restoreOverrideCursor()

        title = _("Connection Test")

        if successfull:
            QMessageBox.information(
                self, title, _('Connection to SC2 client API established!'))
        else:
            QMessageBox.warning(
                self, title,
                _('Unable to connect to SC2 client API.'
                  ' Please make sure that SC2 is currently'
                  ' running on that machine.'))

    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 createAligulacTab(self):
        """Create the aligulac tab."""
        self.aligulacTab = QWidget()

        layout = QGridLayout()
        self.aligulacTreeview = AligulacTreeView(
            self, self.controller.aligulacManager)

        layout.addWidget(self.aligulacTreeview, 0, 0, 3, 1)

        self.pb_addAligulacID = QPushButton(_("Add Aligluac ID"))
        self.pb_addAligulacID.clicked.connect(
            lambda x, self=self: self.addAligulacID())
        layout.addWidget(self.pb_addAligulacID, 1, 1)

        self.pb_removeAligulacID = QPushButton(_("Remove Aligulac ID"))
        self.pb_removeAligulacID.clicked.connect(self.removeAligulacID)
        layout.addWidget(self.pb_removeAligulacID, 2, 1)

        layout.addItem(
            QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Minimum), 0, 1)

        self.aligulacTab.setLayout(layout)

    def addAligulacID(self, name='', aligulac_id=1):
        """Add an aligulac ID."""
        text, ok = QInputDialog.getText(self,
                                        _('Player Name'),
                                        _('Player Name') + ':',
                                        text=name)
        text = text.strip()
        if not ok or not text:
            return
        aligulac_id, ok = QInputDialog.getInt(self,
                                              _('Aligulac ID'),
                                              _('Aligulac ID') + ':',
                                              value=aligulac_id,
                                              min=1)
        if not ok:
            return

        self.aligulacTreeview.insertItem(text, aligulac_id)

    def removeAligulacID(self):
        """Remove an selected aligulac ID."""
        self.aligulacTreeview.removeSelected()

    def createCounterTab(self):
        """Create the aligulac tab."""
        self.counterTab = QWidget()
        mainLayout = QVBoxLayout()

        box = QGroupBox(_("Countdown"))
        layout = QFormLayout()
        self.le_countdown_replacement = QLineEdit()
        self.le_countdown_replacement.setText(
            scctool.settings.config.parser.get("Countdown", "replacement"))
        self.le_countdown_replacement.textChanged.connect(self.changed)
        layout.addRow(QLabel(_('Replacement Text')),
                      self.le_countdown_replacement)
        self.cb_counter_matchgrabber_update = QCheckBox('')
        self.cb_counter_matchgrabber_update.setChecked(
            scctool.settings.config.parser.getboolean("Countdown",
                                                      "matchgrabber_update"))
        self.cb_counter_matchgrabber_update.stateChanged.connect(self.changed)
        layout.addRow(QLabel(_('Update Static Countdown via MatchGrabber')),
                      self.cb_counter_matchgrabber_update)
        self.counter_pretext = QPlainTextEdit()
        self.counter_pretext.setPlainText(
            scctool.settings.config.parser.get("Countdown", "pre_txt"))
        self.counter_pretext.textChanged.connect(self.changed)
        self.counter_posttext = QPlainTextEdit()
        self.counter_posttext.setPlainText(
            scctool.settings.config.parser.get("Countdown", "post_txt"))
        self.counter_posttext.textChanged.connect(self.changed)
        layout.addRow(QLabel(_('Pre-Text (in countdown.txt)')),
                      self.counter_pretext)
        layout.addRow(QLabel(_('Post-Text (in countdown.txt)')),
                      self.counter_posttext)
        box.setLayout(layout)
        mainLayout.addWidget(box)

        box = QGroupBox(_("Ticker"))
        layout = QFormLayout()
        box.setLayout(layout)
        self.ticker_pretext = QLineEdit()
        self.ticker_pretext.setText(
            scctool.settings.config.parser.get("Ticker", "prefix"))
        self.ticker_pretext.textChanged.connect(self.changed)
        layout.addRow(QLabel(_('Prefix text (in ticker.txt)')),
                      self.ticker_pretext)
        mainLayout.addWidget(box)

        self.counterTab.setLayout(mainLayout)

    def createMapsBox(self):
        """Create box for map manager."""
        self.mapsize = 300

        self.mapsBox = QWidget()

        layout = QGridLayout()

        self.maplist = QListWidget()
        self.maplist.setSortingEnabled(True)
        for sc2map in scctool.settings.maps:
            self.maplist.addItem(QListWidgetItem(sc2map))
        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.maplist)
        self.sc_removeMap.setAutoRepeat(False)
        self.sc_removeMap.setContext(Qt.WidgetWithChildrenShortcut)
        self.sc_removeMap.activated.connect(self.deleteMap)

        self.cb_newMapsPrompt = QCheckBox(
            _('Prompt to download new ladders maps.'))
        self.cb_newMapsPrompt.setChecked(
            scctool.settings.config.parser.getboolean("SCT",
                                                      "new_maps_prompt"))
        self.cb_newMapsPrompt.stateChanged.connect(self.changed)

        self.pb_downloadLadderMaps = QPushButton(_("Download Ladder Maps"))
        self.pb_downloadLadderMaps.clicked.connect(self.downloadLadderMaps)

        box = QWidget()
        container = QHBoxLayout()

        container.addWidget(self.pb_addMapLiquipedia, 0)
        container.addWidget(self.pb_addMap, 0)
        container.addWidget(QLabel(), 1)
        container.addWidget(self.pb_downloadLadderMaps, 0)
        container.addWidget(QLabel(), 1)
        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.addWidget(self.cb_newMapsPrompt, 3, 0, 1, 1)
        layout.addItem(
            QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding), 3,
            2, 1, 2)

        layout.addItem(
            QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding), 4,
            0, 1, 2)

        self.changePreview()
        self.mapsBox.setLayout(layout)

    def renameMap(self):
        """Rename maps."""
        item = self.maplist.currentItem()
        mapname = item.text()
        text, ok = QInputDialog.getText(self,
                                        _('Map Name'),
                                        _('Map Name') + ':',
                                        text=mapname)
        if not ok:
            return
        text = text.strip()
        if (text == mapname):
            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(mapname, True), text)
        self.controller.deleteMap(mapname)
        item.setText(text)

    def changeMap(self):
        """Change a map."""
        current_map = self.maplist.currentItem().text()
        fileName, ok = QFileDialog.getOpenFileName(
            self, _("Select Map Image (> 500x500px recommended)"), "",
            _("Supported Images") + " (*.png *.jpg *.jpeg)")
        if ok:
            base = os.path.basename(fileName)
            name, __ = os.path.splitext(base)
            name = name.replace("_", " ")
            self.controller.deleteMap(current_map)
            self.controller.addMap(fileName, current_map)
            self.changePreview()

    def addMap(self):
        """Add a map."""
        fileName, ok = QFileDialog.getOpenFileName(
            self, _("Select Map Image (> 500x500px recommended)"), "",
            _("Supported Images") + " (*.png *.jpg  *.jpeg)")
        if ok:
            base = os.path.basename(fileName)
            name, __ = 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 downloadLadderMaps(self):
        players_per_team, ok = QInputDialog.getItem(
            self,
            _('Select the type of ladder maps to download'),
            _('Please select a map type') + ':',
            ['1vs1', '2vs2', '3vs3', '4vs4'],
            editable=False)
        players_per_team = int(players_per_team[0])
        found_a_map = False
        for sc2map in LiquipediaGrabber().get_ladder_mappool(players_per_team):
            if not sc2map in scctool.settings.maps:
                found_a_map = True
                self.controller.autoDownloadMap(sc2map, self)
                scctool.settings.maps.append(sc2map)
                items = self.maplist.findItems(sc2map, Qt.MatchExactly)
                if len(items) == 0:
                    item = QListWidgetItem(sc2map)
                    self.maplist.addItem(item)
                    self.maplist.setCurrentItem(item)
                else:
                    self.maplist.setCurrentItem(items[0])
                self.changePreview()
        if not found_a_map:
            QMessageBox.information(
                self, _("No missing map"),
                _('All of the current ladder maps are already present.'))

    def addFromLquipedia(self):
        """Add a map from Liquipedia."""
        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:
                        QApplication.setOverrideCursor(Qt.WaitCursor)
                        sc2map = grabber.get_map(search_str)
                    except MapNotFound:
                        QMessageBox.critical(
                            self, _("Map not found"),
                            _('"{}" was not found on Liquipedia.').format(
                                search_str))
                        continue
                    finally:
                        QApplication.restoreOverrideCursor()
                    map_name = sc2map.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)

                    try:
                        QApplication.setOverrideCursor(Qt.WaitCursor)
                        images = grabber.get_images(sc2map.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:
                        raise
                    finally:
                        QApplication.restoreOverrideCursor()
            except Exception as e:
                module_logger.exception("message")
                QMessageBox.critical(self, _("Error"), str(e))
            break

    def deleteMap(self):
        """Delete a map."""
        item = self.maplist.currentItem()
        mapname = item.text()
        buttonReply = QMessageBox.question(
            self, _('Delete map?'),
            _("Delete '{}' permanently?").format(mapname),
            QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if buttonReply == QMessageBox.Yes:
            self.controller.deleteMap(mapname)
            self.maplist.takeItem(self.maplist.currentRow())

    def changePreview(self):
        """Change the map preview."""
        if self.maplist.count() < 1:
            return

        mapname = self.maplist.currentItem().text()
        if (mapname == "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(mapname, True)
        pixmap = QPixmap(file)
        height = pixmap.height()
        width = pixmap.width()
        ext = os.path.splitext(file)[1].replace(".", "").upper()
        size = humanize.naturalsize(os.path.getsize(file))
        pixmap = QPixmap(file).scaled(self.mapsize, self.mapsize,
                                      Qt.KeepAspectRatio)
        self.mapPreview.setPixmap(pixmap)
        text = f"{width}x{height}px, {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:
            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", "new_maps_prompt",
                str(self.cb_newMapsPrompt.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()))
            scctool.settings.config.parser.set(
                "SCT", "sc2_network_listener_address",
                self.listener_address.text().strip())
            scctool.settings.config.parser.set(
                "SCT", "sc2_network_listener_enabled",
                str(self.cb_usesc2listener.isChecked()))
            scctool.settings.config.parser.set(
                "Countdown", "matchgrabber_update",
                str(self.cb_counter_matchgrabber_update.isChecked()))
            scctool.settings.config.parser.set(
                "Countdown", "replacement",
                self.le_countdown_replacement.text())
            scctool.settings.config.parser.set(
                "Countdown", "pre_txt", self.counter_pretext.toPlainText())
            scctool.settings.config.parser.set(
                "Countdown", "post_txt", self.counter_posttext.toPlainText())
            scctool.settings.config.parser.set(
                "Ticker", "prefix",
                self.ticker_pretext.text().strip())
            self.controller.matchControl.tickerChanged.emit()
            self.controller.refreshButtonStatus()
            # self.controller.setCBS()
            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.updateAllMapCompleters()
            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:
            module_logger.exception("message")
Ejemplo n.º 20
0
class BetterEditor:
    """QGIS Plugin Implementation."""
    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value("locale/userLocale")[0:2]
        locale_path = os.path.join(self.plugin_dir, "i18n",
                                   "BetterEditor_{}.qm".format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)
            QCoreApplication.installTranslator(self.translator)

        # Init settings
        self.settings = QSettings()
        self.settings.beginGroup("plugins/bettereditor")

    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate("BetterEditor", message)

    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        # Create settings dialog
        self.settings_dialog = SettingsDialog(self.settings,
                                              self.iface.mainWindow())
        self.settings_dialog.settingsChanged.connect(self.on_settings_changed)

        # Show Python console to trigger its creation
        self.python_console = self.iface.mainWindow().findChild(PythonConsole)
        if not self.python_console:
            self.iface.actionShowPythonDialog().trigger()
            self.python_console = self.iface.mainWindow().findChild(
                PythonConsole)
            self.python_console.hide()
            self.iface.actionShowPythonDialog().setChecked(False)

        self.about_action = QAction(
            QIcon(":/plugins/bettereditor/icons/about.svg"),
            self.tr("About"),
            parent=self.iface.mainWindow(),
        )
        self.about_action.triggered.connect(self.show_about)

        self.settings_action = QAction(
            QIcon(":/images/themes/default/console/iconSettingsConsole.svg"),
            self.tr("Settings"),
            parent=self.iface.mainWindow(),
        )
        self.settings_action.triggered.connect(self.show_settings)

        self.plugin_menu = self.iface.pluginMenu().addMenu(
            QIcon(":/plugins/bettereditor/icons/icon.svg"), "Better Editor")
        self.plugin_menu.addAction(self.about_action)
        self.plugin_menu.addAction(self.settings_action)
        self.toolbar = self.python_console.findChild(QToolBar)
        self.tab_widget = self.python_console.findChild(EditorTabWidget)

        # Connect current
        self.tab_widget.currentChanged.connect(self.customize_current_editor)

        # Tweak zoom shortcuts to prevent them from interfering
        # when typing '|' and '}' with an AZERTY (French) keyboard layout
        action_zoom_in = self.iface.mainWindow().findChild(
            QAction, "mActionZoomIn")
        action_zoom_out = self.iface.mainWindow().findChild(
            QAction, "mActionZoomOut")
        action_zoom_in.setShortcut("")
        action_zoom_out.setShortcut("")

        self.iface.initializationCompleted.connect(
            self.on_initialization_completed)
        for shortcut_name in (
                "ZoomInToCanvas",
                "ZoomInToCanvas2",
                "ZoomIn2",
                "ZoomOutOfCanvas",
        ):
            shortcut = self.iface.mainWindow().findChild(
                QShortcut, shortcut_name)
            if shortcut:
                shortcut.setParent(self.iface.mapCanvas())
                shortcut.setContext(Qt.WidgetWithChildrenShortcut)
        self.zoom_out_shortcut = QShortcut("Ctrl+Alt+-",
                                           self.iface.mapCanvas())
        self.zoom_out_shortcut.setObjectName("MyZoomOut")
        self.zoom_out_shortcut.setContext(Qt.WidgetWithChildrenShortcut)
        self.zoom_out_shortcut.activated.connect(action_zoom_out.trigger)

        # Customize buttons tooltips
        save_button = self.python_console.widget().saveFileButton
        saveas_button = self.python_console.widget().saveAsFileButton
        run_button = self.python_console.widget().runScriptEditorButton

        save_button.setToolTip(f"<b>{save_button.text()}</b> (Ctrl+S)")
        saveas_button.setToolTip(
            f"<b>{saveas_button.text()}</b> (Ctrl+Shift+S)")
        run_button.setToolTip(f"<b>{run_button.text()}</b> (Ctrl+R)")

        # Create our own toggle comment action
        separator = self.toolbar.addSeparator()
        separator = separator.setObjectName("separator")
        self.toggle_comment_action = self.toolbar.addAction(
            QIcon(
                ":/images/themes/default/console/iconCommentEditorConsole.svg"
            ),
            self.tr("Toggle Comment"),
        )
        self.toggle_comment_action.setObjectName("toggleComment")
        self.toggle_comment_action.triggered.connect(self.toggle_comment)
        self.toggle_comment_action.setShortcut("Ctrl+:")
        self.toggle_comment_action.setToolTip(
            f"<b>{self.toggle_comment_action.text()}</b> ({self.toggle_comment_action.shortcut().toString()})"
        )

        # Check that submodules are installed
        self.black = None
        self.jedi = None
        self.check_dependencies()

        # Add format action
        self.format_action = self.toolbar.addAction(
            QIcon(r":/plugins/bettereditor/icons/wizard.svg"),
            self.tr("Format file"))
        self.format_action.setObjectName("format")
        self.format_action.setShortcut("Ctrl+Alt+F")
        self.format_action.triggered.connect(self.format_file)
        self.format_action.setToolTip(
            f"<b>{self.format_action.text()}</b> ({self.format_action.shortcut().toString()})"
        )
        if not self.black:
            self.format_action.setEnabled(False)

        self.project = None
        if self.jedi:
            self.project = self.jedi.Project("",
                                             sys_path=sys.path,
                                             load_unsafe_extensions=True,
                                             smart_sys_path=False)

        patch(Editor, MonkeyEditor)
        patch(EditorTab, MonkeyEditorTab)
        patch(ScriptEdit, MonkeyScriptEditor)
        patch(ScriptEditorDialog, MonkeyScriptEditorDialog)
        ScriptEdit.project = self.project
        ScriptEdit.settings = self.settings

        self.oldAutoCloseBracketEditor = QSettings().value(
            "pythonConsole/autoCloseBracketEditor", False, bool)
        QSettings().setValue("pythonConsole/autoCloseBracketEditor", False)

        # Add insert icon from ressource action
        self.insert_resource_action = self.toolbar.addAction(
            QIcon(":/images/themes/default/propertyicons/diagram.svg"),
            self.tr("Insert resource path"),
        )
        self.insert_resource_action.setObjectName("insertResource")
        self.insert_resource_action.triggered.connect(self.insert_resource)
        self.insert_resource_action.setToolTip(
            f"<b>{self.insert_resource_action.text()}</b>")

        # Add next / previous tab shortcuts
        self.next_tab_shortcut = QShortcut("Ctrl+PgDown", self.python_console)
        self.next_tab_shortcut.setObjectName("NextTab")
        self.next_tab_shortcut.activated.connect(self.go_to_next_tab)

        self.previous_tab_shortcut = QShortcut("Ctrl+PgUp",
                                               self.python_console)
        self.previous_tab_shortcut.setObjectName("PreviousTab")
        self.previous_tab_shortcut.activated.connect(self.go_to_previous_tab)

        self.on_settings_changed()

        if not self.black or not self.jedi:
            if not check_pip():

                QMessageBox.warning(
                    self.iface.mainWindow(),
                    self.tr("Error"),
                    self.
                    tr("Pip is not installed. Try to get it, then restart QGIS, or  manually install <b>black</b> and <b>jedi</b>"
                       ),
                )

            else:
                if not self.black:
                    QMessageBox.warning(
                        self.iface.mainWindow(),
                        self.tr("Error"),
                        self.
                        tr("Unable to load <b>black</b>. Formatting will be disabled. You could try to manually install <b>black</b> with pip"
                           ),
                    )

                if not self.jedi:

                    # If check_module return true, an obsolete version was loaded, ad user was already informed
                    if not check_module("jedi"):
                        QMessageBox.warning(
                            self.iface.mainWindow(),
                            self.tr("Error"),
                            self.
                            tr("Unable to load <b>jedi</b>. Multi syntax error check will be disabled. You could try to manually install <b>jedi</b> with pip"
                               ),
                        )

    def check_dependencies(self):
        install("packaging")
        self.black, _ = import_or_install("black")
        self.jedi, jedi_version = import_or_install("jedi")

        # JEDI 0.17 is required
        if not check_minimum_version(jedi_version, "0.17"):
            res = QMessageBox.question(
                self.iface.mainWindow(),
                self.tr("Information"),
                self.
                tr("<b>jedi</b> version is {0} and BetterEditor needs {1}. Do you want to upgrade <b>jedi</b>?<br><b>Warning:</b> it could cause old code relying on the obsolete <b>jedi</b> to stop working correctly."
                   ).format(jedi_version, "0.17"),
                QMessageBox.Yes | QMessageBox.No,
            )

            if res == QMessageBox.Yes:
                install("jedi", True)
                QMessageBox.information(
                    self.iface.mainWindow(),
                    self.tr("Information"),
                    self.
                    tr("Jedi was upgraded. You need to restart QGIS to fully use BetterEditor"
                       ),
                )

            self.jedi = None

    def on_initialization_completed(self):
        """ Called after QGIS has completed its initialization """

        # Shortcuts are created after plugins
        for shortcut_name in (
                "ZoomInToCanvas",
                "ZoomInToCanvas2",
                "ZoomIn2",
                "ZoomOutOfCanvas",
        ):
            shortcut = self.iface.mainWindow().findChild(
                QShortcut, shortcut_name)
            if shortcut:
                shortcut.setParent(self.iface.mapCanvas())
                shortcut.setContext(Qt.WidgetWithChildrenShortcut)

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""

        # Delete Settings dialog
        self.settings_dialog.deleteLater()

        # Remove buttons tooltips
        save_button = self.python_console.widget().saveFileButton
        saveas_button = self.python_console.widget().saveAsFileButton
        run_button = self.python_console.widget().runScriptEditorButton

        save_button.setToolTip(save_button.text())
        saveas_button.setToolTip(saveas_button.text())
        run_button.setToolTip(run_button.text())

        # Show comment actions
        self.set_old_comments_action_visible(True)

        # Remove custom actions
        for action_name in ("separator", "toggleComment", "format",
                            "insertResource"):
            action = self.toolbar.findChild(QAction, action_name)
            if action:
                action.deleteLater()

        # Remove Next tab / previous tab shortcuts
        for shortcut in (self.next_tab_shortcut, self.previous_tab_shortcut):
            shortcut.activated.disconnect()
            shortcut.setEnabled(False)
            shortcut.deleteLater()

        # Reenable zoom shortcuts & actions
        for shortcut_name in (
                "ZoomInToCanvas",
                "ZoomInToCanvas2",
                "ZoomIn2",
                "ZoomOutOfCanvas",
        ):
            shortcut = self.iface.mainWindow().findChild(
                QShortcut, shortcut_name)
            if shortcut:
                shortcut.setParent(self.iface.mainWindow())
                shortcut.setContext(Qt.ApplicationShortcut)

        self.iface.mainWindow().findChild(
            QAction, "mActionZoomIn").setShortcut("Ctrl+Alt++")
        self.iface.mainWindow().findChild(
            QAction, "mActionZoomOut").setShortcut("Ctrl+Alt+-")

        self.zoom_out_shortcut.activated.disconnect()
        self.zoom_out_shortcut.setEnabled(False)
        self.zoom_out_shortcut.deleteLater()

        self.tab_widget.currentChanged.disconnect(
            self.customize_current_editor)
        for editor in self.python_console.findChildren(Editor):
            clear_all_indicators(editor)
            self.restore_editor(editor)

        # Revert MonkeyPatch
        unpatch(Editor)
        unpatch(EditorTab)
        unpatch(ScriptEdit)
        unpatch(ScriptEditorDialog)

        del ScriptEdit.project
        del ScriptEdit.settings

        # Remove menu from plugins menu
        self.iface.pluginMenu().removeAction(self.plugin_menu.menuAction())

        # Reactivate old autoCloseBracketEditor
        QSettings().setValue("pythonConsole/autoCloseBracketEditor",
                             self.oldAutoCloseBracketEditor)

    def current_editor(self) -> Editor:
        if not self.tab_widget.currentWidget():
            return None
        return self.tab_widget.currentWidget().findChild(Editor)

    def toggle_comment(self):
        self.current_editor().toggle_comment()

    def format_file(self):
        self.current_editor().format_file()

    def insert_resource(self):
        self.current_editor().insert_resource()

    def go_to_next_tab(self):
        self.tab_widget.setCurrentIndex(
            (self.tab_widget.currentIndex() + 1) % self.tab_widget.count())

    def go_to_previous_tab(self):
        self.tab_widget.setCurrentIndex(
            (self.tab_widget.currentIndex() - 1) % self.tab_widget.count())

    def show_about(self):

        # Used to display plugin icon in the about message box
        bogus = QWidget(self.iface.mainWindow())
        bogus.setWindowIcon(QIcon(":/plugins/bettereditor/icons/icon.svg"))

        cfg = configparser.ConfigParser()
        cfg.read(os.path.join(os.path.dirname(__file__), "metadata.txt"))
        version = cfg.get("general", "version")

        QMessageBox.about(
            bogus,
            self.tr("About Better Editor"),
            "<b>Version</b> {0}<br><br>"
            "<b>{1}</b> : <a href=https://github.com/YoannQDQ/qgis-better-editor>GitHub</a><br>"
            "<b>{2}</b> : <a href=https://github.com/YoannQDQ/qgis-better-editor/issues>GitHub</a><br>"
            "<b>{3}</b> : <a href=https://github.com/YoannQDQ/qgis-better-editor#better-editor-qgis-plugin>GitHub</a>"
            .format(
                version,
                self.tr("Source code"),
                self.tr("Report issues"),
                self.tr("Documentation"),
            ),
        )

        bogus.deleteLater()

    def set_old_comments_action_visible(self, value):
        self.toolbar.actions()[13].setVisible(value)
        self.toolbar.actions()[14].setVisible(value)
        self.toolbar.actions()[15].setVisible(value)

    def show_settings(self):

        self.settings_dialog.show()
        self.settings_dialog.raise_()

    def on_settings_changed(self):

        # Hide / Show old comment actions
        self.set_old_comments_action_visible(
            not self.settings.value("hide_old_comment_actions", True, bool))

        for editor in self.python_console.findChildren(Editor):
            self.customize_editor(editor)

    def customize_current_editor(self):
        return self.customize_editor()

    def customize_editor(self, editor: Editor = None):
        if editor is None:
            editor = self.current_editor()

        if editor is None:
            return
        editor.project = self.project

        # Disable shortcuts
        for shortcut in editor.findChildren(QShortcut):
            shortcut.setEnabled(False)

        editor.set_completer(QCompleter(editor))
        editor.completer.setModel(CompletionModel([], editor))
        editor.callTips = CallTips(editor)
        editor.callTipsTimer = QTimer(editor)
        editor.callTipsTimer.setSingleShot(True)
        editor.callTipsTimer.setInterval(500)
        editor.callTipsTimer.timeout.connect(editor.update_calltips)

        editor.setCallTipsStyle(QsciScintilla.CallTipsNone)
        editor.setAutoCompletionSource(QsciScintilla.AcsNone)
        editor.setFolding(
            self.settings.value("folding_style",
                                QsciScintilla.BoxedTreeFoldStyle, int))

        # Add a small margin after the indicator (if folding is not Plain or None)
        if editor.folding() > 1:
            editor.setMarginWidth(3, "0")
        else:
            editor.setMarginWidth(3, "")

        if self.settings.value("ruler_visible", True, bool):
            editor.setEdgeMode(QsciScintilla.EdgeLine)
            editor.setEdgeColumn(
                self.settings.value("max_line_length", 88, int))
            editor.setEdgeColor(
                self.settings.value("ruler_color", QColor("#00aaff"), QColor))
        else:
            editor.setEdgeMode(QsciScintilla.EdgeNone)

        # Change syntax error marker
        define_indicators(editor)

        editor.cursorPositionChanged.connect(editor.on_position_changed)

    def restore_editor(self, editor: Editor):
        editor.cursorPositionChanged.disconnect(editor.on_position_changed)
        editor.setFolding(QsciScintilla.PlainFoldStyle)
        editor.setEdgeMode(QsciScintilla.EdgeLine)
        editor.setEdgeColumn(80)
        editor.setMarginWidth(3, "")
        editor.setEdgeColor(QSettings().value("pythonConsole/edgeColorEditor",
                                              QColor("#efefef"), QColor))

        # Disable shortcuts
        for shortcut in editor.findChildren(QShortcut):
            shortcut.setEnabled(True)

        editor.markerDefine(
            QgsApplication.getThemePixmap(
                "console/iconSyntaxErrorConsole.svg"),
            editor.MARKER_NUM,
        )

        editor.setAnnotationDisplay(QsciScintilla.AnnotationBoxed)
        editor.setCallTipsStyle(QsciScintilla.CallTipsNoContext)
        editor.setAutoCompletionSource(QsciScintilla.AcsAll)

        editor.callTips.deleteLater()
        del editor.callTips
        editor.callTipsTimer.deleteLater()
        del editor.callTipsTimer
        editor.completer.deleteLater()
        del editor.completer
        del editor.project
Ejemplo n.º 21
0
    def make_shortcut(self):
        shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_L), self)
        shortcut.setContext(Qt.WindowShortcut)
        shortcut.activated.connect(self.controller.show_location_toolbar)

        def show_filter():
            self.file_filter.setFocus(Qt.ShortcutFocusReason)
            self.filter_toolbar.show()

        shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_K), self)
        shortcut.setContext(Qt.WindowShortcut)
        shortcut.activated.connect(show_filter)

        shortcut = QShortcut(QKeySequence(Qt.Key_F3), self)
        shortcut.setContext(Qt.WindowShortcut)
        shortcut.activated.connect(self.controller.show_search)

        shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_F), self)
        shortcut.setContext(Qt.WindowShortcut)
        shortcut.activated.connect(self.controller.show_search)

        shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_W), self)
        shortcut.setContext(Qt.WindowShortcut)
        shortcut.activated.connect(self.controller.close_window)

        shortcut = QShortcut(QKeySequence(Qt.ALT + Qt.Key_Up), self)
        shortcut.setContext(Qt.WindowShortcut)
        shortcut.activated.connect(self.controller.parent_directory)

        shortcut = QShortcut(Qt.Key_Home, self)
        shortcut.setContext(Qt.WindowShortcut)
        shortcut.activated.connect(lambda: self.file_view.ensureVisible(0, 0, 1, 1))

        shortcut = QShortcut(Qt.Key_End, self)
        shortcut.setContext(Qt.WindowShortcut)
        shortcut.activated.connect(
            lambda: self.file_view.ensureVisible(
                0, self.file_view._layout.get_bounding_rect().height(), 1, 1))

        shortcut = QShortcut(Qt.Key_PageUp, self)
        shortcut.setContext(Qt.WindowShortcut)
        shortcut.activated.connect(lambda: self.file_view.scroll_by(0, -self.file_view.viewport().height()))

        shortcut = QShortcut(Qt.Key_PageDown, self)
        shortcut.setContext(Qt.WindowShortcut)
        shortcut.activated.connect(lambda: self.file_view.scroll_by(0, self.file_view.viewport().height()))
Ejemplo n.º 22
0
class My_MainWindow(Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.tree_model = None
        self.running_threads = set()
        self.downloaded_class = set()
        self.best_schedules = []
        self.solve_schedule_thread = None
        self.req_breaks = []

    def setupUi(self, MainWindow):
        super().setupUi(MainWindow)
        self.tree_model = ClassTreeModel()
        self.treeView.setModel(self.tree_model)
        self.treeView.setColumnWidth(0, 180)
        self.treeView.setColumnWidth(1, 80)
        self.treeView.setColumnWidth(2, 80)
        self.treeView.setColumnWidth(6, 80)

        # signals to add courses
        self.addClassButton.clicked.connect(self.retrieve_class_on_click)
        self.classNameLineEdit.returnPressed.connect(
            self.retrieve_class_on_click)

        # set up schedule ploting area
        self.plot_canvas = FigureCanvas(Figure(figsize=(12, 6)))
        self.plot_canvas.setSizePolicy(QSizePolicy.Expanding,
                                       QSizePolicy.Expanding)
        self.scheduleTabHorizontalLayout.addWidget(self.plot_canvas)
        self.plot_ax = self.plot_canvas.figure.subplots()
        self.show_time_table()

        # signals to update schedules calculations
        self.updatPushButton.clicked.connect(self.calculate_schedules)

        # signals to handle schedule list selection
        self.scheduleScoreTreeWidget.itemSelectionChanged.connect(
            self.handle_score_list_selection)

        # signals to handle policy page actions
        self.earlyPenaltyLineEdit.textEdited.connect(
            self.handle_early_penalty_line_edit_change)
        self.latePenaltyLineEdit.textEdited.connect(
            self.handle_late_penalty_line_edit_change)
        self.intervalPenaltyLineEdit.textChanged.connect(
            self.handle_interval_penalty_line_edit_change)
        self.requiredBreaksLineEdit.textChanged.connect(
            self.handle_breaks_line_edit_change)
        self.addBreakPushButton.clicked.connect(self.add_required_breaks)

        self.delete_break_short_cut = QShortcut(
            QKeySequence(QKeySequence.Delete), self.breakTreeWidget)
        self.delete_break_short_cut.setContext(Qt.WidgetShortcut)
        self.delete_break_short_cut.activated.connect(
            self.delete_selected_break)

        self.delete_course_short_cut = QShortcut(
            QKeySequence(QKeySequence.Delete), self.treeView)
        self.delete_course_short_cut.setContext(Qt.WidgetShortcut)
        self.delete_course_short_cut.activated.connect(
            self.delete_selected_course)

    def retrieve_class_on_click(self):
        term = self.termLineEdit.text()
        class_name = self.classNameLineEdit.text().upper()
        url = 'https://classes.usc.edu/term-' + term + '/course/' + class_name + '/'

        if class_name in self.downloaded_class:
            QMessageBox(QMessageBox.Warning, "Already Exists",
                        class_name + " already exists.",
                        QMessageBox.Close).exec()
            return

        self.downloaded_class.add(class_name)
        thread = LoadClassThread(url, class_name)
        self.running_threads.add(thread)
        thread.results_ready.connect(self.add_class)
        msg = "Downloading"
        for running_thread in self.running_threads:
            msg += " " + running_thread.name
        msg += " ..."
        self.statusBar.showMessage(msg)
        thread.start()

    def add_class(self, thread):
        self.running_threads.remove(thread)
        if self.running_threads:
            msg = "Downloading"
            for running_thread in self.running_threads:
                msg += " " + running_thread.name
            msg += " ..."
            self.statusBar.showMessage(msg)
        else:
            self.statusBar.clearMessage()
        if thread.root is None:
            QMessageBox(
                QMessageBox.Warning, "Download Failed",
                "Invalid term / course name or bad Internet connection.\n" +
                thread.url, QMessageBox.Close).exec()
            self.downloaded_class.remove(thread.name)
            return
        self.tree_model.add_top_level_child(thread.root)

    def show_time_table(self, sections=None):

        if sections is None:
            sections = []

        self.plot_ax.clear()
        for section in sections:
            for day in section.days_list:
                bar_bottom = section.start_end[0]
                bar_height = section.start_end[1] - section.start_end[0]
                self.plot_ax.bar(day,
                                 bar_height,
                                 width=0.92,
                                 bottom=bar_bottom,
                                 linewidth=0,
                                 fc='#3CA730')
                description = (section.name + " " + section.section_id + " " +
                               section.section_type[:4])
                self.plot_ax.text(day,
                                  bar_bottom + bar_height / 2,
                                  description,
                                  horizontalalignment='center',
                                  verticalalignment='center',
                                  fontfamily='Nirmala UI',
                                  color='white',
                                  fontsize='medium')

        self.plot_ax.set_axisbelow(True)
        self.plot_ax.minorticks_on()
        self.plot_ax.set_xticks([0, 1, 2, 3, 4])
        self.plot_ax.set_xticks([0.5, 1.5, 2.5, 3.5], minor=True)
        self.plot_ax.set_yticks(range(5 * 60, 24 * 60, 60))
        self.plot_ax.set_yticklabels(
            [str(time) + ":00" for time in range(5, 24)],
            fontfamily='Nirmala UI')
        self.plot_ax.set_yticks(range(5 * 60 + 30, 24 * 60, 60), minor=True)
        self.plot_ax.set_xlim(-0.5, 4.5)
        self.plot_ax.set_ylim(23 * 60, 5 * 60)
        self.plot_ax.xaxis.tick_top()
        self.plot_ax.set_xticklabels(["Mon", "Tue", "Wed", "Thu", "Fri"],
                                     fontfamily='Nirmala UI',
                                     fontsize='x-large')

        # ax.grid(which = 'major', visible = False)
        self.plot_ax.grid(which='minor', axis='x', linewidth=0.5, alpha=0.8)
        self.plot_ax.grid(which='major', axis='y', linewidth=0.5, alpha=0.8)
        self.plot_ax.grid(which='minor', axis='y', linewidth=0.5, alpha=0.3)
        self.plot_ax.tick_params(which='both',
                                 top=False,
                                 left=False,
                                 right=False,
                                 bottom=False)
        self.plot_ax.spines['bottom'].set_color("#bababa")
        self.plot_ax.spines['top'].set_color("#bababa")
        self.plot_ax.spines['left'].set_color("#bababa")
        self.plot_ax.spines['right'].set_color("#bababa")
        self.plot_canvas.draw()

    def calculate_schedules(self):
        if (self.solve_schedule_thread):
            return
        list_of_componets = []
        self.tree_model.lock(True)
        for course in self.tree_model.root.data:
            if not course.is_included():
                continue
            for component in course.data:
                if not component.is_included():
                    continue
                list_of_sections = [
                    section.data for section in component.data
                    if section.data.include
                ]
                list_of_componets.append(list_of_sections)

        if not list_of_componets:
            self.tree_model.lock(False)
            QMessageBox(QMessageBox.Warning, "No Course Selected",
                        "Cannot make schedules since no course is selected.",
                        QMessageBox.Close).exec()
            return

        if self.earlyHorizontalSlider.isEnabled():
            time = qtime2minutes(self.earlyTimeEdit.time())
            penalty = self.earlyHorizontalSlider.value() / 1000
            early_curve = [(0, penalty * time), (time, 0)]
        else:
            early_curve = parse_ELI_penalty(self.earlyPenaltyLineEdit.text())
            if early_curve is None:
                QMessageBox(QMessageBox.Warning, "Invalid Early Penalty",
                            self.earlyPenaltyLineEdit.text() + " isn't valid.",
                            QMessageBox.Close).exec()
                self.tree_model.lock(False)
                return

        if self.lateHorizontalSlider.isEnabled():
            time = qtime2minutes(self.lateTimeEdit.time())
            penalty = self.lateHorizontalSlider.value() / 1000
            late_curve = [(time, 0), (1440, penalty * (1440 - time))]
        else:
            late_curve = parse_ELI_penalty(self.latePenaltyLineEdit.text())
            if late_curve is None:
                QMessageBox(QMessageBox.Warning, "Invalid Late Penalty",
                            self.latePenaltyLineEdit.text() + " isn't valid.",
                            QMessageBox.Close).exec()
                self.tree_model.lock(False)
                return

        if self.intervalHorizontalSlider.isEnabled():
            time = qtime2minutes(self.intervalTimeEdit.time())
            penalty = self.intervalHorizontalSlider.value() / 1000
            interval_curve = [(time, 0), (1440, penalty * (1440 - time))]
        else:
            interval_curve = parse_ELI_penalty(
                self.intervalPenaltyLineEdit.text())
            if interval_curve is None:
                QMessageBox(
                    QMessageBox.Warning, "Invalid Interval Penalty",
                    self.intervalPenaltyLineEdit.text() + " isn't valid.",
                    QMessageBox.Close).exec()
                self.tree_model.lock(False)
                return

        if self.breakTreeWidget.isEnabled():
            req_breaks = self.req_breaks
        else:
            req_breaks = parse_req_breaks(self.requiredBreaksLineEdit.text())
            if req_breaks is None:
                QMessageBox(
                    QMessageBox.Warning, "Invalid Required Breaks",
                    self.requiredBreaksLineEdit.text() + " isn't valid.",
                    QMessageBox.Close).exec()
                self.tree_model.lock(False)
                return

        self.solve_schedule_thread = CalcScheduleThread(
            list_of_componets, early_curve, late_curve, interval_curve,
            req_breaks)

        self.solve_schedule_thread.results_ready.connect(
            self.handle_schedule_calc_results)
        self.solve_schedule_thread.update_count.connect(
            self.handle_schedule_calc_update)

        self.scheduleScoreTreeWidget.clear()
        self.scheduleDetailsTreeWidget.clear()
        self.solve_schedule_thread.start()

    def handle_schedule_calc_results(self, thread):
        self.tree_model.lock(False)
        if thread.best:
            self.best_schedules = []
            while thread.best:
                self.best_schedules.append(heapq.heappop(thread.best))
            self.best_schedules.reverse()
            num_score_pair_list = []
            for i in range(len(self.best_schedules)):
                fields = []
                fields.append(str(i + 1))
                fields.append(str("{:.2f}".format(-self.best_schedules[i][0])))
                fields.append(str("{:.2f}".format(self.best_schedules[i][2])))
                fields.append(str("{:.2f}".format(self.best_schedules[i][3])))
                fields.append(str("{:.2f}".format(self.best_schedules[i][4])))
                fields.append(str("{:.2f}".format(self.best_schedules[i][5])))
                num_score_pair_list.append(QTreeWidgetItem(None, fields))
            self.scheduleScoreTreeWidget.insertTopLevelItems(
                0, num_score_pair_list)
        self.solve_schedule_thread = None

    def handle_schedule_calc_update(self, count):
        self.statusBar.showMessage(
            "Solving for best schedules... {} valid schedules found.".format(
                count), 1000)

    def handle_score_list_selection(self):
        selected = self.scheduleScoreTreeWidget.selectedItems()
        if selected:
            index = self.scheduleScoreTreeWidget.indexOfTopLevelItem(
                selected[0])
            if index >= 0 and index < len(self.best_schedules):
                self.show_schedule_details(self.best_schedules[index][1])
                self.show_time_table(self.best_schedules[index][1])

    def show_schedule_details(self, schedule):
        section_item_list = []
        for section in schedule:
            fields = []
            fields.append(section.name)
            fields.append(section.section_type)
            fields.append(section.section_id)
            fields.append(section.time)
            fields.append(section.days)
            fields.append(section.registered)
            fields.append("X" if section.closed else "")
            fields.append(section.instructor)
            fields.append(section.location)
            section_item_list.append(QTreeWidgetItem(None, fields))
        self.scheduleDetailsTreeWidget.clear()
        self.scheduleDetailsTreeWidget.insertTopLevelItems(
            0, section_item_list)

    def handle_early_penalty_line_edit_change(self, text):
        if text:
            self.earlyHorizontalSlider.setEnabled(False)
            self.earlyTimeEdit.setEnabled(False)
            if parse_ELI_penalty(text):
                self.earlyPenaltyLineEdit.setStyleSheet(
                    "background-color: #b6fac2")
            else:
                self.earlyPenaltyLineEdit.setStyleSheet(
                    "background-color: #fab6b6")
        else:
            self.earlyHorizontalSlider.setEnabled(True)
            self.earlyTimeEdit.setEnabled(True)
            self.earlyPenaltyLineEdit.setStyleSheet("")

    def handle_late_penalty_line_edit_change(self, text):
        if text:
            self.lateHorizontalSlider.setEnabled(False)
            self.lateTimeEdit.setEnabled(False)
            if parse_ELI_penalty(text):
                self.latePenaltyLineEdit.setStyleSheet(
                    "background-color: #b6fac2")
            else:
                self.latePenaltyLineEdit.setStyleSheet(
                    "background-color: #fab6b6")
        else:
            self.lateHorizontalSlider.setEnabled(True)
            self.lateTimeEdit.setEnabled(True)
            self.latePenaltyLineEdit.setStyleSheet("")

    def handle_interval_penalty_line_edit_change(self, text):
        if text:
            self.intervalHorizontalSlider.setEnabled(False)
            self.intervalTimeEdit.setEnabled(False)
            if parse_ELI_penalty(text):
                self.intervalPenaltyLineEdit.setStyleSheet(
                    "background-color: #b6fac2")
            else:
                self.intervalPenaltyLineEdit.setStyleSheet(
                    "background-color: #fab6b6")
        else:
            self.intervalHorizontalSlider.setEnabled(True)
            self.intervalTimeEdit.setEnabled(True)
            self.intervalPenaltyLineEdit.setStyleSheet("")

    def handle_breaks_line_edit_change(self, text):
        if text:
            self.addBreakPushButton.setEnabled(False)
            self.breakHorizontalSlider.setEnabled(False)
            self.breakStartTimeEdit.setEnabled(False)
            self.breakEndTimeEdit.setEnabled(False)
            self.breakLenTimeEdit.setEnabled(False)
            self.breakTreeWidget.setEnabled(False)
            if parse_req_breaks(text):
                self.requiredBreaksLineEdit.setStyleSheet(
                    "background-color: #b6fac2")
            else:
                self.requiredBreaksLineEdit.setStyleSheet(
                    "background-color: #fab6b6")
        else:
            self.addBreakPushButton.setEnabled(True)
            self.breakHorizontalSlider.setEnabled(True)
            self.breakStartTimeEdit.setEnabled(True)
            self.breakEndTimeEdit.setEnabled(True)
            self.breakLenTimeEdit.setEnabled(True)
            self.breakTreeWidget.setEnabled(True)
            self.requiredBreaksLineEdit.setStyleSheet("")

    def add_required_breaks(self):
        start = qtime2minutes(self.breakStartTimeEdit.time())
        end = qtime2minutes(self.breakEndTimeEdit.time())
        penalty = self.breakHorizontalSlider.value() / 5
        length = qtime2minutes(self.breakLenTimeEdit.time())
        if start > end:
            start, end = end, start
        self.req_breaks.append(req_break((start, end), length, penalty))
        self.breakTreeWidget.clear()
        break_item_list = []
        for some_break in self.req_breaks:
            fields = []
            fields.append(minutes2str(some_break.start_end[0]))
            fields.append(minutes2str(some_break.start_end[1]))
            fields.append(minutes2str(some_break.length))
            fields.append(str(some_break.penalty))
            break_item_list.append(QTreeWidgetItem(None, fields))
        self.breakTreeWidget.insertTopLevelItems(0, break_item_list)

    def delete_selected_break(self):
        selected = self.breakTreeWidget.selectedItems()
        if not selected:
            return
        index = self.breakTreeWidget.indexOfTopLevelItem(selected[0])
        if index < len(self.req_breaks):
            self.req_breaks.pop(index)
        self.breakTreeWidget.clear()
        break_item_list = []
        for some_break in self.req_breaks:
            fields = []
            fields.append(minutes2str(some_break.start_end[0]))
            fields.append(minutes2str(some_break.start_end[1]))
            fields.append(minutes2str(some_break.length))
            fields.append(str(some_break.penalty))
            break_item_list.append(QTreeWidgetItem(None, fields))
        self.breakTreeWidget.insertTopLevelItems(0, break_item_list)

    def delete_selected_course(self):
        selected = self.treeView.selectedIndexes()
        if selected and self.tree_model.parent(selected[0]) == QModelIndex():
            name = self.tree_model.delete_top_level_child(selected[0].row())
            if name in self.downloaded_class:
                self.downloaded_class.remove(name)
Ejemplo n.º 23
0
class Lookup(QWidget):
    MODEL_CLASS = None

    def __init__(self, parent, model):
        QWidget.__init__(self, parent, Qt.Window)
        self.model = model
        self.model.view = self
        self._setupUi()

        self.searchEdit.searchChanged.connect(self.searchChanged)
        self.searchEdit.returnPressed.connect(self.returnPressed)
        self.namesList.currentRowChanged.connect(self.currentRowChanged)
        self.namesList.itemDoubleClicked.connect(self.itemDoubleClicked)
        self._shortcutUp.activated.connect(self.upPressed)
        self._shortcutDown.activated.connect(self.downPressed)

    def _setupUi(self):
        self.setWindowTitle(tr("Lookup"))
        self.resize(314, 331)
        self.verticalLayout = QVBoxLayout(self)
        self.searchEdit = SearchEdit(self)
        self.verticalLayout.addWidget(self.searchEdit)
        self.namesList = QListWidget(self)
        self.namesList.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.namesList.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.namesList.setUniformItemSizes(True)
        self.namesList.setSelectionRectVisible(True)
        self.verticalLayout.addWidget(self.namesList)

        self.searchEdit.immediate = True
        self._shortcutUp = QShortcut(self.searchEdit)
        self._shortcutUp.setKey(QKeySequence(Qt.Key_Up))
        self._shortcutUp.setContext(Qt.WidgetShortcut)
        self._shortcutDown = QShortcut(self.searchEdit)
        self._shortcutDown.setKey(QKeySequence(Qt.Key_Down))
        self._shortcutDown.setContext(Qt.WidgetShortcut)

    def _restoreSelection(self):
        self.namesList.setCurrentRow(self.model.selected_index)

    #--- Event Handlers
    def returnPressed(self):
        self.model.go()

    def searchChanged(self):
        self.model.search_query = str(self.searchEdit.text())

    def currentRowChanged(self, row):
        if row >= 0:
            self.model.selected_index = row

    def itemDoubleClicked(self, item):
        self.model.go()

    def upPressed(self):
        if self.namesList.currentRow() > 0:
            self.namesList.setCurrentRow(self.namesList.currentRow()-1)

    def downPressed(self):
        if self.namesList.currentRow() < self.namesList.count()-1:
            self.namesList.setCurrentRow(self.namesList.currentRow()+1)

    #--- model --> view
    def refresh(self):
        self.namesList.clear()
        self.namesList.addItems(self.model.names)
        self._restoreSelection()
        self.searchEdit.setText(self.model.search_query)

    def show(self):
        QWidget.show(self)
        self.searchEdit.setFocus()
        # see csv_options
        self.raise_()

    def hide(self):
        QWidget.hide(self)
Ejemplo n.º 24
0
def install_shortcuts(obj, actions, ide):
    short = resources.get_shortcut
    for action in actions:
        short_key = action.get("shortcut", None)
        action_data = action.get("action", None)
        connect = action.get("connect", None)
        shortcut = None
        item_ui = None
        func = None
        if connect is not None:
            func = getattr(obj, connect, None)

        if short_key and not action_data:
            if isinstance(short_key, QKeySequence):
                shortcut = QShortcut(short_key, ide)
            else:
                if short(short_key) is None:
                    logger.warning("Not shorcut for %s" % short_key)
                    continue
                shortcut = QShortcut(short(short_key), ide)
            shortcut.setContext(Qt.ApplicationShortcut)
            if isinstance(func, collections.Callable):
                shortcut.activated.connect(func)
        if action_data:
            is_menu = action_data.get('is_menu', False)
            if is_menu:
                item_ui = QMenu(action_data['text'], ide)
            else:
                item_ui = QAction(action_data['text'], ide)
                object_name = "%s.%s" % (obj.__class__.__name__, connect)
                item_ui.setObjectName(object_name)
                # FIXME: Configurable
                item_ui.setIconVisibleInMenu(False)
            image_name = action_data.get('image', None)
            section = action_data.get('section', None)
            weight = action_data.get('weight', None)
            keysequence = action_data.get('keysequence', None)
            if image_name:
                if isinstance(image_name, int):
                    icon = ide.style().standardIcon(image_name)
                    item_ui.setIcon(icon)
                elif isinstance(image_name, str):
                    if image_name.startswith("/home"):
                        icon = QIcon(image_name)
                    else:
                        icon = QIcon(":img/" + image_name)
                    item_ui.setIcon(icon)
            if short_key and not is_menu:
                if short(short_key) is None:
                    logger.warning("Not shortcut for %s" % short_key)
                    continue
                item_ui.setShortcut(short(short_key))
                # Add tooltip with append shortcut
                item_ui.setToolTip(
                    tooltip_with_shortcut(item_ui.text(), short(short_key)))
                item_ui.setShortcutContext(Qt.ApplicationShortcut)
            elif keysequence and not is_menu:
                item_ui.setShortcut(short(keysequence))
                item_ui.setShortcutContext(Qt.ApplicationShortcut)
            if isinstance(func, collections.Callable) and not is_menu:
                item_ui.triggered.connect(lambda _, func=func: func())
            if section and section[0] is not None and weight:
                ide.register_menuitem(item_ui, section, weight)
                if image_name and not is_menu:
                    ide.register_toolbar(item_ui, section, weight)

        if short_key and shortcut:
            ide.register_shortcut(short_key, shortcut, item_ui)
Ejemplo n.º 25
0
def install_shortcuts(obj, actions, ide):
    short = resources.get_shortcut
    for action in actions:
        short_key = action.get("shortcut", None)
        action_data = action.get("action", None)
        connect = action.get("connect", None)
        shortcut = None
        item_ui = None
        func = None
        if connect is not None:
            func = getattr(obj, connect, None)

        if short_key and not action_data:
            if isinstance(short_key, QKeySequence):
                shortcut = QShortcut(short_key, ide)
            else:
                if short(short_key) is None:
                    logger.warning("Not shorcut for %s" % short_key)
                    continue
                shortcut = QShortcut(short(short_key), ide)
            shortcut.setContext(Qt.ApplicationShortcut)
            if isinstance(func, collections.Callable):
                shortcut.activated.connect(func)
        if action_data:
            is_menu = action_data.get('is_menu', False)
            if is_menu:
                item_ui = QMenu(action_data['text'], ide)
            else:
                item_ui = QAction(action_data['text'], ide)
                object_name = "%s.%s" % (obj.__class__.__name__, connect)
                item_ui.setObjectName(object_name)
                # FIXME: Configurable
                item_ui.setIconVisibleInMenu(False)
            image_name = action_data.get('image', None)
            section = action_data.get('section', None)
            weight = action_data.get('weight', None)
            keysequence = action_data.get('keysequence', None)
            if image_name:
                if isinstance(image_name, int):
                    icon = ide.style().standardIcon(image_name)
                    item_ui.setIcon(icon)
                elif isinstance(image_name, str):
                    if image_name.startswith("/home"):
                        icon = QIcon(image_name)
                    else:
                        icon = QIcon(":img/" + image_name)
                    item_ui.setIcon(icon)
            if short_key and not is_menu:
                if short(short_key) is None:
                    logger.warning("Not shortcut for %s" % short_key)
                    continue
                item_ui.setShortcut(short(short_key))
                # Add tooltip with append shortcut
                item_ui.setToolTip(
                    tooltip_with_shortcut(item_ui.text(), short(short_key)))
                item_ui.setShortcutContext(Qt.ApplicationShortcut)
            elif keysequence and not is_menu:
                item_ui.setShortcut(short(keysequence))
                item_ui.setShortcutContext(Qt.ApplicationShortcut)
            if isinstance(func, collections.Callable) and not is_menu:
                item_ui.triggered.connect(lambda _, func=func: func())
            if section and section[0] is not None and weight:
                ide.register_menuitem(item_ui, section, weight)
                if image_name and not is_menu:
                    ide.register_toolbar(item_ui, section, weight)

        if short_key and shortcut:
            ide.register_shortcut(short_key, shortcut, item_ui)
Ejemplo n.º 26
0
class SearchWidget(QFrame):
    """Widget, appeared, when Ctrl+F pressed.
    Has different forms for different search modes
    """

    Normal = 'normal'
    Good = 'good'
    Bad = 'bad'
    Incorrect = 'incorrect'

    visibilityChanged = pyqtSignal(bool)
    """
    visibilityChanged(visible)

    **Signal** emitted, when widget has been shown or hidden
    """  # pylint: disable=W0105

    searchInDirectoryStartPressed = pyqtSignal(type(re.compile('')), list, str)
    """
    searchInDirectoryStartPressed(regEx, mask, path)

    **Signal** emitted, when 'search in directory' button had been pressed
    """  # pylint: disable=W0105

    searchInDirectoryStopPressed = pyqtSignal()
    """
    searchInDirectoryStopPressed()

    **Signal** emitted, when 'stop search in directory' button had been pressed
    """  # pylint: disable=W0105

    replaceCheckedStartPressed = pyqtSignal(str)
    """
    replaceCheckedStartPressed(replText)

    **Signal** emitted, when 'replace checked' button had been pressed
    """  # pylint: disable=W0105

    replaceCheckedStopPressed = pyqtSignal()
    """
    replaceCheckedStartPressed()

    **Signal** emitted, when 'stop replacing checked' button had been pressed
    """  # pylint: disable=W0105

    searchRegExpChanged = pyqtSignal(type(re.compile('')))
    """
    searchRegExpValidStateChanged(regEx)

    **Signal** emitted, when search regexp has been changed.
    If reg exp is invalid - regEx object contains empty pattern
    """  # pylint: disable=W0105

    searchNext = pyqtSignal()
    """
    searchNext()

    **Signal** emitted, when 'Search Next' had been pressed
    """  # pylint: disable=W0105

    searchPrevious = pyqtSignal()
    """
    searchPrevious()

    **Signal** emitted, when 'Search Previous' had been pressed
    """  # pylint: disable=W0105

    replaceFileOne = pyqtSignal(str)
    """
    replaceFileOne(replText)

    **Signal** emitted, when 'Replace' had been pressed
    """  # pylint: disable=W0105

    replaceFileAll = pyqtSignal(str)
    """
    replaceFileAll(replText)

    **Signal** emitted, when 'Replace All' had been pressed
    """  # pylint: disable=W0105

    def __init__(self, plugin):
        QFrame.__init__(self, core.workspace())
        self._mode = None
        self.plugin = plugin
        uic.loadUi(os.path.join(os.path.dirname(__file__), 'SearchWidget.ui'), self)

        self.cbSearch.setCompleter(None)
        self.cbReplace.setCompleter(None)
        self.cbMask.setCompleter(None)

        self.fsModel = QDirModel(self.cbPath.lineEdit())
        self.fsModel.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot)

        self.cbPath.lineEdit().setCompleter(QCompleter(self.fsModel,
                                                       self.cbPath.lineEdit()))
        self._pathBackspaceShortcut = QShortcut(QKeySequence("Ctrl+Backspace"), self.cbPath, self._onPathBackspace)
        self._pathBackspaceShortcut.setContext(Qt.WidgetWithChildrenShortcut)

        # TODO QDirModel is deprecated but QCompleter does not yet handle
        # QFileSystemodel - please update when possible."""
        self.cbSearch.setCompleter(None)
        self.pbSearchStop.setVisible(False)
        self.pbReplaceCheckedStop.setVisible(False)

        self._progress = QProgressBar(self)
        self._progress.setAlignment(Qt.AlignCenter)
        self._progress.setToolTip(self.tr("Search in progress..."))
        self._progress.setMaximumSize(QSize(80, 16))
        core.mainWindow().statusBar().insertPermanentWidget(1, self._progress)
        self._progress.setVisible(False)

        # cd up action
        self.tbCdUp = QToolButton(self.cbPath.lineEdit())
        self.tbCdUp.setIcon(QIcon(":/enkiicons/go-up.png"))
        self.tbCdUp.setCursor(Qt.ArrowCursor)
        self.tbCdUp.installEventFilter(self)  # for drawing button

        self.cbSearch.installEventFilter(self)  # for catching Tab and Shift+Tab
        self.cbReplace.installEventFilter(self)  # for catching Tab and Shift+Tab
        self.cbPath.installEventFilter(self)  # for catching Tab and Shift+Tab
        self.cbMask.installEventFilter(self)  # for catching Tab and Shift+Tab

        self._closeShortcut = QShortcut(QKeySequence("Esc"), self)
        self._closeShortcut.setContext(Qt.WidgetWithChildrenShortcut)
        self._closeShortcut.activated.connect(self.hide)

        # connections
        self.cbSearch.lineEdit().textChanged.connect(self._onSearchRegExpChanged)

        self.cbSearch.lineEdit().returnPressed.connect(self._onReturnPressed)
        self.cbReplace.lineEdit().returnPressed.connect(self._onReturnPressed)
        self.cbPath.lineEdit().returnPressed.connect(self._onReturnPressed)
        self.cbMask.lineEdit().returnPressed.connect(self._onReturnPressed)

        self.cbRegularExpression.stateChanged.connect(self._onSearchRegExpChanged)
        self.cbCaseSensitive.stateChanged.connect(self._onSearchRegExpChanged)
        self.cbWholeWord.stateChanged.connect(self._onSearchRegExpChanged)

        self.tbCdUp.clicked.connect(self._onCdUpPressed)

        self.pbNext.pressed.connect(self.searchNext)
        self.pbPrevious.pressed.connect(self.searchPrevious)
        self.pbSearchStop.pressed.connect(self.searchInDirectoryStopPressed)
        self.pbReplaceCheckedStop.pressed.connect(self.replaceCheckedStopPressed)

        core.mainWindow().hideAllWindows.connect(self.hide)
        core.workspace().escPressed.connect(self.hide)

        core.workspace().currentDocumentChanged.connect(
            lambda old, new: self.setVisible(self.isVisible() and new is not None))

    def show(self):
        """Reimplemented function. Sends signal
        """
        super(SearchWidget, self).show()
        self.visibilityChanged.emit(self.isVisible())

    def hide(self):
        """Reimplemented function.
        Sends signal, returns focus to workspace
        """
        super(SearchWidget, self).hide()
        core.workspace().focusCurrentDocument()
        self.visibilityChanged.emit(self.isVisible())

    def setVisible(self, visible):
        """Reimplemented function. Sends signal
        """
        super(SearchWidget, self).setVisible(visible)
        self.visibilityChanged.emit(self.isVisible())

    def _regExEscape(self, text):
        """Improved version of re.escape()
        Doesn't escape space, comma, underscore.
        Escapes \n and \t
        """
        text = re.escape(text)
        # re.escape escapes space, comma, underscore, but, it is not necessary and makes text not readable
        for symbol in (' ,_=\'"/:@#%&'):
            text = text.replace('\\' + symbol, symbol)

        text = text.replace('\\\n', '\\n')
        text = text.replace('\\\t', '\\t')

        return text

    def _makeEscapeSeqsVisible(self, text):
        """Replace invisible \n and \t with escape sequences
        """
        text = text.replace('\\', '\\\\')
        text = text.replace('\t', '\\t')
        text = text.replace('\n', '\\n')
        return text

    def setMode(self, mode):
        """Change search mode.
        i.e. from "Search file" to "Replace directory"
        """
        if self._mode == mode and self.isVisible():
            if core.workspace().currentDocument() is not None and \
               not core.workspace().currentDocument().hasFocus():
                self.cbSearch.lineEdit().selectAll()
                self.cbSearch.setFocus()

        self._mode = mode

        # Set Search and Replace text
        document = core.workspace().currentDocument()
        if document is not None and \
           document.hasFocus() and \
           document.qutepart.selectedText:
            searchText = document.qutepart.selectedText

            self.cbReplace.setEditText(self._makeEscapeSeqsVisible(searchText))

            if self.cbRegularExpression.checkState() == Qt.Checked:
                searchText = self._regExEscape(searchText)
            self.cbSearch.setEditText(searchText)

        if not self.cbReplace.lineEdit().text() and \
                self.cbSearch.lineEdit().text() and \
                not self.cbRegularExpression.checkState() == Qt.Checked:
            replaceText = self.cbSearch.lineEdit().text().replace('\\', '\\\\')
            self.cbReplace.setEditText(replaceText)

        # Move focus to Search edit
        self.cbSearch.setFocus()
        self.cbSearch.lineEdit().selectAll()

        # Set search path
        if mode & MODE_FLAG_DIRECTORY and \
           not (self.isVisible() and self.cbPath.isVisible()):
            try:
                searchPath = os.path.abspath(str(os.path.curdir))
            except OSError:  # current directory might have been deleted
                pass
            else:
                self.cbPath.setEditText(searchPath)

        # Set widgets visibility flag according to state
        widgets = (self.wSearch, self.pbPrevious, self.pbNext, self.pbSearch, self.wReplace, self.wPath,
                   self.pbReplace, self.pbReplaceAll, self.pbReplaceChecked, self.wOptions, self.wMask)
        #                         wSear  pbPrev pbNext pbSear wRepl  wPath  pbRep  pbRAll pbRCHK wOpti wMask
        visible = \
            {MODE_SEARCH:               (1,     1,     1,     0,     0,     0,     0,     1,     1,    1,    0,),
             MODE_REPLACE:               (1,     1,     1,     0,     1,     0,     1,     1,     0,    1,    0,),
             MODE_SEARCH_DIRECTORY:      (1,     0,     0,     1,     0,     1,     0,     0,     0,    1,    1,),
             MODE_REPLACE_DIRECTORY:     (1,     0,     0,     1,     1,     1,     0,     0,     1,    1,    1,),
             MODE_SEARCH_OPENED_FILES:   (1,     0,     0,     1,     0,     0,     0,     0,     0,    1,    1,),
             MODE_REPLACE_OPENED_FILES:  (1,     0,     0,     1,     1,     0,     0,     0,     1,    1,    1,)}

        for i, widget in enumerate(widgets):
            widget.setVisible(visible[mode][i])

        # Search next button text
        if mode == MODE_REPLACE:
            self.pbNext.setText('Next')
        else:
            self.pbNext.setText('Next↵')

        # Finaly show all with valid size
        self.show()  # show before updating widgets and labels
        self._updateLabels()
        self._updateWidgets()

    def eventFilter(self, object_, event):
        """ Event filter for mode switch tool button
        Draws icons in the search and path lineEdits
        """
        if event.type() == QEvent.Paint and object_ is self.tbCdUp:  # draw CdUp button in search path QLineEdit
            toolButton = object_
            lineEdit = self.cbPath.lineEdit()
            lineEdit.setContentsMargins(lineEdit.height(), 0, 0, 0)

            height = lineEdit.height()
            availableRect = QRect(0, 0, height, height)

            if toolButton.rect() != availableRect:
                toolButton.setGeometry(availableRect)

            painter = QPainter(toolButton)
            toolButton.icon().paint(painter, availableRect)

            return True

        elif event.type() == QEvent.KeyPress:  # Tab and Shift+Tab in QLineEdits

            if event.key() == Qt.Key_Tab:
                self._moveFocus(1)
                return True
            elif event.key() == Qt.Key_Backtab:
                self._moveFocus(-1)
                return True

        return QFrame.eventFilter(self, object_, event)

    def _onReturnPressed(self):
        """Return or Enter pressed on widget.
        Search next or Replace next
        """
        if self.pbReplace.isVisible():
            self.pbReplace.click()
        elif self.pbNext.isVisible():
            self.pbNext.click()
        elif self.pbSearch.isVisible():
            self.pbSearch.click()
        elif self.pbSearchStop.isVisible():
            self.pbSearchStop.click()

    def _onPathBackspace(self):
        """Ctrl+Backspace pressed on path.
        Remove 1 path level.
        Default behavior would be to remove one word on Linux or all on Windows
        """
        path = self.cbPath.currentText()
        if path.endswith('/') or \
           path.endswith('\\'):
            path = path[:-1]

        head, tail = os.path.split(path)
        if head and \
           head != path:
            if not head.endswith(os.sep):
                head += os.sep
            self.cbPath.lineEdit().setText(head)

    def _moveFocus(self, step):
        """Move focus forward or backward according to step.
        Standard Qt Keyboard focus algorithm doesn't allow circular navigation
        """
        allFocusableWidgets = (self.cbSearch, self.cbReplace, self.cbPath, self.cbMask)
        visibleWidgets = [widget for widget in allFocusableWidgets
                          if widget.isVisible()]

        try:
            focusedIndex = visibleWidgets.index(QApplication.focusWidget())
        except ValueError:
            print('Invalid focused widget in Search Widget', file=sys.stderr)
            return

        nextFocusedIndex = (focusedIndex + step) % len(visibleWidgets)

        visibleWidgets[nextFocusedIndex].setFocus()
        visibleWidgets[nextFocusedIndex].lineEdit().selectAll()

    def _updateLabels(self):
        """Update 'Search' 'Replace' 'Path' labels geometry
        """
        width = 0

        if self.lSearch.isVisible():
            width = max(width, self.lSearch.minimumSizeHint().width())

        if self.lReplace.isVisible():
            width = max(width, self.lReplace.minimumSizeHint().width())

        if self.lPath.isVisible():
            width = max(width, self.lPath.minimumSizeHint().width())

        self.lSearch.setMinimumWidth(width)
        self.lReplace.setMinimumWidth(width)
        self.lPath.setMinimumWidth(width)

    def _updateWidgets(self):
        """Update geometry of widgets with buttons
        """
        width = 0

        if self.wSearchRight.isVisible():
            width = max(width, self.wSearchRight.minimumSizeHint().width())

        if self.wReplaceRight.isVisible():
            width = max(width, self.wReplaceRight.minimumSizeHint().width())

        if self.wPathRight.isVisible():
            width = max(width, self.wPathRight.minimumSizeHint().width())

        self.wSearchRight.setMinimumWidth(width)
        self.wReplaceRight.setMinimumWidth(width)
        self.wPathRight.setMinimumWidth(width)

    def updateComboBoxes(self):
        """Update comboboxes with last used texts
        """
        searchText = self.cbSearch.currentText()
        replaceText = self.cbReplace.currentText()
        maskText = self.cbMask.currentText()

        # search
        if searchText:
            index = self.cbSearch.findText(searchText)

            if index == -1:
                self.cbSearch.addItem(searchText)

        # replace
        if replaceText:
            index = self.cbReplace.findText(replaceText)

            if index == -1:
                self.cbReplace.addItem(replaceText)

        # mask
        if maskText:
            index = self.cbMask.findText(maskText)

            if index == -1:
                self.cbMask.addItem(maskText)

    def _searchPatternTextAndFlags(self):
        """Get search pattern and flags
        """
        pattern = self.cbSearch.currentText()

        pattern = pattern.replace('\u2029', '\n')  # replace unicode paragraph separator with habitual \n

        if not self.cbRegularExpression.checkState() == Qt.Checked:
            pattern = re.escape(pattern)

        if self.cbWholeWord.checkState() == Qt.Checked:
            pattern = r'\b' + pattern + r'\b'

        flags = 0
        if not self.cbCaseSensitive.checkState() == Qt.Checked:
            flags = re.IGNORECASE
        return pattern, flags

    def getRegExp(self):
        """Read search parameters from controls and present it as a regular expression
        """
        pattern, flags = self._searchPatternTextAndFlags()
        return re.compile(pattern, flags)

    def isSearchRegExpValid(self):
        """Try to compile search pattern to check if it is valid
        Returns bool result and text error
        """
        pattern, flags = self._searchPatternTextAndFlags()
        try:
            re.compile(pattern, flags)
        except re.error as ex:
            return False, str(ex)

        return True, None

    def _getSearchMask(self):
        """Get search mask as list of patterns
        """
        mask = [s.strip() for s in self.cbMask.currentText().split(' ')]
        # remove empty
        mask = [_f for _f in mask if _f]
        return mask

    def setState(self, state):
        """Change line edit color according to search result
        """
        widget = self.cbSearch.lineEdit()

        color = {SearchWidget.Normal: QApplication.instance().palette().color(QPalette.Base),
                 SearchWidget.Good: QColor(Qt.green),
                 SearchWidget.Bad: QColor(Qt.red),
                 SearchWidget.Incorrect: QColor(Qt.darkYellow)}

        stateColor = color[state]
        if state != SearchWidget.Normal:
            stateColor.setAlpha(100)

        pal = widget.palette()
        pal.setColor(widget.backgroundRole(), stateColor)
        widget.setPalette(pal)

    def setSearchInProgress(self, inProgress):
        """Search thread started or stopped
        """
        self.pbSearchStop.setVisible(inProgress)
        self.pbSearch.setVisible(not inProgress)
        self._updateWidgets()
        self._progress.setVisible(inProgress)

    def onSearchProgressChanged(self, value, total):
        """Signal from the thread, progress changed
        """
        self._progress.setValue(value)
        self._progress.setMaximum(total)

    def setReplaceInProgress(self, inProgress):
        """Replace thread started or stopped
        """
        self.pbReplaceCheckedStop.setVisible(inProgress)
        self.pbReplaceChecked.setVisible(not inProgress)
        self._updateWidgets()

    def setSearchInFileActionsEnabled(self, enabled):
        """Set enabled state for Next, Prev, Replace, ReplaceAll
        """
        for button in (self.pbNext, self.pbPrevious, self.pbReplace, self.pbReplaceAll):
            button.setEnabled(enabled)

    def _onSearchRegExpChanged(self):
        """User edited search text or checked/unchecked checkboxes
        """
        valid, error = self.isSearchRegExpValid()
        if valid:
            self.setState(self.Normal)
            core.mainWindow().statusBar().clearMessage()
            self.pbSearch.setEnabled(len(self.getRegExp().pattern) > 0)
        else:
            core.mainWindow().statusBar().showMessage(error, 3000)
            self.setState(self.Incorrect)
            self.pbSearch.setEnabled(False)
            self.searchRegExpChanged.emit(re.compile(''))
            return

        self.searchRegExpChanged.emit(self.getRegExp())

    def _onCdUpPressed(self):
        """User pressed "Up" button, need to remove one level from search path
        """
        text = self.cbPath.currentText()
        if not os.path.exists(text):
            return

        editText = os.path.normpath(os.path.join(text, os.path.pardir))
        self.cbPath.setEditText(editText)

    def on_pbSearch_pressed(self):
        """Handler of click on "Search" button (for search in directory)
        """
        self.setState(SearchWidget.Normal)

        self.searchInDirectoryStartPressed.emit(self.getRegExp(),
                                                self._getSearchMask(),
                                                self.cbPath.currentText())

    def on_pbReplace_pressed(self):
        """Handler of click on "Replace" (in file) button
        """
        self.replaceFileOne.emit(self.cbReplace.currentText())

    def on_pbReplaceAll_pressed(self):
        """Handler of click on "Replace all" (in file) button
        """
        self.replaceFileAll.emit(self.cbReplace.currentText())

    def on_pbReplaceChecked_pressed(self):
        """Handler of click on "Replace checked" (in directory) button
        """
        self.replaceCheckedStartPressed.emit(self.cbReplace.currentText())

    def on_pbBrowse_pressed(self):
        """Handler of click on "Browse" button. Explores FS for search directory path
        """
        path = QFileDialog.getExistingDirectory(self, self.tr("Search path"), self.cbPath.currentText())

        if path:
            self.cbPath.setEditText(path)
Ejemplo n.º 27
0
class WINENCERCLED(QWidget):
    
    def __init__(self,conf=None,name='VISU'):
        
        super().__init__()
        self.name=name
        p = pathlib.Path(__file__)
        if conf==None:
            self.conf=QtCore.QSettings(str(p.parent / 'confVisu.ini'), QtCore.QSettings.IniFormat)
        else :
            self.conf=conf
        
        sepa=os.sep
        self.icon=str(p.parent) + sepa+'icons' +sepa

        self.isWinOpen=False
        self.setWindowTitle('Encercled')
        self.setWindowIcon(QIcon(self.icon+'LOA.png'))
        self.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
        self.left=100
        self.top=30
        self.width=800
        self.height=800
        self.setGeometry(self.left,self.top,self.width,self.height)
        self.dimx=1200
        self.dimy=900
        self.bloqq=1
        self.xec=int(self.conf.value(self.name+"/xec"))
        self.yec=int(self.conf.value(self.name+"/yec"))
        self.r1x=int(self.conf.value(self.name+"/r1x"))
        self.r1y=int(self.conf.value(self.name+"/r1y"))
        self.r2=int(self.conf.value(self.name+"/r2x"))
        self.r2=int(self.conf.value(self.name+"/r2y"))
        
        self.kE=0 # variable pour la courbe E fct du nb shoot
        
        self.Xec=[]
        self.Yec=[]
        self.fwhmX=100
        self.fwhmY=100
        self.setWindowIcon(QIcon('./icons/LOA.png'))
        self.E = []
        
        #self.E=np.array([2,3,5])
        self.Xec=[]
        self.Yec=[]
        
        # Create x and y indices
        x = np.arange(0,self.dimx)
        y = np.arange(0,self.dimy)
        y,x = np.meshgrid(y, x)
    
        self.data=(40*np.random.rand(self.dimx,self.dimy)).round()
        
        self.setup()
        self.ActionButton()
        self.Display(self.data)
        
    def setup(self):
        
        TogOff=self.icon+'Toggle_Off.png'
        TogOn=self.icon+'Toggle_On.png'
        
        
        TogOff=pathlib.Path(TogOff)
        TogOff=pathlib.PurePosixPath(TogOff)
        TogOn=pathlib.Path(TogOn)
        TogOn=pathlib.PurePosixPath(TogOn)
        self.setStyleSheet("QCheckBox::indicator{width: 30px;height: 30px;}""QCheckBox::indicator:unchecked { image : url(%s);}""QCheckBox::indicator:checked { image:  url(%s);}""QCheckBox{font :10pt;}" % (TogOff,TogOn) )
        
        vbox1=QVBoxLayout()
        hbox=QHBoxLayout()
        self.checkBoxAuto=QCheckBox('Auto',self)
        self.checkBoxAuto.setChecked(True)
        hbox.addWidget(self.checkBoxAuto)
        self.resetButton=QPushButton('Reset',self)
        hbox.addWidget(self.resetButton)
        vbox1.addLayout(hbox)
        hbox0=QHBoxLayout()
        self.energieRes=QLabel('?')
        self.energieRes.setMaximumHeight(30)
        self.energieRes.setMaximumWidth(120)
        self.lEnergie=QLabel('s(E1)/s(E2) :')
        self.lEnergie.setStyleSheet("color:blue;font:14pt")
        self.lEnergie.setMaximumWidth(80)
        hbox0.addWidget(self.lEnergie)
        hbox0.addWidget(self.energieRes)
        #vbox1.addStretch(1)
        vbox1.addLayout(hbox0)
        
        
        LabelR1x=QLabel("fwhm X/0.85")
        LabelR1x.setStyleSheet("color:red;font:14pt")
        self.r1xBox=QSpinBox()
        #self.r1Box.setMaximumWidth(60)
        self.r1xBox.setMaximum(2000)
        LabelR1y=QLabel('fwhm Y/0.85')
        LabelR1y.setStyleSheet("color:green;font:14pt")
        self.r1yBox=QSpinBox()
        self.r1yBox.setMaximum(2000)
        #self.r2Box.setMaximumWidth(60)
        LabelR2=QLabel('R2')
        LabelR2.setStyleSheet("color:yellow;font:14pt")
        self.r2Box=QSpinBox()
        self.r2Box.setMaximum(2000)
        
        LabelE1=QLabel("E1 Sum ")
        LabelE1.setStyleSheet("color:red;font:14pt")
        self.LabelE1Sum=QLabel("? ")
        self.LabelE1Sum.setStyleSheet("color:red;font:14pt")
        LabelE1M=QLabel("E1 mean ")
        LabelE1M.setStyleSheet("color:red;font:14pt")
        self.LabelE1Mean=QLabel("? ")
        self.LabelE1Mean.setStyleSheet("color:red;font:14pt")
        
        
        LabelE2=QLabel("E2 Sum ")
        LabelE2.setStyleSheet("color:yellow;font:14pt")
        self.LabelE2Sum=QLabel("? ")
        self.LabelE2Sum.setStyleSheet("color:yellow;font:14pt")
        LabelE2M=QLabel("E2 mean ")
        LabelE2M.setStyleSheet("color:yellow ;font:14pt")
        self.LabelE2Mean=QLabel("? ")
        self.LabelE2Mean.setStyleSheet("color:yellow;font:14pt")
        
        grid_layout1 = QGridLayout()
        grid_layout1.addWidget(LabelR1x, 0, 0)
        grid_layout1.addWidget(self.r1xBox, 0, 1)
        grid_layout1.addWidget(LabelR1y, 1, 0)
        grid_layout1.addWidget(self.r1yBox, 1,1)
        grid_layout1.addWidget(LabelR2, 2, 0)
        grid_layout1.addWidget(self.r2Box, 2,1)
        grid_layout1.addWidget(LabelE1,3,0)
        grid_layout1.addWidget(self.LabelE1Sum,3,1)
        grid_layout1.addWidget(LabelE1M,4,0)
        grid_layout1.addWidget(self.LabelE1Mean,4,1)
        
        grid_layout1.addWidget(LabelE2,5,0)
        grid_layout1.addWidget(self.LabelE2Sum,5,1)
        grid_layout1.addWidget(LabelE2M,6,0)
        grid_layout1.addWidget(self.LabelE2Mean,6,1)
        
        
        vbox1.addLayout(grid_layout1)
        
        vbox1.addStretch(1)
        
        self.winImage = pg.GraphicsLayoutWidget()
        self.winImage.setContentsMargins(0,0,0,0)
        self.winImage.setAspectLocked(True)
        self.winImage.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        #self.winImage.ci.setContentsMargins(0,0,0,0)
        
        vbox2=QVBoxLayout()
        hbox2=QHBoxLayout()
        
        
        hbox2.addWidget(self.winImage)
        vbox2.addLayout(hbox2)
        vbox2.setContentsMargins(0,0,0,0)
        
        self.p1=self.winImage.addPlot()
        
        self.imh=pg.ImageItem()
        self.p1.addItem(self.imh)
        
        self.p1.setMouseEnabled(x=False,y=False)
        self.p1.setContentsMargins(0,0,0,0)
        
        self.p1.setAspectLocked(True,ratio=1)
        self.p1.showAxis('right',show=False)
        self.p1.showAxis('top',show=False)
        self.p1.showAxis('left',show=False)
        self.p1.showAxis('bottom',show=False)
        self.vLine = pg.InfiniteLine(angle=90, movable=False,pen='w')
        self.hLine = pg.InfiniteLine(angle=0, movable=False,pen='w')
        self.p1.addItem(self.vLine)
        self.p1.addItem(self.hLine)
        
        self.vLine.setPos(self.xec)
        self.hLine.setPos(self.yec)
        
        self.roi1=pg.CircleROI([self.xec,self.yec],[2*self.r1x,2*self.r1y],pen='r',movable=False)
        self.roi1.setPos([self.xec-(self.r1x),self.yec-(self.r1y)])
        self.p1.addItem(self.roi1)
       
        self.roi2=pg.CircleROI([self.xec,self.yec],[2*self.r2,2*self.r2],pen='y',movable=False)
        self.roi2.setPos([self.xec-(self.r2),self.yec-(self.r2)])
        self.p1.addItem(self.roi2)
        
        #histogramme
        self.hist = pg.HistogramLUTItem() 
        self.hist.setImageItem(self.imh)
        self.hist.autoHistogramRange()
        self.hist.gradient.loadPreset('flame')
        
        self.curve2=pg.PlotCurveItem()
        self.curve3=pg.PlotCurveItem()
        # text pour afficher fwhm sur p1
        self.textX = pg.TextItem(angle=-90) 
        self.textY = pg.TextItem()
        self.p1.addItem(self.curve2)
        self.p1.addItem(self.curve3)
        self.p1.addItem(self.textX)
        self.p1.addItem(self.textY)
        
        
        hLayout1=QHBoxLayout()
        
        hLayout1.addLayout(vbox2)
        hLayout1.addLayout(vbox1)
        
        
        hLayout1.setContentsMargins(1,1,1,1)
#        hLayout1.setSpacing(1)
#        hLayout1.setStretch(10,1)
        
        vMainLayout=QVBoxLayout()
        vMainLayout.addLayout(hLayout1)
        
        
        self.winCurve=QVBoxLayout()
        
        
        self.win2=pg.PlotWidget()
        self.p2=self.win2.plot(pen='b',symbol='t',symboleSize=2,clear=True,symbolPen='b',symbolBrush='b',name="rapport")
        self.win2.setContentsMargins(0,0,0,0)
        self.win2.setLabel('left','E1/E2',units='%')
        self.hLineMeanE = pg.InfiniteLine(angle=0, movable=False,pen=pg.mkPen('b', width=3, style=QtCore.Qt.DashLine) ) 
        self.win2.addItem(self.hLineMeanE, ignoreBounds=True)
        
        self.win2.addItem(self.hLineMeanE, ignoreBounds=True)
        
        
        self.winCurve.addWidget(self.win2)
        
        self.win3=pg.PlotWidget()
        self.p3=self.win3.plot(pen='r',symbol='t',symboleSize=2,clear=True,symbolPen='r',symbolBrush='r',name="x")
        self.win3.setContentsMargins(0,0,0,0)
        self.win3.setLabel('left','X')#,units='pixel')
        self.hLineMeanX = pg.InfiniteLine(angle=0, movable=False,pen=pg.mkPen('r', width=3, style=QtCore.Qt.DashLine))
        self.win3.addItem(self.hLineMeanX, ignoreBounds=True)
        self.winCurve.addWidget(self.win3)
        
        
        self.win4=pg.PlotWidget()
        self.p4=self.win4.plot(pen='g',symbol='t',symboleSize=2,clear=True,symbolPen='g',symbolBrush='g',name="y")
        self.win4.setLabel('left','Y')#,units='pixel')
        self.win4.setLabel('bottom',"Shoot number")
        self.hLineMeanY = pg.InfiniteLine(angle=0, movable=False,pen=pg.mkPen('g', width=3, style=QtCore.Qt.DashLine))
        self.win4.addItem(self.hLineMeanY, ignoreBounds=True)
        self.winCurve.addWidget(self.win4)
        
        labelMean=QLabel('<E1/E2> ')
        labelMean.setStyleSheet("color:blue;font:14pt")
        #labelMean.setMaximumWidth(120)
        self.meanAff=QLabel('?')
        #self.meanAff.setMaximumWidth(60)
        labelPV=QLabel('std E1/E2')
        labelPV.setStyleSheet("color:blue;font:14pt")
        self.PVAff=QLabel('?')
        
        labelMeanX=QLabel('<X>')
        self.meanXAff=QLabel()
        labelMeanX.setStyleSheet("color:red;font:14pt")
        labelMeanY=QLabel('<Y>')
        labelMeanY.setStyleSheet("color:green;font:14pt")
        self.meanYAff=QLabel()
        
        labelStdX=QLabel('std X')
        labelStdX.setStyleSheet("color:red;font:14pt")
        self.stdXAff=QLabel()
        labelStdY=QLabel('std Y')
        labelStdY.setStyleSheet("color:green;font:14pt")
        self.stdYAff=QLabel()
        
        
        grid_layout2 = QGridLayout()
        grid_layout2.addWidget(labelMean, 0, 0)
        grid_layout2.addWidget(self.meanAff, 0, 1)
        grid_layout2.addWidget(labelPV, 1, 0)
        grid_layout2.addWidget(self.PVAff, 1,1)
        
        grid_layout2.addWidget(labelMeanX, 2, 0)
        grid_layout2.addWidget(self.meanXAff, 2, 1)
        grid_layout2.addWidget(labelStdX, 3, 0)
        grid_layout2.addWidget(self.stdXAff, 3,1)
        
        grid_layout2.addWidget(labelMeanY, 4, 0)
        grid_layout2.addWidget(self.meanYAff, 4, 1)
        grid_layout2.addWidget(labelStdY, 5, 0)
        grid_layout2.addWidget(self.stdYAff, 5,1)
        
        
        hLayout2=QHBoxLayout()
        
        hLayout2.addLayout(self.winCurve)
        hLayout2.addLayout(grid_layout2)
        
        vMainLayout.addLayout(hLayout2)
        
        
        hMainLayout=QHBoxLayout()
        hMainLayout.addLayout(vMainLayout)
        self.setLayout(hMainLayout)
        self.setContentsMargins(1,1,1,1)
        
        
        
    def ActionButton(self):   
        # Blocage de la souris
        self.roi1.sigRegionChangeFinished.connect(self.energSouris) # signal si changement à la souris de la taille des cercles
        self.roi2.sigRegionChangeFinished.connect(self.energSouris)
#
        self.r1xBox.editingFinished.connect(self.Rayon) #w.r1Box.returnPressed.connect(Rayon)# rayon change a la main
        self.r1yBox.editingFinished.connect(self.Rayon)
        self.r2Box.editingFinished.connect(self.Rayon)
       
        self.shortcutb=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+b"),self)
        self.shortcutb.activated.connect(self.bloquer)
        self.shortcutd=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+d"),self)
        self.shortcutd.activated.connect(self.debloquer)
         
        self.shortcutPu=QShortcut(QtGui.QKeySequence("+"),self)
        self.shortcutPu.activated.connect(self.paletteup)
        self.shortcutPu.setContext(Qt.ShortcutContext(3))
        #3: The shortcut is active when its parent widget, or any of its children has focus. default O The shortcut is active when its parent widget has focus.
        self.shortcutPd=QtGui.QShortcut(QtGui.QKeySequence("-"),self)
        self.shortcutPd.activated.connect(self.palettedown)
        self.shortcutPd.setContext(Qt.ShortcutContext(3))
        
        self.checkBoxAuto.stateChanged.connect(lambda:self.Display(self.data))
        # mvt de la souris
        self.proxy=pg.SignalProxy(self.p1.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
        self.p1.scene().sigMouseClicked.connect(self.mouseClick)
        
        self.vb=self.p1.vb
        
        self.checkBoxAuto.stateChanged.connect(self.AutoE)
        self.resetButton.clicked.connect(self.Reset)
        
        
    def mouseClick(self):
        # bloque ou debloque la souris si click su le graph
        
        if self.bloqq==1:
            self.debloquer()
        else :
            self.bloquer()  
            
    def bloquer(self): # bloque la croix 
        self.bloqq=1
        self.conf.setValue(self.name+"/xec",int(self.xec)) # save cross postion in ini file
        self.conf.setValue(self.name+"/yec",int(self.yec))
        self.CalculE()
        
    def debloquer(self): # deblaoque la croix : elle bouge avec la souris
        self.bloqq=0
    
    # mvt de la souris
    
    def mouseMoved(self,evt):
        ## pour que la cross suive le mvt de la souris
        if self.checkBoxAuto.isChecked()==False:

            if self.bloqq==0: # souris non bloquer
                pos = evt[0]  ## using signal proxy turns original arguments into a tuple
                if self.p1.sceneBoundingRect().contains(pos):
                    mousePoint = self.vb.mapSceneToView(pos)
                    self.xec =int (mousePoint.x())
                    self.yec= int(mousePoint.y())
                    if ((self.xec>0 and self.xec<self.data.shape[0]) and (self.yec>0 and self.yec<self.data.shape[1]) ):
                            self.vLine.setPos(self.xec)
                            self.hLine.setPos(self.yec) # la croix ne bouge que dans le graph  
                            
                            self.roi1.setPos([self.xec-(self.r1x),self.yec-(self.r1y)])
                            self.roi2.setPos([self.xec-(self.r2),self.yec-(self.r2)])
                            
    
    def AutoE(self):
        if self.checkBoxAuto.isChecked()==False:
            self.energSouris()
            self.roi1.setSize([2*self.r1x,2*self.r1y])
            self.roi2.setSize([2*self.r2,2*self.r2])
            
            
    def energSouris(self): # changement des rayons à la souris 
        if self.checkBoxAuto.isChecked()==False:
            s1=self.roi1.size()
            s2=self.roi2.size()
            self.r1xBox.setValue((int(s1[0]/2)))
            self.r1yBox.setValue((int(s1[1]/2)))
            self.r2Box.setValue((int(s2[0]/2)))
            self.r1x=int(s1[0]/2)
            self.r1y=int(s1[1]/2)
            self.r2=int(s2[0]/2)
            if self.bloqq==1:
                self.CalculE()
     
        
    def Rayon(self): 
        """changement rayon dans les box
        """
        if self.checkBoxAuto.isChecked()==False:
            if self.r1xBox.hasFocus() :
                self.r1x=(float(self.r1xBox.text()))
                self.roi1.setSize([2*self.r1x,2*self.r1y])
            if self.r1yBox.hasFocus() :
                self.r1y=(float(self.r1yBox.text()))
                self.roi1.setSize([2*self.r1x,2*self.r1y])
            
            if self.r2Box.hasFocus():
                self.r2=(float(self.r2Box.text()))
                self.roi2.setSize([2*self.r2,2*self.r2])
            
            self.roi1.setPos([self.xec-(self.r1x),self.yec-(self.r1y)])
            self.roi2.setPos([self.xec-(self.r2),self.yec-(self.r2)])
            if self.bloqq==1:
                self.CalculE()
    
    
    def CalculE(self):
        
        if self.fwhmX==None or self.fwhmY==None:
            self.fwhmX=100
            self.fwhmY=100
        
        if self.checkBoxAuto.isChecked()==True:
            self.r1x=self.fwhmX/0.849
            self.r1y=self.fwhmY/0.849
            self.r1xBox.setValue(int(self.r1x))
            self.r1yBox.setValue(int(self.r1y))
            nbG=2 # ré= 2 fois r1 pour le grand cercle
            self.roi2.setSize([2*nbG*self.r1x,2*nbG*self.r1y])
            self.roi2.setPos([self.xec-nbG*self.r1x,self.yec-nbG*self.r1y])
            self.r2Box.setValue(int(2*nbG*self.r1x))
            self.roi1.setSize([2*self.r1x,2*self.r1y])
            self.roi1.setPos([self.xec-self.r1x,self.yec-self.r1y])
            
        else:
            self.r1x=self.r1x
            self.r1y=self.r1y
           
        E1=self.roi1.getArrayRegion(self.data,self.imh).sum()
        E2=self.roi2.getArrayRegion(self.data,self.imh).sum()
        self.rap=100*E1/E2
        self.energieRes.setText('%.2f %%' % self.rap)
        self.E=np.append(self.E,self.rap)
        #self.E.append(self.rap)
        Emean=np.mean(self.E)
        self.meanAff.setText('%.2f' % Emean)
        EPV=np.std(self.E)
        self.PVAff.setText('%.2f' % EPV)
        self.hLineMeanE.setPos(Emean)
        self.textX.setText('fwhm='+str(self.fwhmY))
        self.textY.setText('fwhm='+str(self.fwhmX),color='w')
        self.LabelE1Sum.setText('%.2f' %E1)
        self.LabelE1Mean.setText('%.2f' % (self.roi1.getArrayRegion(self.data,self.imh).mean()))
        self.LabelE2Sum.setText('%.2f' %E2)
        self.LabelE2Mean.setText('%.2f' % (self.roi2.getArrayRegion(self.data,self.imh).mean()))
        
    def Display(self,data):
        self.data=data
        self.dimx=self.data.shape[0]
        self.dimy=self.data.shape[1]
        self.p1.setXRange(0,self.dimx)
        self.p1.setYRange(0,self.dimy)
        self.p1.setAspectLocked(True,ratio=1)
        self.imh.setImage(data.astype(float),autoLevels=True,autoDownsample=True)
        self.CalculCentroid()
        self.Coupe()
        self.CalculE() 
        
        self.Xec.append(self.xec)
        self.Yec.append(self.yec)
        
        Xmean=np.mean(self.Xec)
        self.meanXAff.setText('%.2f' % Xmean)
        XPV=np.std(self.Xec)
        self.stdXAff.setText('%.2f' % XPV)
        self.hLineMeanX.setPos(Xmean)
        Ymean=np.mean(self.Yec)
        self.meanYAff.setText('%.2f' % Ymean)
        YPV=np.std(self.Yec)
        self.stdYAff.setText('%.2f' % YPV)
        self.hLineMeanY.setPos(Ymean)
        self.plotGraph()
       
        
    
    def plotGraph(self):
        
        
        
        self.p2.setData(self.E)#,pen='b',symbol='t',symboleSize=2,clear=True,symbolPen='b',symbolBrush='b',name="rapport")
        #self.p2.addItem(self.hLineMeanE, ignoreBounds=True)
        self.p3.setData(self.Xec)#,pen='r',symbol='t',symboleSize=2,clear=True,symbolPen='r',symbolBrush='r',name="x")
        #self.p3.addItem(self.hLineMeanX, ignoreBounds=True)
        self.p4.setData(self.Yec)#,pen='g',symbol='t',symboleSize=2,clear=True,symbolPen='g',symbolBrush='g',name="y")
        #self.p4.addItem(self.hLineMeanY, ignoreBounds=True)
    
    
    
    def CalculCentroid(self):
        
        if self.checkBoxAuto.isChecked()==True:
            dataF=gaussian_filter(self.data,5)
            (self.xec,self.yec)=pylab.unravel_index(dataF.argmax(),self.data.shape) #prend le max 
            self.vLine.setPos(self.xec)
            self.hLine.setPos(self.yec)       
            self.roi1.setPos([self.xec-(self.r1x),self.yec-(self.r1y)])
            self.roi2.setPos([self.xec-(self.r2),self.yec-(self.r2)])
        
        
    def fwhm(self,x, y, order=3):
        
        """
            Determine full-with-half-maximum of a peaked set of points, x and y.
            Assumes that there is only one peak present in the datasset.  The function
            uses a spline interpolation of order k.
        """
        y=gaussian_filter(y,5) # filtre pour reduire le bruit
        half_max = np.amax(y)/2
        try:
            s = splrep(x, y - half_max,k=order) # Find the B-spline representation of 1-D curve.
            roots = sproot(s) # Given the knots (>=8) and coefficients of a cubic B-spline return the roots of the spline.
        except:
           roots=0
           
        if len(roots) > 2:
            pass
            #print( "The dataset appears to have multiple peaks, and ","thus the FWHM can't be determined.")
        elif len(roots) < 2:
            pass
           # print( "No proper peaks were found in the data set; likely ","the dataset is flat (e.g. all zeros).")
        else:
            return np.around(abs(roots[1] - roots[0]),decimals=2)
         
    def Coupe(self):
        
        xxx=np.arange(0,int(self.dimx),1)#
        yyy=np.arange(0,int(self.dimy),1)#
        coupeX=self.data[int(self.xec),:]
        coupeXMax=np.max(coupeX)
        
        if coupeXMax==0: # evite la div par zero
            coupeXMax=1
            
        coupeXnorm=(self.data.shape[0]/10)*(coupeX/coupeXMax) # normalise les coupes pour pas prendre tout l ecran
        self.curve2.setData(30+coupeXnorm,yyy,clear=True)
        
        coupeY=self.data[:,int(self.yec)]
        coupeYMax=np.max(coupeY)
        if coupeYMax==0:
            coupeYMax=1
            
        coupeYnorm=(self.data.shape[1]/10)*(coupeY/coupeYMax)
        self.curve3.setData(xxx,20+coupeYnorm,clear=True)
        
        ### affichage de fwhm sur les coupes X et Y que si le max est >20 counts
        xCXmax=np.amax(coupeXnorm) # max
        if xCXmax>20:
            self.fwhmY=self.fwhm(yyy, coupeXnorm, order=3)
            
            
            yCXmax=yyy[coupeXnorm.argmax()]
            self.textX.setPos(xCXmax-3,yCXmax+3)
            
        yCYmax=np.amax(coupeYnorm) # max
        if yCYmax>20:
            self.fwhmX=self.fwhm(xxx, coupeYnorm, order=3)
            xCYmax=xxx[coupeYnorm.argmax()]            
            
            self.textY.setPos(xCYmax-3,yCYmax-3) 

    def paletteup(self):
        levels=self.imh.getLevels()
        if levels[0]==None:
            xmax =self.data.max()
            xmin=self.data.min()
        else :
            xmax=levels[1]
            xmin=levels[0]
            
        self.imh.setLevels([xmin, xmax+(xmax- xmin) / 10])
        #hist.setImageItem(imh,clear=True)
        self.hist.setHistogramRange(xmin,xmax)

    def palettedown(self):
        levels=self.imh.getLevels()
        if levels[0]==None:
            xmax=self.data.max()
            xmin=self.data.min()
        else :
            xmax=levels[1]
            xmin=levels[0]
            
        self.imh.setLevels([xmin, xmax- (xmax- xmin) / 10])
        #hist.setImageItem(imh,clear=True)
        self.hist.setHistogramRange(xmin,xmax)
        
    def Reset(self):
        self.E = []
        self.Xec=[]
        self.Yec=[]
        
        
    def closeEvent(self, event):
        """ when closing the window
        """
        self.isWinOpen=False
        self.E=[]
        self.Xec=[]
        self.Yec=[]
        time.sleep(0.1)
        event.accept()
Ejemplo n.º 28
0
class Lookup(QWidget):
    MODEL_CLASS = None

    def __init__(self, parent, model):
        QWidget.__init__(self, parent, Qt.Window)
        self.model = model
        self.model.view = self
        self._setupUi()

        self.searchEdit.searchChanged.connect(self.searchChanged)
        self.searchEdit.returnPressed.connect(self.returnPressed)
        self.namesList.currentRowChanged.connect(self.currentRowChanged)
        self.namesList.itemDoubleClicked.connect(self.itemDoubleClicked)
        self._shortcutUp.activated.connect(self.upPressed)
        self._shortcutDown.activated.connect(self.downPressed)

    def _setupUi(self):
        self.setWindowTitle(tr("Lookup"))
        self.resize(314, 331)
        self.verticalLayout = QVBoxLayout(self)
        self.searchEdit = SearchEdit(self)
        self.verticalLayout.addWidget(self.searchEdit)
        self.namesList = QListWidget(self)
        self.namesList.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.namesList.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.namesList.setUniformItemSizes(True)
        self.namesList.setSelectionRectVisible(True)
        self.verticalLayout.addWidget(self.namesList)

        self.searchEdit.immediate = True
        self._shortcutUp = QShortcut(self.searchEdit)
        self._shortcutUp.setKey(QKeySequence(Qt.Key_Up))
        self._shortcutUp.setContext(Qt.WidgetShortcut)
        self._shortcutDown = QShortcut(self.searchEdit)
        self._shortcutDown.setKey(QKeySequence(Qt.Key_Down))
        self._shortcutDown.setContext(Qt.WidgetShortcut)

    def _restoreSelection(self):
        self.namesList.setCurrentRow(self.model.selected_index)

    # --- Event Handlers
    def returnPressed(self):
        self.model.go()

    def searchChanged(self):
        self.model.search_query = str(self.searchEdit.text())

    def currentRowChanged(self, row):
        if row >= 0:
            self.model.selected_index = row

    def itemDoubleClicked(self, item):
        self.model.go()

    def upPressed(self):
        if self.namesList.currentRow() > 0:
            self.namesList.setCurrentRow(self.namesList.currentRow() - 1)

    def downPressed(self):
        if self.namesList.currentRow() < self.namesList.count() - 1:
            self.namesList.setCurrentRow(self.namesList.currentRow() + 1)

    # --- model --> view
    def refresh(self):
        self.namesList.clear()
        self.namesList.addItems(self.model.names)
        self._restoreSelection()
        self.searchEdit.setText(self.model.search_query)

    def show(self):
        QWidget.show(self)
        self.searchEdit.setFocus()
        # see csv_options
        self.raise_()

    def hide(self):
        QWidget.hide(self)
Ejemplo n.º 29
0
class PlaylistView(QTableView):
    def __init__(self, listplayer, status_bar: QStatusBar, play_ctrls, parent=None):
        super().__init__(parent=parent)
        self.player = listplayer
        self.status_bar = status_bar
        self.play_ctrls = play_ctrls

        self.setSelectionBehavior(self.SelectRows)
        self.setDragDropMode(self.InternalMove)
        self.setDragDropOverwriteMode(False)
        self.setEditTriggers(QTableView.NoEditTriggers)
        self.setAlternatingRowColors(True)
        self.setDropIndicatorShown(True)
        self.setHorizontalHeader(PlaylistViewHeader(parent=self))
        self.setContextMenuPolicy(Qt.CustomContextMenu)

        # Create shortcuts
        self.rem_selected_items_shortcut = QShortcut(self)
        self.rem_selected_items_shortcut.setKey(QKeySequence.Delete)
        self.rem_selected_items_shortcut.setContext(Qt.WidgetWithChildrenShortcut)
        self.rem_selected_items_shortcut.activated.connect(self.remove_selected_items)

        self.play_selected_item_shortcut = QShortcut(self)
        self.play_selected_item_shortcut.setKey(Qt.Key_Return)
        self.play_selected_item_shortcut.setContext(Qt.WidgetWithChildrenShortcut)
        self.play_selected_item_shortcut.activated.connect(self.play_selected_item)

        self.setModel(PlaylistModel())

        # Setup signals
        self.customContextMenuRequested.connect(self.show_context_menu)
        self.doubleClicked.connect(self.on_doubleClicked)
        self.selectionModel().selectionChanged.connect(self.on_selectionChanged)

    def showEvent(self, e):
        if self.model().rowCount():
            if not self.selectionModel().hasSelection():
                self.setCurrentIndex(self.model().item(0).index())
        self.setFocus()

    @pyqtSlot()
    def play_selected_item(self):
        self.player.load_media(index=self.currentIndex())
        self.player.mp.play()

    def mousePressEvent(self, e):
        """Clear both row and current index selections when clicking away from items."""
        clicked_index = self.indexAt(e.pos())
        if clicked_index.isValid():
            item = self.model().item(clicked_index.row())
            status_tip = item.data(role=Qt.DisplayRole)
            self.status_bar.showMessage(status_tip)
        else:
            self.selectionModel().clear()
        return super().mousePressEvent(e)

    def on_selectionChanged(self, selected, deselected):
        if not selected:
            self.selectionModel().clear()

    @pyqtSlot(QModelIndex)
    def on_doubleClicked(self, index):
        self.player.load_media(index=index)
        self.player.mp.play()

    def dropEvent(self, e):
        dragged_index = self.currentIndex()
        dropped_index = self.indexAt(e.pos())

        log.debug(
            f"dragged_index={dragged_index.row(), dragged_index.column()} dropped_index={dropped_index.row(), dropped_index.column()} action={e.dropAction()} source={e.source()}"
        )

        if dropped_index.row() == -1:
            return None

        model = self.model()
        item = model.takeRow(dragged_index.row())
        model.insertRow(dropped_index.row(), item)
        self.setCurrentIndex(dropped_index)
        e.ignore()

    @pyqtSlot(int)
    def on_model_rowCountChanged(self, count):
        """Enable/disable GUI elements when media is added or removed"""
        if count:
            self.play_ctrls.setEnabled(True)
        else:
            self.play_ctrls.setEnabled(False)

    def setModel(self, model):
        # Disconnect previous model
        if self.model():
            self.model().rowCountChanged.disconnect()
        # Connect this model
        model.rowCountChanged.connect(self.on_model_rowCountChanged)
        model.rowCountChanged.connect(self.player.on_playlist_rowCountChanged)
        super().setModel(model)

    def selected_items(self):
        items = []
        for i in self.selectionModel().selectedRows():
            items.append(self.model().itemFromIndex(i))
        return items

    def show_context_menu(self, pos: QPoint):
        selected_items = self.selected_items()
        if len(selected_items) <= 1:
            rem_selected_text = f"Remove '{selected_items[0].data(Qt.DisplayRole)}'"
        else:
            rem_selected_text = f"Remove {len(selected_items)} items"
        menu = QMenu(self)
        menu.addAction(
            icons.get("file_remove"),
            rem_selected_text,
            self.remove_selected_items,
            self.rem_selected_items_shortcut.key(),
        )
        menu.exec_(self.mapToGlobal(pos))

    @pyqtSlot()
    def remove_selected_items(self):
        indexes = self.selectionModel().selectedRows()
        items = [self.model().itemFromIndex(i) for i in indexes]
        self.remove_items(items)

    def remove_items(self, items):
        # Create a status message
        if len(items) == 1:
            status_msg = f"Removed '{items[0].data(Qt.DisplayRole)}'"
        else:
            status_msg = f"Removed {len(items)} items"

        # Unload from player
        self.player.unload_media(items=items)

        # Remove from model
        start_row = self.model().indexFromItem(items[0]).row()
        num_rows = len(items)
        self.model().removeRows(start_row, num_rows)

        # Push status message
        self.status_bar.showMessage(status_msg)
Ejemplo n.º 30
0
	def __init__(self, pwMap, settings, dbFilename):
		"""
		@param pwMap: a PasswordMap instance with encrypted passwords
		@param dbFilename: file name for saving pwMap
		"""
		super(MainWindow, self).__init__()
		self.setupUi(self)

		self.logger = settings.logger
		self.settings = settings
		self.pwMap = pwMap
		self.selectedGroup = None
		self.modified = False  # modified flag for "Save?" question on exit
		self.dbFilename = dbFilename

		self.groupsModel = QStandardItemModel(parent=self)
		self.groupsModel.setHorizontalHeaderLabels([u"Password group"])
		self.groupsFilter = QSortFilterProxyModel(parent=self)
		self.groupsFilter.setSourceModel(self.groupsModel)

		self.groupsTree.setModel(self.groupsFilter)
		self.groupsTree.setContextMenuPolicy(Qt.CustomContextMenu)
		self.groupsTree.customContextMenuRequested.connect(self.showGroupsContextMenu)
		# Dont use e following line, it would cause loadPasswordsBySelection
		# to be called twice on mouse-click.
		# self.groupsTree.clicked.connect(self.loadPasswordsBySelection)
		self.groupsTree.selectionModel().selectionChanged.connect(self.loadPasswordsBySelection)
		self.groupsTree.setSortingEnabled(True)

		self.passwordTable.setContextMenuPolicy(Qt.CustomContextMenu)
		self.passwordTable.customContextMenuRequested.connect(self.showPasswdContextMenu)
		self.passwordTable.setSelectionBehavior(QAbstractItemView.SelectRows)
		self.passwordTable.setSelectionMode(QAbstractItemView.SingleSelection)

		shortcut = QShortcut(QKeySequence(u"Ctrl+C"), self.passwordTable, self.copyPasswordFromSelection)
		shortcut.setContext(Qt.WidgetShortcut)

		self.actionQuit.triggered.connect(self.close)
		self.actionQuit.setShortcut(QKeySequence(u"Ctrl+Q"))
		self.actionExport.triggered.connect(self.exportCsv)
		self.actionImport.triggered.connect(self.importCsv)
		self.actionBackup.triggered.connect(self.saveBackup)
		self.actionAbout.triggered.connect(self.printAbout)
		self.actionSave.triggered.connect(self.saveDatabase)
		self.actionSave.setShortcut(QKeySequence(u"Ctrl+S"))

		# headerKey = QTableWidgetItem(u"Key")
		# headerValue = QTableWidgetItem(u"Password/Value")
		# headerComments = QTableWidgetItem(u"Comments")
		# self.passwordTable.setColumnCount(self.NO_OF_PASSWDTABLE_COLUMNS)
		# self.passwordTable.setHorizontalHeaderItem(self.KEY_IDX, headerKey)
		# self.passwordTable.setHorizontalHeaderItem(self.PASSWORD_IDX, headerValue)
		# self.passwordTable.setHorizontalHeaderItem(self.COMMENTS_IDX, headerComments)
		#
		# self.passwordTable.resizeRowsToContents()
		# self.passwordTable.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
		# self.passwordTable.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeToContents)
		# self.passwordTable.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeToContents)

		self.searchEdit.textChanged.connect(self.filterGroups)

		if pwMap is not None:
			self.setPwMap(pwMap)

		self.clipboard = QApplication.clipboard()

		self.timer = QTimer(parent=self)
		self.timer.timeout.connect(self.clearClipboard)
Ejemplo n.º 31
0
class ListTable(QTableWidget):
    """Define a custom table list."""

    dataModified = pyqtSignal()

    def __init__(self, noColumns=1, data=[]):
        """Init table list."""
        super().__init__()

        data = self.__processData(data)
        self.__noColumns = noColumns

        self.setCornerButtonEnabled(False)
        self.horizontalHeader().hide()
        self.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.verticalHeader().hide()
        self.verticalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)
        self.setData(data)
        self.shortcut = QShortcut(QKeySequence("DEL"), self)
        self.shortcut.setAutoRepeat(False)
        self.shortcut.setContext(Qt.WidgetWithChildrenShortcut)
        self.shortcut.activated.connect(self.delClicked)

    def __handleDataChanged(self, item):
        self.setData(self.getData(), item)
        self.dataModified.emit()

    def __processData(self, data):
        seen = set()
        uniq = [x for x in data if x not in seen and not seen.add(x)]
        uniq.sort()
        return uniq

    def delClicked(self):
        item = self.currentItem()
        if item and item.isSelected() and item.text().strip():
            item.setText("")

    def setData(self, data, item=""):
        """Set the data."""
        try:
            self.itemChanged.disconnect()
        except Exception:
            pass

        if item:
            item = item.text()

        self.setColumnCount(self.__noColumns)
        self.setRowCount(int(len(data) / self.__noColumns) + 1)
        for idx, entry in enumerate(data):
            row, column = divmod(idx, self.__noColumns)
            self.setItem(row, column, QTableWidgetItem(entry))
            if entry == item:
                self.setCurrentCell(row, column)

        row = int(len(data) / self.__noColumns)
        for col in range(len(data) % self.__noColumns, self.__noColumns):
            self.setItem(row, col, QTableWidgetItem(""))

        row = int(len(data) / self.__noColumns) + 1
        for col in range(self.__noColumns):
            self.setItem(row, col, QTableWidgetItem(""))

        self.itemChanged.connect(self.__handleDataChanged)

    def getData(self):
        """Get the data."""
        data = []
        for row in range(self.rowCount()):
            for col in range(self.columnCount()):
                try:
                    element = self.item(row, col).text().strip()
                    if (element == ""):
                        continue
                    data.append(element)
                except Exception:
                    pass
        return self.__processData(data)
Ejemplo n.º 32
0
def spaceBarPressed():
    global myIt, activeLayerId
    aLayer = iface.activeLayer()
    if not aLayer or not aLayer.type() == 0:
        print("Please first select a vector layer in the ToC.")
        return
    if activeLayerId != aLayer.id():
        activeLayerId = aLayer.id()
        myIt = None
    if not myIt:
        myIt = aLayer.getFeatures()

    feat = next(myIt, None)
    if feat:
        aLayer.removeSelection()
        aLayer.select(feat.id())
        iface.actionZoomToSelected().trigger()
        print("Selected feature:", str(feat.id()))
    else:
        print ("We reached the last feature of this layer already.\n" + \
            "If you want to restart press the Escape key.")


shortcutEscape = QShortcut(QKeySequence(Qt.Key_Escape), iface.mapCanvas())
shortcutEscape.setContext(Qt.ApplicationShortcut)
shortcutEscape.activated.connect(escapePressed)

shortcutSpaceBar = QShortcut(QKeySequence(Qt.Key_Space), iface.mapCanvas())
shortcutSpaceBar.setContext(Qt.ApplicationShortcut)
shortcutSpaceBar.activated.connect(spaceBarPressed)
Ejemplo n.º 33
0
class CAMERABASLERACQ(QWidget) :

    def __init__(self,name=None,visuGauche=False):
        super(CAMERABASLERACQ, self).__init__()
        self.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5()) # dark style 
        self.visuGauche=visuGauche
        if name==None:
            self.nbcam='camTest'
        else:   
            self.nbcam=name
        self.confCCD = QtCore.QSettings('confBasler.ini', QtCore.QSettings.IniFormat)
        self.camType=self.confCCD.value(self.nbcam+"/camType")
        
        if self.camType != 'basler':
            print('error camera type')
        
        self.id=self.confCCD.value(self.nbcam+"/camId")
        self.camName=self.confCCD.value(self.nbcam+"/name")
        camConnected=None
        for i in pylon.TlFactory.GetInstance().EnumerateDevices():
            if i.GetSerialNumber()==self.id:
                camConnected=i
        try :
            if camConnected is not None:
                self.cam0= pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateDevice(camConnected))
                self.isConnected=True
                print(self.camName,'connected @',i.GetSerialNumber())
#            else:
#                self.cam0= pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateFirstDevice())
#                print('fisrt camera connected')
#                self.isConnected=True
            else:
                 self.isConnected=False
                 print('no camera connected')
        except:
            self.isConnected=False
            print('no camera connected')
            
        self.bloqHandle=1 # bloque la taille du cercle
        self.setup()
        self.Color()
        self.cameName=self.confCCD.value(self.nbcam+"/name")
        self.setWindowTitle(self.cameName)
        p = pathlib.Path(__file__)
        sepa=os.sep
        self.icon=str(p.parent) + sepa + 'icons' +sepa
        self.setWindowIcon(QIcon(self.icon+'LOA.png'))
        #pg.setConfigOptions(antialias=True)
        self.winSC=FULLSCREEN(title=self.cameName,conf=self.confCCD,nbcam=self.nbcam)
        self.actionButton()
        self.bloqq=1
        if self.isConnected==False:
        
        
            print ('not connected')
            self.nbcam='camTest'
            self.runButton.setEnabled(False)
            self.runButton.setStyleSheet("background-color:gray")
            self.runButton.setStyleSheet("QPushButton:!pressed{image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0,0)}""QPushButton:pressed{image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0)}")
            
            self.hSliderShutter.setEnabled(False)
            self.trigg.setEnabled(False)
            self.hSliderGain.setEnabled(False)
            self.stopButton.setEnabled(False)
            self.stopButton.setStyleSheet("background-color:gray")
            self.stopButton.setStyleSheet("QPushButton:!pressed{border-image: url(./icons/Stop.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0,0);}""QPushButton:pressed{image: url(./icons/Stop.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0)}")

            
        if self.isConnected==True:
            self.cam0.Open()
 
            self.cam0.GainAuto.SetValue('Off')
            self.cam0.TriggerMode.SetValue('Off')
            self.cam0.TriggerSelector.SetValue("AcquisitionStart")
            self.cam0.ExposureAuto.SetValue('Off')

            self.cam0.Width=self.cam0.Width.Max
            self.cam0.Height=self.cam0.Height.Max
#            self.hSliderShutter.setMinimum(self.cam0.ExposureTimeAbs.GetMin())
#            self.hSliderShutter.setMaximum(self.cam0.ExposureTimeAbs.GetMax())
            sh=int(self.confCCD.value(self.nbcam+"/shutter"))
            self.hSliderShutter.setValue(sh)
            self.shutterBox.setValue(int(sh))
            
            self.cam0.ExposureTimeAbs.SetValue(int(sh*1000))
            
            self.hSliderGain.setMinimum(self.cam0.GainRaw.GetMin())
            self.hSliderGain.setMaximum(self.cam0.GainRaw.GetMax())
            g=int(self.confCCD.value(self.nbcam+"/gain"))
            self.hSliderGain.setValue(g)
            self.cam0.GainRaw.SetValue(int(g))
            
            
            self.gainBox.setMinimum(self.cam0.GainRaw.GetMin())
            self.gainBox.setMaximum(self.cam0.GainRaw.GetMax())
            self.gainBox.setValue(int(self.cam0.GainRaw.GetValue()))
            
            
            self.dimy=self.cam0.SensorHeight.GetValue()
            self.dimx=self.cam0.SensorWidth.GetValue()
            print("number of pixels :",self.dimx,'*',self.dimy)
        
        else :
            self.dimy=960
            self.dimx=1240
            
        
        def twoD_Gaussian(x,y, amplitude, xo, yo, sigma_x, sigma_y, theta, offset):
            xo = float(xo)
            yo = float(yo)    
            a = (np.cos(theta)**2)/(2*sigma_x**2) + (np.sin(theta)**2)/(2*sigma_y**2)
            b = -(np.sin(2*theta))/(4*sigma_x**2) + (np.sin(2*theta))/(4*sigma_y**2)
            c = (np.sin(theta)**2)/(2*sigma_x**2) + (np.cos(theta)**2)/(2*sigma_y**2)
            return offset + amplitude*np.exp( - (a*((x-xo)**2) + 2*b*(x-xo)*(y-yo) + c*((y-yo)**2)))

        # Create x and y indices
        x = np.arange(0,self.dimx)
        y = np.arange(0,self.dimy)
        y,x = np.meshgrid(y, x)

        self.data=twoD_Gaussian(x, y,250, 300, 600, 40, 40, 0, 10)+(50*np.random.rand(self.dimx,self.dimy)).round() 
        #self.data=(50*np.random.rand(self.dimx,self.dimy)).round() + 150
        
        self.p1.setXRange(0,self.dimx)
        self.p1.setYRange(0,self.dimy)
        #self.p1.setGeometry(1,1,self.dimx,self.dimy)
        #self.winImage.setGeometry(1,1,self.dimx,self.dimy)
        self.Display(self.data)
        
        
    def setup(self):    
        
        vbox1=QVBoxLayout() 
        
        
        self.camNameLabel=QLabel('nomcam',self)
        
        self.camNameLabel.setText(self.confCCD.value(self.nbcam+"/name"))

        self.camNameLabel.setAlignment(Qt.AlignCenter)
        self.camNameLabel.setStyleSheet('font: bold 20px')
        self.camNameLabel.setStyleSheet('color: yellow')
        vbox1.addWidget(self.camNameLabel)
        
        hbox1=QHBoxLayout() # horizontal layout pour run et stop
        self.runButton=QPushButton(self)
        self.runButton.setMaximumWidth(60)
        self.runButton.setMinimumHeight(60)
        self.runButton.setStyleSheet("QPushButton:!pressed{border-image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: rgb(0, 0, 0,0) ;border-color: green;}""QPushButton:pressed{image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0)}")
        self.stopButton=QPushButton(self)
        
        self.stopButton.setMaximumWidth(60)
        self.stopButton.setMinimumHeight(50)
        self.stopButton.setStyleSheet("QPushButton:!pressed{border-image: url(./icons/Stop.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0,0);}""QPushButton:pressed{image: url(./icons/Stop.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0)}")
        
        
        hbox1.addWidget(self.runButton)
        hbox1.addWidget(self.stopButton)
#        self.oneButton=QPushButton(self)
#        hbox1.addWidget(self.oneButton)
        
        vbox1.addLayout(hbox1)
        
        self.trigg=QComboBox()
        self.trigg.setMaximumWidth(60)
        self.trigg.addItem('OFF')
        self.trigg.addItem('ON')
        self.labelTrigger=QLabel('Trigger')
        self.labelTrigger.setMaximumWidth(60)
        self.itrig=self.trigg.currentIndex()
        hbox2=QHBoxLayout()
        hbox2.addWidget(self.labelTrigger)
        hbox2.addWidget(self.trigg)
        vbox1.addLayout(hbox2)
        
        self.labelExp=QLabel('Exposure (ms)')
        self.labelExp.setMaximumWidth(120)
        self.labelExp.setAlignment(Qt.AlignCenter)
        vbox1.addWidget(self.labelExp)
        self.hSliderShutter=QSlider(Qt.Horizontal)
        self.hSliderShutter.setMinimum(1)
        self.hSliderShutter.setMaximum(1000)
        self.hSliderShutter.setMaximumWidth(120)
        self.shutterBox=QSpinBox()
        self.shutterBox.setMinimum(1)
        self.shutterBox.setMaximum(1000)
        self.shutterBox.setMaximumWidth(60)
       
        hboxShutter=QHBoxLayout()
        hboxShutter.addWidget(self.hSliderShutter)
        hboxShutter.addWidget(self.shutterBox)
        vbox1.addLayout(hboxShutter)
        
        
        

        hboxGain=QHBoxLayout()
        self.labelGain=QLabel('Gain')
        self.labelGain.setMaximumWidth(120)
        self.labelGain.setAlignment(Qt.AlignCenter)
        vbox1.addWidget(self.labelGain)
        self.hSliderGain=QSlider(Qt.Horizontal)
        self.hSliderGain.setMaximumWidth(120)
        
        self.gainBox=QSpinBox()
        
           
        self.gainBox.setMaximumWidth(60)
        hboxGain.addWidget(self.hSliderGain)
        hboxGain.addWidget(self.gainBox)
        vbox1.addLayout(hboxGain)
        
        
        hbox3=QHBoxLayout()
        self.checkBoxScale=QCheckBox('AScale',self)
        self.checkBoxScale.setChecked(True)
        self.checkBoxScale.setStyleSheet("QCheckBox::indicator{width: 30px;height: 30px;}""QCheckBox::indicator:unchecked { image : url(./icons/Toggle Off-595b40b85ba036ed117dac78.svg);}""QCheckBox::indicator:checked { image:  url(./icons/Toggle On-595b40b85ba036ed117dac79.svg);}")
    
        hbox3.addWidget(self.checkBoxScale)
        
        self.checkBoxColor=QCheckBox('Color',self)
        self.checkBoxColor.setChecked(True)
        self.checkBoxColor.setStyleSheet("QCheckBox::indicator{width: 30px;height: 30px;}""QCheckBox::indicator:unchecked { image : url(./icons/Toggle Off-595b40b85ba036ed117dac78.svg);}""QCheckBox::indicator:checked { image:  url(./icons/Toggle On-595b40b85ba036ed117dac79.svg);}")
    
        hbox3.addWidget(self.checkBoxColor)
        
        vbox1.addLayout(hbox3)
        hbox4=QHBoxLayout()
        self.checkBoxZoom=QCheckBox('Zoom',self)
        self.checkBoxZoom.setChecked(False)
        self.checkBoxZoom.setStyleSheet("QCheckBox::indicator{width: 30px;height: 30px;}""QCheckBox::indicator:unchecked { image : url(./icons/Toggle Off-595b40b85ba036ed117dac78.svg);}""QCheckBox::indicator:checked { image:  url(./icons/Toggle On-595b40b85ba036ed117dac79.svg);}")
    
        hbox4.addWidget(self.checkBoxZoom)
        
        self.checkBoxFullScreen=QCheckBox('FScreen',self)
        self.checkBoxFullScreen.setChecked(False)
        self.checkBoxFullScreen.setStyleSheet("QCheckBox::indicator{width: 30px;height: 30px;}""QCheckBox::indicator:unchecked { image : url(./icons/Toggle Off-595b40b85ba036ed117dac78.svg);}""QCheckBox::indicator:checked { image:  url(./icons/Toggle On-595b40b85ba036ed117dac79.svg);}")
    
        hbox4.addWidget(self.checkBoxFullScreen)
        
        
        vbox1.addLayout(hbox4)
        
        vbox1.setContentsMargins(0,0,0,0)
        vbox1.addStretch(1)
        self.vbox1=vbox1
        
        ### affichage image###
        
        self.winImage = pg.GraphicsLayoutWidget()
        self.winImage.setContentsMargins(0,0,0,0)
        self.winImage.setAspectLocked(True)
        self.winImage.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.winImage.ci.setContentsMargins(0,0,0,0)
        
        vbox2=QVBoxLayout()
        vbox2.addWidget(self.winImage)
        vbox2.setContentsMargins(1,1,1,1)
        
    
        self.p1=self.winImage.addPlot()
        self.imh=pg.ImageItem()
        self.p1.addItem(self.imh)
        self.p1.setMouseEnabled(x=False,y=False)
        self.p1.setContentsMargins(0,0,0,0)
        self.p1.setAspectLocked(True,ratio=1)
        self.p1.showAxis('right',show=False)
        self.p1.showAxis('top',show=False)
        self.p1.showAxis('left',show=False)
        self.p1.showAxis('bottom',show=False)
        
        self.vLine = pg.InfiniteLine(angle=90, movable=False,pen='y')
        self.hLine = pg.InfiniteLine(angle=0, movable=False,pen='y')
        self.p1.addItem(self.vLine)
        self.p1.addItem(self.hLine, ignoreBounds=False)
        self.xc=int(self.confCCD.value(self.nbcam+"/xc"))
        self.yc=int(self.confCCD.value(self.nbcam+"/yc"))
        self.rx=int(self.confCCD.value(self.nbcam+"/rx"))
        self.ry=int(self.confCCD.value(self.nbcam+"/ry"))
        self.vLine.setPos(self.xc)
        self.hLine.setPos(self.yc)
        
        self.ro1=pg.EllipseROI([self.xc,self.yc],[self.rx,self.ry],pen='y',movable=False)#maxBounds=QtCore.QRectF(0,0,self.rx,self.ry)
        self.ro1.setPos([self.xc-(self.rx/2),self.yc-(self.ry/2)])
        self.p1.addItem(self.ro1)
        
        
        #histogramme
        self.hist = pg.HistogramLUTItem() 
        self.hist.setImageItem(self.imh)
        self.hist.autoHistogramRange()
        self.hist.gradient.loadPreset('flame')
        
        ## Graph coupe XY  
        
        self.curve2=pg.PlotCurveItem()
        self.curve3=pg.PlotCurveItem()
        
        ## main layout
        
        hMainLayout=QHBoxLayout()
        if self.visuGauche==True:
            hMainLayout.addLayout(self.vbox1)
            hMainLayout.addLayout(vbox2)
        else:
            hMainLayout.addLayout(vbox2)
            hMainLayout.addLayout(self.vbox1)
        hMainLayout.setContentsMargins(1,1,1,1)
        hMainLayout.setSpacing(1)
        hMainLayout.setStretch(3,1)
        
        self.setLayout(hMainLayout)
        self.setContentsMargins(1,1,1,1)
        
        # Blocage de la souris
        self.shortcutb=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+b"),self)
        self.shortcutb.activated.connect(self.bloquer)
        self.shortcutb.setContext(Qt.ShortcutContext(3))
        self.shortcutd=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+d"),self)
        self.shortcutd.activated.connect(self.debloquer)
        self.shortcutd.setContext(Qt.ShortcutContext(3))
        self.shortcutPu=QShortcut(QtGui.QKeySequence("+"),self)
        self.shortcutPu.activated.connect(self.paletteup)
        self.shortcutPu.setContext(Qt.ShortcutContext(3))
        #3: The shortcut is active when its parent widget, or any of its children has focus. default O The shortcut is active when its parent widget has focus.
        self.shortcutPd=QtGui.QShortcut(QtGui.QKeySequence("-"),self)
        self.shortcutPd.activated.connect(self.palettedown)
        self.shortcutPd.setContext(Qt.ShortcutContext(3))
        
        # mvt de la souris
        self.proxy=pg.SignalProxy(self.p1.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
        self.vb=self.p1.vb
        
        # text pour afficher fwhm sur p1
        self.textX = pg.TextItem(angle=-90) 
        self.textY = pg.TextItem()
        
        
    def actionButton(self):
        self.runButton.clicked.connect(self.acquireMultiImage)
        self.stopButton.clicked.connect(self.stopAcq)
        self.hSliderShutter.sliderMoved.connect(self.mSliderShutter)
        self.shutterBox.editingFinished.connect(self.shutter)
        self.hSliderGain.sliderMoved.connect(self.mSliderGain)
        self.gainBox.editingFinished.connect(self.gain)
        self.trigg.currentIndexChanged.connect(self.Trig)
        self.checkBoxColor.stateChanged.connect(self.Color)
        
        self.ro1.sigRegionChangeFinished.connect(self.roiChanged)
        self.checkBoxZoom.stateChanged.connect(self.Zoom)
        self.checkBoxFullScreen.stateChanged.connect(self.FullScreen)
#        self.oneButton.clicked.connect(self.acquireOneImage)
        
    def shutter(self):
        
        sh=self.shutterBox.value() # 
        self.hSliderShutter.setValue(sh) # set value of slider
        time.sleep(0.1)
        print(sh,'sh')
        self.cam0.ExposureTimeAbs.SetValue(int(sh*1000))
            
        self.confCCD.setValue(self.nbcam+"/shutter",float(sh))
        self.confCCD.sync()

    def mSliderShutter(self): # for shutter slider 
        sh=self.hSliderShutter.value() 
        self.shutterBox.setValue(sh) # 
        time.sleep(0.1)
        self.cam0.ExposureTimeAbs.SetValue(int(sh*1000)) # Set shutter CCD in microseconde
        self.confCCD.setValue(self.nbcam+"/shutter",float(sh))   
    
    def Color(self):
        """ image in colour
        """
        if self.checkBoxColor.isChecked()==1:
            self.color='flame'
            self.hist.gradient.loadPreset('flame')
        else:
            self.hist.gradient.loadPreset('grey')
            self.color='grey'
            
    def Zoom(self):
        if self.checkBoxZoom.isChecked()==1:
            self.p1.setXRange(self.xc-200,self.xc+200)
            self.p1.setYRange(self.yc-200,self.yc+200)
        else:
            self.p1.setXRange(0,self.dimx)
            self.p1.setYRange(0,self.dimy)
        
    def FullScreen(self):
        if self.checkBoxFullScreen.isChecked()==1:
            self.open_widget(self.winSC)
            self.winSC.Display(self.data,color=self.color)
            #self.winSC.showMaximized()
        else:
             self.winSC.close()
         
    def gain(self):
        g=self.gainBox.value() # 
        self.hSliderGain.setValue(g) # set slider value
        time.sleep(0.1)
        self.cam0.GainRaw.SetValue(int(g))
        
        self.confCCD.setValue(self.nbcam+"/gain",float(g))
        self.confCCD.sync()
    
    def mSliderGain(self):
        g=self.hSliderGain.value()
        self.gainBox.setValue(g) # set valeur de la box
        time.sleep(0.1)
        self.cam0.GainRaw.SetValue(int(g))
        self.confCCD.setValue(self.nbcam+"/gain",float(g))
        self.confCCD.sync()
        
    def Trig(self):
        self.itrig=self.trigg.currentIndex()
        
        if self.itrig==0:
            self.cam0.TriggerMode.SetValue('Off')
#            print ("trigger OFF")
        if self.itrig==1:
            self.cam0.TriggerMode.SetValue('On')
#            print("Trigger ON")
        
    def acquireMultiImage(self):   
        #print('live...')
        
        self.runButton.setEnabled(False)
        self.runButton.setStyleSheet("QPushButton:!pressed{border-image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: gray ;border-color: rgb(0, 0, 0,0);}""QPushButton:pressed{image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: gray ;border-color: rgb(0, 0, 0)}")
        #self.runButton.setStyleSheet("background-color:gray")
        try:
            self.threadRunAcq=ThreadRunAcq(self)
            self.threadRunAcq.newDataRun.connect(self.Display)
            self.threadRunAcq.start()
        except :
            pass
    
    
    def acquireOneImage(self):   
        
        
        self.runButton.setEnabled(False)
        self.runButton.setStyleSheet("QPushButton:!pressed{border-image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: gray ;border-color: rgb(0, 0, 0,0);}""QPushButton:pressed{image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: gray ;border-color: rgb(0, 0, 0)}")
        #self.runButton.setStyleSheet("background-color:gray")
        try:
            self.threadOneAcq=ThreadOneAcq(self)
            self.threadOneAcq.newDataOne.connect(self.Display)
            self.threadOneAcq.start()
        except :
            print('error')
            pass
        self.runButton.setEnabled(True)
        self.runButton.setStyleSheet("QPushButton:!pressed{border-image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0,0);}""QPushButton:pressed{image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0)}")
        
    
    
    def stopAcq(self):
#        print('Stop live')
        try:
            self.threadRunAcq.stopThreadRunAcq()
            print('ici')
            self.cam0.ExecuteSoftwareTrigger()
        except :
            print('error stop thread')
            pass
        self.runButton.setEnabled(True)
        #self.runButton.setStyleSheet("background-color: rgb(0, 200, 0)")
        self.runButton.setStyleSheet("QPushButton:!pressed{border-image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0,0);}""QPushButton:pressed{image: url(./icons/Circled Play-595b40b65ba036ed117d436f.svg);background-color: rgb(0, 0, 0,0) ;border-color: rgb(0, 0, 0)}")
        
        #self.threadAcq.terminate()    
        
    def Display(self,data):
        self.data=data
        if self.checkBoxScale.isChecked()==1: # autoscale on
            self.imh.setImage(data.astype(float),autoLevels=True,autoDownsample=True)
            if self.checkBoxFullScreen.isChecked()==1 and self.winSC.isWinOpen==True:
                self.winSC.Display(self.data,autoLevels=True,color=self.color)
        else :
            self.imh.setImage(data.astype(float),autoLevels=False,autoDownsample=True)
            if self.checkBoxFullScreen.isChecked()==1 and self.winSC.isWinOpen==True:
                self.winSC.Display(self.data,autoLevels=False,color=self.color)
        
        if self.winSC.isWinOpen==False:
            self.checkBoxFullScreen.setChecked(False)
    
        
    def bloquer(self): # bloque la croix 
        self.bloqq=1
        self.confCCD.setValue(self.nbcam+"/xc",int(self.xc)) # save cross postion in ini file
        self.confCCD.setValue(self.nbcam+"/yc",int(self.yc))
        print('xc',self.xc,'yc',self.yc)
        
        
    def debloquer(self): # deblaoque la croix : elle bouge avec la souris
        self.bloqq=0
    
    def roiChanged(self):
        self.rx=self.ro1.size()[0]
        self.ry=self.ro1.size()[1]
        self.confCCD.setValue(self.nbcam+"/rx",int(self.rx))
        self.confCCD.setValue(self.nbcam+"/ry",int(self.ry))
        
        
    def mouseMoved(self,evt):
        ## pour que la cross suive le mvt de la souris
        if self.bloqq==0: # souris non bloquer
            pos = evt[0]  ## using signal proxy turns original arguments into a tuple
            if self.p1.sceneBoundingRect().contains(pos):
                mousePoint = self.vb.mapSceneToView(pos)
                self.xc = (mousePoint.x())
                self.yc= (mousePoint.y())
                if ((self.xc>0 and self.xc<self.data.shape[0]) and (self.yc>0 and self.yc<self.data.shape[1]) ):
                        self.vLine.setPos(self.xc)
                        self.hLine.setPos(self.yc) # la croix ne bouge que dans le graph       
                        self.ro1.setPos([self.xc-(self.rx/2),self.yc-(self.ry/2)])
                        
    
    
            
    def paletteup(self):
        levels=self.imh.getLevels()
        if levels[0]==None:
            xmax =self.data.max()
            xmin=self.data.min()
        else :
            xmax=levels[1]
            xmin=levels[0]
            
        self.imh.setLevels([xmin, xmax+(xmax- xmin) / 10])
        #hist.setImageItem(imh,clear=True)
        self.hist.setHistogramRange(xmin,xmax)

    def palettedown(self):
        levels=self.imh.getLevels()
        if levels[0]==None:
            xmax=self.data.max()
            xmin=self.data.min()
        else :
            xmax=levels[1]
            xmin=levels[0]
            
        self.imh.setLevels([xmin, xmax- (xmax- xmin) / 10])
        #hist.setImageItem(imh,clear=True)
        self.hist.setHistogramRange(xmin,xmax)
    
    
    def open_widget(self,fene):
        """ open new widget 
        """

        if fene.isWinOpen==False:
            fene.setup
            fene.isWinOpen=True
            
            #fene.Display(self.data)
            fene.show()
        else:
            #fene.activateWindow()
            fene.raise_()
            fene.showNormal()
            
            
    def closeEvent(self,event):
        self.fin()
        event.accept()
    
    
    def fin(self):
        try :
            self.threadRunAcq.stopThreadRunAcq()
        except :
            pass
        try :
            self.cam0.close()
        except :
            pass
        sys.exit(0)  
Ejemplo n.º 34
0
class Tree(QTreeView):
    """File system tree
    """

    _fileActivated = pyqtSignal()

    def __init__(self, fileBrowser):
        QTreeView.__init__(self, fileBrowser)

        self._fileBrowser = fileBrowser

        self.setAttribute(Qt.WA_MacShowFocusRect, False)
        self.setAttribute(Qt.WA_MacSmallSize)
        self.setContextMenuPolicy(Qt.ActionsContextMenu)
        self.setHeaderHidden(True)
        self.setUniformRowHeights(True)
        self.setTextElideMode(Qt.ElideMiddle)

        # dir model
        self._dirsModel = _FileSystemModel(self)
        self._dirsModel.setNameFilterDisables(False)
        self._dirsModel.setFilter(QDir.AllDirs | QDir.AllEntries | QDir.CaseSensitive | QDir.NoDotAndDotDot)
        # self._dirsModel.directoryLoaded.connect(self.setFocus)  TODO don't have this signal in my Qt version

        # create proxy model
        self._filteredModel = FileBrowserFilteredModel(self)
        self._filteredModel.setSourceModel(self._dirsModel)

        self.setModel(self._filteredModel)

        if not sys.platform.startswith('win'):
            self._dirsModel.setRootPath("/")
        else:
            self._dirsModel.setRootPath('')

        # shortcut accessible only when self._tree has focus
        self._upShortcut = QShortcut(QKeySequence("BackSpace"), self)
        self._upShortcut.setContext(Qt.WidgetShortcut)
        self._upShortcut.activated.connect(self.moveUp)

        # shortcut accessible only when self._tree has focus
        self._homeShortcut = QShortcut(QKeySequence("`"), self)
        self._homeShortcut.setContext(Qt.WidgetShortcut)
        self._homeShortcut.activated.connect(self._goUserHomeDir)

        # shortcut accessible only when self._tree has focus
        self._homeShortcut = QShortcut(QKeySequence("."), self)
        self._homeShortcut.setContext(Qt.WidgetShortcut)
        self._homeShortcut.activated.connect(self._goCurrentDir)

        self.activated.connect(self._onActivated)
        self._fileActivated.connect(fileBrowser.fileActivated)

        # QDirModel loads item asynchronously, therefore we need timer for setting focus to the first item
        self._setFocusTimer = QTimer()
        self._setFocusTimer.timeout.connect(self._setFirstItemAsCurrent)
        self._setFocusTimer.setInterval(50)
        self._timerAttempts = 0

    def term(self):
        self._setFocusTimer.stop()

    def _onActivated(self, idx):
        """File or directory doubleClicked
        """
        index = self._filteredModel.mapToSource(idx)
        path = self._dirsModel.filePath(index)

        if os.path.isdir(path):
            self._fileBrowser.setCurrentPath(path)
        else:
            self._fileActivated.emit()
            core.workspace().openFile(path)
            core.workspace().focusCurrentDocument()

    def moveUp(self):
        """User pressed Up key or button. Move focus and root up
        """
        current = self.currentIndex()
        if not current.isValid():
            current = self.rootIndex().child(0, 0)
            self.setCurrentIndex(current)

        if current.parent() == self.rootIndex() or \
           current == self.rootIndex():  # need to move root up
            if self.rootIndex().parent().isValid():  # not reached root of the FS tree
                newRoot = self.rootIndex().parent()
                parentPath = self._filteredModelIndexToPath(current.parent())
                self._fileBrowser.setCurrentPath(self._filteredModelIndexToPath(newRoot))
                self.collapseAll()  # if moving root up - collapse all items
                parentIndex = self._filteredModel.mapFromSource(self._dirsModel.index(parentPath))
                self._setCurrentItem(parentIndex)
        else:  # need to move selection up
            parentOfCurrent = self.currentIndex().parent()
            self._setCurrentItem(parentOfCurrent)  # move selection up

    def _goUserHomeDir(self):
        """Go to home directory
        """
        self._fileBrowser.setCurrentPath(os.path.expanduser("~"))
        self.collapseAll()

    def _goCurrentDir(self):
        """Go to current directory
        """
        self._fileBrowser.setCurrentPath(_getCurDir())
        self.collapseAll()

    def _filteredModelIndexToPath(self, index):
        """Map index to file path
        """
        srcIndex = self._filteredModel.mapToSource(index)
        return self._dirsModel.filePath(srcIndex)

    def currentPath(self):
        """Get current path (root of the tree)
        """
        index = self.rootIndex()
        index = self._filteredModel.mapToSource(index)
        return self._dirsModel.filePath(index)

    def _isDescendant(self, child, parent):
        """Check if child is descendant of parent
        """
        while child.isValid():
            if child.parent() == parent:
                return True
            child = child.parent()
        return False

    def _setFirstItemAsCurrent(self):
        """QDirModel loads items asynchronously.
        Therefore we select current item by timer
        """
        if not self.currentIndex().isValid() or \
           not self._isDescendant(self.currentIndex(), self.rootIndex()):
            firstChild = self.rootIndex().child(0, 0)
            if firstChild.isValid():
                self._setFocusTimer.stop()
                self._setCurrentItem(self.rootIndex().child(0, 0))
            else:
                self._timerAttempts -= 1
                if not self._timerAttempts:
                    self._setFocusTimer.stop()
        else:  # nothing to do, have focus
            self._setFocusTimer.stop()

    def setCurrentPath(self, path):
        """Set current path (root of the tree)
        """
        # get index
        index = self._dirsModel.index(path)

        # set current path
        self._filteredModel.invalidate()
        newRoot = self._filteredModel.mapFromSource(index)
        self.setRootIndex(newRoot)

        self._timerAttempts = 10
        self._setFocusTimer.start()

    def _setCurrentItem(self, index):
        """Make the item current and select it
        """
        self.setCurrentIndex(index)
        self.selectionModel().select(index, QItemSelectionModel.SelectCurrent)
Ejemplo n.º 35
0
 def p_shortcut_connect(k, cb):  # an alias to simplify code
     sc = QShortcut(KS(k), ui.pc_panel)
     sc.setContext(Qt.WidgetWithChildrenShortcut)
     sc.activated.connect(cb)
Ejemplo n.º 36
0
class DockWidget(QDockWidget):
    """Extended QDockWidget for Enki main window
    """

    closed = pyqtSignal()
    """
    closed()

    **Signal** emitted, when dock is closed
    """

    shown = pyqtSignal()
    """
    shown()

    **Signal** emitted, when dock is shown
    """

    def __init__(self, parentObject, windowTitle, windowIcon=QIcon(), shortcut=None):
        QDockWidget.__init__(self, parentObject)
        self._showAction = None

        self.setObjectName(str(self.__class__))
        self.setWindowTitle(windowTitle)

        if not windowIcon.isNull():
            self.setWindowIcon(windowIcon)
        if shortcut is not None:
            self.showAction().setShortcut(shortcut)

        self._titleBar = _TitleBar(self)
        self.setTitleBarWidget(self._titleBar)

        if shortcut is not None:
            toolTip = "Move focus with <b>%s</b>,<br/>close with <b>Esc</b>" % shortcut
        else:
            toolTip = "Close with <b>Esc</b>"
        self._titleBar.setToolTip(toolTip)

        self._closeShortcut = QShortcut(QKeySequence("Esc"), self)
        self._closeShortcut.setContext(Qt.WidgetWithChildrenShortcut)
        self._closeShortcut.activated.connect(self._close)

    def keyPressEvent(self, event):
        """Catch Esc. Not using QShortcut, because dock shall be closed,
        only if child widgets haven't catched Esc event
        """
        if event.key() == Qt.Key_Escape and \
           event.modifiers() == Qt.NoModifier:
            self._hide()
        else:
            QDockWidget.keyPressEvent(self, event)

    def showAction(self):
        """Action shows the widget and set focus on it.

        Add this action to the main menu
        """
        if not self._showAction:
            self._showAction = QAction(self.windowIcon(), self.windowTitle(), self)
            self._showAction.triggered.connect(self.show)
            self._showAction.triggered.connect(self._handleFocusProxy)

        return self._showAction

    def titleBarWidget(self):
        """QToolBar on the title.

        You may add own actions to this tool bar
        """
        # method was added only for documenting
        return QDockWidget.titleBarWidget(self)

    def _handleFocusProxy(self):
        """Set focus to focus proxy.
        Called after widget has been shown
        """
        if self.focusProxy() is not None:
            self.setFocus()

    def _close(self):
        """Hide and return focus to MainWindow focus proxy
        """
        self.close()
        if ( self.parent() is not None and
          self.parent().focusProxy() is not None and
          self.hasFocus() ):
            self.parent().focusProxy().setFocus()

    def closeEvent(self, event):
        """Widget was closed"""
        self.closed.emit()

    def show(self):
        QDockWidget.show(self)
        # If floating, then active this window so it will receive keyboard
        # input.
        if self.isFloating():
            self.activateWindow()

    def showEvent(self, event):
        """Widget was shown"""
        self.shown.emit()

    def isPinned(self):
        """True if the widget is pinned; false if unpinned (auto-hide mode)."""
        return not self._titleBar.tbUnPinned.isChecked()
Ejemplo n.º 37
0
    def __init__(self):

        QMainWindow.__init__(self)
        Ui_MainWindow.setupUi(self, self)

        self.playlistDrop.dragEnterEvent = self.playlistDragEnterEvent
        self.playlistDrop.dropEvent = self.playlistDropEvent

        self.playlistModel = PlaylistModel()
        self.playlistTable.setModel(self.playlistModel)
        self.playlistTable.customContextMenuRequested.connect(self.playlistContextMenu)
        self.playlistTable.doubleClicked.connect(self.onPlaylistDoubleClick)

        self.playback = PlaybackWidget(self)
        self.playbackLayout.addWidget(self.playback)
        self.playback.playButton.clicked.connect(self.onPlaySelected)

        self.playback.nextButton.clicked.connect(self.onNextClicked)
        self.playback.prevButton.clicked.connect(self.onPrevClicked)

        self.libraryDock.setTitleBarWidget(QWidget())
        self.playlistsDock.setTitleBarWidget(QWidget())
        self.toggleLibraryButton.clicked.connect(self.onToggleLibrary)
        self.togglePlaylistsButton.clicked.connect(self.onTogglePlaylists)

        self.library = LibraryWidget(self)
        self.libraryDock.setWidget(self.library)
        self.libraryDock.hide()
        self.library.itemsActivated.connect(self.onLibraryItemActivated)

        self.playlists = PlaylistsWidget(self)
        self.playlistsDock.setWidget(self.playlists)
        self.playlistsDock.hide()
        self.playlists.loadPlaylist.connect(self.onPlaylistLoad)

        self.dockState = 0

        self.settings = QSettings('txplaya', 'txplaya')

        if u'geometry/main' in self.settings.allKeys():
            self.setGeometry(self.settings.value(u'geometry/main'))

            for col in range(self.playlistModel.columnCount()):
                width = self.settings.value(u'geometry/playlist/col/%d' % col)
                self.playlistTable.setColumnWidth(col, int(width))

            dockState = int(self.settings.value(u'geometry/dock/state'))
            self.dockShow(dockState)

        self.systemTray = QSystemTrayIcon(self.windowIcon())
        self.systemTray.setToolTip('Playa')
        self.systemTray.show()
        self.systemTray.activated.connect(self.systemTrayToggle)
        systemTrayMenu = QMenu()
        systemTrayMenu.addAction(self.restore)
        systemTrayMenu.addAction(self.quit)
        self.systemTray.setContextMenu(systemTrayMenu)
        self.restore.triggered.connect(self.restoreWindow)
        self.quit.triggered.connect(self.quitEvent)
        self.quitButton.clicked.connect(self.quitEvent)
        self.quitFlag = False

        # keyboard shortcuts
        focusLibraryShortcut = QShortcut(QKeySequence('Ctrl+F'), self)
        focusLibraryShortcut.activated.connect(self.onFocusLibrary)
        deleteTrackShortcut = QShortcut(QKeySequence('Del'), self.playlistTable)
        deleteTrackShortcut.setContext(Qt.WidgetShortcut)
        deleteTrackShortcut.activated.connect(self.onDeleteTrack)
        togglePlaybackShortcut = QShortcut(QKeySequence('Space'), self)
        togglePlaybackShortcut.activated.connect(self.onTogglePlayback)
        startShortcut = QShortcut(QKeySequence(Qt.Key_Return), self.playlistTable)
        startShortcut.setContext(Qt.WidgetShortcut)
        startShortcut.activated.connect(self.onPlaySelected)
        undoShortcut = QShortcut(QKeySequence('Ctrl+Z'), self)
        undoShortcut.activated.connect(self.onPlaylistUndo)
        redoShortcut = QShortcut(QKeySequence('Ctrl+Shift+Z'), self)
        redoShortcut.activated.connect(self.onPlaylistRedo)
        saveShortcut = QShortcut(QKeySequence('Ctrl+S'), self)
        saveShortcut.activated.connect(self.onPlaylistSave)

        self.infoStreamStart()
        QTimer.singleShot(200, self.fetchLibrary)
Ejemplo n.º 38
0
class DockWidget(QDockWidget):
    """Extended QDockWidget for Enki main window
    """

    closed = pyqtSignal()
    """
    closed()

    **Signal** emitted, when dock is closed
    """

    shown = pyqtSignal()
    """
    shown()

    **Signal** emitted, when dock is shown
    """

    def __init__(self, parentObject, windowTitle, windowIcon=QIcon(), shortcut=None):
        QDockWidget.__init__(self, parentObject)
        self._showAction = None

        self.setObjectName(str(self.__class__))
        self.setWindowTitle(windowTitle)

        self.setFeatures(self.features() & (~QDockWidget.DockWidgetFloatable))

        if not windowIcon.isNull():
            self.setWindowIcon(windowIcon)
        if shortcut is not None:
            self.showAction().setShortcut(shortcut)

        self._titleBar = _TitleBar(self)
        self.setTitleBarWidget(self._titleBar)

        if shortcut is not None:
            toolTip = "Move focus with <b>%s</b>,<br/>close with <b>Esc</b>" % shortcut
        else:
            toolTip = "Close with <b>Esc</b>"
        self._titleBar.setToolTip(toolTip)

        self._closeShortcut = QShortcut(QKeySequence("Esc"), self)
        self._closeShortcut.setContext(Qt.WidgetWithChildrenShortcut)
        self._closeShortcut.activated.connect(self._close)

    def keyPressEvent(self, event):
        """Catch Esc. Not using QShortcut, because dock shall be closed,
        only if child widgets haven't catched Esc event
        """
        if event.key() == Qt.Key_Escape and \
           event.modifiers() == Qt.NoModifier:
            self._hide()
        else:
            QDockWidget.keyPressEvent(self, event)

    def showAction(self):
        """Action shows the widget and set focus on it.

        Add this action to the main menu
        """
        if not self._showAction:
            self._showAction = QAction(self.windowIcon(), self.windowTitle(), self)
            self._showAction.triggered.connect(self.show)
            self._showAction.triggered.connect(self._handleFocusProxy)

        return self._showAction

    def titleBarWidget(self):
        """QToolBar on the title.

        You may add own actions to this tool bar
        """
        # method was added only for documenting
        return QDockWidget.titleBarWidget(self)

    def _handleFocusProxy(self):
        """Set focus to focus proxy.
        Called after widget has been shown
        """
        if self.focusProxy() is not None:
            self.setFocus()

    def _close(self):
        """Hide and return focus to MainWindow focus proxy
        """
        self.close()
        if self.parent() is not None and \
           self.parent().focusProxy() is not None:
            self.parent().focusProxy().setFocus()

    def closeEvent(self, event):
        """Widget was closed"""
        self.closed.emit()

    def showEvent(self, event):
        """Widget was shown"""
        self.shown.emit()
Ejemplo n.º 39
0
    def __init__(self, controller: 'Controller') -> None:
        super().__init__()

        self._controller = controller

        self.setCacheMode(QGraphicsView.CacheBackground)

        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        # self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)

        self._show_filtered = False

        self._location2item: Dict[Location, List[FileItem]] = defaultdict(list)
        self.setAcceptDrops(True)

        self._scene = FileGraphicsScene()
        self._scene.sig_files_drop.connect(self._controller.on_files_drop)
        self.setScene(self._scene)

        self._scene.selectionChanged.connect(self.on_selection_changed)

        self._style = FileViewStyle()

        self._modes: List[Mode] = [
            IconMode(self),
            ListMode(self),
            DetailMode(self)
        ]
        self._mode = self._modes[FileItemStyle.ICON.value]

        self._layout: Optional[RootLayout] = None

        self._items: List[FileItem] = []

        self._file_collection: Optional[FileCollection] = None

        self._needs_layout = True

        self.apply_zoom()
        self._cursor_item: Optional[FileItem] = None
        self._crop_thumbnails = False
        self.setBackgroundBrush(QBrush(Qt.white, Qt.SolidPattern))
        self._resize_timer: Optional[int] = None

        self.setDragMode(QGraphicsView.RubberBandDrag)

        self.setRenderHints(QPainter.SmoothPixmapTransform |
                            QPainter.TextAntialiasing |
                            QPainter.Antialiasing)

        shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_G), self)
        shortcut.setContext(Qt.WidgetShortcut)
        shortcut.activated.connect(self._on_reset)

        shortcut = QShortcut(QKeySequence(Qt.Key_Slash), self)
        shortcut.setContext(Qt.WidgetShortcut)
        shortcut.activated.connect(lambda: self._controller.show_location_toolbar(False))

        self._leap_widget = LeapWidget(self)
        self._leap_widget.sig_leap.connect(self.leap_to)

        self._scroll_timer = None
        self._is_scrolling = False
        self.verticalScrollBar().sliderReleased.connect(self._on_vertical_scrollbar_slider_released)
        self.verticalScrollBar().valueChanged.connect(self._on_vertical_scrollbar_slider_value_changed)
Ejemplo n.º 40
0
class SEELIGHTTHREAD(QWidget) :
    '''open and plot file : 
        SEE(file='nameFile,path=pathFileName,confpath,confMot)
        Make plot profile ands differents measurements(max,min mean...)
        Can open .spe .SPE .sif .TIFF files
        confpath :usefull if more than 2 SEE object used
        confMot usefull if RSAI motors is read
    '''
    
    newMesurment=QtCore.pyqtSignal(object)
    def __init__(self,parent=None,file=None,path=None,**kwds):
        
        print('LightThread')
        super(SEELIGHTTHREAD, self).__init__()
        self.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5()) # dark style
        self.parent=parent
        version=__version__
        p = pathlib.Path(__file__)
        sepa=os.sep
        self.icon=str(p.parent) + sepa+'icons' +sepa
         ## kwds definition:
        if "confpath"in kwds :
            self.confpath=kwds["confpath"]
            self.conf=QtCore.QSettings(self.confpath, QtCore.QSettings.IniFormat)
        else:
            self.conf=QtCore.QSettings(str(p.parent / 'confVisu.ini'), QtCore.QSettings.IniFormat)
        if "name" in kwds:
            self.name=kwds["name"]
        else:
            self.name="VISU"
        
        if "meas" in kwds:
            self.meas=kwds["meas"]
        else:
           self.meas="on" 
        
        if "confMot" in kwds:
            print('motor accepted')
            if self.meas=="on":
                self.confMot=kwds["confoMot"]
                self.winM=MEAS(confMot=self.confMot,conf=self.conf,name=self.name)
        else :
            if self.meas=="on":
                self.winM=MEAS(self,conf=self.conf,name=self.name)
           
        
        if "aff" in kwds:
            self.aff=kwds["aff"]
        else:
            self.aff="left"
        
        
        if "saveTiff" in kwds:
            self.tiff=kwds["saveTiff"]
        else:       
            self.tiff=True
            
            
        self.nomFichier=''
        self.ite=None
        self.path=path
        self.setWindowTitle('Visualization'+'       v.'+ version)
        self.bloqKeyboard=bool((self.conf.value(self.name+"/bloqKeyboard"))  )  # block cross by keyboard
        self.bloqq=1 # block the cross by click on mouse
        self.setup()
        self.shortcut()
        self.actionButton()
        self.activateWindow()
        self.raise_()
        self.showNormal()
       
        self.setWindowIcon(QIcon(self.icon+'LOA.png'))
        
        def twoD_Gaussian(x,y, amplitude, xo, yo, sigma_x, sigma_y, theta, offset):
           xo = float(xo)
           yo = float(yo)    
           a = (np.cos(theta)**2)/(2*sigma_x**2) + (np.sin(theta)**2)/(2*sigma_y**2)
           b = -(np.sin(2*theta))/(4*sigma_x**2) + (np.sin(2*theta))/(4*sigma_y**2)
           c = (np.sin(theta)**2)/(2*sigma_x**2) + (np.cos(theta)**2)/(2*sigma_y**2)
           return offset + amplitude*np.exp( - (a*((x-xo)**2) + 2*b*(x-xo)*(y-yo) + c*((y-yo)**2)))

        
        if file==None:
            # to have a gaussian picture when we start
            self.dimy=960
            self.dimx=1240
            # Create x and y index
            self.x = np.arange(0,self.dimx)
            self.y = np.arange(0,self.dimy)
            self.y,self.x = np.meshgrid(self.y, self.x)
            
            self.data=twoD_Gaussian(self.x, self.y,450, 800, 600, 40, 40, 0, 10)+(50*np.random.rand(self.dimx,self.dimy)).round() 
        
            #self.data=(50*np.random.rand(self.dimx,self.dimy)).round() + 150
        else:
            if path==None:
                self.path=self.conf.value(self.name+"/path")
            
            self.data=self.OpenF(fileOpen=self.path+'/'+file)
        
        
        self.Display(self.data)
       
        
        
        
        
    def setup(self):
        # definition of all button 
        
        TogOff=self.icon+'Toggle_Off.png' 
        TogOn=self.icon+'Toggle_On.png'
        TogOff=pathlib.Path(TogOff)
        TogOff=pathlib.PurePosixPath(TogOff)
        TogOn=pathlib.Path(TogOn)
        TogOn=pathlib.PurePosixPath(TogOn)
        
        self.setStyleSheet("QCheckBox::indicator{width: 30px;height: 30px;}""QCheckBox::indicator:unchecked { image : url(%s);}""QCheckBox::indicator:checked { image:  url(%s);}""QCheckBox{font :10pt;}" % (TogOff,TogOn) )
        
        vbox1=QVBoxLayout() 
        self.hbox0=QHBoxLayout()
        vbox1.addLayout(self.hbox0)
                
        hbox1=QHBoxLayout()
        self.checkBoxPlot=QCheckBox('CROSS',self)
        self.checkBoxPlot.setChecked(False)
        self.label_CrossValue=QLabel()
        self.label_CrossValue.setStyleSheet("font:13pt")
        hbox1.addWidget(self.checkBoxPlot)
        hbox1.addWidget(self.label_CrossValue)
        
        hbox2=QHBoxLayout()
        self.label_Cross=QLabel()
        #self.label_Cross.setMaximumHeight(20)
        self.label_Cross.setMaximumWidth(170)
        self.label_Cross. setStyleSheet("font:12pt")
        hbox2.addWidget(self.label_Cross)
        
        vbox1.addLayout(hbox1)
        vbox1.addLayout(hbox2)
        
        self.ZoomLabel=QLabel('Zoom')
        vbox1.addWidget(self.ZoomLabel)
        self.checkBoxZoom=QSlider(Qt.Horizontal)
        self.checkBoxZoom.setMaximumWidth(250)
        self.checkBoxZoom.setMinimum(0)
        self.checkBoxZoom.setMaximum(200)
        self.checkBoxZoom.setValue(0)
        vbox1.addWidget(self.checkBoxZoom)
        
        self.checkBoxScale=QCheckBox('Auto Scale',self)
        self.checkBoxScale.setChecked(True)
        self.checkBoxScale.setMaximumWidth(100)
        
        self.checkBoxColor=QCheckBox('Color',self)
        self.checkBoxColor.setChecked(True)
    
        self.checkBoxHist=QCheckBox('Hist',self)
        self.checkBoxHist.setChecked(False)
        self.maxGraphBox=QCheckBox('Max',self)
        hbox3=QHBoxLayout()
        grid_layout = QGridLayout()
        grid_layout.setVerticalSpacing(0)
        grid_layout.setHorizontalSpacing(10)
        grid_layout.addWidget(self.checkBoxScale, 0, 0)
        grid_layout.addWidget(self.checkBoxColor,1,0)
        grid_layout.addWidget(self.checkBoxHist, 0, 1)
        #grid_layout.addWidget(self.checkBoxZoom, 1, 0)
        grid_layout.addWidget(self.maxGraphBox, 1,1)
        
        hbox3.addLayout(grid_layout)
        
        vbox1.addLayout(hbox3)
        
        hbox4=QHBoxLayout()
        
        if self.meas=='on':
            self.MeasButton=QPushButton('Meas.')
            hbox4.addWidget(self.MeasButton)
        
        
        vbox1.addLayout(hbox4)
        
        vbox1.addStretch(1)
        
        self.winImage = pg.GraphicsLayoutWidget()
        #self.winImage.setContentsMargins(1,1,1,1)
        self.winImage.setAspectLocked(True)
        self.winImage.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        #self.winImage.ci.setContentsMargins(1,1,1,1)
        
        vbox2=QVBoxLayout()
        # self.dockImage=QDockWidget(self)
        
        # self.dockImage.setWidget(self.winImage)
        # self.dockImage.setFeatures(QDockWidget.DockWidgetFloatable)
        #vbox2.addWidget(self.dockImage)
        vbox2.addWidget(self.winImage)
        vbox2.setContentsMargins(0,0,0,0)
        
        self.p1=self.winImage.addPlot()
        self.imh=pg.ImageItem()
        self.axeX=self.p1.getAxis('bottom')
        self.axeY=self.p1.getAxis('left')
        self.p1.addItem(self.imh)
        self.p1.setMouseEnabled(x=False,y=False)
        self.p1.setContentsMargins(0,0,0,0)
   
        self.p1.setAspectLocked(True,ratio=1)
        self.p1.showAxis('right',show=False)
        self.p1.showAxis('top',show=False)
        self.p1.showAxis('left',show=True)
        self.p1.showAxis('bottom',show=True)
        
        if self.bloqKeyboard==True:
            self.vLine = pg.InfiniteLine(angle=90, movable=False,pen='r')
            self.hLine = pg.InfiniteLine(angle=0, movable=False,pen='r')
        else:
            self.vLine = pg.InfiniteLine(angle=90, movable=False,pen='y')
            self.hLine = pg.InfiniteLine(angle=0, movable=False,pen='y')

        self.xc=int(self.conf.value(self.name+"/xc"))
        self.yc=int(self.conf.value(self.name+"/yc"))
        self.rx=int(self.conf.value(self.name+"/rx"))
        self.ry=int(self.conf.value(self.name+"/ry"))
        self.vLine.setPos(self.xc)
        self.hLine.setPos(self.yc)
       
        
        self.ro1=pg.EllipseROI([self.xc,self.yc],[self.rx,self.ry],pen='y',movable=False,maxBounds=QtCore.QRectF(0,0,self.rx,self.ry))
        self.ro1.setPos([self.xc-(self.rx/2),self.yc-(self.ry/2)])
      
       
        # text for fwhm on p1
        self.textX = pg.TextItem(angle=-90) 
        self.textY = pg.TextItem()
        
        #histogram
        self.hist = pg.HistogramLUTItem() 
        self.hist.setImageItem(self.imh)
        self.hist.autoHistogramRange()
        self.hist.gradient.loadPreset('flame')
        
        ##  XY  graph
        self.curve2=pg.PlotCurveItem()
        self.curve3=pg.PlotCurveItem()
        
        ## main layout
        hMainLayout=QHBoxLayout()
        if self.aff=='right':
            hMainLayout.addLayout(vbox2)
            hMainLayout.addLayout(vbox1)
        else :
            hMainLayout.addLayout(vbox1)
            hMainLayout.addLayout(vbox2)
            
        hMainLayout.setContentsMargins(1,1,1,1)
        hMainLayout.setSpacing(1)
        hMainLayout.setStretch(10,1)
        
        self.setLayout(hMainLayout)
        self.setContentsMargins(1,1,1,1)
        
        
    def actionButton(self):
        # action of button
        
        
        self.checkBoxColor.stateChanged.connect(self.Color)
        self.checkBoxPlot.stateChanged.connect(self.PlotXY)
        self.ro1.sigRegionChangeFinished.connect(self.roiChanged)
        self.checkBoxZoom.valueChanged.connect(self.Zoom)
        #self.checkBoxZoom.stateChanged.connect(self.Zoom)
       
        self.checkBoxHist.stateChanged.connect(self.HIST)
        self.maxGraphBox.stateChanged.connect(self.Coupe)  
        if self.meas=='on':
            self.MeasButton.clicked.connect(self.Measurement,QtCore.Qt.DirectConnection) # send data to widget measurement
        
        if self.parent is not None : # reveceive data display it
            self.parent.dataSignal.connect(self.Display)#,QtCore.Qt.DirectConnection)  
        
        
    def shortcut(self):
        # keyboard shortcut
        
        self.shortcutPu=QShortcut(QtGui.QKeySequence("+"),self)
        self.shortcutPu.activated.connect(self.paletteup)
        self.shortcutPu.setContext(Qt.ShortcutContext(3))
        #3: The shortcut is active when its parent widget, or any of its children has focus. default O The shortcut is active when its parent widget has focus.
        self.shortcutPd=QtGui.QShortcut(QtGui.QKeySequence("-"),self)
        self.shortcutPd.activated.connect(self.palettedown)
        self.shortcutPd.setContext(Qt.ShortcutContext(3))
        
        self.shortcutOpen=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+o"),self)
        self.shortcutOpen.activated.connect(self.OpenF)
        self.shortcutOpen.setContext(Qt.ShortcutContext(3))
        
        self.shortcutSave=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+s"),self)
        self.shortcutSave.activated.connect(self.SaveF)
        self.shortcutSave.setContext(Qt.ShortcutContext(3))
        
        
        if self.meas=='on':
            self.shortcutMeas=QtGui.QShortcut(QtGui.QKeySequence('Ctrl+m'),self)
            self.shortcutMeas.activated.connect(self.Measurement)
            self.shortcutMeas.setContext(Qt.ShortcutContext(3))
        
        
        self.shortcutBloq=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+b"),self)
        self.shortcutBloq.activated.connect(self.bloquer)
        self.shortcutBloq.setContext(Qt.ShortcutContext(3))
        
        self.shortcutDebloq=QtGui.QShortcut(QtGui.QKeySequence("Ctrl+d"),self)
        self.shortcutDebloq.activated.connect(self.debloquer)
        self.shortcutDebloq.setContext(Qt.ShortcutContext(3))
        
        # mousse action:
        self.proxy=pg.SignalProxy(self.p1.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
        self.p1.scene().sigMouseClicked.connect(self.mouseClick)
        self.vb=self.p1.vb
        
        
    
        
    
     
        
        
    def Measurement(self) :
        # show widget for measurement on all image or ROI  (max, min mean ...)
        if self.ite=='rect':
            self.RectChanged()
            self.winM.setFile(self.nomFichier)
            self.open_widget(self.winM)
            self.winM.Display(self.cut)
            
        if self.ite=='cercle':
            self.CercChanged()
            self.winM.setFile(self.nomFichier)
            self.open_widget(self.winM)
            self.winM.Display(self.cut)
        
        # if self.ite=='line':
        #     self.LigneChanged()
        #     self.winM.setFile(self.nomFichier)
        #     self.open_widget(self.winM)
        #     self.winM.Display(self.cut)
        if self.meas=="on":
            if self.ite==None:
                self.winM.setFile(self.nomFichier)
                self.open_widget(self.winM)
                self.winM.Display(self.data)
    

        
        
    def Display(self,data):
        #  display the data and refresh all the calculated things and plots
        self.data=data
        self.dimy=np.shape(self.data)[1]
        self.dimx=np.shape(self.data)[0]
        self.p1.setXRange(0,self.dimx)
        self.p1.setYRange(0,self.dimy)
        self.p1.setAspectLocked(True,ratio=1)
        
            
        
        if self.checkBoxScale.isChecked()==1: # autoscale on
           self.imh.setImage(self.data.astype(float),autoLevels=True,autoDownsample=True)
        else :
            self.imh.setImage(self.data.astype(float),autoLevels=False,autoDownsample=True)
        
         

        if self.meas=="on" :       
            
            if self.winM.isWinOpen==True:
                self.newMesurment.emit(self.data)#  measurement update
                
                
                #self.Measurement()
                
        
        
    
        self.Zoom() # update zoom
    
    def mouseClick(self): # block the cross if mousse button clicked
        
        if self.bloqq==1:
            self.bloqq=0
            
        else :
            self.bloqq=1
            self.conf.setValue(self.name+"/xc",int(self.xc)) # save cross postion in ini file
            self.conf.setValue(self.name+"/yc",int(self.yc))
            
            
    def mouseMoved(self,evt):

        ## the cross mouve with the mousse mvt
        if self.bloqKeyboard==False :  #mouse not  blocked by  keyboard
            if self.bloqq==0: # mouse not  blocked by mouse  click
                
                pos = evt[0]  ## using signal proxy turns original arguments into a tuple
                if self.p1.sceneBoundingRect().contains(pos):
                    
                    mousePoint = self.vb.mapSceneToView(pos)
                    self.xMouse = (mousePoint.x())
                    self.yMouse= (mousePoint.y())
                    if ((self.xMouse>0 and self.xMouse<self.dimx-1) and (self.yMouse>0 and self.yMouse<self.dimy-1) ):
                            self.xc = self.xMouse
                            self.yc= self.yMouse  
                            self.vLine.setPos(self.xc)
                            self.hLine.setPos(self.yc) # the cross move only in the graph    
                            #self.ro1.setPos([self.xc-(self.rx/2),self.yc-(self.ry/2)])
                            self.PlotXY()
                
    def fwhm(self,x, y, order=3):
        """
            Determine full-with-half-maximum of a peaked set of points, x and y.
    
        """
        y=gaussian_filter(y,5) # filtre for reducing noise
        half_max = np.amax(y)/2.0
        s = splrep(x, y - half_max,k=order) # F
        roots = sproot(s) # Given the knots .
        if len(roots) > 2:
            pass
           
        elif len(roots) < 2:
            pass
        else:
            return np.around(abs(roots[1] - roots[0]),decimals=2)
        
        
    def Coupe(self):
        # make  plot profile on cross
        
        
        if self.maxGraphBox.isChecked()==True and self.bloqKeyboard==False: # find and fix the cross on the maximum of the image
            
            dataF=gaussian_filter(self.data,5)
            (self.xc,self.yc)=pylab.unravel_index(dataF.argmax(),self.data.shape) #take the max ndimage.measurements.center_of_mass(dataF)#
            self.vLine.setPos(self.xc)
            self.hLine.setPos(self.yc)
        
            
        dataCross=self.data[int(self.xc),int(self.yc)] 
        coupeX=self.data[int(self.xc),:]
        coupeY=self.data[:,int(self.yc)]
        xxx=np.arange(0,int(self.dimx),1)#
        yyy=np.arange(0,int(self.dimy),1)#
        coupeXMax=np.max(coupeX)
        coupeYMax=np.max(coupeY)
        
        
        if coupeXMax==0: # avoid zero
            coupeXMax=1
        
        if coupeYMax==0:
            coupeYMax=1
            
        
        self.label_Cross.setText('x='+ str(int(self.xc)) + ' y=' + str(int(self.yc)) )
            
        dataCross=round(dataCross,3) # take data  value  on the cross
        self.label_CrossValue.setText(' v.=' + str(dataCross))
        
        
        coupeXnorm=(self.data.shape[0]/10)*(coupeX/coupeXMax) # normalize the curves
        self.curve2.setData(20+self.xminR+coupeXnorm,yyy,clear=True)

          
        coupeYnorm=(self.data.shape[1]/10)*(coupeY/coupeYMax)
        self.curve3.setData(xxx,20+self.yminR+coupeYnorm,clear=True)
        
    
 
    def PlotXY(self): # plot curves on the  graph
        
        if self.checkBoxPlot.isChecked()==1:
            
            self.p1.addItem(self.vLine, ignoreBounds=False)
            self.p1.addItem(self.hLine, ignoreBounds=False)
            self.p1.addItem(self.curve2)
            self.p1.addItem(self.curve3)
            self.p1.showAxis('left',show=True)
            self.p1.showAxis('bottom',show=True)
            self.p1.addItem(self.textX)
            self.p1.addItem(self.textY)
            self.Coupe()
        else:
            self.p1.removeItem(self.vLine)
            self.p1.removeItem(self.hLine)
            self.p1.removeItem(self.curve2)
            self.p1.removeItem(self.curve3)
            self.p1.removeItem(self.textX)
            self.p1.removeItem(self.textY)
            self.p1.showAxis('left',show=False)
            self.p1.showAxis('bottom',show=False)
            self.p1.removeItem(self.textX)
            self.p1.removeItem(self.textY)
            
    def paletteup(self):
        # change the color scale
        levels=self.imh.getLevels()
        if levels[0]==None:
            xmax =self.data.max()
            xmin=self.data.min()
        else :
            xmax=levels[1]
            xmin=levels[0]
            
        self.imh.setLevels([xmin, xmax-(xmax- xmin) / 10])
        #hist.setImageItem(imh,clear=True)
        self.hist.setHistogramRange(xmin,xmax)

    def palettedown(self):
        
        levels=self.imh.getLevels()
        if levels[0]==None:
            xmax=self.data.max()
            xmin=self.data.min()
        else :
            xmax=levels[1]
            xmin=levels[0]
            
        self.imh.setLevels([xmin, xmax+ (xmax- xmin) / 10])
        #hist.setImageItem(imh,clear=True)
        self.hist.setHistogramRange(xmin,xmax)
    
    def Color(self):
        """ image in colour/n&b
        """
        if self.checkBoxColor.isChecked()==1:
            self.hist.gradient.loadPreset('flame')
        else:
            self.hist.gradient.loadPreset('grey')
            
    def Zoom(self):
        
        """Zoom function
        """
        self.zo=self.checkBoxZoom.value()
        
        # if self.checkBoxPlot.isChecked()==0:
        #     self.xc=self.dimx/2
        #     self.yc=self.dimy/2
        
       
        if self.zo<=2:
            self.zo=0
            self.p1.setXRange(0,self.dimx)
            self.p1.setYRange(0,self.dimy)
            self.xminR=0
            self.yminR=0
            self.xmaxR=self.dimx
            self.ymaxR=self.dimy
        
        else:
            
            self.xminR=self.xc-(self.dimx-self.xc)*(1-self.zo/200)
            self.xmaxR=self.xc+(self.dimx-self.xc)*(1-self.zo/200)
            
            
            self.yminR=self.yc-(self.dimy-self.yc)*(1-self.zo/200)
            self.ymaxR=self.yc+(self.dimy-self.yc)*(1-self.zo/200)
            
        
            if self.xminR<0:
                self.xminR=0
            if self.xmaxR>self.dimx:
                self.xmaxR=self.dimx   
                
            if self.yminR<0:
                self.yminR=0
            if self.ymaxR>self.dimy:
                self.ymaxR=self.dimy 
            
            
            self.p1.setXRange(self.xminR,self.xmaxR)
            self.p1.setYRange(self.yminR,self.ymaxR)
            
        self.Coupe()
            
    def roiChanged(self):
        
        self.rx=self.ro1.size()[0]
        self.ry=self.ro1.size()[1]
        self.conf.setValue(self.name+"/rx",int(self.rx))
        self.conf.setValue(self.name+"/ry",int(self.ry))
      
        
    def bloquer(self): # block the cross
        
        self.bloqKeyboard=bool(True)
        self.conf.setValue(self.name+"/xc",int(self.xc))# save cross postion in ini file
        self.conf.setValue(self.name+"/yc",int(self.yc))
        self.conf.setValue(self.name+"/bloqKeyboard",bool(self.bloqKeyboard))
        self.vLine.setPen('r')
        self.hLine.setPen('r')
        
    def debloquer(self): # unblock the cross
        
        self.bloqKeyboard=bool(False)
        self.vLine.setPen('y')
        self.hLine.setPen('y')
        self.conf.setValue(self.name+"/bloqKeyboard",bool(self.bloqKeyboard))
        
        
        
    def HIST(self):
        #show histogramm
        if self.checkBoxHist.isChecked()==1:
            self.winImage.addItem(self.hist)
        else:
            self.winImage.removeItem(self.hist)
    
        
    def OpenF(self,fileOpen=False):
        #open file in txt spe TIFF sif  format
        fileOpen=fileOpen
        print(fileOpen)
        print('open')
        if fileOpen==False:
            print('ici')
            chemin=self.conf.value(self.name+"/path")
            fname=QtGui.QFileDialog.getOpenFileName(self,"Open File",chemin,"Images (*.txt *.spe *.TIFF *.sif *.tif);;Text File(*.txt);;Ropper File (*.SPE);;Andor File(*.sif);; TIFF file(*.TIFF)")
            fichier=fname[0]
        else:
            fichier=str(fileOpen)
            
        ext=os.path.splitext(fichier)[1]
        
        if ext=='.txt': # text file
            data=np.loadtxt(str(fichier))
        elif ext=='.spe' or ext=='.SPE': # SPE file
            dataSPE=SpeFile(fichier)
            data1=dataSPE.data[0]#.transpose() # first frame
            data=data1#np.flipud(data1)
        elif ext=='.TIFF' or ext=='.tif':# tiff File
            dat=Image.open(fichier)
            data=np.array(dat)
        elif ext=='.sif': 
            sifop=SifFile()
            im=sifop.openA(fichier)
            data=np.rot90(im,3)
#            self.data=self.data[250:495,:]
        else :
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Wrong file format !")
            msg.setInformativeText("The format of the file must be : .SPE  .TIFF .sif or .txt ")
            msg.setWindowTitle("Warning ...")
            msg.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
            msg.exec_()
            
        chemin=os.path.dirname(fichier)
        self.conf.setValue(self.name+"/path",chemin)
        self.conf.setValue(self.name+"/lastFichier",os.path.split(fichier)[1])
        self.fileName.setText(os.path.split(fichier)[1])
        self.nomFichier=os.path.split(fichier)[1]
    
        self.newDataReceived(data)
    

    def SaveF (self):
        # save data  in TIFF 
        
        if self.tiff==True: 
            fname=QtGui.QFileDialog.getSaveFileName(self,"Save data as TIFF",self.path)
            self.path=os.path.dirname(str(fname[0]))
            fichier=fname[0]
        
            ext=os.path.splitext(fichier)[1]
            #print(ext)
            print(fichier,' is saved')
            self.conf.setValue(self.name+"/path",self.path)
            time.sleep(0.1)
            img_PIL = Image.fromarray(self.data)

            img_PIL.save(str(fname[0])+'.TIFF',format='TIFF')
            
            
        else :
            fname=QtGui.QFileDialog.getSaveFileName(self,"Save data as txt",self.path)
            self.path=os.path.dirname(str(fname[0]))
            fichier=fname[0]
        
            ext=os.path.splitext(fichier)[1]
            #print(ext)
            print(fichier,' is saved')
            self.conf.setValue(self.name+"/path",self.path)
            time.sleep(0.1)
            np.savetxt(str(fichier)+'.txt',self.data)
            

  
    def newDataReceived(self,data):
        # Do display and save origin data when new data is  sent to  visu
        self.data=data
        self.dimy=np.shape(self.data)[1]
        self.dimx=np.shape(self.data)[0]
        #self.Display(self.data)
        self.dataSignal.emit(self.data)
       
    def open_widget(self,fene):
        """ open new widget 
        """

        if fene.isWinOpen==False:
            fene.setup
            fene.isWinOpen=True
            
            #fene.Display(self.data)
            fene.show()
        else:
            #fene.activateWindow()
            fene.raise_()
            fene.showNormal()


    def closeEvent(self,event):
        # when the window is closed
       
        if self.winM.isWinOpen==True:
            self.winM.close()
Ejemplo n.º 41
0
class SearchWidget(QFrame):
    """Widget, appeared, when Ctrl+F pressed.
    Has different forms for different search modes
    """

    Normal = 'normal'
    Good = 'good'
    Bad = 'bad'
    Incorrect = 'incorrect'

    visibilityChanged = pyqtSignal(bool)
    """
    visibilityChanged(visible)

    **Signal** emitted, when widget has been shown or hidden
    """  # pylint: disable=W0105

    searchInDirectoryStartPressed = pyqtSignal(type(re.compile('')), list, str)
    """
    searchInDirectoryStartPressed(regEx, mask, path)

    **Signal** emitted, when 'search in directory' button had been pressed
    """  # pylint: disable=W0105

    searchInDirectoryStopPressed = pyqtSignal()
    """
    searchInDirectoryStopPressed()

    **Signal** emitted, when 'stop search in directory' button had been pressed
    """  # pylint: disable=W0105

    replaceCheckedStartPressed = pyqtSignal(str)
    """
    replaceCheckedStartPressed(replText)

    **Signal** emitted, when 'replace checked' button had been pressed
    """  # pylint: disable=W0105

    replaceCheckedStopPressed = pyqtSignal()
    """
    replaceCheckedStartPressed()

    **Signal** emitted, when 'stop replacing checked' button had been pressed
    """  # pylint: disable=W0105

    searchRegExpChanged = pyqtSignal(type(re.compile('')))
    """
    searchRegExpValidStateChanged(regEx)

    **Signal** emitted, when search regexp has been changed.
    If reg exp is invalid - regEx object contains empty pattern
    """  # pylint: disable=W0105

    searchNext = pyqtSignal()
    """
    searchNext()

    **Signal** emitted, when 'Search Next' had been pressed
    """  # pylint: disable=W0105

    searchPrevious = pyqtSignal()
    """
    searchPrevious()

    **Signal** emitted, when 'Search Previous' had been pressed
    """  # pylint: disable=W0105

    replaceFileOne = pyqtSignal(str)
    """
    replaceFileOne(replText)

    **Signal** emitted, when 'Replace' had been pressed
    """  # pylint: disable=W0105

    replaceFileAll = pyqtSignal(str)
    """
    replaceFileAll(replText)

    **Signal** emitted, when 'Replace All' had been pressed
    """  # pylint: disable=W0105

    def __init__(self, plugin):
        QFrame.__init__(self, core.workspace())
        self._mode = None
        self.plugin = plugin
        uic.loadUi(os.path.join(os.path.dirname(__file__), 'SearchWidget.ui'),
                   self)

        self.cbSearch.setCompleter(None)
        self.cbReplace.setCompleter(None)
        self.cbMask.setCompleter(None)

        self.fsModel = QDirModel(self.cbPath.lineEdit())
        self.fsModel.setFilter(QDir.AllDirs | QDir.NoDotAndDotDot)

        self.cbPath.lineEdit().setCompleter(
            QCompleter(self.fsModel, self.cbPath.lineEdit()))
        self._pathBackspaceShortcut = QShortcut(QKeySequence("Ctrl+Backspace"),
                                                self.cbPath,
                                                self._onPathBackspace)
        self._pathBackspaceShortcut.setContext(Qt.WidgetWithChildrenShortcut)

        # TODO QDirModel is deprecated but QCompleter does not yet handle
        # QFileSystemodel - please update when possible."""
        self.cbSearch.setCompleter(None)
        self.pbSearchStop.setVisible(False)
        self.pbReplaceCheckedStop.setVisible(False)

        self._progress = QProgressBar(self)
        self._progress.setAlignment(Qt.AlignCenter)
        self._progress.setToolTip(self.tr("Search in progress..."))
        self._progress.setMaximumSize(QSize(80, 16))
        core.mainWindow().statusBar().insertPermanentWidget(1, self._progress)
        self._progress.setVisible(False)

        # cd up action
        self.tbCdUp = QToolButton(self.cbPath.lineEdit())
        self.tbCdUp.setIcon(QIcon(":/enkiicons/go-up.png"))
        self.tbCdUp.setCursor(Qt.ArrowCursor)
        self.tbCdUp.installEventFilter(self)  # for drawing button

        self.cbSearch.installEventFilter(
            self)  # for catching Tab and Shift+Tab
        self.cbReplace.installEventFilter(
            self)  # for catching Tab and Shift+Tab
        self.cbPath.installEventFilter(self)  # for catching Tab and Shift+Tab
        self.cbMask.installEventFilter(self)  # for catching Tab and Shift+Tab

        self._closeShortcut = QShortcut(QKeySequence("Esc"), self)
        self._closeShortcut.setContext(Qt.WidgetWithChildrenShortcut)
        self._closeShortcut.activated.connect(self.hide)

        # connections
        self.cbSearch.lineEdit().textChanged.connect(
            self._onSearchRegExpChanged)

        self.cbSearch.lineEdit().returnPressed.connect(self._onReturnPressed)
        self.cbReplace.lineEdit().returnPressed.connect(self._onReturnPressed)
        self.cbPath.lineEdit().returnPressed.connect(self._onReturnPressed)
        self.cbMask.lineEdit().returnPressed.connect(self._onReturnPressed)

        self.cbRegularExpression.stateChanged.connect(
            self._onSearchRegExpChanged)
        self.cbCaseSensitive.stateChanged.connect(self._onSearchRegExpChanged)
        self.cbWholeWord.stateChanged.connect(self._onSearchRegExpChanged)

        self.tbCdUp.clicked.connect(self._onCdUpPressed)

        self.pbNext.pressed.connect(self.searchNext)
        self.pbPrevious.pressed.connect(self.searchPrevious)
        self.pbSearchStop.pressed.connect(self.searchInDirectoryStopPressed)
        self.pbReplaceCheckedStop.pressed.connect(
            self.replaceCheckedStopPressed)

        core.mainWindow().hideAllWindows.connect(self.hide)
        core.workspace().escPressed.connect(self.hide)

        core.workspace().currentDocumentChanged.connect(
            lambda old, new: self.setVisible(self.isVisible() and new is
                                             not None))

    def show(self):
        """Reimplemented function. Sends signal
        """
        super(SearchWidget, self).show()
        self.visibilityChanged.emit(self.isVisible())

    def hide(self):
        """Reimplemented function.
        Sends signal, returns focus to workspace
        """
        super(SearchWidget, self).hide()
        core.workspace().focusCurrentDocument()
        self.visibilityChanged.emit(self.isVisible())

    def setVisible(self, visible):
        """Reimplemented function. Sends signal
        """
        super(SearchWidget, self).setVisible(visible)
        self.visibilityChanged.emit(self.isVisible())

    def _regExEscape(self, text):
        """Improved version of re.escape()
        Doesn't escape space, comma, underscore.
        Escapes \n and \t
        """
        text = re.escape(text)
        # re.escape escapes space, comma, underscore, but, it is not necessary and makes text not readable
        for symbol in (' ,_=\'"/:@#%&'):
            text = text.replace('\\' + symbol, symbol)

        text = text.replace('\\\n', '\\n')
        text = text.replace('\\\t', '\\t')

        return text

    def _makeEscapeSeqsVisible(self, text):
        """Replace invisible \n and \t with escape sequences
        """
        text = text.replace('\\', '\\\\')
        text = text.replace('\t', '\\t')
        text = text.replace('\n', '\\n')
        return text

    def setMode(self, mode):
        """Change search mode.
        i.e. from "Search file" to "Replace directory"
        """
        if self._mode == mode and self.isVisible():
            if core.workspace().currentDocument() is not None and \
               not core.workspace().currentDocument().hasFocus():
                self.cbSearch.lineEdit().selectAll()
                self.cbSearch.setFocus()

        self._mode = mode

        # Set Search and Replace text
        document = core.workspace().currentDocument()
        if document is not None and \
           document.hasFocus() and \
           document.qutepart.selectedText:
            searchText = document.qutepart.selectedText

            self.cbReplace.setEditText(self._makeEscapeSeqsVisible(searchText))

            if self.cbRegularExpression.checkState() == Qt.Checked:
                searchText = self._regExEscape(searchText)
            self.cbSearch.setEditText(searchText)

        if not self.cbReplace.lineEdit().text() and \
                self.cbSearch.lineEdit().text() and \
                not self.cbRegularExpression.checkState() == Qt.Checked:
            replaceText = self.cbSearch.lineEdit().text().replace('\\', '\\\\')
            self.cbReplace.setEditText(replaceText)

        # Move focus to Search edit
        self.cbSearch.setFocus()
        self.cbSearch.lineEdit().selectAll()

        # Set search path
        if mode & MODE_FLAG_DIRECTORY and \
           not (self.isVisible() and self.cbPath.isVisible()):
            try:
                searchPath = os.path.abspath(str(os.path.curdir))
            except OSError:  # current directory might have been deleted
                pass
            else:
                self.cbPath.setEditText(searchPath)

        # Set widgets visibility flag according to state
        widgets = (self.wSearch, self.pbPrevious, self.pbNext, self.pbSearch,
                   self.wReplace, self.wPath, self.pbReplace,
                   self.pbReplaceAll, self.pbReplaceChecked, self.wOptions,
                   self.wMask)
        #                         wSear  pbPrev pbNext pbSear wRepl  wPath  pbRep  pbRAll pbRCHK wOpti wMask
        visible = \
            {MODE_SEARCH:               (1,     1,     1,     0,     0,     0,     0,     1,     1,    1,    0,),
             MODE_REPLACE:               (1,     1,     1,     0,     1,     0,     1,     1,     0,    1,    0,),
             MODE_SEARCH_DIRECTORY:      (1,     0,     0,     1,     0,     1,     0,     0,     0,    1,    1,),
             MODE_REPLACE_DIRECTORY:     (1,     0,     0,     1,     1,     1,     0,     0,     1,    1,    1,),
             MODE_SEARCH_OPENED_FILES:   (1,     0,     0,     1,     0,     0,     0,     0,     0,    1,    1,),
             MODE_REPLACE_OPENED_FILES:  (1,     0,     0,     1,     1,     0,     0,     0,     1,    1,    1,)}

        for i, widget in enumerate(widgets):
            widget.setVisible(visible[mode][i])

        # Search next button text
        if mode == MODE_REPLACE:
            self.pbNext.setText('Next')
        else:
            self.pbNext.setText('Next↵')

        # Finaly show all with valid size
        self.show()  # show before updating widgets and labels
        self._updateLabels()
        self._updateWidgets()

    def eventFilter(self, object_, event):
        """ Event filter for mode switch tool button
        Draws icons in the search and path lineEdits
        """
        if event.type(
        ) == QEvent.Paint and object_ is self.tbCdUp:  # draw CdUp button in search path QLineEdit
            toolButton = object_
            lineEdit = self.cbPath.lineEdit()
            lineEdit.setContentsMargins(lineEdit.height(), 0, 0, 0)

            height = lineEdit.height()
            availableRect = QRect(0, 0, height, height)

            if toolButton.rect() != availableRect:
                toolButton.setGeometry(availableRect)

            painter = QPainter(toolButton)
            toolButton.icon().paint(painter, availableRect)

            return True

        elif event.type(
        ) == QEvent.KeyPress:  # Tab and Shift+Tab in QLineEdits

            if event.key() == Qt.Key_Tab:
                self._moveFocus(1)
                return True
            elif event.key() == Qt.Key_Backtab:
                self._moveFocus(-1)
                return True

        return QFrame.eventFilter(self, object_, event)

    def _onReturnPressed(self):
        """Return or Enter pressed on widget.
        Search next or Replace next
        """
        if self.pbReplace.isVisible():
            self.pbReplace.click()
        elif self.pbNext.isVisible():
            self.pbNext.click()
        elif self.pbSearch.isVisible():
            self.pbSearch.click()
        elif self.pbSearchStop.isVisible():
            self.pbSearchStop.click()

    def _onPathBackspace(self):
        """Ctrl+Backspace pressed on path.
        Remove 1 path level.
        Default behavior would be to remove one word on Linux or all on Windows
        """
        path = self.cbPath.currentText()
        if path.endswith('/') or \
           path.endswith('\\'):
            path = path[:-1]

        head, tail = os.path.split(path)
        if head and \
           head != path:
            if not head.endswith(os.sep):
                head += os.sep
            self.cbPath.lineEdit().setText(head)

    def _moveFocus(self, step):
        """Move focus forward or backward according to step.
        Standard Qt Keyboard focus algorithm doesn't allow circular navigation
        """
        allFocusableWidgets = (self.cbSearch, self.cbReplace, self.cbPath,
                               self.cbMask)
        visibleWidgets = [
            widget for widget in allFocusableWidgets if widget.isVisible()
        ]

        try:
            focusedIndex = visibleWidgets.index(QApplication.focusWidget())
        except ValueError:
            print('Invalid focused widget in Search Widget', file=sys.stderr)
            return

        nextFocusedIndex = (focusedIndex + step) % len(visibleWidgets)

        visibleWidgets[nextFocusedIndex].setFocus()
        visibleWidgets[nextFocusedIndex].lineEdit().selectAll()

    def _updateLabels(self):
        """Update 'Search' 'Replace' 'Path' labels geometry
        """
        width = 0

        if self.lSearch.isVisible():
            width = max(width, self.lSearch.minimumSizeHint().width())

        if self.lReplace.isVisible():
            width = max(width, self.lReplace.minimumSizeHint().width())

        if self.lPath.isVisible():
            width = max(width, self.lPath.minimumSizeHint().width())

        self.lSearch.setMinimumWidth(width)
        self.lReplace.setMinimumWidth(width)
        self.lPath.setMinimumWidth(width)

    def _updateWidgets(self):
        """Update geometry of widgets with buttons
        """
        width = 0

        if self.wSearchRight.isVisible():
            width = max(width, self.wSearchRight.minimumSizeHint().width())

        if self.wReplaceRight.isVisible():
            width = max(width, self.wReplaceRight.minimumSizeHint().width())

        if self.wPathRight.isVisible():
            width = max(width, self.wPathRight.minimumSizeHint().width())

        self.wSearchRight.setMinimumWidth(width)
        self.wReplaceRight.setMinimumWidth(width)
        self.wPathRight.setMinimumWidth(width)

    def updateComboBoxes(self):
        """Update comboboxes with last used texts
        """
        searchText = self.cbSearch.currentText()
        replaceText = self.cbReplace.currentText()
        maskText = self.cbMask.currentText()

        # search
        if searchText:
            index = self.cbSearch.findText(searchText)

            if index == -1:
                self.cbSearch.addItem(searchText)

        # replace
        if replaceText:
            index = self.cbReplace.findText(replaceText)

            if index == -1:
                self.cbReplace.addItem(replaceText)

        # mask
        if maskText:
            index = self.cbMask.findText(maskText)

            if index == -1:
                self.cbMask.addItem(maskText)

    def _searchPatternTextAndFlags(self):
        """Get search pattern and flags
        """
        pattern = self.cbSearch.currentText()

        pattern = pattern.replace(
            '\u2029',
            '\n')  # replace unicode paragraph separator with habitual \n

        if not self.cbRegularExpression.checkState() == Qt.Checked:
            pattern = re.escape(pattern)

        if self.cbWholeWord.checkState() == Qt.Checked:
            pattern = r'\b' + pattern + r'\b'

        flags = 0
        if not self.cbCaseSensitive.checkState() == Qt.Checked:
            flags = re.IGNORECASE
        return pattern, flags

    def getRegExp(self):
        """Read search parameters from controls and present it as a regular expression
        """
        pattern, flags = self._searchPatternTextAndFlags()
        return re.compile(pattern, flags)

    def isSearchRegExpValid(self):
        """Try to compile search pattern to check if it is valid
        Returns bool result and text error
        """
        pattern, flags = self._searchPatternTextAndFlags()
        try:
            re.compile(pattern, flags)
        except re.error as ex:
            return False, str(ex)

        return True, None

    def _getSearchMask(self):
        """Get search mask as list of patterns
        """
        mask = [s.strip() for s in self.cbMask.currentText().split(' ')]
        # remove empty
        mask = [_f for _f in mask if _f]
        return mask

    def setState(self, state):
        """Change line edit color according to search result
        """
        widget = self.cbSearch.lineEdit()

        color = {
            SearchWidget.Normal:
            QApplication.instance().palette().color(QPalette.Base),
            SearchWidget.Good:
            QColor(Qt.green),
            SearchWidget.Bad:
            QColor(Qt.red),
            SearchWidget.Incorrect:
            QColor(Qt.darkYellow)
        }

        stateColor = color[state]
        if state != SearchWidget.Normal:
            stateColor.setAlpha(100)

        pal = widget.palette()
        pal.setColor(widget.backgroundRole(), stateColor)
        widget.setPalette(pal)

    def setSearchInProgress(self, inProgress):
        """Search thread started or stopped
        """
        self.pbSearchStop.setVisible(inProgress)
        self.pbSearch.setVisible(not inProgress)
        self._updateWidgets()
        self._progress.setVisible(inProgress)

    def onSearchProgressChanged(self, value, total):
        """Signal from the thread, progress changed
        """
        self._progress.setValue(value)
        self._progress.setMaximum(total)

    def setReplaceInProgress(self, inProgress):
        """Replace thread started or stopped
        """
        self.pbReplaceCheckedStop.setVisible(inProgress)
        self.pbReplaceChecked.setVisible(not inProgress)
        self._updateWidgets()

    def setSearchInFileActionsEnabled(self, enabled):
        """Set enabled state for Next, Prev, Replace, ReplaceAll
        """
        for button in (self.pbNext, self.pbPrevious, self.pbReplace,
                       self.pbReplaceAll):
            button.setEnabled(enabled)

    def _onSearchRegExpChanged(self):
        """User edited search text or checked/unchecked checkboxes
        """
        valid, error = self.isSearchRegExpValid()
        if valid:
            self.setState(self.Normal)
            core.mainWindow().statusBar().clearMessage()
            self.pbSearch.setEnabled(len(self.getRegExp().pattern) > 0)
        else:
            core.mainWindow().statusBar().showMessage(error, 3000)
            self.setState(self.Incorrect)
            self.pbSearch.setEnabled(False)
            self.searchRegExpChanged.emit(re.compile(''))
            return

        self.searchRegExpChanged.emit(self.getRegExp())

    def _onCdUpPressed(self):
        """User pressed "Up" button, need to remove one level from search path
        """
        text = self.cbPath.currentText()
        if not os.path.exists(text):
            return

        editText = os.path.normpath(os.path.join(text, os.path.pardir))
        self.cbPath.setEditText(editText)

    def on_pbSearch_pressed(self):
        """Handler of click on "Search" button (for search in directory)
        """
        self.setState(SearchWidget.Normal)

        self.searchInDirectoryStartPressed.emit(self.getRegExp(),
                                                self._getSearchMask(),
                                                self.cbPath.currentText())

    def on_pbReplace_pressed(self):
        """Handler of click on "Replace" (in file) button
        """
        self.replaceFileOne.emit(self.cbReplace.currentText())

    def on_pbReplaceAll_pressed(self):
        """Handler of click on "Replace all" (in file) button
        """
        self.replaceFileAll.emit(self.cbReplace.currentText())

    def on_pbReplaceChecked_pressed(self):
        """Handler of click on "Replace checked" (in directory) button
        """
        self.replaceCheckedStartPressed.emit(self.cbReplace.currentText())

    def on_pbBrowse_pressed(self):
        """Handler of click on "Browse" button. Explores FS for search directory path
        """
        path = QFileDialog.getExistingDirectory(self, self.tr("Search path"),
                                                self.cbPath.currentText())

        if path:
            self.cbPath.setEditText(path)