62 logging.basicConfig(level=logging.DEBUG) |
69 logging.basicConfig(level=logging.DEBUG) |
63 |
70 |
64 for arg in sys.argv[:]: |
71 for arg in sys.argv[:]: |
65 if arg.startswith("--config="): |
72 if arg.startswith("--config="): |
66 import Globals |
73 import Globals |
|
74 |
67 configDir = arg.replace("--config=", "") |
75 configDir = arg.replace("--config=", "") |
68 Globals.setConfigDir(configDir) |
76 Globals.setConfigDir(configDir) |
69 sys.argv.remove(arg) |
77 sys.argv.remove(arg) |
70 elif arg.startswith("--settings="): |
78 elif arg.startswith("--settings="): |
71 from PyQt6.QtCore import QSettings |
79 from PyQt6.QtCore import QSettings |
|
80 |
72 settingsDir = os.path.expanduser(arg.replace("--settings=", "")) |
81 settingsDir = os.path.expanduser(arg.replace("--settings=", "")) |
73 if not os.path.isdir(settingsDir): |
82 if not os.path.isdir(settingsDir): |
74 os.makedirs(settingsDir) |
83 os.makedirs(settingsDir) |
75 QSettings.setPath( |
84 QSettings.setPath( |
76 QSettings.Format.IniFormat, QSettings.Scope.UserScope, settingsDir) |
85 QSettings.Format.IniFormat, QSettings.Scope.UserScope, settingsDir |
|
86 ) |
77 sys.argv.remove(arg) |
87 sys.argv.remove(arg) |
78 |
88 |
79 # make Third-Party package available as a packages repository |
89 # make Third-Party package available as a packages repository |
80 sys.path.insert(2, os.path.join(os.path.dirname(__file__), |
90 sys.path.insert(2, os.path.join(os.path.dirname(__file__), "ThirdParty", "Jasy")) |
81 "ThirdParty", "Jasy")) |
91 sys.path.insert(2, os.path.join(os.path.dirname(__file__), "DebugClients", "Python")) |
82 sys.path.insert(2, os.path.join(os.path.dirname(__file__), |
|
83 "DebugClients", "Python")) |
|
84 |
92 |
85 from EricWidgets.EricApplication import EricApplication |
93 from EricWidgets.EricApplication import EricApplication |
86 |
94 |
87 |
95 |
88 def handleSingleApplication(ddindex): |
96 def handleSingleApplication(ddindex): |
89 """ |
97 """ |
90 Global function to handle the single application mode. |
98 Global function to handle the single application mode. |
91 |
99 |
92 @param ddindex index of a '--' option in the options list |
100 @param ddindex index of a '--' option in the options list |
93 """ |
101 """ |
94 from EricWidgets.EricSingleApplication import EricSingleApplicationClient |
102 from EricWidgets.EricSingleApplication import EricSingleApplicationClient |
95 |
103 |
96 client = EricSingleApplicationClient() |
104 client = EricSingleApplicationClient() |
97 res = client.connect() |
105 res = client.connect() |
98 if res > 0: |
106 if res > 0: |
99 if ( |
107 if "--no-splash" in sys.argv and sys.argv.index("--no-splash") < ddindex: |
100 "--no-splash" in sys.argv and |
|
101 sys.argv.index("--no-splash") < ddindex |
|
102 ): |
|
103 sys.argv.remove("--no-splash") |
108 sys.argv.remove("--no-splash") |
104 ddindex -= 1 |
109 ddindex -= 1 |
105 if "--no-open" in sys.argv and sys.argv.index("--no-open") < ddindex: |
110 if "--no-open" in sys.argv and sys.argv.index("--no-open") < ddindex: |
106 sys.argv.remove("--no-open") |
111 sys.argv.remove("--no-open") |
107 ddindex -= 1 |
112 ddindex -= 1 |
108 if "--no-crash" in sys.argv and sys.argv.index("--no-crash") < ddindex: |
113 if "--no-crash" in sys.argv and sys.argv.index("--no-crash") < ddindex: |
109 sys.argv.remove("--no-crash") |
114 sys.argv.remove("--no-crash") |
110 if ( |
115 if ( |
111 "--disable-crash" in sys.argv and |
116 "--disable-crash" in sys.argv |
112 sys.argv.index("--disable-crash") < ddindex |
117 and sys.argv.index("--disable-crash") < ddindex |
113 ): |
118 ): |
114 sys.argv.remove("--disable-crash") |
119 sys.argv.remove("--disable-crash") |
115 ddindex -= 1 |
120 ddindex -= 1 |
116 if "--debug" in sys.argv and sys.argv.index("--debug") < ddindex: |
121 if "--debug" in sys.argv and sys.argv.index("--debug") < ddindex: |
117 sys.argv.remove("--debug") |
122 sys.argv.remove("--debug") |
118 ddindex -= 1 |
123 ddindex -= 1 |
119 for arg in sys.argv: |
124 for arg in sys.argv: |
120 if ( |
125 if arg.startswith("--config=") and sys.argv.index(arg) < ddindex: |
121 arg.startswith("--config=") and |
|
122 sys.argv.index(arg) < ddindex |
|
123 ): |
|
124 sys.argv.remove(arg) |
126 sys.argv.remove(arg) |
125 ddindex -= 1 |
127 ddindex -= 1 |
126 break |
128 break |
127 for arg in sys.argv: |
129 for arg in sys.argv: |
128 if ( |
130 if arg.startswith("--plugin=") and sys.argv.index(arg) < ddindex: |
129 arg.startswith("--plugin=") and |
|
130 sys.argv.index(arg) < ddindex |
|
131 ): |
|
132 sys.argv.remove(arg) |
131 sys.argv.remove(arg) |
133 ddindex -= 1 |
132 ddindex -= 1 |
134 break |
133 break |
135 for arg in sys.argv[:]: |
134 for arg in sys.argv[:]: |
136 if ( |
135 if arg.startswith("--disable-plugin=") and sys.argv.index(arg) < ddindex: |
137 arg.startswith("--disable-plugin=") and |
|
138 sys.argv.index(arg) < ddindex |
|
139 ): |
|
140 sys.argv.remove(arg) |
136 sys.argv.remove(arg) |
141 ddindex -= 1 |
137 ddindex -= 1 |
142 |
138 |
143 if len(sys.argv) > 1: |
139 if len(sys.argv) > 1: |
144 client.processArgs(sys.argv[1:]) |
140 client.processArgs(sys.argv[1:]) |
145 sys.exit(0) |
141 sys.exit(0) |
146 elif res < 0: |
142 elif res < 0: |
147 print("eric7: {0}".format(client.errstr())) |
143 print("eric7: {0}".format(client.errstr())) |
150 |
146 |
151 |
147 |
152 def excepthook(excType, excValue, tracebackobj): |
148 def excepthook(excType, excValue, tracebackobj): |
153 """ |
149 """ |
154 Global function to catch unhandled exceptions. |
150 Global function to catch unhandled exceptions. |
155 |
151 |
156 @param excType exception type |
152 @param excType exception type |
157 @param excValue exception value |
153 @param excValue exception value |
158 @param tracebackobj traceback object |
154 @param tracebackobj traceback object |
159 """ |
155 """ |
160 from UI.Info import BugAddress |
156 from UI.Info import BugAddress |
161 import Utilities |
157 import Utilities |
162 import Globals |
158 import Globals |
163 |
159 |
164 # Workaround for a strange issue with QScintilla |
160 # Workaround for a strange issue with QScintilla |
165 if str(excValue) == "unable to convert a QVariant back to a Python object": |
161 if str(excValue) == "unable to convert a QVariant back to a Python object": |
166 return |
162 return |
167 |
163 |
168 separator = '-' * 80 |
164 separator = "-" * 80 |
169 logFile = os.path.join(Globals.getConfigDir(), "eric7_error.log") |
165 logFile = os.path.join(Globals.getConfigDir(), "eric7_error.log") |
170 notice = ( |
166 notice = ( |
171 """An unhandled exception occurred. Please report the problem\n""" |
167 """An unhandled exception occurred. Please report the problem\n""" |
172 """using the error reporting dialog or via email to <{0}>.\n""" |
168 """using the error reporting dialog or via email to <{0}>.\n""" |
173 """A log has been written to "{1}".\n\nError information:\n""".format( |
169 """A log has been written to "{1}".\n\nError information:\n""".format( |
174 BugAddress, logFile) |
170 BugAddress, logFile |
|
171 ) |
175 ) |
172 ) |
176 timeString = time.strftime("%Y-%m-%d, %H:%M:%S") |
173 timeString = time.strftime("%Y-%m-%d, %H:%M:%S") |
177 |
174 |
178 versionInfo = "\n{0}\n{1}".format( |
175 versionInfo = "\n{0}\n{1}".format(separator, Utilities.generateVersionInfo()) |
179 separator, Utilities.generateVersionInfo()) |
|
180 pluginVersionInfo = Utilities.generatePluginsVersionInfo() |
176 pluginVersionInfo = Utilities.generatePluginsVersionInfo() |
181 if pluginVersionInfo: |
177 if pluginVersionInfo: |
182 versionInfo += "\n{0}\n{1}".format(separator, pluginVersionInfo) |
178 versionInfo += "\n{0}\n{1}".format(separator, pluginVersionInfo) |
183 distroInfo = Utilities.generateDistroInfo() |
179 distroInfo = Utilities.generateDistroInfo() |
184 if distroInfo: |
180 if distroInfo: |
185 versionInfo += "\n{0}\n{1}".format(separator, distroInfo) |
181 versionInfo += "\n{0}\n{1}".format(separator, distroInfo) |
186 |
182 |
187 if isinstance(excType, str): |
183 if isinstance(excType, str): |
188 tbinfo = tracebackobj |
184 tbinfo = tracebackobj |
189 else: |
185 else: |
190 tbinfofile = io.StringIO() |
186 tbinfofile = io.StringIO() |
191 traceback.print_tb(tracebackobj, None, tbinfofile) |
187 traceback.print_tb(tracebackobj, None, tbinfofile) |
192 tbinfofile.seek(0) |
188 tbinfofile.seek(0) |
193 tbinfo = tbinfofile.read() |
189 tbinfo = tbinfofile.read() |
194 errmsg = '{0}: \n{1}'.format(str(excType), str(excValue)) |
190 errmsg = "{0}: \n{1}".format(str(excType), str(excValue)) |
195 sections = ['', separator, timeString, separator, errmsg, separator, |
191 sections = ["", separator, timeString, separator, errmsg, separator, tbinfo] |
196 tbinfo] |
192 msg = "\n".join(sections) |
197 msg = '\n'.join(sections) |
193 with contextlib.suppress(OSError), open(logFile, "w", encoding="utf-8") as f: |
198 with contextlib.suppress(OSError), \ |
|
199 open(logFile, "w", encoding="utf-8") as f: |
|
200 f.write(msg) |
194 f.write(msg) |
201 f.write(versionInfo) |
195 f.write(versionInfo) |
202 |
196 |
203 if inMainLoop is None: |
197 if inMainLoop is None: |
204 warning = notice + msg + versionInfo |
198 warning = notice + msg + versionInfo |
205 print(warning) # __IGNORE_WARNING_M801__ |
199 print(warning) # __IGNORE_WARNING_M801__ |
206 else: |
200 else: |
207 warning = notice + msg + versionInfo |
201 warning = notice + msg + versionInfo |
208 # Escape &<> otherwise it's not visible in the error dialog |
202 # Escape &<> otherwise it's not visible in the error dialog |
209 warning = ( |
203 warning = ( |
210 warning |
204 warning.replace("&", "&").replace(">", ">").replace("<", "<") |
211 .replace("&", "&") |
|
212 .replace(">", ">") |
|
213 .replace("<", "<") |
|
214 ) |
205 ) |
215 qWarning(warning) |
206 qWarning(warning) |
216 |
207 |
217 |
208 |
218 def uiStartUp(): |
209 def uiStartUp(): |
219 """ |
210 """ |
220 Global function to finalize the start up of the main UI. |
211 Global function to finalize the start up of the main UI. |
221 |
212 |
222 Note: It is activated by a zero timeout single-shot timer. |
213 Note: It is activated by a zero timeout single-shot timer. |
223 """ |
214 """ |
224 global args, mainWindow, splash |
215 global args, mainWindow, splash |
225 |
216 |
226 if splash: |
217 if splash: |
227 splash.finish(mainWindow) |
218 splash.finish(mainWindow) |
228 del splash |
219 del splash |
229 |
220 |
230 mainWindow.checkForErrorLog() |
221 mainWindow.checkForErrorLog() |
231 mainWindow.processArgs(args) |
222 mainWindow.processArgs(args) |
232 mainWindow.processInstallInfoFile() |
223 mainWindow.processInstallInfoFile() |
233 mainWindow.checkProjectsWorkspace() |
224 mainWindow.checkProjectsWorkspace() |
234 mainWindow.checkConfigurationStatus() |
225 mainWindow.checkConfigurationStatus() |
241 """ |
232 """ |
242 Main entry point into the application. |
233 Main entry point into the application. |
243 """ |
234 """ |
244 from Globals import AppInfo |
235 from Globals import AppInfo |
245 import Globals |
236 import Globals |
246 |
237 |
247 global app, args, mainWindow, splash, restartArgs, inMainLoop |
238 global app, args, mainWindow, splash, restartArgs, inMainLoop |
248 |
239 |
249 sys.excepthook = excepthook |
240 sys.excepthook = excepthook |
250 |
241 |
251 from PyQt6.QtGui import QGuiApplication |
242 from PyQt6.QtGui import QGuiApplication |
|
243 |
252 QGuiApplication.setDesktopFileName("eric7.desktop") |
244 QGuiApplication.setDesktopFileName("eric7.desktop") |
253 |
245 |
254 options = [ |
246 options = [ |
255 ("--config=configDir", |
247 ( |
256 "use the given directory as the one containing the config files"), |
248 "--config=configDir", |
|
249 "use the given directory as the one containing the config files", |
|
250 ), |
257 ("--debug", "activate debugging output to the console"), |
251 ("--debug", "activate debugging output to the console"), |
258 ("--no-splash", "don't show the splash screen"), |
252 ("--no-splash", "don't show the splash screen"), |
259 ("--no-open", |
253 ("--no-open", "don't open anything at startup except that given in command"), |
260 "don't open anything at startup except that given in command"), |
|
261 ("--no-crash", "don't check for a crash session file on startup"), |
254 ("--no-crash", "don't check for a crash session file on startup"), |
262 ("--disable-crash", "disable the support for crash sessions"), |
255 ("--disable-crash", "disable the support for crash sessions"), |
263 ("--disable-plugin=<plug-in name>", |
256 ( |
264 "disable the given plug-in (may be repeated)"), |
257 "--disable-plugin=<plug-in name>", |
265 ("--plugin=plugin-file", |
258 "disable the given plug-in (may be repeated)", |
266 "load the given plugin file (plugin development)"), |
259 ), |
267 ("--settings=settingsDir", |
260 ("--plugin=plugin-file", "load the given plugin file (plugin development)"), |
268 "use the given directory to store the settings files"), |
261 ( |
269 ("--small-screen", |
262 "--settings=settingsDir", |
270 "adjust the interface for screens smaller than FHD"), |
263 "use the given directory to store the settings files", |
|
264 ), |
|
265 ("--small-screen", "adjust the interface for screens smaller than FHD"), |
271 ("--start-file", "load the most recently opened file"), |
266 ("--start-file", "load the most recently opened file"), |
272 ("--start-multi", "load the most recently opened multi-project"), |
267 ("--start-multi", "load the most recently opened multi-project"), |
273 ("--start-project", "load the most recently opened project"), |
268 ("--start-project", "load the most recently opened project"), |
274 ("--start-session", "load the global session file"), |
269 ("--start-session", "load the global session file"), |
275 ("--", |
270 ("--", "indicate that there are options for the program to be debugged"), |
276 "indicate that there are options for the program to be debugged"), |
271 ("", "(everything after that is considered arguments for this program)"), |
277 ("", |
|
278 "(everything after that is considered arguments for this program)") |
|
279 ] |
272 ] |
280 appinfo = AppInfo.makeAppInfo(sys.argv, |
273 appinfo = AppInfo.makeAppInfo( |
281 "Eric7", |
274 sys.argv, |
282 "[project | files... [--] [debug-options]]", |
275 "Eric7", |
283 "A Python IDE", |
276 "[project | files... [--] [debug-options]]", |
284 options) |
277 "A Python IDE", |
285 |
278 options, |
|
279 ) |
|
280 |
286 if "__PYVENV_LAUNCHER__" in os.environ: |
281 if "__PYVENV_LAUNCHER__" in os.environ: |
287 del os.environ["__PYVENV_LAUNCHER__"] |
282 del os.environ["__PYVENV_LAUNCHER__"] |
288 |
283 |
289 # make sure our executable directory (i.e. that of the used Python |
284 # make sure our executable directory (i.e. that of the used Python |
290 # interpreter) is included in the executable search path |
285 # interpreter) is included in the executable search path |
291 pathList = os.environ["PATH"].split(os.pathsep) |
286 pathList = os.environ["PATH"].split(os.pathsep) |
292 exeDir = os.path.dirname(sys.executable) |
287 exeDir = os.path.dirname(sys.executable) |
293 if exeDir not in pathList: |
288 if exeDir not in pathList: |
294 pathList.insert(0, exeDir) |
289 pathList.insert(0, exeDir) |
295 os.environ["PATH"] = os.pathsep.join(pathList) |
290 os.environ["PATH"] = os.pathsep.join(pathList) |
296 |
291 |
297 from Toolbox import Startup |
292 from Toolbox import Startup |
|
293 |
298 # set the library paths for plugins |
294 # set the library paths for plugins |
299 Startup.setLibraryPaths() |
295 Startup.setLibraryPaths() |
300 |
296 |
301 if WEBENGINE_AVAILABLE: |
297 if WEBENGINE_AVAILABLE: |
302 scheme = QWebEngineUrlScheme(b"qthelp") |
298 scheme = QWebEngineUrlScheme(b"qthelp") |
303 scheme.setSyntax(QWebEngineUrlScheme.Syntax.Path) |
299 scheme.setSyntax(QWebEngineUrlScheme.Syntax.Path) |
304 scheme.setFlags(QWebEngineUrlScheme.Flag.SecureScheme) |
300 scheme.setFlags(QWebEngineUrlScheme.Flag.SecureScheme) |
305 QWebEngineUrlScheme.registerScheme(scheme) |
301 QWebEngineUrlScheme.registerScheme(scheme) |
306 |
302 |
307 app = EricApplication(sys.argv) |
303 app = EricApplication(sys.argv) |
308 ddindex = Startup.handleArgs(sys.argv, appinfo) |
304 ddindex = Startup.handleArgs(sys.argv, appinfo) |
309 |
305 |
310 logging.debug("Importing Preferences") |
306 logging.debug("Importing Preferences") |
311 import Preferences |
307 import Preferences |
312 |
308 |
313 if Preferences.getUI("SingleApplicationMode"): |
309 if Preferences.getUI("SingleApplicationMode"): |
314 handleSingleApplication(ddindex) |
310 handleSingleApplication(ddindex) |
315 |
311 |
316 # set the application style sheet |
312 # set the application style sheet |
317 app.setStyleSheetFile(Preferences.getUI("StyleSheet")) |
313 app.setStyleSheetFile(Preferences.getUI("StyleSheet")) |
318 |
314 |
319 # set the search path for icons |
315 # set the search path for icons |
320 Startup.initializeResourceSearchPath(app) |
316 Startup.initializeResourceSearchPath(app) |
321 |
317 |
322 # generate and show a splash window, if not suppressed |
318 # generate and show a splash window, if not suppressed |
323 from UI.SplashScreen import SplashScreen, NoneSplashScreen |
319 from UI.SplashScreen import SplashScreen, NoneSplashScreen |
|
320 |
324 if "--no-splash" in sys.argv and sys.argv.index("--no-splash") < ddindex: |
321 if "--no-splash" in sys.argv and sys.argv.index("--no-splash") < ddindex: |
325 sys.argv.remove("--no-splash") |
322 sys.argv.remove("--no-splash") |
326 ddindex -= 1 |
323 ddindex -= 1 |
327 splash = NoneSplashScreen() |
324 splash = NoneSplashScreen() |
328 elif not Preferences.getUI("ShowSplash"): |
325 elif not Preferences.getUI("ShowSplash"): |
377 sys.argv.remove(arg) |
368 sys.argv.remove(arg) |
378 ddindex -= 1 |
369 ddindex -= 1 |
379 pluginFile = os.path.expanduser(pluginFile) |
370 pluginFile = os.path.expanduser(pluginFile) |
380 pluginFile = os.path.abspath(pluginFile) |
371 pluginFile = os.path.abspath(pluginFile) |
381 break |
372 break |
382 |
373 |
383 # is there a set of filenames or options on the command line, |
374 # is there a set of filenames or options on the command line, |
384 # if so, pass them to the UI |
375 # if so, pass them to the UI |
385 if len(sys.argv) > 1: |
376 if len(sys.argv) > 1: |
386 args = sys.argv[1:] |
377 args = sys.argv[1:] |
387 |
378 |
388 # get the Qt translations directory |
379 # get the Qt translations directory |
389 qtTransDir = Preferences.getQtTranslationsDir() |
380 qtTransDir = Preferences.getQtTranslationsDir() |
390 if not qtTransDir: |
381 if not qtTransDir: |
391 qtTransDir = QLibraryInfo.path( |
382 qtTransDir = QLibraryInfo.path(QLibraryInfo.LibraryPath.TranslationsPath) |
392 QLibraryInfo.LibraryPath.TranslationsPath) |
383 |
393 |
|
394 # Load translation files and install them |
384 # Load translation files and install them |
395 loc = Startup.loadTranslators(qtTransDir, app, ("qscintilla",)) |
385 loc = Startup.loadTranslators(qtTransDir, app, ("qscintilla",)) |
396 |
386 |
397 # Initialize SSL stuff |
387 # Initialize SSL stuff |
398 from EricNetwork.EricSslUtilities import initSSL |
388 from EricNetwork.EricSslUtilities import initSSL |
|
389 |
399 initSSL() |
390 initSSL() |
400 |
391 |
401 splash.showMessage(QCoreApplication.translate("eric7", "Starting...")) |
392 splash.showMessage(QCoreApplication.translate("eric7", "Starting...")) |
402 # We can only import these after creating the EricApplication because they |
393 # We can only import these after creating the EricApplication because they |
403 # make Qt calls that need the EricApplication to exist. |
394 # make Qt calls that need the EricApplication to exist. |
404 from UI.UserInterface import UserInterface |
395 from UI.UserInterface import UserInterface |
405 |
396 |
406 splash.showMessage( |
397 splash.showMessage(QCoreApplication.translate("eric7", "Generating Main Window...")) |
407 QCoreApplication.translate("eric7", "Generating Main Window...")) |
398 mainWindow = UserInterface( |
408 mainWindow = UserInterface(app, loc, splash, pluginFile, disabledPlugins, |
399 app, |
409 noopen, nocrash, disablecrash, restartArgs, |
400 loc, |
410 originalPathString) |
401 splash, |
|
402 pluginFile, |
|
403 disabledPlugins, |
|
404 noopen, |
|
405 nocrash, |
|
406 disablecrash, |
|
407 restartArgs, |
|
408 originalPathString, |
|
409 ) |
411 app.lastWindowClosed.connect(app.quit) |
410 app.lastWindowClosed.connect(app.quit) |
412 mainWindow.show() |
411 mainWindow.show() |
413 |
412 |
414 QTimer.singleShot(0, uiStartUp) |
413 QTimer.singleShot(0, uiStartUp) |
415 |
414 |
416 # generate a graphical error handler |
415 # generate a graphical error handler |
417 from EricWidgets import EricErrorMessage |
416 from EricWidgets import EricErrorMessage |
|
417 |
418 eMsg = EricErrorMessage.qtHandler() |
418 eMsg = EricErrorMessage.qtHandler() |
419 eMsg.setMinimumSize(600, 400) |
419 eMsg.setMinimumSize(600, 400) |
420 |
420 |
421 # start the event loop |
421 # start the event loop |
422 inMainLoop = True |
422 inMainLoop = True |
423 res = app.exec() |
423 res = app.exec() |
424 logging.debug("Shutting down, result %d", res) |
424 logging.debug("Shutting down, result %d", res) |
425 logging.shutdown() |
425 logging.shutdown() |
426 sys.exit(res) |
426 sys.exit(res) |
427 |
427 |
428 if __name__ == '__main__': |
428 |
|
429 if __name__ == "__main__": |
429 main() |
430 main() |