feat: add clickable BigLadder doc links to Inspector and SimSettings headers#876
feat: add clickable BigLadder doc links to Inspector and SimSettings headers#876Ski90Moo wants to merge 1 commit into
Conversation
…headers Add IddObjectDocUrl.hpp mapping 300+ OS IDD type names to EnergyPlus 25.1 Input/Output Reference URLs. InspectorGadget::layoutText() now renders IDD type headers as clickable hyperlinks in the right-sidebar inspector. Extend CollapsibleInspector to accept an optional URL parameter, and wire 15 section headers in SimSettingsView (plus the Run Period, Sizing Parameters, and Timestep H1 labels) to their respective BigLadder doc anchors. Closes openstudiocoalition#160 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| // Returns the BigLadder EnergyPlus 25.1 Input/Output Reference URL for the given | ||
| // OS IDD type name (e.g. "OS:ThermalZone"), or an empty string if none is known. | ||
| inline QString iddObjectDocUrl(const QString& iddTypeName) { | ||
| static const QString base = QStringLiteral("https://bigladdersoftware.com/epx/docs/25-1/input-output-reference/"); |
There was a problem hiding this comment.
Let's define this base url in one spot, ideally in FindOpenStudioSDK.cmake
| if (level == AccessPolicy::LOCKED) { | ||
| // string stripped(val); | ||
| // std::replace(stripped.begin(), stripped.end(), '_', ' '); // replace all '_' to ' ' | ||
| auto* label = new QLabel(QString(val.c_str()), parent); |
There was a problem hiding this comment.
Shouldn't this also apply in the else block where level != AccessPolicy::LOCKED
There was a problem hiding this comment.
Hmm, this seems to apply to IGHeader only, I'm not sure why a header would ever be not locked. Not an issue with this PR, just confusing existing code.
There was a problem hiding this comment.
index == -1 seems to be used for all headers, I'd suggest only doing the iddObjectDocUrl if index == -1 to save some time, and add a comment that // index == -1 indicates that this is a header row
There was a problem hiding this comment.
Actually this whole overload is only used for the headers, index could be removed as an input parameter. I can do some clean up on this
There was a problem hiding this comment.
Here is a cleaned-up function, if you want to replace it in your PR
void InspectorGadget::layoutHeaderText(QVBoxLayout* layout, QWidget* parent, const std::string& val, const std::string& comment) {
auto* frame = new QFrame(parent);
frame->setContentsMargins(0, 0, 0, 0);
auto* hbox = new QHBoxLayout();
frame->setLayout(hbox);
frame->setObjectName("IGHeader");
hbox->setSpacing(0);
hbox->setContentsMargins(0, 0, 0, 0);
// string stripped(val);
// std::replace(stripped.begin(), stripped.end(), '_', ' '); // replace all '_' to ' '
auto* label = new QLabel(parent);
label->setObjectName("IGHeader");
label->setStyleSheet("font: bold");
const QString typeName = QString::fromStdString(val);
const QString docUrl = iddObjectDocUrl(typeName);
if (!docUrl.isEmpty()) {
label->setTextFormat(Qt::RichText);
label->setOpenExternalLinks(true);
label->setText(
QStringLiteral(R"(<a href="%1" style="color: #ddeeff; font-weight: bold;">%2</a>)").arg(docUrl, typeName.toHtmlEscaped()));
} else {
label->setText(typeName);
}
// Qt::Alignment a = Qt::AlignHCenter;
hbox->addWidget(label);
hbox->addStretch();
auto* commentText = new QLineEdit(QString(comment.c_str()), parent);
commentText->setProperty(s_indexSlotName, -1);
connect(commentText, &QLineEdit::textEdited, this, &InspectorGadget::IGcommentChanged);
if (!m_showComments) {
commentText->hide();
}
hbox->addWidget(commentText);
commentText->setObjectName("IDFHeaderComment");
layout->addWidget(frame);
}
|
Looks pretty good, the one thing I would ask for is a tooltip which shows you the url before you click |
3f0d922 to
453f037
Compare
Summary
Implements the enhancement requested in #160 — adds clickable hyperlinks from IDD type headers and Simulation Settings section headers to the relevant EnergyPlus 25.1 Input/Output Reference pages on BigLadder Software.
src/model_editor/IddObjectDocUrl.hpp(new): header-only hash map (QHash<QString, QString>) mapping 300+OS:*IDD type names to their BigLadder EnergyPlus 25.1 I/O Reference URLssrc/model_editor/InspectorGadget.cpp: renders the locked IDD type header in the right-sidebar inspector as aQt::RichTexthyperlink when a URL mapping existssrc/openstudio_lib/CollapsibleInspector.hpp/.cpp: extendsCollapsibleInspector/CollapsibleInspectorHeaderwith an optional URL parameter; when set, the section title renders as a clickable linksrc/openstudio_lib/SimSettingsView.cpp: wires 15CollapsibleInspectorsection headers and the 3 top-level H1 labels (Run Period, Sizing Parameters, Timestep) to their BigLadder doc anchorsCoverage
Inspector gadget links cover most major OS object categories: zones, HVAC, coils, heat pumps, plant equipment, airflow, schedules, constructions/materials, controls, and more. Remaining categories (AirflowNetwork, Generators, EMS, etc.) are tracked for follow-up.
Test plan
scripts/check_doc_urls.py(to be added) to verify no stale anchor IDs — see notes belowNotes on stale-link checking
Two options were considered for a future automated check:
Option A (recommended): Python script —
scripts/check_doc_urls.pyparsesIddObjectDocUrl.hppandSimSettingsView.cppwith regex to extract every URL, fetches each BigLadder page once (deduplicating by page), parses the HTML to check that the anchor ID actually exists, and reports broken mappings with source location. No build step, runs standalone, can be a CI check or pre-commit hook.Option B: GTest — A
DocUrl_GTest.cppusingQNetworkAccessManagerthat iterates the hash map and checks each URL. Fits the existing test infrastructure but network tests are slow and flaky in CI, and GTest does not provide a natural way to fetch-and-parse HTML for anchor verification.Option A is preferred because the BigLadder server returns HTTP 200 for any anchor on an existing page — a plain HTTP HEAD check will silently miss renamed anchors. Verifying anchor IDs requires fetching the page HTML and scanning for
id="..."attributes. Python'srequests+html.parserhandles that cleanly in ~80 lines.Closes #160
🤖 Generated with Claude Code