56 self.__ui = parent |
56 self.__ui = parent |
57 self.__e5project = e5App().getObject("Project") |
57 self.__e5project = e5App().getObject("Project") |
58 self.__projectpath = '' |
58 self.__projectpath = '' |
59 self.__projectLanguage = "" |
59 self.__projectLanguage = "" |
60 self.__projectopen = False |
60 self.__projectopen = False |
|
61 self.__ropeConfig = {} |
61 |
62 |
62 self.__mainMenu = None |
63 self.__mainMenu = None |
63 self.__helpDialog = None |
64 self.__helpDialog = None |
64 self.__progressDialog = None |
65 self.__progressDialog = None |
65 |
66 |
909 """ |
910 """ |
910 Private method to handle a rope error. |
911 Private method to handle a rope error. |
911 |
912 |
912 @param result dictionary containing the error information |
913 @param result dictionary containing the error information |
913 @type dict |
914 @type dict |
914 """ |
915 @return flag indicating, that the error is to be ignored |
|
916 @rtype bool |
|
917 """ |
|
918 if "Error" not in result: |
|
919 return True |
|
920 |
915 if result["Error"] == 'ModuleSyntaxError': |
921 if result["Error"] == 'ModuleSyntaxError': |
916 res = E5MessageBox.warning( |
922 res = E5MessageBox.warning( |
917 self.__ui, result["Title"], |
923 self.__ui, result["Title"], |
918 self.tr("Rope error: {0}").format( |
924 self.tr("Rope error: {0}").format( |
919 result["ErrorString"]), |
925 result["ErrorString"]), |
921 if res == E5MessageBox.Open: |
927 if res == E5MessageBox.Open: |
922 e5App().getObject("ViewManager").openSourceFile( |
928 e5App().getObject("ViewManager").openSourceFile( |
923 os.path.join(self.__e5project.getProjectPath(), |
929 os.path.join(self.__e5project.getProjectPath(), |
924 result["ErrorFile"]), |
930 result["ErrorFile"]), |
925 result["ErrorLine"]) |
931 result["ErrorLine"]) |
|
932 elif result["Error"] == "InterruptedTaskError": |
|
933 return True |
926 else: |
934 else: |
927 E5MessageBox.warning( |
935 E5MessageBox.warning( |
928 self.__ui, result["Title"], |
936 self.__ui, result["Title"], |
929 self.tr("Rope error: {0}").format( |
937 self.tr("Rope error: {0}").format( |
930 result["ErrorString"]) |
938 result["ErrorString"]) |
931 ) |
939 ) |
|
940 |
|
941 return False |
932 |
942 |
933 def __getOffset(self, editor, line, index): |
943 def __getOffset(self, editor, line, index): |
934 r""" |
944 r""" |
935 Private method to get the offset into the text treating CRLF as ONE |
945 Private method to get the offset into the text treating CRLF as ONE |
936 character. |
946 character. |
1916 the client. |
1926 the client. |
1917 |
1927 |
1918 @param result dictionary containing the result data |
1928 @param result dictionary containing the result data |
1919 @type dict |
1929 @type dict |
1920 """ |
1930 """ |
1921 if "Error" in result: |
1931 if self.__handleRopeError(result): |
1922 self.__handleRopeError(result) |
|
1923 else: |
|
1924 title = result["Title"] |
1932 title = result["Title"] |
1925 if result["EntriesCount"] > 0: |
1933 if result["EntriesCount"] > 0: |
1926 from MatchesDialog import MatchesDialog |
1934 from MatchesDialog import MatchesDialog |
1927 self.dlg = MatchesDialog(self.__ui, True) |
1935 self.dlg = MatchesDialog(self.__ui, True) |
1928 self.dlg.show() |
1936 self.dlg.show() |
1929 for occurrence in result["Entries"]: |
1937 for occurrence in result["Entries"]: |
1930 self.dlg.addEntry( |
1938 self.dlg.addEntry( |
1931 # resource, lineno, unsure |
1939 # file name, lineno, unsure |
1932 occurrence[0], occurrence[1], occurrence[2]) |
1940 occurrence[0], occurrence[1], occurrence[2]) |
1933 else: |
1941 else: |
1934 E5MessageBox.warning( |
1942 E5MessageBox.warning( |
1935 self.__ui, title, |
1943 self.__ui, title, |
1936 self.tr("No occurrences found.")) |
1944 self.tr("No occurrences found.")) |
1942 aw = e5App().getObject("ViewManager").activeWindow() |
1950 aw = e5App().getObject("ViewManager").activeWindow() |
1943 |
1951 |
1944 if aw is None: |
1952 if aw is None: |
1945 return |
1953 return |
1946 |
1954 |
1947 title = self.tr("Find &Definition") |
1955 title = self.tr("Find Definition") |
1948 |
1956 |
1949 if not self.confirmAllBuffersSaved(): |
1957 if not self.confirmAllBuffersSaved(): |
1950 return |
1958 return |
1951 |
1959 |
1952 filename = aw.getFileName() |
1960 filename = aw.getFileName() |
1953 line, index = aw.getCursorPosition() |
1961 line, index = aw.getCursorPosition() |
1954 offset = self.__getOffset(aw, line, index) |
1962 offset = self.__getOffset(aw, line, index) |
1955 |
1963 |
1956 import rope.contrib.findit |
1964 self.sendJson("QueryDefinition", { |
1957 resource = rope.base.libutils.path_to_resource( |
1965 "Title": title, |
1958 self.__project, filename) |
1966 "FileName": filename, |
1959 try: |
1967 "Offset": offset, |
1960 location = rope.contrib.findit.find_definition( |
1968 "Source": aw.text(), |
1961 self.__project, aw.text(), offset, resource) |
1969 "Subcommand": "Query", |
1962 except Exception as err: |
1970 }) |
1963 self.handleRopeError(err, title) |
|
1964 return |
|
1965 |
|
1966 if location is not None: |
|
1967 from MatchesDialog import MatchesDialog |
|
1968 self.dlg = MatchesDialog(self.__ui, False) |
|
1969 self.dlg.show() |
|
1970 self.dlg.addEntry(location.resource, location.lineno) |
|
1971 else: |
|
1972 E5MessageBox.warning( |
|
1973 self.__ui, title, |
|
1974 self.tr("No matching definition found.")) |
|
1975 |
1971 |
1976 def gotoDefinition(self, editor): |
1972 def gotoDefinition(self, editor): |
1977 """ |
1973 """ |
1978 Public slot to find the definition for the word at the cursor position |
1974 Public slot to find the definition for the word at the cursor position |
1979 and go to it. |
1975 and go to it. |
1984 """ |
1980 """ |
1985 filename = editor.getFileName() |
1981 filename = editor.getFileName() |
1986 line, index = editor.getCursorPosition() |
1982 line, index = editor.getCursorPosition() |
1987 offset = self.__getOffset(editor, line, index) |
1983 offset = self.__getOffset(editor, line, index) |
1988 |
1984 |
1989 import rope.contrib.findit |
1985 self.sendJson("QueryDefinition", { |
1990 resource = rope.base.libutils.path_to_resource( |
1986 "Title": "", |
1991 self.__project, filename) |
1987 "FileName": filename, |
1992 try: |
1988 "Offset": offset, |
1993 location = rope.contrib.findit.find_definition( |
1989 "Source": editor.text(), |
1994 self.__project, editor.text(), offset, resource) |
1990 "Subcommand": "Goto", |
1995 except Exception: |
1991 }) |
1996 # simply ignore them |
1992 |
1997 return |
1993 def __queryDefinitionResult(self, result): |
1998 |
1994 """ |
1999 if location is not None: |
1995 Private method to handle the "Query Definition" result sent by |
2000 try: |
1996 the client. |
2001 e5App().getObject("ViewManager").openSourceFile( |
1997 |
2002 location.resource.real_path, location.lineno, addNext=True) |
1998 @param result dictionary containing the result data |
2003 except TypeError: |
1999 @type dict |
2004 # backward compatibility; <= 17.03 |
2000 """ |
2005 e5App().getObject("ViewManager").openSourceFile( |
2001 if result["Subcommand"] == "Query": |
2006 location.resource.real_path, location.lineno, next=True) |
2002 if self.__handleRopeError(result): |
2007 else: |
2003 title = result["Title"] |
2008 e5App().getObject("UserInterface").statusBar().showMessage( |
2004 if "Location" in result: |
2009 self.tr('No definition found'), 5000) |
2005 location = result["Location"] |
|
2006 |
|
2007 from MatchesDialog import MatchesDialog |
|
2008 self.dlg = MatchesDialog(self.__ui, False) |
|
2009 self.dlg.show() |
|
2010 self.dlg.addEntry(location[0], location[1]) |
|
2011 # file name, lineno |
|
2012 else: |
|
2013 E5MessageBox.warning( |
|
2014 self.__ui, title, |
|
2015 self.tr("No matching definition found.")) |
|
2016 elif result["Subcommand"] == "Goto": |
|
2017 if "Error" not in result: |
|
2018 # ignore errors silently |
|
2019 if "Location" in result: |
|
2020 location = result["Location"] |
|
2021 try: |
|
2022 e5App().getObject("ViewManager").openSourceFile( |
|
2023 location[0], location[1], addNext=True) |
|
2024 except TypeError: |
|
2025 # backward compatibility; <= 17.03 |
|
2026 e5App().getObject("ViewManager").openSourceFile( |
|
2027 location[0], location[1], next=True) |
|
2028 else: |
|
2029 e5App().getObject("UserInterface").statusBar().showMessage( |
|
2030 self.tr('No definition found'), 5000) |
2010 |
2031 |
2011 def __queryImplementations(self): |
2032 def __queryImplementations(self): |
2012 """ |
2033 """ |
2013 Private slot to handle the Find Implementations action. |
2034 Private slot to handle the Find Implementations action. |
2014 """ |
2035 """ |
2024 |
2045 |
2025 filename = aw.getFileName() |
2046 filename = aw.getFileName() |
2026 line, index = aw.getCursorPosition() |
2047 line, index = aw.getCursorPosition() |
2027 offset = self.__getOffset(aw, line, index) |
2048 offset = self.__getOffset(aw, line, index) |
2028 |
2049 |
2029 import rope.contrib.findit |
2050 self.sendJson("QueryImplementations", { |
2030 from ProgressHandle import ProgressHandle |
2051 "Title": title, |
2031 resource = rope.base.libutils.path_to_resource( |
2052 "FileName": filename, |
2032 self.__project, filename) |
2053 "Offset": offset, |
2033 handle = ProgressHandle(title, True, self.__ui) |
2054 }) |
2034 handle.show() |
2055 |
2035 QApplication.processEvents() |
2056 def __queryImplementationsResult(self, result): |
2036 try: |
2057 """ |
2037 occurrences = rope.contrib.findit.find_implementations( |
2058 Private method to handle the "Query Implementations" result sent by |
2038 self.__project, resource, offset, task_handle=handle) |
2059 the client. |
2039 except Exception as err: |
2060 |
2040 self.handleRopeError(err, title, handle) |
2061 @param result dictionary containing the result data |
2041 return |
2062 @type dict |
2042 handle.reset() |
2063 """ |
2043 |
2064 if self.__handleRopeError(result): |
2044 if occurrences: |
2065 title = result["Title"] |
2045 from MatchesDialog import MatchesDialog |
2066 if result["EntriesCount"] > 0: |
2046 self.dlg = MatchesDialog(self.__ui, True) |
2067 from MatchesDialog import MatchesDialog |
2047 self.dlg.show() |
2068 self.dlg = MatchesDialog(self.__ui, True) |
2048 for occurrence in occurrences: |
2069 self.dlg.show() |
2049 self.dlg.addEntry( |
2070 for occurrence in result["Entries"]: |
2050 occurrence.resource, occurrence.lineno, occurrence.unsure) |
2071 self.dlg.addEntry( |
2051 else: |
2072 # file name, lineno, unsure |
2052 E5MessageBox.warning( |
2073 occurrence[0], occurrence[1], occurrence[2]) |
2053 self.__ui, title, self.tr("No occurrences found.")) |
2074 else: |
|
2075 E5MessageBox.warning( |
|
2076 self.__ui, title, self.tr("No implementations found.")) |
2054 |
2077 |
2055 ##################################################### |
2078 ##################################################### |
2056 ## Various actions |
2079 ## Various actions |
2057 ##################################################### |
2080 ##################################################### |
2058 |
2081 |
2059 def __editConfig(self): |
2082 def __editConfig(self): |
2060 """ |
2083 """ |
2061 Private slot to open the rope configuration file in an editor. |
2084 Private slot to open the rope configuration file in an editor. |
2062 """ |
2085 """ |
2063 ropedir = self.__project.ropefolder |
2086 ropedir = self.__ropeConfig["RopeFolderName"] |
2064 configfile = "" |
2087 configfile = "" |
2065 if ropedir is not None: |
2088 if ropedir and os.path.exists(ropedir): |
2066 configfile = os.path.join(ropedir.real_path, "config.py") |
2089 configfile = os.path.join(ropedir, "config.py") |
2067 if os.path.exists(configfile): |
2090 if os.path.exists(configfile): |
2068 from QScintilla.MiniEditor import MiniEditor |
2091 from QScintilla.MiniEditor import MiniEditor |
2069 self.__editor = MiniEditor(configfile) |
2092 self.__editor = MiniEditor(configfile) |
2070 self.__editor.show() |
2093 self.__editor.show() |
2071 self.__editor.editorSaved.connect(self.__configChanged) |
2094 self.__editor.editorSaved.connect(self.__configChanged) |
2112 """ |
2135 """ |
2113 Private slot to show help about the refactorings offered by Rope. |
2136 Private slot to show help about the refactorings offered by Rope. |
2114 """ |
2137 """ |
2115 if self.__helpDialog is None: |
2138 if self.__helpDialog is None: |
2116 from HelpDialog import HelpDialog |
2139 from HelpDialog import HelpDialog |
2117 if sys.version_info[0] >= 3: |
|
2118 directory = 'rope_py3' |
|
2119 else: |
|
2120 directory = 'rope_py2' |
|
2121 helpfile = os.path.join(os.path.dirname(__file__), |
|
2122 directory, "rope", "docs", "overview.txt") |
|
2123 self.__helpDialog = \ |
2140 self.__helpDialog = \ |
2124 HelpDialog(self.tr("Help about rope refactorings"), |
2141 HelpDialog(self.tr("Help about rope refactorings"), |
2125 helpfile) |
2142 self.__ropeConfig["RopeHelpFile"]) |
2126 self.__helpDialog.show() |
2143 self.__helpDialog.show() |
2127 |
2144 |
2128 def __performSOA(self): |
2145 def __performSOA(self): |
2129 """ |
2146 """ |
2130 Private slot to perform SOA on all modules. |
2147 Private slot to perform SOA on all modules. |
2134 self.__ui, |
2151 self.__ui, |
2135 title, |
2152 title, |
2136 self.tr("""This action might take some time. """ |
2153 self.tr("""This action might take some time. """ |
2137 """Do you really want to perform SOA?""")) |
2154 """Do you really want to perform SOA?""")) |
2138 if res: |
2155 if res: |
2139 from ProgressHandle import ProgressHandle |
2156 |
2140 handle = ProgressHandle(title, True, self.__ui) |
2157 self.sendJson("PerformSoa", { |
2141 handle.show() |
2158 "Title": title, |
2142 QApplication.processEvents() |
2159 }) |
2143 try: |
2160 |
2144 rope.base.libutils.analyze_modules( |
2161 def __soaFinished(self, result): |
2145 self.__project, task_handle=handle) |
2162 """ |
2146 handle.reset() |
2163 Private method to handle the "Soa Finished" result sent by |
2147 E5MessageBox.information( |
2164 the client. |
2148 self.__ui, |
2165 |
2149 title, |
2166 @param result dictionary containing the result data |
2150 self.tr("""Static object analysis (SOA) done. """ |
2167 @type dict |
2151 """SOA database updated.""")) |
2168 """ |
2152 except Exception as err: |
2169 if self.__handleRopeError(result): |
2153 self.handleRopeError(err, title, handle) |
2170 title = result["Title"] |
|
2171 |
|
2172 E5MessageBox.information( |
|
2173 self.__ui, |
|
2174 title, |
|
2175 self.tr("""Static object analysis (SOA) done. """ |
|
2176 """SOA database updated.""")) |
2154 |
2177 |
2155 ################################################################## |
2178 ################################################################## |
2156 ## methods below are private utility methods |
2179 ## methods below are private utility methods |
2157 ################################################################## |
2180 ################################################################## |
2158 |
2181 |
2161 Private method to get the name of the rope configuration file. |
2184 Private method to get the name of the rope configuration file. |
2162 |
2185 |
2163 @return name of the rope configuration file (string) |
2186 @return name of the rope configuration file (string) |
2164 """ |
2187 """ |
2165 configfile = None |
2188 configfile = None |
2166 if self.__project is not None: |
2189 if self.__ropeConfig: |
2167 ropedir = self.__project.ropefolder |
2190 ropedir = self.__ropeConfig["RopeFolderName"] |
2168 if ropedir is not None: |
2191 if ropedir: |
2169 configfile = os.path.join(ropedir.real_path, "config.py") |
2192 configfile = os.path.join(ropedir, "config.py") |
2170 if not os.path.exists(configfile): |
2193 if not os.path.exists(configfile): |
2171 configfile = None |
2194 configfile = None |
2172 return configfile |
2195 return configfile |
2173 |
2196 |
2174 def __configChanged(self): |
2197 def __configChanged(self): |
2175 """ |
2198 """ |
2176 Private slot called, when the rope config file has changed. |
2199 Private slot called, when the rope config file has changed. |
2177 """ |
2200 """ |
2178 import rope.base.project |
2201 self.sendJson("ConfigChanged", {}) |
2179 self.__project.close() |
|
2180 self.__project = rope.base.project.Project( |
|
2181 self.__projectpath, fscommands=self.__fsCommands) |
|
2182 |
2202 |
2183 def __defaultConfig(self): |
2203 def __defaultConfig(self): |
2184 """ |
2204 """ |
2185 Private slot to return the contents of rope's default configuration. |
2205 Private slot to return the contents of rope's default configuration. |
2186 |
2206 |
2187 @return string containing the source of rope's default |
2207 @return string containing the source of rope's default |
2188 configuration (string) |
2208 configuration (string) |
2189 """ |
2209 """ |
2190 if self.__project is not None: |
2210 if self.__ropeConfig and "DefaultConfig" in self.__ropeConfig: |
2191 return self.__project._default_config() |
2211 return self.__ropeConfig["DefaultConfig"] |
2192 else: |
2212 else: |
2193 return "" |
2213 return "" |
2194 |
2214 |
2195 ################################################################## |
2215 ################################################################## |
2196 ## methods below are public utility methods |
2216 ## methods below are public utility methods |
2283 """ |
2304 """ |
2284 res = e5App().getObject("ViewManager").checkAllDirty() |
2305 res = e5App().getObject("ViewManager").checkAllDirty() |
2285 self.sendJson("Validate", {}) |
2306 self.sendJson("Validate", {}) |
2286 return res |
2307 return res |
2287 |
2308 |
|
2309 # TODO: port this |
2288 def refreshEditors(self, changes): |
2310 def refreshEditors(self, changes): |
2289 """ |
2311 """ |
2290 Public method to refresh modified editors. |
2312 Public method to refresh modified editors. |
2291 |
2313 |
2292 @param changes reference to the ChangeSet object |
2314 @param changes reference to the ChangeSet object |
2293 (rope.base.change.ChangeSet) |
2315 (rope.base.change.ChangeSet) |
2294 """ |
2316 """ |
2295 vm = e5App().getObject("ViewManager") |
2317 vm = e5App().getObject("ViewManager") |
2296 |
2318 |
2297 changedFiles = [] |
2319 changedFiles = [] |
2298 for resource in changes.get_changed_resources(): |
2320 # for resource in changes.get_changed_resources(): |
2299 if not resource.is_folder(): |
2321 # if not resource.is_folder(): |
2300 changedFiles.append(resource.real_path) |
2322 # changedFiles.append(resource.real_path) |
2301 |
2323 |
2302 openFiles = [Utilities.normcasepath(f) for f in vm.getOpenFilenames()] |
2324 openFiles = [Utilities.normcasepath(f) for f in vm.getOpenFilenames()] |
2303 |
2325 |
2304 for file in changedFiles: |
2326 for file in changedFiles: |
2305 normfile = Utilities.normcasepath(file) |
2327 normfile = Utilities.normcasepath(file) |
2318 Public slot to report some changed sources. |
2340 Public slot to report some changed sources. |
2319 |
2341 |
2320 @param filename file name of the changed source (string) |
2342 @param filename file name of the changed source (string) |
2321 @param oldSource source code before the change (string) |
2343 @param oldSource source code before the change (string) |
2322 """ |
2344 """ |
2323 if self.__project and self.__e5project.isProjectFile(filename): |
2345 if self.__e5project.isOpen() and \ |
2324 try: |
2346 self.__e5project.isProjectFile(filename): |
2325 rope.base.libutils.report_change( |
2347 self.sendJson("ReportChanged", { |
2326 self.__project, filename, oldSource) |
2348 "FileName": filename, |
2327 except RuntimeError: |
2349 "OldSource": oldSource, |
2328 # this could come from trying to do PyQt4/PyQt5 mixed stuff |
2350 }) |
2329 # simply ignore it |
|
2330 pass |
|
2331 |
2351 |
2332 ####################################################################### |
2352 ####################################################################### |
2333 ## Methods below handle the network connection |
2353 ## Methods below handle the network connection |
2334 ####################################################################### |
2354 ####################################################################### |
2335 |
2355 |
2399 if self.__progressDialog is not None: |
2420 if self.__progressDialog is not None: |
2400 self.__progressDialog.reset() |
2421 self.__progressDialog.reset() |
2401 |
2422 |
2402 elif method == "QueryReferencesResult": |
2423 elif method == "QueryReferencesResult": |
2403 self.__queryReferencesResult(params) |
2424 self.__queryReferencesResult(params) |
|
2425 |
|
2426 elif method == "QueryDefinitionResult": |
|
2427 self.__queryDefinitionResult(params) |
|
2428 |
|
2429 elif method == "QueryImplementationsResult": |
|
2430 self.__queryImplementationsResult(params) |
|
2431 |
|
2432 elif method == "SoaFinished": |
|
2433 self.__soaFinished(params) |
2404 |
2434 |
2405 def __startRefactoringClient(self, interpreter): |
2435 def __startRefactoringClient(self, interpreter): |
2406 """ |
2436 """ |
2407 Private method to start the refactoring client. |
2437 Private method to start the refactoring client. |
2408 |
2438 |