From 453f0377a0f5c4ead46fe2a72659be8ba7d0f9e5 Mon Sep 17 00:00:00 2001 From: Ski90Moo Date: Sun, 24 May 2026 15:12:15 +0200 Subject: [PATCH 01/13] feat: add clickable BigLadder doc links to Inspector and SimSettings 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 #160 Co-Authored-By: Claude Sonnet 4.6 --- src/model_editor/IddObjectDocUrl.hpp | 418 ++++++++++++++++++++ src/model_editor/InspectorGadget.cpp | 15 +- src/openstudio_lib/CollapsibleInspector.cpp | 17 +- src/openstudio_lib/CollapsibleInspector.hpp | 4 +- src/openstudio_lib/SimSettingsView.cpp | 47 ++- 5 files changed, 479 insertions(+), 22 deletions(-) create mode 100644 src/model_editor/IddObjectDocUrl.hpp diff --git a/src/model_editor/IddObjectDocUrl.hpp b/src/model_editor/IddObjectDocUrl.hpp new file mode 100644 index 000000000..ff3aacc84 --- /dev/null +++ b/src/model_editor/IddObjectDocUrl.hpp @@ -0,0 +1,418 @@ +/*********************************************************************************************************************** +* OpenStudio(R), Copyright (c) OpenStudio Coalition and other contributors. +* See also https://openstudiocoalition.org/about/software_license/ +***********************************************************************************************************************/ + +#ifndef MODELEDITOR_IDDOBJECTDOCURL_HPP +#define MODELEDITOR_IDDOBJECTDOCURL_HPP + +#include +#include + +// 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/"); + + // clang-format off + static const QHash urlMap{ + // Simulation Parameters + {"OS:SimulationControl", "group-simulation-parameters.html#simulationcontrol"}, + {"OS:Building", "group-simulation-parameters.html#building"}, + {"OS:Timestep", "group-simulation-parameters.html#timestep"}, + {"OS:RunPeriod", "group-simulation-parameters.html#runperiod"}, + {"OS:ShadowCalculation", "group-simulation-parameters.html#shadowcalculation"}, + {"OS:SurfaceConvectionAlgorithm:Inside", "group-simulation-parameters.html#surfaceconvectionalgorithminside"}, + {"OS:SurfaceConvectionAlgorithm:Outside", "group-simulation-parameters.html#surfaceconvectionalgorithmoutside"}, + {"OS:HeatBalanceAlgorithm", "group-simulation-parameters.html#heatbalancealgorithm"}, + {"OS:ZoneAirHeatBalanceAlgorithm", "group-simulation-parameters.html#zoneairheatbalancealgorithm"}, + {"OS:ZoneAirContaminantBalance", "group-simulation-parameters.html#zoneaircontaminantbalance"}, + + // Location and Climate + {"OS:Site:Location", "group-location-climate-weather-file-access.html#sitelocation"}, + {"OS:Site:GroundTemperature:BuildingSurface", "group-location-climate-weather-file-access.html#sitegroundtemperaturebuildingsurface"}, + {"OS:Site:GroundTemperature:FCfactorMethod", "group-location-climate-weather-file-access.html#sitegroundtemperaturefcfactormethod"}, + {"OS:Site:GroundReflectance", "group-location-climate-weather-file-access.html#sitegroundreflectance"}, + {"OS:Site:WaterMainsTemperature", "group-location-climate-weather-file-access.html#sitewatermainstemperature"}, + {"OS:SizingPeriod:DesignDay", "group-location-climate-weather-file-access.html#sizingperioddesignday"}, + {"OS:DesignDay", "group-location-climate-weather-file-access.html#sizingperioddesignday"}, + + // Schedules + {"OS:ScheduleTypeLimits", "group-schedules.html#scheduletypelimits"}, + {"OS:Schedule:Compact", "group-schedules.html#schedulecompact"}, + {"OS:Schedule:Constant", "group-schedules.html#scheduleconstant"}, + {"OS:Schedule:Day:Hourly", "group-schedules.html#scheduledayhourly"}, + {"OS:Schedule:Day:Interval", "group-schedules.html#scheduledayinterval"}, + {"OS:Schedule:Week:Daily", "group-schedules.html#scheduleweekdaily"}, + {"OS:Schedule:Week:Compact", "group-schedules.html#scheduleweekcompact"}, + {"OS:Schedule:Year", "group-schedules.html#scheduleyear"}, + {"OS:Schedule:Ruleset", "group-schedules.html#scheduleyear"}, + + // Surface Construction Elements + {"OS:Material", "group-surface-construction-elements.html#material"}, + {"OS:Material:NoMass", "group-surface-construction-elements.html#materialnomass"}, + {"OS:Material:AirGap", "group-surface-construction-elements.html#materialaingap"}, + {"OS:Material:InfraredTransparent", "group-surface-construction-elements.html#materialinfraredtransparent"}, + {"OS:Material:RoofVegetation", "group-surface-construction-elements.html#materialroofvegetation"}, + {"OS:WindowMaterial:Glazing", "group-surface-construction-elements.html#windowmaterialglazing"}, + {"OS:WindowMaterial:Gas", "group-surface-construction-elements.html#windowmaterialgas"}, + {"OS:WindowMaterial:GasMixture", "group-surface-construction-elements.html#windowmaterialgasmixture"}, + {"OS:WindowMaterial:SimpleGlazingSystem", "group-surface-construction-elements.html#windowmaterialsimpleglazingsystem"}, + {"OS:WindowMaterial:Blind", "group-surface-construction-elements.html#windowmaterialblind"}, + {"OS:WindowMaterial:Screen", "group-surface-construction-elements.html#windowmaterialscreen"}, + {"OS:WindowMaterial:Shade", "group-surface-construction-elements.html#windowmaterialshade"}, + {"OS:Construction", "group-surface-construction-elements.html#construction"}, + {"OS:Construction:InternalSource", "group-surface-construction-elements.html#constructioninternalsource"}, + {"OS:Construction:WindowDataFile", "group-surface-construction-elements.html#constructionwindowdatafile"}, + {"OS:WindowProperty:FrameAndDivider", "group-surface-construction-elements.html#windowpropertyframeanddivider"}, + + // Thermal Zone Description and Geometry + {"OS:ThermalZone", "group-thermal-zone-description-geometry.html"}, + {"OS:Space", "group-thermal-zone-description-geometry.html"}, + {"OS:SpaceType", "group-thermal-zone-description-geometry.html"}, + {"OS:BuildingStory", "group-thermal-zone-description-geometry.html"}, + {"OS:Surface", "group-thermal-zone-description-geometry.html#buildingsurface-detailed"}, + {"OS:SubSurface", "group-thermal-zone-description-geometry.html#fenestrationsurface-detailed"}, + {"OS:ShadingControl", "group-thermal-zone-description-geometry.html#shadingcontrol"}, + {"OS:InteriorPartitionSurface", "group-thermal-zone-description-geometry.html#interiorpartitionsurface-detailed"}, + {"OS:InteriorPartitionSurfaceGroup", "group-thermal-zone-description-geometry.html"}, + + // Daylighting + {"OS:Daylighting:Control", "group-daylighting.html#daylightingcontrols"}, + {"OS:DaylightingDevice:Shelf", "group-daylighting.html#daylightingdeviceshelf"}, + {"OS:DaylightingDevice:Tubular", "group-daylighting.html#daylightingdevicetubular"}, + {"OS:DaylightingDevice:LightWell", "group-daylighting.html#daylightingdevicelightwell"}, + + // Internal Gains + {"OS:People", "group-internal-gains-people-lights-other.html#people"}, + {"OS:Lights", "group-internal-gains-people-lights-other.html#lights"}, + {"OS:ElectricEquipment", "group-internal-gains-people-lights-other.html#electricequipment"}, + {"OS:GasEquipment", "group-internal-gains-people-lights-other.html#gasequipment"}, + {"OS:HotWaterEquipment", "group-internal-gains-people-lights-other.html#hotwatersupportequipment"}, + {"OS:SteamEquipment", "group-internal-gains-people-lights-other.html#steamequipment"}, + {"OS:OtherEquipment", "group-internal-gains-people-lights-other.html#otherequipment"}, + {"OS:InternalMass", "group-internal-gains-people-lights-other.html#internalmass"}, + + // Exterior Energy Use + {"OS:Exterior:Lights", "group-exterior-energy-use-equipment.html#exteriorlights"}, + {"OS:Exterior:FuelEquipment", "group-exterior-energy-use-equipment.html#exteriorfuelequipment"}, + {"OS:Exterior:WaterEquipment", "group-exterior-energy-use-equipment.html#exteriorwaterequipment"}, + // Older OpenStudio type names + {"OS:ExteriorLights", "group-exterior-energy-use-equipment.html#exteriorlights"}, + {"OS:ExteriorFuelEquipment", "group-exterior-energy-use-equipment.html#exteriorfuelequipment"}, + {"OS:ExteriorWaterEquipment", "group-exterior-energy-use-equipment.html#exteriorwaterequipment"}, + + // Zone Airflow + {"OS:SpaceInfiltration:DesignFlowRate", "group-airflow.html#zoneinfiltrationdesignflowrate"}, + {"OS:SpaceInfiltration:EffectiveLeakageArea", "group-airflow.html#zoneinfiltrationeffectiveleakagearea"}, + {"OS:ZoneVentilation:DesignFlowRate", "group-airflow.html#zoneventilationdesignflowrate"}, + {"OS:ZoneVentilation:WindandStackOpenArea", "group-airflow.html#zoneventilationwindandstackopenarea"}, + {"OS:ZoneMixing", "group-airflow.html#zonemixing"}, + {"OS:ZoneCrossMixing", "group-airflow.html#zonecrossmixing"}, + + // Design Objects / Sizing + {"OS:DesignSpecification:OutdoorAir", "group-design-objects.html#designspecificationoutdoorair"}, + {"OS:DesignSpecification:ZoneAirDistribution", "group-design-objects.html#designspecificationzoneairdistribution"}, + {"OS:Sizing:Zone", "group-design-objects.html#sizingzone"}, + {"OS:Sizing:System", "group-design-objects.html#sizingsystem"}, + {"OS:Sizing:Plant", "group-design-objects.html#sizingplant"}, + {"OS:Sizing:Parameters", "group-design-objects.html#sizingparameters"}, + + // Zone HVAC Controls and Thermostats + {"OS:ThermostatSetpoint:DualSetpoint", "group-zone-controls-thermostats.html#thermostatsetpointdualsetpoint"}, + {"OS:ThermostatSetpoint:SingleHeating", "group-zone-controls-thermostats.html#thermostatsetpointsingleheating"}, + {"OS:ThermostatSetpoint:SingleCooling", "group-zone-controls-thermostats.html#thermostatsetpointsinglecooling"}, + {"OS:ZoneControl:Thermostat", "group-zone-controls-thermostats.html#zonecontrolthermostat"}, + {"OS:ZoneControl:ContaminantController", "group-zone-controls-thermostats.html#zonecontrolcontaminantcontroller"}, + {"OS:ZoneControl:Humidistat", "group-zone-controls-thermostats.html#zonecontrolhumidistat"}, + {"OS:ZoneControl:Thermostat:StagedDualSetpoint", "group-zone-controls-thermostats.html#zonecontrolthermostatstageddualsetpoint"}, + + // Zone HVAC Equipment Connections + {"OS:ZoneHVAC:EquipmentList", "group-zone-equipment.html#zonehvacequipmentlist"}, + {"OS:ZoneHVAC:EquipmentConnections", "group-zone-equipment.html#zonehvacequipmentconnections"}, + + // Zone HVAC Forced Air Units + {"OS:ZoneHVAC:PackagedTerminalAirConditioner", "group-zone-forced-air-units.html#zonehvacpackagedterminalairconditioner"}, + {"OS:ZoneHVAC:PackagedTerminalHeatPump", "group-zone-forced-air-units.html#zonehvacpackagedterminalheatpump"}, + {"OS:ZoneHVAC:WaterToAirHeatPump", "group-zone-forced-air-units.html#zonehvacwatertoairheatpump"}, + {"OS:ZoneHVAC:FourPipeFanCoil", "group-zone-forced-air-units.html#zonehvacfourpipefancoil"}, + {"OS:ZoneHVAC:UnitVentilator", "group-zone-forced-air-units.html#zonehvacunitventilator"}, + {"OS:ZoneHVAC:UnitHeater", "group-zone-forced-air-units.html#zonehvacunitheater"}, + {"OS:ZoneHVAC:IdealLoadsAirSystem", "group-zone-forced-air-units.html#zonehvacidealloadsairsystem"}, + {"OS:ZoneHVAC:EnergyRecoveryVentilator", "group-zone-forced-air-units.html#zonehvacenergyrecoveryventilator"}, + {"OS:ZoneHVAC:Dehumidifier:DX", "group-zone-forced-air-units.html#zonehvacdehumidifierdx"}, + {"OS:ZoneHVAC:EvaporativeCoolerUnit", "group-zone-forced-air-units.html#zonehvacevaporativecoolerunit"}, + {"OS:ZoneHVAC:Baseboard:Convective:Water", "group-radiative-convective-units.html#zonehvacbaseboardconvectivewater"}, + {"OS:ZoneHVAC:Baseboard:Convective:Electric", "group-radiative-convective-units.html#zonehvacbaseboardconvectiveelectric"}, + {"OS:ZoneHVAC:TerminalUnit:VariableRefrigerantFlow", "group-zone-forced-air-units.html#zonehvacterminalunitvariablerefrigerantflow"}, + + // Zone HVAC Radiative / Cooling Panels + {"OS:ZoneHVAC:CoolingPanel:RadiantConvective:Water", "group-radiative-convective-units.html#zonehvaccoolingpanelradiantconvectivewater"}, + {"OS:ZoneHVAC:Baseboard:RadiantConvective:Water", "group-radiative-convective-units.html#zonehvacbaseboardradiantconvectivewater"}, + {"OS:ZoneHVAC:Baseboard:RadiantConvective:Electric","group-radiative-convective-units.html#zonehvacbaseboardradiantconvectiveelectric"}, + {"OS:ZoneHVAC:HighTemperatureRadiant", "group-radiative-convective-units.html#zonehvachightemperatureradiant"}, + {"OS:ZoneHVAC:LowTemperatureRadiant:VariableFlow", "group-radiative-convective-units.html#zonehvaclowtemperatureradiantvariableflow"}, + {"OS:ZoneHVAC:LowTemperatureRadiant:ConstantFlow", "group-radiative-convective-units.html#zonehvaclowtemperatureradiantconstantflow"}, + {"OS:ZoneHVAC:LowTemperatureRadiant:Electric", "group-radiative-convective-units.html#zonehvaclowtemperatureradiantelectric"}, + + // Air Terminals + {"OS:AirTerminal:SingleDuct:VAV:Reheat", "group-air-distribution-equipment.html#airterminalsingleductvavreheat"}, + {"OS:AirTerminal:SingleDuct:VAV:NoReheat", "group-air-distribution-equipment.html#airterminalsingleductvavnoreheat"}, + {"OS:AirTerminal:SingleDuct:VAV:HeatAndCool:Reheat", "group-air-distribution-equipment.html#airterminalsingleductvavheatandcoolreheat"}, + {"OS:AirTerminal:SingleDuct:VAV:HeatAndCool:NoReheat", "group-air-distribution-equipment.html#airterminalsingleductvavheatandcoolnoreheat"}, + {"OS:AirTerminal:SingleDuct:ConstantVolume:Reheat", "group-air-distribution-equipment.html#airterminalsingleductconstantvolumereheat"}, + {"OS:AirTerminal:SingleDuct:ConstantVolume:NoReheat", "group-air-distribution-equipment.html#airterminalsingleductuncontrolled"}, + {"OS:AirTerminal:SingleDuct:ConstantVolume:CooledBeam", "group-air-distribution-equipment.html#airterminalsingleductconstantvolumecooledbeam"}, + {"OS:AirTerminal:SingleDuct:ConstantVolume:FourPipeBeam", "group-air-distribution-equipment.html#airterminalsingleductconstantvolumefourpipebeam"}, + {"OS:AirTerminal:SingleDuct:ParallelPIU:Reheat", "group-air-distribution-equipment.html#airterminalsingleductparallelpiu"}, + {"OS:AirTerminal:SingleDuct:SeriesPIU:Reheat", "group-air-distribution-equipment.html#airterminalsingleductseriespiu"}, + {"OS:AirTerminal:SingleDuct:InletSideMixer", "group-air-distribution-equipment.html#airterminalsingleductinletsidemixer"}, + {"OS:AirTerminal:DualDuct:VAV", "group-air-distribution-equipment.html#airterminaldualductvav"}, + {"OS:AirTerminal:DualDuct:VAV:OutdoorAir", "group-air-distribution-equipment.html#airterminaldualductvavoutdoorair"}, + {"OS:AirTerminal:DualDuct:ConstantVolume", "group-air-distribution-equipment.html#airterminaldualductconstantvolume"}, + {"OS:AirTerminal:FourPipeInduction", "group-air-distribution-equipment.html#airterminalfourpipeinduction"}, + + // Fans + {"OS:Fan:ConstantVolume", "group-fans.html#fanconstantvolume"}, + {"OS:Fan:VariableVolume", "group-fans.html#fanvariablevolume"}, + {"OS:Fan:OnOff", "group-fans.html#fanonoff"}, + {"OS:Fan:ZoneExhaust", "group-fans.html#fanzoneexhaust"}, + {"OS:Fan:SystemModel", "group-fans.html#fansystemmodel"}, + + // Coils - Cooling + {"OS:Coil:Cooling:DX:SingleSpeed", "group-heating-and-cooling-coils.html#coilcoolingdxsinglespeed"}, + {"OS:Coil:Cooling:DX:TwoSpeed", "group-heating-and-cooling-coils.html#coilcoolingdxtwospeed"}, + {"OS:Coil:Cooling:DX:MultiSpeed", "group-heating-and-cooling-coils.html#coilcoolingdxmultispeed"}, + {"OS:Coil:Cooling:DX:VariableSpeed", "group-heating-and-cooling-coils.html#coilcoolingdxvariablespeed"}, + {"OS:Coil:Cooling:DX:VariableRefrigerantFlow", "group-heating-and-cooling-coils.html#coilcoolingdxvariablerefrigerantflow"}, + {"OS:Coil:Cooling:DX:VariableRefrigerantFlow:FluidTemperatureControl", "group-heating-and-cooling-coils.html#coilcoolingdxvariablerefrigerantflowfluidtemperaturecontrol"}, + {"OS:Coil:Cooling:Water", "group-heating-and-cooling-coils.html#coilcoolingwater"}, + {"OS:Coil:Cooling:Water:DetailedGeometry", "group-heating-and-cooling-coils.html#coilcoolingwaterdetailedgeometry"}, + {"OS:Coil:Cooling:WaterToAirHeatPump:EquationFit", "group-heating-and-cooling-coils.html#coilcoolingwatertoairheatpumpequationfit"}, + {"OS:Coil:Cooling:WaterToAirHeatPump:VariableSpeedEquationFit", "group-heating-and-cooling-coils.html#coilcoolingwatertoairheatpumpvariablespeedequationfit"}, + {"OS:Coil:Cooling:FourPipeBeam", "group-heating-and-cooling-coils.html#coilcoolingfourpipebeam"}, + + // Coils - Heating + {"OS:Coil:Heating:Gas", "group-heating-and-cooling-coils.html#coilheatinggas-000"}, + {"OS:Coil:Heating:Fuel", "group-heating-and-cooling-coils.html#coilheatingfuel"}, + {"OS:Coil:Heating:Electric", "group-heating-and-cooling-coils.html#coilheatingelectric"}, + {"OS:Coil:Heating:Water", "group-heating-and-cooling-coils.html#coilheatingwater"}, + {"OS:Coil:Heating:DX:SingleSpeed", "group-heating-and-cooling-coils.html#coilheatingdxsinglespeed"}, + {"OS:Coil:Heating:DX:MultiSpeed", "group-heating-and-cooling-coils.html#coilheatingdxmultispeed"}, + {"OS:Coil:Heating:DX:VariableSpeed", "group-heating-and-cooling-coils.html#coilheatingdxvariablespeed"}, + {"OS:Coil:Heating:DX:VariableRefrigerantFlow", "group-heating-and-cooling-coils.html#coilheatingdxvariablerefrigerantflow"}, + {"OS:Coil:Heating:DX:VariableRefrigerantFlow:FluidTemperatureControl", "group-heating-and-cooling-coils.html#coilheatingdxvariablerefrigerantflowfluidtemperaturecontrol"}, + {"OS:Coil:Heating:WaterToAirHeatPump:EquationFit", "group-heating-and-cooling-coils.html#coilheatingwatertoairheatpumpequationfit"}, + {"OS:Coil:Heating:WaterToAirHeatPump:VariableSpeedEquationFit", "group-heating-and-cooling-coils.html#coilheatingwatertoairheatpumpvariablespeedequationfit"}, + {"OS:Coil:Heating:Desuperheater", "group-heating-and-cooling-coils.html#coilheatingdesuperheater"}, + {"OS:Coil:Heating:FourPipeBeam", "group-heating-and-cooling-coils.html#coilheatingfourpipebeam"}, + {"OS:Coil:WaterHeating:AirToWaterHeatPump:Pumped", "group-heating-and-cooling-coils.html#coilwaterheatingairtowaterheatpumppumped"}, + {"OS:Coil:WaterHeating:AirToWaterHeatPump:Wrapped", "group-heating-and-cooling-coils.html#coilwaterheatingairtowaterheatpumpwrapped"}, + {"OS:Coil:WaterHeating:Desuperheater", "group-heating-and-cooling-coils.html#coilwaterheatingdesuperheater"}, + + // Evaporative Coolers + {"OS:EvaporativeCooler:Direct:ResearchSpecial", "group-evaporative-coolers.html#evaporativecoolerdirectresearchspecial"}, + {"OS:EvaporativeCooler:Indirect:ResearchSpecial", "group-evaporative-coolers.html#evaporativecoolerindirectresearchspecial"}, + {"OS:EvaporativeCooler:Direct:CelDekPad", "group-evaporative-coolers.html#evaporativecoolerdirectceldeckpad"}, + {"OS:EvaporativeCooler:Indirect:CelDekPad", "group-evaporative-coolers.html#evaporativecoolerindirectceldeckpad"}, + {"OS:EvaporativeCooler:Indirect:WetCoil", "group-evaporative-coolers.html#evaporativecoolerindirectwetcoil"}, + + // Humidifiers + {"OS:Humidifier:Steam:Electric", "group-humidifiers-and-dehumidifiers.html#humidifiersteamelectric"}, + {"OS:Humidifier:Steam:Gas", "group-humidifiers-and-dehumidifiers.html#humidifiersteamgas"}, + + // Unitary Equipment + {"OS:AirLoopHVAC:UnitaryHeatPump:AirToAir", "group-unitary-equipment.html#airloophvacunitaryheatpumpairtoair"}, + {"OS:AirLoopHVAC:UnitaryHeatPump:AirToAir:MultiSpeed", "group-unitary-equipment.html#airloophvacunitaryheatpumpairtoairmultispeed"}, + {"OS:AirLoopHVAC:UnitarySystem", "group-unitary-equipment.html#airloophvacunitarysystem"}, + {"OS:AirLoopHVAC:UnitaryHeatCool:VAVChangeoverBypass", "group-unitary-equipment.html#airloophvacunitaryheatcoolvavchangeoverbypass"}, + + // Variable Refrigerant Flow + {"OS:AirConditioner:VariableRefrigerantFlow", "group-variable-refrigerant-flow-equipment.html#airconditionervariablerefrigerantflow"}, + {"OS:AirConditioner:VariableRefrigerantFlow:FluidTemperatureControl", "group-variable-refrigerant-flow-equipment.html#airconditionervariablerefrigerantflowfluidtemperaturecontrol"}, + {"OS:AirConditioner:VariableRefrigerantFlow:FluidTemperatureControl:HR", "group-variable-refrigerant-flow-equipment.html#airconditionervariablerefrigerantflowfluidtemperaturecontrolhr"}, + + // Air Distribution / AirLoop + {"OS:AirLoopHVAC", "group-air-distribution.html#group-air-distribution"}, + {"OS:AirLoopHVAC:OutdoorAirSystem", "group-air-distribution.html#airloophvacoutdoorairsystem"}, + {"OS:OutdoorAir:Mixer", "group-airflow.html#outdoorairmixer"}, + {"OS:Controller:OutdoorAir", "group-controllers.html#controlleroutdoorair"}, + {"OS:Controller:MechanicalVentilation", "group-controllers.html#controllermechanicalventilation"}, + {"OS:ZoneHVAC:EnergyRecoveryVentilator:Controller", "group-controllers.html#zonehvacenergyrecoveryventilatorcontroller"}, + {"OS:AirLoopHVAC:ZoneMixer", "group-airflow.html#airloophvaczonemixer"}, + {"OS:AirLoopHVAC:ZoneSplitter", "group-airflow.html#airloophvaczonesplitter"}, + {"OS:AirLoopHVAC:ReturnPlenum", "group-airflow.html#airloophvacreturnplenum"}, + {"OS:AirLoopHVAC:SupplyPlenum", "group-airflow.html#airloophvacsupplyplenum"}, + + // Setpoint Managers + {"OS:SetpointManager:Scheduled", "group-setpoint-managers.html#setpointmanagerscheduled"}, + {"OS:SetpointManager:Scheduled:DualSetpoint", "group-setpoint-managers.html#setpointmanagerscheduleddualsetpoint"}, + {"OS:SetpointManager:MixedAir", "group-setpoint-managers.html#setpointmanagermixedair"}, + {"OS:SetpointManager:OutdoorAirReset", "group-setpoint-managers.html#setpointmanageroutdoorarreset"}, + {"OS:SetpointManager:SingleZone:Reheat", "group-setpoint-managers.html#setpointmanagersinglezonereheat"}, + {"OS:SetpointManager:SingleZone:Heating", "group-setpoint-managers.html#setpointmanagersinglezoneheating"}, + {"OS:SetpointManager:SingleZone:Cooling", "group-setpoint-managers.html#setpointmanagersinglezonecooling"}, + {"OS:SetpointManager:Warmest", "group-setpoint-managers.html#setpointmanagerwarmest"}, + {"OS:SetpointManager:Coldest", "group-setpoint-managers.html#setpointmanagercoldest"}, + {"OS:SetpointManager:FollowOutdoorAirTemperature", "group-setpoint-managers.html#setpointmanagerfollowoutdoorairtemperature"}, + {"OS:SetpointManager:FollowGroundTemperature", "group-setpoint-managers.html#setpointmanagerfollowgroundtemperature"}, + {"OS:SetpointManager:CondenserEnteringReset", "group-setpoint-managers.html#setpointmanagercondenserenteringreset"}, + {"OS:SetpointManager:WarmestTemperatureFlow", "group-setpoint-managers.html#setpointmanagerwarmesttemperatureflow"}, + {"OS:SetpointManager:OutdoorAirPretreat", "group-setpoint-managers.html#setpointmanageroutdoorairpretreat"}, + {"OS:SetpointManager:MultiZone:Heating:Average", "group-setpoint-managers.html#setpointmanagermultizoneheataverage"}, + {"OS:SetpointManager:MultiZone:Cooling:Average", "group-setpoint-managers.html#setpointmanagermultizonecoolaverage"}, + + // Pumps + {"OS:Pump:VariableSpeed", "group-pumps.html#pumpvariablespeed"}, + {"OS:Pump:ConstantSpeed", "group-pumps.html#pumpconstantspeed"}, + {"OS:HeaderedPumps:VariableSpeed", "group-pumps.html#headeredpumpsvariablespeed"}, + {"OS:HeaderedPumps:ConstantSpeed", "group-pumps.html#headeredpumpsconstantspeed"}, + + // Solar Collectors + {"OS:SolarCollector:FlatPlate:Water", "group-solar-collectors.html#solarcollectorflatplatewater"}, + {"OS:SolarCollector:IntegralCollectorStorage", "group-solar-collectors.html#solarcollectorintegralcollectorstorage"}, + {"OS:SolarCollector:UnglazedTranspired", "group-solar-collectors.html#solarcollectorunglazedtranspired"}, + {"OS:SolarCollector:FlatPlate:PhotovoltaicThermal", "group-solar-collectors.html#solarcollectorflatplatephotovoltaicthermal"}, + + // Plant Heating and Cooling Equipment + {"OS:Boiler:HotWater", "group-plant-equipment.html#boilerhotwater"}, + {"OS:Boiler:Steam", "group-plant-equipment.html#boilersteam"}, + {"OS:Chiller:Electric:EIR", "group-plant-equipment.html#chillerelectriceir"}, + {"OS:Chiller:Electric:ReformulatedEIR", "group-plant-equipment.html#chillerelectricreformulatedeir"}, + {"OS:Chiller:Absorption:Indirect", "group-plant-equipment.html#chillerabsorptionindirect"}, + {"OS:Chiller:Absorption:Direct", "group-plant-equipment.html#chillerabsorptiondirect"}, + {"OS:ChillerHeater:Absorption:DirectFired", "group-plant-equipment.html#chillerheaterabsorptiondirectfired"}, + {"OS:DistrictCooling", "group-plant-equipment.html#districtcooling"}, + {"OS:DistrictHeating", "group-plant-equipment.html#districtheating"}, + {"OS:DistrictHeating:Water", "group-plant-equipment.html#districtheating"}, + {"OS:HeatPump:PlantLoop:EIR:Cooling", "group-plant-equipment.html#heatpumpplantloopeircooling"}, + {"OS:HeatPump:PlantLoop:EIR:Heating", "group-plant-equipment.html#heatpumpplantloopeirheating"}, + {"OS:HeatPump:WaterToWater:EquationFit:Cooling", "group-plant-equipment.html#heatpumpwatertowaterequationfitcooling"}, + {"OS:HeatPump:WaterToWater:EquationFit:Heating", "group-plant-equipment.html#heatpumpwatertowaterequationfitheating"}, + {"OS:HeatPump:AirToWater:FuelFired:Cooling", "group-plant-equipment.html#plhp_fuelfired"}, + {"OS:HeatPump:AirToWater:FuelFired:Heating", "group-plant-equipment.html#plhp_fuelfired"}, + {"OS:HeatPump:AirToWater", "group-plant-equipment.html#plhp_air_to_water"}, + {"OS:HeatPump:AirToWater:Cooling", "group-plant-equipment.html#plhp_air_to_water"}, + {"OS:HeatPump:AirToWater:Heating", "group-plant-equipment.html#plhp_air_to_water"}, + {"OS:CentralHeatPumpSystem", "group-plant-equipment.html#centralheatpumpsystem"}, + {"OS:ChillerHeaterPerformance:Electric:EIR", "group-plant-equipment.html#chillerheaterperformancelectriceir"}, + + // Cooling Towers and Fluid Coolers + {"OS:CoolingTower:SingleSpeed", "group-condenser-equipment.html#coolingtowersinglespeed"}, + {"OS:CoolingTower:TwoSpeed", "group-condenser-equipment.html#coolingtowertwospeed"}, + {"OS:CoolingTower:VariableSpeed:Merkel", "group-condenser-equipment.html#coolingtowervariablespeedmerkel"}, + {"OS:EvaporativeFluidCooler:SingleSpeed", "group-condenser-equipment.html#evaporativefluidcoolersinglespeed"}, + {"OS:EvaporativeFluidCooler:TwoSpeed", "group-condenser-equipment.html#evaporativefluidcoolertwospeed"}, + {"OS:FluidCooler:SingleSpeed", "group-condenser-equipment.html#fluidcoolersinglespeed"}, + {"OS:FluidCooler:TwoSpeed", "group-condenser-equipment.html#fluidcoolertwospeed"}, + + // Heat Recovery + {"OS:HeatExchanger:AirToAir:SensibleAndLatent", "group-heat-recovery.html#heatexchangerairtoairsensibleandlatent"}, + {"OS:HeatExchanger:FluidToFluid", "group-heat-recovery.html#heatexchangerfluidtofluid"}, + {"OS:HeatExchanger:Desiccant:BalancedFlow", "group-heat-recovery.html#heatexchangerdesiccantbalancedflow"}, + + // Condenser Equipment and Ground Heat Exchangers + {"OS:GroundHeatExchanger:Vertical", "group-condenser-equipment.html#groundheatexchangervertical"}, + {"OS:GroundHeatExchanger:HorizontalTrench", "group-condenser-equipment.html#groundheatexchangerhorizontaltrench"}, + {"OS:GroundHeatExchanger:Slinky", "group-condenser-equipment.html#groundheatexchangerslinky"}, + + // Water Heaters and Thermal Storage + {"OS:WaterHeater:Mixed", "group-water-heaters.html#waterheatermixed"}, + {"OS:WaterHeater:Stratified", "group-water-heaters.html#waterheaterstratified"}, + {"OS:WaterHeater:HeatPump", "group-water-heaters.html#waterheaterheatpump"}, + {"OS:WaterHeater:HeatPump:PumpedCondenser", "group-water-heaters.html#waterheaterheatpumppumpedcondenser"}, + {"OS:WaterHeater:HeatPump:WrappedCondenser", "group-water-heaters.html#waterheaterheatpumpwrappedcondenser"}, + {"OS:WaterHeater:Sizing", "group-water-heaters.html#waterheatersizing"}, + {"OS:ThermalStorage:Ice:Detailed", "group-water-heaters.html#thermalstorageicedetailed"}, + {"OS:ThermalStorage:ChilledWater:Stratified", "group-water-heaters.html#thermalstoragechilledwaterstratified"}, + + // Water Systems + {"OS:WaterUse:Equipment", "group-water-systems.html#wateruseequipment"}, + {"OS:WaterUse:Connections", "group-water-systems.html#wateruseconnections"}, + + // Refrigeration + {"OS:Refrigeration:AirChiller", "group-refrigeration.html#refrigerationairchiller"}, + {"OS:Refrigeration:Case", "group-refrigeration.html#refrigerationcase"}, + {"OS:Refrigeration:Compressor", "group-refrigeration.html#refrigerationcompressor"}, + {"OS:Refrigeration:CompressorRack", "group-refrigeration.html#refrigerationcompressorrack"}, + {"OS:Refrigeration:Condenser:AirCooled", "group-refrigeration.html#refrigerationcondenseraircooled"}, + {"OS:Refrigeration:Condenser:Cascade", "group-refrigeration.html#refrigerationcondensercascade"}, + {"OS:Refrigeration:Condenser:EvaporativeCooled", "group-refrigeration.html#refrigerationcondenserevaporativecooled"}, + {"OS:Refrigeration:Condenser:WaterCooled", "group-refrigeration.html#refrigerationcondenserwatercooled"}, + {"OS:Refrigeration:DefrostCycleParameters", "group-refrigeration.html#refrigerationwalkin"}, + {"OS:Refrigeration:GasCooler:AirCooled", "group-refrigeration.html#refrigerationgascooleraircooled"}, + {"OS:Refrigeration:SecondarySystem", "group-refrigeration.html#refrigerationsecondarysystem"}, + {"OS:Refrigeration:Subcooler:LiquidSuction", "group-refrigeration.html#refrigerationsubcooler"}, + {"OS:Refrigeration:Subcooler:Mechanical", "group-refrigeration.html#refrigerationsubcooler"}, + {"OS:Refrigeration:System", "group-refrigeration.html#refrigerationsystem"}, + {"OS:Refrigeration:TranscriticalSystem", "group-refrigeration.html#refrigerationtranscriticalsystem"}, + {"OS:Refrigeration:WalkIn", "group-refrigeration.html#refrigerationwalkin"}, + {"OS:Refrigeration:WalkIn:ZoneBoundary", "group-refrigeration.html#refrigerationwalkin"}, + + // Node / Branch Management + {"OS:Pipe:Adiabatic", "group-node-branch-management.html#pipeadiabatic"}, + + // Plant / Condenser Control + {"OS:PlantLoop", "group-plant-condenser-control.html#plantloop"}, + {"OS:CondenserLoop", "group-plant-condenser-control.html#condenserloop"}, + {"OS:PlantEquipmentList", "group-plant-condenser-control.html#plantequipmentlist"}, + {"OS:PlantEquipmentOperation:CoolingLoad", "group-plant-condenser-control.html#plantequipmentoperationcoolingload"}, + {"OS:PlantEquipmentOperation:HeatingLoad", "group-plant-condenser-control.html#plantequipmentoperationheatingload"}, + {"OS:PlantEquipmentOperation:ComponentSetpoint", "group-plant-condenser-control.html#plantequipmentoperationcomponentsetpoint"}, + {"OS:PlantEquipmentOperation:OutdoorDryBulb", "group-plant-condenser-control.html#plantequipmentoperationoutdoordrybulb"}, + {"OS:PlantEquipmentOperation:OutdoorWetBulb", "group-plant-condenser-control.html#plantequipmentoperationoutdoorwetbulb"}, + {"OS:PlantEquipmentOperation:ThermalEnergyStorage", "group-plant-condenser-control.html#plantequipmentoperationthermalenergystorage"}, + {"OS:PlantEquipmentOperation:Uncontrolled", "group-plant-condenser-control.html#plantequipmentoperationuncontrolled"}, + {"OS:AvailabilityManagerAssignmentList", "group-system-availability-managers.html#availabilitymanagerassignmentlist"}, + {"OS:AvailabilityManager:Scheduled", "group-system-availability-managers.html#availabilitymanagerscheduled"}, + {"OS:AvailabilityManager:ScheduledOn", "group-system-availability-managers.html#availabilitymanagerscheduledon"}, + {"OS:AvailabilityManager:ScheduledOff", "group-system-availability-managers.html#availabilitymanagerscheduledoff"}, + {"OS:AvailabilityManager:NightCycle", "group-system-availability-managers.html#availabilitymanagernightcycle"}, + {"OS:AvailabilityManager:DifferentialThermostat", "group-system-availability-managers.html#availabilitymanagerdifferentialthermostat"}, + {"OS:AvailabilityManager:OptimumStart", "group-system-availability-managers.html#availabilitymanageroptimumstart"}, + {"OS:AvailabilityManager:NightVentilation", "group-system-availability-managers.html#availabilitymanagernightventilation"}, + {"OS:AvailabilityManager:HybridVentilation", "group-system-availability-managers.html#availabilitymanagerhybridventilation"}, + {"OS:AvailabilityManager:LowTemperatureTurnOn", "group-system-availability-managers.html#availabilitymanagerlowtemperatureturnon"}, + {"OS:AvailabilityManager:HighTemperatureTurnOff", "group-system-availability-managers.html#availabilitymanagerhightemperatureturnoff"}, + {"OS:AvailabilityManager:LowTemperatureTurnOff", "group-system-availability-managers.html#availabilitymanagerlowtemperatureturnoff"}, + {"OS:AvailabilityManager:HighTemperatureTurnOn", "group-system-availability-managers.html#availabilitymanagerhightemperatureturnon"}, + + // Energy Management System + {"OS:EnergyManagementSystem:Sensor", "group-energy-management-system-ems.html#energymanagementsystemsensor"}, + {"OS:EnergyManagementSystem:Actuator", "group-energy-management-system-ems.html#energymanagementsystemactuator"}, + {"OS:EnergyManagementSystem:Program", "group-energy-management-system-ems.html#energymanagementsystemprogram"}, + {"OS:EnergyManagementSystem:ProgramCallingManager", "group-energy-management-system-ems.html#energymanagementsystemprogramcallingmanager"}, + {"OS:EnergyManagementSystem:GlobalVariable", "group-energy-management-system-ems.html#energymanagementsystemglobalvariable"}, + {"OS:EnergyManagementSystem:OutputVariable", "group-energy-management-system-ems.html#energymanagementsystemoutputvariable"}, + {"OS:EnergyManagementSystem:TrendVariable", "group-energy-management-system-ems.html#energymanagementsystemtrendvariable"}, + {"OS:EnergyManagementSystem:InternalVariable", "group-energy-management-system-ems.html#energymanagementsysteminternalvariable"}, + {"OS:EnergyManagementSystem:ConstructionIndexVariable", "group-energy-management-system-ems.html#energymanagementsystemconstructionindexvariable"}, + + // Performance Curves + {"OS:Curve:Linear", "group-performance-curves.html#curvelinear"}, + {"OS:Curve:Quadratic", "group-performance-curves.html#curvequadratic"}, + {"OS:Curve:Cubic", "group-performance-curves.html#curvecubic"}, + {"OS:Curve:Quartic", "group-performance-curves.html#curvequartic"}, + {"OS:Curve:Exponent", "group-performance-curves.html#curveexponent"}, + {"OS:Curve:Bicubic", "group-performance-curves.html#curvebicubic"}, + {"OS:Curve:Biquadratic", "group-performance-curves.html#curvebiquadratic"}, + {"OS:Curve:QuadraticLinear", "group-performance-curves.html#curvequadraticlinear"}, + {"OS:Curve:CubicLinear", "group-performance-curves.html#curvecubiclinear"}, + {"OS:Curve:Triquadratic", "group-performance-curves.html#curvetriquadratic"}, + {"OS:Curve:FanPressureRise", "group-performance-curves.html#curvefanpressurerise"}, + {"OS:Curve:ExponentialDecay", "group-performance-curves.html#curveexponentialdecay"}, + {"OS:Curve:Sigmoid", "group-performance-curves.html#curvesigmoid"}, + {"OS:Table:IndependentVariable", "group-performance-tables.html#tableindependentvariable"}, + {"OS:Table:IndependentVariableList", "group-performance-tables.html#tableindependentvariablelist"}, + {"OS:Table:Lookup", "group-performance-tables.html#tablelookup"}, + }; + // clang-format on + + auto it = urlMap.constFind(iddTypeName); + if (it != urlMap.constEnd()) { + return base + it.value(); + } + return QString(); +} + +#endif // MODELEDITOR_IDDOBJECTDOCURL_HPP diff --git a/src/model_editor/InspectorGadget.cpp b/src/model_editor/InspectorGadget.cpp index aae9a1d08..470d40f52 100644 --- a/src/model_editor/InspectorGadget.cpp +++ b/src/model_editor/InspectorGadget.cpp @@ -6,6 +6,7 @@ #include "InspectorGadget.hpp" #include "BridgeClasses.hpp" +#include "IddObjectDocUrl.hpp" #include "IGLineEdit.hpp" #include "IGSpinBoxes.hpp" @@ -467,9 +468,21 @@ void InspectorGadget::layoutText(QVBoxLayout* layout, QWidget* parent, openstudi 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); + 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"(%2)").arg(docUrl, typeName.toHtmlEscaped())); + } else { + label->setText(typeName); + } + // Qt::Alignment a = Qt::AlignHCenter; hbox->addWidget(label); diff --git a/src/openstudio_lib/CollapsibleInspector.cpp b/src/openstudio_lib/CollapsibleInspector.cpp index 91a3e6146..b8ab69a45 100644 --- a/src/openstudio_lib/CollapsibleInspector.cpp +++ b/src/openstudio_lib/CollapsibleInspector.cpp @@ -20,6 +20,11 @@ CollapsibleInspector::CollapsibleInspector(QString text, QWidget* inspector, QWi createLayout(); } +CollapsibleInspector::CollapsibleInspector(QString text, QString url, QWidget* inspector, QWidget* parent) + : QWidget(parent), m_header(new CollapsibleInspectorHeader(std::move(text), std::move(url))), m_inspector(inspector) { + createLayout(); +} + void CollapsibleInspector::createLayout() { setContentsMargins(0, 0, 0, 0); @@ -46,7 +51,8 @@ void CollapsibleInspector::on_headerToggled(bool checked) { //////////////////////////////////////////////////////////////////////////////// -CollapsibleInspectorHeader::CollapsibleInspectorHeader(QString text, QWidget* parent) : QAbstractButton(parent), m_text(std::move(text)) { +CollapsibleInspectorHeader::CollapsibleInspectorHeader(QString text, QString url, QWidget* parent) + : QAbstractButton(parent), m_text(std::move(text)), m_url(std::move(url)) { createLayout(); } @@ -67,9 +73,16 @@ void CollapsibleInspectorHeader::createLayout() { mainHLayout->addWidget(m_arrowLabel, 0, Qt::AlignLeft); // Name - auto* textLabel = new QLabel(m_text); + auto* textLabel = new QLabel(); textLabel->setWordWrap(false); textLabel->setObjectName("H2"); + if (!m_url.isEmpty()) { + textLabel->setTextFormat(Qt::RichText); + textLabel->setOpenExternalLinks(true); + textLabel->setText(QStringLiteral(R"(%2)").arg(m_url, m_text.toHtmlEscaped())); + } else { + textLabel->setText(m_text); + } mainHLayout->addWidget(textLabel, 0, Qt::AlignLeft); // Stretch diff --git a/src/openstudio_lib/CollapsibleInspector.hpp b/src/openstudio_lib/CollapsibleInspector.hpp index 71cce79e0..855e59639 100644 --- a/src/openstudio_lib/CollapsibleInspector.hpp +++ b/src/openstudio_lib/CollapsibleInspector.hpp @@ -22,6 +22,7 @@ class CollapsibleInspector : public QWidget public: CollapsibleInspector(QString text, QWidget* inspector, QWidget* parent = nullptr); + CollapsibleInspector(QString text, QString url, QWidget* inspector, QWidget* parent = nullptr); virtual ~CollapsibleInspector() {} @@ -42,7 +43,7 @@ class CollapsibleInspectorHeader : public QAbstractButton Q_OBJECT public: - explicit CollapsibleInspectorHeader(QString text, QWidget* parent = nullptr); + explicit CollapsibleInspectorHeader(QString text, QString url = {}, QWidget* parent = nullptr); void setChecked(bool isChecked); @@ -57,6 +58,7 @@ class CollapsibleInspectorHeader : public QAbstractButton void setImage(bool isChecked); QString m_text; + QString m_url; QLabel* m_arrowLabel; diff --git a/src/openstudio_lib/SimSettingsView.cpp b/src/openstudio_lib/SimSettingsView.cpp index 6a4e9102b..79b2e336e 100644 --- a/src/openstudio_lib/SimSettingsView.cpp +++ b/src/openstudio_lib/SimSettingsView.cpp @@ -239,7 +239,9 @@ void SimSettingsView::createWidgets() { //******************* OS:Timestep ******************* mainLayout->addWidget(createTimestepWidget()); - collapsibleInspector = new CollapsibleInspector("Advanced RunPeriod Parameters", createRunPeriodAdvancedWidget()); + static const QString iorf = QStringLiteral("https://bigladdersoftware.com/epx/docs/25-1/input-output-reference/"); + + collapsibleInspector = new CollapsibleInspector(tr("Advanced RunPeriod Parameters"), iorf + "group-location-climate-weather-file-access.html#runperiod", createRunPeriodAdvancedWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:RadianceParameters ******************* @@ -247,7 +249,7 @@ void SimSettingsView::createWidgets() { mainLayout->addWidget(collapsibleInspector); //******************* OS:SimulationControl ******************* - collapsibleInspector = new CollapsibleInspector("Simulation Control", createSimulationControlWidget()); + collapsibleInspector = new CollapsibleInspector(tr("Simulation Control"), iorf + "group-simulation-parameters.html#simulationcontrol", createSimulationControlWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:ProgramControl ******************* @@ -255,55 +257,55 @@ void SimSettingsView::createWidgets() { mainLayout->addWidget(collapsibleInspector); //******************* OS:OutputControl:ReportingTolerances ******************* - collapsibleInspector = new CollapsibleInspector("Output Control Reporting Tolerances", createOutputControlReportingTolerancesWidget()); + collapsibleInspector = new CollapsibleInspector(tr("Output Control Reporting Tolerances"), iorf + "input-for-output.html#outputcontrolreportingtolerances", createOutputControlReportingTolerancesWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:ConvergenceLimits ******************* - collapsibleInspector = new CollapsibleInspector("Convergence Limits", createConvergenceLimitsWidget()); + collapsibleInspector = new CollapsibleInspector(tr("Convergence Limits"), iorf + "group-simulation-parameters.html#convergencelimits", createConvergenceLimitsWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:ShadowCalculation ******************* - collapsibleInspector = new CollapsibleInspector("Shadow Calculation", createShadowCalculationWidget()); + collapsibleInspector = new CollapsibleInspector(tr("Shadow Calculation"), iorf + "group-simulation-parameters.html#shadowcalculation", createShadowCalculationWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:SurfaceConvectionAlgorithm:Inside ******************* - collapsibleInspector = new CollapsibleInspector("Inside Surface Convection Algorithm", createSurfaceConvectionAlgorithmInsideWidget()); + collapsibleInspector = new CollapsibleInspector(tr("Inside Surface Convection Algorithm"), iorf + "group-simulation-parameters.html#surfaceconvectionalgorithminside", createSurfaceConvectionAlgorithmInsideWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:SurfaceConvectionAlgorithm:Outside ******************* - collapsibleInspector = new CollapsibleInspector("Outside Surface Convection Algorithm", createSurfaceConvectionAlgorithmOutsideWidget()); + collapsibleInspector = new CollapsibleInspector(tr("Outside Surface Convection Algorithm"), iorf + "group-simulation-parameters.html#surfaceconvectionalgorithmoutside", createSurfaceConvectionAlgorithmOutsideWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:HeatBalanceAlgorithm ******************* - collapsibleInspector = new CollapsibleInspector("Heat Balance Algorithm", createHeatBalanceAlgorithmWidget()); + collapsibleInspector = new CollapsibleInspector(tr("Heat Balance Algorithm"), iorf + "group-simulation-parameters.html#heatbalancealgorithm", createHeatBalanceAlgorithmWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:ZoneAirHeatBalanceAlgorithm ******************* - collapsibleInspector = new CollapsibleInspector("Zone Air Heat Balance Algorithm", createZoneAirHeatBalanceAlgorithmWidget()); + collapsibleInspector = new CollapsibleInspector(tr("Zone Air Heat Balance Algorithm"), iorf + "group-simulation-parameters.html#zoneairheatbalancealgorithm", createZoneAirHeatBalanceAlgorithmWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:ZoneAirContaminantBalance ******************* - collapsibleInspector = new CollapsibleInspector("Zone Air Contaminant Balance", createZoneAirContaminantBalanceWidget()); + collapsibleInspector = new CollapsibleInspector(tr("Zone Air Contaminant Balance"), iorf + "group-simulation-parameters.html#zoneaircontaminantbalance", createZoneAirContaminantBalanceWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:ZoneCapacitanceMultiplier:ResearchSpecial ******************* - collapsibleInspector = new CollapsibleInspector("Zone Capacitance Multiple Research Special", createZoneCapacitanceMultipleResearchSpecialWidget()); + collapsibleInspector = new CollapsibleInspector(tr("Zone Capacitance Multiple Research Special"), iorf + "group-simulation-parameters.html#zonecapacitancemultiplierresearchspecial", createZoneCapacitanceMultipleResearchSpecialWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:Output:JSON ******************* - collapsibleInspector = new CollapsibleInspector("Output JSON", createOutputJSONWidget()); + collapsibleInspector = new CollapsibleInspector(tr("Output JSON"), iorf + "input-for-output.html#outputjson", createOutputJSONWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:Output:Table:SummaryReports ******************* - collapsibleInspector = new CollapsibleInspector("Output Table Summary Reports", createOutputTableSummaryReportsWidget()); + collapsibleInspector = new CollapsibleInspector(tr("Output Table Summary Reports"), iorf + "output-table-summaryreports.html#outputtablesummaryreports", createOutputTableSummaryReportsWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:Output:Diagnostics ******************* - collapsibleInspector = new CollapsibleInspector("Output Diagnostics", createOutputDiagnosticsWidget()); + collapsibleInspector = new CollapsibleInspector(tr("Output Diagnostics"), iorf + "group-simulation-parameters.html#outputdiagnostics", createOutputDiagnosticsWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:OutputControl:ResilienceSummaries ******************* - collapsibleInspector = new CollapsibleInspector("Output Control Resilience Summaries", createOutputControlResilienceSummariesWidget()); + collapsibleInspector = new CollapsibleInspector(tr("Output Control Resilience Summaries"), iorf + "input-for-output.html#OutputControlResilienceSummaries", createOutputControlResilienceSummariesWidget()); mainLayout->addWidget(collapsibleInspector); mainLayout->addStretch(); @@ -324,8 +326,11 @@ QWidget* SimSettingsView::createRunPeriodWidget() { QHBoxLayout* hLayout = nullptr; - label = new QLabel("Run Period"); + label = new QLabel(); label->setObjectName("H1"); + label->setTextFormat(Qt::RichText); + label->setOpenExternalLinks(true); + label->setText(QStringLiteral(R"(%1)").arg(tr("Run Period"))); mainVLayout->addWidget(label); mainVLayout->addLayout(mainHLayout); @@ -601,8 +606,11 @@ QWidget* SimSettingsView::createSizingParametersWidget() { QLabel* label = nullptr; - label = new QLabel("Sizing Parameters"); + label = new QLabel(); label->setObjectName("H1"); + label->setTextFormat(Qt::RichText); + label->setOpenExternalLinks(true); + label->setText(QStringLiteral(R"(%1)").arg(tr("Sizing Parameters"))); mainLayout->addWidget(label); auto* gridLayout = new QGridLayout(); @@ -651,8 +659,11 @@ QWidget* SimSettingsView::createTimestepWidget() { QLabel* label = nullptr; - label = new QLabel("Timestep"); + label = new QLabel(); label->setObjectName("H1"); + label->setTextFormat(Qt::RichText); + label->setOpenExternalLinks(true); + label->setText(QStringLiteral(R"(%1)").arg(tr("Timestep"))); mainLayout->addWidget(label); auto* gridLayout = new QGridLayout(); From 180e3eebd23eb5e6aa8dc4fa8c715b753700e6dd Mon Sep 17 00:00:00 2001 From: Ski90Moo Date: Sun, 31 May 2026 11:07:01 +0200 Subject: [PATCH 02/13] fix: address PR #876 review comments - Define ENERGYPLUS_VERSION_MAJOR/MINOR and BIGLADDERSOFTWARE_DOC_BASE_URL in FindOpenStudioSDK.cmake (single source of truth for the BigLadder URL base); pass to C++ via target_compile_definitions in model_editor and openstudio_lib; remove hardcoded URL strings from IddObjectDocUrl.hpp and SimSettingsView.cpp - Rename layoutText header overload to layoutHeaderText, drop unused level/ index parameters per macumber's cleaned-up version - Add setToolTip(docUrl) to all clickable doc links so the URL is visible on hover before clicking (InspectorGadget header, CollapsibleInspector section headers, SimSettings H1 labels) Co-Authored-By: Claude Sonnet 4.6 --- FindOpenStudioSDK.cmake | 4 ++ src/model_editor/CMakeLists.txt | 3 ++ src/model_editor/IddObjectDocUrl.hpp | 7 +-- src/model_editor/InspectorGadget.cpp | 56 ++++++++------------- src/model_editor/InspectorGadget.hpp | 3 +- src/openstudio_lib/CMakeLists.txt | 3 ++ src/openstudio_lib/CollapsibleInspector.cpp | 1 + src/openstudio_lib/SimSettingsView.cpp | 20 ++++++-- 8 files changed, 54 insertions(+), 43 deletions(-) diff --git a/FindOpenStudioSDK.cmake b/FindOpenStudioSDK.cmake index 8110aa3de..8d6ff499b 100644 --- a/FindOpenStudioSDK.cmake +++ b/FindOpenStudioSDK.cmake @@ -8,6 +8,10 @@ set(OPENSTUDIO_VERSION_PRERELEASE "") # Enter SHA, always, eg "+79857912c4" set(OPENSTUDIO_VERSION_SHA "+241b8abb4d") +set(ENERGYPLUS_VERSION_MAJOR 25) +set(ENERGYPLUS_VERSION_MINOR 1) +set(BIGLADDERSOFTWARE_DOC_BASE_URL "https://bigladdersoftware.com/epx/docs/${ENERGYPLUS_VERSION_MAJOR}-${ENERGYPLUS_VERSION_MINOR}/input-output-reference/") + # Paths where the cmake-downloaded archives will be put set(OPENSTUDIO_ARCHIVE_DIR "${PROJECT_BINARY_DIR}/OpenStudio-${OPENSTUDIO_VERSION}") diff --git a/src/model_editor/CMakeLists.txt b/src/model_editor/CMakeLists.txt index 63aca23c1..c8ee35816 100644 --- a/src/model_editor/CMakeLists.txt +++ b/src/model_editor/CMakeLists.txt @@ -103,6 +103,9 @@ else() target_compile_definitions(${target_name} PUBLIC model_editor_EXPORTS) endif() +target_compile_definitions(${target_name} PRIVATE + "BIGLADDERSOFTWARE_DOC_BASE_URL=\"${BIGLADDERSOFTWARE_DOC_BASE_URL}\"") + set(${target_name}_test_src test/ModelEditorFixture.hpp test/ModelEditorFixture.cpp diff --git a/src/model_editor/IddObjectDocUrl.hpp b/src/model_editor/IddObjectDocUrl.hpp index ff3aacc84..91bf84339 100644 --- a/src/model_editor/IddObjectDocUrl.hpp +++ b/src/model_editor/IddObjectDocUrl.hpp @@ -9,10 +9,11 @@ #include #include -// 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. +// Returns the BigLadder EnergyPlus I/O Reference URL for the given OS IDD type name +// (e.g. "OS:ThermalZone"), or an empty string if none is known. +// Base URL version is controlled by ENERGYPLUS_VERSION_MAJOR/MINOR in FindOpenStudioSDK.cmake. inline QString iddObjectDocUrl(const QString& iddTypeName) { - static const QString base = QStringLiteral("https://bigladdersoftware.com/epx/docs/25-1/input-output-reference/"); + static const QString base = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL); // clang-format off static const QHash urlMap{ diff --git a/src/model_editor/InspectorGadget.cpp b/src/model_editor/InspectorGadget.cpp index 470d40f52..12ba75f9a 100644 --- a/src/model_editor/InspectorGadget.cpp +++ b/src/model_editor/InspectorGadget.cpp @@ -266,7 +266,7 @@ void InspectorGadget::layoutItems(QVBoxLayout* masterLayout, QWidget* parent, bo hlayout->setContentsMargins(0, 0, 0, 0); masterLayout->addLayout(hlayout); hlayout->addLayout(layout); - layoutText(layout, parent, AccessPolicy::LOCKED, iddObj.type().valueDescription(), -1, comment); + layoutHeaderText(layout, parent, iddObj.type().valueDescription(), comment); const AccessPolicy* pAccessPolicy = AccessPolicyStore::Instance().getPolicy(iddObj.type()); @@ -455,8 +455,7 @@ void InspectorGadget::parseItem(QVBoxLayout* layout, QWidget* parent, openstudio } } -void InspectorGadget::layoutText(QVBoxLayout* layout, QWidget* parent, openstudio::model::AccessPolicy::ACCESS_LEVEL level, const std::string& val, - int index, const std::string& comment) { +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(); @@ -465,42 +464,31 @@ void InspectorGadget::layoutText(QVBoxLayout* layout, QWidget* parent, openstudi hbox->setSpacing(0); hbox->setContentsMargins(0, 0, 0, 0); - if (level == AccessPolicy::LOCKED) { - // 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"(%2)").arg(docUrl, typeName.toHtmlEscaped())); - } else { - label->setText(typeName); - } - - // Qt::Alignment a = Qt::AlignHCenter; - hbox->addWidget(label); - - hbox->addStretch(); + // 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->setToolTip(docUrl); + label->setText( + QStringLiteral(R"(%2)").arg(docUrl, typeName.toHtmlEscaped())); } else { - //QLineEdit* text = new QLineEdit( QString(val.c_str()), parent ); - auto* text = new IGLineEdit(QString(val.c_str()), this, parent); - hbox->addWidget(text); - text->setProperty(s_indexSlotName, index); + label->setText(typeName); + } - //connect(text, &IGLineEdit::textEdited, this, &InspectorGadget::IGvalueChanged, Qt::QueuedConnection); + // Qt::Alignment a = Qt::AlignHCenter; + hbox->addWidget(label); - connect(text, &IGLineEdit::editingFinished, text, &IGLineEdit::editDone); - connect(text, &IGLineEdit::newValue, this, &InspectorGadget::IGvalueChanged); - } + hbox->addStretch(); auto* commentText = new QLineEdit(QString(comment.c_str()), parent); - commentText->setProperty(s_indexSlotName, index); + commentText->setProperty(s_indexSlotName, -1); connect(commentText, &QLineEdit::textEdited, this, &InspectorGadget::IGcommentChanged); if (!m_showComments) { commentText->hide(); diff --git a/src/model_editor/InspectorGadget.hpp b/src/model_editor/InspectorGadget.hpp index 3dcfb8953..4f5446625 100644 --- a/src/model_editor/InspectorGadget.hpp +++ b/src/model_editor/InspectorGadget.hpp @@ -248,8 +248,7 @@ class MODELEDITOR_API InspectorGadget void parseItem(QVBoxLayout* layout, QWidget* parent, openstudio::IddField& field, const std::string& name, const std::string& curVal, openstudio::model::AccessPolicy::ACCESS_LEVEL level, int index, const std::string& comment, bool exists); - void layoutText(QVBoxLayout* layout, QWidget* parent, openstudio::model::AccessPolicy::ACCESS_LEVEL level, const std::string& val, int index, - const std::string& comment); + void layoutHeaderText(QVBoxLayout* layout, QWidget* parent, const std::string& val, const std::string& comment); void layoutText(QVBoxLayout* layout, QWidget* parent, openstudio::IddField& field, openstudio::model::AccessPolicy::ACCESS_LEVEL level, const std::string& name, const std::string& curVal, int index, const std::string& comment, bool exists, bool number, diff --git a/src/openstudio_lib/CMakeLists.txt b/src/openstudio_lib/CMakeLists.txt index 28977df89..143c5bbb4 100644 --- a/src/openstudio_lib/CMakeLists.txt +++ b/src/openstudio_lib/CMakeLists.txt @@ -778,6 +778,9 @@ if (NINJA) target_compile_definitions(${target_name} PRIVATE NINJA=1) endif() +target_compile_definitions(${target_name} PRIVATE + "BIGLADDERSOFTWARE_DOC_BASE_URL=\"${BIGLADDERSOFTWARE_DOC_BASE_URL}\"") + set(${target_name}_depends openstudio_modeleditor openstudio::openstudiolib diff --git a/src/openstudio_lib/CollapsibleInspector.cpp b/src/openstudio_lib/CollapsibleInspector.cpp index b8ab69a45..a7a14c470 100644 --- a/src/openstudio_lib/CollapsibleInspector.cpp +++ b/src/openstudio_lib/CollapsibleInspector.cpp @@ -79,6 +79,7 @@ void CollapsibleInspectorHeader::createLayout() { if (!m_url.isEmpty()) { textLabel->setTextFormat(Qt::RichText); textLabel->setOpenExternalLinks(true); + textLabel->setToolTip(m_url); textLabel->setText(QStringLiteral(R"(%2)").arg(m_url, m_text.toHtmlEscaped())); } else { textLabel->setText(m_text); diff --git a/src/openstudio_lib/SimSettingsView.cpp b/src/openstudio_lib/SimSettingsView.cpp index 79b2e336e..42a530403 100644 --- a/src/openstudio_lib/SimSettingsView.cpp +++ b/src/openstudio_lib/SimSettingsView.cpp @@ -239,7 +239,7 @@ void SimSettingsView::createWidgets() { //******************* OS:Timestep ******************* mainLayout->addWidget(createTimestepWidget()); - static const QString iorf = QStringLiteral("https://bigladdersoftware.com/epx/docs/25-1/input-output-reference/"); + static const QString iorf = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL); collapsibleInspector = new CollapsibleInspector(tr("Advanced RunPeriod Parameters"), iorf + "group-location-climate-weather-file-access.html#runperiod", createRunPeriodAdvancedWidget()); mainLayout->addWidget(collapsibleInspector); @@ -330,7 +330,11 @@ QWidget* SimSettingsView::createRunPeriodWidget() { label->setObjectName("H1"); label->setTextFormat(Qt::RichText); label->setOpenExternalLinks(true); - label->setText(QStringLiteral(R"(%1)").arg(tr("Run Period"))); + { + static const QString url = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL "group-location-climate-weather-file-access.html#runperiod"); + label->setToolTip(url); + label->setText(QStringLiteral(R"(%2)").arg(url, tr("Run Period"))); + } mainVLayout->addWidget(label); mainVLayout->addLayout(mainHLayout); @@ -610,7 +614,11 @@ QWidget* SimSettingsView::createSizingParametersWidget() { label->setObjectName("H1"); label->setTextFormat(Qt::RichText); label->setOpenExternalLinks(true); - label->setText(QStringLiteral(R"(%1)").arg(tr("Sizing Parameters"))); + { + static const QString url = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL "group-design-objects.html#sizingparameters"); + label->setToolTip(url); + label->setText(QStringLiteral(R"(%2)").arg(url, tr("Sizing Parameters"))); + } mainLayout->addWidget(label); auto* gridLayout = new QGridLayout(); @@ -663,7 +671,11 @@ QWidget* SimSettingsView::createTimestepWidget() { label->setObjectName("H1"); label->setTextFormat(Qt::RichText); label->setOpenExternalLinks(true); - label->setText(QStringLiteral(R"(%1)").arg(tr("Timestep"))); + { + static const QString url = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL "group-simulation-parameters.html#timestep"); + label->setToolTip(url); + label->setText(QStringLiteral(R"(%2)").arg(url, tr("Timestep"))); + } mainLayout->addWidget(label); auto* gridLayout = new QGridLayout(); From 74274c974d02bc78947993ef255acf029c1a230c Mon Sep 17 00:00:00 2001 From: Ski90Moo Date: Sun, 31 May 2026 13:06:45 +0200 Subject: [PATCH 03/13] feat: add 11 missing IDD type URL mappings - OS:Schedule:Day - OS:Coil:Cooling:DX:TwoStageWithHumidityControlMode - OS:Coil:Cooling:DX:MultiSpeed:StageData - OS:Coil:Cooling:Water:Panel:Radiant - OS:Coil:Heating:Gas:MultiStage + :StageData - OS:Coil:Heating:LowTemperatureRadiant:ConstantFlow + :VariableFlow - OS:Coil:Heating:Water:Baseboard:Radiant - OS:Coil:WaterHeating:AirToWaterHeatPump - OS:SetpointManager:FollowSystemNodeTemperature Co-Authored-By: Claude Sonnet 4.6 --- src/model_editor/IddObjectDocUrl.hpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/model_editor/IddObjectDocUrl.hpp b/src/model_editor/IddObjectDocUrl.hpp index 91bf84339..3aae4f016 100644 --- a/src/model_editor/IddObjectDocUrl.hpp +++ b/src/model_editor/IddObjectDocUrl.hpp @@ -42,6 +42,7 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:ScheduleTypeLimits", "group-schedules.html#scheduletypelimits"}, {"OS:Schedule:Compact", "group-schedules.html#schedulecompact"}, {"OS:Schedule:Constant", "group-schedules.html#scheduleconstant"}, + {"OS:Schedule:Day", "group-schedules.html#day-schedules"}, {"OS:Schedule:Day:Hourly", "group-schedules.html#scheduledayhourly"}, {"OS:Schedule:Day:Interval", "group-schedules.html#scheduledayinterval"}, {"OS:Schedule:Week:Daily", "group-schedules.html#scheduleweekdaily"}, @@ -192,6 +193,9 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:Coil:Cooling:WaterToAirHeatPump:EquationFit", "group-heating-and-cooling-coils.html#coilcoolingwatertoairheatpumpequationfit"}, {"OS:Coil:Cooling:WaterToAirHeatPump:VariableSpeedEquationFit", "group-heating-and-cooling-coils.html#coilcoolingwatertoairheatpumpvariablespeedequationfit"}, {"OS:Coil:Cooling:FourPipeBeam", "group-heating-and-cooling-coils.html#coilcoolingfourpipebeam"}, + {"OS:Coil:Cooling:DX:TwoStageWithHumidityControlMode", "group-heating-and-cooling-coils.html#coilcoolingdxtwostagewithhumiditycontrolmode"}, + {"OS:Coil:Cooling:DX:MultiSpeed:StageData", "group-heating-and-cooling-coils.html#coilcoolingdxmultispeed"}, + {"OS:Coil:Cooling:Water:Panel:Radiant", "group-radiative-convective-units.html#zonehvaccoolingpanelradiantconvectivewater"}, // Coils - Heating {"OS:Coil:Heating:Gas", "group-heating-and-cooling-coils.html#coilheatinggas-000"}, @@ -207,6 +211,12 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:Coil:Heating:WaterToAirHeatPump:VariableSpeedEquationFit", "group-heating-and-cooling-coils.html#coilheatingwatertoairheatpumpvariablespeedequationfit"}, {"OS:Coil:Heating:Desuperheater", "group-heating-and-cooling-coils.html#coilheatingdesuperheater"}, {"OS:Coil:Heating:FourPipeBeam", "group-heating-and-cooling-coils.html#coilheatingfourpipebeam"}, + {"OS:Coil:Heating:Gas:MultiStage", "group-heating-and-cooling-coils.html#coilheatinggasmultistage"}, + {"OS:Coil:Heating:Gas:MultiStage:StageData", "group-heating-and-cooling-coils.html#coilheatinggasmultistage"}, + {"OS:Coil:Heating:LowTemperatureRadiant:ConstantFlow", "group-radiative-convective-units.html#zonehvaclowtemperatureradiantconstantflow"}, + {"OS:Coil:Heating:LowTemperatureRadiant:VariableFlow", "group-radiative-convective-units.html#zonehvaclowtemperatureradiantvariableflowdesign"}, + {"OS:Coil:Heating:Water:Baseboard:Radiant", "group-radiative-convective-units.html#zonehvacbaseboardradiantconvectivewater"}, + {"OS:Coil:WaterHeating:AirToWaterHeatPump", "group-heating-and-cooling-coils.html#coilwaterheatingairtowaterheatpumppumped"}, {"OS:Coil:WaterHeating:AirToWaterHeatPump:Pumped", "group-heating-and-cooling-coils.html#coilwaterheatingairtowaterheatpumppumped"}, {"OS:Coil:WaterHeating:AirToWaterHeatPump:Wrapped", "group-heating-and-cooling-coils.html#coilwaterheatingairtowaterheatpumpwrapped"}, {"OS:Coil:WaterHeating:Desuperheater", "group-heating-and-cooling-coils.html#coilwaterheatingdesuperheater"}, @@ -262,6 +272,7 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:SetpointManager:OutdoorAirPretreat", "group-setpoint-managers.html#setpointmanageroutdoorairpretreat"}, {"OS:SetpointManager:MultiZone:Heating:Average", "group-setpoint-managers.html#setpointmanagermultizoneheataverage"}, {"OS:SetpointManager:MultiZone:Cooling:Average", "group-setpoint-managers.html#setpointmanagermultizonecoolaverage"}, + {"OS:SetpointManager:FollowSystemNodeTemperature", "group-setpoint-managers.html#setpointmanagerfollowsystemnodetemperature"}, // Pumps {"OS:Pump:VariableSpeed", "group-pumps.html#pumpvariablespeed"}, From 059fd079a58a76c54ee36a5c9b63c82645cd4fe3 Mon Sep 17 00:00:00 2001 From: Ski90Moo Date: Sun, 31 May 2026 18:04:11 +0200 Subject: [PATCH 04/13] feat: add 37 more IDD type URL mappings Adds BigLadder doc URL mappings for: LowTemperatureRadiant coils, CoilPerformance:DX:Cooling, Coil:Heating:Water:Baseboard, 10 setpoint managers (MultiZone/SingleZone humidity, SingleZone stage, SystemNodeReset), SolarCollectorPerformance x2, Chiller:Absorption, CentralHeatPumpSystem:Module, PlantComponent:TemperatureSource/UserDefined, CoolingTower:VariableSpeed, CoolingTowerPerformance x2, Pipe:Indoor/Outdoor/Duct, TemperingValve, LoadProfile:Plant, Fan:ComponentModel, Site:GroundTemperature:Undisturbed:KusudaAchenbach, SwimmingPool:Indoor, AirTerminal:SingleDuct:ConstantVolume:FourPipeInduction, and 5 new curve types. Co-Authored-By: Claude Sonnet 4.6 --- src/model_editor/IddObjectDocUrl.hpp | 47 +++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/model_editor/IddObjectDocUrl.hpp b/src/model_editor/IddObjectDocUrl.hpp index 3aae4f016..3d202a2fa 100644 --- a/src/model_editor/IddObjectDocUrl.hpp +++ b/src/model_editor/IddObjectDocUrl.hpp @@ -30,7 +30,8 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:ZoneAirContaminantBalance", "group-simulation-parameters.html#zoneaircontaminantbalance"}, // Location and Climate - {"OS:Site:Location", "group-location-climate-weather-file-access.html#sitelocation"}, + {"OS:Site:Location", "group-location-climate-weather-file-access.html#sitelocation"}, + {"OS:Site:GroundTemperature:Undisturbed:KusudaAchenbach", "group-location-climate-weather-file-access.html#sitegroundtemperatureundisturbedkusudaachenbach"}, {"OS:Site:GroundTemperature:BuildingSurface", "group-location-climate-weather-file-access.html#sitegroundtemperaturebuildingsurface"}, {"OS:Site:GroundTemperature:FCfactorMethod", "group-location-climate-weather-file-access.html#sitegroundtemperaturefcfactormethod"}, {"OS:Site:GroundReflectance", "group-location-climate-weather-file-access.html#sitegroundreflectance"}, @@ -94,6 +95,7 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:SteamEquipment", "group-internal-gains-people-lights-other.html#steamequipment"}, {"OS:OtherEquipment", "group-internal-gains-people-lights-other.html#otherequipment"}, {"OS:InternalMass", "group-internal-gains-people-lights-other.html#internalmass"}, + {"OS:SwimmingPool:Indoor", "group-internal-gains-people-lights-other.html#swimmingpoolindoor"}, // Exterior Energy Use {"OS:Exterior:Lights", "group-exterior-energy-use-equipment.html#exteriorlights"}, @@ -172,7 +174,8 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:AirTerminal:DualDuct:VAV", "group-air-distribution-equipment.html#airterminaldualductvav"}, {"OS:AirTerminal:DualDuct:VAV:OutdoorAir", "group-air-distribution-equipment.html#airterminaldualductvavoutdoorair"}, {"OS:AirTerminal:DualDuct:ConstantVolume", "group-air-distribution-equipment.html#airterminaldualductconstantvolume"}, - {"OS:AirTerminal:FourPipeInduction", "group-air-distribution-equipment.html#airterminalfourpipeinduction"}, + {"OS:AirTerminal:FourPipeInduction", "group-air-distribution-equipment.html#airterminalfourpipeinduction"}, + {"OS:AirTerminal:SingleDuct:ConstantVolume:FourPipeInduction", "group-air-distribution-equipment.html#airterminalsingleductconstantvolumefourpipeinduction"}, // Fans {"OS:Fan:ConstantVolume", "group-fans.html#fanconstantvolume"}, @@ -180,6 +183,7 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:Fan:OnOff", "group-fans.html#fanonoff"}, {"OS:Fan:ZoneExhaust", "group-fans.html#fanzoneexhaust"}, {"OS:Fan:SystemModel", "group-fans.html#fansystemmodel"}, + {"OS:Fan:ComponentModel", "group-fans.html#fancomponentmodel"}, // Coils - Cooling {"OS:Coil:Cooling:DX:SingleSpeed", "group-heating-and-cooling-coils.html#coilcoolingdxsinglespeed"}, @@ -196,6 +200,9 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:Coil:Cooling:DX:TwoStageWithHumidityControlMode", "group-heating-and-cooling-coils.html#coilcoolingdxtwostagewithhumiditycontrolmode"}, {"OS:Coil:Cooling:DX:MultiSpeed:StageData", "group-heating-and-cooling-coils.html#coilcoolingdxmultispeed"}, {"OS:Coil:Cooling:Water:Panel:Radiant", "group-radiative-convective-units.html#zonehvaccoolingpanelradiantconvectivewater"}, + {"OS:Coil:Cooling:LowTemperatureRadiant:ConstantFlow", "group-radiative-convective-units.html#zonehvaclowtemperatureradiantconstantflow"}, + {"OS:Coil:Cooling:LowTemperatureRadiant:VariableFlow", "group-radiative-convective-units.html#zonehvaclowtemperatureradiantvariableflow"}, + {"OS:CoilPerformance:DX:Cooling", "group-heating-and-cooling-coils.html#coilperformancedxcooling"}, // Coils - Heating {"OS:Coil:Heating:Gas", "group-heating-and-cooling-coils.html#coilheatinggas-000"}, @@ -215,6 +222,7 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:Coil:Heating:Gas:MultiStage:StageData", "group-heating-and-cooling-coils.html#coilheatinggasmultistage"}, {"OS:Coil:Heating:LowTemperatureRadiant:ConstantFlow", "group-radiative-convective-units.html#zonehvaclowtemperatureradiantconstantflow"}, {"OS:Coil:Heating:LowTemperatureRadiant:VariableFlow", "group-radiative-convective-units.html#zonehvaclowtemperatureradiantvariableflowdesign"}, + {"OS:Coil:Heating:Water:Baseboard", "group-radiative-convective-units.html#zonehvacbaseboardconvectivewater"}, {"OS:Coil:Heating:Water:Baseboard:Radiant", "group-radiative-convective-units.html#zonehvacbaseboardradiantconvectivewater"}, {"OS:Coil:WaterHeating:AirToWaterHeatPump", "group-heating-and-cooling-coils.html#coilwaterheatingairtowaterheatpumppumped"}, {"OS:Coil:WaterHeating:AirToWaterHeatPump:Pumped", "group-heating-and-cooling-coils.html#coilwaterheatingairtowaterheatpumppumped"}, @@ -272,7 +280,17 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:SetpointManager:OutdoorAirPretreat", "group-setpoint-managers.html#setpointmanageroutdoorairpretreat"}, {"OS:SetpointManager:MultiZone:Heating:Average", "group-setpoint-managers.html#setpointmanagermultizoneheataverage"}, {"OS:SetpointManager:MultiZone:Cooling:Average", "group-setpoint-managers.html#setpointmanagermultizonecoolaverage"}, - {"OS:SetpointManager:FollowSystemNodeTemperature", "group-setpoint-managers.html#setpointmanagerfollowsystemnodetemperature"}, + {"OS:SetpointManager:FollowSystemNodeTemperature", "group-setpoint-managers.html#setpointmanagerfollowsystemnodetemperature"}, + {"OS:SetpointManager:MultiZone:Humidity:Maximum", "group-setpoint-managers.html#setpointmanagermultizonehumiditymaximum"}, + {"OS:SetpointManager:MultiZone:Humidity:Minimum", "group-setpoint-managers.html#setpointmanagermultizonehumidityminimum"}, + {"OS:SetpointManager:MultiZone:MaximumHumidity:Average", "group-setpoint-managers.html#setpointmanagermultizonemaximumhumidityaverage"}, + {"OS:SetpointManager:MultiZone:MinimumHumidity:Average", "group-setpoint-managers.html#setpointmanagermultizoneminimumhumidityaverage"}, + {"OS:SetpointManager:SingleZone:Humidity:Maximum", "group-setpoint-managers.html#setpointmanagersinglezonehumiditymaximum"}, + {"OS:SetpointManager:SingleZone:Humidity:Minimum", "group-setpoint-managers.html#setpointmanagersinglezonehumidityminimum"}, + {"OS:SetpointManager:SingleZone:OneStageCooling", "group-setpoint-managers.html#setpointmanagersinglezoneonestagecooling"}, + {"OS:SetpointManager:SingleZone:OneStageHeating", "group-setpoint-managers.html#setpointmanagersinglezoneonestageheating"}, + {"OS:SetpointManager:SystemNodeReset:Humidity", "group-setpoint-managers.html#setpointmanagersystemnoderesethumidity"}, + {"OS:SetpointManager:SystemNodeReset:Temperature", "group-setpoint-managers.html#setpointmanagersystemnoderesettemperature"}, // Pumps {"OS:Pump:VariableSpeed", "group-pumps.html#pumpvariablespeed"}, @@ -285,12 +303,15 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:SolarCollector:IntegralCollectorStorage", "group-solar-collectors.html#solarcollectorintegralcollectorstorage"}, {"OS:SolarCollector:UnglazedTranspired", "group-solar-collectors.html#solarcollectorunglazedtranspired"}, {"OS:SolarCollector:FlatPlate:PhotovoltaicThermal", "group-solar-collectors.html#solarcollectorflatplatephotovoltaicthermal"}, + {"OS:SolarCollectorPerformance:FlatPlate", "group-solar-collectors.html#solarcollectorperformanceflatplate"}, + {"OS:SolarCollectorPerformance:IntegralCollectorStorage", "group-solar-collectors.html#solarcollectorperformanceintegralcollectorstorage"}, // Plant Heating and Cooling Equipment {"OS:Boiler:HotWater", "group-plant-equipment.html#boilerhotwater"}, {"OS:Boiler:Steam", "group-plant-equipment.html#boilersteam"}, {"OS:Chiller:Electric:EIR", "group-plant-equipment.html#chillerelectriceir"}, {"OS:Chiller:Electric:ReformulatedEIR", "group-plant-equipment.html#chillerelectricreformulatedeir"}, + {"OS:Chiller:Absorption", "group-plant-equipment.html#chillerabsorption"}, {"OS:Chiller:Absorption:Indirect", "group-plant-equipment.html#chillerabsorptionindirect"}, {"OS:Chiller:Absorption:Direct", "group-plant-equipment.html#chillerabsorptiondirect"}, {"OS:ChillerHeater:Absorption:DirectFired", "group-plant-equipment.html#chillerheaterabsorptiondirectfired"}, @@ -307,12 +328,18 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:HeatPump:AirToWater:Cooling", "group-plant-equipment.html#plhp_air_to_water"}, {"OS:HeatPump:AirToWater:Heating", "group-plant-equipment.html#plhp_air_to_water"}, {"OS:CentralHeatPumpSystem", "group-plant-equipment.html#centralheatpumpsystem"}, + {"OS:CentralHeatPumpSystem:Module", "group-plant-equipment.html#centralheatpumpsystem"}, {"OS:ChillerHeaterPerformance:Electric:EIR", "group-plant-equipment.html#chillerheaterperformancelectriceir"}, + {"OS:PlantComponent:TemperatureSource", "group-plant-equipment.html#plantcomponenttemperaturesource"}, + {"OS:PlantComponent:UserDefined", "group-user-defined-hvac-and-plant-component.html#plantcomponentuserdefined"}, // Cooling Towers and Fluid Coolers {"OS:CoolingTower:SingleSpeed", "group-condenser-equipment.html#coolingtowersinglespeed"}, {"OS:CoolingTower:TwoSpeed", "group-condenser-equipment.html#coolingtowertwospeed"}, + {"OS:CoolingTower:VariableSpeed", "group-condenser-equipment.html#coolingtowervariablespeed"}, {"OS:CoolingTower:VariableSpeed:Merkel", "group-condenser-equipment.html#coolingtowervariablespeedmerkel"}, + {"OS:CoolingTowerPerformance:CoolTools", "group-condenser-equipment.html#coolingtowerperformancecooltools"}, + {"OS:CoolingTowerPerformance:YorkCalc", "group-condenser-equipment.html#coolingtowerperformanceyorkcalc"}, {"OS:EvaporativeFluidCooler:SingleSpeed", "group-condenser-equipment.html#evaporativefluidcoolersinglespeed"}, {"OS:EvaporativeFluidCooler:TwoSpeed", "group-condenser-equipment.html#evaporativefluidcoolertwospeed"}, {"OS:FluidCooler:SingleSpeed", "group-condenser-equipment.html#fluidcoolersinglespeed"}, @@ -363,6 +390,9 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { // Node / Branch Management {"OS:Pipe:Adiabatic", "group-node-branch-management.html#pipeadiabatic"}, + {"OS:Pipe:Indoor", "group-node-branch-management.html#pipeindoor"}, + {"OS:Pipe:Outdoor", "group-node-branch-management.html#pipeoutdoor"}, + {"OS:Duct", "group-node-branch-management.html#duct"}, // Plant / Condenser Control {"OS:PlantLoop", "group-plant-condenser-control.html#plantloop"}, @@ -375,6 +405,8 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:PlantEquipmentOperation:OutdoorWetBulb", "group-plant-condenser-control.html#plantequipmentoperationoutdoorwetbulb"}, {"OS:PlantEquipmentOperation:ThermalEnergyStorage", "group-plant-condenser-control.html#plantequipmentoperationthermalenergystorage"}, {"OS:PlantEquipmentOperation:Uncontrolled", "group-plant-condenser-control.html#plantequipmentoperationuncontrolled"}, + {"OS:TemperingValve", "group-plant-condenser-flow-control.html#temperingvalve"}, + {"OS:LoadProfile:Plant", "group-non-zone-equipment.html#loadprofileplant"}, {"OS:AvailabilityManagerAssignmentList", "group-system-availability-managers.html#availabilitymanagerassignmentlist"}, {"OS:AvailabilityManager:Scheduled", "group-system-availability-managers.html#availabilitymanagerscheduled"}, {"OS:AvailabilityManager:ScheduledOn", "group-system-availability-managers.html#availabilitymanagerscheduledon"}, @@ -412,8 +444,13 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:Curve:CubicLinear", "group-performance-curves.html#curvecubiclinear"}, {"OS:Curve:Triquadratic", "group-performance-curves.html#curvetriquadratic"}, {"OS:Curve:FanPressureRise", "group-performance-curves.html#curvefanpressurerise"}, - {"OS:Curve:ExponentialDecay", "group-performance-curves.html#curveexponentialdecay"}, - {"OS:Curve:Sigmoid", "group-performance-curves.html#curvesigmoid"}, + {"OS:Curve:ExponentialDecay", "group-performance-curves.html#curveexponentialdecay"}, + {"OS:Curve:ExponentialSkewNormal", "group-performance-curves.html#curveexponentialskewnormal"}, + {"OS:Curve:Sigmoid", "group-performance-curves.html#curvesigmoid"}, + {"OS:Curve:QuadLinear", "group-performance-curves.html#curvequadlinear"}, + {"OS:Curve:QuintLinear", "group-performance-curves.html#curvequintlinear"}, + {"OS:Curve:RectangularHyperbola1", "group-performance-curves.html#curverectangularhyperbola1"}, + {"OS:Curve:RectangularHyperbola2", "group-performance-curves.html#curverectangularhyperbola2"}, {"OS:Table:IndependentVariable", "group-performance-tables.html#tableindependentvariable"}, {"OS:Table:IndependentVariableList", "group-performance-tables.html#tableindependentvariablelist"}, {"OS:Table:Lookup", "group-performance-tables.html#tablelookup"}, From 4e7c6c3346f0a5f3d519c9569e052d2412c6630e Mon Sep 17 00:00:00 2001 From: Ski90Moo Date: Sun, 31 May 2026 20:45:55 +0200 Subject: [PATCH 05/13] feat: add clickable doc links to sidebar category headers Extends OSCollapsibleItemHeader to optionally render its text as a clickable BigLadder hyperlink. Adds a URL-aware constructor to ModelObjectTypeListView. Applies links to four left-sidebar panels: Loads, Constructions (subtab), Materials (subtab), and Other Schedules. Co-Authored-By: Claude Sonnet 4.6 --- src/openstudio_lib/ConstructionsView.cpp | 34 ++++++----- src/openstudio_lib/ConstructionsView.hpp | 5 +- src/openstudio_lib/LoadsView.cpp | 41 +++++++------ src/openstudio_lib/LoadsView.hpp | 5 +- src/openstudio_lib/MaterialsView.cpp | 58 +++++++++---------- src/openstudio_lib/MaterialsView.hpp | 5 +- .../ModelObjectTypeListView.cpp | 14 ++++- .../ModelObjectTypeListView.hpp | 9 ++- .../OSCollapsibleItemHeader.cpp | 17 +++++- .../OSCollapsibleItemHeader.hpp | 5 +- src/openstudio_lib/ScheduleOthersView.cpp | 24 +++++--- src/openstudio_lib/ScheduleOthersView.hpp | 5 +- 12 files changed, 141 insertions(+), 81 deletions(-) diff --git a/src/openstudio_lib/ConstructionsView.cpp b/src/openstudio_lib/ConstructionsView.cpp index eee61c450..ce80d4158 100644 --- a/src/openstudio_lib/ConstructionsView.cpp +++ b/src/openstudio_lib/ConstructionsView.cpp @@ -19,28 +19,32 @@ #include #include +#include +#include namespace openstudio { ConstructionsView::ConstructionsView(bool isIP, const openstudio::model::Model& model, QWidget* parent) - : ModelSubTabView(new ModelObjectTypeListView(ConstructionsView::modelObjectTypesAndNames(), model, true, OSItemType::ListItem, false, parent), - new ConstructionsInspectorView(isIP, model, parent), false, parent) { + : ModelSubTabView( + new ModelObjectTypeListView(ConstructionsView::modelObjectTypesNamesAndUrls(), model, true, OSItemType::ListItem, false, parent), + new ConstructionsInspectorView(isIP, model, parent), false, parent) { connect(this, &ConstructionsView::toggleUnitsClicked, modelObjectInspectorView(), &ModelObjectInspectorView::toggleUnitsClicked); } -std::vector> ConstructionsView::modelObjectTypesAndNames() { - std::vector> result; - result.push_back(std::make_pair(IddObjectType::OS_Construction, "Constructions")); - result.push_back(std::make_pair(IddObjectType::OS_Construction_AirBoundary, "Air Boundary Constructions")); - result.push_back(std::make_pair(IddObjectType::OS_Construction_InternalSource, "Internal Source Constructions")); - result.push_back( - std::make_pair(IddObjectType::OS_Construction_CfactorUndergroundWall, "C-factor Underground Wall Constructions")); - result.push_back( - std::make_pair(IddObjectType::OS_Construction_FfactorGroundFloor, "F-factor Ground Floor Constructions")); - // Not currently supported - //result.push_back(std::make_pair(IddObjectType::OS_Construction_WindowDataFile, "Window Data File Constructions")); - - return result; +std::vector> ConstructionsView::modelObjectTypesNamesAndUrls() { + static const QString base = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL); + static const QString sce = base + QStringLiteral("group-surface-construction-elements.html"); + + using T = std::tuple; + return { + T{IddObjectType::OS_Construction, "Constructions", sce + "#construction-000"}, + T{IddObjectType::OS_Construction_AirBoundary, "Air Boundary Constructions", sce + "#constructionairboundary"}, + T{IddObjectType::OS_Construction_InternalSource, "Internal Source Constructions", sce + "#constructioninternalsource"}, + T{IddObjectType::OS_Construction_CfactorUndergroundWall, "C-factor Underground Wall Constructions", sce + "#constructioncfactorundergroundwall"}, + T{IddObjectType::OS_Construction_FfactorGroundFloor, "F-factor Ground Floor Constructions", sce + "#constructionffactorgroundfloor"}, + // Not currently supported + // T{IddObjectType::OS_Construction_WindowDataFile, "Window Data File Constructions", {}}, + }; } ConstructionsInspectorView::ConstructionsInspectorView(bool isIP, const model::Model& model, QWidget* parent) diff --git a/src/openstudio_lib/ConstructionsView.hpp b/src/openstudio_lib/ConstructionsView.hpp index 07e88843f..f27cc5ed3 100644 --- a/src/openstudio_lib/ConstructionsView.hpp +++ b/src/openstudio_lib/ConstructionsView.hpp @@ -11,6 +11,9 @@ #include +#include +#include + namespace openstudio { class ConstructionsView : public ModelSubTabView @@ -23,7 +26,7 @@ class ConstructionsView : public ModelSubTabView virtual ~ConstructionsView() {} private: - static std::vector> modelObjectTypesAndNames(); + static std::vector> modelObjectTypesNamesAndUrls(); }; class ConstructionsInspectorView : public ModelObjectInspectorView diff --git a/src/openstudio_lib/LoadsView.cpp b/src/openstudio_lib/LoadsView.cpp index 3e505a96a..c4f7b1d3b 100644 --- a/src/openstudio_lib/LoadsView.cpp +++ b/src/openstudio_lib/LoadsView.cpp @@ -20,6 +20,7 @@ #include +#include #include #include #include @@ -28,32 +29,38 @@ #include #include #include +#include #include namespace openstudio { LoadsView::LoadsView(bool isIP, const openstudio::model::Model& model, QWidget* parent) - : ModelSubTabView(new ModelObjectTypeListView(LoadsView::modelObjectTypesAndNames(), model, true, OSItemType::CollapsibleListHeader, false, parent), - new LoadsInspectorView(isIP, model, parent), false, parent) { + : ModelSubTabView( + new ModelObjectTypeListView(LoadsView::modelObjectTypesNamesAndUrls(), model, true, OSItemType::CollapsibleListHeader, false, parent), + new LoadsInspectorView(isIP, model, parent), false, parent) { connect(this, &LoadsView::toggleUnitsClicked, modelObjectInspectorView(), &ModelObjectInspectorView::toggleUnitsClicked); } -std::vector> LoadsView::modelObjectTypesAndNames() { - std::vector> result; - - result.push_back(std::make_pair(IddObjectType::OS_People_Definition, "People Definitions")); - result.push_back(std::make_pair(IddObjectType::OS_Lights_Definition, "Lights Definitions")); - result.push_back(std::make_pair(IddObjectType::OS_Luminaire_Definition, "Luminaire Definitions")); - result.push_back(std::make_pair(IddObjectType::OS_ElectricEquipment_Definition, "Electric Equipment Definitions")); - result.push_back(std::make_pair(IddObjectType::OS_GasEquipment_Definition, "Gas Equipment Definitions")); - result.push_back(std::make_pair(IddObjectType::OS_SteamEquipment_Definition, "Steam Equipment Definitions")); - result.push_back(std::make_pair(IddObjectType::OS_OtherEquipment_Definition, "Other Equipment Definitions")); - result.push_back(std::make_pair(IddObjectType::OS_InternalMass_Definition, "Internal Mass Definitions")); - result.push_back(std::make_pair(IddObjectType::OS_WaterUse_Equipment_Definition, "Water Use Equipment Definitions")); - result.push_back(std::make_pair(IddObjectType::OS_HotWaterEquipment_Definition, "Hot Water Equipment Definitions")); - - return result; +std::vector> LoadsView::modelObjectTypesNamesAndUrls() { + static const QString base = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL); + static const QString iag = base + QStringLiteral("group-internal-gains-people-lights-other.html"); + static const QString tzg = base + QStringLiteral("group-thermal-zone-description-geometry.html"); + static const QString wsg = base + QStringLiteral("group-water-systems.html"); + + using T = std::tuple; + return { + T{IddObjectType::OS_People_Definition, "People Definitions", iag + "#people"}, + T{IddObjectType::OS_Lights_Definition, "Lights Definitions", iag + "#lights-000"}, + T{IddObjectType::OS_Luminaire_Definition, "Luminaire Definitions", {}}, + T{IddObjectType::OS_ElectricEquipment_Definition, "Electric Equipment Definitions", iag + "#electricequipment"}, + T{IddObjectType::OS_GasEquipment_Definition, "Gas Equipment Definitions", iag + "#gasequipment"}, + T{IddObjectType::OS_SteamEquipment_Definition, "Steam Equipment Definitions", iag + "#steamequipment"}, + T{IddObjectType::OS_OtherEquipment_Definition, "Other Equipment Definitions", iag + "#otherequipment"}, + T{IddObjectType::OS_InternalMass_Definition, "Internal Mass Definitions", tzg + "#internalmass"}, + T{IddObjectType::OS_WaterUse_Equipment_Definition, "Water Use Equipment Definitions", wsg + "#wateruseequipment"}, + T{IddObjectType::OS_HotWaterEquipment_Definition, "Hot Water Equipment Definitions", iag + "#hotwaterequipment"}, + }; } void LoadsView::toggleUnits(bool displayIP) {} diff --git a/src/openstudio_lib/LoadsView.hpp b/src/openstudio_lib/LoadsView.hpp index 0fc7d1472..312caa574 100644 --- a/src/openstudio_lib/LoadsView.hpp +++ b/src/openstudio_lib/LoadsView.hpp @@ -13,6 +13,9 @@ #include +#include +#include + class QStackedWidget; namespace openstudio { @@ -27,7 +30,7 @@ class LoadsView : public ModelSubTabView virtual ~LoadsView() {} private: - static std::vector> modelObjectTypesAndNames(); + static std::vector> modelObjectTypesNamesAndUrls(); public slots: diff --git a/src/openstudio_lib/MaterialsView.cpp b/src/openstudio_lib/MaterialsView.cpp index 9eb763d2d..91513f8e6 100644 --- a/src/openstudio_lib/MaterialsView.cpp +++ b/src/openstudio_lib/MaterialsView.cpp @@ -29,44 +29,44 @@ #include #include +#include +#include namespace openstudio { MaterialsView::MaterialsView(bool isIP, const openstudio::model::Model& model, const QString& tabLabel, bool hasSubTabs, QWidget* parent) : ModelSubTabView( - new ModelObjectTypeListView(MaterialsView::modelObjectTypesAndNames(), model, true, OSItemType::CollapsibleListHeader, false, parent), - new MaterialsInspectorView(isIP, model, parent), false, parent) { + new ModelObjectTypeListView(MaterialsView::modelObjectTypesNamesAndUrls(), model, true, OSItemType::CollapsibleListHeader, false, parent), + new MaterialsInspectorView(isIP, model, parent), false, parent) { // ModelObjectTypeListView will call reportItems for each IddObjectType, this results in inspector being build for each IddObjecType then thrown away connect(this, &MaterialsView::toggleUnitsClicked, modelObjectInspectorView(), &ModelObjectInspectorView::toggleUnitsClicked); } -std::vector> MaterialsView::modelObjectTypesAndNames() { - std::vector> result; - result.push_back(std::make_pair(IddObjectType::OS_Material, "Materials")); - result.push_back(std::make_pair(IddObjectType::OS_Material_NoMass, "No Mass Materials")); - result.push_back(std::make_pair(IddObjectType::OS_Material_AirGap, "Air Gap Materials")); - - result.push_back( - std::make_pair(IddObjectType::OS_WindowMaterial_SimpleGlazingSystem, "Simple Glazing System Window Materials")); - result.push_back(std::make_pair(IddObjectType::OS_WindowMaterial_Glazing, "Glazing Window Materials")); - result.push_back(std::make_pair(IddObjectType::OS_WindowMaterial_Gas, "Gas Window Materials")); - result.push_back(std::make_pair(IddObjectType::OS_WindowMaterial_GasMixture, "Gas Mixture Window Materials")); - result.push_back(std::make_pair(IddObjectType::OS_WindowMaterial_Blind, "Blind Window Materials")); - result.push_back(std::make_pair(IddObjectType::OS_WindowMaterial_DaylightRedirectionDevice, - "Daylight Redirection Device Window Materials")); - result.push_back(std::make_pair(IddObjectType::OS_WindowMaterial_Screen, "Screen Window Materials")); - result.push_back(std::make_pair(IddObjectType::OS_WindowMaterial_Shade, "Shade Window Materials")); - - // Oddballs to be listed at the bottom of the list - result.push_back(std::make_pair(IddObjectType::OS_Material_InfraredTransparent, "Infrared Transparent Materials")); - result.push_back(std::make_pair(IddObjectType::OS_Material_RoofVegetation, "Roof Vegetation Materials")); - result.push_back(std::make_pair(IddObjectType::OS_WindowMaterial_Glazing_RefractionExtinctionMethod, - "Refraction Extinction Method Glazing Window Materials")); - - // TODO: commented out until ThermochromicGlazing is properly wrapped - // result.push_back(std::make_pair(IddObjectType::OS_WindowMaterial_GlazingGroup_Thermochromic, "Glazing Group Thermochromic Window Materials")); - - return result; +std::vector> MaterialsView::modelObjectTypesNamesAndUrls() { + static const QString base = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL); + static const QString sce = base + QStringLiteral("group-surface-construction-elements.html"); + + using T = std::tuple; + return { + T{IddObjectType::OS_Material, "Materials", sce + "#material"}, + T{IddObjectType::OS_Material_NoMass, "No Mass Materials", sce + "#materialnomass"}, + T{IddObjectType::OS_Material_AirGap, "Air Gap Materials", sce + "#materialairgap"}, + T{IddObjectType::OS_WindowMaterial_SimpleGlazingSystem, "Simple Glazing System Window Materials", sce + "#windowmaterialsimpleglazingsystem"}, + T{IddObjectType::OS_WindowMaterial_Glazing, "Glazing Window Materials", sce + "#windowmaterialglazing"}, + T{IddObjectType::OS_WindowMaterial_Gas, "Gas Window Materials", sce + "#windowmaterialgas"}, + T{IddObjectType::OS_WindowMaterial_GasMixture, "Gas Mixture Window Materials", sce + "#windowmaterialgasmixture"}, + T{IddObjectType::OS_WindowMaterial_Blind, "Blind Window Materials", sce + "#windowmaterialblind"}, + T{IddObjectType::OS_WindowMaterial_DaylightRedirectionDevice, "Daylight Redirection Device Window Materials", sce + "#windowmaterialblind"}, + T{IddObjectType::OS_WindowMaterial_Screen, "Screen Window Materials", sce + "#windowmaterialscreen"}, + T{IddObjectType::OS_WindowMaterial_Shade, "Shade Window Materials", sce + "#windowmaterialshade"}, + // Oddballs at the bottom + T{IddObjectType::OS_Material_InfraredTransparent, "Infrared Transparent Materials", sce + "#materialinfraredtransparent"}, + T{IddObjectType::OS_Material_RoofVegetation, "Roof Vegetation Materials", sce + "#materialroofvegetation"}, + T{IddObjectType::OS_WindowMaterial_Glazing_RefractionExtinctionMethod, "Refraction Extinction Method Glazing Window Materials", + sce + "#windowmaterialglazingrefractionextinctionmethod"}, + // TODO: commented out until ThermochromicGlazing is properly wrapped + // T{IddObjectType::OS_WindowMaterial_GlazingGroup_Thermochromic, "Glazing Group Thermochromic Window Materials", sce + "#windowmaterialglazinggroupthermochromic"}, + }; } MaterialsInspectorView::MaterialsInspectorView(bool isIP, const model::Model& model, QWidget* parent) diff --git a/src/openstudio_lib/MaterialsView.hpp b/src/openstudio_lib/MaterialsView.hpp index bd938d05d..373a8f5bb 100644 --- a/src/openstudio_lib/MaterialsView.hpp +++ b/src/openstudio_lib/MaterialsView.hpp @@ -11,6 +11,9 @@ #include +#include +#include + class QStackedWidget; namespace openstudio { @@ -25,7 +28,7 @@ class MaterialsView : public ModelSubTabView virtual ~MaterialsView() {} private: - static std::vector> modelObjectTypesAndNames(); + static std::vector> modelObjectTypesNamesAndUrls(); }; class MaterialsInspectorView : public ModelObjectInspectorView diff --git a/src/openstudio_lib/ModelObjectTypeListView.cpp b/src/openstudio_lib/ModelObjectTypeListView.cpp index 0132115ef..43c1d7148 100644 --- a/src/openstudio_lib/ModelObjectTypeListView.cpp +++ b/src/openstudio_lib/ModelObjectTypeListView.cpp @@ -38,8 +38,18 @@ ModelObjectTypeListView::ModelObjectTypeListView(const std::vector>& modelObjectTypesNamesAndUrls, + const model::Model& model, bool addScrollArea, OSItemType headerType, bool isLibrary, + QWidget* parent) + : OSCollapsibleItemList(addScrollArea, parent), m_model(model), m_headerType(headerType), m_isLibrary(isLibrary) { + for (auto it = modelObjectTypesNamesAndUrls.rbegin(); it != modelObjectTypesNamesAndUrls.rend(); ++it) { + addModelObjectType(std::get<0>(*it), std::get<1>(*it), std::get<2>(*it)); + } + selectFirstCollapsibleItem(); +} + +void ModelObjectTypeListView::addModelObjectType(const IddObjectType& iddObjectType, const std::string& name, const QString& url) { + auto* collapsibleItemHeader = new OSCollapsibleItemHeader(name, OSItemId("", "", false), m_headerType, url); auto* modelObjectListView = new ModelObjectListView(iddObjectType, m_model, false, m_isLibrary); auto* modelObjectTypeItem = new ModelObjectTypeItem(collapsibleItemHeader, modelObjectListView); diff --git a/src/openstudio_lib/ModelObjectTypeListView.hpp b/src/openstudio_lib/ModelObjectTypeListView.hpp index f3e48a93c..815e1e3bb 100644 --- a/src/openstudio_lib/ModelObjectTypeListView.hpp +++ b/src/openstudio_lib/ModelObjectTypeListView.hpp @@ -14,6 +14,10 @@ #include +#include + +#include + class QVBoxLayout; class QHBoxLayout; @@ -30,9 +34,12 @@ class ModelObjectTypeListView : public OSCollapsibleItemList ModelObjectTypeListView(const std::vector>& modelObjectTypesAndNames, const model::Model& model, bool addScrollArea, OSItemType headerType, bool isLibrary, QWidget* parent = nullptr); + ModelObjectTypeListView(const std::vector>& modelObjectTypesNamesAndUrls, + const model::Model& model, bool addScrollArea, OSItemType headerType, bool isLibrary, QWidget* parent = nullptr); + virtual ~ModelObjectTypeListView() {} - void addModelObjectType(const IddObjectType& iddObjectType, const std::string& name); + void addModelObjectType(const IddObjectType& iddObjectType, const std::string& name, const QString& url = {}); void addModelObjectCategoryPlaceholder(const std::string& name); diff --git a/src/openstudio_lib/OSCollapsibleItemHeader.cpp b/src/openstudio_lib/OSCollapsibleItemHeader.cpp index 462250aab..53aca6bbc 100644 --- a/src/openstudio_lib/OSCollapsibleItemHeader.cpp +++ b/src/openstudio_lib/OSCollapsibleItemHeader.cpp @@ -18,7 +18,8 @@ namespace openstudio { -OSCollapsibleItemHeader::OSCollapsibleItemHeader(const std::string& text, const OSItemId& itemId, OSItemType type, QWidget* parent) +OSCollapsibleItemHeader::OSCollapsibleItemHeader(const std::string& text, const OSItemId& itemId, OSItemType type, const QString& url, + QWidget* parent) : QWidget(parent), m_mouseDown(false) { setFixedHeight(50); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); @@ -35,9 +36,19 @@ OSCollapsibleItemHeader::OSCollapsibleItemHeader(const std::string& text, const // Label - m_textLabel = new QLabel(QString::fromStdString(text)); + m_plainText = QString::fromStdString(text); + m_textLabel = new QLabel(); m_textLabel->setWordWrap(true); m_textLabel->setObjectName("H2"); + if (!url.isEmpty()) { + m_textLabel->setTextFormat(Qt::RichText); + m_textLabel->setOpenExternalLinks(true); + m_textLabel->setToolTip(url); + m_textLabel->setText( + QStringLiteral(R"(%2)").arg(url, m_plainText.toHtmlEscaped())); + } else { + m_textLabel->setText(m_plainText); + } mainHLayout->addWidget(m_textLabel, 10); mainHLayout->addStretch(); @@ -57,7 +68,7 @@ QSize OSCollapsibleItemHeader::sizeHint() const { } QString OSCollapsibleItemHeader::text() const { - return m_textLabel->text(); + return m_plainText; } bool OSCollapsibleItemHeader::expanded() const { diff --git a/src/openstudio_lib/OSCollapsibleItemHeader.hpp b/src/openstudio_lib/OSCollapsibleItemHeader.hpp index 14cafa455..e6b1c477e 100644 --- a/src/openstudio_lib/OSCollapsibleItemHeader.hpp +++ b/src/openstudio_lib/OSCollapsibleItemHeader.hpp @@ -8,6 +8,8 @@ #include "OSItem.hpp" +#include + class QLabel; class QVBoxLayout; class QPaintEvent; @@ -21,7 +23,7 @@ class OSCollapsibleItemHeader : public QWidget public: OSCollapsibleItemHeader(const std::string& text, const OSItemId& itemId, OSItemType type = OSItemType::CollapsibleListHeader, - QWidget* parent = nullptr); + const QString& url = {}, QWidget* parent = nullptr); virtual ~OSCollapsibleItemHeader() = default; @@ -49,6 +51,7 @@ class OSCollapsibleItemHeader : public QWidget QLabel* m_arrowLabel; QLabel* m_textLabel; + QString m_plainText; bool m_expanded; bool m_selected; diff --git a/src/openstudio_lib/ScheduleOthersView.cpp b/src/openstudio_lib/ScheduleOthersView.cpp index 33c449133..2c34c4ae7 100644 --- a/src/openstudio_lib/ScheduleOthersView.cpp +++ b/src/openstudio_lib/ScheduleOthersView.cpp @@ -16,20 +16,26 @@ #include #include +#include +#include namespace openstudio { ScheduleOthersView::ScheduleOthersView(const openstudio::model::Model& model, QWidget* parent) : ModelSubTabView( - new ModelObjectTypeListView(ScheduleOthersView::modelObjectTypesAndNames(), model, true, OSItemType::CollapsibleListHeader, false, parent), - new ScheduleOthersInspectorView(model, parent), false, parent) {} - -std::vector> ScheduleOthersView::modelObjectTypesAndNames() { - return {{ - {IddObjectType::OS_Schedule_Constant, "Schedule Constant"}, - {IddObjectType::OS_Schedule_Compact, "Schedule Compact"}, - {IddObjectType::OS_Schedule_File, "Schedule File"}, - }}; + new ModelObjectTypeListView(ScheduleOthersView::modelObjectTypesNamesAndUrls(), model, true, OSItemType::CollapsibleListHeader, false, parent), + new ScheduleOthersInspectorView(model, parent), false, parent) {} + +std::vector> ScheduleOthersView::modelObjectTypesNamesAndUrls() { + static const QString base = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL); + static const QString sch = base + QStringLiteral("group-schedules.html"); + + using T = std::tuple; + return { + T{IddObjectType::OS_Schedule_Constant, "Schedule Constant", sch + "#scheduleconstant"}, + T{IddObjectType::OS_Schedule_Compact, "Schedule Compact", sch + "#schedulecompact"}, + T{IddObjectType::OS_Schedule_File, "Schedule File", sch + "#schedulefile"}, + }; } ScheduleOthersInspectorView::ScheduleOthersInspectorView(const model::Model& model, QWidget* parent) diff --git a/src/openstudio_lib/ScheduleOthersView.hpp b/src/openstudio_lib/ScheduleOthersView.hpp index c57e830c0..0262e3699 100644 --- a/src/openstudio_lib/ScheduleOthersView.hpp +++ b/src/openstudio_lib/ScheduleOthersView.hpp @@ -11,6 +11,9 @@ #include +#include +#include + class QStackedWidget; namespace openstudio { @@ -25,7 +28,7 @@ class ScheduleOthersView : public ModelSubTabView virtual ~ScheduleOthersView() = default; private: - static std::vector> modelObjectTypesAndNames(); + static std::vector> modelObjectTypesNamesAndUrls(); }; class ScheduleOthersInspectorView : public ModelObjectInspectorView From bece6047c55352b0cbff7ba7461c55378bb48755 Mon Sep 17 00:00:00 2001 From: Ski90Moo Date: Sun, 31 May 2026 21:45:18 +0200 Subject: [PATCH 06/13] feat: add doc links to Site, Facility, and Life Cycle Costs tabs - Site / Weather File & Design Days: Weather File, Design Days, and Daylight Savings Time headers link to BigLadder I/O Reference - Site / Ground Temperatures: all five sidebar entries link to their respective Site:GroundTemperature:* and Site:WaterMainsTemperature docs - Site / Life Cycle Cost: Life Cycle Cost Parameters and NIST Fuel Escalation Rates headers link to LifeCycleCost docs - Facility tab: North Axis label links to Building object docs Co-Authored-By: Claude Sonnet 4.6 --- src/openstudio_lib/BuildingInspectorView.cpp | 11 +++++-- src/openstudio_lib/GroundTemperatureView.cpp | 31 +++++++++++++++----- src/openstudio_lib/GroundTemperatureView.hpp | 3 +- src/openstudio_lib/LifeCycleCostsTabView.cpp | 23 +++++++++++++-- src/openstudio_lib/LocationTabView.cpp | 21 +++++++++++-- src/openstudio_lib/YearSettingsWidget.cpp | 11 ++++++- 6 files changed, 85 insertions(+), 15 deletions(-) diff --git a/src/openstudio_lib/BuildingInspectorView.cpp b/src/openstudio_lib/BuildingInspectorView.cpp index eff88aac6..21761d573 100644 --- a/src/openstudio_lib/BuildingInspectorView.cpp +++ b/src/openstudio_lib/BuildingInspectorView.cpp @@ -41,6 +41,7 @@ #include #include #include +#include namespace openstudio { @@ -437,8 +438,14 @@ BuildingInspectorView::BuildingInspectorView(bool isIP, bool displayAdditionalPr vLayout = new QVBoxLayout(); label = new QLabel(); - label->setText("North Axis: "); - label->setStyleSheet("QLabel { font: bold; }"); + label->setTextFormat(Qt::RichText); + label->setOpenExternalLinks(true); + { + static const QString url = + QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL "group-simulation-parameters.html#building"); + label->setToolTip(url); + label->setText(QStringLiteral(R"(North Axis:)").arg(url)); + } vLayout->addWidget(label); m_northAxisEdit = new OSQuantityEdit2("deg", "deg", "deg", m_isIP); diff --git a/src/openstudio_lib/GroundTemperatureView.cpp b/src/openstudio_lib/GroundTemperatureView.cpp index 4ce5d28ba..f1e42dfe0 100644 --- a/src/openstudio_lib/GroundTemperatureView.cpp +++ b/src/openstudio_lib/GroundTemperatureView.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,7 @@ namespace openstudio { // GroundTemperatureEntry // ───────────────────────────────────────────────────────── -GroundTemperatureEntry::GroundTemperatureEntry(const QString& label, QWidget* parent) : QWidget(parent) { +GroundTemperatureEntry::GroundTemperatureEntry(const QString& label, const QString& url, QWidget* parent) : QWidget(parent) { setFixedHeight(50); setObjectName("GroundTemperatureEntry"); setProperty("style", "0"); @@ -48,9 +49,18 @@ GroundTemperatureEntry::GroundTemperatureEntry(const QString& label, QWidget* pa layout->setContentsMargins(9, 0, 9, 0); setLayout(layout); - m_label = new QLabel(label); + m_label = new QLabel(); m_label->setObjectName("H2"); m_label->setWordWrap(true); + if (!url.isEmpty()) { + m_label->setTextFormat(Qt::RichText); + m_label->setOpenExternalLinks(true); + m_label->setToolTip(url); + m_label->setText( + QStringLiteral(R"(%2)").arg(url, label.toHtmlEscaped())); + } else { + m_label->setText(label); + } layout->addWidget(m_label); } @@ -90,11 +100,18 @@ GroundTemperatureListView::GroundTemperatureListView(QWidget* parent) : QWidget( layout->setSpacing(0); setLayout(layout); - m_bsEntry = new GroundTemperatureEntry(tr("Building Surface Ground Temperatures"), this); - m_shEntry = new GroundTemperatureEntry(tr("Shallow Ground Temperatures"), this); - m_deepEntry = new GroundTemperatureEntry(tr("Deep Ground Temperatures"), this); - m_fcEntry = new GroundTemperatureEntry(tr("FCfactorMethod Ground Temperatures"), this); - m_waterMainsEntry = new GroundTemperatureEntry(tr("Water Mains Temperature"), this); + static const QString lcwBase = + QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL "group-location-climate-weather-file-access.html"); + m_bsEntry = new GroundTemperatureEntry(tr("Building Surface Ground Temperatures"), + lcwBase + "#sitegroundtemperaturebuildingsurface", this); + m_shEntry = new GroundTemperatureEntry(tr("Shallow Ground Temperatures"), + lcwBase + "#sitegroundtemperatureshallow", this); + m_deepEntry = new GroundTemperatureEntry(tr("Deep Ground Temperatures"), + lcwBase + "#sitegroundtemperaturedeep", this); + m_fcEntry = new GroundTemperatureEntry(tr("FCfactorMethod Ground Temperatures"), + lcwBase + "#sitegroundtemperaturefcfactormethod", this); + m_waterMainsEntry = new GroundTemperatureEntry(tr("Water Mains Temperature"), + lcwBase + "#sitewatermainstemperature", this); connect(m_bsEntry, &GroundTemperatureEntry::clicked, this, &GroundTemperatureListView::onBuildingSurfaceClicked); connect(m_shEntry, &GroundTemperatureEntry::clicked, this, &GroundTemperatureListView::onShallowClicked); diff --git a/src/openstudio_lib/GroundTemperatureView.hpp b/src/openstudio_lib/GroundTemperatureView.hpp index 94c30fa25..a8e426d24 100644 --- a/src/openstudio_lib/GroundTemperatureView.hpp +++ b/src/openstudio_lib/GroundTemperatureView.hpp @@ -12,6 +12,7 @@ #include #include +#include class QLabel; class QPushButton; @@ -36,7 +37,7 @@ class GroundTemperatureEntry : public QWidget Q_OBJECT public: - explicit GroundTemperatureEntry(const QString& label, QWidget* parent = nullptr); + explicit GroundTemperatureEntry(const QString& label, const QString& url = {}, QWidget* parent = nullptr); void setSelected(bool selected); diff --git a/src/openstudio_lib/LifeCycleCostsTabView.cpp b/src/openstudio_lib/LifeCycleCostsTabView.cpp index 670363625..ff6c222aa 100644 --- a/src/openstudio_lib/LifeCycleCostsTabView.cpp +++ b/src/openstudio_lib/LifeCycleCostsTabView.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #define OS_EDIT_WIDTH 150 @@ -58,8 +59,15 @@ void LifeCycleCostsView::createWidgets() { vLayout->setSpacing(10); label = new QLabel(); - label->setText("Life Cycle Cost Parameters"); label->setObjectName("H2"); + label->setTextFormat(Qt::RichText); + label->setOpenExternalLinks(true); + { + static const QString url = + QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL "lifecyclecost-parameters.html#lifecyclecostparameters"); + label->setToolTip(url); + label->setText(QStringLiteral(R"(Life Cycle Cost Parameters)").arg(url)); + } vLayout->addWidget(label); label = new QLabel(); @@ -142,8 +150,19 @@ void LifeCycleCostsView::createWidgets() { vLayout->setSpacing(5); label = new QLabel(); - label->setText("Use National Institute of Standards and Technology (NIST) Fuel Escalation Rates"); label->setObjectName("H2"); + label->setTextFormat(Qt::RichText); + label->setOpenExternalLinks(true); + { + static const QString url = + QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL "lifecyclecost-usepriceescalation.html#lifecyclecostusepriceescalation"); + label->setToolTip(url); + label->setText( + QStringLiteral(R"()" + "Use National Institute of Standards and Technology (NIST) Fuel Escalation Rates" + R"()") + .arg(url)); + } vLayout->addWidget(label); m_nistGroup = new QButtonGroup(this); diff --git a/src/openstudio_lib/LocationTabView.cpp b/src/openstudio_lib/LocationTabView.cpp index ce6cdb460..79402d0c8 100644 --- a/src/openstudio_lib/LocationTabView.cpp +++ b/src/openstudio_lib/LocationTabView.cpp @@ -209,8 +209,17 @@ LocationView::LocationView(bool isIP, const model::Model& model, const QString& mainHLine->setFrameShadow(QFrame::Sunken); // ***** Weather File ***** - auto* label = new QLabel(tr("Weather File")); + auto* label = new QLabel(); label->setObjectName("H2"); + label->setTextFormat(Qt::RichText); + label->setOpenExternalLinks(true); + { + static const QString url = QStringLiteral( + BIGLADDERSOFTWARE_DOC_BASE_URL + "group-location-climate-weather-file-access.html#group----location----climate----weather-file-access"); + label->setToolTip(url); + label->setText(QStringLiteral(R"(%2)").arg(url, tr("Weather File"))); + } m_weatherFileBtn = new QPushButton(this); m_weatherFileBtn->setFlat(true); @@ -456,8 +465,16 @@ LocationView::LocationView(bool isIP, const model::Model& model, const QString& scrollLayout->addWidget(mainHLine); // ***** Design Days ***** - label = new QLabel(tr("Design Days")); + label = new QLabel(); label->setObjectName("H2"); + label->setTextFormat(Qt::RichText); + label->setOpenExternalLinks(true); + { + static const QString url = + QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL "group-location-climate-weather-file-access.html#sizingperioddesignday"); + label->setToolTip(url); + label->setText(QStringLiteral(R"(%2)").arg(url, tr("Design Days"))); + } auto* btn = new QPushButton(tr("Import From DDY"), this); btn->setFlat(true); diff --git a/src/openstudio_lib/YearSettingsWidget.cpp b/src/openstudio_lib/YearSettingsWidget.cpp index fe838aa47..a2d761e69 100644 --- a/src/openstudio_lib/YearSettingsWidget.cpp +++ b/src/openstudio_lib/YearSettingsWidget.cpp @@ -102,8 +102,17 @@ YearSettingsWidget::YearSettingsWidget(const model::Model& model, QWidget* paren dstHLayout1->setContentsMargins(0, 0, 0, 0); dstHLayout1->setSpacing(10); - auto* dstLabel = new QLabel(tr("Daylight Savings Time:")); + auto* dstLabel = new QLabel(); dstLabel->setObjectName("H2"); + dstLabel->setTextFormat(Qt::RichText); + dstLabel->setOpenExternalLinks(true); + { + static const QString url = QStringLiteral( + BIGLADDERSOFTWARE_DOC_BASE_URL + "group-location-climate-weather-file-access.html#field-daylight-saving-time-indicator"); + dstLabel->setToolTip(url); + dstLabel->setText(QStringLiteral(R"(%2)").arg(url, tr("Daylight Savings Time:"))); + } dstHLayout1->addWidget(dstLabel); m_dstOnOffButton = new OSSwitch2(); From 40bdf5b076d64ea79f9b33c38bc4b1a6fb6a7129 Mon Sep 17 00:00:00 2001 From: Ski90Moo Date: Sun, 31 May 2026 22:01:07 +0200 Subject: [PATCH 07/13] refactor: replace BIGLADDERSOFTWARE_DOC_BASE_URL macro with accessor function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per PR review feedback: instead of passing the URL via target_compile_definitions, add bigladdersoftwareDocBaseUrl() to OpenStudioApplicationPathHelpers following the existing .cxx.in pattern. The URL is configured from BIGLADDERSOFTWARE_DOC_BASE_URL in FindOpenStudioSDK.cmake — visible alongside EnergyPlus version bumps each release. All call sites updated to use QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()). Co-Authored-By: Claude Sonnet 4.6 --- src/model_editor/CMakeLists.txt | 3 --- src/model_editor/IddObjectDocUrl.hpp | 4 +++- src/openstudio_lib/BuildingInspectorView.cpp | 3 ++- src/openstudio_lib/CMakeLists.txt | 3 --- src/openstudio_lib/ConstructionsView.cpp | 3 ++- src/openstudio_lib/GroundTemperatureView.cpp | 3 ++- src/openstudio_lib/LifeCycleCostsTabView.cpp | 5 +++-- src/openstudio_lib/LoadsView.cpp | 3 ++- src/openstudio_lib/LocationTabView.cpp | 8 ++++---- src/openstudio_lib/MaterialsView.cpp | 3 ++- src/openstudio_lib/ScheduleOthersView.cpp | 3 ++- src/openstudio_lib/SimSettingsView.cpp | 9 +++++---- src/openstudio_lib/YearSettingsWidget.cpp | 6 +++--- src/utilities/OpenStudioApplicationPathHelpers.cxx.in | 4 ++++ src/utilities/OpenStudioApplicationPathHelpers.hpp | 3 +++ 15 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/model_editor/CMakeLists.txt b/src/model_editor/CMakeLists.txt index c8ee35816..63aca23c1 100644 --- a/src/model_editor/CMakeLists.txt +++ b/src/model_editor/CMakeLists.txt @@ -103,9 +103,6 @@ else() target_compile_definitions(${target_name} PUBLIC model_editor_EXPORTS) endif() -target_compile_definitions(${target_name} PRIVATE - "BIGLADDERSOFTWARE_DOC_BASE_URL=\"${BIGLADDERSOFTWARE_DOC_BASE_URL}\"") - set(${target_name}_test_src test/ModelEditorFixture.hpp test/ModelEditorFixture.cpp diff --git a/src/model_editor/IddObjectDocUrl.hpp b/src/model_editor/IddObjectDocUrl.hpp index 3d202a2fa..8189c4804 100644 --- a/src/model_editor/IddObjectDocUrl.hpp +++ b/src/model_editor/IddObjectDocUrl.hpp @@ -9,11 +9,13 @@ #include #include +#include "../utilities/OpenStudioApplicationPathHelpers.hpp" + // Returns the BigLadder EnergyPlus I/O Reference URL for the given OS IDD type name // (e.g. "OS:ThermalZone"), or an empty string if none is known. // Base URL version is controlled by ENERGYPLUS_VERSION_MAJOR/MINOR in FindOpenStudioSDK.cmake. inline QString iddObjectDocUrl(const QString& iddTypeName) { - static const QString base = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL); + static const QString base = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()); // clang-format off static const QHash urlMap{ diff --git a/src/openstudio_lib/BuildingInspectorView.cpp b/src/openstudio_lib/BuildingInspectorView.cpp index 21761d573..48da0dcc9 100644 --- a/src/openstudio_lib/BuildingInspectorView.cpp +++ b/src/openstudio_lib/BuildingInspectorView.cpp @@ -4,6 +4,7 @@ ***********************************************************************************************************************/ #include "BuildingInspectorView.hpp" +#include "../utilities/OpenStudioApplicationPathHelpers.hpp" #include "../shared_gui_components/OSComboBox.hpp" #include "../shared_gui_components/OSIntegerEdit.hpp" @@ -442,7 +443,7 @@ BuildingInspectorView::BuildingInspectorView(bool isIP, bool displayAdditionalPr label->setOpenExternalLinks(true); { static const QString url = - QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL "group-simulation-parameters.html#building"); + QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "group-simulation-parameters.html#building"; label->setToolTip(url); label->setText(QStringLiteral(R"(North Axis:)").arg(url)); } diff --git a/src/openstudio_lib/CMakeLists.txt b/src/openstudio_lib/CMakeLists.txt index 143c5bbb4..28977df89 100644 --- a/src/openstudio_lib/CMakeLists.txt +++ b/src/openstudio_lib/CMakeLists.txt @@ -778,9 +778,6 @@ if (NINJA) target_compile_definitions(${target_name} PRIVATE NINJA=1) endif() -target_compile_definitions(${target_name} PRIVATE - "BIGLADDERSOFTWARE_DOC_BASE_URL=\"${BIGLADDERSOFTWARE_DOC_BASE_URL}\"") - set(${target_name}_depends openstudio_modeleditor openstudio::openstudiolib diff --git a/src/openstudio_lib/ConstructionsView.cpp b/src/openstudio_lib/ConstructionsView.cpp index ce80d4158..81f6ffec0 100644 --- a/src/openstudio_lib/ConstructionsView.cpp +++ b/src/openstudio_lib/ConstructionsView.cpp @@ -12,6 +12,7 @@ #include "ConstructionInternalSourceInspectorView.hpp" #include "ConstructionWindowDataFileInspectorView.hpp" #include "ModelObjectTypeListView.hpp" +#include "../utilities/OpenStudioApplicationPathHelpers.hpp" #include @@ -32,7 +33,7 @@ ConstructionsView::ConstructionsView(bool isIP, const openstudio::model::Model& } std::vector> ConstructionsView::modelObjectTypesNamesAndUrls() { - static const QString base = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL); + static const QString base = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()); static const QString sce = base + QStringLiteral("group-surface-construction-elements.html"); using T = std::tuple; diff --git a/src/openstudio_lib/GroundTemperatureView.cpp b/src/openstudio_lib/GroundTemperatureView.cpp index f1e42dfe0..82b3b7540 100644 --- a/src/openstudio_lib/GroundTemperatureView.cpp +++ b/src/openstudio_lib/GroundTemperatureView.cpp @@ -4,6 +4,7 @@ ***********************************************************************************************************************/ #include "GroundTemperatureView.hpp" +#include "../utilities/OpenStudioApplicationPathHelpers.hpp" #include "OSAppBase.hpp" #include "OSDocument.hpp" @@ -101,7 +102,7 @@ GroundTemperatureListView::GroundTemperatureListView(QWidget* parent) : QWidget( setLayout(layout); static const QString lcwBase = - QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL "group-location-climate-weather-file-access.html"); + QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "group-location-climate-weather-file-access.html"; m_bsEntry = new GroundTemperatureEntry(tr("Building Surface Ground Temperatures"), lcwBase + "#sitegroundtemperaturebuildingsurface", this); m_shEntry = new GroundTemperatureEntry(tr("Shallow Ground Temperatures"), diff --git a/src/openstudio_lib/LifeCycleCostsTabView.cpp b/src/openstudio_lib/LifeCycleCostsTabView.cpp index ff6c222aa..97a921606 100644 --- a/src/openstudio_lib/LifeCycleCostsTabView.cpp +++ b/src/openstudio_lib/LifeCycleCostsTabView.cpp @@ -4,6 +4,7 @@ ***********************************************************************************************************************/ #include "LifeCycleCostsTabView.hpp" +#include "../utilities/OpenStudioApplicationPathHelpers.hpp" #include "../shared_gui_components/OSComboBox.hpp" #include "../shared_gui_components/OSDoubleEdit.hpp" @@ -64,7 +65,7 @@ void LifeCycleCostsView::createWidgets() { label->setOpenExternalLinks(true); { static const QString url = - QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL "lifecyclecost-parameters.html#lifecyclecostparameters"); + QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "lifecyclecost-parameters.html#lifecyclecostparameters"; label->setToolTip(url); label->setText(QStringLiteral(R"(Life Cycle Cost Parameters)").arg(url)); } @@ -155,7 +156,7 @@ void LifeCycleCostsView::createWidgets() { label->setOpenExternalLinks(true); { static const QString url = - QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL "lifecyclecost-usepriceescalation.html#lifecyclecostusepriceescalation"); + QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "lifecyclecost-usepriceescalation.html#lifecyclecostusepriceescalation"; label->setToolTip(url); label->setText( QStringLiteral(R"()" diff --git a/src/openstudio_lib/LoadsView.cpp b/src/openstudio_lib/LoadsView.cpp index c4f7b1d3b..4ce6e41ec 100644 --- a/src/openstudio_lib/LoadsView.cpp +++ b/src/openstudio_lib/LoadsView.cpp @@ -5,6 +5,7 @@ #include "LoadsView.hpp" #include "ModelObjectTypeListView.hpp" +#include "../utilities/OpenStudioApplicationPathHelpers.hpp" #include "PeopleInspectorView.hpp" #include "InternalMassInspectorView.hpp" #include "LightsInspectorView.hpp" @@ -43,7 +44,7 @@ LoadsView::LoadsView(bool isIP, const openstudio::model::Model& model, QWidget* } std::vector> LoadsView::modelObjectTypesNamesAndUrls() { - static const QString base = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL); + static const QString base = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()); static const QString iag = base + QStringLiteral("group-internal-gains-people-lights-other.html"); static const QString tzg = base + QStringLiteral("group-thermal-zone-description-geometry.html"); static const QString wsg = base + QStringLiteral("group-water-systems.html"); diff --git a/src/openstudio_lib/LocationTabView.cpp b/src/openstudio_lib/LocationTabView.cpp index 79402d0c8..23e0070d5 100644 --- a/src/openstudio_lib/LocationTabView.cpp +++ b/src/openstudio_lib/LocationTabView.cpp @@ -4,6 +4,7 @@ ***********************************************************************************************************************/ #include "LocationTabView.hpp" +#include "../utilities/OpenStudioApplicationPathHelpers.hpp" #include "DesignDayGridView.hpp" #include "ModelObjectListView.hpp" @@ -214,9 +215,8 @@ LocationView::LocationView(bool isIP, const model::Model& model, const QString& label->setTextFormat(Qt::RichText); label->setOpenExternalLinks(true); { - static const QString url = QStringLiteral( - BIGLADDERSOFTWARE_DOC_BASE_URL - "group-location-climate-weather-file-access.html#group----location----climate----weather-file-access"); + static const QString url = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + + "group-location-climate-weather-file-access.html#group----location----climate----weather-file-access"; label->setToolTip(url); label->setText(QStringLiteral(R"(%2)").arg(url, tr("Weather File"))); } @@ -471,7 +471,7 @@ LocationView::LocationView(bool isIP, const model::Model& model, const QString& label->setOpenExternalLinks(true); { static const QString url = - QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL "group-location-climate-weather-file-access.html#sizingperioddesignday"); + QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "group-location-climate-weather-file-access.html#sizingperioddesignday"; label->setToolTip(url); label->setText(QStringLiteral(R"(%2)").arg(url, tr("Design Days"))); } diff --git a/src/openstudio_lib/MaterialsView.cpp b/src/openstudio_lib/MaterialsView.cpp index 91513f8e6..a0d7a9320 100644 --- a/src/openstudio_lib/MaterialsView.cpp +++ b/src/openstudio_lib/MaterialsView.cpp @@ -11,6 +11,7 @@ #include "MaterialNoMassInspectorView.hpp" #include "MaterialRoofVegetationInspectorView.hpp" #include "ModelObjectTypeListView.hpp" +#include "../utilities/OpenStudioApplicationPathHelpers.hpp" #include "WindowMaterialBlindInspectorView.hpp" #include "WindowMaterialDaylightRedirectionDeviceInspectorView.hpp" #include "WindowMaterialGasInspectorView.hpp" @@ -43,7 +44,7 @@ MaterialsView::MaterialsView(bool isIP, const openstudio::model::Model& model, c } std::vector> MaterialsView::modelObjectTypesNamesAndUrls() { - static const QString base = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL); + static const QString base = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()); static const QString sce = base + QStringLiteral("group-surface-construction-elements.html"); using T = std::tuple; diff --git a/src/openstudio_lib/ScheduleOthersView.cpp b/src/openstudio_lib/ScheduleOthersView.cpp index 2c34c4ae7..77a5a3258 100644 --- a/src/openstudio_lib/ScheduleOthersView.cpp +++ b/src/openstudio_lib/ScheduleOthersView.cpp @@ -5,6 +5,7 @@ #include "ScheduleOthersView.hpp" #include "ModelObjectTypeListView.hpp" +#include "../utilities/OpenStudioApplicationPathHelpers.hpp" #include "ScheduleConstantInspectorView.hpp" #include "ScheduleCompactInspectorView.hpp" @@ -27,7 +28,7 @@ ScheduleOthersView::ScheduleOthersView(const openstudio::model::Model& model, QW new ScheduleOthersInspectorView(model, parent), false, parent) {} std::vector> ScheduleOthersView::modelObjectTypesNamesAndUrls() { - static const QString base = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL); + static const QString base = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()); static const QString sch = base + QStringLiteral("group-schedules.html"); using T = std::tuple; diff --git a/src/openstudio_lib/SimSettingsView.cpp b/src/openstudio_lib/SimSettingsView.cpp index 42a530403..1dfe43d3f 100644 --- a/src/openstudio_lib/SimSettingsView.cpp +++ b/src/openstudio_lib/SimSettingsView.cpp @@ -7,6 +7,7 @@ #include "CollapsibleInspector.hpp" #include "ModelObjectTypeListView.hpp" +#include "../utilities/OpenStudioApplicationPathHelpers.hpp" #include "OSAppBase.hpp" #include "../shared_gui_components/OSComboBox.hpp" #include "OSDocument.hpp" @@ -239,7 +240,7 @@ void SimSettingsView::createWidgets() { //******************* OS:Timestep ******************* mainLayout->addWidget(createTimestepWidget()); - static const QString iorf = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL); + static const QString iorf = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()); collapsibleInspector = new CollapsibleInspector(tr("Advanced RunPeriod Parameters"), iorf + "group-location-climate-weather-file-access.html#runperiod", createRunPeriodAdvancedWidget()); mainLayout->addWidget(collapsibleInspector); @@ -331,7 +332,7 @@ QWidget* SimSettingsView::createRunPeriodWidget() { label->setTextFormat(Qt::RichText); label->setOpenExternalLinks(true); { - static const QString url = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL "group-location-climate-weather-file-access.html#runperiod"); + static const QString url = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "group-location-climate-weather-file-access.html#runperiod"; label->setToolTip(url); label->setText(QStringLiteral(R"(%2)").arg(url, tr("Run Period"))); } @@ -615,7 +616,7 @@ QWidget* SimSettingsView::createSizingParametersWidget() { label->setTextFormat(Qt::RichText); label->setOpenExternalLinks(true); { - static const QString url = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL "group-design-objects.html#sizingparameters"); + static const QString url = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "group-design-objects.html#sizingparameters"; label->setToolTip(url); label->setText(QStringLiteral(R"(%2)").arg(url, tr("Sizing Parameters"))); } @@ -672,7 +673,7 @@ QWidget* SimSettingsView::createTimestepWidget() { label->setTextFormat(Qt::RichText); label->setOpenExternalLinks(true); { - static const QString url = QStringLiteral(BIGLADDERSOFTWARE_DOC_BASE_URL "group-simulation-parameters.html#timestep"); + static const QString url = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "group-simulation-parameters.html#timestep"; label->setToolTip(url); label->setText(QStringLiteral(R"(%2)").arg(url, tr("Timestep"))); } diff --git a/src/openstudio_lib/YearSettingsWidget.cpp b/src/openstudio_lib/YearSettingsWidget.cpp index a2d761e69..2ef235034 100644 --- a/src/openstudio_lib/YearSettingsWidget.cpp +++ b/src/openstudio_lib/YearSettingsWidget.cpp @@ -4,6 +4,7 @@ ***********************************************************************************************************************/ #include "YearSettingsWidget.hpp" +#include "../utilities/OpenStudioApplicationPathHelpers.hpp" #include "OSAppBase.hpp" #include "OSDocument.hpp" @@ -107,9 +108,8 @@ YearSettingsWidget::YearSettingsWidget(const model::Model& model, QWidget* paren dstLabel->setTextFormat(Qt::RichText); dstLabel->setOpenExternalLinks(true); { - static const QString url = QStringLiteral( - BIGLADDERSOFTWARE_DOC_BASE_URL - "group-location-climate-weather-file-access.html#field-daylight-saving-time-indicator"); + static const QString url = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + + "group-location-climate-weather-file-access.html#field-daylight-saving-time-indicator"; dstLabel->setToolTip(url); dstLabel->setText(QStringLiteral(R"(%2)").arg(url, tr("Daylight Savings Time:"))); } diff --git a/src/utilities/OpenStudioApplicationPathHelpers.cxx.in b/src/utilities/OpenStudioApplicationPathHelpers.cxx.in index ff82e797d..b4631ea6d 100644 --- a/src/utilities/OpenStudioApplicationPathHelpers.cxx.in +++ b/src/utilities/OpenStudioApplicationPathHelpers.cxx.in @@ -205,6 +205,10 @@ bool isOpenStudioApplicationModuleRunningFromBuildDirectory() { return pathBeginsWith(buildDir, runDir); } +std::string bigladdersoftwareDocBaseUrl() { + return "${BIGLADDERSOFTWARE_DOC_BASE_URL}"; +} + openstudio::path getOpenStudioCoreCLI() { openstudio::path cliPath; diff --git a/src/utilities/OpenStudioApplicationPathHelpers.hpp b/src/utilities/OpenStudioApplicationPathHelpers.hpp index 1a334ffc6..5a99366bd 100644 --- a/src/utilities/OpenStudioApplicationPathHelpers.hpp +++ b/src/utilities/OpenStudioApplicationPathHelpers.hpp @@ -60,6 +60,9 @@ OSAPP_UTILITIES_API bool isOpenStudioApplicationModuleRunningFromBuildDirectory( /// \returns The path to the OpenStudio Command Line Interface if it exists. OSAPP_UTILITIES_API openstudio::path getOpenStudioCoreCLI(); +/// \returns The base URL for the BigLadder EnergyPlus I/O Reference (versioned, trailing slash included) +OSAPP_UTILITIES_API std::string bigladdersoftwareDocBaseUrl(); + } // namespace openstudio #endif //OSAPP_UTILITIES_APPLICATIONPATHHELPERS_HPP From 0547c9f440f4cbb6a81b2e28826a1864535d4407 Mon Sep 17 00:00:00 2001 From: Ski90Moo Date: Sun, 31 May 2026 22:20:08 +0200 Subject: [PATCH 08/13] chore: add check_doc_urls.py script to verify BigLadder doc link anchors Scans IddObjectDocUrl.hpp and all .cpp files that reference bigladdersoftwareDocBaseUrl(), fetches each unique BigLadder page once, and verifies that every anchor ID referenced actually exists in the page HTML. Exits 0 if all OK, 1 if any anchors are missing or pages fail to load. Usage: python scripts/check_doc_urls.py [--repo-root PATH] [--delay SEC] Co-Authored-By: Claude Sonnet 4.6 --- scripts/check_doc_urls.py | 196 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 scripts/check_doc_urls.py diff --git a/scripts/check_doc_urls.py b/scripts/check_doc_urls.py new file mode 100644 index 000000000..74ab1e17a --- /dev/null +++ b/scripts/check_doc_urls.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python3 +""" +check_doc_urls.py - Verify BigLadder EnergyPlus I/O Reference URLs in OpenStudioApp source. + +Scans source files for doc URL strings, fetches each unique page once, checks that +every anchor referenced actually exists in the page HTML, and reports failures. + +Usage: + python scripts/check_doc_urls.py [--repo-root PATH] + +Exit codes: + 0 All URLs valid + 1 One or more broken/missing anchors found + 2 Usage / dependency error +""" + +import argparse +import re +import sys +import time +from collections import defaultdict +from html.parser import HTMLParser +from pathlib import Path +from urllib.request import urlopen +from urllib.error import URLError + +# --------------------------------------------------------------------------- +# Files to scan and the regex patterns that extract URL fragments from them +# --------------------------------------------------------------------------- + +# Matches values in the IddObjectDocUrl.hpp urlMap: +# {"OS:Something", "group-foo.html#anchor"}, +IDDOBJECTDOCURL_PATTERN = re.compile( + r'"OS:[^"]+"\s*,\s*"([^"]+\.html(?:#[^"]*)?)"' +) + +# Matches QString URL constructions in .cpp files: +# QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "page.html#anchor" +# or the old QStringLiteral(BASE "page.html#anchor") form +CPP_URL_FRAGMENT_PATTERN = re.compile( + r'(?:bigladdersoftwareDocBaseUrl\(\)\s*\+\s*"([^"]+\.html(?:#[^"]*)?)"' + r'|QStringLiteral\(BIGLADDERSOFTWARE_DOC_BASE_URL\s*"([^"]+\.html(?:#[^"]*)?)"' + r'|\+\s*"(group-[^"]+\.html(?:#[^"]*)?)"' + r'|\+\s*"(lifecyclecost-[^"]+\.html(?:#[^"]*)?)")' +) + +SOURCE_FILES = [ + "src/model_editor/IddObjectDocUrl.hpp", + "src/openstudio_lib/SimSettingsView.cpp", + "src/openstudio_lib/LoadsView.cpp", + "src/openstudio_lib/ConstructionsView.cpp", + "src/openstudio_lib/MaterialsView.cpp", + "src/openstudio_lib/ScheduleOthersView.cpp", + "src/openstudio_lib/LocationTabView.cpp", + "src/openstudio_lib/YearSettingsWidget.cpp", + "src/openstudio_lib/GroundTemperatureView.cpp", + "src/openstudio_lib/LifeCycleCostsTabView.cpp", + "src/openstudio_lib/BuildingInspectorView.cpp", +] + +BIGLADDERSOFTWARE_BASE = "https://bigladdersoftware.com/epx/docs/25-1/input-output-reference/" + + +# --------------------------------------------------------------------------- +# HTML parser that collects all id= attributes +# --------------------------------------------------------------------------- + +class AnchorCollector(HTMLParser): + def __init__(self): + super().__init__() + self.ids = set() + + def handle_starttag(self, tag, attrs): + for name, value in attrs: + if name == "id" and value: + self.ids.add(value) + + +# --------------------------------------------------------------------------- +# URL extraction +# --------------------------------------------------------------------------- + +def extract_fragments(repo_root: Path): + """ + Returns a dict: page_url -> list of (anchor_or_None, source_file, line_no) + """ + results = defaultdict(list) + + for rel_path in SOURCE_FILES: + src = repo_root / rel_path + if not src.exists(): + print(f" WARNING: {rel_path} not found, skipping", file=sys.stderr) + continue + + text = src.read_text(encoding="utf-8") + + if rel_path.endswith("IddObjectDocUrl.hpp"): + pattern = IDDOBJECTDOCURL_PATTERN + else: + pattern = CPP_URL_FRAGMENT_PATTERN + + for lineno, line in enumerate(text.splitlines(), 1): + for m in pattern.finditer(line): + fragment = next((g for g in m.groups() if g), None) + if not fragment: + continue + if "#" in fragment: + page_part, anchor = fragment.split("#", 1) + else: + page_part, anchor = fragment, None + page_url = BIGLADDERSOFTWARE_BASE + page_part + results[page_url].append((anchor, rel_path, lineno)) + + return results + + +# --------------------------------------------------------------------------- +# Page fetching with simple cache +# --------------------------------------------------------------------------- + +def fetch_anchors(url: str, delay: float = 0.5) -> set | None: + """Fetch a page and return the set of id= values, or None on error.""" + try: + time.sleep(delay) + with urlopen(url, timeout=15) as resp: + html = resp.read().decode("utf-8", errors="replace") + parser = AnchorCollector() + parser.feed(html) + return parser.ids + except URLError as e: + print(f" ERROR fetching {url}: {e}", file=sys.stderr) + return None + + +# --------------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------------- + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--repo-root", + default=".", + help="Path to the OpenStudioApplication repo root (default: current directory)", + ) + parser.add_argument( + "--delay", + type=float, + default=0.5, + help="Seconds to wait between page fetches (default: 0.5)", + ) + args = parser.parse_args() + + repo_root = Path(args.repo_root).resolve() + print(f"Scanning repo: {repo_root}") + + fragments = extract_fragments(repo_root) + if not fragments: + print("No URLs found — check SOURCE_FILES list.", file=sys.stderr) + sys.exit(2) + + print(f"\nFound {sum(len(v) for v in fragments.values())} URL references across {len(fragments)} unique pages.\n") + + failures = [] + page_cache = {} + + for page_url in sorted(fragments): + print(f"Checking: {page_url}") + if page_url not in page_cache: + page_cache[page_url] = fetch_anchors(page_url, delay=args.delay) + + page_ids = page_cache[page_url] + + for anchor, src_file, lineno in fragments[page_url]: + if page_ids is None: + failures.append((src_file, lineno, page_url, anchor, "page fetch failed")) + elif anchor and anchor not in page_ids: + failures.append((src_file, lineno, page_url, anchor, "anchor not found in page")) + else: + status = "OK" if anchor else "OK (no anchor)" + print(f" {status}: #{anchor or ''}") + + print() + if failures: + print(f"FAILURES ({len(failures)}):") + for src_file, lineno, page_url, anchor, reason in failures: + print(f" {src_file}:{lineno} #{anchor} -> {reason}") + print(f" {page_url}#{anchor or ''}") + sys.exit(1) + else: + print("All URLs OK.") + sys.exit(0) + + +if __name__ == "__main__": + main() From 02a4712da09aaaa45bffa0f825f9b7f054489acf Mon Sep 17 00:00:00 2001 From: Ski90Moo Date: Sun, 31 May 2026 23:12:38 +0200 Subject: [PATCH 09/13] fix: correct 31 broken/wrong-page doc URL anchors in IddObjectDocUrl.hpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Identified by scripts/check_doc_urls.py which fetches BigLadder pages and verifies anchor IDs exist in the HTML. Fixes include: - Wrong page: RunPeriod, InternalMass, PlantLoop/CondenserLoop, AvailabilityManagerAssignmentList, HeatExchanger:FluidToFluid, OutdoorAir:Mixer, ZoneMixer/Splitter/ReturnPlenum/SupplyPlenum - Typos: materialaingap→materialairgap, celdeckpad→celdekpad (×2), outdoorarreset→outdoorairreset, multizoneheat/coolaverage→heating/coolingaverage - Sphinx suffixes: lights→lights-000, construction→construction-000, daylightingcontrols→daylightingcontrols-000 - Hyphen removal: buildingsurface-detailed→buildingsurfacedetailed, fenestrationsurface-detailed→fenestrationsurfacedetailed - Renames: Uncontrolled→ConstantVolume:NoReheat, Fuel→Gas-000, ShadingControl→WindowPropertyShadingControl, WaterHeaterHeatPump→WaterHeaterHeatPumpPumpedCondenser, GroundHeatExchanger:Vertical→GroundHeatExchangerSystem - FourPipeBeam coils moved to air-distribution-equipment page 7 anchors remain unverifiable (page too long for fetch tool): HeatPump:PlantLoop:EIR:Cooling/Heating, PLHP:AirToWater (×3), WindowProperty:FrameAndDivider, InteriorPartitionSurface:Detailed. Also updates check_doc_urls.py docstring with rationale for choosing Python script over GTest, and updates OpenStudioApplicationPathHelpers with bigladdersoftwareDocBaseUrl() accessor function. Co-Authored-By: Claude Sonnet 4.6 --- scripts/check_doc_urls.py | 18 ++++++- src/model_editor/IddObjectDocUrl.hpp | 70 +++++++++++++------------- src/openstudio_lib/LocationTabView.cpp | 2 +- 3 files changed, 53 insertions(+), 37 deletions(-) diff --git a/scripts/check_doc_urls.py b/scripts/check_doc_urls.py index 74ab1e17a..c574c076c 100644 --- a/scripts/check_doc_urls.py +++ b/scripts/check_doc_urls.py @@ -6,12 +6,28 @@ every anchor referenced actually exists in the page HTML, and reports failures. Usage: - python scripts/check_doc_urls.py [--repo-root PATH] + python scripts/check_doc_urls.py [--repo-root PATH] [--delay SEC] Exit codes: 0 All URLs valid 1 One or more broken/missing anchors found 2 Usage / dependency error + +Why a Python script rather than a GTest network test +----------------------------------------------------- +BigLadder returns HTTP 200 for *any* URL on an existing page, regardless of whether +the anchor exists. A plain HTTP HEAD or GET check would silently pass even when an +anchor has been renamed or removed. Verifying anchor IDs requires fetching the full +page HTML and scanning for id="..." attributes — straightforward in Python with +html.parser, but awkward in C++/Qt without a full HTML parser dependency. + +GTest network tests were also considered but ruled out because: + - They are slow and flaky in CI (network dependency). + - QNetworkAccessManager requires a running event loop and async handling. + - GTest provides no natural mechanism to fetch-and-parse HTML for anchor checks. + +This script runs standalone (no build step), can be invoked as a pre-commit hook or +CI job, and completes in roughly one second per unique page fetched. """ import argparse diff --git a/src/model_editor/IddObjectDocUrl.hpp b/src/model_editor/IddObjectDocUrl.hpp index 8189c4804..01dc100d5 100644 --- a/src/model_editor/IddObjectDocUrl.hpp +++ b/src/model_editor/IddObjectDocUrl.hpp @@ -23,7 +23,7 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:SimulationControl", "group-simulation-parameters.html#simulationcontrol"}, {"OS:Building", "group-simulation-parameters.html#building"}, {"OS:Timestep", "group-simulation-parameters.html#timestep"}, - {"OS:RunPeriod", "group-simulation-parameters.html#runperiod"}, + {"OS:RunPeriod", "group-location-climate-weather-file-access.html#runperiod"}, {"OS:ShadowCalculation", "group-simulation-parameters.html#shadowcalculation"}, {"OS:SurfaceConvectionAlgorithm:Inside", "group-simulation-parameters.html#surfaceconvectionalgorithminside"}, {"OS:SurfaceConvectionAlgorithm:Outside", "group-simulation-parameters.html#surfaceconvectionalgorithmoutside"}, @@ -56,7 +56,7 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { // Surface Construction Elements {"OS:Material", "group-surface-construction-elements.html#material"}, {"OS:Material:NoMass", "group-surface-construction-elements.html#materialnomass"}, - {"OS:Material:AirGap", "group-surface-construction-elements.html#materialaingap"}, + {"OS:Material:AirGap", "group-surface-construction-elements.html#materialairgap"}, {"OS:Material:InfraredTransparent", "group-surface-construction-elements.html#materialinfraredtransparent"}, {"OS:Material:RoofVegetation", "group-surface-construction-elements.html#materialroofvegetation"}, {"OS:WindowMaterial:Glazing", "group-surface-construction-elements.html#windowmaterialglazing"}, @@ -66,7 +66,7 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:WindowMaterial:Blind", "group-surface-construction-elements.html#windowmaterialblind"}, {"OS:WindowMaterial:Screen", "group-surface-construction-elements.html#windowmaterialscreen"}, {"OS:WindowMaterial:Shade", "group-surface-construction-elements.html#windowmaterialshade"}, - {"OS:Construction", "group-surface-construction-elements.html#construction"}, + {"OS:Construction", "group-surface-construction-elements.html#construction-000"}, {"OS:Construction:InternalSource", "group-surface-construction-elements.html#constructioninternalsource"}, {"OS:Construction:WindowDataFile", "group-surface-construction-elements.html#constructionwindowdatafile"}, {"OS:WindowProperty:FrameAndDivider", "group-surface-construction-elements.html#windowpropertyframeanddivider"}, @@ -76,27 +76,27 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:Space", "group-thermal-zone-description-geometry.html"}, {"OS:SpaceType", "group-thermal-zone-description-geometry.html"}, {"OS:BuildingStory", "group-thermal-zone-description-geometry.html"}, - {"OS:Surface", "group-thermal-zone-description-geometry.html#buildingsurface-detailed"}, - {"OS:SubSurface", "group-thermal-zone-description-geometry.html#fenestrationsurface-detailed"}, - {"OS:ShadingControl", "group-thermal-zone-description-geometry.html#shadingcontrol"}, + {"OS:Surface", "group-thermal-zone-description-geometry.html#buildingsurfacedetailed"}, + {"OS:SubSurface", "group-thermal-zone-description-geometry.html#fenestrationsurfacedetailed"}, + {"OS:ShadingControl", "group-thermal-zone-description-geometry.html#windowpropertyshadingcontrol"}, {"OS:InteriorPartitionSurface", "group-thermal-zone-description-geometry.html#interiorpartitionsurface-detailed"}, {"OS:InteriorPartitionSurfaceGroup", "group-thermal-zone-description-geometry.html"}, // Daylighting - {"OS:Daylighting:Control", "group-daylighting.html#daylightingcontrols"}, + {"OS:Daylighting:Control", "group-daylighting.html#daylightingcontrols-000"}, {"OS:DaylightingDevice:Shelf", "group-daylighting.html#daylightingdeviceshelf"}, {"OS:DaylightingDevice:Tubular", "group-daylighting.html#daylightingdevicetubular"}, {"OS:DaylightingDevice:LightWell", "group-daylighting.html#daylightingdevicelightwell"}, // Internal Gains {"OS:People", "group-internal-gains-people-lights-other.html#people"}, - {"OS:Lights", "group-internal-gains-people-lights-other.html#lights"}, + {"OS:Lights", "group-internal-gains-people-lights-other.html#lights-000"}, {"OS:ElectricEquipment", "group-internal-gains-people-lights-other.html#electricequipment"}, {"OS:GasEquipment", "group-internal-gains-people-lights-other.html#gasequipment"}, - {"OS:HotWaterEquipment", "group-internal-gains-people-lights-other.html#hotwatersupportequipment"}, + {"OS:HotWaterEquipment", "group-internal-gains-people-lights-other.html#hotwaterequipment"}, {"OS:SteamEquipment", "group-internal-gains-people-lights-other.html#steamequipment"}, {"OS:OtherEquipment", "group-internal-gains-people-lights-other.html#otherequipment"}, - {"OS:InternalMass", "group-internal-gains-people-lights-other.html#internalmass"}, + {"OS:InternalMass", "group-thermal-zone-description-geometry.html#internalmass"}, {"OS:SwimmingPool:Indoor", "group-internal-gains-people-lights-other.html#swimmingpoolindoor"}, // Exterior Energy Use @@ -167,16 +167,16 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:AirTerminal:SingleDuct:VAV:HeatAndCool:Reheat", "group-air-distribution-equipment.html#airterminalsingleductvavheatandcoolreheat"}, {"OS:AirTerminal:SingleDuct:VAV:HeatAndCool:NoReheat", "group-air-distribution-equipment.html#airterminalsingleductvavheatandcoolnoreheat"}, {"OS:AirTerminal:SingleDuct:ConstantVolume:Reheat", "group-air-distribution-equipment.html#airterminalsingleductconstantvolumereheat"}, - {"OS:AirTerminal:SingleDuct:ConstantVolume:NoReheat", "group-air-distribution-equipment.html#airterminalsingleductuncontrolled"}, + {"OS:AirTerminal:SingleDuct:ConstantVolume:NoReheat", "group-air-distribution-equipment.html#airterminalsingleductconstantvolumenoreheat"}, {"OS:AirTerminal:SingleDuct:ConstantVolume:CooledBeam", "group-air-distribution-equipment.html#airterminalsingleductconstantvolumecooledbeam"}, {"OS:AirTerminal:SingleDuct:ConstantVolume:FourPipeBeam", "group-air-distribution-equipment.html#airterminalsingleductconstantvolumefourpipebeam"}, - {"OS:AirTerminal:SingleDuct:ParallelPIU:Reheat", "group-air-distribution-equipment.html#airterminalsingleductparallelpiu"}, - {"OS:AirTerminal:SingleDuct:SeriesPIU:Reheat", "group-air-distribution-equipment.html#airterminalsingleductseriespiu"}, - {"OS:AirTerminal:SingleDuct:InletSideMixer", "group-air-distribution-equipment.html#airterminalsingleductinletsidemixer"}, + {"OS:AirTerminal:SingleDuct:ParallelPIU:Reheat", "group-air-distribution-equipment.html#airterminalsingleductparallelpiureheat"}, + {"OS:AirTerminal:SingleDuct:SeriesPIU:Reheat", "group-air-distribution-equipment.html#airterminalsingleductseriespiureheat"}, + {"OS:AirTerminal:SingleDuct:InletSideMixer", "group-air-distribution-equipment.html#airterminalsingleductmixer"}, {"OS:AirTerminal:DualDuct:VAV", "group-air-distribution-equipment.html#airterminaldualductvav"}, {"OS:AirTerminal:DualDuct:VAV:OutdoorAir", "group-air-distribution-equipment.html#airterminaldualductvavoutdoorair"}, {"OS:AirTerminal:DualDuct:ConstantVolume", "group-air-distribution-equipment.html#airterminaldualductconstantvolume"}, - {"OS:AirTerminal:FourPipeInduction", "group-air-distribution-equipment.html#airterminalfourpipeinduction"}, + {"OS:AirTerminal:FourPipeInduction", "group-air-distribution-equipment.html#airterminalsingleductconstantvolumefourpipeinduction"}, {"OS:AirTerminal:SingleDuct:ConstantVolume:FourPipeInduction", "group-air-distribution-equipment.html#airterminalsingleductconstantvolumefourpipeinduction"}, // Fans @@ -198,7 +198,7 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:Coil:Cooling:Water:DetailedGeometry", "group-heating-and-cooling-coils.html#coilcoolingwaterdetailedgeometry"}, {"OS:Coil:Cooling:WaterToAirHeatPump:EquationFit", "group-heating-and-cooling-coils.html#coilcoolingwatertoairheatpumpequationfit"}, {"OS:Coil:Cooling:WaterToAirHeatPump:VariableSpeedEquationFit", "group-heating-and-cooling-coils.html#coilcoolingwatertoairheatpumpvariablespeedequationfit"}, - {"OS:Coil:Cooling:FourPipeBeam", "group-heating-and-cooling-coils.html#coilcoolingfourpipebeam"}, + {"OS:Coil:Cooling:FourPipeBeam", "group-air-distribution-equipment.html#airterminalsingleductconstantvolumefourpipebeam"}, {"OS:Coil:Cooling:DX:TwoStageWithHumidityControlMode", "group-heating-and-cooling-coils.html#coilcoolingdxtwostagewithhumiditycontrolmode"}, {"OS:Coil:Cooling:DX:MultiSpeed:StageData", "group-heating-and-cooling-coils.html#coilcoolingdxmultispeed"}, {"OS:Coil:Cooling:Water:Panel:Radiant", "group-radiative-convective-units.html#zonehvaccoolingpanelradiantconvectivewater"}, @@ -208,7 +208,7 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { // Coils - Heating {"OS:Coil:Heating:Gas", "group-heating-and-cooling-coils.html#coilheatinggas-000"}, - {"OS:Coil:Heating:Fuel", "group-heating-and-cooling-coils.html#coilheatingfuel"}, + {"OS:Coil:Heating:Fuel", "group-heating-and-cooling-coils.html#coilheatinggas-000"}, {"OS:Coil:Heating:Electric", "group-heating-and-cooling-coils.html#coilheatingelectric"}, {"OS:Coil:Heating:Water", "group-heating-and-cooling-coils.html#coilheatingwater"}, {"OS:Coil:Heating:DX:SingleSpeed", "group-heating-and-cooling-coils.html#coilheatingdxsinglespeed"}, @@ -219,7 +219,7 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:Coil:Heating:WaterToAirHeatPump:EquationFit", "group-heating-and-cooling-coils.html#coilheatingwatertoairheatpumpequationfit"}, {"OS:Coil:Heating:WaterToAirHeatPump:VariableSpeedEquationFit", "group-heating-and-cooling-coils.html#coilheatingwatertoairheatpumpvariablespeedequationfit"}, {"OS:Coil:Heating:Desuperheater", "group-heating-and-cooling-coils.html#coilheatingdesuperheater"}, - {"OS:Coil:Heating:FourPipeBeam", "group-heating-and-cooling-coils.html#coilheatingfourpipebeam"}, + {"OS:Coil:Heating:FourPipeBeam", "group-air-distribution-equipment.html#airterminalsingleductconstantvolumefourpipebeam"}, {"OS:Coil:Heating:Gas:MultiStage", "group-heating-and-cooling-coils.html#coilheatinggasmultistage"}, {"OS:Coil:Heating:Gas:MultiStage:StageData", "group-heating-and-cooling-coils.html#coilheatinggasmultistage"}, {"OS:Coil:Heating:LowTemperatureRadiant:ConstantFlow", "group-radiative-convective-units.html#zonehvaclowtemperatureradiantconstantflow"}, @@ -234,8 +234,8 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { // Evaporative Coolers {"OS:EvaporativeCooler:Direct:ResearchSpecial", "group-evaporative-coolers.html#evaporativecoolerdirectresearchspecial"}, {"OS:EvaporativeCooler:Indirect:ResearchSpecial", "group-evaporative-coolers.html#evaporativecoolerindirectresearchspecial"}, - {"OS:EvaporativeCooler:Direct:CelDekPad", "group-evaporative-coolers.html#evaporativecoolerdirectceldeckpad"}, - {"OS:EvaporativeCooler:Indirect:CelDekPad", "group-evaporative-coolers.html#evaporativecoolerindirectceldeckpad"}, + {"OS:EvaporativeCooler:Direct:CelDekPad", "group-evaporative-coolers.html#evaporativecoolerdirectceldekpad"}, + {"OS:EvaporativeCooler:Indirect:CelDekPad", "group-evaporative-coolers.html#evaporativecoolerindirectceldekpad"}, {"OS:EvaporativeCooler:Indirect:WetCoil", "group-evaporative-coolers.html#evaporativecoolerindirectwetcoil"}, // Humidifiers @@ -256,20 +256,20 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { // Air Distribution / AirLoop {"OS:AirLoopHVAC", "group-air-distribution.html#group-air-distribution"}, {"OS:AirLoopHVAC:OutdoorAirSystem", "group-air-distribution.html#airloophvacoutdoorairsystem"}, - {"OS:OutdoorAir:Mixer", "group-airflow.html#outdoorairmixer"}, + {"OS:OutdoorAir:Mixer", "group-air-distribution.html#outdoorairmixer"}, {"OS:Controller:OutdoorAir", "group-controllers.html#controlleroutdoorair"}, {"OS:Controller:MechanicalVentilation", "group-controllers.html#controllermechanicalventilation"}, {"OS:ZoneHVAC:EnergyRecoveryVentilator:Controller", "group-controllers.html#zonehvacenergyrecoveryventilatorcontroller"}, - {"OS:AirLoopHVAC:ZoneMixer", "group-airflow.html#airloophvaczonemixer"}, - {"OS:AirLoopHVAC:ZoneSplitter", "group-airflow.html#airloophvaczonesplitter"}, - {"OS:AirLoopHVAC:ReturnPlenum", "group-airflow.html#airloophvacreturnplenum"}, - {"OS:AirLoopHVAC:SupplyPlenum", "group-airflow.html#airloophvacsupplyplenum"}, + {"OS:AirLoopHVAC:ZoneMixer", "group-air-path.html#airloophvaczonemixer"}, + {"OS:AirLoopHVAC:ZoneSplitter", "group-air-path.html#airloophvaczonesplitter"}, + {"OS:AirLoopHVAC:ReturnPlenum", "group-air-path.html#airloophvacreturnplenum"}, + {"OS:AirLoopHVAC:SupplyPlenum", "group-air-path.html#airloophvacsupplyplenum"}, // Setpoint Managers {"OS:SetpointManager:Scheduled", "group-setpoint-managers.html#setpointmanagerscheduled"}, {"OS:SetpointManager:Scheduled:DualSetpoint", "group-setpoint-managers.html#setpointmanagerscheduleddualsetpoint"}, {"OS:SetpointManager:MixedAir", "group-setpoint-managers.html#setpointmanagermixedair"}, - {"OS:SetpointManager:OutdoorAirReset", "group-setpoint-managers.html#setpointmanageroutdoorarreset"}, + {"OS:SetpointManager:OutdoorAirReset", "group-setpoint-managers.html#setpointmanageroutdoorairreset"}, {"OS:SetpointManager:SingleZone:Reheat", "group-setpoint-managers.html#setpointmanagersinglezonereheat"}, {"OS:SetpointManager:SingleZone:Heating", "group-setpoint-managers.html#setpointmanagersinglezoneheating"}, {"OS:SetpointManager:SingleZone:Cooling", "group-setpoint-managers.html#setpointmanagersinglezonecooling"}, @@ -280,8 +280,8 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:SetpointManager:CondenserEnteringReset", "group-setpoint-managers.html#setpointmanagercondenserenteringreset"}, {"OS:SetpointManager:WarmestTemperatureFlow", "group-setpoint-managers.html#setpointmanagerwarmesttemperatureflow"}, {"OS:SetpointManager:OutdoorAirPretreat", "group-setpoint-managers.html#setpointmanageroutdoorairpretreat"}, - {"OS:SetpointManager:MultiZone:Heating:Average", "group-setpoint-managers.html#setpointmanagermultizoneheataverage"}, - {"OS:SetpointManager:MultiZone:Cooling:Average", "group-setpoint-managers.html#setpointmanagermultizonecoolaverage"}, + {"OS:SetpointManager:MultiZone:Heating:Average", "group-setpoint-managers.html#setpointmanagermultizoneheatingaverage"}, + {"OS:SetpointManager:MultiZone:Cooling:Average", "group-setpoint-managers.html#setpointmanagermultizonecoolingaverage"}, {"OS:SetpointManager:FollowSystemNodeTemperature", "group-setpoint-managers.html#setpointmanagerfollowsystemnodetemperature"}, {"OS:SetpointManager:MultiZone:Humidity:Maximum", "group-setpoint-managers.html#setpointmanagermultizonehumiditymaximum"}, {"OS:SetpointManager:MultiZone:Humidity:Minimum", "group-setpoint-managers.html#setpointmanagermultizonehumidityminimum"}, @@ -315,7 +315,7 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:Chiller:Electric:ReformulatedEIR", "group-plant-equipment.html#chillerelectricreformulatedeir"}, {"OS:Chiller:Absorption", "group-plant-equipment.html#chillerabsorption"}, {"OS:Chiller:Absorption:Indirect", "group-plant-equipment.html#chillerabsorptionindirect"}, - {"OS:Chiller:Absorption:Direct", "group-plant-equipment.html#chillerabsorptiondirect"}, + {"OS:Chiller:Absorption:Direct", "group-plant-equipment.html#chillerabsorption"}, {"OS:ChillerHeater:Absorption:DirectFired", "group-plant-equipment.html#chillerheaterabsorptiondirectfired"}, {"OS:DistrictCooling", "group-plant-equipment.html#districtcooling"}, {"OS:DistrictHeating", "group-plant-equipment.html#districtheating"}, @@ -349,18 +349,18 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { // Heat Recovery {"OS:HeatExchanger:AirToAir:SensibleAndLatent", "group-heat-recovery.html#heatexchangerairtoairsensibleandlatent"}, - {"OS:HeatExchanger:FluidToFluid", "group-heat-recovery.html#heatexchangerfluidtofluid"}, + {"OS:HeatExchanger:FluidToFluid", "group-condenser-equipment.html#heatexchangerfluidtofluid"}, {"OS:HeatExchanger:Desiccant:BalancedFlow", "group-heat-recovery.html#heatexchangerdesiccantbalancedflow"}, // Condenser Equipment and Ground Heat Exchangers - {"OS:GroundHeatExchanger:Vertical", "group-condenser-equipment.html#groundheatexchangervertical"}, + {"OS:GroundHeatExchanger:Vertical", "group-condenser-equipment.html#groundheatexchangersystem"}, {"OS:GroundHeatExchanger:HorizontalTrench", "group-condenser-equipment.html#groundheatexchangerhorizontaltrench"}, {"OS:GroundHeatExchanger:Slinky", "group-condenser-equipment.html#groundheatexchangerslinky"}, // Water Heaters and Thermal Storage {"OS:WaterHeater:Mixed", "group-water-heaters.html#waterheatermixed"}, {"OS:WaterHeater:Stratified", "group-water-heaters.html#waterheaterstratified"}, - {"OS:WaterHeater:HeatPump", "group-water-heaters.html#waterheaterheatpump"}, + {"OS:WaterHeater:HeatPump", "group-water-heaters.html#waterheaterheatpumppumpedcondenser"}, {"OS:WaterHeater:HeatPump:PumpedCondenser", "group-water-heaters.html#waterheaterheatpumppumpedcondenser"}, {"OS:WaterHeater:HeatPump:WrappedCondenser", "group-water-heaters.html#waterheaterheatpumpwrappedcondenser"}, {"OS:WaterHeater:Sizing", "group-water-heaters.html#waterheatersizing"}, @@ -397,8 +397,8 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:Duct", "group-node-branch-management.html#duct"}, // Plant / Condenser Control - {"OS:PlantLoop", "group-plant-condenser-control.html#plantloop"}, - {"OS:CondenserLoop", "group-plant-condenser-control.html#condenserloop"}, + {"OS:PlantLoop", "group-plant-condenser-loops.html#plantloop"}, + {"OS:CondenserLoop", "group-plant-condenser-loops.html#condenserloop"}, {"OS:PlantEquipmentList", "group-plant-condenser-control.html#plantequipmentlist"}, {"OS:PlantEquipmentOperation:CoolingLoad", "group-plant-condenser-control.html#plantequipmentoperationcoolingload"}, {"OS:PlantEquipmentOperation:HeatingLoad", "group-plant-condenser-control.html#plantequipmentoperationheatingload"}, @@ -409,7 +409,7 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:PlantEquipmentOperation:Uncontrolled", "group-plant-condenser-control.html#plantequipmentoperationuncontrolled"}, {"OS:TemperingValve", "group-plant-condenser-flow-control.html#temperingvalve"}, {"OS:LoadProfile:Plant", "group-non-zone-equipment.html#loadprofileplant"}, - {"OS:AvailabilityManagerAssignmentList", "group-system-availability-managers.html#availabilitymanagerassignmentlist"}, + {"OS:AvailabilityManagerAssignmentList", "group-air-distribution.html#availabilitymanagerassignmentlist"}, {"OS:AvailabilityManager:Scheduled", "group-system-availability-managers.html#availabilitymanagerscheduled"}, {"OS:AvailabilityManager:ScheduledOn", "group-system-availability-managers.html#availabilitymanagerscheduledon"}, {"OS:AvailabilityManager:ScheduledOff", "group-system-availability-managers.html#availabilitymanagerscheduledoff"}, diff --git a/src/openstudio_lib/LocationTabView.cpp b/src/openstudio_lib/LocationTabView.cpp index 23e0070d5..58d403330 100644 --- a/src/openstudio_lib/LocationTabView.cpp +++ b/src/openstudio_lib/LocationTabView.cpp @@ -216,7 +216,7 @@ LocationView::LocationView(bool isIP, const model::Model& model, const QString& label->setOpenExternalLinks(true); { static const QString url = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) - + "group-location-climate-weather-file-access.html#group----location----climate----weather-file-access"; + + "group-location-climate-weather-file-access.html"; label->setToolTip(url); label->setText(QStringLiteral(R"(%2)").arg(url, tr("Weather File"))); } From 941995346223cbafac8e718816f4e29a18b8a237 Mon Sep 17 00:00:00 2001 From: Ski90Moo Date: Mon, 1 Jun 2026 08:22:01 +0200 Subject: [PATCH 10/13] fix: resolve final 7 broken anchors in IddObjectDocUrl.hpp - WindowProperty:FrameAndDivider: correct page (thermal-zone not surface-construction) - InteriorPartitionSurface: remove (no EnergyPlus object, not user-facing in GUI) - HeatPump:PlantLoop:EIR:Cooling/Heating: correct anchors (#plhp_eir_cooling/heating) - HeatPump:AirToWater / :Cooling / :Heating: remove (no EnergyPlus object) All 384 URL references now pass check_doc_urls.py verification. Co-Authored-By: Claude Sonnet 4.6 --- src/model_editor/IddObjectDocUrl.hpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/model_editor/IddObjectDocUrl.hpp b/src/model_editor/IddObjectDocUrl.hpp index 01dc100d5..679e5234a 100644 --- a/src/model_editor/IddObjectDocUrl.hpp +++ b/src/model_editor/IddObjectDocUrl.hpp @@ -69,7 +69,7 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:Construction", "group-surface-construction-elements.html#construction-000"}, {"OS:Construction:InternalSource", "group-surface-construction-elements.html#constructioninternalsource"}, {"OS:Construction:WindowDataFile", "group-surface-construction-elements.html#constructionwindowdatafile"}, - {"OS:WindowProperty:FrameAndDivider", "group-surface-construction-elements.html#windowpropertyframeanddivider"}, + {"OS:WindowProperty:FrameAndDivider", "group-thermal-zone-description-geometry.html#windowpropertyframeanddivider"}, // Thermal Zone Description and Geometry {"OS:ThermalZone", "group-thermal-zone-description-geometry.html"}, @@ -79,7 +79,6 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:Surface", "group-thermal-zone-description-geometry.html#buildingsurfacedetailed"}, {"OS:SubSurface", "group-thermal-zone-description-geometry.html#fenestrationsurfacedetailed"}, {"OS:ShadingControl", "group-thermal-zone-description-geometry.html#windowpropertyshadingcontrol"}, - {"OS:InteriorPartitionSurface", "group-thermal-zone-description-geometry.html#interiorpartitionsurface-detailed"}, {"OS:InteriorPartitionSurfaceGroup", "group-thermal-zone-description-geometry.html"}, // Daylighting @@ -320,15 +319,12 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { {"OS:DistrictCooling", "group-plant-equipment.html#districtcooling"}, {"OS:DistrictHeating", "group-plant-equipment.html#districtheating"}, {"OS:DistrictHeating:Water", "group-plant-equipment.html#districtheating"}, - {"OS:HeatPump:PlantLoop:EIR:Cooling", "group-plant-equipment.html#heatpumpplantloopeircooling"}, - {"OS:HeatPump:PlantLoop:EIR:Heating", "group-plant-equipment.html#heatpumpplantloopeirheating"}, + {"OS:HeatPump:PlantLoop:EIR:Cooling", "group-plant-equipment.html#plhp_eir_cooling"}, + {"OS:HeatPump:PlantLoop:EIR:Heating", "group-plant-equipment.html#plhp_eir_heating"}, {"OS:HeatPump:WaterToWater:EquationFit:Cooling", "group-plant-equipment.html#heatpumpwatertowaterequationfitcooling"}, {"OS:HeatPump:WaterToWater:EquationFit:Heating", "group-plant-equipment.html#heatpumpwatertowaterequationfitheating"}, {"OS:HeatPump:AirToWater:FuelFired:Cooling", "group-plant-equipment.html#plhp_fuelfired"}, {"OS:HeatPump:AirToWater:FuelFired:Heating", "group-plant-equipment.html#plhp_fuelfired"}, - {"OS:HeatPump:AirToWater", "group-plant-equipment.html#plhp_air_to_water"}, - {"OS:HeatPump:AirToWater:Cooling", "group-plant-equipment.html#plhp_air_to_water"}, - {"OS:HeatPump:AirToWater:Heating", "group-plant-equipment.html#plhp_air_to_water"}, {"OS:CentralHeatPumpSystem", "group-plant-equipment.html#centralheatpumpsystem"}, {"OS:CentralHeatPumpSystem:Module", "group-plant-equipment.html#centralheatpumpsystem"}, {"OS:ChillerHeaterPerformance:Electric:EIR", "group-plant-equipment.html#chillerheaterperformancelectriceir"}, From 8a7f8d18520e41544cfdf61e8e0f9766eadc0463 Mon Sep 17 00:00:00 2001 From: Ski90Moo Date: Mon, 1 Jun 2026 08:54:09 +0200 Subject: [PATCH 11/13] style: apply clang-format to PR-touched files Run clang-format -style=file on all C++ files changed relative to develop, to satisfy the Clang Format CI check. Co-Authored-By: Claude Sonnet 4.6 --- src/model_editor/InspectorGadget.cpp | 3 +- src/openstudio_lib/BuildingInspectorView.cpp | 3 +- src/openstudio_lib/ConstructionsView.cpp | 5 +- src/openstudio_lib/GroundTemperatureView.cpp | 18 +++---- src/openstudio_lib/LifeCycleCostsTabView.cpp | 9 ++-- src/openstudio_lib/LocationTabView.cpp | 3 +- src/openstudio_lib/MaterialsView.cpp | 3 +- .../ModelObjectTypeListView.hpp | 4 +- .../OSCollapsibleItemHeader.cpp | 3 +- src/openstudio_lib/SimSettingsView.cpp | 54 +++++++++++++------ src/openstudio_lib/YearSettingsWidget.cpp | 2 +- 11 files changed, 58 insertions(+), 49 deletions(-) diff --git a/src/model_editor/InspectorGadget.cpp b/src/model_editor/InspectorGadget.cpp index 12ba75f9a..7e69a0d73 100644 --- a/src/model_editor/InspectorGadget.cpp +++ b/src/model_editor/InspectorGadget.cpp @@ -476,8 +476,7 @@ void InspectorGadget::layoutHeaderText(QVBoxLayout* layout, QWidget* parent, con label->setTextFormat(Qt::RichText); label->setOpenExternalLinks(true); label->setToolTip(docUrl); - label->setText( - QStringLiteral(R"(%2)").arg(docUrl, typeName.toHtmlEscaped())); + label->setText(QStringLiteral(R"(%2)").arg(docUrl, typeName.toHtmlEscaped())); } else { label->setText(typeName); } diff --git a/src/openstudio_lib/BuildingInspectorView.cpp b/src/openstudio_lib/BuildingInspectorView.cpp index 48da0dcc9..648c65d8d 100644 --- a/src/openstudio_lib/BuildingInspectorView.cpp +++ b/src/openstudio_lib/BuildingInspectorView.cpp @@ -442,8 +442,7 @@ BuildingInspectorView::BuildingInspectorView(bool isIP, bool displayAdditionalPr label->setTextFormat(Qt::RichText); label->setOpenExternalLinks(true); { - static const QString url = - QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "group-simulation-parameters.html#building"; + static const QString url = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "group-simulation-parameters.html#building"; label->setToolTip(url); label->setText(QStringLiteral(R"(North Axis:)").arg(url)); } diff --git a/src/openstudio_lib/ConstructionsView.cpp b/src/openstudio_lib/ConstructionsView.cpp index 81f6ffec0..940d34639 100644 --- a/src/openstudio_lib/ConstructionsView.cpp +++ b/src/openstudio_lib/ConstructionsView.cpp @@ -26,9 +26,8 @@ namespace openstudio { ConstructionsView::ConstructionsView(bool isIP, const openstudio::model::Model& model, QWidget* parent) - : ModelSubTabView( - new ModelObjectTypeListView(ConstructionsView::modelObjectTypesNamesAndUrls(), model, true, OSItemType::ListItem, false, parent), - new ConstructionsInspectorView(isIP, model, parent), false, parent) { + : ModelSubTabView(new ModelObjectTypeListView(ConstructionsView::modelObjectTypesNamesAndUrls(), model, true, OSItemType::ListItem, false, parent), + new ConstructionsInspectorView(isIP, model, parent), false, parent) { connect(this, &ConstructionsView::toggleUnitsClicked, modelObjectInspectorView(), &ModelObjectInspectorView::toggleUnitsClicked); } diff --git a/src/openstudio_lib/GroundTemperatureView.cpp b/src/openstudio_lib/GroundTemperatureView.cpp index 82b3b7540..5c75ea0c3 100644 --- a/src/openstudio_lib/GroundTemperatureView.cpp +++ b/src/openstudio_lib/GroundTemperatureView.cpp @@ -57,8 +57,7 @@ GroundTemperatureEntry::GroundTemperatureEntry(const QString& label, const QStri m_label->setTextFormat(Qt::RichText); m_label->setOpenExternalLinks(true); m_label->setToolTip(url); - m_label->setText( - QStringLiteral(R"(%2)").arg(url, label.toHtmlEscaped())); + m_label->setText(QStringLiteral(R"(%2)").arg(url, label.toHtmlEscaped())); } else { m_label->setText(label); } @@ -103,16 +102,11 @@ GroundTemperatureListView::GroundTemperatureListView(QWidget* parent) : QWidget( static const QString lcwBase = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "group-location-climate-weather-file-access.html"; - m_bsEntry = new GroundTemperatureEntry(tr("Building Surface Ground Temperatures"), - lcwBase + "#sitegroundtemperaturebuildingsurface", this); - m_shEntry = new GroundTemperatureEntry(tr("Shallow Ground Temperatures"), - lcwBase + "#sitegroundtemperatureshallow", this); - m_deepEntry = new GroundTemperatureEntry(tr("Deep Ground Temperatures"), - lcwBase + "#sitegroundtemperaturedeep", this); - m_fcEntry = new GroundTemperatureEntry(tr("FCfactorMethod Ground Temperatures"), - lcwBase + "#sitegroundtemperaturefcfactormethod", this); - m_waterMainsEntry = new GroundTemperatureEntry(tr("Water Mains Temperature"), - lcwBase + "#sitewatermainstemperature", this); + m_bsEntry = new GroundTemperatureEntry(tr("Building Surface Ground Temperatures"), lcwBase + "#sitegroundtemperaturebuildingsurface", this); + m_shEntry = new GroundTemperatureEntry(tr("Shallow Ground Temperatures"), lcwBase + "#sitegroundtemperatureshallow", this); + m_deepEntry = new GroundTemperatureEntry(tr("Deep Ground Temperatures"), lcwBase + "#sitegroundtemperaturedeep", this); + m_fcEntry = new GroundTemperatureEntry(tr("FCfactorMethod Ground Temperatures"), lcwBase + "#sitegroundtemperaturefcfactormethod", this); + m_waterMainsEntry = new GroundTemperatureEntry(tr("Water Mains Temperature"), lcwBase + "#sitewatermainstemperature", this); connect(m_bsEntry, &GroundTemperatureEntry::clicked, this, &GroundTemperatureListView::onBuildingSurfaceClicked); connect(m_shEntry, &GroundTemperatureEntry::clicked, this, &GroundTemperatureListView::onShallowClicked); diff --git a/src/openstudio_lib/LifeCycleCostsTabView.cpp b/src/openstudio_lib/LifeCycleCostsTabView.cpp index 97a921606..d4fbe39b9 100644 --- a/src/openstudio_lib/LifeCycleCostsTabView.cpp +++ b/src/openstudio_lib/LifeCycleCostsTabView.cpp @@ -158,11 +158,10 @@ void LifeCycleCostsView::createWidgets() { static const QString url = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "lifecyclecost-usepriceescalation.html#lifecyclecostusepriceescalation"; label->setToolTip(url); - label->setText( - QStringLiteral(R"()" - "Use National Institute of Standards and Technology (NIST) Fuel Escalation Rates" - R"()") - .arg(url)); + label->setText(QStringLiteral(R"()" + "Use National Institute of Standards and Technology (NIST) Fuel Escalation Rates" + R"()") + .arg(url)); } vLayout->addWidget(label); diff --git a/src/openstudio_lib/LocationTabView.cpp b/src/openstudio_lib/LocationTabView.cpp index 58d403330..542cdd8b7 100644 --- a/src/openstudio_lib/LocationTabView.cpp +++ b/src/openstudio_lib/LocationTabView.cpp @@ -215,8 +215,7 @@ LocationView::LocationView(bool isIP, const model::Model& model, const QString& label->setTextFormat(Qt::RichText); label->setOpenExternalLinks(true); { - static const QString url = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) - + "group-location-climate-weather-file-access.html"; + static const QString url = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "group-location-climate-weather-file-access.html"; label->setToolTip(url); label->setText(QStringLiteral(R"(%2)").arg(url, tr("Weather File"))); } diff --git a/src/openstudio_lib/MaterialsView.cpp b/src/openstudio_lib/MaterialsView.cpp index a0d7a9320..82b8d5264 100644 --- a/src/openstudio_lib/MaterialsView.cpp +++ b/src/openstudio_lib/MaterialsView.cpp @@ -49,8 +49,7 @@ std::vector> MaterialsView::mode using T = std::tuple; return { - T{IddObjectType::OS_Material, "Materials", sce + "#material"}, - T{IddObjectType::OS_Material_NoMass, "No Mass Materials", sce + "#materialnomass"}, + T{IddObjectType::OS_Material, "Materials", sce + "#material"}, T{IddObjectType::OS_Material_NoMass, "No Mass Materials", sce + "#materialnomass"}, T{IddObjectType::OS_Material_AirGap, "Air Gap Materials", sce + "#materialairgap"}, T{IddObjectType::OS_WindowMaterial_SimpleGlazingSystem, "Simple Glazing System Window Materials", sce + "#windowmaterialsimpleglazingsystem"}, T{IddObjectType::OS_WindowMaterial_Glazing, "Glazing Window Materials", sce + "#windowmaterialglazing"}, diff --git a/src/openstudio_lib/ModelObjectTypeListView.hpp b/src/openstudio_lib/ModelObjectTypeListView.hpp index 815e1e3bb..3fdbc451e 100644 --- a/src/openstudio_lib/ModelObjectTypeListView.hpp +++ b/src/openstudio_lib/ModelObjectTypeListView.hpp @@ -34,8 +34,8 @@ class ModelObjectTypeListView : public OSCollapsibleItemList ModelObjectTypeListView(const std::vector>& modelObjectTypesAndNames, const model::Model& model, bool addScrollArea, OSItemType headerType, bool isLibrary, QWidget* parent = nullptr); - ModelObjectTypeListView(const std::vector>& modelObjectTypesNamesAndUrls, - const model::Model& model, bool addScrollArea, OSItemType headerType, bool isLibrary, QWidget* parent = nullptr); + ModelObjectTypeListView(const std::vector>& modelObjectTypesNamesAndUrls, const model::Model& model, + bool addScrollArea, OSItemType headerType, bool isLibrary, QWidget* parent = nullptr); virtual ~ModelObjectTypeListView() {} diff --git a/src/openstudio_lib/OSCollapsibleItemHeader.cpp b/src/openstudio_lib/OSCollapsibleItemHeader.cpp index 53aca6bbc..e62e65e39 100644 --- a/src/openstudio_lib/OSCollapsibleItemHeader.cpp +++ b/src/openstudio_lib/OSCollapsibleItemHeader.cpp @@ -44,8 +44,7 @@ OSCollapsibleItemHeader::OSCollapsibleItemHeader(const std::string& text, const m_textLabel->setTextFormat(Qt::RichText); m_textLabel->setOpenExternalLinks(true); m_textLabel->setToolTip(url); - m_textLabel->setText( - QStringLiteral(R"(%2)").arg(url, m_plainText.toHtmlEscaped())); + m_textLabel->setText(QStringLiteral(R"(%2)").arg(url, m_plainText.toHtmlEscaped())); } else { m_textLabel->setText(m_plainText); } diff --git a/src/openstudio_lib/SimSettingsView.cpp b/src/openstudio_lib/SimSettingsView.cpp index 1dfe43d3f..d2af7a843 100644 --- a/src/openstudio_lib/SimSettingsView.cpp +++ b/src/openstudio_lib/SimSettingsView.cpp @@ -242,7 +242,8 @@ void SimSettingsView::createWidgets() { static const QString iorf = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()); - collapsibleInspector = new CollapsibleInspector(tr("Advanced RunPeriod Parameters"), iorf + "group-location-climate-weather-file-access.html#runperiod", createRunPeriodAdvancedWidget()); + collapsibleInspector = new CollapsibleInspector( + tr("Advanced RunPeriod Parameters"), iorf + "group-location-climate-weather-file-access.html#runperiod", createRunPeriodAdvancedWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:RadianceParameters ******************* @@ -250,7 +251,8 @@ void SimSettingsView::createWidgets() { mainLayout->addWidget(collapsibleInspector); //******************* OS:SimulationControl ******************* - collapsibleInspector = new CollapsibleInspector(tr("Simulation Control"), iorf + "group-simulation-parameters.html#simulationcontrol", createSimulationControlWidget()); + collapsibleInspector = + new CollapsibleInspector(tr("Simulation Control"), iorf + "group-simulation-parameters.html#simulationcontrol", createSimulationControlWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:ProgramControl ******************* @@ -258,39 +260,53 @@ void SimSettingsView::createWidgets() { mainLayout->addWidget(collapsibleInspector); //******************* OS:OutputControl:ReportingTolerances ******************* - collapsibleInspector = new CollapsibleInspector(tr("Output Control Reporting Tolerances"), iorf + "input-for-output.html#outputcontrolreportingtolerances", createOutputControlReportingTolerancesWidget()); + collapsibleInspector = + new CollapsibleInspector(tr("Output Control Reporting Tolerances"), iorf + "input-for-output.html#outputcontrolreportingtolerances", + createOutputControlReportingTolerancesWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:ConvergenceLimits ******************* - collapsibleInspector = new CollapsibleInspector(tr("Convergence Limits"), iorf + "group-simulation-parameters.html#convergencelimits", createConvergenceLimitsWidget()); + collapsibleInspector = + new CollapsibleInspector(tr("Convergence Limits"), iorf + "group-simulation-parameters.html#convergencelimits", createConvergenceLimitsWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:ShadowCalculation ******************* - collapsibleInspector = new CollapsibleInspector(tr("Shadow Calculation"), iorf + "group-simulation-parameters.html#shadowcalculation", createShadowCalculationWidget()); + collapsibleInspector = + new CollapsibleInspector(tr("Shadow Calculation"), iorf + "group-simulation-parameters.html#shadowcalculation", createShadowCalculationWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:SurfaceConvectionAlgorithm:Inside ******************* - collapsibleInspector = new CollapsibleInspector(tr("Inside Surface Convection Algorithm"), iorf + "group-simulation-parameters.html#surfaceconvectionalgorithminside", createSurfaceConvectionAlgorithmInsideWidget()); + collapsibleInspector = + new CollapsibleInspector(tr("Inside Surface Convection Algorithm"), iorf + "group-simulation-parameters.html#surfaceconvectionalgorithminside", + createSurfaceConvectionAlgorithmInsideWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:SurfaceConvectionAlgorithm:Outside ******************* - collapsibleInspector = new CollapsibleInspector(tr("Outside Surface Convection Algorithm"), iorf + "group-simulation-parameters.html#surfaceconvectionalgorithmoutside", createSurfaceConvectionAlgorithmOutsideWidget()); + collapsibleInspector = + new CollapsibleInspector(tr("Outside Surface Convection Algorithm"), iorf + "group-simulation-parameters.html#surfaceconvectionalgorithmoutside", + createSurfaceConvectionAlgorithmOutsideWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:HeatBalanceAlgorithm ******************* - collapsibleInspector = new CollapsibleInspector(tr("Heat Balance Algorithm"), iorf + "group-simulation-parameters.html#heatbalancealgorithm", createHeatBalanceAlgorithmWidget()); + collapsibleInspector = new CollapsibleInspector(tr("Heat Balance Algorithm"), iorf + "group-simulation-parameters.html#heatbalancealgorithm", + createHeatBalanceAlgorithmWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:ZoneAirHeatBalanceAlgorithm ******************* - collapsibleInspector = new CollapsibleInspector(tr("Zone Air Heat Balance Algorithm"), iorf + "group-simulation-parameters.html#zoneairheatbalancealgorithm", createZoneAirHeatBalanceAlgorithmWidget()); + collapsibleInspector = + new CollapsibleInspector(tr("Zone Air Heat Balance Algorithm"), iorf + "group-simulation-parameters.html#zoneairheatbalancealgorithm", + createZoneAirHeatBalanceAlgorithmWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:ZoneAirContaminantBalance ******************* - collapsibleInspector = new CollapsibleInspector(tr("Zone Air Contaminant Balance"), iorf + "group-simulation-parameters.html#zoneaircontaminantbalance", createZoneAirContaminantBalanceWidget()); + collapsibleInspector = new CollapsibleInspector( + tr("Zone Air Contaminant Balance"), iorf + "group-simulation-parameters.html#zoneaircontaminantbalance", createZoneAirContaminantBalanceWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:ZoneCapacitanceMultiplier:ResearchSpecial ******************* - collapsibleInspector = new CollapsibleInspector(tr("Zone Capacitance Multiple Research Special"), iorf + "group-simulation-parameters.html#zonecapacitancemultiplierresearchspecial", createZoneCapacitanceMultipleResearchSpecialWidget()); + collapsibleInspector = new CollapsibleInspector(tr("Zone Capacitance Multiple Research Special"), + iorf + "group-simulation-parameters.html#zonecapacitancemultiplierresearchspecial", + createZoneCapacitanceMultipleResearchSpecialWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:Output:JSON ******************* @@ -298,15 +314,19 @@ void SimSettingsView::createWidgets() { mainLayout->addWidget(collapsibleInspector); //******************* OS:Output:Table:SummaryReports ******************* - collapsibleInspector = new CollapsibleInspector(tr("Output Table Summary Reports"), iorf + "output-table-summaryreports.html#outputtablesummaryreports", createOutputTableSummaryReportsWidget()); + collapsibleInspector = new CollapsibleInspector( + tr("Output Table Summary Reports"), iorf + "output-table-summaryreports.html#outputtablesummaryreports", createOutputTableSummaryReportsWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:Output:Diagnostics ******************* - collapsibleInspector = new CollapsibleInspector(tr("Output Diagnostics"), iorf + "group-simulation-parameters.html#outputdiagnostics", createOutputDiagnosticsWidget()); + collapsibleInspector = + new CollapsibleInspector(tr("Output Diagnostics"), iorf + "group-simulation-parameters.html#outputdiagnostics", createOutputDiagnosticsWidget()); mainLayout->addWidget(collapsibleInspector); //******************* OS:OutputControl:ResilienceSummaries ******************* - collapsibleInspector = new CollapsibleInspector(tr("Output Control Resilience Summaries"), iorf + "input-for-output.html#OutputControlResilienceSummaries", createOutputControlResilienceSummariesWidget()); + collapsibleInspector = + new CollapsibleInspector(tr("Output Control Resilience Summaries"), iorf + "input-for-output.html#OutputControlResilienceSummaries", + createOutputControlResilienceSummariesWidget()); mainLayout->addWidget(collapsibleInspector); mainLayout->addStretch(); @@ -332,7 +352,8 @@ QWidget* SimSettingsView::createRunPeriodWidget() { label->setTextFormat(Qt::RichText); label->setOpenExternalLinks(true); { - static const QString url = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "group-location-climate-weather-file-access.html#runperiod"; + static const QString url = + QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "group-location-climate-weather-file-access.html#runperiod"; label->setToolTip(url); label->setText(QStringLiteral(R"(%2)").arg(url, tr("Run Period"))); } @@ -618,7 +639,8 @@ QWidget* SimSettingsView::createSizingParametersWidget() { { static const QString url = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "group-design-objects.html#sizingparameters"; label->setToolTip(url); - label->setText(QStringLiteral(R"(%2)").arg(url, tr("Sizing Parameters"))); + label->setText( + QStringLiteral(R"(%2)").arg(url, tr("Sizing Parameters"))); } mainLayout->addWidget(label); diff --git a/src/openstudio_lib/YearSettingsWidget.cpp b/src/openstudio_lib/YearSettingsWidget.cpp index 2ef235034..10d52631c 100644 --- a/src/openstudio_lib/YearSettingsWidget.cpp +++ b/src/openstudio_lib/YearSettingsWidget.cpp @@ -109,7 +109,7 @@ YearSettingsWidget::YearSettingsWidget(const model::Model& model, QWidget* paren dstLabel->setOpenExternalLinks(true); { static const QString url = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) - + "group-location-climate-weather-file-access.html#field-daylight-saving-time-indicator"; + + "group-location-climate-weather-file-access.html#field-daylight-saving-time-indicator"; dstLabel->setToolTip(url); dstLabel->setText(QStringLiteral(R"(%2)").arg(url, tr("Daylight Savings Time:"))); } From 2b581104791b1b818dd3320af69bfe788db96bac Mon Sep 17 00:00:00 2001 From: Ski90Moo Date: Mon, 1 Jun 2026 09:43:52 +0200 Subject: [PATCH 12/13] fix: address macumber review comments on IddObjectDocUrl and BuildingInspectorView - Add qWarning log when iddObjectDocUrl cannot find a URL for a type - Use iddObjectDocUrl("OS:Building") in BuildingInspectorView instead of hardcoded URL fragment, consolidating all URL fragments in one place Co-Authored-By: Claude Sonnet 4.6 --- src/model_editor/IddObjectDocUrl.hpp | 4 +++- src/openstudio_lib/BuildingInspectorView.cpp | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/model_editor/IddObjectDocUrl.hpp b/src/model_editor/IddObjectDocUrl.hpp index 679e5234a..002fee04d 100644 --- a/src/model_editor/IddObjectDocUrl.hpp +++ b/src/model_editor/IddObjectDocUrl.hpp @@ -8,6 +8,7 @@ #include #include +#include #include "../utilities/OpenStudioApplicationPathHelpers.hpp" @@ -459,7 +460,8 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { if (it != urlMap.constEnd()) { return base + it.value(); } - return QString(); + qWarning() << "Cannot find doc url for: " + iddTypeName; + return {}; } #endif // MODELEDITOR_IDDOBJECTDOCURL_HPP diff --git a/src/openstudio_lib/BuildingInspectorView.cpp b/src/openstudio_lib/BuildingInspectorView.cpp index 648c65d8d..0c6d28dcc 100644 --- a/src/openstudio_lib/BuildingInspectorView.cpp +++ b/src/openstudio_lib/BuildingInspectorView.cpp @@ -4,7 +4,7 @@ ***********************************************************************************************************************/ #include "BuildingInspectorView.hpp" -#include "../utilities/OpenStudioApplicationPathHelpers.hpp" +#include "../model_editor/IddObjectDocUrl.hpp" #include "../shared_gui_components/OSComboBox.hpp" #include "../shared_gui_components/OSIntegerEdit.hpp" @@ -442,7 +442,7 @@ BuildingInspectorView::BuildingInspectorView(bool isIP, bool displayAdditionalPr label->setTextFormat(Qt::RichText); label->setOpenExternalLinks(true); { - static const QString url = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "group-simulation-parameters.html#building"; + static const QString url = iddObjectDocUrl(QStringLiteral("OS:Building")); label->setToolTip(url); label->setText(QStringLiteral(R"(North Axis:)").arg(url)); } From 8c05784baf8e3bec981cbfa46d3c48482de72a64 Mon Sep 17 00:00:00 2001 From: Ski90Moo Date: Mon, 1 Jun 2026 11:26:46 +0200 Subject: [PATCH 13/13] feat: add iddGroupDocUrl() mapping OpenStudio IDD groups to BigLadder pages Adds a new iddGroupDocUrl(groupName) function to IddObjectDocUrl.hpp that maps OpenStudio.idd \group names to their corresponding BigLadder EnergyPlus I/O Reference page URLs. Groups that span multiple EnergyPlus chapters (e.g. "OpenStudio HVAC") are intentionally omitted. Also updates check_doc_urls.py regex to cover groupMap entries alongside the existing urlMap entries. Co-Authored-By: Claude Sonnet 4.6 --- scripts/check_doc_urls.py | 5 ++-- src/model_editor/IddObjectDocUrl.hpp | 36 ++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/scripts/check_doc_urls.py b/scripts/check_doc_urls.py index c574c076c..959bc766b 100644 --- a/scripts/check_doc_urls.py +++ b/scripts/check_doc_urls.py @@ -44,10 +44,11 @@ # Files to scan and the regex patterns that extract URL fragments from them # --------------------------------------------------------------------------- -# Matches values in the IddObjectDocUrl.hpp urlMap: +# Matches values in the IddObjectDocUrl.hpp urlMap and groupMap: # {"OS:Something", "group-foo.html#anchor"}, +# {"OpenStudio Group Name", "group-foo.html"}, IDDOBJECTDOCURL_PATTERN = re.compile( - r'"OS:[^"]+"\s*,\s*"([^"]+\.html(?:#[^"]*)?)"' + r'"(?:OS:|OpenStudio |Solar |Electric |Energy |User |Python |Airflow)[^"]*"\s*,\s*"([^"]+\.html(?:#[^"]*)?)"' ) # Matches QString URL constructions in .cpp files: diff --git a/src/model_editor/IddObjectDocUrl.hpp b/src/model_editor/IddObjectDocUrl.hpp index 002fee04d..2c0aa3333 100644 --- a/src/model_editor/IddObjectDocUrl.hpp +++ b/src/model_editor/IddObjectDocUrl.hpp @@ -464,4 +464,40 @@ inline QString iddObjectDocUrl(const QString& iddTypeName) { return {}; } +// Returns the BigLadder EnergyPlus I/O Reference page URL for a given +// OpenStudio IDD group name (e.g. "OpenStudio Simulation"), or an empty string +// if the group has no known BigLadder page. Group names match \group +// declarations in OpenStudio.idd. Groups that span multiple EnergyPlus +// chapters (e.g. "OpenStudio HVAC") are omitted. +inline QString iddGroupDocUrl(const QString& groupName) { + static const QString base = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()); + + // clang-format off + static const QHash groupMap{ + {"OpenStudio Core", "group-simulation-parameters.html"}, + {"OpenStudio Simulation", "group-simulation-parameters.html"}, + {"OpenStudio Site", "group-location-climate-weather-file-access.html"}, + {"OpenStudio Materials", "group-surface-construction-elements.html"}, + {"OpenStudio Constructions", "group-surface-construction-elements.html"}, + {"OpenStudio Space Load Definitions", "group-internal-gains-people-lights-other.html"}, + {"OpenStudio Exterior Equipment Definitions", "group-exterior-energy-use-equipment.html"}, + {"OpenStudio Schedules", "group-schedules.html"}, + {"OpenStudio Geometry", "group-thermal-zone-description-geometry.html"}, + {"OpenStudio Space Loads", "group-internal-gains-people-lights-other.html"}, + {"OpenStudio Exterior Equipment", "group-exterior-energy-use-equipment.html"}, + {"OpenStudio Lighting Simulation", "group-daylighting.html"}, + {"OpenStudio Refrigeration", "group-refrigeration.html"}, + {"Solar Collectors", "group-solar-collectors.html"}, + {"Energy Management System (EMS)", "group-energy-management-system-ems.html"}, + {"User Defined HVAC and Plant Component Models", "group-user-defined-hvac-and-plant-component.html"}, + }; + // clang-format on + + auto it = groupMap.constFind(groupName); + if (it != groupMap.constEnd()) { + return base + it.value(); + } + return {}; +} + #endif // MODELEDITOR_IDDOBJECTDOCURL_HPP