Geant4 Cross Reference |
1 // ******************************************************************** 2 // * License and Disclaimer * 3 // * * 4 // * The Geant4 software is copyright of the Copyright Holders of * 5 // * the Geant4 Collaboration. It is provided under the terms and * 6 // * conditions of the Geant4 Software License, included in the file * 7 // * LICENSE and available at http://cern.ch/geant4/license . These * 8 // * include a list of copyright holders. * 9 // * * 10 // * Neither the authors of this software system, nor their employing * 11 // * institutes,nor the agencies providing financial support for this * 12 // * work make any representation or warranty, express or implied, * 13 // * regarding this software system or assume any liability for its * 14 // * use. Please see the license in the file LICENSE and URL above * 15 // * for the full disclaimer and the limitation of liability. * 16 // * * 17 // * This code implementation is the result of the scientific and * 18 // * technical work of the GEANT4 collaboration. * 19 // * By using, copying, modifying or distributing the software (or * 20 // * any work based on the software) you agree to acknowledge its * 21 // * use in resulting scientific publications, and indicate your * 22 // * acceptance of all terms of the Geant4 Software license. * 23 // ******************************************************************** 24 // 25 // G4UIcommandTree 26 // 27 // Author: Makoto Asai (SLAC), 1998 28 // Midified: Makoto Asai (SLAC), 2021 29 // Improve output HTML file layout and add option to sort 30 // command/directory names in alphabetic order 31 // -------------------------------------------------------------------- 32 33 #include "G4UIcommandTree.hh" 34 35 #include "G4StateManager.hh" 36 #include "G4UIdirectory.hh" 37 #include "G4UImanager.hh" 38 #include "G4ios.hh" 39 40 #include <fstream> 41 42 // -------------------------------------------------------------------- 43 G4UIcommandTree::G4UIcommandTree(const char* thePathName) 44 { 45 pathName = thePathName; 46 } 47 48 // -------------------------------------------------------------------- 49 G4UIcommandTree::~G4UIcommandTree() 50 { 51 for (auto& i : tree) { 52 delete i; 53 } 54 } 55 56 // -------------------------------------------------------------------- 57 G4bool G4UIcommandTree::operator==(const G4UIcommandTree& right) const 58 { 59 return (pathName == right.GetPathName()); 60 } 61 62 // -------------------------------------------------------------------- 63 G4bool G4UIcommandTree::operator!=(const G4UIcommandTree& right) const 64 { 65 return (pathName != right.GetPathName()); 66 } 67 68 // -------------------------------------------------------------------- 69 void G4UIcommandTree::AddNewCommand(G4UIcommand* newCommand, G4bool workerThreadOnly) 70 { 71 G4String commandPath = newCommand->GetCommandPath(); 72 G4String remainingPath = commandPath; 73 remainingPath.erase(0, pathName.length()); 74 if (remainingPath.empty()) { 75 if (guidance == nullptr) { 76 guidance = newCommand; 77 if (!(newCommand->ToBeBroadcasted())) { 78 broadcastCommands = false; 79 } 80 if (workerThreadOnly) { 81 newCommand->SetWorkerThreadOnly(); 82 } 83 } 84 return; 85 } 86 87 if (guidance != nullptr) { 88 auto* dir = static_cast<G4UIdirectory*>(guidance); 89 ifSort = dir->IfSort(); 90 } 91 std::size_t i = remainingPath.find('/'); 92 if (i == std::string::npos) { 93 // Adding a new command to this directory 94 std::size_t n_commandEntry = command.size(); 95 for (std::size_t i_thCommand = 0; i_thCommand < n_commandEntry; ++i_thCommand) { 96 if (remainingPath == command[i_thCommand]->GetCommandName()) { 97 // a command of same name has already defined. do nothing and return. 98 if (G4UImanager::GetUIpointer()->GetVerboseLevel() > 8) { 99 G4ExceptionDescription ed; 100 ed << "Command <" << commandPath << "> already exist. New command is not added."; 101 G4Exception("G4UIcommandTree::AddNewCommand", "UI_ComTree_001", 102 // FatalException, 103 JustWarning, ed); 104 } 105 return; 106 } 107 } 108 if (!broadcastCommands) { 109 newCommand->SetToBeBroadcasted(false); 110 } 111 if (workerThreadOnly) { 112 newCommand->SetWorkerThreadOnly(); 113 } 114 if (ifSort) { 115 auto j = command.cbegin(); 116 for (; j != command.cend(); ++j) { 117 if (newCommand->GetCommandPath() < (*j)->GetCommandPath()) { 118 break; 119 } 120 } 121 command.insert(j, newCommand); 122 } 123 else { 124 command.push_back(newCommand); 125 } 126 return; 127 } 128 129 // Adding a new command to a sub-directory 130 G4String nextPath = pathName; 131 nextPath.append(remainingPath.substr(0, i + 1)); 132 std::size_t n_treeEntry = tree.size(); 133 for (std::size_t i_thTree = 0; i_thTree < n_treeEntry; ++i_thTree) { 134 if (nextPath == tree[i_thTree]->GetPathName()) { 135 if (!broadcastCommands) { 136 newCommand->SetToBeBroadcasted(false); 137 } 138 tree[i_thTree]->AddNewCommand(newCommand, workerThreadOnly); 139 return; 140 } 141 } 142 // Creating a new sub-directory 143 auto* newTree = new G4UIcommandTree(nextPath); 144 if (ifSort) { 145 auto j = tree.cbegin(); 146 for (; j != tree.cend(); ++j) { 147 if (newTree->GetPathName() < (*j)->GetPathName()) { 148 break; 149 } 150 } 151 tree.insert(j, newTree); 152 } 153 else { 154 tree.push_back(newTree); 155 } 156 if (!broadcastCommands) { 157 newCommand->SetToBeBroadcasted(false); 158 } 159 // In case a new sub-directry is created with a new G4UIdirectory 160 // (most-likely this is the case), inherit the sort flag 161 newCommand->SetDefaultSortFlag(ifSort); 162 newTree->AddNewCommand(newCommand, workerThreadOnly); 163 return; 164 } 165 166 // -------------------------------------------------------------------- 167 void G4UIcommandTree::RemoveCommand(G4UIcommand* aCommand, G4bool workerThreadOnly) 168 { 169 if (workerThreadOnly && !(aCommand->IsWorkerThreadOnly())) { 170 return; 171 } 172 G4String commandPath = aCommand->GetCommandPath(); 173 commandPath.erase(0, pathName.length()); 174 if (commandPath.empty()) { 175 guidance = nullptr; 176 } 177 else { 178 std::size_t i = commandPath.find('/'); 179 if (i == std::string::npos) { 180 // Find command 181 std::size_t n_commandEntry = command.size(); 182 for (std::size_t i_thCommand = 0; i_thCommand < n_commandEntry; ++i_thCommand) { 183 if (commandPath == command[i_thCommand]->GetCommandName()) { 184 command.erase(command.begin() + i_thCommand); 185 break; 186 } 187 } 188 } 189 else { 190 // Find path 191 G4String nextPath = pathName; 192 nextPath.append(commandPath.substr(0, i + 1)); 193 std::size_t n_treeEntry = tree.size(); 194 for (std::size_t i_thTree = 0; i_thTree < n_treeEntry; ++i_thTree) { 195 if (nextPath == tree[i_thTree]->GetPathName()) { 196 tree[i_thTree]->RemoveCommand(aCommand); 197 G4int n_commandRemain = tree[i_thTree]->GetCommandEntry(); 198 G4int n_treeRemain = tree[i_thTree]->GetTreeEntry(); 199 if (n_commandRemain == 0 && n_treeRemain == 0) { 200 G4UIcommandTree* emptyTree = tree[i_thTree]; 201 tree.erase(tree.begin() + i_thTree); 202 delete emptyTree; 203 } 204 break; 205 } 206 } 207 } 208 } 209 } 210 211 // -------------------------------------------------------------------- 212 G4UIcommand* G4UIcommandTree::FindPath(const char* commandPath) const 213 { 214 // This function tries to match a command name 215 216 G4String remainingPath = commandPath; 217 if (remainingPath.find(pathName) == std::string::npos) { 218 return nullptr; 219 } 220 remainingPath.erase(0, pathName.length()); 221 std::size_t i = remainingPath.find('/'); 222 if (i == std::string::npos) { 223 // Find command 224 std::size_t n_commandEntry = command.size(); 225 for (std::size_t i_thCommand = 0; i_thCommand < n_commandEntry; ++i_thCommand) { 226 if (remainingPath == command[i_thCommand]->GetCommandName()) { 227 return command[i_thCommand]; 228 } 229 } 230 } 231 else { 232 // Find path 233 G4String nextPath = pathName; 234 nextPath.append(remainingPath.substr(0, i + 1)); 235 std::size_t n_treeEntry = tree.size(); 236 for (std::size_t i_thTree = 0; i_thTree < n_treeEntry; ++i_thTree) { 237 if (nextPath == tree[i_thTree]->GetPathName()) { 238 return tree[i_thTree]->FindPath(commandPath); 239 } 240 } 241 } 242 return nullptr; 243 } 244 245 // -------------------------------------------------------------------- 246 G4UIcommandTree* G4UIcommandTree::FindCommandTree(const char* commandPath) 247 { 248 // Try to match a command or a path with the one given. 249 // @commandPath : command or path to match 250 // @return the commandTree found or nullptr if not 251 252 G4String remainingPath = commandPath; 253 if (remainingPath.find(pathName) == std::string::npos) { 254 return nullptr; 255 } 256 remainingPath.erase(0, pathName.length()); 257 std::size_t i = remainingPath.find('/'); 258 if (i != std::string::npos) { 259 // Find path 260 G4String nextPath = pathName; 261 nextPath.append(remainingPath.substr(0, i + 1)); 262 std::size_t n_treeEntry = tree.size(); 263 for (std::size_t i_thTree = 0; i_thTree < n_treeEntry; ++i_thTree) { 264 if (tree[i_thTree]->GetPathName() == commandPath) { 265 return tree[i_thTree]; 266 } 267 if (nextPath == tree[i_thTree]->GetPathName()) { 268 return tree[i_thTree]->FindCommandTree(commandPath); 269 } 270 } 271 } 272 else { 273 return this; 274 } 275 return nullptr; 276 } 277 278 // -------------------------------------------------------------------- 279 G4String G4UIcommandTree::CompleteCommandPath(const G4String& aCommandPath) 280 { 281 G4String pName = aCommandPath; 282 G4String remainingPath = aCommandPath; 283 G4String empty = ""; 284 G4String matchingPath = empty; 285 286 // find the tree 287 auto jpre = pName.rfind('/'); 288 if (jpre != G4String::npos) { 289 pName.erase(jpre + 1); 290 } 291 G4UIcommandTree* aTree = FindCommandTree(pName); 292 293 if (aTree == nullptr) { 294 return empty; 295 } 296 297 if (pName.find(pName) == std::string::npos) { 298 return empty; 299 } 300 301 std::vector<G4String> paths; 302 303 // list matched directories/commands 304 G4String strtmp; 305 G4int nMatch = 0; 306 307 G4int Ndir = aTree->GetTreeEntry(); 308 G4int Ncmd = aTree->GetCommandEntry(); 309 310 // directory ... 311 for (G4int idir = 1; idir <= Ndir; ++idir) { 312 const G4String& fpdir = aTree->GetTree(idir)->GetPathName(); 313 // matching test 314 if (fpdir.find(remainingPath, 0) == 0) { 315 if (nMatch == 0) { 316 matchingPath = fpdir; 317 } 318 else { 319 matchingPath = GetFirstMatchedString(fpdir, matchingPath); 320 } 321 ++nMatch; 322 paths.push_back(fpdir); 323 } 324 } 325 326 if (paths.size() >= 2) { 327 G4cout << "Matching directories :" << G4endl; 328 for (const auto& path : paths) { 329 G4cout << path << G4endl; 330 } 331 } 332 333 // command ... 334 std::vector<G4String> commands; 335 336 for (G4int icmd = 1; icmd <= Ncmd; ++icmd) { 337 G4String fpcmd = aTree->GetPathName() + aTree->GetCommand(icmd)->GetCommandName(); 338 // matching test 339 if (fpcmd.find(remainingPath, 0) == 0) { 340 if (nMatch == 0) { 341 matchingPath = fpcmd + " "; 342 } 343 else { 344 strtmp = fpcmd + " "; 345 matchingPath = GetFirstMatchedString(matchingPath, strtmp); 346 } 347 nMatch++; 348 commands.emplace_back(fpcmd + " "); 349 } 350 } 351 352 if (commands.size() >= 2) { 353 G4cout << "Matching commands :" << G4endl; 354 for (const auto& matched : commands) { 355 G4cout << matched << G4endl; 356 } 357 } 358 359 return matchingPath; 360 } 361 362 // -------------------------------------------------------------------- 363 G4String G4UIcommandTree::GetFirstMatchedString(const G4String& str1, const G4String& str2) const 364 { 365 std::size_t nlen1 = str1.length(); 366 std::size_t nlen2 = str2.length(); 367 368 std::size_t nmin = nlen1 < nlen2 ? nlen1 : nlen2; 369 370 G4String strMatched; 371 for (G4int i = 0; i < (G4int)nmin; ++i) { 372 if (str1[i] == str2[i]) { 373 strMatched += str1[i]; 374 } 375 else { 376 break; 377 } 378 } 379 380 return strMatched; 381 } 382 383 // -------------------------------------------------------------------- 384 void G4UIcommandTree::ListCurrent() const 385 { 386 G4cout << "Command directory path : " << pathName << G4endl; 387 if (guidance != nullptr) { 388 guidance->List(); 389 } 390 G4cout << " Sub-directories : " << G4endl; 391 std::size_t n_treeEntry = tree.size(); 392 for (std::size_t i_thTree = 0; i_thTree < n_treeEntry; ++i_thTree) { 393 G4cout << " " << tree[i_thTree]->GetPathName(); 394 if ((tree[i_thTree]->GetGuidance() != nullptr) 395 && tree[i_thTree]->GetGuidance()->IsWorkerThreadOnly()) 396 { 397 G4cout << " @ "; 398 } 399 else { 400 G4cout << " "; 401 } 402 G4cout << tree[i_thTree]->GetTitle() << G4endl; 403 } 404 G4cout << " Commands : " << G4endl; 405 std::size_t n_commandEntry = command.size(); 406 for (std::size_t i_thCommand = 0; i_thCommand < n_commandEntry; ++i_thCommand) { 407 G4cout << " " << command[i_thCommand]->GetCommandName(); 408 if (command[i_thCommand]->IsWorkerThreadOnly()) { 409 G4cout << " @ "; 410 } 411 else { 412 G4cout << " * "; 413 } 414 G4cout << command[i_thCommand]->GetTitle() << G4endl; 415 } 416 } 417 418 // -------------------------------------------------------------------- 419 void G4UIcommandTree::ListCurrentWithNum() const 420 { 421 G4cout << "Command directory path : " << pathName << G4endl; 422 if (guidance != nullptr) { 423 guidance->List(); 424 } 425 G4int i = 0; 426 G4cout << " Sub-directories : " << G4endl; 427 std::size_t n_treeEntry = tree.size(); 428 for (std::size_t i_thTree = 0; i_thTree < n_treeEntry; ++i_thTree) { 429 ++i; 430 G4cout << " " << i << ") " << tree[i_thTree]->GetPathName() << " " 431 << tree[i_thTree]->GetTitle() << G4endl; 432 } 433 G4cout << " Commands : " << G4endl; 434 std::size_t n_commandEntry = command.size(); 435 for (std::size_t i_thCommand = 0; i_thCommand < n_commandEntry; ++i_thCommand) { 436 ++i; 437 G4cout << " " << i << ") " << command[i_thCommand]->GetCommandName() << " * " 438 << command[i_thCommand]->GetTitle() << G4endl; 439 } 440 } 441 442 // -------------------------------------------------------------------- 443 void G4UIcommandTree::List() const 444 { 445 ListCurrent(); 446 std::size_t n_commandEntry = command.size(); 447 for (std::size_t i_thCommand = 0; i_thCommand < n_commandEntry; ++i_thCommand) { 448 command[i_thCommand]->List(); 449 } 450 std::size_t n_treeEntry = tree.size(); 451 for (std::size_t i_thTree = 0; i_thTree < n_treeEntry; ++i_thTree) { 452 tree[i_thTree]->List(); 453 } 454 } 455 456 // -------------------------------------------------------------------- 457 G4String G4UIcommandTree::CreateFileName(const char* pName) 458 { 459 G4String fn = pName; 460 std::size_t idxs; 461 while ((idxs = fn.find('/')) != std::string::npos) { 462 fn[(G4int)idxs] = '_'; 463 } 464 fn += ".html"; 465 return fn; 466 } 467 468 // -------------------------------------------------------------------- 469 G4String G4UIcommandTree::ModStr(const char* strS) 470 { 471 G4String sx; 472 G4String str = strS; 473 for (G4int i = 0; i < G4int(str.length()); ++i) { 474 char c = str[i]; 475 switch (c) { 476 case '<': 477 sx += "<"; 478 break; 479 case '>': 480 sx += ">"; 481 break; 482 case '&': 483 sx += "&"; 484 break; 485 default: 486 sx += c; 487 } 488 } 489 return sx; 490 } 491 492 // -------------------------------------------------------------------- 493 void G4UIcommandTree::CreateHTML(const G4String& sideBar) 494 { 495 G4String ofileName = CreateFileName(pathName); 496 std::ofstream oF(ofileName, std::ios::out); 497 498 oF << "<html><head><title>Commands in " << ModStr(pathName) << "</title></head>" << G4endl; 499 oF << "<style> \ 500 table,table td,table th { \ 501 border:1px solid #eee \ 502 } \ 503 table td,table th { \ 504 padding:5px 20px; \ 505 line-height:1.3; \ 506 text-align:inherit \ 507 } \ 508 a { \ 509 color:#17a81a; \ 510 text-decoration:none; \ 511 transition-duration:0.3s \ 512 } \ 513 a:hover { \ 514 color:#17a81a \ 515 } \ 516 table { \ 517 border-collapse:collapse; \ 518 border-spacing:0; \ 519 margin-bottom:5px; \ 520 } \ 521 h1 { \ 522 font-size:2.25em; \ 523 font-weight:300; \ 524 letter-spacing:-1px; \ 525 line-height:1.15em; \ 526 margin-bottom:0.5em; \ 527 word-wrap:break-word \ 528 } \ 529 h2 { \ 530 font-size:1.5em; \ 531 font-weight:300; \ 532 letter-spacing:-1px; \ 533 line-height:1.15em; \ 534 margin-bottom:0.5em; \ 535 word-wrap:break-word \ 536 } \ 537 h3 { \ 538 color:#26282a; \ 539 font-weight:300; \ 540 font-size:1.3em; \ 541 padding:15px 0 15px 0; \ 542 border-bottom:2px #eee solid; \ 543 word-wrap:break-word \ 544 } \ 545 .sidebar { \ 546 display:block; \ 547 position:relative; \ 548 position:sticky; \ 549 float:left; \ 550 -webkit-box-sizing:border-box; \ 551 -moz-box-sizing:border-box; \ 552 -ms-box-sizing:border-box; \ 553 box-sizing:border-box; \ 554 width:20%; \ 555 padding-right:20px \ 556 } \ 557 .context { \ 558 width:80%; \ 559 display:inline-block; \ 560 background-color:#fff; \ 561 padding: 25px 35px 20px 30px; \ 562 -webkit-box-sizing:border-box; \ 563 -moz-box-sizing:border-box; \ 564 -ms-box-sizing:border-box; \ 565 box-sizing:border-box \ 566 } \ 567 </style>" 568 << G4endl; 569 oF << "<body bgcolor=\"#ffffff\">" << G4endl; 570 571 // Left Panel 572 if (createHTMLTreeLevel == 0) { 573 oF << "<div class=\"sidebar\">" << sideBar << "</div>" << G4endl; 574 } 575 // Right Panel 576 oF << "<div class=\"context\">"; 577 oF << "<h1>" << ModStr(pathName) << "</h1>" << G4endl; 578 579 if (guidance != nullptr) { 580 for (G4int i = 0; i < (G4int)guidance->GetGuidanceEntries(); ++i) { 581 oF << ModStr(guidance->GetGuidanceLine(i)) << "<br>" << G4endl; 582 } 583 } 584 if (!tree.empty()) { 585 G4String menu = ""; 586 G4String newSideBar = ""; 587 menu += "<h2>Sub-directories </h2><table>"; 588 newSideBar += "<h2><a href=\"" + ofileName + "\">Top level </a></h2><table>"; 589 // Build menu short version 590 for (auto& i_thTree : tree) { 591 newSideBar += "<tr><td><a href=\"" + CreateFileName(i_thTree->GetPathName()) + "\">" 592 + ModStr(i_thTree->GetPathName()) + "</a>"; 593 } 594 // Build menu 595 for (auto& i_thTree : tree) { 596 menu += "<tr><td><a href=\"" + CreateFileName(i_thTree->GetPathName()) + "\">" 597 + ModStr(i_thTree->GetPathName()) + "</a>"; 598 menu += "</td><td>" + ModStr(i_thTree->GetTitle()) + "</tr>"; 599 } 600 menu += "</table>"; 601 newSideBar += "</table>"; 602 for (auto& i_thTree : tree) { 603 createHTMLTreeLevel++; 604 i_thTree->CreateHTML(newSideBar); 605 createHTMLTreeLevel--; 606 } 607 oF << menu << G4endl; 608 } 609 610 if (!command.empty()) { 611 oF << "<h2>Commands </h2>" << G4endl; 612 613 // resume 614 oF << "<table>" << G4endl; 615 for (std::size_t i_thCommand = 0; i_thCommand < command.size(); ++i_thCommand) { 616 G4UIcommand* cmd = command[i_thCommand]; 617 oF << "<tr><td><a href=\"#c" << i_thCommand << "\">" << ModStr(cmd->GetCommandName()); 618 oF << "</a></td></tr>" << G4endl; 619 } 620 oF << "</table>" << G4endl; 621 for (std::size_t i_thCommand = 0; i_thCommand < command.size(); ++i_thCommand) { 622 G4UIcommand* cmd = command[i_thCommand]; 623 oF << "<h3 id=\"c" << i_thCommand << "\">" << ModStr(cmd->GetCommandName()); 624 if (cmd->GetParameterEntries() > 0) { 625 for (G4int i_thParam = 0; i_thParam < (G4int)cmd->GetParameterEntries(); ++i_thParam) { 626 oF << " [<i>" << ModStr(cmd->GetParameter(i_thParam)->GetParameterName()) << "</i>]"; 627 } 628 } 629 oF << "</h3>" << G4endl; 630 oF << "<p>" << G4endl; 631 for (G4int i = 0; i < (G4int)cmd->GetGuidanceEntries(); ++i) { 632 oF << ModStr(cmd->GetGuidanceLine(i)) << "<br>" << G4endl; 633 } 634 if (!(cmd->GetRange()).empty()) { 635 oF << "<p>Range : " << ModStr(cmd->GetRange()) << G4endl; 636 } 637 std::vector<G4ApplicationState>* availabelStateList = cmd->GetStateList(); 638 if (availabelStateList->size() == 6) { 639 oF << "<p>Available at all Geant4 states." << G4endl; 640 } 641 else { 642 oF << "<p>Available Geant4 state(s) : "; 643 for (auto& ias : *availabelStateList) { 644 oF << G4StateManager::GetStateManager()->GetStateString(ias) << " " << G4endl; 645 } 646 } 647 if (cmd->GetParameterEntries() > 0) { 648 oF << "<p>Parameters<table border=1>" << G4endl; 649 for (G4int i_thParam = 0; i_thParam < (G4int)cmd->GetParameterEntries(); ++i_thParam) { 650 G4UIparameter* prm = cmd->GetParameter(i_thParam); 651 oF << "<tr><td>" << ModStr(prm->GetParameterName()) << G4endl; 652 oF << "<td>type " << prm->GetParameterType() << G4endl; 653 oF << "<td>"; 654 if (prm->IsOmittable()) { 655 oF << "Omittable : "; 656 if (prm->GetCurrentAsDefault()) { 657 oF << "current value is used as the default value." << G4endl; 658 } 659 else { 660 oF << "default value = " << prm->GetDefaultValue() << G4endl; 661 } 662 } 663 oF << "<td>"; 664 if (!(prm->GetParameterRange()).empty()) { 665 oF << "Parameter range : " << ModStr(prm->GetParameterRange()) << G4endl; 666 } 667 else if (!(prm->GetParameterCandidates()).empty()) { 668 oF << "Parameter candidates : " << ModStr(prm->GetParameterCandidates()) << G4endl; 669 } 670 } 671 oF << "</table>" << G4endl; 672 } 673 } 674 } 675 oF << "</div></body></html>" << G4endl; 676 oF.close(); 677 } 678 679 // -------------------------------------------------------------------- 680 G4UIcommandTree* G4UIcommandTree::GetTree(const char* comNameC) 681 { 682 G4String comName = comNameC; 683 for (auto& i : tree) { 684 if (comName == i->GetPathName()) { 685 return i; 686 } 687 } 688 return nullptr; 689 } 690