]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Scripts/PackageDocumentTools/packagedocapp.pyw
BaseTools: Use absolute import in Scripts
[mirror_edk2.git] / BaseTools / Scripts / PackageDocumentTools / packagedocapp.pyw
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
16 import os, sys, wx, logging
17
18 import wx.stc
19 import wx.lib.newevent
20 import wx.lib.agw.genericmessagedialog as GMD
21 import plugins.EdkPlugins.edk2.model.baseobject as baseobject
22 import plugins.EdkPlugins.edk2.model.doxygengen as doxygengen
23
24 if hasattr(sys, "frozen"):
25 appPath = os.path.abspath(os.path.dirname(sys.executable))
26 else:
27 appPath = os.path.abspath(os.path.dirname(__file__))
28
29 AppCallBackEvent, EVT_APP_CALLBACK = wx.lib.newevent.NewEvent()
30 LogEvent, EVT_LOG = wx.lib.newevent.NewEvent()
31
32 class 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
61 class 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\
314 and 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
384 class 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
1012 import threading
1013 class 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
1033 class DoxygenProcess(wx.Process):
1034 def OnTerminate(self, id, status):
1035 self._parent.OnTerminateDoxygenProcess()
1036
1037 def SetParent(self, parent):
1038 self._parent = parent
1039
1040 class CHMProcess(wx.Process):
1041 def OnTerminate(self, id, status):
1042 self._parent.OnTerminateCHMProcess()
1043
1044 def SetParent(self, parent):
1045 self._parent = parent
1046
1047 class 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
1064 if __name__ == '__main__':
1065 app = PackageDocApp(redirect=False)
1066 app.MainLoop()