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/scripts/check_doc_urls.py b/scripts/check_doc_urls.py new file mode 100644 index 000000000..959bc766b --- /dev/null +++ b/scripts/check_doc_urls.py @@ -0,0 +1,213 @@ +#!/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] [--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 +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 and groupMap: +# {"OS:Something", "group-foo.html#anchor"}, +# {"OpenStudio Group Name", "group-foo.html"}, +IDDOBJECTDOCURL_PATTERN = re.compile( + r'"(?:OS:|OpenStudio |Solar |Electric |Energy |User |Python |Airflow)[^"]*"\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() diff --git a/src/model_editor/IddObjectDocUrl.hpp b/src/model_editor/IddObjectDocUrl.hpp new file mode 100644 index 000000000..2c0aa3333 --- /dev/null +++ b/src/model_editor/IddObjectDocUrl.hpp @@ -0,0 +1,503 @@ +/*********************************************************************************************************************** +* 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 +#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 = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()); + + // 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-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"}, + {"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: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"}, + {"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", "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"}, + {"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#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"}, + {"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-000"}, + {"OS:Construction:InternalSource", "group-surface-construction-elements.html#constructioninternalsource"}, + {"OS:Construction:WindowDataFile", "group-surface-construction-elements.html#constructionwindowdatafile"}, + {"OS:WindowProperty:FrameAndDivider", "group-thermal-zone-description-geometry.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#buildingsurfacedetailed"}, + {"OS:SubSurface", "group-thermal-zone-description-geometry.html#fenestrationsurfacedetailed"}, + {"OS:ShadingControl", "group-thermal-zone-description-geometry.html#windowpropertyshadingcontrol"}, + {"OS:InteriorPartitionSurfaceGroup", "group-thermal-zone-description-geometry.html"}, + + // Daylighting + {"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-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#hotwaterequipment"}, + {"OS:SteamEquipment", "group-internal-gains-people-lights-other.html#steamequipment"}, + {"OS:OtherEquipment", "group-internal-gains-people-lights-other.html#otherequipment"}, + {"OS:InternalMass", "group-thermal-zone-description-geometry.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"}, + {"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#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#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#airterminalsingleductconstantvolumefourpipeinduction"}, + {"OS:AirTerminal:SingleDuct:ConstantVolume:FourPipeInduction", "group-air-distribution-equipment.html#airterminalsingleductconstantvolumefourpipeinduction"}, + + // 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"}, + {"OS:Fan:ComponentModel", "group-fans.html#fancomponentmodel"}, + + // 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-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"}, + {"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"}, + {"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"}, + {"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-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"}, + {"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"}, + {"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#evaporativecoolerdirectceldekpad"}, + {"OS:EvaporativeCooler:Indirect:CelDekPad", "group-evaporative-coolers.html#evaporativecoolerindirectceldekpad"}, + {"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-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-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#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"}, + {"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#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"}, + {"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"}, + {"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"}, + {"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#chillerabsorption"}, + {"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#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: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"}, + {"OS:FluidCooler:TwoSpeed", "group-condenser-equipment.html#fluidcoolertwospeed"}, + + // Heat Recovery + {"OS:HeatExchanger:AirToAir:SensibleAndLatent", "group-heat-recovery.html#heatexchangerairtoairsensibleandlatent"}, + {"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#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#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"}, + {"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"}, + {"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-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"}, + {"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:TemperingValve", "group-plant-condenser-flow-control.html#temperingvalve"}, + {"OS:LoadProfile:Plant", "group-non-zone-equipment.html#loadprofileplant"}, + {"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"}, + {"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: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"}, + }; + // clang-format on + + auto it = urlMap.constFind(iddTypeName); + if (it != urlMap.constEnd()) { + return base + it.value(); + } + qWarning() << "Cannot find doc url for: " + 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 diff --git a/src/model_editor/InspectorGadget.cpp b/src/model_editor/InspectorGadget.cpp index aae9a1d08..7e69a0d73 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" @@ -265,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()); @@ -454,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(); @@ -464,30 +464,30 @@ 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(QString(val.c_str()), parent); - label->setObjectName("IGHeader"); - label->setStyleSheet("font: bold"); - // 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/BuildingInspectorView.cpp b/src/openstudio_lib/BuildingInspectorView.cpp index eff88aac6..0c6d28dcc 100644 --- a/src/openstudio_lib/BuildingInspectorView.cpp +++ b/src/openstudio_lib/BuildingInspectorView.cpp @@ -4,6 +4,7 @@ ***********************************************************************************************************************/ #include "BuildingInspectorView.hpp" +#include "../model_editor/IddObjectDocUrl.hpp" #include "../shared_gui_components/OSComboBox.hpp" #include "../shared_gui_components/OSIntegerEdit.hpp" @@ -41,6 +42,7 @@ #include #include #include +#include namespace openstudio { @@ -437,8 +439,13 @@ 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 = iddObjectDocUrl(QStringLiteral("OS: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/CollapsibleInspector.cpp b/src/openstudio_lib/CollapsibleInspector.cpp index 91a3e6146..a7a14c470 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,17 @@ 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->setToolTip(m_url); + 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/ConstructionsView.cpp b/src/openstudio_lib/ConstructionsView.cpp index eee61c450..940d34639 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 @@ -19,28 +20,31 @@ #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), + : 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 = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()); + 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/GroundTemperatureView.cpp b/src/openstudio_lib/GroundTemperatureView.cpp index 4ce5d28ba..5c75ea0c3 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" @@ -25,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +37,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 +50,17 @@ 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,13 @@ 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 = + 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); 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..d4fbe39b9 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" @@ -19,6 +20,7 @@ #include #include #include +#include #include #define OS_EDIT_WIDTH 150 @@ -58,8 +60,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 = + QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "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 +151,18 @@ 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 = + 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)); + } vLayout->addWidget(label); m_nistGroup = new QButtonGroup(this); diff --git a/src/openstudio_lib/LoadsView.cpp b/src/openstudio_lib/LoadsView.cpp index 3e505a96a..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" @@ -20,6 +21,7 @@ #include +#include #include #include #include @@ -28,32 +30,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 = 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"); + + 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/LocationTabView.cpp b/src/openstudio_lib/LocationTabView.cpp index ce6cdb460..542cdd8b7 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" @@ -209,8 +210,15 @@ 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 = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()) + "group-location-climate-weather-file-access.html"; + label->setToolTip(url); + label->setText(QStringLiteral(R"(%2)").arg(url, tr("Weather File"))); + } m_weatherFileBtn = new QPushButton(this); m_weatherFileBtn->setFlat(true); @@ -456,8 +464,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 = + 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"))); + } auto* btn = new QPushButton(tr("Import From DDY"), this); btn->setFlat(true); diff --git a/src/openstudio_lib/MaterialsView.cpp b/src/openstudio_lib/MaterialsView.cpp index 9eb763d2d..82b8d5264 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" @@ -29,44 +30,43 @@ #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 = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()); + 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..3fdbc451e 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..e62e65e39 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,18 @@ 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 +67,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..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" @@ -16,20 +17,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 = QString::fromStdString(openstudio::bigladdersoftwareDocBaseUrl()); + 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 diff --git a/src/openstudio_lib/SimSettingsView.cpp b/src/openstudio_lib/SimSettingsView.cpp index 6a4e9102b..d2af7a843 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,10 @@ void SimSettingsView::createWidgets() { //******************* OS:Timestep ******************* mainLayout->addWidget(createTimestepWidget()); - collapsibleInspector = new CollapsibleInspector("Advanced RunPeriod Parameters", createRunPeriodAdvancedWidget()); + 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); //******************* OS:RadianceParameters ******************* @@ -247,7 +251,8 @@ 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 +260,73 @@ 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 +347,16 @@ QWidget* SimSettingsView::createRunPeriodWidget() { QHBoxLayout* hLayout = nullptr; - label = new QLabel("Run Period"); + label = new QLabel(); label->setObjectName("H1"); + label->setTextFormat(Qt::RichText); + label->setOpenExternalLinks(true); + { + 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"))); + } mainVLayout->addWidget(label); mainVLayout->addLayout(mainHLayout); @@ -601,8 +632,16 @@ QWidget* SimSettingsView::createSizingParametersWidget() { QLabel* label = nullptr; - label = new QLabel("Sizing Parameters"); + label = new QLabel(); label->setObjectName("H1"); + label->setTextFormat(Qt::RichText); + label->setOpenExternalLinks(true); + { + 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"))); + } mainLayout->addWidget(label); auto* gridLayout = new QGridLayout(); @@ -651,8 +690,15 @@ QWidget* SimSettingsView::createTimestepWidget() { QLabel* label = nullptr; - label = new QLabel("Timestep"); + label = new QLabel(); label->setObjectName("H1"); + label->setTextFormat(Qt::RichText); + label->setOpenExternalLinks(true); + { + 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"))); + } mainLayout->addWidget(label); auto* gridLayout = new QGridLayout(); diff --git a/src/openstudio_lib/YearSettingsWidget.cpp b/src/openstudio_lib/YearSettingsWidget.cpp index fe838aa47..10d52631c 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" @@ -102,8 +103,16 @@ 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 = 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:"))); + } dstHLayout1->addWidget(dstLabel); m_dstOnOffButton = new OSSwitch2(); 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