52 Commits

Author SHA1 Message Date
Christoph Holzheuer
35ebcd2986 tried PCH 2025-09-24 17:29:10 +02:00
93879db3dd very first step... 2025-09-23 22:24:56 +02:00
5a7e309c24 ... 2025-09-23 11:26:07 +02:00
f509668c47 ... 2025-09-23 10:44:02 +02:00
e063ed7f75 Create README.md, part I 2025-09-23 09:13:03 +02:00
9192c0beb2 Changed Doxyfile 2025-09-23 08:50:31 +02:00
3ee5b1adfc remove word file. 2025-09-21 13:02:51 +02:00
2180b62bf1 added doxygen files 2025-09-21 12:50:15 +02:00
Christoph Holzheuer
bf49d8321f semi fixed missing sections 2025-09-16 16:45:21 +02:00
Christoph Holzheuer
28aa03b31a messups. 2025-09-15 16:37:35 +02:00
fa6499e3da Merge branch 'experimental/add-tree-children' 2025-09-13 22:54:48 +02:00
0f8addbe7f add ignore 2025-09-13 22:54:25 +02:00
b6890257f1 cosmetics 2025-09-13 22:53:32 +02:00
10752908ca try to fix vcx proj 2025-09-13 22:44:33 +02:00
32c5121fcd Merge branch 'experimental/qml-edit' into experimental/add-tree-children
# Conflicts:
#	src/application/xqchildmodel.cpp
2025-09-12 17:21:35 +02:00
Christoph Holzheuer
d07ef3fbf9 First steps. 2025-09-12 15:38:06 +02:00
fd94b2d354 --- fy 2025-09-12 00:39:51 +02:00
cc441d094c Added write-back for combos 2025-09-11 23:09:14 +02:00
Christoph Holzheuer
d5c1f8925c re-merge. 2025-09-11 17:45:44 +02:00
fd41138175 Fix choice model. 2025-09-10 23:32:00 +02:00
Christoph Holzheuer
03b0dafdcc -- fy 2025-09-10 17:57:10 +02:00
a0064b2566 delegate cleanups 2025-09-10 07:27:09 +02:00
Christoph Holzheuer
cbe8b92582 --- fy 2025-09-09 16:22:59 +02:00
809ef10c0d fixed toggle section 2025-09-08 22:58:52 +02:00
Christoph Holzheuer
95b7b026ff --- mess 2025-09-08 15:42:15 +02:00
05bc5ad5d9 -- fy 2025-09-07 23:34:09 +02:00
93ec52933e -- pre fy 2025-09-07 16:22:42 +02:00
3ac129ef26 fixed delete undo. 2025-09-07 15:46:01 +02:00
50703a4c44 fixed cut undo. 2025-09-07 11:29:51 +02:00
1531ec14f1 -- semi-fy 2025-09-06 22:13:46 +02:00
0fe15d6043 fixed selection crashes. 2025-09-06 16:06:47 +02:00
89c671295f finally, fixed hiding of headers. 2025-09-06 14:07:25 +02:00
a9dacca684 Fixed toggleSection 2025-09-06 11:08:07 +02:00
3887748c1a remorked sections. 2025-09-05 21:42:40 +02:00
b8f0893d59 Backup. 2025-09-05 17:12:38 +02:00
9c6f7688d7 Enable section toggle 2025-09-05 11:49:36 +02:00
8d26c32e51 cleanups, added const iterators to xqmaptor 2025-09-05 09:57:43 +02:00
c9b61c1c2b Fixed ::setData, part II 2025-09-04 20:09:21 +02:00
d6ccac1d85 Fixed ::setData, part I 2025-09-04 18:10:14 +02:00
5d2fb1b378 Added new-undo == delete 2025-09-04 17:01:01 +02:00
89c5fd21f1 Completed cmdNew implementation. 2025-09-04 14:56:18 +02:00
f8bd0886d3 Added cmdNew implementation. 2025-09-04 13:52:23 +02:00
Christoph Holzheuer
831daf898c --fy 2025-09-03 17:23:52 +02:00
Christoph Holzheuer
3e7b65dca5 add signal prototypes 2025-09-02 16:58:56 +02:00
147769bf60 added signal handler 'itemChanged' 2025-09-01 23:28:24 +02:00
Christoph Holzheuer
527de65074 -- fy 2025-09-01 17:40:08 +02:00
4d49a495fd -- fy 2025-08-31 23:18:14 +02:00
952409ab1a repaired it (a bit) 2025-08-31 14:38:11 +02:00
c6454f3106 cracket it. 2025-08-27 15:39:33 +02:00
04b0f650d6 -- pre-holiday 2025-08-27 14:06:31 +02:00
6ee677c595 looking better. 2025-08-26 19:41:28 +02:00
5057edb9ad Merge branch 'experimental/qml-widget' 2025-08-26 17:57:16 +02:00
89 changed files with 12486 additions and 1748 deletions

7
.gitignore vendored
View File

@@ -7,9 +7,6 @@ release/
enc_temp_folder/ enc_temp_folder/
ui_* ui_*
*autosave *autosave
doc/~$ree_thoughts.docx
doc/~WRL0004.tmp
UsersC998D~1.HOLAppDataLocalTemptmpj0mbo3rd
xml/fitzefatz.xml
build* build*
doc/ src/xtree.vcxproj.user
doc/html/

View File

@@ -1,4 +1,36 @@
# XTree # xtree
Bla blu moo!
...
## Build
```
git clone https://gitea.sourceworx.org/chris/xtree.git
cd xtree/src
qmake xtree.pro
make
```
## Verzeichnisstruktur
| |
|--------|
| `deprecated/` | Reste & Fehlversuche
| `doc/` | Quellcode-Dokumentation
| `qml/` | QML Quellcode
| `src/` | c++ -Quellcode
| `xml/` | XML modeldefinition & Demodaten
## keys
- Widgetset für XML Daten
- experimenteller qml support
- docs erzeugen
-
experimenelle
## Also, noch mal von vorn: ## Also, noch mal von vorn:
@@ -56,3 +88,55 @@ die Testfiles.
- [ ] ```class XQModelHub : public XQModel, public XQModelReader```: etwas fragwürdig, spart aber leidige Verpointerungen - [ ] ```class XQModelHub : public XQModel, public XQModelReader```: etwas fragwürdig, spart aber leidige Verpointerungen
# libPiGPIO
libPiGPIO: Eine C++ Softwarebibliothek für den Pi4 zur Einbindung elektronischer Steuerelemente
## Getting started
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
## Add your files
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
```
mkdir existing_repo
git remote add origin http://sourceworx.org:9099/opensource/libpigpio.git
git branch -M main
git push -uf origin main
```
## Integrate with your tools
- [ ] [Set up project integrations](http://sourceworx.org:9099/opensource/libpigpio/-/settings/integrations)
## Collaborate with your team
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
## Test and Deploy
Use the built-in continuous integration in GitLab.
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
***
# Editing this README
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
## Suggestions for a good README
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.

2987
doc/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

6
doc/doxygen-awesome-css/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
docs/html
.DS_Store
.idea
node_modules
*.tgz

View File

@@ -0,0 +1,3 @@
*
!doxygen-awesome*

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,39 @@
# SPDX-FileCopyrightText: 2022 Andrea Pappacoda <andrea@pappacoda.it>
# SPDX-License-Identifier: MIT
.POSIX:
PROJECT = doxygen-awesome-css
# Paths
PREFIX = /usr/local
DATADIR = share
INSTALLDIR = $(DESTDIR)$(PREFIX)/$(DATADIR)/$(PROJECT)
# Utilities
INSTALL = install -m 644
MKDIR = mkdir -p
RM = rm -f
# Files to be installed
FILES = doxygen-awesome-darkmode-toggle.js \
doxygen-awesome-fragment-copy-button.js \
doxygen-awesome-interactive-toc.js \
doxygen-awesome-paragraph-link.js \
doxygen-awesome-sidebar-only-darkmode-toggle.css \
doxygen-awesome-sidebar-only.css \
doxygen-awesome-tabs.js \
doxygen-awesome.css
# Empty targets so that `make` and `make clean` do not cause errors
all:
clean:
install:
$(MKDIR) $(INSTALLDIR)
$(INSTALL) $(FILES) $(INSTALLDIR)/
uninstall:
$(RM) -r $(INSTALLDIR)/
.PHONY: all clean install uninstall

View File

@@ -0,0 +1,207 @@
# Doxygen Awesome
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/jothepro/doxygen-awesome-css)](https://github.com/jothepro/doxygen-awesome-css/releases/latest)
[![GitHub](https://img.shields.io/github/license/jothepro/doxygen-awesome-css)](https://github.com/jothepro/doxygen-awesome-css/blob/main/LICENSE)
![GitHub Repo stars](https://img.shields.io/github/stars/jothepro/doxygen-awesome-css)
<div class="title_screenshot">
![Screenshot of Doxygen Awesome CSS](img/screenshot.png)
</div>
**Doxygen Awesome** is a custom CSS theme for Doxygen HTML documentation with lots of customization parameters.
## Motivation
I really like how the Doxygen HTML documentation is structured! But IMHO it looks a bit outdated.
This theme is an attempt to update the visuals of Doxygen without changing its overall layout too much.
## Features
- 🌈 Clean, modern design
- 🚀 Heavily customizable by adjusting CSS variables
- 🧩 No changes to the HTML structure of Doxygen are required
- 📱 Improved mobile usability
- 🌘 Dark mode support!
- 🥇 Works best with **doxygen 1.9.1** - **1.9.4** and **1.9.6** - **1.12.0**
## Examples
Some websites using this theme:
- [Documentation of this repository](https://jothepro.github.io/doxygen-awesome-css/)
- [wxWidgets](https://docs.wxwidgets.org/3.2/)
- [OpenCV 5.x](https://docs.opencv.org/5.x/)
- [Zephyr](https://docs.zephyrproject.org/latest/doxygen/html/index.html)
- [FELTOR](https://mwiesenberger.github.io/feltor/dg/html/modules.html)
- [Spatial Audio Framework (SAF)](https://leomccormack.github.io/Spatial_Audio_Framework/index.html)
- [Randolf Richardson's C++ classes](https://www.randolf.ca/c++/docs/)
- [libCloudSync](https://jothepro.github.io/libCloudSync/)
- [libsl3](https://a4z.github.io/libsl3/)
- [DuMu<sup>x</sup>](https://dumux.org/docs/doxygen/master/)
## Installation
To use the theme when generating your documentation, bring the required CSS and JS files from this repository into your project.
This can be done in several ways:
- manually copying the files
- adding the project as a Git submodule
- downloading the project with CMake FetchContent
- adding the project as a npm/xpm dependency
- installing the theme system-wide
All theme files are located in the root of this repository and start with the prefix `doxygen-awesome-`. You may not need all of them. Follow the install instructions to figure out what files are required for your setup.
### Git submodule
For projects that use git, add the repository as a submodule and check out the desired release:
```sh
git submodule add https://github.com/jothepro/doxygen-awesome-css.git
cd doxygen-awesome-css
git checkout v2.3.4
```
### CMake with FetchContent
For project that build with CMake, the `FetchContent` module can be used to download the repository at configure-time.
Add the following snippet to your `CMakeLists.txt`
```cmake
include(FetchContent)
FetchContent_Declare(
doxygen-awesome-css
URL https://github.com/jothepro/doxygen-awesome-css/archive/refs/heads/main.zip
)
FetchContent_MakeAvailable(doxygen-awesome-css)
# Save the location the files were cloned into
# This allows us to get the path to doxygen-awesome.css
FetchContent_GetProperties(doxygen-awesome-css SOURCE_DIR AWESOME_CSS_DIR)
# Generate the Doxyfile
set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile.in)
set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY)
```
This downloads the latest main (but any other revision could be used) and unpacks in the build folder. The `Doxyfile.in` can reference this location in the `HTML_EXTRA_STYLESHEET` field
```text
HTML_EXTRA_STYLESHEET = @AWESOME_CSS_DIR@/doxygen-awesome.css
```
When the configure stage of CMake is run, the `Doxyfile.in` is rendered to Doxyfile and Doxygen can be run as usual.
### npm/xpm dependency
In the npm ecosystem, this project can be added as a development dependency
to your project:
```sh
cd your-project
npm install https://github.com/jothepro/doxygen-awesome-css#v2.3.4 --save-dev
ls -l node_module/@jothepro/doxygen-awesome-css
```
Similarly, in the [xPack](https://xpack.github.io) ecosystem, this project can be added
as a development dependency to an [`xpm`](https://xpack.github.io/xpm/)
managed project.
### System-wide
You can even install the theme system-wide by running `make install`.
The files will be installed to `/usr/local/share/` by default,
but you can customize the install location with `make PREFIX=/my/custom/path install`.
### Choosing a layout
There are two layout options. Choose one of them and configure Doxygen accordingly:
<div class="tabbed">
- <b class="tab-title">Base Theme</b><div class="darkmode_inverted_image">
![](img/theme-variants-base.drawio.svg)
</div>
Comes with the typical Doxygen titlebar. Optionally the treeview in the sidebar can be enabled.
Required files: `doxygen-awesome.css`
Required `Doxyfile` configuration:
```
GENERATE_TREEVIEW = YES # optional. Also works without treeview
DISABLE_INDEX = NO
FULL_SIDEBAR = NO
HTML_EXTRA_STYLESHEET = doxygen-awesome-css/doxygen-awesome.css
HTML_COLORSTYLE = LIGHT # required with Doxygen >= 1.9.5
```
- <b class="tab-title">Sidebar-Only Theme</b><div class="darkmode_inverted_image">
![](img/theme-variants-sidebar-only.drawio.svg)
</div>
Hides the top titlebar to give more space to the content. The treeview must be enabled in order for this theme to work.
Required files: `doxygen-awesome.css`, `doxygen-awesome-sidebar-only.css`
Required `Doxyfile` configuration:
```
GENERATE_TREEVIEW = YES # required!
DISABLE_INDEX = NO
FULL_SIDEBAR = NO
HTML_EXTRA_STYLESHEET = doxygen-awesome-css/doxygen-awesome.css \
doxygen-awesome-css/doxygen-awesome-sidebar-only.css
HTML_COLORSTYLE = LIGHT # required with Doxygen >= 1.9.5
```
</div>
<br>
@warning
- This theme is not compatible with the `FULL_SIDEBAR = YES` option provided by Doxygen!
- `HTML_COLORSTYLE` must be set to `LIGHT` since Doxygen 1.9.5!
### Further installation instructions
- [Installing extensions](docs/extensions.md)
- [Customizing the theme (colors, spacing, border-radius, ...)](docs/customization.md)
- [Tips and Tricks for further configuration](docs/tricks.md)
## Browser support
Tested with
- Chrome 119, Chrome 119 for Android, Chrome 119 for iOS
- Safari 17, Safari for iOS 16
- Firefox 118, Firefox 120 for Android, Firefox 119 for iOS
- Edge 119
- Opera 108
The theme does not strive to be backward compatible with (significantly) older browser versions.
## Credits
Thanks for all the bug reports and inspiring feedback on GitHub!
Special thanks to all the contributors:
<br><br>
<a href="https://github.com/jothepro/doxygen-awesome-css/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jothepro/doxygen-awesome-css" />
</a>
<div class="section_buttons">
| Read Next |
|---------------------------------:|
| [Extensions](docs/extensions.md) |
</div>

View File

@@ -0,0 +1,121 @@
# Customization
[TOC]
## CSS-Variables
This theme is highly customizable because a lot of things are parameterized with CSS variables.
Just to give you an idea of how flexible the styling is, click this button:
<div class="alter-theme-button" onclick="toggle_alternative_theme()" onkeypress="if (event.keyCode == 13) toggle_alternative_theme()" tabindex=0>Alter theme</div>
<br><hr>
### Setup
It is recommended to add your own `custom.css` and overwrite the variables there:
```
HTML_EXTRA_STYLESHEET = doxygen-awesome.css custom.css
```
Make sure to override the variables in the correct spot. All variables should be customized where they have been defined, in the `html` tag selector:
```css
html {
/* override light-mode variables here */
}
```
For dark-mode overrides, you have to choose where to put them, depending on whether the dark-mode toggle extension is installed or not:
<div class="tabbed">
- <b class="tab-title">dark-mode toggle is installed</b>
```css
html.dark-mode {
/* define dark-mode variable overrides here if you DO use doxygen-awesome-darkmode-toggle.js */
}
```
- <b class="tab-title">dark-mode toggle is **NOT** installed</b>
The dark-mode is enabled automatically depending on the system preference:
```css
@media (prefers-color-scheme: dark) {
html:not(.light-mode) {
/* define dark-mode variable overrides here if you DON'T use doxygen-awesome-darkmode-toggle.js */
}
}
```
</div>
### Available variables
The following list gives an overview of the variables defined in [`doxygen-awesome.css`](https://github.com/jothepro/doxygen-awesome-css/blob/main/doxygen-awesome.css).
The list is not complete. To explore all available variables, have a look at the CSS starting from [here](https://github.com/jothepro/doxygen-awesome-css/blob/main/doxygen-awesome.css#L30).
All variables are defined at the beginning of the stylesheet.
| Parameter | Default (Light) | Default (Dark) |
| :---------------------------------- | :---------------------------------------------------------- | :---------------------------------------------------------- |
| **Color Scheme**:<br>primary theme colors. This will affect the entire websites color scheme: links, arrows, labels, ... |||
| `--primary-color` | <code style="background:#1779c4;color:white">#1779c4</code> | <code style="background:#1982d2;color:white">#1982d2</code> |
| `--primary-dark-color` | <code style="background:#335c80;color:white">#335c80</code> | <code style="background:#5ca8e2;color:black">#5ca8e2</code> |
| `--primary-light-color` | <code style="background:#70b1e9;color:black">#70b1e9</code> | <code style="background:#4779ac;color:white">#4779ac</code> |
| **Page Colors**:<br>background and foreground (text-color) of the documentation. |||
| `--page-background-color` | <code style="background:#ffffff;color:black">#ffffff</code> | <code style="background:#1C1D1F;color:white">#1C1D1F</code> |
| `--page-foreground-color` | <code style="background:#2f4153;color:white">#2f4153</code> | <code style="background:#d2dbde;color:black">#d2dbde</code> |
| `--page-secondary-foreground-color` | <code style="background:#6f7e8e;color:white">#6f7e8e</code> | <code style="background:#859399;color:white">#859399</code> |
| **Spacing:**<br>default spacings. Most ui components reference these values for spacing, to provide uniform spacing on the page. |||
| `--spacing-small` | `5px` | |
| `--spacing-medium` | `10px` | |
| `--spacing-large` | `16px` | |
| **Border Radius**:<br>border radius for all rounded ui components. Will affect many components, like dropdowns, memitems, codeblocks, ... |||
| `--border-radius-small` | `4px` | |
| `--border-radius-medium` | `6px` | |
| `--border-radius-large` | `8px` | |
| **Content Width**:<br>The content is centered and constrained in its width. To make the content fill the whole page, set the following variable to `auto`. |||
| `--content-maxwidth` | `1000px` | |
| **Code Fragment Colors**:<br>Color-Scheme of multiline codeblocks |||
| `--fragment-background` | <code style="background:#F8F9FA;color:black">#F8F9FA</code> | <code style="background:#282c34;color:white">#282c34</code> |
| `--fragment-foreground` | <code style="background:#37474F;color:white">#37474F</code> | <code style="background:#dbe4eb;color:black">#dbe4eb</code> |
| **Arrow Opacity**:<br>By default the arrows in the sidebar are only visible on hover. You can override this behavior so they are visible all the time. |||
| `--side-nav-arrow-opacity` | `0` | |
| `--side-nav-arrow-hover-opacity` | `0.9` | |
| ...and many more |||
If you miss a configuration option or find a bug, please consider [opening an issue](https://github.com/jothepro/doxygen-awesome-css/issues)!
## Doxygen generator
The theme overrides most colors with the `--primary-color-*` variables.
But there are a few small images and graphics that the theme cannot adjust or replace. To make these blend in better with
the rest, it is recommended to adjust the [doxygen color settings](https://www.doxygen.nl/manual/customize.html#minor_tweaks_colors)
to something that matches the chosen color scheme.
For the default color scheme, these values work out quite well:
```
# Doxyfile
HTML_COLORSTYLE_HUE = 209
HTML_COLORSTYLE_SAT = 255
HTML_COLORSTYLE_GAMMA = 113
```
## Share your customizations
If you have customized the theme with custom colors, spacings, font-sizes, etc. and you want to share your creation with others, you can do this [here](https://github.com/jothepro/doxygen-awesome-css/discussions/13).
I am always curious to learn about how you made the theme look even better!
<div class="section_buttons">
| Previous | Next |
|:----------------------------|---------------------------:|
| [Extensions](extensions.md) | [Tips & Tricks](tricks.md) |
</div>

View File

@@ -0,0 +1,284 @@
# Extensions
[TOC]
On top of the base theme provided by `doxygen-awesome.css`, this repository comes with Javascript extensions that require additional setup steps to get them running.
The extensions require customizations in the header HTML template.
This is how you can create the default template with Doxygen:
1. Create default header template:
```sh
doxygen -w html header.html delete_me.html delete_me.css
```
2. Reference the template in your `Doxyfile`:
```
HTML_HEADER = header.html
```
[More details on header customization](https://www.doxygen.nl/manual/customize.html#minor_tweaks_header_css)
## Dark Mode Toggle {#extension-dark-mode-toggle}
Adds a button next to the search bar to enable and disable the dark theme variant manually:
<div class="darkmode_inverted_image bordered_image">
![](img/darkmode_toggle.png){width=250px}
</div>
### Installation
1. Add the required resources in your `Doxyfile`:
- **HTML_EXTRA_FILES:** `doxygen-awesome-darkmode-toggle.js`
- **HTML_EXTRA_STYLESHEET:** `doxygen-awesome-sidebar-only-darkmode-toggle.css`
<em>(ONLY required for the sidebar-only theme variant!)</em>
2. In the `header.html` template, include `doxygen-awesome-darkmode-toggle.js` at the end of the `<head>` and then initialize it:
```html
<html>
<head>
<!-- ... other metadata & script includes ... -->
<script type="text/javascript" src="$relpath^doxygen-awesome-darkmode-toggle.js"></script>
<script type="text/javascript">
DoxygenAwesomeDarkModeToggle.init()
</script>
</head>
<body>
```
### Customizing
Changing the tooltip of the button:
```js
DoxygenAwesomeDarkModeToggle.title = "Zwischen hellem/dunklem Modus wechseln"
```
Changing Icons. Both Emoji or SVG icons are supported:
```js
DoxygenAwesomeDarkModeToggle.lightModeIcon = '🌞'
// icon from https://fonts.google.com/icons
DoxygenAwesomeDarkModeToggle.darkModeIcon = `<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#009793"><g><rect fill="none" height="24" width="24"/></g><g><g><path d="M8.1,14.15C9.77,14.63,11,16.17,11,18c0,0.68-0.19,1.31-0.48,1.87c0.48,0.09,0.97,0.14,1.48,0.14 c1.48,0,2.9-0.41,4.13-1.15c-2.62-0.92-5.23-2.82-6.8-5.86C7.74,9.94,7.78,7.09,8.29,4.9c-2.57,1.33-4.3,4.01-4.3,7.1c0,0,0,0,0,0 c0.01,0,0.01,0,0.02,0C5.66,12,7.18,12.83,8.1,14.15z" opacity=".3"/><path d="M19.78,17.51c-2.47,0-6.57-1.33-8.68-5.43C8.77,7.57,10.6,3.6,11.63,2.01C6.27,2.2,1.98,6.59,1.98,12 c0,0.14,0.02,0.28,0.02,0.42C2.61,12.16,3.28,12,3.98,12c0,0,0,0,0,0c0-3.09,1.73-5.77,4.3-7.1C7.78,7.09,7.74,9.94,9.32,13 c1.57,3.04,4.18,4.95,6.8,5.86c-1.23,0.74-2.65,1.15-4.13,1.15c-0.5,0-1-0.05-1.48-0.14c-0.37,0.7-0.94,1.27-1.64,1.64 c0.98,0.32,2.03,0.5,3.11,0.5c3.5,0,6.58-1.8,8.37-4.52C20.18,17.5,19.98,17.51,19.78,17.51z"/><path d="M7,16l-0.18,0C6.4,14.84,5.3,14,4,14c-1.66,0-3,1.34-3,3s1.34,3,3,3c0.62,0,2.49,0,3,0c1.1,0,2-0.9,2-2 C9,16.9,8.1,16,7,16z"/></g></g></svg>`
```
All customizations must be applied before calling `DoxygenAwesomeDarkModeToggle.init()`!
## Fragment Copy Button {#extension-copy-button}
Shows a copy button when the user hovers over a code fragment:
<div class="darkmode_inverted_image bordered_image">
![](img/fragment_copy_button.png){width=490}
</div>
### Installation
1. Add the required resources in your `Doxyfile`:
- **HTML_EXTRA_FILES:** `doxygen-awesome-fragment-copy-button.js`
- **HTML_COPY_CLIPBOARD:** `NO` required with Doxygen >= 1.10.0
2. In the `header.html` template, include `doxygen-awesome-fragment-copy-button.js` at the end of the `<head>` and then initialize it:
```html
<html>
<head>
<!-- ... other metadata & script includes ... -->
<script type="text/javascript" src="$relpath^doxygen-awesome-fragment-copy-button.js"></script>
<script type="text/javascript">
DoxygenAwesomeFragmentCopyButton.init()
</script>
</head>
<body>
```
### Customizing
The tooltip of the button can be changed:
```js
DoxygenAwesomeFragmentCopyButton.title = "In die Zwischenablage kopieren"
```
The icon can be changed. It must be an SVG:
```js
DoxygenAwesomeFragmentCopyButton.copyIcon = `<svg ...>`
DoxygenAwesomeFragmentCopyButton.successIcon = `<svg ...>`
```
All customizations must be applied before calling `DoxygenAwesomeDarkModeToggle.init()`!
## Paragraph Linking {#extension-para}
Provides a button on hover behind every headline to allow easy creation of a permanent link to the headline:
<div class="darkmode_inverted_image bordered_image">
![](img/paragraph_link.png){width=220}
</div>
Works for all headlines and for many documentation section titles.
### Installation
1. Add the required resources in your `Doxyfile`:
- **HTML_EXTRA_FILES:** `doxygen-awesome-paragraph-link.js`
2. In the `header.html` template, include `doxygen-awesome-paragraph-link.js` at the end of the `<head>` and then initialize it:
```html
<html>
<head>
<!-- ... other metadata & script includes ... -->
<script type="text/javascript" src="$relpath^doxygen-awesome-paragraph-link.js"></script>
<script type="text/javascript">
DoxygenAwesomeParagraphLink.init()
</script>
</head>
<body>
```
### Customizing
The button tooltip can be changed:
```js
DoxygenAwesomeParagraphLink.title = "Abschnitt verknüpfen"
```
The icon of the button can be changed. Both plain characters or SVG icons are supported:
```js
DoxygenAwesomeParagraphLink.icon = "¶"
```
All customizations must be applied before calling `DoxygenAwesomeParagraphLink.init()`!
## Interactive TOC {#extension-toc}
On large screens, the Table of Contents (TOC) is anchored on the top right of the page. This extension visualizes the reading progress by dynamically highlighting the currently active section.
On small screens, the extension hides the TOC by default. The user can open it manually when needed:
<div class="darkmode_inverted_image bordered_image">
![](img/interactive_toc_mobile.png){width=380}
</div>
### Installation
1. Add the required resources in your `Doxyfile`:
- **HTML_EXTRA_FILES:** `doxygen-awesome-interactive-toc.js`
2. In the `header.html` template, include `doxygen-awesome-interactive-toc.js` at the end of the `<head>` and then initialize it:
```html
<html>
<head>
<!-- ... other metadata & script includes ... -->
<script type="text/javascript" src="$relpath^doxygen-awesome-interactive-toc.js"></script>
<script type="text/javascript">
DoxygenAwesomeInteractiveToc.init()
</script>
</head>
<body>
```
### Customizing
The offset for when a headline is considered active can be changed. A smaller value means that the headline of the section must be closer to the top of the viewport before it is highlighted in the TOC:
```js
DoxygenAwesomeInteractiveToc.topOffset = 45
```
Hiding the TOC on small screens can be disabled. It is still interactive and can be hidden by the user but will now be open by default:
```js
DoxygenAwesomeInteractiveToc.hideMobileMenu = false
```
## Tabs {#extension-tabs}
@warning Experimental feature! Please report bugs [here](https://github.com/jothepro/doxygen-awesome-css/issues).
This extension allows to arrange list content in tabs:
<div class="tabbed">
- <b class="tab-title">Tab 1</b>
This is the content of tab 1
- <b class="tab-title">Tab 2</b>
This is the content of tab 2
1. it has a list
2. with multiple items
</div>
### Installation
1. Add the required resources in your `Doxyfile`:
- **HTML_EXTRA_FILES:** `doxygen-awesome-tabs.js`
2. In the `header.html` template, include `doxygen-awesome-tabs.js` at the end of the `<head>` and then initialize it:
```html
<html>
<head>
<!-- ... other metadata & script includes ... -->
<script type="text/javascript" src="$relpath^doxygen-awesome-tabs.js"></script>
<script type="text/javascript">
DoxygenAwesomeTabs.init()
</script>
</head>
<body>
```
### Usage
Each list that is supposed to be displayed as tabs has to be wrapped with the `tabbed` CSS class.
Each item in the list must start with an element that has the class `tab-title`. It will then be used as tab title.
```md
<div class="tabbed">
- <b class="tab-title">Tab 1</b> This is the content of tab 1
- <b class="tab-title">Tab 2</b> This is the content of tab 2
</div>
```
## Page Navigation {#extension-page-navigation}
@warning Experimental feature! Please report bugs [here](https://github.com/jothepro/doxygen-awesome-css/issues).
To allow the user to easily navigate from one document to another, "Next" and "Previous" buttons can be added at the end of a Markdown document.
### Installation
The feature is shipped inside the default `doxygen-awesome.css`. No additional stylesheets or scripts need to be added.
### Usage
The following conditions must be met for the feature to work properly:
- The navigation must be inside a Markdown table with 1-2 columns.
- The alignment of the column defines the alignment of the arrow on the navigation button.
- the table must be wrapped inside a `<div>` with the class `section_buttons`.
<div class="tabbed">
- <span class="tab-title">Code</span>
```md
<div class="section_buttons">
| Previous | Next |
|:------------------|----------------------------------:|
| [Home](README.md) | [Customization](customization.md) |
</div>
```
- <span class="tab-title">Result</span>
<div class="section_buttons">
| Previous | Next |
|:------------------|----------------------------------:|
| [Home](README.md) | [Customization](customization.md) |
</div>
</div>
<div class="section_buttons">
| Previous | Next |
|:------------------|----------------------------------:|
| [Home](README.md) | [Customization](customization.md) |
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,127 @@
# Tips & Tricks
[TOC]
## Diagrams with Graphviz {#tricks-graphviz}
To get the best-looking class diagrams for your documentation, generate them with Graphviz as vector graphics with transparent background:
```
# Doxyfile
HAVE_DOT = YES
DOT_IMAGE_FORMAT = svg
DOT_TRANSPARENT = YES
```
In case `INTERACTIVE_SVG = YES` is set in the Doxyfile, all user-defined dotgraphs must be wrapped with the `interactive_dotgraph` CSS class for them to be rendered correctly:
```md
<div class="interactive_dotgraph">
\dotfile graph.dot
</div>
```
@note Both the default overflow scrolling behavior in this theme and the interactive editor enabled by `INTERACTIVE_SVG` are unsatisfying workarounds IMHO. Consider designing your graphs to be narrow enough to fit the page to avoid scrolling.
## Disable Dark Mode {#tricks-darkmode}
If you don't want the theme to automatically switch to dark mode depending on the browser preference,
you can disable dark mode by adding the `light-mode` class to the HTML tag in the header template:
```html
<html xmlns="http://www.w3.org/1999/xhtml" class="light-mode">
```
The same can be done to always enable dark mode:
```html
<html xmlns="http://www.w3.org/1999/xhtml" class="dark-mode">
```
@warning This only works if you don't use the dark-mode toggle extension.
## Choosing Sidebar Width {#tricks-sidebar}
If you have enabled the sidebar-only theme variant, make sure to carefully choose a proper width for your sidebar.
It should be wide enough to hold the icon, project title and version number. If the content is too wide, it will be
cut off.
```css
html {
/* Make sure sidebar is wide enough to contain the page title (logo + title + version) */
--side-nav-fixed-width: 335px;
}
```
The chosen width should also be set in the Doxyfile:
```
# Doxyfile
TREEVIEW_WIDTH = 335
```
## Formatting Tables {#tricks-tables}
By default tables in this theme are left-aligned and as wide as required to fit their content.
Those properties can be changed for individual tables.
### Centering
Tables can be centered by wrapping them in the `<center>` HTML tag.
<div class="tabbed">
- <span class="tab-title">Code</span>
```md
<center>
| This table | is centered |
|------------|----------------------|
| test 1 | test 2 |
</center>
```
- <span class="tab-title">Result</span>
<center>
| This table | is centered |
|------------|----------------------|
| test 1 | test 2 |
</center>
</div>
### Full Width
To make tables span the full width of the page, no matter how wide the content is, wrap the table in the `full_width_table` CSS class.
@warning Apply with caution! This breaks the overflow scrolling of the table. Content might be cut off on small screens!
<div class="tabbed">
- <span class="tab-title">Code</span>
```md
<div class="full_width_table">
| This table | spans the full width |
|------------|----------------------|
| test 1 | test 2 |
</div>
```
- <span class="tab-title">Result</span>
<div class="full_width_table">
| This table | spans the full width |
|------------|----------------------|
| test 1 | test 2 |
</div>
</div>
<div class="section_buttons">
| Previous | Next |
|:----------------------------------|---------------------------------------:|
| [Customization](customization.md) | [Example](https://jothepro.github.io/doxygen-awesome-css/class_my_library_1_1_example.html) |
</div>

View File

@@ -0,0 +1,157 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2021 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeDarkModeToggle extends HTMLElement {
// SVG icons from https://fonts.google.com/icons
// Licensed under the Apache 2.0 license:
// https://www.apache.org/licenses/LICENSE-2.0.html
static lightModeIcon = `<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#FCBF00"><rect fill="none" height="24" width="24"/><circle cx="12" cy="12" opacity=".3" r="3"/><path d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"/></svg>`
static darkModeIcon = `<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#FE9700"><rect fill="none" height="24" width="24"/><path d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27 C17.45,17.19,14.93,19,12,19c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z" opacity=".3"/><path d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"/></svg>`
static title = "Toggle Light/Dark Mode"
static prefersLightModeInDarkModeKey = "prefers-light-mode-in-dark-mode"
static prefersDarkModeInLightModeKey = "prefers-dark-mode-in-light-mode"
static _staticConstructor = function() {
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.userPreference)
// Update the color scheme when the browsers preference changes
// without user interaction on the website.
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
})
// Update the color scheme when the tab is made visible again.
// It is possible that the appearance was changed in another tab
// while this tab was in the background.
document.addEventListener("visibilitychange", visibilityState => {
if (document.visibilityState === 'visible') {
DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
}
});
}()
static init() {
$(function() {
$(document).ready(function() {
const toggleButton = document.createElement('doxygen-awesome-dark-mode-toggle')
toggleButton.title = DoxygenAwesomeDarkModeToggle.title
toggleButton.updateIcon()
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
toggleButton.updateIcon()
})
document.addEventListener("visibilitychange", visibilityState => {
if (document.visibilityState === 'visible') {
toggleButton.updateIcon()
}
});
$(document).ready(function(){
document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
})
$(window).resize(function(){
document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
})
})
})
}
constructor() {
super();
this.onclick=this.toggleDarkMode
}
/**
* @returns `true` for dark-mode, `false` for light-mode system preference
*/
static get systemPreference() {
return window.matchMedia('(prefers-color-scheme: dark)').matches
}
/**
* @returns `true` for dark-mode, `false` for light-mode user preference
*/
static get userPreference() {
return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) ||
(DoxygenAwesomeDarkModeToggle.systemPreference && !localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey))
}
static set userPreference(userPreference) {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = userPreference
if(!userPreference) {
if(DoxygenAwesomeDarkModeToggle.systemPreference) {
localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey, true)
} else {
localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)
}
} else {
if(!DoxygenAwesomeDarkModeToggle.systemPreference) {
localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey, true)
} else {
localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey)
}
}
DoxygenAwesomeDarkModeToggle.onUserPreferenceChanged()
}
static enableDarkMode(enable) {
if(enable) {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = true
document.documentElement.classList.add("dark-mode")
document.documentElement.classList.remove("light-mode")
} else {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = false
document.documentElement.classList.remove("dark-mode")
document.documentElement.classList.add("light-mode")
}
}
static onSystemPreferenceChanged() {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = DoxygenAwesomeDarkModeToggle.userPreference
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
}
static onUserPreferenceChanged() {
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
}
toggleDarkMode() {
DoxygenAwesomeDarkModeToggle.userPreference = !DoxygenAwesomeDarkModeToggle.userPreference
this.updateIcon()
}
updateIcon() {
if(DoxygenAwesomeDarkModeToggle.darkModeEnabled) {
this.innerHTML = DoxygenAwesomeDarkModeToggle.darkModeIcon
} else {
this.innerHTML = DoxygenAwesomeDarkModeToggle.lightModeIcon
}
}
}
customElements.define("doxygen-awesome-dark-mode-toggle", DoxygenAwesomeDarkModeToggle);

View File

@@ -0,0 +1,85 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2022 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeFragmentCopyButton extends HTMLElement {
constructor() {
super();
this.onclick=this.copyContent
}
static title = "Copy to clipboard"
static copyIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>`
static successIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/></svg>`
static successDuration = 980
static init() {
$(function() {
$(document).ready(function() {
if(navigator.clipboard) {
const fragments = document.getElementsByClassName("fragment")
for(const fragment of fragments) {
const fragmentWrapper = document.createElement("div")
fragmentWrapper.className = "doxygen-awesome-fragment-wrapper"
const fragmentCopyButton = document.createElement("doxygen-awesome-fragment-copy-button")
fragmentCopyButton.innerHTML = DoxygenAwesomeFragmentCopyButton.copyIcon
fragmentCopyButton.title = DoxygenAwesomeFragmentCopyButton.title
fragment.parentNode.replaceChild(fragmentWrapper, fragment)
fragmentWrapper.appendChild(fragment)
fragmentWrapper.appendChild(fragmentCopyButton)
}
}
})
})
}
copyContent() {
const content = this.previousSibling.cloneNode(true)
// filter out line number from file listings
content.querySelectorAll(".lineno, .ttc").forEach((node) => {
node.remove()
})
let textContent = content.textContent
// remove trailing newlines that appear in file listings
let numberOfTrailingNewlines = 0
while(textContent.charAt(textContent.length - (numberOfTrailingNewlines + 1)) == '\n') {
numberOfTrailingNewlines++;
}
textContent = textContent.substring(0, textContent.length - numberOfTrailingNewlines)
navigator.clipboard.writeText(textContent);
this.classList.add("success")
this.innerHTML = DoxygenAwesomeFragmentCopyButton.successIcon
window.setTimeout(() => {
this.classList.remove("success")
this.innerHTML = DoxygenAwesomeFragmentCopyButton.copyIcon
}, DoxygenAwesomeFragmentCopyButton.successDuration);
}
}
customElements.define("doxygen-awesome-fragment-copy-button", DoxygenAwesomeFragmentCopyButton)

View File

@@ -0,0 +1,91 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2022 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeInteractiveToc {
static topOffset = 38
static hideMobileMenu = true
static headers = []
static init() {
window.addEventListener("load", () => {
let toc = document.querySelector(".contents > .toc")
if(toc) {
toc.classList.add("interactive")
if(!DoxygenAwesomeInteractiveToc.hideMobileMenu) {
toc.classList.add("open")
}
document.querySelector(".contents > .toc > h3")?.addEventListener("click", () => {
if(toc.classList.contains("open")) {
toc.classList.remove("open")
} else {
toc.classList.add("open")
}
})
document.querySelectorAll(".contents > .toc > ul a").forEach((node) => {
let id = node.getAttribute("href").substring(1)
DoxygenAwesomeInteractiveToc.headers.push({
node: node,
headerNode: document.getElementById(id)
})
document.getElementById("doc-content")?.addEventListener("scroll",this.throttle(DoxygenAwesomeInteractiveToc.update, 100))
})
DoxygenAwesomeInteractiveToc.update()
}
})
}
static update() {
let active = DoxygenAwesomeInteractiveToc.headers[0]?.node
DoxygenAwesomeInteractiveToc.headers.forEach((header) => {
let position = header.headerNode.getBoundingClientRect().top
header.node.classList.remove("active")
header.node.classList.remove("aboveActive")
if(position < DoxygenAwesomeInteractiveToc.topOffset) {
active = header.node
active?.classList.add("aboveActive")
}
})
active?.classList.add("active")
active?.classList.remove("aboveActive")
}
static throttle(func, delay) {
let lastCall = 0;
return function (...args) {
const now = new Date().getTime();
if (now - lastCall < delay) {
return;
}
lastCall = now;
return setTimeout(() => {func(...args)}, delay);
};
}
}

View File

@@ -0,0 +1,51 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2022 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeParagraphLink {
// Icon from https://fonts.google.com/icons
// Licensed under the Apache 2.0 license:
// https://www.apache.org/licenses/LICENSE-2.0.html
static icon = `<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 0 24 24" width="20px"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M17 7h-4v2h4c1.65 0 3 1.35 3 3s-1.35 3-3 3h-4v2h4c2.76 0 5-2.24 5-5s-2.24-5-5-5zm-6 8H7c-1.65 0-3-1.35-3-3s1.35-3 3-3h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-2zm-3-4h8v2H8z"/></svg>`
static title = "Permanent Link"
static init() {
$(function() {
$(document).ready(function() {
document.querySelectorAll(".contents a.anchor[id], .contents .groupheader > a[id]").forEach((node) => {
let anchorlink = document.createElement("a")
anchorlink.setAttribute("href", `#${node.getAttribute("id")}`)
anchorlink.setAttribute("title", DoxygenAwesomeParagraphLink.title)
anchorlink.classList.add("anchorlink")
node.classList.add("anchor")
anchorlink.innerHTML = DoxygenAwesomeParagraphLink.icon
node.parentElement.appendChild(anchorlink)
})
})
})
}
}

View File

@@ -0,0 +1,40 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2021 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
@media screen and (min-width: 768px) {
#MSearchBox {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - var(--searchbar-height) - 1px);
}
#MSearchField {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 66px - var(--searchbar-height));
}
}

View File

@@ -0,0 +1,116 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2021 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
html {
/* side nav width. MUST be = `TREEVIEW_WIDTH`.
* Make sure it is wide enough to contain the page title (logo + title + version)
*/
--side-nav-fixed-width: 335px;
--menu-display: none;
--top-height: 120px;
--toc-sticky-top: -25px;
--toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 25px);
}
#projectname {
white-space: nowrap;
}
@media screen and (min-width: 768px) {
html {
--searchbar-background: var(--page-background-color);
}
#side-nav {
min-width: var(--side-nav-fixed-width);
max-width: var(--side-nav-fixed-width);
top: var(--top-height);
overflow: visible;
}
#nav-tree, #side-nav {
height: calc(100vh - var(--top-height)) !important;
}
#nav-tree {
padding: 0;
}
#top {
display: block;
border-bottom: none;
height: var(--top-height);
margin-bottom: calc(0px - var(--top-height));
max-width: var(--side-nav-fixed-width);
overflow: hidden;
background: var(--side-nav-background);
}
#main-nav {
float: left;
padding-right: 0;
}
.ui-resizable-handle {
cursor: default;
width: 1px !important;
background: var(--separator-color);
box-shadow: 0 calc(-2 * var(--top-height)) 0 0 var(--separator-color);
}
#nav-path {
position: fixed;
right: 0;
left: var(--side-nav-fixed-width);
bottom: 0;
width: auto;
}
#doc-content {
height: calc(100vh - 31px) !important;
padding-bottom: calc(3 * var(--spacing-large));
padding-top: calc(var(--top-height) - 80px);
box-sizing: border-box;
margin-left: var(--side-nav-fixed-width) !important;
}
#MSearchBox {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)));
}
#MSearchField {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 65px);
}
#MSearchResultsWindow {
left: var(--spacing-medium) !important;
right: auto;
}
}

View File

@@ -0,0 +1,90 @@
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
MIT License
Copyright (c) 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
class DoxygenAwesomeTabs {
static init() {
window.addEventListener("load", () => {
document.querySelectorAll(".tabbed:not(:empty)").forEach((tabbed, tabbedIndex) => {
let tabLinkList = []
tabbed.querySelectorAll(":scope > ul > li").forEach((tab, tabIndex) => {
tab.id = "tab_" + tabbedIndex + "_" + tabIndex
let header = tab.querySelector(".tab-title")
let tabLink = document.createElement("button")
tabLink.classList.add("tab-button")
tabLink.appendChild(header)
header.title = header.textContent
tabLink.addEventListener("click", () => {
tabbed.querySelectorAll(":scope > ul > li").forEach((tab) => {
tab.classList.remove("selected")
})
tabLinkList.forEach((tabLink) => {
tabLink.classList.remove("active")
})
tab.classList.add("selected")
tabLink.classList.add("active")
})
tabLinkList.push(tabLink)
if(tabIndex == 0) {
tab.classList.add("selected")
tabLink.classList.add("active")
}
})
let tabsOverview = document.createElement("div")
tabsOverview.classList.add("tabs-overview")
let tabsOverviewContainer = document.createElement("div")
tabsOverviewContainer.classList.add("tabs-overview-container")
tabLinkList.forEach((tabLink) => {
tabsOverview.appendChild(tabLink)
})
tabsOverviewContainer.appendChild(tabsOverview)
tabbed.before(tabsOverviewContainer)
function resize() {
let maxTabHeight = 0
tabbed.querySelectorAll(":scope > ul > li").forEach((tab, tabIndex) => {
let visibility = tab.style.display
tab.style.display = "block"
maxTabHeight = Math.max(tab.offsetHeight, maxTabHeight)
tab.style.display = visibility
})
tabbed.style.height = `${maxTabHeight + 10}px`
}
resize()
new ResizeObserver(resize).observe(tabbed)
})
})
}
static resize(tabbed) {
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,54 @@
html.alternative {
/* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */
--primary-color: #AF7FE4;
--primary-dark-color: #9270E4;
--primary-light-color: #7aabd6;
--primary-lighter-color: #cae1f1;
--primary-lightest-color: #e9f1f8;
/* page base colors */
--page-background-color: white;
--page-foreground-color: #2c3e50;
--page-secondary-foreground-color: #67727e;
--border-radius-large: 22px;
--border-radius-small: 9px;
--border-radius-medium: 14px;
--spacing-small: 8px;
--spacing-medium: 14px;
--spacing-large: 19px;
--top-height: 125px;
--side-nav-background: #324067;
--side-nav-foreground: #F1FDFF;
--header-foreground: var(--side-nav-foreground);
--searchbar-background: var(--side-nav-foreground);
--searchbar-border-radius: var(--border-radius-medium);
--header-background: var(--side-nav-background);
--header-foreground: var(--side-nav-foreground);
--toc-background: rgb(243, 240, 252);
--toc-foreground: var(--page-foreground-color);
}
html.alternative.dark-mode {
color-scheme: dark;
--primary-color: #AF7FE4;
--primary-dark-color: #9270E4;
--primary-light-color: #4779ac;
--primary-lighter-color: #191e21;
--primary-lightest-color: #191a1c;
--page-background-color: #1C1D1F;
--page-foreground-color: #d2dbde;
--page-secondary-foreground-color: #859399;
--separator-color: #3a3246;
--side-nav-background: #171D32;
--side-nav-foreground: #F1FDFF;
--toc-background: #20142C;
--searchbar-background: var(--page-background-color);
}

View File

@@ -0,0 +1,57 @@
.github-corner svg {
fill: var(--primary-light-color);
color: var(--page-background-color);
width: 72px;
height: 72px;
}
@media screen and (max-width: 767px) {
.github-corner svg {
width: 50px;
height: 50px;
}
#projectnumber {
margin-right: 22px;
}
}
.alter-theme-button {
display: inline-block;
cursor: pointer;
background: var(--primary-color);
color: var(--page-background-color) !important;
border-radius: var(--border-radius-medium);
padding: var(--spacing-small) var(--spacing-medium);
text-decoration: none;
}
.alter-theme-button:hover {
background: var(--primary-dark-color);
}
html.dark-mode .darkmode_inverted_image img, /* < doxygen 1.9.3 */
html.dark-mode .darkmode_inverted_image object[type="image/svg+xml"] /* doxygen 1.9.3 */ {
filter: brightness(89%) hue-rotate(180deg) invert();
}
.bordered_image {
border-radius: var(--border-radius-small);
border: 1px solid var(--separator-color);
display: inline-block;
overflow: hidden;
}
html.dark-mode .bordered_image img, /* < doxygen 1.9.3 */
html.dark-mode .bordered_image object[type="image/svg+xml"] /* doxygen 1.9.3 */ {
border-radius: var(--border-radius-small);
}
.title_screenshot {
filter: drop-shadow(0px 3px 10px rgba(0,0,0,0.22));
max-width: 500px;
margin: var(--spacing-large) 0;
}
.title_screenshot .caption {
display: none;
}

View File

@@ -0,0 +1,90 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen $doxygenversion"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<!-- BEGIN opengraph metadata -->
<meta property="og:title" content="Doxygen Awesome" />
<meta property="og:image" content="https://repository-images.githubusercontent.com/348492097/4f16df80-88fb-11eb-9d31-4015ff22c452" />
<meta property="og:description" content="Custom CSS theme for doxygen html-documentation with lots of customization parameters." />
<meta property="og:url" content="https://jothepro.github.io/doxygen-awesome-css/" />
<!-- END opengraph metadata -->
<!-- BEGIN twitter metadata -->
<meta name="twitter:image:src" content="https://repository-images.githubusercontent.com/348492097/4f16df80-88fb-11eb-9d31-4015ff22c452" />
<meta name="twitter:title" content="Doxygen Awesome" />
<meta name="twitter:description" content="Custom CSS theme for doxygen html-documentation with lots of customization parameters." />
<!-- END twitter metadata -->
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
<link rel="icon" type="image/svg+xml" href="logo.drawio.svg"/>
<script type="text/javascript" src="$relpath^jquery.js"></script>
<script type="text/javascript" src="$relpath^dynsections.js"></script>
<script type="text/javascript" src="$relpath^doxygen-awesome-darkmode-toggle.js"></script>
<script type="text/javascript" src="$relpath^doxygen-awesome-fragment-copy-button.js"></script>
<script type="text/javascript" src="$relpath^doxygen-awesome-paragraph-link.js"></script>
<script type="text/javascript" src="$relpath^doxygen-awesome-interactive-toc.js"></script>
<script type="text/javascript" src="$relpath^doxygen-awesome-tabs.js"></script>
<script type="text/javascript" src="$relpath^toggle-alternative-theme.js"></script>
<script type="text/javascript">
DoxygenAwesomeFragmentCopyButton.init()
DoxygenAwesomeDarkModeToggle.init()
DoxygenAwesomeParagraphLink.init()
DoxygenAwesomeInteractiveToc.init()
DoxygenAwesomeTabs.init()
</script>
$treeview
$search
$mathjax
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet
</head>
<body>
<!-- https://tholman.com/github-corners/ -->
<a href="https://github.com/jothepro/doxygen-awesome-css" class="github-corner" title="View source on GitHub" target="_blank" rel="noopener noreferrer">
<svg viewBox="0 0 250 250" width="40" height="40" style="position: absolute; top: 0; border: 0; right: 0; z-index: 99;" aria-hidden="true">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<!--BEGIN TITLEAREA-->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<!--BEGIN PROJECT_LOGO-->
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
<!--END PROJECT_LOGO-->
<!--BEGIN PROJECT_NAME-->
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">$projectname
<!--BEGIN PROJECT_NUMBER-->&#160;<span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
</div>
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
</td>
<!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME-->
<!--BEGIN PROJECT_BRIEF-->
<td style="padding-left: 0.5em;">
<div id="projectbrief">$projectbrief</div>
</td>
<!--END PROJECT_BRIEF-->
<!--END !PROJECT_NAME-->
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN SEARCHENGINE-->
<td>$searchbox</td>
<!--END SEARCHENGINE-->
<!--END DISABLE_INDEX-->
</tr>
</tbody>
</table>
</div>
<!--END TITLEAREA-->
<!-- end header part -->

View File

@@ -0,0 +1,12 @@
let original_theme_active = true;
function toggle_alternative_theme() {
if(original_theme_active) {
document.documentElement.classList.add("alternative")
original_theme_active = false;
} else {
document.documentElement.classList.remove("alternative")
original_theme_active = true;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -0,0 +1,117 @@
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="491px" height="261px" viewBox="-0.5 -0.5 491 261" content="&lt;mxfile&gt;&lt;diagram id=&quot;6E4AiNPWWr3a8GvC3Ypl&quot; name=&quot;Page-1&quot;&gt;xZfLrpswEIafBqndIIzBwLK5tZt2k0pd+wQHrBqcOs6tT98xmABxmrYiUUEK+Pd1vhkPjofn1fmjorvys8yZ8MIgP3t44YVhihL4NcKlFZIkbYVC8byVUC+s+U9mxcCqB56z/aihllJovhuLG1nXbKNHGlVKnsbNtlKMZ93RgjnCekOFq37juS6tWXHQ658YL8puZhTYmop2ja2wL2kuTwMJLz08V1Lq9q06z5kw7Doubb/Vb2qvC1Os1n/ToVvHkYqDNc4uTF86awslDzsPz+BR58x0DKBE1cY6JoWSO69dypEpzc73vELfugl6wyFgmKyYVhdod+rRRpldZznAGhIrUuvO4tq3txherNH3AZA/2z+2+1RyzdY7ujG1Jwhv0EpdwfgLBK97reR3NpdCqqY3JktzQ00h6H5vBwEEmvKaKVt28V0dc8vvP3GKHE5zsMEs97m4ls09FUlXm6V+jNteNtVEkZ/a7DPgBi19Qlx0KI19hKfTCx16X7kW7I0qUN99oUdeUM1l7RkbwfRgzWB/le+nwd1yIQZoF8vlYrV6GKMvjcMGPUqyqPudzhU7XNfwZXCwPpfjKjH36zg+jFQUEj/Br4vU2CG6go8Ra4DOFKP5Rh2q3X4i0deSg4wHu3lwZQ7GuwGKsY9HF5nOM3EjtNnaD/ihKfy2kJUHekjM/aR0ihPkJ2GEcJJhFOAoHmVWdLu9Qzd4A+R3naM0TOLsTiDf+I6k052Q3vnIE6EtruZI0hEjPw7m7DXr2Q0kUphnk7q7AWDqdoy2znEroNWPfFfLmt2kGCtRwYsaioJtzQjGTRyOoB+sXPE8N5PcDZXxZjQLtGe1cPJp43x1U5qROEZdQIT/Ggyw24ahkJL4JcEAxf443dQN/pPg5S8=&lt;/diagram&gt;&lt;/mxfile&gt;">
<defs/>
<g>
<rect x="0" y="0" width="490" height="260" fill="rgb(255, 255, 255)" stroke="#6e6e6e" pointer-events="none"/>
<rect x="198.53" y="44.87" width="219.66" height="185.13" fill="rgb(255, 255, 255)" stroke="#e3e3e3" pointer-events="none"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 218px; height: 1px; padding-top: 137px; margin-left: 200px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">
Content
</div>
</div>
</div>
</foreignObject>
<text x="308" y="141" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
Content
</text>
</switch>
</g>
<rect x="0" y="0" width="490" height="44.87" fill="#deedff" stroke="#6e6e6e" pointer-events="none"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 488px; height: 1px; padding-top: 22px; margin-left: 1px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">
Titlebar (Navigation + Search)
</div>
</div>
</div>
</foreignObject>
<text x="245" y="26" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
Titlebar (Navigation + Search)
</text>
</switch>
</g>
<rect x="0" y="44.87" width="126.73" height="185.13" fill="#f7f7f7" stroke="#6e6e6e" pointer-events="none"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 125px; height: 1px; padding-top: 137px; margin-left: 1px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">
Sidebar (Navigation)
</div>
</div>
</div>
</foreignObject>
<text x="63" y="141" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
Sidebar (Navigation)
</text>
</switch>
</g>
<rect x="0" y="226.67" width="490" height="33.33" fill="rgb(255, 255, 255)" stroke="#6e6e6e" pointer-events="none"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 488px; height: 1px; padding-top: 243px; margin-left: 1px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">
Footer (Breadcrumbs)
</div>
</div>
</div>
</foreignObject>
<text x="245" y="247" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
Footer (Breadcrumbs)
</text>
</switch>
</g>
<rect x="371.72" y="14.87" width="101.38" height="16.67" rx="2.5" ry="2.5" fill="rgb(255, 255, 255)" stroke="#6e6e6e" pointer-events="none"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 99px; height: 1px; padding-top: 23px; margin-left: 373px;">
<div data-drawio-colors="color: #262626; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(38, 38, 38); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">
Search
</div>
</div>
</div>
</foreignObject>
<text x="422" y="27" fill="#262626" font-family="Helvetica" font-size="12px" text-anchor="middle">
Search
</text>
</switch>
</g>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 32px; height: 1px; padding-top: 23px; margin-left: 19px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;">
<div style="display: inline-block; font-size: 20px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">
<font color="#262626">
Title
</font>
</div>
</div>
</div>
</foreignObject>
<text x="19" y="29" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="20px">
Tit...
</text>
</switch>
</g>
</g>
<switch>
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
<a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank">
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
Text is not SVG - cannot display
</text>
</a>
</switch>
</svg>

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@@ -0,0 +1,102 @@
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="491px" height="261px" viewBox="-0.5 -0.5 491 261" content="&lt;mxfile&gt;&lt;diagram id=&quot;6E4AiNPWWr3a8GvC3Ypl&quot; name=&quot;Page-1&quot;&gt;xZZNj5swEIZ/DdL2gjAGA8cmm7SX9pJKPTvBAasGU8f56q/vOJjFLOxqpbC7WIrMO/5gnhlP7OFldfmmaFP+kDkTXhjkFw8/emGYogR+jXBthSRJW6FQPG8l1Asb/o9ZMbDqkefsMBiopRSaN0NxJ+ua7fRAo0rJ83DYXorhrg0t2EjY7KgYq795rkvrVhz0+nfGi7LbGQXWUtFusBUOJc3l2ZHwysNLJaVue9VlyYRh13Fp561fsD59mGK1ftOErJ1xouJonbMfpq+dt4WSx2a8sN3rxJRmlynsdNut0HsGGcFkxbS6wrhzzy7KLJDS4RYSK1Ibr+Jpbu8SdKxX0x6+wUHwr86ZGR94eHEuuWabhu6M9Qz5C1qpK1j/EUH3oJX8w5ZSSHWbjcnKNLBMIMpeYPRJLLrz48BYylqb752XyerW7mXSWbPUj8Osf2z1sMUDEZ9YxYEIs3xCJjhi7GM8A0o0QrmBorSlyjPpTgTst9jCCylM7+EX14DWmIBJ8JOeeEE1l/WX+8jvuRAO93Vi2odkKQqJn4TvlajhiO4aaiIzcB8WitF8p45Vc7iT3jtRuriEIoSTDKMARzEe5C2Qggx1n1ESY4L9MIlTEgYkzUgcj3Hf0tl9yAz08Ti3GVW78hXa6B7aeyhCjh4S02aLApQHJwrpsHpEaBiEcSVBAfK7yVEK4cjGUUDPQ5nOEIVo4p+rrSuG1+1/tkNG/h7NjWHRw3OktgLZAtQuAHu3a7S2UVyBrX4teLWs2bPqYyUqeFHDq2B7s4KJE4eL01crVzzPzSaTuTI8u+YD7dUvDD4mGRCaDqN7JLHv5kJKJs7kDNkAr/0l8GZzbtJ49R8=&lt;/diagram&gt;&lt;/mxfile&gt;">
<defs/>
<g>
<rect x="0" y="0" width="490" height="260" fill="rgb(255, 255, 255)" stroke="#6e6e6e" pointer-events="none"/>
<rect x="198.53" y="16.67" width="219.66" height="233.33" fill="rgb(255, 255, 255)" stroke="#e3e3e3" pointer-events="none"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 218px; height: 1px; padding-top: 133px; margin-left: 200px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">
Content
</div>
</div>
</div>
</foreignObject>
<text x="308" y="137" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
Content
</text>
</switch>
</g>
<rect x="0" y="0" width="126.72" height="260" fill="#f7f7f7" stroke="#6e6e6e" pointer-events="none"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 125px; height: 1px; padding-top: 130px; margin-left: 1px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">
Sidebar
<br/>
(Title + Navigation)
</div>
</div>
</div>
</foreignObject>
<text x="63" y="134" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
Sidebar...
</text>
</switch>
</g>
<rect x="126.72" y="226.67" width="363.28" height="33.33" fill="rgb(255, 255, 255)" stroke="#6e6e6e" pointer-events="none"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 361px; height: 1px; padding-top: 243px; margin-left: 128px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">
Footer (Breadcrumbs)
</div>
</div>
</div>
</foreignObject>
<text x="308" y="247" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">
Footer (Breadcrumbs)
</text>
</switch>
</g>
<rect x="12.67" y="41.67" width="101.38" height="16.67" rx="2.5" ry="2.5" fill="rgb(255, 255, 255)" stroke="#6e6e6e" pointer-events="none"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 99px; height: 1px; padding-top: 50px; margin-left: 14px;">
<div data-drawio-colors="color: #262626; " style="box-sizing: border-box; font-size: 0px; text-align: center;">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(38, 38, 38); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">
Search
</div>
</div>
</div>
</foreignObject>
<text x="63" y="54" fill="#262626" font-family="Helvetica" font-size="12px" text-anchor="middle">
Search
</text>
</switch>
</g>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 32px; height: 1px; padding-top: 20px; margin-left: 15px;">
<div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;">
<div style="display: inline-block; font-size: 20px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">
<font color="#262626">
Title
</font>
</div>
</div>
</div>
</foreignObject>
<text x="15" y="26" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="20px">
Tit...
</text>
</switch>
</g>
</g>
<switch>
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
<a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank">
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
Text is not SVG - cannot display
</text>
</a>
</switch>
</svg>

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@@ -0,0 +1,169 @@
#pragma once
#include <string>
namespace MyLibrary {
enum Color { red = 1, green = 2, blue = 3 };
/**
* @brief Example class to demonstrate the features of the custom CSS.
*
* @author jothepro
*
*/
class Example {
public:
/**
* @brief brief summary
*
* doxygen test documentation
*
* @param test this is the only parameter of this test function. It does nothing!
*
* # Supported elements
*
* These elements have been tested with the custom CSS.
*
* ## Tables
*
* <div class="tabbed">
*
* - <b class="tab-title">Basic</b>
* This theme supports normal markdown tables:<br>
* | Item | Title | Description | More |
* |-----:|-------|-----------------------|--------------------------------------------|
* | 1 | Foo | A placeholder | Some lorem ipsum to make this table wider. |
* | 2 | Bar | Also a placeholder | More lorem ipsum. |
* | 3 | Baz | The third placeholder | More lorem ipsum. |
* - <b class="tab-title">Centered</b>
* <center>
* A table can be centered with the `<center>` html tag:<br>
* | Item | Title | Description | More |
* |-----:|-------|-----------------------|--------------------------------------------|
* | 1 | Foo | A placeholder | Some lorem ipsum to make this table wider. |
* | 2 | Bar | Also a placeholder | More lorem ipsum. |
* | 3 | Baz | The third placeholder | More lorem ipsum. |
* </center>
* - <b class="tab-title">Stretched</b>
* A table wrapped in `<div class="full_width_table">` fills the full page width.
* <div class="full_width_table">
* | Item | Title | Description | More |
* |-----:|-------|-----------------------|--------------------------------------------|
* | 1 | Foo | A placeholder | Some lorem ipsum to make this table wider. |
* | 2 | Bar | Also a placeholder | More lorem ipsum. |
* | 3 | Baz | The third placeholder | More lorem ipsum. |
* </div>
* **Caution**: This will break the overflow scrolling support!
* - <b class="tab-title">Complex</b>
* Complex [Doxygen tables](https://www.doxygen.nl/manual/tables.html) are also supported as seen in @ref multi_row "this example":<br>
* <table>
* <caption id="multi_row">Complex table</caption>
* <tr><th>Column 1 <th>Column 2 <th>Column 3
* <tr><td rowspan="2">cell row=1+2,col=1<td>cell row=1,col=2<td>cell row=1,col=3
* <tr><td rowspan="2">cell row=2+3,col=2 <td>cell row=2,col=3
* <tr><td>cell row=3,col=1 <td>cell row=3,col=3
* </table>
* - <b class="tab-title">Overflow Scrolling</b> The table content is scrollable if the table gets too wide.<br>
* | first_column | second_column | third_column | fourth_column | fifth_column | sixth_column | seventh_column | eighth_column | ninth_column |
* |--------------|---------------|--------------|---------------|--------------|--------------|----------------|---------------|--------------|
* | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
* - <b class="tab-title">Images</b>A table can contain images:<br>
* | Column 1 | Column 2 |
* |---------------------------|-------------------------------------------------|
* | ![doxygen](testimage.png) | ← the image should not be inverted in dark-mode |
*
*
* </div>
*
* ## Diagrams
*
* Graphviz diagrams support dark mode and can be scrolled once they get too wide:
*
* \dot Graphviz with a caption
* digraph example {
* node [fontsize="12"];
* rankdir="LR"
* a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k;
* }
* \enddot
*
* ## Lists
*
* - element 1
* - element 2
*
* 1. element 1
* ```
* code in lists
* ```
* 2. element 2
*
* ## Quotes
*
* > Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
* > ut labore et dolore magna aliqua. Vitae proin sagittis nisl rhoncus mattis rhoncus urna neque viverra.
* > Velit sed ullamcorper morbi tincidunt ornare.
* >
* > Lorem ipsum dolor sit amet consectetur adipiscing elit duis.
* *- jothepro*
*
* ## Code block
*
* ```cpp
* auto x = "code within md fences";
* ```
*
* @code{.cpp}
* // code within @code block
* while(true) {
* auto example = std::make_shared<Example>(5);
* example->test("test");
* }
* @endcode
*
* // code within indented code block
* auto test = std::shared_ptr<Example(5);
*
*
* Inline `code` elements in a text. *Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.* This also works within multiline text and does not break the `layout`.
*
*
* ## Special hints
*
* @warning this is a warning only for demonstration purposes
*
* @note this is a note to show that notes work. They can also include `code`:
* @code{.c}
* void this_looks_awesome();
* @endcode
*
* @bug example bug
*
* @deprecated None of this will be deprecated, because it's beautiful!
*
* @invariant This is an invariant
*
* @pre This is a precondition
*
* @post This is a postcondition
*
* @todo This theme is never finished!
*
* @remark This is awesome!
*
*/
std::string test(const std::string& test);
virtual int virtualfunc() = 0;
static bool staticfunc();
};
class SecondExample {
std::string foo();
}
}

View File

@@ -0,0 +1,46 @@
#pragma once
#include <string>
#include "example.hpp"
#include <iostream>
namespace MyLibrary {
/**
* @brief some subclass
*/
template<typename TemplatedClass>
class SubclassExample : public Example {
public:
/**
* @bug second bug
* @return
*/
int virtualfunc() override;
/**
* @brief Template function function
*/
template <typename T>
std::shared_ptr<std::string> function_template_test(std::shared_ptr<T>& param);
/**
* @brief Extra long function with lots of parameters and many template types.
*
* Also has a long return type.
*
* @param param1 first parameter
* @param param2 second parameter
* @param parameter3 third parameter
*/
template <typename T, typename Foo, typename Bar, typename Alice, typename Bob, typename Charlie, typename Hello, typename World>
std::pair<std::string, std::string> long_function_with_many_parameters(std::shared_ptr<T>& param1, std::shared_ptr<std::string>& param2, bool parameter3, Alice paramater4 Bob parameter 5) {
if(true) {
std::cout << "this even has some code." << std::endl;
}
}
};
}

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="61px" height="74px" viewBox="-0.5 -0.5 61 74" content="&lt;mxfile host=&quot;drawio-plugin&quot; modified=&quot;2021-03-16T23:58:23.462Z&quot; agent=&quot;5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36&quot; version=&quot;13.7.9&quot; etag=&quot;JoeaGLJ54FcERO7YrWLQ&quot; type=&quot;embed&quot;&gt;&lt;diagram id=&quot;JMB9aH8b_oZ7EWDuqJgx&quot; name=&quot;Page-1&quot;&gt;7VdNc5swEP01HDsjkGPDsSVJe+lMZnzoWYENaAwsI8ux6a+vCCtA4KSu62kmSS+M9LT7tB9P0uDxuDx8VaLOv2MKhRew9ODxay8Igigy3xZoCOC8AzIl0w7yB2AtfwKBjNCdTGHrGGrEQsvaBROsKki0gwmlcO+aPWDh7lqLDGbAOhHFHP0hU513aHjFBvwbyCy3O/uMVkphjQnY5iLF/QjiNx6PFaLuRuUhhqKtna1L53f7zGofmIJKn+RAcTyKYkfJUWC6sdlmCnc1mYHScDhWY3Fvzdk8Br/PzCgCsAStGmNCRJy2JDH4pIV8VMG+edS4rCcZcjMDSu+ZVP3fpwpV+rnVh5ndF5hsPP4l16VhvPbN8AErTWI0re7mMRaonpw5Y8tlHBvcsNzKwnpttVDaslZYgcXIhj3NFW56LS1bbrM44l6m4Wq5MLhxzEDfgZKmAKDWtUhklRFNgqVM7LYb0Enu8I9j9dkVC80KtgS6Lb3fGnYVgXSm/1Ez2fFu7oeTYA/CuIUWU1AILR9d/mN9pR3uUJqde7F88leOWhYLl2GLO5UAOY2FP+GxMm3c6CwNlXlKY9oompFZ3Rps59EOkuw8BoH2BTtNs8EfaZbUdYZkXQGuXhDgR9DYRBycXURj00D+UmMT2ktJLnr9B8HG0IzFcPkHYfUe3oPZqfOjMEiDs1+KEw5n9P/+/1f3f/gq1394lt7erqQ+0HVvpsPPRWc+/KHxm18=&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><path d="M 13 57 L 13.01 57.01 L 15.87 50.14 L 18.37 43.14 L 20.91 36.15 L 23.67 29.25 L 26.4 22.33 Q 30 13 33.71 22.28 L 33.55 22.22 L 35.48 26.91 L 37.49 31.64 L 39.48 36.36 L 41.2 40.97 L 43.05 45.63" fill="none" stroke="#010508" stroke-opacity="0.1" stroke-width="6" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 47.51 56.77 L 47.65 56.93 L 45.43 54.91 L 43.41 53.11 L 41.43 51.35 L 39.63 49.8 L 37.48 47.86 L 37.39 47.64 L 39.79 47.17 L 41.9 45.98 L 44.24 45.37 L 46.48 44.52 L 48.62 43.4 L 48.54 43.39 L 48.58 46.09 L 48.04 48.74 L 48.04 51.43 L 47.8 54.1 L 47.51 56.77 Z Z" fill-opacity="0.1" fill="#010508" stroke="#010508" stroke-opacity="0.1" stroke-width="6" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><path d="M 10 43 L 9.94 42.88 L 12.16 41.98 L 14.31 40.96 L 16.51 40.01 L 18.62 38.89 L 20.88 38.1 Q 30 34 40 34 L 40 33.75 L 42 33.83 L 44 33.8 L 46 33.79 L 48 34.05 L 50 34" fill="none" stroke="#010508" stroke-opacity="0.1" stroke-width="7" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 10 54 L 9.97 53.99 L 12.69 47.07 L 15.43 40.16 L 18.07 33.21 L 20.65 26.24 L 23.4 19.33 Q 27 10 30.71 19.28 L 30.66 19.26 L 32.46 23.91 L 34.55 28.66 L 36.26 33.27 L 38.35 38.03 L 40.05 42.63" fill="none" stroke="#1982d2" stroke-width="6" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 44.51 53.77 L 44.56 53.83 L 42.48 51.97 L 40.5 50.21 L 38.48 48.41 L 36.41 46.56 L 34.48 44.86 L 34.55 45.02 L 36.72 44 L 39 43.24 L 41.21 42.28 L 43.48 41.51 L 45.62 40.4 L 45.78 40.42 L 45.51 43.09 L 45.01 45.74 L 44.87 48.42 L 44.94 51.12 L 44.51 53.77 Z Z" fill="#1982d2" stroke="#1982d2" stroke-width="6" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><path d="M 7 40 L 7.02 40.05 L 9.28 39.25 L 11.33 38 L 13.48 36.96 L 15.73 36.14 L 17.88 35.1 Q 27 31 37 31 L 37 30.79 L 39 31.11 L 41 30.85 L 43 30.78 L 45 30.89 L 47 31" fill="none" stroke="#1982d2" stroke-width="8" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/></g></svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,34 @@
{
"name": "@jothepro/doxygen-awesome-css",
"version": "2.3.4",
"description": "Custom CSS theme for doxygen html-documentation with lots of customization parameters.",
"main": "",
"scripts": {
"npm-pack": "npm pack",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/jothepro/doxygen-awesome-css.git"
},
"homepage": "https://jothepro.github.io/doxygen-awesome-css/",
"bugs": {
"url": "https://github.com/jothepro/doxygen-awesome-css/issues"
},
"keywords": [
"doxygen",
"css",
"theme",
"awesome"
],
"author": {
"name": "jothepro",
"url": "https://github.com/jothepro",
"git": "https://github.com/jothepro/doxygen-awesome-css"
},
"license": "MIT",
"config": {},
"dependencies": {},
"devDependencies": {},
"xpack": {}
}

View File

@@ -1,44 +0,0 @@
// SPDX-FileCopyrightText: 2025 Martin Leutelt <martin.leutelt@basyskom.com>
// SPDX-FileCopyrightText: 2025 basysKom GmbH
//
// SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick
import QtQuick.Controls
Control {
id: container
required property int column
required property var model
property int sortOrder: Qt.AscendingOrder
signal clicked(int sortOrder)
padding: 8
background: Rectangle {
color: tapHandler.pressed ? "gray" : "lightgray"
TapHandler {
id: tapHandler
onTapped: {
if (container.sortOrder === Qt.AscendingOrder) {
container.sortOrder = Qt.DescendingOrder
} else {
container.sortOrder = Qt.AscendingOrder
}
container.clicked(container.sortOrder)
}
}
}
contentItem: Label {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
text: container.model.display
}
}

View File

@@ -1,26 +0,0 @@
import QtQuick
import QtQuick.Controls
Control {
id: container
required property int row
required property var model
padding: 8
background: Rectangle {
color: tapHandler.pressed ? "gray" : "lightgray"
TapHandler {
id: tapHandler
}
}
contentItem: Label {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
text: container.model.display
}
}

View File

@@ -1,161 +0,0 @@
// SPDX-FileCopyrightText: 2025 Martin Leutelt <martin.leutelt@basyskom.com>
// SPDX-FileCopyrightText: 2025 basysKom GmbH
//
// SPDX-License-Identifier: LGPL-3.0-or-later
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
ApplicationWindow {
width: 640
height: 480
visible: true
title: Application.displayName
header: ToolBar {
ColumnLayout {
RowLayout {
Label {
text: "Rows"
}
SpinBox {
id: rowSettings
from: 1
to: 20
}
ToolSeparator {}
Label {
text: "Columns"
}
SpinBox {
id: columnSettings
from: 1
to: 20
}
ToolSeparator {}
CheckBox {
id: movableColumnsSetting
text: "Movable columns"
}
ToolSeparator {}
CheckBox {
id: resizableColumnsSetting
text: "Resizable columns"
}
}
RowLayout {
Label {
text: "Selection"
}
ComboBox {
id: selectionSetting
textRole: "text"
valueRole: "value"
model: [
{ text: "disabled", value: TableView.SelectionDisabled },
{ text: "by cells", value: TableView.SelectCells },
{ text: "by rows", value: TableView.SelectRows },
{ text: "by columns", value: TableView.SelectColumns }
]
onCurrentIndexChanged: tableView.selectionModel.clear()
}
Label {
text: "Longpress to start selection, modify selection with CTRL/SHIFT of by mouse"
visible: selectionSetting.currentIndex > 0
}
}
}
}
Rectangle {
id: tableBackground
anchors.fill: parent
color: Application.styleHints.colorScheme === Qt.Light ? palette.mid : palette.midlight
HorizontalHeaderView {
id: horizontalHeader
anchors.left: tableView.left
anchors.top: parent.top
syncView: tableView
movableColumns: movableColumnsSetting.checked
resizableColumns: resizableColumnsSetting.checked
clip: true
boundsBehavior: tableView.boundsBehavior
delegate: HorizontalHeaderViewDelegate {
onClicked: (sortOrder) => tableView.model.sort(column, sortOrder)
}
}
VerticalHeaderView {
id: verticalHeader
anchors.top: tableView.top
anchors.left: parent.left
syncView: tableView
clip: true
boundsBehavior: tableView.boundsBehavior
delegate: VerticalHeaderViewDelegate {}
}
TableView {
id: tableView
anchors.left: verticalHeader.right
anchors.top: horizontalHeader.bottom
anchors.right: parent.right
anchors.bottom: parent.bottom
clip: true
columnSpacing: 1
rowSpacing: 1
rowHeightProvider: (row) => 40
boundsBehavior: TableView.StopAtBounds
selectionModel: ItemSelectionModel {}
selectionBehavior: selectionSetting.currentValue
model: SortFilterModel {
sourceModel: TableModel {
columns: columnSettings.value
rows: rowSettings.value
// when adding a new column its width isn't properly applied to the header, so we do that manually
onColumnsInserted: {
if (columns > 1) {
horizontalHeader.setColumnWidth(columns - 1, tableView.implicitColumnWidth(columns - 1))
}
}
}
}
delegate: TableViewDelegate {
implicitWidth: tableView.width / columnSettings.to
}
ScrollBar.horizontal: ScrollBar {}
ScrollBar.vertical: ScrollBar {}
}
SelectionRectangle {
target: tableView
}
}
}

View File

@@ -1,45 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Window
ApplicationWindow
{
visible: true
width: 600
height: 400
title: "TableView mit myChildModel"
TreeView
{
anchors.fill: parent
clip: true
columnSpacing: 1
rowSpacing: 1
model: myChildModel
delegate: Rectangle
{
implicitWidth: 150
implicitHeight: 40
border.color: "#cccccc"
//color: index % 2 === 0 ? "#f9f9f9" : "#e0e0e0"
Text {
anchors.centerIn: parent
text: display
font.pixelSize: 14
}
}
ScrollBar.horizontal: ScrollBar {}
ScrollBar.vertical: ScrollBar {}
}
}

View File

@@ -1,65 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Window
{
width: 640
height: 480
visible: true
title: qsTr("StringListModel")
TableView
{
id: childTableView
anchors.fill: parent
model: myChildModel // z.B. QStandardItemModel mit 9 Spalten
delegate: Rectangle
{
required property string display
//height: 5
//width: childTableView.width
color : "blue"
border.color: "#ccc"
width: childTableView.width;
RowLayout
{
anchors.fill: parent
anchors.margins: 2
TextField
{
text : display
font.pixelSize: 10
Layout.fillWidth: true
background: Rectangle
{
color : "white"
}
onEditingFinished:
{
console.log("Editing finished, new text is :"+ text + " at index :" + index)
model.names = text //The roles here are defined in model class
}
}
}
}
ScrollBar.horizontal: ScrollBar {}
ScrollBar.vertical: ScrollBar {}
// // Optional: Spaltenbreiten setzen
// onModelChanged: {
// for (let i = 0; i < model.columns; ++i)
// table.setColumnWidth(i, 100)
// }
}
}

83
qml/xqtreeview.qml Normal file
View File

@@ -0,0 +1,83 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
TreeView
{
anchors.fill: parent
clip: true
columnSpacing: 1
rowSpacing: 1
model: xtrChildModel
columnWidthProvider: function(column)
{
var z= 1.7*(width / columns);
return z;
}
delegate: Rectangle
{
required property int row
required property int column
required property var model
border.width: 0
implicitWidth: 30
implicitHeight: 20
border.color: "#cccccc"
//color: index % 2 === 0 ? "#f9f9f9" : "#e0e0e0"
//color: TreeView.isSelected ? "#d0eaff" : (row % 2 === 0 ? "#f9f9f9" : "#ffffff")
//color: TreeView.isSelected ? "#d0eaff" : (row % 2 === 0 ? "#f9f9f9" : "#ffffff")
TextField
{
id: currentEntry
anchors.centerIn: parent
text: display
font.pixelSize: 12
// Ändere die Border-Farbe je nachdem, ob das Feld den Fokus hat
property color borderColor: currentEntry.activeFocus ? "dodgerblue" : "gray"
property int borderWidth: currentEntry.activeFocus ? 2 : 1
background: Rectangle {
// Die Farbe des Hintergrunds im Normalzustand
color: "#ffffff"
// Hier werden Rahmenfarbe und -breite definiert
border.color: currentEntry.borderColor
border.width: currentEntry.borderWidth
// Abgerundete Ecken für ein modernes Aussehen
radius: 4
// Sanfter Übergang der Rahmenfarbe und -breite
Behavior on border.color {
ColorAnimation { duration: 150 }
}
Behavior on border.width {
NumberAnimation { duration: 150 }
}
}
onEditingFinished:
{
console.log("Editing finished, new text is :"+ text + " at index :" + index)
model.display = text //The roles here are defined in model class
}
}
}
ScrollBar.horizontal: ScrollBar {}
ScrollBar.vertical: ScrollBar {}
}

View File

@@ -38,6 +38,7 @@ const QString c_ProjectID = "ProjectID";
const QString c_ModelSheetFileName = "xml/modelsheets.xml"; const QString c_ModelSheetFileName = "xml/modelsheets.xml";
const QString c_ModelDummyFileName = "xml/saved_testfile.xtr"; const QString c_ModelDummyFileName = "xml/saved_testfile.xtr";
const QString c_DocumentDirectory = "xml/"; const QString c_DocumentDirectory = "xml/";
const QString c_DocumentFileName1 = "xml/modeldata1.xtr"; const QString c_DocumentFileName1 = "xml/modeldata1.xtr";
const QString c_DocumentFileName2 = "xml/modeldata2.xtr"; const QString c_DocumentFileName2 = "xml/modeldata2.xtr";
const QString c_DocumentFileName3 = "xml/modeldata3.xtr"; const QString c_DocumentFileName3 = "xml/modeldata3.xtr";

View File

@@ -36,10 +36,6 @@ XQChildModel::XQChildModel( QObject *parent )
void XQChildModel::addModelData( const XQNodePtr& contentRoot ) void XQChildModel::addModelData( const XQNodePtr& contentRoot )
{ {
// __fix: set object name ??
qDebug() << " --- create Model Data: " << contentRoot->to_string();
// Die Datenbasis als shared_ptr sichern // Die Datenbasis als shared_ptr sichern
_contentRoot = contentRoot; _contentRoot = contentRoot;
@@ -50,70 +46,81 @@ void XQChildModel::addModelData( const XQNodePtr& contentRoot )
// Das ist hier der Typ des Eintrags: Panel, Battery ... // Das ist hier der Typ des Eintrags: Panel, Battery ...
QString key = contentEntry->tag_name(); QString key = contentEntry->tag_name();
// 'silent failure' hier der Datenbaum kann auch Knoten enthalten // 'silent failure' hier der Datenbaum kann auch Knoten enthalten
// die nicht für uns gedacht sind. // die nicht für uns gedacht sind.
if (!_sections.hasValidSection(key)) if (!_sections.hasValidSection(key))
continue; continue;
XQModelSection& section = _sections.at( key ); const XQModelSection& section = _sections.sectionByKey( key );
// wir speichern das parent des datenknoten auch in der
// section.
// contentEntry->parent == _contentRoot, aber halt nur weil das model flach ist
//qDebug() << " --- add section ENTRY: " << key << " TagName: " << contentEntry->attribute("TagName");
section.setContentRootNode( contentEntry->parent() ); section.setContentRootNode( contentEntry->parent() );
int newRow = _sections.lastRow(section); int newRow = _sections.lastRow(section);
XQNodePtr sheetNode = section.sheetRootNode(); XQNodePtr sheetNode = section.sheetRootNode();
XQItemList list = _itemFactory.makeRow( XQItemFactory::mData, sheetNode, contentEntry ); XQItemList list = _itemFactory.makeRow( sheetNode, contentEntry );
// als Baum? // als Baum?
//section.headerItem().appendRow( list ); //section.headerItem().appendRow( list );
insertRow( newRow, list);
// _hinter_ der letzen zeile einfügen
insertRow( newRow+1, list);
if( contentEntry->has_children())
{
qDebug() << " --- AddModelData: CHILD Found for: :" << contentEntry->tag_name() << " sheet parent: " << sheetNode->tag_name();
if( !sheetNode->has_children() )
qDebug() << " --- AUA";
//else
}
} // for } // for
} }
//! Erzeugt eine model-section und fügt den zugehörigen header ein.
void XQChildModel::addSectionEntry( const QString& key, const XQNodePtr& contentEntry ) void XQChildModel::addSectionEntry( const QString& key, const XQNodePtr& contentEntry )
{ {
XQModelSection& section = _sections.at( key ); const XQModelSection& section = _sections.sectionByKey( key );
if(section.isValid() ) if(section.isValid() )
{ {
section.setContentRootNode( contentEntry->parent() ); section.setContentRootNode( contentEntry->parent() );
int newRow = _sections.lastRow(section); int newRow =_sections.lastRow(section);
XQNodePtr sheetNode = section.sheetRootNode(); XQNodePtr sheetNode = section.sheetRootNode();
XQItemList list = _itemFactory.makeRow( XQItemFactory::mHeader, sheetNode, contentEntry ); XQItemList list = _itemFactory.makeRow( sheetNode, nullptr );
insertRow( newRow, list); insertRow( newRow, list);
} }
} }
//! erzeugt ein adhoc-contextmenu, je nachdem welche aktionen gerade möflich sind.
//! erzeugt ein adhoc-contextmenu, je nachdem welche aktionen gerade möglich sind.
void XQChildModel::initContextMenu() void XQChildModel::initContextMenu()
{ {
// __fixme! add a menu title // __fixme! add a menu title
_contextMenu->clear(); _contextMenu->clear();
const QModelIndex& curIdx = _treeTable->currentIndex(); const QModelIndex& curIdx = _treeTable->currentIndex();
bool hasSel = curIdx.isValid() && _treeTable->selectionModel()->hasSelection();
bool canPaste = _clipBoard.canPaste( curIdx );
_contextMenu->addAction( "icn11Dummy", "Undo", XQCommand::cmdUndo, _undoStack->canUndo() ); _contextMenu->addAction( "icn11Dummy", "Undo", XQCommand::cmdUndo, _undoStack->canUndo() );
_contextMenu->addAction( "icn17Dummy", "Redo", XQCommand::cmdRedo, _undoStack->canRedo() ); _contextMenu->addAction( "icn17Dummy", "Redo", XQCommand::cmdRedo, _undoStack->canRedo() );
_contextMenu->addAction( "icn58Dummy", "Cut", XQCommand::cmdCut, hasSel ); // editieren nur wenns kein header ist.
_contextMenu->addAction( "icn61Dummy", "Paste", XQCommand::cmdPaste, canPaste ); if ( !xqItemFromIndex(curIdx).isHeaderStyle() )
_contextMenu->addAction( "icn55Dummy", "Copy", XQCommand::cmdCopy, hasSel ); {
//_contextMenu->addAction( "icn35Dummy", "Move", XQCommand::cmdMove, hasSel ); bool hasSel = curIdx.isValid() && _treeTable->selectionModel()->hasSelection();
_contextMenu->addAction( "icn70Dummy", "New", XQCommand::cmdNew, hasSel ); bool canPaste = _clipBoard.canPaste( curIdx );
_contextMenu->addAction( "icn50Dummy", "Delete", XQCommand::cmdDelete, hasSel );
_contextMenu->addAction( "icn58Dummy", "Cut", XQCommand::cmdCut, hasSel );
_contextMenu->addAction( "icn61Dummy", "Paste", XQCommand::cmdPaste, canPaste );
_contextMenu->addAction( "icn55Dummy", "Copy", XQCommand::cmdCopy, hasSel );
//_contextMenu->addAction( "icn35Dummy", "Move", XQCommand::cmdMove, hasSel );
_contextMenu->addAction( "icn70Dummy", "New", XQCommand::cmdNew, hasSel );
_contextMenu->addAction( "icn50Dummy", "Delete", XQCommand::cmdDelete, hasSel );
}
// __fixme! set 'toggle section <name>' entry // __fixme! set 'toggle section <name>' entry
//contextMenu.actions().first()->setText("<name>"); //contextMenu.actions().first()->setText("<name>");
_contextMenu->addAction( "icn29Dummy", "Toggle Section", XQCommand::cmdToggleSection, hasSel); _contextMenu->addAction( "icn29Dummy", "Hide Section", XQCommand::cmdToggleSection, true );
} }

View File

@@ -18,8 +18,8 @@
//! erzeugt ein docukument //! erzeugt ein docukument
XQDocument::XQDocument(const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aModelView ) XQDocument::XQDocument(const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aViewModel )
: fileName{ aFileName }, friendlyName{ aFriendlyName }, treeItem{ aTreeItem }, modelView{ aModelView } : fileName{ aFileName }, friendlyName{ aFriendlyName }, treeItem{ aTreeItem }, viewModel{ aViewModel }
{ {
} }
@@ -44,9 +44,9 @@ XQDocumentStore::~XQDocumentStore()
//! erzeugt ein document eintrag //! erzeugt ein document eintrag
void XQDocumentStore::addDocument( const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aModelView ) void XQDocumentStore::addDocument(const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aViewModel )
{ {
XQDocument newDocument( aFileName, aFriendlyName, aTreeItem, aModelView ); XQDocument newDocument( aFileName, aFriendlyName, aTreeItem, aViewModel );
addAtKey( aFileName, newDocument ); addAtKey( aFileName, newDocument );
// attention: this assumes the presence of the 'ProjectID' value // attention: this assumes the presence of the 'ProjectID' value
//addAlias( aFileName, aTreeItem->attribute(c_ProjectID) ); //addAlias( aFileName, aTreeItem->attribute(c_ProjectID) );

View File

@@ -28,12 +28,10 @@ struct XQDocument
XQDocument() = default; XQDocument() = default;
XQDocument( const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aModelView ); XQDocument( const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aModelView );
virtual ~XQDocument() = default;
QString fileName; // also used as key QString fileName; // also used as key
QString friendlyName; QString friendlyName;
XQItem* treeItem{}; XQItem* treeItem{};
XQViewModel* modelView{}; XQViewModel* viewModel{};
}; };
@@ -46,11 +44,7 @@ public:
XQDocumentStore() = default; XQDocumentStore() = default;
virtual ~ XQDocumentStore(); virtual ~ XQDocumentStore();
void addDocument( const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aModelView ); void addDocument( const QString& aFileName, const QString& aFriendlyName, XQItem* aTreeItem, XQViewModel* aViewModel );
protected:
XQNode _treeRootNode{ "treeRootNode" };
}; };

View File

@@ -45,57 +45,36 @@ void XQMainModel::initContextMenu()
XQItem* XQMainModel::addProjectItem( XQNodePtr contentNode ) XQItem* XQMainModel::addProjectItem( XQNodePtr contentNode )
{ {
// wir durchsuchen alle unsere section nach dem passenden content-type, // wir durchsuchen alle unsere sections nach dem passenden content-type,
// hier: content-type beschreibt die // hier: content-type beschreibt den projekt-status
const QString& sectionKey = contentNode->attribute(c_ContentType);
for(const auto& section : _sections ) if( _sections.hasValidSection( sectionKey ) )
{ {
const XQModelSection& section = _sections.sectionByKey( sectionKey );
// __fixme! das ist mist!
const XQNodePtr sheetNode = section.sheetRootNode()->first_child();
XQItem* newItem = _itemFactory.makeSingleItem( sheetNode, contentNode->attribute( "ProjectName") );
if( contentNode->attribute( c_ContentType) == section.contentType() ) // den neuen eintrag in die passende section der übersicht eintragen ...
{ section.headerItem().appendRow( newItem );
// erzeuger sheet node speichern
qDebug() << " --- add PROJECT: contentNode: " << contentNode->to_string(); newItem->setSheetNode( sheetNode );
expandNewItem(section.headerItem().index() );
// __fixme! das ist mist! return newItem;
const XQNodePtr sheetNode = section.sheetRootNode()->first_child();
XQItemList list = _itemFactory.makeRow( XQItemFactory::mSingle, sheetNode, contentNode, "ProjectName");
// den neuen eintrag in die passende section der übersicht eintragen ...
section.headerItem().appendRow( list );
// ... ausklappen...
const QModelIndex index = section.headerItem().index();
_treeTable->expand( index );
// ... und markieren
_treeTable->setCurrentIndex( index );
// quellknoten auch speichern
//newItem->setContentNode( contentNode );
//emit itemCreated( newItem );
XQItem* newItem = dynamic_cast<XQItem*>(list[0]);
// erzeuger sheet node speichern
newItem->setSheetNode( sheetNode );
return newItem;
}
} }
throw XQException( "addProjectItem: main model should not be empty!" ); throw XQException( "addProjectItem: main model should not be empty!" );
} }
//! erzeugt einen einzelen baum-eintrag mit hilfe der section und den projekt-daten
void XQMainModel::addSectionItem( const XQModelSection& section, XQItem* projectItem ) void XQMainModel::addSectionItem( const XQModelSection& section, XQItem* projectItem )
{ {
return;
// ich brauche _meine_ section für den sheetNode!
XQNodePtr sheetNode = projectItem->sheetNode()->find_child_by_tag_name("CurrentSection"); XQNodePtr sheetNode = projectItem->sheetNode()->find_child_by_tag_name("CurrentSection");
XQItemList list = _itemFactory.makeRow( XQItemFactory::mSingle, sheetNode, nullptr, c_ContentType ); XQItem* newItem = _itemFactory.makeSingleItem( sheetNode, section.contentType() );
projectItem->appendRow( list ); projectItem->appendRow( newItem );
_treeTable->expand( projectItem->index() ); expandNewItem(projectItem->index() );
} }

View File

@@ -35,6 +35,7 @@ public:
XQItem* addProjectItem( XQNodePtr contentNode ); XQItem* addProjectItem( XQNodePtr contentNode );
void addSectionItem( const XQModelSection& section, XQItem* projectItem ); void addSectionItem( const XQModelSection& section, XQItem* projectItem );
protected: protected:
void initContextMenu() override; void initContextMenu() override;

View File

@@ -88,36 +88,39 @@ void XQMainWindow::initMainWindow()
connect( _actionExit, &QAction::triggered, this, &XQMainWindow::onExit ); connect( _actionExit, &QAction::triggered, this, &XQMainWindow::onExit );
connect( _actionAbout, &QAction::triggered, this, &XQMainWindow::onAbout ); connect( _actionAbout, &QAction::triggered, this, &XQMainWindow::onAbout );
connect( _tabWidget, SIGNAL(tabBarClicked(int)), this, SLOT(onChildViewTabClicked(int)) );
//connect(&_mainModel, &QStandardItemModel::itemChanged, this, &XQMainWindow::onTreeItemChanged );
//connect( _mainTreeView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(onDoubleClicked(QModelIndex)) ); //connect( _mainTreeView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(onDoubleClicked(QModelIndex)) );
connect( _mainTreeView, SIGNAL(clicked(QModelIndex)), this, SLOT(onTreeItemClicked(QModelIndex)) ); //connect( _mainTreeView, SIGNAL(clicked(QModelIndex)), this, SLOT(onTreeItemClicked(QModelIndex)) );
connect( _tabWidget, SIGNAL(tabBarClicked(int)), this, SLOT(onTabClicked(int)) );
connect(&_mainModel, &XQViewModel::xqItemChanged, this, &XQMainWindow::onTreeViewItemChanged );
connect( _mainTreeView, &QTreeView::clicked, this, [&,this](const QModelIndex& index)
/*
connect( &_mainModelView, &XQViewModel::itemCreated, this, [=, this](XQItem* item)
{ {
// when a new main tree item has been created ... onTreeViewItemClicked( XQItem::xqItemFromIndex(index) );
QString pID = item->contentNode()->attribute(c_ProjectID); });
_mainTreeView->setCurrentIndex( item->index() );
// ... we set the current view to this node
if( _documentStore.contains( pID ) )
_tabWidget->setCurrentWidget( _documentStore[pID].modelView->treeTable() );
} );
*/
try try
{ {
// hand over undostack // hand over undostack
_mainModelView.setUndoStack(&_undoStack); _mainModel.setUndoStack(&_undoStack);
// hand over left side navigation tree // hand over left side navigation tree
_mainModelView.setTreeTable(_mainTreeView); _mainModel.setTreeTable(_mainTreeView);
// #1. init the left side main tree view // #1. init the left side main tree view
_mainModelView.initModel( c_MainModelName ); _mainModel.initModel( c_MainModelName );
// 1: Wiebelbach
// 2: Gerbrunn
// 3: TBB
// #2. load demo data // #2. load demo data
loadDocument( c_DocumentFileName1 ); loadDocument( c_DocumentFileName1 );
loadDocumentQML( c_DocumentFileName2 ); loadDocument( c_DocumentFileName2, true );
//loadDocument( c_DocumentFileName2 );
//loadDocument( c_DocumentFileName3 );
qDebug() << " --- all here: " << XQNode::s_Count; qDebug() << " --- all here: " << XQNode::s_Count;
@@ -131,9 +134,6 @@ void XQMainWindow::initMainWindow()
} }
//! slot für zentrales undo //! slot für zentrales undo
void XQMainWindow::onUndo() void XQMainWindow::onUndo()
@@ -235,7 +235,7 @@ void XQMainWindow::onAbout()
QMessageBox msgBox(QMessageBox::NoIcon, "About", "", QMessageBox::Ok); QMessageBox msgBox(QMessageBox::NoIcon, "About", "", QMessageBox::Ok);
QString text = "<b>xtree concept</b><br>"; QString text = "<b>xtree concept</b><br>";
text += "2024 c.holzheuer<br><br>"; text += "2024-2025 c.holzheuer<br><br>";
text += "<a href=\"https://sourceworx.org/xtree\">sourceworx.org/xtree</a>"; text += "<a href=\"https://sourceworx.org/xtree\">sourceworx.org/xtree</a>";
msgBox.setTextFormat(Qt::RichText); // This allows you to click the link msgBox.setTextFormat(Qt::RichText); // This allows you to click the link
@@ -245,66 +245,190 @@ void XQMainWindow::onAbout()
} }
//! wenn ein item im navigations-baum geklickt wird, soll die document //! wenn ein item im navigations-baum geklickt wird, soll die document
//! view rechts angepasst werden. //! view rechts angepasst werden.
void XQMainWindow::onTreeItemClicked(const QModelIndex& index ) void XQMainWindow::onTreeViewItemClicked( const XQItem& item )
{ {
//qDebug() << " --- Tree item CLICK:" << item.text() << " : " << item.itemType().text();
XQItem& entry = XQItem::xqItemFromIndex(index); if( item.itemType().text() == "TreeChildType" )
qDebug() << " --- XXX mainWindow onTreeItemClicked:" << entry.text();
_mainTreeView->selectionModel()->select(index, QItemSelectionModel::Select);
if( XQNodePtr contentNode = entry.contentNode() )
{ {
QString key = contentNode->attribute(c_ProjectID); setChildTabByName( item.text() );
qDebug() << " --- FIRZ: key: " << key;
bool isThere = _documentStore.contains(key);
if( isThere)
_tabWidget->setCurrentWidget( _documentStore[key].modelView->treeTable() );
} }
}
void XQMainWindow::onTreeViewItemChanged(const XQItem& item )
{
qDebug() << " --- TREE VIEW itemChanged: text" << item.text() << " parent: " << item.parent()->text() << " type: " << item.itemType().text() << " : " << (void*)&_mainModel << " : " << (void*) sender();
// hier müssen wir erst das projekt aktivieren
XQItem* xqItem = static_cast<XQItem*>(item.parent());
onTreeViewItemClicked( *xqItem );
//if( item.itemType().text() == "TreeSectionType" )
{
int idx = _tabWidget->currentIndex();
if(_documentStore.contains(idx) )
{
qDebug() << " --- Has Document and might toggle: " << item.text();
XQViewModel& childModel = *_documentStore[idx].viewModel;
childModel.onToggleSection(item.text());
}
}
} }
//! beim click auf ein tab im linken fenster wird der navigationsbaum angepasst. //! beim click auf ein tab im linken fenster wird der navigationsbaum angepasst.
void XQMainWindow::onTabClicked( int index ) void XQMainWindow::onChildViewTabClicked( int idx )
{ {
//const QString& key = _documentStore[index].treeItem->attribute( c_ProjectID ); if(_documentStore.contains(idx) )
//qDebug() << " ---- tab clicked: " << index << " : " << _documentStore[index].friendlyName;// << ": " << key;
//_mainTreeView->setCurrentIndex( _documentStore[index].treeItem->index() );
}
void XQMainWindow::onSectionCreated( const XQModelSection& section )
{
qDebug() << " --- XXX section created: " << section.contentType() << ":" << section.sheetRootNode()->to_string();
if( _currentProjectItem )
{ {
_mainModelView.addSectionItem( section, _currentProjectItem ); QModelIndex treeIndex =_documentStore[idx].treeItem->index();
_mainModel.expandNewItem( treeIndex );
} }
} }
void XQMainWindow::onSectionToggled( const XQModelSection& section )
//! SLOT, der aufgerufen wird, sobald eine section erzeugt worden ist.
void XQMainWindow::onSectionCreated( const XQModelSection& section )
{ {
//qDebug() << " --- XXX section toggled: " << section.contentType() << ":" << section.sheetRootNode()->to_string(); if( _currentProjectItem )
{
_mainModel.addSectionItem( section, _currentProjectItem );
}
} }
QStandardItemModel* createModel() {
auto* model = new QStandardItemModel;
model->setHorizontalHeaderLabels({ "Name" });
QStandardItem* parent = new QStandardItem("Tiere"); //! SLOT, der aufgerufen wird, wenn eine section getoggelt wurde.
parent->appendRow(new QStandardItem("Hund"));
parent->appendRow(new QStandardItem("Katze"));
model->appendRow(parent);
return model; void XQMainWindow::onSectionToggled( const XQModelSection& section )
{
for (int row = 0; row < _currentProjectItem->rowCount(); ++row)
{
QStandardItem* child = _currentProjectItem->child(row);
if (child->text() == section.contentType() )
{
bool checked = (child->checkState() == Qt::Checked);
child->setCheckState( checked ? Qt::Unchecked :Qt::Checked );
break;
}
}
} }
//! aktiviert das tab, das zum dokument mit dem schlüssel 'key' gehört.
void XQMainWindow::setChildTabByName( const QString& key )
{
for( int i=0; i<_documentStore.size(); ++i )
{
if( key == _documentStore[i].friendlyName)
{
_tabWidget->setCurrentIndex(i);
return;
}
}
}
XQNodePtr XQMainWindow::createDataTree( const QString& fileName )
{
// gibts die Datei?
if( !QFile::exists( fileName) )
throw XQException( "no such file", fileName );
XQNodeFactory treeLoader;
// xml daten laden
XQNodePtr rawTree = treeLoader.load_tree( qPrintable(fileName) );
// versteckten root node ignorieren
return rawTree->first_child();
}
XQChildModel* XQMainWindow::createChildModel( const XQNodePtr& contentRoot )
{
// Ein neues Child-Model erzeugen
XQChildModel* childModel = new XQChildModel(this);
connect( childModel, SIGNAL(sectionCreated(XQModelSection)), this, SLOT(onSectionCreated(XQModelSection)) );
connect( childModel, SIGNAL(sectionToggled(XQModelSection)), this, SLOT(onSectionToggled(XQModelSection)) );
// Den globalen undo-stack ...
childModel->setUndoStack(&_undoStack);
// die Modelstruktur anlegen
childModel->initModel( c_ChildModelName );
// model inhalte laden
childModel->addModelData( contentRoot->first_child() );
childModel->setObjectName( contentRoot->friendly_name() );
return childModel;
}
//! liest eine XML datei namens 'fileName'
void XQMainWindow::loadDocument( const QString& fileName, bool useQML )
{
// Datenbaum laden
XQNodePtr contentRoot = createDataTree( fileName );
// Falls schon vorhanden ...
const QString& pID = contentRoot->attribute(c_ProjectID);
int idx = _documentStore.indexOf( pID );
if( idx > -1 )
{
const XQDocument& document = _documentStore.at(idx);
QMessageBox::warning( this, "Load Document", QString("File: %1 already loaded.").arg( fileName ) );
_mainTreeView->setCurrentIndex( document.treeItem->index() );
_tabWidget->setCurrentIndex( idx );
// ... wird nichts wieter unternommen
return;
}
// 'friendly Name' ist ein Link auf ein anderes Attribute
// das als Namen verwendet wird.
const QString& fName = contentRoot->friendly_name();
QString pTabTitle = QString("Project %1: %2").arg( pID, fName );
// neuen eintrag im übsichts-baum erzeugen
_currentProjectItem = _mainModel.addProjectItem( contentRoot );
// Kindmodel für den Datenbaum erzeugen.
XQChildModel* childModel = createChildModel(contentRoot);
_documentStore.addDocument( fileName, fName, _currentProjectItem, childModel );
QWidget* childView{};
if(useQML)
{
XQQuickWidget* quickView = new XQQuickWidget(_tabWidget);
//quickChild->setResizeMode(QQuickWidget::SizeViewToRootObject);
quickView->rootContext()->setContextProperty("xtrChildModel", childModel);
quickView->setSource(QUrl("qrc:/xqtreeview.qml"));
childView = quickView;
}
else
{
// Eine neue TreeView erzeugn und im TabWidget parken.
XQTreeTable* treeTable = new XQTreeTable(_tabWidget);
// und die TreeView übergeben
childModel->setTreeTable(treeTable);
childView = treeTable;
}
_tabWidget->addTab( childView, pTabTitle );
_tabWidget->setCurrentWidget( childView );
setWindowTitle( pTabTitle );
}
void XQMainWindow::loadDocumentQML( const QString& fileName ) void XQMainWindow::loadDocumentQML( const QString& fileName )
{ {
// gibts die Datei? // gibts die Datei?
@@ -332,75 +456,14 @@ void XQMainWindow::loadDocumentQML( const QString& fileName )
XQQuickWidget* quickChild = new XQQuickWidget(_tabWidget); XQQuickWidget* quickChild = new XQQuickWidget(_tabWidget);
//quickChild->setResizeMode(QQuickWidget::SizeViewToRootObject); //quickChild->setResizeMode(QQuickWidget::SizeViewToRootObject);
quickChild->rootContext()->setContextProperty("myChildModel", childModel); quickChild->rootContext()->setContextProperty("xtrChildModel", childModel);
quickChild->setSource(QUrl("qrc:/xqtableview.qml")); quickChild->setSource(QUrl("qrc:/xqtreeview.qml"));
_tabWidget->addTab( quickChild, "QML:"+fName ); _tabWidget->addTab( quickChild, "QML:"+fName );
_tabWidget->setCurrentWidget( quickChild ); _tabWidget->setCurrentWidget( quickChild );
quickChild->setResizeMode(QQuickWidget::SizeRootObjectToView); quickChild->setResizeMode(QQuickWidget::SizeRootObjectToView);
} }
//! liest eine XML datei namens 'fileName'
void XQMainWindow::loadDocument( const QString& fileName )
{
// gibts die Datei?
if( !QFile::exists( fileName) )
throw XQException( "no such file", fileName );
XQNodeFactory treeLoader;
// xml daten laden
XQNodePtr rawTree = treeLoader.load_tree( qPrintable(fileName) );
// versteckten root node ignorieren
XQNodePtr contentRoot = rawTree->first_child();
// Project-ID behandeln
const QString& pID = contentRoot->attribute(c_ProjectID);
int idx = _documentStore.indexOf( pID );
if( idx > -1 )
{
const XQDocument& document = _documentStore.at(idx);
QMessageBox::warning( this, "Load Document", QString("File: %1 already loaded.").arg( fileName ) );
_mainTreeView->setCurrentIndex( document.treeItem->index() );
_tabWidget->setCurrentIndex( idx );
return;
}
// 'friendly Name' ist ein Link auf ein anderes Attribute
// das als Namen verwendet wird.
const QString& fName = contentRoot->friendly_name();
QString pTitle = QString("Project %1: %2").arg( pID, fName );
// Eine neue TreeView erzeugn und im TabWidget parken.
XQTreeTable* childTreeView = new XQTreeTable(_tabWidget);
_tabWidget->addTab( childTreeView, pTitle );
_tabWidget->setCurrentWidget( childTreeView );
setWindowTitle( pTitle );
// Ein neues Child-Model erzeugen
XQChildModel* childModel = new XQChildModel(this);
connect( childModel, SIGNAL(sectionCreated(XQModelSection)), this, SLOT(onSectionCreated(XQModelSection)) );
connect( childModel, SIGNAL(sectionToggled(XQModelSection)), this, SLOT(onSectionToggled(XQModelSection)) );
// Den globalen undo-stack ...
childModel->setUndoStack(&_undoStack);
// und die TreeView übergeben
childModel->setTreeTable(childTreeView);
// neuen eintrag im übsichts-baum erzeugen
_currentProjectItem = _mainModelView.addProjectItem( contentRoot );
_documentStore.addDocument( fileName, pTitle, _currentProjectItem, childModel );
// die Modelstruktur anlegen
childModel->initModel( c_ChildModelName );
// model inhalte laden
childModel->addModelData( contentRoot->first_child() );
}
//! speichert ein XML unter dem 'filename' //! speichert ein XML unter dem 'filename'
@@ -409,7 +472,9 @@ void XQMainWindow::saveDocument( const QString& fileName )
{ {
XQNodeWriter nodeWriter; XQNodeWriter nodeWriter;
int curIdx = _tabWidget->currentIndex(); int curIdx = _tabWidget->currentIndex();
XQNodePtr rootNode = _documentStore[curIdx].treeItem->contentNode(); //XQNodePtr rootNode = _documentStore[curIdx].treeItem->contentNode();
XQNodePtr rootNode = _documentStore[curIdx].viewModel->contentRootNode();
Q_ASSERT(rootNode);
nodeWriter.dumpTree( rootNode, fileName ); nodeWriter.dumpTree( rootNode, fileName );
} }

View File

@@ -35,6 +35,11 @@ public:
public slots: public slots:
virtual void onMyFirz(XQItem& item)
{
qDebug() << " --- myFirz: " << item.text();
}
void onUndo(); void onUndo();
void onRedo(); void onRedo();
@@ -46,31 +51,38 @@ public slots:
void onAbout(); void onAbout();
void onExit(); void onExit();
void onTreeItemClicked(const QModelIndex& index ); void onTreeViewItemClicked( const XQItem& item );
void onTabClicked( int index ); void onTreeViewItemChanged( const XQItem& item );
void onChildViewTabClicked( int index );
//void onItemCreated( XQItem* item ); //void onItemCreated( XQItem* item );
void onSectionCreated( const XQModelSection& section); void onSectionCreated( const XQModelSection& section);
void onSectionToggled( const XQModelSection& section ); void onSectionToggled( const XQModelSection& section );
void setChildTabByName( const QString& key );
// fixme implement
//void showDocument( const QString& key ){}
void loadDocument( const QString& fileName, bool useQML=false );
void loadDocumentQML( const QString& fileName );
void saveDocument( const QString& fileName );
static void setupWorkingDir(); static void setupWorkingDir();
protected: protected:
XQNodePtr createDataTree( const QString& fileName );
XQChildModel* createChildModel( const XQNodePtr& contentRoot );
// fixme implement
void showDocumnet( const QString& key ){}
void loadDocument( const QString& fileName );
void loadDocumentQML( const QString& fileName );
void saveDocument( const QString& fileName );
QUndoStack _undoStack; QUndoStack _undoStack;
XQDocumentStore _documentStore; XQDocumentStore _documentStore;
XQMainModel _mainModelView; XQMainModel _mainModel;
XQItem* _currentProjectItem{}; XQItem* _currentProjectItem{};
//XQChildModel* _currentChildModel{};
}; };

View File

@@ -64,7 +64,7 @@ XQItem::XQRenderStyleMap XQItem::s_RenderStyleMap
{ "CustomRenderStyle", CustomRenderStyle }, { "CustomRenderStyle", CustomRenderStyle },
{ "PickerStyle", PickerStyle }, { "PickerStyle", PickerStyle },
{ "SpinBoxStyle", SpinBoxStyle }, { "SpinBoxStyle", SpinBoxStyle },
{ "ProgressBarStyle", ProgressBarStyle}, { "ColorBarStyle", ColorBarStyle},
{ "FormattedStyle", FormattedStyle}, { "FormattedStyle", FormattedStyle},
}; };
@@ -74,7 +74,7 @@ XQItem::XQEditorTypeMap XQItem::s_EditorTypeMap
{ "LineEditType", LineEditType }, { "LineEditType", LineEditType },
{ "ComboBoxType", ComboBoxType }, { "ComboBoxType", ComboBoxType },
{ "PickerType", PickerType }, { "PickerType", PickerType },
{ "ProgressBarType", ProgressBarType }, { "ColorBarType", ColorBarType },
{ "SpinBoxType", SpinBoxType}, { "SpinBoxType", SpinBoxType},
{ "CustomEditorType", CustomEditorType} { "CustomEditorType", CustomEditorType}
}; };
@@ -116,6 +116,8 @@ XQItem::XQPrefixExponentMap XQItem::s_PrefixExponentMap
}; };
//! Default konstruktor, setzt einen ungültigen (dummy)
//! itemType.
XQItem::XQItem() XQItem::XQItem()
: XQItem{XQItemType::staticItemType()} : XQItem{XQItemType::staticItemType()}
@@ -123,6 +125,9 @@ XQItem::XQItem()
} }
//! Default konstruktor mit einem vorhandenen itemType.
XQItem::XQItem( XQItemType* itemType ) XQItem::XQItem( XQItemType* itemType )
: QStandardItem{} : QStandardItem{}
{ {
@@ -130,12 +135,21 @@ XQItem::XQItem( XQItemType* itemType )
} }
XQItem::XQItem(XQItemType* itemType, const QString *content ) //! konstruiert ein daten-item mit zeiger auf 'unser' attribut
//! im übergeordneten content-node.
XQItem::XQItem(XQItemType* itemType, const QString* content )
: XQItem{ itemType } : XQItem{ itemType }
{ {
setContent(content); // hier setzen wir direkt ohne umwege den string pointer
QStandardItem::setData( QVariant::fromValue<const QString*>(content), XQItem::ContentRole );
} }
XQItem::XQItem( XQItemType* itemType, const QString& content )
: XQItem{ itemType }
{
setText(content);
}
//! ruft den copy-konstruktor auf. //! ruft den copy-konstruktor auf.
XQItem* XQItem::clone() const XQItem* XQItem::clone() const
@@ -147,21 +161,36 @@ XQItem* XQItem::clone() const
//! false für ein ungültiges item. 'ungültig' heisst hier, dass nur ein //! false für ein ungültiges item. 'ungültig' heisst hier, dass nur ein
//! mockup-itemtype gesetzt ist. //! mockup-itemtype gesetzt ist.
bool XQItem::isValid() const bool XQItem::isValidX() const
{ {
XQItemType* dummyType = XQItemType::staticItemType(); XQItemType* dummyType = XQItemType::staticItemType();
return QStandardItem::data( XQItem::ItemTypeRole ).value<XQItemType*>() != dummyType; return QStandardItem::data( XQItem::ItemTypeRole ).value<XQItemType*>() != dummyType;
} }
bool XQItem::hasContentNode() const
{
if( column() == 0)
{
QVariant value = QStandardItem::data( XQItem::ContentNodeRole );
return !value.isNull();
}
// sonst: delegieren an den node-Besitzer
QModelIndex pIndex = model()->index( row(), 0 );
if( pIndex.isValid() )
{
XQItem& firstItem = xqItemFromIndex( pIndex );
return firstItem.hasContentNode();
}
return false;
}
//! gibt den content-node zurück. //! gibt den content-node zurück.
XQNodePtr XQItem::contentNode() const XQNodePtr XQItem::contentNode() const
{ {
XQNodePtr node = data( ContentNodeRole ).value<XQNodePtr>(); return data( ContentNodeRole ).value<XQNodePtr>();
if( node )
return node;
throw XQException("XQItem::contentNode() nullptr");
} }
@@ -319,37 +348,23 @@ QString XQItem::rawText() const
//! Gibt den string-zeiger auf das attribut aus unseren XQNodePtr zurück. //! Gibt den string-zeiger auf das attribut aus unseren XQNodePtr zurück.
/*
QString* XQItem::content() const QString* XQItem::content() const
{ {
// macht jetzt das, ws draufsteht: gibt einen string* zurück // macht jetzt das, was draufsteht: gibt einen string* zurück
return data( XQItem::ContentRole ).value<QString*>(); return data( XQItem::ContentRole ).value<QString*>();
} }
*/
//! set den content()-string pointer. (als leihgabe) //! Gibt den content-format string zurück
void XQItem::setContent( const QString* content )
{
setData( QVariant::fromValue<const QString*>(content), XQItem::ContentRole );
}
//! holt den schlüssel bzw. bezeicher des content() string aus 'unserem' content knoten.
QString XQItem::contentKey() const
{
return contentNode()->attributes().key_of( rawText() );
}
//! gibt den content-format string zurück
QString XQItem::contentFormat() const QString XQItem::contentFormat() const
{ {
return data( XQItem::ContentFormatRole ).toString(); return data( XQItem::ContentFormatRole ).toString();
} }
//! setz den den content format-string. wird im itemType gespeichert. //! Setzt den den content format-string. wird im itemType gespeichert.
void XQItem::setContentFormat(const QString& contentFormat) void XQItem::setContentFormat(const QString& contentFormat)
{ {
@@ -357,7 +372,7 @@ void XQItem::setContentFormat(const QString& contentFormat)
} }
//! gibt das read-only auswahl-model zurück (wenn dieses item als //! Gibt das read-only auswahl-model zurück (wenn dieses item als
//! combobox gerendert wird). wird im itemType gespeichert. //! combobox gerendert wird). wird im itemType gespeichert.
QStandardItemModel* XQItem::fixedChoices() const QStandardItemModel* XQItem::fixedChoices() const
@@ -413,6 +428,30 @@ QString XQItem::dataRoleName(int role) const
return XQItem::fetchItemDataRoleName(role); return XQItem::fetchItemDataRoleName(role);
} }
bool XQItem::hasContentPtr() const
{
return !QStandardItem::data( XQItem::ContentRole ).isNull();
}
//! Gibt den content()-String zurück, sofern vorhanden.
//! sonst: gibt der ihnalt der Qt::DisplayRole als fallback
//! zurück.
QString XQItem::contentFallBackText() const
{
if( hasContentPtr() )
{
const QString* contentPtr = QStandardItem::data( XQItem::ContentRole ).value<const QString*>();
if(contentPtr)
return *contentPtr;
}
// wenn wir keinen contentPtr haben, benutzen wir als fallback
// die basis-text() role
return QStandardItem::data( Qt::DisplayRole ).toString();
}
//! angespasste variante von qstandarditem::setData. geteilte attribute //! angespasste variante von qstandarditem::setData. geteilte attribute
//! werden vom xqitemtype geholt //! werden vom xqitemtype geholt
@@ -438,33 +477,35 @@ QVariant XQItem::data(int role ) const
return itemType().data(role); return itemType().data(role);
} }
// Zugriffe auf den sichtbaren inhalt geben den inhalt des string pointer case XQItem::ContentRole:
// auf ein feld in content node wieder.
// DisplayRole gibt den formatieren inhalt wieder. die formatierung übernimmt
// der item type
// auf den original inhalt im content node zurückgeben.
case Qt::DisplayRole :
{ {
if( itemType().renderStyle() == XQItem::FormattedStyle)//return "display:"+content(); qDebug() << " --- data(XQItem::ContentRole) should NOT be called!";
return itemType().formatText( *this ); return *QStandardItem::data( XQItem::ContentRole ).value<QString*>();
[[fallthrough]];
} }
// EditRole & ContentRole sollen den 'rohen' inhalt unseres string-pointers // EditRole & ContentRole sollen den 'rohen' inhalt unseres string-pointers
// auf den original inhalt im content node zurückgeben. // auf den original inhalt im content node zurückgeben.
case Qt::EditRole : case Qt::EditRole :
case XQItem::ContentRole:
{ {
// Zugriffe auf den text-inhalt geben den inhalt des string pointer
// auf ein feld in content-node wieder. Wenn kein content-node vorhanden
// ist (single-items), wird Qt::DisplayRole zurückgeliefert.
const QString* contentPtr = QStandardItem::data( XQItem::ContentRole ).value<const QString*>(); return contentFallBackText();
if(contentPtr) //[[fallthrough]];
return *contentPtr; }
static const QString s_dummyContent("-"); // DisplayRole gibt den formatierten inhalt wieder. die formatierung übernimmt
return s_dummyContent; // der item type
case Qt::DisplayRole :
{
QString plainText = contentFallBackText();
//if( renderStyle() == XQItem::FormattedStyle)
if( unitType() != XQItem::NoUnitType)
return XQItemType::formatToSI( plainText, unitType() );
return plainText;
} }
case Qt::ToolTipRole: case Qt::ToolTipRole:
@@ -479,16 +520,30 @@ QVariant XQItem::data(int role ) const
case ContentNodeRole: case ContentNodeRole:
{ {
// Das Node-Besitzer-Item wohnt in der ersten Spalte, // Das Node-Besitzer-Item wohnt in der ersten Spalte,
// wenn wir also der Node-Besitzer item sind ... // wenn wir also der Node-Besitzer item sind ...
if( column() == 0) if( column() == 0)
return QStandardItem::data( XQItem::ContentNodeRole ); {
QVariant value = QStandardItem::data( XQItem::ContentNodeRole );
if( !value.isNull() )
return value;
// sonst: delegieren an den node-Besitzer // das gibt immerhin was zurück, was auf nullptr getestet werden kann,
QModelIndex pIndex = model()->index( row(), 0 ); return QVariant::fromValue<XQNodePtr>(nullptr);
// diese variante erzieht uns zur verwendung von 'hasContentNode()'
// was ist besser ?
throw XQException( "ContentNode is nullptr!");
}
// sonst: delegieren an den node-Besitzer
QModelIndex pIndex = model()->index( row(), 0 );
if( pIndex.isValid())
{
XQItem& firstItem = xqItemFromIndex( pIndex ); XQItem& firstItem = xqItemFromIndex( pIndex );
return firstItem.data( XQItem::ContentNodeRole ); return firstItem.data( XQItem::ContentNodeRole );
}
throw XQException( "Item has no valid index (yet)!");
} }
case Qt::StatusTipRole: case Qt::StatusTipRole:
@@ -537,7 +592,6 @@ void XQItem::setData(const QVariant& value, int role )
{ {
switch(role) switch(role)
{ {
case RenderStyleRole : case RenderStyleRole :
case EditorTypeRole : case EditorTypeRole :
case UnitTypeRole: case UnitTypeRole:
@@ -557,30 +611,33 @@ void XQItem::setData(const QVariant& value, int role )
return; return;
} }
// set the raw, unformatted data case Qt::DisplayRole:
case ContentRole: case Qt::EditRole:
case XQItem::ContentRole:
{ {
// string ptr setzen kann die basis. QVariant newValue;
break;
}
case Qt::EditRole : //if( itemType().renderStyle() == XQItem::FormattedStyle)
{ if( unitType() != XQItem::NoUnitType)
qDebug() << " --- setting EDITrole: " << value.toString(); newValue = XQItemType::unFormatFromSI( value.toString() );
break; else
} newValue = value;
case Qt::DisplayRole : // fallback: wenns keinen content node gibt, dann nehmen wir
{ // das standardverfahren.
// what will happen? value is a string ptr ?! if( !hasContentPtr() )
qDebug() << " --- setting DISPLAYrole: " << value.toString(); return QStandardItem::setData( newValue, Qt::DisplayRole );
break;
// wir nehmen den string pointer
const QString* constContentPtr = QStandardItem::data( XQItem::ContentRole ).value<const QString*>();
// aua, aua, muss aber sein, weil sonst alle anderen consts nicht durchgehalten werden könnten
*const_cast<QString*>(constContentPtr) = newValue.toString();
return;
} }
// alles andere wie gehabt // alles andere wie gehabt
case ContentNodeRole: case ContentNodeRole:
case SheetNodeRole: case SheetNodeRole:
//case TypeKeyRole: not used //case TypeKeyRole: not used
default: default:
break; break;
@@ -591,6 +648,133 @@ void XQItem::setData(const QVariant& value, int role )
} }
//! erzeugt eine QVariant zur gegebenen rolle aus dem gegebenen string.
//! Hack: Das Item wird hier als zusätzliche datenquelle übergeben,
//! um _vorher_ erzeugte eigenschaften des items als parameter für _jetzt_
//! erzeugte eigenschaft verwenden zu können.
//! Beispiel
QVariant XQItem::makeVariant( XQItem* item, int dataRole, const QString& source )
{
QVariant value;
//qDebug() << " ----- makeVariant: " << XQItem::fetchItemDataRoleName( dataRole );
switch(dataRole)
{
// das ist ein pointer auf den original-string aus dem XML
case XQItem::ContentRole:
{
// content() -> QString*
value = QVariant::fromValue(&source);
break;
}
/*
case XQItem::ItemTypeRole:
{
// itemType() -> XQItemType*
XQItemType* itemType = findItemTypeTemplate( source );
value = QVariant::fromValue(itemType);
break;
}
*/
case XQItem::RenderStyleRole:
{
XQItem::RenderStyle renderStyle = XQItem::fetchRenderStyle( source );
value = QVariant::fromValue(renderStyle);
break;
}
case XQItem::EditorTypeRole:
{
XQItem::EditorType editorType = XQItem::fetchEditorType( source );
value = QVariant::fromValue(editorType);
break;
}
case XQItem::UnitTypeRole:
{
//qDebug() << " --- make unit type: " << source;
XQItem::UnitType unitType = XQItem::fetchUnitType( source );
value = QVariant::fromValue(unitType);
break;
}
case XQItem::ContentFormatRole:
{
// contentFormat() -> QString
value = QVariant::fromValue(source);
break;
}
case XQItem::FlagsRole:
{
QFlags itemFlags = Qt::NoItemFlags;
const QStringList flagKeys = source.split( '|' );
for( const QString& flagKey : flagKeys )
{
Qt::ItemFlag flag = XQItem::fetchItemFlag( flagKey );
itemFlags.setFlag( flag );
}
value = QVariant::fromValue(itemFlags);
break;
}
case XQItem::IconRole:
{
QIcon typeIcon = XQAppData::typeIcon(source);
value = QVariant::fromValue(typeIcon);
break;
}
case XQItem::FixedChoicesRole:
{
const QStringList choices = source.split( '|' );
QStandardItemModel* fixedChoices = new QStandardItemModel();
for( const QString& entry : choices )
{
QString result = entry;
if( item->unitType() != XQItem::NoUnitType )
result = XQItemType::formatToSI( entry, item->unitType() );
fixedChoices->appendRow( new QStandardItem( result ) );
}
value = QVariant::fromValue(fixedChoices);
break;
}
/*
case XQItem::ContentNodeRole:
{
value = QVariant::fromValue(&source);
break;
}
case XQItem::XQItem::SheetNodeRole:
{
value = QVariant::fromValue(&source);
break;
}
*/
default:
case XQItem::XQItem::NoRole:
{
break;
}
};
//if( !value.toString().isEmpty())
// setData( value, dataRole);
return value;
}
//! gibt ein statisches invalid-item zurück, anstelle von nullptr //! gibt ein statisches invalid-item zurück, anstelle von nullptr
@@ -694,13 +878,10 @@ XQItem::UnitType XQItem::fetchUnitType(const QString& unitTypeKey)
return s_UnitTypeMap.key(unitTypeKey); return s_UnitTypeMap.key(unitTypeKey);
} }
//! gibt die bezeichung für den gegebenen unitType aus. //! gibt die bezeichung für den gegebenen unitType aus.
QString XQItem::fetchUnitTypeToString( UnitType unitType) QString XQItem::fetchUnitTypeToString( UnitType unitType)
{ {
return s_UnitTypeMap[unitType]; return s_UnitTypeMap[unitType];
} }
/// ---
/// ---
/// ---

View File

@@ -15,6 +15,7 @@
#ifndef XQITEM_H #ifndef XQITEM_H
#define XQITEM_H #define XQITEM_H
#include <QtQmlIntegration>
#include <QVariant> #include <QVariant>
#include <QVector> #include <QVector>
#include <QStandardItem> #include <QStandardItem>
@@ -35,6 +36,8 @@ class XQItemType;
class XQItem : public QStandardItem class XQItem : public QStandardItem
{ {
QML_ELEMENT
friend class XQItemFactory; friend class XQItemFactory;
public: public:
@@ -81,7 +84,7 @@ public:
ComboBoxStyle, ComboBoxStyle,
PickerStyle, PickerStyle,
SpinBoxStyle, SpinBoxStyle,
ProgressBarStyle, ColorBarStyle,
FormattedStyle, FormattedStyle,
TreeHeaderStyle, TreeHeaderStyle,
CustomRenderStyle, CustomRenderStyle,
@@ -96,7 +99,7 @@ public:
LineEditType, LineEditType,
ComboBoxType, ComboBoxType,
PickerType, PickerType,
ProgressBarType, ColorBarType,
SpinBoxType, SpinBoxType,
CustomEditorType, CustomEditorType,
EditorTypeEnd EditorTypeEnd
@@ -130,6 +133,7 @@ public:
XQItem(); XQItem();
XQItem( XQItemType* itemType ); XQItem( XQItemType* itemType );
XQItem( XQItemType* itemType, const QString* content ); XQItem( XQItemType* itemType, const QString* content );
XQItem( XQItemType* itemType, const QString& content );
virtual ~XQItem() = default; virtual ~XQItem() = default;
@@ -137,14 +141,16 @@ public:
//! -- not used at the moment -- //! -- not used at the moment --
XQItem* clone() const override; XQItem* clone() const override;
//! //! __fix Tested, ob ein itemtype vorhanden ist.
bool isValid() const; bool isValidX() const;
//! gibt den zu diesem item gehörigen datenknoten zurück bool hasContentNode() const;
virtual XQNodePtr contentNode() const; //! gibt den zu diesem item gehörigen datenknoten zurück
XQNodePtr contentNode() const;
virtual XQNodePtr sheetNode() const;
virtual void setSheetNode( const XQNodePtr& sheetNode ); XQNodePtr sheetNode() const;
void setSheetNode( const XQNodePtr& sheetNode );
XQItemType& itemType() const; XQItemType& itemType() const;
void setItemType( XQItemType* itemTypePtr ); void setItemType( XQItemType* itemTypePtr );
@@ -159,9 +165,8 @@ public:
QString rawText() const; QString rawText() const;
// changed: gibt jetzt den pointer zurück. // changed: gibt jetzt den pointer zurück.
QString* content() const; //QString* content() const;
QString contentKey() const; //void setContent( const QString* content );
void setContent( const QString* content );
// //
// Convenience-Funktionen zum Memberzugriff, die Implementierung // Convenience-Funktionen zum Memberzugriff, die Implementierung
@@ -219,6 +224,8 @@ public:
/// Static convenience methods /// Static convenience methods
/// ///
static QVariant makeVariant( XQItem* item, int dataRole, const QString& source );
static XQItem& xqItemFromIndex( const QModelIndex& index ); static XQItem& xqItemFromIndex( const QModelIndex& index );
static XQItem& fallBackDummyItem(); static XQItem& fallBackDummyItem();
@@ -238,6 +245,10 @@ protected:
XQItem(const XQItem& other) = default; XQItem(const XQItem& other) = default;
XQItem& operator=(const XQItem& other) = default; XQItem& operator=(const XQItem& other) = default;
bool hasContentPtr() const;
QString contentFallBackText() const;
// das ist protected, weil damit der content()-zugriff demoliert werden kann
void setContentNode(const XQNodePtr& contentNode ); void setContentNode(const XQNodePtr& contentNode );
using XQItemFlagMap = QMap<QString,int>; using XQItemFlagMap = QMap<QString,int>;
@@ -259,9 +270,7 @@ protected:
}; };
Q_DECLARE_METATYPE(XQItem);
Q_DECLARE_METATYPE(XQItem::RenderStyle); Q_DECLARE_METATYPE(XQItem::RenderStyle);
Q_DECLARE_METATYPE(XQItem::EditorType); Q_DECLARE_METATYPE(XQItem::EditorType);
Q_DECLARE_METATYPE(XQItem::UnitType); Q_DECLARE_METATYPE(XQItem::UnitType);

View File

@@ -17,6 +17,7 @@
#include <QComboBox> #include <QComboBox>
#include <QDoubleSpinBox> #include <QDoubleSpinBox>
#include <QProgressBar> #include <QProgressBar>
#include <QSlider>
#include <QPainter> #include <QPainter>
#include <QHeaderView> #include <QHeaderView>
@@ -28,153 +29,167 @@
#include <xqviewmodel.h> #include <xqviewmodel.h>
//! erzeugt eine editorfactory mit den hauseigenen editortypen.
class XQItemEditorFactory : public QItemEditorFactory class XQItemEditorFactory : public QItemEditorFactory
{ {
public: public:
XQItemEditorFactory() XQItemEditorFactory()
{ {
registerEditor(XQItem::LineEditType, new QStandardItemEditorCreator<QLineEdit>()); registerEditor(XQItem::LineEditType, new QStandardItemEditorCreator<QLineEdit>());
registerEditor(XQItem::ComboBoxType, new QStandardItemEditorCreator<QLineEdit>()); registerEditor(XQItem::ComboBoxType, new QStandardItemEditorCreator<QComboBox>());
registerEditor(XQItem::PickerType, new QStandardItemEditorCreator<QLineEdit>()); registerEditor(XQItem::PickerType, new QStandardItemEditorCreator<QLineEdit>());
registerEditor(XQItem::ProgressBarType, new QStandardItemEditorCreator<QLineEdit>()); //registerEditor(XQItem::ColorBarType, new QStandardItemEditorCreator<QProgressBar>());
registerEditor(XQItem::SpinBoxType, new QStandardItemEditorCreator<QLineEdit>()); registerEditor(XQItem::ColorBarType, new QStandardItemEditorCreator<QSlider>());
registerEditor(XQItem::SpinBoxType, new QStandardItemEditorCreator<QSpinBox>());
registerEditor(XQItem::CustomEditorType, new QStandardItemEditorCreator<QLineEdit>()); registerEditor(XQItem::CustomEditorType, new QStandardItemEditorCreator<QLineEdit>());
/*
registerEditor(XQItem::LineEditStyle, new QStandardItemEditorCreator<QLineEdit>());
registerEditor(XQItemType::ComboBoxStyle, new QStandardItemEditorCreator<QComboBox>());
//registerEditor(XQItemType::ProgressBarStyle, new QStandardItemEditorCreator<QProgressBar>());
registerEditor(XQItemType::SpinBoxStyle, new QStandardItemEditorCreator<QSpinBox>());
*/
/*
registerEditor(XQItem::etDoubleSpinType, new QStandardItemEditorCreator<QDoubleSpinBox>());
registerEditor(XQItemItemTypes::etDoubleSpinType, new QStandardItemEditorCreator<QDoubleSpinBox>());
registerEditor(XQItemItemTypes::etIPAddressType, new QStandardItemEditorCreator<NTIpAddressEdit>());
registerEditor(XQItemItemTypes::etLineEditBrowser, new QStandardItemEditorCreator<NTFileSelectLine>());
*/
} }
}; };
//! kontruktor mit dem zusändigen viewModel
XQItemDelegate::XQItemDelegate( XQViewModel& modelView) XQItemDelegate::XQItemDelegate( XQViewModel& viewModel)
: _modelView{modelView} : QStyledItemDelegate(), _modelView{viewModel}
{ {
static XQItemEditorFactory s_EditorFactory; static XQItemEditorFactory s_EditorFactory;
setItemEditorFactory(&s_EditorFactory); setItemEditorFactory(&s_EditorFactory);
} }
//! gibt die interne tree table zurück
XQTreeTable* XQItemDelegate::treeTable() const XQTreeTable* XQItemDelegate::treeTable() const
{ {
return _modelView.treeTable(); return _modelView.treeTable();
} }
//! shortcut: gibt das XQItem für den gegebenen index zurück.
XQItem& XQItemDelegate::xqItemFromIndex( const QModelIndex& index ) const XQItem& XQItemDelegate::xqItemFromIndex( const QModelIndex& index ) const
{ {
return _modelView.xqItemFromIndex( index ); return _modelView.xqItemFromIndex( index );
} }
//! überladene paint-methode: zeichnet das item je nach render-style.
void XQItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const void XQItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{ {
if( !index.isValid() ) if( index.isValid() )
qDebug() << " index DEAD!";
XQItem& item = xqItemFromIndex( index );
if( item.isValid() )
{ {
XQItem& item = xqItemFromIndex( index );
switch( item.renderStyle() ) switch( item.renderStyle() )
{ {
case XQItem::HeaderStyle : case XQItem::HeaderStyle :
return drawHeaderStyle( painter, option, index ); return drawHeaderStyle( painter, option, item );
//return drawHeaderStyleX( painter, option, index );
case XQItem::ComboBoxStyle : case XQItem::ComboBoxStyle :
return drawComboBoxStyle( painter, option, index ); return drawComboBoxStyle( painter, option, item );
case XQItem::ColorBarStyle :
return drawColorBarStyle( painter, option, item );
// das funktioniert nicht unter windows11
//case XQItem::SpinBoxStyle :
// return drawSpinBoxStyle( painter, option, item );
case XQItem::HiddenStyle : case XQItem::HiddenStyle :
return; return;
//case XQItem::ProgressBarStyle :
// return drawProgressBarStyle( painter, option, index );
default: default:
break; break;
} // switch } // switch
} }
else
{
qDebug() << " ---- paint: INDEX DEAD!" ;
}
QStyledItemDelegate::paint(painter, option, index); QStyledItemDelegate::paint(painter, option, index);
} }
//! einen section header im header-style zeichnen //! einen section header im header-style zeichnen
void XQItemDelegate::drawHeaderStyle(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const void XQItemDelegate::drawHeaderStyle(QPainter* painter, const QStyleOptionViewItem& option, const XQItem& item) const
{ {
QStyleOptionHeader headerOption; QStyleOptionHeader headerOption;
XQItem& item = xqItemFromIndex( index );
// use the header as "parent" for style init // use the header as "parent" for style init
QWidget* srcWidget = treeTable();//->header(); QWidget* srcWidget = treeTable();//->header();
headerOption.initFrom(srcWidget); headerOption.initFrom(srcWidget);
headerOption.text = index.data(Qt::DisplayRole).toString(); headerOption.text = item.text();//index.data(Qt::DisplayRole).toString();
headerOption.rect = option.rect.adjusted(0,0,0,3); headerOption.rect = option.rect;//.adjusted(0,0,0,3);
headerOption.styleObject = option.styleObject; headerOption.styleObject = option.styleObject;
// __ch: reduce inner offset when painting // __ch: reduce inner offset when painting
headerOption.textAlignment |= Qt::AlignVCenter; headerOption.textAlignment |= Qt::AlignVCenter;
headerOption.icon = item.icon(); headerOption.icon = item.icon();
if (srcWidget != nullptr) // save painter
{ painter->save();
// save painter //value = index.data(Qt::ForegroundRole);
painter->save(); //if (value.canConvert<QBrush>())
//value = index.data(Qt::ForegroundRole); //headerOption.palette.setBrush(QPalette::Text, Qt::red );
//if (value.canConvert<QBrush>()) //headerOption.palette.setBrush(QPalette::Window, Qt::red );
//headerOption.palette.setBrush(QPalette::Text, Qt::red ); //QCommonStyle itemStyle;
//headerOption.palette.setBrush(QPalette::Window, Qt::red );
QCommonStyle itemStyle;
//headerOption.backgroundBrush()
//srcWidget->style()->drawControl(QStyle::CE_Header, &headerOption, painter, srcWidget);
itemStyle.drawControl(QStyle::CE_Header, &headerOption, painter, srcWidget);
// restore painter
painter->restore();
}
}
void XQItemDelegate::drawProgressBarStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const //qApp->style()->drawControl(QStyle::CE_Header, &headerOption, painter, srcWidget);
{ //srcWidget->style()->drawControl(QStyle::CE_Header, &headerOption, painter, srcWidget);
// warum das nur mit dem commonstyle, ist mir echt unklar.
_commonStyle.drawControl(QStyle::CE_Header, &headerOption, painter, srcWidget);
// restore painter
painter->restore();
int progress = index.data(XQItem::ContentRole ).toInt();
QStyleOptionProgressBar progressBarOption;
progressBarOption.rect = option.rect;
progressBarOption.minimum = 0;
progressBarOption.maximum = 100;
progressBarOption.progress = progress;
progressBarOption.text = QString::number(progress) + "%";
progressBarOption.textAlignment = Qt::AlignCenter;
progressBarOption.textVisible = true;
QApplication::style()->drawControl(QStyle::CE_ProgressBar,&progressBarOption, painter);
} }
void XQItemDelegate::drawComboBoxStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
//! Zeichnet prozent-werte als balken
void XQItemDelegate::drawColorBarStyle(QPainter* painter, const QStyleOptionViewItem& option, const XQItem& item) const
{ {
//QStyledItemDelegate::paint(painter, option, item);
// Wert aus dem Modell holen
bool ok;
int value = item.data(Qt::EditRole).toInt(&ok);
if (!ok || value < 0 || value > 100)
return;
// Balkenbereich berechnen
QRect rect = option.rect.adjusted(2, 2, -2, -2); // etwas Padding
int barWidth = static_cast<int>(rect.width() * (value / 100.0));
// Balken zeichnen
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
QRect barRect(rect.left(), rect.top(), barWidth, rect.height());
QColor barColor = QColor(100, 180, 255);
painter->setBrush(barColor);
painter->setPen(Qt::NoPen);
painter->drawRect(barRect);
painter->setPen(Qt::black);
painter->drawText(rect, Qt::AlignCenter, item.text() );
painter->restore();
}
//! Zeichnet das Item als combo box.
void XQItemDelegate::drawComboBoxStyle(QPainter* painter, const QStyleOptionViewItem& option, const XQItem& item) const
{
QStyleOptionComboBox comboOption;
QWidget* srcWidget = qobject_cast<QWidget*>(option.styleObject); QWidget* srcWidget = qobject_cast<QWidget*>(option.styleObject);
QStyleOptionComboBox comboOption;
QStyle* comboStyle = srcWidget->style();
comboOption.initFrom(srcWidget); comboOption.initFrom(srcWidget);
// set options // set options
@@ -182,68 +197,102 @@ void XQItemDelegate::drawComboBoxStyle(QPainter *painter, const QStyleOptionView
comboOption.state = option.state | QStyle::State_Selected | QStyle::State_Enabled; comboOption.state = option.state | QStyle::State_Selected | QStyle::State_Enabled;
// not editable => only visual, but painter needs to know it // not editable => only visual, but painter needs to know it
comboOption.editable = false; comboOption.editable = false;
comboOption.currentText = index.data(Qt::DisplayRole).toString(); comboOption.currentText = item.text();
// decoration (if any) // decoration (if any)
comboOption.currentIcon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole)); comboOption.currentIcon = qvariant_cast<QIcon>(item.data(Qt::DecorationRole));
comboOption.iconSize = comboOption.currentIcon.actualSize(QSize(option.rect.height() - 3, option.rect.height() - 3)); comboOption.iconSize = comboOption.currentIcon.actualSize(QSize(option.rect.height() - 3, option.rect.height() - 3));
// save painter // save painter
painter->save(); painter->save();
// hier wiederum funktioniert der '_commonStyle' nicht
QStyle* widgetStyle = srcWidget->style();
// draw combo // draw combo
comboStyle->drawComplexControl(QStyle::CC_ComboBox, &comboOption, painter, srcWidget); widgetStyle->drawComplexControl(QStyle::CC_ComboBox, &comboOption, painter, srcWidget);
// and combobox label // and combobox label
comboStyle->drawControl(QStyle::CE_ComboBoxLabel, &comboOption, painter, srcWidget); widgetStyle->drawControl(QStyle::CE_ComboBoxLabel, &comboOption, painter, srcWidget);
// restore painter // restore painter
painter->restore(); painter->restore();
} }
void XQItemDelegate::drawSpinBoxStyle(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
//! Zeichnet das Item als spin box.
void XQItemDelegate::drawSpinBoxStyle(QPainter* painter, const QStyleOptionViewItem& option, const XQItem& item) const
{ {
// xx_fix! qDebug() << " --- jawas +++? SPINBOX!";
//int value = index.data(XQItem::ContentRole ).toInt();
QStyleOptionSpinBox spinBoxOption; QWidget* srcWidget = qobject_cast<QWidget*>(option.styleObject);
spinBoxOption.rect = option.rect; QStyleOptionViewItem viewOption(option);
/* QStyleOptionSpinBox spinBoxOption;
spinBoxOption.text = QString::number(value); spinBoxOption.initFrom(srcWidget);
spinBoxOption.textAlignment = Qt::AlignCenter;
spinBoxOption.textVisible = true; initStyleOption(&viewOption, item.index());
*/ if (option.state & QStyle::State_HasFocus)
{
viewOption.state = viewOption.state ^ QStyle::State_HasFocus; // Fokus nicht auf dem Hintergrund malen
}
QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &viewOption, painter);
spinBoxOption.rect = option.rect;//.adjusted( 0,0,-40,0);
spinBoxOption.state = option.state | QStyle::State_Sunken; // Sunken-State für den "LineEdit"-Look
spinBoxOption.buttonSymbols = QAbstractSpinBox::UpDownArrows;
spinBoxOption.stepEnabled = QAbstractSpinBox::StepUpEnabled | QAbstractSpinBox::StepDownEnabled;
spinBoxOption.frame = true;
_commonStyle.drawComplexControl(QStyle::CC_SpinBox, &spinBoxOption, painter, nullptr);
QRect editRect =_commonStyle.subControlRect(QStyle::CC_SpinBox, &spinBoxOption, QStyle::SC_SpinBoxEditField, nullptr);
painter->drawText(spinBoxOption.rect, Qt::AlignCenter, item.text());
QApplication::style()->drawComplexControl(QStyle::CC_SpinBox,&spinBoxOption, painter);
} }
QSize XQItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const //! Überschreibt QStyledItemDelegate::sizeHint(option, index);
QSize XQItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{ {
return QStyledItemDelegate::sizeHint(option, index); return QStyledItemDelegate::sizeHint(option, index);
} }
//! Erzeugt ein editor-widget, sofern ein gültiger content-Ptr vorhanden und ein editor-Type gesetzt ist.
QWidget* XQItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const QWidget* XQItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{ {
Q_UNUSED(option);
return QStyledItemDelegate::createEditor( parent, option, index ); XQItem& item = xqItemFromIndex(index);
XQItem::EditorType edType = item.editorType();
int editorType = XQItem::xqItemFromIndex(index).editorType(); if( edType == XQItem::NoEditorType )
QWidget* editor = itemEditorFactory()->createEditor(editorType, parent);
if( editor )
{ {
return editor; qDebug() << "---- NO Content or NO EditorType";
return nullptr;
} }
qDebug() << "---- ed type:" << XQItem::fetchEditorTypeToString( edType ) << ": " << edType;
QWidget* editor = itemEditorFactory()->createEditor(edType, parent);;
//return QStyledItemDelegate::createEditor( parent, option, index );
return editor;
} }
//! Füttert einen editor mit den model-daten
void XQItemDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const void XQItemDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{ {
XQItem& item = xqItemFromIndex( index ); XQItem& item = xqItemFromIndex( index );
switch( item.editorType() ) XQItem::EditorType edType = item.editorType();
if( edType == XQItem::NoEditorType )
return;
switch( edType )
{ {
case XQItemType::ComboBoxType : case XQItemType::ComboBoxType :
{ {
QComboBox* comboBox = qobject_cast<QComboBox*>(editor); QComboBox* comboBox = qobject_cast<QComboBox*>(editor);
// wir erwarten hier ein gültiges model?
comboBox->setModel( item.fixedChoices()); comboBox->setModel( item.fixedChoices());
comboBox->setCurrentText( item.data().toString() ); comboBox->setCurrentText( item.data().toString() );
comboBox->showPopup(); comboBox->showPopup();
@@ -251,24 +300,37 @@ void XQItemDelegate::setEditorData(QWidget* editor, const QModelIndex& index) co
} }
default: default:
break;
// wir benutzen hier die DisplayRole wenn der Inhalt schon formatiert ist.
int role = item.renderStyle() == XQItem::FormattedStyle ? Qt::DisplayRole : Qt::EditRole;
QVariant value = index.data(role);
QByteArray userProp = editor->metaObject()->userProperty().name();
if (!userProp.isEmpty())
{
if (!value.isValid())
value = QVariant(editor->property(userProp).metaType());
editor->setProperty(userProp, value);
}
} }
QStyledItemDelegate::setEditorData(editor, index);
} }
void XQItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
//! Schreibt die daten aus dem editor ins model zurück
void XQItemDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
{ {
XQItem& item = xqItemFromIndex( index ); XQItem& item = xqItemFromIndex( index );
switch( item.editorType() ) switch( item.editorType() )
{ {
case XQItem::ComboBoxType : case XQItem::ComboBoxType :
{ {
QComboBox* comboBox = qobject_cast<QComboBox*>(editor); QComboBox* comboBox = qobject_cast<QComboBox*>(editor);
item.setData( comboBox->currentText(), Qt::DisplayRole );
return; return;
} }
@@ -280,8 +342,12 @@ void XQItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, co
QStyledItemDelegate::setModelData(editor, model, index); QStyledItemDelegate::setModelData(editor, model, index);
} }
//! Überschreibt QItemDelegate::updateEditorGeometry. Nicht implementiert.
void XQItemDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const void XQItemDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const
{ {
//qDebug() << " --- update Editor Geometry"; //qDebug() << " --- update Editor Geometry";
QStyledItemDelegate::updateEditorGeometry(editor, option, index); QStyledItemDelegate::updateEditorGeometry(editor, option, index);
} }

View File

@@ -16,6 +16,7 @@
#define XQITEMDELEGATE_H #define XQITEMDELEGATE_H
#include <QStyledItemDelegate> #include <QStyledItemDelegate>
#include <QCommonStyle>
#include <xqappdata.h> #include <xqappdata.h>
class XQItem; class XQItem;
@@ -32,26 +33,27 @@ class XQItemDelegate : public QStyledItemDelegate
public: public:
explicit XQItemDelegate(XQViewModel& modelView); explicit XQItemDelegate(XQViewModel& viewModel);
XQTreeTable* treeTable() const; XQTreeTable* treeTable() const;
XQItem& xqItemFromIndex( const QModelIndex& index ) const; XQItem& xqItemFromIndex( const QModelIndex& index ) const;
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
void setEditorData(QWidget *editor, const QModelIndex &index) const override; void setEditorData(QWidget* editor, const QModelIndex& index) const override;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override; void setModelData(QWidget* editor, QAbstractItemModel *model, const QModelIndex& index) const override;
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
protected: protected:
void drawHeaderStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawHeaderStyle(QPainter* painter, const QStyleOptionViewItem& option, const XQItem& item ) const;
void drawProgressBarStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawColorBarStyle(QPainter* painter, const QStyleOptionViewItem& option, const XQItem& item) const;
void drawComboBoxStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawComboBoxStyle(QPainter* painter, const QStyleOptionViewItem& option, const XQItem& item) const;
void drawSpinBoxStyle(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawSpinBoxStyle(QPainter* painter, const QStyleOptionViewItem& option, const XQItem& item) const;
XQViewModel& _modelView; XQViewModel& _modelView;
QCommonStyle _commonStyle;
}; };

View File

@@ -29,7 +29,7 @@ void XQItemFactory::initItemFactory( const QString& modelSheetFileName )
for( const auto& [key,value] : sheetNode->attributes() ) for( const auto& [key,value] : sheetNode->attributes() )
{ {
//qDebug() << " --- conf item Type: " << key << " : " << value; //qDebug() << " --- conf item Type: " << key << " : " << value;
setItemDataFromString( *itemType, key, value ); setItemTypeDataFromString( *itemType, key, value );
} }
}; };
@@ -91,7 +91,7 @@ XQItemType* XQItemFactory::makeItemType(const XQNodePtr& sheetEntry )
// wenn ja, überschreiben // wenn ja, überschreiben
if( role != XQItem::NoRole ) if( role != XQItem::NoRole )
{ {
QVariant newValue = makeVariant(role, attrEntry.second ); QVariant newValue = XQItem::makeVariant( itemType, role, attrEntry.second );
itemType = itemType->replaceAttribute( newValue, role ); itemType = itemType->replaceAttribute( newValue, role );
} }
@@ -99,12 +99,13 @@ XQItemType* XQItemFactory::makeItemType(const XQNodePtr& sheetEntry )
return itemType; return itemType;
} }
//! sucht einen item typ aus der map mit 'vorgefertigen' itemtypen. //! sucht einen item typ aus der map mit 'vorgefertigen' itemtypen.
XQItemType* XQItemFactory::findItemTypeTemplate(const QString& key ) const XQItemType* XQItemFactory::findItemTypeTemplate(const QString& key ) const
{ {
if( !key.isEmpty() && s_ItemTypeTemplates.contains(key)) if( !key.isEmpty() && s_ItemTypeTemplates.contains(key))
return s_ItemTypeTemplates[key]; return s_ItemTypeTemplates[key];
throw XQException( "itemfactory: findItemTypeTemplate: not found:", key ); throw XQException( "itemfactory: findItemTypeTemplate: not found:", key );
} }
@@ -123,188 +124,21 @@ XQNodePtr XQItemFactory::findModelSheet( const QString& modelName ) const
//! erzeugt eine QVariant aus dem gegebenen string und setzt diese dann via role im item. //! erzeugt eine QVariant aus dem gegebenen string und setzt diese dann via role im item.
void XQItemFactory::setItemDataFromString( XQItem& item, const QString& roleKey, const QString& source ) const void XQItemFactory::setItemTypeDataFromString( XQItem& item, const QString& roleKey, const QString& source ) const
{ {
int dataRole = XQItem::fetchItemDataRole( roleKey ); int dataRole = XQItem::fetchItemDataRole( roleKey );
if( dataRole != XQItem::NoRole) if( dataRole != XQItem::NoRole)
{ {
QVariant variant = makeVariant( dataRole, source ); QVariant variant = XQItem::makeVariant( &item, dataRole, source );
if( !variant.isNull() && variant.isValid() ) if( !variant.isNull() && variant.isValid() )
item.setData( variant, dataRole ); item.setData( variant, dataRole );
} }
} }
//! erzeugt eine QVariant aus dem gegebenen string
QVariant XQItemFactory::makeVariant( int dataRole, const QString& source ) const
{
QVariant value;
switch(dataRole)
{
// das ist ein pointer auf den original-string aus dem XML
case XQItem::ContentRole:
{
// content() -> QString*
value = QVariant::fromValue(&source);
break;
}
case XQItem::ItemTypeRole:
{
// itemType() -> XQItemType*
//qDebug() << " --- makeVariant: make ItemType: " << source;
XQItemType* itemType = findItemTypeTemplate( source );
value = QVariant::fromValue(itemType);
break;
}
case XQItem::RenderStyleRole:
{
XQItem::RenderStyle renderStyle = XQItem::fetchRenderStyle( source );
value = QVariant::fromValue(renderStyle);
break;
}
case XQItem::EditorTypeRole:
{
XQItem::EditorType editorType = XQItem::fetchEditorType( source );
value = QVariant::fromValue(editorType);
break;
}
case XQItem::UnitTypeRole:
{
//qDebug() << " --- make unit type: " << source;
XQItem::UnitType unitType = XQItem::fetchUnitType( source );
value = QVariant::fromValue(unitType);
break;
}
case XQItem::ContentFormatRole:
{
// contentFormat() -> QString
value = QVariant::fromValue(source);
break;
}
case XQItem::FlagsRole:
{
QFlags itemFlags = Qt::NoItemFlags;
const QStringList flagKeys = source.split( '|' );
for( const QString& flagKey : flagKeys )
{
Qt::ItemFlag flag = XQItem::fetchItemFlag( flagKey );
itemFlags.setFlag( flag );
}
value = QVariant::fromValue(itemFlags);
break;
}
case XQItem::IconRole:
{
QIcon typeIcon = XQAppData::typeIcon(source);
value = QVariant::fromValue(typeIcon);
break;
}
case XQItem::FixedChoicesRole:
{
const QStringList choices = source.split( '|' );
QStandardItemModel* fixedChoices = new QStandardItemModel();
for( const QString& entry : choices )
fixedChoices->appendRow( new QStandardItem( entry ) );
value = QVariant::fromValue(fixedChoices);
break;
}
/*
case XQItem::ContentNodeRole:
{
value = QVariant::fromValue(&source);
break;
}
case XQItem::XQItem::SheetNodeRole:
{
value = QVariant::fromValue(&source);
break;
}
*/
default:
case XQItem::XQItem::NoRole:
{
break;
}
};
//if( !value.toString().isEmpty())
// setData( value, dataRole);
return value;
}
///
/// ------------------------------------------------
///
/*
XQItemList XQItemFactory::makeEmptyRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode )
{
Q_UNUSED(contentNode)
XQItemList list;
// create a data node for each sheet entry
size_t max = sheetNode->children().size();
for( size_t i=0; i<max; ++i )
{
// __fix
//list.append( new XQItem( "", XQItemType::EmptyStyle ) );
}
return list;
}
*/
/*
XQItemList XQItemFactory::createGenericRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode )
{
// we have a new empty contentNode, so we add attributes first.
for( const auto& sheetEntry : sheetNode->children() )
{
QString value = "[" + sheetEntry->tag_name() + "]";
if( sheetEntry->has_attribute("Unit") )
value = "0";
contentNode->set_attribute( sheetEntry->tag_name(), value );
}
if( sheetNode->has_attribute( c_FriendlyName ) )
contentNode->set_attribute( c_FriendlyName, sheetNode->friendly_name() );
// now, we can create a normal entry row
return makeContentRow(contentNode, sheetNode );
}
*/
//! erzeugt eine item-row. //! erzeugt eine item-row.
XQItemList XQItemFactory::makeRow(CreationMode mode, const XQNodePtr& sheetNode, const XQNodePtr& contentNode, const QString& captionKey ) XQItemList XQItemFactory::makeRow(const XQNodePtr& sheetNode, const XQNodePtr& contentNode )
{ {
XQItemList list; XQItemList list;
@@ -320,24 +154,31 @@ XQItemList XQItemFactory::makeRow(CreationMode mode, const XQNodePtr& sheetNode,
// //
for( const auto& sheetEntry : sheetNode->children() ) for( const auto& sheetEntry : sheetNode->children() )
list.append( makeItem( mode, sheetEntry, contentNode, captionKey ) ); list.append( makeItem( sheetEntry, contentNode ) );
Q_ASSERT(!list.empty()); Q_ASSERT(!list.empty());
// wir merken uns den original content node auch, aber // wir merken uns den original content node auch, aber
// im ersten Item. // im ersten Item. Kann null sein, macht aber erstmal nix.
dynamic_cast<XQItem*>(list[0])->setContentNode(contentNode); dynamic_cast<XQItem*>(list[0])->setContentNode(contentNode);
return list; return list;
} }
XQItemList XQItemFactory::makeChildRow( XQItem* parent, const XQNodePtr& sheetNode, const XQNodePtr& contentNode )
{
Q_UNUSED(parent);
Q_UNUSED(sheetNode);
Q_UNUSED(contentNode);
//! fixme! unsinn! return XQItemList();
//! erzeugt ein XQItem aus einer typ-beschreibung ('sheetNode') und einem daten-knoten ('contentNode'). }
//! wenn der content node nicht gesetzt ist, wird stattdess das attribut 'Caption' aus der typ-beschreibung
//! verwendet: es handelt sich dann um ein header item, das erzeugt wurde.
XQItem* XQItemFactory::makeItem(CreationMode mode, const XQNodePtr& sheetNode, const XQNodePtr& contentNode, const QString& captionKey ) //! Erzeugt ein XQItem aus einer typ-beschreibung ('sheetNode') und einem daten-knoten ('contentNode').
//! Wenn der content node nicht gesetzt ist, wird stattdess das attribut 'Caption' aus der typ-beschreibung
//! verwendet: es handelt sich dann um ein header item
XQItem* XQItemFactory::makeItem(const XQNodePtr& sheetNode, const XQNodePtr& contentNode )
{ {
// den itemtype des neuen items rausfinden // den itemtype des neuen items rausfinden
XQItemType* itemType = makeItemType(sheetNode); // throws XQItemType* itemType = makeItemType(sheetNode); // throws
@@ -347,19 +188,10 @@ XQItem* XQItemFactory::makeItem(CreationMode mode, const XQNodePtr& sheetNode, c
// das ist Unterschied vom HeaderItem zum normalen Item: Der Titel kommt aus der Modelbeschreibung, // das ist Unterschied vom HeaderItem zum normalen Item: Der Titel kommt aus der Modelbeschreibung,
// sonst wird der content indirekt über den tag-name des sheetnode geholt // sonst wird der content indirekt über den tag-name des sheetnode geholt
switch( mode ) if( !contentNode )
{ contentPtr = sheetNode->attribute_ptr(c_Caption);
case mHeader: else
contentPtr = sheetNode->attribute_ptr(captionKey); contentPtr = contentNode->attribute_ptr( sheetNode->tag_name() );
break;
case mData:
contentPtr = contentNode->attribute_ptr( sheetNode->tag_name() );
break;
case mSingle:
contentPtr = contentNode->attribute_ptr( captionKey );
}
XQItem* newItem = new XQItem( itemType, contentPtr); XQItem* newItem = new XQItem( itemType, contentPtr);
@@ -371,3 +203,18 @@ XQItem* XQItemFactory::makeItem(CreationMode mode, const XQNodePtr& sheetNode, c
return newItem; return newItem;
} }
//! Erzeugt ein Item _ohne_ internen content node, sondern
XQItem* XQItemFactory::makeSingleItem( const XQNodePtr& sheetNode, const QString& caption )
{
// den itemtype des neuen items rausfinden
XQItemType* itemType = makeItemType(sheetNode); // throws
XQItem* newItem = new XQItem( itemType, caption);
// __fixme!
if( newItem->isCheckable() )
{
newItem->setCheckState( Qt::Checked );
}
return newItem;
}

View File

@@ -28,35 +28,25 @@ class XQItemFactory : public xsingleton<XQItemFactory>
public: public:
enum CreationMode
{
mHeader,
mData,
mSingle
};
void initItemFactory(const QString& modelSheetFileName ); void initItemFactory(const QString& modelSheetFileName );
XQNodePtr findModelSheet( const QString& modelName ) const; XQNodePtr findModelSheet( const QString& modelName ) const;
//XQItemList makeEmptyRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode ); XQItemList makeRow( const XQNodePtr& sheetNode, const XQNodePtr& contentNode );
XQItemList makeChildRow( XQItem* parent, const XQNodePtr& sheetNode, const XQNodePtr& contentNode );
XQItem* makeSingleItem( const XQNodePtr& sheetNode, const QString& caption );
XQItemList makeRow( CreationMode mode, const XQNodePtr& sheetNode, const XQNodePtr& contentNode, const QString& captionKey=c_Caption ); void setItemTypeDataFromString( XQItem& item, const QString& roleKey, const QString& source ) const;
// wozu ist das gut?
//XQItemList createGenericRow( const XQNodePtr& contentNode, const XQNodePtr& sheetNode );
void setItemDataFromString( XQItem& item, const QString& roleKey, const QString& source ) const;
XQItemType* makeItemType(const XQNodePtr& sheetEntry ); XQItemType* makeItemType(const XQNodePtr& sheetEntry );
XQItemType* findItemTypeTemplate(const QString& key ) const; XQItemType* findItemTypeTemplate(const QString& key ) const;
QVariant makeVariant(int dataRole, const QString &value ) const;
protected: protected:
bool isValid(); bool isValid();
XQItem* makeItem( CreationMode mode, const XQNodePtr& sheetNode, const XQNodePtr& contentNode, const QString& captionKey ); XQItem* makeItem(const XQNodePtr& sheetNode, const XQNodePtr& contentNode );
// shortcuts // shortcuts
using ItemConfigFunc = std::function<void( XQItem* item, const QString& attrValue, XQNodePtr contentNode, XQNodePtr sheetNode )>; using ItemConfigFunc = std::function<void( XQItem* item, const QString& attrValue, XQNodePtr contentNode, XQNodePtr sheetNode )>;

View File

@@ -113,6 +113,7 @@ XQItemType* XQItemType::replaceAttribute( const QVariant& newValue, int role )
// Gibt es den geänderten ItemType schon? // Gibt es den geänderten ItemType schon?
QString newKey = myClone->makeItemTypeKey(); QString newKey = myClone->makeItemTypeKey();
// jawoll // jawoll
if( s_ItemTypeMap.contains( newKey ) ) if( s_ItemTypeMap.contains( newKey ) )
{ {
// abräumen ... // abräumen ...
@@ -134,22 +135,9 @@ XQItemType* XQItemType::replaceAttribute( const QVariant& newValue, int role )
} }
//! formatiert den content() string eines items.
QVariant XQItemType::formatText( const XQItem& item ) const
{
XQItem::UnitType uType = unitType();
//qDebug() << " --- formatText: " << XQItem::fetchUnitTypeToString( uType);
const QString& cont = item.rawText();
if( uType != XQItem::NoUnitType )
return formatToSI( cont, uType );
return cont;
}
//! formatiert einen zahlenwert als string mit einheit. //! formatiert einen zahlenwert als string mit einheit.
QString XQItemType::formatToSI( const QString& valueTxt, XQItem::UnitType unitType ) const QString XQItemType::formatToSI( const QString& valueTxt, XQItem::UnitType unitType )
{ {
if( valueTxt.isEmpty() ) if( valueTxt.isEmpty() )
@@ -180,18 +168,18 @@ QString XQItemType::formatToSI( const QString& valueTxt, XQItem::UnitType unitTy
strVal = sysLocale.toString(nVal, 'f', 2); strVal = sysLocale.toString(nVal, 'f', 2);
strPrefix = s_PrefixExponentMap.key(exp); strPrefix = s_PrefixExponentMap.key(exp);
//qDebug() << " convert: " << dVal << " : " << valueTxt << ": " << strVal << ":" << exp << " : " << strPrefix << ": " << nVal; //qDebug() << " convert: " << dVal << " : " << valueTxt << ": " << strVal << ":" << exp << " : " << strPrefix << ": " << nVal;
QString unitStr = XQItem::fetchUnitTypeToString( unitType);
return QString("%1 %2%3").arg( strVal, strPrefix, unitTypeToString() ); return QString("%1 %2%3").arg( strVal, strPrefix, unitStr );
} }
//! entfernt die einheit aus einem formatierten string //! entfernt die einheit aus einem formatierten string
QString XQItemType::unFormatFromSI(const QString& formText ) const QString XQItemType::unFormatFromSI(const QString& formText )
{ {
QString input = formText.simplified(); const QString input = formText.simplified();
// #1: strip numeric part // #1: strip numeric part
if( input.isEmpty() ) if( input.isEmpty() )
return input; return input;

View File

@@ -40,17 +40,14 @@ public:
QVariant data( int role ) const override; QVariant data( int role ) const override;
void setData(const QVariant& value, int role ) override; void setData(const QVariant& value, int role ) override;
QVariant formatText( const XQItem& item ) const;
QString formatToSI(const QString& rawText, XQItem::UnitType unitType ) const;
QString unFormatFromSI(const QString& valueText ) const;
int roleForAttributeKey( const QString& attrKey ); int roleForAttributeKey( const QString& attrKey );
XQItemType* replaceAttribute(const QVariant& newValue, int role ); XQItemType* replaceAttribute(const QVariant& newValue, int role );
QString makeItemTypeKey(); QString makeItemTypeKey();
static XQItemType* staticItemType(); static XQItemType* staticItemType();
static QString formatToSI(const QString& rawText, XQItem::UnitType unitType );
static QString unFormatFromSI(const QString& valueText );
protected: protected:

View File

@@ -19,6 +19,7 @@
#include <QQmlApplicationEngine> #include <QQmlApplicationEngine>
#include <QUrl> #include <QUrl>
#include <QQmlContext> #include <QQmlContext>
#include <QStyleFactory>
#include <xqchildmodel.h> #include <xqchildmodel.h>
#include <xqquickwidget.h> #include <xqquickwidget.h>
@@ -73,60 +74,67 @@ XQChildModel* createChildModel()
} }
/*
class DummyModel : public XQChildModel
{
public: CONFIG += precompile_header
PRECOMPILED_HEADER = pch.h
DummyModel() // pch.h Precompiled Header für Qt-Projekt
{
initModel( c_ChildModelName ); Stelle sicher, dass pch.h im Projektordner liegt und in den .cpp-Dateien eingebunden wird:
XQNodeFactory treeLoader;
// xml daten laden
XQNodePtr rawTree = treeLoader.load_tree( qPrintable(c_DocumentFileName1) );
// versteckten root node ignorieren
XQNodePtr contentRoot = rawTree->first_child();
addModelData( contentRoot->first_child() );
//XQTreeTable* treeTable = new XQTreeTable; C++
//treeTable->setModel(this); #include "pch.h"
//setTreeTable( treeTable );
//treeTable->show(); #ifndef PCH_H
} #define PCH_H
};
// Qt Core
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtCore/QObject>
#include <QtCore/QTimer>
#include <QtCore/QDateTime>
// Qt GUI
#include <QtGui/QGuiApplication>
#include <QtGui/QIcon>
#include <QtGui/QPixmap>
// Qt Widgets (falls verwendet)
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QLabel>
// STL
#include <vector>
#include <string>
#include <map>
#include <memory>
#endif // PCH_H
*/
using namespace Qt::Literals::StringLiterals; using namespace Qt::Literals::StringLiterals;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
/*
// Signal für einzelne QStandardItem-Änderungen
connect(model, &QStandardItemModel::itemChanged,
this, [](QStandardItem *changedItem){
QVariant state = changedItem->data(Qt::CheckStateRole);
qDebug() << "Neuer Check-State:" << state.toInt();
});
*/
/*
QApplication app(argc, argv); QApplication app(argc, argv);
//app.setStyle("fusion"); //qDebug() << QStyleFactory::keys();
//QApplication::setStyle("fusion");
//QApplication::setStyle("windowsvista");
//QApplication::setStyle("windows");
XQMainWindow window; XQMainWindow window;
window.show(); window.show();
*/
/*
QApplication app(argc, argv); QApplication app(argc, argv);
XQMainWindow::setupWorkingDir(); XQMainWindow::setupWorkingDir();
XQItemFactory::instance().initItemFactory( c_ModelSheetFileName ); XQItemFactory::instance().initItemFactory( c_ModelSheetFileName );
@@ -152,6 +160,7 @@ connect(model, &QStandardItemModel::itemChanged,
qDebug() << " hhakl!"; qDebug() << " hhakl!";
*/
return app.exec(); return app.exec();
} }

View File

@@ -28,10 +28,10 @@ void XQNodeStore::dumpList( const QString& title ) const
} }
//! kostruktor. übergibt command-type und die aufrufende modelView. //! kostruktor. übergibt command-type und die aufrufende viewModel.
XQCommand::XQCommand(CmdType cmdType, XQViewModel* modelView ) XQCommand::XQCommand(CmdType cmdType, XQViewModel* viewModel )
: _cmdType{ cmdType }, _viewModel(modelView) : _cmdType{ cmdType }, _viewModel(viewModel)
{ {
} }
@@ -108,20 +108,22 @@ void XQCommand::setOriginIndex( const QModelIndex& origin )
void XQCommand::saveNodes( const QModelIndexList& list ) void XQCommand::saveNodes( const QModelIndexList& list )
{ {
clear(); clear();
// über jede zeil // über jede zeile
for( auto entry : list ) for( auto entry : list )
{ {
// knoten holen // knoten holen
const XQNodePtr& contentNode = XQItem::xqItemFromIndex( entry ).contentNode(); const XQNodePtr& contentNode = XQItem::xqItemFromIndex( entry ).contentNode();
// hier speichern wir den original knoten, nicht einen clone, wie im clipboard. // hier speichern wir den original knoten, nicht einen clone, wie im clipboard.
push_back( {entry.row(), contentNode->own_pos(), contentNode } ); // obacht: bei einem Header is der content node null
if(contentNode)
push_back( {entry.row(), contentNode->own_pos(), contentNode } );
} }
} }
//! erzeugt einen string aus dem command-type, fürs debuggen. //! erzeugt einen string aus dem command-type, fürs debuggen.
QString XQCommand::toString() QString XQCommand::toString() const
{ {
static QMap<CmdType,QString> s_CmdTypeMap static QMap<CmdType,QString> s_CmdTypeMap

View File

@@ -66,7 +66,7 @@ public:
cmdExtern //?? cmdExtern //??
}; };
XQCommand(CmdType cmdType, XQViewModel* modelView ); XQCommand(CmdType cmdType, XQViewModel* viewModel );
virtual ~XQCommand(); virtual ~XQCommand();
CmdType commandType() const; CmdType commandType() const;
@@ -80,7 +80,7 @@ public:
void redo() override; void redo() override;
void undo() override; void undo() override;
QString toString(); QString toString() const;
protected: protected:

View File

@@ -1,206 +0,0 @@
/***************************************************************************
source::worx xtree
Copyright © 2024-2025 c.holzheuer
christoph.holzheuer@gmail.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
***************************************************************************/
#include <xqmodelsectionlist.h>
//! kontstruktor. übergibt den start-index und einen model-knoten mit der beschreibung
//! der datenknoten.
XQModelSection::XQModelSection(const QModelIndex& modelIndex, XQNodePtr sheetNode)
: _modelIndex{ modelIndex }, _sectionRootNode{ sheetNode }
{
}
//! elementvergleich.
bool XQModelSection::operator==(const XQModelSection& other) const
{
return _modelIndex == other._modelIndex && _sectionRootNode == other._sectionRootNode;
}
//! true wenn der start-index valide und ein model-knoten vorhanden.
bool XQModelSection::isValid() const
{
return _modelIndex.isValid() && _sectionRootNode;
}
QModelIndex XQModelSection::persistentModelIndex() const
{
return _modelIndex.operator QModelIndex();
}
XQNodePtr XQModelSection::sectionRootNode() const
{
return _sectionRootNode;
}
//! Gibt den sheet-node zurück, das ist die model-beschreibung,
//! siehe modelsheet.xml:
//! <section>
//! <header>
//! <data> <- dort
//! __fix! das versteht doch kein mensch!
XQNodePtr XQModelSection::sheetRootNode() const
{
return _sectionRootNode->find_child_by_tag_name( c_ModelSheet );
}
//! Gibt den content root node zurück, das ist der
//! zeiger auf die realen inhalte.
XQNodePtr XQModelSection::contentRootNode() const
{
return _contentRootNode;
}
void XQModelSection::setContentRootNode( const XQNodePtr contentRootNode )
{
_contentRootNode = contentRootNode;
}
//! gibt die zeile des start-index zurück.
int XQModelSection::XQModelSection::row() const
{
return _modelIndex.row();
}
//! gibt den 'content type' zurück.
const QString& XQModelSection::contentType() const
{
return _sectionRootNode->attribute( c_ContentType );
}
//! gibt das dieser section entsprechende header-item zurück.
XQItem& XQModelSection::XQModelSection::headerItem() const
{
return XQItem::xqItemFromIndex( _modelIndex );
}
//! testet, ob die unter 'sectionKey' eine gültige section vorhanden ist.
bool XQModelSectionList::hasValidSection(const QString& sectionKey) const
{
if (!contains(sectionKey) )
return false;
return at(sectionKey).isValid();
}
//! gibt für einen model index die 'zuständige' section zurück.
const XQModelSection& XQModelSectionList::sectionFromIndex( const QModelIndex& index ) const
{
return sectionFromRow( index.row() );
}
//! gibt für eine zeile die 'zuständige' section zurück: der bestand an section wird
//! nach der passenden section durchsucht.
const XQModelSection& XQModelSectionList::sectionFromRow(int itemRow ) const
{
int i = size() - 1;
for (; i >= 0; --i)
{
if ( at(i).persistentModelIndex().row() < itemRow )
return at(i);
}
static XQModelSection s_DummySection;
return s_DummySection;
}
//! ermittelt die erste zeile einer section.
int XQModelSectionList::firstRow(const QModelIndex& idx) const
{
return sectionFromRow(idx.row() ).row();
}
//! ermittelt die zeile unterhalb des gegebenen modelindex,
//! zum einfügen neuer items ebendort.
int XQModelSectionList::lastRow(const QModelIndex& idx) const
{
return lastRow(sectionFromRow(idx.row()));
}
//! ermittelt die zeile unterhalb der gegebenen section,
//! zum einfügen neuer items ebendort.
int XQModelSectionList::lastRow(const XQModelSection& section ) const
{
//qDebug() << " -- last row in section: " << section.modelIndex.data().toString() << " --> " << section.modelIndex.row();
// row() der section unterhalb dieser
// __fix? index mit speichern?
int index = indexOf(section);
if (index > -1)
{
// last section? return last row of model
if (index == size() - 1)
return section.persistentModelIndex().model()->rowCount();// - 1;
// return row above the row of the next section -> last row of given section
return at(index+1).row();
}
return -1;
}
//! gibt alle sections aus, zum ankucken.
void XQModelSectionList::dump() const
{
qDebug() << " --- sections dump(): " <<size() << " entries.";
for( int i = 0; i<size(); ++i )
{
QModelIndex idx = at(i).persistentModelIndex();
qDebug() << " --- sections:" << i << "row: " << idx.row() << " keyOf(i): " << keyOf(i) << " indexData: "<< idx.data().toString() << " itemData: " << XQItem::xqItemFromIndex(idx).data(Qt::DisplayRole).toString();
}
}

View File

@@ -0,0 +1,207 @@
/***************************************************************************
source::worx xtree
Copyright © 2024-2025 c.holzheuer
christoph.holzheuer@gmail.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
***************************************************************************/
#include <xqsectionmanager.h>
//! kontstruktor. übergibt den start-index und einen model-knoten mit der beschreibung
//! der datenknoten.
XQModelSection::XQModelSection(const QModelIndex& modelIndex, XQNodePtr sheetNode)
: _modelIndex{ modelIndex }, _sectionSheetRootNode{ sheetNode }
{
}
//! elementvergleich.
bool XQModelSection::operator==(const XQModelSection& other) const
{
return _modelIndex == other._modelIndex && _sectionSheetRootNode == other._sectionSheetRootNode;
}
//! true wenn der start-index valide und ein model-knoten vorhanden.
bool XQModelSection::isValid() const
{
return _modelIndex.isValid() && _sectionSheetRootNode;
}
QModelIndex XQModelSection::startIndex() const
{
return _modelIndex.operator QModelIndex();
}
XQNodePtr XQModelSection::sectionRootNode() const
{
return _sectionSheetRootNode;
}
//! Gibt den sheet-node zurück, das ist die model-beschreibung,
//! siehe modelsheet.xml:
//! <section>
//! <header>
//! <data> <- dort
//! __fix! das versteht doch kein mensch!
XQNodePtr XQModelSection::sheetRootNode() const
{
return _sectionSheetRootNode->find_child_by_tag_name( c_ModelSheet );
}
//! Gibt den content root node zurück, das ist der
//! zeiger auf die realen inhalte.
XQNodePtr XQModelSection::contentRootNode() const
{
return _contentRootNode;
}
void XQModelSection::setContentRootNode( const XQNodePtr contentRootNode ) const
{
_contentRootNode = contentRootNode;
}
//! gibt die zeile des start-index zurück.
int XQModelSection::XQModelSection::firstRow() const
{
return _modelIndex.row();
}
//! gibt den 'content type' zurück.
const QString& XQModelSection::contentType() const
{
//qDebug() << " ---AUA & AUS!";
return _sectionSheetRootNode->attribute( c_ContentType );
}
//! gibt das dieser section entsprechende header-item zurück.
XQItem& XQModelSection::XQModelSection::headerItem() const
{
return XQItem::xqItemFromIndex( _modelIndex );
}
//! testet, ob die unter 'sectionKey' eine gültige section vorhanden ist.
bool XQSectionManager::hasValidSection(const QString& sectionKey) const
{
if (!_sections.contains(sectionKey) )
return false;
return _sections.at(sectionKey).isValid();
}
const XQModelSection& XQSectionManager::sectionByKey( const QString& sectionKey ) const
{
if( hasValidSection( sectionKey ) )
return _sections.at(sectionKey);
throw XQException( "No section for key", sectionKey);
}
//! gibt für eine zeile die 'zuständige' section zurück: der bestand an section wird
//! nach der passenden section durchsucht.
const XQModelSection& XQSectionManager::sectionByRow(int itemRow ) const
{
for (const auto& section : _sections)
{
qDebug() << " ---- SEC: " << itemRow << " -> " << section.firstRow() << " : " << lastRow( section );
XQSectionRange range = sectionRange(section);
if( itemRow >= range.firstRow && itemRow <= range.lastRow)
return section;
}
throw XQException( "No section for item row", QString::number(itemRow));
}
const XQModelSection& XQSectionManager::createSection(const QModelIndex& modelIndex, XQNodePtr sheetNode)
{
const QString& sectionKey = sheetNode->attribute(c_ContentType);
//qDebug() << " --- create Section: " << sectionKey << ": " << modelIndex.data().toString();
XQModelSection section(modelIndex, sheetNode );
_sections.addAtKey( sectionKey, section);
return sectionByKey(sectionKey);
}
//! ermittelt die zeile unterhalb des gegebenen modelindex,
//! zum einfügen neuer items ebendort.
int XQSectionManager::lastRow(const XQModelSection& section ) const
{
//qDebug() << " -- last row in section: " << section.startIndex().data().toString() << " --> " << section.startIndex().row();
// row() der section unterhalb dieser
// __fix? index mit speichern?
int index = _sections.indexOf(section);
if (index > -1)
{
// last section? return last row of model
if (index == _sections.size() - 1)
return section.startIndex().model()->rowCount() - 1;
// return row above the row of the next section -> last row of given section
return _sections.at(index+1).firstRow() - 1;
}
return -1;
}
XQSectionRange XQSectionManager::sectionRange(const XQModelSection& section ) const
{
return XQSectionRange{ section.startIndex().row(), lastRow(section) };
}
//! gibt alle sections aus, zum ankucken.
void XQSectionManager::dump() const
{
qDebug() << " --- sections dump(): " <<_sections.size() << " entries.";
for( int i = 0; i<_sections.size(); ++i )
{
QModelIndex idx = _sections.at(i).startIndex();
qDebug() << " --- sections:" << i << "row: " << idx.row() << " keyOf(i): " << _sections.keyOf(i) << " indexData: "<< idx.data().toString() << " itemData: " << XQItem::xqItemFromIndex(idx).data(Qt::DisplayRole).toString();
}
}

View File

@@ -12,17 +12,18 @@
***************************************************************************/ ***************************************************************************/
#ifndef XQMODELSECTIONLIST_H #ifndef XQSECTIONMANAGER_H
#define XQMODELSECTIONLIST_H #define XQSECTIONMANAGER_H
#include <QPersistentModelIndex> #include <QPersistentModelIndex>
#include <xqmaptor.h> #include <xqmaptor.h>
#include <xqitem.h> #include <xqitem.h>
/**
* @brief Struct containing data for a header section
*/
//! Daten zur beschreibung einer 'sektion' des models.
class XQModelSection class XQModelSection
{ {
@@ -35,13 +36,13 @@ public:
bool operator==(const XQModelSection& other) const; bool operator==(const XQModelSection& other) const;
bool isValid() const; bool isValid() const;
int row() const; int firstRow() const;
QModelIndex persistentModelIndex() const; QModelIndex startIndex() const;
XQNodePtr sectionRootNode() const; XQNodePtr sectionRootNode() const;
XQNodePtr sheetRootNode() const; XQNodePtr sheetRootNode() const;
XQNodePtr contentRootNode() const; XQNodePtr contentRootNode() const;
void setContentRootNode( const XQNodePtr dataRootNode ); void setContentRootNode( const XQNodePtr dataRootNode ) const;
const QString& contentType() const; const QString& contentType() const;
XQItem& headerItem() const; XQItem& headerItem() const;
@@ -50,32 +51,42 @@ protected:
QPersistentModelIndex _modelIndex; QPersistentModelIndex _modelIndex;
XQNodePtr _sectionRootNode{}; mutable XQNodePtr _sectionSheetRootNode{};
XQNodePtr _contentRootNode{}; mutable XQNodePtr _contentRootNode{};
}; };
Q_DECLARE_METATYPE(XQModelSection) Q_DECLARE_METATYPE(XQModelSection)
/** //! Erste und letzte ziele einer XQModelSection
* @brief Maptor containing all header sections. struct XQSectionRange
*/ {
int firstRow{-1};
int lastRow{-1};
};
class XQModelSectionList : public XQMaptor<XQModelSection>
//! struktur, die alle sections enthält
class XQSectionManager
{ {
public: public:
bool hasValidSection(const QString& sectionKey) const; bool hasValidSection(const QString& sectionKey) const;
const XQModelSection& sectionFromRow( int row ) const; const XQModelSection& sectionByKey( const QString& sectionKey ) const;
const XQModelSection& sectionFromIndex( const QModelIndex& index ) const; const XQModelSection& sectionByRow( int row ) const;
int firstRow(const QModelIndex& idx) const; const XQModelSection& createSection(const QModelIndex& modelIndex, XQNodePtr sheetNode);
int lastRow(const QModelIndex& idx) const; int lastRow(const XQModelSection& section ) const;
int lastRow(const XQModelSection& section) const; XQSectionRange sectionRange(const XQModelSection &section) const;
void dump()const override; void dump()const;
protected:
XQMaptor<XQModelSection> _sections;
}; };
#endif // XQMODELSECTIONLIST_H #endif // XQSECTIONMANAGER_H

View File

@@ -35,28 +35,34 @@ XQSelectionModel::XQSelectionModel(QAbstractItemModel* model, QObject* parent)
} }
//! firz //! jetzt die selektierten indices, wie die basisklasse, aber nur die innerhalt einer section.
void XQSelectionModel::select(const QItemSelection& selection, QItemSelectionModel::SelectionFlags command) void XQSelectionModel::select(const QItemSelection& selection, QItemSelectionModel::SelectionFlags command)
{ {
// step #0: fetch selected indices. // step #0: die ursprüngliche selection bestimmen
const QModelIndexList list = selection.indexes(); const QModelIndexList list = selection.indexes();
if (list.isEmpty() || selectedRows().isEmpty() ) if (list.isEmpty() || selectedRows().isEmpty() )
return QItemSelectionModel::select(selection, command); return QItemSelectionModel::select(selection, command);
// fetch first index // step 01: den ersten index bestimmen
QModelIndex firstValid = list.first(); QModelIndex firstValid = list.first();
if (hasSelection() ) if (hasSelection() )
firstValid = selectedRows().first(); firstValid = selectedRows().first();
//XQItem& firstItem = XQItem::xqItemFromIndex(firstValid); // step 02: finde das erste item gültigem content node.
//if( firstItem.isValid() ) XQNodePtr firstNode = XQItem::xqItemFromIndex(firstValid).contentNode();
while( !firstNode)
{ {
firstValid = firstValid.siblingAtRow( firstValid.row()+1);
firstNode = XQItem::xqItemFromIndex(firstValid).contentNode();
}
XQNodePtr firstNode = XQItem::xqItemFromIndex(firstValid).contentNode(); // step 03: selektiere nur knoten, die den gleichen tag_name haben, sich also
// in der selben section befinden
if( firstNode )
{
QItemSelection newSelection; QItemSelection newSelection;
// __fixme! das crasht!
for (const QModelIndex& idx : list) for (const QModelIndex& idx : list)
{ {
XQNodePtr nextNode = XQItem::xqItemFromIndex(idx).contentNode(); XQNodePtr nextNode = XQItem::xqItemFromIndex(idx).contentNode();
@@ -66,5 +72,7 @@ void XQSelectionModel::select(const QItemSelection& selection, QItemSelectionMod
} }
return QItemSelectionModel::select(newSelection, command); return QItemSelectionModel::select(newSelection, command);
} }
// fallback
QItemSelectionModel::select(selection, command); QItemSelectionModel::select(selection, command);
} }

View File

@@ -35,18 +35,34 @@
void showItemList( const XQItemList& list) void showItemList( const XQItemList& list)
{ {
for(const auto& entry : list ) for(const auto& entry : list )
qDebug() << " --- itemList: " << ((XQItem*)entry)->content(); qDebug() << " --- itemList: " << entry->text();
qDebug();
}
void showSelectionList( const QModelIndexList& list)
{
for(const auto& entry : list )
qDebug() << " --- SelectionList: " << entry.data().toString();
qDebug(); qDebug();
} }
//! Konstruktur mit parent. //! Konstruktor mit parent.
XQViewModel::XQViewModel( QObject* parent ) XQViewModel::XQViewModel( QObject* parent )
: QStandardItemModel{ parent }, _itemFactory{ XQItemFactory::instance() } : QStandardItemModel{ parent }, _itemFactory{ XQItemFactory::instance() }
{ {
invisibleRootItem()->setData( "[rootItem]", Qt::DisplayRole ); invisibleRootItem()->setData( "[rootItem]", Qt::DisplayRole );
setItemPrototype( new XQItem ); setItemPrototype( new XQItem );
// auf änderungen kann in den unterklassen reagiert werden
connect(this, &QStandardItemModel::itemChanged, this, [this](QStandardItem *item)
{
XQItem* xqItem = static_cast<XQItem*>(item);
emit xqItemChanged( *xqItem );
});
// not needed
//qRegisterMetaType<XQItem>("XQItem");
} }
@@ -59,7 +75,14 @@ const XQItem& XQViewModel::xqRootItem()
// dynamisch über den ItemData Mechanismus wie in QStandardItem // dynamisch über den ItemData Mechanismus wie in QStandardItem
return *static_cast<XQItem*>(invisibleRootItem()); return *static_cast<XQItem*>(invisibleRootItem());
}
//! Gibt den daten root node des models zurück.
XQNodePtr XQViewModel::contentRootNode()
{
return _contentRoot;
} }
@@ -83,6 +106,16 @@ XQItem& XQViewModel::xqFirstItem(int row) const
return *static_cast<XQItem*>( QStandardItemModel::item(row) ); return *static_cast<XQItem*>( QStandardItemModel::item(row) );
} }
void XQViewModel::expandNewItem(const QModelIndex& index)
{
if( _treeTable )
{
// ... ausklappen...
_treeTable->expand( index );
// ... und markieren
_treeTable->setCurrentIndex( index );
}
}
//! initialisiert dieses model über den namen. Es wird hier //! initialisiert dieses model über den namen. Es wird hier
//! nur die strukur erzeugt, keine inhalte. //! nur die strukur erzeugt, keine inhalte.
@@ -99,9 +132,7 @@ void XQViewModel::initModel(const QString& modelName)
*/ */
setObjectName( modelName ); setObjectName( modelName );
qDebug() << " --- initModel: " << objectName(); // model rootnode finden -> <DocumentTreeModel>
// model rootnode finden -> <DocumentTreeModel>
XQNodePtr modelSheet = _itemFactory.findModelSheet( modelName ); // throws XQNodePtr modelSheet = _itemFactory.findModelSheet( modelName ); // throws
// #1: über alle sections // #1: über alle sections
@@ -111,7 +142,7 @@ void XQViewModel::initModel(const QString& modelName)
const XQNodePtr header = sectionNode->find_child_by_tag_name( c_Header ); const XQNodePtr header = sectionNode->find_child_by_tag_name( c_Header );
if( header ) if( header )
{ {
XQItemList list = _itemFactory.makeRow( XQItemFactory::mHeader, header, nullptr ); XQItemList list = _itemFactory.makeRow( header, nullptr );
addSection(list, sectionNode ); addSection(list, sectionNode );
} }
} }
@@ -122,25 +153,24 @@ void XQViewModel::initModel(const QString& modelName)
//! die section kann erst gültig sein, wenn die items im model gelandet sind, //! die section kann erst gültig sein, wenn die items im model gelandet sind,
//! deswegen ist das hier zusammengefasst. //! deswegen ist das hier zusammengefasst.
//! Wrzeugt dann eine section aus einer frisch erzeugten itemlist. Der erste modelindex //! Erzeugt dann eine section aus einer frisch erzeugten itemlist. Der erste modelindex
//! der liste und der root knoten der model-beschreibung werden gespeichert. //! der liste und der root knoten der model-beschreibung werden gespeichert.
void XQViewModel::addSection(const XQItemList& list, const XQNodePtr& sectionNode ) void XQViewModel::addSection(const XQItemList& list, const XQNodePtr& sheetNode )
{ {
// 1. die liste darf nicht leer sein // 1. die liste darf nicht leer sein
Q_ASSERT(!list.isEmpty()); Q_ASSERT(!list.isEmpty());
// 2. sectionNode muss da sein // 2. sheetNode muss da sein
Q_ASSERT(sectionNode); Q_ASSERT(sheetNode);
// 3. 'ContenType' muss vorhanden sein // 3. 'ContenType' muss vorhanden sein
if( !sectionNode->has_attribute( c_ContentType) ) if( !sheetNode->has_attribute( c_ContentType) )
throw XQException( "section list: Section node needs attribute 'ContentType'!"); throw XQException( "section list: Section node needs attribute 'ContentType'!");
// 5. das erzeugt dann auch valide indices // 5. das erzeugt dann auch valide indices
appendRow(list); appendRow(list);
// 6. jetzt können wir auch die sction erzeugen // 6. jetzt können wir auch die section erzeugen
XQModelSection section(list[0]->index(), sectionNode ); const XQModelSection& section = _sections.createSection( list[0]->index(), sheetNode );
_sections.addAtKey(sectionNode->attribute( c_ContentType), section);
// ... und es der welt mitteilen. // ... und es der welt mitteilen.
emit sectionCreated( section ); emit sectionCreated( section );
@@ -148,11 +178,46 @@ void XQViewModel::addSection(const XQItemList& list, const XQNodePtr& sectionNod
} }
//! SLOT, toggled die section mit dem 'sectionKey' (hier: contentType)
void XQViewModel::onToggleSection(const QString& sectionKey )
{
qDebug() << " --- Model: " << this->objectName() << " should toggle: " << sectionKey << ": " << _sections.hasValidSection( sectionKey );
_sections.dump();
if(_sections.hasValidSection( sectionKey ) )
toggleSection( _sections.sectionByKey(sectionKey) );
}
//! toggled die gegebene model section.
void XQViewModel::toggleSection( const XQModelSection& section )
{
if( section.isValid() && _treeTable )
{
XQSectionRange pos = _sections.sectionRange(section);
qDebug() << " --- Section RANGE: " << pos.firstRow << " -> " << pos.lastRow;
_treeTable->toggleRowsHidden(pos.firstRow, pos.lastRow );
}
}
/*
//! SLOT als weiterleitung vom SIGNAL itemchanged
void XQViewModel::onItemChanged(XQItem* item )
{
qDebug() << " --- BASE item changed: " << item->text();
}
*/
//! SLOT, der aufgerufen wird, wenn eine edit-action getriggert wurde. //! SLOT, der aufgerufen wird, wenn eine edit-action getriggert wurde.
void XQViewModel::onActionTriggered(QAction* action) void XQViewModel::onActionTriggered(QAction* action)
{ {
qDebug() << " --- onActionTriggered: count:" << XQNode::s_Count; qDebug() << " --- onActionTriggered: count:" << action->text() <<": " << XQNode::s_Count;
// all selected indices // all selected indices
QModelIndexList selectionList = treeTable()->selectionModel()->selectedRows(); QModelIndexList selectionList = treeTable()->selectionModel()->selectedRows();
@@ -161,6 +226,7 @@ void XQViewModel::onActionTriggered(QAction* action)
switch( cmdType ) switch( cmdType )
{ {
// just handle undo ... // just handle undo ...
case XQCommand::cmdUndo : case XQCommand::cmdUndo :
return _undoStack->undo(); return _undoStack->undo();
@@ -185,45 +251,22 @@ void XQViewModel::onActionTriggered(QAction* action)
// we create a command // we create a command
XQCommand* command = new XQCommand( cmdType, this ); XQCommand* command = new XQCommand( cmdType, this );
QModelIndex currentIndex = treeTable()->currentIndex();
command->setOriginIndex(currentIndex);
// store the row positions of the selected indices // store the row positions of the selected indices
showSelectionList(selectionList);
command->saveNodes( selectionList ); command->saveNodes( selectionList );
command->setOriginIndex( treeTable()->currentIndex() );
// execute command // execute command
_undoStack->push( command ); _undoStack->push( command );
} }
/*
switch (command.commandType())
{
case XQCommand::cmdToggleSection:
return cmdToggleSection( command.originIndex() );
case XQCommand::cmdCut:
return cmdCut( command );
case XQCommand::cmdPaste:
return cmdPaste( command );
case XQCommand::cmdNew:
return cmdNew( command );
case XQCommand::cmdDelete:
return cmdDelete( command );
case XQCommand::cmdMove:
break;
default:
qDebug() << " --- onCommandRedo: default: not handled: " << command.toString();
}
*/
//! führt die 'redo' action des gegebenen commnds aus. //! führt die 'redo' action des gegebenen commnds aus.
void XQViewModel::onCommandRedo( XQCommand& command ) void XQViewModel::onCommandRedo( const XQCommand& command )
{ {
static MemCallMap redoCalls static MemCallMap redoCalls
{ {
@@ -249,45 +292,10 @@ void XQViewModel::onCommandRedo( XQCommand& command )
} }
} }
/*
try
{
switch (command.commandType())
{
case XQCommand::cmdToggleSection:
return cmdToggleSection( command.originIndex() );
break;
// undo Cut -> perform undoCut
case XQCommand::cmdCut:
return cmdCutUndo( command );
// undo Paste -> perform Cut
case XQCommand::cmdPaste:
return cmdPasteUndo( command );
// undo Move -> perform move back
case XQCommand::cmdMove:
// not yet implemented
break;
// undo New -> perform Delete
case XQCommand::cmdNew:
cmdNewUndo( command );
break;
// undo Delete -> perform New
case XQCommand::cmdDelete:
qDebug() << " --- onCommandUndo: delete: " << command.toString();
return cmdDeleteUndo( command );
default:
qDebug() << " --- onCommandUndo: default: not handled: " << command.toString();
}
*/
//! führt die 'undo' action des gegebenen commnds aus. //! führt die 'undo' action des gegebenen commnds aus.
void XQViewModel::onCommandUndo( XQCommand& command ) void XQViewModel::onCommandUndo( const XQCommand& command )
{ {
qDebug() << " --- onCommandUndo: count: " << XQNode::s_Count; qDebug() << " --- onCommandUndo: count: " << XQNode::s_Count;
@@ -319,18 +327,26 @@ void XQViewModel::onCommandUndo( XQCommand& command )
//! markierte knoten entfernen, 'command' enthält die liste //! markierte knoten entfernen, 'command' enthält die liste
void XQViewModel::cmdCut( XQCommand& command ) void XQViewModel::cmdCut( const XQCommand& command )
{ {
int itmPos = command.first().itemPos;
const XQModelSection& section = _sections.sectionByRow( itmPos );
qDebug() << " --- HEADSHOT I: " << itmPos << "->" << section.contentType();
// wir gehen rückwärts über alle gemerkten knoten ... // wir gehen rückwärts über alle gemerkten knoten ...
for (auto it = command.rbegin(); it != command.rend(); ++it) for (auto it = command.rbegin(); it != command.rend(); ++it)
{ {
// ... holen das erste item, das auch den content node enthält // ... holen das erste item, das auch den content node enthält
//const XQNodeBackup& entry = *it; //const XQNodeBackup& entry = *it;
// jetzt löschen, dabei wird die parent-verbindung entfernt // jetzt löschen, dabei wird die parent-verbindung entfernt
const XQNodeBackup& entry = *it; const XQNodeBackup& entry = *it;
XQItem& firstItem = xqFirstItem( (*it).itemPos ); XQItem& firstItem = xqFirstItem( (*it).itemPos );
qDebug() << " --- Cut: " << firstItem.text() << " " << firstItem.row() << " id#" << entry.contentNode->_id; //qDebug() << " --- Cut: " << firstItem.text() << " " << firstItem.row() << " id#" << entry.contentNode->_id;
qDebug() << " ---- command CUT: itemPos: " << entry.itemPos << " nodePos: "<< entry.nodePos << " is " << entry.contentNode->friendly_name();
entry.contentNode->unlink_self(); entry.contentNode->unlink_self();
removeRow(entry.itemPos ); removeRow(entry.itemPos );
@@ -340,31 +356,37 @@ void XQViewModel::cmdCut( XQCommand& command )
//! entfernte knoten wieder einfügen , 'command' enthält die liste //! entfernte knoten wieder einfügen , 'command' enthält die liste
void XQViewModel::cmdCutUndo( XQCommand& command ) void XQViewModel::cmdCutUndo( const XQCommand& command )
{ {
// die anfangsposition // die anfangsposition
int itmPos = command.first().itemPos; int itmPos = command.first().itemPos;
// die 'zuständige' section rausfinden // die 'zuständige' section rausfinden
const XQModelSection& section = _sections.sectionFromRow( itmPos ); const XQModelSection& section = _sections.sectionByRow( itmPos );
qDebug() << " --- HEADSHOT II: " << itmPos << "->" << section.contentType();
// über alle einträge ... // über alle einträge ...
for (auto& entry : command ) for (auto& entry : command )
{ {
const XQNodePtr& savedNode = entry.contentNode; const XQNodePtr& savedNode = entry.contentNode;
// __fix! should not be _contentRoot! // __fix! should not be _contentRoot!
savedNode->add_me_at( entry.nodePos, _contentRoot ); savedNode->add_me_at( entry.nodePos, _contentRoot );
XQItemList list = _itemFactory.makeRow( XQItemFactory::mData, section.sheetRootNode(), savedNode ); XQItemList list = _itemFactory.makeRow( section.sheetRootNode(), savedNode );
insertRow( entry.itemPos, list );
XQItem& firstItem = *((XQItem*)list[0]); XQItem& firstItem = *((XQItem*)list[0]);
qDebug() << " ---- command cut UNDO2: itemPos: " << entry.itemPos << " nodePos: "<< entry.nodePos << " is " << entry.contentNode->friendly_name();
qDebug() << " --- Cut Undo: " << firstItem.text() << " " << firstItem.row() << " id#" << entry.contentNode->_id << " count: " << entry.contentNode.use_count(); qDebug() << " --- Cut Undo: " << firstItem.text() << " " << firstItem.row() << " id#" << entry.contentNode->_id << " count: " << entry.contentNode.use_count();
insertRow( entry.itemPos, list );
} }
} }
//! clipboard inhalte einfügen //! clipboard inhalte einfügen
void XQViewModel::cmdPaste( XQCommand& command ) void XQViewModel::cmdPaste( const XQCommand& command )
{ {
// selection holen ... // selection holen ...
QItemSelectionModel* selectionModel = treeTable()->selectionModel(); QItemSelectionModel* selectionModel = treeTable()->selectionModel();
@@ -379,7 +401,7 @@ void XQViewModel::cmdPaste( XQCommand& command )
int nodePos = item.contentNode()->own_pos()+1; int nodePos = item.contentNode()->own_pos()+1;
// die zugehörige section finden // die zugehörige section finden
const XQModelSection& section = _sections.sectionFromRow( insRow-1 ); const XQModelSection& section = _sections.sectionByRow( insRow-1 );
// wir pasten das clipboard // wir pasten das clipboard
for (auto& entry : _clipBoard ) for (auto& entry : _clipBoard )
{ {
@@ -388,7 +410,7 @@ void XQViewModel::cmdPaste( XQCommand& command )
// ... diesen einfügen ... // ... diesen einfügen ...
newNode->add_me_at( nodePos ); newNode->add_me_at( nodePos );
// ... und damit eine frische item-row erzeugen // ... und damit eine frische item-row erzeugen
XQItemList list = _itemFactory.makeRow( XQItemFactory::mData, section.sheetRootNode(), newNode ); XQItemList list = _itemFactory.makeRow( section.sheetRootNode(), newNode );
insertRow( insRow, list ); insertRow( insRow, list );
// die neue item-row selektieren // die neue item-row selektieren
const QModelIndex& selIdx = list[0]->index(); const QModelIndex& selIdx = list[0]->index();
@@ -399,14 +421,16 @@ void XQViewModel::cmdPaste( XQCommand& command )
} }
// unsere änderungen merken fürs 'undo' // unsere änderungen merken fürs 'undo'
command.saveNodes( selectionModel->selectedRows() );
/// fix_xx
const_cast<XQCommand&>(command).saveNodes( selectionModel->selectedRows() );
} }
//! einfügen aus dem clipboard wieder rückgängig machen //! einfügen aus dem clipboard wieder rückgängig machen
void XQViewModel::cmdPasteUndo( XQCommand& command ) void XQViewModel::cmdPasteUndo( const XQCommand& command )
{ {
command.dumpList("Paste UNDO"); command.dumpList("Paste UNDO");
// wir gehen rückwärts über alle markieren knoten ... // wir gehen rückwärts über alle markieren knoten ...
@@ -427,7 +451,7 @@ void XQViewModel::cmdPasteUndo( XQCommand& command )
//! entfernen der selection ohne copy in clipboard. //! entfernen der selection ohne copy in clipboard.
void XQViewModel::cmdDelete( XQCommand& command ) void XQViewModel::cmdDelete( const XQCommand& command )
{ {
// wir gehen rückwärts über alle markieren knoten ... // wir gehen rückwärts über alle markieren knoten ...
for (auto it = command.rbegin(); it != command.rend(); ++it) for (auto it = command.rbegin(); it != command.rend(); ++it)
@@ -435,83 +459,85 @@ void XQViewModel::cmdDelete( XQCommand& command )
// ... holen das erste item, das auch den content node enthält // ... holen das erste item, das auch den content node enthält
const XQNodeBackup& entry = *it; const XQNodeBackup& entry = *it;
XQItem& firstItem = xqFirstItem( (*it).itemPos ); XQItem& firstItem = xqFirstItem( (*it).itemPos );
qDebug() << " --- Cut: " << firstItem.text() << " " << firstItem.row(); qDebug() << " --- delete: " << firstItem.text() << " " << firstItem.row();
// jetzt löschen // jetzt löschen
entry.contentNode->unlink_self(); entry.contentNode->unlink_self();
removeRow(entry.itemPos ); removeRow(entry.itemPos );
} }
} }
//! macht 'delete' wirder rückgängig. //! macht 'delete' wieder rückgängig.
void XQViewModel::cmdDeleteUndo( XQCommand& command ) void XQViewModel::cmdDeleteUndo( const XQCommand& command )
{ {
for (const auto& entry : command)
{
qDebug() << " --- delete UNDo: " << entry.contentNode->friendly_name();
}
cmdCutUndo(command);
} }
//! legt eine neue, leere zeile an. //! legt eine neue, leere zeile an.
void XQViewModel::cmdNew( XQCommand& command ) void XQViewModel::cmdNew( const XQCommand& command )
{ {
// __fix
/*
const QModelIndex& origin = command.originIndex(); const QModelIndex& origin = command.originIndex();
if( !origin.isValid() )
throw XQException("cmdNewRow failed: index not valid ");
XQItem* target = xqItemFromIndex( origin ); XQItem& target = xqItemFromIndex( origin );
// current data node // current data node
XQNodePtr node = target->contentNode(); XQNodePtr node = target.contentNode();
// we create a new data node
// we create a new data node XQNodePtr newNode = XQNode::make_node( node->tag_name(), node->tag_value() );
//XQNodePtr newNode = new XQNodePtr( node->tag_name(), node->parent() );
XQNodePtr newNode = XQNode::make_node( node->tag_name(), node->tag_value(), node->parent() );
// store node in node->parent() // store node in node->parent()
//node->add_before_me( newNode ); newNode->add_me_at( node->own_pos(), node->parent() );
// store node also in 'command' to enable undo
const XQModelSection& section = _sections.sectionFromIndex( origin );
// create new item row
XQItemList list = _itemFactory.createGenericRow( newNode, section.sheetRootNode );
// add it to the treeview ... //...
const XQModelSection& section = _sections.sectionByRow( origin.row() );
// neue, leere zeile erzeugen ...
XQItemList list =_itemFactory.makeRow( section.sheetRootNode(), newNode );
// ... zur treeview hinzufügen ...
insertRow( origin.row(), list ); insertRow( origin.row(), list );
// ... editierbar machen ...
QModelIndex newIndex = list[0]->index();
treeTable()->setCurrentIndex( newIndex );
treeTable()->edit( newIndex );
// ,,, und fürs undo speichern
const_cast<XQCommand&>(command).saveNodes( {newIndex} );
// ... and make it ...
treeTable()->setCurrentIndex( list[0]->index() );
// ... editable
treeTable()->edit( list[0]->index() );
*/
} }
//! entfernt die neu angelegte zeile. //! entfernt die neu angelegte zeile.
void XQViewModel::cmdNewUndo( XQCommand& command ) void XQViewModel::cmdNewUndo( const XQCommand& command )
{ {
cmdDelete( command );
} }
//! schaltet eine section sichtbar oder unsichtbar. //! schaltet eine section sichtbar oder unsichtbar.
void XQViewModel::cmdToggleSection( XQCommand& command ) void XQViewModel::cmdToggleSection( const XQCommand& command )
{ {
const QModelIndex& index = command.originIndex(); const QModelIndex& index = command.originIndex();
Q_ASSERT(index.isValid()); Q_ASSERT(index.isValid());
const XQModelSection& section = _sections.sectionByRow(index.row());
int fstRow = _sections.firstRow( index ); // Obacht! Das ist hier etwas unsauber, 'toogleSection'' ändert den check-State
int lstRow = _sections.lastRow( index ); // im document-tree, was wiederum die 'toggleSection' auslöst, das gibt also
// einen doppelten Aufruf und wir sind dann wieder im Anfangszustand.
bool hidden =_treeTable->isRowHidden( fstRow, _treeTable->rootIndex() ); //toggleSection( section );
for (int row = fstRow; row < lstRow; ++row )
_treeTable->setRowHidden( row, _treeTable->rootIndex(), !hidden ); emit sectionToggled(section);
emit sectionToggled( _sections.sectionFromIndex(index) );
} }
//! git die treetable zurück //! gibt die treetable zurück
XQTreeTable* XQViewModel::treeTable() XQTreeTable* XQViewModel::treeTable()
{ {
@@ -524,7 +550,7 @@ void XQViewModel::setTreeTable(XQTreeTable* mainView )
{ {
// store view for direct access: the maintree // store view for direct access: the maintree
_treeTable = mainView; _treeTable = mainView;
// connect myself as model to the mainview // set myself as model to the mainview
_treeTable->setModel(this); _treeTable->setModel(this);
XQItemDelegate* delegate = new XQItemDelegate( *this ); XQItemDelegate* delegate = new XQItemDelegate( *this );
_treeTable->setItemDelegate( delegate ); _treeTable->setItemDelegate( delegate );

View File

@@ -22,7 +22,7 @@
#include <QtQmlIntegration> #include <QtQmlIntegration>
#include <xqsimpleclipboard.h> #include <xqsimpleclipboard.h>
#include <xqmodelsectionlist.h> #include <xqsectionmanager.h>
#include <xqitemfactory.h> #include <xqitemfactory.h>
#include <xqcontextmenu.h> #include <xqcontextmenu.h>
@@ -37,7 +37,7 @@ class XQCommand;
class XQViewModel : public QStandardItemModel class XQViewModel : public QStandardItemModel
{ {
Q_OBJECT Q_OBJECT
//QML_ELEMENT QML_ELEMENT
public: public:
@@ -54,78 +54,65 @@ public:
virtual void initModel( const QString& modelName); virtual void initModel( const QString& modelName);
void expandNewItem(const QModelIndex& index);
void toggleSection( const XQModelSection& section );
//little helpers //little helpers
const XQItem& xqRootItem(); const XQItem& xqRootItem();
XQNodePtr contentRootNode();
XQItem& xqItemFromIndex(const QModelIndex& index) const; XQItem& xqItemFromIndex(const QModelIndex& index) const;
XQItem& xqFirstItem(int row) const; XQItem& xqFirstItem(int row) const;
// undo-/redo-able stuff // undo-/redo-able stuff
virtual void cmdToggleSection( XQCommand& command ); virtual void cmdToggleSection( const XQCommand& command );
virtual void cmdCut( XQCommand& command ); virtual void cmdCut( const XQCommand& command );
virtual void cmdCutUndo( XQCommand& command ); virtual void cmdCutUndo( const XQCommand& command );
virtual void cmdPaste( XQCommand& command ); virtual void cmdPaste( const XQCommand& command );
virtual void cmdPasteUndo( XQCommand& command ); virtual void cmdPasteUndo( const XQCommand& command );
virtual void cmdDelete( XQCommand& command ); virtual void cmdDelete( const XQCommand& command );
virtual void cmdDeleteUndo( XQCommand& command ); virtual void cmdDeleteUndo( const XQCommand& command );
virtual void cmdNew( XQCommand& command ); virtual void cmdNew( const XQCommand& command );
virtual void cmdNewUndo( XQCommand& command ); virtual void cmdNewUndo( const XQCommand& command );
// Derzeit wird die default-implementierung von data/setData genutzt. hier wäre dann die
// Stelle um setData & data an externe 'handler' umzubiegen, siehe giovannies 'model-injection'
signals:
/*! void xqItemChanged( const XQItem& item );
void itemCreated( XQItem* newItem );
Derzeit wird die default-implementierung von data/setData genutzt. hier wäre dann die void sectionCreated( const XQModelSection& section );
Stelle um setData & data an externe 'handler' umzubiegen, siehe giovannies 'model-injection' void sectionToggled( const XQModelSection& section );
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
{
return QStandardItemModel::data( index, role );
}
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override
{
qDebug() << " --- setData: " << value.toString();
return QStandardItemModel::setData( index, value, role );
}
*/
public slots: public slots:
virtual void onShowContextMenu(const QPoint& point); virtual void onShowContextMenu(const QPoint& point);
virtual void onActionTriggered(QAction* action); virtual void onActionTriggered(QAction* action);
virtual void onToggleSection(const QString& sectionKey );
// handle XQCommands ( == UndoCommand ) // handle XQCommands ( == UndoCommand )
virtual void onCommandRedo( XQCommand& command ); virtual void onCommandRedo( const XQCommand& command );
virtual void onCommandUndo( XQCommand& command ); virtual void onCommandUndo( const XQCommand& command );
signals:
void itemCreated( XQItem* newItem );
void sectionCreated( const XQModelSection& section );
void sectionToggled( const XQModelSection& section );
protected: protected:
void addSection(const XQItemList& list, const XQNodePtr& sheetNode ); void addSection(const XQItemList& list, const XQNodePtr& sheetNode );
virtual void initContextMenu(){} virtual void initContextMenu() = 0;
// __fixme: should be created from xml // __fixme: should be created from xml
virtual void setupViewProperties(); virtual void setupViewProperties();
protected: protected:
using MemCall = void (XQViewModel::*)(XQCommand&); using MemCall = void (XQViewModel::*)(const XQCommand&);
using MemCallMap = QMap<XQCommand::CmdType,MemCall>; using MemCallMap = QMap<XQCommand::CmdType,MemCall>;
// das eine reference auf ein globales singleton // das eine reference auf ein globales singleton
XQItemFactory& _itemFactory; XQItemFactory& _itemFactory;
XQSimpleClipBoard _clipBoard; XQSimpleClipBoard _clipBoard;
XQModelSectionList _sections; XQSectionManager _sections;
XQTreeTable* _treeTable{}; XQTreeTable* _treeTable{};
//QAbstractItemView* _treeTable{}; //QAbstractItemView* _treeTable{};
QUndoStack* _undoStack{}; QUndoStack* _undoStack{};
XQContextMenu* _contextMenu{}; XQContextMenu* _contextMenu{};

View File

@@ -53,6 +53,7 @@ namespace znode
//! einfache tree-klasse, besonderheit: der nutzlast-string-type ist templated. //! einfache tree-klasse, besonderheit: der nutzlast-string-type ist templated.
template<typename str_t> template<typename str_t>
//class zbasic_node : public zid, public zpayload<str_t>, public std::enable_shared_from_this<zbasic_node<str_t>>
class zbasic_node : public zid, public zpayload<str_t>, public std::enable_shared_from_this<zbasic_node<str_t>> class zbasic_node : public zid, public zpayload<str_t>, public std::enable_shared_from_this<zbasic_node<str_t>>
{ {
@@ -78,6 +79,7 @@ namespace znode
zweak_node _parent; zweak_node _parent;
znode_list _children; znode_list _children;
// functor, der auf pointer gleichheit prüft.
struct match_node struct match_node
{ {
match_node( zbasic_node* match ) match_node( zbasic_node* match )
@@ -95,9 +97,11 @@ namespace znode
public: public:
//! shortcut auf std::make_shared... //! shortcut auf std::make_shared...
static zshared_node make_node( str_cref arg1, str_cref arg2 = "" , zshared_cref parent = nullptr ) //! beachte: der eltern-knoten wird hier nicht gesetzt, der neue knoten
//! wird nirgends eingefügt.
static zshared_node make_node( str_cref arg1, str_cref arg2 = "" )
{ {
return std::make_shared<zbasic_node>( arg1, arg2, parent ); return std::make_shared<zbasic_node>( arg1, arg2 );
} }
//! leerer konstruktor //! leerer konstruktor
@@ -136,7 +140,7 @@ namespace znode
zbasic_node(const zbasic_node&) = delete; zbasic_node(const zbasic_node&) = delete;
zbasic_node& operator=(const zbasic_node&) = delete; zbasic_node& operator=(const zbasic_node&) = delete;
// 'move' geht (shared_from_this bleibt gültig) //! 'move' geht (shared_from_this bleibt gültig)
zbasic_node(zbasic_node&&) noexcept = default; zbasic_node(zbasic_node&&) noexcept = default;
zbasic_node& operator=(zbasic_node&&) noexcept = default; zbasic_node& operator=(zbasic_node&&) noexcept = default;
@@ -178,31 +182,31 @@ namespace znode
return _parent.lock(); return _parent.lock();
} }
//! gibt den nachfolge-knoten oder 'end()' zurück.
zshared_node sibling() zshared_node sibling()
{ {
if( !parent() ) if( parent() )
//return zshared_node( make_node("WTF1") ); {
return zshared_node(); znode_list& childs = _parent->_children;
auto it = std::find( childs.begin(), childs.end(), this->shared_from_this() );
znode_list& childs = _parent->_children;
auto it = std::find( childs.begin(), childs.end(), this->shared_from_this() );
if( ++it != childs.end())
return *(it); return *(it);
}
//return zshared_node( make_node("WTF?") ); throw std::runtime_error("sibling(): no parent node");
return zshared_node();
} }
//! gibt den vector mit kind-knoten zurück
inline const znode_list& children() const inline const znode_list& children() const
{ {
return _children; return _children;
} }
//! testet, ob kinder vorhanden sind.
bool has_children() const bool has_children() const
{ {
return !children().empty(); return !children().empty();
} }
//! gibt das erste kind zurück
zshared_node first_child() zshared_node first_child()
{ {
if(!children().empty()) if(!children().empty())
@@ -210,6 +214,7 @@ namespace znode
return nullptr; return nullptr;
} }
//! gibt das letzte kind oder nullptr zurück
zshared_node last_child() zshared_node last_child()
{ {
if(!children().empty()) if(!children().empty())
@@ -237,7 +242,6 @@ namespace znode
int add_child_at( int idx, const zshared_node& node ) int add_child_at( int idx, const zshared_node& node )
{ {
// _fixme! was ist, wenn da schon ein elternknoten ist? // _fixme! was ist, wenn da schon ein elternknoten ist?
_children.insert(children().begin() + idx, node ); _children.insert(children().begin() + idx, node );
node->_parent = this->shared_from_this(); node->_parent = this->shared_from_this();
return int(children().size() - 1); return int(children().size() - 1);
@@ -250,10 +254,9 @@ namespace znode
parent()->add_child_at( offset, this->shared_from_this() ); parent()->add_child_at( offset, this->shared_from_this() );
else else
throw std::runtime_error("add_me_at(offset): no parent node"); throw std::runtime_error("add_me_at(offset): no parent node");
} }
//! fügt einen shard_ptr von 'mir' in die kinderliste des übergebenen knotens ein //! fügt einen shared_ptr von 'mir' in die kinderliste des übergebenen knotens ein
//! und macht diesen zu meinem elternknoten. //! und macht diesen zu meinem elternknoten.
void add_me_at( int offset, const zshared_node& parent_node ) void add_me_at( int offset, const zshared_node& parent_node )
{ {
@@ -266,18 +269,17 @@ namespace znode
{ {
throw std::runtime_error("add_me_at(offset,parent): no parent node"); throw std::runtime_error("add_me_at(offset,parent): no parent node");
} }
} }
//! findet die eigene position im eltern-knoten
int own_pos() int own_pos()
{ {
if( parent()) if( parent())
return parent()->child_pos( this->shared_from_this() ); return parent()->child_pos( this->shared_from_this() );
return -1; return -1;
} }
//int child_pos(zbasic_node* child) //! findet die postion eines kind-knotens
int child_pos(const zshared_node& child) int child_pos(const zshared_node& child)
{ {
//auto pos = std::find_if(children().begin(), children().end(), match_node(child) ); //auto pos = std::find_if(children().begin(), children().end(), match_node(child) );
@@ -287,7 +289,7 @@ namespace znode
return -1; return -1;
} }
//zshared_node unlink_child( zbasic_node* node ) //! findet die postion eines kind-knotens
zshared_node unlink_child( const zshared_node& node ) zshared_node unlink_child( const zshared_node& node )
{ {
auto it = std::find(_children.begin(), _children.end(), node); auto it = std::find(_children.begin(), _children.end(), node);
@@ -315,11 +317,10 @@ namespace znode
{ {
for( auto child : _children ) for( auto child : _children )
{ {
qDebug() << " --#- " << child->name() << " : " << child->has_attribute( attrkey, attrvalue );
if( child->has_attribute( attrkey, attrvalue )) if( child->has_attribute( attrkey, attrvalue ))
return child; return child;
} }
return zshared_node(); return nullptr;
} }
// //
@@ -330,7 +331,7 @@ namespace znode
if( child->tag_name() == tagname ) if( child->tag_name() == tagname )
return child; return child;
} }
return zshared_node(); return nullptr;
} }
zshared_node find_child_by_id( int id ) zshared_node find_child_by_id( int id )
@@ -340,46 +341,7 @@ namespace znode
if (child->_id == id) if (child->_id == id)
return child; return child;
} }
return zshared_node(); return nullptr;
}
void dump(int indent = 0) const
{
// fix_me!
qDebug() << std::string(indent * 2, ' ').c_str() << this->to_string();
//qDebug() << to_string();
//qDebug() << '\n';// std::endl;
if (!children().empty())
{
for (auto child : _children)
{
//qDebug() << " --- type: " << typeid(child).name();
child.get()->dump( indent + 1 );
}
}
}
template<typename T>
bool for_each_x( T func, int depth = 0 )
//bool for_each( auto func ) const
{
if( !apply( func, depth ) )
return false;
if( !children().empty() )
{
for( auto child : _children )
{
if( !child->for_each( func, depth+1 ) )
return false;
}
}
return true;
} }
// find ... // find ...
@@ -392,22 +354,6 @@ namespace znode
}; };
class zbasic_node_walker
{
public:
virtual void begin()
{}
template<typename str_t>
void for_each_node( zbasic_node<str_t>* node );
virtual void end()
{}
};
} //namespace znode } //namespace znode

View File

@@ -100,7 +100,7 @@ namespace znode
//parent->add_child( new_node ); //parent->add_child( new_node );
//zbasic_node<str_t>* new_node = new zbasic_node<str_t>( node.name(), node.child_value(), parent ); //zbasic_node<str_t>* new_node = new zbasic_node<str_t>( node.name(), node.child_value(), parent );
zshared_node new_node = zbasic_node<str_t>::make_node( xml_node.name(), xml_node.child_value(), parent ); zshared_node new_node = zbasic_node<str_t>::make_node( xml_node.name(), xml_node.child_value() );
parent->add_child( new_node ); parent->add_child( new_node );
if( !xml_node.attributes().empty() ) if( !xml_node.attributes().empty() )

View File

@@ -4,9 +4,6 @@
#include <vector> #include <vector>
#include <map> #include <map>
//#include <znode_stringmap.h>
//#include <znode_attributes.h>
namespace znode namespace znode
{ {
template<typename str_t> template<typename str_t>

View File

@@ -73,12 +73,23 @@ public:
return _data.end(); return _data.end();
} }
auto begin() const
{
return _data.begin();
}
auto end() const
{
return _data.end();
}
inline int size() const inline int size() const
{ {
return (int) _data.size(); return (int) _data.size();
} }
inline bool isEmpty() const inline bool isEmpty() const
{ {
return (_data.size()==0); return (_data.size()==0);
@@ -94,13 +105,11 @@ public:
return mapIndex().contains(key); return mapIndex().contains(key);
} }
inline const XQMapIndex& mapIndex() const inline const XQMapIndex& mapIndex() const
{ {
return _index; return _index;
} }
int indexOf( const QString& key ) const int indexOf( const QString& key ) const
{ {
return mapIndex().indexOf(key); return mapIndex().indexOf(key);
@@ -121,7 +130,6 @@ public:
return mapIndex().key( index ); return mapIndex().key( index );
} }
T& operator[]( int index ) T& operator[]( int index )
{ {
if( contains(index) ) if( contains(index) )
@@ -129,7 +137,6 @@ public:
throw XQException("XQMaptor operator[ int index ]: out of range"); throw XQException("XQMaptor operator[ int index ]: out of range");
} }
const T& operator[]( int index ) const const T& operator[]( int index ) const
{ {
if ( contains(index) ) if ( contains(index) )
@@ -150,19 +157,17 @@ public:
T& operator[]( const QString& key ) T& operator[]( const QString& key )
{ {
if( key.isEmpty() || !contains(key) ) if( key.isEmpty() || !contains(key) )
throw XQException("maprow operator[]: key empty || not found: " + key); throw XQException("XQMaptor operator[]: key empty || not found: " + key);
return _data[ _index[key] ]; return _data[ _index[key] ];
} }
const T& operator[]( const QString& key ) const const T& operator[]( const QString& key ) const
{ {
if (key.isEmpty() || !contains(key)) if (key.isEmpty() || !contains(key))
throw XQException("maprow operator[]: key empty || not found: " + key); throw XQException("XQMaptor operator[]: key empty || not found: " + key);
return _data[_index[key]]; return _data[_index[key]];
} }
T& at( const QString& key ) T& at( const QString& key )
{ {
return (*this)[key]; return (*this)[key];
@@ -173,28 +178,54 @@ public:
return (*this)[key]; return (*this)[key];
} }
const T& last() const
{
if(_data.isEmpty())
throw XQException( "XQMaptor last: is empty!" );
return _data.last();
}
const T& first() const
{
if(_data.isEmpty())
throw XQException( "XQMaptor first: is empty!" );
return _data.first();
}
T& last()
{
if(_data.isEmpty())
throw XQException( "XQMaptor last: is empty!" );
return _data.last();
}
T& first()
{
if(_data.isEmpty())
throw XQException( "XQMaptor first: is empty!" );
return _data.first();
}
virtual int add( const T& item ) virtual int add( const T& item )
{ {
_data.push_back( item ); _data.push_back( item );
return _data.size()-1; return _data.size()-1;
} }
virtual void addAtIndex( int index, const T& item ) virtual void addAtIndex( int index, const T& item )
{ {
if(contains(index)) if(contains(index))
throw XQException( "QStringrow::add: index out of range!" ); throw XQException( "XQMaptor add at index: index out of range!" );
_data[index] = item; _data[index] = item;
} }
// convenience method to mimic QMap<T,QString> // convenience method to mimic QMap<T,QString>
virtual void insert( const T& item, const QString& key ) virtual void insert( const T& item, const QString& key )
{ {
addAtKey(key, item ); addAtKey(key, item );
} }
virtual void addAtKey( const QString& key, const T& item ) virtual void addAtKey( const QString& key, const T& item )
{ {
XQMapIndex::iterator pos = _index.find( key ); XQMapIndex::iterator pos = _index.find( key );
@@ -209,7 +240,6 @@ public:
} }
} }
bool addAlias( const QString& key, const QString& alias ) bool addAlias( const QString& key, const QString& alias )
{ {
// look for 'original' key // look for 'original' key
@@ -227,20 +257,17 @@ public:
return true; return true;
} }
void addKey( const QString& key, int index ) void addKey( const QString& key, int index )
{ {
_index.addKey( key, index ); _index.addKey( key, index );
} }
virtual void clear() virtual void clear()
{ {
_data.clear(); _data.clear();
_index.clear(); _index.clear();
} }
virtual bool killEntry( const QString& key ) virtual bool killEntry( const QString& key )
{ {
int idx = indexOf( key ); int idx = indexOf( key );
@@ -249,7 +276,6 @@ public:
return killEntry( (int) idx ); return killEntry( (int) idx );
} }
virtual bool killEntry( int index ) virtual bool killEntry( int index )
{ {
if( index >= this->_data.size() ) if( index >= this->_data.size() )
@@ -261,19 +287,16 @@ public:
return true; return true;
} }
virtual QString toString() const virtual QString toString() const
{ {
return join( ";" ); return join( ";" );
} }
virtual void dump() const virtual void dump() const
{ {
throw XQException("XQMaptor: dump not implemented!" ); throw XQException("XQMaptor: dump not implemented!" );
} }
virtual QString join( const QString& sep, int from=0, int to=-1) const virtual QString join( const QString& sep, int from=0, int to=-1) const
{ {
Q_UNUSED(sep) Q_UNUSED(sep)
@@ -283,7 +306,6 @@ public:
return "--"; return "--";
} }
int replaceKey( const QString& oldkey, const QString& newkey ) int replaceKey( const QString& oldkey, const QString& newkey )
{ {
int idx = indexOf( oldkey ); int idx = indexOf( oldkey );

View File

@@ -31,7 +31,7 @@ void XQContextMenu::addAction(const QString& text, XQCommand::CmdType commandTyp
QAction* newAction = new QAction(text, this); QAction* newAction = new QAction(text, this);
newAction->setData(commandType); newAction->setData(commandType);
_actionMap[commandType] = newAction; _actionMap[commandType] = newAction;
QWidget::addAction(newAction); QMenu::addAction(newAction);
setActionEnabled( commandType, enabled ); setActionEnabled( commandType, enabled );
} }
@@ -53,7 +53,7 @@ void XQContextMenu::addAction(const QIcon& icon, const QString& text, XQCommand:
QAction* newAction = new QAction(icon, text, this); QAction* newAction = new QAction(icon, text, this);
newAction->setData(commandType); newAction->setData(commandType);
_actionMap[commandType] = newAction; _actionMap[commandType] = newAction;
QWidget::addAction(newAction); QMenu::addAction(newAction);
setActionEnabled( commandType, enabled ); setActionEnabled( commandType, enabled );
} }

View File

@@ -14,7 +14,7 @@
#include <xqquickwidget.h> #include <xqquickwidget.h>
XQQuickWidget::XQQuickWidget(QWidget *parent) XQQuickWidget::XQQuickWidget(QWidget* parent)
: QQuickWidget(parent) : QQuickWidget(parent)
{ {

View File

@@ -23,7 +23,7 @@ class XQQuickWidget : public QQuickWidget
public: public:
XQQuickWidget(QWidget *parent = nullptr); XQQuickWidget(QWidget* parent = nullptr);
}; };
#endif // XQQUICKWIDGET_H #endif // XQQUICKWIDGET_H

View File

@@ -38,7 +38,7 @@ XQTreeTable::XQTreeTable(QWidget* parent)
//! gibt die verbundene modelview zurück, cast auf 'model()' //! gibt die verbundene modelview zurück, cast auf 'model()'
XQViewModel* XQTreeTable::modelView() XQViewModel* XQTreeTable::viewModel()
{ {
return static_cast<XQViewModel*>(model()); return static_cast<XQViewModel*>(model());
} }
@@ -48,7 +48,18 @@ XQViewModel* XQTreeTable::modelView()
XQItem& XQTreeTable::xqItemFromIndex(const QModelIndex& index ) XQItem& XQTreeTable::xqItemFromIndex(const QModelIndex& index )
{ {
return modelView()->xqItemFromIndex( index ); return viewModel()->xqItemFromIndex( index );
}
//! rows sichtbar/unsichtbar schalten, von 'fstRow' bis _einschliesslich_
//! 'lstRow'
void XQTreeTable::toggleRowsHidden( int fstRow, int lstRow )
{
bool hidden = isRowHidden( fstRow, rootIndex() );
for (int row = fstRow; row <= lstRow; ++row )
setRowHidden( row, rootIndex(), !hidden );
} }
@@ -71,7 +82,7 @@ void XQTreeTable::currentChanged(const QModelIndex& current, const QModelIndex&
} }
//! firz //! ändert die breite eines header-feldes anhand der maus-position
void XQTreeTable::mouseResizeHeaderEntry(int xpos) void XQTreeTable::mouseResizeHeaderEntry(int xpos)
{ {
@@ -96,7 +107,7 @@ void XQTreeTable::mouseResizeHeaderEntry(int xpos)
} }
//! firz //! behandelt den mouse-drag zur grössenänderung der header-felder.
void XQTreeTable::mouseMoveEvent(QMouseEvent* event) void XQTreeTable::mouseMoveEvent(QMouseEvent* event)
{ {
@@ -106,10 +117,9 @@ void XQTreeTable::mouseMoveEvent(QMouseEvent* event)
bool leftBtn = (event->buttons() & Qt::LeftButton); bool leftBtn = (event->buttons() & Qt::LeftButton);
QPoint eventPos = event->pos(); QPoint eventPos = event->pos();
// splitcursor ist active // splitcursor ist gesetzt
bool splitCursor = (cursor().shape() == Qt::SplitHCursor); bool splitCursor = (cursor().shape() == Qt::SplitHCursor);
// sind wir schon am 'draggen'? // sind wir schon am 'draggen'?
if (_indexToResize.isValid() && splitCursor && leftBtn) if (_indexToResize.isValid() && splitCursor && leftBtn)
{ {

View File

@@ -38,9 +38,11 @@ public:
XQTreeTable(QWidget* parent = nullptr ); XQTreeTable(QWidget* parent = nullptr );
virtual ~XQTreeTable() = default; virtual ~XQTreeTable() = default;
XQViewModel* modelView(); XQViewModel* viewModel();
XQItem& xqItemFromIndex(const QModelIndex& index ); XQItem& xqItemFromIndex(const QModelIndex& index );
void toggleRowsHidden(int fstRow, int lstRow );
protected: protected:
void currentChanged(const QModelIndex& current, const QModelIndex& previous) override; void currentChanged(const QModelIndex& current, const QModelIndex& previous) override;

View File

@@ -2,6 +2,7 @@ QT += core gui widgets quick quickwidgets
# widgets-private # widgets-private
CONFIG += c++20 qmltypes CONFIG += c++20 qmltypes
CONFIG -= qml_debug
QML_IMPORT_NAME = org.sourceworx.qmlcomponents QML_IMPORT_NAME = org.sourceworx.qmlcomponents
QML_IMPORT_MAJOR_VERSION = 1 QML_IMPORT_MAJOR_VERSION = 1
@@ -23,9 +24,9 @@ HEADERS += \
items/xqitemtype.h \ items/xqitemtype.h \
items/xqitemdelegate.h \ items/xqitemdelegate.h \
model/xqcommand.h \ model/xqcommand.h \
model/xqmodelsectionlist.h \
model/xqnode.h \ model/xqnode.h \
model/xqnodewriter.h \ model/xqnodewriter.h \
model/xqsectionmanager.h \
model/xqselectionmodel.h \ model/xqselectionmodel.h \
model/xqsimpleclipboard.h \ model/xqsimpleclipboard.h \
model/xqviewmodel.h \ model/xqviewmodel.h \
@@ -61,9 +62,9 @@ SOURCES += \
items/xqitemdelegate.cpp \ items/xqitemdelegate.cpp \
main.cpp \ main.cpp \
model/xqcommand.cpp \ model/xqcommand.cpp \
model/xqmodelsectionlist.cpp \
model/xqnode.cpp \ model/xqnode.cpp \
model/xqnodewriter.cpp \ model/xqnodewriter.cpp \
model/xqsectionmanager.cpp \
model/xqselectionmodel.cpp \ model/xqselectionmodel.cpp \
model/xqsimpleclipboard.cpp \ model/xqsimpleclipboard.cpp \
model/xqviewmodel.cpp \ model/xqviewmodel.cpp \

View File

@@ -1,13 +1,9 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file alias="modeldata1.xtr">../xml/modeldata1.xtr</file> <file alias="modeldata1.xtr">../xml/modeldata1.xtr</file>
<file alias="modeldata2.xtr">../xml/modeldata2.xtr</file> <file alias="modeldata2.xtr">../xml/modeldata2.xtr</file>
<file alias="modeldata3.xtr">../xml/modeldata3.xtr</file> <file alias="modeldata3.xtr">../xml/modeldata3.xtr</file>
<file alias="modelsheet.xml">../xml/modelsheets.xml</file> <file alias="modelsheet.xml">../xml/modelsheets.xml</file>
<file alias="xqtableview.qml">../qml/xqtableview.qml</file> <file alias="xqtreeview.qml">../qml/xqtreeview.qml</file>
<file alias="HorizontalHeaderViewDelegate.qml">../qml/HorizontalHeaderViewDelegate.qml</file> </qresource>
<file alias="XMain.qml">../qml/XMain.qml</file> </RCC>
<file alias="VerticalHeaderViewDelegate.qml">../qml/VerticalHeaderViewDelegate.qml</file>
<file alias="dummyview.qml">../qml/dummyview.qml</file>
</qresource>
</RCC>

View File

@@ -7,14 +7,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xtree", "xtree.vcxproj", "{
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86 Debug|x64 = Debug|x64
Release|x86 = Release|x86 Release|x64 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D9E56CB4-F99F-4F88-B721-1443A0AFD5D0}.Debug|x86.ActiveCfg = Debug|Win32 {D9E56CB4-F99F-4F88-B721-1443A0AFD5D0}.Debug|x64.ActiveCfg = Debug|x64
{D9E56CB4-F99F-4F88-B721-1443A0AFD5D0}.Debug|x86.Build.0 = Debug|Win32 {D9E56CB4-F99F-4F88-B721-1443A0AFD5D0}.Debug|x64.Build.0 = Debug|x64
{D9E56CB4-F99F-4F88-B721-1443A0AFD5D0}.Release|x86.ActiveCfg = Release|Win32 {D9E56CB4-F99F-4F88-B721-1443A0AFD5D0}.Release|x64.ActiveCfg = Release|x64
{D9E56CB4-F99F-4F88-B721-1443A0AFD5D0}.Release|x86.Build.0 = Release|Win32 {D9E56CB4-F99F-4F88-B721-1443A0AFD5D0}.Release|x64.Build.0 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@@ -5,16 +5,26 @@
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
<Platform>Win32</Platform> <Platform>Win32</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32"> <ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<Platform>Win32</Platform> <Platform>Win32</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{D9E56CB4-F99F-4F88-B721-1443A0AFD5D0}</ProjectGuid> <ProjectGuid>{D9E56CB4-F99F-4F88-B721-1443A0AFD5D0}</ProjectGuid>
<Keyword>QtVS_v304</Keyword> <Keyword>QtVS_v304</Keyword>
<WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'">10.0</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'">10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'">10.0</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'">10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)'=='Release|x64'">10.0</WindowsTargetPlatformVersion>
<QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild> <QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@@ -24,6 +34,12 @@
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v143</PlatformToolset>
@@ -31,13 +47,25 @@
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')"> <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
<Import Project="$(QtMsBuild)\qt_defaults.props" /> <Import Project="$(QtMsBuild)\qt_defaults.props" />
</ImportGroup> </ImportGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'" Label="QtSettings"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'" Label="QtSettings">
<QtInstall>qt691</QtInstall> <QtInstall>qt692</QtInstall>
<QtModules>core;gui;widgets</QtModules> <QtModules>core;gui;quick;quickcontrols2;quickdialogs2;quicklayouts;widgets;quickwidgets</QtModules>
<QtBuildConfig>debug</QtBuildConfig>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="QtSettings">
<QtInstall>qt692</QtInstall>
<QtModules>core;gui;quick;widgets;quickwidgets</QtModules>
<QtBuildConfig>debug</QtBuildConfig> <QtBuildConfig>debug</QtBuildConfig>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="QtSettings"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="QtSettings">
@@ -45,6 +73,11 @@
<QtModules>core;gui;widgets</QtModules> <QtModules>core;gui;widgets</QtModules>
<QtBuildConfig>release</QtBuildConfig> <QtBuildConfig>release</QtBuildConfig>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="QtSettings">
<QtInstall>VS2017x86Default</QtInstall>
<QtModules>core;gui;widgets</QtModules>
<QtBuildConfig>release</QtBuildConfig>
</PropertyGroup>
<Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')"> <Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
<Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." /> <Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
</Target> </Target>
@@ -54,13 +87,22 @@
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(QtMsBuild)\Qt.props" /> <Import Project="$(QtMsBuild)\Qt.props" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(QtMsBuild)\Qt.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'"> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(QtMsBuild)\Qt.props" /> <Import Project="$(QtMsBuild)\Qt.props" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(QtMsBuild)\Qt.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'">
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'">
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@@ -69,6 +111,12 @@
<LanguageStandard>stdcpp17</LanguageStandard> <LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile> </ClCompile>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>items;model;application;widgets;util;nodes;pugixml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'" Label="Configuration"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'" Label="Configuration">
<ClCompile> <ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -81,6 +129,18 @@
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="Configuration"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="Configuration">
<ClCompile> <ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -97,62 +157,70 @@
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<QtRcc Include="xtree.qrc" /> <QtRcc Include="xtree.qrc" />
<QtUic Include="application\xqmainwindow.ui" /> <QtUic Include="application\xqmainwindow.ui" />
<ClCompile Include="application\xqappdata.cpp" /> <ClCompile Include="application\xqappdata.cpp" />
<ClCompile Include="application\xqchildmodelview.cpp" /> <ClCompile Include="application\xqchildmodel.cpp" />
<ClCompile Include="application\xqdocumentstore.cpp" /> <ClCompile Include="application\xqdocumentstore.cpp" />
<ClCompile Include="application\xqmainmodelview.cpp" /> <ClCompile Include="application\xqmainmodel.cpp" />
<ClCompile Include="application\xqmainwindow.cpp" /> <ClCompile Include="application\xqmainwindow.cpp" />
<ClCompile Include="items\xqgenericitem.cpp" />
<ClCompile Include="items\xqitem.cpp" /> <ClCompile Include="items\xqitem.cpp" />
<ClCompile Include="items\xqitemdelegate.cpp" /> <ClCompile Include="items\xqitemdelegate.cpp" />
<ClCompile Include="items\xqitemfactory.cpp" /> <ClCompile Include="items\xqitemfactory.cpp" />
<ClCompile Include="items\xqitemtype.cpp" /> <ClCompile Include="items\xqitemtype.cpp" />
<ClCompile Include="model\xqcommand.cpp" /> <ClCompile Include="model\xqcommand.cpp" />
<ClCompile Include="model\xqitemtype.cpp" />
<ClCompile Include="model\xqitemtypefactory.cpp" />
<ClCompile Include="model\xqnodewriter.cpp" /> <ClCompile Include="model\xqnodewriter.cpp" />
<ClCompile Include="model\xqsectionmanager.cpp" />
<ClCompile Include="model\xqselectionmodel.cpp" /> <ClCompile Include="model\xqselectionmodel.cpp" />
<ClCompile Include="model\xqitem.cpp" />
<ClCompile Include="model\xqmodelview.cpp" />
<ClCompile Include="model\xqmodelsections.cpp" />
<ClCompile Include="model\xqsimpleclipboard.cpp" /> <ClCompile Include="model\xqsimpleclipboard.cpp" />
<ClCompile Include="model\xqitemfactory.cpp" />
<ClCompile Include="model\xqnode.cpp" /> <ClCompile Include="model\xqnode.cpp" />
<ClCompile Include="model\xqviewmodel.cpp" />
<ClCompile Include="nodes\znode.cpp" /> <ClCompile Include="nodes\znode.cpp" />
<ClCompile Include="pugixml\pugixml.cpp" /> <ClCompile Include="pugixml\pugixml.cpp" />
<ClCompile Include="util\xqexception.cpp" /> <ClCompile Include="util\xqexception.cpp" />
<ClCompile Include="widgets\xqitemdelegate.cpp" />
<ClCompile Include="widgets\xqcontextmenu.cpp" /> <ClCompile Include="widgets\xqcontextmenu.cpp" />
<ClCompile Include="widgets\xqtreeview.cpp" /> <ClCompile Include="widgets\xqquickwidget.cpp" />
<ClCompile Include="widgets\xqtreetable.cpp" />
<ClCompile Include="main.cpp" /> <ClCompile Include="main.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<QtMoc Include="application\xqchildmodelview.h" />
</ItemGroup>
<ItemGroup>
<QtMoc Include="application\xqmainmodelview.h" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<QtMoc Include="application\xqmainwindow.h" /> <QtMoc Include="application\xqmainwindow.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtMoc Include="widgets\xqtreetable.h" />
<QtMoc Include="widgets\xqquickwidget.h" />
<QtMoc Include="application\xqdocumentstore.h" /> <QtMoc Include="application\xqdocumentstore.h" />
<ClInclude Include="application\xqappdata.h" /> <ClInclude Include="application\xqappdata.h" />
<ClInclude Include="items\xqgenericitem.h" /> <QtMoc Include="application\xqchildmodel.h" />
<QtMoc Include="application\xqmainmodel.h" />
<ClInclude Include="items\xqitem.h" /> <ClInclude Include="items\xqitem.h" />
<ClInclude Include="items\xqitemdelegate.h" /> <ClInclude Include="items\xqitemdelegate.h" />
<ClInclude Include="items\xqitemfactory.h" /> <ClInclude Include="items\xqitemfactory.h" />
<ClInclude Include="items\xqitemtype.h" /> <ClInclude Include="items\xqitemtype.h" />
<ClInclude Include="model\xqcommand.h" /> <ClInclude Include="model\xqcommand.h" />
<ClInclude Include="model\xqmodelsections.h" />
<ClInclude Include="model\xqnodewriter.h" /> <ClInclude Include="model\xqnodewriter.h" />
<ClInclude Include="model\xqsectionmanager.h" />
<ClInclude Include="model\xqsimpleclipboard.h" /> <ClInclude Include="model\xqsimpleclipboard.h" />
<ClInclude Include="model\xqnode.h" /> <ClInclude Include="model\xqnode.h" />
<QtMoc Include="model\xqviewmodel.h" />
<ClInclude Include="nodes\znode.h" /> <ClInclude Include="nodes\znode.h" />
<ClInclude Include="nodes\znode_attributes.h" />
<ClInclude Include="nodes\znode_factory.h" /> <ClInclude Include="nodes\znode_factory.h" />
<ClInclude Include="nodes\znode_id.h" /> <ClInclude Include="nodes\znode_id.h" />
<ClInclude Include="nodes\znode_iterator.h" /> <ClInclude Include="nodes\znode_iterator.h" />
@@ -166,10 +234,7 @@
<ClInclude Include="util\xqptrmaptor.h" /> <ClInclude Include="util\xqptrmaptor.h" />
<ClInclude Include="util\xsingleton.h" /> <ClInclude Include="util\xsingleton.h" />
<ClInclude Include="util\xtreewalker.h" /> <ClInclude Include="util\xtreewalker.h" />
<QtMoc Include="widgets\xqtreeview.h" />
<QtMoc Include="widgets\xqcontextmenu.h" /> <QtMoc Include="widgets\xqcontextmenu.h" />
<QtMoc Include="widgets\xqitemdelegate.h" />
<QtMoc Include="model\xqmodelview.h" />
<QtMoc Include="model\xqselectionmodel.h" /> <QtMoc Include="model\xqselectionmodel.h" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@@ -76,42 +76,21 @@
<ClCompile Include="model\xqcommand.cpp"> <ClCompile Include="model\xqcommand.cpp">
<Filter>Source Files\model</Filter> <Filter>Source Files\model</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="model\xqitem.cpp">
<Filter>Source Files\model</Filter>
</ClCompile>
<ClCompile Include="model\xqmodelview.cpp">
<Filter>Source Files\model</Filter>
</ClCompile>
<ClCompile Include="model\xqnode.cpp"> <ClCompile Include="model\xqnode.cpp">
<Filter>Source Files\model</Filter> <Filter>Source Files\model</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="application\xqmainmodelview.cpp">
<Filter>Source Files\application</Filter>
</ClCompile>
<ClCompile Include="application\xqmainwindow.cpp"> <ClCompile Include="application\xqmainwindow.cpp">
<Filter>Source Files\application</Filter> <Filter>Source Files\application</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="nodes\znode.cpp"> <ClCompile Include="nodes\znode.cpp">
<Filter>Source Files\nodes</Filter> <Filter>Source Files\nodes</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="widgets\xqitemdelegate.cpp">
<Filter>Source Files\widgets</Filter>
</ClCompile>
<ClCompile Include="widgets\xqtreeview.cpp">
<Filter>Source Files\widgets</Filter>
</ClCompile>
<ClCompile Include="pugixml\pugixml.cpp"> <ClCompile Include="pugixml\pugixml.cpp">
<Filter>Source Files\pugixml</Filter> <Filter>Source Files\pugixml</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="model\xqmodelsections.cpp">
<Filter>Source Files\model</Filter>
</ClCompile>
<ClCompile Include="model\xqselectionmodel.cpp"> <ClCompile Include="model\xqselectionmodel.cpp">
<Filter>Source Files\model</Filter> <Filter>Source Files\model</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="application\xqchildmodelview.cpp">
<Filter>Source Files\application</Filter>
</ClCompile>
<ClCompile Include="model\xqsimpleclipboard.cpp"> <ClCompile Include="model\xqsimpleclipboard.cpp">
<Filter>Source Files\model</Filter> <Filter>Source Files\model</Filter>
</ClCompile> </ClCompile>
@@ -127,21 +106,9 @@
<ClCompile Include="model\xqnodewriter.cpp"> <ClCompile Include="model\xqnodewriter.cpp">
<Filter>Source Files\model</Filter> <Filter>Source Files\model</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="model\xqitemfactory.cpp">
<Filter>Source Files\model</Filter>
</ClCompile>
<ClCompile Include="application\xqappdata.cpp"> <ClCompile Include="application\xqappdata.cpp">
<Filter>Source Files\application</Filter> <Filter>Source Files\application</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="model\xqitemtypefactory.cpp">
<Filter>Source Files\model</Filter>
</ClCompile>
<ClCompile Include="model\xqitemtype.cpp">
<Filter>Source Files\model</Filter>
</ClCompile>
<ClCompile Include="items\xqgenericitem.cpp">
<Filter>Source Files\Items</Filter>
</ClCompile>
<ClCompile Include="items\xqitem.cpp"> <ClCompile Include="items\xqitem.cpp">
<Filter>Source Files\Items</Filter> <Filter>Source Files\Items</Filter>
</ClCompile> </ClCompile>
@@ -154,6 +121,24 @@
<ClCompile Include="items\xqitemtype.cpp"> <ClCompile Include="items\xqitemtype.cpp">
<Filter>Source Files\Items</Filter> <Filter>Source Files\Items</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="model\xqsectionmanager.cpp">
<Filter>Source Files\model</Filter>
</ClCompile>
<ClCompile Include="model\xqviewmodel.cpp">
<Filter>Source Files\model</Filter>
</ClCompile>
<ClCompile Include="widgets\xqquickwidget.cpp">
<Filter>Source Files\widgets</Filter>
</ClCompile>
<ClCompile Include="widgets\xqtreetable.cpp">
<Filter>Source Files\widgets</Filter>
</ClCompile>
<ClCompile Include="application\xqchildmodel.cpp">
<Filter>Source Files\application</Filter>
</ClCompile>
<ClCompile Include="application\xqmainmodel.cpp">
<Filter>Source Files\application</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="model\xqcommand.h"> <ClInclude Include="model\xqcommand.h">
@@ -183,9 +168,6 @@
<ClInclude Include="pugixml\pugixml.hpp"> <ClInclude Include="pugixml\pugixml.hpp">
<Filter>Header Files\pugixml</Filter> <Filter>Header Files\pugixml</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="model\xqmodelsections.h">
<Filter>Header Files\model</Filter>
</ClInclude>
<ClInclude Include="util\xqmapindex.h"> <ClInclude Include="util\xqmapindex.h">
<Filter>Header Files\util</Filter> <Filter>Header Files\util</Filter>
</ClInclude> </ClInclude>
@@ -216,12 +198,6 @@
<ClInclude Include="nodes\znode_payload.h"> <ClInclude Include="nodes\znode_payload.h">
<Filter>Header Files\nodes</Filter> <Filter>Header Files\nodes</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="nodes\znode_attributes.h">
<Filter>Header Files\nodes</Filter>
</ClInclude>
<ClInclude Include="items\xqgenericitem.h">
<Filter>Header Files\items</Filter>
</ClInclude>
<ClInclude Include="items\xqitem.h"> <ClInclude Include="items\xqitem.h">
<Filter>Header Files\items</Filter> <Filter>Header Files\items</Filter>
</ClInclude> </ClInclude>
@@ -234,33 +210,36 @@
<ClInclude Include="items\xqitemtype.h"> <ClInclude Include="items\xqitemtype.h">
<Filter>Header Files\items</Filter> <Filter>Header Files\items</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="model\xqsectionmanager.h">
<Filter>Header Files\model</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtMoc Include="model\xqmodelview.h">
<Filter>Header Files\model</Filter>
</QtMoc>
<QtMoc Include="application\xqmainmodelview.h">
<Filter>Header Files\application</Filter>
</QtMoc>
<QtMoc Include="application\xqmainwindow.h"> <QtMoc Include="application\xqmainwindow.h">
<Filter>Header Files\application</Filter> <Filter>Header Files\application</Filter>
</QtMoc> </QtMoc>
<QtMoc Include="widgets\xqitemdelegate.h">
<Filter>Header Files\widgets</Filter>
</QtMoc>
<QtMoc Include="widgets\xqtreeview.h">
<Filter>Header Files\widgets</Filter>
</QtMoc>
<QtMoc Include="widgets\xqcontextmenu.h"> <QtMoc Include="widgets\xqcontextmenu.h">
<Filter>Header Files\widgets</Filter> <Filter>Header Files\widgets</Filter>
</QtMoc> </QtMoc>
<QtMoc Include="model\xqselectionmodel.h"> <QtMoc Include="model\xqselectionmodel.h">
<Filter>Header Files\model</Filter> <Filter>Header Files\model</Filter>
</QtMoc> </QtMoc>
<QtMoc Include="application\xqchildmodelview.h"> <QtMoc Include="application\xqdocumentstore.h">
<Filter>Header Files\application</Filter> <Filter>Header Files\application</Filter>
</QtMoc> </QtMoc>
<QtMoc Include="application\xqdocumentstore.h"> <QtMoc Include="model\xqviewmodel.h">
<Filter>Header Files\model</Filter>
</QtMoc>
<QtMoc Include="widgets\xqquickwidget.h">
<Filter>Header Files\widgets</Filter>
</QtMoc>
<QtMoc Include="widgets\xqtreetable.h">
<Filter>Header Files\widgets</Filter>
</QtMoc>
<QtMoc Include="application\xqchildmodel.h">
<Filter>Header Files\application</Filter>
</QtMoc>
<QtMoc Include="application\xqmainmodel.h">
<Filter>Header Files\application</Filter> <Filter>Header Files\application</Filter>
</QtMoc> </QtMoc>
</ItemGroup> </ItemGroup>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<QtTouchProperty>
</QtTouchProperty>
</PropertyGroup>
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<QtTouchProperty>
</QtTouchProperty>
</PropertyGroup>
</Project>

View File

@@ -10,21 +10,20 @@
<Panel PanelID="#4 JA 04" FriendlyName="@PanelName" PanelName="JA 04 Solar X58C" Manufacturer="JA Solar 4" WattPeak="440" Height="1,70" Width="1,10" Weight="12" MaxVolt="42" MaxAmpere="11"/> <Panel PanelID="#4 JA 04" FriendlyName="@PanelName" PanelName="JA 04 Solar X58C" Manufacturer="JA Solar 4" WattPeak="440" Height="1,70" Width="1,10" Weight="12" MaxVolt="42" MaxAmpere="11"/>
<Panel PanelID="#5 JA 05" FriendlyName="@PanelName" PanelName="JA 05 Solar X58C" Manufacturer="JA Solar 5" WattPeak="440" Height="1,70" Width="1,10" Weight="12" MaxVolt="42" MaxAmpere="11"/> <Panel PanelID="#5 JA 05" FriendlyName="@PanelName" PanelName="JA 05 Solar X58C" Manufacturer="JA Solar 5" WattPeak="440" Height="1,70" Width="1,10" Weight="12" MaxVolt="42" MaxAmpere="11"/>
<Panel PanelID="#6 JA 06" FriendlyName="@PanelName" PanelName="JA 06 Solar X58C" Manufacturer="JA Solar 6" WattPeak="440" Height="1,70" Width="1,10" Weight="12" MaxVolt="42" MaxAmpere="11"/> <Panel PanelID="#6 JA 06" FriendlyName="@PanelName" PanelName="JA 06 Solar X58C" Manufacturer="JA Solar 6" WattPeak="440" Height="1,70" Width="1,10" Weight="12" MaxVolt="42" MaxAmpere="11"/>
<Inverter InverterID="#1 HM600 01" FriendlyName="@InverterName" InverterName="01 HM600 S2 TMax" Manufacturer="HoyMiles" MaxPowerInput="2000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="600" NumStrings="2" Weight="28"/> <Inverter InverterID="#1 HM600 01" FriendlyName="@InverterName" InverterName="01 HM600 S2 TMax" Manufacturer="HoyMiles" MaxPowerInput="3000,00" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="600" NumStrings="2" Weight="28"/>
<Inverter InverterID="#2 HM800 02" FriendlyName="@InverterName" InverterName="02 HM800 S2 TMax" Manufacturer="HoyMiles" MaxPowerInput="4000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="800" NumStrings="2" Weight="29"/> <Inverter InverterID="#2 HM800 02" FriendlyName="@InverterName" InverterName="02 HM800 S2 TMax" Manufacturer="HoyMiles" MaxPowerInput="4000" MaxPowerInputChoice="4000;6000;8000" MaxPowerOutput="800" NumStrings="2" Weight="29"/>
<Inverter InverterID="#3 HM1600 03" FriendlyName="@InverterName" InverterName="03 HM1600 S4 TMax" Manufacturer="HoyMiles" MaxPowerInput="6000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="1600" NumStrings="4" Weight="32"/> <Inverter InverterID="#3 HM1600 03" FriendlyName="@InverterName" InverterName="03 HM1600 S4 TMax" Manufacturer="HoyMiles" MaxPowerInput="9000,00" MaxPowerInputChoice="6000;8000;10000" MaxPowerOutput="1600" NumStrings="4" Weight="32"/>
<Inverter InverterID="#4 D12K 04" FriendlyName="@InverterName" InverterName="04 HM600 S2 TMax" Manufacturer="Deye" MaxPowerInput="12000,33" MaxPowerInputChoice="6000;8000;12000" MaxPowerOutput="600" NumStrings="2" Weight="28"/> <Inverter InverterID="#4 D12K 04" FriendlyName="@InverterName" InverterName="04 HM600 S2 TMax" Manufacturer="Deye" MaxPowerInput="8000" MaxPowerInputChoice="6000;8000;12000" MaxPowerOutput="600" NumStrings="2" Weight="28"/>
<Battery BatteryID="#1 BYD 01" FriendlyName="@BatteryName" BatteryName="01 BYD T01 Stackable" Manufacturer="BYD" Capacity="4500" Yield="90" MaxCurrent="120" MaxVolt="48"> <Battery BatteryID="#1 BYD 01" FriendlyName="@BatteryName" BatteryName="01 BYD T01 Stackable" Manufacturer="BYD" Capacity="4500" Yield="90" MaxCurrent="120" MaxVolt="48">
<AdditionalData DataItem="Image" DataValue="image.png"/> <Images FrontView="image.png" PackageView="package.png" InstalledView="installed.png"/>
<AdditionalData DataItem="Manual" DataValue="manual.docx"/> <Documents Manual="manual.docx" Certificate="certificate.pdf"/>
<AdditionalData DataItem="Certificate" DataValue="certificate.pdf"/>
</Battery> </Battery>
<Battery BatteryID="#2 BYD 02" FriendlyName="@BatteryName" BatteryName="02 BYD T02 Stackable" Manufacturer="BYD" Capacity="9000" Yield="94" MaxCurrent="120" MaxVolt="48"/> <Battery BatteryID="#2 BYD 02" FriendlyName="@BatteryName" BatteryName="02 BYD T02 Stackable" Manufacturer="BYD" Capacity="9000" Yield="94" MaxCurrent="120" MaxVolt="48"/>
<Battery BatteryID="#3 BYD 03" FriendlyName="@BatteryName" BatteryName="03 BYD T01 Stackable" Manufacturer="BYD" Capacity="4500" Yield="86" MaxCurrent="120" MaxVolt="48"/> <Battery BatteryID="#3 BYD 03" FriendlyName="@BatteryName" BatteryName="03 BYD T01 Stackable" Manufacturer="BYD" Capacity="4500" Yield="86" MaxCurrent="120" MaxVolt="48"/>
<Battery BatteryID="#4 BYD 04" FriendlyName="@BatteryName" BatteryName="04 BYD T02 Stackable" Manufacturer="BYD" Capacity="9000" Yield="98" MaxCurrent="120" MaxVolt="48"/> <Battery BatteryID="#4 BYD 04" FriendlyName="@BatteryName" BatteryName="04 BYD T02 Stackable" Manufacturer="BYD" Capacity="9000" Yield="91" MaxCurrent="120" MaxVolt="48"/>
<Battery BatteryID="#5 GroWatt 05 G2K" FriendlyName="@BatteryName" BatteryName="05 BYD T01 Stackable" Manufacturer="GroWatt" Capacity="4500" Yield="94" MaxCurrent="120" MaxVolt="48"/> <Battery BatteryID="#5 GroWatt 05 G2K" FriendlyName="@BatteryName" BatteryName="05 BYD T01 Stackable" Manufacturer="GroWatt" Capacity="4500" Yield="94" MaxCurrent="120" MaxVolt="48"/>
<Battery BatteryID="#6 GroWatt 06 G4K" FriendlyName="@BatteryName" BatteryName="06 BYD T02 Stackable" Manufacturer="GroWatt" Capacity="9000" Yield="49" MaxCurrent="120" MaxVolt="48"/> <Battery BatteryID="#6 GroWatt 06 G4K" FriendlyName="@BatteryName" BatteryName="06 BYD T02 Stackable" Manufacturer="GroWatt" Capacity="9000" Yield="49" MaxCurrent="120" MaxVolt="48"/>
<Battery BatteryID="#7 Pyne 07 G4K" FriendlyName="@BatteryName" BatteryName="07 Pyne K7 Stackable" Manufacturer="PyNe" Capacity="9000" Yield="49" MaxCurrent="120" MaxVolt="48"/> <Battery BatteryID="#7 Pyne 07 G4K" FriendlyName="@BatteryName" BatteryName="07 Pyne K7 Stackable" Manufacturer="PyNe" Capacity="9000" Yield="68" MaxCurrent="120" MaxVolt="48"/>
</Components> </Components>
<IrgendWasAnderes> <IrgendWasAnderes>

View File

@@ -4,9 +4,9 @@
<Project ProjectID="HA02" FriendlyName="@ProjectName" ProjectName="Gerbrunn Ost" Established="2006" WattPeak="9840" ContentType="planned"> <Project ProjectID="HA02" FriendlyName="@ProjectName" ProjectName="Gerbrunn Ost" Established="2006" WattPeak="9840" ContentType="planned">
<Components> <Components>
<Panel PanelID="Jingli 01" FriendlyName="@PanelName" PanelName="Jingli 01 Solar T62B" Manufacturer="Jingli Solar" WattPeak="620" Height="2,70" Width="1,10" Weight="12" MaxVolt="67" MaxAmpere="11"> <Panel PanelID="Jingli 01" FriendlyName="@PanelName" PanelName="Jingli 01 Solar T62B" Manufacturer="Jingli Solar" WattPeak="620" Height="2,70" Width="1,10" Weight="12" MaxVolt="67" MaxAmpere="11">
<AdditionalData DataItem="Image" DataValue="image,png"/> <AdditionalData DataItem="Image" DataValue="image.png"/>
<AdditionalData DataItem="Manual" DataValue="manual,docx"/> <AdditionalData DataItem="Manual" DataValue="manual.docx"/>
<AdditionalData DataItem="Certificate" DataValue="certificate,pdf"/> <AdditionalData DataItem="Certificate" DataValue="certificate.pdf"/>
</Panel> </Panel>
<Panel PanelID="Jingli 02" FriendlyName="@PanelName" PanelName="Jingli 02 Solar X58C" Manufacturer="Jingli Solar" WattPeak="440" Height="1,70" Width="1,10" Weight="12" MaxVolt="42" MaxAmpere="11"/> <Panel PanelID="Jingli 02" FriendlyName="@PanelName" PanelName="Jingli 02 Solar X58C" Manufacturer="Jingli Solar" WattPeak="440" Height="1,70" Width="1,10" Weight="12" MaxVolt="42" MaxAmpere="11"/>
<Panel PanelID="Jingli 03" FriendlyName="@PanelName" PanelName="Jingli 03 Solar T62B" Manufacturer="Jingli Solar" WattPeak="620" Height="2,70" Width="1,10" Weight="12" MaxVolt="67" MaxAmpere="11"/> <Panel PanelID="Jingli 03" FriendlyName="@PanelName" PanelName="Jingli 03 Solar T62B" Manufacturer="Jingli Solar" WattPeak="620" Height="2,70" Width="1,10" Weight="12" MaxVolt="67" MaxAmpere="11"/>

View File

@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<Project ProjectID="HA03" FriendlyName="@ProjectName" ProjectName="Neubrunn Süd" Established="2006" WattPeak="9840" ContentType="runnning"> <Project ProjectID="HA03" FriendlyName="@ProjectName" ProjectName="Tauberbischoffsheim SÜD" Established="2006" WattPeak="9840" ContentType="runnning">
<Components> <Components>
<Panel PanelID="AIKO 01" FriendlyName="@PanelName" PanelName="AIKO 01 Solar T62B" Manufacturer="AIKO Solar" WattPeak="620" Height="2,70" Width="1,10" Weight="12" MaxVolt="67" MaxAmpere="11"> <Panel PanelID="AIKO 01" FriendlyName="@PanelName" PanelName="AIKO 01 Solar T62B" Manufacturer="AIKO Solar" WattPeak="620" Height="2,70" Width="1,10" Weight="12" MaxVolt="67" MaxAmpere="11">
<AdditionalData DataItem="Image" DataValue="image.png"/> <AdditionalData DataItem="Image" DataValue="image.png"/>

View File

@@ -6,28 +6,29 @@
--> -->
<ItemTypes> <ItemTypes>
<TreeParentType RenderStyle="PlainStyle" ItemFlags="IsEnabled|IsDropEnabled" Icon="DirIcon" /> <TreeParentType RenderStyle="PlainStyle" EditorType="LineEditType" ItemFlags="IsEnabled|IsDropEnabled" Icon="DirIcon" />
<TreeSectionType RenderStyle="PlainStyle" ItemFlags="IsEnabled" Icon="DesktopIcon"/> <TreeChildType RenderStyle="PlainStyle" EditorType="LineEditType" ItemFlags="IsEnabled" Icon="MediaPlay"/>
<TreeChildType RenderStyle="PlainStyle" ItemFlags="IsUserCheckable|IsEnabled" Icon="MediaPlay"/> <TreeSectionType RenderStyle="PlainStyle" EditorType="LineEditType" ItemFlags="IsUserCheckable|IsEnabled" Icon="DesktopIcon"/>
<HeaderType RenderStyle="HeaderStyle" ItemFlags="IsEnabled"/> <HeaderType RenderStyle="HeaderStyle" EditorType="LineEditType" ItemFlags="IsEnabled"/>
<HiddenType RenderStyle="HiddenStyle"/> <HiddenType RenderStyle="HiddenStyle"/>
<StaticType RenderStyle="PlainStyle"/> <StaticType RenderStyle="PlainStyle"/>
<PlainType RenderStyle="PlainStyle" ItemFlags="IsEnabled|IsEditable|IsSelectable"/> <PlainType RenderStyle="PlainStyle" EditorType="LineEditType" ItemFlags="IsEnabled|IsEditable|IsSelectable"/>
<ValueType RenderStyle="FormattedStyle" ItemFlags="IsEnabled|IsEditable|IsSelectable" UnitType="Coulomb"/> <ValueType RenderStyle="FormattedStyle" EditorType="LineEditType" ItemFlags="IsEnabled|IsEditable|IsSelectable" UnitType="Coulomb"/>
<CheckableType RenderStyle="FormattedStyle" ItemFlags="IsEnabled|IsEditable|IsSelectable" UnitType="###"/> <CheckableType RenderStyle="FormattedStyle" EditorType="LineEditType" ItemFlags="IsEnabled|IsEditable|IsSelectable" />
<PercentageType RenderStyle="ProgressBarStyle" ItemFlags="IsEnabled|IsSelectable"/> <PercentageType RenderStyle="ColorBarStyle" EditorType="ColorBarType" ItemFlags="IsEnabled|IsEditable|IsSelectable" UnitType="%"/>
<ChoiceType RenderStyle="ComboBoxStyle" ItemFlags="IsEnabled|IsSelectable|IsEditable" FixedChoices="la|le|lo|lu"/> <ChoiceType RenderStyle="ComboBoxStyle" EditorType="ComboBoxType" ItemFlags="IsEnabled|IsEditable|IsSelectable" UnitType="W" FixedChoices="2000|4000|6000|8000" />
<IntValueType RenderStyle="SpinBoxStyle" ItemFlags="IsEnabled|IsSelectable"/> <IntValueType RenderStyle="SpinBoxStyle" EditorType="SpinBoxType" ItemFlags="IsEnabled|IsEditable|IsSelectable"/>
</ItemTypes> </ItemTypes>
<DocumentTreeModel> <DocumentTreeModel>
<Section ContentType="runnning"> <Section ContentType="runnning">
<Header> <Header>
<Entry Caption="Active Projects" ItemType="TreeParentType"/> <Entry Caption="Active Projects" ItemType="TreeParentType"/>
</Header> </Header>
<ModelSheet firz="running"> <ModelSheet>
<Project Caption="@ProjectName" ItemType="TreeChildType"> <Project Caption="@ProjectName" ItemType="TreeChildType">
<CurrentSection ItemType="TreeSectionType"/> <CurrentSection ItemType="TreeSectionType"/>
</Project> </Project>
@@ -37,7 +38,7 @@
<Header> <Header>
<Entry Caption="Planned Projects" ItemType="TreeParentType"/> <Entry Caption="Planned Projects" ItemType="TreeParentType"/>
</Header> </Header>
<ModelSheet firz="planned"> <ModelSheet>
<Project Caption="@ProjectName" ItemType="TreeChildType"> <Project Caption="@ProjectName" ItemType="TreeChildType">
<CurrentSection ItemType="TreeSectionType"/> <CurrentSection ItemType="TreeSectionType"/>
</Project> </Project>
@@ -47,7 +48,7 @@
<Header> <Header>
<Entry Caption="Finished Projects" ItemType="TreeParentType"/> <Entry Caption="Finished Projects" ItemType="TreeParentType"/>
</Header> </Header>
<ModelSheet firz="finished"> <ModelSheet>
<Project Caption="@ProjectName" ItemType="TreeChildType"> <Project Caption="@ProjectName" ItemType="TreeChildType">
<CurrentSection ItemType="TreeSectionType"/> <CurrentSection ItemType="TreeSectionType"/>
</Project> </Project>
@@ -75,10 +76,10 @@
<!-- 'Icon' überschreibt den default wert im ItemType und erzeugt damit einen neuen ItemType--> <!-- 'Icon' überschreibt den default wert im ItemType und erzeugt damit einen neuen ItemType-->
<PanelID ItemType="PlainType" Icon="DesktopIcon"/> <PanelID ItemType="PlainType" Icon="DesktopIcon"/>
<PanelName ItemType="PlainType" Icon="BrowserStop"/> <PanelName ItemType="PlainType" Icon="BrowserStop"/>
<Manufacturer ItemType="ValueType"/> <Manufacturer ItemType="PlainType"/>
<!-- 'UnitType' überschreibt den default wert im ItemType und erzeugt damit einen neuen ItemType--> <!-- 'UnitType' überschreibt den default wert im ItemType und erzeugt damit einen neuen ItemType-->
<WattPeak ItemType="ValueType" UnitType="Wp"/> <WattPeak ItemType="ValueType" UnitType="Wp"/>
<Width ItemType="CheckableType" Icon="VistaShield" UnitType="m"/> <Width ItemType="ValueType" Icon="VistaShield" UnitType="m"/>
<Height ItemType="ValueType" UnitType="m"/> <Height ItemType="ValueType" UnitType="m"/>
<Weight ItemType="ValueType" UnitType="kg"/> <Weight ItemType="ValueType" UnitType="kg"/>
<MaxVolt ItemType="ValueType" UnitType="V"/> <MaxVolt ItemType="ValueType" UnitType="V"/>
@@ -86,8 +87,7 @@
</ModelSheet> </ModelSheet>
</Section> </Section>
<Section ContentType="Inverter" >
<Section ContentType="Inverter" >
<Header > <Header >
<InverterID Caption="Inverter" ItemType="HeaderType" /> <InverterID Caption="Inverter" ItemType="HeaderType" />
<InverterName Caption="Name" ItemType="HeaderType" /> <InverterName Caption="Name" ItemType="HeaderType" />
@@ -98,20 +98,20 @@
<Weight Caption="Weight" ItemType="HeaderType" /> <Weight Caption="Weight" ItemType="HeaderType" />
</Header> </Header>
<ModelSheet> <ModelSheet>
<InverterID Caption="Inverter" ItemType="ValueType" /> <InverterID ItemType="PlainType" />
<InverterName Caption="Name" ItemType="ValueType" /> <InverterName ItemType="PlainType" />
<Manufacturer Caption="Manufacturer" ItemType="ValueType" /> <Manufacturer ItemType="PlainType" />
<MaxPowerInput Caption="max. Input" ItemType="ValueType" ItemType="ChoiceType" ChoiceModelSheetSource="MaxPowerInputChoice" UnitType="W"/> <MaxPowerInput ItemType="ChoiceType" FixedChoices="2000|4000|6000|8000" UnitType="W"/>
<MaxPowerOutput Caption="max Output" ItemType="ValueType" UnitType="W"/> <MaxPowerOutput ItemType="ValueType" UnitType="W"/>
<NumStrings Caption="Strings" ItemType="ValueType" /> <NumStrings ItemType="IntValueType" />
<Weight Caption="Weight" ItemType="ValueType" UnitType="kg"/> <Weight ItemType="ValueType" UnitType="kg"/>
</ModelSheet> </ModelSheet>
</Section> </Section>
<Section ContentType="Battery" > <Section ContentType="Battery" >
<Header> <Header>
<BatteryID Caption="Name" ItemType="HeaderType" /> <BatteryID Caption="Battery" ItemType="HeaderType" />
<BatteryName Caption="Battery" ItemType="HeaderType" /> <BatteryName Caption="Name" ItemType="HeaderType" />
<Manufacturer Caption="Manufacturer" ItemType="HeaderType" /> <Manufacturer Caption="Manufacturer" ItemType="HeaderType" />
<Capacity Caption="Capacity" ItemType="HeaderType"/> <Capacity Caption="Capacity" ItemType="HeaderType"/>
<Yield Caption="Yield" ItemType="HeaderType" /> <Yield Caption="Yield" ItemType="HeaderType" />
@@ -119,14 +119,24 @@
<MaxVolt Caption="max. Volt" ItemType="HeaderType" /> <MaxVolt Caption="max. Volt" ItemType="HeaderType" />
</Header> </Header>
<ModelSheet> <ModelSheet>
<BatteryID Caption="Battery" ItemType="ValueType" /> <BatteryID ItemType="PlainType" />
<BatteryName Caption="Name" ItemType="ValueType" /> <BatteryName ItemType="PlainType" />
<Manufacturer Caption="Manufacturer" ItemType="ValueType" /> <Manufacturer ItemType="PlainType" />
<Capacity Caption="Capacity" ItemType="ValueType" UnitType="Wh"/> <Capacity ItemType="ValueType" UnitType="Wh"/>
<Yield Caption="Yield" ItemType="ValueType" ItemType="PercentageType" UnitType="%"/> <Yield ItemType="PercentageType" UnitType="%"/>
<MaxCurrent Caption="max. Current" ItemType="ValueType" UnitType="A"/> <MaxCurrent ItemType="ValueType" UnitType="A">
<MaxVolt Caption="max. Volt" ItemType="ValueType" UnitType="V"/> <SubType ItemType="PlainType"/>
</MaxCurrent>
<MaxVolt ItemType="ValueType" UnitType="V"/>
<firz ItemType="PlainType"/>
<Image DataValue="image.png" ItemType="PlainType"/>
<Manual DataValue="manual.docx" ItemType="PlainType"/>
<Certificate DataValue="certificate.pdf" ItemType="PlainType"/>
</ModelSheet> </ModelSheet>
</Section> </Section>
</DocumentDetailsModel> </DocumentDetailsModel>

View File

@@ -1,27 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Project Established="2006" FriendlyName="@ProjectName" ProjectID="HA01" ProjectName="Wiebelbach West" State="runnning" WattPeak="84000"> <Components>
<Components> <Panel FriendlyName="@PanelName" Height="2,70" Manufacturer="Jingli Solar" MaxAmpere="11" MaxVolt="67" PanelID="Jingli 01" PanelName="Jingli 01 Solar T62B" WattPeak="620" Weight="12" Width="1,10">
<Panel FriendlyName="@PanelName" Height="2,70" Manufacturer="JA Solar 1 XX" MaxAmpere="11" MaxVolt="67" PanelID="#1 JA 01" PanelName="JA 01 Solar T62B" WattPeak="620" Weight="12" Width="1,10"/> <AdditionalData DataItem="Image" DataValue="image.png"/>
<Panel FriendlyName="@PanelName" Height="1,70" Manufacturer="JA Solar 2" MaxAmpere="11" MaxVolt="42" PanelID="#2 JA 02" PanelName="JA 02 Solar X58C" WattPeak="440" Weight="12" Width="1,10"/> <AdditionalData DataItem="Manual" DataValue="manual.docx"/>
<Panel FriendlyName="@PanelName" Height="2,70" Manufacturer="JA Solar 3" MaxAmpere="11" MaxVolt="67" PanelID="#3 JA 03" PanelName="JA 03 Solar T62B" WattPeak="620" Weight="12" Width="1,10"/> <AdditionalData DataItem="Certificate" DataValue="certificate.pdf"/>
<Panel FriendlyName="@PanelName" Height="1,70" Manufacturer="JA Solar 4" MaxAmpere="11" MaxVolt="42" PanelID="#4 JA 04" PanelName="JA 04 Solar X58C" WattPeak="440" Weight="12" Width="1,10"/> </Panel>
<Panel FriendlyName="@PanelName" Height="1,70" Manufacturer="JA Solar 5" MaxAmpere="11" MaxVolt="42" PanelID="#5 JA 05" PanelName="JA 05 Solar X58C" WattPeak="440" Weight="12" Width="1,10"/> <Panel FriendlyName="@PanelName" Height="1,70" Manufacturer="Jingli Solar" MaxAmpere="11" MaxVolt="42" PanelID="Jingli 02" PanelName="Jingli 02 Solar X58C" WattPeak="440" Weight="12" Width="1,10"/>
<Panel FriendlyName="@PanelName" Height="1,70" Manufacturer="JA Solar 6" MaxAmpere="11" MaxVolt="42" PanelID="#6 JA 06" PanelName="JA 06 Solar X58C" WattPeak="440" Weight="12" Width="1,10"/> <Panel FriendlyName="@PanelName" Height="2,70" Manufacturer="Jingli Solar" MaxAmpere="11" MaxVolt="67" PanelID="Jingli 03" PanelName="Jingli 03 Solar T62B" WattPeak="620" Weight="12" Width="1,10"/>
<Inverter FriendlyName="@InverterName" InverterID="#1 HM600 01" InverterName="01 HM600 S2 TMax" Manufacturer="HoyMiles" MaxPowerInput="2000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="600" NumStrings="2" Weight="28"/> <Inverter FriendlyName="@InverterName" InverterID="HM600 01" InverterName="01 HM600 S2 TMax" Manufacturer="HoyMiles" MaxPowerInput="4000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="600" NumStrings="2" Weight="28"/>
<Inverter FriendlyName="@InverterName" InverterID="#2 HM800 02" InverterName="02 HM800 S2 TMax" Manufacturer="HoyMiles" MaxPowerInput="4000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="800" NumStrings="2" Weight="29"/> <Inverter FriendlyName="@InverterName" InverterID="HM800 02" InverterName="02 HM800 S2 TMax" Manufacturer="HoyMiles" MaxPowerInput="4000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="800" NumStrings="2" Weight="29"/>
<Inverter FriendlyName="@InverterName" InverterID="#3 HM1600 03" InverterName="03 HM1600 S4 TMax" Manufacturer="HoyMiles" MaxPowerInput="6000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="1600" NumStrings="4" Weight="32"/> <Inverter FriendlyName="@InverterName" InverterID="HM1600 03" InverterName="03 HM1600 S4 TMax" Manufacturer="HoyMiles" MaxPowerInput="4000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="1600" NumStrings="4" Weight="32"/>
<Inverter FriendlyName="@InverterName" InverterID="#4 D12K 04" InverterName="04 HM600 S2 TMax" Manufacturer="Deye" MaxPowerInput="12000,33" MaxPowerInputChoice="6000;8000;12000" MaxPowerOutput="600" NumStrings="2" Weight="28"/> <Inverter FriendlyName="@InverterName" InverterID="D12K 04" InverterName="04 HM600 S2 TMax" Manufacturer="Deye" MaxPowerInput="4000" MaxPowerInputChoice="2000;4000;6000" MaxPowerOutput="600" NumStrings="2" Weight="28"/>
<Battery BatteryID="#1 BYD 01" BatteryName="01 BYD T01 Stackable" Capacity="4500" FriendlyName="@BatteryName" Manufacturer="BYD" MaxCurrent="120" MaxVolt="48" Yield="90"> <Battery BatteryID="BYD 01" BatteryName="FIRZ!" Capacity="4500" FriendlyName="@BatteryName" Manufacturer="BYD" MaxCurrent="120" MaxVolt="48" Yield="88">
<AdditionalData DataItem="Image" DataValue="image.png"/> <AdditionalData DataItem="Image" DataValue="image.png"/>
<AdditionalData DataItem="Manual" DataValue="manual.docx"/> <AdditionalData DataItem="Manual" DataValue="manual.docx"/>
<AdditionalData DataItem="Certificate" DataValue="certificate.pdf"/> <AdditionalData DataItem="Certificate" DataValue="certificate.pdf"/>
</Battery> </Battery>
<Battery BatteryID="#2 BYD 02" BatteryName="02 BYD T02 Stackable" Capacity="9000" FriendlyName="@BatteryName" Manufacturer="BYD" MaxCurrent="120" MaxVolt="48" Yield="94"/> <Battery BatteryID="BYD 04" BatteryName="04 BYD T02 Stackable" Capacity="9000" FriendlyName="@BatteryName" Manufacturer="BYD" MaxCurrent="120" MaxVolt="48" Yield="32"/>
<Battery BatteryID="#3 BYD 03" BatteryName="03 BYD T01 Stackable" Capacity="4500" FriendlyName="@BatteryName" Manufacturer="BYD" MaxCurrent="120" MaxVolt="48" Yield="86"/> <Battery BatteryID="GroWatt 05 G2K" BatteryName="05 BYD T01 Stackable" Capacity="4500" FriendlyName="@BatteryName" Manufacturer="PylonTech" MaxCurrent="120" MaxVolt="48" Yield="46"/>
<Battery BatteryID="#4 BYD 04" BatteryName="04 BYD T02 Stackable" Capacity="9000" FriendlyName="@BatteryName" Manufacturer="BYD" MaxCurrent="120" MaxVolt="48" Yield="98"/> <Battery BatteryID="GroWatt 06 G4K" BatteryName="06 BYD T02 Stackable" Capacity="9000" FriendlyName="@BatteryName" Manufacturer="PylonTech" MaxCurrent="120" MaxVolt="48" Yield="94"/>
<Battery BatteryID="#5 GroWatt 05 G2K" BatteryName="05 BYD T01 Stackable" Capacity="4500" FriendlyName="@BatteryName" Manufacturer="GroWatt" MaxCurrent="120" MaxVolt="48" Yield="94"/> </Components>
<Battery BatteryID="#6 GroWatt 06 G4K" BatteryName="06 BYD T02 Stackable" Capacity="9000" FriendlyName="@BatteryName" Manufacturer="GroWatt" MaxCurrent="120" MaxVolt="48" Yield="49"/>
<Battery BatteryID="#7 Pyne 07 G4K" BatteryName="07 Pyne K7 Stackable" Capacity="9000" FriendlyName="@BatteryName" Manufacturer="PyNe" MaxCurrent="120" MaxVolt="48" Yield="49"/>
</Components>
<IrgendWasAnderes/>
</Project>