Revision control

++ {#-
++ Copyright (C) 2025 The Qt Company Ltd.
++ SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
++ -#}
++ <!DOCTYPE html>
++ <html lang="en">
++ <head>
++ <meta charset="UTF-8">
++ <meta name="viewport" content="width=device-width, initial-scale=1.0">
++ <title>{{ escape_html(title) }}</title>
++ {%- if stylesheetEnabled %}
++ <link rel="stylesheet" href="{{ escape_html(stylesheetName) }}">
++ {%- endif %}
++ </head>
++ <body>
++ <header class="header-bar">
++ <div class="qt-logo">
++ <img src="qt-logo-documentation.png" alt="Qt Documentation" height="28">
++ </div>
++ <nav class="breadcrumbs" aria-label="Breadcrumbs">
++ {% if exists("breadcrumbs") %}{% for crumb in breadcrumbs %}{% if existsIn(crumb, "current") %}<span class="crumb current">{{ escape_html(crumb.title) }}</span>{% else %}<span class="crumb">{{ escape_html(crumb.title) }}</span>{% if not loop.is_last %}<span class="separator">&gt;</span>{% endif %}{% endif %}{% endfor %}{% else %}<span class="crumb current">{{ escape_html(title) }}</span>{% endif %}
++ </nav>
++ </header>
++
++ <main class="content">
++ <h1>{{ escape_html(fullTitle) }}</h1>
++ {% if default(brief, "") != "" %}
++ <p class="brief">{{ escape_html(brief) }}</p>
++ {% endif %}
++
++ {% set ai_prompt = "I'm reading the Qt documentation for the '" + title + "' module" %}
++ {% if brief %}{% set ai_prompt = ai_prompt + ". Summary: " + brief %}{% endif %}
++ {% set ai_prompt = ai_prompt + ". Explain the key classes and typical usage patterns." %}
++ <div class="toolbar">
++ <button class="toolbar-btn" id="copy-btn" onclick="copyPage()" title="Copy page content">
++ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="5.5" y="5.5" width="8" height="9" rx="1"/><path d="M3 10.5V3a1 1 0 011-1h6.5"/></svg> Copy
++ </button>
++ <a href="#" id="md-link" class="toolbar-btn" title="View as Markdown">
++ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="1" y="3" width="14" height="10" rx="1.5"/><path d="M4 10V6l2 2.5L8 6v4"/><path d="M11 8.5l1.5 1.5L14 8.5"/></svg> Markdown
++ </a>
++ <details class="ask-ai">
++ <summary class="toolbar-btn">
++ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8 1v2M8 13v2M1 8h2M13 8h2M3.5 3.5l1.4 1.4M11.1 11.1l1.4 1.4M12.5 3.5l-1.4 1.4M4.9 11.1l-1.4 1.4"/><circle cx="8" cy="8" r="2.5"/></svg> Ask AI
++ </summary>
++ <nav class="dropdown-content" id="ai-menu" data-prompt="{{ escape_html(ai_prompt) }}">
++ <a class="ai-link" data-provider="claude"><span class="ai-badge ai-claude">C</span> Explain with Claude</a>
++ <a class="ai-link" data-provider="chatgpt"><span class="ai-badge ai-chatgpt">G</span> Explain with ChatGPT</a>
++ <a class="ai-link" data-provider="grok"><span class="ai-badge ai-grok">X</span> Explain with Grok</a>
++ </nav>
++ </details>
++ </div>
++
++ {% if hasCollection %}
++ {% if existsIn(collection, "state") %}
++ <p><b>Status:</b> {{ escape_html(collection.state) }}</p>
++ {% endif %}
++
++ {% if collection.isModule %}
++ <table class="requisites">
++ {% if collection.cmakePackage %}
++ <tr><td class="memItemLeft">CMake:</td>
++ <td class="memItemRight"><code>find_package({{ escape_html(collection.cmakePackage) }} REQUIRED COMPONENTS {{ escape_html(collection.cmakeComponent) }})</code><br/><code>target_link_libraries(mytarget PRIVATE {{ escape_html(collection.cmakeTargetItem) }})</code></td></tr>
++ {% endif %}
++ {% if collection.qtVariable %}
++ <tr><td class="memItemLeft">qmake:</td>
++ <td class="memItemRight"><code>QT += {{ escape_html(collection.qtVariable) }}</code></td></tr>
++ {% endif %}
++ </table>
++ {% endif %}
++ {% endif %}
++
++ {% include "partials/html/content_blocks.html" %}
++
++ {% if hasCollection %}{% if not collection.noAutoList %}
++ {% if collection.isModule %}
++ {% if length(collection.namespaces) > 0 %}
++ <h2>Namespaces</h2>
++ <table class="annotated">
++ {% for entry in collection.namespaces %}
++ <tr><td class="tblName">{% if entry.href != "" %}<a href="{{ entry.href }}">{{ escape_html(entry.name) }}</a>{% else %}{{ escape_html(entry.name) }}{% endif %}</td><td class="tblDescr">{{ escape_html(entry.brief) }}</td></tr>
++ {% endfor %}
++ </table>
++ {% endif %}
++ {% if length(collection.classes) > 0 %}
++ <h2>Classes</h2>
++ <table class="annotated">
++ {% for entry in collection.classes %}
++ <tr><td class="tblName">{% if entry.href != "" %}<a href="{{ entry.href }}">{{ escape_html(entry.name) }}</a>{% else %}{{ escape_html(entry.name) }}{% endif %}</td><td class="tblDescr">{{ escape_html(entry.brief) }}</td></tr>
++ {% endfor %}
++ </table>
++ {% endif %}
++ {% else %}
++ {% if length(collection.members) > 0 %}
++ <table class="annotated">
++ {% for entry in collection.members %}
++ <tr><td class="tblName">{% if entry.href != "" %}<a href="{{ entry.href }}">{{ escape_html(entry.name) }}</a>{% else %}{{ escape_html(entry.name) }}{% endif %}</td><td class="tblDescr">{{ escape_html(entry.brief) }}</td></tr>
++ {% endfor %}
++ </table>
++ {% endif %}
++ {% endif %}
++ {% endif %}{% endif %}
++ </main>
++
++ <footer class="content footer">
++ <p>Generated by QDoc.</p>
++ </footer>
++
++ <script>
++ function copyPage() {
++ var btn = document.getElementById('copy-btn');
++ var text = document.querySelector('main.content').innerText;
++ navigator.clipboard.writeText(text).then(function() {
++ btn.textContent = 'Copied!';
++ setTimeout(function() { btn.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="5.5" y="5.5" width="8" height="9" rx="1"/><path d="M3 10.5V3a1 1 0 011-1h6.5"/></svg> Copy'; }, 1500);
++ });
++ }
++ document.addEventListener('DOMContentLoaded', function() {
++ var menu = document.getElementById('ai-menu');
++ if (menu) {
++ var prompt = encodeURIComponent(menu.getAttribute('data-prompt'));
++ var urls = { claude: 'https://claude.ai/new?q=', chatgpt: 'https://chatgpt.com/?q=', grok: 'https://grok.com/?q=' };
++ var links = menu.querySelectorAll('.ai-link');
++ for (var i = 0; i < links.length; i++) {
++ var provider = links[i].getAttribute('data-provider');
++ if (urls[provider]) links[i].href = urls[provider] + prompt;
++ links[i].target = '_blank';
++ links[i].rel = 'noopener';
++ }
++ }
++ var mdLink = document.getElementById('md-link');
++ if (mdLink) {
++ var path = window.location.pathname;
++ var name = path.substring(path.lastIndexOf('/') + 1).replace('.html', '.md');
++ mdLink.href = '../markdown/' + name;
++ }
++ document.querySelectorAll('pre').forEach(function(pre) {
++ var btn = document.createElement('button');
++ btn.className = 'code-copy-btn';
++ btn.textContent = 'Copy';
++ btn.addEventListener('click', function() {
++ navigator.clipboard.writeText(pre.textContent).then(function() {
++ btn.textContent = 'Copied!';
++ setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
++ });
++ });
++ pre.style.position = 'relative';
++ pre.appendChild(btn);
++ });
++ });
++ </script>
++ </body>
++ </html>