summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Wicking <[email protected]>2025-08-18 08:17:29 +0200
committerPaul Wicking <[email protected]>2025-08-21 12:28:47 +0200
commit74711c4f1d4ca64f5f916519ee56fe48a926aeda (patch)
tree45dd68304d8790b76cae8708510dcf4f8efbdd2c /src
parent70e18dda1184c44f354a493bc1c0d510267b93a1 (diff)
QDoc: Group property role notes in outputHEADdev
When a signal (or other role) applies to multiple properties, QDoc repeats the same “<Role> for property X.” line for each property. This creates noisy, hard-to-scan documentation. This change modifies `Generator::generateAddendum()` such that it groups properties by `FunctionRole`. This allows QDoc to emit a single admonition per role, listing all applicable properties. For example: Notifier signal for properties Foo, Bar, and Baz. Properties are listed alphabetically; roles follow enum order (Getter, Setter, Resetter, Notifier, Bindable). This ensures deterministic output. There's no change to semantics or links, as this is a wording/format improvement only. The change also includes a validate-output test (HTML/DocBook/WebXML) that demonstrates the previous repetition and the new grouped output. Fixes: QTBUG-86490 Pick-to: 6.10 6.9 6.8 Change-Id: I5221c25f8040cc617dd2ec595f58c95d16120ac7 Reviewed-by: Topi Reiniö <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/qdoc/qdoc/src/qdoc/docbookgenerator.cpp56
-rw-r--r--src/qdoc/qdoc/src/qdoc/generator.cpp57
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/docbook/testaction.xml157
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/docbook/testmodule-module.xml26
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/html/multisignaltest.index50
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/html/testaction-members.html28
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/html/testaction.html139
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/html/testmodule-module.html33
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/webxml/multisignaltest.index50
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/webxml/testaction.webxml101
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/webxml/testmodule-module.webxml4
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/multisignal.qdocconf30
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/src/testaction.cpp117
-rw-r--r--src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/src/testaction.h44
14 files changed, 874 insertions, 18 deletions
diff --git a/src/qdoc/qdoc/src/qdoc/docbookgenerator.cpp b/src/qdoc/qdoc/src/qdoc/docbookgenerator.cpp
index 62098efdf..bfb8e1ae2 100644
--- a/src/qdoc/qdoc/src/qdoc/docbookgenerator.cpp
+++ b/src/qdoc/qdoc/src/qdoc/docbookgenerator.cpp
@@ -4064,14 +4064,37 @@ void DocBookGenerator::generateAddendum(const Node *node, Addendum type, CodeMar
if (!node->isFunction())
return;
const auto *fn = static_cast<const FunctionNode *>(node);
- auto propertyNodes = fn->associatedProperties();
- if (propertyNodes.isEmpty())
+ auto nodes = fn->associatedProperties();
+ if (nodes.isEmpty())
return;
- std::sort(propertyNodes.begin(), propertyNodes.end(), Node::nodeNameLessThan);
- for (const auto propertyNode : std::as_const(propertyNodes)) {
+ std::sort(nodes.begin(), nodes.end(), Node::nodeNameLessThan);
+
+ // Group properties by their role for more concise output
+ QMap<PropertyNode::FunctionRole, QList<const PropertyNode *>> roleGroups;
+ for (const auto *n : std::as_const(nodes)) {
+ const auto *pn = static_cast<const PropertyNode *>(n);
+ PropertyNode::FunctionRole role = pn->role(fn);
+ roleGroups[role].append(pn);
+ }
+
+ // Generate text for each role group in an explicit order
+ static constexpr PropertyNode::FunctionRole roleOrder[] = {
+ PropertyNode::FunctionRole::Getter,
+ PropertyNode::FunctionRole::Setter,
+ PropertyNode::FunctionRole::Resetter,
+ PropertyNode::FunctionRole::Notifier,
+ PropertyNode::FunctionRole::Bindable,
+ };
+
+ for (auto role : roleOrder) {
+ const auto it = roleGroups.constFind(role);
+ if (it == roleGroups.cend())
+ continue;
+
+ const auto &properties = it.value();
+
QString msg;
- const auto pn = static_cast<const PropertyNode *>(propertyNode);
- switch (pn->role(fn)) {
+ switch (role) {
case PropertyNode::FunctionRole::Getter:
msg = QStringLiteral("Getter function");
break;
@@ -4084,13 +4107,28 @@ void DocBookGenerator::generateAddendum(const Node *node, Addendum type, CodeMar
case PropertyNode::FunctionRole::Notifier:
msg = QStringLiteral("Notifier signal");
break;
+ case PropertyNode::FunctionRole::Bindable:
+ msg = QStringLiteral("Bindable function");
+ break;
default:
continue;
}
+
m_writer->writeStartElement(dbNamespace, "para");
- m_writer->writeCharacters(msg + " for property ");
- generateSimpleLink(linkForNode(pn, nullptr), pn->name());
- m_writer->writeCharacters(". ");
+ if (properties.size() == 1) {
+ const auto *pn = properties.first();
+ m_writer->writeCharacters(msg + " for property ");
+ generateSimpleLink(linkForNode(pn, nullptr), pn->name());
+ m_writer->writeCharacters(". ");
+ } else {
+ m_writer->writeCharacters(msg + " for properties ");
+ for (qsizetype i = 0; i < properties.size(); ++i) {
+ const auto *pn = properties.at(i);
+ generateSimpleLink(linkForNode(pn, nullptr), pn->name());
+ m_writer->writeCharacters(Utilities::separator(i, properties.size()));
+ }
+ m_writer->writeCharacters(" ");
+ }
m_writer->writeEndElement(); // para
newLine();
}
diff --git a/src/qdoc/qdoc/src/qdoc/generator.cpp b/src/qdoc/qdoc/src/qdoc/generator.cpp
index 71cdade2d..2c84d49e0 100644
--- a/src/qdoc/qdoc/src/qdoc/generator.cpp
+++ b/src/qdoc/qdoc/src/qdoc/generator.cpp
@@ -1317,28 +1317,67 @@ void Generator::generateAddendum(const Node *node, Addendum type, CodeMarker *ma
if (nodes.isEmpty())
return;
std::sort(nodes.begin(), nodes.end(), Node::nodeNameLessThan);
+
+ // Group properties by their role for more concise output
+ QMap<PropertyNode::FunctionRole, QList<const PropertyNode *>> roleGroups;
for (const auto *n : std::as_const(nodes)) {
- QString msg;
const auto *pn = static_cast<const PropertyNode *>(n);
- switch (pn->role(fn)) {
+ PropertyNode::FunctionRole role = pn->role(fn);
+ roleGroups[role].append(pn);
+ }
+
+ // Generate text for each role group in an explicit order
+ static constexpr PropertyNode::FunctionRole roleOrder[] = {
+ PropertyNode::FunctionRole::Getter,
+ PropertyNode::FunctionRole::Setter,
+ PropertyNode::FunctionRole::Resetter,
+ PropertyNode::FunctionRole::Notifier,
+ PropertyNode::FunctionRole::Bindable,
+ };
+ for (auto role : roleOrder) {
+ const auto it = roleGroups.constFind(role);
+ if (it == roleGroups.cend())
+ continue;
+
+ const auto &properties = it.value();
+
+ QString msg;
+ switch (role) {
case PropertyNode::FunctionRole::Getter:
- msg = QStringLiteral("Getter function");
+ msg = u"Getter function"_s;
break;
case PropertyNode::FunctionRole::Setter:
- msg = QStringLiteral("Setter function");
+ msg = u"Setter function"_s;
break;
case PropertyNode::FunctionRole::Resetter:
- msg = QStringLiteral("Resetter function");
+ msg = u"Resetter function"_s;
break;
case PropertyNode::FunctionRole::Notifier:
- msg = QStringLiteral("Notifier signal");
+ msg = u"Notifier signal"_s;
+ break;
+ case PropertyNode::FunctionRole::Bindable:
+ msg = u"Bindable function"_s;
break;
default:
continue;
}
- text << msg << " for property " << Atom(Atom::Link, pn->name())
- << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << pn->name()
- << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << ". ";
+
+ if (properties.size() == 1) {
+ const auto *pn = properties.first();
+ text << msg << u" for property "_s << Atom(Atom::Link, pn->name())
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << pn->name()
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << u". "_s;
+ } else {
+ text << msg << u" for properties "_s;
+ for (qsizetype i = 0; i < properties.size(); ++i) {
+ const auto *pn = properties.at(i);
+ text << Atom(Atom::Link, pn->name())
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << pn->name()
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
+ << Utilities::separator(i, properties.size());
+ }
+ text << u" "_s;
+ }
}
break;
}
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/docbook/testaction.xml b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/docbook/testaction.xml
new file mode 100644
index 000000000..93580fea3
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/docbook/testaction.xml
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<db:article xmlns:db="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.2" xml:lang="en">
+<db:info>
+<db:title>TestAction Class</db:title>
+<db:productname>MultiSignalTest</db:productname>
+<db:titleabbrev>Test for improved multi-property signal documentation</db:titleabbrev>
+<db:abstract>
+<db:para>A test class to demonstrate improved multi-property signal documentation.</db:para>
+</db:abstract>
+</db:info>
+<db:variablelist>
+<db:varlistentry>
+<db:term>Header</db:term>
+<db:listitem>
+<db:para>TestAction</db:para>
+</db:listitem>
+</db:varlistentry>
+<db:varlistentry>
+<db:term>Inherits</db:term>
+<db:listitem>
+<db:para/>
+</db:listitem>
+</db:varlistentry>
+</db:variablelist>
+<db:section xml:id="details">
+<db:title>Detailed Description</db:title>
+<db:para>This class has properties with different notification patterns.</db:para>
+</db:section>
+<db:section xml:id="property-documentation">
+<db:title>Property Documentation</db:title>
+<db:section xml:id="checkable-prop">
+<db:title>checkable : bool</db:title>
+<db:para>This property holds whether the action is checkable</db:para>
+<db:para>This property determines if the action can be toggled.</db:para>
+<db:para>
+<db:emphasis role="bold">Access functions:
+</db:emphasis>
+</db:para>
+<db:itemizedlist>
+<db:listitem>
+<db:para><db:type>bool</db:type> <db:emphasis role="bold"><db:link xlink:href="">isCheckable</db:link></db:emphasis>() const</db:para>
+</db:listitem>
+<db:listitem>
+<db:para><db:type>void</db:type> <db:emphasis role="bold"><db:link xlink:href="">setCheckable</db:link></db:emphasis>(<db:type>bool</db:type> <db:emphasis>checkable</db:emphasis>)</db:para>
+</db:listitem>
+</db:itemizedlist>
+<db:para>
+<db:emphasis role="bold">Notifier signal:
+</db:emphasis>
+</db:para>
+<db:itemizedlist>
+<db:listitem>
+<db:para><db:type>void</db:type> <db:emphasis role="bold"><db:link xlink:href="testaction.xml#singlePropertySignal">singlePropertySignal</db:link></db:emphasis>()</db:para>
+</db:listitem>
+</db:itemizedlist>
+</db:section>
+<db:section xml:id="enabled-prop">
+<db:title>enabled : bool</db:title>
+<db:para>This property holds whether the action is enabled</db:para>
+<db:para>This property determines if the action can be triggered.</db:para>
+<db:para>
+<db:emphasis role="bold">Access functions:
+</db:emphasis>
+</db:para>
+<db:itemizedlist>
+<db:listitem>
+<db:para><db:type>bool</db:type> <db:emphasis role="bold"><db:link xlink:href="">isEnabled</db:link></db:emphasis>() const</db:para>
+</db:listitem>
+<db:listitem>
+<db:para><db:type>void</db:type> <db:emphasis role="bold"><db:link xlink:href="">setEnabled</db:link></db:emphasis>(<db:type>bool</db:type> <db:emphasis>enabled</db:emphasis>)</db:para>
+</db:listitem>
+</db:itemizedlist>
+<db:para>
+<db:emphasis role="bold">Notifier signal:
+</db:emphasis>
+</db:para>
+<db:itemizedlist>
+<db:listitem>
+<db:para><db:type>void</db:type> <db:emphasis role="bold"><db:link xlink:href="testaction.xml#changed">changed</db:link></db:emphasis>()</db:para>
+</db:listitem>
+</db:itemizedlist>
+</db:section>
+<db:section xml:id="text-prop">
+<db:title>text : QString</db:title>
+<db:para>This property holds the action's display text</db:para>
+<db:para>This property holds the text that is displayed for the action.</db:para>
+<db:para>
+<db:emphasis role="bold">Access functions:
+</db:emphasis>
+</db:para>
+<db:itemizedlist>
+<db:listitem>
+<db:para><db:type>QString</db:type> <db:emphasis role="bold"><db:link xlink:href="">text</db:link></db:emphasis>() const</db:para>
+</db:listitem>
+<db:listitem>
+<db:para><db:type>void</db:type> <db:emphasis role="bold"><db:link xlink:href="">setText</db:link></db:emphasis>(const <db:type>QString</db:type> &amp;<db:emphasis>text</db:emphasis>)</db:para>
+</db:listitem>
+</db:itemizedlist>
+<db:para>
+<db:emphasis role="bold">Notifier signal:
+</db:emphasis>
+</db:para>
+<db:itemizedlist>
+<db:listitem>
+<db:para><db:type>void</db:type> <db:emphasis role="bold"><db:link xlink:href="testaction.xml#changed">changed</db:link></db:emphasis>()</db:para>
+</db:listitem>
+</db:itemizedlist>
+</db:section>
+<db:section xml:id="visible-prop">
+<db:title>visible : bool</db:title>
+<db:para>This property holds whether the action is visible</db:para>
+<db:para>This property determines if the action is shown in UI.</db:para>
+<db:para>
+<db:emphasis role="bold">Access functions:
+</db:emphasis>
+</db:para>
+<db:itemizedlist>
+<db:listitem>
+<db:para><db:type>bool</db:type> <db:emphasis role="bold"><db:link xlink:href="">isVisible</db:link></db:emphasis>() const</db:para>
+</db:listitem>
+<db:listitem>
+<db:para><db:type>void</db:type> <db:emphasis role="bold"><db:link xlink:href="">setVisible</db:link></db:emphasis>(<db:type>bool</db:type> <db:emphasis>visible</db:emphasis>)</db:para>
+</db:listitem>
+</db:itemizedlist>
+<db:para>
+<db:emphasis role="bold">Notifier signal:
+</db:emphasis>
+</db:para>
+<db:itemizedlist>
+<db:listitem>
+<db:para><db:type>void</db:type> <db:emphasis role="bold"><db:link xlink:href="testaction.xml#changed">changed</db:link></db:emphasis>()</db:para>
+</db:listitem>
+</db:itemizedlist>
+</db:section>
+</db:section>
+<db:section xml:id="member-function-documentation">
+<db:title>Member Function Documentation</db:title>
+<db:section xml:id="TestAction">
+<db:title>[explicit] TestAction::TestAction(QObject *<db:emphasis>parent</db:emphasis> = nullptr)</db:title>
+<db:para>Constructs a <db:link xlink:href="testaction.xml">TestAction</db:link> with the given <db:code role="parameter">parent</db:code>.</db:para>
+</db:section>
+<db:section xml:id="changed">
+<db:title>[signal] void TestAction::changed()</db:title>
+<db:para>This signal is emitted when certain properties of the action change. The properties that trigger this signal are enabled, visible, and text.</db:para>
+<db:note>
+<db:para>Notifier signal for properties <db:link xlink:href="testaction.xml#enabled-prop">enabled</db:link>, <db:link xlink:href="testaction.xml#text-prop">text</db:link>, and <db:link xlink:href="testaction.xml#visible-prop">visible</db:link>. </db:para>
+</db:note>
+</db:section>
+<db:section xml:id="singlePropertySignal">
+<db:title>[signal] void TestAction::singlePropertySignal()</db:title>
+<db:para>This signal is emitted when the checkable property changes.</db:para>
+<db:note>
+<db:para>Notifier signal for property <db:link xlink:href="testaction.xml#checkable-prop">checkable</db:link>. </db:para>
+</db:note>
+</db:section>
+</db:section>
+</db:article>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/docbook/testmodule-module.xml b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/docbook/testmodule-module.xml
new file mode 100644
index 000000000..dbdeb41ef
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/docbook/testmodule-module.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<db:article xmlns:db="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.2" xml:lang="en">
+<db:info>
+<db:title></db:title>
+<db:productname>MultiSignalTest</db:productname>
+<db:titleabbrev>Test for improved multi-property signal documentation</db:titleabbrev>
+<db:abstract>
+<db:para>A test module.</db:para>
+</db:abstract>
+</db:info>
+<db:para>A test module.</db:para>
+<db:section xml:id="classes">
+<db:title>Classes</db:title>
+<db:variablelist role="classes">
+<db:varlistentry>
+<db:term><db:link xlink:href="testaction.xml" xlink:role="class">TestAction</db:link></db:term>
+<db:listitem>
+<db:para>A test class to demonstrate improved multi-property signal documentation.</db:para>
+</db:listitem>
+</db:varlistentry>
+</db:variablelist>
+</db:section>
+<db:section xml:id="details">
+<db:title>Detailed Description</db:title>
+</db:section>
+</db:article>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/html/multisignaltest.index b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/html/multisignaltest.index
new file mode 100644
index 000000000..87e4f0cbd
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/html/multisignaltest.index
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE QDOCINDEX>
+<INDEX url="" title="Test for improved multi-property signal documentation" version="" project="MultiSignalTest">
+ <namespace name="" status="active" access="public" module="multisignaltest">
+ <class name="TestAction" href="testaction.html" status="active" access="public" location="testaction.h" documented="true" bases="QObject" module="TestModule" brief="A test class to demonstrate improved multi-property signal documentation">
+ <function name="TestAction" fullname="TestAction::TestAction" href="testaction.html#TestAction" status="active" access="public" location="testaction.h" documented="true" meta="constructor" explicit="true" signature="TestAction(QObject *parent)">
+ <parameter type="QObject *" name="parent" default="nullptr"/>
+ </function>
+ <function name="changed" fullname="TestAction::changed" href="testaction.html#changed" status="active" access="public" location="testaction.h" documented="true" meta="signal" associated-property="enabled,text,visible" type="void" signature="void changed()"/>
+ <function name="isCheckable" fullname="TestAction::isCheckable" href="testaction.html#checkable-prop" status="active" access="public" location="testaction.h" meta="plain" const="true" associated-property="checkable" type="bool" signature="bool isCheckable() const"/>
+ <function name="isEnabled" fullname="TestAction::isEnabled" href="testaction.html#enabled-prop" status="active" access="public" location="testaction.h" meta="plain" const="true" associated-property="enabled" type="bool" signature="bool isEnabled() const"/>
+ <function name="isVisible" fullname="TestAction::isVisible" href="testaction.html#visible-prop" status="active" access="public" location="testaction.h" meta="plain" const="true" associated-property="visible" type="bool" signature="bool isVisible() const"/>
+ <function name="setCheckable" fullname="TestAction::setCheckable" href="testaction.html#checkable-prop" status="active" access="public" location="testaction.h" meta="plain" associated-property="checkable" type="void" signature="void setCheckable(bool checkable)">
+ <parameter type="bool" name="checkable" default=""/>
+ </function>
+ <function name="setEnabled" fullname="TestAction::setEnabled" href="testaction.html#enabled-prop" status="active" access="public" location="testaction.h" meta="plain" associated-property="enabled" type="void" signature="void setEnabled(bool enabled)">
+ <parameter type="bool" name="enabled" default=""/>
+ </function>
+ <function name="setText" fullname="TestAction::setText" href="testaction.html#text-prop" status="active" access="public" location="testaction.h" meta="plain" associated-property="text" type="void" signature="void setText(const QString &amp;text)">
+ <parameter type="const QString &amp;" name="text" default=""/>
+ </function>
+ <function name="setVisible" fullname="TestAction::setVisible" href="testaction.html#visible-prop" status="active" access="public" location="testaction.h" meta="plain" associated-property="visible" type="void" signature="void setVisible(bool visible)">
+ <parameter type="bool" name="visible" default=""/>
+ </function>
+ <function name="singlePropertySignal" fullname="TestAction::singlePropertySignal" href="testaction.html#singlePropertySignal" status="active" access="public" location="testaction.h" documented="true" meta="signal" associated-property="checkable" type="void" signature="void singlePropertySignal()"/>
+ <function name="text" fullname="TestAction::text" href="testaction.html#text-prop" status="active" access="public" location="testaction.h" meta="plain" const="true" associated-property="text" type="QString" signature="QString text() const"/>
+ <property name="checkable" fullname="TestAction::checkable" href="testaction.html#checkable-prop" status="active" access="public" location="testaction.h" documented="true" brief="This property holds whether the action is checkable">
+ <getter name="isCheckable"/>
+ <setter name="setCheckable"/>
+ <notifier name="singlePropertySignal"/>
+ </property>
+ <property name="enabled" fullname="TestAction::enabled" href="testaction.html#enabled-prop" status="active" access="public" location="testaction.h" documented="true" brief="This property holds whether the action is enabled">
+ <getter name="isEnabled"/>
+ <setter name="setEnabled"/>
+ <notifier name="changed"/>
+ </property>
+ <property name="text" fullname="TestAction::text" href="testaction.html#text-prop" status="active" access="public" location="testaction.h" documented="true" brief="This property holds the action's display text">
+ <getter name="text"/>
+ <setter name="setText"/>
+ <notifier name="changed"/>
+ </property>
+ <property name="visible" fullname="TestAction::visible" href="testaction.html#visible-prop" status="active" access="public" location="testaction.h" documented="true" brief="This property holds whether the action is visible">
+ <getter name="isVisible"/>
+ <setter name="setVisible"/>
+ <notifier name="changed"/>
+ </property>
+ </class>
+ <module name="TestModule" href="testmodule-module.html" status="active" documented="true" seen="true" title="" brief="A test module"/>
+ </namespace>
+</INDEX>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/html/testaction-members.html b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/html/testaction-members.html
new file mode 100644
index 000000000..a544ffcd9
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/html/testaction-members.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+<!-- testaction.cpp -->
+ <meta name="description" content="A test class to demonstrate improved multi-property signal documentation.">
+ <title>List of All Members for TestAction | MultiSignalTest</title>
+</head>
+<body>
+<li>TestAction</li>
+<div class="sidebar"><div class="sidebar-content" id="sidebar-content"></div></div>
+<h1 class="title" translate="no">List of All Members for TestAction</h1>
+<p>This is the complete list of members for <a href="testaction.html">TestAction</a>, including inherited members.</p>
+<ul>
+<li class="fn" translate="no"><span class="name"><b><a href="testaction.html#TestAction" translate="no">TestAction</a></b></span>(QObject *)</li>
+<li class="fn" translate="no"><span class="name"><b><a href="testaction.html#changed" translate="no">changed</a></b></span>()</li>
+<li class="fn" translate="no"><span class="name"><b><a href="testaction.html#checkable-prop" translate="no">isCheckable</a></b></span>() const : bool</li>
+<li class="fn" translate="no"><span class="name"><b><a href="testaction.html#enabled-prop" translate="no">isEnabled</a></b></span>() const : bool</li>
+<li class="fn" translate="no"><span class="name"><b><a href="testaction.html#visible-prop" translate="no">isVisible</a></b></span>() const : bool</li>
+<li class="fn" translate="no"><span class="name"><b><a href="testaction.html#checkable-prop" translate="no">setCheckable</a></b></span>(bool)</li>
+<li class="fn" translate="no"><span class="name"><b><a href="testaction.html#enabled-prop" translate="no">setEnabled</a></b></span>(bool)</li>
+<li class="fn" translate="no"><span class="name"><b><a href="testaction.html#text-prop" translate="no">setText</a></b></span>(const QString &amp;)</li>
+<li class="fn" translate="no"><span class="name"><b><a href="testaction.html#visible-prop" translate="no">setVisible</a></b></span>(bool)</li>
+<li class="fn" translate="no"><span class="name"><b><a href="testaction.html#singlePropertySignal" translate="no">singlePropertySignal</a></b></span>()</li>
+<li class="fn" translate="no"><span class="name"><b><a href="testaction.html#text-prop" translate="no">text</a></b></span>() const : QString</li>
+</ul>
+</body>
+</html>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/html/testaction.html b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/html/testaction.html
new file mode 100644
index 000000000..be14c129d
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/html/testaction.html
@@ -0,0 +1,139 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+<!-- testaction.cpp -->
+ <meta name="description" content="A test class to demonstrate improved multi-property signal documentation.">
+ <title>TestAction Class | MultiSignalTest</title>
+</head>
+<body>
+<li>TestAction</li>
+<div class="sidebar">
+<div class="toc">
+<h3 id="toc">Contents</h3>
+<ul>
+<li class="level1"><a href="#properties">Properties</a></li>
+<li class="level1"><a href="#public-functions">Public Functions</a></li>
+<li class="level1"><a href="#signals">Signals</a></li>
+<li class="level1"><a href="#details">Detailed Description</a></li>
+</ul>
+</div>
+<div class="sidebar-content" id="sidebar-content"></div></div>
+<h1 class="title" translate="no">TestAction Class</h1>
+<!-- $$$TestAction-brief -->
+<p>A test class to demonstrate improved multi-property signal documentation. <a href="#details">More...</a></p>
+<!-- @@@TestAction -->
+<div class="table"><table class="alignedsummary requisites" translate="no">
+<tr><td class="memItemLeft rightAlign topAlign"> Header:</td><td class="memItemRight bottomAlign"> <code translate="no">#include &lt;TestAction&gt;</code></td></tr>
+</table></div>
+<ul>
+<li><a href="testaction-members.html">List of all members, including inherited members</a></li>
+</ul>
+<h2 id="properties">Properties</h2>
+<ul>
+<li class="fn" translate="no"><b><a href="testaction.html#checkable-prop" translate="no">checkable</a></b> : bool</li>
+<li class="fn" translate="no"><b><a href="testaction.html#enabled-prop" translate="no">enabled</a></b> : bool</li>
+<li class="fn" translate="no"><b><a href="testaction.html#text-prop" translate="no">text</a></b> : QString</li>
+<li class="fn" translate="no"><b><a href="testaction.html#visible-prop" translate="no">visible</a></b> : bool</li>
+</ul>
+<h2 id="public-functions">Public Functions</h2>
+<div class="table"><table class="alignedsummary" translate="no">
+<tr><td class="memItemLeft rightAlign topAlign"> </td><td class="memItemRight bottomAlign"><b><a href="testaction.html#TestAction" translate="no">TestAction</a></b>(QObject *<i>parent</i> = nullptr)</td></tr>
+<tr><td class="memItemLeft rightAlign topAlign"> bool </td><td class="memItemRight bottomAlign"><b><a href="testaction.html#checkable-prop" translate="no">isCheckable</a></b>() const</td></tr>
+<tr><td class="memItemLeft rightAlign topAlign"> bool </td><td class="memItemRight bottomAlign"><b><a href="testaction.html#enabled-prop" translate="no">isEnabled</a></b>() const</td></tr>
+<tr><td class="memItemLeft rightAlign topAlign"> bool </td><td class="memItemRight bottomAlign"><b><a href="testaction.html#visible-prop" translate="no">isVisible</a></b>() const</td></tr>
+<tr><td class="memItemLeft rightAlign topAlign"> void </td><td class="memItemRight bottomAlign"><b><a href="testaction.html#checkable-prop" translate="no">setCheckable</a></b>(bool <i>checkable</i>)</td></tr>
+<tr><td class="memItemLeft rightAlign topAlign"> void </td><td class="memItemRight bottomAlign"><b><a href="testaction.html#enabled-prop" translate="no">setEnabled</a></b>(bool <i>enabled</i>)</td></tr>
+<tr><td class="memItemLeft rightAlign topAlign"> void </td><td class="memItemRight bottomAlign"><b><a href="testaction.html#text-prop" translate="no">setText</a></b>(const QString &amp;<i>text</i>)</td></tr>
+<tr><td class="memItemLeft rightAlign topAlign"> void </td><td class="memItemRight bottomAlign"><b><a href="testaction.html#visible-prop" translate="no">setVisible</a></b>(bool <i>visible</i>)</td></tr>
+<tr><td class="memItemLeft rightAlign topAlign"> QString </td><td class="memItemRight bottomAlign"><b><a href="testaction.html#text-prop" translate="no">text</a></b>() const</td></tr>
+</table></div>
+<h2 id="signals">Signals</h2>
+<div class="table"><table class="alignedsummary" translate="no">
+<tr><td class="memItemLeft rightAlign topAlign"> void </td><td class="memItemRight bottomAlign"><b><a href="testaction.html#changed" translate="no">changed</a></b>()</td></tr>
+<tr><td class="memItemLeft rightAlign topAlign"> void </td><td class="memItemRight bottomAlign"><b><a href="testaction.html#singlePropertySignal" translate="no">singlePropertySignal</a></b>()</td></tr>
+</table></div>
+<!-- $$$TestAction-description -->
+<div class="descr">
+<h2 id="details">Detailed Description</h2>
+<p>This class has properties with different notification patterns.</p>
+</div>
+<!-- @@@TestAction -->
+<div class="prop">
+<h2>Property Documentation</h2>
+<!-- $$$checkable-prop$$$isCheckable$$$setCheckablebool$$$singlePropertySignal -->
+<h3 class="fn" translate="no" id="checkable-prop"><span class="name">checkable</span> : <span class="type">bool</span></h3>
+<p>This property holds whether the action is checkable</p>
+<p>This property determines if the action can be toggled.</p>
+<p><b>Access functions:</b></p>
+<div class="table"><table class="alignedsummary" translate="no">
+<tr><td class="memItemLeft topAlign rightAlign"> bool </td><td class="memItemRight bottomAlign"><span class="name"><b>isCheckable</b></span>() const</td></tr>
+<tr><td class="memItemLeft topAlign rightAlign"> void </td><td class="memItemRight bottomAlign"><span class="name"><b>setCheckable</b></span>(bool <i>checkable</i>)</td></tr>
+</table></div>
+<p><b>Notifier signal:</b></p>
+<div class="table"><table class="alignedsummary" translate="no">
+<tr><td class="memItemLeft topAlign rightAlign"> void </td><td class="memItemRight bottomAlign"><span class="name"><b><a href="testaction.html#singlePropertySignal" translate="no">singlePropertySignal</a></b></span>()</td></tr>
+</table></div>
+<!-- @@@checkable -->
+<!-- $$$enabled-prop$$$isEnabled$$$setEnabledbool$$$changed -->
+<h3 class="fn" translate="no" id="enabled-prop"><span class="name">enabled</span> : <span class="type">bool</span></h3>
+<p>This property holds whether the action is enabled</p>
+<p>This property determines if the action can be triggered.</p>
+<p><b>Access functions:</b></p>
+<div class="table"><table class="alignedsummary" translate="no">
+<tr><td class="memItemLeft topAlign rightAlign"> bool </td><td class="memItemRight bottomAlign"><span class="name"><b>isEnabled</b></span>() const</td></tr>
+<tr><td class="memItemLeft topAlign rightAlign"> void </td><td class="memItemRight bottomAlign"><span class="name"><b>setEnabled</b></span>(bool <i>enabled</i>)</td></tr>
+</table></div>
+<p><b>Notifier signal:</b></p>
+<div class="table"><table class="alignedsummary" translate="no">
+<tr><td class="memItemLeft topAlign rightAlign"> void </td><td class="memItemRight bottomAlign"><span class="name"><b><a href="testaction.html#changed" translate="no">changed</a></b></span>()</td></tr>
+</table></div>
+<!-- @@@enabled -->
+<!-- $$$text-prop$$$text$$$setTextconstQString&$$$changed -->
+<h3 class="fn" translate="no" id="text-prop"><span class="name">text</span> : <span class="type">QString</span></h3>
+<p>This property holds the action's display text</p>
+<p>This property holds the text that is displayed for the action.</p>
+<p><b>Access functions:</b></p>
+<div class="table"><table class="alignedsummary" translate="no">
+<tr><td class="memItemLeft topAlign rightAlign"> QString </td><td class="memItemRight bottomAlign"><span class="name"><b>text</b></span>() const</td></tr>
+<tr><td class="memItemLeft topAlign rightAlign"> void </td><td class="memItemRight bottomAlign"><span class="name"><b>setText</b></span>(const QString &amp;<i>text</i>)</td></tr>
+</table></div>
+<p><b>Notifier signal:</b></p>
+<div class="table"><table class="alignedsummary" translate="no">
+<tr><td class="memItemLeft topAlign rightAlign"> void </td><td class="memItemRight bottomAlign"><span class="name"><b><a href="testaction.html#changed" translate="no">changed</a></b></span>()</td></tr>
+</table></div>
+<!-- @@@text -->
+<!-- $$$visible-prop$$$isVisible$$$setVisiblebool$$$changed -->
+<h3 class="fn" translate="no" id="visible-prop"><span class="name">visible</span> : <span class="type">bool</span></h3>
+<p>This property holds whether the action is visible</p>
+<p>This property determines if the action is shown in UI.</p>
+<p><b>Access functions:</b></p>
+<div class="table"><table class="alignedsummary" translate="no">
+<tr><td class="memItemLeft topAlign rightAlign"> bool </td><td class="memItemRight bottomAlign"><span class="name"><b>isVisible</b></span>() const</td></tr>
+<tr><td class="memItemLeft topAlign rightAlign"> void </td><td class="memItemRight bottomAlign"><span class="name"><b>setVisible</b></span>(bool <i>visible</i>)</td></tr>
+</table></div>
+<p><b>Notifier signal:</b></p>
+<div class="table"><table class="alignedsummary" translate="no">
+<tr><td class="memItemLeft topAlign rightAlign"> void </td><td class="memItemRight bottomAlign"><span class="name"><b><a href="testaction.html#changed" translate="no">changed</a></b></span>()</td></tr>
+</table></div>
+<!-- @@@visible -->
+</div>
+<div class="func">
+<h2>Member Function Documentation</h2>
+<!-- $$$TestAction[overload1]$$$TestActionQObject* -->
+<h3 class="fn" translate="no" id="TestAction"><code class="details extra" translate="no">[explicit]</code> TestAction::<span class="name">TestAction</span>(<span class="type">QObject</span> *<i>parent</i> = nullptr)</h3>
+<p>Constructs a TestAction with the given <i translate="no">parent</i>.</p>
+<!-- @@@TestAction -->
+<!-- $$$changed -->
+<h3 class="fn" translate="no" id="changed"><code class="details extra" translate="no">[signal]</code> <span class="type">void</span> TestAction::<span class="name">changed</span>()</h3>
+<p>This signal is emitted when certain properties of the action change. The properties that trigger this signal are enabled, visible, and text.</p>
+<div class="admonition note"><p><b>Note: </b>Notifier signal for properties <a href="testaction.html#enabled-prop" translate="no">enabled</a>, <a href="testaction.html#text-prop" translate="no">text</a>, and <a href="testaction.html#visible-prop" translate="no">visible</a>. </p>
+</div><!-- @@@changed -->
+<!-- $$$singlePropertySignal -->
+<h3 class="fn" translate="no" id="singlePropertySignal"><code class="details extra" translate="no">[signal]</code> <span class="type">void</span> TestAction::<span class="name">singlePropertySignal</span>()</h3>
+<p>This signal is emitted when the checkable property changes.</p>
+<div class="admonition note"><p><b>Note: </b>Notifier signal for property <a href="testaction.html#checkable-prop" translate="no">checkable</a>. </p>
+</div><!-- @@@singlePropertySignal -->
+</div>
+</body>
+</html>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/html/testmodule-module.html b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/html/testmodule-module.html
new file mode 100644
index 000000000..9c1f5697b
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/html/testmodule-module.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+<!-- testaction.cpp -->
+ <meta name="description" content="A test module.">
+ <title></title>
+</head>
+<body>
+<div class="sidebar">
+<div class="toc">
+<h3 id="toc">Contents</h3>
+<ul>
+<li class="level1"><a href="#namespaces">Namespaces</a></li>
+<li class="level1"><a href="#classes">Classes</a></li>
+<li class="level1"><a href="#details">Detailed Description</a></li>
+</ul>
+</div>
+<div class="sidebar-content" id="sidebar-content"></div></div>
+<!-- $$$TestModule-brief -->
+<p>A test module. <a href="#details">More...</a></p>
+<!-- @@@TestModule -->
+<h2 id="classes">Classes</h2>
+<div class="table"><table class="annotated">
+<tr class="odd topAlign"><td class="tblName" translate="no"><p><a href="testaction.html">TestAction</a></p></td><td class="tblDescr"><p>A test class to demonstrate improved multi-property signal documentation</p></td></tr>
+</table></div>
+<!-- $$$TestModule-description -->
+<div class="descr">
+<h2 id="details">Detailed Description</h2>
+</div>
+<!-- @@@TestModule -->
+</body>
+</html>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/webxml/multisignaltest.index b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/webxml/multisignaltest.index
new file mode 100644
index 000000000..bca127b07
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/webxml/multisignaltest.index
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE QDOCINDEX>
+<INDEX url="" title="Test for improved multi-property signal documentation" version="" project="MultiSignalTest">
+ <namespace name="" status="active" access="public" module="multisignaltest">
+ <class name="TestAction" href="testaction.html" status="active" access="public" location="testaction.h" documented="true" bases="QObject" module="TestModule" brief="A test class to demonstrate improved multi-property signal documentation">
+ <function name="TestAction" fullname="TestAction::TestAction" href="testaction.html#TestAction" status="active" access="public" location="testaction.h" documented="true" meta="constructor" explicit="true" signature="TestAction(QObject *parent)">
+ <parameter type="QObject *" name="parent" default="nullptr"/>
+ </function>
+ <function name="changed" fullname="TestAction::changed" href="testaction.html#changed" status="active" access="public" location="testaction.h" documented="true" meta="signal" associated-property="enabled,text,visible" type="void" signature="void changed()"/>
+ <function name="isCheckable" fullname="TestAction::isCheckable" href="testaction.html#checkable-prop" status="active" access="public" location="testaction.h" meta="plain" const="true" associated-property="checkable" type="bool" signature="bool isCheckable() const"/>
+ <function name="isEnabled" fullname="TestAction::isEnabled" href="testaction.html#enabled-prop" status="active" access="public" location="testaction.h" meta="plain" const="true" associated-property="enabled" type="bool" signature="bool isEnabled() const"/>
+ <function name="isVisible" fullname="TestAction::isVisible" href="testaction.html#visible-prop" status="active" access="public" location="testaction.h" meta="plain" const="true" associated-property="visible" type="bool" signature="bool isVisible() const"/>
+ <function name="setCheckable" fullname="TestAction::setCheckable" href="testaction.html#checkable-prop" status="active" access="public" location="testaction.h" meta="plain" associated-property="checkable" type="void" signature="void setCheckable(bool checkable)">
+ <parameter type="bool" name="checkable" default=""/>
+ </function>
+ <function name="setEnabled" fullname="TestAction::setEnabled" href="testaction.html#enabled-prop" status="active" access="public" location="testaction.h" meta="plain" associated-property="enabled" type="void" signature="void setEnabled(bool enabled)">
+ <parameter type="bool" name="enabled" default=""/>
+ </function>
+ <function name="setText" fullname="TestAction::setText" href="testaction.html#text-prop" status="active" access="public" location="testaction.h" meta="plain" associated-property="text" type="void" signature="void setText(const QString &amp;text)">
+ <parameter type="const QString &amp;" name="text" default=""/>
+ </function>
+ <function name="setVisible" fullname="TestAction::setVisible" href="testaction.html#visible-prop" status="active" access="public" location="testaction.h" meta="plain" associated-property="visible" type="void" signature="void setVisible(bool visible)">
+ <parameter type="bool" name="visible" default=""/>
+ </function>
+ <function name="singlePropertySignal" fullname="TestAction::singlePropertySignal" href="testaction.html#singlePropertySignal" status="active" access="public" location="testaction.h" documented="true" meta="signal" associated-property="checkable" type="void" signature="void singlePropertySignal()"/>
+ <function name="text" fullname="TestAction::text" href="testaction.html#text-prop" status="active" access="public" location="testaction.h" meta="plain" const="true" associated-property="text" type="QString" signature="QString text() const"/>
+ <property name="checkable" fullname="TestAction::checkable" href="testaction.html#checkable-prop" status="active" access="public" location="testaction.h" documented="true" brief="Whether the action is checkable">
+ <getter name="isCheckable"/>
+ <setter name="setCheckable"/>
+ <notifier name="singlePropertySignal"/>
+ </property>
+ <property name="enabled" fullname="TestAction::enabled" href="testaction.html#enabled-prop" status="active" access="public" location="testaction.h" documented="true" brief="Whether the action is enabled">
+ <getter name="isEnabled"/>
+ <setter name="setEnabled"/>
+ <notifier name="changed"/>
+ </property>
+ <property name="text" fullname="TestAction::text" href="testaction.html#text-prop" status="active" access="public" location="testaction.h" documented="true" brief="The action's display text">
+ <getter name="text"/>
+ <setter name="setText"/>
+ <notifier name="changed"/>
+ </property>
+ <property name="visible" fullname="TestAction::visible" href="testaction.html#visible-prop" status="active" access="public" location="testaction.h" documented="true" brief="Whether the action is visible">
+ <getter name="isVisible"/>
+ <setter name="setVisible"/>
+ <notifier name="changed"/>
+ </property>
+ </class>
+ <module name="TestModule" href="testmodule-module.html" status="active" documented="true" seen="true" title="" brief="A test module"/>
+ </namespace>
+</INDEX>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/webxml/testaction.webxml b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/webxml/testaction.webxml
new file mode 100644
index 000000000..9aa5ac721
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/webxml/testaction.webxml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<WebXML>
+ <document>
+ <class name="TestAction" href="testaction.html" status="active" access="public" location="testaction.h" documented="true" bases="QObject" module="TestModule" brief="A test class to demonstrate improved multi-property signal documentation">
+ <description>
+ <brief>A test class to demonstrate improved multi-property signal documentation.</brief>
+ <para>This class has properties with different notification patterns.</para>
+ </description>
+ <function name="TestAction" fullname="TestAction::TestAction" href="testaction.html#TestAction" status="active" access="public" location="testaction.h" documented="true" meta="constructor" explicit="true" signature="TestAction(QObject *parent)">
+ <parameter type="QObject *" name="parent" default="nullptr"/>
+ <description>
+ <para>Constructs a <link raw="TestAction" href="testaction.html" type="class">TestAction</link> with the given <argument>parent</argument>.</para>
+ </description>
+ </function>
+ <function name="changed" fullname="TestAction::changed" href="testaction.html#changed" status="active" access="public" location="testaction.h" documented="true" meta="signal" associated-property="enabled,text,visible" type="void" signature="void changed()">
+ <description>
+ <para>This signal is emitted when certain properties of the action change. The properties that trigger this signal are enabled, visible, and text.</para>
+ </description>
+ </function>
+ <function name="isCheckable" fullname="TestAction::isCheckable" href="testaction.html#checkable-prop" status="active" access="public" location="testaction.h" meta="plain" const="true" associated-property="checkable" type="bool" signature="bool isCheckable() const">
+ <description/>
+ </function>
+ <function name="isEnabled" fullname="TestAction::isEnabled" href="testaction.html#enabled-prop" status="active" access="public" location="testaction.h" meta="plain" const="true" associated-property="enabled" type="bool" signature="bool isEnabled() const">
+ <description/>
+ </function>
+ <function name="isVisible" fullname="TestAction::isVisible" href="testaction.html#visible-prop" status="active" access="public" location="testaction.h" meta="plain" const="true" associated-property="visible" type="bool" signature="bool isVisible() const">
+ <description/>
+ </function>
+ <function name="setCheckable" fullname="TestAction::setCheckable" href="testaction.html#checkable-prop" status="active" access="public" location="testaction.h" meta="plain" associated-property="checkable" type="void" signature="void setCheckable(bool checkable)">
+ <parameter type="bool" name="checkable" default=""/>
+ <description>
+ <see-also>isCheckable()</see-also>
+ </description>
+ </function>
+ <function name="setEnabled" fullname="TestAction::setEnabled" href="testaction.html#enabled-prop" status="active" access="public" location="testaction.h" meta="plain" associated-property="enabled" type="void" signature="void setEnabled(bool enabled)">
+ <parameter type="bool" name="enabled" default=""/>
+ <description>
+ <see-also>isEnabled()</see-also>
+ </description>
+ </function>
+ <function name="setText" fullname="TestAction::setText" href="testaction.html#text-prop" status="active" access="public" location="testaction.h" meta="plain" associated-property="text" type="void" signature="void setText(const QString &amp;text)">
+ <parameter type="const QString &amp;" name="text" default=""/>
+ <description>
+ <see-also>text()</see-also>
+ </description>
+ </function>
+ <function name="setVisible" fullname="TestAction::setVisible" href="testaction.html#visible-prop" status="active" access="public" location="testaction.h" meta="plain" associated-property="visible" type="void" signature="void setVisible(bool visible)">
+ <parameter type="bool" name="visible" default=""/>
+ <description>
+ <see-also>isVisible()</see-also>
+ </description>
+ </function>
+ <function name="singlePropertySignal" fullname="TestAction::singlePropertySignal" href="testaction.html#singlePropertySignal" status="active" access="public" location="testaction.h" documented="true" meta="signal" associated-property="checkable" type="void" signature="void singlePropertySignal()">
+ <description>
+ <para>This signal is emitted when the checkable property changes.</para>
+ </description>
+ </function>
+ <function name="text" fullname="TestAction::text" href="testaction.html#text-prop" status="active" access="public" location="testaction.h" meta="plain" const="true" associated-property="text" type="QString" signature="QString text() const">
+ <description>
+ <see-also>setText()</see-also>
+ </description>
+ </function>
+ <property name="checkable" fullname="TestAction::checkable" href="testaction.html#checkable-prop" status="active" access="public" location="testaction.h" documented="true" brief="Whether the action is checkable">
+ <getter name="isCheckable"/>
+ <setter name="setCheckable"/>
+ <notifier name="singlePropertySignal"/>
+ <description>
+ <brief>This property holds whether the action is checkable.</brief>
+ <para>This property determines if the action can be toggled.</para>
+ </description>
+ </property>
+ <property name="enabled" fullname="TestAction::enabled" href="testaction.html#enabled-prop" status="active" access="public" location="testaction.h" documented="true" brief="Whether the action is enabled">
+ <getter name="isEnabled"/>
+ <setter name="setEnabled"/>
+ <notifier name="changed"/>
+ <description>
+ <brief>This property holds whether the action is enabled.</brief>
+ <para>This property determines if the action can be triggered.</para>
+ </description>
+ </property>
+ <property name="text" fullname="TestAction::text" href="testaction.html#text-prop" status="active" access="public" location="testaction.h" documented="true" brief="The action's display text">
+ <getter name="text"/>
+ <setter name="setText"/>
+ <notifier name="changed"/>
+ <description>
+ <brief>This property holds the action's display text.</brief>
+ <para>This property holds the text that is displayed for the action.</para>
+ </description>
+ </property>
+ <property name="visible" fullname="TestAction::visible" href="testaction.html#visible-prop" status="active" access="public" location="testaction.h" documented="true" brief="Whether the action is visible">
+ <getter name="isVisible"/>
+ <setter name="setVisible"/>
+ <notifier name="changed"/>
+ <description>
+ <brief>This property holds whether the action is visible.</brief>
+ <para>This property determines if the action is shown in UI.</para>
+ </description>
+ </property>
+ </class>
+ </document>
+</WebXML>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/webxml/testmodule-module.webxml b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/webxml/testmodule-module.webxml
new file mode 100644
index 000000000..5d24b3077
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/expected/webxml/testmodule-module.webxml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<WebXML>
+ <document/>
+</WebXML>
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/multisignal.qdocconf b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/multisignal.qdocconf
new file mode 100644
index 000000000..3d0d3713c
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/multisignal.qdocconf
@@ -0,0 +1,30 @@
+project = MultiSignalTest
+description = Test for improved multi-property signal documentation
+
+headerdirs = src
+sourcedirs = src
+
+outputformats = WebXML HTML DocBook
+WebXML.quotinginformation = true
+WebXML.nosubdirs = true
+WebXML.outputsubdir = webxml
+
+HTML.nosubdirs = true
+HTML.outputsubdir = html
+
+DocBook.nosubdirs = true
+DocBook.outputsubdir = docbook
+
+sources.fileextensions = "*.qml *.cpp *.qdoc"
+headers.fileextensions = "*.h"
+
+# images
+imagedirs = ./src/images
+
+# zero warning policy
+warninglimit = 0
+warninglimit.enabled = true
+
+# don't write host system-specific paths to index files
+locationinfo = false
+
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/src/testaction.cpp b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/src/testaction.cpp
new file mode 100644
index 000000000..2fd6adad2
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/src/testaction.cpp
@@ -0,0 +1,117 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testaction.h"
+
+/*!
+ \module TestModule
+ \brief A test module.
+*/
+
+/*!
+ \class TestAction
+ \inmodule TestModule
+ \brief A test class to demonstrate improved multi-property signal documentation.
+
+ This class has properties with different notification patterns.
+*/
+
+/*!
+ \fn TestAction::TestAction(QObject *parent)
+
+ Constructs a TestAction with the given \a parent.
+*/
+TestAction::TestAction(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ \property TestAction::enabled
+ \brief whether the action is enabled
+
+ This property determines if the action can be triggered.
+*/
+bool TestAction::isEnabled() const
+{
+ return m_enabled;
+}
+
+void TestAction::setEnabled(bool enabled)
+{
+ if (m_enabled != enabled) {
+ m_enabled = enabled;
+ emit changed();
+ }
+}
+
+/*!
+ \property TestAction::visible
+ \brief whether the action is visible
+
+ This property determines if the action is shown in UI.
+*/
+bool TestAction::isVisible() const
+{
+ return m_visible;
+}
+
+void TestAction::setVisible(bool visible)
+{
+ if (m_visible != visible) {
+ m_visible = visible;
+ emit changed();
+ }
+}
+
+/*!
+ \property TestAction::text
+ \brief the action's display text
+
+ This property holds the text that is displayed for the action.
+*/
+QString TestAction::text() const
+{
+ return m_text;
+}
+
+void TestAction::setText(const QString &text)
+{
+ if (m_text != text) {
+ m_text = text;
+ emit changed();
+ }
+}
+
+/*!
+ \property TestAction::checkable
+ \brief whether the action is checkable
+
+ This property determines if the action can be toggled.
+*/
+bool TestAction::isCheckable() const
+{
+ return m_checkable;
+}
+
+void TestAction::setCheckable(bool checkable)
+{
+ if (m_checkable != checkable) {
+ m_checkable = checkable;
+ emit singlePropertySignal();
+ }
+}
+
+/*!
+ \fn void TestAction::changed()
+
+ This signal is emitted when certain properties of the action change.
+ The properties that trigger this signal are enabled, visible, and text.
+*/
+
+/*!
+ \fn void TestAction::singlePropertySignal()
+
+ This signal is emitted when the checkable property changes.
+*/
+
diff --git a/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/src/testaction.h b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/src/testaction.h
new file mode 100644
index 000000000..568f8a362
--- /dev/null
+++ b/src/qdoc/qdoc/tests/validateqdocoutputfiles/testdata/multisignal/src/testaction.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTACTION_H
+#define TESTACTION_H
+
+#include <QtCore/QObject>
+
+class TestAction : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY changed)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY changed)
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY changed)
+ Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY singlePropertySignal)
+
+public:
+ explicit TestAction(QObject *parent = nullptr);
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+
+ bool isVisible() const;
+ void setVisible(bool visible);
+
+ QString text() const;
+ void setText(const QString &text);
+
+ bool isCheckable() const;
+ void setCheckable(bool checkable);
+
+signals:
+ void changed(); // This signal notifies for multiple properties (enabled, visible, text)
+ void singlePropertySignal(); // This signal notifies for a single property (checkable)
+
+private:
+ bool m_enabled = true;
+ bool m_visible = true;
+ QString m_text;
+ bool m_checkable = false;
+};
+
+#endif // TESTACTION_H
+