10273:e075c8fe07fd | 10349:df7edc29cbfb |
---|---|
29 Qt, | 29 Qt, |
30 QTimer, | 30 QTimer, |
31 pyqtSignal, | 31 pyqtSignal, |
32 pyqtSlot, | 32 pyqtSlot, |
33 ) | 33 ) |
34 from PyQt6.QtGui import QActionGroup, QFont, QPainter, QPalette, QPixmap | 34 from PyQt6.QtGui import QAction, QActionGroup, QFont, QPainter, QPalette, QPixmap |
35 from PyQt6.QtPrintSupport import ( | 35 from PyQt6.QtPrintSupport import ( |
36 QAbstractPrintDialog, | 36 QAbstractPrintDialog, |
37 QPrintDialog, | 37 QPrintDialog, |
38 QPrinter, | 38 QPrinter, |
39 QPrintPreviewDialog, | 39 QPrintPreviewDialog, |
147 mouseDoubleClick = pyqtSignal(QPoint, Qt.MouseButton) | 147 mouseDoubleClick = pyqtSignal(QPoint, Qt.MouseButton) |
148 | 148 |
149 WarningCode = 1 | 149 WarningCode = 1 |
150 WarningPython = 2 | 150 WarningPython = 2 |
151 WarningStyle = 3 | 151 WarningStyle = 3 |
152 WarningInfo = 4 | |
153 WarningError = 5 | |
152 | 154 |
153 # Autocompletion icon definitions | 155 # Autocompletion icon definitions |
154 ClassID = 1 | 156 ClassID = 1 |
155 ClassProtectedID = 2 | 157 ClassProtectedID = 2 |
156 ClassPrivateID = 3 | 158 ClassPrivateID = 3 |
249 # bookmarks are just a list of handles to the | 251 # bookmarks are just a list of handles to the |
250 # bookmark markers | 252 # bookmark markers |
251 self.syntaxerrors = {} | 253 self.syntaxerrors = {} |
252 # key: marker handle | 254 # key: marker handle |
253 # value: list of (error message, error index) | 255 # value: list of (error message, error index) |
254 self.warnings = {} | 256 self._warnings = {} |
255 # key: marker handle | 257 # key: marker handle |
256 # value: list of (warning message, warning type) | 258 # value: list of (warning message, warning type) |
257 self.notcoveredMarkers = [] # just a list of marker handles | 259 self.notcoveredMarkers = [] # just a list of marker handles |
258 self.showingNotcoveredMarkers = False | 260 self.showingNotcoveredMarkers = False |
259 | 261 |
312 Preferences.getEditor("MarkOccurrencesTimeout") | 314 Preferences.getEditor("MarkOccurrencesTimeout") |
313 ) | 315 ) |
314 self.__markOccurrencesTimer.timeout.connect(self.__markOccurrences) | 316 self.__markOccurrencesTimer.timeout.connect(self.__markOccurrences) |
315 self.__markedText = "" | 317 self.__markedText = "" |
316 self.__searchIndicatorLines = [] | 318 self.__searchIndicatorLines = [] |
319 | |
320 # set the autosave attributes | |
321 self.__autosaveInterval = Preferences.getEditor("AutosaveIntervalSeconds") | |
322 self.__autosaveManuallyDisabled = False | |
323 | |
324 # initialize the autosave timer | |
325 self.__autosaveTimer = QTimer(self) | |
326 self.__autosaveTimer.setObjectName("AutosaveTimer") | |
327 self.__autosaveTimer.setSingleShot(True) | |
328 self.__autosaveTimer.timeout.connect(self.__autosave) | |
317 | 329 |
318 # initialize some spellchecking stuff | 330 # initialize some spellchecking stuff |
319 self.spell = None | 331 self.spell = None |
320 self.lastLine = 0 | 332 self.lastLine = 0 |
321 self.lastIndex = 0 | 333 self.lastIndex = 0 |
546 bnd = req.boundedTo(self.vm.size()) | 558 bnd = req.boundedTo(self.vm.size()) |
547 | 559 |
548 if bnd.width() < req.width() or bnd.height() < req.height(): | 560 if bnd.width() < req.width() or bnd.height() < req.height(): |
549 self.resize(bnd) | 561 self.resize(bnd) |
550 | 562 |
551 # set the autosave flag | |
552 self.autosaveEnabled = Preferences.getEditor("AutosaveInterval") > 0 | |
553 self.autosaveManuallyDisabled = False | |
554 | |
555 # code coverage related attributes | 563 # code coverage related attributes |
556 self.__coverageFile = "" | 564 self.__coverageFile = "" |
557 | 565 |
558 self.__initContextMenu() | 566 self.__initContextMenu() |
559 self.__initContextMenuMargins() | 567 self.__initContextMenuMargins() |
569 # it's a clone | 577 # it's a clone |
570 self.__languageChanged(editor.apiLanguage, propagate=False) | 578 self.__languageChanged(editor.apiLanguage, propagate=False) |
571 self.__encodingChanged(editor.encoding, propagate=False) | 579 self.__encodingChanged(editor.encoding, propagate=False) |
572 self.__spellLanguageChanged(editor.getSpellingLanguage(), propagate=False) | 580 self.__spellLanguageChanged(editor.getSpellingLanguage(), propagate=False) |
573 # link the warnings to the original editor | 581 # link the warnings to the original editor |
574 self.warnings = editor.warnings | 582 self._warnings = editor._warnings |
575 | 583 |
576 self.setAcceptDrops(True) | 584 self.setAcceptDrops(True) |
577 | 585 |
578 # breakpoint handling | 586 # breakpoint handling |
579 self.breakpointModel = self.dbs.getBreakPointModel() | 587 self.breakpointModel = self.dbs.getBreakPointModel() |
955 self.menuActs["MonospacedFont"].setChecked(self.useMonospaced) | 963 self.menuActs["MonospacedFont"].setChecked(self.useMonospaced) |
956 self.menuActs["AutosaveEnable"] = self.menu.addAction( | 964 self.menuActs["AutosaveEnable"] = self.menu.addAction( |
957 self.tr("Autosave enabled"), self.__autosaveEnable | 965 self.tr("Autosave enabled"), self.__autosaveEnable |
958 ) | 966 ) |
959 self.menuActs["AutosaveEnable"].setCheckable(True) | 967 self.menuActs["AutosaveEnable"].setCheckable(True) |
960 self.menuActs["AutosaveEnable"].setChecked(self.autosaveEnabled) | 968 self.menuActs["AutosaveEnable"].setChecked(self.__autosaveInterval > 0) |
961 self.menuActs["TypingAidsEnabled"] = self.menu.addAction( | 969 self.menuActs["TypingAidsEnabled"] = self.menu.addAction( |
962 self.tr("Typing aids enabled"), self.__toggleTypingAids | 970 self.tr("Typing aids enabled"), self.__toggleTypingAids |
963 ) | 971 ) |
964 self.menuActs["TypingAidsEnabled"].setCheckable(True) | 972 self.menuActs["TypingAidsEnabled"].setCheckable(True) |
965 self.menuActs["TypingAidsEnabled"].setEnabled(self.completer is not None) | 973 self.menuActs["TypingAidsEnabled"].setEnabled(self.completer is not None) |
1537 self, | 1545 self, |
1538 self.tr("Export source"), | 1546 self.tr("Export source"), |
1539 self.tr("""No export format given. Aborting..."""), | 1547 self.tr("""No export format given. Aborting..."""), |
1540 ) | 1548 ) |
1541 | 1549 |
1550 @pyqtSlot() | |
1542 def __showContextMenuLanguages(self): | 1551 def __showContextMenuLanguages(self): |
1543 """ | 1552 """ |
1544 Private slot handling the aboutToShow signal of the languages context | 1553 Private slot handling the aboutToShow signal of the languages context |
1545 menu. | 1554 menu. |
1546 """ | 1555 """ |
1603 | 1612 |
1604 self.__docstringGenerator = None | 1613 self.__docstringGenerator = None |
1605 | 1614 |
1606 def __languageChanged(self, language, propagate=True): | 1615 def __languageChanged(self, language, propagate=True): |
1607 """ | 1616 """ |
1608 Private slot handling a change of a connected editor's language. | 1617 Private method handling a change of a connected editor's language. |
1609 | 1618 |
1610 @param language language to be set (string) | 1619 @param language language to be set (string) |
1611 @param propagate flag indicating to propagate the change (boolean) | 1620 @param propagate flag indicating to propagate the change (boolean) |
1612 """ | 1621 """ |
1613 if language == "": | 1622 if language == "": |
1708 if act: | 1717 if act: |
1709 act.setChecked(False) | 1718 act.setChecked(False) |
1710 else: | 1719 else: |
1711 self.supportedLanguages[self.apiLanguage][2].setChecked(True) | 1720 self.supportedLanguages[self.apiLanguage][2].setChecked(True) |
1712 | 1721 |
1722 @pyqtSlot() | |
1713 def projectLexerAssociationsChanged(self): | 1723 def projectLexerAssociationsChanged(self): |
1714 """ | 1724 """ |
1715 Public slot to handle changes of the project lexer associations. | 1725 Public slot to handle changes of the project lexer associations. |
1716 """ | 1726 """ |
1717 self.setLanguage(self.fileName) | 1727 self.setLanguage(self.fileName) |
1718 | 1728 |
1729 @pyqtSlot() | |
1719 def __showContextMenuEncodings(self): | 1730 def __showContextMenuEncodings(self): |
1720 """ | 1731 """ |
1721 Private slot handling the aboutToShow signal of the encodings context | 1732 Private slot handling the aboutToShow signal of the encodings context |
1722 menu. | 1733 menu. |
1723 """ | 1734 """ |
1738 Private method to check the selected encoding of the encodings submenu. | 1749 Private method to check the selected encoding of the encodings submenu. |
1739 """ | 1750 """ |
1740 with contextlib.suppress(AttributeError, KeyError): | 1751 with contextlib.suppress(AttributeError, KeyError): |
1741 (self.supportedEncodings[self.__normalizedEncoding()].setChecked(True)) | 1752 (self.supportedEncodings[self.__normalizedEncoding()].setChecked(True)) |
1742 | 1753 |
1754 @pyqtSlot(str) | |
1743 def __encodingChanged(self, encoding, propagate=True): | 1755 def __encodingChanged(self, encoding, propagate=True): |
1744 """ | 1756 """ |
1745 Private slot to handle a change of the encoding. | 1757 Private slot to handle a change of the encoding. |
1746 | 1758 |
1747 @param encoding changed encoding (string) | 1759 @param encoding changed encoding |
1748 @param propagate flag indicating to propagate the change (boolean) | 1760 @type str |
1761 @param propagate flag indicating to propagate the change | |
1762 @type bool | |
1749 """ | 1763 """ |
1750 self.encoding = encoding | 1764 self.encoding = encoding |
1751 self.__checkEncoding() | 1765 self.__checkEncoding() |
1752 | 1766 |
1753 if not self.inEncodingChanged and propagate: | 1767 if not self.inEncodingChanged and propagate: |
1768 encoding.replace("-default", "") | 1782 encoding.replace("-default", "") |
1769 .replace("-guessed", "") | 1783 .replace("-guessed", "") |
1770 .replace("-selected", "") | 1784 .replace("-selected", "") |
1771 ) | 1785 ) |
1772 | 1786 |
1787 @pyqtSlot() | |
1773 def __showContextMenuEol(self): | 1788 def __showContextMenuEol(self): |
1774 """ | 1789 """ |
1775 Private slot handling the aboutToShow signal of the eol context menu. | 1790 Private slot handling the aboutToShow signal of the eol context menu. |
1776 """ | 1791 """ |
1777 self.showMenu.emit("Eol", self.eolMenu, self) | 1792 self.showMenu.emit("Eol", self.eolMenu, self) |
1791 Private method to check the selected eol type of the eol submenu. | 1806 Private method to check the selected eol type of the eol submenu. |
1792 """ | 1807 """ |
1793 with contextlib.suppress(AttributeError, TypeError): | 1808 with contextlib.suppress(AttributeError, TypeError): |
1794 self.supportedEols[self.getLineSeparator()].setChecked(True) | 1809 self.supportedEols[self.getLineSeparator()].setChecked(True) |
1795 | 1810 |
1811 @pyqtSlot() | |
1796 def __eolChanged(self): | 1812 def __eolChanged(self): |
1797 """ | 1813 """ |
1798 Private slot to handle a change of the eol mode. | 1814 Private slot to handle a change of the eol mode. |
1799 """ | 1815 """ |
1800 self.__checkEol() | 1816 self.__checkEol() |
1803 self.inEolChanged = True | 1819 self.inEolChanged = True |
1804 eol = self.getLineSeparator() | 1820 eol = self.getLineSeparator() |
1805 self.eolChanged.emit(eol) | 1821 self.eolChanged.emit(eol) |
1806 self.inEolChanged = False | 1822 self.inEolChanged = False |
1807 | 1823 |
1824 @pyqtSlot() | |
1808 def __showContextMenuSpellCheck(self): | 1825 def __showContextMenuSpellCheck(self): |
1809 """ | 1826 """ |
1810 Private slot handling the aboutToShow signal of the spell check | 1827 Private slot handling the aboutToShow signal of the spell check |
1811 context menu. | 1828 context menu. |
1812 """ | 1829 """ |
1820 ) | 1837 ) |
1821 self.menuActs["SpellCheckLanguages"].setEnabled(spellingAvailable) | 1838 self.menuActs["SpellCheckLanguages"].setEnabled(spellingAvailable) |
1822 | 1839 |
1823 self.showMenu.emit("SpellCheck", self.spellCheckMenu, self) | 1840 self.showMenu.emit("SpellCheck", self.spellCheckMenu, self) |
1824 | 1841 |
1842 @pyqtSlot() | |
1825 def __showContextMenuSpellLanguages(self): | 1843 def __showContextMenuSpellLanguages(self): |
1826 """ | 1844 """ |
1827 Private slot handling the aboutToShow signal of the spell check | 1845 Private slot handling the aboutToShow signal of the spell check |
1828 languages context menu. | 1846 languages context menu. |
1829 """ | 1847 """ |
1838 """ | 1856 """ |
1839 language = act.data() | 1857 language = act.data() |
1840 self.__setSpellingLanguage(language) | 1858 self.__setSpellingLanguage(language) |
1841 self.spellLanguageChanged.emit(language) | 1859 self.spellLanguageChanged.emit(language) |
1842 | 1860 |
1861 @pyqtSlot() | |
1843 def __checkSpellLanguage(self): | 1862 def __checkSpellLanguage(self): |
1844 """ | 1863 """ |
1845 Private slot to check the selected spell check language action. | 1864 Private slot to check the selected spell check language action. |
1846 """ | 1865 """ |
1847 language = self.getSpellingLanguage() | 1866 language = self.getSpellingLanguage() |
1848 with contextlib.suppress(AttributeError, KeyError): | 1867 with contextlib.suppress(AttributeError, KeyError): |
1849 self.supportedSpellLanguages[language].setChecked(True) | 1868 self.supportedSpellLanguages[language].setChecked(True) |
1850 | 1869 |
1870 @pyqtSlot(str) | |
1851 def __spellLanguageChanged(self, language, propagate=True): | 1871 def __spellLanguageChanged(self, language, propagate=True): |
1852 """ | 1872 """ |
1853 Private slot to handle a change of the spell check language. | 1873 Private slot to handle a change of the spell check language. |
1854 | 1874 |
1855 @param language new spell check language | 1875 @param language new spell check language |
1865 self.spellLanguageChanged.emit(language) | 1885 self.spellLanguageChanged.emit(language) |
1866 self.__inSpellLanguageChanged = False | 1886 self.__inSpellLanguageChanged = False |
1867 | 1887 |
1868 def __bindLexer(self, filename, pyname=""): | 1888 def __bindLexer(self, filename, pyname=""): |
1869 """ | 1889 """ |
1870 Private slot to set the correct lexer depending on language. | 1890 Private method to set the correct lexer depending on language. |
1871 | 1891 |
1872 @param filename filename used to determine the associated lexer | 1892 @param filename filename used to determine the associated lexer |
1873 language (string) | 1893 language |
1874 @param pyname name of the pygments lexer to use (string) | 1894 @type str |
1895 @param pyname name of the pygments lexer to use | |
1896 @type str | |
1875 """ | 1897 """ |
1876 if self.lexer_ is not None and ( | 1898 if self.lexer_ is not None and ( |
1877 self.lexer_.lexer() == "container" or self.lexer_.lexer() is None | 1899 self.lexer_.lexer() == "container" or self.lexer_.lexer() is None |
1878 ): | 1900 ): |
1879 self.SCN_STYLENEEDED.disconnect(self.__styleNeeded) | 1901 self.SCN_STYLENEEDED.disconnect(self.__styleNeeded) |
1981 self.__setAnnotationStyles() | 2003 self.__setAnnotationStyles() |
1982 | 2004 |
1983 self.lexer_.setDefaultColor(self.lexer_.color(0)) | 2005 self.lexer_.setDefaultColor(self.lexer_.color(0)) |
1984 self.lexer_.setDefaultPaper(self.lexer_.paper(0)) | 2006 self.lexer_.setDefaultPaper(self.lexer_.paper(0)) |
1985 | 2007 |
2008 @pyqtSlot(int) | |
1986 def __styleNeeded(self, position): | 2009 def __styleNeeded(self, position): |
1987 """ | 2010 """ |
1988 Private slot to handle the need for more styling. | 2011 Private slot to handle the need for more styling. |
1989 | 2012 |
1990 @param position end position, that needs styling (integer) | 2013 @param position end position, that needs styling |
2014 @type int | |
1991 """ | 2015 """ |
1992 self.lexer_.styleText(self.getEndStyled(), position) | 2016 self.lexer_.styleText(self.getEndStyled(), position) |
1993 | 2017 |
1994 def getLexer(self): | 2018 def getLexer(self): |
1995 """ | 2019 """ |
2031 """ | 2055 """ |
2032 return self.apiLanguage | 2056 return self.apiLanguage |
2033 | 2057 |
2034 def __bindCompleter(self, filename): | 2058 def __bindCompleter(self, filename): |
2035 """ | 2059 """ |
2036 Private slot to set the correct typing completer depending on language. | 2060 Private method to set the correct typing completer depending on language. |
2037 | 2061 |
2038 @param filename filename used to determine the associated typing | 2062 @param filename filename used to determine the associated typing |
2039 completer language (string) | 2063 completer language |
2064 @type str | |
2040 """ | 2065 """ |
2041 if self.completer is not None: | 2066 if self.completer is not None: |
2042 self.completer.setEnabled(False) | 2067 self.completer.setEnabled(False) |
2043 self.completer = None | 2068 self.completer = None |
2044 | 2069 |
2059 | 2084 |
2060 @return the completer object (CompleterBase) | 2085 @return the completer object (CompleterBase) |
2061 """ | 2086 """ |
2062 return self.completer | 2087 return self.completer |
2063 | 2088 |
2089 @pyqtSlot(bool) | |
2064 def __modificationChanged(self, m): | 2090 def __modificationChanged(self, m): |
2065 """ | 2091 """ |
2066 Private slot to handle the modificationChanged signal. | 2092 Private slot to handle the modificationChanged signal. |
2067 | 2093 |
2068 It emits the signal modificationStatusChanged with parameters | 2094 It emits the signal modificationStatusChanged with parameters |
2069 m and self. | 2095 m and self. |
2070 | 2096 |
2071 @param m modification status | 2097 @param m modification status |
2098 @type bool | |
2072 """ | 2099 """ |
2073 if not m and bool(self.fileName) and pathlib.Path(self.fileName).exists(): | 2100 if not m and bool(self.fileName) and pathlib.Path(self.fileName).exists(): |
2074 self.lastModified = pathlib.Path(self.fileName).stat().st_mtime | 2101 self.lastModified = pathlib.Path(self.fileName).stat().st_mtime |
2075 self.modificationStatusChanged.emit(m, self) | 2102 self.modificationStatusChanged.emit(m, self) |
2076 self.undoAvailable.emit(self.isUndoAvailable()) | 2103 self.undoAvailable.emit(self.isUndoAvailable()) |
2077 self.redoAvailable.emit(self.isRedoAvailable()) | 2104 self.redoAvailable.emit(self.isRedoAvailable()) |
2078 | 2105 |
2106 if not m: | |
2107 self.__autosaveTimer.stop() | |
2108 | |
2109 @pyqtSlot(int, int) | |
2079 def __cursorPositionChanged(self, line, index): | 2110 def __cursorPositionChanged(self, line, index): |
2080 """ | 2111 """ |
2081 Private slot to handle the cursorPositionChanged signal. | 2112 Private slot to handle the cursorPositionChanged signal. |
2082 | 2113 |
2083 It emits the signal cursorChanged with parameters fileName, | 2114 It emits the signal cursorChanged with parameters fileName, |
2084 line and pos. | 2115 line and pos. |
2085 | 2116 |
2086 @param line line number of the cursor | 2117 @param line line number of the cursor |
2118 @type int | |
2087 @param index position in line of the cursor | 2119 @param index position in line of the cursor |
2120 @type int | |
2088 """ | 2121 """ |
2089 self.cursorChanged.emit(self.fileName, line + 1, index) | 2122 self.cursorChanged.emit(self.fileName, line + 1, index) |
2090 | 2123 |
2091 if Preferences.getEditor("MarkOccurrencesEnabled"): | 2124 if Preferences.getEditor("MarkOccurrencesEnabled"): |
2092 self.__markOccurrencesTimer.stop() | |
2093 self.__markOccurrencesTimer.start() | 2125 self.__markOccurrencesTimer.start() |
2094 | 2126 |
2095 if self.lastLine != line: | 2127 if self.lastLine != line: |
2096 self.cursorLineChanged.emit(line) | 2128 self.cursorLineChanged.emit(line) |
2097 | 2129 |
2110 self.__markerMap.update() | 2142 self.__markerMap.update() |
2111 | 2143 |
2112 self.lastLine = line | 2144 self.lastLine = line |
2113 self.lastIndex = index | 2145 self.lastIndex = index |
2114 | 2146 |
2147 @pyqtSlot() | |
2115 def __modificationReadOnly(self): | 2148 def __modificationReadOnly(self): |
2116 """ | 2149 """ |
2117 Private slot to handle the modificationAttempted signal. | 2150 Private slot to handle the modificationAttempted signal. |
2118 """ | 2151 """ |
2119 EricMessageBox.warning( | 2152 EricMessageBox.warning( |
2380 @param foldPrev previous fold level (integer) | 2413 @param foldPrev previous fold level (integer) |
2381 @param token ??? | 2414 @param token ??? |
2382 @param annotationLinesAdded number of added/deleted annotation lines | 2415 @param annotationLinesAdded number of added/deleted annotation lines |
2383 (integer) | 2416 (integer) |
2384 """ | 2417 """ |
2385 if ( | 2418 if mtype & (self.SC_MOD_INSERTTEXT | self.SC_MOD_DELETETEXT): |
2386 mtype & (self.SC_MOD_INSERTTEXT | self.SC_MOD_DELETETEXT) | 2419 # 1. set/reset the autosave timer |
2387 and linesAdded != 0 | 2420 if self.__autosaveInterval > 0: |
2388 and self.breaks | 2421 self.__autosaveTimer.start(self.__autosaveInterval * 1000) |
2389 ): | 2422 |
2390 bps = [] # list of breakpoints | 2423 # 2. move breakpoints if a line was inserted or deleted |
2391 for handle, (ln, cond, temp, enabled, ignorecount) in self.breaks.items(): | 2424 if linesAdded != 0 and self.breaks: |
2392 line = self.markerLine(handle) + 1 | 2425 bps = [] # list of breakpoints |
2393 if ln != line: | 2426 for handle, ( |
2394 bps.append((ln, line)) | 2427 ln, |
2395 self.breaks[handle] = (line, cond, temp, enabled, ignorecount) | 2428 cond, |
2396 self.inLinesChanged = True | 2429 temp, |
2397 for ln, line in sorted(bps, reverse=linesAdded > 0): | 2430 enabled, |
2398 index1 = self.breakpointModel.getBreakPointIndex(self.fileName, ln) | 2431 ignorecount, |
2399 index2 = self.breakpointModel.index(index1.row(), 1) | 2432 ) in self.breaks.items(): |
2400 self.breakpointModel.setData(index2, line) | 2433 line = self.markerLine(handle) + 1 |
2401 self.inLinesChanged = False | 2434 if ln != line: |
2435 bps.append((ln, line)) | |
2436 self.breaks[handle] = (line, cond, temp, enabled, ignorecount) | |
2437 self.inLinesChanged = True | |
2438 for ln, line in sorted(bps, reverse=linesAdded > 0): | |
2439 index1 = self.breakpointModel.getBreakPointIndex(self.fileName, ln) | |
2440 index2 = self.breakpointModel.index(index1.row(), 1) | |
2441 self.breakpointModel.setData(index2, line) | |
2442 self.inLinesChanged = False | |
2402 | 2443 |
2403 def __restoreBreakpoints(self): | 2444 def __restoreBreakpoints(self): |
2404 """ | 2445 """ |
2405 Private method to restore the breakpoints. | 2446 Private method to restore the breakpoints. |
2406 """ | 2447 """ |
2407 for handle in list(self.breaks.keys()): | 2448 for handle in self.breaks: |
2408 self.markerDeleteHandle(handle) | 2449 self.markerDeleteHandle(handle) |
2409 self.__addBreakPoints(QModelIndex(), 0, self.breakpointModel.rowCount() - 1) | 2450 self.__addBreakPoints(QModelIndex(), 0, self.breakpointModel.rowCount() - 1) |
2410 self.__markerMap.update() | 2451 self.__markerMap.update() |
2411 | 2452 |
2453 @pyqtSlot(QModelIndex, int, int) | |
2412 def __deleteBreakPoints(self, parentIndex, start, end): | 2454 def __deleteBreakPoints(self, parentIndex, start, end): |
2413 """ | 2455 """ |
2414 Private slot to delete breakpoints. | 2456 Private slot to delete breakpoints. |
2415 | 2457 |
2416 @param parentIndex index of parent item (QModelIndex) | 2458 @param parentIndex index of parent item |
2417 @param start start row (integer) | 2459 @type QModelIndex |
2418 @param end end row (integer) | 2460 @param start start row |
2461 @type int | |
2462 @param end end row | |
2463 @type int | |
2419 """ | 2464 """ |
2420 for row in range(start, end + 1): | 2465 for row in range(start, end + 1): |
2421 index = self.breakpointModel.index(row, 0, parentIndex) | 2466 index = self.breakpointModel.index(row, 0, parentIndex) |
2422 fn, lineno = self.breakpointModel.getBreakPointByIndex(index)[0:2] | 2467 fn, lineno = self.breakpointModel.getBreakPointByIndex(index)[0:2] |
2423 if fn == self.fileName: | 2468 if fn == self.fileName: |
2424 self.clearBreakpoint(lineno) | 2469 self.clearBreakpoint(lineno) |
2425 | 2470 |
2471 @pyqtSlot(QModelIndex, QModelIndex) | |
2426 def __changeBreakPoints(self, startIndex, endIndex): | 2472 def __changeBreakPoints(self, startIndex, endIndex): |
2427 """ | 2473 """ |
2428 Private slot to set changed breakpoints. | 2474 Private slot to set changed breakpoints. |
2429 | 2475 |
2430 @param startIndex start index of the breakpoints being changed | 2476 @param startIndex start index of the breakpoints being changed |
2431 (QModelIndex) | 2477 @type QModelIndex |
2432 @param endIndex end index of the breakpoints being changed | 2478 @param endIndex end index of the breakpoints being changed |
2433 (QModelIndex) | 2479 @type QModelIndex |
2434 """ | 2480 """ |
2435 if not self.inLinesChanged: | 2481 if not self.inLinesChanged: |
2436 self.__addBreakPoints(QModelIndex(), startIndex.row(), endIndex.row()) | 2482 self.__addBreakPoints(QModelIndex(), startIndex.row(), endIndex.row()) |
2437 | 2483 |
2484 @pyqtSlot(QModelIndex, QModelIndex) | |
2438 def __breakPointDataAboutToBeChanged(self, startIndex, endIndex): | 2485 def __breakPointDataAboutToBeChanged(self, startIndex, endIndex): |
2439 """ | 2486 """ |
2440 Private slot to handle the dataAboutToBeChanged signal of the | 2487 Private slot to handle the dataAboutToBeChanged signal of the |
2441 breakpoint model. | 2488 breakpoint model. |
2442 | 2489 |
2443 @param startIndex start index of the rows to be changed (QModelIndex) | 2490 @param startIndex start index of the rows to be changed |
2444 @param endIndex end index of the rows to be changed (QModelIndex) | 2491 @type QModelIndex |
2492 @param endIndex end index of the rows to be changed | |
2493 @type QModelIndex | |
2445 """ | 2494 """ |
2446 self.__deleteBreakPoints(QModelIndex(), startIndex.row(), endIndex.row()) | 2495 self.__deleteBreakPoints(QModelIndex(), startIndex.row(), endIndex.row()) |
2447 | 2496 |
2497 @pyqtSlot(QModelIndex, int, int) | |
2448 def __addBreakPoints(self, parentIndex, start, end): | 2498 def __addBreakPoints(self, parentIndex, start, end): |
2449 """ | 2499 """ |
2450 Private slot to add breakpoints. | 2500 Private slot to add breakpoints. |
2451 | 2501 |
2452 @param parentIndex index of parent item (QModelIndex) | 2502 @param parentIndex index of parent item |
2453 @param start start row (integer) | 2503 @type QModelIndex |
2454 @param end end row (integer) | 2504 @param start start row |
2505 @type int | |
2506 @param end end row | |
2507 @type int | |
2455 """ | 2508 """ |
2456 for row in range(start, end + 1): | 2509 for row in range(start, end + 1): |
2457 index = self.breakpointModel.index(row, 0, parentIndex) | 2510 index = self.breakpointModel.index(row, 0, parentIndex) |
2458 ( | 2511 ( |
2459 fn, | 2512 fn, |
2480 if self.inLinesChanged: | 2533 if self.inLinesChanged: |
2481 return | 2534 return |
2482 | 2535 |
2483 for handle in self.breaks: | 2536 for handle in self.breaks: |
2484 if self.markerLine(handle) == line - 1: | 2537 if self.markerLine(handle) == line - 1: |
2485 break | 2538 del self.breaks[handle] |
2486 else: | 2539 self.markerDeleteHandle(handle) |
2487 # not found, simply ignore it | 2540 self.__markerMap.update() |
2488 return | 2541 return |
2489 | |
2490 del self.breaks[handle] | |
2491 self.markerDeleteHandle(handle) | |
2492 self.__markerMap.update() | |
2493 | 2542 |
2494 def newBreakpointWithProperties(self, line, properties): | 2543 def newBreakpointWithProperties(self, line, properties): |
2495 """ | 2544 """ |
2496 Public method to set a new breakpoint and its properties. | 2545 Public method to set a new breakpoint and its properties. |
2497 | 2546 |
2613 | 2662 |
2614 @return flag indicating the presence of breakpoints (boolean) | 2663 @return flag indicating the presence of breakpoints (boolean) |
2615 """ | 2664 """ |
2616 return len(self.breaks) > 0 | 2665 return len(self.breaks) > 0 |
2617 | 2666 |
2667 @pyqtSlot() | |
2618 def __menuToggleTemporaryBreakpoint(self): | 2668 def __menuToggleTemporaryBreakpoint(self): |
2619 """ | 2669 """ |
2620 Private slot to handle the 'Toggle temporary breakpoint' context menu | 2670 Private slot to handle the 'Toggle temporary breakpoint' context menu |
2621 action. | 2671 action. |
2622 """ | 2672 """ |
2624 self.line, index = self.getCursorPosition() | 2674 self.line, index = self.getCursorPosition() |
2625 self.line += 1 | 2675 self.line += 1 |
2626 self.__toggleBreakpoint(self.line, 1) | 2676 self.__toggleBreakpoint(self.line, 1) |
2627 self.line = -1 | 2677 self.line = -1 |
2628 | 2678 |
2679 @pyqtSlot() | |
2629 def menuToggleBreakpoint(self): | 2680 def menuToggleBreakpoint(self): |
2630 """ | 2681 """ |
2631 Public slot to handle the 'Toggle breakpoint' context menu action. | 2682 Public slot to handle the 'Toggle breakpoint' context menu action. |
2632 """ | 2683 """ |
2633 if self.line < 0: | 2684 if self.line < 0: |
2634 self.line, index = self.getCursorPosition() | 2685 self.line, index = self.getCursorPosition() |
2635 self.line += 1 | 2686 self.line += 1 |
2636 self.__toggleBreakpoint(self.line) | 2687 self.__toggleBreakpoint(self.line) |
2637 self.line = -1 | 2688 self.line = -1 |
2638 | 2689 |
2690 @pyqtSlot() | |
2639 def __menuToggleBreakpointEnabled(self): | 2691 def __menuToggleBreakpointEnabled(self): |
2640 """ | 2692 """ |
2641 Private slot to handle the 'Enable/Disable breakpoint' context menu | 2693 Private slot to handle the 'Enable/Disable breakpoint' context menu |
2642 action. | 2694 action. |
2643 """ | 2695 """ |
2645 self.line, index = self.getCursorPosition() | 2697 self.line, index = self.getCursorPosition() |
2646 self.line += 1 | 2698 self.line += 1 |
2647 self.__toggleBreakpointEnabled(self.line) | 2699 self.__toggleBreakpointEnabled(self.line) |
2648 self.line = -1 | 2700 self.line = -1 |
2649 | 2701 |
2702 @pyqtSlot() | |
2650 def menuEditBreakpoint(self, line=None): | 2703 def menuEditBreakpoint(self, line=None): |
2651 """ | 2704 """ |
2652 Public slot to handle the 'Edit breakpoint' context menu action. | 2705 Public slot to handle the 'Edit breakpoint' context menu action. |
2653 | 2706 |
2654 @param line linenumber of the breakpoint to edit | 2707 @param line line number of the breakpoint to edit |
2708 @type int | |
2655 """ | 2709 """ |
2656 from eric7.Debugger.EditBreakpointDialog import EditBreakpointDialog | 2710 from eric7.Debugger.EditBreakpointDialog import EditBreakpointDialog |
2657 | 2711 |
2658 if line is not None: | 2712 if line is not None: |
2659 self.line = line - 1 | 2713 self.line = line - 1 |
2700 | 2754 |
2701 break | 2755 break |
2702 | 2756 |
2703 self.line = -1 | 2757 self.line = -1 |
2704 | 2758 |
2759 @pyqtSlot() | |
2705 def menuNextBreakpoint(self): | 2760 def menuNextBreakpoint(self): |
2706 """ | 2761 """ |
2707 Public slot to handle the 'Next breakpoint' context menu action. | 2762 Public slot to handle the 'Next breakpoint' context menu action. |
2708 """ | 2763 """ |
2709 line, index = self.getCursorPosition() | 2764 line, index = self.getCursorPosition() |
2717 bpline = self.markerFindNext(0, self.breakpointMask) | 2772 bpline = self.markerFindNext(0, self.breakpointMask) |
2718 if bpline >= 0: | 2773 if bpline >= 0: |
2719 self.setCursorPosition(bpline, 0) | 2774 self.setCursorPosition(bpline, 0) |
2720 self.ensureLineVisible(bpline) | 2775 self.ensureLineVisible(bpline) |
2721 | 2776 |
2777 @pyqtSlot() | |
2722 def menuPreviousBreakpoint(self): | 2778 def menuPreviousBreakpoint(self): |
2723 """ | 2779 """ |
2724 Public slot to handle the 'Previous breakpoint' context menu action. | 2780 Public slot to handle the 'Previous breakpoint' context menu action. |
2725 """ | 2781 """ |
2726 line, index = self.getCursorPosition() | 2782 line, index = self.getCursorPosition() |
2734 bpline = self.markerFindPrevious(self.lines() - 1, self.breakpointMask) | 2790 bpline = self.markerFindPrevious(self.lines() - 1, self.breakpointMask) |
2735 if bpline >= 0: | 2791 if bpline >= 0: |
2736 self.setCursorPosition(bpline, 0) | 2792 self.setCursorPosition(bpline, 0) |
2737 self.ensureLineVisible(bpline) | 2793 self.ensureLineVisible(bpline) |
2738 | 2794 |
2795 @pyqtSlot() | |
2739 def __menuClearBreakpoints(self): | 2796 def __menuClearBreakpoints(self): |
2740 """ | 2797 """ |
2741 Private slot to handle the 'Clear all breakpoints' context menu action. | 2798 Private slot to handle the 'Clear all breakpoints' context menu action. |
2742 """ | 2799 """ |
2743 self.__clearBreakpoints(self.fileName) | 2800 self.__clearBreakpoints(self.fileName) |
2744 | 2801 |
2745 def __clearBreakpoints(self, fileName): | 2802 def __clearBreakpoints(self, fileName): |
2746 """ | 2803 """ |
2747 Private slot to clear all breakpoints. | 2804 Private method to clear all breakpoints. |
2748 | 2805 |
2749 @param fileName name of the file (string) | 2806 @param fileName name of the file |
2807 @type str | |
2750 """ | 2808 """ |
2751 idxList = [] | 2809 idxList = [] |
2752 for ln, _, _, _, _ in self.breaks.values(): | 2810 for ln, _, _, _, _ in self.breaks.values(): |
2753 index = self.breakpointModel.getBreakPointIndex(fileName, ln) | 2811 index = self.breakpointModel.getBreakPointIndex(fileName, ln) |
2754 if index.isValid(): | 2812 if index.isValid(): |
2814 | 2872 |
2815 @return flag indicating the presence of bookmarks (boolean) | 2873 @return flag indicating the presence of bookmarks (boolean) |
2816 """ | 2874 """ |
2817 return len(self.bookmarks) > 0 | 2875 return len(self.bookmarks) > 0 |
2818 | 2876 |
2877 @pyqtSlot() | |
2819 def menuToggleBookmark(self): | 2878 def menuToggleBookmark(self): |
2820 """ | 2879 """ |
2821 Public slot to handle the 'Toggle bookmark' context menu action. | 2880 Public slot to handle the 'Toggle bookmark' context menu action. |
2822 """ | 2881 """ |
2823 if self.line < 0: | 2882 if self.line < 0: |
2824 self.line, index = self.getCursorPosition() | 2883 self.line, index = self.getCursorPosition() |
2825 self.line += 1 | 2884 self.line += 1 |
2826 self.toggleBookmark(self.line) | 2885 self.toggleBookmark(self.line) |
2827 self.line = -1 | 2886 self.line = -1 |
2828 | 2887 |
2888 @pyqtSlot() | |
2829 def nextBookmark(self): | 2889 def nextBookmark(self): |
2830 """ | 2890 """ |
2831 Public slot to handle the 'Next bookmark' context menu action. | 2891 Public slot to handle the 'Next bookmark' context menu action. |
2832 """ | 2892 """ |
2833 line, index = self.getCursorPosition() | 2893 line, index = self.getCursorPosition() |
2841 bmline = self.markerFindNext(0, 1 << self.bookmark) | 2901 bmline = self.markerFindNext(0, 1 << self.bookmark) |
2842 if bmline >= 0: | 2902 if bmline >= 0: |
2843 self.setCursorPosition(bmline, 0) | 2903 self.setCursorPosition(bmline, 0) |
2844 self.ensureLineVisible(bmline) | 2904 self.ensureLineVisible(bmline) |
2845 | 2905 |
2906 @pyqtSlot() | |
2846 def previousBookmark(self): | 2907 def previousBookmark(self): |
2847 """ | 2908 """ |
2848 Public slot to handle the 'Previous bookmark' context menu action. | 2909 Public slot to handle the 'Previous bookmark' context menu action. |
2849 """ | 2910 """ |
2850 line, index = self.getCursorPosition() | 2911 line, index = self.getCursorPosition() |
2858 bmline = self.markerFindPrevious(self.lines() - 1, 1 << self.bookmark) | 2919 bmline = self.markerFindPrevious(self.lines() - 1, 1 << self.bookmark) |
2859 if bmline >= 0: | 2920 if bmline >= 0: |
2860 self.setCursorPosition(bmline, 0) | 2921 self.setCursorPosition(bmline, 0) |
2861 self.ensureLineVisible(bmline) | 2922 self.ensureLineVisible(bmline) |
2862 | 2923 |
2924 @pyqtSlot() | |
2863 def clearBookmarks(self): | 2925 def clearBookmarks(self): |
2864 """ | 2926 """ |
2865 Public slot to handle the 'Clear all bookmarks' context menu action. | 2927 Public slot to handle the 'Clear all bookmarks' context menu action. |
2866 """ | 2928 """ |
2867 for handle in self.bookmarks: | 2929 for handle in self.bookmarks: |
2872 | 2934 |
2873 ########################################################################### | 2935 ########################################################################### |
2874 ## Printing methods below | 2936 ## Printing methods below |
2875 ########################################################################### | 2937 ########################################################################### |
2876 | 2938 |
2939 @pyqtSlot() | |
2877 def printFile(self): | 2940 def printFile(self): |
2878 """ | 2941 """ |
2879 Public slot to print the text. | 2942 Public slot to print the text. |
2880 """ | 2943 """ |
2881 from .Printer import Printer | 2944 from .Printer import Printer |
2911 QApplication.processEvents() | 2974 QApplication.processEvents() |
2912 else: | 2975 else: |
2913 sb.showMessage(self.tr("Printing aborted"), 2000) | 2976 sb.showMessage(self.tr("Printing aborted"), 2000) |
2914 QApplication.processEvents() | 2977 QApplication.processEvents() |
2915 | 2978 |
2979 @pyqtSlot() | |
2916 def printPreviewFile(self): | 2980 def printPreviewFile(self): |
2917 """ | 2981 """ |
2918 Public slot to show a print preview of the text. | 2982 Public slot to show a print preview of the text. |
2919 """ | 2983 """ |
2920 from .Printer import Printer | 2984 from .Printer import Printer |
2964 | 3028 |
2965 @return flag indicating the presence of task markers (boolean) | 3029 @return flag indicating the presence of task markers (boolean) |
2966 """ | 3030 """ |
2967 return self.__hasTaskMarkers | 3031 return self.__hasTaskMarkers |
2968 | 3032 |
3033 @pyqtSlot() | |
2969 def nextTask(self): | 3034 def nextTask(self): |
2970 """ | 3035 """ |
2971 Public slot to handle the 'Next task' context menu action. | 3036 Public slot to handle the 'Next task' context menu action. |
2972 """ | 3037 """ |
2973 line, index = self.getCursorPosition() | 3038 line, index = self.getCursorPosition() |
2981 taskline = self.markerFindNext(0, 1 << self.taskmarker) | 3046 taskline = self.markerFindNext(0, 1 << self.taskmarker) |
2982 if taskline >= 0: | 3047 if taskline >= 0: |
2983 self.setCursorPosition(taskline, 0) | 3048 self.setCursorPosition(taskline, 0) |
2984 self.ensureLineVisible(taskline) | 3049 self.ensureLineVisible(taskline) |
2985 | 3050 |
3051 @pyqtSlot() | |
2986 def previousTask(self): | 3052 def previousTask(self): |
2987 """ | 3053 """ |
2988 Public slot to handle the 'Previous task' context menu action. | 3054 Public slot to handle the 'Previous task' context menu action. |
2989 """ | 3055 """ |
2990 line, index = self.getCursorPosition() | 3056 line, index = self.getCursorPosition() |
2998 taskline = self.markerFindPrevious(self.lines() - 1, 1 << self.taskmarker) | 3064 taskline = self.markerFindPrevious(self.lines() - 1, 1 << self.taskmarker) |
2999 if taskline >= 0: | 3065 if taskline >= 0: |
3000 self.setCursorPosition(taskline, 0) | 3066 self.setCursorPosition(taskline, 0) |
3001 self.ensureLineVisible(taskline) | 3067 self.ensureLineVisible(taskline) |
3002 | 3068 |
3069 @pyqtSlot() | |
3003 def extractTasks(self): | 3070 def extractTasks(self): |
3004 """ | 3071 """ |
3005 Public slot to extract all tasks. | 3072 Public slot to extract all tasks. |
3006 """ | 3073 """ |
3007 from eric7.Tasks.Task import Task | 3074 from eric7.Tasks.Task import Task |
3059 painter = QPainter(pixmap) | 3126 painter = QPainter(pixmap) |
3060 painter.fillRect(size - 4, 0, 4, size, Preferences.getEditorColour(key)) | 3127 painter.fillRect(size - 4, 0, 4, size, Preferences.getEditorColour(key)) |
3061 painter.end() | 3128 painter.end() |
3062 return pixmap | 3129 return pixmap |
3063 | 3130 |
3131 @pyqtSlot() | |
3064 def __initOnlineChangeTrace(self): | 3132 def __initOnlineChangeTrace(self): |
3065 """ | 3133 """ |
3066 Private slot to initialize the online change trace. | 3134 Private slot to initialize the online change trace. |
3067 """ | 3135 """ |
3068 self.__hasChangeMarkers = False | 3136 self.__hasChangeMarkers = False |
3076 self.__onlineChangeTraceTimer.timeout.connect( | 3144 self.__onlineChangeTraceTimer.timeout.connect( |
3077 self.__onlineChangeTraceTimerTimeout | 3145 self.__onlineChangeTraceTimerTimeout |
3078 ) | 3146 ) |
3079 self.textChanged.connect(self.__resetOnlineChangeTraceTimer) | 3147 self.textChanged.connect(self.__resetOnlineChangeTraceTimer) |
3080 | 3148 |
3149 @pyqtSlot() | |
3081 def __reinitOnlineChangeTrace(self): | 3150 def __reinitOnlineChangeTrace(self): |
3082 """ | 3151 """ |
3083 Private slot to re-initialize the online change trace. | 3152 Private slot to re-initialize the online change trace. |
3084 """ | 3153 """ |
3085 self.__oldText = self.text() | 3154 self.__oldText = self.text() |
3092 """ | 3161 """ |
3093 if Preferences.getEditor("OnlineChangeTrace"): | 3162 if Preferences.getEditor("OnlineChangeTrace"): |
3094 self.__onlineChangeTraceTimer.stop() | 3163 self.__onlineChangeTraceTimer.stop() |
3095 self.__onlineChangeTraceTimer.start() | 3164 self.__onlineChangeTraceTimer.start() |
3096 | 3165 |
3166 @pyqtSlot() | |
3097 def __onlineChangeTraceTimerTimeout(self): | 3167 def __onlineChangeTraceTimerTimeout(self): |
3098 """ | 3168 """ |
3099 Private slot to mark added and changed lines. | 3169 Private slot to mark added and changed lines. |
3100 """ | 3170 """ |
3101 self.__deleteAllChangeMarkers() | 3171 self.__deleteAllChangeMarkers() |
3124 | 3194 |
3125 if self.__hasChangeMarkers: | 3195 if self.__hasChangeMarkers: |
3126 self.changeMarkersUpdated.emit(self) | 3196 self.changeMarkersUpdated.emit(self) |
3127 self.__markerMap.update() | 3197 self.__markerMap.update() |
3128 | 3198 |
3199 @pyqtSlot() | |
3129 def resetOnlineChangeTraceInfo(self): | 3200 def resetOnlineChangeTraceInfo(self): |
3130 """ | 3201 """ |
3131 Public slot to reset the online change trace info. | 3202 Public slot to reset the online change trace info. |
3132 """ | 3203 """ |
3133 self.__lastSavedText = self.text() | 3204 self.__lastSavedText = self.text() |
3146 | 3217 |
3147 if self.__hasChangeMarkers: | 3218 if self.__hasChangeMarkers: |
3148 self.changeMarkersUpdated.emit(self) | 3219 self.changeMarkersUpdated.emit(self) |
3149 self.__markerMap.update() | 3220 self.__markerMap.update() |
3150 | 3221 |
3222 @pyqtSlot() | |
3151 def __deleteAllChangeMarkers(self): | 3223 def __deleteAllChangeMarkers(self): |
3152 """ | 3224 """ |
3153 Private slot to delete all change markers. | 3225 Private slot to delete all change markers. |
3154 """ | 3226 """ |
3155 self.markerDeleteAll(self.__changeMarkerUnsaved) | 3227 self.markerDeleteAll(self.__changeMarkerUnsaved) |
3186 | 3258 |
3187 @return flag indicating the presence of change markers (boolean) | 3259 @return flag indicating the presence of change markers (boolean) |
3188 """ | 3260 """ |
3189 return self.__hasChangeMarkers | 3261 return self.__hasChangeMarkers |
3190 | 3262 |
3263 @pyqtSlot() | |
3191 def nextChange(self): | 3264 def nextChange(self): |
3192 """ | 3265 """ |
3193 Public slot to handle the 'Next change' context menu action. | 3266 Public slot to handle the 'Next change' context menu action. |
3194 """ | 3267 """ |
3195 line, index = self.getCursorPosition() | 3268 line, index = self.getCursorPosition() |
3203 changeline = self.markerFindNext(0, self.changeMarkersMask) | 3276 changeline = self.markerFindNext(0, self.changeMarkersMask) |
3204 if changeline >= 0: | 3277 if changeline >= 0: |
3205 self.setCursorPosition(changeline, 0) | 3278 self.setCursorPosition(changeline, 0) |
3206 self.ensureLineVisible(changeline) | 3279 self.ensureLineVisible(changeline) |
3207 | 3280 |
3281 @pyqtSlot() | |
3208 def previousChange(self): | 3282 def previousChange(self): |
3209 """ | 3283 """ |
3210 Public slot to handle the 'Previous change' context menu action. | 3284 Public slot to handle the 'Previous change' context menu action. |
3211 """ | 3285 """ |
3212 line, index = self.getCursorPosition() | 3286 line, index = self.getCursorPosition() |
3302 break | 3376 break |
3303 # Couldn't find the unmodified state | 3377 # Couldn't find the unmodified state |
3304 | 3378 |
3305 def readFile(self, fn, createIt=False, encoding=""): | 3379 def readFile(self, fn, createIt=False, encoding=""): |
3306 """ | 3380 """ |
3307 Public slot to read the text from a file. | 3381 Public method to read the text from a file. |
3308 | 3382 |
3309 @param fn filename to read from (string) | 3383 @param fn filename to read from (string) |
3310 @param createIt flag indicating the creation of a new file, if the | 3384 @param createIt flag indicating the creation of a new file, if the |
3311 given one doesn't exist (boolean) | 3385 given one doesn't exist (boolean) |
3312 @param encoding encoding to be used to read the file (string) | 3386 @param encoding encoding to be used to read the file (string) |
3358 self.extractTasks() | 3432 self.extractTasks() |
3359 | 3433 |
3360 self.setModified(modified) | 3434 self.setModified(modified) |
3361 self.lastModified = pathlib.Path(fn).stat().st_mtime | 3435 self.lastModified = pathlib.Path(fn).stat().st_mtime |
3362 | 3436 |
3437 @pyqtSlot() | |
3363 def __convertTabs(self): | 3438 def __convertTabs(self): |
3364 """ | 3439 """ |
3365 Private slot to convert tabulators to spaces. | 3440 Private slot to convert tabulators to spaces. |
3366 """ | 3441 """ |
3367 if ( | 3442 if ( |
3391 ok = self.findNextTarget() | 3466 ok = self.findNextTarget() |
3392 self.endUndoAction() | 3467 self.endUndoAction() |
3393 | 3468 |
3394 def writeFile(self, fn, backup=True): | 3469 def writeFile(self, fn, backup=True): |
3395 """ | 3470 """ |
3396 Public slot to write the text to a file. | 3471 Public method to write the text to a file. |
3397 | 3472 |
3398 @param fn filename to write to (string) | 3473 @param fn filename to write to |
3399 @param backup flag indicating to save a backup (boolean) | 3474 @type str |
3400 @return flag indicating success (boolean) | 3475 @param backup flag indicating to save a backup |
3476 @type bool | |
3477 @return flag indicating success | |
3478 @rtype bool | |
3401 """ | 3479 """ |
3402 config = self.__loadEditorConfigObject(fn) | 3480 config = self.__loadEditorConfigObject(fn) |
3403 | 3481 |
3404 eol = self.__getEditorConfig("EOLMode", nodefault=True, config=config) | 3482 eol = self.__getEditorConfig("EOLMode", nodefault=True, config=config) |
3405 if eol is not None: | 3483 if eol is not None: |
3576 else: | 3654 else: |
3577 fn = self.fileName | 3655 fn = self.fileName |
3578 | 3656 |
3579 self.__loadEditorConfig(fn) | 3657 self.__loadEditorConfig(fn) |
3580 self.editorAboutToBeSaved.emit(self.fileName) | 3658 self.editorAboutToBeSaved.emit(self.fileName) |
3659 if self.__autosaveTimer.isActive(): | |
3660 self.__autosaveTimer.stop() | |
3581 if self.writeFile(fn): | 3661 if self.writeFile(fn): |
3582 if saveas: | 3662 if saveas: |
3583 self.__clearBreakpoints(self.fileName) | 3663 self.__clearBreakpoints(self.fileName) |
3584 self.setFileName(fn) | 3664 self.setFileName(fn) |
3585 self.setModified(False) | 3665 self.setModified(False) |
3617 ) | 3697 ) |
3618 return False | 3698 return False |
3619 | 3699 |
3620 def saveFileAs(self, path=None): | 3700 def saveFileAs(self, path=None): |
3621 """ | 3701 """ |
3622 Public slot to save a file with a new name. | 3702 Public method to save a file with a new name. |
3623 | 3703 |
3624 @param path directory to save the file in (string) | 3704 @param path directory to save the file in |
3625 @return tuple of two values (boolean, string) giving a success | 3705 @type str |
3626 indicator and the name of the saved file | 3706 @return tuple containing a success indicator and the name of the saved file |
3707 @rtype tuple of (bool, str) | |
3627 """ | 3708 """ |
3628 return self.saveFile(True, path) | 3709 return self.saveFile(True, path) |
3629 | 3710 |
3630 def __saveDeviceFile(self, saveas=False): | 3711 def __saveDeviceFile(self, saveas=False): |
3631 """ | 3712 """ |
3667 | 3748 |
3668 return False | 3749 return False |
3669 | 3750 |
3670 def handleRenamed(self, fn): | 3751 def handleRenamed(self, fn): |
3671 """ | 3752 """ |
3672 Public slot to handle the editorRenamed signal. | 3753 Public method to handle the editorRenamed signal. |
3673 | 3754 |
3674 @param fn filename to be set for the editor (string). | 3755 @param fn filename to be set for the editor (string). |
3675 """ | 3756 """ |
3676 self.__clearBreakpoints(fn) | 3757 self.__clearBreakpoints(fn) |
3677 | 3758 |
3685 | 3766 |
3686 self.lastModified = pathlib.Path(fn).stat().st_mtime | 3767 self.lastModified = pathlib.Path(fn).stat().st_mtime |
3687 self.vm.setEditorName(self, self.fileName) | 3768 self.vm.setEditorName(self, self.fileName) |
3688 self.__updateReadOnly(True) | 3769 self.__updateReadOnly(True) |
3689 | 3770 |
3771 @pyqtSlot(str) | |
3690 def fileRenamed(self, fn): | 3772 def fileRenamed(self, fn): |
3691 """ | 3773 """ |
3692 Public slot to handle the editorRenamed signal. | 3774 Public slot to handle the editorRenamed signal. |
3693 | 3775 |
3694 @param fn filename to be set for the editor (string). | 3776 @param fn filename to be set for the editor |
3777 @type str. | |
3695 """ | 3778 """ |
3696 self.handleRenamed(fn) | 3779 self.handleRenamed(fn) |
3697 if not self.inFileRenamed: | 3780 if not self.inFileRenamed: |
3698 self.inFileRenamed = True | 3781 self.inFileRenamed = True |
3699 self.editorRenamed.emit(self.fileName) | 3782 self.editorRenamed.emit(self.fileName) |
3703 ## Utility methods below | 3786 ## Utility methods below |
3704 ########################################################################### | 3787 ########################################################################### |
3705 | 3788 |
3706 def ensureVisible(self, line, expand=False): | 3789 def ensureVisible(self, line, expand=False): |
3707 """ | 3790 """ |
3708 Public slot to ensure, that the specified line is visible. | 3791 Public method to ensure, that the specified line is visible. |
3709 | 3792 |
3710 @param line line number to make visible | 3793 @param line line number to make visible |
3711 @type int | 3794 @type int |
3712 @param expand flag indicating to expand all folds | 3795 @param expand flag indicating to expand all folds |
3713 @type bool | 3796 @type bool |
3720 QsciScintilla.SC_FOLDACTION_EXPAND, | 3803 QsciScintilla.SC_FOLDACTION_EXPAND, |
3721 ) | 3804 ) |
3722 | 3805 |
3723 def ensureVisibleTop(self, line, expand=False): | 3806 def ensureVisibleTop(self, line, expand=False): |
3724 """ | 3807 """ |
3725 Public slot to ensure, that the specified line is visible at the top | 3808 Public method to ensure, that the specified line is visible at the top |
3726 of the editor. | 3809 of the editor. |
3727 | 3810 |
3728 @param line line number to make visible | 3811 @param line line number to make visible |
3729 @type int | 3812 @type int |
3730 @param expand flag indicating to expand all folds | 3813 @param expand flag indicating to expand all folds |
3742 | 3825 |
3743 def __marginClicked(self, margin, line, modifiers): # noqa: U100 | 3826 def __marginClicked(self, margin, line, modifiers): # noqa: U100 |
3744 """ | 3827 """ |
3745 Private slot to handle the marginClicked signal. | 3828 Private slot to handle the marginClicked signal. |
3746 | 3829 |
3747 @param margin id of the clicked margin (integer) | 3830 @param margin id of the clicked margin |
3748 @param line line number of the click (integer) | 3831 @type int |
3749 @param modifiers keyboard modifiers (Qt.KeyboardModifiers) | 3832 @param line line number of the click |
3833 @type int | |
3834 @param modifiers keyboard modifiers | |
3835 @type Qt.KeyboardModifiers | |
3750 """ | 3836 """ |
3751 if margin == self.__bmMargin: | 3837 if margin == self.__bmMargin: |
3752 self.toggleBookmark(line + 1) | 3838 self.toggleBookmark(line + 1) |
3753 elif margin == self.__bpMargin: | 3839 elif margin == self.__bpMargin: |
3754 self.__toggleBreakpoint(line + 1) | 3840 self.__toggleBreakpoint(line + 1) |
3756 if self.markersAtLine(line) & (1 << self.syntaxerror): | 3842 if self.markersAtLine(line) & (1 << self.syntaxerror): |
3757 self.__showSyntaxError(line) | 3843 self.__showSyntaxError(line) |
3758 elif self.markersAtLine(line) & (1 << self.warning): | 3844 elif self.markersAtLine(line) & (1 << self.warning): |
3759 self.__showWarning(line) | 3845 self.__showWarning(line) |
3760 | 3846 |
3847 @pyqtSlot() | |
3761 def handleMonospacedEnable(self): | 3848 def handleMonospacedEnable(self): |
3762 """ | 3849 """ |
3763 Public slot to handle the Use Monospaced Font context menu entry. | 3850 Public slot to handle the Use Monospaced Font context menu entry. |
3764 """ | 3851 """ |
3765 if self.menuActs["MonospacedFont"].isChecked(): | 3852 if self.menuActs["MonospacedFont"].isChecked(): |
3772 self.lexer_.readSubstyles(self) | 3859 self.lexer_.readSubstyles(self) |
3773 self.lexer_.initProperties() | 3860 self.lexer_.initProperties() |
3774 self.setMonospaced(False) | 3861 self.setMonospaced(False) |
3775 self.__setMarginsDisplay() | 3862 self.__setMarginsDisplay() |
3776 | 3863 |
3777 def getWordBoundaries(self, line, index, useWordChars=True): | 3864 def getWordBoundaries(self, line, index, useWordChars=True, forCompletion=False): |
3778 """ | 3865 """ |
3779 Public method to get the word boundaries at a position. | 3866 Public method to get the word boundaries at a position. |
3780 | 3867 |
3781 @param line number of line to look at (int) | 3868 @param line number of line to look at |
3782 @param index position to look at (int) | 3869 @type int |
3870 @param index position to look at | |
3871 @type int | |
3783 @param useWordChars flag indicating to use the wordCharacters | 3872 @param useWordChars flag indicating to use the wordCharacters |
3784 method (boolean) | 3873 method (defaults to True) |
3874 @type bool (optional) | |
3875 @param forCompletion flag indicating a modification for completions (defaults | |
3876 to False) | |
3877 @type bool (optional) | |
3785 @return tuple with start and end indexes of the word at the position | 3878 @return tuple with start and end indexes of the word at the position |
3786 (integer, integer) | 3879 @rtype tuple of (int, int) |
3787 """ | 3880 """ |
3788 wc = self.wordCharacters() | 3881 wc = self.wordCharacters() |
3789 if wc is None or not useWordChars: | 3882 if wc is None or not useWordChars: |
3790 pattern = r"\b[\w_]+\b" | 3883 pattern = r"\b[\w_]+\b" |
3791 else: | 3884 else: |
3792 wc = re.sub(r"\w", "", wc) | 3885 wc = re.sub(r"\w", "", wc) |
3793 pattern = r"\b[\w{0}]+\b".format(re.escape(wc)) | 3886 pattern = r"\b[\w{0}]+\b".format(re.escape(wc)) |
3887 if forCompletion: | |
3888 pattern += "=?" | |
3794 rx = ( | 3889 rx = ( |
3795 re.compile(pattern) | 3890 re.compile(pattern) |
3796 if self.caseSensitive() | 3891 if self.caseSensitive() |
3797 else re.compile(pattern, re.IGNORECASE) | 3892 else re.compile(pattern, re.IGNORECASE) |
3798 ) | 3893 ) |
3803 if start <= index <= end: | 3898 if start <= index <= end: |
3804 return (start, end) | 3899 return (start, end) |
3805 | 3900 |
3806 return (index, index) | 3901 return (index, index) |
3807 | 3902 |
3808 def getWord(self, line, index, direction=0, useWordChars=True): | 3903 def getWord(self, line, index, direction=0, useWordChars=True, forCompletion=False): |
3809 """ | 3904 """ |
3810 Public method to get the word at a position. | 3905 Public method to get the word at a position. |
3811 | 3906 |
3812 @param line number of line to look at (int) | 3907 @param line number of line to look at |
3813 @param index position to look at (int) | 3908 @type int |
3909 @param index position to look at | |
3910 @type int | |
3814 @param direction direction to look in (0 = whole word, 1 = left, | 3911 @param direction direction to look in (0 = whole word, 1 = left, |
3815 2 = right) | 3912 2 = right) |
3913 @type int | |
3816 @param useWordChars flag indicating to use the wordCharacters | 3914 @param useWordChars flag indicating to use the wordCharacters |
3817 method (boolean) | 3915 method (defaults to True) |
3818 @return the word at that position (string) | 3916 @type bool (optional) |
3819 """ | 3917 @param forCompletion flag indicating a modification for completions (defaults |
3820 start, end = self.getWordBoundaries(line, index, useWordChars) | 3918 to False) |
3919 @type bool (optional) | |
3920 @return the word at that position | |
3921 @rtype str | |
3922 """ | |
3923 start, end = self.getWordBoundaries( | |
3924 line, index, useWordChars=useWordChars, forCompletion=forCompletion | |
3925 ) | |
3821 if direction == 1: | 3926 if direction == 1: |
3822 end = index | 3927 end = index |
3823 elif direction == 2: | 3928 elif direction == 2: |
3824 start = index | 3929 start = index |
3825 if end > start: | 3930 if end > start: |
4078 if Preferences.getEditor("CommentColumn0"): | 4183 if Preferences.getEditor("CommentColumn0"): |
4079 return line.startswith(commentStr) | 4184 return line.startswith(commentStr) |
4080 else: | 4185 else: |
4081 return line.strip().startswith(commentStr) | 4186 return line.strip().startswith(commentStr) |
4082 | 4187 |
4188 @pyqtSlot() | |
4083 def toggleCommentBlock(self): | 4189 def toggleCommentBlock(self): |
4084 """ | 4190 """ |
4085 Public slot to toggle the comment of a block. | 4191 Public slot to toggle the comment of a block. |
4086 | 4192 |
4087 If the editor contains selected text and the start line is not commented, it | 4193 If the editor contains selected text and the start line is not commented, it |
4125 # 3. uncomment the determined block and reset the cursor position | 4231 # 3. uncomment the determined block and reset the cursor position |
4126 self.setSelection(begline, 0, endline, self.lineLength(endline)) | 4232 self.setSelection(begline, 0, endline, self.lineLength(endline)) |
4127 self.uncommentLineOrSelection() | 4233 self.uncommentLineOrSelection() |
4128 self.setCursorPosition(line, index - len(commentStr)) | 4234 self.setCursorPosition(line, index - len(commentStr)) |
4129 | 4235 |
4236 @pyqtSlot() | |
4130 def commentLine(self): | 4237 def commentLine(self): |
4131 """ | 4238 """ |
4132 Public slot to comment the current line. | 4239 Public slot to comment the current line. |
4133 """ | 4240 """ |
4134 if self.lexer_ is None or not self.lexer_.canBlockComment(): | 4241 if self.lexer_ is None or not self.lexer_.canBlockComment(): |
4142 lineText = self.text(line) | 4249 lineText = self.text(line) |
4143 pos = len(lineText.replace(lineText.lstrip(" \t"), "")) | 4250 pos = len(lineText.replace(lineText.lstrip(" \t"), "")) |
4144 self.insertAt(self.lexer_.commentStr(), line, pos) | 4251 self.insertAt(self.lexer_.commentStr(), line, pos) |
4145 self.endUndoAction() | 4252 self.endUndoAction() |
4146 | 4253 |
4254 @pyqtSlot() | |
4147 def uncommentLine(self): | 4255 def uncommentLine(self): |
4148 """ | 4256 """ |
4149 Public slot to uncomment the current line. | 4257 Public slot to uncomment the current line. |
4150 """ | 4258 """ |
4151 if self.lexer_ is None or not self.lexer_.canBlockComment(): | 4259 if self.lexer_ is None or not self.lexer_.canBlockComment(): |
4168 pos = len(lineText.replace(lineText.lstrip(" \t"), "")) | 4276 pos = len(lineText.replace(lineText.lstrip(" \t"), "")) |
4169 self.setSelection(line, pos, line, pos + len(commentStr)) | 4277 self.setSelection(line, pos, line, pos + len(commentStr)) |
4170 self.removeSelectedText() | 4278 self.removeSelectedText() |
4171 self.endUndoAction() | 4279 self.endUndoAction() |
4172 | 4280 |
4281 @pyqtSlot() | |
4173 def commentSelection(self): | 4282 def commentSelection(self): |
4174 """ | 4283 """ |
4175 Public slot to comment the current selection. | 4284 Public slot to comment the current selection. |
4176 """ | 4285 """ |
4177 if self.lexer_ is None or not self.lexer_.canBlockComment(): | 4286 if self.lexer_ is None or not self.lexer_.canBlockComment(): |
4198 | 4307 |
4199 # change the selection accordingly | 4308 # change the selection accordingly |
4200 self.setSelection(lineFrom, 0, endLine + 1, 0) | 4309 self.setSelection(lineFrom, 0, endLine + 1, 0) |
4201 self.endUndoAction() | 4310 self.endUndoAction() |
4202 | 4311 |
4312 @pyqtSlot() | |
4203 def uncommentSelection(self): | 4313 def uncommentSelection(self): |
4204 """ | 4314 """ |
4205 Public slot to uncomment the current selection. | 4315 Public slot to uncomment the current selection. |
4206 """ | 4316 """ |
4207 if self.lexer_ is None or not self.lexer_.canBlockComment(): | 4317 if self.lexer_ is None or not self.lexer_.canBlockComment(): |
4246 | 4356 |
4247 # change the selection accordingly | 4357 # change the selection accordingly |
4248 self.setSelection(lineFrom, indexFrom, lineTo, indexTo) | 4358 self.setSelection(lineFrom, indexFrom, lineTo, indexTo) |
4249 self.endUndoAction() | 4359 self.endUndoAction() |
4250 | 4360 |
4361 @pyqtSlot() | |
4251 def commentLineOrSelection(self): | 4362 def commentLineOrSelection(self): |
4252 """ | 4363 """ |
4253 Public slot to comment the current line or current selection. | 4364 Public slot to comment the current line or current selection. |
4254 """ | 4365 """ |
4255 if self.hasSelectedText(): | 4366 if self.hasSelectedText(): |
4256 self.commentSelection() | 4367 self.commentSelection() |
4257 else: | 4368 else: |
4258 self.commentLine() | 4369 self.commentLine() |
4259 | 4370 |
4371 @pyqtSlot() | |
4260 def uncommentLineOrSelection(self): | 4372 def uncommentLineOrSelection(self): |
4261 """ | 4373 """ |
4262 Public slot to uncomment the current line or current selection. | 4374 Public slot to uncomment the current line or current selection. |
4263 """ | 4375 """ |
4264 if self.hasSelectedText(): | 4376 if self.hasSelectedText(): |
4265 self.uncommentSelection() | 4377 self.uncommentSelection() |
4266 else: | 4378 else: |
4267 self.uncommentLine() | 4379 self.uncommentLine() |
4268 | 4380 |
4381 @pyqtSlot() | |
4269 def streamCommentLine(self): | 4382 def streamCommentLine(self): |
4270 """ | 4383 """ |
4271 Public slot to stream comment the current line. | 4384 Public slot to stream comment the current line. |
4272 """ | 4385 """ |
4273 if self.lexer_ is None or not self.lexer_.canStreamComment(): | 4386 if self.lexer_ is None or not self.lexer_.canStreamComment(): |
4279 self.beginUndoAction() | 4392 self.beginUndoAction() |
4280 self.insertAt(commentStr["end"], line, self.lineLength(line)) | 4393 self.insertAt(commentStr["end"], line, self.lineLength(line)) |
4281 self.insertAt(commentStr["start"], line, 0) | 4394 self.insertAt(commentStr["start"], line, 0) |
4282 self.endUndoAction() | 4395 self.endUndoAction() |
4283 | 4396 |
4397 @pyqtSlot() | |
4284 def streamCommentSelection(self): | 4398 def streamCommentSelection(self): |
4285 """ | 4399 """ |
4286 Public slot to comment the current selection. | 4400 Public slot to comment the current selection. |
4287 """ | 4401 """ |
4288 if self.lexer_ is None or not self.lexer_.canStreamComment(): | 4402 if self.lexer_ is None or not self.lexer_.canStreamComment(): |
4312 if lineFrom == endLine: | 4426 if lineFrom == endLine: |
4313 indexTo += len(commentStr["start"]) | 4427 indexTo += len(commentStr["start"]) |
4314 self.setSelection(lineFrom, indexFrom, lineTo, indexTo) | 4428 self.setSelection(lineFrom, indexFrom, lineTo, indexTo) |
4315 self.endUndoAction() | 4429 self.endUndoAction() |
4316 | 4430 |
4431 @pyqtSlot() | |
4317 def streamCommentLineOrSelection(self): | 4432 def streamCommentLineOrSelection(self): |
4318 """ | 4433 """ |
4319 Public slot to stream comment the current line or current selection. | 4434 Public slot to stream comment the current line or current selection. |
4320 """ | 4435 """ |
4321 if self.hasSelectedText(): | 4436 if self.hasSelectedText(): |
4322 self.streamCommentSelection() | 4437 self.streamCommentSelection() |
4323 else: | 4438 else: |
4324 self.streamCommentLine() | 4439 self.streamCommentLine() |
4325 | 4440 |
4441 @pyqtSlot() | |
4326 def boxCommentLine(self): | 4442 def boxCommentLine(self): |
4327 """ | 4443 """ |
4328 Public slot to box comment the current line. | 4444 Public slot to box comment the current line. |
4329 """ | 4445 """ |
4330 if self.lexer_ is None or not self.lexer_.canBoxComment(): | 4446 if self.lexer_ is None or not self.lexer_.canBoxComment(): |
4340 self.insertAt(commentStr["middle"], line, 0) | 4456 self.insertAt(commentStr["middle"], line, 0) |
4341 self.insertAt(eol, line, 0) | 4457 self.insertAt(eol, line, 0) |
4342 self.insertAt(commentStr["start"], line, 0) | 4458 self.insertAt(commentStr["start"], line, 0) |
4343 self.endUndoAction() | 4459 self.endUndoAction() |
4344 | 4460 |
4461 @pyqtSlot() | |
4345 def boxCommentSelection(self): | 4462 def boxCommentSelection(self): |
4346 """ | 4463 """ |
4347 Public slot to box comment the current selection. | 4464 Public slot to box comment the current selection. |
4348 """ | 4465 """ |
4349 if self.lexer_ is None or not self.lexer_.canBoxComment(): | 4466 if self.lexer_ is None or not self.lexer_.canBoxComment(): |
4372 | 4489 |
4373 # change the selection accordingly | 4490 # change the selection accordingly |
4374 self.setSelection(lineFrom, 0, endLine + 3, 0) | 4491 self.setSelection(lineFrom, 0, endLine + 3, 0) |
4375 self.endUndoAction() | 4492 self.endUndoAction() |
4376 | 4493 |
4494 @pyqtSlot() | |
4377 def boxCommentLineOrSelection(self): | 4495 def boxCommentLineOrSelection(self): |
4378 """ | 4496 """ |
4379 Public slot to box comment the current line or current selection. | 4497 Public slot to box comment the current line or current selection. |
4380 """ | 4498 """ |
4381 if self.hasSelectedText(): | 4499 if self.hasSelectedText(): |
4449 indexEnd = indexTo - self.indentationWidth() | 4567 indexEnd = indexTo - self.indentationWidth() |
4450 if indexEnd < 0: | 4568 if indexEnd < 0: |
4451 indexEnd = 0 | 4569 indexEnd = 0 |
4452 self.setSelection(lineFrom, indexStart, lineTo, indexEnd) | 4570 self.setSelection(lineFrom, indexStart, lineTo, indexEnd) |
4453 | 4571 |
4572 @pyqtSlot() | |
4454 def indentLineOrSelection(self): | 4573 def indentLineOrSelection(self): |
4455 """ | 4574 """ |
4456 Public slot to indent the current line or current selection. | 4575 Public slot to indent the current line or current selection. |
4457 """ | 4576 """ |
4458 if self.hasSelectedText(): | 4577 if self.hasSelectedText(): |
4459 self.__indentSelection(True) | 4578 self.__indentSelection(True) |
4460 else: | 4579 else: |
4461 self.__indentLine(True) | 4580 self.__indentLine(True) |
4462 | 4581 |
4582 @pyqtSlot() | |
4463 def unindentLineOrSelection(self): | 4583 def unindentLineOrSelection(self): |
4464 """ | 4584 """ |
4465 Public slot to unindent the current line or current selection. | 4585 Public slot to unindent the current line or current selection. |
4466 """ | 4586 """ |
4467 if self.hasSelectedText(): | 4587 if self.hasSelectedText(): |
4468 self.__indentSelection(False) | 4588 self.__indentSelection(False) |
4469 else: | 4589 else: |
4470 self.__indentLine(False) | 4590 self.__indentLine(False) |
4471 | 4591 |
4592 @pyqtSlot() | |
4472 def smartIndentLineOrSelection(self): | 4593 def smartIndentLineOrSelection(self): |
4473 """ | 4594 """ |
4474 Public slot to indent current line smartly. | 4595 Public slot to indent current line smartly. |
4475 """ | 4596 """ |
4476 if self.hasSelectedText(): | 4597 if self.hasSelectedText(): |
4484 else: | 4605 else: |
4485 self.__indentLine(True) | 4606 self.__indentLine(True) |
4486 | 4607 |
4487 def gotoLine(self, line, pos=1, firstVisible=False, expand=False): | 4608 def gotoLine(self, line, pos=1, firstVisible=False, expand=False): |
4488 """ | 4609 """ |
4489 Public slot to jump to the beginning of a line. | 4610 Public method to jump to the beginning of a line. |
4490 | 4611 |
4491 @param line line number to go to | 4612 @param line line number to go to |
4492 @type int | 4613 @type int |
4493 @param pos position in line to go to | 4614 @param pos position in line to go to |
4494 @type int | 4615 @type int |
4502 if firstVisible: | 4623 if firstVisible: |
4503 self.ensureVisibleTop(line, expand) | 4624 self.ensureVisibleTop(line, expand) |
4504 else: | 4625 else: |
4505 self.ensureVisible(line, expand) | 4626 self.ensureVisible(line, expand) |
4506 | 4627 |
4628 @pyqtSlot() | |
4507 def __textChanged(self): | 4629 def __textChanged(self): |
4508 """ | 4630 """ |
4509 Private slot to handle a change of the editor text. | 4631 Private slot to handle a change of the editor text. |
4510 | 4632 |
4511 This slot defers the handling to the next time the event loop | 4633 This slot defers the handling to the next time the event loop |
4512 is run in order to ensure, that cursor position has been updated | 4634 is run in order to ensure, that cursor position has been updated |
4513 by the underlying Scintilla editor. | 4635 by the underlying Scintilla editor. |
4514 """ | 4636 """ |
4515 QTimer.singleShot(0, self.__saveLastEditPosition) | 4637 QTimer.singleShot(0, self.__saveLastEditPosition) |
4516 | 4638 |
4639 @pyqtSlot() | |
4517 def __saveLastEditPosition(self): | 4640 def __saveLastEditPosition(self): |
4518 """ | 4641 """ |
4519 Private slot to record the last edit position. | 4642 Private slot to record the last edit position. |
4520 """ | 4643 """ |
4521 self.__lastEditPosition = self.getCursorPosition() | 4644 self.__lastEditPosition = self.getCursorPosition() |
4589 | 4712 |
4590 ########################################################################### | 4713 ########################################################################### |
4591 ## Setup methods below | 4714 ## Setup methods below |
4592 ########################################################################### | 4715 ########################################################################### |
4593 | 4716 |
4717 @pyqtSlot() | |
4594 def readSettings(self): | 4718 def readSettings(self): |
4595 """ | 4719 """ |
4596 Public slot to read the settings into our lexer. | 4720 Public slot to read the settings into our lexer. |
4597 """ | 4721 """ |
4598 # read the lexer settings and reinit the properties | 4722 # read the lexer settings and reinit the properties |
4644 | 4768 |
4645 # set the calltips function | 4769 # set the calltips function |
4646 self.__setCallTips() | 4770 self.__setCallTips() |
4647 | 4771 |
4648 # set the autosave flags | 4772 # set the autosave flags |
4649 self.autosaveEnabled = Preferences.getEditor("AutosaveInterval") > 0 | 4773 self.__autosaveInterval = Preferences.getEditor("AutosaveIntervalSeconds") |
4774 if self.__autosaveInterval == 0: | |
4775 self.__autosaveTimer.stop() | |
4776 else: | |
4777 if self.isModified(): | |
4778 self.__autosaveTimer.start(self.__autosaveInterval * 1000) | |
4650 | 4779 |
4651 if Preferences.getEditor("MiniContextMenu") != self.miniMenu: | 4780 if Preferences.getEditor("MiniContextMenu") != self.miniMenu: |
4652 # regenerate context menu | 4781 # regenerate context menu |
4653 self.__initContextMenu() | 4782 self.__initContextMenu() |
4654 else: | 4783 else: |
4656 self.menuActs["AutoCompletionEnable"].setChecked( | 4785 self.menuActs["AutoCompletionEnable"].setChecked( |
4657 self.autoCompletionThreshold() != -1 | 4786 self.autoCompletionThreshold() != -1 |
4658 ) | 4787 ) |
4659 self.menuActs["MonospacedFont"].setChecked(self.useMonospaced) | 4788 self.menuActs["MonospacedFont"].setChecked(self.useMonospaced) |
4660 self.menuActs["AutosaveEnable"].setChecked( | 4789 self.menuActs["AutosaveEnable"].setChecked( |
4661 self.autosaveEnabled and not self.autosaveManuallyDisabled | 4790 self.__autosaveInterval > 0 and not self.__autosaveManuallyDisabled |
4662 ) | 4791 ) |
4663 | 4792 |
4664 # regenerate the margins context menu(s) | 4793 # regenerate the margins context menu(s) |
4665 self.__initContextMenuMargins() | 4794 self.__initContextMenuMargins() |
4666 | 4795 |
4800 self.setMarginWidth(self.__foldMargin, 0) | 4929 self.setMarginWidth(self.__foldMargin, 0) |
4801 self.setFolding( | 4930 self.setFolding( |
4802 QsciScintilla.FoldStyle.NoFoldStyle.value, self.__foldMargin | 4931 QsciScintilla.FoldStyle.NoFoldStyle.value, self.__foldMargin |
4803 ) | 4932 ) |
4804 | 4933 |
4934 @pyqtSlot() | |
4805 def __resizeLinenoMargin(self): | 4935 def __resizeLinenoMargin(self): |
4806 """ | 4936 """ |
4807 Private slot to resize the line numbers margin. | 4937 Private slot to resize the line numbers margin. |
4808 """ | 4938 """ |
4809 linenoMargin = Preferences.getEditor("LinenoMargin") | 4939 linenoMargin = Preferences.getEditor("LinenoMargin") |
5128 elif autoCompletionSource == QsciScintilla.AutoCompletionSource.AcsAPIs: | 5258 elif autoCompletionSource == QsciScintilla.AutoCompletionSource.AcsAPIs: |
5129 self.setAutoCompletionSource(QsciScintilla.AutoCompletionSource.AcsAPIs) | 5259 self.setAutoCompletionSource(QsciScintilla.AutoCompletionSource.AcsAPIs) |
5130 else: | 5260 else: |
5131 self.setAutoCompletionSource(QsciScintilla.AutoCompletionSource.AcsAll) | 5261 self.setAutoCompletionSource(QsciScintilla.AutoCompletionSource.AcsAll) |
5132 | 5262 |
5263 @pyqtSlot() | |
5133 def __toggleAutoCompletionEnable(self): | 5264 def __toggleAutoCompletionEnable(self): |
5134 """ | 5265 """ |
5135 Private slot to handle the Enable Autocompletion context menu entry. | 5266 Private slot to handle the Enable Autocompletion context menu entry. |
5136 """ | 5267 """ |
5137 if self.menuActs["AutoCompletionEnable"].isChecked(): | 5268 if self.menuActs["AutoCompletionEnable"].isChecked(): |
5141 | 5272 |
5142 ################################################################# | 5273 ################################################################# |
5143 ## Support for autocompletion hook methods | 5274 ## Support for autocompletion hook methods |
5144 ################################################################# | 5275 ################################################################# |
5145 | 5276 |
5277 @pyqtSlot(int) | |
5146 def __charAdded(self, charNumber): | 5278 def __charAdded(self, charNumber): |
5147 """ | 5279 """ |
5148 Private slot called to handle the user entering a character. | 5280 Private slot called to handle the user entering a character. |
5149 | 5281 |
5150 @param charNumber value of the character entered (integer) | 5282 @param charNumber value of the character entered |
5283 @type int | |
5151 """ | 5284 """ |
5152 char = chr(charNumber) | 5285 char = chr(charNumber) |
5153 # update code documentation viewer | 5286 # update code documentation viewer |
5154 if char == "(" and Preferences.getDocuViewer("ShowInfoOnOpenParenthesis"): | 5287 if char == "(" and Preferences.getDocuViewer("ShowInfoOnOpenParenthesis"): |
5155 self.vm.showEditorInfo(self) | 5288 self.vm.showEditorInfo(self) |
5197 return False | 5330 return False |
5198 | 5331 |
5199 wseps = self.lexer_.autoCompletionWordSeparators() | 5332 wseps = self.lexer_.autoCompletionWordSeparators() |
5200 return any(wsep.endswith(ch) for wsep in wseps) | 5333 return any(wsep.endswith(ch) for wsep in wseps) |
5201 | 5334 |
5335 @pyqtSlot() | |
5202 def __autocompletionCancelled(self): | 5336 def __autocompletionCancelled(self): |
5203 """ | 5337 """ |
5204 Private slot to handle the cancellation of an auto-completion list. | 5338 Private slot to handle the cancellation of an auto-completion list. |
5205 """ | 5339 """ |
5206 self.__acWatchdog.stop() | 5340 self.__acWatchdog.stop() |
5445 """ | 5579 """ |
5446 Private method to clear the auto-completions cache. | 5580 Private method to clear the auto-completions cache. |
5447 """ | 5581 """ |
5448 self.__acCache.clear() | 5582 self.__acCache.clear() |
5449 | 5583 |
5584 @pyqtSlot(int, str) | |
5450 def __completionListSelected(self, listId, txt): | 5585 def __completionListSelected(self, listId, txt): |
5451 """ | 5586 """ |
5452 Private slot to handle the selection from the completion list. | 5587 Private slot to handle the selection from the completion list. |
5453 | 5588 |
5454 @param listId the ID of the user list (should be 1 or 2) (integer) | 5589 @param listId the ID of the user list (should be 1 or 2) |
5455 @param txt the selected text (string) | 5590 @type int |
5591 @param txt the selected text | |
5592 @type str | |
5456 """ | 5593 """ |
5457 # custom completions via plug-ins | 5594 # custom completions via plug-ins |
5458 if listId == EditorAutoCompletionListID: | 5595 if listId == EditorAutoCompletionListID: |
5459 lst = txt.split() | 5596 lst = txt.split() |
5460 if len(lst) > 1: | 5597 if len(lst) > 1: |
5465 self.selectCurrentWord() | 5602 self.selectCurrentWord() |
5466 self.removeSelectedText() | 5603 self.removeSelectedText() |
5467 line, col = self.getCursorPosition() | 5604 line, col = self.getCursorPosition() |
5468 else: | 5605 else: |
5469 line, col = self.getCursorPosition() | 5606 line, col = self.getCursorPosition() |
5470 wLeft = self.getWordLeft(line, col) | 5607 wLeft = self.getWord(line, col, 1, forCompletion=True) # word left |
5471 if not txt.startswith(wLeft): | 5608 if not txt.startswith(wLeft): |
5472 self.selectCurrentWord() | 5609 self.selectCurrentWord() |
5473 self.removeSelectedText() | 5610 self.removeSelectedText() |
5474 line, col = self.getCursorPosition() | 5611 line, col = self.getCursorPosition() |
5475 elif wLeft: | 5612 elif wLeft: |
5709 | 5846 |
5710 ################################################################# | 5847 ################################################################# |
5711 ## Methods needed by the code documentation viewer | 5848 ## Methods needed by the code documentation viewer |
5712 ################################################################# | 5849 ################################################################# |
5713 | 5850 |
5851 @pyqtSlot() | |
5714 def __showCodeInfo(self): | 5852 def __showCodeInfo(self): |
5715 """ | 5853 """ |
5716 Private slot to handle the context menu action to show code info. | 5854 Private slot to handle the context menu action to show code info. |
5717 """ | 5855 """ |
5718 self.vm.showEditorInfo(self) | 5856 self.vm.showEditorInfo(self) |
5762 elif self.__marginNumber(pos.x()) == self.__indicMargin: | 5900 elif self.__marginNumber(pos.x()) == self.__indicMargin: |
5763 self.indicMarginMenu.popup(self.mapToGlobal(pos)) | 5901 self.indicMarginMenu.popup(self.mapToGlobal(pos)) |
5764 elif self.__marginNumber(pos.x()) == self.__foldMargin: | 5902 elif self.__marginNumber(pos.x()) == self.__foldMargin: |
5765 self.foldMarginMenu.popup(self.mapToGlobal(pos)) | 5903 self.foldMarginMenu.popup(self.mapToGlobal(pos)) |
5766 | 5904 |
5905 @pyqtSlot() | |
5767 def __aboutToShowContextMenu(self): | 5906 def __aboutToShowContextMenu(self): |
5768 """ | 5907 """ |
5769 Private slot handling the aboutToShow signal of the context menu. | 5908 Private slot handling the aboutToShow signal of the context menu. |
5770 """ | 5909 """ |
5771 self.menuActs["Reopen"].setEnabled( | 5910 self.menuActs["Reopen"].setEnabled( |
5826 | 5965 |
5827 self.menuActs["Tools"].setEnabled(not self.toolsMenu.isEmpty()) | 5966 self.menuActs["Tools"].setEnabled(not self.toolsMenu.isEmpty()) |
5828 | 5967 |
5829 self.showMenu.emit("Main", self.menu, self) | 5968 self.showMenu.emit("Main", self.menu, self) |
5830 | 5969 |
5970 @pyqtSlot() | |
5831 def __showContextMenuAutocompletion(self): | 5971 def __showContextMenuAutocompletion(self): |
5832 """ | 5972 """ |
5833 Private slot called before the autocompletion menu is shown. | 5973 Private slot called before the autocompletion menu is shown. |
5834 """ | 5974 """ |
5835 self.menuActs["acDynamic"].setEnabled(self.canProvideDynamicAutoCompletion()) | 5975 self.menuActs["acDynamic"].setEnabled(self.canProvideDynamicAutoCompletion()) |
5837 self.menuActs["acAPI"].setEnabled(self.acAPI) | 5977 self.menuActs["acAPI"].setEnabled(self.acAPI) |
5838 self.menuActs["acAPIDocument"].setEnabled(self.acAPI) | 5978 self.menuActs["acAPIDocument"].setEnabled(self.acAPI) |
5839 | 5979 |
5840 self.showMenu.emit("Autocompletion", self.autocompletionMenu, self) | 5980 self.showMenu.emit("Autocompletion", self.autocompletionMenu, self) |
5841 | 5981 |
5982 @pyqtSlot() | |
5842 def __showContextMenuShow(self): | 5983 def __showContextMenuShow(self): |
5843 """ | 5984 """ |
5844 Private slot called before the show menu is shown. | 5985 Private slot called before the show menu is shown. |
5845 """ | 5986 """ |
5846 prEnable = False | 5987 prEnable = False |
5882 ) | 6023 ) |
5883 self.coverageHideAnnotationMenuAct.setEnabled(len(self.notcoveredMarkers) > 0) | 6024 self.coverageHideAnnotationMenuAct.setEnabled(len(self.notcoveredMarkers) > 0) |
5884 | 6025 |
5885 self.showMenu.emit("Show", self.menuShow, self) | 6026 self.showMenu.emit("Show", self.menuShow, self) |
5886 | 6027 |
6028 @pyqtSlot() | |
5887 def __showContextMenuGraphics(self): | 6029 def __showContextMenuGraphics(self): |
5888 """ | 6030 """ |
5889 Private slot handling the aboutToShow signal of the diagrams context | 6031 Private slot handling the aboutToShow signal of the diagrams context |
5890 menu. | 6032 menu. |
5891 """ | 6033 """ |
5896 else: | 6038 else: |
5897 self.applicationDiagramMenuAct.setEnabled(False) | 6039 self.applicationDiagramMenuAct.setEnabled(False) |
5898 | 6040 |
5899 self.showMenu.emit("Graphics", self.graphicsMenu, self) | 6041 self.showMenu.emit("Graphics", self.graphicsMenu, self) |
5900 | 6042 |
6043 @pyqtSlot(QMenu) | |
5901 def __showContextMenuMargin(self, menu): | 6044 def __showContextMenuMargin(self, menu): |
5902 """ | 6045 """ |
5903 Private slot handling the aboutToShow signal of the margins context | 6046 Private slot handling the aboutToShow signal of the margins context |
5904 menu. | 6047 menu. |
5905 | 6048 |
5954 self.marginMenuActs["ExpandChildren"].setEnabled(isFoldHeader) | 6097 self.marginMenuActs["ExpandChildren"].setEnabled(isFoldHeader) |
5955 self.marginMenuActs["CollapseChildren"].setEnabled(isFoldHeader) | 6098 self.marginMenuActs["CollapseChildren"].setEnabled(isFoldHeader) |
5956 | 6099 |
5957 if menu is self.indicMarginMenu: | 6100 if menu is self.indicMarginMenu: |
5958 hasSyntaxErrors = bool(self.syntaxerrors) | 6101 hasSyntaxErrors = bool(self.syntaxerrors) |
5959 hasWarnings = bool(self.warnings) | 6102 hasWarnings = bool(self._warnings) |
5960 hasNotCoveredMarkers = bool(self.notcoveredMarkers) | 6103 hasNotCoveredMarkers = bool(self.notcoveredMarkers) |
5961 | 6104 |
5962 self.marginMenuActs["GotoSyntaxError"].setEnabled(hasSyntaxErrors) | 6105 self.marginMenuActs["GotoSyntaxError"].setEnabled(hasSyntaxErrors) |
5963 self.marginMenuActs["ClearSyntaxError"].setEnabled(hasSyntaxErrors) | 6106 self.marginMenuActs["ClearSyntaxError"].setEnabled(hasSyntaxErrors) |
5964 if hasSyntaxErrors and self.markersAtLine(self.line) & ( | 6107 if hasSyntaxErrors and self.markersAtLine(self.line) & ( |
5992 self.__hasChangeMarkers | 6135 self.__hasChangeMarkers |
5993 ) | 6136 ) |
5994 | 6137 |
5995 self.showMenu.emit("Margin", menu, self) | 6138 self.showMenu.emit("Margin", menu, self) |
5996 | 6139 |
6140 @pyqtSlot() | |
5997 def __showContextMenuChecks(self): | 6141 def __showContextMenuChecks(self): |
5998 """ | 6142 """ |
5999 Private slot handling the aboutToShow signal of the checks context | 6143 Private slot handling the aboutToShow signal of the checks context |
6000 menu. | 6144 menu. |
6001 """ | 6145 """ |
6002 self.showMenu.emit("Checks", self.checksMenu, self) | 6146 self.showMenu.emit("Checks", self.checksMenu, self) |
6003 | 6147 |
6148 @pyqtSlot() | |
6004 def __showContextMenuTools(self): | 6149 def __showContextMenuTools(self): |
6005 """ | 6150 """ |
6006 Private slot handling the aboutToShow signal of the tools context | 6151 Private slot handling the aboutToShow signal of the tools context |
6007 menu. | 6152 menu. |
6008 """ | 6153 """ |
6009 self.showMenu.emit("Tools", self.toolsMenu, self) | 6154 self.showMenu.emit("Tools", self.toolsMenu, self) |
6010 | 6155 |
6156 @pyqtSlot() | |
6011 def __showContextMenuFormatting(self): | 6157 def __showContextMenuFormatting(self): |
6012 """ | 6158 """ |
6013 Private slot handling the aboutToShow signal of the code formatting context | 6159 Private slot handling the aboutToShow signal of the code formatting context |
6014 menu. | 6160 menu. |
6015 """ | 6161 """ |
6025 encoding = act.data() | 6171 encoding = act.data() |
6026 self.readFile(self.fileName, encoding=encoding) | 6172 self.readFile(self.fileName, encoding=encoding) |
6027 self.__convertTabs() | 6173 self.__convertTabs() |
6028 self.__checkEncoding() | 6174 self.__checkEncoding() |
6029 | 6175 |
6176 @pyqtSlot() | |
6030 def __contextSave(self): | 6177 def __contextSave(self): |
6031 """ | 6178 """ |
6032 Private slot handling the save context menu entry. | 6179 Private slot handling the save context menu entry. |
6033 """ | 6180 """ |
6034 ok = self.saveFile() | 6181 ok = self.saveFile() |
6035 if ok: | 6182 if ok: |
6036 self.vm.setEditorName(self, self.fileName) | 6183 self.vm.setEditorName(self, self.fileName) |
6037 | 6184 |
6185 @pyqtSlot() | |
6038 def __contextSaveAs(self): | 6186 def __contextSaveAs(self): |
6039 """ | 6187 """ |
6040 Private slot handling the save as context menu entry. | 6188 Private slot handling the save as context menu entry. |
6041 """ | 6189 """ |
6042 ok = self.saveFileAs() | 6190 ok = self.saveFileAs() |
6043 if ok: | 6191 if ok: |
6044 self.vm.setEditorName(self, self.fileName) | 6192 self.vm.setEditorName(self, self.fileName) |
6045 | 6193 |
6194 @pyqtSlot() | |
6046 def __contextSaveCopy(self): | 6195 def __contextSaveCopy(self): |
6047 """ | 6196 """ |
6048 Private slot handling the save copy context menu entry. | 6197 Private slot handling the save copy context menu entry. |
6049 """ | 6198 """ |
6050 self.saveFileCopy() | 6199 self.saveFileCopy() |
6051 | 6200 |
6201 @pyqtSlot() | |
6052 def __contextClose(self): | 6202 def __contextClose(self): |
6053 """ | 6203 """ |
6054 Private slot handling the close context menu entry. | 6204 Private slot handling the close context menu entry. |
6055 """ | 6205 """ |
6056 self.vm.closeEditor(self) | 6206 self.vm.closeEditor(self) |
6057 | 6207 |
6208 @pyqtSlot() | |
6058 def __newView(self): | 6209 def __newView(self): |
6059 """ | 6210 """ |
6060 Private slot to create a new view to an open document. | 6211 Private slot to create a new view to an open document. |
6061 """ | 6212 """ |
6062 self.vm.newEditorView(self.fileName, self, self.filetype) | 6213 self.vm.newEditorView(self.fileName, self, self.filetype) |
6063 | 6214 |
6215 @pyqtSlot() | |
6064 def __newViewNewSplit(self): | 6216 def __newViewNewSplit(self): |
6065 """ | 6217 """ |
6066 Private slot to create a new view to an open document. | 6218 Private slot to create a new view to an open document. |
6067 """ | 6219 """ |
6068 self.vm.addSplit() | 6220 self.vm.addSplit() |
6069 self.vm.newEditorView(self.fileName, self, self.filetype) | 6221 self.vm.newEditorView(self.fileName, self, self.filetype) |
6070 | 6222 |
6223 @pyqtSlot() | |
6071 def __selectAll(self): | 6224 def __selectAll(self): |
6072 """ | 6225 """ |
6073 Private slot handling the select all context menu action. | 6226 Private slot handling the select all context menu action. |
6074 """ | 6227 """ |
6075 self.selectAll(True) | 6228 self.selectAll(True) |
6076 | 6229 |
6230 @pyqtSlot() | |
6077 def __deselectAll(self): | 6231 def __deselectAll(self): |
6078 """ | 6232 """ |
6079 Private slot handling the deselect all context menu action. | 6233 Private slot handling the deselect all context menu action. |
6080 """ | 6234 """ |
6081 self.selectAll(False) | 6235 self.selectAll(False) |
6082 | 6236 |
6237 @pyqtSlot() | |
6083 def joinLines(self): | 6238 def joinLines(self): |
6084 """ | 6239 """ |
6085 Public slot to join the current line with the next one. | 6240 Public slot to join the current line with the next one. |
6086 """ | 6241 """ |
6087 curLine = self.getCursorPosition()[0] | 6242 curLine = self.getCursorPosition()[0] |
6119 self.beginUndoAction() | 6274 self.beginUndoAction() |
6120 self.removeSelectedText() | 6275 self.removeSelectedText() |
6121 self.insertAt(" ", curLine, startIndex) | 6276 self.insertAt(" ", curLine, startIndex) |
6122 self.endUndoAction() | 6277 self.endUndoAction() |
6123 | 6278 |
6279 @pyqtSlot() | |
6124 def shortenEmptyLines(self): | 6280 def shortenEmptyLines(self): |
6125 """ | 6281 """ |
6126 Public slot to compress lines consisting solely of whitespace | 6282 Public slot to compress lines consisting solely of whitespace |
6127 characters. | 6283 characters. |
6128 """ | 6284 """ |
6133 while ok: | 6289 while ok: |
6134 self.replaceTarget("") | 6290 self.replaceTarget("") |
6135 ok = self.findNextTarget() | 6291 ok = self.findNextTarget() |
6136 self.endUndoAction() | 6292 self.endUndoAction() |
6137 | 6293 |
6294 @pyqtSlot() | |
6138 def __autosaveEnable(self): | 6295 def __autosaveEnable(self): |
6139 """ | 6296 """ |
6140 Private slot handling the autosave enable context menu action. | 6297 Private slot handling the autosave enable context menu action. |
6141 """ | 6298 """ |
6142 if self.menuActs["AutosaveEnable"].isChecked(): | 6299 if self.menuActs["AutosaveEnable"].isChecked(): |
6143 self.autosaveManuallyDisabled = False | 6300 self.__autosaveManuallyDisabled = False |
6144 else: | 6301 else: |
6145 self.autosaveManuallyDisabled = True | 6302 self.__autosaveManuallyDisabled = True |
6146 | 6303 |
6147 def shouldAutosave(self): | 6304 def __shouldAutosave(self): |
6148 """ | 6305 """ |
6149 Public slot to check the autosave flags. | 6306 Private method to check the autosave flags. |
6150 | 6307 |
6151 @return flag indicating this editor should be saved (boolean) | 6308 @return flag indicating this editor should be saved (boolean) |
6152 """ | 6309 """ |
6153 return ( | 6310 return ( |
6154 bool(self.fileName) | 6311 bool(self.fileName) |
6155 and not self.autosaveManuallyDisabled | 6312 and not self.__autosaveManuallyDisabled |
6156 and not self.isReadOnly() | 6313 and not self.isReadOnly() |
6157 ) | 6314 and self.isModified() |
6315 ) | |
6316 | |
6317 def __autosave(self): | |
6318 """ | |
6319 Private slot to save the contents of the editor automatically. | |
6320 | |
6321 It is only saved by the autosave timer after an initial save (i.e. it already | |
6322 has a name). | |
6323 """ | |
6324 if self.__shouldAutosave(): | |
6325 self.saveFile() | |
6158 | 6326 |
6159 def checkSyntax(self): | 6327 def checkSyntax(self): |
6160 """ | 6328 """ |
6161 Public method to perform an automatic syntax check of the file. | 6329 Public method to perform an automatic syntax check of the file. |
6162 """ | 6330 """ |
6195 fileType, | 6363 fileType, |
6196 self.fileName or "(Unnamed)", | 6364 self.fileName or "(Unnamed)", |
6197 self.text(), | 6365 self.text(), |
6198 ) | 6366 ) |
6199 | 6367 |
6368 @pyqtSlot(str, str) | |
6200 def __processSyntaxCheckError(self, fn, msg): | 6369 def __processSyntaxCheckError(self, fn, msg): |
6201 """ | 6370 """ |
6202 Private slot to report an error message of a syntax check. | 6371 Private slot to report an error message of a syntax check. |
6203 | 6372 |
6204 @param fn filename of the file | 6373 @param fn filename of the file |
6214 | 6383 |
6215 self.toggleWarning(0, 0, True, msg) | 6384 self.toggleWarning(0, 0, True, msg) |
6216 | 6385 |
6217 self.updateVerticalScrollBar() | 6386 self.updateVerticalScrollBar() |
6218 | 6387 |
6388 @pyqtSlot(str, dict) | |
6219 def __processSyntaxCheckResult(self, fn, problems): | 6389 def __processSyntaxCheckResult(self, fn, problems): |
6220 """ | 6390 """ |
6221 Private slot to report the resulting messages of a syntax check. | 6391 Private slot to report the resulting messages of a syntax check. |
6222 | 6392 |
6223 @param fn filename of the checked file (str) | 6393 @param fn filename of the checked file |
6394 @type str | |
6224 @param problems dictionary with the keys 'error' and 'warnings' which | 6395 @param problems dictionary with the keys 'error' and 'warnings' which |
6225 hold a list containing details about the error/ warnings | 6396 hold a list containing details about the error/ warnings |
6226 (file name, line number, column, codestring (only at syntax | 6397 (file name, line number, column, codestring (only at syntax |
6227 errors), the message) (dict) | 6398 errors), the message) |
6399 @type dict | |
6228 """ | 6400 """ |
6229 # Check if it's the requested file, otherwise ignore signal | 6401 # Check if it's the requested file, otherwise ignore signal |
6230 if fn != self.fileName and (bool(self.fileName) or fn != "(Unnamed)"): | 6402 if fn != self.fileName and (bool(self.fileName) or fn != "(Unnamed)"): |
6231 return | 6403 return |
6232 | 6404 |
6236 error = problems.get("error") | 6408 error = problems.get("error") |
6237 if error: | 6409 if error: |
6238 _fn, lineno, col, code, msg = error | 6410 _fn, lineno, col, code, msg = error |
6239 self.toggleSyntaxError(lineno, col, True, msg) | 6411 self.toggleSyntaxError(lineno, col, True, msg) |
6240 | 6412 |
6241 warnings = problems.get("py_warnings", []) | 6413 for _fn, lineno, col, _code, msg in problems.get("py_warnings", []): |
6242 for _fn, lineno, col, _code, msg in warnings: | |
6243 self.toggleWarning(lineno, col, True, msg, warningType=Editor.WarningPython) | 6414 self.toggleWarning(lineno, col, True, msg, warningType=Editor.WarningPython) |
6244 | 6415 |
6245 warnings = problems.get("warnings", []) | 6416 for _fn, lineno, col, _code, msg in problems.get("warnings", []): |
6246 for _fn, lineno, col, _code, msg in warnings: | |
6247 self.toggleWarning(lineno, col, True, msg, warningType=Editor.WarningCode) | 6417 self.toggleWarning(lineno, col, True, msg, warningType=Editor.WarningCode) |
6248 | 6418 |
6249 self.updateVerticalScrollBar() | 6419 self.updateVerticalScrollBar() |
6250 | 6420 |
6421 @pyqtSlot() | |
6251 def __initOnlineSyntaxCheck(self): | 6422 def __initOnlineSyntaxCheck(self): |
6252 """ | 6423 """ |
6253 Private slot to initialize the online syntax check. | 6424 Private slot to initialize the online syntax check. |
6254 """ | 6425 """ |
6255 self.__onlineSyntaxCheckTimer = QTimer(self) | 6426 self.__onlineSyntaxCheckTimer = QTimer(self) |
6432 | 6603 |
6433 @return flag indicating the presence of coverage markers (boolean) | 6604 @return flag indicating the presence of coverage markers (boolean) |
6434 """ | 6605 """ |
6435 return len(self.notcoveredMarkers) > 0 | 6606 return len(self.notcoveredMarkers) > 0 |
6436 | 6607 |
6608 @pyqtSlot() | |
6437 def nextUncovered(self): | 6609 def nextUncovered(self): |
6438 """ | 6610 """ |
6439 Public slot to handle the 'Next uncovered' context menu action. | 6611 Public slot to handle the 'Next uncovered' context menu action. |
6440 """ | 6612 """ |
6441 line, index = self.getCursorPosition() | 6613 line, index = self.getCursorPosition() |
6449 ucline = self.markerFindNext(0, 1 << self.notcovered) | 6621 ucline = self.markerFindNext(0, 1 << self.notcovered) |
6450 if ucline >= 0: | 6622 if ucline >= 0: |
6451 self.setCursorPosition(ucline, 0) | 6623 self.setCursorPosition(ucline, 0) |
6452 self.ensureLineVisible(ucline) | 6624 self.ensureLineVisible(ucline) |
6453 | 6625 |
6626 @pyqtSlot() | |
6454 def previousUncovered(self): | 6627 def previousUncovered(self): |
6455 """ | 6628 """ |
6456 Public slot to handle the 'Previous uncovered' context menu action. | 6629 Public slot to handle the 'Previous uncovered' context menu action. |
6457 """ | 6630 """ |
6458 line, index = self.getCursorPosition() | 6631 line, index = self.getCursorPosition() |
6534 | 6707 |
6535 ########################################################################### | 6708 ########################################################################### |
6536 ## Syntax error handling methods below | 6709 ## Syntax error handling methods below |
6537 ########################################################################### | 6710 ########################################################################### |
6538 | 6711 |
6539 def toggleSyntaxError(self, line, index, error, msg="", show=False): | 6712 def toggleSyntaxError(self, line, index, setError, msg="", show=False): |
6540 """ | 6713 """ |
6541 Public method to toggle a syntax error indicator. | 6714 Public method to toggle a syntax error indicator. |
6542 | 6715 |
6543 @param line line number of the syntax error (integer) | 6716 @param line line number of the syntax error |
6544 @param index index number of the syntax error (integer) | 6717 @type int |
6545 @param error flag indicating if the error marker should be | 6718 @param index index number of the syntax error |
6546 set or deleted (boolean) | 6719 @type int |
6547 @param msg error message (string) | 6720 @param setError flag indicating if the error marker should be |
6721 set or deleted | |
6722 @type bool | |
6723 @param msg error message | |
6724 @type str | |
6548 @param show flag indicating to set the cursor to the error position | 6725 @param show flag indicating to set the cursor to the error position |
6549 (boolean) | 6726 @type bool |
6550 """ | 6727 """ |
6551 if line == 0: | 6728 if line == 0: |
6552 line = 1 | 6729 line = 1 |
6553 # hack to show a syntax error marker, if line is reported to be 0 | 6730 # hack to show a syntax error marker, if line is reported to be 0 |
6554 if error: | 6731 |
6732 line = min(line, self.lines()) | |
6733 # Limit the line number to the ones we really have to ensure proper display | |
6734 # of the error annotation. | |
6735 | |
6736 if setError: | |
6555 # set a new syntax error marker | 6737 # set a new syntax error marker |
6556 markers = self.markersAtLine(line - 1) | 6738 markers = self.markersAtLine(line - 1) |
6557 index += self.indentation(line - 1) | 6739 index += self.indentation(line - 1) |
6558 if not (markers & (1 << self.syntaxerror)): | 6740 if not (markers & (1 << self.syntaxerror)): |
6559 handle = self.markerAdd(line - 1, self.syntaxerror) | 6741 handle = self.markerAdd(line - 1, self.syntaxerror) |
6560 self.syntaxerrors[handle] = [(msg, index)] | 6742 self.syntaxerrors[handle] = [(msg, index)] |
6561 self.syntaxerrorToggled.emit(self) | 6743 self.syntaxerrorToggled.emit(self) |
6562 else: | 6744 else: |
6563 for handle in list(self.syntaxerrors.keys()): | 6745 for handle in self.syntaxerrors: |
6564 if ( | 6746 if ( |
6565 self.markerLine(handle) == line - 1 | 6747 self.markerLine(handle) == line - 1 |
6566 and (msg, index) not in self.syntaxerrors[handle] | 6748 and (msg, index) not in self.syntaxerrors[handle] |
6567 ): | 6749 ): |
6568 self.syntaxerrors[handle].append((msg, index)) | 6750 self.syntaxerrors[handle].append((msg, index)) |
6576 self.markerDeleteHandle(handle) | 6758 self.markerDeleteHandle(handle) |
6577 self.syntaxerrorToggled.emit(self) | 6759 self.syntaxerrorToggled.emit(self) |
6578 | 6760 |
6579 self.__setAnnotation(line - 1) | 6761 self.__setAnnotation(line - 1) |
6580 self.__markerMap.update() | 6762 self.__markerMap.update() |
6581 | |
6582 def getSyntaxErrors(self): | |
6583 """ | |
6584 Public method to retrieve the syntax error markers. | |
6585 | |
6586 @return sorted list of all lines containing a syntax error | |
6587 (list of integer) | |
6588 """ | |
6589 selist = [] | |
6590 for handle in list(self.syntaxerrors.keys()): | |
6591 selist.append(self.markerLine(handle) + 1) | |
6592 | |
6593 selist.sort() | |
6594 return selist | |
6595 | 6763 |
6596 def getSyntaxErrorLines(self): | 6764 def getSyntaxErrorLines(self): |
6597 """ | 6765 """ |
6598 Public method to get the lines containing a syntax error. | 6766 Public method to get the lines containing a syntax error. |
6599 | 6767 |
6615 | 6783 |
6616 @return flag indicating the presence of syntax errors (boolean) | 6784 @return flag indicating the presence of syntax errors (boolean) |
6617 """ | 6785 """ |
6618 return len(self.syntaxerrors) > 0 | 6786 return len(self.syntaxerrors) > 0 |
6619 | 6787 |
6788 @pyqtSlot() | |
6620 def gotoSyntaxError(self): | 6789 def gotoSyntaxError(self): |
6621 """ | 6790 """ |
6622 Public slot to handle the 'Goto syntax error' context menu action. | 6791 Public slot to handle the 'Goto syntax error' context menu action. |
6623 """ | 6792 """ |
6624 seline = self.markerFindNext(0, 1 << self.syntaxerror) | 6793 seline = self.markerFindNext(0, 1 << self.syntaxerror) |
6628 if self.markerLine(handle) == seline: | 6797 if self.markerLine(handle) == seline: |
6629 index = self.syntaxerrors[handle][0][1] | 6798 index = self.syntaxerrors[handle][0][1] |
6630 self.setCursorPosition(seline, index) | 6799 self.setCursorPosition(seline, index) |
6631 self.ensureLineVisible(seline) | 6800 self.ensureLineVisible(seline) |
6632 | 6801 |
6802 @pyqtSlot() | |
6633 def clearSyntaxError(self): | 6803 def clearSyntaxError(self): |
6634 """ | 6804 """ |
6635 Public slot to handle the 'Clear all syntax error' context menu action. | 6805 Public slot to handle the 'Clear all syntax error' context menu action. |
6636 """ | 6806 """ |
6637 for handle in list(self.syntaxerrors.keys()): | 6807 for handle in list(self.syntaxerrors.keys()): |
6639 self.toggleSyntaxError(line, 0, False) | 6809 self.toggleSyntaxError(line, 0, False) |
6640 | 6810 |
6641 self.syntaxerrors.clear() | 6811 self.syntaxerrors.clear() |
6642 self.syntaxerrorToggled.emit(self) | 6812 self.syntaxerrorToggled.emit(self) |
6643 | 6813 |
6814 @pyqtSlot() | |
6644 def __showSyntaxError(self, line=-1): | 6815 def __showSyntaxError(self, line=-1): |
6645 """ | 6816 """ |
6646 Private slot to handle the 'Show syntax error message' | 6817 Private slot to handle the 'Show syntax error message' |
6647 context menu action. | 6818 context menu action. |
6648 | 6819 |
6649 @param line line number to show the syntax error for (integer) | 6820 @param line line number to show the syntax error for |
6821 @type int | |
6650 """ | 6822 """ |
6651 if line == -1: | 6823 if line == -1: |
6652 line = self.line | 6824 line = self.line |
6653 | 6825 |
6654 for handle in list(self.syntaxerrors.keys()): | 6826 for handle in self.syntaxerrors: |
6655 if self.markerLine(handle) == line: | 6827 if self.markerLine(handle) == line: |
6656 errors = [e[0] for e in self.syntaxerrors[handle]] | 6828 errors = [e[0] for e in self.syntaxerrors[handle]] |
6657 EricMessageBox.critical( | 6829 EricMessageBox.critical( |
6658 self, self.tr("Syntax Error"), "\n".join(errors) | 6830 self, self.tr("Syntax Error"), "\n".join(errors) |
6659 ) | 6831 ) |
6691 ########################################################################### | 6863 ########################################################################### |
6692 ## Warning handling methods below | 6864 ## Warning handling methods below |
6693 ########################################################################### | 6865 ########################################################################### |
6694 | 6866 |
6695 def toggleWarning( | 6867 def toggleWarning( |
6696 self, line, col, warning, msg="", warningType=WarningCode # noqa: U100 | 6868 self, line, col, setWarning, msg="", warningType=WarningCode # noqa: U100 |
6697 ): | 6869 ): |
6698 """ | 6870 """ |
6699 Public method to toggle a warning indicator. | 6871 Public method to toggle a warning indicator. |
6700 | 6872 |
6701 Note: This method is used to set pyflakes and code style warnings. | 6873 Note: This method is used to set pyflakes and code style warnings. |
6702 | 6874 |
6703 @param line line number of the warning | 6875 @param line line number of the warning |
6876 @type int | |
6704 @param col column of the warning | 6877 @param col column of the warning |
6705 @param warning flag indicating if the warning marker should be | 6878 @type int |
6706 set or deleted (boolean) | 6879 @param setWarning flag indicating if the warning marker should be |
6707 @param msg warning message (string) | 6880 set or deleted |
6708 @param warningType type of warning message (integer) | 6881 @type bool |
6882 @param msg warning message | |
6883 @type str | |
6884 @param warningType type of warning message | |
6885 @type int | |
6709 """ | 6886 """ |
6710 if line == 0: | 6887 if line == 0: |
6711 line = 1 | 6888 line = 1 |
6712 # hack to show a warning marker, if line is reported to be 0 | 6889 # hack to show a warning marker, if line is reported to be 0 |
6713 if warning: | 6890 |
6891 line = min(line, self.lines()) | |
6892 # Limit the line number to the ones we really have to ensure proper display | |
6893 # of the warning annotation. | |
6894 | |
6895 if setWarning: | |
6714 # set/amend a new warning marker | 6896 # set/amend a new warning marker |
6715 warn = (msg, warningType) | 6897 warn = (msg, warningType) |
6716 markers = self.markersAtLine(line - 1) | 6898 markers = self.markersAtLine(line - 1) |
6717 if not (markers & (1 << self.warning)): | 6899 if not (markers & (1 << self.warning)): |
6718 handle = self.markerAdd(line - 1, self.warning) | 6900 handle = self.markerAdd(line - 1, self.warning) |
6719 self.warnings[handle] = [warn] | 6901 self._warnings[handle] = [warn] |
6720 self.syntaxerrorToggled.emit(self) | 6902 self.syntaxerrorToggled.emit(self) |
6903 # signal is also used for warnings | |
6721 else: | 6904 else: |
6722 for handle in list(self.warnings.keys()): | 6905 for handle in self._warnings: |
6723 if ( | 6906 if ( |
6724 self.markerLine(handle) == line - 1 | 6907 self.markerLine(handle) == line - 1 |
6725 and warn not in self.warnings[handle] | 6908 and warn not in self._warnings[handle] |
6726 ): | 6909 ): |
6727 self.warnings[handle].append(warn) | 6910 self._warnings[handle].append(warn) |
6728 else: | 6911 else: |
6729 for handle in list(self.warnings.keys()): | 6912 for handle in list(self._warnings.keys()): |
6730 if self.markerLine(handle) == line - 1: | 6913 if self.markerLine(handle) == line - 1: |
6731 del self.warnings[handle] | 6914 del self._warnings[handle] |
6732 self.markerDeleteHandle(handle) | 6915 self.markerDeleteHandle(handle) |
6733 self.syntaxerrorToggled.emit(self) | 6916 self.syntaxerrorToggled.emit(self) |
6917 # signal is also used for warnings | |
6734 | 6918 |
6735 self.__setAnnotation(line - 1) | 6919 self.__setAnnotation(line - 1) |
6736 self.__markerMap.update() | 6920 self.__markerMap.update() |
6737 | |
6738 def getWarnings(self): | |
6739 """ | |
6740 Public method to retrieve the warning markers. | |
6741 | |
6742 @return sorted list of all lines containing a warning | |
6743 (list of integer) | |
6744 """ | |
6745 fwlist = [] | |
6746 for handle in list(self.warnings.keys()): | |
6747 fwlist.append(self.markerLine(handle) + 1) | |
6748 | |
6749 fwlist.sort() | |
6750 return fwlist | |
6751 | 6921 |
6752 def getWarningLines(self): | 6922 def getWarningLines(self): |
6753 """ | 6923 """ |
6754 Public method to get the lines containing a warning. | 6924 Public method to get the lines containing a warning. |
6755 | 6925 |
6769 """ | 6939 """ |
6770 Public method to check for the presence of warnings. | 6940 Public method to check for the presence of warnings. |
6771 | 6941 |
6772 @return flag indicating the presence of warnings (boolean) | 6942 @return flag indicating the presence of warnings (boolean) |
6773 """ | 6943 """ |
6774 return len(self.warnings) > 0 | 6944 return len(self._warnings) > 0 |
6775 | 6945 |
6946 @pyqtSlot() | |
6776 def nextWarning(self): | 6947 def nextWarning(self): |
6777 """ | 6948 """ |
6778 Public slot to handle the 'Next warning' context menu action. | 6949 Public slot to handle the 'Next warning' context menu action. |
6779 """ | 6950 """ |
6780 line, index = self.getCursorPosition() | 6951 line, index = self.getCursorPosition() |
6788 fwline = self.markerFindNext(0, 1 << self.warning) | 6959 fwline = self.markerFindNext(0, 1 << self.warning) |
6789 if fwline >= 0: | 6960 if fwline >= 0: |
6790 self.setCursorPosition(fwline, 0) | 6961 self.setCursorPosition(fwline, 0) |
6791 self.ensureLineVisible(fwline) | 6962 self.ensureLineVisible(fwline) |
6792 | 6963 |
6964 @pyqtSlot() | |
6793 def previousWarning(self): | 6965 def previousWarning(self): |
6794 """ | 6966 """ |
6795 Public slot to handle the 'Previous warning' context menu action. | 6967 Public slot to handle the 'Previous warning' context menu action. |
6796 """ | 6968 """ |
6797 line, index = self.getCursorPosition() | 6969 line, index = self.getCursorPosition() |
6805 fwline = self.markerFindPrevious(self.lines() - 1, 1 << self.warning) | 6977 fwline = self.markerFindPrevious(self.lines() - 1, 1 << self.warning) |
6806 if fwline >= 0: | 6978 if fwline >= 0: |
6807 self.setCursorPosition(fwline, 0) | 6979 self.setCursorPosition(fwline, 0) |
6808 self.ensureLineVisible(fwline) | 6980 self.ensureLineVisible(fwline) |
6809 | 6981 |
6982 @pyqtSlot() | |
6810 def clearFlakesWarnings(self): | 6983 def clearFlakesWarnings(self): |
6811 """ | 6984 """ |
6812 Public slot to clear all pyflakes warnings. | 6985 Public slot to clear all pyflakes warnings. |
6813 """ | 6986 """ |
6814 self.__clearTypedWarning(Editor.WarningCode) | 6987 self.__clearTypedWarning(Editor.WarningCode) |
6815 self.__clearTypedWarning(Editor.WarningPython) | 6988 self.__clearTypedWarning(Editor.WarningPython) |
6816 | 6989 |
6990 @pyqtSlot() | |
6817 def clearStyleWarnings(self): | 6991 def clearStyleWarnings(self): |
6818 """ | 6992 """ |
6819 Public slot to clear all style warnings. | 6993 Public slot to clear all style warnings. |
6820 """ | 6994 """ |
6821 self.__clearTypedWarning(Editor.WarningStyle) | 6995 self.__clearTypedWarning(Editor.WarningStyle) |
6996 | |
6997 @pyqtSlot() | |
6998 def clearInfoWarnings(self): | |
6999 """ | |
7000 Public slot to clear all info warnings. | |
7001 """ | |
7002 self.__clearTypedWarning(Editor.WarningInfo) | |
7003 | |
7004 @pyqtSlot() | |
7005 def clearErrorWarnings(self): | |
7006 """ | |
7007 Public slot to clear all error warnings. | |
7008 """ | |
7009 self.__clearTypedWarning(Editor.WarningError) | |
7010 | |
7011 @pyqtSlot() | |
7012 def clearCodeWarnings(self): | |
7013 """ | |
7014 Public slot to clear all code warnings. | |
7015 """ | |
7016 self.__clearTypedWarning(Editor.WarningCode) | |
6822 | 7017 |
6823 def __clearTypedWarning(self, warningKind): | 7018 def __clearTypedWarning(self, warningKind): |
6824 """ | 7019 """ |
6825 Private method to clear warnings of a specific kind. | 7020 Private method to clear warnings of a specific kind. |
6826 | 7021 |
6827 @param warningKind kind of warning to clear (Editor.WarningCode, | 7022 @param warningKind kind of warning to clear (Editor.WarningCode, |
6828 Editor.WarningPython, Editor.WarningStyle) | 7023 Editor.WarningPython, Editor.WarningStyle) |
6829 """ | 7024 """ |
6830 for handle in list(self.warnings.keys()): | 7025 for handle in list(self._warnings.keys()): |
6831 warnings = [] | 7026 issues = [] |
6832 for msg, warningType in self.warnings[handle]: | 7027 for msg, warningType in self._warnings[handle]: |
6833 if warningType == warningKind: | 7028 if warningType == warningKind: |
6834 continue | 7029 continue |
6835 | 7030 |
6836 warnings.append((msg, warningType)) | 7031 issues.append((msg, warningType)) |
6837 | 7032 |
6838 if warnings: | 7033 if issues: |
6839 self.warnings[handle] = warnings | 7034 self._warnings[handle] = issues |
6840 self.__setAnnotation(self.markerLine(handle)) | 7035 self.__setAnnotation(self.markerLine(handle)) |
6841 else: | 7036 else: |
6842 del self.warnings[handle] | 7037 del self._warnings[handle] |
6843 self.__setAnnotation(self.markerLine(handle)) | 7038 self.__setAnnotation(self.markerLine(handle)) |
6844 self.markerDeleteHandle(handle) | 7039 self.markerDeleteHandle(handle) |
6845 self.syntaxerrorToggled.emit(self) | 7040 self.syntaxerrorToggled.emit(self) |
6846 self.__markerMap.update() | 7041 self.__markerMap.update() |
6847 | 7042 |
7043 @pyqtSlot() | |
6848 def clearWarnings(self): | 7044 def clearWarnings(self): |
6849 """ | 7045 """ |
6850 Public slot to clear all warnings. | 7046 Public slot to clear all warnings. |
6851 """ | 7047 """ |
6852 for handle in self.warnings: | 7048 for handle in self._warnings: |
6853 self.warnings[handle] = [] | 7049 self._warnings[handle] = [] |
6854 self.__setAnnotation(self.markerLine(handle)) | 7050 self.__setAnnotation(self.markerLine(handle)) |
6855 self.markerDeleteHandle(handle) | 7051 self.markerDeleteHandle(handle) |
6856 self.warnings.clear() | 7052 self._warnings.clear() |
6857 self.syntaxerrorToggled.emit(self) | 7053 self.syntaxerrorToggled.emit(self) |
6858 self.__markerMap.update() | 7054 self.__markerMap.update() |
6859 | 7055 |
7056 @pyqtSlot() | |
6860 def __showWarning(self, line=-1): | 7057 def __showWarning(self, line=-1): |
6861 """ | 7058 """ |
6862 Private slot to handle the 'Show warning' context menu action. | 7059 Private slot to handle the 'Show warning' context menu action. |
6863 | 7060 |
6864 @param line line number to show the warning for (integer) | 7061 @param line line number to show the warning for |
7062 @type int | |
6865 """ | 7063 """ |
6866 if line == -1: | 7064 if line == -1: |
6867 line = self.line | 7065 line = self.line |
6868 | 7066 |
6869 for handle in list(self.warnings.keys()): | 7067 for handle in self._warnings: |
6870 if self.markerLine(handle) == line: | 7068 if self.markerLine(handle) == line: |
6871 EricMessageBox.warning( | 7069 EricMessageBox.warning( |
6872 self, | 7070 self, |
6873 self.tr("Warning"), | 7071 self.tr("Warning"), |
6874 "\n".join([w[0] for w in self.warnings[handle]]), | 7072 "\n".join([w[0] for w in self._warnings[handle]]), |
6875 ) | 7073 ) |
6876 break | 7074 break |
6877 else: | 7075 else: |
6878 EricMessageBox.warning( | 7076 EricMessageBox.warning( |
6879 self, self.tr("Warning"), self.tr("No warning messages available.") | 7077 self, self.tr("Warning"), self.tr("No warning messages available.") |
6881 | 7079 |
6882 ########################################################################### | 7080 ########################################################################### |
6883 ## Annotation handling methods below | 7081 ## Annotation handling methods below |
6884 ########################################################################### | 7082 ########################################################################### |
6885 | 7083 |
7084 @pyqtSlot() | |
6886 def __setAnnotationStyles(self): | 7085 def __setAnnotationStyles(self): |
6887 """ | 7086 """ |
6888 Private slot to define the style used by inline annotations. | 7087 Private slot to define the style used by inline annotations. |
6889 """ | 7088 """ |
6890 if hasattr(QsciScintilla, "annotate"): | 7089 if hasattr(QsciScintilla, "annotate"): |
6922 QsciScintilla.SCI_STYLESETBACK, | 7121 QsciScintilla.SCI_STYLESETBACK, |
6923 self.annotationStyleStyle, | 7122 self.annotationStyleStyle, |
6924 Preferences.getEditorColour("AnnotationsStyleBackground"), | 7123 Preferences.getEditorColour("AnnotationsStyleBackground"), |
6925 ) | 7124 ) |
6926 | 7125 |
7126 self.annotationInfoStyle = self.annotationStyleStyle + 1 | |
7127 self.SendScintilla( | |
7128 QsciScintilla.SCI_STYLESETFORE, | |
7129 self.annotationInfoStyle, | |
7130 Preferences.getEditorColour("AnnotationsInfoForeground"), | |
7131 ) | |
7132 self.SendScintilla( | |
7133 QsciScintilla.SCI_STYLESETBACK, | |
7134 self.annotationInfoStyle, | |
7135 Preferences.getEditorColour("AnnotationsInfoBackground"), | |
7136 ) | |
7137 | |
6927 def __setAnnotation(self, line): | 7138 def __setAnnotation(self, line): |
6928 """ | 7139 """ |
6929 Private method to set the annotations for the given line. | 7140 Private method to set the annotations for the given line. |
6930 | 7141 |
6931 @param line number of the line that needs annotation (integer) | 7142 @param line number of the line that needs annotation (integer) |
6932 """ | 7143 """ |
6933 if hasattr(QsciScintilla, "annotate"): | 7144 if hasattr(QsciScintilla, "annotate"): |
6934 warningAnnotations = [] | 7145 warningAnnotations = [] |
6935 errorAnnotations = [] | 7146 errorAnnotations = [] |
6936 styleAnnotations = [] | 7147 styleAnnotations = [] |
7148 infoAnnotations = [] | |
6937 | 7149 |
6938 # step 1: do warnings | 7150 # step 1: do warnings |
6939 for handle in self.warnings: | 7151 for handle in self._warnings: |
6940 if self.markerLine(handle) == line: | 7152 if self.markerLine(handle) == line: |
6941 for msg, warningType in self.warnings[handle]: | 7153 for msg, warningType in self._warnings[handle]: |
6942 if warningType == Editor.WarningStyle: | 7154 if warningType == Editor.WarningInfo: |
7155 infoAnnotations.append(self.tr("Info: {0}").format(msg)) | |
7156 elif warningType == Editor.WarningError: | |
7157 errorAnnotations.append(self.tr("Error: {0}").format(msg)) | |
7158 elif warningType == Editor.WarningStyle: | |
6943 styleAnnotations.append(self.tr("Style: {0}").format(msg)) | 7159 styleAnnotations.append(self.tr("Style: {0}").format(msg)) |
6944 elif warningType == Editor.WarningPython: | 7160 elif warningType == Editor.WarningPython: |
6945 warningAnnotations.append(msg) | 7161 warningAnnotations.append(msg) |
6946 else: | 7162 else: |
6947 warningAnnotations.append( | 7163 warningAnnotations.append( |
6952 for handle in self.syntaxerrors: | 7168 for handle in self.syntaxerrors: |
6953 if self.markerLine(handle) == line: | 7169 if self.markerLine(handle) == line: |
6954 for msg, _ in self.syntaxerrors[handle]: | 7170 for msg, _ in self.syntaxerrors[handle]: |
6955 errorAnnotations.append(self.tr("Error: {0}").format(msg)) | 7171 errorAnnotations.append(self.tr("Error: {0}").format(msg)) |
6956 | 7172 |
7173 # step 3: assemble the annotation | |
6957 annotations = [] | 7174 annotations = [] |
7175 if infoAnnotations: | |
7176 annotationInfoTxt = "\n".join(infoAnnotations) | |
7177 if styleAnnotations or warningAnnotations or errorAnnotations: | |
7178 annotationInfoTxt += "\n" | |
7179 annotations.append( | |
7180 QsciStyledText(annotationInfoTxt, self.annotationInfoStyle) | |
7181 ) | |
7182 | |
6958 if styleAnnotations: | 7183 if styleAnnotations: |
6959 annotationStyleTxt = "\n".join(styleAnnotations) | 7184 annotationStyleTxt = "\n".join(styleAnnotations) |
6960 if warningAnnotations or errorAnnotations: | 7185 if warningAnnotations or errorAnnotations: |
6961 annotationStyleTxt += "\n" | 7186 annotationStyleTxt += "\n" |
6962 annotations.append( | 7187 annotations.append( |
6986 """ | 7211 """ |
6987 Private method to refresh the annotations. | 7212 Private method to refresh the annotations. |
6988 """ | 7213 """ |
6989 if hasattr(QsciScintilla, "annotate"): | 7214 if hasattr(QsciScintilla, "annotate"): |
6990 self.clearAnnotations() | 7215 self.clearAnnotations() |
6991 for handle in list(self.warnings.keys()) + list(self.syntaxerrors.keys()): | 7216 for handle in self._warnings: |
7217 line = self.markerLine(handle) | |
7218 self.__setAnnotation(line) | |
7219 for handle in self.syntaxerrors: | |
6992 line = self.markerLine(handle) | 7220 line = self.markerLine(handle) |
6993 self.__setAnnotation(line) | 7221 self.__setAnnotation(line) |
6994 | 7222 |
6995 ################################################################# | 7223 ################################################################# |
6996 ## Fold handling methods | 7224 ## Fold handling methods |
6997 ################################################################# | 7225 ################################################################# |
6998 | 7226 |
7227 @pyqtSlot() | |
6999 def toggleCurrentFold(self): | 7228 def toggleCurrentFold(self): |
7000 """ | 7229 """ |
7001 Public slot to toggle the fold containing the current line. | 7230 Public slot to toggle the fold containing the current line. |
7002 """ | 7231 """ |
7003 line, index = self.getCursorPosition() | 7232 line, index = self.getCursorPosition() |
7004 self.foldLine(line) | 7233 self.foldLine(line) |
7005 | 7234 |
7006 def expandFoldWithChildren(self, line=-1): | 7235 def expandFoldWithChildren(self, line=-1): |
7007 """ | 7236 """ |
7008 Public slot to expand the current fold including its children. | 7237 Public method to expand the current fold including its children. |
7009 | 7238 |
7010 @param line number of line to be expanded | 7239 @param line number of line to be expanded |
7011 @type int | 7240 @type int |
7012 """ | 7241 """ |
7013 if line == -1: | 7242 if line == -1: |
7017 QsciScintilla.SCI_FOLDCHILDREN, line, QsciScintilla.SC_FOLDACTION_EXPAND | 7246 QsciScintilla.SCI_FOLDCHILDREN, line, QsciScintilla.SC_FOLDACTION_EXPAND |
7018 ) | 7247 ) |
7019 | 7248 |
7020 def collapseFoldWithChildren(self, line=-1): | 7249 def collapseFoldWithChildren(self, line=-1): |
7021 """ | 7250 """ |
7022 Public slot to collapse the current fold including its children. | 7251 Public method to collapse the current fold including its children. |
7023 | 7252 |
7024 @param line number of line to be expanded | 7253 @param line number of line to be expanded |
7025 @type int | 7254 @type int |
7026 """ | 7255 """ |
7027 if line == -1: | 7256 if line == -1: |
7029 | 7258 |
7030 self.SendScintilla( | 7259 self.SendScintilla( |
7031 QsciScintilla.SCI_FOLDCHILDREN, line, QsciScintilla.SC_FOLDACTION_CONTRACT | 7260 QsciScintilla.SCI_FOLDCHILDREN, line, QsciScintilla.SC_FOLDACTION_CONTRACT |
7032 ) | 7261 ) |
7033 | 7262 |
7263 @pyqtSlot() | |
7034 def __contextMenuExpandFoldWithChildren(self): | 7264 def __contextMenuExpandFoldWithChildren(self): |
7035 """ | 7265 """ |
7036 Private slot to handle the context menu expand with children action. | 7266 Private slot to handle the context menu expand with children action. |
7037 """ | 7267 """ |
7038 self.expandFoldWithChildren(self.line) | 7268 self.expandFoldWithChildren(self.line) |
7039 | 7269 |
7270 @pyqtSlot() | |
7040 def __contextMenuCollapseFoldWithChildren(self): | 7271 def __contextMenuCollapseFoldWithChildren(self): |
7041 """ | 7272 """ |
7042 Private slot to handle the context menu collapse with children action. | 7273 Private slot to handle the context menu collapse with children action. |
7043 """ | 7274 """ |
7044 self.collapseFoldWithChildren(self.line) | 7275 self.collapseFoldWithChildren(self.line) |
7053 | 7284 |
7054 @return Tuple of macro name and a flag, indicating, if the user | 7285 @return Tuple of macro name and a flag, indicating, if the user |
7055 pressed ok or canceled the operation. (string, boolean) | 7286 pressed ok or canceled the operation. (string, boolean) |
7056 """ | 7287 """ |
7057 qs = [] | 7288 qs = [] |
7058 for s in list(self.macros.keys()): | 7289 for s in self.macros: |
7059 qs.append(s) | 7290 qs.append(s) |
7060 qs.sort() | 7291 qs.sort() |
7061 return QInputDialog.getItem( | 7292 return QInputDialog.getItem( |
7062 self, self.tr("Macro Name"), self.tr("Select a macro name:"), qs, 0, False | 7293 self, self.tr("Macro Name"), self.tr("Select a macro name:"), qs, 0, False |
7063 ) | 7294 ) |
7389 Protected method called when the editor loses focus. | 7620 Protected method called when the editor loses focus. |
7390 | 7621 |
7391 @param event the event object | 7622 @param event the event object |
7392 @type QFocusEvent | 7623 @type QFocusEvent |
7393 """ | 7624 """ |
7625 if Preferences.getEditor("AutosaveOnFocusLost") and self.__shouldAutosave(): | |
7626 self.saveFile() | |
7627 | |
7394 self.vm.editorActGrp.setEnabled(False) | 7628 self.vm.editorActGrp.setEnabled(False) |
7395 self.setCaretWidth(0) | 7629 self.setCaretWidth(0) |
7396 | 7630 |
7397 self.cancelCallTips() | 7631 self.cancelCallTips() |
7398 | 7632 |
7583 """ | 7817 """ |
7584 return ( | 7818 return ( |
7585 self.isLocalFile() and not os.access(self.fileName, os.W_OK) | 7819 self.isLocalFile() and not os.access(self.fileName, os.W_OK) |
7586 ) or self.isReadOnly() | 7820 ) or self.isReadOnly() |
7587 | 7821 |
7822 @pyqtSlot() | |
7588 def refresh(self): | 7823 def refresh(self): |
7589 """ | 7824 """ |
7590 Public slot to refresh the editor contents. | 7825 Public slot to refresh the editor contents. |
7591 """ | 7826 """ |
7592 # save cursor position | 7827 # save cursor position |
7601 | 7836 |
7602 # clear flakes warning markers | 7837 # clear flakes warning markers |
7603 self.clearWarnings() | 7838 self.clearWarnings() |
7604 | 7839 |
7605 # clear breakpoint markers | 7840 # clear breakpoint markers |
7606 for handle in list(self.breaks.keys()): | 7841 for handle in self.breaks: |
7607 self.markerDeleteHandle(handle) | 7842 self.markerDeleteHandle(handle) |
7608 self.breaks.clear() | 7843 self.breaks.clear() |
7609 | 7844 |
7610 if not os.path.exists(self.fileName): | 7845 if not os.path.exists(self.fileName): |
7611 # close the file, if it was deleted in the background | 7846 # close the file, if it was deleted in the background |
7757 | 7992 |
7758 menu.aboutToShow.connect(self.__showContextMenuResources) | 7993 menu.aboutToShow.connect(self.__showContextMenuResources) |
7759 | 7994 |
7760 return menu | 7995 return menu |
7761 | 7996 |
7997 @pyqtSlot() | |
7762 def __showContextMenuResources(self): | 7998 def __showContextMenuResources(self): |
7763 """ | 7999 """ |
7764 Private slot handling the aboutToShow signal of the resources context | 8000 Private slot handling the aboutToShow signal of the resources context |
7765 menu. | 8001 menu. |
7766 """ | 8002 """ |
7934 self.applicationDiagram = UMLDialog( | 8170 self.applicationDiagram = UMLDialog( |
7935 UMLDialogType.APPLICATION_DIAGRAM, self.project, self, noModules=not res | 8171 UMLDialogType.APPLICATION_DIAGRAM, self.project, self, noModules=not res |
7936 ) | 8172 ) |
7937 self.applicationDiagram.show() | 8173 self.applicationDiagram.show() |
7938 | 8174 |
8175 @pyqtSlot() | |
7939 def __loadDiagram(self): | 8176 def __loadDiagram(self): |
7940 """ | 8177 """ |
7941 Private slot to load a diagram from file. | 8178 Private slot to load a diagram from file. |
7942 """ | 8179 """ |
7943 from eric7.Graphics.UMLDialog import UMLDialog, UMLDialogType | 8180 from eric7.Graphics.UMLDialog import UMLDialog, UMLDialogType |
7952 | 8189 |
7953 ####################################################################### | 8190 ####################################################################### |
7954 ## Typing aids related methods below | 8191 ## Typing aids related methods below |
7955 ####################################################################### | 8192 ####################################################################### |
7956 | 8193 |
8194 @pyqtSlot() | |
7957 def __toggleTypingAids(self): | 8195 def __toggleTypingAids(self): |
7958 """ | 8196 """ |
7959 Private slot to toggle the typing aids. | 8197 Private slot to toggle the typing aids. |
7960 """ | 8198 """ |
7961 if self.menuActs["TypingAidsEnabled"].isChecked(): | 8199 if self.menuActs["TypingAidsEnabled"].isChecked(): |
8049 | 8287 |
8050 ####################################################################### | 8288 ####################################################################### |
8051 ## Project related methods | 8289 ## Project related methods |
8052 ####################################################################### | 8290 ####################################################################### |
8053 | 8291 |
8292 @pyqtSlot() | |
8054 def __projectPropertiesChanged(self): | 8293 def __projectPropertiesChanged(self): |
8055 """ | 8294 """ |
8056 Private slot to handle changes of the project properties. | 8295 Private slot to handle changes of the project properties. |
8057 """ | 8296 """ |
8058 if self.spell: | 8297 if self.spell: |
8078 self.project.getProjectSpellLanguage(), pwl=pwl, pel=pel | 8317 self.project.getProjectSpellLanguage(), pwl=pwl, pel=pel |
8079 ) | 8318 ) |
8080 | 8319 |
8081 self.project.projectPropertiesChanged.connect(self.__projectPropertiesChanged) | 8320 self.project.projectPropertiesChanged.connect(self.__projectPropertiesChanged) |
8082 | 8321 |
8322 @pyqtSlot() | |
8083 def projectOpened(self): | 8323 def projectOpened(self): |
8084 """ | 8324 """ |
8085 Public slot to handle the opening of a project. | 8325 Public slot to handle the opening of a project. |
8086 """ | 8326 """ |
8087 if self.fileName and self.project.isProjectCategory(self.fileName, "SOURCES"): | 8327 if self.fileName and self.project.isProjectCategory(self.fileName, "SOURCES"): |
8088 self.project.projectPropertiesChanged.connect( | 8328 self.project.projectPropertiesChanged.connect( |
8089 self.__projectPropertiesChanged | 8329 self.__projectPropertiesChanged |
8090 ) | 8330 ) |
8091 self.setSpellingForProject() | 8331 self.setSpellingForProject() |
8092 | 8332 |
8333 @pyqtSlot() | |
8093 def projectClosed(self): | 8334 def projectClosed(self): |
8094 """ | 8335 """ |
8095 Public slot to handle the closing of a project. | 8336 Public slot to handle the closing of a project. |
8096 """ | 8337 """ |
8097 with contextlib.suppress(TypeError): | 8338 with contextlib.suppress(TypeError): |
8115 | 8356 |
8116 return "" | 8357 return "" |
8117 | 8358 |
8118 def __setSpellingLanguage(self, language, pwl="", pel=""): | 8359 def __setSpellingLanguage(self, language, pwl="", pel=""): |
8119 """ | 8360 """ |
8120 Private slot to set the spell checking language. | 8361 Private method to set the spell checking language. |
8121 | 8362 |
8122 @param language spell checking language to be set (string) | 8363 @param language spell checking language to be set (string) |
8123 @param pwl name of the personal/project word list (string) | 8364 @param pwl name of the personal/project word list (string) |
8124 @param pel name of the personal/project exclude list (string) | 8365 @param pel name of the personal/project exclude list (string) |
8125 """ | 8366 """ |
8215 @pyqtSlot(int) | 8456 @pyqtSlot(int) |
8216 def __spellCharAdded(self, charNumber): | 8457 def __spellCharAdded(self, charNumber): |
8217 """ | 8458 """ |
8218 Private slot called to handle the user entering a character. | 8459 Private slot called to handle the user entering a character. |
8219 | 8460 |
8220 @param charNumber value of the character entered (integer) | 8461 @param charNumber value of the character entered |
8462 @type int | |
8221 """ | 8463 """ |
8222 if self.spell: | 8464 if self.spell: |
8223 if not chr(charNumber).isalnum(): | 8465 if not chr(charNumber).isalnum(): |
8224 self.spell.checkWord(self.positionBefore(self.currentPosition()), True) | 8466 self.spell.checkWord(self.positionBefore(self.currentPosition()), True) |
8225 elif self.hasIndicator(self.spellingIndicator, self.currentPosition()): | 8467 elif self.hasIndicator(self.spellingIndicator, self.currentPosition()): |
8226 self.spell.checkWord(self.currentPosition()) | 8468 self.spell.checkWord(self.currentPosition()) |
8227 | 8469 |
8470 @pyqtSlot() | |
8228 def checkSpelling(self): | 8471 def checkSpelling(self): |
8229 """ | 8472 """ |
8230 Public slot to perform an interactive spell check of the document. | 8473 Public slot to perform an interactive spell check of the document. |
8231 """ | 8474 """ |
8232 from .SpellCheckingDialog import SpellCheckingDialog | 8475 from .SpellCheckingDialog import SpellCheckingDialog |
8237 dlg.exec() | 8480 dlg.exec() |
8238 self.setCursorPosition(cline, cindex) | 8481 self.setCursorPosition(cline, cindex) |
8239 if Preferences.getEditor("AutoSpellCheckingEnabled"): | 8482 if Preferences.getEditor("AutoSpellCheckingEnabled"): |
8240 self.spell.checkDocumentIncrementally() | 8483 self.spell.checkDocumentIncrementally() |
8241 | 8484 |
8485 @pyqtSlot() | |
8242 def __checkSpellingSelection(self): | 8486 def __checkSpellingSelection(self): |
8243 """ | 8487 """ |
8244 Private slot to spell check the current selection. | 8488 Private slot to spell check the current selection. |
8245 """ | 8489 """ |
8246 from .SpellCheckingDialog import SpellCheckingDialog | 8490 from .SpellCheckingDialog import SpellCheckingDialog |
8249 startPos = self.positionFromLineIndex(sline, sindex) | 8493 startPos = self.positionFromLineIndex(sline, sindex) |
8250 endPos = self.positionFromLineIndex(eline, eindex) | 8494 endPos = self.positionFromLineIndex(eline, eindex) |
8251 dlg = SpellCheckingDialog(self.spell, startPos, endPos, self) | 8495 dlg = SpellCheckingDialog(self.spell, startPos, endPos, self) |
8252 dlg.exec() | 8496 dlg.exec() |
8253 | 8497 |
8498 @pyqtSlot() | |
8254 def __checkSpellingWord(self): | 8499 def __checkSpellingWord(self): |
8255 """ | 8500 """ |
8256 Private slot to check the word below the spelling context menu. | 8501 Private slot to check the word below the spelling context menu. |
8257 """ | 8502 """ |
8258 from .SpellCheckingDialog import SpellCheckingDialog | 8503 from .SpellCheckingDialog import SpellCheckingDialog |
8262 wordStartPos = self.positionFromLineIndex(line, wordStart) | 8507 wordStartPos = self.positionFromLineIndex(line, wordStart) |
8263 wordEndPos = self.positionFromLineIndex(line, wordEnd) | 8508 wordEndPos = self.positionFromLineIndex(line, wordEnd) |
8264 dlg = SpellCheckingDialog(self.spell, wordStartPos, wordEndPos, self) | 8509 dlg = SpellCheckingDialog(self.spell, wordStartPos, wordEndPos, self) |
8265 dlg.exec() | 8510 dlg.exec() |
8266 | 8511 |
8512 @pyqtSlot() | |
8267 def __showContextMenuSpelling(self): | 8513 def __showContextMenuSpelling(self): |
8268 """ | 8514 """ |
8269 Private slot to set up the spelling menu before it is shown. | 8515 Private slot to set up the spelling menu before it is shown. |
8270 """ | 8516 """ |
8271 self.spellingMenu.clear() | 8517 self.spellingMenu.clear() |
8287 ) | 8533 ) |
8288 self.spellingMenu.addAction(self.tr("Ignore All"), self.__ignoreSpellingAlways) | 8534 self.spellingMenu.addAction(self.tr("Ignore All"), self.__ignoreSpellingAlways) |
8289 | 8535 |
8290 self.showMenu.emit("Spelling", self.spellingMenu, self) | 8536 self.showMenu.emit("Spelling", self.spellingMenu, self) |
8291 | 8537 |
8538 @pyqtSlot(QAction) | |
8292 def __contextMenuSpellingTriggered(self, action): | 8539 def __contextMenuSpellingTriggered(self, action): |
8293 """ | 8540 """ |
8294 Private slot to handle the selection of a suggestion of the spelling | 8541 Private slot to handle the selection of a suggestion of the spelling |
8295 context menu. | 8542 context menu. |
8296 | 8543 |
8297 @param action reference to the action that was selected (QAction) | 8544 @param action reference to the action that was selected |
8545 @type QAction | |
8298 """ | 8546 """ |
8299 if action in self.spellingSuggActs: | 8547 if action in self.spellingSuggActs: |
8300 replacement = action.text() | 8548 replacement = action.text() |
8301 line, index = self.lineIndexFromPosition(self.spellingMenuPos) | 8549 line, index = self.lineIndexFromPosition(self.spellingMenuPos) |
8302 wordStart, wordEnd = self.getWordBoundaries(line, index) | 8550 wordStart, wordEnd = self.getWordBoundaries(line, index) |
8304 self.beginUndoAction() | 8552 self.beginUndoAction() |
8305 self.removeSelectedText() | 8553 self.removeSelectedText() |
8306 self.insert(replacement) | 8554 self.insert(replacement) |
8307 self.endUndoAction() | 8555 self.endUndoAction() |
8308 | 8556 |
8557 @pyqtSlot() | |
8309 def __addToSpellingDictionary(self): | 8558 def __addToSpellingDictionary(self): |
8310 """ | 8559 """ |
8311 Private slot to add the word below the spelling context menu to the | 8560 Private slot to add the word below the spelling context menu to the |
8312 dictionary. | 8561 dictionary. |
8313 """ | 8562 """ |
8318 wordStart, wordEnd = self.getWordBoundaries(line, index) | 8567 wordStart, wordEnd = self.getWordBoundaries(line, index) |
8319 self.clearIndicator(self.spellingIndicator, line, wordStart, line, wordEnd) | 8568 self.clearIndicator(self.spellingIndicator, line, wordStart, line, wordEnd) |
8320 if Preferences.getEditor("AutoSpellCheckingEnabled"): | 8569 if Preferences.getEditor("AutoSpellCheckingEnabled"): |
8321 self.spell.checkDocumentIncrementally() | 8570 self.spell.checkDocumentIncrementally() |
8322 | 8571 |
8572 @pyqtSlot() | |
8323 def __removeFromSpellingDictionary(self): | 8573 def __removeFromSpellingDictionary(self): |
8324 """ | 8574 """ |
8325 Private slot to remove the word below the context menu to the | 8575 Private slot to remove the word below the context menu to the |
8326 dictionary. | 8576 dictionary. |
8327 """ | 8577 """ |
8366 self.__inRemoteSharedEdit, | 8616 self.__inRemoteSharedEdit, |
8367 ) | 8617 ) |
8368 | 8618 |
8369 def shareConnected(self, connected): | 8619 def shareConnected(self, connected): |
8370 """ | 8620 """ |
8371 Public slot to handle a change of the connected state. | 8621 Public method to handle a change of the connected state. |
8372 | 8622 |
8373 @param connected flag indicating the connected state (boolean) | 8623 @param connected flag indicating the connected state (boolean) |
8374 """ | 8624 """ |
8375 if not connected: | 8625 if not connected: |
8376 self.__inRemoteSharedEdit = False | 8626 self.__inRemoteSharedEdit = False |
8380 self.__isSyncing = False | 8630 self.__isSyncing = False |
8381 self.__receivedWhileSyncing = [] | 8631 self.__receivedWhileSyncing = [] |
8382 | 8632 |
8383 def shareEditor(self, share): | 8633 def shareEditor(self, share): |
8384 """ | 8634 """ |
8385 Public slot to set the shared status of the editor. | 8635 Public method to set the shared status of the editor. |
8386 | 8636 |
8387 @param share flag indicating the share status (boolean) | 8637 @param share flag indicating the share status (boolean) |
8388 """ | 8638 """ |
8389 self.__isShared = share | 8639 self.__isShared = share |
8390 if not share: | 8640 if not share: |
8391 self.shareConnected(False) | 8641 self.shareConnected(False) |
8392 | 8642 |
8643 @pyqtSlot() | |
8393 def startSharedEdit(self): | 8644 def startSharedEdit(self): |
8394 """ | 8645 """ |
8395 Public slot to start a shared edit session for the editor. | 8646 Public slot to start a shared edit session for the editor. |
8396 """ | 8647 """ |
8397 self.__inSharedEdit = True | 8648 self.__inSharedEdit = True |
8403 ).toHex(), | 8654 ).toHex(), |
8404 encoding="utf-8", | 8655 encoding="utf-8", |
8405 ) | 8656 ) |
8406 self.__send(Editor.StartEditToken, hashStr) | 8657 self.__send(Editor.StartEditToken, hashStr) |
8407 | 8658 |
8659 @pyqtSlot() | |
8408 def sendSharedEdit(self): | 8660 def sendSharedEdit(self): |
8409 """ | 8661 """ |
8410 Public slot to end a shared edit session for the editor and | 8662 Public slot to end a shared edit session for the editor and |
8411 send the changes. | 8663 send the changes. |
8412 """ | 8664 """ |
8415 self.__inSharedEdit = False | 8667 self.__inSharedEdit = False |
8416 self.__savedText = "" | 8668 self.__savedText = "" |
8417 | 8669 |
8418 def cancelSharedEdit(self, send=True): | 8670 def cancelSharedEdit(self, send=True): |
8419 """ | 8671 """ |
8420 Public slot to cancel a shared edit session for the editor. | 8672 Public method to cancel a shared edit session for the editor. |
8421 | 8673 |
8422 @param send flag indicating to send the CancelEdit command (boolean) | 8674 @param send flag indicating to send the CancelEdit command (boolean) |
8423 """ | 8675 """ |
8424 self.__inSharedEdit = False | 8676 self.__inSharedEdit = False |
8425 self.__savedText = "" | 8677 self.__savedText = "" |
8445 elif token == Editor.CancelEditToken: | 8697 elif token == Editor.CancelEditToken: |
8446 msg = "{0}{1}c".format(token, Editor.Separator) | 8698 msg = "{0}{1}c".format(token, Editor.Separator) |
8447 | 8699 |
8448 self.vm.send(self.fileName, msg) | 8700 self.vm.send(self.fileName, msg) |
8449 | 8701 |
8702 @pyqtSlot(str) | |
8450 def receive(self, command): | 8703 def receive(self, command): |
8451 """ | 8704 """ |
8452 Public slot to handle received editor commands. | 8705 Public slot to handle received editor commands. |
8453 | 8706 |
8454 @param command command string (string) | 8707 @param command command string |
8708 @type str | |
8455 """ | 8709 """ |
8456 if self.__isShared: | 8710 if self.__isShared: |
8457 if self.__isSyncing and not command.startswith( | 8711 if self.__isSyncing and not command.startswith( |
8458 Editor.SyncToken + Editor.Separator | 8712 Editor.SyncToken + Editor.Separator |
8459 ): | 8713 ): |
8477 elif token == Editor.RequestSyncToken: | 8731 elif token == Editor.RequestSyncToken: |
8478 self.__processRequestSyncCommand(argsString) | 8732 self.__processRequestSyncCommand(argsString) |
8479 elif token == Editor.SyncToken: | 8733 elif token == Editor.SyncToken: |
8480 self.__processSyncCommand(argsString) | 8734 self.__processSyncCommand(argsString) |
8481 | 8735 |
8736 @pyqtSlot(str) | |
8482 def __processStartEditCommand(self, argsString): | 8737 def __processStartEditCommand(self, argsString): |
8483 """ | 8738 """ |
8484 Private slot to process a remote StartEdit command. | 8739 Private slot to process a remote StartEdit command. |
8485 | 8740 |
8486 @param argsString string containing the command parameters (string) | 8741 @param argsString string containing the command parameters |
8742 @type str | |
8487 """ | 8743 """ |
8488 if not self.__inSharedEdit and not self.__inRemoteSharedEdit: | 8744 if not self.__inSharedEdit and not self.__inRemoteSharedEdit: |
8489 self.__inRemoteSharedEdit = True | 8745 self.__inRemoteSharedEdit = True |
8490 self.setReadOnly(True) | 8746 self.setReadOnly(True) |
8491 self.__updateReadOnly() | 8747 self.__updateReadOnly() |
8526 commands.append(formatStr.format("r", j1, i2 - i1, j2 - j1)) | 8782 commands.append(formatStr.format("r", j1, i2 - i1, j2 - j1)) |
8527 commands.extend(newL[j1:j2]) | 8783 commands.extend(newL[j1:j2]) |
8528 | 8784 |
8529 return "\n".join(commands) + "\n" | 8785 return "\n".join(commands) + "\n" |
8530 | 8786 |
8787 @pyqtSlot(str) | |
8531 def __processEndEditCommand(self, argsString): | 8788 def __processEndEditCommand(self, argsString): |
8532 """ | 8789 """ |
8533 Private slot to process a remote EndEdit command. | 8790 Private slot to process a remote EndEdit command. |
8534 | 8791 |
8535 @param argsString string containing the command parameters (string) | 8792 @param argsString string containing the command parameters |
8793 @type str | |
8536 """ | 8794 """ |
8537 commands = argsString.splitlines() | 8795 commands = argsString.splitlines() |
8538 sep = self.getLineSeparator() | 8796 sep = self.getLineSeparator() |
8539 cur = self.getCursorPosition() | 8797 cur = self.getCursorPosition() |
8540 | 8798 |
8565 self.__updateReadOnly() | 8823 self.__updateReadOnly() |
8566 self.__inRemoteSharedEdit = False | 8824 self.__inRemoteSharedEdit = False |
8567 | 8825 |
8568 self.setCursorPosition(*cur) | 8826 self.setCursorPosition(*cur) |
8569 | 8827 |
8828 @pyqtSlot(str) | |
8570 def __processRequestSyncCommand(self, argsString): | 8829 def __processRequestSyncCommand(self, argsString): |
8571 """ | 8830 """ |
8572 Private slot to process a remote RequestSync command. | 8831 Private slot to process a remote RequestSync command. |
8573 | 8832 |
8574 @param argsString string containing the command parameters (string) | 8833 @param argsString string containing the command parameters |
8834 @type str | |
8575 """ | 8835 """ |
8576 if self.__inSharedEdit: | 8836 if self.__inSharedEdit: |
8577 hashStr = str( | 8837 hashStr = str( |
8578 QCryptographicHash.hash( | 8838 QCryptographicHash.hash( |
8579 Utilities.encode(self.__savedText, self.encoding)[0], | 8839 Utilities.encode(self.__savedText, self.encoding)[0], |
8583 ) | 8843 ) |
8584 | 8844 |
8585 if hashStr == argsString: | 8845 if hashStr == argsString: |
8586 self.__send(Editor.SyncToken, self.__savedText) | 8846 self.__send(Editor.SyncToken, self.__savedText) |
8587 | 8847 |
8848 @pyqtSlot(str) | |
8588 def __processSyncCommand(self, argsString): | 8849 def __processSyncCommand(self, argsString): |
8589 """ | 8850 """ |
8590 Private slot to process a remote Sync command. | 8851 Private slot to process a remote Sync command. |
8591 | 8852 |
8592 @param argsString string containing the command parameters (string) | 8853 @param argsString string containing the command parameters |
8854 @type str | |
8593 """ | 8855 """ |
8594 if self.__isSyncing: | 8856 if self.__isSyncing: |
8595 cur = self.getCursorPosition() | 8857 cur = self.getCursorPosition() |
8596 | 8858 |
8597 self.setReadOnly(False) | 8859 self.setReadOnly(False) |
8612 | 8874 |
8613 ####################################################################### | 8875 ####################################################################### |
8614 ## Special search related methods | 8876 ## Special search related methods |
8615 ####################################################################### | 8877 ####################################################################### |
8616 | 8878 |
8879 @pyqtSlot() | |
8617 def searchCurrentWordForward(self): | 8880 def searchCurrentWordForward(self): |
8618 """ | 8881 """ |
8619 Public slot to search the current word forward. | 8882 Public slot to search the current word forward. |
8620 """ | 8883 """ |
8621 self.__searchCurrentWord(forward=True) | 8884 self.__searchCurrentWord(forward=True) |
8622 | 8885 |
8886 @pyqtSlot() | |
8623 def searchCurrentWordBackward(self): | 8887 def searchCurrentWordBackward(self): |
8624 """ | 8888 """ |
8625 Public slot to search the current word backward. | 8889 Public slot to search the current word backward. |
8626 """ | 8890 """ |
8627 self.__searchCurrentWord(forward=False) | 8891 self.__searchCurrentWord(forward=False) |
8664 | 8928 |
8665 ####################################################################### | 8929 ####################################################################### |
8666 ## Sort related methods | 8930 ## Sort related methods |
8667 ####################################################################### | 8931 ####################################################################### |
8668 | 8932 |
8933 @pyqtSlot() | |
8669 def sortLines(self): | 8934 def sortLines(self): |
8670 """ | 8935 """ |
8671 Public slot to sort the lines spanned by a rectangular selection. | 8936 Public slot to sort the lines spanned by a rectangular selection. |
8672 """ | 8937 """ |
8673 from .SortOptionsDialog import SortOptionsDialog | 8938 from .SortOptionsDialog import SortOptionsDialog |
8868 a plug-in. | 9133 a plug-in. |
8869 | 9134 |
8870 @param name name of the plug-in | 9135 @param name name of the plug-in |
8871 @type str | 9136 @type str |
8872 """ | 9137 """ |
8873 keys = [] | 9138 for key in list(self.__mouseClickHandlers.keys()): |
8874 for key in self.__mouseClickHandlers: | |
8875 if self.__mouseClickHandlers[key][0] == name: | 9139 if self.__mouseClickHandlers[key][0] == name: |
8876 keys.append(key) | 9140 del self.__mouseClickHandlers[key] |
8877 for key in keys: | |
8878 del self.__mouseClickHandlers[key] | |
8879 | 9141 |
8880 def gotoReferenceHandler(self, referencesList): | 9142 def gotoReferenceHandler(self, referencesList): |
8881 """ | 9143 """ |
8882 Public method to handle a list of references to perform a goto. | 9144 Public method to handle a list of references to perform a goto. |
8883 | 9145 |
8922 | 9184 |
8923 ####################################################################### | 9185 ####################################################################### |
8924 ## Methods implementing a Shell interface | 9186 ## Methods implementing a Shell interface |
8925 ####################################################################### | 9187 ####################################################################### |
8926 | 9188 |
9189 @pyqtSlot() | |
8927 def __executeSelection(self): | 9190 def __executeSelection(self): |
8928 """ | 9191 """ |
8929 Private slot to execute the selected text in the shell window. | 9192 Private slot to execute the selected text in the shell window. |
8930 """ | 9193 """ |
8931 txt = self.selectedText() | 9194 txt = self.selectedText() |
9134 300, lambda: self.__popupDocstringMenu(lineText2Cursor, cursorPosition) | 9397 300, lambda: self.__popupDocstringMenu(lineText2Cursor, cursorPosition) |
9135 ) | 9398 ) |
9136 | 9399 |
9137 def __popupDocstringMenu(self, lastLineText, lastCursorPosition): | 9400 def __popupDocstringMenu(self, lastLineText, lastCursorPosition): |
9138 """ | 9401 """ |
9139 Private slot to pop up a menu asking the user, if a docstring should be | 9402 Private method to pop up a menu asking the user, if a docstring should be |
9140 inserted. | 9403 inserted. |
9141 | 9404 |
9142 @param lastLineText line contents when the delay timer was started | 9405 @param lastLineText line contents when the delay timer was started |
9143 @type str | 9406 @type str |
9144 @param lastCursorPosition position of the cursor when the delay timer | 9407 @param lastCursorPosition position of the cursor when the delay timer |
9145 was started (line and index) | 9408 was started (line and index) |
9146 @type tuple of (int, int) | 9409 @type tuple of (int, int) |
9147 """ | 9410 """ |
9411 from .DocstringGenerator.BaseDocstringGenerator import DocstringMenuForEnterOnly | |
9412 | |
9148 cursorPosition = self.getCursorPosition() | 9413 cursorPosition = self.getCursorPosition() |
9149 if lastCursorPosition != cursorPosition: | 9414 if lastCursorPosition != cursorPosition: |
9150 return | 9415 return |
9151 | 9416 |
9152 if self.text(cursorPosition[0])[: cursorPosition[1]] != lastLineText: | 9417 if self.text(cursorPosition[0])[: cursorPosition[1]] != lastLineText: |
9153 return | 9418 return |
9154 | 9419 |
9155 generator = self.getDocstringGenerator() | 9420 generator = self.getDocstringGenerator() |
9156 if generator.hasFunctionDefinition(cursorPosition): | 9421 if generator.hasFunctionDefinition(cursorPosition): |
9157 from .DocstringGenerator.BaseDocstringGenerator import ( # __IGNORE_WARNING__ | |
9158 DocstringMenuForEnterOnly, | |
9159 ) | |
9160 | |
9161 docstringMenu = DocstringMenuForEnterOnly(self) | 9422 docstringMenu = DocstringMenuForEnterOnly(self) |
9162 act = docstringMenu.addAction( | 9423 act = docstringMenu.addAction( |
9163 EricPixmapCache.getIcon("fileText"), | 9424 EricPixmapCache.getIcon("fileText"), |
9164 self.tr("Generate Docstring"), | 9425 self.tr("Generate Docstring"), |
9165 lambda: generator.insertDocstring(cursorPosition, fromStart=False), | 9426 lambda: generator.insertDocstring(cursorPosition, fromStart=False), |
9197 else: | 9458 else: |
9198 self.__cancelMouseHoverHelp() | 9459 self.__cancelMouseHoverHelp() |
9199 else: | 9460 else: |
9200 self.__cancelMouseHoverHelp() | 9461 self.__cancelMouseHoverHelp() |
9201 | 9462 |
9463 @pyqtSlot() | |
9202 def __cancelMouseHoverHelp(self): | 9464 def __cancelMouseHoverHelp(self): |
9203 """ | 9465 """ |
9204 Private slot cancelling the display of mouse hover help. | 9466 Private slot cancelling the display of mouse hover help. |
9205 """ | 9467 """ |
9206 if self.__showingMouseHoverHelp: | 9468 if self.__showingMouseHoverHelp: |