ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/MitAna/Utils/src/TDocDirective.cxx
Revision: 1.1
Committed: Tue Aug 11 23:09:28 2009 UTC (15 years, 8 months ago) by loizides
Content type: text/plain
Branch: MAIN
CVS Tags: Mit_032, Mit_031, Mit_025c_branch2, Mit_025c_branch1, Mit_030, Mit_029c, Mit_029b, Mit_030_pre1, Mit_029a, Mit_029, Mit_029_pre1, Mit_028a, Mit_025c_branch0, Mit_028, Mit_027a, Mit_027, Mit_026, Mit_025e, Mit_025d, Mit_025c, Mit_025b, Mit_025a, Mit_025, Mit_025pre2, Mit_024b, Mit_025pre1, Mit_024a, Mit_024, Mit_023, Mit_022a, Mit_022, Mit_020d, TMit_020d, Mit_020c, Mit_021, Mit_021pre2, Mit_021pre1, Mit_020b, Mit_020a, Mit_020, Mit_020pre1, Mit_018, Mit_017, Mit_017pre3, Mit_017pre2, Mit_017pre1, Mit_016, Mit_015b, Mit_015a, Mit_015, Mit_014e, Mit_014d, Mit_014c, Mit_014b, Mit_014a, Mit_014, Mit_014pre3, Mit_014pre2, Mit_014pre1, Mit_013d, Mit_013c, Mit_013b, Mit_013a, Mit_013, Mit_013pre1, Mit_012i, Mit_012h, Mit_012g, Mit_012f, Mit_012e, Mit_012d, Mit_012c, Mit_012b, Mit_012a, Mit_012, Mit_011a, Mit_011, Mit_010a, HEAD
Branch point for: Mit_025c_branch
Log Message:
Added THtml from ROOT

File Contents

# User Rev Content
1 loizides 1.1 #include "MitAna/Utils/interface/TDocDirective.h"
2    
3     #include "TApplication.h"
4     #include "TClass.h"
5     #include "MitAna/Utils/interface/TDocInfo.h"
6     #include "MitAna/Utils/interface/TDocOutput.h"
7     #include "MitAna/Utils/interface/TDocParser.h"
8     #include "MitAna/Utils/interface/THtml.h"
9     #include "TInterpreter.h"
10     #include "TLatex.h"
11     #include "TMacro.h"
12     #include "TObjString.h"
13     #include "TPRegexp.h"
14     #include "TROOT.h"
15     #include "TStyle.h"
16     #include "TSystem.h"
17     #include "TVirtualPad.h"
18     #include "TVirtualMutex.h"
19     #include <fstream>
20     #include <sstream>
21     #include <stdlib.h>
22    
23     //______________________________________________________________________________
24     //
25     // When THtml parses documentation (through TDocParser), it checks for special
26     // words ("begin_something", "end_something", where the begin and end are the
27     // significant part). THtml then searches for a TDocDirective which can handle
28     // these tags ("whatever" in the example), passes the text enclosed by these
29     // tags to the directive, which in turn processes it.
30     //
31     // That way, HTML, latex, and C++ macros can be processed by THtml, e.g. to
32     // generate plain HTML or GIF pictures. The classes reposinsible for parsing
33     // that are TDocHtmlDirective, TDocLatexDirective, and TDocMacroDirective,
34     // respecively.
35     //
36     // Directives can have optional parameters; these are passed as paranthesis
37     // enclosed, comma delimited name=value pairs; see SetParameters().
38     //
39     // You can implement your own directive simply by deriving from TDocDirective;
40     // the tag corresponds to TDocDirective's name (e.g. "HTML" for "begin_html" /
41     // "end_html").
42     //______________________________________________________________________________
43    
44     ClassImp(TDocDirective)
45    
46     //______________________________________________________________________________
47     void TDocDirective::DeleteOutputFiles(const char* ext) const
48     {
49     // Delete all output generated by the directive beginning
50     // with Name() and ending with ext
51     TString basename;
52     GetName(basename);
53     basename += "_";
54     TString dirname(GetOutputDir());
55     void* hDir = gSystem->OpenDirectory(dirname);
56     const char* entry = 0;
57     while ((entry = gSystem->GetDirEntry(hDir))) {
58     TString sEntry(entry);
59     if (sEntry.BeginsWith(basename) && isdigit(sEntry[basename.Length()]) && (!ext || sEntry.EndsWith(ext)))
60     gSystem->Unlink((dirname + "/" + entry).Data());
61     }
62     gSystem->FreeDirectory(hDir);
63     }
64    
65     //______________________________________________________________________________
66     void TDocDirective::GetName(TString& name) const
67     {
68     // Get the full name, based on fName, fTitle, fDocParser's tag.
69    
70     name = fName;
71     if (fDocParser && fDocParser->GetCurrentClass()) {
72     name += "_";
73     TString outfilename;
74     GetHtml()->GetHtmlFileName(fDocParser->GetCurrentClass(), outfilename);
75     outfilename = gSystem->BaseName(outfilename);
76     Ssiz_t posExt = outfilename.Last('.');
77     outfilename.Remove(posExt, outfilename.Length() - posExt);
78     name += outfilename;
79     }
80     if (GetTitle() && strlen(GetTitle())) {
81     name += "_";
82     name += GetTitle();
83     }
84     if (fCounter != -1) {
85     name += "_";
86     name += fCounter;
87     }
88     }
89    
90     //______________________________________________________________________________
91     const char* TDocDirective::GetOutputDir() const
92     {
93     // Get the directory for documentation output.
94    
95     return fHtml ? fHtml->GetOutputDir().Data() : 0;
96     }
97    
98     //______________________________________________________________________________
99     void TDocDirective::SetParameters(const char* params)
100     {
101     // Given a string containing parameters in params,
102     // we call AddParameter() for each of them.
103     // This function splits the parameter names and
104     // extracts their values if they are given.
105     // Parameters are separated by ",", values are
106     // separated from parameter names by "=".
107     // params being
108     // a = "a, b, c", b='d,e'
109     // will issue two calls to AddParameter(), one for
110     // a with value "a, b, c" and one for b with value
111     // "d,e" (each without the quotation marks).
112    
113     fParameters = params;
114    
115     if (!fParameters.Length())
116     return;
117    
118     TString param;
119     Ssiz_t pos = 0;
120     while (fParameters.Tokenize(param, pos, ",")) {
121     param = param.Strip(TString::kBoth);
122     if (!param.Length())
123     continue;
124    
125     Ssiz_t posAssign = param.Index('=');
126     if (posAssign != kNPOS) {
127     TString value(param(posAssign + 1, param.Length()));
128     value = value.Strip(TString::kBoth);
129     if (value[0] == '\'')
130     value = value.Strip(TString::kBoth, '\'');
131     else if (value[0] == '"')
132     value = value.Strip(TString::kBoth, '"');
133     param.Remove(posAssign, param.Length());
134     param = param.Strip(TString::kBoth);
135     AddParameter(param, value);
136     } else {
137     param = param.Strip(TString::kBoth);
138     AddParameter(param, 0);
139     }
140     }
141     }
142    
143     //______________________________________________________________________________
144     void TDocDirective::SetParser(TDocParser* parser)
145     {
146     // Set the parser, and fDocOutput, fHtml from that
147     fDocParser = parser;
148     fDocOutput = parser ? parser->GetDocOutput() : 0;
149     fHtml = fDocOutput? fDocOutput->GetHtml() : 0;
150     }
151    
152    
153     //______________________________________________________________________________
154     //
155     // Process a "begin_html" / "end_html" block. Stop linking keywords and simply
156     // copy the text enclosed by the directive to the output HTML file.
157     //______________________________________________________________________________
158    
159     ClassImp(TDocHtmlDirective)
160    
161     //______________________________________________________________________________
162     void TDocHtmlDirective::AddLine(const TSubString& line)
163     {
164     // Add a line of HTML
165    
166     if (line.Start() == -1) return;
167    
168     TPRegexp pretag("</?[pP][rR][eE][ >]");
169     TSubString iLine(line);
170     Ssiz_t posPre = iLine.String().Index(pretag, iLine.Start());
171     if (posPre == kNPOS)
172     fText += line;
173     else {
174     // remove <pre> in fVerbatim environments, and
175     // </pre> in !fVerbatim environments.
176     while (posPre != kNPOS && posPre > 0) {
177     Bool_t isOpen = line[posPre + 1 - line.Start()] != '/';
178     Ssiz_t posClose = iLine.String().Index(">", posPre);
179     if (posClose ==kNPOS) break; // aka oops.
180     Ssiz_t len = posClose - posPre;
181    
182     if (fVerbatim) {
183     if (isOpen) {
184     // skip
185     fText += iLine.String()(iLine.Start(), posPre - iLine.Start());
186     } else {
187     // write it out
188     fText += iLine.String()(iLine.Start(), posPre + len - iLine.Start());
189     fVerbatim = kFALSE;
190     }
191     } else {
192     if (!isOpen) {
193     // skip
194     fText += iLine.String()(iLine.Start(), posPre - iLine.Start());
195     } else {
196     // write it out
197     fText += iLine.String()(iLine.Start(), posPre + len - iLine.Start());
198     fVerbatim = kTRUE;
199     }
200     }
201    
202     iLine = iLine.String()(posPre + len, iLine.Length());
203     posPre = iLine.String().Index(pretag, iLine.Start());
204     }
205    
206     fText += iLine;
207     }
208     fText += "\n";
209     }
210    
211     //______________________________________________________________________________
212     Bool_t TDocHtmlDirective::GetResult(TString& result)
213     {
214     // Set result to the HTML code that was passed in via AddLine().
215     // Prepend a closing </pre>, append an opening <pre>
216    
217     result = "</pre><!-- TDocHtmlDirective start -->";
218     result += fText + "<!-- TDocHtmlDirective end --><pre>";
219     return kTRUE;
220     }
221    
222    
223    
224     //______________________________________________________________________________
225     //
226     // Process a "begin_macro" / "end_macro" block. The block can be a file name
227     // or a CINT script (i.e. even ".x file.C" is allowed). See AddParameter() for
228     // supported options. Example (the quotes prevent THtml from expanding the
229     // example):
230     //
231     // "BEGIN_MACRO"
232     // .x $ROOTSYS/tutorials/hsimple.C
233     // "END_MACRO"
234     //
235     // The macro is meant to create an object that can be saved as a GIF file by
236     // calling object->SaveAs(outputfile.gif). The macro is expected to return that
237     // object as a TObject*; if it does not, gPad is used and saved. The object
238     // is deleted by TDocMacroDirective once saved.
239     //______________________________________________________________________________
240    
241     ClassImp(TDocMacroDirective)
242    
243     //______________________________________________________________________________
244     TDocMacroDirective::~TDocMacroDirective()
245     {
246     // Destructor
247     delete fMacro;
248     }
249    
250     //______________________________________________________________________________
251     void TDocMacroDirective::AddLine(const TSubString& line)
252     {
253     // Add a macro line.
254     // Lines ending on "*HIDE*" will be executed as part of the
255     // macro, but not shown in the source tab if the parameter
256     // source is supplied.
257    
258     if (!fMacro) {
259     TString name;
260     GetName(name);
261     fMacro = new TMacro(name);
262     }
263    
264     // return if no line - or if there was an intentinal line-break,
265     // i.e. an empty line
266     if (line.Start() == -1 && const_cast<TSubString&>(line).String().Length()) return;
267    
268     TString sLine(line);
269     fMacro->AddLine(sLine);
270     fIsFilename &= !sLine.Contains('{');
271     }
272     //______________________________________________________________________________
273     Bool_t TDocMacroDirective::GetResult(TString& result)
274     {
275     // Get the result (i.e. an HTML img tag) for the macro invocation.
276     // If fShowSource is set, a second tab will be created which shows
277     // the source.
278    
279     if (!fMacro)
280     return kFALSE;
281    
282     if (!fMacro->GetListOfLines()
283     || !fMacro->GetListOfLines()->First()) {
284     Warning("GetResult", "Empty directive found!");
285     return kTRUE;
286     }
287    
288     R__LOCKGUARD(GetHtml()->GetMakeClassMutex());
289    
290     if (gDebug > 3)
291     Info("HandleDirective_Macro", "executing macro \"%s\" with %d lines.",
292     fMacro->GetName(), fMacro->GetListOfLines() ? fMacro->GetListOfLines()->GetEntries() + 1 : 0);
293    
294     Bool_t wasBatch = gROOT->IsBatch();
295     if (!wasBatch && !fNeedGraphics)
296     gROOT->SetBatch();
297     else if (fNeedGraphics) {
298     if (fHtml->IsBatch()) {
299     Warning("GetResult()", "Will not initialize the graphics system; skipping macro %s!", GetName());
300     result = "";
301     return kFALSE;
302     }
303     gROOT->SetBatch(0);
304     TApplication::NeedGraphicsLibs();
305     gApplication->InitializeGraphics();
306     if (gROOT->IsBatch()) {
307     Warning("GetResult()", "Cannot initialize the graphics system; skipping macro %s!", GetName());
308     result = "";
309     return kFALSE;
310     }
311     }
312    
313     TVirtualPad* padSave = gPad;
314    
315     Int_t error = TInterpreter::kNoError;
316     Long_t ret = 0;
317     if (fIsFilename) {
318     TString filename;
319     TIter iLine(fMacro->GetListOfLines());
320     while (filename.Length() == 0)
321     filename = ((TObjString*)iLine())->String().Strip(TString::kBoth);
322    
323     TString macroPath;
324     TString modulename;
325     if (GetHtml() && GetDocParser()) {
326     if (GetDocParser()->GetCurrentClass())
327     GetHtml()->GetModuleNameForClass(modulename, GetDocParser()->GetCurrentClass());
328     else GetDocParser()->GetCurrentModule(modulename);
329     }
330     if (modulename.Length()) {
331     GetHtml()->GetModuleMacroPath(modulename, macroPath);
332     } else macroPath = gSystem->pwd();
333    
334     const char* pathDelimiter = ":"; // use ":" even on windows
335     TObjArray* arrDirs(macroPath.Tokenize(pathDelimiter));
336     TIter iDir(arrDirs);
337     TObjString* osDir = 0;
338     macroPath = "";
339     TString filenameDirPart(gSystem->DirName(filename));
340     filenameDirPart.Prepend('/'); // as dir delimiter, not as root dir
341     while ((osDir = (TObjString*)iDir())) {
342     if (osDir->String().EndsWith("\\"))
343     osDir->String().Remove(osDir->String().Length() - 1);
344     osDir->String() += filenameDirPart;
345     macroPath += osDir->String() + pathDelimiter;
346     }
347    
348     TString plusplus;
349     while (filename.EndsWith("+")) {
350     plusplus += '+';
351     filename.Remove(filename.Length() - 1);
352     }
353    
354     TString params;
355     if (filename.EndsWith(")")) {
356     Ssiz_t posOpen = filename.Last('(');
357     if (posOpen != kNPOS) {
358     params = filename(posOpen, filename.Length());
359     filename.Remove(posOpen, filename.Length());
360     }
361     }
362    
363     TString fileSysName(gSystem->BaseName(filename));
364     if (!gSystem->FindFile(macroPath, fileSysName)) {
365     Error("GetResult", "Cannot find macro '%s' in path '%s'!",
366     gSystem->BaseName(filename), macroPath.Data());
367     result = "";
368     return kFALSE;
369     }
370    
371     if (fShowSource) {
372     // copy macro into fMacro - before running it, in case the macro blocks its file
373     std::ifstream ifMacro(fileSysName);
374     fMacro->GetListOfLines()->Delete();
375     TString line;
376     while (ifMacro) {
377     if (!line.ReadLine(ifMacro, kFALSE) || ifMacro.eof())
378     break;
379     fMacro->AddLine(line);
380     }
381     }
382    
383     fileSysName.Prepend(".x ");
384     fileSysName += params;
385     fileSysName += plusplus;
386     gInterpreter->SaveContext();
387     gInterpreter->SaveGlobalsContext();
388     ret = gROOT->ProcessLine(fileSysName, &error);
389     } else {
390     gInterpreter->SaveContext();
391     gInterpreter->SaveGlobalsContext();
392     ret = fMacro->Exec(0, &error);
393     }
394    
395     if (fShowSource) {
396     // convert the macro source
397     TIter iLine(fMacro->GetListOfLines());
398     TObjString* osLine = 0;
399     std::stringstream ssRaw;
400     while ((osLine = (TObjString*)iLine()))
401     ssRaw << osLine->String() << std::endl;
402    
403     TDocParser *dparser = 0;
404     if (GetDocParser()->GetCurrentClass())
405     dparser = new TDocParser(*(TClassDocOutput*)GetDocOutput(), GetDocParser()->GetCurrentClass());
406     else dparser = new TDocParser(*GetDocOutput());
407     std::stringstream ssConverted;
408     dparser->Convert(ssConverted, ssRaw, "./", kFALSE /*no code*/);
409     delete dparser;
410    
411     fMacro->GetListOfLines()->Delete();
412     TString line;
413     while (!ssConverted.fail()) {
414     if (!line.ReadLine(ssConverted, kFALSE) || ssConverted.eof())
415     break;
416     fMacro->AddLine(line);
417     }
418     }
419    
420     Int_t sleepCycles = 50; // 50 = 5 seconds
421     while (error == TInterpreter::kProcessing && --sleepCycles > 0)
422     gSystem->Sleep(100);
423    
424     gSystem->ProcessEvents(); // in case ret needs to handle some events first
425    
426     if (error != TInterpreter::kNoError)
427     Error("HandleDirective_Macro", "Error processing macro %s!", fMacro->GetName());
428     else if (ret) {
429     const TObject* objRet = (const TObject*)ret;
430     try {
431     typeid(*objRet).name(); // needed to test whether ret is indeed an object with a vtable!
432     objRet = dynamic_cast<const TObject*>(objRet);
433     }
434     catch (...) {
435     objRet = 0;
436     }
437     if (objRet) {
438     TString filename;
439     GetName(filename);
440    
441     if (objRet->GetName() && strlen(objRet->GetName())) {
442     filename += "_";
443     filename += objRet->GetName();
444     }
445     filename.ReplaceAll(" ", "_");
446    
447     result = "<span class=\"macro\"><img class=\"macro\" alt=\"output of ";
448     result += filename;
449    
450     GetDocOutput()->NameSpace2FileName(filename);
451     TString id(filename);
452     filename += ".gif";
453     TString basename(filename);
454    
455     result += "\" title=\"MACRO\" src=\"";
456     result += basename;
457     result += "\" /></span>";
458    
459     gSystem->PrependPathName(GetOutputDir(), filename);
460    
461     if (gDebug > 3)
462     Info("HandleDirective_Macro", "Saving returned %s to file %s.",
463     objRet->IsA()->GetName(), filename.Data());
464    
465     if (fNeedGraphics) {
466     // to get X11 to sync :-( gVirtualX->Update()/Sync() don't do it
467     gSystem->Sleep(1000);
468     gVirtualX->Update(0);
469     gVirtualX->Update(1);
470     }
471    
472     gSystem->ProcessEvents();
473     if (fNeedGraphics) {
474     gVirtualX->Update(0);
475     gVirtualX->Update(1);
476     }
477    
478     objRet->SaveAs(filename);
479     gSystem->ProcessEvents(); // SaveAs triggers an event
480    
481     // ensure objRet is not e.g. the TGMainFrame of a new TCanvas: require padSave == gPad
482     if (objRet != gPad && padSave == gPad)
483     delete objRet;
484    
485     if (fShowSource) {
486     // TODO: we need an accessible version of the source, i.e. visible w/o javascript
487     TString tags("</pre><div class=\"tabs\">\n"
488     "<a id=\"" + id + "_A0\" class=\"tabsel\" href=\"" + basename + "\" onclick=\"javascript:return SetDiv('" + id + "',0);\">Picture</a>\n"
489     "<a id=\"" + id + "_A1\" class=\"tab\" href=\"#\" onclick=\"javascript:return SetDiv('" + id + "',1);\">Source</a>\n"
490     "<br /></div><div class=\"tabcontent\">\n"
491     "<div id=\"" + id + "_0\" class=\"tabvisible\">" + result + "</div>\n"
492     "<div id=\"" + id + "_1\" class=\"tabhidden\"><div class=\"code\"><pre class=\"code\">");
493     TIter iLine(fMacro->GetListOfLines());
494     TObjString* osLine = 0;
495     while ((osLine = (TObjString*) iLine()))
496     if (!TString(osLine->String().Strip()).EndsWith("*HIDE*"))
497     tags += osLine->String() + "\n";
498     if (tags.EndsWith("\n"))
499     tags.Remove(tags.Length()-1); // trailing line break
500     tags += "</pre></div></div><div class=\"clear\"></div></div><pre>";
501     result = tags;
502     }
503     }
504     }
505    
506     // Remove interpreter vars first, so we can check whether we need to delete
507     // gPad ourselves or whether it was a global var in the interpreter.
508     gInterpreter->ResetGlobals();
509     gInterpreter->Reset();
510    
511     if (!wasBatch)
512     gROOT->SetBatch(kFALSE);
513     if (padSave != gPad) {
514     delete gPad;
515     gPad = padSave;
516     }
517    
518     // in case ret's or gPad's deletion provoke events that should be handled
519     gSystem->ProcessEvents();
520    
521     return kTRUE;
522     }
523    
524     //______________________________________________________________________________
525     void TDocMacroDirective::AddParameter(const TString& name, const char* /*value=0*/)
526     {
527     // Setting fNeedGraphics if name is "GUI",
528     // setting fShowSource if name is "SOURCE"
529    
530     if (!name.CompareTo("gui", TString::kIgnoreCase))
531     fNeedGraphics = kTRUE;
532     else if (!name.CompareTo("source", TString::kIgnoreCase))
533     fShowSource = kTRUE;
534     else Warning("AddParameter", "Unknown option %s!", name.Data());
535     }
536    
537    
538    
539     namespace {
540     Float_t gLinePadding = 10.; //px
541     Float_t gColumnPadding = 10.; //px
542    
543     class TLatexLine {
544     private:
545     std::vector<Float_t> fWidths;
546     Float_t fHeight;
547     TObjArray* fColumns; // of TObjString*
548    
549     public:
550     TLatexLine(TObjArray* columns = 0):
551     fHeight(0.), fColumns(columns) { if (columns) fWidths.resize(Size());}
552    
553     Float_t& Width(UInt_t col) {return fWidths[col];}
554     Float_t& Height() {return fHeight;}
555     TString* operator[](Int_t column) {
556     if (fColumns && fColumns->GetEntriesFast() > column)
557     return &(((TObjString*)fColumns->At(column))->String());
558     return 0;
559     }
560     UInt_t Size() const { return fColumns ? fColumns->GetEntries() : 0; }
561     void Delete() { delete fColumns; }
562     };
563     }
564    
565     //______________________________________________________________________________
566     //
567     // Handle a "Begin_Latex"/"End_Latex" directive.
568     // called as
569     // "Begin_Latex(fontsize=10, separator='=,', rseparator='=|,', align=lcl)"
570     // will create and include a TLatex-processed image, with a given fontsize
571     // in pixels (defaults to 16). If (r)separator is given, the formulas on the
572     // following lines will be grouped into columns; a new column starts with
573     // (regexp) match of the separator; by default there is only one column.
574     // separator matches any character, rseparator matches as regexp with one
575     // column per pattern match. Only one of separator or rseparator can be given.
576     // align defines the alignment for each columns; be default, all columns
577     // are right aligned. NOTE that the column separator counts as a column itself!
578     //______________________________________________________________________________
579    
580    
581     ClassImp(TDocLatexDirective)
582    
583     //______________________________________________________________________________
584     TDocLatexDirective::~TDocLatexDirective()
585     {
586     // Destructor
587     gSystem->ProcessEvents();
588     delete fLatex;
589     delete fBBCanvas;
590     gSystem->ProcessEvents();
591     }
592    
593     //______________________________________________________________________________
594     void TDocLatexDirective::AddLine(const TSubString& line)
595     {
596     // Add a latex line
597    
598     if (line.Length() == 0)
599     return;
600    
601     if (!fLatex) {
602     TString name;
603     GetName(name);
604     fLatex = new TMacro(name);
605     }
606    
607     TString sLine(line);
608     GetDocParser()->Strip(sLine);
609     if (sLine.Length() == 0)
610     return;
611    
612     fLatex->AddLine(sLine);
613     }
614    
615     //______________________________________________________________________________
616     void TDocLatexDirective::CreateLatex(const char* filename)
617     {
618     // Create a gif file named filename from a latex expression in fLatex.
619     // Called when "Begin_Latex"/"End_Latex" is processed.
620    
621     if (!fLatex
622     || !fLatex->GetListOfLines()
623     || !fLatex->GetListOfLines()->First())
624     return;
625    
626     R__LOCKGUARD(GetHtml()->GetMakeClassMutex());
627    
628     TVirtualPad* oldPad = gPad;
629    
630     Bool_t wasBatch = gROOT->IsBatch();
631     if (!wasBatch)
632     gROOT->SetBatch();
633    
634     const Float_t canvSize = 1200.;
635     if (!fBBCanvas)
636     // add magic batch vs. gui canvas sizes (4, 28)
637     fBBCanvas = (TVirtualPad*)gROOT->ProcessLineFast(
638     Form("new TCanvas(\"R__TDocLatexDirective_BBCanvas\",\"fBBCanvas\",%g,%g);", -(canvSize + 4.), canvSize + 28.));
639     fBBCanvas->SetBorderMode(0);
640     fBBCanvas->SetFillColor(kWhite);
641    
642     gSystem->ProcessEvents();
643    
644     std::list<TLatexLine> latexLines;
645     std::vector<Float_t> maxWidth(20);
646     UInt_t numColumns = 0;
647     Float_t totalHeight = gLinePadding;
648    
649     TLatex latex;
650     latex.SetTextFont(43);
651     latex.SetTextSize((Float_t)fFontSize);
652     latex.SetTextAlign(12);
653    
654     // calculate positions
655     TIter iterLine(fLatex->GetListOfLines());
656     TObjString* line = 0;
657     TPRegexp regexp;
658     if (fSeparator.Length()) {
659     if (fSepIsRegexp)
660     regexp = TPRegexp(fSeparator);
661     } else fSepIsRegexp = kFALSE;
662    
663     while ((line = (TObjString*) iterLine())) {
664     const TString& str = line->String();
665     TObjArray* split = 0;
666     if (!fSepIsRegexp) {
667     split = new TObjArray();
668     split->SetOwner();
669     }
670     if (!fSeparator.Length())
671     split->Add(new TObjString(str));
672     else {
673     if (fSepIsRegexp)
674     split = regexp.MatchS(str);
675     else {
676     Ssiz_t prevStart = 0;
677     for (Ssiz_t pos = 0; pos < str.Length(); ++pos) {
678     if (fSeparator.Index(str[pos]) != kNPOS) {
679     split->Add(new TObjString(TString(str(prevStart, pos - prevStart))));
680     split->Add(new TObjString(TString(str(pos, 1))));
681     prevStart = pos + 1;
682     }
683     }
684     split->Add(new TObjString(TString(str(prevStart, str.Length() - prevStart))));
685     }
686     }
687    
688     latexLines.push_back(TLatexLine(split));
689     if (numColumns < (UInt_t)split->GetEntries())
690     numColumns = split->GetEntries();
691    
692     Float_t heightLine = -1.;
693     for (UInt_t col = 0; col < (UInt_t)split->GetEntries(); ++col) {
694     Float_t widthLatex = 0.;
695     Float_t heightLatex = 0.;
696     TString* strCol = latexLines.back()[col];
697     if (strCol)
698     GetBoundingBox(latex, *strCol, widthLatex, heightLatex);
699     if (heightLine < heightLatex) heightLine = heightLatex;
700     if (maxWidth.size() < col)
701     maxWidth.resize(col * 2);
702     if (maxWidth[col] < widthLatex)
703     maxWidth[col] = widthLatex;
704     latexLines.back().Width(col) = widthLatex;
705     }
706     latexLines.back().Height() = heightLine;
707     totalHeight += heightLine + gLinePadding;
708     } // while next line
709    
710     std::vector<Float_t> posX(numColumns + 1);
711     for (UInt_t col = 0; col <= numColumns; ++col) {
712     if (col == 0) posX[col] = gColumnPadding;
713     else posX[col] = posX[col - 1] + maxWidth[col - 1] + gColumnPadding;
714     }
715     Float_t totalWidth = posX[numColumns];
716    
717     // draw
718     fBBCanvas->Clear();
719     fBBCanvas->cd();
720     Float_t padSizeX = totalWidth;
721     Float_t padSizeY = totalHeight + 8.;
722     // add magic batch vs. gui canvas sizes (4, 28) + rounding
723     TVirtualPad* padImg = (TVirtualPad*)gROOT->ProcessLineFast(
724     Form("new TCanvas(\"R__TDocLatexDirective_padImg\",\"padImg\",-(Int_t)%g,(Int_t)%g);",
725     padSizeX + 4.5, padSizeY + 28.5));
726     padImg->SetBorderMode(0);
727     padImg->SetFillColor(kWhite);
728     padImg->cd();
729    
730     Float_t posY = 0.;
731     for (std::list<TLatexLine>::iterator iLine = latexLines.begin();
732     iLine != latexLines.end(); ++iLine) {
733     posY += iLine->Height()/2. + gLinePadding;
734     for (UInt_t iCol = 0; iCol < iLine->Size(); ++iCol) {
735     TString* str = (*iLine)[iCol];
736     if (!str) continue;
737     char align = 'l';
738     if ((UInt_t)fAlignment.Length() > iCol)
739     align = fAlignment[(Int_t)iCol];
740     Float_t x = posX[iCol];
741     switch (align) {
742     case 'l': break;
743     case 'r': x += maxWidth[iCol] - iLine->Width(iCol); break;
744     case 'c': x += 0.5*(maxWidth[iCol] - iLine->Width(iCol)); break;
745     default:
746     if (iLine == latexLines.begin())
747     Error("CreateLatex", "Invalid alignment character '%c'!", align);
748     }
749     latex.DrawLatex( x / padSizeX, 1. - posY / padSizeY, str->Data());
750     }
751     posY += iLine->Height()/2.;
752     }
753    
754     padImg->Print(filename);
755    
756     // delete the latex objects
757     for (std::list<TLatexLine>::iterator iLine = latexLines.begin();
758     iLine != latexLines.end(); ++iLine) {
759     iLine->Delete();
760     }
761    
762     delete padImg;
763    
764     if (!wasBatch)
765     gROOT->SetBatch(kFALSE);
766    
767     gPad = oldPad;
768     }
769    
770     //______________________________________________________________________________
771     void TDocLatexDirective::GetBoundingBox(TLatex& latex, const char* text, Float_t& width, Float_t& height)
772     {
773     // Determines the bounding box for text as height and width.
774     // Assumes that we are in batch mode.
775    
776     UInt_t uiWidth = 0;
777     UInt_t uiHeight = 0;
778     fBBCanvas->cd();
779     latex.SetText(0.1, 0.5, text);
780     latex.GetBoundingBox(uiWidth, uiHeight);
781    
782     width = uiWidth;
783     height = uiHeight;
784     }
785    
786     //______________________________________________________________________________
787     TList* TDocLatexDirective::GetListOfLines() const
788     {
789     // Get the list of lines as TObjStrings
790     return fLatex ? fLatex->GetListOfLines() : 0;
791     }
792    
793     //______________________________________________________________________________
794     Bool_t TDocLatexDirective::GetResult(TString& result)
795     {
796     // convert fLatex to a gif by creating a TLatex, drawing it on a
797     // temporary canvas, and saving that to a filename in the output
798     // directory.
799    
800     TString filename;
801     GetName(filename);
802     filename.ReplaceAll(" ", "_");
803     const TString& firstLine = ((TObjString*)fLatex->GetListOfLines()->First())->String();
804     TString latexFilename(firstLine);
805     for (Ssiz_t namepos = 0; namepos < latexFilename.Length(); ++namepos)
806     if (!GetDocParser()->IsWord(latexFilename[namepos])) {
807     latexFilename.Remove(namepos, 1);
808     --namepos;
809     }
810     filename += "_";
811     filename += latexFilename;
812    
813     GetDocOutput()->NameSpace2FileName(filename);
814     filename += ".gif";
815    
816     TString altText(firstLine);
817     GetDocOutput()->ReplaceSpecialChars(altText);
818     altText.ReplaceAll("\"", "&quot;");
819     result = "<span class=\"latex\"><img class=\"latex\" alt=\"";
820     result += altText;
821     result += "\" title=\"LATEX\" src=\"";
822     result += filename;
823     result += "\" /></span>";
824    
825     gSystem->PrependPathName(GetOutputDir(), filename);
826    
827     if (gDebug > 3)
828     Info("HandleDirective_Latex", "Writing Latex \"%s\" to file %s.",
829     fLatex->GetName(), filename.Data());
830    
831     CreateLatex(filename);
832    
833     return kTRUE;
834     }
835    
836     //______________________________________________________________________________
837     void TDocLatexDirective::AddParameter(const TString& name, const char* value /*=0*/)
838     {
839     // Parse fParameters, setting fFontSize, fAlignment, and fSeparator
840    
841     if (!name.CompareTo("fontsize", TString::kIgnoreCase)) {
842     if (!value || !strlen(value))
843     Error("AddParameter", "Option \"fontsize\" needs a value!");
844     else fFontSize = atol(value);
845     } else if (!name.CompareTo("separator", TString::kIgnoreCase)) {
846     if (!value || !strlen(value))
847     Error("AddParameter", "Option \"separator\" needs a value!");
848     else fSeparator = value;
849     } else if (!name.CompareTo("align", TString::kIgnoreCase)) {
850     if (!value || !strlen(value))
851     Error("AddParameter", "Option \"align\" needs a value!");
852     else fAlignment = value;
853     } else
854     Warning("AddParameter", "Unknown option %s!", name.Data());
855     }