/*!
    \title DtkDeclarative Reference Documentation
    \page index.html

    \brief DtkDeclarative 提供一个用于快速开发出符合 DTK/行云设计 应用程序的开发库。

    dtkdeclarative 是基于 QtQuick 及 QtQml 实现的开发控件库，它是用于代替已有的 dtkwidget
    所开发的全新的 DTK 模块，其代码以 qtdeclarative 为基础进行开发，实现了对QML已有控件的覆盖
    （包含Qt Quick Controls 2中的所有控件），增加了大量在 DTK 环境下友好显示的视觉特效和颜
    色风格。该模块通过Qt插件的形式新增了名为“Chameleon”的样式插件，安装在
    /usr/lib/x86_64-linux-gnu/qt5/qml/QtQuick/Controls.2/Chameleon 目录
    (由qml-module-qtquick-controls2-styles-chameleon包提供)。
    此外，与dtkwidget类似，dtkdeclarative也提供了一些QtQuick中所没有的功能，此类功能都以
    QML 接口的形式提供，包含在 org.deepin.dtk 1.0 中，安装在 /usr/lib/x86_64-linux-gnu/qt5/qml/org/deepin/dtk/
    目录（由libdtkdeclarative5包提供）。使用 dtkdeclarative 在 DTK 环境下编程具备一下特点：

    \list
    \li 原始的 Qt 和 Qml 代码风格
    \li 适配传统 Qml 的所有 API
    \li 简单快速的界面开发接口
    \li 统一的控件主题风格
    \li 丰富的特效和色彩
    \endlist

    \image images/introduction.png

    \section1 与 dtkwidget 的区别
    dtkwidget 基于 QtWidgets 模块开发，其与 dtkdeclarative 的区别主要体现在 QtWidgets 和 QtQuick/QtQml 的差异。

    QtWidgets 使用 C++ 语言开发，其控件都继承于 QWidget 并进行拓展，通过 QPainter 在风格插件中进行样式的统一绘制。
    由于 C++ 语言的特殊性，其信号基于回调函数的方式实现，其事件处理基于多态的特性实现。因此在代码复杂度和冗余度上都有明显的劣势。

    QtQuick/QtQml 基于 Qml 语言开发，其特点是通过树状模型来指定父子类别，通过属性绑定来响应变化。除此之外，它能兼容 JavaScript
    和 C++ 语言的特性，保证开发过程的高效和快速，减少 QtWidget 编程中信号槽链接的繁琐程度。

    在使用 dtkdeclarative 之前，应当先熟悉 QtQuick 的开发模式，其最大的特点是使用“声明式语言（QML）”来描述UI的状态，而不用关心
    UI 具体的渲染过程。下面是一些小例子：
    \section2 渲染方式上的区别
    \table
        \header
            \li 方式
            \li 描述
            \li 实现
            \li 效果
        \row
            \li dtkwidget
            \li 渲染一个 100x100 大小的红色矩形
            \li \snippet snippets/dtkdeclarative_example.cpp 0
            \li {1, 2} \image images/renderRedRect.png
        \row
            \li dtkdeclarative
            \li 显示一个 100x100 大小的红色矩形
            \li \snippet snippets/dtkdeclarative_qmlexample.qml 0
    \endtable

    \section2 布局方式上的区别
    \table
        \header
            \li 方式
            \li 描述
            \li 实现
            \li 效果
        \row
            \li dtkwidget
            \li 通过布局控件实现
            \li \snippet snippets/dtkdeclarative_example.cpp 1
            \li \image images/layutFromDtkwidget.png
        \row
            \li {1, 2} dtkdeclarative
            \li 通过锚布局实现
            \li \snippet snippets/dtkdeclarative_qmlexample.qml 1
            \li \image images/layoutUseAnchors.png
        \row
            \li 使用布局器实现
            \li \snippet snippets/dtkdeclarative_qmlexample.qml 2
            \li \image images/layoutUseCustomLayout.png
    \endtable

    \section2 信号槽连接上的区别
    \table
        \header
            \li 方式
            \li 描述
            \li 实现
        \row
            \li dtkwidget
            \li 使用 QObject::connection 方式连接
            \li \snippet snippets/dtkdeclarative_example.cpp 2
        \row
            \li dtkdeclarative
            \li 使用on<Signal>的方式连接
            \li \snippet snippets/dtkdeclarative_qmlexample.qml 3
    \endtable

    \section1 QML 模块分类
        dtkdeclarative 项目内部将不同模块进行划分，以便不同开发者在不同的场景进行使用。
    dtkdeclarative 提供了分为内部和外部使用的不同模块，具体划分如下表所示：

    \table
        \header
            \li 名称
            \li 版本
            \li 介绍
            \li 使用对象

        \row
            \li \l {org.deepin.dtk 模块}{org.deepin.dtk}
            \li 1.0
            \li dtk 统一对外模块，包含所有子模块内容
            \li 外部
        \row
            \li org.deepin.dtk.impl
            \li 1.0
            \li 基础的c++实现
            \li 内部
        \row
            \li org.deepin.dtk.controls
            \li 1.0
            \li 自定义控件、重写 Qt 基础控件
            \li 内部
        \row
            \li org.deepin.dtk.style
            \li 1.0
            \li 控件风格，默认为行云设计风格
            \li 内部
        \row
            \li \l {org.deepin.dtk.settings 模块}{org.deepin.dtk.settings}
            \li 1.0
            \li SettingsDialog 控件相关接口
            \li 外部
    \endtable
    \warning \l {org.deepin.dtk 模块}{org.deepin.dtk} 作为dtk对外提供的统一模块，能够访问大部分模块中的子项，
    但无法访问 org.deepin.dtk.settings 模块下的子项。如需访问请手动导入该项。

    \section1 QML 类型集合
    \generatelist {qmltypesbymodule org.deepin.dtk}

    \section1 Setting 相关类型集合
    \generatelist {qmltypesbymodule org.deepin.dtk.settings}
    \noautolist
 */

/*!
    \qmlmodule org.deepin.dtk 1.0
    \title org.deepin.dtk 模块
    \brief org.deepin.dtk 提供了 dtkdeclarative 项目的主模块.

    \l {org.deepin.dtk 模块}{org.deepin.dtk} 作为 dtkdeclarative 项目的主模块，包含了例如 QML 模块、 C++ 模块、风格模块等等几种不同的子模块。
    作为主模块，当使用任意子模块的控件时，都能正确访问和使用。除此之外，\l {org.deepin.dtk 模块}{org.deepin.dtk} 模块也将 Qt 中一些常用的 QtQuick
    模块导入进来。因此通常情况下， \l {org.deepin.dtk 模块}{org.deepin.dtk} 模块能够满足应用的大部分控件需求，而不需要导入其他模块。

    \l {org.deepin.dtk 模块}{org.deepin.dtk} 模块包含了下表所示的子模块：
    \table
        \header
            \li 名称
            \li 版本
            \li 介绍
            \li 使用对象

        \row
            \li \l {org.deepin.dtk 模块}{org.deepin.dtk}
            \li 1.0
            \li dtk 统一对外模块，包含所有子模块内容
            \li 外部
        \row
            \li org.deepin.dtk.impl
            \li 1.0
            \li 基础的c++实现
            \li 内部
        \row
            \li org.deepin.dtk.controls
            \li 1.0
            \li 自定义控件、重写 Qt 基础控件
            \li 内部
        \row
            \li org.deepin.dtk.style
            \li 1.0
            \li 控件风格，默认为行云设计风格
            \li 内部
        \row
            \li org.deepin.dtk.settings
            \li 1.0
            \li SettingsDialog 控件相关接口
            \li 外部
    \endtable

    \section1 QML 类型集合
    \generatelist {qmltypesbymodule org.deepin.dtk}
    \noautolist

    \section1 重写或实现的 QML 类型
    \annotatedlist QML_TYPES
 */

/*!
    \qmlmodule org.deepin.dtk.settings 1.0
    \title org.deepin.dtk.settings 模块
    \brief org.deepin.dtk.settings 提供了 dtkdeclarative 项目设置相关模块.

    dtkdeclarative适配了配置策略中所有的内容，为了更方便的对接配置策略，将配置策略和qml语法相结合，
    dtkdeclarative设计实现了一套全新的Settings框架。

    \section1 Config 配置

    关于配置策略相关指南，请参见配置策略使用说明，dtkdeclarative封装了C++中的配置策略属性实例，通过“Config”项指定，例如以下代码：
    \qml
    Config {
        name: "example"  // 必须指定
        property int key1 : 1
        property string key2 : "key2 default"
    }
    \endqml

    subpath属性用于指定文件查找路径，默认情况可以不指定，将直接从“appid”和“name”获取对应的路径进行查找。

    Config 项可以直接通过QML属性的形式指定基础的键值类型，例如上述实例代码，该属性也能直接在控件的槽函数中进行绑定，例如以下代码：
    \qml
    Config {
        id: config
        name: "example"  // 必须指定
        property int key1 : 1
        property string key2 : "key2 default"

        onKey2Changed: {
            console.info("Config")
        }
    }

    LineEdit {
        text: config.key2
    }
    \endqml
    对于外部修改的配置项值，Config能够接受其变化并发出对应属性修改的信号，QML中能够监听该信号，并进行文本的实时绑定，监听的方式有两种，如下代码所示：
    \qml
    Config {
        id: config
        name: "example"  // 必须指定
        property int key1 : 1
        property string key2 : "key2 default"

        onKey2Changed: {
            console.info("Config Value changed...")
        }
    }

    // 1. 直接进行属性绑定
    Label {
        text: "property binding key3:" + exampleConfig.key3
    }

    // 2. Qt.binding 进行属性绑定
    Label {
        text: "config.key2"
        Component.onCompleted: {
            text = Qt.binding(function(){ return config.key2 })
        }
    }
    \endqml
    \b {需要注意的是，} Config 中声明的属性，在对应的配置文件中需要有对应的键值，对于Config中新增的属性，不会直接生效到配置文件去；
    相反对于配置文件中有的键值，Config中没有对应属性时，若该值发生变化，将触发Config中valueChanged的信号，控件可以通过使用Connection
    或者 槽函数绑定的形式动态获取，例如以下代码：
    \qml
    Config {
        id: config
        name: "example"  // 必须指定
        property int key1 : 1
        property string key2 : "key2 default"

        // 1. 直接通过信号槽进行连接
        onValueChanged: {
            console.info("Config Key:", key, "Config Value:", config.value(key))
        }

        // 2. 通过Connection进行连接
        Connection {
            target: config
            // 5.11 的写法
            onValueChanged: {
                console.info("Config Key:", key, "Config Value:", config.value(key))
            }
            // 5.15推荐写法
            function  onValueChanged(key) {
                console.info("Config Key:", key, "Config Value:", config.value(key))
            }
        }
    }
    \endqml

    \section1 SettingsDialog 相关
    dtkdeclarative中的SettingsDialog能够更加方便的使用QML语法，更方便的控制布局和样式，同时还能够完成与配置策略的关联。

    dtkwidget中的SettingsDialog通过解析Json文件，完成布局和控件的添加。这种方式存在一些局限性，例如布局的局限性，导致一些高级组合控件无法正常显示；
    界面的改动能够导致各个控件都出现相应的影响等等。

    为了解决与QML的融合，能够使用树状代码结构的形式创建控件，摒弃Json的繁琐性和不易阅读性，并方便配置的统一管理，SettingsDialog有一套统一的控件模板。
    以下展示一个简单的SettingsDialog示例代码：
    \qml
    import org.deepin.dtk.settings 1.0 as Settings

    Config {  // 创建配置项 用于关联到SettingsDialog中
        id: config
        name: "example"
        property string key : "key default" // 配置文件中需要有同名键
    }

    Settings.SettingsDialog {
        height: 600
        width: 680
        config: config

        groups: [  // 创建配置组，管理配置子组和Options
            Settings.SettingsGroup {
                key: "group1"
                name: "group1"
                Settings.SettingsOption {
                    key: "key"  // Option中的键可以直接绑定到config中同名的属性值
                    name: "ComboBox"
                    Settings.ComboBox {  // Settings封装的基础控件类型
                        model: ["first", "sceond", "three"]
                    }
                }
                Settings.SettingsOption {
                    key: "key2"
                    name: "LineEdit"
                    Settings.LineEdit {}
                }
                Settings.SettingsOption {
                    key: "canExit"
                    name: "CheckBox"
                    Settings.CheckBox {}
                }
            }
        ]
    }
    \endqml
    上述示例简单的展示了一个 SettingsDialog 整体树构建过程，对于其中的细节和控件，以下将进行重点介绍：

    \section2 SettingsGroup 和 SettingsOption
    SettingsDialog的子项通过groups属性管理和维护，在窗口组件添加完毕后，它会获取到所有的groups项目树，
    并根据其父子关系进行左侧标题栏的生成和右侧内容页的展示。SettingsGroup就是添加进groups属性的数组子项。

    \b {SettingsGroup：} 其内部用于管理Options，也可以添加子Group，当group存在多个子group时，需要指定其为children对象：
    \qml
    Settings.SettingsDialog {
        height: 600
        width: 680

        groups: [  // 创建配置组，管理配置子组和Options
            Settings.SettingsGroup {
                key: "group1"
                name: "group1"

                children: [
                    Settings.SettingsGroup {
                        key: "group2"
                        name: "group2"

                        Settings.SettingsOption {
                            key: "key"  // Option中的键可以直接绑定到config中同名的属性值
                            name: "ComboBox"
                            Settings.ComboBox {  // Settings封装的基础控件类型
                              model: ["first", "sceond", "three"]
                            }
                        }
                    },
                    Settings.SettingsGroup {
                        key: "group2"
                        name: "group2"

                        Settings.SettingsOption {
                            key: "key2"
                            name: "LineEdit"
                            Settings.LineEdit {}
                        }
                    }
                ]
          }
    }
    \endqml
    \b {SettingsOption：} SettingsGroup的子项，其内部用于添加控件，进行用户操作。和SettingsGroup一致的是它们都有 key
    和、name以及visible 三个属性，但不同的是，SettingsOption中的“key”直接对应与 Config 中对应名称属性，而无需进行手动绑定；
    SettingsGroup 中的“key”通常用于进行以下过滤操作，例如通过单一的“key”过滤出对应的group并控制它们的显示与隐藏。

    \b {附加属性：} SettingsGroup和SettingsOption都有附加属性，对于SettingsGroup和SettingsOption中子控件想要获取他们属性时，
    可以通过附加属性进行获取。不论是SettingsGroup还是SettingsOption，他们的附加属性返回的对象为距离其最近的父类SettingsGroup/SettingsOption对象。

    \section2 Settings 封装的控件
    settings 封装的控件与自定义控件不同，它能够获取对应SettingsOption中的“name”属性并自动添加左右布局的标题描述，同时其属性的改动无需绑定即可自动生效
    到配置文件中，例如ComboBox效果图如下图所示：
    \image images/SettingComboBox.png

    目前被Settings封装好的控件如下表所示(默认添加别名)：
    \table
        \header
            \li 控件名称
            \li Settings控件名称
        \row
            \li CheckBox
            \li \l {CheckBox(Settings)}{Settings.CheckBox}
        \row
            \li ComboBox
            \li \l {ComboBox(Settings)}{Settings.ComboBox}
        \row
            \li LineEdit
            \li \l {LineEdit(Settings)}{Settings.LineEdit}
    \endtable

    添加到SettingsOption中的自定义控件，也能实现上述封装控件的样子，SettingsDialog封装了OptionDelegate控件，对于需要左侧显示名称右侧显示控件的设计需求，
    可以直接将自定义控件放到OptionDelegate中，如下代码所示：
    \qml
    Settings.SettingsGroup {
        key: "group2"
        name: "group2"

        Settings.SettingsOption {
            key: "option1"
            name: "group2.group1.option1"
            Settings.OptionDelegate {
                LineEdit {
                    text: Settings.SettingsOption.name  // Option中的附加属性获取距离最上层的Option对象的name属性
                    onEditingFinished: {  // 需要手动更新配置项的value属性
                        Settings.SettingsOption.value = text  // Option中的附加属性获取距离最上层的Option对象的value属性
                    }
                }
            }
        ]
    }
    \endqml
    需要注意的是，对于此类自定义控件，其Option中对应的value值需要自定义控件进行手动绑定。

    \section2 其他属性

    下表列出了SettingsDialog中的其他属性，并简单介绍：
    \table
        \header
            \li 属性名
            \li 子属性
            \li 描述
        \row
            \li groups
            \li 无
            \li 配置项列表，用于添加 SettingsGroup/SettingsOption 配置项
        \row
            \li config
            \li 无
            \li 配置策略
        \row
            \li {1,5} container
            \li config
            \li 配置策略
        \row
            \li navigationTitle
            \li 导航栏标题，可重载，默认使用Settings.NavigationTitle
        \row
            \li contentTitle
            \li 内容页标题，可重载，默认使用Settings.ContentTitle
        \row
            \li contentBackground
            \li 内容页背景，可重载，默认使用Settings.ContentBackground
        \row
            \li groups
            \li 配置项列表
        \row
            \li navigationView
            \li ListView 中的子属性
            \li 导航列表
        \row
            \li contentView
            \li ListView中的子属性
            \li 内容页列表
    \endtable

    \section1 Setting 相关控件
    \generatelist {qmltypesbymodule org.deepin.dtk.settings}
    \noautolist
*/

/*!
    \page dtkdeclarative-index.html
    \title Dtk Declarative QML Types
    \brief Dtk Declarative 是一个在 UOS 平台创建出符合行云设计风格的开发库

    Dtk Declarative 提供了众多 QML 类型，用于更好的兼容 QtQuick 的基础控件，提供
    更加便捷快速的开发途径。导入 Dtk Declarative 的类型，可以通过下述 QML 代码：
    \qml
    import org.deepin.dtk 1.0
    \endqml

    实现行云设计风格，只需要像其他 QML 代码一样进行特定声明即可。Dtk Declarative 提供的所有
    类型、控件和效果，都是一个独立的 QML 类，下面将从以下几种不同的类别出发，列出所有的 QML 类型。

    \section1 QML 类型集合
    \generatelist {qmltypesbymodule org.deepin.dtk}

    \section1 Setting 相关类型集合
    \generatelist {qmltypesbymodule org.deepin.dtk.settings}
*/
