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