VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/BaseTools/Scripts/PackageDocumentTools/packagedocapp.pyw@ 77662

Last change on this file since 77662 was 77662, checked in by vboxsync, 6 years ago

EFI: First step in UDK2018 merge. Does not build yet.

  • Property svn:eol-style set to native
File size: 45.0 KB
Line 
1## @file
2# This file is used to define common string related functions used in parsing
3# process
4#
5# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
6#
7# This program and the accompanying materials are licensed and made available
8# under the terms and conditions of the BSD License which accompanies this
9# distribution. The full text of the license may be found at
10# http://opensource.org/licenses/bsd-license.php
11#
12# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14#
15
16import os, sys, wx, logging
17
18import wx.stc
19import wx.lib.newevent
20import wx.lib.agw.genericmessagedialog as GMD
21import plugins.EdkPlugins.edk2.model.baseobject as baseobject
22import plugins.EdkPlugins.edk2.model.doxygengen as doxygengen
23
24if hasattr(sys, "frozen"):
25 appPath = os.path.abspath(os.path.dirname(sys.executable))
26else:
27 appPath = os.path.abspath(os.path.dirname(__file__))
28
29AppCallBackEvent, EVT_APP_CALLBACK = wx.lib.newevent.NewEvent()
30LogEvent, EVT_LOG = wx.lib.newevent.NewEvent()
31
32class PackageDocApp(wx.App):
33
34 def OnInit(self):
35 logfile = os.path.join(appPath, 'log.txt')
36 logging.basicConfig(format='%(name)-8s %(levelname)-8s %(message)s',
37 filename=logfile, level=logging.ERROR)
38
39 self.SetAppName('Package Doxygen Generate Application')
40 frame = PackageDocMainFrame(None, "Package Document Generation Application!")
41 self.SetTopWindow(frame)
42
43 frame.Show(True)
44
45 EVT_APP_CALLBACK( self, self.OnAppCallBack)
46 return True
47
48 def GetLogger(self):
49 return logging.getLogger('')
50
51 def ForegroundProcess(self, function, args):
52 wx.PostEvent(self, AppCallBackEvent(callback=function, args=args))
53
54 def OnAppCallBack(self, event):
55 try:
56 event.callback(*event.args)
57 except:
58 self._logger.exception( 'OnAppCallBack<%s.%s>\n' %
59 (event.callback.__module__, event.callback.__name__ ))
60
61class PackageDocMainFrame(wx.Frame):
62 def __init__(self, parent, title):
63 wx.Frame.__init__(self, parent, -1, title, size=(550, 290), style=wx.MINIMIZE_BOX|wx.SYSTEM_MENU|wx.CAPTION|wx.CLOSE_BOX )
64
65 panel = wx.Panel(self)
66 sizer = wx.BoxSizer(wx.VERTICAL)
67
68 subsizer = wx.GridBagSizer(5, 10)
69 subsizer.AddGrowableCol(1)
70 subsizer.Add(wx.StaticText(panel, -1, "Workspace Location : "), (0, 0), flag=wx.ALIGN_CENTER_VERTICAL)
71 self._workspacePathCtrl = wx.ComboBox(panel, -1)
72 list = self.GetConfigure("WorkspacePath")
73 if len(list) != 0:
74 for item in list:
75 self._workspacePathCtrl.Append(item)
76 self._workspacePathCtrl.SetValue(list[len(list) - 1])
77
78 subsizer.Add(self._workspacePathCtrl, (0, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
79 self._workspacePathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN))
80 subsizer.Add(self._workspacePathBt, (0, 2), flag=wx.ALIGN_CENTER_VERTICAL)
81 wx.EVT_BUTTON(self._workspacePathBt, self._workspacePathBt.GetId(), self.OnBrowsePath)
82
83 subsizer.Add(wx.StaticText(panel, -1, "Package DEC Location : "), (1, 0), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
84 self._packagePathCtrl = wx.ComboBox(panel, -1)
85 list = self.GetConfigure("PackagePath")
86 if len(list) != 0:
87 for item in list:
88 self._packagePathCtrl.Append(item)
89 self._packagePathCtrl.SetValue(list[len(list) - 1])
90 subsizer.Add(self._packagePathCtrl, (1, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
91 self._packagePathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN))
92 subsizer.Add(self._packagePathBt, (1, 2), flag=wx.ALIGN_CENTER_VERTICAL)
93 wx.EVT_BUTTON(self._packagePathBt, self._packagePathBt.GetId(), self.OnBrowsePath)
94
95 subsizer.Add(wx.StaticText(panel, -1, "Doxygen Tool Location : "), (2, 0), flag=wx.ALIGN_CENTER_VERTICAL)
96 self._doxygenPathCtrl = wx.TextCtrl(panel, -1)
97 list = self.GetConfigure('DoxygenPath')
98 if len(list) != 0:
99 self._doxygenPathCtrl.SetValue(list[0])
100 else:
101 if wx.Platform == '__WXMSW__':
102 self._doxygenPathCtrl.SetValue('C:\\Program Files\\Doxygen\\bin\\doxygen.exe')
103 else:
104 self._doxygenPathCtrl.SetValue('/usr/bin/doxygen')
105
106 self._doxygenPathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN))
107 subsizer.Add(self._doxygenPathCtrl, (2, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
108 subsizer.Add(self._doxygenPathBt, (2, 2), flag=wx.ALIGN_CENTER_VERTICAL)
109 wx.EVT_BUTTON(self._doxygenPathBt, self._doxygenPathBt.GetId(), self.OnBrowsePath)
110
111 subsizer.Add(wx.StaticText(panel, -1, "CHM Tool Location : "), (3, 0), flag=wx.ALIGN_CENTER_VERTICAL)
112 self._chmPathCtrl = wx.TextCtrl(panel, -1)
113 list = self.GetConfigure('CHMPath')
114 if len(list) != 0:
115 self._chmPathCtrl.SetValue(list[0])
116 else:
117 self._chmPathCtrl.SetValue('C:\\Program Files\\HTML Help Workshop\\hhc.exe')
118
119 self._chmPathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN))
120 subsizer.Add(self._chmPathCtrl, (3, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
121 subsizer.Add(self._chmPathBt, (3, 2), flag=wx.ALIGN_CENTER_VERTICAL)
122 wx.EVT_BUTTON(self._chmPathBt, self._chmPathBt.GetId(), self.OnBrowsePath)
123
124 subsizer.Add(wx.StaticText(panel, -1, "Output Location : "), (4, 0), flag=wx.ALIGN_CENTER_VERTICAL)
125 self._outputPathCtrl = wx.ComboBox(panel, -1)
126 list = self.GetConfigure("OutputPath")
127 if len(list) != 0:
128 for item in list:
129 self._outputPathCtrl.Append(item)
130 self._outputPathCtrl.SetValue(list[len(list) - 1])
131
132 subsizer.Add(self._outputPathCtrl, (4, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
133 self._outputPathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN))
134 subsizer.Add(self._outputPathBt, (4, 2), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
135 wx.EVT_BUTTON(self._outputPathBt, self._outputPathBt.GetId(), self.OnBrowsePath)
136
137 subsizer.Add(wx.StaticText(panel, -1, "Architecture Specified : "), (5, 0), flag=wx.ALIGN_CENTER_VERTICAL)
138 self._archCtrl = wx.ComboBox(panel, -1, value='ALL', choices=['ALL', 'IA32/MSFT', 'IA32/GNU', 'X64/INTEL', 'X64/GNU', 'IPF/MSFT', 'IPF/GNU', 'EBC/INTEL'],
139 style=wx.CB_READONLY)
140 self._archCtrl.Bind(wx.EVT_COMBOBOX, self.OnArchtectureSelectChanged)
141 subsizer.Add(self._archCtrl, (5, 1), (1, 2), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
142 sizer.Add(subsizer, 0, wx.EXPAND|wx.TOP|wx.BOTTOM|wx.LEFT|wx.RIGHT, 5)
143
144 sizer6 = wx.BoxSizer(wx.HORIZONTAL)
145 self._modesel = wx.RadioBox(panel, -1, 'Generated Document Mode', majorDimension=2, choices=['CHM', 'HTML'], style=wx.RA_SPECIFY_COLS)
146 self._modesel.SetStringSelection('HTML')
147
148 self._includeonlysel = wx.CheckBox(panel, -1, 'Only document public include')
149
150 sizer6.Add(self._modesel, 0 , wx.EXPAND)
151 sizer6.Add(self._includeonlysel, 0, wx.EXPAND|wx.LEFT, 5)
152
153 sizer.Add(sizer6, 0, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, 5)
154
155 self._generateBt = wx.Button(panel, -1, "Generate Package Document!")
156 self._generateBt.Bind(wx.EVT_BUTTON, self.OnGenerate)
157 sizer.Add(self._generateBt, 0, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, 5)
158
159 panel.SetSizer(sizer)
160 panel.Layout()
161 panel.SetAutoLayout(True)
162 self.CenterOnScreen()
163
164 def SaveConfigure(self, name, value):
165 if value ==None or len(value) == 0:
166 return
167 config = wx.ConfigBase_Get()
168 oldvalues = config.Read(name, '').split(';')
169 if len(oldvalues) >= 10:
170 oldvalues.remove(oldvalues[0])
171 if value not in oldvalues:
172 oldvalues.append(value)
173 else:
174 oldvalues.remove(value)
175 oldvalues.append(value)
176
177 config.Write(name, ';'.join(oldvalues))
178
179 def GetConfigure(self, name):
180 config = wx.ConfigBase_Get()
181 values = config.Read(name, '').split(';')
182 list = []
183 for item in values:
184 if len(item) != 0:
185 list.append(item)
186 return list
187
188 def OnBrowsePath(self, event):
189 id = event.GetId()
190 editctrl = None
191 startdir = ''
192 isFile = False
193 if id == self._packagePathBt.GetId():
194 dlgTitle = "Choose package path:"
195 editctrl = self._packagePathCtrl
196 isFile = True
197 if os.path.exists(self.GetWorkspace()):
198 startdir = self.GetWorkspace()
199 elif id == self._workspacePathBt.GetId():
200 dlgTitle = "Choose workspace path:"
201 editctrl = self._workspacePathCtrl
202 startdir = editctrl.GetValue()
203 elif id == self._doxygenPathBt.GetId():
204 isFile = True
205 dlgTitle = "Choose doxygen installation path:"
206 editctrl = self._doxygenPathCtrl
207 startdir = editctrl.GetValue()
208 elif id == self._outputPathBt.GetId():
209 dlgTitle = "Choose document output path:"
210 editctrl = self._outputPathCtrl
211 if os.path.exists(self.GetWorkspace()):
212 startdir = self.GetWorkspace()
213 startdir = editctrl.GetValue()
214 elif id == self._chmPathBt.GetId():
215 isFile = True
216 dlgTitle = "Choose installation path for Microsoft HTML workshop software"
217 editctrl = self._chmPathCtrl
218 startdir = editctrl.GetValue()
219 else:
220 return
221
222 if not isFile:
223 dlg = wx.DirDialog(self, dlgTitle, defaultPath=startdir)
224 else:
225 dlg = wx.FileDialog(self, dlgTitle, defaultDir=startdir)
226
227 if dlg.ShowModal() == wx.ID_OK:
228 editctrl.SetValue(dlg.GetPath())
229 dlg.Destroy()
230
231 def OnArchtectureSelectChanged(self, event):
232 str = ''
233 selarch = self._archCtrl.GetValue()
234 if selarch == 'ALL':
235 str += 'MDE_CPU_IA32 MDE_CPU_X64 MDE_CPU_EBC MDE_CPU_IPF _MSC_EXTENSIONS __GNUC__ __INTEL_COMPILER'
236 elif selarch == 'IA32/MSFT':
237 str += 'MDE_CPU_IA32 _MSC_EXTENSIONS'
238 elif selarch == 'IA32/GNU':
239 str += 'MDE_CPU_IA32 __GNUC__'
240 elif selarch == 'X64/MSFT':
241 str += 'MDE_CPU_X64 _MSC_EXTENSIONS'
242 elif selarch == 'X64/GNU':
243 str += 'MDE_CPU_X64 __GNUC__'
244 elif selarch == 'IPF/MSFT':
245 str += 'MDE_CPU_IPF _MSC_EXTENSIONS'
246 elif selarch == 'IPF/GNU':
247 str += 'MDE_CPU_IPF __GNUC__'
248 elif selarch == 'EBC/INTEL':
249 str += 'MDE_CPU_EBC __INTEL_COMPILER'
250
251 str += ' ASM_PFX= OPTIONAL= '
252
253 def OnMacroText(self, event):
254 str = ''
255 selarch = self._archCtrl.GetValue()
256 if selarch == 'ALL':
257 str += 'MDE_CPU_IA32 MDE_CPU_X64 MDE_CPU_EBC MDE_CPU_IPF _MSC_EXTENSIONS __GNUC__ __INTEL_COMPILER'
258 elif selarch == 'IA32/MSFT':
259 str += 'MDE_CPU_IA32 _MSC_EXTENSIONS'
260 elif selarch == 'IA32/GNU':
261 str += 'MDE_CPU_IA32 __GNUC__'
262 elif selarch == 'X64/MSFT':
263 str += 'MDE_CPU_X64 _MSC_EXTENSIONS'
264 elif selarch == 'X64/GNU':
265 str += 'MDE_CPU_X64 __GNUC__'
266 elif selarch == 'IPF/MSFT':
267 str += 'MDE_CPU_IPF _MSC_EXTENSIONS'
268 elif selarch == 'IPF/GNU':
269 str += 'MDE_CPU_IPF __GNUC__'
270 elif selarch == 'EBC/INTEL':
271 str += 'MDE_CPU_EBC __INTEL_COMPILER'
272
273 str += ' ASM_PFX= OPTIONAL= '
274
275 def OnGenerate(self, event):
276 if not self.CheckInput(): return
277
278 dlg = ProgressDialog(self)
279 dlg.ShowModal()
280 dlg.Destroy()
281
282 def CheckInput(self):
283 pPath = self.GetPackagePath()
284 wPath = self.GetWorkspace()
285 dPath = self.GetDoxygenToolPath()
286 cPath = self.GetChmToolPath()
287 oPath = self.GetOutputPath()
288
289 if len(wPath) == 0 or not os.path.exists(wPath):
290 self._Error("Please input existing workspace path!")
291 return False
292 else:
293 self.SaveConfigure('WorkspacePath', wPath)
294
295 if len(pPath) == 0 or not os.path.exists(pPath) or not pPath.lower().endswith('.dec'):
296 self._Error("Please input existing package file location!")
297 return False
298 elif pPath.lower().find(wPath.lower()) == -1:
299 self._Error("Package patch should starts with workspace path, such as if workspace path is c:\\edk2, package patch could be c:\\edk2\MdePkg")
300 return False
301 else:
302 self.SaveConfigure('PackagePath', pPath)
303
304 if len(dPath) == 0 or not os.path.exists(dPath):
305 self._Error("Can not find doxygen tool from path %s! Please download it from www.stack.nl/~dimitri/doxygen/download.html" % dPath)
306 return False
307 else:
308 self.SaveConfigure('DoxygenPath', dPath)
309
310 if self._modesel.GetStringSelection() == 'CHM':
311 if (len(cPath) == 0 or not os.path.exists(cPath)):
312 self._Error("You select CHM mode to generate document, but can not find software of Microsoft HTML Help Workshop.\nPlease\
313 download it from http://www.microsoft.com/downloads/details.aspx?FamilyID=00535334-c8a6-452f-9aa0-d597d16580cc&displaylang=en\n\
314and install!")
315 return False
316 else:
317 self.SaveConfigure('CHMPath', cPath)
318
319 if len(oPath) == 0:
320 self._Error("You must specific document output path")
321 return False
322 else:
323 self.SaveConfigure('OutputPath', oPath)
324
325 if os.path.exists(oPath):
326 # add checking whether there is old doxygen config file here
327 files = os.listdir(oPath)
328 for file in files:
329 if os.path.isfile(os.path.join(oPath,file)):
330 basename, ext = os.path.splitext(file)
331 if ext.lower() == '.doxygen_config':
332 dlg = GMD.GenericMessageDialog(self, "Existing doxygen document in output directory will be overwritten\n, Are you sure?",
333 "Info", wx.ICON_WARNING|wx.YES_NO)
334 if dlg.ShowModal() == wx.ID_YES:
335 break
336 else:
337 return False
338 else:
339 try:
340 os.makedirs(oPath)
341 except:
342 self._Error("Fail to create output directory, please select another output directory!")
343 return False
344
345 return True
346
347 def _Error(self, message):
348 dlg = GMD.GenericMessageDialog(self, message,
349 "Error", wx.ICON_ERROR|wx.OK)
350 dlg.ShowModal()
351 dlg.Destroy()
352
353 def GetWorkspace(self):
354 return os.path.normpath(self._workspacePathCtrl.GetValue())
355
356 def GetPackagePath(self):
357 return os.path.normpath(self._packagePathCtrl.GetValue())
358
359 def GetOutputPath(self):
360 return os.path.normpath(self._outputPathCtrl.GetValue())
361
362 def GetDoxygenToolPath(self):
363 return os.path.normpath(self._doxygenPathCtrl.GetValue())
364
365 def GetChmToolPath(self):
366 return os.path.normpath(self._chmPathCtrl.GetValue())
367
368 def GetDocumentMode(self):
369 return self._modesel.GetStringSelection()
370
371 def GetArchitecture(self):
372 value = self._archCtrl.GetValue()
373 return value.split('/')[0]
374
375 def GetToolTag(self):
376 value = self._archCtrl.GetValue()
377 if value == 'ALL':
378 return 'ALL'
379 return value.split('/')[1]
380
381 def GetIsOnlyDocumentInclude(self):
382 return self._includeonlysel.IsChecked()
383
384class ProgressDialog(wx.Dialog):
385 def __init__(self, parent, id=wx.ID_ANY):
386 title = "Generate Document for " + parent.GetPackagePath()
387 wx.Dialog.__init__(self, parent, id, title=title, style=wx.CAPTION, size=(600, 300))
388 self.Freeze()
389 sizer = wx.BoxSizer(wx.VERTICAL)
390 self._textCtrl = wx.StaticText(self, -1, "Start launching!")
391 self._gaugeCtrl = wx.Gauge(self, -1, 100, size=(-1, 10))
392 self._resultCtrl = wx.stc.StyledTextCtrl(self, -1)
393 self._closeBt = wx.Button(self, -1, "Close")
394 self._gotoOuputBt = wx.Button(self, -1, "Goto Output")
395
396 # clear all margin
397 self._resultCtrl.SetMarginWidth(0, 0)
398 self._resultCtrl.SetMarginWidth(1, 0)
399 self._resultCtrl.SetMarginWidth(2, 0)
400
401 sizer.Add(self._textCtrl, 0, wx.EXPAND|wx.LEFT|wx.TOP|wx.RIGHT, 5)
402 sizer.Add(self._gaugeCtrl, 0, wx.EXPAND|wx.LEFT|wx.TOP|wx.RIGHT, 5)
403 sizer.Add(self._resultCtrl, 1, wx.EXPAND|wx.LEFT|wx.TOP|wx.RIGHT, 5)
404 btsizer = wx.BoxSizer(wx.HORIZONTAL)
405 btsizer.Add(self._gotoOuputBt, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.LEFT|wx.TOP|wx.LEFT|wx.BOTTOM, 5)
406 btsizer.Add(self._closeBt, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.LEFT|wx.TOP|wx.LEFT|wx.BOTTOM, 5)
407 sizer.Add(btsizer, 0, wx.ALIGN_CENTER_HORIZONTAL)
408
409 self.SetSizer(sizer)
410 self.CenterOnScreen()
411 self.Thaw()
412
413 self._logger = logging.getLogger('')
414 self._loghandle = ResultHandler(self)
415 logging.getLogger('edk').addHandler(self._loghandle)
416 logging.getLogger('').addHandler(self._loghandle)
417 logging.getLogger('app').addHandler(self._loghandle)
418
419 wx.EVT_BUTTON(self._closeBt, self._closeBt.GetId(), self.OnButtonClose)
420 wx.EVT_UPDATE_UI(self, self._closeBt.GetId(), self.OnUpdateCloseButton)
421 wx.EVT_BUTTON(self._gotoOuputBt, self._gotoOuputBt.GetId(), self.OnGotoOutput)
422 EVT_LOG(self, self.OnPostLog)
423
424 self._process = None
425 self._pid = None
426 self._input = None
427 self._output = None
428 self._error = None
429 self._inputThread = None
430 self._errorThread = None
431 self._isBusy = True
432 self._pObj = None
433
434 wx.CallAfter(self.GenerateAction)
435
436 def OnUpdateCloseButton(self, event):
437 self._closeBt.Enable(not self._isBusy)
438 return True
439
440 def OnButtonClose(self, event):
441 if self._isBusy:
442 self._InfoDialog("Please don't close in progressing...")
443 return
444
445 if self._process != None:
446 self._process.CloseOutput()
447
448 if self._inputThread:
449 self._inputThread.Terminate()
450 if self._errorThread:
451 self._errorThread.Terminate()
452
453 if self._pid != None:
454 wx.Process.Kill(self._pid, wx.SIGKILL, wx.KILL_CHILDREN)
455
456 logging.getLogger('edk').removeHandler(self._loghandle)
457 logging.getLogger('').removeHandler(self._loghandle)
458 logging.getLogger('app').removeHandler(self._loghandle)
459
460 if self._pObj != None:
461 self._pObj.Destroy()
462
463 self.EndModal(0)
464
465 def OnGotoOutput(self, event):
466 output = self.GetParent().GetOutputPath()
467 if os.path.exists(output):
468 if wx.Platform == '__WXMSW__':
469 os.startfile(self.GetParent().GetOutputPath())
470 else:
471 import webbrowser
472 webbrowser.open(self.GetParent().GetOutputPath())
473 else:
474 self._ErrorDialog("Output directory does not exist!")
475
476 def _ErrorDialog(self, message):
477 dlg = GMD.GenericMessageDialog(self, message,
478 "Error", wx.ICON_ERROR|wx.OK)
479 dlg.ShowModal()
480 dlg.Destroy()
481
482 def _InfoDialog(self, message):
483 dlg = GMD.GenericMessageDialog(self, message,
484 "Info", wx.ICON_INFORMATION|wx.OK)
485 dlg.ShowModal()
486 dlg.Destroy()
487
488 def _LogStep(self, index, message):
489 stepstr = "Step %d: %s" % (index, message)
490 self._textCtrl.SetLabel(stepstr)
491 self.LogMessage(os.linesep + stepstr + os.linesep)
492 self._gaugeCtrl.SetValue(index * 100 / 6 )
493
494 def OnPostLog(self, event):
495 self.LogMessage(event.message)
496
497 def GenerateAction(self):
498 self._LogStep(1, "Create Package Object Model")
499 wsPath = self.GetParent().GetWorkspace()
500 pkPath = self.GetParent().GetPackagePath()[len(wsPath) + 1:]
501
502 try:
503 pObj = baseobject.Package(None, self.GetParent().GetWorkspace())
504 pObj.Load(pkPath)
505 except:
506 self._ErrorDialog("Fail to create package object model! Please check log.txt under this application folder!")
507 self._isBusy = False
508 return
509 self._pObj = pObj
510
511 self.LogMessage(str(pObj.GetPcds()))
512
513 self._LogStep(2, "Preprocess and Generate Doxygen Config File")
514 try:
515 action = doxygengen.PackageDocumentAction(self.GetParent().GetDoxygenToolPath(),
516 self.GetParent().GetChmToolPath(),
517 self.GetParent().GetOutputPath(),
518 pObj,
519 self.GetParent().GetDocumentMode(),
520 self.LogMessage,
521 self.GetParent().GetArchitecture(),
522 self.GetParent().GetToolTag(),
523 self.GetParent().GetIsOnlyDocumentInclude(),
524 True)
525 except:
526 self._ErrorDialog("Fail to preprocess! Please check log.txt under this application folder!")
527 self._isBusy = False
528 return
529
530 action.RegisterCallbackDoxygenProcess(self.CreateDoxygeProcess)
531
532 try:
533 if not action.Generate():
534 self._isBusy = False
535 self.LogMessage("Fail to generate package document! Please check log.txt under this application folder!", 'error')
536 except:
537 import traceback
538 message = traceback.format_exception(*sys.exc_info())
539 logging.getLogger('').error(''.join(message))
540 self._isBusy = False
541 self._ErrorDialog("Fail to generate package document! Please check log.txt under this application folder!")
542
543 def LogMessage(self, message, level='info'):
544 self._resultCtrl.DocumentEnd()
545 self._resultCtrl.SetReadOnly(False)
546 self._resultCtrl.AppendText(message)
547 self._resultCtrl.Home()
548 self._resultCtrl.Home()
549 self._resultCtrl.SetReadOnly(True)
550 if level == 'error':
551 wx.GetApp().GetLogger().error(message)
552
553 def CreateDoxygeProcess(self, doxPath, configFile):
554 self._LogStep(3, "Launch Doxygen Tool and Generate Package Document")
555
556 cmd = '"%s" %s' % (doxPath, configFile)
557 try:
558 self._process = DoxygenProcess()
559 self._process.SetParent(self)
560 self._process.Redirect()
561 self._pid = wx.Execute(cmd, wx.EXEC_ASYNC, self._process)
562 self._input = self._process.GetInputStream()
563 self._output = self._process.GetOutputStream()
564 self._error = self._process.GetErrorStream()
565 except:
566 self._ErrorDialog('Fail to launch doxygen cmd %s! Please check log.txt under this application folder!' % cmd)
567 self._isBusy = False
568 return False
569
570 self._inputThread = MonitorThread(self._input, self.LogMessage)
571 self._errorThread = MonitorThread(self._error, self.LogMessage)
572 self._inputThread.start()
573 self._errorThread.start()
574 return True
575
576 def OnTerminateDoxygenProcess(self):
577 if self._inputThread:
578 self._inputThread.Terminate()
579 self._inputThread = None
580 if self._errorThread:
581 self._errorThread.Terminate()
582 self._errorThread = None
583
584 if self._error:
585 while self._error.CanRead():
586 text = self._error.read()
587 self.LogMessage(text)
588
589 if self._input:
590 while self._input.CanRead():
591 text = self._input.read()
592 self.LogMessage(text)
593 self._process.Detach()
594
595 self._process.CloseOutput()
596 self._process = None
597 self._pid = None
598
599 self.DocumentFixup()
600
601 if self.GetParent().GetDocumentMode().lower() == 'chm':
602 hhcfile = os.path.join(self.GetParent().GetOutputPath(), 'html', 'index.hhc')
603 hhpfile = os.path.join(self.GetParent().GetOutputPath(), 'html', 'index.hhp')
604 self.FixDecDoxygenFileLink(hhcfile, None)
605 if not self.CreateCHMProcess(self.GetParent().GetChmToolPath(), hhpfile):
606 self._ErrorDialog("Fail to Create %s process for %s" % (self.GetParent().GetChmToolPath(), hhpfile))
607 self._isBusy = False
608 else:
609 self._LogStep(6, "Finished Document Generation!")
610 self._isBusy = False
611 indexpath = os.path.realpath(os.path.join(self.GetParent().GetOutputPath(), 'html', 'index.html'))
612 if wx.Platform == '__WXMSW__':
613 os.startfile(indexpath)
614 else:
615 import webbrowser
616 webbrowser.open(indexpath)
617
618 self._InfoDialog('Success create HTML doxgen document %s' % indexpath)
619
620 def CreateCHMProcess(self, chmPath, hhpfile):
621 self.LogMessage(" >>>>>> Start Microsoft HTML workshop process...Zzz...\n")
622 cmd = '"%s" %s' % (chmPath, hhpfile)
623 try:
624 self._process = CHMProcess()
625 self._process.SetParent(self)
626 self._process.Redirect()
627 self._pid = wx.Execute(cmd, wx.EXEC_ASYNC, self._process)
628 self._input = self._process.GetInputStream()
629 self._output = self._process.GetOutputStream()
630 self._error = self._process.GetErrorStream()
631 except:
632 self.LogMessage('\nFail to launch hhp cmd %s!\n' % cmd)
633 self._isBusy = False
634 return False
635 self._inputThread = MonitorThread(self._input, self.LogMessage)
636 self._errorThread = MonitorThread(self._error, self.LogMessage)
637 self._inputThread.start()
638 self._errorThread.start()
639 return True
640
641 def OnTerminateCHMProcess(self):
642 if self._inputThread:
643 self._inputThread.Terminate()
644 self._inputThread = None
645 if self._errorThread:
646 self._errorThread.Terminate()
647 self._errorThread = None
648
649 if self._error:
650 while self._error.CanRead():
651 text = self._error.read()
652 self.LogMessage(text)
653 if self._input:
654 while self._input.CanRead():
655 text = self._input.read()
656 self.LogMessage(text)
657 self._process.Detach()
658
659 self._process.CloseOutput()
660 self._process = None
661 self._pid = None
662 self._isBusy = False
663 indexpath = os.path.realpath(os.path.join(self.GetParent().GetOutputPath(), 'html', 'index.chm'))
664 if os.path.exists(indexpath):
665 if wx.Platform == '__WXMSW__':
666 os.startfile(indexpath)
667 else:
668 import webbrowser
669 webbrowser.open(indexpath)
670
671 self._LogStep(6, "Finished Document Generation!")
672 self.LogMessage('\nSuccess create CHM doxgen document %s\n' % indexpath)
673 self._InfoDialog('Success create CHM doxgen document %s' % indexpath)
674
675 def DocumentFixup(self):
676 # find BASE_LIBRARY_JUMP_BUFFER structure reference page
677 self._LogStep(4, "Fixup Package Document!")
678 self.LogMessage('\n >>> Start fixup document \n')
679
680 for root, dirs, files in os.walk(os.path.join(self.GetParent().GetOutputPath(), 'html')):
681 for dir in dirs:
682 if dir.lower() in ['.svn', '_svn', 'cvs']:
683 dirs.remove(dir)
684 for file in files:
685 wx.YieldIfNeeded()
686 if not file.lower().endswith('.html'): continue
687 fullpath = os.path.join(self.GetParent().GetOutputPath(), root, file)
688 try:
689 f = open(fullpath, 'r')
690 text = f.read()
691 f.close()
692 except:
693 self.LogMessage('\nFail to open file %s\n' % fullpath)
694 continue
695 if text.find('BASE_LIBRARY_JUMP_BUFFER Struct Reference') != -1 and self.GetParent().GetArchitecture() == 'ALL':
696 self.FixPageBASE_LIBRARY_JUMP_BUFFER(fullpath, text)
697 if text.find('MdePkg/Include/Library/BaseLib.h File Reference') != -1 and self.GetParent().GetArchitecture() == 'ALL':
698 self.FixPageBaseLib(fullpath, text)
699 if text.find('IA32_IDT_GATE_DESCRIPTOR Union Reference') != -1 and self.GetParent().GetArchitecture() == 'ALL':
700 self.FixPageIA32_IDT_GATE_DESCRIPTOR(fullpath, text)
701 if text.find('MdePkg/Include/Library/UefiDriverEntryPoint.h File Reference') != -1:
702 self.FixPageUefiDriverEntryPoint(fullpath, text)
703 if text.find('MdePkg/Include/Library/UefiApplicationEntryPoint.h File Reference') != -1:
704 self.FixPageUefiApplicationEntryPoint(fullpath, text)
705 if text.lower().find('.s.dox') != -1 or \
706 text.lower().find('.asm.dox') != -1 or \
707 text.lower().find('.uni.dox') != -1:
708 self.FixDoxFileLink(fullpath, text)
709
710 self.RemoveFileList()
711 self.LogMessage(' >>> Finish all document fixing up! \n')
712
713 def RemoveFileList(self):
714 path_html = os.path.join(self.GetParent().GetOutputPath(), "html", "tree.html")
715 path_chm = os.path.join(self.GetParent().GetOutputPath(), "html", "index.hhc")
716 if os.path.exists(path_html):
717 self.LogMessage(' >>>Remove FileList item from generated HTML document.\n');
718 lines = []
719 f = open (path_html, "r")
720 lines = f.readlines()
721 f.close()
722 bfound = False
723 for index in xrange(len(lines)):
724 if lines[index].find('<a class="el" href="files.html" target="basefrm">File List</a>') != -1:
725 lines[index] = "<!-- %s" % lines[index]
726 bfound = True
727 continue
728 if bfound:
729 if lines[index].find('</div>') != -1:
730 lines[index] = "%s -->" % lines[index]
731 break
732 if bfound:
733 f = open(path_html, "w")
734 f.write("".join(lines))
735 f.close()
736 else:
737 self.LogMessage (' !!!Can not found FileList item in HTML document!\n')
738
739 if os.path.exists(path_chm):
740 self.LogMessage(" >>>Warning: Can not remove FileList for CHM files!\n");
741 """
742 self.LogMessage(' >>>Remove FileList item from generated CHM document!\n');
743 lines = []
744 f = open (path_chm, "r")
745 lines = f.readlines()
746 f.close()
747 bfound = False
748 for index in xrange(len(lines)):
749 if not bfound:
750 if lines[index].find('<param name="Local" value="files.html">') != -1:
751 lines[index] = '<!-- %s' % lines[index]
752 bfound = True
753 continue
754 if bfound:
755 if lines[index].find('</UL>') != -1:
756 lines[index] = '%s -->\n' % lines[index].rstrip()
757 break
758 if bfound:
759 f = open(path_chm, "w")
760 f.write("".join(lines))
761 f.close()
762 import time
763 time.sleep(2)
764 else:
765 self.LogMessage(' !!!Can not found the FileList item in CHM document!')
766 """
767 def FixPageBaseLib(self, path, text):
768 self.LogMessage(' >>> Fixup BaseLib file page at file %s \n' % path)
769 lines = text.split('\n')
770 lastBaseJumpIndex = -1
771 lastIdtGateDescriptor = -1
772 for index in range(len(lines) - 1, -1, -1):
773 line = lines[index]
774 if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;4 </td>':
775 lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;4&nbsp;[IA32] </td>'
776 if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;0x10 </td>':
777 lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;0x10&nbsp;[IPF] </td>'
778 if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;8 </td>':
779 lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;9&nbsp;[EBC, x64] </td>'
780 if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;4') != -1:
781 lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;4',
782 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;4&nbsp;[IA32]')
783 if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;0x10') != -1:
784 lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;0x10',
785 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;0x10&nbsp;[IPF]')
786 if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;8') != -1:
787 lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;8',
788 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;8&nbsp;[x64, EBC]')
789 if line.find('>BASE_LIBRARY_JUMP_BUFFER</a>') != -1:
790 if lastBaseJumpIndex != -1:
791 del lines[lastBaseJumpIndex]
792 lastBaseJumpIndex = index
793 if line.find('>IA32_IDT_GATE_DESCRIPTOR</a></td>') != -1:
794 if lastIdtGateDescriptor != -1:
795 del lines[lastIdtGateDescriptor]
796 lastIdtGateDescriptor = index
797 try:
798 f = open(path, 'w')
799 f.write('\n'.join(lines))
800 f.close()
801 except:
802 self._isBusy = False
803 self.LogMessage(" <<< Fail to fixup file %s\n" % path)
804 self.LogMessage(" <<< Finish to fixup file %s\n" % path)
805
806 def FixPageIA32_IDT_GATE_DESCRIPTOR(self, path, text):
807 self.LogMessage(' >>> Fixup structure reference IA32_IDT_GATE_DESCRIPTOR at file %s \n' % path)
808 lines = text.split('\n')
809 for index in range(len(lines) - 1, -1, -1):
810 line = lines[index].strip()
811 if line.find('struct {</td>') != -1 and lines[index - 2].find('>Uint64</a></td>') != -1:
812 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>')
813 if line.find('struct {</td>') != -1 and lines[index - 1].find('Data Fields') != -1:
814 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>')
815 try:
816 f = open(path, 'w')
817 f.write('\n'.join(lines))
818 f.close()
819 except:
820 self._isBusy = False
821 self.LogMessage(" <<< Fail to fixup file %s\n" % path)
822 self.LogMessage(" <<< Finish to fixup file %s\n" % path)
823
824 def FixPageBASE_LIBRARY_JUMP_BUFFER(self, path, text):
825 self.LogMessage(' >>> Fixup structure reference BASE_LIBRARY_JUMP_BUFFER at file %s \n' % path)
826 lines = text.split('\n')
827 bInDetail = True
828 bNeedRemove = False
829 for index in range(len(lines) - 1, -1, -1):
830 line = lines[index]
831 if line.find('Detailed Description') != -1:
832 bInDetail = False
833 if line.startswith('EBC context buffer used by') and lines[index - 1].startswith('x64 context buffer'):
834 lines[index] = "IA32/IPF/X64/" + line
835 bNeedRemove = True
836 if line.startswith("x64 context buffer") or line.startswith('IPF context buffer used by') or \
837 line.startswith('IA32 context buffer used by'):
838 if bNeedRemove:
839 lines.remove(line)
840 if line.find('>R0</a>') != -1 and not bInDetail:
841 if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>':
842 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>')
843 if line.find('>Rbx</a>') != -1 and not bInDetail:
844 if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>':
845 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>')
846 if line.find('>F2</a>') != -1 and not bInDetail:
847 if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>':
848 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>')
849 if line.find('>Ebx</a>') != -1 and not bInDetail:
850 if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>':
851 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>')
852 try:
853 f = open(path, 'w')
854 f.write('\n'.join(lines))
855 f.close()
856 except:
857 self._isBusy = False
858 self.LogMessage(" <<< Fail to fixup file %s" % path)
859 self.LogMessage(" <<< Finish to fixup file %s\n" % path)
860
861 def FixPageUefiDriverEntryPoint(self, path, text):
862 self.LogMessage(' >>> Fixup file reference MdePkg/Include/Library/UefiDriverEntryPoint.h at file %s \n' % path)
863 lines = text.split('\n')
864 bInModuleEntry = False
865 bInEfiMain = False
866 ModuleEntryDlCount = 0
867 ModuleEntryDelStart = 0
868 ModuleEntryDelEnd = 0
869 EfiMainDlCount = 0
870 EfiMainDelStart = 0
871 EfiMainDelEnd = 0
872
873 for index in range(len(lines)):
874 line = lines[index].strip()
875 if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint </td>') != -1:
876 bInModuleEntry = True
877 if line.find('EFI_STATUS</a> EFIAPI EfiMain </td>') != -1:
878 bInEfiMain = True
879 if line.startswith('<p>References <a'):
880 if bInModuleEntry:
881 ModuleEntryDelEnd = index - 1
882 bInModuleEntry = False
883 elif bInEfiMain:
884 EfiMainDelEnd = index - 1
885 bInEfiMain = False
886 if bInModuleEntry:
887 if line.startswith('</dl>'):
888 ModuleEntryDlCount = ModuleEntryDlCount + 1
889 if ModuleEntryDlCount == 1:
890 ModuleEntryDelStart = index + 1
891 if bInEfiMain:
892 if line.startswith('</dl>'):
893 EfiMainDlCount = EfiMainDlCount + 1
894 if EfiMainDlCount == 1:
895 EfiMainDelStart = index + 1
896
897 if EfiMainDelEnd > EfiMainDelStart:
898 for index in range(EfiMainDelEnd, EfiMainDelStart, -1):
899 del lines[index]
900 if ModuleEntryDelEnd > ModuleEntryDelStart:
901 for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1):
902 del lines[index]
903
904 try:
905 f = open(path, 'w')
906 f.write('\n'.join(lines))
907 f.close()
908 except:
909 self._isBusy = False
910 self.LogMessage(" <<< Fail to fixup file %s" % path)
911 self.LogMessage(" <<< Finish to fixup file %s\n" % path)
912
913 def FixPageUefiApplicationEntryPoint(self, path, text):
914 self.LogMessage(' >>> Fixup file reference MdePkg/Include/Library/UefiApplicationEntryPoint.h at file %s \n' % path)
915 lines = text.split('\n')
916 bInModuleEntry = False
917 bInEfiMain = False
918 ModuleEntryDlCount = 0
919 ModuleEntryDelStart = 0
920 ModuleEntryDelEnd = 0
921 EfiMainDlCount = 0
922 EfiMainDelStart = 0
923 EfiMainDelEnd = 0
924
925 for index in range(len(lines)):
926 line = lines[index].strip()
927 if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint </td>') != -1:
928 bInModuleEntry = True
929 if line.find('EFI_STATUS</a> EFIAPI EfiMain </td>') != -1:
930 bInEfiMain = True
931 if line.startswith('<p>References <a'):
932 if bInModuleEntry:
933 ModuleEntryDelEnd = index - 1
934 bInModuleEntry = False
935 elif bInEfiMain:
936 EfiMainDelEnd = index - 1
937 bInEfiMain = False
938 if bInModuleEntry:
939 if line.startswith('</dl>'):
940 ModuleEntryDlCount = ModuleEntryDlCount + 1
941 if ModuleEntryDlCount == 1:
942 ModuleEntryDelStart = index + 1
943 if bInEfiMain:
944 if line.startswith('</dl>'):
945 EfiMainDlCount = EfiMainDlCount + 1
946 if EfiMainDlCount == 1:
947 EfiMainDelStart = index + 1
948
949 if EfiMainDelEnd > EfiMainDelStart:
950 for index in range(EfiMainDelEnd, EfiMainDelStart, -1):
951 del lines[index]
952 if ModuleEntryDelEnd > ModuleEntryDelStart:
953 for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1):
954 del lines[index]
955
956 try:
957 f = open(path, 'w')
958 f.write('\n'.join(lines))
959 f.close()
960 except:
961 self._isBusy = False
962 self.LogMessage(" <<< Fail to fixup file %s" % path)
963 self.LogMessage(" <<< Finish to fixup file %s\n" % path)
964
965
966 def FixDoxFileLink(self, path, text):
967 self.LogMessage(' >>> Fixup .dox postfix for file %s \n' % path)
968 try:
969 fd = open(path, 'r')
970 text = fd.read()
971 fd.close()
972 except Exception, e:
973 self.LogMessage (" <<<Fail to open file %s" % path)
974 return
975 text = text.replace ('.s.dox', '.s')
976 text = text.replace ('.S.dox', '.S')
977 text = text.replace ('.asm.dox', '.asm')
978 text = text.replace ('.Asm.dox', '.Asm')
979 text = text.replace ('.uni.dox', '.uni')
980 text = text.replace ('.Uni.dox', '.Uni')
981 try:
982 fd = open(path, 'w')
983 fd.write(text)
984 fd.close()
985 except Exception, e:
986 self.LogMessage (" <<<Fail to fixup file %s" % path)
987 return
988 self.LogMessage(' >>> Finish to fixup .dox postfix for file %s \n' % path)
989
990 def FixDecDoxygenFileLink(self, path, text):
991 self.LogMessage(' >>> Fixup .decdoxygen postfix for file %s \n' % path)
992 try:
993 fd = open(path, 'r')
994 lines = fd.readlines()
995 fd.close()
996 except Exception, e:
997 self.LogMessage (" <<<Fail to open file %s" % path)
998 return
999 for line in lines:
1000 if line.find('.decdoxygen') != -1:
1001 lines.remove(line)
1002 break
1003 try:
1004 fd = open(path, 'w')
1005 fd.write("".join(lines))
1006 fd.close()
1007 except Exception, e:
1008 self.LogMessage (" <<<Fail to fixup file %s" % path)
1009 return
1010 self.LogMessage(' >>> Finish to fixup .decdoxygen postfix for file %s \n' % path)
1011
1012import threading
1013class MonitorThread(threading.Thread):
1014 def __init__(self, pipe, callback):
1015 threading.Thread.__init__(self)
1016 self._pipe = pipe
1017 self._callback = callback
1018 self._isCancel = False
1019
1020 def run(self):
1021 while (not self._isCancel):
1022 self._pipe.Peek()
1023 if self._pipe.LastRead() == 0:
1024 break
1025 text = self._pipe.read()
1026 if len(text.strip()) != 0:
1027 wx.GetApp().ForegroundProcess(self._callback, (text,))
1028
1029 def Terminate(self):
1030 self._pipe.flush()
1031 self._isCancel = True
1032
1033class DoxygenProcess(wx.Process):
1034 def OnTerminate(self, id, status):
1035 self._parent.OnTerminateDoxygenProcess()
1036
1037 def SetParent(self, parent):
1038 self._parent = parent
1039
1040class CHMProcess(wx.Process):
1041 def OnTerminate(self, id, status):
1042 self._parent.OnTerminateCHMProcess()
1043
1044 def SetParent(self, parent):
1045 self._parent = parent
1046
1047class ResultHandler:
1048 def __init__(self, parent):
1049 self._parent = parent
1050 self.level = 0
1051
1052 def emit(self, record):
1053 self._parent.LogMessage(record)
1054
1055 def handle(self, record):
1056 wx.PostEvent(self._parent, LogEvent(message=record.getMessage()))
1057
1058 def acquire(self):
1059 pass
1060
1061 def release(self):
1062 pass
1063
1064if __name__ == '__main__':
1065 app = PackageDocApp(redirect=False)
1066 app.MainLoop()
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette