TDocDirective.cxx

Go to the documentation of this file.
00001 #include "TDocDirective.h"
00002 
00003 #include "TApplication.h"
00004 #include "TClass.h"
00005 #include "TDocInfo.h"
00006 #include "TDocOutput.h"
00007 #include "TDocParser.h"
00008 #include "THtml.h"
00009 #include "TInterpreter.h"
00010 #include "TLatex.h"
00011 #include "TMacro.h"
00012 #include "TObjString.h"
00013 #include "TPRegexp.h"
00014 #include "TROOT.h"
00015 #include "TStyle.h"
00016 #include "TSystem.h"
00017 #include "TVirtualPad.h"
00018 #include "TVirtualMutex.h"
00019 #include <typeinfo>
00020 #include <fstream>
00021 #include <sstream>
00022 #include <stdlib.h>
00023 
00024 //______________________________________________________________________________
00025 //
00026 // When THtml parses documentation (through TDocParser), it checks for special
00027 // words ("begin_something", "end_something", where the begin and end are the
00028 // significant part). THtml then searches for a TDocDirective which can handle
00029 // these tags ("whatever" in the example), passes the text enclosed by these
00030 // tags to the directive, which in turn processes it.
00031 //
00032 // That way, HTML, latex, and C++ macros can be processed by THtml, e.g. to
00033 // generate plain HTML or GIF pictures. The classes reposinsible for parsing
00034 // that are TDocHtmlDirective, TDocLatexDirective, and TDocMacroDirective,
00035 // respecively.
00036 //
00037 // Directives can have optional parameters; these are passed as paranthesis
00038 // enclosed, comma delimited name=value pairs; see SetParameters().
00039 //
00040 // You can implement your own directive simply by deriving from TDocDirective;
00041 // the tag corresponds to TDocDirective's name (e.g. "HTML" for "begin_html" /
00042 // "end_html").
00043 //______________________________________________________________________________
00044 
00045 ClassImp(TDocDirective);
00046 
00047 //______________________________________________________________________________
00048 void TDocDirective::DeleteOutputFiles(const char* ext) const
00049 {
00050    // Delete all output generated by the directive beginning 
00051    // with Name() and ending with ext
00052    TString basename;
00053    GetName(basename);
00054    basename += "_";
00055    TString dirname(GetOutputDir());
00056    void* hDir = gSystem->OpenDirectory(dirname);
00057    const char* entry = 0;
00058    while ((entry = gSystem->GetDirEntry(hDir))) {
00059       TString sEntry(entry);
00060       if (sEntry.BeginsWith(basename) && isdigit(sEntry[basename.Length()]) && (!ext || sEntry.EndsWith(ext)))
00061          gSystem->Unlink((dirname + "/" + entry).Data());
00062    }
00063    gSystem->FreeDirectory(hDir);
00064 }
00065 
00066 //______________________________________________________________________________
00067 void TDocDirective::GetName(TString& name) const
00068 {
00069    // Get the full name, based on fName, fTitle, fDocParser's tag.
00070 
00071    name = fName;
00072    if (fDocParser && fDocParser->GetCurrentClass()) {
00073       name += "_";
00074       TString outfilename;
00075       GetHtml()->GetHtmlFileName(fDocParser->GetCurrentClass(), outfilename);
00076       outfilename = gSystem->BaseName(outfilename);
00077       Ssiz_t posExt = outfilename.Last('.');
00078       outfilename.Remove(posExt, outfilename.Length() - posExt);
00079       name += outfilename;
00080    }
00081    if (GetTitle() && strlen(GetTitle())) {
00082       name += "_";
00083       name += GetTitle();
00084    }
00085    if (fCounter != -1) {
00086       name += "_";
00087       name += fCounter;
00088    }
00089 }
00090 
00091 //______________________________________________________________________________
00092 const char* TDocDirective::GetOutputDir() const
00093 {
00094    // Get the directory for documentation output.
00095 
00096    return fHtml ? fHtml->GetOutputDir().Data() : 0;
00097 }
00098 
00099 //______________________________________________________________________________
00100 void TDocDirective::SetParameters(const char* params)
00101 {
00102    // Given a string containing parameters in params,
00103    // we call AddParameter() for each of them.
00104    // This function splits the parameter names and
00105    // extracts their values if they are given.
00106    // Parameters are separated by ",", values are
00107    // separated from parameter names by "=".
00108    // params being
00109    //    a = "a, b, c", b='d,e'
00110    // will issue two calls to AddParameter(), one for 
00111    // a with value "a, b, c" and one for b with value
00112    // "d,e" (each without the quotation marks).
00113 
00114    fParameters = params; 
00115 
00116    if (!fParameters.Length())
00117       return;
00118 
00119    TString param;
00120    Ssiz_t pos = 0;
00121    while (fParameters.Tokenize(param, pos, ",")) {
00122       param = param.Strip(TString::kBoth);
00123       if (!param.Length())
00124          continue;
00125 
00126       Ssiz_t posAssign = param.Index('=');
00127       if (posAssign != kNPOS) {
00128          TString value(param(posAssign + 1, param.Length()));
00129          value = value.Strip(TString::kBoth);
00130          if (value[0] == '\'')
00131             value = value.Strip(TString::kBoth, '\'');
00132          else if (value[0] == '"')
00133             value = value.Strip(TString::kBoth, '"');
00134          param.Remove(posAssign, param.Length());
00135          param = param.Strip(TString::kBoth);
00136          AddParameter(param, value);
00137       } else {
00138          param = param.Strip(TString::kBoth);
00139          AddParameter(param, 0);
00140       }
00141    }
00142 }
00143 
00144 //______________________________________________________________________________
00145 void TDocDirective::SetParser(TDocParser* parser)
00146 { 
00147    // Set the parser, and fDocOutput, fHtml from that
00148    fDocParser    = parser;
00149    fDocOutput = parser ? parser->GetDocOutput() : 0;
00150    fHtml      = fDocOutput? fDocOutput->GetHtml() : 0;
00151 }
00152 
00153 
00154 //______________________________________________________________________________
00155 //
00156 // Process a "begin_html" / "end_html" block. Stop linking keywords and simply
00157 // copy the text enclosed by the directive to the output HTML file.
00158 //______________________________________________________________________________
00159 
00160 ClassImp(TDocHtmlDirective);
00161 
00162 //______________________________________________________________________________
00163 void TDocHtmlDirective::AddLine(const TSubString& line)
00164 {
00165    // Add a line of HTML
00166 
00167    if (line.Start() == -1) return;
00168 
00169    TPRegexp pretag("</?[pP][rR][eE][ >]");
00170    TSubString iLine(line);
00171    Ssiz_t posPre = iLine.String().Index(pretag, iLine.Start());
00172    if (posPre == kNPOS)
00173       fText += line;
00174    else {
00175       // remove <pre> in fVerbatim environments, and 
00176       // </pre> in !fVerbatim environments.
00177       while (posPre != kNPOS && posPre > 0) {
00178          Bool_t isOpen = line[posPre + 1 - line.Start()] != '/';
00179          Ssiz_t posClose = iLine.String().Index(">", posPre);
00180          if (posClose ==kNPOS) break; // aka oops.
00181          Ssiz_t len = posClose - posPre;
00182 
00183          if (fVerbatim) {
00184             if (isOpen) {
00185                // skip
00186                fText += iLine.String()(iLine.Start(), posPre - iLine.Start());
00187             } else {
00188                // write it out
00189                fText += iLine.String()(iLine.Start(), posPre + len - iLine.Start());
00190                fVerbatim = kFALSE;
00191             }
00192          } else {
00193             if (!isOpen) {
00194                // skip
00195                fText += iLine.String()(iLine.Start(), posPre - iLine.Start());
00196             } else {
00197                // write it out
00198                fText += iLine.String()(iLine.Start(), posPre + len - iLine.Start());
00199                fVerbatim = kTRUE;
00200             }
00201          }
00202 
00203          iLine = iLine.String()(posPre + len, iLine.Length());
00204          posPre = iLine.String().Index(pretag, iLine.Start());
00205       }
00206 
00207       fText += iLine;
00208    }
00209    fText += "\n";
00210 }
00211 
00212 //______________________________________________________________________________
00213 Bool_t TDocHtmlDirective::GetResult(TString& result)
00214 {
00215    // Set result to the HTML code that was passed in via AddLine().
00216    // Prepend a closing </pre>, append an opening <pre>
00217 
00218    result = "</pre><!-- TDocHtmlDirective start -->";
00219    result += fText + "<!-- TDocHtmlDirective end --><pre>";
00220    return kTRUE;
00221 }
00222 
00223 
00224 
00225 //______________________________________________________________________________
00226 //
00227 // Process a "begin_macro" / "end_macro" block. The block can be a file name
00228 // or a CINT script (i.e. even ".x file.C" is allowed). See AddParameter() for
00229 // supported options. Example (the quotes prevent THtml from expanding the
00230 // example):
00231 //
00232 // "BEGIN_MACRO"
00233 // .x $ROOTSYS/tutorials/hsimple.C
00234 // "END_MACRO"
00235 //
00236 // The macro is meant to create an object that can be saved as a GIF file by
00237 // calling object->SaveAs(outputfile.gif). The macro is expected to return that
00238 // object as a TObject*; if it does not, gPad is used and saved. The object
00239 // is deleted by TDocMacroDirective once saved.
00240 //______________________________________________________________________________
00241 
00242 ClassImp(TDocMacroDirective);
00243 
00244 //______________________________________________________________________________
00245 TDocMacroDirective::~TDocMacroDirective()
00246 {
00247    // Destructor
00248    delete fMacro;
00249 }
00250 
00251 //______________________________________________________________________________
00252 void TDocMacroDirective::AddLine(const TSubString& line)
00253 {
00254    // Add a macro line.
00255    // Lines ending on "*HIDE*" will be executed as part of the
00256    // macro, but not shown in the source tab if the parameter
00257    // source is supplied.
00258 
00259    if (!fMacro) {
00260       TString name;
00261       GetName(name);
00262       fMacro = new TMacro(name);
00263    }
00264 
00265    // return if no line - or if there was an intentinal line-break,
00266    // i.e. an empty line
00267    if (line.Start() == -1 && const_cast<TSubString&>(line).String().Length()) return;
00268 
00269    TString sLine(line);
00270    fMacro->AddLine(sLine);
00271    fIsFilename &= !sLine.Contains('{');
00272 }
00273 //______________________________________________________________________________
00274 Bool_t TDocMacroDirective::GetResult(TString& result)
00275 {
00276    // Get the result (i.e. an HTML img tag) for the macro invocation.
00277    // If fShowSource is set, a second tab will be created which shows
00278    // the source.
00279 
00280    if (!fMacro)
00281       return kFALSE;
00282 
00283    if (!fMacro->GetListOfLines() 
00284       || !fMacro->GetListOfLines()->First()) {
00285       Warning("GetResult", "Empty directive found!");
00286       return kTRUE;
00287    }
00288 
00289    R__LOCKGUARD(GetHtml()->GetMakeClassMutex());
00290 
00291    if (gDebug > 3)
00292       Info("HandleDirective_Macro", "executing macro \"%s\" with %d lines.",
00293          fMacro->GetName(), fMacro->GetListOfLines() ? fMacro->GetListOfLines()->GetEntries() + 1 : 0);
00294 
00295    Bool_t wasBatch = gROOT->IsBatch();
00296    if (!wasBatch && !fNeedGraphics)
00297       gROOT->SetBatch();
00298    else if (fNeedGraphics) {
00299       if (fHtml->IsBatch()) {
00300          Warning("GetResult()", "Will not initialize the graphics system; skipping macro %s!", GetName());
00301          result = "";
00302          return kFALSE;
00303       }
00304       gROOT->SetBatch(0);
00305       TApplication::NeedGraphicsLibs();
00306       gApplication->InitializeGraphics();
00307       if (gROOT->IsBatch()) {
00308          Warning("GetResult()", "Cannot initialize the graphics system; skipping macro %s!", GetName());
00309          result = "";
00310          return kFALSE;
00311       }
00312    }
00313 
00314    TVirtualPad* padSave = gPad;
00315 
00316    Int_t error = TInterpreter::kNoError;
00317    Long_t ret = 0;
00318    if (fIsFilename) {
00319       TString filename;
00320       TIter iLine(fMacro->GetListOfLines());
00321       while (filename.Length() == 0)
00322          filename = ((TObjString*)iLine())->String().Strip(TString::kBoth);
00323 
00324       TString macroPath;
00325       TString modulename;
00326       if (GetHtml() && GetDocParser()) {
00327          if (GetDocParser()->GetCurrentClass())
00328             GetHtml()->GetModuleNameForClass(modulename, GetDocParser()->GetCurrentClass());
00329          else GetDocParser()->GetCurrentModule(modulename);
00330       }
00331       if (modulename.Length()) {
00332          GetHtml()->GetModuleMacroPath(modulename, macroPath);
00333       } else macroPath = gSystem->pwd();
00334 
00335       const char* pathDelimiter = ":"; // use ":" even on windows
00336       TObjArray* arrDirs(macroPath.Tokenize(pathDelimiter));
00337       TIter iDir(arrDirs);
00338       TObjString* osDir = 0;
00339       macroPath = "";
00340       TString filenameDirPart(gSystem->DirName(filename));
00341       filenameDirPart.Prepend('/'); // as dir delimiter, not as root dir
00342       while ((osDir = (TObjString*)iDir())) {
00343          if (osDir->String().EndsWith("\\"))
00344             osDir->String().Remove(osDir->String().Length() - 1);
00345          osDir->String() += filenameDirPart;
00346          macroPath += osDir->String() + pathDelimiter;
00347       }
00348 
00349       TString plusplus;
00350       while (filename.EndsWith("+")) {
00351          plusplus += '+';
00352          filename.Remove(filename.Length() - 1);
00353       }
00354 
00355       TString params;
00356       if (filename.EndsWith(")")) {
00357          Ssiz_t posOpen = filename.Last('(');
00358          if (posOpen != kNPOS) {
00359             params = filename(posOpen, filename.Length());
00360             filename.Remove(posOpen, filename.Length());
00361          }
00362       }
00363 
00364       TString fileSysName(gSystem->BaseName(filename));
00365       if (!gSystem->FindFile(macroPath, fileSysName)) {
00366          Error("GetResult", "Cannot find macro '%s' in path '%s'!", 
00367                gSystem->BaseName(filename), macroPath.Data());
00368          result = "";
00369          return kFALSE;
00370       }
00371 
00372       if (fShowSource) {
00373          // copy macro into fMacro - before running it, in case the macro blocks its file
00374          std::ifstream ifMacro(fileSysName);
00375          fMacro->GetListOfLines()->Delete();
00376          TString line;
00377          while (ifMacro) {
00378             if (!line.ReadLine(ifMacro, kFALSE) || ifMacro.eof())
00379                break;
00380             fMacro->AddLine(line);
00381          }
00382       }
00383 
00384       fileSysName.Prepend(".x ");
00385       fileSysName += params;
00386       fileSysName += plusplus;
00387       gInterpreter->SaveContext();
00388       gInterpreter->SaveGlobalsContext();
00389       ret = gROOT->ProcessLine(fileSysName, &error);
00390    } else {
00391       gInterpreter->SaveContext();
00392       gInterpreter->SaveGlobalsContext();
00393       ret = fMacro->Exec(0, &error);
00394    }
00395 
00396    if (fShowSource) {
00397       // convert the macro source
00398       TIter iLine(fMacro->GetListOfLines());
00399       TObjString* osLine = 0;
00400       std::stringstream ssRaw;
00401       while ((osLine = (TObjString*)iLine()))
00402          ssRaw << osLine->String() << std::endl;
00403 
00404       TDocParser *dparser = 0;
00405       if (GetDocParser()->GetCurrentClass())
00406          dparser = new TDocParser(*(TClassDocOutput*)GetDocOutput(), GetDocParser()->GetCurrentClass());
00407       else dparser = new TDocParser(*GetDocOutput());
00408       std::stringstream ssConverted;
00409       dparser->Convert(ssConverted, ssRaw, "./", kTRUE /*code*/, kFALSE /*process directives*/);
00410       delete dparser;
00411 
00412       fMacro->GetListOfLines()->Delete();
00413       TString line;
00414       while (!ssConverted.fail()) {
00415          if (!line.ReadLine(ssConverted, kFALSE) || ssConverted.eof())
00416             break;
00417          fMacro->AddLine(line);
00418       }
00419    }
00420          
00421    Int_t sleepCycles = 50; // 50 = 5 seconds
00422    while (error == TInterpreter::kProcessing && --sleepCycles > 0)
00423       gSystem->Sleep(100);
00424 
00425    gSystem->ProcessEvents(); // in case ret needs to handle some events first
00426 
00427    if (error != TInterpreter::kNoError)
00428       Error("HandleDirective_Macro", "Error processing macro %s!", fMacro->GetName());
00429    else if (ret) {
00430       const TObject* objRet = (const TObject*)ret;
00431       try {
00432          typeid(*objRet).name(); // needed to test whether ret is indeed an object with a vtable!
00433          objRet = dynamic_cast<const TObject*>(objRet);
00434       }
00435       catch (...) {
00436          objRet = 0;
00437       }
00438       if (objRet) {
00439          TString filename;
00440          GetName(filename);
00441 
00442          if (objRet->GetName() && strlen(objRet->GetName())) {
00443             filename += "_";
00444             filename += objRet->GetName();
00445          }
00446          filename.ReplaceAll(" ", "_");
00447 
00448          result = "<span class=\"macro\"><img class=\"macro\" alt=\"output of ";
00449          result += filename;
00450 
00451          GetDocOutput()->NameSpace2FileName(filename);
00452          TString id(filename);
00453          filename += ".gif";
00454          TString basename(filename);
00455 
00456          result += "\" title=\"MACRO\" src=\"";
00457          result += basename;
00458          result += "\" /></span>";
00459 
00460          gSystem->PrependPathName(GetOutputDir(), filename);
00461 
00462          if (gDebug > 3)
00463             Info("HandleDirective_Macro", "Saving returned %s to file %s.",
00464                objRet->IsA()->GetName(), filename.Data());
00465 
00466          if (fNeedGraphics) {
00467             // to get X11 to sync :-( gVirtualX->Update()/Sync() don't do it
00468             gSystem->Sleep(1000);
00469             gVirtualX->Update(0);
00470             gVirtualX->Update(1);
00471          }
00472 
00473          gSystem->ProcessEvents();
00474          if (fNeedGraphics) {
00475             gVirtualX->Update(0);
00476             gVirtualX->Update(1);
00477          }
00478 
00479          objRet->SaveAs(filename);
00480          gSystem->ProcessEvents(); // SaveAs triggers an event
00481          
00482          // ensure objRet is not e.g. the TGMainFrame of a new TCanvas: require padSave == gPad
00483          if (objRet != gPad && padSave == gPad)
00484             delete objRet;
00485 
00486          if (fShowSource) {
00487             // TODO: we need an accessible version of the source, i.e. visible w/o javascript
00488             TString tags("</pre><div class=\"tabs\">\n"
00489                "<a id=\"" + id + "_A0\" class=\"tabsel\" href=\"" + basename + "\" onclick=\"javascript:return SetDiv('" + id + "',0);\">Picture</a>\n"
00490                "<a id=\"" + id + "_A1\" class=\"tab\" href=\"#\" onclick=\"javascript:return SetDiv('" + id + "',1);\">Source</a>\n"
00491                "<br /></div><div class=\"tabcontent\">\n"
00492                "<div id=\"" + id + "_0\" class=\"tabvisible\">" + result + "</div>\n"
00493                "<div id=\"" + id + "_1\" class=\"tabhidden\"><div class=\"listing\"><pre class=\"code\">");
00494             TIter iLine(fMacro->GetListOfLines());
00495             TObjString* osLine = 0;
00496             while ((osLine = (TObjString*) iLine()))
00497                if (!TString(osLine->String().Strip()).EndsWith("*HIDE*"))
00498                   tags += osLine->String() + "\n";
00499             if (tags.EndsWith("\n"))
00500                tags.Remove(tags.Length()-1); // trailing line break
00501             tags += "</pre></div></div><div class=\"clear\"></div></div><pre>";
00502             result = tags;
00503          }
00504       }
00505    }
00506 
00507    // Remove interpreter vars first, so we can check whether we need to delete
00508    // gPad ourselves or whether it was a global var in the interpreter.
00509    gInterpreter->ResetGlobals();
00510    gInterpreter->Reset();
00511 
00512    if (!wasBatch)
00513       gROOT->SetBatch(kFALSE);
00514    if (padSave != gPad) {
00515       delete gPad;
00516       gPad = padSave;
00517    }
00518 
00519    // in case ret's or gPad's deletion provoke events that should be handled
00520    gSystem->ProcessEvents();
00521 
00522    return kTRUE;
00523 }
00524 
00525 //______________________________________________________________________________
00526 void TDocMacroDirective::AddParameter(const TString& name, const char* /*value=0*/)
00527 {
00528    // Setting fNeedGraphics if name is "GUI",
00529    // setting fShowSource if name is "SOURCE"
00530 
00531    if (!name.CompareTo("gui", TString::kIgnoreCase))
00532       fNeedGraphics = kTRUE;
00533    else if (!name.CompareTo("source", TString::kIgnoreCase))
00534       fShowSource = kTRUE;
00535    else Warning("AddParameter", "Unknown option %s!", name.Data());
00536 }
00537 
00538 
00539 
00540 namespace {
00541    Float_t gLinePadding = 10.; //px
00542    Float_t gColumnPadding = 10.; //px
00543 
00544    class TLatexLine {
00545    private:
00546       std::vector<Float_t> fWidths;
00547       Float_t fHeight;
00548       TObjArray* fColumns; // of TObjString*
00549 
00550    public:
00551       TLatexLine(TObjArray* columns = 0): 
00552          fHeight(0.), fColumns(columns) { if (columns) fWidths.resize(Size());}
00553 
00554       Float_t& Width(UInt_t col) {return fWidths[col];}
00555       Float_t& Height() {return fHeight;}
00556       TString* operator[](Int_t column) { 
00557          if (fColumns && fColumns->GetEntriesFast() > column)
00558             return &(((TObjString*)fColumns->At(column))->String());
00559          return 0;
00560       }
00561       UInt_t Size() const { return fColumns ? fColumns->GetEntries() : 0; }
00562       void Delete() { delete fColumns; }
00563    };
00564 }
00565 
00566 //______________________________________________________________________________
00567 //
00568 // Handle a "Begin_Latex"/"End_Latex" directive.
00569 // called as
00570 // "Begin_Latex(fontsize=10, separator='=,', rseparator='=|,', align=lcl)"
00571 // will create and include a TLatex-processed image, with a given fontsize
00572 // in pixels (defaults to 16). If (r)separator is given, the formulas on the 
00573 // following lines will be grouped into columns; a new column starts with 
00574 // (regexp) match of the separator; by default there is only one column.
00575 // separator matches any character, rseparator matches as regexp with one 
00576 // column per pattern match. Only one of separator or rseparator can be given.
00577 // align defines the alignment for each columns; be default, all columns 
00578 // are right aligned. NOTE that the column separator counts as a column itself!
00579 //______________________________________________________________________________
00580 
00581 
00582 ClassImp(TDocLatexDirective);
00583 
00584 //______________________________________________________________________________
00585 TDocLatexDirective::~TDocLatexDirective()
00586 {
00587    // Destructor
00588    gSystem->ProcessEvents();
00589    delete fLatex;
00590    delete fBBCanvas;
00591    gSystem->ProcessEvents();
00592 }
00593 
00594 //______________________________________________________________________________
00595 void TDocLatexDirective::AddLine(const TSubString& line)
00596 {
00597    // Add a latex line
00598 
00599    if (line.Length() == 0)
00600       return;
00601 
00602    if (!fLatex) {
00603       TString name;
00604       GetName(name);
00605       fLatex = new TMacro(name);
00606    }
00607 
00608    TString sLine(line);
00609    GetDocParser()->Strip(sLine);
00610    if (sLine.Length() == 0)
00611       return;
00612 
00613    fLatex->AddLine(sLine);
00614 }
00615 
00616 //______________________________________________________________________________
00617 void TDocLatexDirective::CreateLatex(const char* filename)
00618 {
00619    // Create a gif file named filename from a latex expression in fLatex.
00620    // Called when "Begin_Latex"/"End_Latex" is processed.
00621 
00622    if (!fLatex
00623       || !fLatex->GetListOfLines()
00624       || !fLatex->GetListOfLines()->First())
00625       return;
00626 
00627    R__LOCKGUARD(GetHtml()->GetMakeClassMutex());
00628 
00629    TVirtualPad* oldPad = gPad;
00630 
00631    Bool_t wasBatch = gROOT->IsBatch();
00632    if (!wasBatch)
00633       gROOT->SetBatch();
00634 
00635    const Float_t canvSize = 1200.;
00636    if (!fBBCanvas)
00637       // add magic batch vs. gui canvas sizes (4, 28)
00638       fBBCanvas = (TVirtualPad*)gROOT->ProcessLineFast(
00639          Form("new TCanvas(\"R__TDocLatexDirective_BBCanvas\",\"fBBCanvas\",%g,%g);", -(canvSize + 4.), canvSize + 28.));
00640    if (!fBBCanvas) {
00641       Error("CreateLatex", "Cannot create a TCanvas via the interpreter!");
00642       return;
00643    }
00644    fBBCanvas->SetBorderMode(0);
00645    fBBCanvas->SetFillColor(kWhite);
00646 
00647    gSystem->ProcessEvents();
00648 
00649    std::list<TLatexLine> latexLines;
00650    std::vector<Float_t> maxWidth(20);
00651    UInt_t numColumns = 0;
00652    Float_t totalHeight = gLinePadding;
00653 
00654    TLatex latex;
00655    latex.SetTextFont(43);
00656    latex.SetTextSize((Float_t)fFontSize);
00657    latex.SetTextAlign(12);
00658 
00659    // calculate positions
00660    TIter iterLine(fLatex->GetListOfLines());
00661    TObjString* line = 0;
00662    TPRegexp regexp;
00663    if (fSeparator.Length()) {
00664       if (fSepIsRegexp)
00665          regexp = TPRegexp(fSeparator);
00666    } else fSepIsRegexp = kFALSE;
00667 
00668    while ((line = (TObjString*) iterLine())) {
00669       const TString& str = line->String();
00670       TObjArray* split = 0;
00671       if (!fSepIsRegexp) {
00672          split = new TObjArray();
00673          split->SetOwner();
00674       }
00675       if (!fSeparator.Length())
00676          split->Add(new TObjString(str));
00677       else {
00678          if (fSepIsRegexp)
00679             split = regexp.MatchS(str);
00680          else {
00681             Ssiz_t prevStart = 0;
00682             for (Ssiz_t pos = 0; pos < str.Length(); ++pos) {
00683                if (fSeparator.Index(str[pos]) != kNPOS) {
00684                   split->Add(new TObjString(TString(str(prevStart, pos - prevStart))));
00685                   split->Add(new TObjString(TString(str(pos, 1))));
00686                   prevStart = pos + 1;
00687                }
00688             }
00689             split->Add(new TObjString(TString(str(prevStart, str.Length() - prevStart))));
00690          }
00691       }
00692 
00693       latexLines.push_back(TLatexLine(split));
00694       if (numColumns < (UInt_t)split->GetEntries())
00695          numColumns = split->GetEntries();
00696 
00697       Float_t heightLine = -1.;
00698       for (UInt_t col = 0; col < (UInt_t)split->GetEntries(); ++col) {
00699          Float_t widthLatex = 0.;
00700          Float_t heightLatex = 0.;
00701          TString* strCol = latexLines.back()[col];
00702          if (strCol)
00703             GetBoundingBox(latex, *strCol, widthLatex, heightLatex);
00704          if (heightLine < heightLatex)   heightLine = heightLatex;
00705          if (maxWidth.size() < col)
00706             maxWidth.resize(col * 2);
00707          if (maxWidth[col] < widthLatex)
00708             maxWidth[col] = widthLatex;
00709          latexLines.back().Width(col) = widthLatex;
00710       }
00711       latexLines.back().Height() = heightLine;
00712       totalHeight += heightLine + gLinePadding;
00713    } // while next line
00714 
00715    std::vector<Float_t> posX(numColumns + 1);
00716    for (UInt_t col = 0; col <= numColumns; ++col) {
00717       if (col == 0) posX[col] = gColumnPadding;
00718       else          posX[col] = posX[col - 1] + maxWidth[col - 1] + gColumnPadding;
00719    }
00720    Float_t totalWidth = posX[numColumns];
00721 
00722    // draw
00723    fBBCanvas->Clear();
00724    fBBCanvas->cd();
00725    Float_t padSizeX = totalWidth;
00726    Float_t padSizeY = totalHeight + 8.;
00727    // add magic batch vs. gui canvas sizes (4, 28) + rounding
00728    TVirtualPad* padImg = (TVirtualPad*)gROOT->ProcessLineFast(
00729       Form("new TCanvas(\"R__TDocLatexDirective_padImg\",\"padImg\",-(Int_t)%g,(Int_t)%g);",
00730            padSizeX + 4.5, padSizeY + 28.5));
00731    padImg->SetBorderMode(0);
00732    padImg->SetFillColor(kWhite);
00733    padImg->cd();
00734 
00735    Float_t posY = 0.;
00736    for (std::list<TLatexLine>::iterator iLine = latexLines.begin();
00737       iLine != latexLines.end(); ++iLine) {
00738       posY += iLine->Height()/2. + gLinePadding;
00739       for (UInt_t iCol = 0; iCol < iLine->Size(); ++iCol) {
00740          TString* str = (*iLine)[iCol];
00741          if (!str) continue;
00742          char align = 'l';
00743          if ((UInt_t)fAlignment.Length() > iCol)
00744             align = fAlignment[(Int_t)iCol];
00745          Float_t x = posX[iCol];
00746          switch (align) {
00747             case 'l': break;
00748             case 'r': x += maxWidth[iCol] - iLine->Width(iCol); break;
00749             case 'c': x += 0.5*(maxWidth[iCol] - iLine->Width(iCol)); break;
00750             default:
00751                if (iLine == latexLines.begin())
00752                   Error("CreateLatex", "Invalid alignment character '%c'!", align);
00753          }
00754          latex.DrawLatex( x / padSizeX, 1. - posY / padSizeY, str->Data());
00755       }
00756       posY += iLine->Height()/2.;
00757    }
00758 
00759    padImg->Print(filename);
00760 
00761    // delete the latex objects
00762    for (std::list<TLatexLine>::iterator iLine = latexLines.begin();
00763       iLine != latexLines.end(); ++iLine) {
00764       iLine->Delete();
00765    }
00766 
00767    delete padImg;
00768 
00769    if (!wasBatch)
00770       gROOT->SetBatch(kFALSE);
00771 
00772    gPad = oldPad;
00773 }
00774 
00775 //______________________________________________________________________________
00776 void TDocLatexDirective::GetBoundingBox(TLatex& latex, const char* text, Float_t& width, Float_t& height)
00777 {
00778    // Determines the bounding box for text as height and width.
00779    // Assumes that we are in batch mode.
00780 
00781    UInt_t uiWidth = 0;
00782    UInt_t uiHeight = 0;
00783    fBBCanvas->cd();
00784    latex.SetText(0.1, 0.5, text);
00785    latex.GetBoundingBox(uiWidth, uiHeight);
00786 
00787    width = uiWidth;
00788    height = uiHeight;
00789 }
00790 
00791 //______________________________________________________________________________
00792 TList* TDocLatexDirective::GetListOfLines() const
00793 {
00794    // Get the list of lines as TObjStrings
00795    return fLatex ? fLatex->GetListOfLines() : 0;
00796 }
00797 
00798 //______________________________________________________________________________
00799 Bool_t TDocLatexDirective::GetResult(TString& result)
00800 {
00801    // convert fLatex to a gif by creating a TLatex, drawing it on a 
00802    // temporary canvas, and saving that to a filename in the output
00803    // directory.
00804 
00805    TString filename;
00806    GetName(filename);
00807    filename.ReplaceAll(" ", "_");
00808    const TString& firstLine = ((TObjString*)fLatex->GetListOfLines()->First())->String();
00809    TString latexFilename(firstLine);
00810    for (Ssiz_t namepos = 0; namepos < latexFilename.Length(); ++namepos)
00811       if (!GetDocParser()->IsWord(latexFilename[namepos])) {
00812          latexFilename.Remove(namepos, 1);
00813          --namepos;
00814       }
00815    filename += "_";
00816    filename += latexFilename;
00817 
00818    GetDocOutput()->NameSpace2FileName(filename);
00819    filename += ".gif";
00820 
00821    TString altText(firstLine);
00822    GetDocOutput()->ReplaceSpecialChars(altText);
00823    altText.ReplaceAll("\"", "&quot;");
00824    result = "<span class=\"latex\"><img class=\"latex\" alt=\"";
00825    result += altText;
00826    result += "\" title=\"LATEX\" src=\"";
00827    result += filename;
00828    result += "\" /></span>";
00829 
00830    gSystem->PrependPathName(GetOutputDir(), filename);
00831 
00832    if (gDebug > 3)
00833       Info("HandleDirective_Latex", "Writing Latex \"%s\" to file %s.",
00834            fLatex->GetName(), filename.Data());
00835 
00836    CreateLatex(filename);
00837 
00838    return kTRUE;
00839 }
00840 
00841 //______________________________________________________________________________
00842 void TDocLatexDirective::AddParameter(const TString& name, const char* value /*=0*/)
00843 {
00844    // Parse fParameters, setting fFontSize, fAlignment, and fSeparator
00845 
00846    if (!name.CompareTo("fontsize", TString::kIgnoreCase)) {
00847       if (!value || !strlen(value))
00848          Error("AddParameter", "Option \"fontsize\" needs a value!");
00849       else fFontSize = atol(value);
00850    } else if (!name.CompareTo("separator", TString::kIgnoreCase)) {
00851       if (!value || !strlen(value))
00852          Error("AddParameter", "Option \"separator\" needs a value!");
00853       else fSeparator = value;
00854    } else if (!name.CompareTo("align", TString::kIgnoreCase)) {
00855       if (!value || !strlen(value))
00856          Error("AddParameter", "Option \"align\" needs a value!");
00857       else fAlignment = value;
00858    } else
00859       Warning("AddParameter", "Unknown option %s!", name.Data());
00860 }

Generated on Tue Jul 5 14:24:55 2011 for ROOT_528-00b_version by  doxygen 1.5.1