eric6.py

changeset 3667
c9694cc027be
parent 3656
441956d8fce5
child 3670
f0cb7579c0b4
equal deleted inserted replaced
3664:78e522719af3 3667:c9694cc027be
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3
4 # Copyright (c) 2002 - 2014 Detlev Offenbach <detlev@die-offenbachs.de>
5 #
6
7 """
8 Eric5 Python IDE.
9
10 This is the main Python script that performs the necessary initialization
11 of the IDE and starts the Qt event loop.
12 """
13
14 from __future__ import unicode_literals
15
16 try: # Only for Py2
17 import StringIO as io # __IGNORE_EXCEPTION__
18 import Utilities.compatibility_fixes # __IGNORE_WARNING__
19 except ImportError:
20 import io # __IGNORE_WARNING__
21 basestring = str
22
23 try:
24 import sip
25 sip.setdestroyonexit(False)
26 except AttributeError:
27 pass
28
29
30 import sys
31 import os
32 import traceback
33 import time
34 import logging
35
36 from PyQt5.QtCore import qWarning, QLibraryInfo, QTimer, QCoreApplication
37
38 # some global variables needed to start the application
39 args = None
40 mainWindow = None
41 splash = None
42
43 # generate list of arguments to be remembered for a restart
44 restartArgsList = ["--nosplash", "--plugin", "--debug", "--config"]
45 restartArgs = [arg for arg in sys.argv[1:]
46 if arg.split("=", 1)[0] in restartArgsList]
47
48 if "--debug" in sys.argv:
49 del sys.argv[sys.argv.index("--debug")]
50 logging.basicConfig(level=logging.DEBUG)
51
52 for arg in sys.argv:
53 if arg.startswith("--config="):
54 import Globals
55 configDir = arg.replace("--config=", "")
56 Globals.setConfigDir(configDir)
57 sys.argv.remove(arg)
58 break
59
60 # make Third-Party package available as a packages repository
61 sys.path.insert(2, os.path.join(os.path.dirname(__file__),
62 "ThirdParty", "Pygments"))
63 sys.path.insert(2, os.path.join(os.path.dirname(__file__),
64 "ThirdParty", "Jasy"))
65
66 from E5Gui.E5Application import E5Application
67
68
69 def handleSingleApplication(ddindex):
70 """
71 Global function to handle the single application mode.
72
73 @param ddindex index of a '--' option in the options list
74 """
75 from E5Gui.E5SingleApplication import E5SingleApplicationClient
76
77 client = E5SingleApplicationClient()
78 res = client.connect()
79 if res > 0:
80 if "--nosplash" in sys.argv and sys.argv.index("--nosplash") < ddindex:
81 del sys.argv[sys.argv.index("--nosplash")]
82 if "--noopen" in sys.argv and sys.argv.index("--noopen") < ddindex:
83 del sys.argv[sys.argv.index("--noopen")]
84 if "--debug" in sys.argv and sys.argv.index("--debug") < ddindex:
85 del sys.argv[sys.argv.index("--debug")]
86 for arg in sys.argv:
87 if arg.startswith("--config="):
88 sys.argv.remove(arg)
89 break
90 if len(sys.argv) > 1:
91 client.processArgs(sys.argv[1:])
92 sys.exit(0)
93 elif res < 0:
94 print("eric5: {0}".format(client.errstr()))
95 sys.exit(res)
96
97
98 def excepthook(excType, excValue, tracebackobj):
99 """
100 Global function to catch unhandled exceptions.
101
102 @param excType exception type
103 @param excValue exception value
104 @param tracebackobj traceback object
105 """
106 import xml.sax.saxutils
107 from UI.Info import BugAddress
108 import Utilities
109 import Globals
110
111 separator = '-' * 80
112 logFile = os.path.join(Globals.getConfigDir(), "eric5_error.log")
113 notice = \
114 """An unhandled exception occurred. Please report the problem\n"""\
115 """using the error reporting dialog or via email to <{0}>.\n"""\
116 """A log has been written to "{1}".\n\nError information:\n""".format(
117 BugAddress, logFile)
118 timeString = time.strftime("%Y-%m-%d, %H:%M:%S")
119
120 versionInfo = "\n{0}\n{1}".format(
121 separator, Utilities.generateVersionInfo())
122 pluginVersionInfo = Utilities.generatePluginsVersionInfo()
123 if pluginVersionInfo:
124 versionInfo += "{0}\n{1}".format(separator, pluginVersionInfo)
125 distroInfo = Utilities.generateDistroInfo()
126 if distroInfo:
127 versionInfo += "{0}\n{1}".format(separator, distroInfo)
128
129 if isinstance(excType, basestring):
130 tbinfo = tracebackobj
131 else:
132 tbinfofile = io.StringIO()
133 traceback.print_tb(tracebackobj, None, tbinfofile)
134 tbinfofile.seek(0)
135 tbinfo = tbinfofile.read()
136 errmsg = '{0}: \n{1}'.format(str(excType), str(excValue))
137 sections = [separator, timeString, separator, errmsg, separator, tbinfo]
138 msg = '\n'.join(sections)
139 try:
140 f = open(logFile, "w", encoding="utf-8")
141 f.write(msg)
142 f.write(versionInfo)
143 f.close()
144 except IOError:
145 pass
146
147 warning = str(notice) + str(msg) + str(versionInfo)
148 # Escape &<> otherwise it's not visible in the error dialog
149 warning = xml.sax.saxutils.escape(warning)
150 qWarning(warning)
151
152
153 def uiStartUp():
154 """
155 Global function to finalize the start up of the main UI.
156
157 Note: It is activated by a zero timeout single-shot timer.
158 """
159 global args, mainWindow, splash
160
161 if splash:
162 splash.finish(mainWindow)
163 del splash
164
165 mainWindow.checkForErrorLog()
166 mainWindow.processArgs(args)
167 mainWindow.checkProjectsWorkspace()
168 mainWindow.checkConfigurationStatus()
169 mainWindow.performVersionCheck(False)
170 mainWindow.checkPluginUpdatesAvailable()
171 mainWindow.autoConnectIrc()
172
173
174 def main():
175 """
176 Main entry point into the application.
177
178 @exception Exception re-raised for any exception occurring in the main
179 program logic
180 """
181 from Globals import AppInfo
182 import Globals
183
184 global args, mainWindow, splash, restartArgs
185
186 sys.excepthook = excepthook
187
188 options = [
189 ("--config=configDir",
190 "use the given directory as the one containing the config files"),
191 ("--debug", "activate debugging output to the console"),
192 ("--nosplash", "don't show the splash screen"),
193 ("--noopen",
194 "don't open anything at startup except that given in command"),
195 ("--plugin=plugin-file",
196 "load the given plugin file (plugin development)"),
197 ("--start-file", "load the most recently opened file"),
198 ("--start-multi", "load the most recently opened multi-project"),
199 ("--start-project", "load the most recently opened project"),
200 ("--start-session", "load the global session file"),
201 ("--",
202 "indicate that there are options for the program to be debugged"),
203 ("",
204 "(everything after that is considered arguments for this program)")
205 ]
206 appinfo = AppInfo.makeAppInfo(sys.argv,
207 "Eric5",
208 "[project | files... [--] [debug-options]]",
209 "A Python IDE",
210 options)
211
212 if not Globals.checkBlacklistedVersions():
213 sys.exit(100)
214
215 app = E5Application(sys.argv)
216
217 import Utilities
218 from Toolbox import Startup
219
220 ddindex = Startup.handleArgs(sys.argv, appinfo)
221
222 logging.debug("Importing Preferences")
223 import Preferences
224
225 if Preferences.getUI("SingleApplicationMode"):
226 handleSingleApplication(ddindex)
227
228 # set the library paths for plugins
229 Startup.setLibraryPaths()
230
231 # set the search path for icons
232 Startup.initializeResourceSearchPath()
233
234 # generate and show a splash window, if not suppressed
235 from UI.SplashScreen import SplashScreen, NoneSplashScreen
236 if "--nosplash" in sys.argv and sys.argv.index("--nosplash") < ddindex:
237 del sys.argv[sys.argv.index("--nosplash")]
238 splash = NoneSplashScreen()
239 elif not Preferences.getUI("ShowSplash"):
240 splash = NoneSplashScreen()
241 else:
242 splash = SplashScreen()
243
244 # modify the executable search path for the PyQt5 installer
245 if Globals.isWindowsPlatform():
246 pyqtDataDir = Globals.getPyQt5ModulesDirectory()
247 if os.path.exists(os.path.join(pyqtDataDir, "bin")):
248 path = os.path.join(pyqtDataDir, "bin") + \
249 os.pathsep + os.environ["PATH"]
250 else:
251 path = pyqtDataDir + os.pathsep + os.environ["PATH"]
252 os.environ["PATH"] = path
253
254 pluginFile = None
255 noopen = False
256 if "--noopen" in sys.argv and sys.argv.index("--noopen") < ddindex:
257 del sys.argv[sys.argv.index("--noopen")]
258 noopen = True
259 for arg in sys.argv:
260 if arg.startswith("--plugin=") and sys.argv.index(arg) < ddindex:
261 # extract the plugin development option
262 pluginFile = arg.replace("--plugin=", "").replace('"', "")
263 sys.argv.remove(arg)
264 pluginFile = os.path.expanduser(pluginFile)
265 pluginFile = Utilities.normabspath(pluginFile)
266 break
267
268 # is there a set of filenames or options on the command line,
269 # if so, pass them to the UI
270 if len(sys.argv) > 1:
271 args = sys.argv[1:]
272
273 # get the Qt4 translations directory
274 qt4TransDir = Preferences.getQt4TranslationsDir()
275 if not qt4TransDir:
276 qt4TransDir = QLibraryInfo.location(QLibraryInfo.TranslationsPath)
277
278 # Load translation files and install them
279 loc = Startup.loadTranslators(qt4TransDir, app, ("qscintilla",))
280
281 splash.showMessage(QCoreApplication.translate("eric5", "Starting..."))
282 # We can only import these after creating the E5Application because they
283 # make Qt calls that need the E5Application to exist.
284 from UI.UserInterface import UserInterface
285
286 splash.showMessage(
287 QCoreApplication.translate("eric5", "Generating Main Window..."))
288 try:
289 mainWindow = UserInterface(app, loc, splash, pluginFile, noopen,
290 restartArgs)
291 app.lastWindowClosed.connect(app.quit)
292 mainWindow.show()
293
294 QTimer.singleShot(0, uiStartUp)
295
296 # generate a graphical error handler
297 from E5Gui import E5ErrorMessage
298 eMsg = E5ErrorMessage.qtHandler()
299 eMsg.setMinimumSize(600, 400)
300
301 # start the event loop
302 res = app.exec_()
303 logging.debug("Shutting down, result {0:d}".format(res))
304 logging.shutdown()
305 sys.exit(res)
306 except Exception as err:
307 raise err
308
309 if __name__ == '__main__':
310 main()

eric ide

mercurial