Ejemplo n.º 1
0
    def initGui(self):

        for keyseq, slot in (
            (Qt.CTRL + Qt.ALT + Qt.Key_K, self.__create_group),
            (Qt.CTRL + Qt.ALT + Qt.Key_S, self.__select_next_group),
            (Qt.CTRL + Qt.ALT + Qt.Key_N, self.__next_section),
            (Qt.CTRL + Qt.ALT + Qt.Key_B, self.__previous_section),
        ):

            short = QShortcut(QKeySequence(keyseq), self.__iface.mainWindow())
            short.setContext(Qt.ApplicationShortcut)
            short.activated.connect(slot)
            self.__shortcuts.append(short)

        self.__menu = QMenu("Albion")
        self.__menu.aboutToShow.connect(self.__create_menu_entries)
        self.__iface.mainWindow().menuBar().addMenu(self.__menu)

        self.__toolbar = QToolBar("Albion")
        self.__iface.addToolBar(self.__toolbar)

        self.__toolbar.addAction(icon("log_strati.svg"),
                                 "stratigraphic log").triggered.connect(
                                     self.__log_strati_clicked)

        self.__toolbar.addWidget(self.__current_graph)
        self.__current_graph.currentIndexChanged[unicode].connect(
            self.__current_graph_changed)

        self.__toolbar.addWidget(self.__current_section)
        self.__current_section.currentIndexChanged[unicode].connect(
            self.__current_section_changed)

        self.__toolbar.addAction(
            icon("previous_line.svg"),
            "previous section  (Ctrl+Alt+b)").triggered.connect(
                self.__previous_section)

        self.__toolbar.addAction(
            icon("next_line.svg"),
            "next section (Ctrl+Alt+n)").triggered.connect(self.__next_section)

        self.__toolbar.addAction(icon("line_from_selected.svg"),
                                 "create temporary section").triggered.connect(
                                     self.__section_from_selection)

        self.__viewer3d = QDockWidget("3D")
        self.__viewer3d.setWidget(Viewer3d())
        self.__iface.addDockWidget(Qt.LeftDockWidgetArea, self.__viewer3d)
        self.__iface.mainWindow().tabifyDockWidget(
            self.__iface.mainWindow().findChild(QDockWidget, "Layers"),
            self.__viewer3d)

        self.__viewer3d_ctrl = QToolBar("3D controls")
        self.__viewer3d_ctrl.addWidget(ViewerControls(
            self.__viewer3d.widget()))
        self.__iface.addToolBar(self.__viewer3d_ctrl)

        QgsProject.instance().readProject.connect(self.__qgis__project__loaded)
        self.__qgis__project__loaded()  # case of reload
Ejemplo n.º 2
0
 def _shortcutHelper(self, keySequence, group, description, parent, function, context = None, enabled = None):
     shortcut = QShortcut(QKeySequence(keySequence), parent, member=function, ambiguousMember=function)
     if context != None:
         shortcut.setContext(context)
     if enabled != None:
         shortcut.setEnabled(True)
     return shortcut, group, description
Ejemplo n.º 3
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:
            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):
                ide.connect(shortcut, SIGNAL("activated()"), 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:
                ide.connect(item_ui, SIGNAL("triggered()"), 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.º 4
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:
            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):
                ide.connect(shortcut, SIGNAL("activated()"), 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:
                ide.connect(item_ui, SIGNAL("triggered()"), 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.º 5
0
class Shortcut(object):

    def __init__(self, widget, *shortcut):
        self.qshortcut = QShortcut(QKeySequence(*shortcut), widget)
        if isinstance(widget, QMainWindow):
            self.qshortcut.setContext(Qt.ApplicationShortcut)
        else:
            self.qshortcut.setContext(Qt.WidgetShortcut)

    def __rshift__(self, functor):
        s = self.qshortcut
        s.connect(s, SIGNAL("activated()"), functor)
Ejemplo n.º 6
0
 def __init__(self, parent, actions=None):
     QTabWidget.__init__(self, parent)
     tab_bar = TabsBase(self, parent)
     self.connect(tab_bar, SIGNAL('move_tab(int,int)'), self.move_tab)
     self.connect(tab_bar, SIGNAL('move_tab(long,int,int)'),
                  self.move_tab_from_another_tabwidget)
     self.setTabBar(tab_bar)
     self.menu = QMenu(self)
     if actions:
         add_actions(self.menu, actions)
     self.index_history = []
     self.connect(self, SIGNAL('currentChanged(int)'),
                  self.__current_changed)
     tabsc = QShortcut(QKeySequence("Ctrl+Tab"), parent, self.tab_navigate)
     tabsc.setContext(Qt.WidgetWithChildrenShortcut)
Ejemplo n.º 7
0
 def __init__(self, parent, actions=None):
     QTabWidget.__init__(self, parent)
     tab_bar = TabsBase(self, parent)
     self.connect(tab_bar, SIGNAL('move_tab(int,int)'), self.move_tab)
     self.connect(tab_bar, SIGNAL('move_tab(long,int,int)'),
                  self.move_tab_from_another_tabwidget)
     self.setTabBar(tab_bar)
     self.menu = QMenu(self)
     if actions:
         add_actions(self.menu, actions)
     self.index_history = []
     self.connect(self, SIGNAL('currentChanged(int)'),
                  self.__current_changed)
     tabsc = QShortcut(QKeySequence("Ctrl+Tab"), parent, self.tab_navigate)
     tabsc.setContext(Qt.WidgetWithChildrenShortcut)
Ejemplo n.º 8
0
class DockWidget(QDockWidget):
    """Extended QDockWidget for Enki main window
    """
    def __init__(self, *args):
        QDockWidget.__init__(self, *args)

        self._showAction = None
        self._titleBar = _TitleBar( self )
        self.setTitleBarWidget( self._titleBar )
        
        self._closeShortcut = QShortcut( QKeySequence( "Esc" ), self )
        self._closeShortcut.setContext( Qt.WidgetWithChildrenShortcut )
        self._closeShortcut.activated.connect(self._hide)

    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 _hide(self):
        """Hide and return focus to MainWindow focus proxy
        """
        self.hide()
        if self.parent() is not None and \
           self.parent().focusProxy() is not None:
            self.parent().focusProxy().setFocus()
Ejemplo n.º 9
0
 def __init__(self, parent, mainwin):
     QPlainTextEdit.__init__(self, parent)
     self.mainwin = mainwin
     self.setObjectName("restedit")
     self._formats = {}
     self.textChanged.connect(self._restedit_update)
     self.blockCountChanged.connect(self._blockcount_update)
     shortcut = QShortcut(QKeySequence("Ctrl+T"), self)
     shortcut.activated.connect(self._choose_font)
     shortcut = QShortcut(QKeySequence.ZoomIn, self)
     shortcut.activated.connect(self._zoom_in)
     shortcut.setContext(Qt.WidgetShortcut)
     shortcut = QShortcut(QKeySequence.ZoomOut, self)
     shortcut.activated.connect(self._zoom_out)
     shortcut.setContext(Qt.WidgetShortcut)
     self._doc = QApplication.instance().rest
     self._last_warnings = {} # should be moved to the document
Ejemplo n.º 10
0
    def __init__(self, canvas, layer, iface, dockwidget):

        QApplication.restoreOverrideCursor()
        #QApplication.setOverrideCursor(Qt.CrossCursor)
        QgsMapToolEmitPoint.__init__(self, canvas)
        self.layer = layer
        self.start = None
        self.end = None
        self.ends = []

        sample, geo_ref = get_whole_raster(self.layer)
        r = sample[0]
        g = sample[1]
        b = sample[2]
        where_are_NaNs = np.isnan(r)
        r[where_are_NaNs] = 0
        where_are_NaNs = np.isnan(g)
        g[where_are_NaNs] = 0
        where_are_NaNs = np.isnan(b)
        b[where_are_NaNs] = 0

        self.sample = (r, g, b)

        h, s, v = rgb2hsv(r, g, b)
        self.sample_hsv = h, s, v

        self.geo_ref = geo_ref

        self.iface = iface
        self.layer_v = None
        self.points = []
        self.double = False
        self.dockwidget = dockwidget
        self.linetype = "Line"

        shortcut = QShortcut(QKeySequence(Qt.Key_Escape),
                             self.iface.mainWindow())
        shortcut.setContext(Qt.ApplicationShortcut)
        shortcut.activated.connect(self.fesq)

        self.esq = False
        self.layer_v = iface.activeLayer()
Ejemplo n.º 11
0
    def _shortcutHelper(self,
                        keySequence,
                        group,
                        description,
                        parent,
                        function,
                        context=None,
                        enabled=None,
                        widget=None):
        shortcut = QShortcut(QKeySequence(keySequence),
                             parent,
                             member=function,
                             ambiguousMember=function)
        if context != None:
            shortcut.setContext(context)
        if enabled != None:
            shortcut.setEnabled(True)

        ShortcutManager().register(group, description, shortcut, widget)
        return shortcut, group, description
Ejemplo n.º 12
0
 def __init__(self, parent, actions=None):
     BaseTabs.__init__(self, parent, actions)
     tab_bar = TabBar(self, parent)
     self.connect(tab_bar, SIGNAL('move_tab(int,int)'), self.move_tab)
     self.connect(tab_bar, SIGNAL('move_tab(long,int,int)'),
                  self.move_tab_from_another_tabwidget)
     self.setTabBar(tab_bar)
     self.index_history = []
     self.connect(self, SIGNAL('currentChanged(int)'),
                  self.__current_changed)
     tabsc = QShortcut(QKeySequence("Ctrl+Tab"), parent, self.tab_navigate)
     tabsc.setContext(Qt.WidgetWithChildrenShortcut)
     # Browsing tabs button
     browse_button = create_toolbutton(self,
                                       icon=get_icon("browse_tab.png"),
                                       tip=translate("Tabs", "Browse tabs"))
     self.browse_tabs_menu = QMenu(self)
     browse_button.setMenu(self.browse_tabs_menu)
     browse_button.setPopupMode(browse_button.InstantPopup)
     self.connect(self.browse_tabs_menu, SIGNAL("aboutToShow()"),
                  self.update_browse_tabs_menu)
     self.setCornerWidget(browse_button)
Ejemplo n.º 13
0
 def __init__(self, *args, **kw):
     # To override the Qt widget used by RichIPythonWidget
     self.custom_control = IPythonControlWidget
     self.custom_page_control = IPythonPageControlWidget
     super(SMIPythonWidget, self).__init__(*args, **kw)
     self.set_background_color()
     
     # --- Spyder variables ---
     self.ipyclient = None
     
     # --- Keyboard shortcuts ---
     inspectsc = QShortcut(QKeySequence("Ctrl+I"), self,
                           self._control.inspect_current_object)
     inspectsc.setContext(Qt.WidgetWithChildrenShortcut)
     clear_consolesc = QShortcut(QKeySequence("Ctrl+L"), self,
                                 self.clear_console)
     clear_consolesc.setContext(Qt.WidgetWithChildrenShortcut)
     
     # --- IPython variables ---
     # To send an interrupt signal to the Spyder kernel
     self.custom_interrupt = True
     
     # To restart the Spyder kernel in case it dies
     self.custom_restart = True
Ejemplo n.º 14
0
    def __init__(self, *args, **kw):
        # To override the Qt widget used by RichIPythonWidget
        self.custom_control = IPythonControlWidget
        self.custom_page_control = IPythonPageControlWidget
        super(SMIPythonWidget, self).__init__(*args, **kw)
        self.set_background_color()

        # --- Spyder variables ---
        self.ipyclient = None

        # --- Keyboard shortcuts ---
        inspectsc = QShortcut(QKeySequence("Ctrl+I"), self,
                              self._control.inspect_current_object)
        inspectsc.setContext(Qt.WidgetWithChildrenShortcut)
        clear_consolesc = QShortcut(QKeySequence("Ctrl+L"), self,
                                    self.clear_console)
        clear_consolesc.setContext(Qt.WidgetWithChildrenShortcut)

        # --- IPython variables ---
        # To send an interrupt signal to the Spyder kernel
        self.custom_interrupt = True

        # To restart the Spyder kernel in case it dies
        self.custom_restart = True
Ejemplo n.º 15
0
    def atalho_teclado(self):
        shortcut1 = QShortcut(QKeySequence(Qt.Key_1), self.iface.mainWindow())
        shortcut1.setContext(Qt.ApplicationShortcut)
        shortcut1.activated.connect(self.setVerifica1)

        shortcut2 = QShortcut(QKeySequence(Qt.Key_2), self.iface.mainWindow())
        shortcut2.setContext(Qt.ApplicationShortcut)
        shortcut2.activated.connect(self.setVerifica2)

        shortcut3 = QShortcut(QKeySequence(Qt.Key_3), self.iface.mainWindow())
        shortcut3.setContext(Qt.ApplicationShortcut)
        shortcut3.activated.connect(self.setVerifica3)
Ejemplo n.º 16
0
 def __init__(self, parent, mainwin):
     QWebView.__init__(self, parent)
     self.mainwin = mainwin
     self.setUrl(QUrl("about:blank"))
     self.setObjectName("webview")
     self.setTextSizeMultiplier(self.ZOOM_DEFAULT)
     shortcut = QShortcut(QKeySequence.ZoomIn, self)
     shortcut.activated.connect(self._zoom_in)
     shortcut.setContext(Qt.WidgetShortcut)
     shortcut = QShortcut(QKeySequence(Qt.CTRL | Qt.Key_Equal), self)
     shortcut.activated.connect(self._zoom_neutral)
     shortcut.setContext(Qt.WidgetShortcut)
     shortcut = QShortcut(QKeySequence.ZoomOut, self)
     shortcut.activated.connect(self._zoom_out)
     shortcut.setContext(Qt.WidgetShortcut)
Ejemplo n.º 17
0
class SqlEdit(QsciScintilla):

    LEXER_PYTHON = 0
    LEXER_R = 1

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

        self.mylexer = None
        self.api = None

        self.setCommonOptions()
        self.initShortcuts()

    def setCommonOptions(self):
        # Enable non-ASCII characters
        self.setUtf8(True)

        # Default font
        font = QFont()
        font.setFamily('Courier')
        font.setFixedPitch(True)
        font.setPointSize(10)
        self.setFont(font)
        self.setMarginsFont(font)

        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)

        self.setWrapMode(QsciScintilla.WrapWord)
        self.setWrapVisualFlags(QsciScintilla.WrapFlagByText,
                                QsciScintilla.WrapFlagNone, 4)

        self.setSelectionForegroundColor(QColor('#2e3436'))
        self.setSelectionBackgroundColor(QColor('#babdb6'))

        # Show line numbers
        self.setMarginWidth(1, '000')
        self.setMarginLineNumbers(1, True)
        self.setMarginsForegroundColor(QColor('#2e3436'))
        self.setMarginsBackgroundColor(QColor('#babdb6'))

        # Highlight current line
        self.setCaretLineVisible(True)
        self.setCaretLineBackgroundColor(QColor('#d3d7cf'))

        # Folding
        self.setFolding(QsciScintilla.BoxedTreeFoldStyle)
        self.setFoldMarginColors(QColor('#d3d7cf'), QColor('#d3d7cf'))

        # Mark column 80 with vertical line
        self.setEdgeMode(QsciScintilla.EdgeLine)
        self.setEdgeColumn(80)
        self.setEdgeColor(QColor('#eeeeec'))

        # Indentation
        self.setAutoIndent(True)
        self.setIndentationsUseTabs(False)
        self.setIndentationWidth(4)
        self.setTabIndents(True)
        self.setBackspaceUnindents(True)
        self.setTabWidth(4)

        # Autocomletion
        self.setAutoCompletionThreshold(2)
        self.setAutoCompletionSource(QsciScintilla.AcsAPIs)
        self.setAutoCompletionCaseSensitivity(False)

        # Load font from Python console settings
        settings = QSettings()
        fontName = settings.value('pythonConsole/fontfamilytext', 'Monospace')
        fontSize = int(settings.value('pythonConsole/fontsize', 10))

        self.defaultFont = QFont(fontName)
        self.defaultFont.setFixedPitch(True)
        self.defaultFont.setPointSize(fontSize)
        self.defaultFont.setStyleHint(QFont.TypeWriter)
        self.defaultFont.setStretch(QFont.SemiCondensed)
        self.defaultFont.setLetterSpacing(QFont.PercentageSpacing, 87.0)
        self.defaultFont.setBold(False)

        self.boldFont = QFont(self.defaultFont)
        self.boldFont.setBold(True)

        self.italicFont = QFont(self.defaultFont)
        self.italicFont.setItalic(True)

        self.setFont(self.defaultFont)
        self.setMarginsFont(self.defaultFont)

        self.initLexer()

    def initShortcuts(self):
        (ctrl, shift) = (self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16)

        # Disable some shortcuts
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY,
                           ord('L') + ctrl + shift)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl)

        #self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl)
        #self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl)

        # Use Ctrl+Space for autocompletion
        self.shortcutAutocomplete = QShortcut(
            QKeySequence(Qt.CTRL + Qt.Key_Space), self)
        self.shortcutAutocomplete.setContext(Qt.WidgetShortcut)
        self.shortcutAutocomplete.activated.connect(self.autoComplete)

    def autoComplete(self):
        self.autoCompleteFromAll()

    def initLexer(self):
        self.mylexer = QsciLexerSQL()

        colorDefault = QColor('#2e3436')
        colorComment = QColor('#c00')
        colorCommentBlock = QColor('#3465a4')
        colorNumber = QColor('#4e9a06')
        colorType = QColor('#4e9a06')
        colorKeyword = QColor('#204a87')
        colorString = QColor('#ce5c00')

        self.mylexer.setDefaultFont(self.defaultFont)
        self.mylexer.setDefaultColor(colorDefault)

        self.mylexer.setColor(colorComment, 1)
        self.mylexer.setColor(colorNumber, 2)
        self.mylexer.setColor(colorString, 3)
        self.mylexer.setColor(colorString, 4)
        self.mylexer.setColor(colorKeyword, 5)
        self.mylexer.setColor(colorString, 6)
        self.mylexer.setColor(colorString, 7)
        self.mylexer.setColor(colorType, 8)
        self.mylexer.setColor(colorCommentBlock, 12)
        self.mylexer.setColor(colorString, 15)

        self.mylexer.setFont(self.italicFont, 1)
        self.mylexer.setFont(self.boldFont, 5)
        self.mylexer.setFont(self.boldFont, 8)
        self.mylexer.setFont(self.italicFont, 12)

        self.setLexer(self.mylexer)

    def lexer(self):
        return self.mylexer
Ejemplo n.º 18
0
class ShellScintilla(QsciScintilla, code.InteractiveInterpreter):

    def __init__(self, parent=None):
        super(ShellScintilla, self).__init__(parent)
        code.InteractiveInterpreter.__init__(self, locals=None)

        self.parent = parent

        self.opening = ['(', '{', '[', "'", '"']
        self.closing = [')', '}', ']', "'", '"']

        self.settings = QSettings()

        # Enable non-ascii chars for editor
        self.setUtf8(True)

        self.new_input_line = True

        self.setMarginWidth(0, 0)
        self.setMarginWidth(1, 0)
        self.setMarginWidth(2, 0)

        self.buffer = []

        self.displayPrompt(False)

        for line in _init_commands:
            self.runsource(line)

        self.history = []
        self.historyIndex = 0
        # Read history command file
        self.readHistoryFile()

        self.historyDlg = HistoryDialog(self)

        # Brace matching: enable for a brace immediately before or after
        # the current position
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
        self.setMatchedBraceBackgroundColor(QColor("#b7f907"))

        # Current line visible with special background color
        self.setCaretWidth(2)

        self.refreshSettingsShell()

        # Don't want to see the horizontal scrollbar at all
        # Use raw message to Scintilla here (all messages are documented
        # here: http://www.scintilla.org/ScintillaDoc.html)
        self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)

        # not too small
        #self.setMinimumSize(500, 300)

        self.setWrapMode(QsciScintilla.WrapCharacter)
        self.SendScintilla(QsciScintilla.SCI_EMPTYUNDOBUFFER)

        ## Disable command key
        ctrl, shift = self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('Z') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('Y') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl + shift)

        ## New QShortcut = ctrl+space/ctrl+alt+space for Autocomplete
        self.newShortcutCSS = QShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_Space), self)
        self.newShortcutCAS = QShortcut(QKeySequence(Qt.CTRL + Qt.ALT + Qt.Key_Space), self)
        self.newShortcutCSS.setContext(Qt.WidgetShortcut)
        self.newShortcutCAS.setContext(Qt.WidgetShortcut)
        self.newShortcutCAS.activated.connect(self.autoCompleteKeyBinding)
        self.newShortcutCSS.activated.connect(self.showHistory)

    def _setMinimumHeight(self):
        fnt = self.settings.value("pythonConsole/fontfamilytext", "Monospace")
        fntSize = self.settings.value("pythonConsole/fontsize", 10, type=int)
        fm = QFontMetrics(QFont(fnt, fntSize))

        self.setMinimumHeight(fm.height() + 10)

    def refreshSettingsShell(self):
        # Set Python lexer
        self.setLexers()
        threshold = self.settings.value("pythonConsole/autoCompThreshold", 2, type=int)
        self.setAutoCompletionThreshold(threshold)
        radioButtonSource = self.settings.value("pythonConsole/autoCompleteSource", 'fromAPI')
        autoCompEnabled = self.settings.value("pythonConsole/autoCompleteEnabled", True, type=bool)
        if autoCompEnabled:
            if radioButtonSource == 'fromDoc':
                self.setAutoCompletionSource(self.AcsDocument)
            elif radioButtonSource == 'fromAPI':
                self.setAutoCompletionSource(self.AcsAPIs)
            elif radioButtonSource == 'fromDocAPI':
                self.setAutoCompletionSource(self.AcsAll)
        else:
            self.setAutoCompletionSource(self.AcsNone)

        cursorColor = self.settings.value("pythonConsole/cursorColor", QColor(Qt.black))
        self.setCaretForegroundColor(cursorColor)

        # Sets minimum height for input area based of font metric
        self._setMinimumHeight()

    def showHistory(self):
        if not self.historyDlg.isVisible():
            self.historyDlg.show()
        self.historyDlg._reloadHistory()
        self.historyDlg.activateWindow()

    def autoCompleteKeyBinding(self):
        radioButtonSource = self.settings.value("pythonConsole/autoCompleteSource", 'fromAPI')
        autoCompEnabled = self.settings.value("pythonConsole/autoCompleteEnabled", True, type=bool)
        if autoCompEnabled:
            if radioButtonSource == 'fromDoc':
                self.autoCompleteFromDocument()
            elif radioButtonSource == 'fromAPI':
                self.autoCompleteFromAPIs()
            elif radioButtonSource == 'fromDocAPI':
                self.autoCompleteFromAll()

    def commandConsole(self, command):
        if not self.is_cursor_on_last_line():
            self.move_cursor_to_end()
        line, pos = self.getCursorPosition()
        selCmdLenght = len(self.text(line))
        self.setSelection(line, 4, line, selCmdLenght)
        self.removeSelectedText()
        if command == "processing":
            # import Processing class
            self.append('import processing')
        elif command == "qtCore":
            # import QtCore class
            self.append('from PyQt4.QtCore import *')
        elif command == "qtGui":
            # import QtGui class
            self.append('from PyQt4.QtGui import *')
        self.entered()
        self.move_cursor_to_end()
        self.setFocus()

    def setLexers(self):
        self.lexer = QsciLexerPython()

        loadFont = self.settings.value("pythonConsole/fontfamilytext", "Monospace")
        fontSize = self.settings.value("pythonConsole/fontsize", 10, type=int)

        font = QFont(loadFont)
        font.setFixedPitch(True)
        font.setPointSize(fontSize)
        font.setStyleHint(QFont.TypeWriter)
        font.setStretch(QFont.SemiCondensed)
        font.setLetterSpacing(QFont.PercentageSpacing, 87.0)
        font.setBold(False)

        self.lexer.setDefaultFont(font)
        self.lexer.setDefaultColor(QColor(self.settings.value("pythonConsole/defaultFontColor", QColor(Qt.black))))
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/commentFontColor", QColor(Qt.gray))), 1)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/keywordFontColor", QColor(Qt.darkGreen))), 5)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/classFontColor", QColor(Qt.blue))), 8)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/methodFontColor", QColor(Qt.darkGray))), 9)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/decorFontColor", QColor(Qt.darkBlue))), 15)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/commentBlockFontColor", QColor(Qt.gray))), 12)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/singleQuoteFontColor", QColor(Qt.blue))), 4)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/doubleQuoteFontColor", QColor(Qt.blue))), 3)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/tripleSingleQuoteFontColor", QColor(Qt.blue))), 6)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/tripleDoubleQuoteFontColor", QColor(Qt.blue))), 7)
        self.lexer.setFont(font, 1)
        self.lexer.setFont(font, 3)
        self.lexer.setFont(font, 4)

        for style in range(0, 33):
            paperColor = QColor(self.settings.value("pythonConsole/paperBackgroundColor", QColor(Qt.white)))
            self.lexer.setPaper(paperColor, style)

        self.api = QsciAPIs(self.lexer)
        chekBoxAPI = self.settings.value("pythonConsole/preloadAPI", True, type=bool)
        chekBoxPreparedAPI = self.settings.value("pythonConsole/usePreparedAPIFile", False, type=bool)
        if chekBoxAPI:
            pap = os.path.join(QgsApplication.pkgDataPath(), "python", "qsci_apis", "pyqgis.pap")
            self.api.loadPrepared(pap)
        elif chekBoxPreparedAPI:
            self.api.loadPrepared(self.settings.value("pythonConsole/preparedAPIFile"))
        else:
            apiPath = self.settings.value("pythonConsole/userAPI", [])
            for i in range(0, len(apiPath)):
                self.api.load(unicode(apiPath[i]))
            self.api.prepare()
            self.lexer.setAPIs(self.api)

        self.setLexer(self.lexer)

    ## TODO: show completion list for file and directory

    def getText(self):
        """ Get the text as a unicode string. """
        value = self.getBytes().decode('utf-8')
        # print (value) printing can give an error because the console font
        # may not have all unicode characters
        return value

    def getBytes(self):
        """ Get the text as bytes (utf-8 encoded). This is how
        the data is stored internally. """
        len = self.SendScintilla(self.SCI_GETLENGTH) + 1
        bb = QByteArray(len, '0')
        self.SendScintilla(self.SCI_GETTEXT, len, bb)
        return bytes(bb)[:-1]

    def getTextLength(self):
        return self.SendScintilla(QsciScintilla.SCI_GETLENGTH)

    def get_end_pos(self):
        """Return (line, index) position of the last character"""
        line = self.lines() - 1
        return (line, len(self.text(line)))

    def is_cursor_at_end(self):
        """Return True if cursor is at the end of text"""
        cline, cindex = self.getCursorPosition()
        return (cline, cindex) == self.get_end_pos()

    def move_cursor_to_end(self):
        """Move cursor to end of text"""
        line, index = self.get_end_pos()
        self.setCursorPosition(line, index)
        self.ensureCursorVisible()
        self.ensureLineVisible(line)

    def is_cursor_on_last_line(self):
        """Return True if cursor is on the last line"""
        cline, _ = self.getCursorPosition()
        return cline == self.lines() - 1

    def is_cursor_on_edition_zone(self):
        """ Return True if the cursor is in the edition zone """
        cline, cindex = self.getCursorPosition()
        return cline == self.lines() - 1 and cindex >= 4

    def new_prompt(self, prompt):
        """
        Print a new prompt and save its (line, index) position
        """
        self.write(prompt, prompt=True)
        # now we update our cursor giving end of prompt
        line, index = self.getCursorPosition()
        self.ensureCursorVisible()
        self.ensureLineVisible(line)

    def displayPrompt(self, more=False):
        self.append("... ") if more else self.append(">>> ")
        self.move_cursor_to_end()

    def updateHistory(self, command):
        if isinstance(command, list):
            for line in command:
                self.history.append(line)
        elif not command == "":
            if len(self.history) <= 0 or \
               command != self.history[-1]:
                self.history.append(command)
        self.historyIndex = len(self.history)

    def writeHistoryFile(self, fromCloseConsole=False):
        ok = False
        try:
            wH = codecs.open(_historyFile, 'w', encoding='utf-8')
            for s in self.history:
                wH.write(s + '\n')
            ok = True
        except:
            raise
        wH.close()
        if ok and not fromCloseConsole:
            msgText = QCoreApplication.translate('PythonConsole',
                                                 'History saved successfully.')
            self.parent.callWidgetMessageBar(msgText)

    def readHistoryFile(self):
        fileExist = QFile.exists(_historyFile)
        if fileExist:
            rH = codecs.open(_historyFile, 'r', encoding='utf-8')
            for line in rH:
                if line != "\n":
                    l = line.rstrip('\n')
                    self.updateHistory(l)
        else:
            return

    def clearHistory(self, clearSession=False):
        if clearSession:
            self.history = []
            msgText = QCoreApplication.translate('PythonConsole',
                                                 'Session and file history cleared successfully.')
            self.parent.callWidgetMessageBar(msgText)
            return
        ok = False
        try:
            cH = codecs.open(_historyFile, 'w', encoding='utf-8')
            ok = True
        except:
            raise
        cH.close()
        if ok:
            msgText = QCoreApplication.translate('PythonConsole',
                                                 'History cleared successfully.')
            self.parent.callWidgetMessageBar(msgText)

    def clearHistorySession(self):
        self.clearHistory(True)

    def showPrevious(self):
        if self.historyIndex < len(self.history) and self.history:
            line, pos = self.getCursorPosition()
            selCmdLenght = len(self.text(line))
            self.setSelection(line, 4, line, selCmdLenght)
            self.removeSelectedText()
            self.historyIndex += 1
            if self.historyIndex == len(self.history):
                self.insert("")
                pass
            else:
                self.insert(self.history[self.historyIndex])
            self.move_cursor_to_end()
            #self.SendScintilla(QsciScintilla.SCI_DELETEBACK)

    def showNext(self):
        if self.historyIndex > 0 and self.history:
            line, pos = self.getCursorPosition()
            selCmdLenght = len(self.text(line))
            self.setSelection(line, 4, line, selCmdLenght)
            self.removeSelectedText()
            self.historyIndex -= 1
            if self.historyIndex == len(self.history):
                self.insert("")
            else:
                self.insert(self.history[self.historyIndex])
            self.move_cursor_to_end()
            #self.SendScintilla(QsciScintilla.SCI_DELETEBACK)

    def keyPressEvent(self, e):
        startLine, startPos, endLine, endPos = self.getSelection()

        # handle invalid cursor position and multiline selections
        if not self.is_cursor_on_edition_zone() or startLine < endLine:
            # allow to copy and select
            if e.modifiers() & (Qt.ControlModifier | Qt.MetaModifier):
                if e.key() in (Qt.Key_C, Qt.Key_A):
                    QsciScintilla.keyPressEvent(self, e)
                return
            # allow selection
            if e.modifiers() & Qt.ShiftModifier:
                if e.key() in (Qt.Key_Left, Qt.Key_Right, Qt.Key_Home, Qt.Key_End):
                    QsciScintilla.keyPressEvent(self, e)
                return
            # all other keystrokes get sent to the input line
            self.move_cursor_to_end()

        line, index = self.getCursorPosition()
        cmd = self.text(line)

        if e.key() in (Qt.Key_Return, Qt.Key_Enter) and not self.isListActive():
            self.entered()

        elif e.key() in (Qt.Key_Left, Qt.Key_Home):
            QsciScintilla.keyPressEvent(self, e)
            # check whether the cursor is moved out of the edition zone
            newline, newindex = self.getCursorPosition()
            if newline < line or newindex < 4:
                # fix selection and the cursor position
                if self.hasSelectedText():
                    self.setSelection(line, self.getSelection()[3], line, 4)
                else:
                    self.setCursorPosition(line, 4)

        elif e.key() in (Qt.Key_Backspace, Qt.Key_Delete):
            QsciScintilla.keyPressEvent(self, e)
            # check whether the cursor is moved out of the edition zone
            _, newindex = self.getCursorPosition()
            if newindex < 4:
                # restore the prompt chars (if removed) and
                # fix the cursor position
                self.insert(cmd[:3 - newindex] + " ")
                self.setCursorPosition(line, 4)
            self.recolor()

        elif (e.modifiers() & (Qt.ControlModifier | Qt.MetaModifier) and e.key() == Qt.Key_V) or \
             (e.modifiers() & Qt.ShiftModifier and e.key() == Qt.Key_Insert):
            self.paste()
            e.accept()

        elif e.key() == Qt.Key_Down and not self.isListActive():
            self.showPrevious()
        elif e.key() == Qt.Key_Up and not self.isListActive():
            self.showNext()
        ## TODO: press event for auto-completion file directory
        else:
            t = unicode(e.text())
            self.autoCloseBracket = self.settings.value("pythonConsole/autoCloseBracket", False, type=bool)
            self.autoImport = self.settings.value("pythonConsole/autoInsertionImport", True, type=bool)
            txt = cmd[:index].replace('>>> ', '').replace('... ', '')
            ## Close bracket automatically
            if t in self.opening and self.autoCloseBracket:
                i = self.opening.index(t)
                if self.hasSelectedText() and startPos != 0:
                    selText = self.selectedText()
                    self.removeSelectedText()
                    self.insert(self.opening[i] + selText + self.closing[i])
                    self.setCursorPosition(endLine, endPos + 2)
                    return
                elif t == '(' and (re.match(r'^[ \t]*def \w+$', txt)
                                   or re.match(r'^[ \t]*class \w+$', txt)):
                        self.insert('):')
                else:
                    self.insert(self.closing[i])
            ## FIXES #8392 (automatically removes the redundant char
            ## when autoclosing brackets option is enabled)
            elif t in [')', ']', '}'] and self.autoCloseBracket:
                txt = self.text(line)
                try:
                    if txt[index - 1] in self.opening and t == txt[index]:
                        self.setCursorPosition(line, index + 1)
                        self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
                except IndexError:
                    pass
            elif t == ' ' and self.autoImport:
                ptrn = r'^[ \t]*from [\w.]+$'
                if re.match(ptrn, txt):
                    self.insert(' import')
                    self.setCursorPosition(line, index + 7)
            QsciScintilla.keyPressEvent(self, e)

    def contextMenuEvent(self, e):
        menu = QMenu(self)
        subMenu = QMenu(menu)
        titleHistoryMenu = QCoreApplication.translate("PythonConsole", "Command History")
        subMenu.setTitle(titleHistoryMenu)
        subMenu.addAction(
            QCoreApplication.translate("PythonConsole", "Show"),
            self.showHistory, 'Ctrl+Shift+SPACE')
        subMenu.addSeparator()
        subMenu.addAction(
            QCoreApplication.translate("PythonConsole", "Save"),
            self.writeHistoryFile)
        subMenu.addSeparator()
        subMenu.addAction(
            QCoreApplication.translate("PythonConsole", "Clear File"),
            self.clearHistory)
        subMenu.addAction(
            QCoreApplication.translate("PythonConsole", "Clear Session"),
            self.clearHistorySession)
        menu.addMenu(subMenu)
        menu.addSeparator()
        copyAction = menu.addAction(
            QCoreApplication.translate("PythonConsole", "Copy"),
            self.copy, QKeySequence.Copy)
        pasteAction = menu.addAction(
            QCoreApplication.translate("PythonConsole", "Paste"),
            self.paste, QKeySequence.Paste)
        copyAction.setEnabled(False)
        pasteAction.setEnabled(False)
        if self.hasSelectedText():
            copyAction.setEnabled(True)
        if QApplication.clipboard().text():
            pasteAction.setEnabled(True)
        menu.exec_(self.mapToGlobal(e.pos()))

    def mousePressEvent(self, e):
        """
        Re-implemented to handle the mouse press event.
        e: the mouse press event (QMouseEvent)
        """
        self.setFocus()
        if e.button() == Qt.MidButton:
            stringSel = unicode(QApplication.clipboard().text(QClipboard.Selection))
            if not self.is_cursor_on_last_line():
                self.move_cursor_to_end()
            self.insertFromDropPaste(stringSel)
            e.accept()
        else:
            QsciScintilla.mousePressEvent(self, e)

    def paste(self):
        """
        Method to display data from the clipboard.

        XXX: It should reimplement the virtual QScintilla.paste method,
        but it seems not used by QScintilla code.
        """
        stringPaste = unicode(QApplication.clipboard().text())
        if self.is_cursor_on_last_line():
            if self.hasSelectedText():
                self.removeSelectedText()
        else:
            self.move_cursor_to_end()
        self.insertFromDropPaste(stringPaste)

    ## Drag and drop
    def dropEvent(self, e):
        if e.mimeData().hasText():
            stringDrag = e.mimeData().text()
            self.insertFromDropPaste(stringDrag)
            self.setFocus()
            e.setDropAction(Qt.CopyAction)
            e.accept()
        else:
            QsciScintillaCompat.dropEvent(self, e)

    def insertFromDropPaste(self, textDP):
        pasteList = unicode(textDP).splitlines()
        if pasteList:
            for line in pasteList[:-1]:
                cleanLine = line.replace(">>> ", "").replace("... ", "")
                self.insert(unicode(cleanLine))
                self.move_cursor_to_end()
                self.runCommand(unicode(self.currentCommand()))
            if pasteList[-1] != "":
                line = pasteList[-1]
                cleanLine = line.replace(">>> ", "").replace("... ", "")
                self.insert(unicode(cleanLine))
                self.move_cursor_to_end()

    def insertTextFromFile(self, listOpenFile):
        for line in listOpenFile[:-1]:
            self.append(line)
            self.move_cursor_to_end()
            self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
            self.runCommand(unicode(self.currentCommand()))
        self.append(unicode(listOpenFile[-1]))
        self.move_cursor_to_end()
        self.SendScintilla(QsciScintilla.SCI_DELETEBACK)

    def entered(self):
        self.move_cursor_to_end()
        self.runCommand(unicode(self.currentCommand()))
        self.setFocus()
        self.move_cursor_to_end()

    def currentCommand(self):
        linenr, index = self.getCursorPosition()
        string = self.text()
        cmdLine = string[4:]
        cmd = unicode(cmdLine)
        return cmd

    def runCommand(self, cmd):
        self.writeCMD(cmd)
        import webbrowser
        self.updateHistory(cmd)
        if cmd in ('_pyqgis', '_api'):
            if cmd == '_pyqgis':
                webbrowser.open("http://qgis.org/pyqgis-cookbook/")
            elif cmd == '_api':
                webbrowser.open("http://qgis.org/api/")
            more = False
        else:
            self.buffer.append(cmd)
            src = u"\n".join(self.buffer)
            more = self.runsource(src, "<input>")
            if not more:
                self.buffer = []
        ## prevents to commands with more lines to break the console
        ## in the case they have a eol different from '\n'
        self.setText('')
        self.move_cursor_to_end()
        self.displayPrompt(more)

    def write(self, txt):
        sys.stderr.write(txt)

    def writeCMD(self, txt):
        if len(txt) > 0:
            getCmdString = self.text()
            prompt = getCmdString[0:4]
            sys.stdout.write(prompt + txt + '\n')
Ejemplo n.º 19
0
 def newsc(keystr, triggered):
     sc = QShortcut(QKeySequence(keystr), parent, triggered)
     sc.setContext(Qt.WidgetWithChildrenShortcut)
     return sc
Ejemplo n.º 20
0
class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
                        InspectObjectMixin):
    """Python shell widget"""
    QT_CLASS = ShellBaseWidget

    INITHISTORY = ['# -*- coding: utf-8 -*-',
                   '# *** Spyder Python Console History Log ***',]
    SEPARATOR = '%s##---(%s)---' % (os.linesep*2, time.ctime())
    
    def __init__(self, parent, history_filename, profile=False):
        ShellBaseWidget.__init__(self, parent, history_filename, profile)
        TracebackLinksMixin.__init__(self)
        InspectObjectMixin.__init__(self)

        # Local shortcuts
        self.inspectsc = QShortcut(QKeySequence("Ctrl+I"), self,
                                   self.inspect_current_object)
        self.inspectsc.setContext(Qt.WidgetWithChildrenShortcut)
        
    def get_shortcut_data(self):
        """
        Returns shortcut data, a list of tuples (shortcut, text, default)
        shortcut (QShortcut or QAction instance)
        text (string): action/shortcut description
        default (string): default key sequence
        """
        return [
                (self.inspectsc, "Inspect current object", "Ctrl+I"),
                ]


    #------ Context menu
    def setup_context_menu(self):
        """Reimplements ShellBaseWidget method"""
        ShellBaseWidget.setup_context_menu(self)
        self.copy_without_prompts_action = create_action(self,
                                     _("Copy without prompts"),
                                     icon=get_icon('copywop.png'),
                                     triggered=self.copy_without_prompts)
        clear_line_action = create_action(self, _("Clear line"),
                                     QKeySequence("Shift+Escape"),
                                     icon=get_icon('eraser.png'),
                                     tip=_("Clear line"),
                                     triggered=self.clear_line)
        clear_action = create_action(self, _("Clear shell"),
                                     QKeySequence("Ctrl+L"),
                                     icon=get_icon('clear.png'),
                                     tip=_("Clear shell contents "
                                           "('cls' command)"),
                                     triggered=self.clear_terminal)
        add_actions(self.menu, (self.copy_without_prompts_action,
                    clear_line_action, clear_action))
          
    def contextMenuEvent(self, event):
        """Reimplements ShellBaseWidget method"""
        state = self.has_selected_text()
        self.copy_without_prompts_action.setEnabled(state)
        ShellBaseWidget.contextMenuEvent(self, event)
        
    def copy_without_prompts(self):
        """Copy text to clipboard without prompts"""
        text = self.get_selected_text()
        lines = text.split(os.linesep)
        for index, line in enumerate(lines):
            if line.startswith('>>> ') or line.startswith('... '):
                lines[index] = line[4:]
        text = os.linesep.join(lines)
        QApplication.clipboard().setText(text)
    
    
    #------ Key handlers
    def postprocess_keyevent(self, event):
        """Process keypress event"""
        ShellBaseWidget.postprocess_keyevent(self, event)
        if QToolTip.isVisible():
            _event, _text, key, _ctrl, _shift = restore_keyevent(event)
            self.hide_tooltip_if_necessary(key)
                
    def _key_other(self, text):
        """1 character key"""
        if self.is_completion_widget_visible():
            self.completion_text += text
                
    def _key_backspace(self, cursor_position):
        """Action for Backspace key"""
        if self.has_selected_text():
            self.check_selection()
            self.remove_selected_text()
        elif self.current_prompt_pos == cursor_position:
            # Avoid deleting prompt
            return
        elif self.is_cursor_on_last_line():
            self.stdkey_backspace()
            if self.is_completion_widget_visible():
                # Removing only last character because if there was a selection
                # the completion widget would have been canceled
                self.completion_text = self.completion_text[:-1]
                
    def _key_tab(self):
        """Action for TAB key"""
        if self.is_cursor_on_last_line():
            empty_line = not self.get_current_line_to_cursor().strip()
            if empty_line:
                self.stdkey_tab()
            else:
                self.show_code_completion(automatic=False)
                
    def _key_ctrl_space(self):
        """Action for Ctrl+Space"""
        if not self.is_completion_widget_visible():
            self.show_code_completion(automatic=False)
                
    def _key_pageup(self):
        """Action for PageUp key"""
        pass
    
    def _key_pagedown(self):
        """Action for PageDown key"""
        pass
                
    def _key_escape(self):
        """Action for ESCAPE key"""
        if self.is_completion_widget_visible():
            self.hide_completion_widget()

    def _key_question(self, text):
        """Action for '?'"""
        if self.get_current_line_to_cursor():
            last_obj = self.get_last_obj()
            if last_obj and not last_obj.isdigit():
                self.show_docstring(last_obj)
        self.insert_text(text)
        # In case calltip and completion are shown at the same time:
        if self.is_completion_widget_visible():
            self.completion_text += '?'
                
    def _key_parenleft(self, text):
        """Action for '('"""
        self.hide_completion_widget()
        if self.get_current_line_to_cursor():
            last_obj = self.get_last_obj()
            if last_obj and not last_obj.isdigit():
                self.show_docstring(last_obj, call=True)
        self.insert_text(text)
        
    def _key_period(self, text):
        """Action for '.'"""
        self.insert_text(text)
        if self.codecompletion_auto:
            # Enable auto-completion only if last token isn't a float
            last_obj = self.get_last_obj()
            if last_obj and not last_obj.isdigit():
                self.show_code_completion(automatic=True)


    #------ Paste
    def paste(self):
        """Reimplemented slot to handle multiline paste action"""
        text = unicode(QApplication.clipboard().text())
        if len(text.splitlines()) > 1:
            # Multiline paste
            if self.new_input_line:
                self.on_new_line()
            self.remove_selected_text() # Remove selection, eventually
            end = self.get_current_line_from_cursor()
            lines = self.get_current_line_to_cursor() + text + end
            self.clear_line()
            self.execute_lines(lines)
            self.move_cursor(-len(end))
        else:
            # Standard paste
            ShellBaseWidget.paste(self)
    
  
    #------ Code Completion / Calltips        
    # Methods implemented in child class:
    # (e.g. InternalShell)
    def get_dir(self, objtxt):
        """Return dir(object)"""
        raise NotImplementedError
    def get_module_completion(self, objtxt):
        """Return module completion list associated to object name"""
        pass
    def get_globals_keys(self):
        """Return shell globals() keys"""
        raise NotImplementedError
    def get_cdlistdir(self):
        """Return shell current directory list dir"""
        raise NotImplementedError
    def iscallable(self, objtxt):
        """Is object callable?"""
        raise NotImplementedError
    def get_arglist(self, objtxt):
        """Get func/method argument list"""
        raise NotImplementedError
    def get__doc__(self, objtxt):
        """Get object __doc__"""
        raise NotImplementedError
    def get_doc(self, objtxt):
        """Get object documentation"""
        raise NotImplementedError
    def get_source(self, objtxt):
        """Get object source"""
        raise NotImplementedError
    def is_defined(self, objtxt, force_import=False):
        """Return True if object is defined"""
        raise NotImplementedError
        
    def show_code_completion(self, automatic):
        """Display a completion list based on the current line"""
        # Note: unicode conversion is needed only for ExternalShellBase
        text = unicode(self.get_current_line_to_cursor())
        last_obj = self.get_last_obj()
        
        if text.startswith('import '):
            obj_list = self.get_module_completion(text)
            words = text.split(' ')
            if ',' in words[-1]:
                words = words[-1].split(',')
            self.show_completion_list(obj_list, completion_text=words[-1],
                                      automatic=automatic)
            return
            
        elif text.startswith('from '):
            obj_list = self.get_module_completion(text)
            if obj_list is None:
                return
            words = text.split(' ')
            if '(' in words[-1]:
                words = words[:-2] + words[-1].split('(')
            if ',' in words[-1]:
                words = words[:-2] + words[-1].split(',')
            self.show_completion_list(obj_list, completion_text=words[-1],
                                      automatic=automatic)
            return
        
        obj_dir = self.get_dir(last_obj)
        if last_obj and obj_dir and text.endswith('.'):
            self.show_completion_list(obj_dir, automatic=automatic)
            return
        
        # Builtins and globals
        import __builtin__, keyword
        if not text.endswith('.') and last_obj \
           and re.match(r'[a-zA-Z_0-9]*$', last_obj):
            b_k_g = dir(__builtin__)+self.get_globals_keys()+keyword.kwlist
            for objname in b_k_g:
                if objname.startswith(last_obj) and objname != last_obj:
                    self.show_completion_list(b_k_g, completion_text=last_obj,
                                              automatic=automatic)
                    return
            else:
                return
        
        # Looking for an incomplete completion
        if last_obj is None:
            last_obj = text
        dot_pos = last_obj.rfind('.')
        if dot_pos != -1:
            if dot_pos == len(last_obj)-1:
                completion_text = ""
            else:
                completion_text = last_obj[dot_pos+1:]
                last_obj = last_obj[:dot_pos]
            completions = self.get_dir(last_obj)
            if completions is not None:
                self.show_completion_list(completions,
                                          completion_text=completion_text,
                                          automatic=automatic)
                return
        
        # Looking for ' or ": filename completion
        q_pos = max([text.rfind("'"), text.rfind('"')])
        if q_pos != -1:
            completions = self.get_cdlistdir()
            if completions:
                self.show_completion_list(completions,
                                          completion_text=text[q_pos+1:],
                                          automatic=automatic)
            return
            
    #------ Drag'n Drop
    def drop_pathlist(self, pathlist):
        """Drop path list"""
        if pathlist:
            files = ["r'%s'" % path for path in pathlist]
            if len(files) == 1:
                text = files[0]
            else:
                text = "[" + ", ".join(files) + "]"
            if self.new_input_line:
                self.on_new_line()
            self.insert_text(text)
            self.setFocus()
Ejemplo n.º 21
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.destroyed.connect(self._setFocusTimer.stop)
        self._timerAttempts = 0

    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)

    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.º 22
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:
            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.º 23
0
class ShellOutputScintilla(QsciScintilla):

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

        self.settings = QSettings()

        # Creates layout for message bar
        self.layout = QGridLayout(self)
        self.layout.setContentsMargins(0, 0, 0, 0)
        spacerItem = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        self.layout.addItem(spacerItem, 1, 0, 1, 1)
        # messageBar instance
        self.infoBar = QgsMessageBar()
        sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.infoBar.setSizePolicy(sizePolicy)
        self.layout.addWidget(self.infoBar, 0, 0, 1, 1)

        # Enable non-ascii chars for editor
        self.setUtf8(True)

        sys.stdout = writeOut(self, sys.stdout)
        sys.stderr = writeOut(self, sys.stderr, "_traceback")

        self.insertInitText()
        self.refreshSettingsOutput()
        self.setReadOnly(True)

        # Set the default font
        font = QFont()
        font.setFamily('Courier')
        font.setFixedPitch(True)
        font.setPointSize(10)
        self.setFont(font)
        self.setMarginsFont(font)
        # Margin 0 is used for line numbers
        self.setMarginWidth(0, 0)
        self.setMarginWidth(1, 0)
        self.setMarginWidth(2, 0)
        #fm = QFontMetrics(font)
        self.setMarginsFont(font)
        self.setMarginWidth(1, "00000")
        self.setMarginLineNumbers(1, True)
        self.setMarginsForegroundColor(QColor("#3E3EE3"))
        self.setMarginsBackgroundColor(QColor("#f9f9f9"))
        self.setCaretLineVisible(True)
        self.setCaretWidth(0)

        self.setMinimumHeight(120)

        self.setWrapMode(QsciScintilla.WrapCharacter)
        self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)

        self.runScut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_E), self)
        self.runScut.setContext(Qt.WidgetShortcut)
        self.runScut.activated.connect(self.enteredSelected)
        # Reimplemeted copy action to prevent paste prompt (>>>,...) in command view
        self.copyShortcut = QShortcut(QKeySequence.Copy, self)
        self.copyShortcut.activated.connect(self.copy)
        self.selectAllShortcut = QShortcut(QKeySequence.SelectAll, self)
        self.selectAllShortcut.activated.connect(self.selectAll)

    def insertInitText(self):
        txtInit = QCoreApplication.translate("PythonConsole",
                                             "Python Console \n"
                                             "Use iface to access QGIS API interface or Type help(iface) for more info")

        ## some translation string for the console header ends without '\n'
        ## and the first command in console will be appended at the header text.
        ## The following code add a '\n' at the end of the string if not present.
        if txtInit.endswith('\n'):
            self.setText(txtInit)
        else:
            self.setText(txtInit + '\n')

    def refreshSettingsOutput(self):
        # Set Python lexer
        self.setLexers()
        caretLineColor = self.settings.value("pythonConsole/caretLineColor", QColor("#fcf3ed"))
        cursorColor = self.settings.value("pythonConsole/cursorColor", QColor(Qt.black))
        self.setCaretLineBackgroundColor(caretLineColor)
        self.setCaretForegroundColor(cursorColor)

    def setLexers(self):
        self.lexer = QsciLexerPython()

        loadFont = self.settings.value("pythonConsole/fontfamilytext", "Monospace")
        fontSize = self.settings.value("pythonConsole/fontsize", 10, type=int)
        font = QFont(loadFont)
        font.setFixedPitch(True)
        font.setPointSize(fontSize)
        font.setStyleHint(QFont.TypeWriter)
        font.setStretch(QFont.SemiCondensed)
        font.setLetterSpacing(QFont.PercentageSpacing, 87.0)
        font.setBold(False)

        self.lexer.setDefaultFont(font)
        self.lexer.setDefaultColor(QColor(self.settings.value("pythonConsole/defaultFontColor", QColor(Qt.black))))
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/commentFontColor", QColor(Qt.gray))), 1)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/keywordFontColor", QColor(Qt.darkGreen))), 5)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/classFontColor", QColor(Qt.blue))), 8)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/methodFontColor", QColor(Qt.darkGray))), 9)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/decorFontColor", QColor(Qt.darkBlue))), 15)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/commentBlockFontColor", QColor(Qt.gray))), 12)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/singleQuoteFontColor", QColor(Qt.blue))), 4)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/doubleQuoteFontColor", QColor(Qt.blue))), 3)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/tripleSingleQuoteFontColor", QColor(Qt.blue))), 6)
        self.lexer.setColor(QColor(self.settings.value("pythonConsole/tripleDoubleQuoteFontColor", QColor(Qt.blue))), 7)
        self.lexer.setColor(QColor(Qt.red), 14)
        self.lexer.setFont(font, 1)
        self.lexer.setFont(font, 2)
        self.lexer.setFont(font, 3)
        self.lexer.setFont(font, 4)

        for style in range(0, 33):
            paperColor = QColor(self.settings.value("pythonConsole/paperBackgroundColor", QColor(Qt.white)))
            self.lexer.setPaper(paperColor, style)

        self.setLexer(self.lexer)

    def clearConsole(self):
        self.setText('')
        self.insertInitText()
        self.shell.setFocus()

    def contextMenuEvent(self, e):
        menu = QMenu(self)
        iconRun = QgsApplication.getThemeIcon("console/iconRunConsole.png")
        iconClear = QgsApplication.getThemeIcon("console/iconClearConsole.png")
        iconHideTool = QgsApplication.getThemeIcon("console/iconHideToolConsole.png")
        iconSettings = QgsApplication.getThemeIcon("console/iconSettingsConsole.png")
        menu.addAction(iconHideTool,
                       QCoreApplication.translate("PythonConsole", "Hide/Show Toolbar"),
                       self.hideToolBar)
        menu.addSeparator()
        showEditorAction = menu.addAction(
            QCoreApplication.translate("PythonConsole", "Show Editor"),
            self.showEditor)
        menu.addSeparator()
        runAction = menu.addAction(iconRun,
                                   QCoreApplication.translate("PythonConsole", "Enter Selected"),
                                   self.enteredSelected,
                                   QKeySequence(Qt.CTRL + Qt.Key_E))
        clearAction = menu.addAction(iconClear,
                                     QCoreApplication.translate("PythonConsole", "Clear console"),
                                     self.clearConsole)
        menu.addSeparator()
        copyAction = menu.addAction(
            QCoreApplication.translate("PythonConsole", "Copy"),
            self.copy, QKeySequence.Copy)
        menu.addSeparator()
        selectAllAction = menu.addAction(
            QCoreApplication.translate("PythonConsole", "Select All"),
            self.selectAll, QKeySequence.SelectAll)
        menu.addSeparator()
        menu.addAction(iconSettings,
                       QCoreApplication.translate("PythonConsole", "Settings"),
                       self.parent.openSettings)
        runAction.setEnabled(False)
        clearAction.setEnabled(False)
        copyAction.setEnabled(False)
        selectAllAction.setEnabled(False)
        showEditorAction.setEnabled(True)
        if self.hasSelectedText():
            runAction.setEnabled(True)
            copyAction.setEnabled(True)
        if not self.text(3) == '':
            selectAllAction.setEnabled(True)
            clearAction.setEnabled(True)
        if self.parent.tabEditorWidget.isVisible():
            showEditorAction.setEnabled(False)
        menu.exec_(self.mapToGlobal(e.pos()))

    def hideToolBar(self):
        tB = self.parent.toolBar
        tB.hide() if tB.isVisible() else tB.show()
        self.shell.setFocus()

    def showEditor(self):
        Ed = self.parent.splitterObj
        if not Ed.isVisible():
            Ed.show()
            self.parent.showEditorButton.setChecked(True)
        self.shell.setFocus()

    def copy(self):
        """Copy text to clipboard... or keyboard interrupt"""
        if self.hasSelectedText():
            text = unicode(self.selectedText())
            text = text.replace('>>> ', '').replace('... ', '').strip() # removing prompts
            QApplication.clipboard().setText(text)
        else:
            self.emit(SIGNAL("keyboard_interrupt()"))

    def enteredSelected(self):
        cmd = self.selectedText()
        self.shell.insertFromDropPaste(cmd)
        self.shell.entered()

    def keyPressEvent(self, e):
        # empty text indicates possible shortcut key sequence so stay in output
        txt = e.text()
        if len(txt) and txt >= " ":
            self.shell.append(txt)
            self.shell.move_cursor_to_end()
            self.shell.setFocus()
            e.ignore()
        else:
            # possible shortcut key sequence, accept it
            e.accept()

    def widgetMessageBar(self, iface, text):
        timeout = iface.messageTimeout()
        self.infoBar.pushMessage(text, QgsMessageBar.INFO, timeout)
Ejemplo n.º 24
0
class ScintillaPythonEditBox(QsciScintilla, BasePythonEditBox):
    def __init__(self, parent=None):
        QsciScintilla.__init__(self, parent)

        self.lexer = None
        self.api = None
        self.lexerType = -1

        self.setCommonOptions()
        self.initShortcuts()

    def setCommonOptions(self):
        # Enable non-ASCII characters
        self.setUtf8(True)

        # Default font
        # Load font from Python console settings
        settings = QSettings()
        fontName = settings.value('pythonConsole/fontfamilytext', 'Monospace')
        fontSize = int(settings.value('pythonConsole/fontsize', 10))

        self.defaultFont = QFont(fontName)
        self.defaultFont.setFixedPitch(True)
        self.defaultFont.setPointSize(fontSize)
        self.defaultFont.setStyleHint(QFont.TypeWriter)
        self.defaultFont.setStretch(QFont.SemiCondensed)
        self.defaultFont.setLetterSpacing(QFont.PercentageSpacing, 87.0)
        self.defaultFont.setBold(False)

        self.boldFont = QFont(self.defaultFont)
        self.boldFont.setBold(True)

        self.italicFont = QFont(self.defaultFont)
        self.italicFont.setItalic(True)

        self.setFont(self.defaultFont)
        self.setMarginsFont(self.defaultFont)

        self.setFont(self.defaultFont)
        self.setMarginsFont(self.defaultFont)

        self.initLexer()

        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)

        self.setWrapMode(QsciScintilla.WrapWord)
        self.setWrapVisualFlags(QsciScintilla.WrapFlagByText,
                                QsciScintilla.WrapFlagNone, 4)

        self.setSelectionForegroundColor(QColor('#2e3436'))
        self.setSelectionBackgroundColor(QColor('#babdb6'))

        # Show line numbers
        self.setMarginWidth(1, '000')
        self.setMarginLineNumbers(1, True)
        self.setMarginsForegroundColor(QColor('#2e3436'))
        self.setMarginsBackgroundColor(QColor('#babdb6'))

        # Highlight current line
        self.setCaretLineVisible(True)
        self.setCaretLineBackgroundColor(QColor('#d3d7cf'))

        # Mark column 80 with vertical line
        self.setEdgeMode(QsciScintilla.EdgeLine)
        self.setEdgeColumn(80)
        self.setEdgeColor(QColor('#eeeeec'))

        # Indentation
        self.setAutoIndent(True)
        self.setIndentationsUseTabs(False)
        self.setIndentationWidth(4)
        self.setTabIndents(True)
        self.setBackspaceUnindents(True)
        self.setTabWidth(4)

        # Autocomletion
        self.setAutoCompletionThreshold(2)
        self.setAutoCompletionSource(QsciScintilla.AcsAll)

    def initShortcuts(self):
        (ctrl, shift) = (self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16)

        # Disable some shortcuts
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY,
                           ord('L') + ctrl + shift)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl)

        #self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl)
        #self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl)

        # Use Ctrl+Space for autocompletion
        self.shortcutAutocomplete = QShortcut(
            QKeySequence(Qt.CTRL + Qt.Key_Space), self)
        self.shortcutAutocomplete.setContext(Qt.WidgetShortcut)
        self.shortcutAutocomplete.activated.connect(self.autoComplete)

    def autoComplete(self):
        self.autoCompleteFromAll()

    def setLexerType(self, lexerType):
        self.lexerType = lexerType
        self.initLexer()

    def initLexer(self):
        self.lexer = QsciLexerPython()

        colorDefault = QColor('#2e3436')
        colorComment = QColor('#c00')
        colorCommentBlock = QColor('#3465a4')
        colorNumber = QColor('#4e9a06')
        colorType = QColor('#4e9a06')
        colorKeyword = QColor('#204a87')
        colorString = QColor('#ce5c00')

        self.lexer.setDefaultFont(self.defaultFont)
        self.lexer.setDefaultColor(colorDefault)

        self.lexer.setColor(colorComment, 1)
        self.lexer.setColor(colorNumber, 2)
        self.lexer.setColor(colorString, 3)
        self.lexer.setColor(colorString, 4)
        self.lexer.setColor(colorKeyword, 5)
        self.lexer.setColor(colorString, 6)
        self.lexer.setColor(colorString, 7)
        self.lexer.setColor(colorType, 8)
        self.lexer.setColor(colorCommentBlock, 12)
        self.lexer.setColor(colorString, 15)

        self.lexer.setFont(self.italicFont, 1)
        self.lexer.setFont(self.boldFont, 5)
        self.lexer.setFont(self.boldFont, 8)
        self.lexer.setFont(self.italicFont, 12)

        self.api = QsciAPIs(self.lexer)

        settings = QSettings()
        useDefaultAPI = bool(settings.value('pythonConsole/preloadAPI', True))
        if useDefaultAPI:
            # Load QGIS API shipped with Python console
            self.api.loadPrepared(
                os.path.join(QgsApplication.pkgDataPath(), 'python',
                             'qsci_apis', 'pyqgis.pap'))
        else:
            # Load user-defined API files
            apiPaths = settings.value('pythonConsole/userAPI', [])
            for path in apiPaths:
                self.api.load(path)
            self.api.prepare()
            self.lexer.setAPIs(self.api)

        self.setLexer(self.lexer)

    #impliment base editor
    def insertPlainText(self, text):
        self.insert(text)
        pos = self.getCursorPosition()
        self.setCursorPosition(pos[0], pos[1] + len(text))

    def toPlainText(self):
        return self.text()

    def get_font_size(self):
        return self.font().pointSize()

    def set_font_size(self, new_point_size):
        font = self.font()
        self.setFont(QFont(font.family(), new_point_size))

    def wheelEvent(self, event):
        if event.modifiers() == Qt.ControlModifier:
            self.emit(SIGNAL("wheelEvent(QWheelEvent)"), event)
        else:
            super(ScintillaPythonEditBox, self).wheelEvent(event)
Ejemplo n.º 25
0
class ScriptEdit(QsciScintilla):

    LEXER_PYTHON = 0
    LEXER_R = 1

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

        self.lexer = None
        self.api = None
        self.lexerType = -1

        self.setCommonOptions()
        self.initShortcuts()

    def setCommonOptions(self):
        # Enable non-ASCII characters
        self.setUtf8(True)

        # Default font
        font = QFont()
        font.setFamily('Courier')
        font.setFixedPitch(True)
        font.setPointSize(20)
        self.setFont(font)
        self.setMarginsFont(font)

        self.initLexer()

        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)

        self.setWrapMode(QsciScintilla.WrapWord)
        self.setWrapVisualFlags(QsciScintilla.WrapFlagByText,
                                QsciScintilla.WrapFlagNone, 4)

        self.setSelectionForegroundColor(QColor('#2e3436'))
        self.setSelectionBackgroundColor(QColor('#babdb6'))

        # Show line numbers
        self.setMarginWidth(1, '000')
        self.setMarginLineNumbers(1, True)
        self.setMarginsForegroundColor(QColor('#2e3436'))
        self.setMarginsBackgroundColor(QColor('#babdb6'))

        # Highlight current line
        self.setCaretLineVisible(True)
        self.setCaretLineBackgroundColor(QColor('#d3d7cf'))

        # Folding
        self.setFolding(QsciScintilla.BoxedTreeFoldStyle)
        self.setFoldMarginColors(QColor('#d3d7cf'), QColor('#d3d7cf'))

        # Mark column 80 with vertical line
        self.setEdgeMode(QsciScintilla.EdgeLine)
        self.setEdgeColumn(80)
        self.setEdgeColor(QColor('#eeeeec'))

        # Indentation
        self.setAutoIndent(True)
        self.setIndentationsUseTabs(False)
        self.setIndentationWidth(4)
        self.setTabIndents(True)
        self.setBackspaceUnindents(True)
        self.setTabWidth(4)

        # Autocomletion
        self.setAutoCompletionThreshold(2)
        self.setAutoCompletionSource(QsciScintilla.AcsAPIs)

        self.setFonts(10)

    def setFonts(self, size):

        # Load font from Python console settings
        settings = QSettings()
        fontName = settings.value('pythonConsole/fontfamilytext', 'Monospace')
        fontSize = int(settings.value('pythonConsole/fontsize', size))

        self.defaultFont = QFont(fontName)
        self.defaultFont.setFixedPitch(True)
        self.defaultFont.setPointSize(fontSize)
        self.defaultFont.setStyleHint(QFont.TypeWriter)
        self.defaultFont.setStretch(QFont.SemiCondensed)
        self.defaultFont.setLetterSpacing(QFont.PercentageSpacing, 87.0)
        self.defaultFont.setBold(False)

        self.boldFont = QFont(self.defaultFont)
        self.boldFont.setBold(True)

        self.italicFont = QFont(self.defaultFont)
        self.italicFont.setItalic(True)

        self.setFont(self.defaultFont)
        self.setMarginsFont(self.defaultFont)

    def initShortcuts(self):
        (ctrl, shift) = (self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16)

        # Disable some shortcuts
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl
                           + shift)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl)

        #self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl)
        #self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl)

        # Use Ctrl+Space for autocompletion
        self.shortcutAutocomplete = QShortcut(QKeySequence(Qt.CTRL
                                                           + Qt.Key_Space), self)
        self.shortcutAutocomplete.setContext(Qt.WidgetShortcut)
        self.shortcutAutocomplete.activated.connect(self.autoComplete)

    def autoComplete(self):
        self.autoCompleteFromAll()

    def setLexerType(self, lexerType):
        self.lexerType = lexerType
        self.initLexer()

    def initLexer(self):
        if self.lexerType == self.LEXER_PYTHON:
            self.lexer = QsciLexerPython()

            colorDefault = QColor('#2e3436')
            colorComment = QColor('#c00')
            colorCommentBlock = QColor('#3465a4')
            colorNumber = QColor('#4e9a06')
            colorType = QColor('#4e9a06')
            colorKeyword = QColor('#204a87')
            colorString = QColor('#ce5c00')

            self.lexer.setDefaultFont(self.defaultFont)
            self.lexer.setDefaultColor(colorDefault)

            self.lexer.setColor(colorComment, 1)
            self.lexer.setColor(colorNumber, 2)
            self.lexer.setColor(colorString, 3)
            self.lexer.setColor(colorString, 4)
            self.lexer.setColor(colorKeyword, 5)
            self.lexer.setColor(colorString, 6)
            self.lexer.setColor(colorString, 7)
            self.lexer.setColor(colorType, 8)
            self.lexer.setColor(colorCommentBlock, 12)
            self.lexer.setColor(colorString, 15)

            self.lexer.setFont(self.italicFont, 1)
            self.lexer.setFont(self.boldFont, 5)
            self.lexer.setFont(self.boldFont, 8)
            self.lexer.setFont(self.italicFont, 12)

            self.api = QsciAPIs(self.lexer)

            settings = QSettings()
            useDefaultAPI = bool(settings.value('pythonConsole/preloadAPI',
                                                True))
            if useDefaultAPI:
                # Load QGIS API shipped with Python console
                self.api.loadPrepared(
                    os.path.join(QgsApplication.pkgDataPath(),
                                 'python', 'qsci_apis', 'pyqgis.pap'))
            else:
                # Load user-defined API files
                apiPaths = settings.value('pythonConsole/userAPI', [])
                for path in apiPaths:
                    self.api.load(path)
                self.api.prepare()
                self.lexer.setAPIs(self.api)
        elif self.lexerType == self.LEXER_R:
            # R lexer
            self.lexer = LexerR()

        self.setLexer(self.lexer)
Ejemplo n.º 26
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.º 27
0
class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
                        InspectObjectMixin):
    """Python shell widget"""
    QT_CLASS = ShellBaseWidget

    INITHISTORY = [
        '# -*- coding: utf-8 -*-',
        '# *** Spyder Python Console History Log ***',
    ]
    SEPARATOR = '%s##---(%s)---' % (os.linesep * 2, time.ctime())

    def __init__(self, parent, history_filename, profile=False):
        ShellBaseWidget.__init__(self, parent, history_filename, profile)
        TracebackLinksMixin.__init__(self)
        InspectObjectMixin.__init__(self)

        # Local shortcuts
        self.inspectsc = QShortcut(QKeySequence("Ctrl+I"), self,
                                   self.inspect_current_object)
        self.inspectsc.setContext(Qt.WidgetWithChildrenShortcut)

    def get_shortcut_data(self):
        """
        Returns shortcut data, a list of tuples (shortcut, text, default)
        shortcut (QShortcut or QAction instance)
        text (string): action/shortcut description
        default (string): default key sequence
        """
        return [
            (self.inspectsc, "Inspect current object", "Ctrl+I"),
        ]

    #------ Context menu
    def setup_context_menu(self):
        """Reimplements ShellBaseWidget method"""
        ShellBaseWidget.setup_context_menu(self)
        self.copy_without_prompts_action = create_action(
            self,
            _("Copy without prompts"),
            icon=get_icon('copywop.png'),
            triggered=self.copy_without_prompts)
        clear_line_action = create_action(self,
                                          _("Clear line"),
                                          QKeySequence("Shift+Escape"),
                                          icon=get_icon('eraser.png'),
                                          tip=_("Clear line"),
                                          triggered=self.clear_line)
        clear_action = create_action(self,
                                     _("Clear shell"),
                                     QKeySequence("Ctrl+L"),
                                     icon=get_icon('clear.png'),
                                     tip=_("Clear shell contents "
                                           "('cls' command)"),
                                     triggered=self.clear_terminal)
        add_actions(self.menu, (self.copy_without_prompts_action,
                                clear_line_action, clear_action))

    def contextMenuEvent(self, event):
        """Reimplements ShellBaseWidget method"""
        state = self.has_selected_text()
        self.copy_without_prompts_action.setEnabled(state)
        ShellBaseWidget.contextMenuEvent(self, event)

    def copy_without_prompts(self):
        """Copy text to clipboard without prompts"""
        text = self.get_selected_text()
        lines = text.split(os.linesep)
        for index, line in enumerate(lines):
            if line.startswith('>>> ') or line.startswith('... '):
                lines[index] = line[4:]
        text = os.linesep.join(lines)
        QApplication.clipboard().setText(text)

    #------ Key handlers
    def postprocess_keyevent(self, event):
        """Process keypress event"""
        ShellBaseWidget.postprocess_keyevent(self, event)
        if QToolTip.isVisible():
            _event, _text, key, _ctrl, _shift = restore_keyevent(event)
            self.hide_tooltip_if_necessary(key)

    def _key_other(self, text):
        """1 character key"""
        if self.is_completion_widget_visible():
            self.completion_text += text

    def _key_backspace(self, cursor_position):
        """Action for Backspace key"""
        if self.has_selected_text():
            self.check_selection()
            self.remove_selected_text()
        elif self.current_prompt_pos == cursor_position:
            # Avoid deleting prompt
            return
        elif self.is_cursor_on_last_line():
            self.stdkey_backspace()
            if self.is_completion_widget_visible():
                # Removing only last character because if there was a selection
                # the completion widget would have been canceled
                self.completion_text = self.completion_text[:-1]

    def _key_tab(self):
        """Action for TAB key"""
        if self.is_cursor_on_last_line():
            empty_line = not self.get_current_line_to_cursor().strip()
            if empty_line:
                self.stdkey_tab()
            else:
                self.show_code_completion(automatic=False)

    def _key_ctrl_space(self):
        """Action for Ctrl+Space"""
        if not self.is_completion_widget_visible():
            self.show_code_completion(automatic=False)

    def _key_pageup(self):
        """Action for PageUp key"""
        pass

    def _key_pagedown(self):
        """Action for PageDown key"""
        pass

    def _key_escape(self):
        """Action for ESCAPE key"""
        if self.is_completion_widget_visible():
            self.hide_completion_widget()

    def _key_question(self, text):
        """Action for '?'"""
        if self.get_current_line_to_cursor():
            last_obj = self.get_last_obj()
            if last_obj and not last_obj.isdigit():
                self.show_docstring(last_obj)
        self.insert_text(text)
        # In case calltip and completion are shown at the same time:
        if self.is_completion_widget_visible():
            self.completion_text += '?'

    def _key_parenleft(self, text):
        """Action for '('"""
        self.hide_completion_widget()
        if self.get_current_line_to_cursor():
            last_obj = self.get_last_obj()
            if last_obj and not last_obj.isdigit():
                self.show_docstring(last_obj, call=True)
        self.insert_text(text)

    def _key_period(self, text):
        """Action for '.'"""
        self.insert_text(text)
        if self.codecompletion_auto:
            # Enable auto-completion only if last token isn't a float
            last_obj = self.get_last_obj()
            if last_obj and not last_obj.isdigit():
                self.show_code_completion(automatic=True)

    #------ Paste
    def paste(self):
        """Reimplemented slot to handle multiline paste action"""
        text = unicode(QApplication.clipboard().text())
        if len(text.splitlines()) > 1:
            # Multiline paste
            if self.new_input_line:
                self.on_new_line()
            self.remove_selected_text()  # Remove selection, eventually
            end = self.get_current_line_from_cursor()
            lines = self.get_current_line_to_cursor() + text + end
            self.clear_line()
            self.execute_lines(lines)
            self.move_cursor(-len(end))
        else:
            # Standard paste
            ShellBaseWidget.paste(self)

    #------ Code Completion / Calltips
    # Methods implemented in child class:
    # (e.g. InternalShell)
    def get_dir(self, objtxt):
        """Return dir(object)"""
        raise NotImplementedError

    def get_module_completion(self, objtxt):
        """Return module completion list associated to object name"""
        pass

    def get_globals_keys(self):
        """Return shell globals() keys"""
        raise NotImplementedError

    def get_cdlistdir(self):
        """Return shell current directory list dir"""
        raise NotImplementedError

    def iscallable(self, objtxt):
        """Is object callable?"""
        raise NotImplementedError

    def get_arglist(self, objtxt):
        """Get func/method argument list"""
        raise NotImplementedError

    def get__doc__(self, objtxt):
        """Get object __doc__"""
        raise NotImplementedError

    def get_doc(self, objtxt):
        """Get object documentation"""
        raise NotImplementedError

    def get_source(self, objtxt):
        """Get object source"""
        raise NotImplementedError

    def is_defined(self, objtxt, force_import=False):
        """Return True if object is defined"""
        raise NotImplementedError

    def show_code_completion(self, automatic):
        """Display a completion list based on the current line"""
        # Note: unicode conversion is needed only for ExternalShellBase
        text = unicode(self.get_current_line_to_cursor())
        last_obj = self.get_last_obj()

        if text.startswith('import '):
            obj_list = self.get_module_completion(text)
            words = text.split(' ')
            if ',' in words[-1]:
                words = words[-1].split(',')
            self.show_completion_list(obj_list,
                                      completion_text=words[-1],
                                      automatic=automatic)
            return

        elif text.startswith('from '):
            obj_list = self.get_module_completion(text)
            if obj_list is None:
                return
            words = text.split(' ')
            if '(' in words[-1]:
                words = words[:-2] + words[-1].split('(')
            if ',' in words[-1]:
                words = words[:-2] + words[-1].split(',')
            self.show_completion_list(obj_list,
                                      completion_text=words[-1],
                                      automatic=automatic)
            return

        obj_dir = self.get_dir(last_obj)
        if last_obj and obj_dir and text.endswith('.'):
            self.show_completion_list(obj_dir, automatic=automatic)
            return

        # Builtins and globals
        import __builtin__, keyword
        if not text.endswith('.') and last_obj \
           and re.match(r'[a-zA-Z_0-9]*$', last_obj):
            b_k_g = dir(__builtin__) + self.get_globals_keys() + keyword.kwlist
            for objname in b_k_g:
                if objname.startswith(last_obj) and objname != last_obj:
                    self.show_completion_list(b_k_g,
                                              completion_text=last_obj,
                                              automatic=automatic)
                    return
            else:
                return

        # Looking for an incomplete completion
        if last_obj is None:
            last_obj = text
        dot_pos = last_obj.rfind('.')
        if dot_pos != -1:
            if dot_pos == len(last_obj) - 1:
                completion_text = ""
            else:
                completion_text = last_obj[dot_pos + 1:]
                last_obj = last_obj[:dot_pos]
            completions = self.get_dir(last_obj)
            if completions is not None:
                self.show_completion_list(completions,
                                          completion_text=completion_text,
                                          automatic=automatic)
                return

        # Looking for ' or ": filename completion
        q_pos = max([text.rfind("'"), text.rfind('"')])
        if q_pos != -1:
            completions = self.get_cdlistdir()
            if completions:
                self.show_completion_list(completions,
                                          completion_text=text[q_pos + 1:],
                                          automatic=automatic)
            return

    #------ Drag'n Drop
    def drop_pathlist(self, pathlist):
        """Drop path list"""
        if pathlist:
            files = ["r'%s'" % path for path in pathlist]
            if len(files) == 1:
                text = files[0]
            else:
                text = "[" + ", ".join(files) + "]"
            if self.new_input_line:
                self.on_new_line()
            self.insert_text(text)
            self.setFocus()
Ejemplo n.º 28
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.º 29
0
class FindReplace(QWidget):
    """
    Find widget
    
    Signals:
        visibility_changed(bool)
    """
    STYLE = {False: "background-color:rgb(255, 175, 90);",
             True: ""}
    def __init__(self, parent, enable_replace=False):
        QWidget.__init__(self, parent)
        self.enable_replace = enable_replace
        self.editor = None
        self.is_code_editor = None
        
        glayout = QGridLayout()
        glayout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(glayout)
        
        self.close_button = create_toolbutton(self, triggered=self.hide,
                                      icon=get_std_icon("DialogCloseButton"))
        glayout.addWidget(self.close_button, 0, 0)
        
        # Find layout
        self.search_text = PatternComboBox(self, tip=_("Search string"),
                                           adjust_to_minimum=False)
        self.connect(self.search_text, SIGNAL('valid(bool)'),
                     lambda state:
                     self.find(changed=False, forward=True, rehighlight=False))
        self.connect(self.search_text.lineEdit(),
                     SIGNAL("textEdited(QString)"), self.text_has_been_edited)
        
        self.previous_button = create_toolbutton(self,
                                             triggered=self.find_previous,
                                             icon=get_std_icon("ArrowBack"))
        self.next_button = create_toolbutton(self,
                                             triggered=self.find_next,
                                             icon=get_std_icon("ArrowForward"))
        self.connect(self.next_button, SIGNAL('clicked()'),
                     self.update_search_combo)
        self.connect(self.previous_button, SIGNAL('clicked()'),
                     self.update_search_combo)

        self.re_button = create_toolbutton(self, icon=get_icon("advanced.png"),
                                           tip=_("Regular expression"))
        self.re_button.setCheckable(True)
        self.connect(self.re_button, SIGNAL("toggled(bool)"),
                     lambda state: self.find())
        
        self.case_button = create_toolbutton(self,
                                             icon=get_icon("upper_lower.png"),
                                             tip=_("Case Sensitive"))
        self.case_button.setCheckable(True)
        self.connect(self.case_button, SIGNAL("toggled(bool)"),
                     lambda state: self.find())
                     
        self.words_button = create_toolbutton(self,
                                              icon=get_icon("whole_words.png"),
                                              tip=_("Whole words"))
        self.words_button.setCheckable(True)
        self.connect(self.words_button, SIGNAL("toggled(bool)"),
                     lambda state: self.find())
                     
        self.highlight_button = create_toolbutton(self,
                                              icon=get_icon("highlight.png"),
                                              tip=_("Highlight matches"))
        self.highlight_button.setCheckable(True)
        self.connect(self.highlight_button, SIGNAL("toggled(bool)"),
                     self.toggle_highlighting)

        hlayout = QHBoxLayout()
        self.widgets = [self.close_button, self.search_text,
                        self.previous_button, self.next_button,
                        self.re_button, self.case_button, self.words_button,
                        self.highlight_button]
        for widget in self.widgets[1:]:
            hlayout.addWidget(widget)
        glayout.addLayout(hlayout, 0, 1)

        # Replace layout
        replace_with = QLabel(_("Replace with:"))
        self.replace_text = PatternComboBox(self, adjust_to_minimum=False,
                                            tip=_("Replace string"))
        
        self.replace_button = create_toolbutton(self,
                                     text=_("Replace/find"),
                                     icon=get_std_icon("DialogApplyButton"),
                                     triggered=self.replace_find,
                                     text_beside_icon=True)
        self.connect(self.replace_button, SIGNAL('clicked()'),
                     self.update_replace_combo)
        self.connect(self.replace_button, SIGNAL('clicked()'),
                     self.update_search_combo)
        
        self.all_check = QCheckBox(_("Replace all"))
        
        self.replace_layout = QHBoxLayout()
        widgets = [replace_with, self.replace_text, self.replace_button,
                   self.all_check]
        for widget in widgets:
            self.replace_layout.addWidget(widget)
        glayout.addLayout(self.replace_layout, 1, 1)
        self.widgets.extend(widgets)
        self.replace_widgets = widgets
        self.hide_replace()
        
        self.search_text.setTabOrder(self.search_text, self.replace_text)
        
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        
        self.findnext_sc = QShortcut(QKeySequence("F3"), parent,
                                     self.find_next)
        self.findnext_sc.setContext(Qt.WidgetWithChildrenShortcut)
        self.findprev_sc = QShortcut(QKeySequence("Shift+F3"), parent,
                                     self.find_previous)
        self.findprev_sc.setContext(Qt.WidgetWithChildrenShortcut)
        self.togglefind_sc = QShortcut(QKeySequence("Ctrl+F"), parent,
                                       self.show)
        self.togglefind_sc.setContext(Qt.WidgetWithChildrenShortcut)
        self.togglereplace_sc = QShortcut(QKeySequence("Ctrl+H"), parent,
                                          self.toggle_replace_widgets)
        self.togglereplace_sc.setContext(Qt.WidgetWithChildrenShortcut)
        
        escape_sc = QShortcut(QKeySequence("Escape"), parent, self.hide)
        escape_sc.setContext(Qt.WidgetWithChildrenShortcut)

        self.highlight_timer = QTimer(self)
        self.highlight_timer.setSingleShot(True)
        self.highlight_timer.setInterval(1000)
        self.connect(self.highlight_timer, SIGNAL("timeout()"),
                     self.highlight_matches)
        
    def get_shortcut_data(self):
        """
        Returns shortcut data, a list of tuples (shortcut, text, default)
        shortcut (QShortcut or QAction instance)
        text (string): action/shortcut description
        default (string): default key sequence
        """
        return [(self.findnext_sc, "Find next", "F3"),
                (self.findprev_sc, "Find previous", "Shift+F3"),
                (self.togglefind_sc, "Find text", "Ctrl+F"),
                (self.togglereplace_sc, "Replace text", "Ctrl+H"),]
        
    def update_search_combo(self):
        self.search_text.lineEdit().emit(SIGNAL('returnPressed()'))
        
    def update_replace_combo(self):
        self.replace_text.lineEdit().emit(SIGNAL('returnPressed()'))
    
    def toggle_replace_widgets(self):
        if self.enable_replace:
            # Toggle replace widgets
            if self.replace_widgets[0].isVisible():
                self.hide_replace()
                self.hide()
            else:
                self.show_replace()
                self.replace_text.setFocus()
                
    def toggle_highlighting(self, state):
        """Toggle the 'highlight all results' feature"""
        if self.editor is not None:
            if state:
                self.highlight_matches()
            else:
                self.clear_matches()
        
    def show(self):
        """Overrides Qt Method"""
        QWidget.show(self)
        self.emit(SIGNAL("visibility_changed(bool)"), True)
        if self.editor is not None:
            text = self.editor.get_selected_text()
            if len(text) > 0:
                self.search_text.setEditText(text)
                self.search_text.lineEdit().selectAll()
                self.refresh()
            else:
                self.search_text.lineEdit().selectAll()
            self.search_text.setFocus()
        
    def hide(self):
        """Overrides Qt Method"""
        for widget in self.replace_widgets:
            widget.hide()
        QWidget.hide(self)
        self.emit(SIGNAL("visibility_changed(bool)"), False)
        if self.editor is not None:
            self.editor.setFocus()
            self.clear_matches()
        
    def show_replace(self):
        """Show replace widgets"""
        self.show()
        for widget in self.replace_widgets:
            widget.show()
            
    def hide_replace(self):
        """Hide replace widgets"""
        for widget in self.replace_widgets:
            widget.hide()
        
    def refresh(self):
        """Refresh widget"""
        if self.isHidden():
            if self.editor is not None:
                self.clear_matches()
            return
        state = self.editor is not None
        for widget in self.widgets:
            widget.setEnabled(state)
        if state:
            self.find()
            
    def set_editor(self, editor, refresh=True):
        """
        Set associated editor/web page:
            codeeditor.base.TextEditBaseWidget
            browser.WebView
        """
        self.editor = editor
        from PyQt4.QtWebKit import QWebView
        self.words_button.setVisible(not isinstance(editor, QWebView))
        self.re_button.setVisible(not isinstance(editor, QWebView))
        from SMlib.widgets.sourcecode.codeeditor import CodeEditor
        self.is_code_editor = isinstance(editor, CodeEditor)
        self.highlight_button.setVisible(self.is_code_editor)
        if refresh:
            self.refresh()
        if self.isHidden() and editor is not None:
            self.clear_matches()
        
    def find_next(self):
        """Find next occurence"""
        state = self.find(changed=False, forward=True, rehighlight=False)
        self.editor.setFocus()
        self.search_text.add_current_text()
        return state
        
    def find_previous(self):
        """Find previous occurence"""
        state = self.find(changed=False, forward=False, rehighlight=False)
        self.editor.setFocus()
        return state

    def text_has_been_edited(self, text):
        """Find text has been edited (this slot won't be triggered when 
        setting the search pattern combo box text programmatically"""
        self.find(changed=True, forward=True, start_highlight_timer=True)
        
    def highlight_matches(self):
        """Highlight found results"""
        if self.is_code_editor and self.highlight_button.isChecked():
            text = self.search_text.currentText()
            words = self.words_button.isChecked()
            regexp = self.re_button.isChecked()
            self.editor.highlight_found_results(text, words=words,
                                                regexp=regexp)
                                                
    def clear_matches(self):
        """Clear all highlighted matches"""
        if self.is_code_editor:
            self.editor.clear_found_results()
        
    def find(self, changed=True, forward=True,
             rehighlight=True, start_highlight_timer=False):
        """Call the find function"""
        text = self.search_text.currentText()
        if len(text) == 0:
            self.search_text.lineEdit().setStyleSheet("")
            return None
        else:
            case = self.case_button.isChecked()
            words = self.words_button.isChecked()
            regexp = self.re_button.isChecked()
            found = self.editor.find_text(text, changed, forward, case=case,
                                          words=words, regexp=regexp)
            self.search_text.lineEdit().setStyleSheet(self.STYLE[found])
            if self.is_code_editor and found:
                if rehighlight or not self.editor.found_results:
                    self.highlight_timer.stop()
                    if start_highlight_timer:
                        self.highlight_timer.start()
                    else:
                        self.highlight_matches()
            else:
                self.clear_matches()
            return found
            
    def replace_find(self):
        """Replace and find"""
        if (self.editor is not None):
            replace_text = unicode(self.replace_text.currentText())
            search_text = unicode(self.search_text.currentText())
            pattern = search_text if self.re_button.isChecked() else None
            case = self.case_button.isChecked()
            first = True
            cursor = None
            while True:
                if first:
                    # First found
                    seltxt = unicode(self.editor.get_selected_text())
                    cmptxt1 = search_text if case else search_text.lower()
                    cmptxt2 = seltxt if case else seltxt.lower()
                    if self.editor.has_selected_text() and cmptxt1 == cmptxt2:
                        # Text was already found, do nothing
                        pass
                    else:
                        if not self.find(changed=False, forward=True,
                                         rehighlight=False):
                            break
                    first = False
                    wrapped = False
                    position = self.editor.get_position('cursor')
                    position0 = position
                    cursor = self.editor.textCursor()
                    cursor.beginEditBlock()
                else:
                    position1 = self.editor.get_position('cursor')
                    if wrapped:
                        if position1 == position or \
                           is_position_sup(position1, position):
                            # Avoid infinite loop: replace string includes
                            # part of the search string
                            break
                    if position1 == position0:
                        # Avoid infinite loop: single found occurence
                        break
                    if is_position_inf(position1, position0):
                        wrapped = True
                    position0 = position1
                if pattern is None:
                    cursor.removeSelectedText()
                    cursor.insertText(replace_text)
                else:
                    seltxt = unicode(cursor.selectedText())
                    cursor.removeSelectedText()
                    cursor.insertText(re.sub(pattern, replace_text, seltxt))
                if self.find_next():
                    found_cursor = self.editor.textCursor()
                    cursor.setPosition(found_cursor.selectionStart(),
                                       QTextCursor.MoveAnchor)
                    cursor.setPosition(found_cursor.selectionEnd(),
                                       QTextCursor.KeepAnchor)
                else:
                    break
                if not self.all_check.isChecked():
                    break
            self.all_check.setCheckState(Qt.Unchecked)
            if cursor is not None:
                cursor.endEditBlock()
Ejemplo n.º 30
0
    ui.browse_button.clicked.connect(container.browse)
    ui.vna_browse_button.clicked.connect(container.browse)

    ui.actionAbrir.triggered.connect(container.open_file)
    ui.actionGuardar.triggered.connect(container.save_file)
    ui.actionGuardar_como.triggered.connect(container.save_as_file)
    ui.actionSalir.triggered.connect(container.close)
    ui.actionCalibration.triggered.connect(container.launch_calibration)
    ui.actionCalibration_Presets.triggered.connect(container.launch_preset_calibration)
    ui.actionRI.triggered.connect(container.launch_ri)
    ui.actionContinuo_Alterno.triggered.connect(container.launch_conalt)

    ui.left_button.clicked.connect(container.move_left)
    left_shortcut = QShortcut(QKeySequence(QtCore.Qt.ControlModifier + QtCore.Qt.Key_Left), 
            ui.centralwidget)
    left_shortcut.setContext(QtCore.Qt.ApplicationShortcut)
    left_shortcut.activated.connect(container.move_left)

    ui.right_button.clicked.connect(container.move_right)
    right_shortcut = QShortcut(QKeySequence(QtCore.Qt.ControlModifier + QtCore.Qt.Key_Right),
            ui.centralwidget)
    right_shortcut.setContext(QtCore.Qt.ApplicationShortcut)
    right_shortcut.activated.connect(container.move_right)

    ui.all_checkbox.stateChanged.connect(container.checked_all)

    app.aboutToQuit.connect(container.save_ui)
    restore_ui(ui)
    window.show()
    sys.exit(app.exec_())
Ejemplo n.º 31
0
class ShellScintilla(QsciScintilla, code.InteractiveInterpreter):
    def __init__(self, parent=None):
        super(ShellScintilla, self).__init__(parent)
        code.InteractiveInterpreter.__init__(self, locals=None)

        self.parent = parent

        self.opening = ['(', '{', '[', "'", '"']
        self.closing = [')', '}', ']', "'", '"']

        self.settings = QSettings()

        # Enable non-ascii chars for editor
        self.setUtf8(True)

        self.new_input_line = True

        self.setMarginWidth(0, 0)
        self.setMarginWidth(1, 0)
        self.setMarginWidth(2, 0)

        self.buffer = []

        self.displayPrompt(False)

        for line in _init_commands:
            self.runsource(line)

        self.history = []
        self.historyIndex = 0
        # Read history command file
        self.readHistoryFile()

        self.historyDlg = HistoryDialog(self)

        # Brace matching: enable for a brace immediately before or after
        # the current position
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
        self.setMatchedBraceBackgroundColor(QColor("#b7f907"))

        # Current line visible with special background color
        self.setCaretWidth(2)

        self.refreshSettingsShell()

        # Don't want to see the horizontal scrollbar at all
        # Use raw message to Scintilla here (all messages are documented
        # here: http://www.scintilla.org/ScintillaDoc.html)
        self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)

        # not too small
        #self.setMinimumSize(500, 300)

        self.setWrapMode(QsciScintilla.WrapCharacter)
        self.SendScintilla(QsciScintilla.SCI_EMPTYUNDOBUFFER)

        ## Disable command key
        ctrl, shift = self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('Z') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('Y') + ctrl)
        self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY,
                           ord('L') + ctrl + shift)

        ## New QShortcut = ctrl+space/ctrl+alt+space for Autocomplete
        self.newShortcutCSS = QShortcut(
            QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_Space), self)
        self.newShortcutCAS = QShortcut(
            QKeySequence(Qt.CTRL + Qt.ALT + Qt.Key_Space), self)
        self.newShortcutCSS.setContext(Qt.WidgetShortcut)
        self.newShortcutCAS.setContext(Qt.WidgetShortcut)
        self.newShortcutCAS.activated.connect(self.autoCompleteKeyBinding)
        self.newShortcutCSS.activated.connect(self.showHistory)

    def _setMinimumHeight(self):
        fnt = self.settings.value("pythonConsole/fontfamilytext", "Monospace")
        fntSize = self.settings.value("pythonConsole/fontsize", 10, type=int)
        fm = QFontMetrics(QFont(fnt, fntSize))

        self.setMinimumHeight(fm.height() + 10)

    def refreshSettingsShell(self):
        # Set Python lexer
        self.setLexers()
        threshold = self.settings.value("pythonConsole/autoCompThreshold",
                                        2,
                                        type=int)
        self.setAutoCompletionThreshold(threshold)
        radioButtonSource = self.settings.value(
            "pythonConsole/autoCompleteSource", 'fromAPI')
        autoCompEnabled = self.settings.value(
            "pythonConsole/autoCompleteEnabled", True, type=bool)
        if autoCompEnabled:
            if radioButtonSource == 'fromDoc':
                self.setAutoCompletionSource(self.AcsDocument)
            elif radioButtonSource == 'fromAPI':
                self.setAutoCompletionSource(self.AcsAPIs)
            elif radioButtonSource == 'fromDocAPI':
                self.setAutoCompletionSource(self.AcsAll)
        else:
            self.setAutoCompletionSource(self.AcsNone)

        cursorColor = self.settings.value("pythonConsole/cursorColor",
                                          QColor(Qt.black))
        self.setCaretForegroundColor(cursorColor)

        # Sets minimum height for input area based of font metric
        self._setMinimumHeight()

    def showHistory(self):
        if not self.historyDlg.isVisible():
            self.historyDlg.show()
        self.historyDlg._reloadHistory()
        self.historyDlg.activateWindow()

    def autoCompleteKeyBinding(self):
        radioButtonSource = self.settings.value(
            "pythonConsole/autoCompleteSource", 'fromAPI')
        autoCompEnabled = self.settings.value(
            "pythonConsole/autoCompleteEnabled", True, type=bool)
        if autoCompEnabled:
            if radioButtonSource == 'fromDoc':
                self.autoCompleteFromDocument()
            elif radioButtonSource == 'fromAPI':
                self.autoCompleteFromAPIs()
            elif radioButtonSource == 'fromDocAPI':
                self.autoCompleteFromAll()

    def commandConsole(self, command):
        if not self.is_cursor_on_last_line():
            self.move_cursor_to_end()
        line, pos = self.getCursorPosition()
        selCmdLenght = len(self.text(line))
        self.setSelection(line, 4, line, selCmdLenght)
        self.removeSelectedText()
        if command == "processing":
            # import Processing class
            self.append('import processing')
        elif command == "qtCore":
            # import QtCore class
            self.append('from PyQt4.QtCore import *')
        elif command == "qtGui":
            # import QtGui class
            self.append('from PyQt4.QtGui import *')
        self.entered()
        self.move_cursor_to_end()
        self.setFocus()

    def setLexers(self):
        self.lexer = QsciLexerPython()

        loadFont = self.settings.value("pythonConsole/fontfamilytext",
                                       "Monospace")
        fontSize = self.settings.value("pythonConsole/fontsize", 10, type=int)

        font = QFont(loadFont)
        font.setFixedPitch(True)
        font.setPointSize(fontSize)
        font.setStyleHint(QFont.TypeWriter)
        font.setStretch(QFont.SemiCondensed)
        font.setLetterSpacing(QFont.PercentageSpacing, 87.0)
        font.setBold(False)

        self.lexer.setDefaultFont(font)
        self.lexer.setDefaultColor(
            QColor(
                self.settings.value("pythonConsole/defaultFontColor",
                                    QColor(Qt.black))))
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/commentFontColor",
                                    QColor(Qt.gray))), 1)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/keywordFontColor",
                                    QColor(Qt.darkGreen))), 5)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/classFontColor",
                                    QColor(Qt.blue))), 8)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/methodFontColor",
                                    QColor(Qt.darkGray))), 9)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/decorFontColor",
                                    QColor(Qt.darkBlue))), 15)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/commentBlockFontColor",
                                    QColor(Qt.gray))), 12)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/singleQuoteFontColor",
                                    QColor(Qt.blue))), 4)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/doubleQuoteFontColor",
                                    QColor(Qt.blue))), 3)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/tripleSingleQuoteFontColor",
                                    QColor(Qt.blue))), 6)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/tripleDoubleQuoteFontColor",
                                    QColor(Qt.blue))), 7)
        self.lexer.setFont(font, 1)
        self.lexer.setFont(font, 3)
        self.lexer.setFont(font, 4)

        for style in range(0, 33):
            paperColor = QColor(
                self.settings.value("pythonConsole/paperBackgroundColor",
                                    QColor(Qt.white)))
            self.lexer.setPaper(paperColor, style)

        self.api = QsciAPIs(self.lexer)
        chekBoxAPI = self.settings.value("pythonConsole/preloadAPI",
                                         True,
                                         type=bool)
        chekBoxPreparedAPI = self.settings.value(
            "pythonConsole/usePreparedAPIFile", False, type=bool)
        if chekBoxAPI:
            pap = os.path.join(QgsApplication.pkgDataPath(), "python",
                               "qsci_apis", "pyqgis.pap")
            self.api.loadPrepared(pap)
        elif chekBoxPreparedAPI:
            self.api.loadPrepared(
                self.settings.value("pythonConsole/preparedAPIFile"))
        else:
            apiPath = self.settings.value("pythonConsole/userAPI", [])
            for i in range(0, len(apiPath)):
                self.api.load(unicode(apiPath[i]))
            self.api.prepare()
            self.lexer.setAPIs(self.api)

        self.setLexer(self.lexer)

    ## TODO: show completion list for file and directory

    def getText(self):
        """ Get the text as a unicode string. """
        value = self.getBytes().decode('utf-8')
        # print (value) printing can give an error because the console font
        # may not have all unicode characters
        return value

    def getBytes(self):
        """ Get the text as bytes (utf-8 encoded). This is how
        the data is stored internally. """
        len = self.SendScintilla(self.SCI_GETLENGTH) + 1
        bb = QByteArray(len, '0')
        self.SendScintilla(self.SCI_GETTEXT, len, bb)
        return bytes(bb)[:-1]

    def getTextLength(self):
        return self.SendScintilla(QsciScintilla.SCI_GETLENGTH)

    def get_end_pos(self):
        """Return (line, index) position of the last character"""
        line = self.lines() - 1
        return (line, len(self.text(line)))

    def is_cursor_at_end(self):
        """Return True if cursor is at the end of text"""
        cline, cindex = self.getCursorPosition()
        return (cline, cindex) == self.get_end_pos()

    def move_cursor_to_end(self):
        """Move cursor to end of text"""
        line, index = self.get_end_pos()
        self.setCursorPosition(line, index)
        self.ensureCursorVisible()
        self.ensureLineVisible(line)

    def is_cursor_on_last_line(self):
        """Return True if cursor is on the last line"""
        cline, _ = self.getCursorPosition()
        return cline == self.lines() - 1

    def is_cursor_on_edition_zone(self):
        """ Return True if the cursor is in the edition zone """
        cline, cindex = self.getCursorPosition()
        return cline == self.lines() - 1 and cindex >= 4

    def new_prompt(self, prompt):
        """
        Print a new prompt and save its (line, index) position
        """
        self.write(prompt, prompt=True)
        # now we update our cursor giving end of prompt
        line, index = self.getCursorPosition()
        self.ensureCursorVisible()
        self.ensureLineVisible(line)

    def displayPrompt(self, more=False):
        self.append("... ") if more else self.append(">>> ")
        self.move_cursor_to_end()

    def updateHistory(self, command):
        if isinstance(command, list):
            for line in command:
                self.history.append(line)
        elif not command == "":
            if len(self.history) <= 0 or \
               command != self.history[-1]:
                self.history.append(command)
        self.historyIndex = len(self.history)

    def writeHistoryFile(self, fromCloseConsole=False):
        ok = False
        try:
            wH = codecs.open(_historyFile, 'w', encoding='utf-8')
            for s in self.history:
                wH.write(s + '\n')
            ok = True
        except:
            raise
        wH.close()
        if ok and not fromCloseConsole:
            msgText = QCoreApplication.translate(
                'PythonConsole', 'History saved successfully.')
            self.parent.callWidgetMessageBar(msgText)

    def readHistoryFile(self):
        fileExist = QFile.exists(_historyFile)
        if fileExist:
            rH = codecs.open(_historyFile, 'r', encoding='utf-8')
            for line in rH:
                if line != "\n":
                    l = line.rstrip('\n')
                    self.updateHistory(l)
        else:
            return

    def clearHistory(self, clearSession=False):
        if clearSession:
            self.history = []
            msgText = QCoreApplication.translate(
                'PythonConsole',
                'Session and file history cleared successfully.')
            self.parent.callWidgetMessageBar(msgText)
            return
        ok = False
        try:
            cH = codecs.open(_historyFile, 'w', encoding='utf-8')
            ok = True
        except:
            raise
        cH.close()
        if ok:
            msgText = QCoreApplication.translate(
                'PythonConsole', 'History cleared successfully.')
            self.parent.callWidgetMessageBar(msgText)

    def clearHistorySession(self):
        self.clearHistory(True)

    def showPrevious(self):
        if self.historyIndex < len(self.history) and self.history:
            line, pos = self.getCursorPosition()
            selCmdLenght = len(self.text(line))
            self.setSelection(line, 4, line, selCmdLenght)
            self.removeSelectedText()
            self.historyIndex += 1
            if self.historyIndex == len(self.history):
                self.insert("")
                pass
            else:
                self.insert(self.history[self.historyIndex])
            self.move_cursor_to_end()
            #self.SendScintilla(QsciScintilla.SCI_DELETEBACK)

    def showNext(self):
        if self.historyIndex > 0 and self.history:
            line, pos = self.getCursorPosition()
            selCmdLenght = len(self.text(line))
            self.setSelection(line, 4, line, selCmdLenght)
            self.removeSelectedText()
            self.historyIndex -= 1
            if self.historyIndex == len(self.history):
                self.insert("")
            else:
                self.insert(self.history[self.historyIndex])
            self.move_cursor_to_end()
            #self.SendScintilla(QsciScintilla.SCI_DELETEBACK)

    def keyPressEvent(self, e):
        startLine, startPos, endLine, endPos = self.getSelection()

        # handle invalid cursor position and multiline selections
        if not self.is_cursor_on_edition_zone() or startLine < endLine:
            # allow copying and selecting
            if e.modifiers() & (Qt.ControlModifier | Qt.MetaModifier):
                if e.key() in (Qt.Key_C, Qt.Key_A):
                    QsciScintilla.keyPressEvent(self, e)
                return
            # allow selection
            if e.modifiers() & Qt.ShiftModifier:
                if e.key() in (Qt.Key_Left, Qt.Key_Right, Qt.Key_Home,
                               Qt.Key_End):
                    QsciScintilla.keyPressEvent(self, e)
                return
            # all other keystrokes get sent to the input line
            self.move_cursor_to_end()

        line, index = self.getCursorPosition()
        cmd = self.text(line)

        if e.key() in (Qt.Key_Return,
                       Qt.Key_Enter) and not self.isListActive():
            self.entered()

        elif e.key() in (Qt.Key_Left, Qt.Key_Home):
            QsciScintilla.keyPressEvent(self, e)
            # check whether the cursor is moved out of the edition zone
            newline, newindex = self.getCursorPosition()
            if newline < line or newindex < 4:
                # fix selection and the cursor position
                if self.hasSelectedText():
                    self.setSelection(line, self.getSelection()[3], line, 4)
                else:
                    self.setCursorPosition(line, 4)

        elif e.key() in (Qt.Key_Backspace, Qt.Key_Delete):
            QsciScintilla.keyPressEvent(self, e)
            # check whether the cursor is moved out of the edition zone
            _, newindex = self.getCursorPosition()
            if newindex < 4:
                # restore the prompt chars (if removed) and
                # fix the cursor position
                self.insert(cmd[:3 - newindex] + " ")
                self.setCursorPosition(line, 4)
            self.recolor()

        elif (e.modifiers() & (Qt.ControlModifier | Qt.MetaModifier) and e.key() == Qt.Key_V) or \
             (e.modifiers() & Qt.ShiftModifier and e.key() == Qt.Key_Insert):
            self.paste()
            e.accept()

        elif e.key() == Qt.Key_Down and not self.isListActive():
            self.showPrevious()
        elif e.key() == Qt.Key_Up and not self.isListActive():
            self.showNext()
        ## TODO: press event for auto-completion file directory
        else:
            t = unicode(e.text())
            self.autoCloseBracket = self.settings.value(
                "pythonConsole/autoCloseBracket", False, type=bool)
            self.autoImport = self.settings.value(
                "pythonConsole/autoInsertionImport", True, type=bool)
            txt = cmd[:index].replace('>>> ', '').replace('... ', '')
            ## Close bracket automatically
            if t in self.opening and self.autoCloseBracket:
                i = self.opening.index(t)
                if self.hasSelectedText() and startPos != 0:
                    selText = self.selectedText()
                    self.removeSelectedText()
                    self.insert(self.opening[i] + selText + self.closing[i])
                    self.setCursorPosition(endLine, endPos + 2)
                    return
                elif t == '(' and (re.match(r'^[ \t]*def \w+$', txt)
                                   or re.match(r'^[ \t]*class \w+$', txt)):
                    self.insert('):')
                else:
                    self.insert(self.closing[i])
            ## FIXES #8392 (automatically removes the redundant char
            ## when autoclosing brackets option is enabled)
            elif t in [')', ']', '}'] and self.autoCloseBracket:
                txt = self.text(line)
                try:
                    if txt[index - 1] in self.opening and t == txt[index]:
                        self.setCursorPosition(line, index + 1)
                        self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
                except IndexError:
                    pass
            elif t == ' ' and self.autoImport:
                ptrn = r'^[ \t]*from [\w.]+$'
                if re.match(ptrn, txt):
                    self.insert(' import')
                    self.setCursorPosition(line, index + 7)
            QsciScintilla.keyPressEvent(self, e)

    def contextMenuEvent(self, e):
        menu = QMenu(self)
        subMenu = QMenu(menu)
        titleHistoryMenu = QCoreApplication.translate("PythonConsole",
                                                      "Command History")
        subMenu.setTitle(titleHistoryMenu)
        subMenu.addAction(QCoreApplication.translate("PythonConsole", "Show"),
                          self.showHistory, 'Ctrl+Shift+SPACE')
        subMenu.addSeparator()
        subMenu.addAction(QCoreApplication.translate("PythonConsole", "Save"),
                          self.writeHistoryFile)
        subMenu.addSeparator()
        subMenu.addAction(
            QCoreApplication.translate("PythonConsole", "Clear File"),
            self.clearHistory)
        subMenu.addAction(
            QCoreApplication.translate("PythonConsole", "Clear Session"),
            self.clearHistorySession)
        menu.addMenu(subMenu)
        menu.addSeparator()
        copyAction = menu.addAction(
            QCoreApplication.translate("PythonConsole", "Copy"), self.copy,
            QKeySequence.Copy)
        pasteAction = menu.addAction(
            QCoreApplication.translate("PythonConsole", "Paste"), self.paste,
            QKeySequence.Paste)
        copyAction.setEnabled(False)
        pasteAction.setEnabled(False)
        if self.hasSelectedText():
            copyAction.setEnabled(True)
        if QApplication.clipboard().text():
            pasteAction.setEnabled(True)
        menu.exec_(self.mapToGlobal(e.pos()))

    def mousePressEvent(self, e):
        """
        Re-implemented to handle the mouse press event.
        e: the mouse press event (QMouseEvent)
        """
        self.setFocus()
        if e.button() == Qt.MidButton:
            stringSel = unicode(QApplication.clipboard().text(
                QClipboard.Selection))
            if not self.is_cursor_on_last_line():
                self.move_cursor_to_end()
            self.insertFromDropPaste(stringSel)
            e.accept()
        else:
            QsciScintilla.mousePressEvent(self, e)

    def paste(self):
        """
        Method to display data from the clipboard.

        XXX: It should reimplement the virtual QScintilla.paste method,
        but it seems not used by QScintilla code.
        """
        stringPaste = unicode(QApplication.clipboard().text())
        if self.is_cursor_on_last_line():
            if self.hasSelectedText():
                self.removeSelectedText()
        else:
            self.move_cursor_to_end()
        self.insertFromDropPaste(stringPaste)

    ## Drag and drop
    def dropEvent(self, e):
        if e.mimeData().hasText():
            stringDrag = e.mimeData().text()
            self.insertFromDropPaste(stringDrag)
            self.setFocus()
            e.setDropAction(Qt.CopyAction)
            e.accept()
        else:
            QsciScintillaCompat.dropEvent(self, e)

    def insertFromDropPaste(self, textDP):
        pasteList = unicode(textDP).splitlines()
        if pasteList:
            for line in pasteList[:-1]:
                cleanLine = line.replace(">>> ", "").replace("... ", "")
                self.insert(unicode(cleanLine))
                self.move_cursor_to_end()
                self.runCommand(unicode(self.currentCommand()))
            if pasteList[-1] != "":
                line = pasteList[-1]
                cleanLine = line.replace(">>> ", "").replace("... ", "")
                self.insert(unicode(cleanLine))
                self.move_cursor_to_end()

    def insertTextFromFile(self, listOpenFile):
        for line in listOpenFile[:-1]:
            self.append(line)
            self.move_cursor_to_end()
            self.SendScintilla(QsciScintilla.SCI_DELETEBACK)
            self.runCommand(unicode(self.currentCommand()))
        self.append(unicode(listOpenFile[-1]))
        self.move_cursor_to_end()
        self.SendScintilla(QsciScintilla.SCI_DELETEBACK)

    def entered(self):
        self.move_cursor_to_end()
        self.runCommand(unicode(self.currentCommand()))
        self.setFocus()
        self.move_cursor_to_end()

    def currentCommand(self):
        linenr, index = self.getCursorPosition()
        string = self.text()
        cmdLine = string[4:]
        cmd = unicode(cmdLine)
        return cmd

    def runCommand(self, cmd):
        self.writeCMD(cmd)
        import webbrowser
        self.updateHistory(cmd)
        if cmd in ('_pyqgis', '_api'):
            if cmd == '_pyqgis':
                webbrowser.open("http://qgis.org/pyqgis-cookbook/")
            elif cmd == '_api':
                webbrowser.open("http://qgis.org/api/")
            more = False
        else:
            self.buffer.append(cmd)
            src = u"\n".join(self.buffer)
            more = self.runsource(src, "<input>")
            if not more:
                self.buffer = []
        ## prevents to commands with more lines to break the console
        ## in the case they have a eol different from '\n'
        self.setText('')
        self.move_cursor_to_end()
        self.displayPrompt(more)

    def write(self, txt):
        sys.stderr.write(txt)

    def writeCMD(self, txt):
        if len(txt) > 0:
            getCmdString = self.text()
            prompt = getCmdString[0:4]
            sys.stdout.write(prompt + txt + '\n')
Ejemplo n.º 32
0
class DockWidget(QDockWidget):
    """Extended QDockWidget for Enki main window
    """
    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._hide)

    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 _hide(self):
        """Hide and return focus to MainWindow focus proxy
        """
        self.hide()
        if self.parent() is not None and \
           self.parent().focusProxy() is not None:
            self.parent().focusProxy().setFocus()
Ejemplo n.º 33
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 _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)

    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.º 34
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, unicode)
    """
    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(unicode)
    """
    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(unicode)
    """
    replaceFileOne(replText)
    
    **Signal** emitted, when 'Replace' had been pressed
    """  # pylint: disable=W0105

    replaceFileAll = pyqtSignal(unicode)
    """
    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
        from PyQt4 import uic  # lazy import for better startup performance

        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()))
        # 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.tbCdUp.clicked.connect(self._onCdUpPressed)

        core.mainWindow().hideAllWindows.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("\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
        if (
            core.workspace().currentDocument() is not None
            and core.workspace().currentDocument().hasFocus()
            and core.workspace().currentDocument().selectedText()
        ):
            searchText = core.workspace().currentDocument().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
        ):
            self.cbReplace.setEditText(self.cbSearch.lineEdit().text())

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

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

        # 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 = {
            ModeSearch: (1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0),
            ModeReplace: (1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0),
            ModeSearchDirectory: (1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1),
            ModeReplaceDirectory: (1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1),
            ModeSearchOpenedFiles: (1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1),
            ModeReplaceOpenedFiles: (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 == ModeReplace:
            self.pbNext.setText("Next")
        else:
            self.pbNext.setText(u"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 _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 >>sys.stderr, "Invalid focused widget in Search Widget"
            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()
        if not self.cbRegularExpression.checkState() == Qt.Checked:
            pattern = re.escape(pattern)
        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, ex:
            return False, unicode(ex)

        return True, None
Ejemplo n.º 35
0
class ShellOutputScintilla(QsciScintilla):
    def __init__(self, parent=None):
        super(ShellOutputScintilla, self).__init__(parent)
        self.parent = parent
        self.shell = self.parent.shell

        self.settings = QSettings()

        # Creates layout for message bar
        self.layout = QGridLayout(self)
        self.layout.setContentsMargins(0, 0, 0, 0)
        spacerItem = QSpacerItem(20, 40, QSizePolicy.Minimum,
                                 QSizePolicy.Expanding)
        self.layout.addItem(spacerItem, 1, 0, 1, 1)
        # messageBar instance
        self.infoBar = QgsMessageBar()
        sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.infoBar.setSizePolicy(sizePolicy)
        self.layout.addWidget(self.infoBar, 0, 0, 1, 1)

        # Enable non-ascii chars for editor
        self.setUtf8(True)

        sys.stdout = writeOut(self, sys.stdout)
        sys.stderr = writeOut(self, sys.stderr, "_traceback")

        self.insertInitText()
        self.refreshSettingsOutput()
        self.setReadOnly(True)

        # Set the default font
        font = QFont()
        font.setFamily('Courier')
        font.setFixedPitch(True)
        font.setPointSize(10)
        self.setFont(font)
        self.setMarginsFont(font)
        # Margin 0 is used for line numbers
        self.setMarginWidth(0, 0)
        self.setMarginWidth(1, 0)
        self.setMarginWidth(2, 0)
        #fm = QFontMetrics(font)
        self.setMarginsFont(font)
        self.setMarginWidth(1, "00000")
        self.setMarginLineNumbers(1, True)
        self.setMarginsForegroundColor(QColor("#3E3EE3"))
        self.setMarginsBackgroundColor(QColor("#f9f9f9"))
        self.setCaretLineVisible(True)
        self.setCaretWidth(0)

        self.setMinimumHeight(120)

        self.setWrapMode(QsciScintilla.WrapCharacter)
        self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)

        self.runScut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_E), self)
        self.runScut.setContext(Qt.WidgetShortcut)
        self.runScut.activated.connect(self.enteredSelected)
        # Reimplemeted copy action to prevent paste prompt (>>>,...) in command view
        self.copyShortcut = QShortcut(QKeySequence.Copy, self)
        self.copyShortcut.activated.connect(self.copy)
        self.selectAllShortcut = QShortcut(QKeySequence.SelectAll, self)
        self.selectAllShortcut.activated.connect(self.selectAll)

    def insertInitText(self):
        txtInit = QCoreApplication.translate(
            "PythonConsole", "Python Console \n"
            "Use iface to access QGIS API interface or Type help(iface) for more info"
        )

        ## some translation string for the console header ends without '\n'
        ## and the first command in console will be appended at the header text.
        ## The following code add a '\n' at the end of the string if not present.
        if txtInit.endswith('\n'):
            self.setText(txtInit)
        else:
            self.setText(txtInit + '\n')

    def refreshSettingsOutput(self):
        # Set Python lexer
        self.setLexers()
        caretLineColor = self.settings.value("pythonConsole/caretLineColor",
                                             QColor("#fcf3ed"))
        cursorColor = self.settings.value("pythonConsole/cursorColor",
                                          QColor(Qt.black))
        self.setCaretLineBackgroundColor(caretLineColor)
        self.setCaretForegroundColor(cursorColor)

    def setLexers(self):
        self.lexer = QsciLexerPython()

        loadFont = self.settings.value("pythonConsole/fontfamilytext",
                                       "Monospace")
        fontSize = self.settings.value("pythonConsole/fontsize", 10, type=int)
        font = QFont(loadFont)
        font.setFixedPitch(True)
        font.setPointSize(fontSize)
        font.setStyleHint(QFont.TypeWriter)
        font.setStretch(QFont.SemiCondensed)
        font.setLetterSpacing(QFont.PercentageSpacing, 87.0)
        font.setBold(False)

        self.lexer.setDefaultFont(font)
        self.lexer.setDefaultColor(
            QColor(
                self.settings.value("pythonConsole/defaultFontColor",
                                    QColor(Qt.black))))
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/commentFontColor",
                                    QColor(Qt.gray))), 1)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/keywordFontColor",
                                    QColor(Qt.darkGreen))), 5)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/classFontColor",
                                    QColor(Qt.blue))), 8)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/methodFontColor",
                                    QColor(Qt.darkGray))), 9)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/decorFontColor",
                                    QColor(Qt.darkBlue))), 15)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/commentBlockFontColor",
                                    QColor(Qt.gray))), 12)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/singleQuoteFontColor",
                                    QColor(Qt.blue))), 4)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/doubleQuoteFontColor",
                                    QColor(Qt.blue))), 3)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/tripleSingleQuoteFontColor",
                                    QColor(Qt.blue))), 6)
        self.lexer.setColor(
            QColor(
                self.settings.value("pythonConsole/tripleDoubleQuoteFontColor",
                                    QColor(Qt.blue))), 7)
        self.lexer.setColor(QColor(Qt.red), 14)
        self.lexer.setFont(font, 1)
        self.lexer.setFont(font, 2)
        self.lexer.setFont(font, 3)
        self.lexer.setFont(font, 4)

        for style in range(0, 33):
            paperColor = QColor(
                self.settings.value("pythonConsole/paperBackgroundColor",
                                    QColor(Qt.white)))
            self.lexer.setPaper(paperColor, style)

        self.setLexer(self.lexer)

    def clearConsole(self):
        self.setText('')
        self.insertInitText()
        self.shell.setFocus()

    def contextMenuEvent(self, e):
        menu = QMenu(self)
        iconRun = QgsApplication.getThemeIcon("console/iconRunConsole.png")
        iconClear = QgsApplication.getThemeIcon("console/iconClearConsole.png")
        iconHideTool = QgsApplication.getThemeIcon(
            "console/iconHideToolConsole.png")
        iconSettings = QgsApplication.getThemeIcon(
            "console/iconSettingsConsole.png")
        menu.addAction(
            iconHideTool,
            QCoreApplication.translate("PythonConsole", "Hide/Show Toolbar"),
            self.hideToolBar)
        menu.addSeparator()
        showEditorAction = menu.addAction(
            QCoreApplication.translate("PythonConsole", "Show Editor"),
            self.showEditor)
        menu.addSeparator()
        runAction = menu.addAction(
            iconRun,
            QCoreApplication.translate("PythonConsole", "Enter Selected"),
            self.enteredSelected, QKeySequence(Qt.CTRL + Qt.Key_E))
        clearAction = menu.addAction(
            iconClear,
            QCoreApplication.translate("PythonConsole", "Clear Console"),
            self.clearConsole)
        menu.addSeparator()
        copyAction = menu.addAction(
            QCoreApplication.translate("PythonConsole", "Copy"), self.copy,
            QKeySequence.Copy)
        selectAllAction = menu.addAction(
            QCoreApplication.translate("PythonConsole", "Select All"),
            self.selectAll, QKeySequence.SelectAll)
        menu.addSeparator()
        menu.addAction(
            iconSettings,
            QCoreApplication.translate("PythonConsole", "Options..."),
            self.parent.openSettings)
        runAction.setEnabled(False)
        clearAction.setEnabled(False)
        copyAction.setEnabled(False)
        selectAllAction.setEnabled(False)
        showEditorAction.setEnabled(True)
        if self.hasSelectedText():
            runAction.setEnabled(True)
            copyAction.setEnabled(True)
        if not self.text(3) == '':
            selectAllAction.setEnabled(True)
            clearAction.setEnabled(True)
        if self.parent.tabEditorWidget.isVisible():
            showEditorAction.setEnabled(False)
        menu.exec_(self.mapToGlobal(e.pos()))

    def hideToolBar(self):
        tB = self.parent.toolBar
        tB.hide() if tB.isVisible() else tB.show()
        self.shell.setFocus()

    def showEditor(self):
        Ed = self.parent.splitterObj
        if not Ed.isVisible():
            Ed.show()
            self.parent.showEditorButton.setChecked(True)
        self.shell.setFocus()

    def copy(self):
        """Copy text to clipboard... or keyboard interrupt"""
        if self.hasSelectedText():
            text = unicode(self.selectedText())
            text = text.replace('>>> ',
                                '').replace('... ',
                                            '').strip()  # removing prompts
            QApplication.clipboard().setText(text)
        else:
            self.emit(SIGNAL("keyboard_interrupt()"))

    def enteredSelected(self):
        cmd = self.selectedText()
        self.shell.insertFromDropPaste(cmd)
        self.shell.entered()

    def keyPressEvent(self, e):
        # empty text indicates possible shortcut key sequence so stay in output
        txt = e.text()
        if len(txt) and txt >= " ":
            self.shell.append(txt)
            self.shell.move_cursor_to_end()
            self.shell.setFocus()
            e.ignore()
        else:
            # possible shortcut key sequence, accept it
            e.accept()

    def widgetMessageBar(self, iface, text):
        timeout = iface.messageTimeout()
        self.infoBar.pushMessage(text, QgsMessageBar.INFO, timeout)
Ejemplo n.º 36
0
    def __init__(self, parent, enable_replace=False):
        QWidget.__init__(self, parent)
        self.enable_replace = enable_replace
        self.editor = None
        self.is_code_editor = None
        
        glayout = QGridLayout()
        glayout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(glayout)
        
        self.close_button = create_toolbutton(self, triggered=self.hide,
                                      icon=get_std_icon("DialogCloseButton"))
        glayout.addWidget(self.close_button, 0, 0)
        
        # Find layout
        self.search_text = PatternComboBox(self, tip=_("Search string"),
                                           adjust_to_minimum=False)
        self.connect(self.search_text, SIGNAL('valid(bool)'),
                     lambda state:
                     self.find(changed=False, forward=True, rehighlight=False))
        self.connect(self.search_text.lineEdit(),
                     SIGNAL("textEdited(QString)"), self.text_has_been_edited)
        
        self.previous_button = create_toolbutton(self,
                                             triggered=self.find_previous,
                                             icon=get_std_icon("ArrowBack"))
        self.next_button = create_toolbutton(self,
                                             triggered=self.find_next,
                                             icon=get_std_icon("ArrowForward"))
        self.connect(self.next_button, SIGNAL('clicked()'),
                     self.update_search_combo)
        self.connect(self.previous_button, SIGNAL('clicked()'),
                     self.update_search_combo)

        self.re_button = create_toolbutton(self, icon=get_icon("advanced.png"),
                                           tip=_("Regular expression"))
        self.re_button.setCheckable(True)
        self.connect(self.re_button, SIGNAL("toggled(bool)"),
                     lambda state: self.find())
        
        self.case_button = create_toolbutton(self,
                                             icon=get_icon("upper_lower.png"),
                                             tip=_("Case Sensitive"))
        self.case_button.setCheckable(True)
        self.connect(self.case_button, SIGNAL("toggled(bool)"),
                     lambda state: self.find())
                     
        self.words_button = create_toolbutton(self,
                                              icon=get_icon("whole_words.png"),
                                              tip=_("Whole words"))
        self.words_button.setCheckable(True)
        self.connect(self.words_button, SIGNAL("toggled(bool)"),
                     lambda state: self.find())
                     
        self.highlight_button = create_toolbutton(self,
                                              icon=get_icon("highlight.png"),
                                              tip=_("Highlight matches"))
        self.highlight_button.setCheckable(True)
        self.connect(self.highlight_button, SIGNAL("toggled(bool)"),
                     self.toggle_highlighting)

        hlayout = QHBoxLayout()
        self.widgets = [self.close_button, self.search_text,
                        self.previous_button, self.next_button,
                        self.re_button, self.case_button, self.words_button,
                        self.highlight_button]
        for widget in self.widgets[1:]:
            hlayout.addWidget(widget)
        glayout.addLayout(hlayout, 0, 1)

        # Replace layout
        replace_with = QLabel(_("Replace with:"))
        self.replace_text = PatternComboBox(self, adjust_to_minimum=False,
                                            tip=_("Replace string"))
        
        self.replace_button = create_toolbutton(self,
                                     text=_("Replace/find"),
                                     icon=get_std_icon("DialogApplyButton"),
                                     triggered=self.replace_find,
                                     text_beside_icon=True)
        self.connect(self.replace_button, SIGNAL('clicked()'),
                     self.update_replace_combo)
        self.connect(self.replace_button, SIGNAL('clicked()'),
                     self.update_search_combo)
        
        self.all_check = QCheckBox(_("Replace all"))
        
        self.replace_layout = QHBoxLayout()
        widgets = [replace_with, self.replace_text, self.replace_button,
                   self.all_check]
        for widget in widgets:
            self.replace_layout.addWidget(widget)
        glayout.addLayout(self.replace_layout, 1, 1)
        self.widgets.extend(widgets)
        self.replace_widgets = widgets
        self.hide_replace()
        
        self.search_text.setTabOrder(self.search_text, self.replace_text)
        
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        
        self.findnext_sc = QShortcut(QKeySequence("F3"), parent,
                                     self.find_next)
        self.findnext_sc.setContext(Qt.WidgetWithChildrenShortcut)
        self.findprev_sc = QShortcut(QKeySequence("Shift+F3"), parent,
                                     self.find_previous)
        self.findprev_sc.setContext(Qt.WidgetWithChildrenShortcut)
        self.togglefind_sc = QShortcut(QKeySequence("Ctrl+F"), parent,
                                       self.show)
        self.togglefind_sc.setContext(Qt.WidgetWithChildrenShortcut)
        self.togglereplace_sc = QShortcut(QKeySequence("Ctrl+H"), parent,
                                          self.toggle_replace_widgets)
        self.togglereplace_sc.setContext(Qt.WidgetWithChildrenShortcut)
        
        escape_sc = QShortcut(QKeySequence("Escape"), parent, self.hide)
        escape_sc.setContext(Qt.WidgetWithChildrenShortcut)

        self.highlight_timer = QTimer(self)
        self.highlight_timer.setSingleShot(True)
        self.highlight_timer.setInterval(1000)
        self.connect(self.highlight_timer, SIGNAL("timeout()"),
                     self.highlight_matches)
Ejemplo n.º 37
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,
                                               unicode)
    """
    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(unicode)
    """
    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(unicode)
    """
    replaceFileOne(replText)
    
    **Signal** emitted, when 'Replace' had been pressed
    """  # pylint: disable=W0105

    replaceFileAll = pyqtSignal(unicode)
    """
    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
        from PyQt4 import uic  # lazy import for better startup performance
        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()))
        # 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(unicode(os.path.curdir))
                self.cbPath.setEditText(searchPath)
            except OSError:  # current directory might have been deleted
                pass

        # 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(u'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 _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 >> sys.stderr, 'Invalid focused widget in Search Widget'
            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(
            u'\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, ex:
            return False, unicode(ex)

        return True, None