583{
584
585 std::stringstream outputstream;
586
587 boost::write_graphviz(outputstream,
591
592
593
594
595
596
597
598 struct VertexStyle
599 {
600 const std::string shape;
601 const std::string color;
602 };
603
604 const std::unordered_map<ObjectKind, VertexStyle> vertex_styles{ {
ObjectKind::kSession, {
"octagon",
"black" } },
608
609 std::string dotfile_slurped = outputstream.str();
610 std::vector<std::string> legend_entries{};
611 std::vector<std::string> legend_ordering_code{};
612
614
615 std::stringstream vertexstr{};
616 std::stringstream legendstr{};
617 std::stringstream labelstringstr{};
618 size_t insertion_location{ 0 };
619
620 auto calculate_insertion_location = [&]() {
621 labelstringstr << "label=\"" << eo.config_object.UID() << "\n";
622 insertion_location = dotfile_slurped.find(labelstringstr.str());
623 assert(insertion_location != std::string::npos);
624 return insertion_location;
625 };
626
627
628
629
630
631
632
633 auto add_vertex_info = [&]() {
634 vertexstr << "shape=" << vertex_styles.at(eo.kind).shape << ", color=" << vertex_styles.at(eo.kind).color
635 << ", fontcolor=" << vertex_styles.at(eo.kind).color << ", ";
636 dotfile_slurped.insert(calculate_insertion_location(), vertexstr.str());
637 };
638
639 auto add_legend_entry = [&](char letter, const std::string objkind) {
640 legendstr << "legend" << letter << " [label=<<font color=\"" << vertex_styles.at(eo.kind).color << "\"><b><i>"
641 << vertex_styles.at(eo.kind).color << ": " << objkind
642 << "</i></b></font>>, shape=plaintext, color=" << vertex_styles.at(eo.kind).color
643 << ", fontcolor=" << vertex_styles.at(eo.kind).color << "];";
644 };
645
646
647
648
649
650
651 switch (eo.kind) {
653 add_vertex_info();
654 add_legend_entry('A', "session");
655 break;
657 add_vertex_info();
658 add_legend_entry('B', "segment");
659 break;
661 add_vertex_info();
662 add_legend_entry('C', "application");
663 break;
665 add_vertex_info();
666 add_legend_entry('D', "DAQModule");
667 break;
669 legendstr
670 << "legendE [label=<<font color=\"black\">O:<b><i> External Data Source</i></b></font>>, shape=plaintext];";
671 break;
673 legendstr
674 << "legendF [label=<<font color=\"black\">X:<b><i> External Data Sink</i></b></font>>, shape=plaintext];";
675 break;
676 default:
677 assert(false);
678 }
679
680 if (std::ranges::find(legend_entries, legendstr.str()) == legend_entries.end()) {
681 legend_entries.emplace_back(legendstr.str());
682 }
683 }
684
685 std::ranges::sort(legend_entries);
686
687
688
689
690
691
692
693
694
695
696
697
698 auto legend_tokens = legend_entries | std::views::transform([](const std::string& line) {
699 return line.substr(0, line.find(' '));
700 });
701
702 auto it = legend_tokens.begin();
703 for (auto next_it = std::next(it); next_it != legend_tokens.end(); ++it, ++next_it) {
704 std::stringstream astr{};
705 astr << " " << *it << " -> " << *next_it << " [style=invis];";
706 legend_ordering_code.push_back(astr.str());
707 }
708
709 constexpr int chars_to_last_brace = 2;
710 auto last_brace_iter = dotfile_slurped.end() - chars_to_last_brace;
711 assert(*last_brace_iter == '}');
712 size_t last_brace_loc = last_brace_iter - dotfile_slurped.begin();
713
714 std::string legend_code{};
715 legend_code += "\n\n\n";
716
717 for (const auto& l : legend_entries) {
718 legend_code +=
l +
"\n";
719 }
720
721 legend_code += "\n\n\n";
722
723 for (const auto& l : legend_ordering_code) {
724 legend_code +=
l +
"\n";
725 }
726
727 dotfile_slurped.insert(last_brace_loc, legend_code);
728
729
730
731
732
733
734 const std::string unlabeled_edge = "label=\"\"";
735 const std::string edge_modifier = ", style=\"dotted\", arrowhead=\"none\"";
736
737 size_t pos = 0;
738 while ((pos = dotfile_slurped.find(unlabeled_edge, pos)) != std::string::npos) {
739 dotfile_slurped.replace(pos, unlabeled_edge.length(), unlabeled_edge + edge_modifier);
740 pos += (unlabeled_edge + edge_modifier).length();
741 }
742
743
744
745 std::ofstream outputfile;
746 outputfile.open(outputfilename);
747
748 if (outputfile.is_open()) {
749 outputfile << dotfile_slurped.c_str();
750 } else {
751 std::stringstream errmsg;
752 errmsg << "Unable to open requested file \"" << outputfilename << "\" for writing";
753 throw daqconf::GeneralGraphToolError(
ERS_HERE, errmsg.str());
754 }
755}
const std::string displaylabel
const std::string displaylabel