mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-26 11:54:14 +02:00
Compare commits
116 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 923367d2a8 | |||
| 6dd260a7b2 | |||
| 132c564aef | |||
| e9c4969af7 | |||
| 040c4b5e29 | |||
| 71d708e2da | |||
| b490720652 | |||
| 519f2245f6 | |||
| b61193f66f | |||
| 0ca4b9f6c3 | |||
| a08cdf7272 | |||
| 2fdb225936 | |||
| 95f3ea2f6d | |||
| 0e02190eb2 | |||
| 2807771200 | |||
| 4cffdf93b6 | |||
| 9738345b45 | |||
| 286002fe25 | |||
| ce0e7e6867 | |||
| 5f0b015186 | |||
| e5738c5b7d | |||
| c3c264cd78 | |||
| d392ab4b8f | |||
| ebd4a57563 | |||
| 23d83ec153 | |||
| d43c535cc9 | |||
| 71782aec20 | |||
| 59dc59cf2f | |||
| 469c8cbc70 | |||
| 1330dbb435 | |||
| e7f19de2da | |||
| 4c9a307cb9 | |||
| 4381c6caa3 | |||
| 07d7aedc26 | |||
| 5622308ba2 | |||
| 149ae961cc | |||
| ac40d110fb | |||
| 4f309770f0 | |||
| 72cf86ece0 | |||
| 8aefdcc481 | |||
| 3a45625d69 | |||
| 988357057f | |||
| e9676ef87e | |||
| ca507dc0f3 | |||
| 1932150ea6 | |||
| 23241fba69 | |||
| f2f1051914 | |||
| 313aafc95b | |||
| aaeaff55cc | |||
| bb037ee3ff | |||
| 17ebbffbca | |||
| 04e2279a7f | |||
| 9987f05835 | |||
| a94f30b256 | |||
| 73075a5154 | |||
| 9875de85d7 | |||
| 48883b320e | |||
| d1256872c2 | |||
| b93d8d8baa | |||
| ae41dd7686 | |||
| 800189debb | |||
| 522e008c26 | |||
| 7fbbb71aac | |||
| 232724bf82 | |||
| 12f826e969 | |||
| 245aafb0d1 | |||
| 0d231ef548 | |||
| 3513f692fd | |||
| 5a27f3cf80 | |||
| d3a9adbe44 | |||
| 8ab4e24b61 | |||
| 2d2bf5ca2b | |||
| 2f6ab8f63b | |||
| 2266497b0b | |||
| dcb79b6553 | |||
| 745b4a936c | |||
| 7ac3719c37 | |||
| ddfa234943 | |||
| 9af562fcbd | |||
| c85276f61b | |||
| c1cc9a5b98 | |||
| f3a31c291f | |||
| a06220e8dc | |||
| 79990e40ee | |||
| e1e7ea4888 | |||
| 54b8fe5df4 | |||
| be0d214b75 | |||
| 2f988e6e2c | |||
| 9786006ca4 | |||
| 91e8956734 | |||
| 6fad3390df | |||
| 231ab990c3 | |||
| f10275cb22 | |||
| 3d0e7a27a3 | |||
| f14278324c | |||
| d5318eb7b4 | |||
| f10ef3ded7 | |||
| 6f7ea63589 | |||
| 9a6029a2bb | |||
| bc0ca56c7e | |||
| 1d4c0326d4 | |||
| 3457a88e81 | |||
| 4e361f93fe | |||
| 6a8838e719 | |||
| 774f803626 | |||
| 5b0785fcce | |||
| de9b3eae06 | |||
| 032f2249a3 | |||
| 1890cee801 | |||
| 3eea3059bf | |||
| bf7f49f334 | |||
| 2ec413a578 | |||
| 61ce75e380 | |||
| 83b9f32bd0 | |||
| e35cab33f0 | |||
| 2e4bb486bb |
@@ -28,7 +28,7 @@ jobs:
|
|||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
ca-certificates build-essential cmake ninja-build git pkg-config \
|
ca-certificates build-essential cmake ninja-build git pkg-config \
|
||||||
qt6-base-dev qt6-base-private-dev qt6-tools-dev qt6-tools-dev-tools \
|
qt6-base-dev qt6-base-private-dev qt6-tools-dev qt6-tools-dev-tools \
|
||||||
libqt6svg6-dev libqt6sql6-sqlite libcups2-dev \
|
libqt6svg6-dev libqt6sql6-sqlite libcups2-dev libsqlite3-dev \
|
||||||
libxkbcommon-x11-0 \
|
libxkbcommon-x11-0 \
|
||||||
xvfb openbox xdotool x11-utils
|
xvfb openbox xdotool x11-utils
|
||||||
# extra-cmake-modules and the KF6 libraries are installed rather than
|
# extra-cmake-modules and the KF6 libraries are installed rather than
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ jobs:
|
|||||||
mingw-w64-ucrt-x86_64-qt6-tools
|
mingw-w64-ucrt-x86_64-qt6-tools
|
||||||
mingw-w64-ucrt-x86_64-qt6-translations
|
mingw-w64-ucrt-x86_64-qt6-translations
|
||||||
mingw-w64-ucrt-x86_64-qt6-pdf
|
mingw-w64-ucrt-x86_64-qt6-pdf
|
||||||
|
mingw-w64-ucrt-x86_64-sqlite3
|
||||||
mingw-w64-ucrt-x86_64-pkg-config
|
mingw-w64-ucrt-x86_64-pkg-config
|
||||||
mingw-w64-ucrt-x86_64-kwidgetsaddons
|
mingw-w64-ucrt-x86_64-kwidgetsaddons
|
||||||
mingw-w64-ucrt-x86_64-kcoreaddons
|
mingw-w64-ucrt-x86_64-kcoreaddons
|
||||||
@@ -56,6 +57,7 @@ jobs:
|
|||||||
mingw-w64-ucrt-x86_64-nsis
|
mingw-w64-ucrt-x86_64-nsis
|
||||||
mingw-w64-ucrt-x86_64-angleproject
|
mingw-w64-ucrt-x86_64-angleproject
|
||||||
mingw-w64-ucrt-x86_64-qt6-declarative
|
mingw-w64-ucrt-x86_64-qt6-declarative
|
||||||
|
mingw-w64-ucrt-x86_64-hidapi
|
||||||
|
|
||||||
- name: Cache ccache
|
- name: Cache ccache
|
||||||
uses: actions/cache@v5
|
uses: actions/cache@v5
|
||||||
@@ -119,9 +121,12 @@ jobs:
|
|||||||
-DCMAKE_POLICY_DEFAULT_CMP0077=NEW \
|
-DCMAKE_POLICY_DEFAULT_CMP0077=NEW \
|
||||||
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
|
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
|
||||||
-DQET_EXPORT_PROJECT_DB=ON \
|
-DQET_EXPORT_PROJECT_DB=ON \
|
||||||
|
-DQET_ENABLE_SPACEMOUSE=ON \
|
||||||
|
-DQET_SPACEMOUSE_BACKEND=hid \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=/ucrt64/bin/ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=/ucrt64/bin/ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=/ucrt64/bin/ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=/ucrt64/bin/ccache \
|
||||||
|
-DSQLite3_INCLUDE_DIR=/ucrt64/include \
|
||||||
|
-DSQLite3_LIBRARY=/ucrt64/lib/libsqlite3.dll.a \
|
||||||
..
|
..
|
||||||
ninja -j"$NPROC"
|
ninja -j"$NPROC"
|
||||||
|
|
||||||
@@ -144,6 +149,11 @@ jobs:
|
|||||||
SIZE=$(stat -c%s "$EXE")
|
SIZE=$(stat -c%s "$EXE")
|
||||||
echo "Exe found: $EXE ($SIZE bytes)"
|
echo "Exe found: $EXE ($SIZE bytes)"
|
||||||
[ "$SIZE" -gt 100000 ] || { echo "ERROR: exe too small"; exit 1; }
|
[ "$SIZE" -gt 100000 ] || { echo "ERROR: exe too small"; exit 1; }
|
||||||
|
# 3D mouse support (discussion #599): CMake only warns when hidapi
|
||||||
|
# is missing, which would ship a package without it -- fail here.
|
||||||
|
ldd "$EXE" | grep -qi 'libhidapi' \
|
||||||
|
|| { echo "ERROR: exe not linked against hidapi -- 3D mouse support missing"; exit 1; }
|
||||||
|
echo "3D mouse support: linked against $(ldd "$EXE" | grep -io 'libhidapi[^ ]*' | head -1)"
|
||||||
|
|
||||||
- name: Deploy — copy exe + windeployqt + DLLs
|
- name: Deploy — copy exe + windeployqt + DLLs
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
@@ -189,11 +199,20 @@ jobs:
|
|||||||
echo "=== $DLL_COUNT DLLs present after scan ==="
|
echo "=== $DLL_COUNT DLLs present after scan ==="
|
||||||
ls -lh "$BIN/QElectroTech.exe" || { echo "ERROR: exe missing from bin/"; exit 1; }
|
ls -lh "$BIN/QElectroTech.exe" || { echo "ERROR: exe missing from bin/"; exit 1; }
|
||||||
[ "$DLL_COUNT" -gt 5 ] || { echo "ERROR: too few DLLs"; exit 1; }
|
[ "$DLL_COUNT" -gt 5 ] || { echo "ERROR: too few DLLs"; exit 1; }
|
||||||
|
# Without it QElectroTech.exe would not start at all.
|
||||||
|
[ -f "$BIN/libhidapi-0.dll" ] || { echo "ERROR: libhidapi-0.dll not deployed"; exit 1; }
|
||||||
cd "$GITHUB_WORKSPACE"
|
cd "$GITHUB_WORKSPACE"
|
||||||
|
|
||||||
cp /ucrt64/bin/libgcc_s_seh-1.dll "$BIN/"
|
cp /ucrt64/bin/libgcc_s_seh-1.dll "$BIN/"
|
||||||
cp /ucrt64/bin/libstdc++-6.dll "$BIN/"
|
cp /ucrt64/bin/libstdc++-6.dll "$BIN/"
|
||||||
cp /ucrt64/bin/libwinpthread-1.dll "$BIN/"
|
cp /ucrt64/bin/libwinpthread-1.dll "$BIN/"
|
||||||
|
SQLITE=$(find /ucrt64/bin -name "libsqlite3*.dll" | head -1)
|
||||||
|
if [ -n "$SQLITE" ]; then
|
||||||
|
cp "$SQLITE" "$BIN/"
|
||||||
|
echo "SQLite3 copied: $(basename $SQLITE)"
|
||||||
|
else
|
||||||
|
echo "WARNING: libsqlite3 not found in /ucrt64/bin/"
|
||||||
|
fi
|
||||||
|
|
||||||
cp "$GITHUB_WORKSPACE/build-aux/windows/QET64.nsi" "$NSIS_ROOT/"
|
cp "$GITHUB_WORKSPACE/build-aux/windows/QET64.nsi" "$NSIS_ROOT/"
|
||||||
cp "$GITHUB_WORKSPACE/build-aux/windows/lang_extra.nsh" "$NSIS_ROOT/"
|
cp "$GITHUB_WORKSPACE/build-aux/windows/lang_extra.nsh" "$NSIS_ROOT/"
|
||||||
|
|||||||
+1
-9
@@ -9,12 +9,4 @@ doc/*
|
|||||||
!doc/QElectroTech.qch
|
!doc/QElectroTech.qch
|
||||||
QElectroTech.tag
|
QElectroTech.tag
|
||||||
!doc/doc-utils
|
!doc/doc-utils
|
||||||
lang/*.qm
|
ui_*.h
|
||||||
|
|
||||||
# -- IDE settings/intermediate files --
|
|
||||||
# zed
|
|
||||||
.zed
|
|
||||||
.cache
|
|
||||||
|
|
||||||
# VS Code
|
|
||||||
.vscode
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ include(cmake/git_update_submodules.cmake)
|
|||||||
include(cmake/git_last_commit_sha.cmake)
|
include(cmake/git_last_commit_sha.cmake)
|
||||||
include(cmake/fetch_singleapplication.cmake)
|
include(cmake/fetch_singleapplication.cmake)
|
||||||
include(cmake/fetch_pugixml.cmake)
|
include(cmake/fetch_pugixml.cmake)
|
||||||
|
include(cmake/find_spacemouse.cmake)
|
||||||
include(cmake/qet_compilation_vars.cmake)
|
include(cmake/qet_compilation_vars.cmake)
|
||||||
|
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
@@ -169,6 +170,13 @@ else()
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(QET_SPACEMOUSE_BACKEND_SPNAV_ENABLED)
|
||||||
|
list(APPEND QET_SPACEMOUSE_LIBRARIES PkgConfig::SPNAV)
|
||||||
|
endif()
|
||||||
|
if(QET_SPACEMOUSE_BACKEND_HID_ENABLED)
|
||||||
|
list(APPEND QET_SPACEMOUSE_LIBRARIES PkgConfig::HIDAPI)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
# CFBundleIdentifier must not be empty. CMake's default Info.plist
|
# CFBundleIdentifier must not be empty. CMake's default Info.plist
|
||||||
# template fills it from MACOSX_BUNDLE_GUI_IDENTIFIER; with that unset
|
# template fills it from MACOSX_BUNDLE_GUI_IDENTIFIER; with that unset
|
||||||
@@ -287,6 +295,7 @@ target_link_libraries(
|
|||||||
SQLite3::SQLite3
|
SQLite3::SQLite3
|
||||||
${KF_PRIVATE_LIBRARIES}
|
${KF_PRIVATE_LIBRARIES}
|
||||||
${QET_PRIVATE_LIBRARIES}
|
${QET_PRIVATE_LIBRARIES}
|
||||||
|
${QET_SPACEMOUSE_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(
|
target_include_directories(
|
||||||
|
|||||||
+21
-7
@@ -27,12 +27,18 @@ git submodule update --init --recursive
|
|||||||
| C++17 compiler | required | GCC or Clang on Unix-like platforms; MSVC or MinGW-w64 g++ on Windows — see [Choosing a compiler](#3-choosing-a-compiler-unix) / [Building on Windows](#6-building-on-windows-msvc--mingw) |
|
| C++17 compiler | required | GCC or Clang on Unix-like platforms; MSVC or MinGW-w64 g++ on Windows — see [Choosing a compiler](#3-choosing-a-compiler-unix) / [Building on Windows](#6-building-on-windows-msvc--mingw) |
|
||||||
| Qt6 base + widgets | required | |
|
| Qt6 base + widgets | required | |
|
||||||
| Qt6 **GuiPrivate** headers | required | needed for clickable PDF hyperlinks; **hard build failure** at CMake generate time if missing, see below |
|
| Qt6 **GuiPrivate** headers | required | needed for clickable PDF hyperlinks; **hard build failure** at CMake generate time if missing, see below |
|
||||||
|
| SQLite3 | required | used by the nomenclature/summary database |
|
||||||
| Qt Linguist tools (`lrelease`) | required | compiles the tracked `.ts` files into `.qm` as part of every normal build |
|
| Qt Linguist tools (`lrelease`) | required | compiles the tracked `.ts` files into `.qm` as part of every normal build |
|
||||||
| pugixml | handled automatically | fetched and built via CMake FetchContent if not already present on the system — see [pugixml](#8-pugixml) below |
|
| pugixml | handled automatically | fetched and built via CMake FetchContent if not already present on the system — see [pugixml](#8-pugixml) below |
|
||||||
| Qt Test module | required if building tests | `PACKAGE_TESTS` is `ON` by default; QtTest ships as part of the base Qt6 dev packages listed below on every platform, no extra package needed |
|
| Qt Test module | required if building tests | `PACKAGE_TESTS` is `ON` by default; QtTest ships as part of the base Qt6 dev packages listed below on every platform, no extra package needed |
|
||||||
| KDE Frameworks (KF6) | optional | see [Building without KDE Frameworks](#9-building-without-kde-frameworks) |
|
| KDE Frameworks (KF6) | optional | see [Building without KDE Frameworks](#9-building-without-kde-frameworks) |
|
||||||
| QtPdf module | optional | see [PDF page import](#7-pdf-page-import-qtpdf) |
|
| QtPdf module | optional | see [PDF page import](#7-pdf-page-import-qtpdf) |
|
||||||
|
|
||||||
|
A note on CMake versions: the project declares a minimum of 3.5 but is
|
||||||
|
routinely built with much newer releases; if your CMake is older than 4.3 it
|
||||||
|
simply won't have the newer `SQLite3::SQLite3` target name, which the build
|
||||||
|
script compensates for automatically. There is nothing you need to do either
|
||||||
|
way.
|
||||||
|
|
||||||
## 3. Building (out-of-source build)
|
## 3. Building (out-of-source build)
|
||||||
|
|
||||||
@@ -100,7 +106,7 @@ the closest match.
|
|||||||
sudo apt install \
|
sudo apt install \
|
||||||
build-essential cmake ninja-build git \
|
build-essential cmake ninja-build git \
|
||||||
qt6-base-dev qt6-base-private-dev qt6-tools-dev qt6-tools-dev-tools \
|
qt6-base-dev qt6-base-private-dev qt6-tools-dev qt6-tools-dev-tools \
|
||||||
|
libsqlite3-dev \
|
||||||
libkf6coreaddons-dev libkf6widgetsaddons-dev
|
libkf6coreaddons-dev libkf6widgetsaddons-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -132,6 +138,7 @@ sudo apt install libpugixml-dev
|
|||||||
sudo dnf install \
|
sudo dnf install \
|
||||||
cmake gcc-c++ git \
|
cmake gcc-c++ git \
|
||||||
qt6-qtbase-devel qt6-qtbase-private-devel qt6-qttools-devel \
|
qt6-qtbase-devel qt6-qtbase-private-devel qt6-qttools-devel \
|
||||||
|
sqlite-devel \
|
||||||
kf6-kcoreaddons-devel kf6-kwidgetsaddons-devel
|
kf6-kcoreaddons-devel kf6-kwidgetsaddons-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -148,10 +155,11 @@ Optional, for a system pugixml: `sudo dnf install pugixml-devel`.
|
|||||||
pkg install \
|
pkg install \
|
||||||
cmake git \
|
cmake git \
|
||||||
qt6-base qt6-tools \
|
qt6-base qt6-tools \
|
||||||
|
sqlite3 \
|
||||||
kf6-kcoreaddons kf6-kwidgetsaddons
|
kf6-kcoreaddons kf6-kwidgetsaddons
|
||||||
```
|
```
|
||||||
|
|
||||||
(from ports: `devel/qt6-base`, `devel/qt6-tools`,
|
(from ports: `devel/qt6-base`, `devel/qt6-tools`, `databases/sqlite3`,
|
||||||
`devel/kf6-kcoreaddons`, `x11-toolkits/kf6-kwidgetsaddons`.) Qt6's
|
`devel/kf6-kcoreaddons`, `x11-toolkits/kf6-kwidgetsaddons`.) Qt6's
|
||||||
`GuiPrivate` headers ship as part of `qt6-base` on FreeBSD, no separate
|
`GuiPrivate` headers ship as part of `qt6-base` on FreeBSD, no separate
|
||||||
package is needed. `QtPdf` is not packaged on FreeBSD at the time of writing
|
package is needed. `QtPdf` is not packaged on FreeBSD at the time of writing
|
||||||
@@ -167,7 +175,7 @@ Optional, for a system pugixml: `pkg install pugixml` (`devel/pugixml`).
|
|||||||
Using [Homebrew](https://brew.sh):
|
Using [Homebrew](https://brew.sh):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
brew install cmake qt ninja
|
brew install cmake qt sqlite ninja
|
||||||
```
|
```
|
||||||
|
|
||||||
Homebrew's `qt` formula is Qt6 and includes the private headers, so no
|
Homebrew's `qt` formula is Qt6 and includes the private headers, so no
|
||||||
@@ -185,7 +193,7 @@ Optional, for a system pugixml: `brew install pugixml`.
|
|||||||
|
|
||||||
See [Building on Windows](#6-building-on-windows-msvc--mingw) below — the
|
See [Building on Windows](#6-building-on-windows-msvc--mingw) below — the
|
||||||
package sources differ enough from the Unix-like platforms above (no system
|
package sources differ enough from the Unix-like platforms above (no system
|
||||||
package manager and Qt aren't provided the same way) that it gets
|
package manager, SQLite3 and Qt aren't provided the same way) that it gets
|
||||||
its own section.
|
its own section.
|
||||||
|
|
||||||
## 5. pugixml
|
## 5. pugixml
|
||||||
@@ -207,7 +215,7 @@ on Debian/Ubuntu, `pugixml-devel` on Fedora).
|
|||||||
Both toolchains QET's CMake build targets on Windows are covered here:
|
Both toolchains QET's CMake build targets on Windows are covered here:
|
||||||
**MSVC** (Visual Studio 2019/2022) and **MinGW-w64** (gcc). Unlike the
|
**MSVC** (Visual Studio 2019/2022) and **MinGW-w64** (gcc). Unlike the
|
||||||
Unix-like platforms above, there's no single system package manager, so
|
Unix-like platforms above, there's no single system package manager, so
|
||||||
Qt and (optionally) KDE Frameworks each need to be sourced
|
Qt, SQLite3 and (optionally) KDE Frameworks each need to be sourced
|
||||||
separately per toolchain.
|
separately per toolchain.
|
||||||
|
|
||||||
One piece of good news either way: unlike Debian/Fedora, the official Qt
|
One piece of good news either way: unlike Debian/Fedora, the official Qt
|
||||||
@@ -228,7 +236,11 @@ normally use `-DBUILD_WITH_KF=OFF` (see the
|
|||||||
1. Install Visual Studio with the "Desktop development with C++" workload,
|
1. Install Visual Studio with the "Desktop development with C++" workload,
|
||||||
and install Qt6 for MSVC (e.g. the `msvc2019_64` or `msvc2022_64` kit)
|
and install Qt6 for MSVC (e.g. the `msvc2019_64` or `msvc2022_64` kit)
|
||||||
via the [Qt Online Installer](https://www.qt.io/download-qt-installer).
|
via the [Qt Online Installer](https://www.qt.io/download-qt-installer).
|
||||||
2. Configure and build from an "x64 Native Tools Command Prompt for VS":
|
2. Get SQLite3 — the simplest route is [vcpkg](https://vcpkg.io):
|
||||||
|
```bat
|
||||||
|
vcpkg install sqlite3:x64-windows
|
||||||
|
```
|
||||||
|
3. Configure and build from an "x64 Native Tools Command Prompt for VS":
|
||||||
```bat
|
```bat
|
||||||
mkdir build && cd build
|
mkdir build && cd build
|
||||||
cmake .. -G "Visual Studio 17 2022" -A x64 ^
|
cmake .. -G "Visual Studio 17 2022" -A x64 ^
|
||||||
@@ -281,7 +293,9 @@ Using the Qt Online Installer's bundled MinGW kit instead: point
|
|||||||
`CMAKE_PREFIX_PATH` at that kit (e.g. `C:\Qt\6.x.x\mingw_64`) and make sure
|
`CMAKE_PREFIX_PATH` at that kit (e.g. `C:\Qt\6.x.x\mingw_64`) and make sure
|
||||||
its bundled `g++.exe` comes first on `PATH`, or pass
|
its bundled `g++.exe` comes first on `PATH`, or pass
|
||||||
`-DCMAKE_C_COMPILER`/`-DCMAKE_CXX_COMPILER` explicitly so CMake doesn't pick
|
`-DCMAKE_C_COMPILER`/`-DCMAKE_CXX_COMPILER` explicitly so CMake doesn't pick
|
||||||
up a different MinGW installation.
|
up a different MinGW installation. SQLite3 still has to come from elsewhere
|
||||||
|
in this path — vcpkg with a `mingw`-flavoured triplet, or MSYS2's package as
|
||||||
|
above.
|
||||||
|
|
||||||
## 7. Qt6 private headers (mandatory)
|
## 7. Qt6 private headers (mandatory)
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ parts:
|
|||||||
- python3-lxml
|
- python3-lxml
|
||||||
- python3-tk
|
- python3-tk
|
||||||
- libtk8.6
|
- libtk8.6
|
||||||
|
- libspnav0
|
||||||
|
|
||||||
kde-sdk-setup:
|
kde-sdk-setup:
|
||||||
plugin: nil
|
plugin: nil
|
||||||
@@ -71,6 +72,7 @@ parts:
|
|||||||
source: .
|
source: .
|
||||||
stage-packages:
|
stage-packages:
|
||||||
- git
|
- git
|
||||||
|
- sqlite3
|
||||||
- xdg-user-dirs
|
- xdg-user-dirs
|
||||||
- libqt6qml6
|
- libqt6qml6
|
||||||
# libxcb-cursor0 workaround was needed against the Qt5/KF5 core22 content
|
# libxcb-cursor0 workaround was needed against the Qt5/KF5 core22 content
|
||||||
@@ -81,7 +83,7 @@ parts:
|
|||||||
- git
|
- git
|
||||||
- cmake
|
- cmake
|
||||||
- ninja-build
|
- ninja-build
|
||||||
|
- libsqlite3-dev
|
||||||
- qt6-tools-dev
|
- qt6-tools-dev
|
||||||
- qt6-base-private-dev
|
- qt6-base-private-dev
|
||||||
- qt6-declarative-dev
|
- qt6-declarative-dev
|
||||||
@@ -91,6 +93,7 @@ parts:
|
|||||||
# runs FindCups at configure time and fails without the CUPS headers.
|
# runs FindCups at configure time and fails without the CUPS headers.
|
||||||
# Build-time only: nothing from it is staged into the snap.
|
# Build-time only: nothing from it is staged into the snap.
|
||||||
- libcups2-dev
|
- libcups2-dev
|
||||||
|
- libspnav-dev
|
||||||
override-build: |
|
override-build: |
|
||||||
displayed_version=$(cat sources/qetversion.cpp | grep "return QVersionNumber{"| head -n 1| awk -F "{" '{ print $2 }' | awk -F "}" '{ print $1 }' | sed -e 's/,/./g' -e 's/ //g')
|
displayed_version=$(cat sources/qetversion.cpp | grep "return QVersionNumber{"| head -n 1| awk -F "{" '{ print $2 }' | awk -F "}" '{ print $1 }' | sed -e 's/,/./g' -e 's/ //g')
|
||||||
snap_version="${displayed_version}-g$(git rev-parse --short=8 HEAD)"
|
snap_version="${displayed_version}-g$(git rev-parse --short=8 HEAD)"
|
||||||
@@ -105,7 +108,8 @@ parts:
|
|||||||
-DBUILD_KF=OFF \
|
-DBUILD_KF=OFF \
|
||||||
-DPACKAGE_TESTS=OFF \
|
-DPACKAGE_TESTS=OFF \
|
||||||
-DBUILD_PUGIXML=ON \
|
-DBUILD_PUGIXML=ON \
|
||||||
-DQET_EXPORT_PROJECT_DB=ON
|
-DQET_EXPORT_PROJECT_DB=ON \
|
||||||
|
-DQET_ENABLE_SPACEMOUSE=ON
|
||||||
ninja -C build -j${CRAFT_PARALLEL_BUILD_COUNT}
|
ninja -C build -j${CRAFT_PARALLEL_BUILD_COUNT}
|
||||||
DESTDIR="$CRAFT_PART_INSTALL" ninja -C build install
|
DESTDIR="$CRAFT_PART_INSTALL" ninja -C build install
|
||||||
override-stage: |
|
override-stage: |
|
||||||
|
|||||||
@@ -47,3 +47,8 @@ option(BUILD_WITH_KF "Build with KDE Frameworks" ON)
|
|||||||
# compile for everyone else. Leaving it off keeps CI and contributors on the
|
# compile for everyone else. Leaving it off keeps CI and contributors on the
|
||||||
# strict behaviour, and only developers who opt in trade that for the speed.
|
# strict behaviour, and only developers who opt in trade that for the speed.
|
||||||
option(QET_ENABLE_PCH "Use precompiled headers (developer build speed; may mask missing #includes)" OFF)
|
option(QET_ENABLE_PCH "Use precompiled headers (developer build speed; may mask missing #includes)" OFF)
|
||||||
|
|
||||||
|
# Discussion #599: 3Dconnexion SpaceMouse/SpacePilot pan/zoom support. Off by
|
||||||
|
# default -- see cmake/find_spacemouse.cmake for the backends and what happens
|
||||||
|
# when it is on but no library is found.
|
||||||
|
option(QET_ENABLE_SPACEMOUSE "Build with 3D mouse (3Dconnexion SpaceMouse) support for pan/zoom; needs libspnav or hidapi, see QET_SPACEMOUSE_BACKEND" OFF)
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
# Copyright 2006 The QElectroTech Team
|
||||||
|
# This file is part of QElectroTech.
|
||||||
|
#
|
||||||
|
# QElectroTech 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.
|
||||||
|
#
|
||||||
|
# QElectroTech is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
message(" - find_spacemouse")
|
||||||
|
|
||||||
|
# QET_ENABLE_SPACEMOUSE (cmake/developer_options.cmake) is off by default,
|
||||||
|
# so none of this runs, and the default build is entirely unaffected: no new
|
||||||
|
# dependency, no new source files, no new symbols.
|
||||||
|
#
|
||||||
|
# When it is on, QET_SPACEMOUSE_BACKEND picks how the device is read -- see
|
||||||
|
# sources/spacemouse/spacemousebackend.h for what a backend is:
|
||||||
|
# spnav Linux, through the spacenavd daemon (libspnav)
|
||||||
|
# hid any platform, directly over USB (hidapi), no 3Dconnexion driver
|
||||||
|
# auto spnav on Linux when libspnav is found, hid otherwise
|
||||||
|
# On macOS the 3DxWare backend is added to whichever of these is chosen.
|
||||||
|
# A backend whose library is not found downgrades the option to off with a
|
||||||
|
# warning, rather than failing configure for an opt-in feature.
|
||||||
|
set(QET_SPACEMOUSE_BACKEND "auto" CACHE STRING "3D mouse backend: auto, spnav or hid")
|
||||||
|
set_property(CACHE QET_SPACEMOUSE_BACKEND PROPERTY STRINGS auto spnav hid)
|
||||||
|
|
||||||
|
set(QET_SPACEMOUSE_ENABLED FALSE)
|
||||||
|
set(QET_SPACEMOUSE_BACKEND_SPNAV_ENABLED FALSE)
|
||||||
|
set(QET_SPACEMOUSE_BACKEND_HID_ENABLED FALSE)
|
||||||
|
set(QET_SPACEMOUSE_BACKEND_CONNEXION_ENABLED FALSE)
|
||||||
|
|
||||||
|
if(QET_ENABLE_SPACEMOUSE)
|
||||||
|
find_package(PkgConfig)
|
||||||
|
|
||||||
|
set(_qet_spacemouse_try_spnav FALSE)
|
||||||
|
set(_qet_spacemouse_try_hid FALSE)
|
||||||
|
if(QET_SPACEMOUSE_BACKEND STREQUAL "spnav")
|
||||||
|
set(_qet_spacemouse_try_spnav TRUE)
|
||||||
|
elseif(QET_SPACEMOUSE_BACKEND STREQUAL "hid")
|
||||||
|
set(_qet_spacemouse_try_hid TRUE)
|
||||||
|
else()
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
set(_qet_spacemouse_try_spnav TRUE)
|
||||||
|
endif()
|
||||||
|
set(_qet_spacemouse_try_hid TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# libspnav: Debian/Ubuntu's libspnav-dev ships spnav.pc.
|
||||||
|
if(_qet_spacemouse_try_spnav AND PkgConfig_FOUND)
|
||||||
|
pkg_check_modules(SPNAV IMPORTED_TARGET spnav)
|
||||||
|
if(SPNAV_FOUND)
|
||||||
|
set(QET_SPACEMOUSE_ENABLED TRUE)
|
||||||
|
set(QET_SPACEMOUSE_BACKEND_SPNAV_ENABLED TRUE)
|
||||||
|
add_definitions(-DQET_SPACEMOUSE_BACKEND_SPNAV)
|
||||||
|
message("QET_ENABLE_SPACEMOUSE ON (backend: libspnav ${SPNAV_VERSION})")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# hidapi: hidapi-hidraw.pc on Linux (libhidapi-dev), hidapi.pc from
|
||||||
|
# MSYS2 (mingw-w64-ucrt-x86_64-hidapi) and Homebrew (hidapi).
|
||||||
|
if(NOT QET_SPACEMOUSE_ENABLED AND _qet_spacemouse_try_hid AND PkgConfig_FOUND)
|
||||||
|
pkg_search_module(HIDAPI IMPORTED_TARGET hidapi-hidraw hidapi)
|
||||||
|
if(HIDAPI_FOUND)
|
||||||
|
set(QET_SPACEMOUSE_ENABLED TRUE)
|
||||||
|
set(QET_SPACEMOUSE_BACKEND_HID_ENABLED TRUE)
|
||||||
|
add_definitions(-DQET_SPACEMOUSE_BACKEND_HID)
|
||||||
|
message("QET_ENABLE_SPACEMOUSE ON (backend: hidapi ${HIDAPI_VERSION})")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# macOS: with 3DxWare installed the device can only be read through
|
||||||
|
# 3DxWare, so its backend comes too, whichever backend was asked for.
|
||||||
|
# It loads 3DxWare's library at run time and needs nothing to build.
|
||||||
|
if(APPLE)
|
||||||
|
set(QET_SPACEMOUSE_ENABLED TRUE)
|
||||||
|
set(QET_SPACEMOUSE_BACKEND_CONNEXION_ENABLED TRUE)
|
||||||
|
add_definitions(-DQET_SPACEMOUSE_BACKEND_CONNEXION)
|
||||||
|
message("QET_ENABLE_SPACEMOUSE ON (backend: 3DxWare when installed)")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(QET_SPACEMOUSE_ENABLED)
|
||||||
|
add_definitions(-DQET_SPACEMOUSE_SUPPORT)
|
||||||
|
else()
|
||||||
|
message(WARNING "QET_ENABLE_SPACEMOUSE is ON but no library was found for the "
|
||||||
|
"'${QET_SPACEMOUSE_BACKEND}' backend (libspnav-dev for spnav, "
|
||||||
|
"hidapi for hid, via pkg-config) -- building WITHOUT 3D mouse support.")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
@@ -168,6 +168,9 @@ set(QET_SRC_FILES
|
|||||||
${QET_DIR}/sources/borderproperties.h
|
${QET_DIR}/sources/borderproperties.h
|
||||||
${QET_DIR}/sources/bordertitleblock.cpp
|
${QET_DIR}/sources/bordertitleblock.cpp
|
||||||
${QET_DIR}/sources/bordertitleblock.h
|
${QET_DIR}/sources/bordertitleblock.h
|
||||||
|
${QET_DIR}/sources/bordercelllabels.h
|
||||||
|
${QET_DIR}/sources/cellruler.cpp
|
||||||
|
${QET_DIR}/sources/cellruler.h
|
||||||
${QET_DIR}/sources/conductorautonumerotation.cpp
|
${QET_DIR}/sources/conductorautonumerotation.cpp
|
||||||
${QET_DIR}/sources/conductorautonumerotation.h
|
${QET_DIR}/sources/conductorautonumerotation.h
|
||||||
${QET_DIR}/sources/conductornumexport.cpp
|
${QET_DIR}/sources/conductornumexport.cpp
|
||||||
@@ -297,6 +300,8 @@ set(QET_SRC_FILES
|
|||||||
${QET_DIR}/sources/autoNum/numerotationcontextcommands.h
|
${QET_DIR}/sources/autoNum/numerotationcontextcommands.h
|
||||||
${QET_DIR}/sources/autoNum/numerotationcontext.cpp
|
${QET_DIR}/sources/autoNum/numerotationcontext.cpp
|
||||||
${QET_DIR}/sources/autoNum/numerotationcontext.h
|
${QET_DIR}/sources/autoNum/numerotationcontext.h
|
||||||
|
${QET_DIR}/sources/autoNum/renumberelementscommand.cpp
|
||||||
|
${QET_DIR}/sources/autoNum/renumberelementscommand.h
|
||||||
${QET_DIR}/sources/autoNum/ui/autonumberingdockwidget.cpp
|
${QET_DIR}/sources/autoNum/ui/autonumberingdockwidget.cpp
|
||||||
${QET_DIR}/sources/autoNum/ui/autonumberingdockwidget.h
|
${QET_DIR}/sources/autoNum/ui/autonumberingdockwidget.h
|
||||||
${QET_DIR}/sources/autoNum/ui/autonumberingmanagementw.cpp
|
${QET_DIR}/sources/autoNum/ui/autonumberingmanagementw.cpp
|
||||||
@@ -307,6 +312,8 @@ set(QET_SRC_FILES
|
|||||||
${QET_DIR}/sources/autoNum/ui/formulaautonumberingw.h
|
${QET_DIR}/sources/autoNum/ui/formulaautonumberingw.h
|
||||||
${QET_DIR}/sources/autoNum/ui/numparteditorw.cpp
|
${QET_DIR}/sources/autoNum/ui/numparteditorw.cpp
|
||||||
${QET_DIR}/sources/autoNum/ui/numparteditorw.h
|
${QET_DIR}/sources/autoNum/ui/numparteditorw.h
|
||||||
|
${QET_DIR}/sources/autoNum/ui/renumberelementsdialog.cpp
|
||||||
|
${QET_DIR}/sources/autoNum/ui/renumberelementsdialog.h
|
||||||
${QET_DIR}/sources/autoNum/ui/selectautonumw.cpp
|
${QET_DIR}/sources/autoNum/ui/selectautonumw.cpp
|
||||||
${QET_DIR}/sources/autoNum/ui/selectautonumw.h
|
${QET_DIR}/sources/autoNum/ui/selectautonumw.h
|
||||||
|
|
||||||
@@ -871,6 +878,43 @@ list(APPEND QET_SRC_FILES
|
|||||||
${QET_DIR}/sources/scripting/qetscripting.h
|
${QET_DIR}/sources/scripting/qetscripting.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(QET_SPACEMOUSE_ENABLED)
|
||||||
|
list(APPEND QET_SRC_FILES
|
||||||
|
${QET_DIR}/sources/spacemouse/spacemousebackend.h
|
||||||
|
${QET_DIR}/sources/spacemouse/spacemousebuttonmap.cpp
|
||||||
|
${QET_DIR}/sources/spacemouse/spacemousebuttonmap.h
|
||||||
|
${QET_DIR}/sources/spacemouse/spacemouselistener.cpp
|
||||||
|
${QET_DIR}/sources/spacemouse/spacemouselistener.h
|
||||||
|
${QET_DIR}/sources/spacemouse/spacemousemotion.cpp
|
||||||
|
${QET_DIR}/sources/spacemouse/spacemousemotion.h
|
||||||
|
${QET_DIR}/sources/ui/configpage/spacemouseconfigpage.cpp
|
||||||
|
${QET_DIR}/sources/ui/configpage/spacemouseconfigpage.h
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(QET_SPACEMOUSE_BACKEND_SPNAV_ENABLED)
|
||||||
|
list(APPEND QET_SRC_FILES
|
||||||
|
${QET_DIR}/sources/spacemouse/spnavbackend.cpp
|
||||||
|
${QET_DIR}/sources/spacemouse/spnavbackend.h
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(QET_SPACEMOUSE_BACKEND_HID_ENABLED)
|
||||||
|
list(APPEND QET_SRC_FILES
|
||||||
|
${QET_DIR}/sources/spacemouse/hidbackend.cpp
|
||||||
|
${QET_DIR}/sources/spacemouse/hidbackend.h
|
||||||
|
${QET_DIR}/sources/spacemouse/spacemousehid.cpp
|
||||||
|
${QET_DIR}/sources/spacemouse/spacemousehid.h
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(QET_SPACEMOUSE_BACKEND_CONNEXION_ENABLED)
|
||||||
|
list(APPEND QET_SRC_FILES
|
||||||
|
${QET_DIR}/sources/spacemouse/connexionbackend.cpp
|
||||||
|
${QET_DIR}/sources/spacemouse/connexionbackend.h
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(TS_FILES
|
set(TS_FILES
|
||||||
${QET_DIR}/lang/qet_ar.ts
|
${QET_DIR}/lang/qet_ar.ts
|
||||||
${QET_DIR}/lang/qet_ca.ts
|
${QET_DIR}/lang/qet_ca.ts
|
||||||
|
|||||||
+1
-1
Submodule elements updated: 60eacc28a6...08e438a919
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,222 @@
|
|||||||
|
<!DOCTYPE QPH>
|
||||||
|
<QPH sourcelanguage="fr_FR" language="ca">
|
||||||
|
<phrase>
|
||||||
|
<source>Réf. croisée</source>
|
||||||
|
<target>Ref. creuada</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>armoire</source>
|
||||||
|
<target>armari</target>
|
||||||
|
<definition>cabinet / enclosure</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>bobine</source>
|
||||||
|
<target>bobina</target>
|
||||||
|
<definition>coil</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>borne</source>
|
||||||
|
<target>born</target>
|
||||||
|
<definition>terminal - a connection point on a symbol</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>bornier</source>
|
||||||
|
<target>bornes</target>
|
||||||
|
<definition>terminal strip</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>cable</source>
|
||||||
|
<target>cable</target>
|
||||||
|
<definition>cable</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>calibre</source>
|
||||||
|
<target>calibre</target>
|
||||||
|
<definition>rating - the current rating of a device</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>cartouche</source>
|
||||||
|
<target>cartutx</target>
|
||||||
|
<definition>title block - the framed information panel</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>champ de texte</source>
|
||||||
|
<target>camp de text</target>
|
||||||
|
<definition>text field</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>collection</source>
|
||||||
|
<target>col·lecció</target>
|
||||||
|
<definition>collection - the symbol library</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>conducteur</source>
|
||||||
|
<target>conductor</target>
|
||||||
|
<definition>conductor - the drawn wire between terminals</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>contact</source>
|
||||||
|
<target>contacte</target>
|
||||||
|
<definition>contact</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>contacteur</source>
|
||||||
|
<target>contactor</target>
|
||||||
|
<definition>contactor</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>courant</source>
|
||||||
|
<target>corrent</target>
|
||||||
|
<definition>current</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>disjoncteur</source>
|
||||||
|
<target>disjuntor</target>
|
||||||
|
<definition>circuit breaker</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>dossier</source>
|
||||||
|
<target>carpeta</target>
|
||||||
|
<definition>folder</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>element</source>
|
||||||
|
<target>element</target>
|
||||||
|
<definition>element - a symbol placed on a sheet</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>esclave</source>
|
||||||
|
<target>esclau</target>
|
||||||
|
<definition>slave - the contact block belonging to a master</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>fil</source>
|
||||||
|
<target>fil</target>
|
||||||
|
<definition>wire</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>folio</source>
|
||||||
|
<target>plec</target>
|
||||||
|
<definition>sheet - one drawing of a set</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>fusible</source>
|
||||||
|
<target>fusible</target>
|
||||||
|
<definition>fuse</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>grille</source>
|
||||||
|
<target>graella</target>
|
||||||
|
<definition>grid</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>interrupteur</source>
|
||||||
|
<target>interruptor</target>
|
||||||
|
<definition>switch</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>maitre</source>
|
||||||
|
<target>mestre</target>
|
||||||
|
<definition>master - the element a cross-reference points from</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>modele</source>
|
||||||
|
<target>plantilla</target>
|
||||||
|
<definition>template</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>moteur</source>
|
||||||
|
<target>motor</target>
|
||||||
|
<definition>motor</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>neutre</source>
|
||||||
|
<target>neutre</target>
|
||||||
|
<definition>neutral</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>nomenclature</source>
|
||||||
|
<target>nomenclatura</target>
|
||||||
|
<definition>parts list / bill of materials</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>numerotation</source>
|
||||||
|
<target>numeració</target>
|
||||||
|
<definition>numbering - automatic wire and part numbering</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>phase</source>
|
||||||
|
<target>fase</target>
|
||||||
|
<definition>phase</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>potentiel</source>
|
||||||
|
<target>potencial</target>
|
||||||
|
<definition>potential - conductors electrically joined as one node</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>projet</source>
|
||||||
|
<target>projecte</target>
|
||||||
|
<definition>project - the .qet file holding the sheets</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>puissance</source>
|
||||||
|
<target>potència</target>
|
||||||
|
<definition>power</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>relais</source>
|
||||||
|
<target>relé</target>
|
||||||
|
<definition>relay</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>renvoi de folio</source>
|
||||||
|
<target>referència de plec</target>
|
||||||
|
<definition>sheet cross-reference</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>repere</source>
|
||||||
|
<target>referència</target>
|
||||||
|
<definition>designation - the identifying mark on a part</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>report de folio</source>
|
||||||
|
<target>remissió de plec</target>
|
||||||
|
<definition>sheet cross-reference (the arrow symbol)</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>schema</source>
|
||||||
|
<target>esquema</target>
|
||||||
|
<definition>diagram</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>section</source>
|
||||||
|
<target>secció</target>
|
||||||
|
<definition>cross-section - conductor size in mm2</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>sommaire</source>
|
||||||
|
<target>sumari</target>
|
||||||
|
<definition>summary / table of contents</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>tension</source>
|
||||||
|
<target>tensió</target>
|
||||||
|
<definition>voltage</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>terre</source>
|
||||||
|
<target>terra</target>
|
||||||
|
<definition>earth / ground</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>texte</source>
|
||||||
|
<target>text</target>
|
||||||
|
<definition>text</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>transformateur</source>
|
||||||
|
<target>transformador</target>
|
||||||
|
<definition>transformer</definition>
|
||||||
|
</phrase>
|
||||||
|
</QPH>
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -100,4 +100,8 @@
|
|||||||
<source>traduction</source>
|
<source>traduction</source>
|
||||||
<target>Übersetzung</target>
|
<target>Übersetzung</target>
|
||||||
</phrase>
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier le nom de la borne</source>
|
||||||
|
<target>Klemmenname ändern</target>
|
||||||
|
</phrase>
|
||||||
</QPH>
|
</QPH>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,918 @@
|
|||||||
|
<!DOCTYPE QPH>
|
||||||
|
<QPH sourcelanguage="fr_FR" language="en">
|
||||||
|
<phrase>
|
||||||
|
<source>Blue : Blue</source>
|
||||||
|
<target>Blue : Blue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Blue : CornflowerBlue</source>
|
||||||
|
<target>Blue : CornflowerBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Blue : DarkBlue</source>
|
||||||
|
<target>Blue : DarkBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Blue : DeepSkyBlue</source>
|
||||||
|
<target>Blue : DeepSkyBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Blue : DodgerBlue</source>
|
||||||
|
<target>Blue : DodgerBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Blue : LightBlue</source>
|
||||||
|
<target>Blue : LightBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Blue : LightSkyBlue</source>
|
||||||
|
<target>Blue : LightSkyBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Blue : LightSteelBlue</source>
|
||||||
|
<target>Blue : LightSteelBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Blue : MediumBlue</source>
|
||||||
|
<target>Blue : MediumBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Blue : MidnightBlue</source>
|
||||||
|
<target>Blue : MidnightBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Blue : Navy</source>
|
||||||
|
<target>Blue : Navy</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Blue : PowderBlue</source>
|
||||||
|
<target>Blue : PowderBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Blue : RoyalBlue</source>
|
||||||
|
<target>Blue : RoyalBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Blue : SkyBlue</source>
|
||||||
|
<target>Blue : SkyBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Blue : SteelBlue</source>
|
||||||
|
<target>Blue : SteelBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : Bisque</source>
|
||||||
|
<target>Brown : Bisque</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : BlanchedAlmond</source>
|
||||||
|
<target>Brown : BlanchedAlmond</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : Brown</source>
|
||||||
|
<target>Brown : Brown</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : Burlywood</source>
|
||||||
|
<target>Brown : Burlywood</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : Chocolate</source>
|
||||||
|
<target>Brown : Chocolate</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : Cornsilk</source>
|
||||||
|
<target>Brown : Cornsilk</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : DarkGoldenrod</source>
|
||||||
|
<target>Brown : DarkGoldenrod</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : Goldenrod</source>
|
||||||
|
<target>Brown : Goldenrod</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : Maroon</source>
|
||||||
|
<target>Brown : Maroon</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : NavajoWhite</source>
|
||||||
|
<target>Brown : NavajoWhite</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : Peru</source>
|
||||||
|
<target>Brown : Peru</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : RosyBrown</source>
|
||||||
|
<target>Brown : RosyBrown</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : SaddleBrown</source>
|
||||||
|
<target>Brown : SaddleBrown</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : SandyBrown</source>
|
||||||
|
<target>Brown : SandyBrown</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : Sienna</source>
|
||||||
|
<target>Brown : Sienna</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : Tan</source>
|
||||||
|
<target>Brown : Tan</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Brown : Wheat</source>
|
||||||
|
<target>Brown : Wheat</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cyan : Aqua</source>
|
||||||
|
<target>Cyan : Aqua</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cyan : Aquamarine</source>
|
||||||
|
<target>Cyan : Aquamarine</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cyan : CadetBlue</source>
|
||||||
|
<target>Cyan : CadetBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cyan : Cyan</source>
|
||||||
|
<target>Cyan : Cyan</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cyan : DarkCyan</source>
|
||||||
|
<target>Cyan : DarkCyan</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cyan : DarkTurquoise</source>
|
||||||
|
<target>Cyan : DarkTurquoise</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cyan : LightCyan</source>
|
||||||
|
<target>Cyan : LightCyan</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cyan : LightSeaGreen</source>
|
||||||
|
<target>Cyan : LightSeaGreen</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cyan : MediumTurquoise</source>
|
||||||
|
<target>Cyan : MediumTurquoise</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cyan : PaleTurquoise</source>
|
||||||
|
<target>Cyan : PaleTurquoise</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cyan : Teal</source>
|
||||||
|
<target>Cyan : Teal</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cyan : Turquoise</source>
|
||||||
|
<target>Cyan : Turquoise</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Gray : Black</source>
|
||||||
|
<target>Gray : Black</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Gray : DarkGray</source>
|
||||||
|
<target>Gray : DarkGray</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Gray : DarkSlateGray</source>
|
||||||
|
<target>Gray : DarkSlateGray</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Gray : DimGray</source>
|
||||||
|
<target>Gray : DimGray</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Gray : Gainsboro</source>
|
||||||
|
<target>Gray : Gainsboro</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Gray : Gray</source>
|
||||||
|
<target>Gray : Gray</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Gray : LightGray</source>
|
||||||
|
<target>Gray : LightGray</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Gray : LightSlateGray</source>
|
||||||
|
<target>Gray : LightSlateGray</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Gray : Silver</source>
|
||||||
|
<target>Gray : Silver</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Gray : SlateGray</source>
|
||||||
|
<target>Gray : SlateGray</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : Chartreuse</source>
|
||||||
|
<target>Green : Chartreuse</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : DarkGreen</source>
|
||||||
|
<target>Green : DarkGreen</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : DarkOliveGreen</source>
|
||||||
|
<target>Green : DarkOliveGreen</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : DarkSeaGreen</source>
|
||||||
|
<target>Green : DarkSeaGreen</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : ForestGreen</source>
|
||||||
|
<target>Green : ForestGreen</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : Green</source>
|
||||||
|
<target>Green : Green</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : GreenYellow</source>
|
||||||
|
<target>Green : GreenYellow</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : LawnGreen</source>
|
||||||
|
<target>Green : LawnGreen</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : LightGreen</source>
|
||||||
|
<target>Green : LightGreen</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : Lime</source>
|
||||||
|
<target>Green : Lime</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : LimeGreen</source>
|
||||||
|
<target>Green : LimeGreen</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : MediumAquamarine</source>
|
||||||
|
<target>Green : MediumAquamarine</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : MediumSeaGreen</source>
|
||||||
|
<target>Green : MediumSeaGreen</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : MediumSpringGreen</source>
|
||||||
|
<target>Green : MediumSpringGreen</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : Olive</source>
|
||||||
|
<target>Green : Olive</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : OliveDrab</source>
|
||||||
|
<target>Green : OliveDrab</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : PaleGreen</source>
|
||||||
|
<target>Green : PaleGreen</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : SeaGreen</source>
|
||||||
|
<target>Green : SeaGreen</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : SpringGreen</source>
|
||||||
|
<target>Green : SpringGreen</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Green : YellowGreen</source>
|
||||||
|
<target>Green : YellowGreen</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Orange : Coral</source>
|
||||||
|
<target>Orange : Coral</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Orange : DarkOrange</source>
|
||||||
|
<target>Orange : DarkOrange</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Orange : Orange</source>
|
||||||
|
<target>Orange : Orange</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Orange : OrangeRed</source>
|
||||||
|
<target>Orange : OrangeRed</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Orange : Tomato</source>
|
||||||
|
<target>Orange : Tomato</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Pink : DeepPink</source>
|
||||||
|
<target>Pink: DeepPink</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Pink : HotPink</source>
|
||||||
|
<target>Pink: HotPink</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Pink : LightPink</source>
|
||||||
|
<target>Pink: LightPink</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Pink : MediumVioletRed</source>
|
||||||
|
<target>Pink: MediumVioletRed</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Pink : PaleVioletRed</source>
|
||||||
|
<target>Pink: PaleVioletRed</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Pink : Pink</source>
|
||||||
|
<target>Pink: Pink</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : BlueViolet</source>
|
||||||
|
<target>Purple : BlueViolet</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : DarkMagenta</source>
|
||||||
|
<target>Purple : DarkMagenta</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : DarkOrchid</source>
|
||||||
|
<target>Purple : DarkOrchid</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : DarkSlateBlue</source>
|
||||||
|
<target>Purple : DarkSlateBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : DarkViolet</source>
|
||||||
|
<target>Purple : DarkViolet</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : Fuchsia</source>
|
||||||
|
<target>Purple : Fuchsia</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : Indigo</source>
|
||||||
|
<target>Purple : Indigo</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : Lavender</source>
|
||||||
|
<target>Purple : Lavender</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : Magenta</source>
|
||||||
|
<target>Purple : Magenta</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : MediumOrchid</source>
|
||||||
|
<target>Purple : MediumOrchid</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : MediumPurple</source>
|
||||||
|
<target>Purple : MediumPurple</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : MediumSlateBlue</source>
|
||||||
|
<target>Purple : MediumSlateBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : Orchid</source>
|
||||||
|
<target>Purple : Orchid</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : Plum</source>
|
||||||
|
<target>Purple : Plum</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : Purple</source>
|
||||||
|
<target>Purple : Purple</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : SlateBlue</source>
|
||||||
|
<target>Purple : SlateBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : Thistle</source>
|
||||||
|
<target>Purple : Thistle</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Purple : Violet</source>
|
||||||
|
<target>Purple : Violet</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Red : Crimson</source>
|
||||||
|
<target>Red : Crimson</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Red : DarkRed</source>
|
||||||
|
<target>Red : DarkRed</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Red : DarkSalmon</source>
|
||||||
|
<target>Red: DarkSalmon</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Red : Firebrick</source>
|
||||||
|
<target>Red : Firebrick</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Red : IndianRed</source>
|
||||||
|
<target>Red: IndianRed</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Red : LightCoral</source>
|
||||||
|
<target>Red: LightCoral</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Red : LightSalmon</source>
|
||||||
|
<target>Red: LightSalmon</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Red : Red</source>
|
||||||
|
<target>Red : Red</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Red : Salmon</source>
|
||||||
|
<target>Red: Salmon</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : AliceBlue</source>
|
||||||
|
<target>White : AliceBlue</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : AntiqueWhite</source>
|
||||||
|
<target>White : AntiqueWhite</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : Azure</source>
|
||||||
|
<target>White : Azure</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : Beige</source>
|
||||||
|
<target>White : Beige</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : FloralWhite</source>
|
||||||
|
<target>White : FloralWhite</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : GhostWhite</source>
|
||||||
|
<target>White : GhostWhite</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : Honeydew</source>
|
||||||
|
<target>White : Honeydew</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : Ivory</source>
|
||||||
|
<target>White : Ivory</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : LavenderBlush</source>
|
||||||
|
<target>White : LavenderBlush</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : Linen</source>
|
||||||
|
<target>White : Linen</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : MintCream</source>
|
||||||
|
<target>White : MintCream</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : MistyRose</source>
|
||||||
|
<target>White : MistyRose</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : OldLace</source>
|
||||||
|
<target>White : OldLace</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : Seashell</source>
|
||||||
|
<target>White : Seashell</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : Snow</source>
|
||||||
|
<target>White : Snow</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : White</source>
|
||||||
|
<target>White : White</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>White : WhiteSmoke</source>
|
||||||
|
<target>White : WhiteSmoke</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Yellow : DarkKhaki</source>
|
||||||
|
<target>Yellow : DarkKhaki</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Yellow : Gold</source>
|
||||||
|
<target>Yellow : Gold</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Yellow : Khaki</source>
|
||||||
|
<target>Yellow : Khaki</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Yellow : LemonChiffon</source>
|
||||||
|
<target>Yellow : LemonChiffon</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Yellow : LightGoldenrodYellow</source>
|
||||||
|
<target>Yellow : LightGoldenrodYellow</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Yellow : LightYellow</source>
|
||||||
|
<target>Yellow : LightYellow</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Yellow : Moccasin</source>
|
||||||
|
<target>Yellow : Moccasin</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Yellow : PaleGoldenrod</source>
|
||||||
|
<target>Yellow : PaleGoldenrod</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Yellow : PapayaWhip</source>
|
||||||
|
<target>Yellow : PapayaWhip</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Yellow : PeachPuff</source>
|
||||||
|
<target>Yellow : PeachPuff</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Yellow : Yellow</source>
|
||||||
|
<target>Yellow : Yellow</target>
|
||||||
|
<definition>element part filling</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>armoire</source>
|
||||||
|
<target>cabinet</target>
|
||||||
|
<definition>cabinet / enclosure</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>bobine</source>
|
||||||
|
<target>coil</target>
|
||||||
|
<definition>coil</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>borne</source>
|
||||||
|
<target>terminal</target>
|
||||||
|
<definition>terminal - a connection point on a symbol</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>bornier</source>
|
||||||
|
<target>terminal strip</target>
|
||||||
|
<definition>terminal strip</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>cable</source>
|
||||||
|
<target>cable</target>
|
||||||
|
<definition>cable</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>calibre</source>
|
||||||
|
<target>rating</target>
|
||||||
|
<definition>rating - the current rating of a device</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>cartouche</source>
|
||||||
|
<target>title block</target>
|
||||||
|
<definition>title block - the framed information panel</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>champ de texte</source>
|
||||||
|
<target>text field</target>
|
||||||
|
<definition>text field</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>collection</source>
|
||||||
|
<target>collection</target>
|
||||||
|
<definition>collection - the symbol library</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>conducteur</source>
|
||||||
|
<target>conductor</target>
|
||||||
|
<definition>conductor - the drawn wire between terminals</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>contact</source>
|
||||||
|
<target>contact</target>
|
||||||
|
<definition>contact</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>contacteur</source>
|
||||||
|
<target>contactor</target>
|
||||||
|
<definition>contactor</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>courant</source>
|
||||||
|
<target>current</target>
|
||||||
|
<definition>current</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>disjoncteur</source>
|
||||||
|
<target>circuit breaker</target>
|
||||||
|
<definition>circuit breaker</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>dossier</source>
|
||||||
|
<target>folder</target>
|
||||||
|
<definition>folder</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>element</source>
|
||||||
|
<target>element</target>
|
||||||
|
<definition>element - a symbol placed on a sheet</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>esclave</source>
|
||||||
|
<target>slave</target>
|
||||||
|
<definition>slave - the contact block belonging to a master</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>fil</source>
|
||||||
|
<target>wire</target>
|
||||||
|
<definition>wire</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>folio</source>
|
||||||
|
<target>sheet</target>
|
||||||
|
<definition>sheet - one drawing of a set</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>fusible</source>
|
||||||
|
<target>fuse</target>
|
||||||
|
<definition>fuse</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>grille</source>
|
||||||
|
<target>grid</target>
|
||||||
|
<definition>grid</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>interrupteur</source>
|
||||||
|
<target>switch</target>
|
||||||
|
<definition>switch</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>maitre</source>
|
||||||
|
<target>master</target>
|
||||||
|
<definition>master - the element a cross-reference points from</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>modele</source>
|
||||||
|
<target>template</target>
|
||||||
|
<definition>template</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>moteur</source>
|
||||||
|
<target>motor</target>
|
||||||
|
<definition>motor</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>neutre</source>
|
||||||
|
<target>neutral</target>
|
||||||
|
<definition>neutral</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>nomenclature</source>
|
||||||
|
<target>parts list</target>
|
||||||
|
<definition>parts list / bill of materials</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>numerotation</source>
|
||||||
|
<target>numbering</target>
|
||||||
|
<definition>numbering - automatic wire and part numbering</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>phase</source>
|
||||||
|
<target>phase</target>
|
||||||
|
<definition>phase</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>potentiel</source>
|
||||||
|
<target>potential</target>
|
||||||
|
<definition>potential - conductors electrically joined as one node</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>projet</source>
|
||||||
|
<target>project</target>
|
||||||
|
<definition>project - the .qet file holding the sheets</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>puissance</source>
|
||||||
|
<target>power</target>
|
||||||
|
<definition>power</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>relais</source>
|
||||||
|
<target>relay</target>
|
||||||
|
<definition>relay</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>renvoi de folio</source>
|
||||||
|
<target>sheet cross-reference</target>
|
||||||
|
<definition>sheet cross-reference</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>repere</source>
|
||||||
|
<target>designation</target>
|
||||||
|
<definition>designation - the identifying mark on a part</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>report de folio</source>
|
||||||
|
<target>sheet cross-reference</target>
|
||||||
|
<definition>sheet cross-reference (the arrow symbol)</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>schema</source>
|
||||||
|
<target>diagram</target>
|
||||||
|
<definition>diagram</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>section</source>
|
||||||
|
<target>cross-section</target>
|
||||||
|
<definition>cross-section - conductor size in mm2</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>sommaire</source>
|
||||||
|
<target>summary</target>
|
||||||
|
<definition>summary / table of contents</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>tension</source>
|
||||||
|
<target>voltage</target>
|
||||||
|
<definition>voltage</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>terre</source>
|
||||||
|
<target>earth</target>
|
||||||
|
<definition>earth / ground</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>texte</source>
|
||||||
|
<target>text</target>
|
||||||
|
<definition>text</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>transformateur</source>
|
||||||
|
<target>transformer</target>
|
||||||
|
<definition>transformer</definition>
|
||||||
|
</phrase>
|
||||||
|
</QPH>
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,941 @@
|
|||||||
|
<!DOCTYPE QPH>
|
||||||
|
<QPH sourcelanguage="fr_FR" language="nl_BE">
|
||||||
|
<phrase>
|
||||||
|
<source> Contacts : NO : %1, NC : %2, inverseurs : %3, autres : %4
|
||||||
|
</source>
|
||||||
|
<target>Contacten: NO: %1, NC: %2, wisselcontacten: %3, andere: %4
|
||||||
|
</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> Contacts : NO : %1/%2, NC : %3/%4, inverseurs : %5/%6, autres : %7/%8
|
||||||
|
</source>
|
||||||
|
<target>Contacten: NO: %1/%2, NC: %3/%4, wisselcontacten: %5/%6, andere: %7/%8
|
||||||
|
</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> %</source>
|
||||||
|
<target>%</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> (Ctrl pendant le glissement = position libre, sans accrochage à la grille)</source>
|
||||||
|
<target>(Ctrl tijdens het slepen = vrije positie, zonder vastklikken aan het raster)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> -- %1 : mode %2</source>
|
||||||
|
<target>-- %1 : modus %2</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> ; point rouge : glisser pour repositionner le centre de rotation</source>
|
||||||
|
<target>; rood punt: slepen om het draaipunt te verplaatsen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> ; point turquoise : arc</source>
|
||||||
|
<target>; turquoise punt: boog</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> ; un bord : inclinaison</source>
|
||||||
|
<target>; een rand: kanteling</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> °</source>
|
||||||
|
<target>°</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> — Cliquer : mode %1</source>
|
||||||
|
<target>— Klikken: modus %1</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>, Alt = créer des poignées</source>
|
||||||
|
<target>, Alt = handgrepen creëren</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>, Alt = détacher en polyligne</source>
|
||||||
|
<target>, Alt = losmaken als polylijn</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Ajoute une courbe de Bézier sur le folio actuel</source>
|
||||||
|
<target>Voegt een Béziercurve toe op het huidige blad</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Ajouter la borne %1</source>
|
||||||
|
<target>Klem %1 toevoegen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Ajouter un point à une courbe</source>
|
||||||
|
<target>Een punt aan een curve toevoegen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Ajouter une courbe</source>
|
||||||
|
<target>Een curve toevoegen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Angle</source>
|
||||||
|
<target>Hoek</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Anguleux</source>
|
||||||
|
<target>Hoekig</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Aperçu</source>
|
||||||
|
<target>Voorbeeld</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Arrondir les coins d'%1</source>
|
||||||
|
<target>Hoeken van %1 afronden</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Borne 1</source>
|
||||||
|
<target>Klem 1</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Borne 2</source>
|
||||||
|
<target>Klem 2</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Catégorie</source>
|
||||||
|
<target>Categorie</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Ce format ne prend pas en charge la transparence : l'image sera enregistrée telle qu'elle était avant l'application de la couleur transparente. Continuer ?</source>
|
||||||
|
<target>Dit formaat ondersteunt geen transparantie: de afbeelding wordt opgeslagen zoals ze was vóór het toepassen van de transparante kleur. Doorgaan?</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Champ de texte</source>
|
||||||
|
<target>Tekstveld</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic : positionner à la taille d'origine. Cliquer-glisser : positionner et redimensionner. Clic droit : pivoter de 90°. Ctrl+molette : ajuster la taille.</source>
|
||||||
|
<target>Klik: op oorspronkelijke grootte plaatsen. Klikken en slepen: plaatsen en formaat wijzigen. Rechtsklik: 90° draaien. Ctrl+muiswiel: formaat aanpassen.</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic gauche : point suivant ; double-clic ou Entrée : terminer ; clic droit : annuler le dernier point</source>
|
||||||
|
<target>Linkerklik: volgend punt; dubbelklik of Enter: beëindigen; rechtsklik: laatste punt annuleren</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic gauche : positionner le coin opposé (Maj = carré, Ctrl = depuis le centre + position libre, Ctrl+Maj = carré centré) ; clic droit : annuler</source>
|
||||||
|
<target>Linkerklik: tegenoverliggende hoek plaatsen (Shift = vierkant, Ctrl = vanuit het midden + vrije positie, Ctrl+Shift = gecentreerd vierkant); rechtsklik: annuleren</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic gauche : positionner le coin opposé (Maj = cercle, Ctrl = depuis le centre + position libre, Ctrl+Maj = cercle centré) ; clic droit : annuler</source>
|
||||||
|
<target>Linkerklik: tegenoverliggende hoek plaatsen (Shift = cirkel, Ctrl = vanuit het midden + vrije positie, Ctrl+Shift = gecentreerde cirkel); rechtsklik: annuleren</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic gauche : positionner le point de départ (Ctrl = position libre)</source>
|
||||||
|
<target>Linkerklik: startpunt plaatsen (Ctrl = vrije positie)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic gauche : positionner le point final (Ctrl = position libre) ; clic droit : annuler</source>
|
||||||
|
<target>Linkerklik: eindpunt plaatsen (Ctrl = vrije positie); rechtsklik: annuleren</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic gauche : positionner le premier coin (Ctrl = point central, position libre)</source>
|
||||||
|
<target>Linkerklik: eerste hoek plaatsen (Ctrl = middelpunt, vrije positie)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic gauche : positionner le premier point (Ctrl = position libre)</source>
|
||||||
|
<target>Linkerklik: eerste punt plaatsen (Ctrl = vrije positie)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic: point anguleux. Cliquer-glisser: point courbe. Clic sur le premier point: fermer. Échap/Entrée: terminer. Clic droit: annuler le dernier point.</source>
|
||||||
|
<target>Klik: hoekpunt. Klikken en slepen: curvepunt. Klik op het eerste punt: sluiten. Esc/Enter: beëindigen. Rechtsklik: laatste punt annuleren.</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cliquer</source>
|
||||||
|
<target>Klikken</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cliquer : mode %1</source>
|
||||||
|
<target>Klikken: modus %1</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cliquez pour choisir une couleur</source>
|
||||||
|
<target>Klik om een kleur te kiezen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cliquez sur l'image pour ajouter une couleur. Ajustez la tolérance de chaque couleur avec son curseur, ou cliquez sur × pour la retirer.</source>
|
||||||
|
<target>Klik op de afbeelding om een kleur toe te voegen. Pas de tolerantie van elke kleur aan met de schuifregelaar, of klik op × om ze te verwijderen.</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cliquez sur l'image pour choisir une couleur</source>
|
||||||
|
<target>Klik op de afbeelding om een kleur te kiezen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Coins arrondis</source>
|
||||||
|
<target>Afgeronde hoeken</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Composant 1</source>
|
||||||
|
<target>Component 1</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Composant 2</source>
|
||||||
|
<target>Component 2</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Convertir %1 en courbe de Bézier</source>
|
||||||
|
<target>%1 omzetten naar Béziercurve</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Convertir %1 en polyligne</source>
|
||||||
|
<target>%1 omzetten naar polylijn</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Convertir en courbe de Bézier</source>
|
||||||
|
<target>Omzetten naar Béziercurve</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Convertir en polyligne</source>
|
||||||
|
<target>Omzetten naar polylijn</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Couleur transparente</source>
|
||||||
|
<target>Transparante kleur</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Couleur transparente...</source>
|
||||||
|
<target>Transparante kleur...</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Courant nominal</source>
|
||||||
|
<target>Nominale stroom</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Deplacer le centre de rotation</source>
|
||||||
|
<target>Draaipunt verplaatsen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Description</source>
|
||||||
|
<target>Beschrijving</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Distance in pixels between the label and the slave cross reference</source>
|
||||||
|
<target>Afstand in pixels tussen het label en de slave-kruisverwijzing</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Distance label - slave :</source>
|
||||||
|
<target>Afstand label - slave:</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Définir une couleur transparente</source>
|
||||||
|
<target>Een transparante kleur instellen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Déformer une courbe</source>
|
||||||
|
<target>Een curve vervormen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Déplacer le centre de rotation d'une image</source>
|
||||||
|
<target>Het draaipunt van een afbeelding verplaatsen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Déverrouillé : largeur et hauteur peuvent être modifiées indépendamment. Cliquer pour verrouiller.</source>
|
||||||
|
<target>Ontgrendeld: breedte en hoogte kunnen onafhankelijk worden gewijzigd. Klik om te vergrendelen.</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Enregistrer l'image d'origine sous...</source>
|
||||||
|
<target>Oorspronkelijke afbeelding opslaan als...</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Enregistrer l'image sous...</source>
|
||||||
|
<target>Afbeelding opslaan als...</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Erreur</source>
|
||||||
|
<target>Fout</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Exclure de la nomenclature</source>
|
||||||
|
<target>Uitsluiten van de stuklijst</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Faire pivoter %1</source>
|
||||||
|
<target>%1 roteren</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Faire pivoter une image</source>
|
||||||
|
<target>Een afbeelding draaien</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Faites glisser les poignées, ou l'intérieur du cadre, pour ajuster la zone à conserver.</source>
|
||||||
|
<target>Sleep de handgrepen, of het binnenste van het kader, om het te behouden gebied aan te passen.</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Fil</source>
|
||||||
|
<target>Draad</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Folio</source>
|
||||||
|
<target>Blad</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Forme fermée</source>
|
||||||
|
<target>Gesloten vorm</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser %1 : rotation (Maj = 15°)</source>
|
||||||
|
<target>Sleep %1: rotatie (Shift = 15°)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : ajuster l'arc (Ctrl = position libre, Maj = 15°)</source>
|
||||||
|
<target>Slepen: de boog aanpassen (Ctrl = vrije positie, Shift = 15°)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : arrondir les coins (Ctrl = position libre)</source>
|
||||||
|
<target>Slepen: hoeken afronden (Ctrl = vrije positie)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : déformer la courbe (Ctrl = position libre, Alt = briser la tangente)</source>
|
||||||
|
<target>Slepen: de curve vervormen (Ctrl = vrije positie, Alt = de raaklijn breken)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : déplacer ce point</source>
|
||||||
|
<target>Slepen: dit punt verplaatsen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : déplacer le centre de rotation</source>
|
||||||
|
<target>Slepen: draaipunt verplaatsen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : déplacer le point (Ctrl = position libre</source>
|
||||||
|
<target>Slepen: het punt verplaatsen (Ctrl = vrije positie</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : inclinaison (Ctrl = position libre, Maj = 15°)</source>
|
||||||
|
<target>Slepen: kanteling (Ctrl = vrije positie, Shift = 15°)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : incliner (Maj = par pas de 15°)</source>
|
||||||
|
<target>Slepen: kantelen (Shift = stappen van 15°)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : pivoter (Maj = par pas de 15°)</source>
|
||||||
|
<target>Slepen: draaien (Shift = stappen van 15°)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : redimensionner (Ctrl = depuis le centre + position libre, Maj = proportions</source>
|
||||||
|
<target>Slepen: formaat wijzigen (Ctrl = vanuit het midden + vrije positie, Shift = verhoudingen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : redimensionner (Maj = conserver les proportions, Ctrl = depuis le centre)</source>
|
||||||
|
<target>Slepen: formaat wijzigen (Shift = verhoudingen behouden, Ctrl = vanuit het midden)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : repositionner le centre de rotation (Ctrl = position libre)</source>
|
||||||
|
<target>Slepen: het draaipunt verplaatsen (Ctrl = vrije positie)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : rotation (Ctrl = position libre, Maj = 15°)</source>
|
||||||
|
<target>Slepen: rotatie (Ctrl = vrije positie, Shift = 15°)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser le point violet : arrondir les coins</source>
|
||||||
|
<target>Sleep het paarse punt: hoeken afronden</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser un coin : pivoter (Maj = par pas de 15°) ; glisser un bord : incliner (Maj = par pas de 15°) ; point rouge : déplacer le centre de rotation</source>
|
||||||
|
<target>Sleep een hoek: draaien (Shift = stappen van 15°); sleep een rand: kantelen (Shift = stappen van 15°); rood punt: draaipunt verplaatsen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser un coin/bord : redimensionner (Ctrl = depuis le centre, Maj = conserver les proportions)</source>
|
||||||
|
<target>Sleep een hoek/rand: formaat wijzigen (Ctrl = vanuit het midden, Shift = verhoudingen behouden)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser un coin/bord : redimensionner (Ctrl = depuis le centre, Maj = proportions, Alt = détacher en polyligne)</source>
|
||||||
|
<target>Sleep een hoek/rand: formaat wijzigen (Ctrl = vanuit het midden, Shift = verhoudingen, Alt = losmaken als polylijn)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser un point : le déplacer</source>
|
||||||
|
<target>Sleep een punt: het verplaatsen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser une extrémité : la déplacer</source>
|
||||||
|
<target>Sleep een uiteinde: het verplaatsen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser une poignée ou la courbe : déformer (Alt = briser la tangente) ; Alt+glisser un point anguleux : créer des poignées ; clic droit : menu du nœud le plus proche</source>
|
||||||
|
<target>Sleep een handgreep of de curve: vervormen (Alt = de raaklijn breken); Alt+sleep een hoekpunt: handgrepen creëren; rechtsklik: menu van het dichtstbijzijnde knooppunt</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Géométrie</source>
|
||||||
|
<target>Geometrie</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Hauteur</source>
|
||||||
|
<target>Hoogte</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Image BMP (*.bmp)</source>
|
||||||
|
<target>BMP-afbeelding (*.bmp)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Image Files (*.png *.jpg *.jpeg *.bmp *.svg)</source>
|
||||||
|
<target>Afbeeldingsbestanden (*.png *.jpg *.jpeg *.bmp *.svg)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Image JPEG (*.jpg *.jpeg)</source>
|
||||||
|
<target>JPEG-afbeelding (*.jpg *.jpeg)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Image PNG (*.png)</source>
|
||||||
|
<target>PNG-afbeelding (*.png)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Image source</source>
|
||||||
|
<target>Bronafbeelding</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Image SVG (*.svg)</source>
|
||||||
|
<target>SVG-afbeelding (*.svg)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Images non incluses dans l'export DXF</source>
|
||||||
|
<target>Afbeeldingen niet inbegrepen in de DXF-export</target>
|
||||||
|
<definition>message box title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Impossible d'enregistrer l'image à cet emplacement.</source>
|
||||||
|
<target>Kan de afbeelding niet op die locatie opslaan.</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Impossible d'enregistrer la nomenclature dans %1.
|
||||||
|
%2</source>
|
||||||
|
<target>Kan de stuklijst niet opslaan in %1.
|
||||||
|
%2</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Impossible de charger l'image.</source>
|
||||||
|
<target>Kan de afbeelding niet laden.</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Inclinaison X</source>
|
||||||
|
<target>Kanteling X</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Inclinaison Y</source>
|
||||||
|
<target>Kanteling Y</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Incliner %1</source>
|
||||||
|
<target>%1 kantelen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Incliner une image</source>
|
||||||
|
<target>Een afbeelding kantelen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>La limite fixée pour cet élément maître est atteinte (Limite: %1).
|
||||||
|
|
||||||
|
Voulez-vous tout de même lier ce contact esclave ?</source>
|
||||||
|
<target>De limiet voor dit hoofdelement is bereikt (Limiet: %1).
|
||||||
|
|
||||||
|
Wilt u dit hulpcontact toch koppelen?</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Largeur</source>
|
||||||
|
<target>Breedte</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Le format DXF utilisé ici (AC1006) ne permet pas d'inclure d'image. Les images seront représentées uniquement par un rectangle de contour (position, taille, rotation et inclinaison conservées), sans le contenu de l'image.</source>
|
||||||
|
<target>Het hier gebruikte DXF-formaat (AC1006) laat niet toe afbeeldingen op te nemen. Afbeeldingen worden enkel voorgesteld door een omtrekrechthoek (positie, grootte, rotatie en kanteling behouden), zonder de inhoud van de afbeelding.</target>
|
||||||
|
<definition>message box content</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Lisse</source>
|
||||||
|
<target>Vloeiend</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Liste de câblage</source>
|
||||||
|
<target>Bekabelingslijst</target>
|
||||||
|
<definition>window title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Liste de câblage (base de données)</source>
|
||||||
|
<target>Bekabelingslijst (database)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Localisation :</source>
|
||||||
|
<target>Locatie:</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Longueur</source>
|
||||||
|
<target>Lengte</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>margin: 5px; font-weight: bold;</source>
|
||||||
|
<target>margin: 5px; font-weight: bold;</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>max:</source>
|
||||||
|
<target>max:</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>min:</source>
|
||||||
|
<target>min:</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Miroir horizontal</source>
|
||||||
|
<target>Horizontaal spiegelen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Miroir horizontal d'une image</source>
|
||||||
|
<target>Horizontaal spiegelen van een afbeelding</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Miroir horizontal de %1</source>
|
||||||
|
<target>Horizontaal spiegelen van %1</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Miroir impossible : inclinaison trop extrême pour cette forme</source>
|
||||||
|
<target>Spiegelen onmogelijk: kanteling te extreem voor deze vorm</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Miroir vertical</source>
|
||||||
|
<target>Verticaal spiegelen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Miroir vertical d'une image</source>
|
||||||
|
<target>Verticaal spiegelen van een afbeelding</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Miroir vertical de %1</source>
|
||||||
|
<target>Verticaal spiegelen van %1</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier l'angle d'un arc</source>
|
||||||
|
<target>Hoek van een boog wijzigen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier l'angle d'une forme</source>
|
||||||
|
<target>Hoek van een vorm wijzigen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier l'angle d'une image</source>
|
||||||
|
<target>De hoek van een afbeelding wijzigen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier l'inclinaison d'une image</source>
|
||||||
|
<target>De kanteling van een afbeelding wijzigen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier la courbure d'%1</source>
|
||||||
|
<target>Kromming van %1 wijzigen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier la forme d'%1</source>
|
||||||
|
<target>Vorm van %1 wijzigen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier la hauteur d'une image</source>
|
||||||
|
<target>De hoogte van een afbeelding wijzigen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier la largeur d'une image</source>
|
||||||
|
<target>De breedte van een afbeelding wijzigen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier la longueur d'une ligne</source>
|
||||||
|
<target>Lengte van een lijn wijzigen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier la taille d'une forme</source>
|
||||||
|
<target>Grootte van een vorm wijzigen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier le type d'un nœud</source>
|
||||||
|
<target>Het type van een knooppunt wijzigen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier une image</source>
|
||||||
|
<target>Een afbeelding wijzigen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modèle</source>
|
||||||
|
<target>Model</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Nombre maximum de contacts esclaves définis : non défini
|
||||||
|
</source>
|
||||||
|
<target>Maximumaantal gedefinieerde hulpcontacten: niet gedefinieerd
|
||||||
|
</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Notes</source>
|
||||||
|
<target>Notities</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Nœud le plus proche</source>
|
||||||
|
<target>Dichtstbijzijnde knooppunt</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>pivoter/incliner</source>
|
||||||
|
<target>draaien/kantelen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Ponter des bornes entre-elles</source>
|
||||||
|
<target>Klemmen onderling doorverbinden</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Rayon X</source>
|
||||||
|
<target>Straal X</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Rayon Y</source>
|
||||||
|
<target>Straal Y</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>redimensionner</source>
|
||||||
|
<target>formaat wijzigen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Redimensionner %1</source>
|
||||||
|
<target>%1 vergroten/verkleinen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Redimensionner une image</source>
|
||||||
|
<target>Formaat van een afbeelding wijzigen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Remplacer l'image...</source>
|
||||||
|
<target>Afbeelding vervangen...</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Remplacer une image</source>
|
||||||
|
<target>Een afbeelding vervangen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Restaurer les proportions</source>
|
||||||
|
<target>Verhoudingen herstellen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Restaurer les proportions d'une image</source>
|
||||||
|
<target>De verhoudingen van een afbeelding herstellen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Retirer cette couleur</source>
|
||||||
|
<target>Deze kleur verwijderen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Revenir à l'image complète, sans rognage</source>
|
||||||
|
<target>Terug naar de volledige afbeelding, zonder bijsnijden</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>rgb(%1, %2, %3)</source>
|
||||||
|
<target>rgb(%1, %2, %3)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Rogner l'image</source>
|
||||||
|
<target>Afbeelding bijsnijden</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Rogner une image</source>
|
||||||
|
<target>Een afbeelding bijsnijden</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Rogner...</source>
|
||||||
|
<target>Bijsnijden...</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Rotation/Inclinaison</source>
|
||||||
|
<target>Rotatie/kanteling</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Réinitialiser</source>
|
||||||
|
<target>Herinitialiseren</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Selectionner une image...</source>
|
||||||
|
<target>Een afbeelding selecteren...</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Supprimer le nœud le plus proche</source>
|
||||||
|
<target>Het dichtstbijzijnde knooppunt verwijderen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Supprimer un point d'une courbe</source>
|
||||||
|
<target>Een punt van een curve verwijderen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Symétrique</source>
|
||||||
|
<target>Symmetrisch</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Séparation de potentiel</source>
|
||||||
|
<target>Potentiaalscheiding</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Taille</source>
|
||||||
|
<target>Grootte</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Tension nominale</source>
|
||||||
|
<target>Nominale spanning</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Tolérance pour cette couleur</source>
|
||||||
|
<target>Tolerantie voor deze kleur</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Tous les fichiers (*)</source>
|
||||||
|
<target>Alle bestanden (*)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Transformer %1</source>
|
||||||
|
<target>%1 omvormen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Transparence non conservée</source>
|
||||||
|
<target>Transparantie niet behouden</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>un arc</source>
|
||||||
|
<target>een boog</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>un coin</source>
|
||||||
|
<target>een hoek</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>un point</source>
|
||||||
|
<target>een punt</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>une courbe</source>
|
||||||
|
<target>een curve</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>une extrémité</source>
|
||||||
|
<target>een uiteinde</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>une image</source>
|
||||||
|
<target>een afbeelding</target>
|
||||||
|
<definition>part of a sentence listing the content of a diagram</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Verrouiller la numérotation automatique</source>
|
||||||
|
<target>Automatische nummering vergrendelen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Verrouiller la position</source>
|
||||||
|
<target>Positie vergrendelen</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Verrouillé : modifier la largeur ou la hauteur ajuste l'autre pour conserver les proportions. Cliquer pour déverrouiller.</source>
|
||||||
|
<target>Vergrendeld: het wijzigen van de breedte of hoogte past de andere aan om de verhoudingen te behouden. Klik om te ontgrendelen.</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Échec de l'enregistrement</source>
|
||||||
|
<target>Opslaan mislukt</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Édition des nœuds</source>
|
||||||
|
<target>Knooppunten bewerken</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>armoire</source>
|
||||||
|
<target>kast</target>
|
||||||
|
<definition>cabinet / enclosure</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>bobine</source>
|
||||||
|
<target>spoel</target>
|
||||||
|
<definition>coil</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>borne</source>
|
||||||
|
<target>klem</target>
|
||||||
|
<definition>terminal - a connection point on a symbol</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>bornier</source>
|
||||||
|
<target>klemmenstrook</target>
|
||||||
|
<definition>terminal strip</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>cable</source>
|
||||||
|
<target>kabel</target>
|
||||||
|
<definition>cable</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>calibre</source>
|
||||||
|
<target>kaliber</target>
|
||||||
|
<definition>rating - the current rating of a device</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>cartouche</source>
|
||||||
|
<target>titelblok</target>
|
||||||
|
<definition>title block - the framed information panel</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>collection</source>
|
||||||
|
<target>collectie</target>
|
||||||
|
<definition>collection - the symbol library</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>conducteur</source>
|
||||||
|
<target>geleider</target>
|
||||||
|
<definition>conductor - the drawn wire between terminals</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>contact</source>
|
||||||
|
<target>contact</target>
|
||||||
|
<definition>contact</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>contacteur</source>
|
||||||
|
<target>contacteur</target>
|
||||||
|
<definition>contactor</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>courant</source>
|
||||||
|
<target>stroom</target>
|
||||||
|
<definition>current</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>disjoncteur</source>
|
||||||
|
<target>automaat</target>
|
||||||
|
<definition>circuit breaker</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>dossier</source>
|
||||||
|
<target>map</target>
|
||||||
|
<definition>folder</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>element</source>
|
||||||
|
<target>element</target>
|
||||||
|
<definition>element - a symbol placed on a sheet</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>esclave</source>
|
||||||
|
<target>hulpcontact</target>
|
||||||
|
<definition>slave - the contact block belonging to a master</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>fusible</source>
|
||||||
|
<target>zekering</target>
|
||||||
|
<definition>fuse</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>grille</source>
|
||||||
|
<target>raster</target>
|
||||||
|
<definition>grid</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>interrupteur</source>
|
||||||
|
<target>schakelaar</target>
|
||||||
|
<definition>switch</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>maitre</source>
|
||||||
|
<target>hoofd</target>
|
||||||
|
<definition>master - the element a cross-reference points from</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>modele</source>
|
||||||
|
<target>sjabloon</target>
|
||||||
|
<definition>template</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>moteur</source>
|
||||||
|
<target>motor</target>
|
||||||
|
<definition>motor</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>neutre</source>
|
||||||
|
<target>nul</target>
|
||||||
|
<definition>neutral</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>nomenclature</source>
|
||||||
|
<target>stuklijst</target>
|
||||||
|
<definition>parts list / bill of materials</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>numerotation</source>
|
||||||
|
<target>nummering</target>
|
||||||
|
<definition>numbering - automatic wire and part numbering</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>phase</source>
|
||||||
|
<target>fase</target>
|
||||||
|
<definition>phase</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>potentiel</source>
|
||||||
|
<target>potentiaal</target>
|
||||||
|
<definition>potential - conductors electrically joined as one node</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>projet</source>
|
||||||
|
<target>project</target>
|
||||||
|
<definition>project - the .qet file holding the sheets</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>puissance</source>
|
||||||
|
<target>vermogen</target>
|
||||||
|
<definition>power</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>relais</source>
|
||||||
|
<target>relais</target>
|
||||||
|
<definition>relay</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>renvoi de folio</source>
|
||||||
|
<target>bladverwijzing</target>
|
||||||
|
<definition>sheet cross-reference</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>repere</source>
|
||||||
|
<target>aanduiding</target>
|
||||||
|
<definition>designation - the identifying mark on a part</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>report de folio</source>
|
||||||
|
<target>bladverwijzing</target>
|
||||||
|
<definition>sheet cross-reference (the arrow symbol)</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>schema</source>
|
||||||
|
<target>schema</target>
|
||||||
|
<definition>diagram</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>section</source>
|
||||||
|
<target>doorsnede</target>
|
||||||
|
<definition>cross-section - conductor size in mm2</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>sommaire</source>
|
||||||
|
<target>inhoudstafel</target>
|
||||||
|
<definition>summary / table of contents</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>tension</source>
|
||||||
|
<target>spanning</target>
|
||||||
|
<definition>voltage</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>terre</source>
|
||||||
|
<target>aarde</target>
|
||||||
|
<definition>earth / ground</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>texte</source>
|
||||||
|
<target>tekst</target>
|
||||||
|
<definition>text</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>transformateur</source>
|
||||||
|
<target>transformator</target>
|
||||||
|
<definition>transformer</definition>
|
||||||
|
</phrase>
|
||||||
|
</QPH>
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
<!DOCTYPE QPH>
|
||||||
|
<QPH sourcelanguage="fr_FR" language="pl">
|
||||||
|
<phrase>
|
||||||
|
<source>armoire</source>
|
||||||
|
<target>Szafa</target>
|
||||||
|
<definition>cabinet / enclosure</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>bobine</source>
|
||||||
|
<target>Cewka</target>
|
||||||
|
<definition>coil</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>borne</source>
|
||||||
|
<target>Zacisk</target>
|
||||||
|
<definition>terminal - a connection point on a symbol</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>bornier</source>
|
||||||
|
<target>Listwa zaciskowa</target>
|
||||||
|
<definition>terminal strip</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>cable</source>
|
||||||
|
<target>Kabel</target>
|
||||||
|
<definition>cable</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>calibre</source>
|
||||||
|
<target>Prąd znamionowy</target>
|
||||||
|
<definition>rating - the current rating of a device</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>cartouche</source>
|
||||||
|
<target>Tabliczka rysunkowa</target>
|
||||||
|
<definition>title block - the framed information panel</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>champ de texte</source>
|
||||||
|
<target>Pole tekstowe</target>
|
||||||
|
<definition>text field</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>collection</source>
|
||||||
|
<target>Biblioteka</target>
|
||||||
|
<definition>collection - the symbol library</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>conducteur</source>
|
||||||
|
<target>Przewód</target>
|
||||||
|
<definition>conductor - the drawn wire between terminals</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>contact</source>
|
||||||
|
<target>Styk</target>
|
||||||
|
<definition>contact</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>contacteur</source>
|
||||||
|
<target>Stycznik</target>
|
||||||
|
<definition>contactor</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>courant</source>
|
||||||
|
<target>Prąd</target>
|
||||||
|
<definition>current</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>disjoncteur</source>
|
||||||
|
<target>Wyłącznik nadprądowy</target>
|
||||||
|
<definition>circuit breaker</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>dossier</source>
|
||||||
|
<target>Folder</target>
|
||||||
|
<definition>folder</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>element</source>
|
||||||
|
<target>Element</target>
|
||||||
|
<definition>element - a symbol placed on a sheet</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>esclave</source>
|
||||||
|
<target>Element podrzędny</target>
|
||||||
|
<definition>slave - the contact block belonging to a master</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>fil</source>
|
||||||
|
<target>Przewód</target>
|
||||||
|
<definition>wire</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>folio</source>
|
||||||
|
<target>Arkusz</target>
|
||||||
|
<definition>sheet - one drawing of a set</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>fusible</source>
|
||||||
|
<target>Bezpiecznik</target>
|
||||||
|
<definition>fuse</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>grille</source>
|
||||||
|
<target>Siatka</target>
|
||||||
|
<definition>grid</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>interrupteur</source>
|
||||||
|
<target>Wyłącznik</target>
|
||||||
|
<definition>switch</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>maitre</source>
|
||||||
|
<target>Element główny</target>
|
||||||
|
<definition>master - the element a cross-reference points from</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>modele</source>
|
||||||
|
<target>Szablon</target>
|
||||||
|
<definition>template</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>moteur</source>
|
||||||
|
<target>Silnik</target>
|
||||||
|
<definition>motor</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>neutre</source>
|
||||||
|
<target>Neutralny</target>
|
||||||
|
<definition>neutral</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>nomenclature</source>
|
||||||
|
<target>Zestawienie materiałów</target>
|
||||||
|
<definition>parts list / bill of materials</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>numerotation</source>
|
||||||
|
<target>Numeracja</target>
|
||||||
|
<definition>numbering - automatic wire and part numbering</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>phase</source>
|
||||||
|
<target>Faza</target>
|
||||||
|
<definition>phase</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>potentiel</source>
|
||||||
|
<target>Potencjał</target>
|
||||||
|
<definition>potential - conductors electrically joined as one node</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>projet</source>
|
||||||
|
<target>Projekt</target>
|
||||||
|
<definition>project - the .qet file holding the sheets</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>puissance</source>
|
||||||
|
<target>Moc</target>
|
||||||
|
<definition>power</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>relais</source>
|
||||||
|
<target>Przekaźnik</target>
|
||||||
|
<definition>relay</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>renvoi de folio</source>
|
||||||
|
<target>Odnośnik do arkusza</target>
|
||||||
|
<definition>sheet cross-reference</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>repere</source>
|
||||||
|
<target>Oznaczenie</target>
|
||||||
|
<definition>designation - the identifying mark on a part</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>report de folio</source>
|
||||||
|
<target>Odnośnik do arkusza</target>
|
||||||
|
<definition>sheet cross-reference (the arrow symbol)</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>schema</source>
|
||||||
|
<target>Schemat</target>
|
||||||
|
<definition>diagram</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>section</source>
|
||||||
|
<target>Przekrój</target>
|
||||||
|
<definition>cross-section - conductor size in mm2</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>sommaire</source>
|
||||||
|
<target>Spis treści</target>
|
||||||
|
<definition>summary / table of contents</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>tension</source>
|
||||||
|
<target>Napięcie</target>
|
||||||
|
<definition>voltage</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>terre</source>
|
||||||
|
<target>Uziemienie</target>
|
||||||
|
<definition>earth / ground</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>texte</source>
|
||||||
|
<target>Tekst</target>
|
||||||
|
<definition>text</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>transformateur</source>
|
||||||
|
<target>Transformator</target>
|
||||||
|
<definition>transformer</definition>
|
||||||
|
</phrase>
|
||||||
|
</QPH>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,465 @@
|
|||||||
|
<!DOCTYPE QPH>
|
||||||
|
<QPH sourcelanguage="fr_FR" language="pt_BR">
|
||||||
|
<phrase>
|
||||||
|
<source> Contacts : NO : %1, NC : %2, inverseurs : %3, autres : %4
|
||||||
|
</source>
|
||||||
|
<target>Contatos: NA: %1, NF: %2, reversíveis: %3, outros: %4
|
||||||
|
</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> Contacts : NO : %1/%2, NC : %3/%4, inverseurs : %5/%6, autres : %7/%8
|
||||||
|
</source>
|
||||||
|
<target>Contatos: NA: %1/%2, NF: %3/%4, reversíveis: %5/%6, outros: %7/%8
|
||||||
|
</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Aperçu</source>
|
||||||
|
<target>Pré-visualização</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Arrondir les coins d'%1</source>
|
||||||
|
<target>Arredondar os cantos de %1</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Borne 1</source>
|
||||||
|
<target>Borne 1</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Borne 2</source>
|
||||||
|
<target>Borne 2</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Catégorie</source>
|
||||||
|
<target>Categoria</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Ce format ne prend pas en charge la transparence : l'image sera enregistrée telle qu'elle était avant l'application de la couleur transparente. Continuer ?</source>
|
||||||
|
<target>Este formato não suporta transparência: a imagem será salva como estava antes da aplicação da cor transparente. Continuar?</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Champ de texte</source>
|
||||||
|
<target>Campo de texto</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Composant 1</source>
|
||||||
|
<target>Componente 1</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Composant 2</source>
|
||||||
|
<target>Componente 2</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Convertir %1 en courbe de Bézier</source>
|
||||||
|
<target>Converter %1 em curva de Bézier</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Convertir en courbe de Bézier</source>
|
||||||
|
<target>Converter em curva de Bézier</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Courant nominal</source>
|
||||||
|
<target>Corrente nominal</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Distance in pixels between the label and the slave cross reference</source>
|
||||||
|
<target>Distância em pixels entre o rótulo e a referência cruzada do escravo</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Distance label - slave :</source>
|
||||||
|
<target>Distância do rótulo - escravo:</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Enregistrer l'image d'origine sous...</source>
|
||||||
|
<target>Salvar a imagem original como...</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Enregistrer l'image sous...</source>
|
||||||
|
<target>Salvar a imagem como...</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Erreur</source>
|
||||||
|
<target>Erro</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Exclure de la nomenclature</source>
|
||||||
|
<target>Excluir da lista de materiais</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Faire pivoter %1</source>
|
||||||
|
<target>Girar %1</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Faire pivoter une image</source>
|
||||||
|
<target>Girar uma imagem</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Fil</source>
|
||||||
|
<target>Fio</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Folio</source>
|
||||||
|
<target>Folha</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Hauteur</source>
|
||||||
|
<target>Altura</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Image BMP (*.bmp)</source>
|
||||||
|
<target>Imagem BMP (*.bmp)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Image JPEG (*.jpg *.jpeg)</source>
|
||||||
|
<target>Imagem JPEG (*.jpg *.jpeg)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Image PNG (*.png)</source>
|
||||||
|
<target>Imagem PNG (*.png)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Image SVG (*.svg)</source>
|
||||||
|
<target>Imagem SVG (*.svg)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Images non incluses dans l'export DXF</source>
|
||||||
|
<target>Imagens não incluídas na exportação DXF</target>
|
||||||
|
<definition>message box title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Impossible d'enregistrer l'image à cet emplacement.</source>
|
||||||
|
<target>Não foi possível salvar a imagem neste local.</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Impossible d'enregistrer la nomenclature dans %1.
|
||||||
|
%2</source>
|
||||||
|
<target>Não foi possível salvar a lista de materiais em %1.
|
||||||
|
%2</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Impossible de charger l'image.</source>
|
||||||
|
<target>Não foi possível carregar a imagem.</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Incliner %1</source>
|
||||||
|
<target>Inclinar %1</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Incliner une image</source>
|
||||||
|
<target>Inclinar uma imagem</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>La limite fixée pour cet élément maître est atteinte (Limite: %1).
|
||||||
|
|
||||||
|
Voulez-vous tout de même lier ce contact esclave ?</source>
|
||||||
|
<target>O limite definido para este elemento mestre foi atingido (Limite: %1).
|
||||||
|
|
||||||
|
Deseja vincular este contato escravo mesmo assim?</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Largeur</source>
|
||||||
|
<target>Largura</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Le format DXF utilisé ici (AC1006) ne permet pas d'inclure d'image. Les images seront représentées uniquement par un rectangle de contour (position, taille, rotation et inclinaison conservées), sans le contenu de l'image.</source>
|
||||||
|
<target>O formato DXF usado aqui (AC1006) não permite incluir imagens. As imagens serão representadas apenas por um retângulo de contorno (posição, tamanho, rotação e inclinação preservados), sem o conteúdo da imagem.</target>
|
||||||
|
<definition>message box content</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Liste de câblage</source>
|
||||||
|
<target>Lista de cabeamento</target>
|
||||||
|
<definition>window title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Liste de câblage (base de données)</source>
|
||||||
|
<target>Lista de cabeamento (banco de dados)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>margin: 5px; font-weight: bold;</source>
|
||||||
|
<target>margin: 5px; font-weight: bold;</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier l'angle d'un arc</source>
|
||||||
|
<target>Modificar o ângulo de um arco</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier la courbure d'%1</source>
|
||||||
|
<target>Modificar a curvatura de %1</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier la forme d'%1</source>
|
||||||
|
<target>Modificar a forma de %1</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modèle</source>
|
||||||
|
<target>Modelo</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Nombre maximum de contacts esclaves définis : non défini
|
||||||
|
</source>
|
||||||
|
<target>Número máximo de contatos escravos definidos: não definido
|
||||||
|
</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Notes</source>
|
||||||
|
<target>Observações</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Redimensionner %1</source>
|
||||||
|
<target>Redimensionar %1</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Redimensionner une image</source>
|
||||||
|
<target>Redimensionar uma imagem</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Réinitialiser</source>
|
||||||
|
<target>Redefinir</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Selectionner une image...</source>
|
||||||
|
<target>Selecionar uma imagem...</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Séparation de potentiel</source>
|
||||||
|
<target>Separação de potencial</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Taille</source>
|
||||||
|
<target>Tamanho</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Tension nominale</source>
|
||||||
|
<target>Tensão nominal</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Tous les fichiers (*)</source>
|
||||||
|
<target>Todos os arquivos (*)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Transparence non conservée</source>
|
||||||
|
<target>Transparência não preservada</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>une image</source>
|
||||||
|
<target>uma imagem</target>
|
||||||
|
<definition>part of a sentence listing the content of a diagram</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Verrouiller la numérotation automatique</source>
|
||||||
|
<target>Bloquear a numeração automática</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Verrouiller la position</source>
|
||||||
|
<target>Bloquear a posição</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Échec de l'enregistrement</source>
|
||||||
|
<target>Falha ao salvar</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>armoire</source>
|
||||||
|
<target>armário</target>
|
||||||
|
<definition>cabinet / enclosure</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>bobine</source>
|
||||||
|
<target>bobina</target>
|
||||||
|
<definition>coil</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>borne</source>
|
||||||
|
<target>borne</target>
|
||||||
|
<definition>terminal - a connection point on a symbol</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>bornier</source>
|
||||||
|
<target>borneira</target>
|
||||||
|
<definition>terminal strip</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>cable</source>
|
||||||
|
<target>cabo</target>
|
||||||
|
<definition>cable</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>calibre</source>
|
||||||
|
<target>calibre</target>
|
||||||
|
<definition>rating - the current rating of a device</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>cartouche</source>
|
||||||
|
<target>bloco de título</target>
|
||||||
|
<definition>title block - the framed information panel</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>collection</source>
|
||||||
|
<target>coleção</target>
|
||||||
|
<definition>collection - the symbol library</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>conducteur</source>
|
||||||
|
<target>condutor</target>
|
||||||
|
<definition>conductor - the drawn wire between terminals</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>contact</source>
|
||||||
|
<target>contato</target>
|
||||||
|
<definition>contact</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>contacteur</source>
|
||||||
|
<target>contator</target>
|
||||||
|
<definition>contactor</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>courant</source>
|
||||||
|
<target>corrente</target>
|
||||||
|
<definition>current</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>disjoncteur</source>
|
||||||
|
<target>disjuntor</target>
|
||||||
|
<definition>circuit breaker</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>dossier</source>
|
||||||
|
<target>pasta</target>
|
||||||
|
<definition>folder</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>element</source>
|
||||||
|
<target>elemento</target>
|
||||||
|
<definition>element - a symbol placed on a sheet</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>esclave</source>
|
||||||
|
<target>escravo</target>
|
||||||
|
<definition>slave - the contact block belonging to a master</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>fusible</source>
|
||||||
|
<target>fusível</target>
|
||||||
|
<definition>fuse</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>grille</source>
|
||||||
|
<target>grade</target>
|
||||||
|
<definition>grid</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>interrupteur</source>
|
||||||
|
<target>interruptor</target>
|
||||||
|
<definition>switch</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>maitre</source>
|
||||||
|
<target>mestre</target>
|
||||||
|
<definition>master - the element a cross-reference points from</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>modele</source>
|
||||||
|
<target>modelo</target>
|
||||||
|
<definition>template</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>moteur</source>
|
||||||
|
<target>motor</target>
|
||||||
|
<definition>motor</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>neutre</source>
|
||||||
|
<target>neutro</target>
|
||||||
|
<definition>neutral</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>nomenclature</source>
|
||||||
|
<target>lista de materiais</target>
|
||||||
|
<definition>parts list / bill of materials</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>numerotation</source>
|
||||||
|
<target>numeração</target>
|
||||||
|
<definition>numbering - automatic wire and part numbering</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>phase</source>
|
||||||
|
<target>fase</target>
|
||||||
|
<definition>phase</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>potentiel</source>
|
||||||
|
<target>potencial</target>
|
||||||
|
<definition>potential - conductors electrically joined as one node</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>projet</source>
|
||||||
|
<target>projeto</target>
|
||||||
|
<definition>project - the .qet file holding the sheets</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>puissance</source>
|
||||||
|
<target>potência</target>
|
||||||
|
<definition>power</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>relais</source>
|
||||||
|
<target>relé</target>
|
||||||
|
<definition>relay</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>renvoi de folio</source>
|
||||||
|
<target>referência de folha</target>
|
||||||
|
<definition>sheet cross-reference</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>repere</source>
|
||||||
|
<target>designação</target>
|
||||||
|
<definition>designation - the identifying mark on a part</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>report de folio</source>
|
||||||
|
<target>remissão de folha</target>
|
||||||
|
<definition>sheet cross-reference (the arrow symbol)</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>schema</source>
|
||||||
|
<target>diagrama</target>
|
||||||
|
<definition>diagram</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>section</source>
|
||||||
|
<target>seção</target>
|
||||||
|
<definition>cross-section - conductor size in mm2</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>sommaire</source>
|
||||||
|
<target>sumário</target>
|
||||||
|
<definition>summary / table of contents</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>tension</source>
|
||||||
|
<target>tensão</target>
|
||||||
|
<definition>voltage</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>terre</source>
|
||||||
|
<target>terra</target>
|
||||||
|
<definition>earth / ground</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>texte</source>
|
||||||
|
<target>texto</target>
|
||||||
|
<definition>text</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>transformateur</source>
|
||||||
|
<target>transformador</target>
|
||||||
|
<definition>transformer</definition>
|
||||||
|
</phrase>
|
||||||
|
</QPH>
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,917 @@
|
|||||||
|
<!DOCTYPE QPH>
|
||||||
|
<QPH sourcelanguage="fr_FR" language="zh">
|
||||||
|
<phrase>
|
||||||
|
<source> Contacts : NO : %1, NC : %2, inverseurs : %3, autres : %4
|
||||||
|
</source>
|
||||||
|
<target>触点:常开:%1,常闭:%2,转换:%3,其他:%4
|
||||||
|
</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> Contacts : NO : %1/%2, NC : %3/%4, inverseurs : %5/%6, autres : %7/%8
|
||||||
|
</source>
|
||||||
|
<target>触点:常开:%1/%2,常闭:%3/%4,转换:%5/%6,其他:%7/%8
|
||||||
|
</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> %</source>
|
||||||
|
<target>%</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> (Ctrl pendant le glissement = position libre, sans accrochage à la grille)</source>
|
||||||
|
<target>(拖动时按 Ctrl = 自由位置,不吸附到网格)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> -- %1 : mode %2</source>
|
||||||
|
<target>-- %1:%2 模式</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> ; point rouge : glisser pour repositionner le centre de rotation</source>
|
||||||
|
<target>;红点:拖动以重新定位旋转中心</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> ; point turquoise : arc</source>
|
||||||
|
<target>;青色点:圆弧</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> ; un bord : inclinaison</source>
|
||||||
|
<target>;边:倾斜</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> °</source>
|
||||||
|
<target>°</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source> — Cliquer : mode %1</source>
|
||||||
|
<target>— 单击:%1 模式</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>, Alt = créer des poignées</source>
|
||||||
|
<target>,Alt = 创建控制柄</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>, Alt = détacher en polyligne</source>
|
||||||
|
<target>,Alt = 分离为多段线</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Ajoute une courbe de Bézier sur le folio actuel</source>
|
||||||
|
<target>在当前图纸上添加贝塞尔曲线</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Ajouter un point à une courbe</source>
|
||||||
|
<target>向曲线添加点</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Ajouter une courbe</source>
|
||||||
|
<target>添加曲线</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Angle</source>
|
||||||
|
<target>角度</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Anguleux</source>
|
||||||
|
<target>角点</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Aperçu</source>
|
||||||
|
<target>预览</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Arrondir les coins d'%1</source>
|
||||||
|
<target>将%1的角变圆</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Borne 1</source>
|
||||||
|
<target>端子1</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Borne 2</source>
|
||||||
|
<target>端子2</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Catégorie</source>
|
||||||
|
<target>类别</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Ce format ne prend pas en charge la transparence : l'image sera enregistrée telle qu'elle était avant l'application de la couleur transparente. Continuer ?</source>
|
||||||
|
<target>此格式不支持透明度:图像将按应用透明色之前的状态保存。是否继续?</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Champ de texte</source>
|
||||||
|
<target>文本字段</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic : positionner à la taille d'origine. Cliquer-glisser : positionner et redimensionner. Clic droit : pivoter de 90°. Ctrl+molette : ajuster la taille.</source>
|
||||||
|
<target>单击:按原始尺寸放置。单击拖动:放置并调整大小。右键:旋转 90°。Ctrl+滚轮:调整大小。</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic gauche : point suivant ; double-clic ou Entrée : terminer ; clic droit : annuler le dernier point</source>
|
||||||
|
<target>左键单击:下一个点;双击或 Enter:结束;右键单击:撤销上一个点</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic gauche : positionner le coin opposé (Maj = carré, Ctrl = depuis le centre + position libre, Ctrl+Maj = carré centré) ; clic droit : annuler</source>
|
||||||
|
<target>左键单击:放置对角(Shift = 正方形,Ctrl = 从中心 + 自由位置,Ctrl+Shift = 居中正方形);右键单击:取消</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic gauche : positionner le coin opposé (Maj = cercle, Ctrl = depuis le centre + position libre, Ctrl+Maj = cercle centré) ; clic droit : annuler</source>
|
||||||
|
<target>左键单击:放置对角(Shift = 圆形,Ctrl = 从中心 + 自由位置,Ctrl+Shift = 居中圆形);右键单击:取消</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic gauche : positionner le point de départ (Ctrl = position libre)</source>
|
||||||
|
<target>左键单击:放置起点(Ctrl = 自由位置)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic gauche : positionner le point final (Ctrl = position libre) ; clic droit : annuler</source>
|
||||||
|
<target>左键单击:放置终点(Ctrl = 自由位置);右键单击:取消</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic gauche : positionner le premier coin (Ctrl = point central, position libre)</source>
|
||||||
|
<target>左键单击:放置第一个角(Ctrl = 中心点,自由位置)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic gauche : positionner le premier point (Ctrl = position libre)</source>
|
||||||
|
<target>左键单击:放置第一个点(Ctrl = 自由位置)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Clic: point anguleux. Cliquer-glisser: point courbe. Clic sur le premier point: fermer. Échap/Entrée: terminer. Clic droit: annuler le dernier point.</source>
|
||||||
|
<target>单击:角点。单击拖动:曲线点。单击第一个点:闭合。Esc/Enter:结束。右键:撤销上一个点。</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cliquer</source>
|
||||||
|
<target>单击</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cliquer : mode %1</source>
|
||||||
|
<target>单击:%1 模式</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cliquez pour choisir une couleur</source>
|
||||||
|
<target>点击选择颜色</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cliquez sur l'image pour ajouter une couleur. Ajustez la tolérance de chaque couleur avec son curseur, ou cliquez sur × pour la retirer.</source>
|
||||||
|
<target>单击图像以添加颜色。使用滑块调整每种颜色的容差,或单击 × 将其移除。</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Cliquez sur l'image pour choisir une couleur</source>
|
||||||
|
<target>单击图像选择颜色</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Coins arrondis</source>
|
||||||
|
<target>圆角</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Composant 1</source>
|
||||||
|
<target>元件1</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Composant 2</source>
|
||||||
|
<target>元件2</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Convertir %1 en courbe de Bézier</source>
|
||||||
|
<target>将 %1 转换为贝塞尔曲线</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Convertir %1 en polyligne</source>
|
||||||
|
<target>将 %1 转换为多段线</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Convertir en courbe de Bézier</source>
|
||||||
|
<target>转换为贝塞尔曲线</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Convertir en polyligne</source>
|
||||||
|
<target>转换为多段线</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Couleur transparente</source>
|
||||||
|
<target>透明色</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Couleur transparente...</source>
|
||||||
|
<target>透明色...</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Courant nominal</source>
|
||||||
|
<target>额定电流</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Deplacer le centre de rotation</source>
|
||||||
|
<target>移动旋转中心</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Distance in pixels between the label and the slave cross reference</source>
|
||||||
|
<target>标签与从站交叉引用之间的像素距离</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Distance label - slave :</source>
|
||||||
|
<target>标签距离 - 从站:</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Définir une couleur transparente</source>
|
||||||
|
<target>设置透明色</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Déformer une courbe</source>
|
||||||
|
<target>变形曲线</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Déplacer le centre de rotation d'une image</source>
|
||||||
|
<target>移动图像的旋转中心</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Déverrouillé : largeur et hauteur peuvent être modifiées indépendamment. Cliquer pour verrouiller.</source>
|
||||||
|
<target>已解锁:宽度和高度可独立修改。单击锁定。</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Enregistrer l'image d'origine sous...</source>
|
||||||
|
<target>原始图像另存为...</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Enregistrer l'image sous...</source>
|
||||||
|
<target>图像另存为...</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Erreur</source>
|
||||||
|
<target>错误</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Exclure de la nomenclature</source>
|
||||||
|
<target>从物料清单中排除</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Faire pivoter %1</source>
|
||||||
|
<target>旋转 %1</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Faire pivoter une image</source>
|
||||||
|
<target>旋转图像</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Faites glisser les poignées, ou l'intérieur du cadre, pour ajuster la zone à conserver.</source>
|
||||||
|
<target>拖动控制柄或框内区域,调整要保留的区域。</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Fil</source>
|
||||||
|
<target>导线</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Folio</source>
|
||||||
|
<target>图页</target>
|
||||||
|
<definition>column title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Forme fermée</source>
|
||||||
|
<target>闭合形状</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser %1 : rotation (Maj = 15°)</source>
|
||||||
|
<target>拖动 %1:旋转(Shift = 15°)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : ajuster l'arc (Ctrl = position libre, Maj = 15°)</source>
|
||||||
|
<target>拖动:调整圆弧(Ctrl = 自由位置,Shift = 15°)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : arrondir les coins (Ctrl = position libre)</source>
|
||||||
|
<target>拖动:圆角(Ctrl = 自由位置)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : déformer la courbe (Ctrl = position libre, Alt = briser la tangente)</source>
|
||||||
|
<target>拖动:变形曲线(Ctrl = 自由位置,Alt = 断开切线)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : déplacer ce point</source>
|
||||||
|
<target>拖动:移动此点</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : déplacer le centre de rotation</source>
|
||||||
|
<target>拖动:移动旋转中心</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : déplacer le point (Ctrl = position libre</source>
|
||||||
|
<target>拖动:移动点(Ctrl = 自由位置</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : inclinaison (Ctrl = position libre, Maj = 15°)</source>
|
||||||
|
<target>拖动:倾斜(Ctrl = 自由位置,Shift = 15°)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : incliner (Maj = par pas de 15°)</source>
|
||||||
|
<target>拖动:倾斜(Shift = 以 15° 为步长)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : pivoter (Maj = par pas de 15°)</source>
|
||||||
|
<target>拖动:旋转(Shift = 以 15° 为步长)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : redimensionner (Ctrl = depuis le centre + position libre, Maj = proportions</source>
|
||||||
|
<target>拖动:调整大小(Ctrl = 从中心 + 自由位置,Shift = 比例</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : redimensionner (Maj = conserver les proportions, Ctrl = depuis le centre)</source>
|
||||||
|
<target>拖动:调整大小(Shift = 保持比例,Ctrl = 从中心)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : repositionner le centre de rotation (Ctrl = position libre)</source>
|
||||||
|
<target>拖动:重新定位旋转中心(Ctrl = 自由位置)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser : rotation (Ctrl = position libre, Maj = 15°)</source>
|
||||||
|
<target>拖动:旋转(Ctrl = 自由位置,Shift = 15°)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser le point violet : arrondir les coins</source>
|
||||||
|
<target>拖动紫色点:圆角</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser un coin : pivoter (Maj = par pas de 15°) ; glisser un bord : incliner (Maj = par pas de 15°) ; point rouge : déplacer le centre de rotation</source>
|
||||||
|
<target>拖动角:旋转(Shift = 以 15° 为步长);拖动边:倾斜(Shift = 以 15° 为步长);红点:移动旋转中心</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser un coin/bord : redimensionner (Ctrl = depuis le centre, Maj = conserver les proportions)</source>
|
||||||
|
<target>拖动角/边:调整大小(Ctrl = 从中心,Shift = 保持比例)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser un coin/bord : redimensionner (Ctrl = depuis le centre, Maj = proportions, Alt = détacher en polyligne)</source>
|
||||||
|
<target>拖动角/边:调整大小(Ctrl = 从中心,Shift = 比例,Alt = 分离为多段线)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser un point : le déplacer</source>
|
||||||
|
<target>拖动点:移动它</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser une extrémité : la déplacer</source>
|
||||||
|
<target>拖动端点:移动它</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Glisser une poignée ou la courbe : déformer (Alt = briser la tangente) ; Alt+glisser un point anguleux : créer des poignées ; clic droit : menu du nœud le plus proche</source>
|
||||||
|
<target>拖动控制柄或曲线:变形(Alt = 断开切线);Alt+拖动角点:创建控制柄;右键单击:最近节点菜单</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Géométrie</source>
|
||||||
|
<target>几何</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Hauteur</source>
|
||||||
|
<target>高度</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Image BMP (*.bmp)</source>
|
||||||
|
<target>BMP 图像 (*.bmp)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Image Files (*.png *.jpg *.jpeg *.bmp *.svg)</source>
|
||||||
|
<target>图像文件 (*.png *.jpg *.jpeg *.bmp *.svg)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Image JPEG (*.jpg *.jpeg)</source>
|
||||||
|
<target>JPEG 图像 (*.jpg *.jpeg)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Image PNG (*.png)</source>
|
||||||
|
<target>PNG 图像 (*.png)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Image source</source>
|
||||||
|
<target>源图像</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Image SVG (*.svg)</source>
|
||||||
|
<target>SVG 图像 (*.svg)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Images non incluses dans l'export DXF</source>
|
||||||
|
<target>图像未包含在 DXF 导出中</target>
|
||||||
|
<definition>message box title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Impossible d'enregistrer l'image à cet emplacement.</source>
|
||||||
|
<target>无法将图像保存到该位置。</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Impossible d'enregistrer la nomenclature dans %1.
|
||||||
|
%2</source>
|
||||||
|
<target>无法将物料清单保存到 %1。
|
||||||
|
%2</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Impossible de charger l'image.</source>
|
||||||
|
<target>无法加载图像。</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Inclinaison X</source>
|
||||||
|
<target>X 倾斜</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Inclinaison Y</source>
|
||||||
|
<target>Y 倾斜</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Incliner %1</source>
|
||||||
|
<target>倾斜 %1</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Incliner une image</source>
|
||||||
|
<target>倾斜图像</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>La limite fixée pour cet élément maître est atteinte (Limite: %1).
|
||||||
|
|
||||||
|
Voulez-vous tout de même lier ce contact esclave ?</source>
|
||||||
|
<target>已达到此主元件的限制(限制:%1)。
|
||||||
|
|
||||||
|
是否仍要链接此从属触点?</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Largeur</source>
|
||||||
|
<target>宽度</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Le format DXF utilisé ici (AC1006) ne permet pas d'inclure d'image. Les images seront représentées uniquement par un rectangle de contour (position, taille, rotation et inclinaison conservées), sans le contenu de l'image.</source>
|
||||||
|
<target>此处使用的 DXF 格式 (AC1006) 无法包含图像。图像将仅以轮廓矩形表示(保留位置、大小、旋转和倾斜),不包含图像内容。</target>
|
||||||
|
<definition>message box content</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Lisse</source>
|
||||||
|
<target>平滑</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Liste de câblage</source>
|
||||||
|
<target>接线列表</target>
|
||||||
|
<definition>window title</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Liste de câblage (base de données)</source>
|
||||||
|
<target>接线列表(数据库)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Longueur</source>
|
||||||
|
<target>长度</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>margin: 5px; font-weight: bold;</source>
|
||||||
|
<target>margin: 5px; font-weight: bold;</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Miroir horizontal</source>
|
||||||
|
<target>水平镜像</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Miroir horizontal d'une image</source>
|
||||||
|
<target>图像水平镜像</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Miroir horizontal de %1</source>
|
||||||
|
<target>%1 的水平镜像</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Miroir impossible : inclinaison trop extrême pour cette forme</source>
|
||||||
|
<target>无法镜像:此形状的倾斜过于极端</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Miroir vertical</source>
|
||||||
|
<target>垂直镜像</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Miroir vertical d'une image</source>
|
||||||
|
<target>图像垂直镜像</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Miroir vertical de %1</source>
|
||||||
|
<target>%1 的垂直镜像</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier l'angle d'un arc</source>
|
||||||
|
<target>修改弧的角度</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier l'angle d'une forme</source>
|
||||||
|
<target>修改形状角度</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier l'angle d'une image</source>
|
||||||
|
<target>修改图像角度</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier l'inclinaison d'une image</source>
|
||||||
|
<target>修改图像倾斜</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier la courbure d'%1</source>
|
||||||
|
<target>修改%1的曲率</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier la forme d'%1</source>
|
||||||
|
<target>修改%1的形状</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier la hauteur d'une image</source>
|
||||||
|
<target>修改图像高度</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier la largeur d'une image</source>
|
||||||
|
<target>修改图像宽度</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier la longueur d'une ligne</source>
|
||||||
|
<target>修改线条长度</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier la taille d'une forme</source>
|
||||||
|
<target>修改形状大小</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier le type d'un nœud</source>
|
||||||
|
<target>修改节点类型</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modifier une image</source>
|
||||||
|
<target>修改图像</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Modèle</source>
|
||||||
|
<target>型号</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Nombre maximum de contacts esclaves définis : non défini
|
||||||
|
</source>
|
||||||
|
<target>已定义的从属触点最大数量:未定义
|
||||||
|
</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Notes</source>
|
||||||
|
<target>备注</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Nœud le plus proche</source>
|
||||||
|
<target>最近节点</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>pivoter/incliner</source>
|
||||||
|
<target>旋转/倾斜</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Rayon X</source>
|
||||||
|
<target>X半径</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Rayon Y</source>
|
||||||
|
<target>Y半径</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>redimensionner</source>
|
||||||
|
<target>调整大小</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Redimensionner %1</source>
|
||||||
|
<target>调整 %1 大小</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Redimensionner une image</source>
|
||||||
|
<target>调整图像大小</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Remplacer l'image...</source>
|
||||||
|
<target>替换图像...</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Remplacer une image</source>
|
||||||
|
<target>替换图像</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Restaurer les proportions</source>
|
||||||
|
<target>恢复比例</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Restaurer les proportions d'une image</source>
|
||||||
|
<target>恢复图像比例</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Retirer cette couleur</source>
|
||||||
|
<target>移除此颜色</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Revenir à l'image complète, sans rognage</source>
|
||||||
|
<target>恢复为完整图像,不裁剪</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>rgb(%1, %2, %3)</source>
|
||||||
|
<target>rgb(%1, %2, %3)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Rogner l'image</source>
|
||||||
|
<target>裁剪图像</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Rogner une image</source>
|
||||||
|
<target>裁剪图像</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Rogner...</source>
|
||||||
|
<target>裁剪...</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Rotation/Inclinaison</source>
|
||||||
|
<target>旋转/倾斜</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Réinitialiser</source>
|
||||||
|
<target>重置</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Selectionner une image...</source>
|
||||||
|
<target>选择图像...</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Supprimer le nœud le plus proche</source>
|
||||||
|
<target>删除最近节点</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Supprimer un point d'une courbe</source>
|
||||||
|
<target>从曲线删除点</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Symétrique</source>
|
||||||
|
<target>对称</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Séparation de potentiel</source>
|
||||||
|
<target>电位分隔</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Taille</source>
|
||||||
|
<target>大小</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Tension nominale</source>
|
||||||
|
<target>额定电压</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Tolérance pour cette couleur</source>
|
||||||
|
<target>此颜色的容差</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Tous les fichiers (*)</source>
|
||||||
|
<target>所有文件 (*)</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Transformer %1</source>
|
||||||
|
<target>变换 %1</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Transparence non conservée</source>
|
||||||
|
<target>不保留透明度</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>un arc</source>
|
||||||
|
<target>一段弧</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>un coin</source>
|
||||||
|
<target>一个角</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>un point</source>
|
||||||
|
<target>一个点</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>une courbe</source>
|
||||||
|
<target>一条曲线</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>une extrémité</source>
|
||||||
|
<target>一个端点</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>une image</source>
|
||||||
|
<target>一张图像</target>
|
||||||
|
<definition>part of a sentence listing the content of a diagram</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Verrouiller la numérotation automatique</source>
|
||||||
|
<target>锁定自动编号</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Verrouiller la position</source>
|
||||||
|
<target>锁定位置</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Verrouillé : modifier la largeur ou la hauteur ajuste l'autre pour conserver les proportions. Cliquer pour déverrouiller.</source>
|
||||||
|
<target>已锁定:修改宽度或高度会调整另一个以保持比例。单击解锁。</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Échec de l'enregistrement</source>
|
||||||
|
<target>保存失败</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>Édition des nœuds</source>
|
||||||
|
<target>节点编辑</target>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>armoire</source>
|
||||||
|
<target>机柜</target>
|
||||||
|
<definition>cabinet / enclosure</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>bobine</source>
|
||||||
|
<target>线圈</target>
|
||||||
|
<definition>coil</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>borne</source>
|
||||||
|
<target>端子</target>
|
||||||
|
<definition>terminal - a connection point on a symbol</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>bornier</source>
|
||||||
|
<target>端子排</target>
|
||||||
|
<definition>terminal strip</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>cable</source>
|
||||||
|
<target>电缆</target>
|
||||||
|
<definition>cable</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>calibre</source>
|
||||||
|
<target>额定值</target>
|
||||||
|
<definition>rating - the current rating of a device</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>cartouche</source>
|
||||||
|
<target>标题栏</target>
|
||||||
|
<definition>title block - the framed information panel</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>collection</source>
|
||||||
|
<target>符号库</target>
|
||||||
|
<definition>collection - the symbol library</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>conducteur</source>
|
||||||
|
<target>导线</target>
|
||||||
|
<definition>conductor - the drawn wire between terminals</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>contact</source>
|
||||||
|
<target>触点</target>
|
||||||
|
<definition>contact</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>contacteur</source>
|
||||||
|
<target>接触器</target>
|
||||||
|
<definition>contactor</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>courant</source>
|
||||||
|
<target>电流</target>
|
||||||
|
<definition>current</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>disjoncteur</source>
|
||||||
|
<target>断路器</target>
|
||||||
|
<definition>circuit breaker</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>dossier</source>
|
||||||
|
<target>文件夹</target>
|
||||||
|
<definition>folder</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>element</source>
|
||||||
|
<target>元件</target>
|
||||||
|
<definition>element - a symbol placed on a sheet</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>esclave</source>
|
||||||
|
<target>从</target>
|
||||||
|
<definition>slave - the contact block belonging to a master</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>fusible</source>
|
||||||
|
<target>熔断器</target>
|
||||||
|
<definition>fuse</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>grille</source>
|
||||||
|
<target>网格</target>
|
||||||
|
<definition>grid</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>interrupteur</source>
|
||||||
|
<target>开关</target>
|
||||||
|
<definition>switch</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>maitre</source>
|
||||||
|
<target>主</target>
|
||||||
|
<definition>master - the element a cross-reference points from</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>modele</source>
|
||||||
|
<target>模板</target>
|
||||||
|
<definition>template</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>moteur</source>
|
||||||
|
<target>电动机</target>
|
||||||
|
<definition>motor</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>neutre</source>
|
||||||
|
<target>中性线</target>
|
||||||
|
<definition>neutral</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>nomenclature</source>
|
||||||
|
<target>物料清单</target>
|
||||||
|
<definition>parts list / bill of materials</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>numerotation</source>
|
||||||
|
<target>编号</target>
|
||||||
|
<definition>numbering - automatic wire and part numbering</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>phase</source>
|
||||||
|
<target>相</target>
|
||||||
|
<definition>phase</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>potentiel</source>
|
||||||
|
<target>电位</target>
|
||||||
|
<definition>potential - conductors electrically joined as one node</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>projet</source>
|
||||||
|
<target>项目</target>
|
||||||
|
<definition>project - the .qet file holding the sheets</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>puissance</source>
|
||||||
|
<target>功率</target>
|
||||||
|
<definition>power</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>relais</source>
|
||||||
|
<target>继电器</target>
|
||||||
|
<definition>relay</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>renvoi de folio</source>
|
||||||
|
<target>图纸交叉引用</target>
|
||||||
|
<definition>sheet cross-reference</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>repere</source>
|
||||||
|
<target>标识</target>
|
||||||
|
<definition>designation - the identifying mark on a part</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>report de folio</source>
|
||||||
|
<target>图纸交叉引用</target>
|
||||||
|
<definition>sheet cross-reference (the arrow symbol)</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>schema</source>
|
||||||
|
<target>原理图</target>
|
||||||
|
<definition>diagram</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>section</source>
|
||||||
|
<target>截面积</target>
|
||||||
|
<definition>cross-section - conductor size in mm2</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>sommaire</source>
|
||||||
|
<target>目录</target>
|
||||||
|
<definition>summary / table of contents</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>tension</source>
|
||||||
|
<target>电压</target>
|
||||||
|
<definition>voltage</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>terre</source>
|
||||||
|
<target>接地</target>
|
||||||
|
<definition>earth / ground</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>texte</source>
|
||||||
|
<target>文本</target>
|
||||||
|
<definition>text</definition>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
<source>transformateur</source>
|
||||||
|
<target>变压器</target>
|
||||||
|
<definition>transformer</definition>
|
||||||
|
</phrase>
|
||||||
|
</QPH>
|
||||||
+1
-1
@@ -62,6 +62,6 @@
|
|||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
<string>NSApplication</string>
|
<string>NSApplication</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>12.3.0</string>
|
<string>14.0.0</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -99,11 +99,14 @@ fi
|
|||||||
|
|
||||||
cmake -S . -B "$BUILD_DIR" -G Ninja \
|
cmake -S . -B "$BUILD_DIR" -G Ninja \
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \
|
||||||
-DQT_VERSION_MAJOR=$QT_MAJOR \
|
-DQT_VERSION_MAJOR=$QT_MAJOR \
|
||||||
-DBUILD_WITH_KF=$BUILD_WITH_KF \
|
-DBUILD_WITH_KF=$BUILD_WITH_KF \
|
||||||
-DBUILD_KF=OFF \
|
-DBUILD_KF=OFF \
|
||||||
-DQET_EXPORT_PROJECT_DB=ON \
|
-DQET_EXPORT_PROJECT_DB=ON \
|
||||||
-DPACKAGE_TESTS=OFF
|
-DPACKAGE_TESTS=OFF \
|
||||||
|
-DQET_ENABLE_SPACEMOUSE=ON \
|
||||||
|
-DQET_SPACEMOUSE_BACKEND=hid
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "ERROR: cmake configure failed."
|
echo "ERROR: cmake configure failed."
|
||||||
@@ -256,6 +259,7 @@ echo "Install Info.plist and app icon:"
|
|||||||
cp -R ${current_dir}/misc/Info.plist $BUNDLE/Contents/
|
cp -R ${current_dir}/misc/Info.plist $BUNDLE/Contents/
|
||||||
cp -R ${current_dir}/ico/mac_icon/*.icns $BUNDLE/Contents/Resources/
|
cp -R ${current_dir}/ico/mac_icon/*.icns $BUNDLE/Contents/Resources/
|
||||||
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION r$HEAD" "$BUNDLE/Contents/Info.plist"
|
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION r$HEAD" "$BUNDLE/Contents/Info.plist"
|
||||||
|
/usr/libexec/PlistBuddy -c "Set :LSMinimumSystemVersion 14.0.0" "$BUNDLE/Contents/Info.plist"
|
||||||
|
|
||||||
### add missing files ###############################################
|
### add missing files ###############################################
|
||||||
echo
|
echo
|
||||||
@@ -396,10 +400,12 @@ done
|
|||||||
|
|
||||||
echo "-- Signing main executable..."
|
echo "-- Signing main executable..."
|
||||||
codesign --force --sign "$IDENTITY" --timestamp --options=runtime \
|
codesign --force --sign "$IDENTITY" --timestamp --options=runtime \
|
||||||
|
--entitlements "${current_dir}/misc/qelectrotech.entitlements" \
|
||||||
"$BUNDLE/Contents/MacOS/$APPNAME"
|
"$BUNDLE/Contents/MacOS/$APPNAME"
|
||||||
|
|
||||||
echo "-- Signing bundle..."
|
echo "-- Signing bundle..."
|
||||||
codesign --force --sign "$IDENTITY" --timestamp --options=runtime "$BUNDLE"
|
codesign --force --sign "$IDENTITY" --timestamp --options=runtime \
|
||||||
|
--entitlements "${current_dir}/misc/qelectrotech.entitlements" "$BUNDLE"
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Verifying bundle signature..."
|
echo "Verifying bundle signature..."
|
||||||
@@ -500,8 +506,10 @@ find "$MOUNT_POINT/$BUNDLE/Contents/PlugIns" \( -name "*.dylib" -o -name "*.so"
|
|||||||
codesign --force --sign "$IDENTITY" --timestamp --options=runtime "$lib"
|
codesign --force --sign "$IDENTITY" --timestamp --options=runtime "$lib"
|
||||||
done
|
done
|
||||||
codesign --force --sign "$IDENTITY" --timestamp --options=runtime \
|
codesign --force --sign "$IDENTITY" --timestamp --options=runtime \
|
||||||
|
--entitlements "${current_dir}/misc/qelectrotech.entitlements" \
|
||||||
"$MOUNT_POINT/$BUNDLE/Contents/MacOS/$APPNAME"
|
"$MOUNT_POINT/$BUNDLE/Contents/MacOS/$APPNAME"
|
||||||
codesign --force --sign "$IDENTITY" --timestamp --options=runtime \
|
codesign --force --sign "$IDENTITY" --timestamp --options=runtime \
|
||||||
|
--entitlements "${current_dir}/misc/qelectrotech.entitlements" \
|
||||||
"$MOUNT_POINT/$BUNDLE"
|
"$MOUNT_POINT/$BUNDLE"
|
||||||
|
|
||||||
echo "Verifying bundle signature inside DMG..."
|
echo "Verifying bundle signature inside DMG..."
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<!-- 3D mouse with 3DxWare installed: lets QElectroTech load
|
||||||
|
3Dconnexion's client library, which 3Dconnexion signs, at run time
|
||||||
|
(sources/spacemouse/connexionbackend.h). The hardened runtime
|
||||||
|
refuses it otherwise, and the 3D mouse does nothing. -->
|
||||||
|
<key>com.apple.security.cs.disable-library-validation</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
Executable
+659
@@ -0,0 +1,659 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Copyright 2006-2026 The QElectroTech Team
|
||||||
|
# This file is part of QElectroTech.
|
||||||
|
#
|
||||||
|
# QElectroTech 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.
|
||||||
|
#
|
||||||
|
# QElectroTech is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
r"""Record raw USB reports from a 3Dconnexion 3D mouse, for QElectroTech.
|
||||||
|
|
||||||
|
QElectroTech's Windows/macOS 3D mouse support reads the device directly
|
||||||
|
over USB, so it has to decode each device model's raw reports itself.
|
||||||
|
This records what your device sends while you make a few guided
|
||||||
|
movements, and saves it to one file you can attach to discussion #599.
|
||||||
|
Nothing is sent anywhere. One recording per device model is enough, from
|
||||||
|
any of the three systems: the device sends the same reports on all of them.
|
||||||
|
|
||||||
|
It takes about two minutes. Each step says what to do: press Enter, make
|
||||||
|
the movement and hold it until the next prompt. Push firmly.
|
||||||
|
|
||||||
|
Linux
|
||||||
|
Python 3 is already installed.
|
||||||
|
1. Download: curl -LO https://raw.githubusercontent.com/qelectrotech/qelectrotech-source-mirror/master/misc/spacemouse-capture.py
|
||||||
|
2. List: sudo python3 spacemouse-capture.py --list
|
||||||
|
3. Record: sudo python3 spacemouse-capture.py --seconds 3
|
||||||
|
If --list shows several devices (a Logitech receiver shows up as
|
||||||
|
several), add --device /dev/hidrawN with the 3D mouse's line.
|
||||||
|
sudo is needed because /dev/hidraw* is readable by root only.
|
||||||
|
spacenavd can keep running; if the recording comes out empty, stop it
|
||||||
|
(sudo systemctl stop spacenavd) and try again.
|
||||||
|
|
||||||
|
macOS
|
||||||
|
Python 3 comes with the Xcode command line tools; if "python3" asks
|
||||||
|
to install them, accept. Open Terminal, then:
|
||||||
|
1. Download: curl -LO https://raw.githubusercontent.com/qelectrotech/qelectrotech-source-mirror/master/misc/spacemouse-capture.py
|
||||||
|
2. Record: python3 spacemouse-capture.py --seconds 3
|
||||||
|
No sudo. If it says another program holds the device, quit 3DxWare
|
||||||
|
(or uninstall it) and try again. If it says macOS refused access,
|
||||||
|
allow Terminal in System Settings > Privacy & Security > Input
|
||||||
|
Monitoring, and try again. (Rather not use Terminal? The SpaceMouse
|
||||||
|
Check app does the same with a window: see discussion #599.)
|
||||||
|
|
||||||
|
Windows
|
||||||
|
Install Python 3 from https://www.python.org/downloads/ (tick "Add
|
||||||
|
python.exe to PATH") or from the Microsoft Store. Open a Command
|
||||||
|
Prompt (Windows key, type cmd, Enter), then:
|
||||||
|
1. cd %USERPROFILE%\Downloads
|
||||||
|
2. Download: curl -LO https://raw.githubusercontent.com/qelectrotech/qelectrotech-source-mirror/master/misc/spacemouse-capture.py
|
||||||
|
3. Record: python spacemouse-capture.py --seconds 3
|
||||||
|
No administrator rights needed, and 3DxWare can keep running.
|
||||||
|
Windows does not give out the device's report descriptor, so a
|
||||||
|
recording made on Linux or macOS is a little more complete.
|
||||||
|
|
||||||
|
Every system
|
||||||
|
--list only show the 3D mice found
|
||||||
|
--device PATH pick one, if several are found (a path from --list)
|
||||||
|
--seconds N multiply the time per step (3 triples it)
|
||||||
|
-o FILE where to save (default: spacemouse-capture-<id>.json)
|
||||||
|
|
||||||
|
The file is saved in the current folder: attach it to discussion #599.
|
||||||
|
Only Python's standard library is used.
|
||||||
|
"""
|
||||||
|
import argparse
|
||||||
|
import datetime
|
||||||
|
import glob
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import select
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
VENDORS = {0x046D: 'Logitech (older 3Dconnexion)', 0x256F: '3Dconnexion'}
|
||||||
|
|
||||||
|
STEPS = [
|
||||||
|
('rest', 'Do not touch the device.', 3),
|
||||||
|
('right', 'Push the cap to the RIGHT and hold it, then let go.', 4),
|
||||||
|
('left', 'Push the cap to the LEFT and hold it, then let go.', 4),
|
||||||
|
('away', 'Push the cap AWAY from you and hold it, then let go.', 4),
|
||||||
|
('toward', 'Pull the cap TOWARDS you and hold it, then let go.', 4),
|
||||||
|
('down', 'Press the cap DOWN and hold it, then let go.', 4),
|
||||||
|
('up', 'Lift the cap UP and hold it, then let go.', 4),
|
||||||
|
('twist_cw', 'TWIST the cap CLOCKWISE (seen from above) and hold, then let go.', 4),
|
||||||
|
('twist_ccw', 'TWIST the cap ANTICLOCKWISE and hold, then let go.', 4),
|
||||||
|
('tilt_away', 'TILT the cap AWAY from you and hold, then let go.', 4),
|
||||||
|
('tilt_right', 'TILT the cap to the RIGHT and hold, then let go.', 4),
|
||||||
|
('buttons', 'Press each button once, slowly, one at a time, in any order.', 15),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Processes that may also be reading the device.
|
||||||
|
OTHER_READERS = ('3dconnexion', '3dx', 'spacenavd') # 3DxWare: 3DconnexionHelper, 3DxNLServer...
|
||||||
|
|
||||||
|
|
||||||
|
def other_readers():
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
try:
|
||||||
|
out = subprocess.run(['tasklist', '/fo', 'csv', '/nh'], capture_output=True,
|
||||||
|
text=True, timeout=10).stdout
|
||||||
|
except (OSError, subprocess.SubprocessError):
|
||||||
|
return ['unknown']
|
||||||
|
names = {line.split('","')[0].strip('"') for line in out.splitlines() if line}
|
||||||
|
return sorted(n for n in names if any(r in n.lower() for r in OTHER_READERS))
|
||||||
|
try:
|
||||||
|
out = subprocess.run(['ps', '-A', '-o', 'comm='], capture_output=True,
|
||||||
|
text=True, timeout=5).stdout
|
||||||
|
except (OSError, subprocess.SubprocessError):
|
||||||
|
return ['unknown']
|
||||||
|
names = {os.path.basename(line.strip()) for line in out.splitlines()}
|
||||||
|
return sorted(n for n in names if any(r in n.lower() for r in OTHER_READERS))
|
||||||
|
|
||||||
|
|
||||||
|
# --- Linux: /dev/hidraw ----------------------------------------------------
|
||||||
|
|
||||||
|
class HidrawDevice:
|
||||||
|
backend = 'hidraw'
|
||||||
|
|
||||||
|
def __init__(self, path, name='?', vendor='?', product='?', sysfs=None):
|
||||||
|
self.path, self.name, self.vendor, self.product = path, name, vendor, product
|
||||||
|
self.sysfs = sysfs
|
||||||
|
self.fd = None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def find():
|
||||||
|
found = []
|
||||||
|
for sysdir in sorted(glob.glob('/sys/class/hidraw/hidraw*')):
|
||||||
|
try:
|
||||||
|
with open(os.path.join(sysdir, 'device', 'uevent')) as f:
|
||||||
|
uevent = dict(line.strip().split('=', 1) for line in f if '=' in line)
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
|
# HID_ID=0003:0000256F:0000C635 (bus:vendor:product)
|
||||||
|
try:
|
||||||
|
_bus, vendor, product = (int(x, 16) for x in uevent.get('HID_ID', '').split(':'))
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
if vendor not in VENDORS:
|
||||||
|
continue
|
||||||
|
found.append(HidrawDevice('/dev/' + os.path.basename(sysdir),
|
||||||
|
uevent.get('HID_NAME', '?'),
|
||||||
|
'%04x' % vendor, '%04x' % product, sysdir))
|
||||||
|
return found
|
||||||
|
|
||||||
|
def descriptor(self):
|
||||||
|
if not self.sysfs:
|
||||||
|
return 'unknown'
|
||||||
|
try:
|
||||||
|
with open(os.path.join(self.sysfs, 'device', 'report_descriptor'), 'rb') as f:
|
||||||
|
return f.read().hex()
|
||||||
|
except OSError as e:
|
||||||
|
return 'unreadable: %s' % e
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
try:
|
||||||
|
self.fd = os.open(self.path, os.O_RDONLY | os.O_NONBLOCK)
|
||||||
|
except PermissionError:
|
||||||
|
sys.exit('Permission denied on %s -- run with sudo.' % self.path)
|
||||||
|
|
||||||
|
def record(self, seconds):
|
||||||
|
"""Read every report arriving within `seconds`; return [[ms, hex], ...]."""
|
||||||
|
reports = []
|
||||||
|
start = time.monotonic()
|
||||||
|
while True:
|
||||||
|
left = seconds - (time.monotonic() - start)
|
||||||
|
if left <= 0:
|
||||||
|
return reports
|
||||||
|
ready, _, _ = select.select([self.fd], [], [], left)
|
||||||
|
if not ready:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
data = os.read(self.fd, 64)
|
||||||
|
except BlockingIOError:
|
||||||
|
continue
|
||||||
|
if not data: # only a test FIFO with no writer does this
|
||||||
|
time.sleep(0.01)
|
||||||
|
continue
|
||||||
|
reports.append([round((time.monotonic() - start) * 1000, 1), data.hex()])
|
||||||
|
|
||||||
|
def drain(self):
|
||||||
|
"""Drop reports queued while waiting for Enter."""
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
if not os.read(self.fd, 64):
|
||||||
|
return
|
||||||
|
except BlockingIOError:
|
||||||
|
return
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
os.close(self.fd)
|
||||||
|
|
||||||
|
def empty_hint(self):
|
||||||
|
return 'Try stopping spacenavd first: sudo systemctl stop spacenavd'
|
||||||
|
|
||||||
|
|
||||||
|
# --- macOS: IOKit, the same calls hidapi's mac backend makes ----------------
|
||||||
|
|
||||||
|
class MacHid:
|
||||||
|
"""ctypes bindings to the few CoreFoundation/IOKit calls needed."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
import ctypes as c
|
||||||
|
self.c = c
|
||||||
|
cf = c.CDLL('/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation')
|
||||||
|
io = c.CDLL('/System/Library/Frameworks/IOKit.framework/IOKit')
|
||||||
|
vp, i32, u32, idx = c.c_void_p, c.c_int32, c.c_uint32, c.c_long
|
||||||
|
|
||||||
|
def fn(lib, name, res, *args):
|
||||||
|
f = getattr(lib, name)
|
||||||
|
f.restype, f.argtypes = res, list(args)
|
||||||
|
return f
|
||||||
|
|
||||||
|
self.CFStringCreateWithCString = fn(cf, 'CFStringCreateWithCString', vp, vp, c.c_char_p, u32)
|
||||||
|
self.CFStringGetCString = fn(cf, 'CFStringGetCString', c.c_bool, vp, c.c_char_p, idx, u32)
|
||||||
|
self.CFGetTypeID = fn(cf, 'CFGetTypeID', c.c_ulong, vp)
|
||||||
|
self.CFNumberGetTypeID = fn(cf, 'CFNumberGetTypeID', c.c_ulong)
|
||||||
|
self.CFStringGetTypeID = fn(cf, 'CFStringGetTypeID', c.c_ulong)
|
||||||
|
self.CFDataGetTypeID = fn(cf, 'CFDataGetTypeID', c.c_ulong)
|
||||||
|
self.CFNumberGetValue = fn(cf, 'CFNumberGetValue', c.c_bool, vp, idx, vp)
|
||||||
|
self.CFDataGetLength = fn(cf, 'CFDataGetLength', idx, vp)
|
||||||
|
self.CFDataGetBytePtr = fn(cf, 'CFDataGetBytePtr', vp, vp)
|
||||||
|
self.CFSetGetCount = fn(cf, 'CFSetGetCount', idx, vp)
|
||||||
|
self.CFSetGetValues = fn(cf, 'CFSetGetValues', None, vp, c.POINTER(vp))
|
||||||
|
self.CFRunLoopGetCurrent = fn(cf, 'CFRunLoopGetCurrent', vp)
|
||||||
|
self.CFRunLoopRunInMode = fn(cf, 'CFRunLoopRunInMode', i32, vp, c.c_double, c.c_bool)
|
||||||
|
self.kCFRunLoopDefaultMode = vp.in_dll(cf, 'kCFRunLoopDefaultMode').value
|
||||||
|
|
||||||
|
self.IOHIDManagerCreate = fn(io, 'IOHIDManagerCreate', vp, vp, u32)
|
||||||
|
self.IOHIDManagerSetDeviceMatching = fn(io, 'IOHIDManagerSetDeviceMatching', None, vp, vp)
|
||||||
|
self.IOHIDManagerScheduleWithRunLoop = fn(io, 'IOHIDManagerScheduleWithRunLoop', None, vp, vp, vp)
|
||||||
|
self.IOHIDManagerCopyDevices = fn(io, 'IOHIDManagerCopyDevices', vp, vp)
|
||||||
|
self.IOHIDDeviceGetProperty = fn(io, 'IOHIDDeviceGetProperty', vp, vp, vp)
|
||||||
|
self.IOHIDDeviceOpen = fn(io, 'IOHIDDeviceOpen', i32, vp, u32)
|
||||||
|
self.IOHIDDeviceClose = fn(io, 'IOHIDDeviceClose', i32, vp, u32)
|
||||||
|
self.IOHIDDeviceScheduleWithRunLoop = fn(io, 'IOHIDDeviceScheduleWithRunLoop', None, vp, vp, vp)
|
||||||
|
self.IOHIDDeviceUnscheduleFromRunLoop = fn(io, 'IOHIDDeviceUnscheduleFromRunLoop', None, vp, vp, vp)
|
||||||
|
# void (*)(void *ctx, IOReturn, void *sender, IOHIDReportType, uint32_t id, uint8_t *, CFIndex)
|
||||||
|
self.ReportCallback = c.CFUNCTYPE(None, vp, i32, vp, c.c_int, u32, c.POINTER(c.c_uint8), idx)
|
||||||
|
self.IOHIDDeviceRegisterInputReportCallback = fn(
|
||||||
|
io, 'IOHIDDeviceRegisterInputReportCallback', None, vp, vp, idx, self.ReportCallback, vp)
|
||||||
|
|
||||||
|
def cfstr(self, s):
|
||||||
|
return self.CFStringCreateWithCString(None, s.encode(), 0x08000100) # UTF-8
|
||||||
|
|
||||||
|
def prop(self, dev, key):
|
||||||
|
"""A device property as int, str or bytes, or None."""
|
||||||
|
c = self.c
|
||||||
|
ref = self.IOHIDDeviceGetProperty(dev, self.cfstr(key))
|
||||||
|
if not ref:
|
||||||
|
return None
|
||||||
|
t = self.CFGetTypeID(ref)
|
||||||
|
if t == self.CFNumberGetTypeID():
|
||||||
|
v = c.c_int64()
|
||||||
|
self.CFNumberGetValue(ref, 4, c.byref(v)) # kCFNumberSInt64Type
|
||||||
|
return v.value
|
||||||
|
if t == self.CFStringGetTypeID():
|
||||||
|
buf = c.create_string_buffer(256)
|
||||||
|
return buf.value.decode('utf-8', 'replace') if self.CFStringGetCString(
|
||||||
|
ref, buf, len(buf), 0x08000100) else None
|
||||||
|
if t == self.CFDataGetTypeID():
|
||||||
|
return c.string_at(self.CFDataGetBytePtr(ref), self.CFDataGetLength(ref))
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class MacDevice:
|
||||||
|
backend = 'iokit'
|
||||||
|
_hid = None
|
||||||
|
|
||||||
|
def __init__(self, ref, name, vendor, product, location):
|
||||||
|
self.ref, self.name, self.vendor, self.product = ref, name, vendor, product
|
||||||
|
self.path = 'iokit:%08x' % location
|
||||||
|
self.reports = []
|
||||||
|
self.start = time.monotonic()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def hid(cls):
|
||||||
|
if cls._hid is None:
|
||||||
|
cls._hid = MacHid()
|
||||||
|
return cls._hid
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def find(cls):
|
||||||
|
h = cls.hid()
|
||||||
|
mgr = h.IOHIDManagerCreate(None, 0)
|
||||||
|
h.IOHIDManagerSetDeviceMatching(mgr, None)
|
||||||
|
h.IOHIDManagerScheduleWithRunLoop(mgr, h.CFRunLoopGetCurrent(), h.kCFRunLoopDefaultMode)
|
||||||
|
devset = h.IOHIDManagerCopyDevices(mgr)
|
||||||
|
if not devset:
|
||||||
|
return []
|
||||||
|
n = h.CFSetGetCount(devset)
|
||||||
|
refs = (h.c.c_void_p * n)()
|
||||||
|
h.CFSetGetValues(devset, refs)
|
||||||
|
found = []
|
||||||
|
for ref in refs:
|
||||||
|
vendor = h.prop(ref, 'VendorID')
|
||||||
|
if vendor not in VENDORS:
|
||||||
|
continue
|
||||||
|
# The same test as QET's SpaceMouseHid::isSpaceMouse(): Generic
|
||||||
|
# Desktop / Multi-axis Controller, or no usage at all. This also
|
||||||
|
# skips Logitech's ordinary mice and keyboards.
|
||||||
|
usage = (h.prop(ref, 'PrimaryUsagePage') or 0, h.prop(ref, 'PrimaryUsage') or 0)
|
||||||
|
if usage not in ((1, 8), (0, 0)):
|
||||||
|
continue
|
||||||
|
found.append(cls(ref, h.prop(ref, 'Product') or '?', '%04x' % vendor,
|
||||||
|
'%04x' % (h.prop(ref, 'ProductID') or 0),
|
||||||
|
h.prop(ref, 'LocationID') or 0))
|
||||||
|
return sorted(found, key=lambda d: d.path)
|
||||||
|
|
||||||
|
def descriptor(self):
|
||||||
|
d = self.hid().prop(self.ref, 'ReportDescriptor')
|
||||||
|
return d.hex() if d else 'unreadable'
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
h = self.hid()
|
||||||
|
ret = h.IOHIDDeviceOpen(self.ref, 0) & 0xFFFFFFFF # kIOHIDOptionsTypeNone: shared
|
||||||
|
if ret == 0xE00002C5:
|
||||||
|
sys.exit('The device is held exclusively by another program '
|
||||||
|
'(kIOReturnExclusiveAccess). Quit 3DxWare and try again.')
|
||||||
|
if ret in (0xE00002E2, 0xE00002C1):
|
||||||
|
sys.exit('macOS refused access (0x%08X). Allow Terminal under System Settings > '
|
||||||
|
'Privacy & Security > Input Monitoring, then try again.' % ret)
|
||||||
|
if ret:
|
||||||
|
sys.exit('Could not open the device (IOReturn 0x%08X).' % ret)
|
||||||
|
size = h.prop(self.ref, 'MaxInputReportSize') or 64
|
||||||
|
self.buf = h.c.create_string_buffer(size)
|
||||||
|
|
||||||
|
def on_report(_ctx, _result, _sender, _type, _id, data, length):
|
||||||
|
self.reports.append([round((time.monotonic() - self.start) * 1000, 1),
|
||||||
|
h.c.string_at(data, length).hex()])
|
||||||
|
self.callback = h.ReportCallback(on_report) # must outlive the device
|
||||||
|
h.IOHIDDeviceRegisterInputReportCallback(self.ref, self.buf, size, self.callback, None)
|
||||||
|
h.IOHIDDeviceScheduleWithRunLoop(self.ref, h.CFRunLoopGetCurrent(), h.kCFRunLoopDefaultMode)
|
||||||
|
|
||||||
|
def record(self, seconds):
|
||||||
|
h = self.hid()
|
||||||
|
self.reports, self.start = [], time.monotonic()
|
||||||
|
while True:
|
||||||
|
left = seconds - (time.monotonic() - self.start)
|
||||||
|
if left <= 0:
|
||||||
|
return self.reports
|
||||||
|
h.CFRunLoopRunInMode(h.kCFRunLoopDefaultMode, left, False)
|
||||||
|
|
||||||
|
def drain(self):
|
||||||
|
self.hid().CFRunLoopRunInMode(self.hid().kCFRunLoopDefaultMode, 0.05, False)
|
||||||
|
self.reports = []
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
h = self.hid()
|
||||||
|
h.IOHIDDeviceUnscheduleFromRunLoop(self.ref, h.CFRunLoopGetCurrent(), h.kCFRunLoopDefaultMode)
|
||||||
|
h.IOHIDDeviceClose(self.ref, 0)
|
||||||
|
|
||||||
|
def empty_hint(self):
|
||||||
|
return ('Quit 3DxWare if it is running, or allow Terminal under System Settings > '
|
||||||
|
'Privacy & Security > Input Monitoring, and try again.')
|
||||||
|
|
||||||
|
|
||||||
|
# --- Windows: hid.dll, the same calls hidapi's Windows backend makes ---------
|
||||||
|
|
||||||
|
class WinHid:
|
||||||
|
"""ctypes bindings to the SetupAPI/HID/kernel32 calls needed."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
import ctypes as c
|
||||||
|
from ctypes import wintypes as w
|
||||||
|
self.c, self.w = c, w
|
||||||
|
self.hid = c.WinDLL('hid')
|
||||||
|
self.setupapi = c.WinDLL('setupapi')
|
||||||
|
self.k32 = c.WinDLL('kernel32', use_last_error=True)
|
||||||
|
k, sa = self.k32, self.setupapi
|
||||||
|
|
||||||
|
class GUID(c.Structure):
|
||||||
|
_fields_ = [('Data1', w.DWORD), ('Data2', w.WORD), ('Data3', w.WORD),
|
||||||
|
('Data4', c.c_ubyte * 8)]
|
||||||
|
|
||||||
|
class InterfaceData(c.Structure):
|
||||||
|
_fields_ = [('cbSize', w.DWORD), ('InterfaceClassGuid', GUID),
|
||||||
|
('Flags', w.DWORD), ('Reserved', c.c_void_p)]
|
||||||
|
|
||||||
|
class Attributes(c.Structure):
|
||||||
|
_fields_ = [('Size', w.ULONG), ('VendorID', w.USHORT), ('ProductID', w.USHORT),
|
||||||
|
('VersionNumber', w.USHORT)]
|
||||||
|
|
||||||
|
class Caps(c.Structure):
|
||||||
|
_fields_ = [('Usage', w.USHORT), ('UsagePage', w.USHORT),
|
||||||
|
('InputReportByteLength', w.USHORT), ('OutputReportByteLength', w.USHORT),
|
||||||
|
('FeatureReportByteLength', w.USHORT), ('Reserved', w.USHORT * 17),
|
||||||
|
('rest', w.USHORT * 10)]
|
||||||
|
|
||||||
|
class Overlapped(c.Structure):
|
||||||
|
_fields_ = [('Internal', c.c_void_p), ('InternalHigh', c.c_void_p),
|
||||||
|
('Offset', w.DWORD), ('OffsetHigh', w.DWORD), ('hEvent', w.HANDLE)]
|
||||||
|
|
||||||
|
self.GUID, self.InterfaceData, self.Attributes = GUID, InterfaceData, Attributes
|
||||||
|
self.Caps, self.Overlapped = Caps, Overlapped
|
||||||
|
|
||||||
|
k.CreateFileW.restype = w.HANDLE
|
||||||
|
k.CreateFileW.argtypes = [w.LPCWSTR, w.DWORD, w.DWORD, c.c_void_p, w.DWORD, w.DWORD, w.HANDLE]
|
||||||
|
k.CreateEventW.restype = w.HANDLE
|
||||||
|
k.CreateEventW.argtypes = [c.c_void_p, w.BOOL, w.BOOL, w.LPCWSTR]
|
||||||
|
k.ReadFile.argtypes = [w.HANDLE, c.c_void_p, w.DWORD, c.c_void_p, c.c_void_p]
|
||||||
|
k.GetOverlappedResult.argtypes = [w.HANDLE, c.c_void_p, c.POINTER(w.DWORD), w.BOOL]
|
||||||
|
k.WaitForSingleObject.argtypes = [w.HANDLE, w.DWORD]
|
||||||
|
k.WaitForSingleObject.restype = w.DWORD
|
||||||
|
k.CancelIo.argtypes = [w.HANDLE]
|
||||||
|
k.CloseHandle.argtypes = [w.HANDLE]
|
||||||
|
sa.SetupDiGetClassDevsW.restype = w.HANDLE
|
||||||
|
sa.SetupDiGetClassDevsW.argtypes = [c.c_void_p, w.LPCWSTR, w.HWND, w.DWORD]
|
||||||
|
sa.SetupDiEnumDeviceInterfaces.argtypes = [w.HANDLE, c.c_void_p, c.c_void_p, w.DWORD, c.c_void_p]
|
||||||
|
sa.SetupDiGetDeviceInterfaceDetailW.argtypes = [w.HANDLE, c.c_void_p, c.c_void_p, w.DWORD,
|
||||||
|
c.POINTER(w.DWORD), c.c_void_p]
|
||||||
|
sa.SetupDiDestroyDeviceInfoList.argtypes = [w.HANDLE]
|
||||||
|
self.hid.HidD_GetHidGuid.argtypes = [c.c_void_p]
|
||||||
|
self.hid.HidD_GetAttributes.argtypes = [w.HANDLE, c.c_void_p]
|
||||||
|
self.hid.HidD_GetPreparsedData.argtypes = [w.HANDLE, c.POINTER(c.c_void_p)]
|
||||||
|
self.hid.HidD_FreePreparsedData.argtypes = [c.c_void_p]
|
||||||
|
self.hid.HidP_GetCaps.argtypes = [c.c_void_p, c.c_void_p]
|
||||||
|
self.hid.HidD_GetProductString.argtypes = [w.HANDLE, c.c_void_p, w.ULONG]
|
||||||
|
|
||||||
|
INVALID = (2 ** 64 - 1, 2 ** 32 - 1, -1) # INVALID_HANDLE_VALUE, 64/32-bit
|
||||||
|
|
||||||
|
def paths(self):
|
||||||
|
"""Every HID interface path on the system."""
|
||||||
|
c, w = self.c, self.w
|
||||||
|
guid = self.GUID()
|
||||||
|
self.hid.HidD_GetHidGuid(c.byref(guid))
|
||||||
|
info = self.setupapi.SetupDiGetClassDevsW(c.byref(guid), None, None, 0x12) # PRESENT|INTERFACE
|
||||||
|
paths = []
|
||||||
|
i = 0
|
||||||
|
while True:
|
||||||
|
data = self.InterfaceData()
|
||||||
|
data.cbSize = c.sizeof(data)
|
||||||
|
if not self.setupapi.SetupDiEnumDeviceInterfaces(info, None, c.byref(guid), i, c.byref(data)):
|
||||||
|
break
|
||||||
|
i += 1
|
||||||
|
needed = w.DWORD()
|
||||||
|
self.setupapi.SetupDiGetDeviceInterfaceDetailW(info, c.byref(data), None, 0, c.byref(needed), None)
|
||||||
|
buf = c.create_string_buffer(needed.value)
|
||||||
|
# SP_DEVICE_INTERFACE_DETAIL_DATA_W: DWORD cbSize, then the path.
|
||||||
|
c.cast(buf, c.POINTER(w.DWORD))[0] = 8 if c.sizeof(c.c_void_p) == 8 else 6
|
||||||
|
if self.setupapi.SetupDiGetDeviceInterfaceDetailW(info, c.byref(data), buf, needed, None, None):
|
||||||
|
paths.append(c.wstring_at(c.addressof(buf) + 4))
|
||||||
|
self.setupapi.SetupDiDestroyDeviceInfoList(info)
|
||||||
|
return paths
|
||||||
|
|
||||||
|
def open(self, path, access):
|
||||||
|
# FILE_SHARE_READ|WRITE, OPEN_EXISTING, FILE_FLAG_OVERLAPPED
|
||||||
|
h = self.k32.CreateFileW(path, access, 3, None, 3, 0x40000000, None)
|
||||||
|
return None if h is None or h in self.INVALID else h
|
||||||
|
|
||||||
|
def describe(self, h):
|
||||||
|
"""(vendor, product, usage_page, usage, input_length, name) of an open handle."""
|
||||||
|
c = self.c
|
||||||
|
attrs = self.Attributes()
|
||||||
|
attrs.Size = c.sizeof(attrs)
|
||||||
|
if not self.hid.HidD_GetAttributes(h, c.byref(attrs)):
|
||||||
|
return None
|
||||||
|
page = usage = length = 0
|
||||||
|
pre = c.c_void_p()
|
||||||
|
if self.hid.HidD_GetPreparsedData(h, c.byref(pre)):
|
||||||
|
caps = self.Caps()
|
||||||
|
self.hid.HidP_GetCaps(pre, c.byref(caps))
|
||||||
|
page, usage, length = caps.UsagePage, caps.Usage, caps.InputReportByteLength
|
||||||
|
self.hid.HidD_FreePreparsedData(pre)
|
||||||
|
name = c.create_unicode_buffer(128)
|
||||||
|
if not self.hid.HidD_GetProductString(h, name, c.sizeof(name)):
|
||||||
|
name.value = '?'
|
||||||
|
return attrs.VendorID, attrs.ProductID, page, usage, length, name.value
|
||||||
|
|
||||||
|
|
||||||
|
class WinDevice:
|
||||||
|
backend = 'windows-hid'
|
||||||
|
_hid = None
|
||||||
|
|
||||||
|
def __init__(self, path, name, vendor, product, length):
|
||||||
|
self.path, self.name, self.vendor, self.product = path, name, vendor, product
|
||||||
|
self.length = length or 64
|
||||||
|
self.handle = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def hid(cls):
|
||||||
|
if cls._hid is None:
|
||||||
|
cls._hid = WinHid()
|
||||||
|
return cls._hid
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def find(cls):
|
||||||
|
h = cls.hid()
|
||||||
|
found = []
|
||||||
|
for path in h.paths():
|
||||||
|
handle = h.open(path, 0) # no access: enough to read attributes
|
||||||
|
if handle is None:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
d = h.describe(handle)
|
||||||
|
finally:
|
||||||
|
h.k32.CloseHandle(handle)
|
||||||
|
if not d:
|
||||||
|
continue
|
||||||
|
vendor, product, page, usage, length, name = d
|
||||||
|
# The same test as QET's SpaceMouseHid::isSpaceMouse().
|
||||||
|
if vendor not in VENDORS or (page, usage) not in ((1, 8), (0, 0)):
|
||||||
|
continue
|
||||||
|
found.append(cls(path, name, '%04x' % vendor, '%04x' % product, length))
|
||||||
|
return found
|
||||||
|
|
||||||
|
def descriptor(self):
|
||||||
|
# Windows only gives out a parsed form of it.
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
h = self.hid()
|
||||||
|
self.handle = h.open(self.path, 0x80000000) # GENERIC_READ
|
||||||
|
if self.handle is None:
|
||||||
|
sys.exit('Could not open the device (error %d).' % h.c.get_last_error())
|
||||||
|
self.event = h.k32.CreateEventW(None, True, False, None)
|
||||||
|
self.buf = h.c.create_string_buffer(self.length)
|
||||||
|
self.pending = False
|
||||||
|
self.start = time.monotonic()
|
||||||
|
|
||||||
|
def _read(self, wait_ms):
|
||||||
|
"""One report if it arrives within wait_ms, else None."""
|
||||||
|
h = self.hid()
|
||||||
|
c, w = h.c, h.w
|
||||||
|
if not self.pending:
|
||||||
|
self.ov = h.Overlapped()
|
||||||
|
self.ov.hEvent = self.event
|
||||||
|
h.k32.ReadFile(self.handle, self.buf, self.length, None, c.byref(self.ov))
|
||||||
|
self.pending = True
|
||||||
|
if h.k32.WaitForSingleObject(self.event, max(0, int(wait_ms))) != 0:
|
||||||
|
return None
|
||||||
|
self.pending = False
|
||||||
|
n = w.DWORD()
|
||||||
|
if not h.k32.GetOverlappedResult(self.handle, c.byref(self.ov), c.byref(n), False):
|
||||||
|
return None
|
||||||
|
data = self.buf.raw[:n.value]
|
||||||
|
# Windows puts a report ID in front even when the device has none;
|
||||||
|
# hidapi drops that 0, so QET never sees it.
|
||||||
|
return data[1:] if data[:1] == b'\0' else data
|
||||||
|
|
||||||
|
def record(self, seconds):
|
||||||
|
reports = []
|
||||||
|
start = time.monotonic()
|
||||||
|
while True:
|
||||||
|
left = seconds - (time.monotonic() - start)
|
||||||
|
if left <= 0:
|
||||||
|
return reports
|
||||||
|
data = self._read(left * 1000)
|
||||||
|
if data:
|
||||||
|
reports.append([round((time.monotonic() - start) * 1000, 1), data.hex()])
|
||||||
|
|
||||||
|
def drain(self):
|
||||||
|
while self._read(0):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
h = self.hid()
|
||||||
|
if self.pending:
|
||||||
|
h.k32.CancelIo(self.handle)
|
||||||
|
h.k32.CloseHandle(self.event)
|
||||||
|
h.k32.CloseHandle(self.handle)
|
||||||
|
|
||||||
|
def empty_hint(self):
|
||||||
|
return 'Check the cable, push the cap firmly, and try again.'
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
ap = argparse.ArgumentParser(description=__doc__,
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
ap.add_argument('--list', action='store_true', help='only list matching devices')
|
||||||
|
ap.add_argument('--device', help='device path from --list, if more than one is found')
|
||||||
|
ap.add_argument('--descriptor', help=argparse.SUPPRESS) # testing without a device
|
||||||
|
ap.add_argument('--yes', action='store_true', help=argparse.SUPPRESS) # no Enter prompts
|
||||||
|
ap.add_argument('-o', '--output', help='output file (default: spacemouse-capture-<product>.json)')
|
||||||
|
ap.add_argument('--seconds', type=float, default=1.0,
|
||||||
|
help='multiply each step\'s recording time (default: 1.0, e.g. 3 triples it)')
|
||||||
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
Device = {'darwin': MacDevice, 'win32': WinDevice}.get(sys.platform, HidrawDevice)
|
||||||
|
devices = Device.find()
|
||||||
|
if args.list:
|
||||||
|
for d in devices:
|
||||||
|
print('%s %s:%s %s' % (d.path, d.vendor, d.product, d.name))
|
||||||
|
if not devices:
|
||||||
|
print('No 3Dconnexion device found.')
|
||||||
|
return 0 if devices else 1
|
||||||
|
|
||||||
|
if args.device:
|
||||||
|
dev = next((d for d in devices if d.path == args.device), None)
|
||||||
|
if dev is None:
|
||||||
|
if Device is not HidrawDevice:
|
||||||
|
sys.exit('No device %s (try --list)' % args.device)
|
||||||
|
dev = HidrawDevice(args.device)
|
||||||
|
elif len(devices) == 1:
|
||||||
|
dev = devices[0]
|
||||||
|
elif not devices:
|
||||||
|
sys.exit('No 3Dconnexion device found. Is it plugged in? (try --list)')
|
||||||
|
else:
|
||||||
|
sys.exit('Several devices found, pick one with --device:\n' +
|
||||||
|
'\n'.join(' %s %s' % (d.path, d.name) for d in devices))
|
||||||
|
|
||||||
|
if args.descriptor:
|
||||||
|
with open(args.descriptor, 'rb') as f:
|
||||||
|
descriptor = f.read().hex()
|
||||||
|
else:
|
||||||
|
descriptor = dev.descriptor()
|
||||||
|
|
||||||
|
dev.open()
|
||||||
|
print('Recording from %s (%s, %s:%s).' % (dev.path, dev.name, dev.vendor, dev.product))
|
||||||
|
readers = other_readers()
|
||||||
|
if readers:
|
||||||
|
print('Also running: %s. If nothing gets recorded, quit it and try again.' % ', '.join(readers))
|
||||||
|
print('For each step, press Enter, do the movement, and wait for the next prompt.\n')
|
||||||
|
|
||||||
|
result = {
|
||||||
|
'tool': 'spacemouse-capture.py 2',
|
||||||
|
'date': datetime.datetime.now(datetime.timezone.utc).isoformat(timespec='seconds'),
|
||||||
|
'system': platform.platform(),
|
||||||
|
'backend': dev.backend,
|
||||||
|
'other_readers': readers,
|
||||||
|
'device': {'name': dev.name, 'vendor': dev.vendor, 'product': dev.product},
|
||||||
|
'report_descriptor': descriptor,
|
||||||
|
'steps': [],
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
for i, (key, text, seconds) in enumerate(STEPS, 1):
|
||||||
|
seconds = seconds * args.seconds
|
||||||
|
print('[%d/%d] %s' % (i, len(STEPS), text))
|
||||||
|
if not args.yes:
|
||||||
|
input(' Press Enter to start (%.0f s)... ' % seconds)
|
||||||
|
dev.drain()
|
||||||
|
reports = dev.record(seconds)
|
||||||
|
print(' %d reports recorded.\n' % len(reports))
|
||||||
|
result['steps'].append({'step': key, 'instruction': text, 'reports': reports})
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print('\nStopped early -- saving what was recorded so far.')
|
||||||
|
finally:
|
||||||
|
dev.close()
|
||||||
|
|
||||||
|
out = args.output or 'spacemouse-capture-%s.json' % dev.product
|
||||||
|
with open(out, 'w') as f:
|
||||||
|
json.dump(result, f, indent=1)
|
||||||
|
total = sum(len(s['reports']) for s in result['steps'])
|
||||||
|
print('Saved %s (%d reports in total).' % (out, total))
|
||||||
|
if total == 0:
|
||||||
|
print('Nothing was recorded. ' + dev.empty_hint())
|
||||||
|
else:
|
||||||
|
print('Please attach this file to discussion #599. Thank you!')
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
#Based on raspberry pi 5 8 Gb Trixie
|
#Based on raspberry pi 5 8 Gb Trixie
|
||||||
#sudo apt install git ssh rsync libqt5svg5-dev qt5-qmake qtbase5-dev libkf5widgetsaddons-dev libkf5coreaddons-dev pkgconf libqt5waylandclient5-dev libqt5waylandcompositor5-dev g++ make
|
#sudo apt install git ssh rsync libqt5svg5-dev qt5-qmake qtbase5-dev libkf5widgetsaddons-dev libkf5coreaddons-dev libsqlite3-dev pkgconf libqt5waylandclient5-dev libqt5waylandcompositor5-dev g++ make
|
||||||
#mkdir -p AppImage/0.100.0/aarch64
|
#mkdir -p AppImage/0.100.0/aarch64
|
||||||
# Get GIT sources
|
# Get GIT sources
|
||||||
#git clone --recursive https://github.com/qelectrotech/qelectrotech-source-mirror.git
|
#git clone --recursive https://github.com/qelectrotech/qelectrotech-source-mirror.git
|
||||||
|
|||||||
@@ -49,6 +49,14 @@ ElementsCollectionModel::ElementsCollectionModel(QObject *parent) :
|
|||||||
*/
|
*/
|
||||||
ElementsCollectionModel::~ElementsCollectionModel()
|
ElementsCollectionModel::~ElementsCollectionModel()
|
||||||
{
|
{
|
||||||
|
// Without cancel(), the wait below runs the whole queued
|
||||||
|
// QtConcurrent::map() to completion, so closing this dialog on a
|
||||||
|
// large collection blocks until every remaining item has been
|
||||||
|
// processed -- a visible hang on the button pressed precisely to
|
||||||
|
// stop the work. cancel() drops the not-yet-started items so the
|
||||||
|
// wait that follows (still needed, so an in-flight item can't
|
||||||
|
// dereference this object after it's gone) is short.
|
||||||
|
m_future.cancel();
|
||||||
m_future.waitForFinished();
|
m_future.waitForFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,7 +439,7 @@ void ElementsCollectionModel::addLocation(const ElementsLocation& location)
|
|||||||
collection_name);
|
collection_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ANPASSUNG: Makros und Custom Collection werden hier behandelt!
|
// Macros and Custom Collection are handled here
|
||||||
else if (location.isCustomCollection() || location.isMacrosCollection()) {
|
else if (location.isCustomCollection() || location.isMacrosCollection()) {
|
||||||
QList <ElementCollectionItem *> child_list;
|
QList <ElementCollectionItem *> child_list;
|
||||||
|
|
||||||
@@ -495,6 +503,10 @@ void ElementsCollectionModel::addProject(QETProject *project, bool set_data)
|
|||||||
connect(project->embeddedElementCollection(),
|
connect(project->embeddedElementCollection(),
|
||||||
&XmlElementCollection::directoryRemoved,
|
&XmlElementCollection::directoryRemoved,
|
||||||
this, &ElementsCollectionModel::itemRemovedFromCollection);
|
this, &ElementsCollectionModel::itemRemovedFromCollection);
|
||||||
|
connect(project, &QETProject::projectTitleChanged,
|
||||||
|
this, &ElementsCollectionModel::projectNameChanged);
|
||||||
|
connect(project, &QETProject::projectFilePathChanged,
|
||||||
|
this, &ElementsCollectionModel::projectNameChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -526,6 +538,10 @@ void ElementsCollectionModel::removeProject(QETProject *project)
|
|||||||
&XmlElementCollection::directoryRemoved,
|
&XmlElementCollection::directoryRemoved,
|
||||||
this,
|
this,
|
||||||
&ElementsCollectionModel::itemRemovedFromCollection);
|
&ElementsCollectionModel::itemRemovedFromCollection);
|
||||||
|
disconnect(project, &QETProject::projectTitleChanged,
|
||||||
|
this, &ElementsCollectionModel::projectNameChanged);
|
||||||
|
disconnect(project, &QETProject::projectFilePathChanged,
|
||||||
|
this, &ElementsCollectionModel::projectNameChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -647,7 +663,7 @@ QModelIndex ElementsCollectionModel::indexFromLocation(
|
|||||||
if (eci->type() == FileElementCollectionItem::Type) {
|
if (eci->type() == FileElementCollectionItem::Type) {
|
||||||
if (FileElementCollectionItem *feci = static_cast<FileElementCollectionItem *>(eci)) {
|
if (FileElementCollectionItem *feci = static_cast<FileElementCollectionItem *>(eci)) {
|
||||||
|
|
||||||
// ANPASSUNG: Makro-Prüfung hinzugefügt, damit das Modell den Pfad im Baum findet!
|
// Macro check added so the model finds the path in the tree
|
||||||
if ( (location.isCommonCollection() && feci->isCommonCollection()) ||
|
if ( (location.isCommonCollection() && feci->isCommonCollection()) ||
|
||||||
(location.isCompanyCollection() && feci->isCompanyCollection()) ||
|
(location.isCompanyCollection() && feci->isCompanyCollection()) ||
|
||||||
(location.isMacrosCollection() && feci->isMacrosCollection()) ||
|
(location.isMacrosCollection() && feci->isMacrosCollection()) ||
|
||||||
@@ -766,3 +782,15 @@ void ElementsCollectionModel::updateItem(const QString& path)
|
|||||||
eci->setUpData();
|
eci->setUpData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief ElementsCollectionModel::projectNameChanged
|
||||||
|
Update the displayed name of the collection of project,
|
||||||
|
when its title or its file path changed.
|
||||||
|
@param project
|
||||||
|
*/
|
||||||
|
void ElementsCollectionModel::projectNameChanged(QETProject *project)
|
||||||
|
{
|
||||||
|
if (XmlProjectElementCollectionItem *xpeci = m_project_hash.value(project))
|
||||||
|
xpeci->updateProjectName();
|
||||||
|
}
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ class ElementsCollectionModel : public QStandardItemModel
|
|||||||
void elementIntegratedToCollection (const QString& path);
|
void elementIntegratedToCollection (const QString& path);
|
||||||
void itemRemovedFromCollection (const QString& path);
|
void itemRemovedFromCollection (const QString& path);
|
||||||
void updateItem (const QString& path);
|
void updateItem (const QString& path);
|
||||||
|
void projectNameChanged (QETProject *project);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList <QETProject *> m_project_list;
|
QList <QETProject *> m_project_list;
|
||||||
|
|||||||
@@ -653,10 +653,17 @@ QDomElement ElementsLocation::xml() const
|
|||||||
if (!m_project)
|
if (!m_project)
|
||||||
{
|
{
|
||||||
QFile file (m_file_system_path);
|
QFile file (m_file_system_path);
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
|
return QDomElement();
|
||||||
|
|
||||||
QDomDocument docu;
|
QDomDocument docu;
|
||||||
if (docu.setContent(&file))
|
if (docu.setContent(&file))
|
||||||
|
{
|
||||||
|
file.close();
|
||||||
return docu.documentElement();
|
return docu.documentElement();
|
||||||
}
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QString str = m_collection_path;
|
QString str = m_collection_path;
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ QString FileElementCollectionItem::localName()
|
|||||||
else if (m_path == QETApp::customElementsDirN())
|
else if (m_path == QETApp::customElementsDirN())
|
||||||
setText(QObject::tr("Collection utilisateur"));
|
setText(QObject::tr("Collection utilisateur"));
|
||||||
else if (m_path == macrosPath)
|
else if (m_path == macrosPath)
|
||||||
setText(QObject::tr("Makros"));
|
setText(QObject::tr("Macros"));
|
||||||
else
|
else
|
||||||
setText(QObject::tr("Collection inconnue"));
|
setText(QObject::tr("Collection inconnue"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
#include "../qetproject.h"
|
#include "../qetproject.h"
|
||||||
#include "xmlelementcollection.h"
|
#include "xmlelementcollection.h"
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief XmlProjectElementCollectionItem::XmlProjectElementCollectionItem
|
@brief XmlProjectElementCollectionItem::XmlProjectElementCollectionItem
|
||||||
Constructor
|
Constructor
|
||||||
@@ -58,10 +60,7 @@ QString XmlProjectElementCollectionItem::localName()
|
|||||||
return text();
|
return text();
|
||||||
|
|
||||||
if (isCollectionRoot()) {
|
if (isCollectionRoot()) {
|
||||||
if (m_project->title().isEmpty())
|
updateProjectName();
|
||||||
setText(QObject::tr("Projet sans titre"));
|
|
||||||
else
|
|
||||||
setText(m_project->title());
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ElementsLocation location (embeddedPath(), m_project);
|
ElementsLocation location (embeddedPath(), m_project);
|
||||||
@@ -71,6 +70,25 @@ QString XmlProjectElementCollectionItem::localName()
|
|||||||
return text();
|
return text();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief XmlProjectElementCollectionItem::updateProjectName
|
||||||
|
Set the displayed name of the collection root from the project :
|
||||||
|
its title, or its file name when it has no title, like the project panel.
|
||||||
|
Does nothing if this item is not the root of the collection.
|
||||||
|
*/
|
||||||
|
void XmlProjectElementCollectionItem::updateProjectName()
|
||||||
|
{
|
||||||
|
if (!isCollectionRoot() || !m_project)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!m_project->title().isEmpty())
|
||||||
|
setText(m_project->title());
|
||||||
|
else if (!m_project->filePath().isEmpty())
|
||||||
|
setText(QFileInfo(m_project->filePath()).completeBaseName());
|
||||||
|
else
|
||||||
|
setText(QObject::tr("Projet sans titre"));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief XmlProjectElementCollectionItem::name
|
@brief XmlProjectElementCollectionItem::name
|
||||||
@return The collection name of this item
|
@return The collection name of this item
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class XmlProjectElementCollectionItem : public ElementCollectionItem
|
|||||||
bool isCollectionRoot() const override;
|
bool isCollectionRoot() const override;
|
||||||
void addChildAtPath(const QString &collection_name) override;
|
void addChildAtPath(const QString &collection_name) override;
|
||||||
QETProject * project() const;
|
QETProject * project() const;
|
||||||
|
void updateProjectName();
|
||||||
|
|
||||||
void setProject (QETProject *project,
|
void setProject (QETProject *project,
|
||||||
bool set_data = true,
|
bool set_data = true,
|
||||||
|
|||||||
@@ -46,10 +46,11 @@ FreeTerminalEditor::FreeTerminalEditor(QETProject *project, QWidget *parent) :
|
|||||||
connect(m_project, &QObject::destroyed, this, &FreeTerminalEditor::reload);
|
connect(m_project, &QObject::destroyed, this, &FreeTerminalEditor::reload);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Disabled the move if the table is currently edited (yellow cell)
|
//Disable the move button while cells are edited (yellow), re-evaluate on every change
|
||||||
connect(m_model, &FreeTerminalModel::dataChanged, this, [=] {
|
connect(m_model, &FreeTerminalModel::dataChanged, this, &FreeTerminalEditor::selectionChanged);
|
||||||
this->setDisabledMove();
|
|
||||||
});
|
connect(ui->m_table_view->selectionModel(), &QItemSelectionModel::selectionChanged,
|
||||||
|
this, &FreeTerminalEditor::selectionChanged);
|
||||||
|
|
||||||
connect(ui->m_table_view, &QAbstractItemView::doubleClicked, this, [=](const QModelIndex &index)
|
connect(ui->m_table_view, &QAbstractItemView::doubleClicked, this, [=](const QModelIndex &index)
|
||||||
{
|
{
|
||||||
@@ -102,7 +103,7 @@ void FreeTerminalEditor::reload()
|
|||||||
QString str(strip->installation() + " " + strip->location() + " " + strip->name());
|
QString str(strip->installation() + " " + strip->location() + " " + strip->name());
|
||||||
ui->m_move_in_cb->addItem(str, strip->uuid());
|
ui->m_move_in_cb->addItem(str, strip->uuid());
|
||||||
}
|
}
|
||||||
setDisabledMove(false);
|
selectionChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,10 +274,19 @@ void FreeTerminalEditor::on_m_move_pb_clicked()
|
|||||||
reload();
|
reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FreeTerminalEditor::selectionChanged()
|
||||||
|
{
|
||||||
|
const bool has_selection = !ui->m_table_view->selectionModel()->selectedIndexes().isEmpty();
|
||||||
|
const bool has_pending = !m_model->modifiedModelRealTerminalData().isEmpty();
|
||||||
|
setDisabledMove(!has_selection || has_pending);
|
||||||
|
}
|
||||||
|
|
||||||
void FreeTerminalEditor::setDisabledMove(bool b)
|
void FreeTerminalEditor::setDisabledMove(bool b)
|
||||||
{
|
{
|
||||||
ui->m_move_label->setDisabled(b);
|
ui->m_move_label->setDisabled(b);
|
||||||
ui->m_move_in_cb->setDisabled(b);
|
ui->m_move_in_cb->setDisabled(b);
|
||||||
ui->m_move_pb->setDisabled(b);
|
ui->m_move_pb->setDisabled(b);
|
||||||
|
ui->m_move_pb->setToolTip(b ? tr("Appliquez ou annulez les modifications en cours avant de déplacer")
|
||||||
|
: tr("Déplacer les bornes sélectionnées vers le bornier choisi"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ bool FreeTerminalModel::setData(const QModelIndex &index, const QVariant &value,
|
|||||||
modified_ = true;
|
modified_ = true;
|
||||||
modified_cell = FUNCTION_CELL;
|
modified_cell = FUNCTION_CELL;
|
||||||
}
|
}
|
||||||
else if (column_ == LED_CELL)
|
else if (column_ == LED_CELL && mrtd.led_ != value.toBool())
|
||||||
{
|
{
|
||||||
mrtd.led_ = value.toBool();
|
mrtd.led_ = value.toBool();
|
||||||
modified_ = true;
|
modified_ = true;
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2006-2026 The QElectroTech Team
|
||||||
|
This file is part of QElectroTech.
|
||||||
|
|
||||||
|
QElectroTech 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.
|
||||||
|
|
||||||
|
QElectroTech is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "renumberelementscommand.h"
|
||||||
|
|
||||||
|
#include "../qetproject.h"
|
||||||
|
#include "../qetgraphicsitem/element.h"
|
||||||
|
|
||||||
|
RenumberElementsCommand::RenumberElementsCommand(
|
||||||
|
QETProject *project,
|
||||||
|
QVector<ElementChange> changes,
|
||||||
|
QHash<QString, NumerotationContext> old_ctx,
|
||||||
|
QHash<QString, NumerotationContext> new_ctx,
|
||||||
|
const QString &text)
|
||||||
|
: QUndoCommand(text)
|
||||||
|
, project_(project)
|
||||||
|
, changes_(std::move(changes))
|
||||||
|
, old_ctx_(std::move(old_ctx))
|
||||||
|
, new_ctx_(std::move(new_ctx))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenumberElementsCommand::undo()
|
||||||
|
{
|
||||||
|
apply(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenumberElementsCommand::redo()
|
||||||
|
{
|
||||||
|
// QUndoStack calls redo() once immediately after push(); keep standard behaviour.
|
||||||
|
if (first_redo_) {
|
||||||
|
first_redo_ = false;
|
||||||
|
}
|
||||||
|
apply(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenumberElementsCommand::apply(bool use_new)
|
||||||
|
{
|
||||||
|
if (!project_) return;
|
||||||
|
|
||||||
|
// Restore project contexts
|
||||||
|
const auto &ctx = use_new ? new_ctx_ : old_ctx_;
|
||||||
|
for (auto it = ctx.constBegin(); it != ctx.constEnd(); ++it) {
|
||||||
|
project_->addElementAutoNum(it.key(), it.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply per-element changes
|
||||||
|
for (const ElementChange &c : changes_) {
|
||||||
|
if (!c.element) continue;
|
||||||
|
|
||||||
|
const bool frozen = use_new ? c.new_frozen : c.old_frozen;
|
||||||
|
const auto &infos = use_new ? c.new_infos : c.old_infos;
|
||||||
|
const auto &seq = use_new ? c.new_seq : c.old_seq;
|
||||||
|
|
||||||
|
// Temporarily unfreeze so that label/infos update correctly.
|
||||||
|
const bool was_frozen = c.element->isFreezeLabel();
|
||||||
|
if (was_frozen) c.element->freezeLabel(false);
|
||||||
|
|
||||||
|
c.element->rSequenceStruct() = seq;
|
||||||
|
c.element->setElementInformations(infos);
|
||||||
|
c.element->freezeLabel(frozen);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2006-2026 The QElectroTech Team
|
||||||
|
This file is part of QElectroTech.
|
||||||
|
|
||||||
|
QElectroTech 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.
|
||||||
|
|
||||||
|
QElectroTech is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RENUMBERELEMENTSCOMMAND_H
|
||||||
|
#define RENUMBERELEMENTSCOMMAND_H
|
||||||
|
|
||||||
|
#include <QUndoCommand>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
#include "../diagramcontext.h"
|
||||||
|
#include "assignvariables.h" // defines autonum::sequentialNumbers
|
||||||
|
|
||||||
|
class Element;
|
||||||
|
class QETProject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Undoable renumbering of element labels and sequence structs.
|
||||||
|
*/
|
||||||
|
class RenumberElementsCommand final : public QUndoCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct ElementChange
|
||||||
|
{
|
||||||
|
Element *element = nullptr;
|
||||||
|
DiagramContext old_infos;
|
||||||
|
DiagramContext new_infos;
|
||||||
|
autonum::sequentialNumbers old_seq;
|
||||||
|
autonum::sequentialNumbers new_seq;
|
||||||
|
bool old_frozen = false;
|
||||||
|
bool new_frozen = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
RenumberElementsCommand(
|
||||||
|
QETProject *project,
|
||||||
|
QVector<ElementChange> changes,
|
||||||
|
QHash<QString, NumerotationContext> old_ctx,
|
||||||
|
QHash<QString, NumerotationContext> new_ctx,
|
||||||
|
const QString &text);
|
||||||
|
|
||||||
|
void undo() override;
|
||||||
|
void redo() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void apply(bool use_new);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QETProject *project_ = nullptr;
|
||||||
|
QVector<ElementChange> changes_;
|
||||||
|
QHash<QString, NumerotationContext> old_ctx_;
|
||||||
|
QHash<QString, NumerotationContext> new_ctx_;
|
||||||
|
bool first_redo_ = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // RENUMBERELEMENTSCOMMAND_H
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "formulaautonumberingw.h"
|
#include "formulaautonumberingw.h"
|
||||||
#include "numparteditorw.h"
|
#include "numparteditorw.h"
|
||||||
#include "qdebug.h"
|
#include "qdebug.h"
|
||||||
|
#include "renumberelementsdialog.h"
|
||||||
#include "ui_autonumberingmanagementw.h"
|
#include "ui_autonumberingmanagementw.h"
|
||||||
#include "ui_formulaautonumberingw.h"
|
#include "ui_formulaautonumberingw.h"
|
||||||
|
|
||||||
@@ -48,6 +49,8 @@ AutoNumberingManagementW::AutoNumberingManagementW(QETProject *project,
|
|||||||
ui->m_selected_folios_le->setDisabled(true);
|
ui->m_selected_folios_le->setDisabled(true);
|
||||||
ui->m_selected_folios_le->setReadOnly(true);
|
ui->m_selected_folios_le->setReadOnly(true);
|
||||||
ui->m_apply_project_rb->setChecked(true);
|
ui->m_apply_project_rb->setChecked(true);
|
||||||
|
// Enabled only when project is in "Under Development" status and not read-only.
|
||||||
|
ui->m_renumber_elements_pb->setEnabled(ui->m_status_cb->currentIndex() == 0 && project_ && !project_->isReadOnly());
|
||||||
setProjectContext();
|
setProjectContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,6 +90,7 @@ void AutoNumberingManagementW::on_m_status_cb_currentIndexChanged(int index)
|
|||||||
ui->m_both_conductor_rb->setChecked(true);
|
ui->m_both_conductor_rb->setChecked(true);
|
||||||
ui->m_both_element_rb->setChecked(true);
|
ui->m_both_element_rb->setChecked(true);
|
||||||
ui->m_both_folio_rb->setChecked(true);
|
ui->m_both_folio_rb->setChecked(true);
|
||||||
|
ui->m_renumber_elements_pb->setEnabled(true);
|
||||||
}
|
}
|
||||||
//Installing
|
//Installing
|
||||||
else if (index == 1) {
|
else if (index == 1) {
|
||||||
@@ -96,15 +100,31 @@ void AutoNumberingManagementW::on_m_status_cb_currentIndexChanged(int index)
|
|||||||
ui->m_new_conductor_rb->setChecked(true);
|
ui->m_new_conductor_rb->setChecked(true);
|
||||||
ui->m_new_element_rb->setChecked(true);
|
ui->m_new_element_rb->setChecked(true);
|
||||||
ui->m_new_folio_rb->setChecked(true);
|
ui->m_new_folio_rb->setChecked(true);
|
||||||
|
ui->m_renumber_elements_pb->setEnabled(true);
|
||||||
}
|
}
|
||||||
//Built
|
//Built
|
||||||
else if (index == 2) {
|
else if (index == 2) {
|
||||||
ui->m_disable_conductor_rb->setChecked(true);
|
ui->m_disable_conductor_rb->setChecked(true);
|
||||||
ui->m_disable_element_rb->setChecked(true);
|
ui->m_disable_element_rb->setChecked(true);
|
||||||
ui->m_disable_folio_rb->setChecked(true);
|
ui->m_disable_folio_rb->setChecked(true);
|
||||||
|
ui->m_renumber_elements_pb->setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AutoNumberingManagementW::on_m_renumber_elements_pb_clicked()
|
||||||
|
{
|
||||||
|
if (!project_ || project_->isReadOnly()) return;
|
||||||
|
// Only allowed during "Under Development"
|
||||||
|
// if (ui->m_status_cb->currentIndex() != 1) return;
|
||||||
|
|
||||||
|
QStringList titles = project_->elementAutoNum().keys();
|
||||||
|
titles.sort(Qt::CaseInsensitive);
|
||||||
|
RenumberElementsDialog dlg(titles, this);
|
||||||
|
if (dlg.exec() != QDialog::Accepted) return;
|
||||||
|
|
||||||
|
project_->renumberElementsBySchemeTitle(dlg.selectedSchemeTitle());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief AutoNumberingManagementW::on_m_apply_folios_rb_clicked
|
@brief AutoNumberingManagementW::on_m_apply_folios_rb_clicked
|
||||||
Set From Folios Combobox
|
Set From Folios Combobox
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ class AutoNumberingManagementW : public QWidget
|
|||||||
void on_m_from_folios_cb_currentIndexChanged(int);
|
void on_m_from_folios_cb_currentIndexChanged(int);
|
||||||
void on_m_to_folios_cb_currentIndexChanged(int);
|
void on_m_to_folios_cb_currentIndexChanged(int);
|
||||||
void on_m_status_cb_currentIndexChanged(int);
|
void on_m_status_cb_currentIndexChanged(int);
|
||||||
|
void on_m_renumber_elements_pb_clicked();
|
||||||
void on_m_apply_folios_rb_clicked();
|
void on_m_apply_folios_rb_clicked();
|
||||||
void on_m_apply_project_rb_clicked();
|
void on_m_apply_project_rb_clicked();
|
||||||
void on_buttonBox_clicked(QAbstractButton *);
|
void on_buttonBox_clicked(QAbstractButton *);
|
||||||
|
|||||||
@@ -305,6 +305,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="m_renumber_elements_pb">
|
||||||
|
<property name="text">
|
||||||
|
<string>Renumber element(s)…</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_2">
|
<spacer name="horizontalSpacer_2">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2006-2026 The QElectroTech Team
|
||||||
|
This file is part of QElectroTech.
|
||||||
|
|
||||||
|
QElectroTech 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.
|
||||||
|
|
||||||
|
QElectroTech is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "renumberelementsdialog.h"
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QFormLayout>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QRadioButton>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
RenumberElementsDialog::RenumberElementsDialog(const QStringList &scheme_titles, QWidget *parent)
|
||||||
|
: QDialog(parent)
|
||||||
|
, m_scheme_titles(scheme_titles)
|
||||||
|
{
|
||||||
|
setWindowTitle(tr("Renumber element(s)"));
|
||||||
|
setModal(true);
|
||||||
|
|
||||||
|
auto *vl = new QVBoxLayout(this);
|
||||||
|
|
||||||
|
auto *scope = new QGroupBox(tr("Scope"), this);
|
||||||
|
auto *scope_l = new QVBoxLayout(scope);
|
||||||
|
m_all_rb = new QRadioButton(tr("All schemes"), scope);
|
||||||
|
m_one_rb = new QRadioButton(tr("One scheme"), scope);
|
||||||
|
scope_l->addWidget(m_all_rb);
|
||||||
|
scope_l->addWidget(m_one_rb);
|
||||||
|
vl->addWidget(scope);
|
||||||
|
|
||||||
|
auto *form = new QFormLayout();
|
||||||
|
m_combo = new QComboBox(this);
|
||||||
|
m_combo->addItems(m_scheme_titles);
|
||||||
|
form->addRow(new QLabel(tr("Scheme:"), this), m_combo);
|
||||||
|
vl->addLayout(form);
|
||||||
|
|
||||||
|
m_buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
||||||
|
connect(m_buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||||
|
connect(m_buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
vl->addWidget(m_buttons);
|
||||||
|
|
||||||
|
m_all_rb->setChecked(true);
|
||||||
|
updateUi();
|
||||||
|
|
||||||
|
connect(m_all_rb, &QRadioButton::toggled, this, &RenumberElementsDialog::updateUi);
|
||||||
|
connect(m_one_rb, &QRadioButton::toggled, this, &RenumberElementsDialog::updateUi);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString RenumberElementsDialog::selectedSchemeTitle() const
|
||||||
|
{
|
||||||
|
if (m_all_rb && m_all_rb->isChecked()) return QString();
|
||||||
|
return m_combo ? m_combo->currentText() : QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenumberElementsDialog::updateUi()
|
||||||
|
{
|
||||||
|
const bool one = m_one_rb && m_one_rb->isChecked();
|
||||||
|
if (m_combo) m_combo->setEnabled(one);
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2006-2026 The QElectroTech Team
|
||||||
|
This file is part of QElectroTech.
|
||||||
|
|
||||||
|
QElectroTech 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.
|
||||||
|
|
||||||
|
QElectroTech is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RENUMBERELEMENTSDIALOG_H
|
||||||
|
#define RENUMBERELEMENTSDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
class QComboBox;
|
||||||
|
class QRadioButton;
|
||||||
|
class QDialogButtonBox;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Simple dialog to pick renumbering scope for elements.
|
||||||
|
*
|
||||||
|
* The user can choose between:
|
||||||
|
* - all element autonumbering schemes
|
||||||
|
* - one selected scheme title
|
||||||
|
*/
|
||||||
|
class RenumberElementsDialog final : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit RenumberElementsDialog(const QStringList &scheme_titles, QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Empty string if "all" is selected, otherwise the chosen scheme title.
|
||||||
|
*/
|
||||||
|
QString selectedSchemeTitle() const;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void updateUi();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStringList m_scheme_titles;
|
||||||
|
QRadioButton *m_all_rb = nullptr;
|
||||||
|
QRadioButton *m_one_rb = nullptr;
|
||||||
|
QComboBox *m_combo = nullptr;
|
||||||
|
QDialogButtonBox *m_buttons = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // RENUMBERELEMENTSDIALOG_H
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2006-2026 The QElectroTech Team
|
||||||
|
This file is part of QElectroTech.
|
||||||
|
|
||||||
|
QElectroTech 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.
|
||||||
|
|
||||||
|
QElectroTech is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef BORDERCELLLABELS_H
|
||||||
|
#define BORDERCELLLABELS_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
/// The labels the border of a folio writes on its rows and columns, shared
|
||||||
|
/// by BorderTitleBlock::draw() and the cell rulers of DiagramView so the
|
||||||
|
/// two cannot disagree. Header-only so it can be unit-tested directly --
|
||||||
|
/// see tests/qttest/tst_bordercelllabels.cpp.
|
||||||
|
namespace BorderCellLabels {
|
||||||
|
|
||||||
|
/// @return the label of row \a row, counted from 1: A..Z, then AA, AB...
|
||||||
|
/// (the sequence BorderTitleBlock::incrementLetters() walks through).
|
||||||
|
inline QString rowLabel(int row)
|
||||||
|
{
|
||||||
|
QString label;
|
||||||
|
while (row > 0) {
|
||||||
|
--row;
|
||||||
|
label.prepend(QChar('A' + row % 26));
|
||||||
|
row /= 26;
|
||||||
|
}
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @return the label of column \a column, counted from 1. When
|
||||||
|
/// \a starts_at_zero (the "border-columns_0" setting) the first column
|
||||||
|
/// is labelled 0.
|
||||||
|
inline QString columnLabel(int column, bool starts_at_zero)
|
||||||
|
{
|
||||||
|
return QString::number(starts_at_zero ? column - 1 : column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BORDERCELLLABELS_H
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "bordertitleblock.h"
|
#include "bordertitleblock.h"
|
||||||
|
|
||||||
|
#include "bordercelllabels.h"
|
||||||
#include "createdxf.h"
|
#include "createdxf.h"
|
||||||
#include "diagram.h"
|
#include "diagram.h"
|
||||||
#include "diagramposition.h"
|
#include "diagramposition.h"
|
||||||
@@ -29,6 +30,7 @@
|
|||||||
|
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
#include <QRegularExpression>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#define MIN_COLUMN_COUNT 3
|
#define MIN_COLUMN_COUNT 3
|
||||||
@@ -533,6 +535,8 @@ void BorderTitleBlock::draw(QPainter *painter)
|
|||||||
|
|
||||||
//Draw the nums of columns
|
//Draw the nums of columns
|
||||||
if (display_border_ && display_columns_) {
|
if (display_border_ && display_columns_) {
|
||||||
|
const bool columns_start_at_zero =
|
||||||
|
settings.value("border-columns_0", true).toBool();
|
||||||
for (int i = 1 ; i <= columns_count_ ; ++ i) {
|
for (int i = 1 ; i <= columns_count_ ; ++ i) {
|
||||||
QRectF numbered_rectangle = QRectF(
|
QRectF numbered_rectangle = QRectF(
|
||||||
diagram_rect_.topLeft().x()
|
diagram_rect_.topLeft().x()
|
||||||
@@ -543,23 +547,15 @@ void BorderTitleBlock::draw(QPainter *painter)
|
|||||||
columns_header_height_
|
columns_header_height_
|
||||||
);
|
);
|
||||||
painter -> drawRect(numbered_rectangle);
|
painter -> drawRect(numbered_rectangle);
|
||||||
if (settings.value("border-columns_0", true).toBool()){
|
|
||||||
painter -> drawText(numbered_rectangle,
|
painter -> drawText(numbered_rectangle,
|
||||||
Qt::AlignVCenter
|
Qt::AlignVCenter
|
||||||
| Qt::AlignCenter,
|
| Qt::AlignCenter,
|
||||||
QString("%1").arg(i - 1));
|
BorderCellLabels::columnLabel(i, columns_start_at_zero));
|
||||||
}else{
|
|
||||||
painter -> drawText(numbered_rectangle,
|
|
||||||
Qt::AlignVCenter
|
|
||||||
| Qt::AlignCenter,
|
|
||||||
QString("%1").arg(i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Draw the nums of rows
|
//Draw the nums of rows
|
||||||
if (display_border_ && display_rows_) {
|
if (display_border_ && display_rows_) {
|
||||||
QString row_string("A");
|
|
||||||
for (int i = 1 ; i <= rows_count_ ; ++ i) {
|
for (int i = 1 ; i <= rows_count_ ; ++ i) {
|
||||||
QRectF lettered_rectangle = QRectF(
|
QRectF lettered_rectangle = QRectF(
|
||||||
diagram_rect_.topLeft().x(),
|
diagram_rect_.topLeft().x(),
|
||||||
@@ -575,8 +571,7 @@ void BorderTitleBlock::draw(QPainter *painter)
|
|||||||
painter -> drawText(lettered_rectangle,
|
painter -> drawText(lettered_rectangle,
|
||||||
Qt::AlignVCenter
|
Qt::AlignVCenter
|
||||||
| Qt::AlignCenter,
|
| Qt::AlignCenter,
|
||||||
row_string);
|
BorderCellLabels::rowLabel(i));
|
||||||
row_string = incrementLetters(row_string);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -935,6 +930,46 @@ void BorderTitleBlock::updateDiagramContextForTitleBlock(
|
|||||||
m_titleblock_template_renderer -> setContext(context);
|
m_titleblock_template_renderer -> setContext(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief BorderTitleBlock::cellRect
|
||||||
|
Convert a cell written the way the border labels it (ex : B13, the row
|
||||||
|
letter(s) then the column number) to its rect in scene coordinate.
|
||||||
|
This is the reverse of convertPosition().
|
||||||
|
@param cell : the cell to convert, case and surrounding spaces ignored
|
||||||
|
@return the rect of the cell, or a null QRectF if \a cell is not a
|
||||||
|
cell reference or lies outside of the border.
|
||||||
|
*/
|
||||||
|
QRectF BorderTitleBlock::cellRect(const QString &cell) const
|
||||||
|
{
|
||||||
|
static const QRegularExpression cell_re(
|
||||||
|
QStringLiteral("^\\s*([A-Za-z]+)\\s*(\\d{1,4})\\s*$"));
|
||||||
|
const QRegularExpressionMatch match = cell_re.match(cell);
|
||||||
|
if (!match.hasMatch())
|
||||||
|
return QRectF();
|
||||||
|
|
||||||
|
//Row letters count like A..Z, AA, AB... (see incrementLetters())
|
||||||
|
int row = 0;
|
||||||
|
for (const QChar c : match.captured(1).toUpper()) {
|
||||||
|
row = row * 26 + (c.unicode() - 'A' + 1);
|
||||||
|
if (row > rows_count_)
|
||||||
|
return QRectF();
|
||||||
|
}
|
||||||
|
|
||||||
|
int column = match.captured(2).toInt();
|
||||||
|
QSettings settings;
|
||||||
|
if (settings.value("border-columns_0", true).toBool())
|
||||||
|
++column;
|
||||||
|
|
||||||
|
if (row < 1 || column < 1 || column > columns_count_)
|
||||||
|
return QRectF();
|
||||||
|
|
||||||
|
const QPointF top_left = insideBorderRect().topLeft();
|
||||||
|
return QRectF(top_left.x() + (column - 1) * columns_width_,
|
||||||
|
top_left.y() + (row - 1) * rows_height_,
|
||||||
|
columns_width_,
|
||||||
|
rows_height_);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief BorderTitleBlock::incrementLetters
|
@brief BorderTitleBlock::incrementLetters
|
||||||
increments string with Letters A to Z
|
increments string with Letters A to Z
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ class BorderTitleBlock : public QObject
|
|||||||
void setDiagramHeight(const qreal &);
|
void setDiagramHeight(const qreal &);
|
||||||
|
|
||||||
DiagramPosition convertPosition(const QPointF &);
|
DiagramPosition convertPosition(const QPointF &);
|
||||||
|
QRectF cellRect(const QString &cell) const;
|
||||||
|
|
||||||
// methods to set title block basic data
|
// methods to set title block basic data
|
||||||
void setFolio(const QString &folio);
|
void setFolio(const QString &folio);
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2006-2026 The QElectroTech Team
|
||||||
|
This file is part of QElectroTech.
|
||||||
|
|
||||||
|
QElectroTech 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.
|
||||||
|
|
||||||
|
QElectroTech is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "cellruler.h"
|
||||||
|
|
||||||
|
#include "bordercelllabels.h"
|
||||||
|
#include "diagram.h"
|
||||||
|
#include "diagramview.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief CellRuler::CellRuler
|
||||||
|
@param orientation : Qt::Horizontal for the column numbers along the
|
||||||
|
top, Qt::Vertical for the row letters along the left
|
||||||
|
@param view : the view this ruler is placed on
|
||||||
|
*/
|
||||||
|
CellRuler::CellRuler(Qt::Orientation orientation, DiagramView *view) :
|
||||||
|
QWidget(view),
|
||||||
|
m_orientation(orientation),
|
||||||
|
m_view(view)
|
||||||
|
{
|
||||||
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief CellRuler::thickness
|
||||||
|
@return the height of the top ruler, which is also the width of the
|
||||||
|
side ruler, so the corner they share is square. Constant whatever the
|
||||||
|
zoom.
|
||||||
|
*/
|
||||||
|
int CellRuler::thickness() const
|
||||||
|
{
|
||||||
|
const QFontMetrics metrics = fontMetrics();
|
||||||
|
return qMax(metrics.height(), metrics.horizontalAdvance(QStringLiteral("WW"))) + 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief CellRuler::setLeadingSpace
|
||||||
|
@param space : pixels left empty before the first pixel of the
|
||||||
|
viewport, along this ruler
|
||||||
|
*/
|
||||||
|
void CellRuler::setLeadingSpace(int space)
|
||||||
|
{
|
||||||
|
m_leading_space = space;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief CellRuler::paintEvent
|
||||||
|
Draw a cell for each column (or row) of the folio border, at the
|
||||||
|
position the view shows it. When the cells get too small for their
|
||||||
|
labels, only one label every 2, 5, 10... cells is written.
|
||||||
|
*/
|
||||||
|
void CellRuler::paintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event)
|
||||||
|
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.fillRect(rect(), palette().color(QPalette::Button));
|
||||||
|
|
||||||
|
const bool horizontal = m_orientation == Qt::Horizontal;
|
||||||
|
const int length = horizontal ? width() : height();
|
||||||
|
const int depth = horizontal ? height() : width();
|
||||||
|
|
||||||
|
//Separate the ruler from the drawing
|
||||||
|
painter.setPen(palette().color(QPalette::Dark));
|
||||||
|
if (horizontal) {
|
||||||
|
painter.drawLine(0, depth - 1, length, depth - 1);
|
||||||
|
} else {
|
||||||
|
painter.drawLine(depth - 1, 0, depth - 1, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Diagram *diagram = m_view->diagram();
|
||||||
|
if (!diagram) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const BorderTitleBlock &border = diagram->border_and_titleblock;
|
||||||
|
const QRectF inside = border.insideBorderRect();
|
||||||
|
const QTransform transform = m_view->viewportTransform();
|
||||||
|
|
||||||
|
const int count = horizontal ? border.columnsCount() : border.rowsCount();
|
||||||
|
const qreal cell_size = horizontal ? border.columnsWidth() : border.rowsHeight();
|
||||||
|
const qreal first = horizontal ? inside.left() : inside.top();
|
||||||
|
const qreal scale = horizontal ? transform.m11() : transform.m22();
|
||||||
|
const qreal offset = (horizontal ? transform.dx() : transform.dy()) + m_leading_space;
|
||||||
|
const qreal cell_pixels = cell_size * scale;
|
||||||
|
if (count < 1 || cell_pixels <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool columns_start_at_zero =
|
||||||
|
QSettings().value("border-columns_0", true).toBool();
|
||||||
|
auto label = [&](int index) {
|
||||||
|
return horizontal ? BorderCellLabels::columnLabel(index, columns_start_at_zero)
|
||||||
|
: BorderCellLabels::rowLabel(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Room one label needs along the ruler, and the smallest step
|
||||||
|
//between written labels that gives it that room
|
||||||
|
const QFontMetrics metrics = fontMetrics();
|
||||||
|
const int label_room = horizontal
|
||||||
|
? metrics.horizontalAdvance(label(count)) + 6
|
||||||
|
: metrics.height() + 2;
|
||||||
|
int step = 1;
|
||||||
|
for (int candidate : {1, 2, 5, 10, 20, 50, 100, 200, 500}) {
|
||||||
|
step = candidate;
|
||||||
|
if (candidate * cell_pixels >= label_room) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1 ; i <= count ; ++i) {
|
||||||
|
const qreal start = offset + (first + (i - 1) * cell_size) * scale;
|
||||||
|
const qreal end = start + cell_pixels;
|
||||||
|
if (end < m_leading_space || start > length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Cell edges, drawn only when the cells are wide enough
|
||||||
|
//for them to read as cells rather than as a hatching
|
||||||
|
painter.setPen(palette().color(QPalette::Dark));
|
||||||
|
if (cell_pixels >= 4) {
|
||||||
|
if (horizontal) {
|
||||||
|
painter.drawLine(QPointF(start, 0), QPointF(start, depth - 1));
|
||||||
|
if (i == count) painter.drawLine(QPointF(end, 0), QPointF(end, depth - 1));
|
||||||
|
} else {
|
||||||
|
painter.drawLine(QPointF(0, start), QPointF(depth - 1, start));
|
||||||
|
if (i == count) painter.drawLine(QPointF(0, end), QPointF(depth - 1, end));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Written labels are the ones a multiple of step: 0, 5, 10...
|
||||||
|
//for the columns, A, F, K... for the rows
|
||||||
|
const int position = (horizontal && !columns_start_at_zero) ? i : i - 1;
|
||||||
|
if (position % step != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
painter.setPen(palette().color(QPalette::ButtonText));
|
||||||
|
const qreal centre = (start + end) / 2;
|
||||||
|
const QRectF text_rect = horizontal
|
||||||
|
? QRectF(centre - label_room / 2.0, 0, label_room, depth - 1)
|
||||||
|
: QRectF(0, centre - label_room / 2.0, depth - 1, label_room);
|
||||||
|
painter.drawText(text_rect, Qt::AlignCenter | Qt::TextDontClip, label(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Keep the corner empty: the other ruler's labels do not belong there
|
||||||
|
if (m_leading_space > 0) {
|
||||||
|
painter.fillRect(horizontal ? QRect(0, 0, m_leading_space, depth - 1)
|
||||||
|
: QRect(0, 0, depth - 1, m_leading_space),
|
||||||
|
palette().color(QPalette::Button));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2006-2026 The QElectroTech Team
|
||||||
|
This file is part of QElectroTech.
|
||||||
|
|
||||||
|
QElectroTech 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.
|
||||||
|
|
||||||
|
QElectroTech is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef CELLRULER_H
|
||||||
|
#define CELLRULER_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class DiagramView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief The CellRuler class
|
||||||
|
A bar along the top or the left edge of a DiagramView that repeats the
|
||||||
|
column numbers or the row letters of the folio border, aligned with the
|
||||||
|
cells at any zoom, so they stay in sight however far the view is
|
||||||
|
scrolled. It sits in the view's margins, outside of the scene: printing
|
||||||
|
and exporting are unaffected.
|
||||||
|
*/
|
||||||
|
class CellRuler : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
CellRuler(Qt::Orientation orientation, DiagramView *view);
|
||||||
|
|
||||||
|
int thickness() const;
|
||||||
|
void setLeadingSpace(int space);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Qt::Orientation m_orientation;
|
||||||
|
DiagramView *m_view;
|
||||||
|
/// Pixels before the viewport starts, left empty: the corner the
|
||||||
|
/// side ruler fills when both rulers are shown.
|
||||||
|
int m_leading_space = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CELLRULER_H
|
||||||
@@ -227,6 +227,7 @@ int exportPdf(QETProject &project, const QString &output,
|
|||||||
// Rewrite the URI link annotations into native internal GoTo actions, so
|
// Rewrite the URI link annotations into native internal GoTo actions, so
|
||||||
// the cross-references jump inside the document in any PDF viewer.
|
// the cross-references jump inside the document in any PDF viewer.
|
||||||
PdfLinks::convertUriToGoTo(output);
|
PdfLinks::convertUriToGoTo(output);
|
||||||
|
PdfLinks::removeUnusedPdfxNamespace(output);
|
||||||
|
|
||||||
out << "Exported " << diagrams.size() << " page(s) -> " << output << "\n";
|
out << "Exported " << diagrams.size() << " page(s) -> " << output << "\n";
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -319,10 +319,23 @@ void projectDataBase::addElement(Element *element)
|
|||||||
void projectDataBase::removeElement(Element *element)
|
void projectDataBase::removeElement(Element *element)
|
||||||
{
|
{
|
||||||
m_content_changed = true;
|
m_content_changed = true;
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
m_remove_element_query.bindValue(":uuid", element->uuid().toString());
|
m_remove_element_query.bindValue(":uuid", element->uuid().toString());
|
||||||
if(!m_remove_element_query.exec()) {
|
if (m_remove_element_query.exec()) {
|
||||||
qDebug() << "projectDataBase::removeElement remove error : " << m_remove_element_query.lastError();
|
changed = true;
|
||||||
} else {
|
} else {
|
||||||
|
qDebug() << "projectDataBase::removeElement remove error : " << m_remove_element_query.lastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_remove_element_info_query.bindValue(":uuid", element->uuid().toString());
|
||||||
|
if (m_remove_element_info_query.exec()) {
|
||||||
|
changed = true;
|
||||||
|
} else {
|
||||||
|
qDebug() << "projectDataBase::removeElement remove element_info error : " << m_remove_element_info_query.lastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
emit dataBaseUpdated();
|
emit dataBaseUpdated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1159,6 +1172,21 @@ void projectDataBase::prepareQuery()
|
|||||||
m_remove_element_query = QSqlQuery(m_data_base);
|
m_remove_element_query = QSqlQuery(m_data_base);
|
||||||
m_remove_element_query.prepare(remove_element);
|
m_remove_element_query.prepare(remove_element);
|
||||||
|
|
||||||
|
//REMOVE ELEMENT INFO
|
||||||
|
//element_info has no ON DELETE CASCADE (foreign keys aren't
|
||||||
|
//enforced by this connection), so removeElement() must clear it
|
||||||
|
//explicitly. Without this, the row is orphaned under the removed
|
||||||
|
//element's uuid, and re-adding an element with that same uuid
|
||||||
|
//later -- undo of this same removal, or a redo replaying it --
|
||||||
|
//hits element_info's PRIMARY KEY constraint on element_uuid: the
|
||||||
|
//element re-add succeeds, but its element_info insert silently
|
||||||
|
//fails and is lost. removeDiagram()'s cascade already clears this
|
||||||
|
//table when a whole folio goes, but that does not run for a
|
||||||
|
//single element removed on its own.
|
||||||
|
QString remove_element_info("DELETE FROM element_info WHERE element_uuid=:uuid");
|
||||||
|
m_remove_element_info_query = QSqlQuery(m_data_base);
|
||||||
|
m_remove_element_info_query.prepare(remove_element_info);
|
||||||
|
|
||||||
//UPDATE ELEMENT INFO
|
//UPDATE ELEMENT INFO
|
||||||
QString update_str("UPDATE element_info SET ");
|
QString update_str("UPDATE element_info SET ");
|
||||||
for (auto string : QETInformation::elementInfoKeys()) {
|
for (auto string : QETInformation::elementInfoKeys()) {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class QETProject;
|
|||||||
class Diagram;
|
class Diagram;
|
||||||
class Conductor;
|
class Conductor;
|
||||||
class Terminal;
|
class Terminal;
|
||||||
class sqlite3;
|
struct sqlite3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief The projectDataBase class
|
@brief The projectDataBase class
|
||||||
@@ -139,6 +139,7 @@ class projectDataBase : public QObject
|
|||||||
QSqlQuery m_insert_elements_query,
|
QSqlQuery m_insert_elements_query,
|
||||||
m_insert_element_info_query,
|
m_insert_element_info_query,
|
||||||
m_remove_element_query,
|
m_remove_element_query,
|
||||||
|
m_remove_element_info_query,
|
||||||
m_update_element_query,
|
m_update_element_query,
|
||||||
m_insert_diagram_query,
|
m_insert_diagram_query,
|
||||||
m_remove_diagram_query,
|
m_remove_diagram_query,
|
||||||
|
|||||||
+76
-30
@@ -42,7 +42,10 @@
|
|||||||
#include "qetinformation.h"
|
#include "qetinformation.h"
|
||||||
#include "qetproject.h"
|
#include "qetproject.h"
|
||||||
#include "diagramsortkeys.h"
|
#include "diagramsortkeys.h"
|
||||||
|
#include "textgrid.h"
|
||||||
|
#include <QTextStream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <climits>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
@@ -99,6 +102,43 @@ namespace {
|
|||||||
QString b = terminalSortKey(cond->terminal2);
|
QString b = terminalSortKey(cond->terminal2);
|
||||||
return (a <= b) ? (a + QLatin1Char('>') + b) : (b + QLatin1Char('>') + a);
|
return (a <= b) ? (a + QLatin1Char('>') + b) : (b + QLatin1Char('>') + a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serialize @p items and append them to a new @p tag block of @p root,
|
||||||
|
/// in stacking order (@p stack_rank). items() cannot be trusted for
|
||||||
|
/// this: with NoIndex, the first removeItem() on the scene sorts Qt's
|
||||||
|
/// item list by pointer address, so from then on items() hands them over
|
||||||
|
/// in a per-run order (bugtracker #343). Stacking order is what reloading
|
||||||
|
/// the file rebuilds, so the drawing is unchanged and a resave is stable.
|
||||||
|
template <typename T>
|
||||||
|
void appendInStackingOrder(QDomDocument &document, QDomElement &root,
|
||||||
|
const QString &tag, const QVector<T *> &items,
|
||||||
|
const QHash<const QGraphicsItem *, int> &stack_rank)
|
||||||
|
{
|
||||||
|
if (items.isEmpty())
|
||||||
|
return;
|
||||||
|
struct Entry { int rank; QString xml_text; QDomElement xml; };
|
||||||
|
QVector<Entry> sorted;
|
||||||
|
for (T *item : items) {
|
||||||
|
Entry entry{stack_rank.value(item, INT_MAX), QString(),
|
||||||
|
item->toXml(document)};
|
||||||
|
// Only an item the stacking query missed needs a tiebreak.
|
||||||
|
if (entry.rank == INT_MAX) {
|
||||||
|
QTextStream stream(&entry.xml_text);
|
||||||
|
entry.xml.save(stream, 0);
|
||||||
|
}
|
||||||
|
sorted.append(entry);
|
||||||
|
}
|
||||||
|
std::stable_sort(sorted.begin(), sorted.end(),
|
||||||
|
[](const Entry &a, const Entry &b) {
|
||||||
|
return a.rank != b.rank ? a.rank < b.rank
|
||||||
|
: a.xml_text < b.xml_text;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto block = document.createElement(tag);
|
||||||
|
for (const auto &entry : sorted)
|
||||||
|
block.appendChild(entry.xml);
|
||||||
|
root.appendChild(block);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Diagram::xGrid = 10;
|
int Diagram::xGrid = 10;
|
||||||
@@ -1223,37 +1263,20 @@ QDomDocument Diagram::toXml(bool whole_content, bool is_copy_command) {
|
|||||||
dom_root.appendChild(dom_conductors);
|
dom_root.appendChild(dom_conductors);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!list_texts.isEmpty()) {
|
// A rect query, unlike items(), returns true stacking order (z, then
|
||||||
auto dom_texts = document.createElement(QStringLiteral("inputs"));
|
// insertion order) even with NoIndex.
|
||||||
for (auto dti : list_texts) {
|
QHash<const QGraphicsItem *, int> stack_rank;
|
||||||
dom_texts.appendChild(dti->toXml(document));
|
{
|
||||||
}
|
const QList<QGraphicsItem *> stacked = items(
|
||||||
dom_root.appendChild(dom_texts);
|
QRectF(-1e9, -1e9, 2e9, 2e9), Qt::IntersectsItemBoundingRect,
|
||||||
}
|
Qt::AscendingOrder);
|
||||||
|
for (int i = 0 ; i < stacked.size() ; ++i)
|
||||||
if (!list_images.isEmpty()) {
|
stack_rank.insert(stacked.at(i), i);
|
||||||
auto dom_images = document.createElement(QStringLiteral("images"));
|
|
||||||
for (auto dii : list_images) {
|
|
||||||
dom_images.appendChild(dii->toXml(document));
|
|
||||||
}
|
|
||||||
dom_root.appendChild(dom_images);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!list_shapes.isEmpty()) {
|
|
||||||
auto dom_shapes = document.createElement(QStringLiteral("shapes"));
|
|
||||||
for (auto dii : list_shapes) {
|
|
||||||
dom_shapes.appendChild(dii -> toXml(document));
|
|
||||||
}
|
|
||||||
dom_root.appendChild(dom_shapes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (table_vector.size()) {
|
|
||||||
auto tables = document.createElement(QStringLiteral("tables"));
|
|
||||||
for (auto table : table_vector) {
|
|
||||||
tables.appendChild(table->toXml(document));
|
|
||||||
}
|
|
||||||
dom_root.appendChild(tables);
|
|
||||||
}
|
}
|
||||||
|
appendInStackingOrder(document, dom_root, QStringLiteral("inputs"), list_texts, stack_rank);
|
||||||
|
appendInStackingOrder(document, dom_root, QStringLiteral("images"), list_images, stack_rank);
|
||||||
|
appendInStackingOrder(document, dom_root, QStringLiteral("shapes"), list_shapes, stack_rank);
|
||||||
|
appendInStackingOrder(document, dom_root, QStringLiteral("tables"), table_vector, stack_rank);
|
||||||
|
|
||||||
if (!strip_vector.isEmpty()) {
|
if (!strip_vector.isEmpty()) {
|
||||||
dom_root.appendChild(TerminalStripItemXml::toXml(strip_vector, document));
|
dom_root.appendChild(TerminalStripItemXml::toXml(strip_vector, document));
|
||||||
@@ -2662,6 +2685,29 @@ QPointF Diagram::snapToGrid(const QPointF &p)
|
|||||||
return (QPointF(p_x, p_y));
|
return (QPointF(p_x, p_y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Diagram::snapToTextGrid
|
||||||
|
Return the nearest point of p on the text grid, see TextGrid.
|
||||||
|
Ctrl held rounds to the nearest pixel instead, as snapToGrid() does.
|
||||||
|
@param p point to find the nearest snapped point
|
||||||
|
@return
|
||||||
|
*/
|
||||||
|
QPointF Diagram::snapToTextGrid(const QPointF &p)
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
const qreal divisor =
|
||||||
|
QApplication::keyboardModifiers().testFlag(Qt::ControlModifier)
|
||||||
|
? 0
|
||||||
|
: settings.value(TextGrid::settings_key, 1).toReal();
|
||||||
|
|
||||||
|
return TextGrid::snap(p,
|
||||||
|
settings.value(QStringLiteral("diagrameditor/Xgrid"),
|
||||||
|
Diagram::xGrid).toInt(),
|
||||||
|
settings.value(QStringLiteral("diagrameditor/Ygrid"),
|
||||||
|
Diagram::yGrid).toInt(),
|
||||||
|
divisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -233,6 +233,7 @@ class Diagram : public QGraphicsScene
|
|||||||
BorderOptions borderOptions();
|
BorderOptions borderOptions();
|
||||||
DiagramPosition convertPosition(const QPointF &);
|
DiagramPosition convertPosition(const QPointF &);
|
||||||
static QPointF snapToGrid(const QPointF &p);
|
static QPointF snapToGrid(const QPointF &p);
|
||||||
|
static QPointF snapToTextGrid(const QPointF &p);
|
||||||
|
|
||||||
bool drawTerminals() const;
|
bool drawTerminals() const;
|
||||||
void setDrawTerminals(bool);
|
void setDrawTerminals(bool);
|
||||||
|
|||||||
@@ -77,6 +77,23 @@ void PasteDiagramCommand::redo()
|
|||||||
{
|
{
|
||||||
first_redo = false;
|
first_redo = false;
|
||||||
|
|
||||||
|
//Resolve a linked master/slave pair pasted together (bugtracker
|
||||||
|
//#607) before anything below renews their uuids: at this exact
|
||||||
|
//moment a pasted element's tmp_uuids_link still holds its
|
||||||
|
//source's original partner uuid, which still equals the
|
||||||
|
//not-yet-renewed uuid of that partner's own pasted copy if it
|
||||||
|
//was carried along in the same batch. Scoped to this batch only
|
||||||
|
//(not a project-wide search), so a pair pasted together links to
|
||||||
|
//each other and not to an original element left elsewhere that
|
||||||
|
//happens to still carry that same soon-to-be-replaced uuid. If
|
||||||
|
//only one half of a linked group was pasted, its link entry
|
||||||
|
//simply finds no match here and is dropped -- same "leave it
|
||||||
|
//unlinked" outcome as always.
|
||||||
|
const QList <Element *> elmts_list = content.m_elements;
|
||||||
|
for (Element *e : elmts_list) {
|
||||||
|
e->initLink(elmts_list);
|
||||||
|
}
|
||||||
|
|
||||||
//make new uuid for every pasted conductor, because old uuid are
|
//make new uuid for every pasted conductor, because old uuid are
|
||||||
//the uuid of the copied conductor
|
//the uuid of the copied conductor
|
||||||
const QList <Conductor *> all_pasted_conductors = content.conductors();
|
const QList <Conductor *> all_pasted_conductors = content.conductors();
|
||||||
@@ -85,7 +102,6 @@ void PasteDiagramCommand::redo()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//this is the first paste, we do some actions for the new element
|
//this is the first paste, we do some actions for the new element
|
||||||
const QList <Element *> elmts_list = content.m_elements;
|
|
||||||
for (Element *e : elmts_list)
|
for (Element *e : elmts_list)
|
||||||
{
|
{
|
||||||
//make new uuid, because old uuid are the uuid of the copied element
|
//make new uuid, because old uuid are the uuid of the copied element
|
||||||
|
|||||||
@@ -117,7 +117,16 @@ void DiagramEventAddImage::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
|||||||
}
|
}
|
||||||
else if (m_image && !m_pressed && event->button() == Qt::RightButton)
|
else if (m_image && !m_pressed && event->button() == Qt::RightButton)
|
||||||
{
|
{
|
||||||
m_image->setRotation(m_image->rotation() + 90);
|
// rotationAngle()/setRotationAngle(), not QGraphicsItem's own
|
||||||
|
// rotation()/setRotation(): DiagramImageItem's whole handle/undo/
|
||||||
|
// XML-save machinery reads exclusively from its own m_transform
|
||||||
|
// (see diagramimageitem.cpp's toXml() comment) and never looks at
|
||||||
|
// QGraphicsItem's built-in convenience property at all -- using
|
||||||
|
// it here left a rotation that displayed correctly in this tool
|
||||||
|
// but silently vanished the moment the item was saved and
|
||||||
|
// reloaded, and additionally desynced the rotate-handle's pivot
|
||||||
|
// math once the image was later selected for editing.
|
||||||
|
m_image->setRotationAngle(m_image->rotationAngle() + 90);
|
||||||
event->setAccepted(true);
|
event->setAccepted(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,6 +176,22 @@ void DiagramEventAddImage::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// setPivot(QPointF(0, 0)), not left at its default
|
||||||
|
// boundingRect().center(): DiagramImageItem's own m_transform
|
||||||
|
// is pivot-centered, so with the default center pivot the
|
||||||
|
// setPos(qMin(...)) below would no longer land on the image's
|
||||||
|
// actual top-left corner the moment scale != 1 (the corner
|
||||||
|
// only coincides with pos() when the pivot is the local
|
||||||
|
// origin). Anchoring here to (0, 0) -- exactly the same
|
||||||
|
// temporary-anchor trick DiagramImageItem::handlerMousePressEvent()
|
||||||
|
// already uses for its own Resize handles -- makes pos()
|
||||||
|
// keep meaning "scene position of the top-left corner"
|
||||||
|
// regardless of scale, so the qMin(...) line below still
|
||||||
|
// needs no change at all. setPivot() itself is a no-op past
|
||||||
|
// the first call (same pivot value), and compensates pos()
|
||||||
|
// automatically so nothing visibly jumps at the switch.
|
||||||
|
m_image->setPivot(QPointF(0, 0));
|
||||||
|
|
||||||
const QSizeF naturalSize = m_image->boundingRect().size();
|
const QSizeF naturalSize = m_image->boundingRect().size();
|
||||||
if (naturalSize.width() > 0 && naturalSize.height() > 0)
|
if (naturalSize.width() > 0 && naturalSize.height() > 0)
|
||||||
{
|
{
|
||||||
@@ -179,7 +204,12 @@ void DiagramEventAddImage::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
|||||||
// free-form one -- breaking aspect ratio on purpose is
|
// free-form one -- breaking aspect ratio on purpose is
|
||||||
// its own, separate, larger piece of work.
|
// its own, separate, larger piece of work.
|
||||||
const qreal newScale = qBound(0.01, qMax(scaleX, scaleY), 50.0);
|
const qreal newScale = qBound(0.01, qMax(scaleX, scaleY), 50.0);
|
||||||
m_image->setScale(newScale);
|
// scaleFactorX()/scaleFactorY(), not QGraphicsItem's own
|
||||||
|
// scale(): see the mousePressEvent right-click rotate
|
||||||
|
// comment above for why -- identical reasoning, identical
|
||||||
|
// fix.
|
||||||
|
m_image->setScaleFactorX(newScale);
|
||||||
|
m_image->setScaleFactorY(newScale);
|
||||||
}
|
}
|
||||||
m_image->setPos(qMin(m_press_pos.x(), pos.x()), qMin(m_press_pos.y(), pos.y()));
|
m_image->setPos(qMin(m_press_pos.x(), pos.x()), qMin(m_press_pos.y(), pos.y()));
|
||||||
}
|
}
|
||||||
@@ -206,6 +236,17 @@ void DiagramEventAddImage::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
|||||||
{
|
{
|
||||||
if (m_image && m_pressed && event->button() == Qt::LeftButton)
|
if (m_image && m_pressed && event->button() == Qt::LeftButton)
|
||||||
{
|
{
|
||||||
|
// Undo whatever temporary origin-anchoring mouseMoveEvent's
|
||||||
|
// resize-drag branch did (a no-op if it never engaged): every
|
||||||
|
// other DiagramImageItem code path -- handles, undo, XML save --
|
||||||
|
// expects an image's pivot to be its bounding-rect center unless
|
||||||
|
// the user deliberately customized it, exactly like a completed
|
||||||
|
// handle-resize already resets it via resetPivotToBoundingRectCenter().
|
||||||
|
// Doing this before reading pos() below is what makes the pushed
|
||||||
|
// command capture the final, center-pivot position rather than
|
||||||
|
// the drag's temporary corner-anchored one.
|
||||||
|
m_image->setPivot(m_image->boundingRect().center());
|
||||||
|
|
||||||
m_diagram->undoStack().push(new AddGraphicsObjectCommand(m_image, m_diagram, m_image->pos()));
|
m_diagram->undoStack().push(new AddGraphicsObjectCommand(m_image, m_diagram, m_image->pos()));
|
||||||
|
|
||||||
for (QGraphicsView *view : m_diagram->views()) {
|
for (QGraphicsView *view : m_diagram->views()) {
|
||||||
@@ -246,10 +287,32 @@ void DiagramEventAddImage::wheelEvent(QGraphicsSceneWheelEvent *event)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qreal scaling = m_image->scale();
|
// scaleFactorX()/scaleFactorY(), not QGraphicsItem's own scale(): see
|
||||||
event->delta() > 1? scaling += 0.01 : scaling -= 0.01;
|
// the right-click rotate comment in mousePressEvent for why. Wheel-
|
||||||
if (scaling>0.01 && scaling <= 2) {
|
// scaling only ever runs while !m_pressed (guarded above), i.e. before
|
||||||
m_image->setScale(scaling);
|
// any drag-resize has anchored the pivot to the origin (see
|
||||||
|
// mouseMoveEvent), so the pivot here is still the default
|
||||||
|
// boundingRect().center() and this scales the image in place around
|
||||||
|
// its own middle, exactly like before.
|
||||||
|
//
|
||||||
|
// Step each axis from its own current value rather than reading X and
|
||||||
|
// writing it back to both: scaleFactorX and scaleFactorY cannot
|
||||||
|
// actually differ at this point today (every other mutator in this
|
||||||
|
// class -- the drag-resize branch above, and this same wheelEvent --
|
||||||
|
// only ever sets them to the same value, and mouseReleaseEvent commits
|
||||||
|
// and ends this tool on any left-button release, so a handle-based
|
||||||
|
// non-uniform resize can never happen first and leave this instance
|
||||||
|
// still alive). Stepping both from their own value rather than
|
||||||
|
// collapsing Y to X costs nothing today and removes the trap if that
|
||||||
|
// invariant ever stops holding.
|
||||||
|
qreal scalingX = m_image->scaleFactorX();
|
||||||
|
qreal scalingY = m_image->scaleFactorY();
|
||||||
|
const qreal step = event->delta() > 1 ? 0.01 : -0.01;
|
||||||
|
scalingX += step;
|
||||||
|
scalingY += step;
|
||||||
|
if (scalingX > 0.01 && scalingX <= 2 && scalingY > 0.01 && scalingY <= 2) {
|
||||||
|
m_image->setScaleFactorX(scalingX);
|
||||||
|
m_image->setScaleFactorY(scalingY);
|
||||||
}
|
}
|
||||||
|
|
||||||
event->setAccepted(true);
|
event->setAccepted(true);
|
||||||
|
|||||||
@@ -41,7 +41,6 @@
|
|||||||
DiagramEventAddPaste::DiagramEventAddPaste(Diagram *diagram, const QPointF &start_pos) :
|
DiagramEventAddPaste::DiagramEventAddPaste(Diagram *diagram, const QPointF &start_pos) :
|
||||||
DiagramEventInterface(diagram)
|
DiagramEventInterface(diagram)
|
||||||
{
|
{
|
||||||
Q_UNUSED(start_pos); // items stay at their original XML position
|
|
||||||
//DiagramEventInterface::init() is called by Diagram::setEventInterface
|
//DiagramEventInterface::init() is called by Diagram::setEventInterface
|
||||||
//only when it is replacing an earlier interface, so call it here as
|
//only when it is replacing an earlier interface, so call it here as
|
||||||
//DiagramEventAddMacro does.
|
//DiagramEventAddMacro does.
|
||||||
@@ -77,21 +76,26 @@
|
|||||||
const QList<QGraphicsItem *> movable = m_content.items(MovableItems);
|
const QList<QGraphicsItem *> movable = m_content.items(MovableItems);
|
||||||
if (movable.isEmpty()) return;
|
if (movable.isEmpty()) return;
|
||||||
|
|
||||||
//Compute the top-left of all items' positions (not bounding
|
//Compute the top-left of all items' actual on-screen bounding
|
||||||
//rects) and snap to grid: this is the point that gets placed
|
//boxes (not their raw pos()) and snap to grid: this is the point
|
||||||
//under the cursor, and the baseline moveTo() measures from.
|
//that gets placed under the cursor, and the baseline moveTo()
|
||||||
QPointF top_left;
|
//measures from. mapToScene(boundingRect()) matters here, not
|
||||||
bool first = true;
|
//pos() alone: pos() is the scene location of an item's local
|
||||||
|
//origin, but for anything with a pivot-centered transform (a
|
||||||
|
//scaled or rotated image, in particular) that origin can sit far
|
||||||
|
//from where the item is actually drawn -- pivot + scale*(0 -
|
||||||
|
//pivot) is nowhere near (0, 0) once scale is well under 1. Using
|
||||||
|
//pos() here silently pasted content at the right *delta* from a
|
||||||
|
//point that wasn't actually where the content visually was,
|
||||||
|
//producing a constant, scale-dependent offset between the cursor
|
||||||
|
//and the pasted picture. Diagram::fromXml()'s own position
|
||||||
|
//parameter already gets this right the same way, for the same
|
||||||
|
//reason.
|
||||||
|
QRectF items_rect;
|
||||||
for (auto *item : movable) {
|
for (auto *item : movable) {
|
||||||
const QPointF p = item->pos();
|
items_rect = items_rect.united(item->mapToScene(item->boundingRect()).boundingRect());
|
||||||
if (first) {
|
|
||||||
top_left = p;
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
if (p.x() < top_left.x()) top_left.setX(p.x());
|
|
||||||
if (p.y() < top_left.y()) top_left.setY(p.y());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
const QPointF top_left = items_rect.topLeft();
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
const int xGrid = settings.value(QStringLiteral("diagrameditor/Xgrid"),
|
const int xGrid = settings.value(QStringLiteral("diagrameditor/Xgrid"),
|
||||||
Diagram::xGrid).toInt();
|
Diagram::xGrid).toInt();
|
||||||
@@ -102,9 +106,24 @@
|
|||||||
qRound(p.x() / xGrid) * xGrid,
|
qRound(p.x() / xGrid) * xGrid,
|
||||||
qRound(p.y() / yGrid) * yGrid);
|
qRound(p.y() / yGrid) * yGrid);
|
||||||
};
|
};
|
||||||
const QPointF grid_origin = snapGrid(top_left);
|
const QPointF grid_origin = snapGrid(start_pos);
|
||||||
|
|
||||||
//Store each item's original position. moveTo() applies a
|
//Land the pasted content under the cursor immediately, rather than
|
||||||
|
//leaving it at the copied source's own coordinates: fromXml() above
|
||||||
|
//loads items at their original position purely because it doesn't
|
||||||
|
//know the target yet, not because that is where a paste should end
|
||||||
|
//up. The previous approach instead left items there and warped the
|
||||||
|
//OS cursor to match -- QCursor::setPos() is silently ignored by
|
||||||
|
//many window managers and compositors (Wayland in particular), so
|
||||||
|
//on any of those the warp simply never happened and the paste was
|
||||||
|
//left wherever it had originally been copied from, which could be
|
||||||
|
//anywhere on the folio -- exactly the "far from the cursor" bug.
|
||||||
|
const QPointF initial_delta = grid_origin - snapGrid(top_left);
|
||||||
|
for (auto *item : movable) {
|
||||||
|
item->setPos(item->pos() + initial_delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Store each item's now-placed position. moveTo() applies a
|
||||||
//grid-snapped delta from the baseline to these, so items
|
//grid-snapped delta from the baseline to these, so items
|
||||||
//preserve their layout and move in whole grid steps.
|
//preserve their layout and move in whole grid steps.
|
||||||
for (auto *item : movable) {
|
for (auto *item : movable) {
|
||||||
@@ -134,14 +153,6 @@
|
|||||||
if (const auto qde = QETApp::diagramEditorAncestorOf(view)) {
|
if (const auto qde = QETApp::diagramEditorAncestorOf(view)) {
|
||||||
m_status_bar = qde->statusBar();
|
m_status_bar = qde->statusBar();
|
||||||
}
|
}
|
||||||
//Warp the cursor to the group's grid-snapped origin so
|
|
||||||
//the actual cursor position matches m_initial_cursor.
|
|
||||||
//Without this the first mouseMoveEvent computes a large
|
|
||||||
//delta (cursor is still at the Ctrl+V press location)
|
|
||||||
//and the items jump on first touch.
|
|
||||||
const QPoint view_pos = view->mapFromScene(m_initial_cursor);
|
|
||||||
const QPoint global_pos = view->viewport()->mapToGlobal(view_pos);
|
|
||||||
QCursor::setPos(global_pos);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
showHint();
|
showHint();
|
||||||
|
|||||||
@@ -84,7 +84,10 @@ void DiagramEventAddPdf::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
|||||||
}
|
}
|
||||||
else if (m_image && event->button() == Qt::RightButton)
|
else if (m_image && event->button() == Qt::RightButton)
|
||||||
{
|
{
|
||||||
m_image->setRotation(m_image->rotation() + 90);
|
// rotationAngle()/setRotationAngle(), not QGraphicsItem's own
|
||||||
|
// rotation()/setRotation(): see DiagramEventAddImage's identical
|
||||||
|
// fix (mousePressEvent) for why -- same class, same reasoning.
|
||||||
|
m_image->setRotationAngle(m_image->rotationAngle() + 90);
|
||||||
event->setAccepted(true);
|
event->setAccepted(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,14 +135,35 @@ void DiagramEventAddPdf::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
|
|||||||
*/
|
*/
|
||||||
void DiagramEventAddPdf::wheelEvent(QGraphicsSceneWheelEvent *event)
|
void DiagramEventAddPdf::wheelEvent(QGraphicsSceneWheelEvent *event)
|
||||||
{
|
{
|
||||||
if (!m_is_added || !m_image || event->modifiers() != Qt::CTRL) {
|
// event->modifiers() & Qt::ControlModifier, not != Qt::CTRL: the same
|
||||||
|
// exact-equality bug already found and fixed elsewhere this session --
|
||||||
|
// Ctrl held together with any other modifier would silently fail to
|
||||||
|
// register as Ctrl at all.
|
||||||
|
if (!m_is_added || !m_image || !(event->modifiers() & Qt::ControlModifier)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qreal scaling = m_image->scale();
|
// scaleFactorX()/scaleFactorY(), not QGraphicsItem's own scale(): see
|
||||||
event->delta() > 1 ? scaling += 0.01 : scaling -= 0.01;
|
// DiagramEventAddImage's identical fix for why. No drag-to-resize
|
||||||
if (scaling > 0.01 && scaling <= 2) {
|
// exists here, and the pivot is never touched elsewhere in this
|
||||||
m_image->setScale(scaling);
|
// class, so it stays at its default boundingRect().center() and this
|
||||||
|
// scales the page in place around its own middle, exactly like
|
||||||
|
// before.
|
||||||
|
//
|
||||||
|
// Step each axis from its own current value rather than reading X and
|
||||||
|
// writing it back to both: scaleFactorX and scaleFactorY cannot
|
||||||
|
// actually differ here today (nothing in this class ever sets them to
|
||||||
|
// different values, and there is no drag-resize at all), but stepping
|
||||||
|
// both independently costs nothing and removes the trap if that ever
|
||||||
|
// changes.
|
||||||
|
qreal scalingX = m_image->scaleFactorX();
|
||||||
|
qreal scalingY = m_image->scaleFactorY();
|
||||||
|
const qreal step = event->delta() > 1 ? 0.01 : -0.01;
|
||||||
|
scalingX += step;
|
||||||
|
scalingY += step;
|
||||||
|
if (scalingX > 0.01 && scalingX <= 2 && scalingY > 0.01 && scalingY <= 2) {
|
||||||
|
m_image->setScaleFactorX(scalingX);
|
||||||
|
m_image->setScaleFactorY(scalingY);
|
||||||
}
|
}
|
||||||
|
|
||||||
event->setAccepted(true);
|
event->setAccepted(true);
|
||||||
|
|||||||
@@ -87,9 +87,9 @@ DiagramEventAddShape::~DiagramEventAddShape()
|
|||||||
Applies a drag/click position to the in-progress shape, honouring two
|
Applies a drag/click position to the in-progress shape, honouring two
|
||||||
modifiers that mirror how the very same shape can already be edited
|
modifiers that mirror how the very same shape can already be edited
|
||||||
afterward, once placed:
|
afterward, once placed:
|
||||||
- Ctrl, for Rectangle/Ellipse only: the first click becomes the
|
- Ctrl, for Rectangle/Ellipse only: the first click's point acts as
|
||||||
shape's *center* rather than a corner, growing symmetrically as
|
the shape's *center* rather than a corner, growing symmetrically
|
||||||
the cursor moves away from it -- the same meaning Ctrl already
|
as the cursor moves away from it -- the same meaning Ctrl already
|
||||||
has on a Resize handle (anchor at center). Deliberately not
|
has on a Resize handle (anchor at center). Deliberately not
|
||||||
offered for Line: unlike the Rectangle/Ellipse case, there's no
|
offered for Line: unlike the Rectangle/Ellipse case, there's no
|
||||||
established convention for "a line grows symmetrically from its
|
established convention for "a line grows symmetrically from its
|
||||||
@@ -100,12 +100,18 @@ DiagramEventAddShape::~DiagramEventAddShape()
|
|||||||
dragged dimensions is currently larger and mirroring that onto
|
dragged dimensions is currently larger and mirroring that onto
|
||||||
the other, preserving the direction the user is actually
|
the other, preserving the direction the user is actually
|
||||||
dragging in.
|
dragging in.
|
||||||
Both can combine (Ctrl+Shift: a centered square/circle). Whether or
|
Both can combine (Ctrl+Shift: a centered square/circle). Whether Ctrl
|
||||||
not Ctrl is currently held, the non-anchored branch always rebuilds
|
currently anchors from the center is re-decided on every call, from
|
||||||
from m_anchor_point rather than nudging the existing rect/line --
|
the live modifiers passed in here -- not frozen at whatever was held
|
||||||
otherwise, if Ctrl had been held earlier in the same drag (moving the
|
on the first click. Every comparable tool (Illustrator, Photoshop,
|
||||||
shape's own first point to a mirrored position), releasing it would
|
Figma, Inkscape...) lets you press or release the center-origin
|
||||||
leave that point stuck there instead of actually restoring it.
|
modifier at any point mid-drag, with the shape immediately jumping to
|
||||||
|
match; that jump is the expected feedback for changing which point is
|
||||||
|
anchored, not a glitch. Freezing the choice at the first click instead
|
||||||
|
meant holding Ctrl anywhere other than the initial mouse-down did
|
||||||
|
nothing visible -- which, tried the more natural way (drag first,
|
||||||
|
then reach for Ctrl once you decide you want it centered), read as
|
||||||
|
"Ctrl doesn't work" rather than as a deliberate one-shot decision.
|
||||||
*/
|
*/
|
||||||
void DiagramEventAddShape::applyPosition(const QPointF &pos, Qt::KeyboardModifiers mods)
|
void DiagramEventAddShape::applyPosition(const QPointF &pos, Qt::KeyboardModifiers mods)
|
||||||
{
|
{
|
||||||
@@ -125,14 +131,13 @@ void DiagramEventAddShape::applyPosition(const QPointF &pos, Qt::KeyboardModifie
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// m_center_anchored is decided once, in mousePressEvent, not
|
m_center_anchored = (mods & Qt::ControlModifier)
|
||||||
// re-checked here on every call -- re-checking it live meant
|
&& (m_shape_type == QetShapeItem::Rectangle || m_shape_type == QetShapeItem::Ellipse);
|
||||||
// releasing Ctrl mid-drag (something you'd naturally do the moment
|
if (m_center_anchored)
|
||||||
// your hand gets tired holding it, long before you're done resizing)
|
showCenterMarker(m_anchor_point);
|
||||||
// silently snapped the shape back to corner-anchored, discarding
|
else
|
||||||
// what felt like an already-made decision. Deciding it once at the
|
hideCenterMarker();
|
||||||
// first click matches "I held Ctrl when I clicked, so this shape is
|
|
||||||
// centered" -- a single, predictable rule instead of a live toggle.
|
|
||||||
QPointF target = pos;
|
QPointF target = pos;
|
||||||
|
|
||||||
if ((mods & Qt::ShiftModifier)
|
if ((mods & Qt::ShiftModifier)
|
||||||
@@ -218,10 +223,9 @@ void DiagramEventAddShape::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
|||||||
{
|
{
|
||||||
m_shape_item = new QetShapeItem(pos, pos, m_shape_type);
|
m_shape_item = new QetShapeItem(pos, pos, m_shape_type);
|
||||||
m_anchor_point = pos;
|
m_anchor_point = pos;
|
||||||
// Decided once, here, rather than re-checked on every mouse
|
// Initial feedback only -- applyPosition() re-decides this
|
||||||
// move for the rest of the drag -- see applyPosition()'s doc
|
// live on every subsequent move, from whatever Ctrl state is
|
||||||
// comment for why continuous re-checking made releasing Ctrl
|
// held at the time.
|
||||||
// mid-drag feel like a bug rather than a deliberate choice.
|
|
||||||
m_center_anchored = (event->modifiers() & Qt::ControlModifier)
|
m_center_anchored = (event->modifiers() & Qt::ControlModifier)
|
||||||
&& (m_shape_type == QetShapeItem::Rectangle || m_shape_type == QetShapeItem::Ellipse);
|
&& (m_shape_type == QetShapeItem::Rectangle || m_shape_type == QetShapeItem::Ellipse);
|
||||||
if (m_center_anchored)
|
if (m_center_anchored)
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class DiagramEventAddShape : public DiagramEventInterface
|
|||||||
QGraphicsLineItem *m_help_horiz, *m_help_verti;
|
QGraphicsLineItem *m_help_horiz, *m_help_verti;
|
||||||
QPointF m_anchor_point; // the shape's first-click point -- meaningful once m_shape_item exists
|
QPointF m_anchor_point; // the shape's first-click point -- meaningful once m_shape_item exists
|
||||||
QGraphicsEllipseItem *m_center_marker = nullptr; // shown only while Ctrl-anchoring is actually in effect, so it doubles as confirmation that it is
|
QGraphicsEllipseItem *m_center_marker = nullptr; // shown only while Ctrl-anchoring is actually in effect, so it doubles as confirmation that it is
|
||||||
bool m_center_anchored = false; // decided once, at the first click -- see applyPosition()'s doc comment for why
|
bool m_center_anchored = false; // re-decided live on every applyPosition() call, from current Ctrl state
|
||||||
QPointF m_last_mouse_scene_pos; // raw, unsnapped -- lets a modifier-only change re-snap correctly when reapplied
|
QPointF m_last_mouse_scene_pos; // raw, unsnapped -- lets a modifier-only change re-snap correctly when reapplied
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+127
-4
@@ -16,6 +16,7 @@
|
|||||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include "diagramview.h"
|
#include "diagramview.h"
|
||||||
|
#include "cellruler.h"
|
||||||
#include "lastusedstyle.h"
|
#include "lastusedstyle.h"
|
||||||
#include "qetproject.h"
|
#include "qetproject.h"
|
||||||
#include "QPropertyUndoCommand/qpropertyundocommand.h"
|
#include "QPropertyUndoCommand/qpropertyundocommand.h"
|
||||||
@@ -43,6 +44,7 @@
|
|||||||
#include <QDropEvent>
|
#include <QDropEvent>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Constructeur
|
Constructeur
|
||||||
@@ -107,6 +109,13 @@ DiagramView::DiagramView(Diagram *diagram, QWidget *parent) :
|
|||||||
connect(&(m_diagram -> border_and_titleblock), &BorderTitleBlock::informationChanged, this, &DiagramView::updateWindowTitle);
|
connect(&(m_diagram -> border_and_titleblock), &BorderTitleBlock::informationChanged, this, &DiagramView::updateWindowTitle);
|
||||||
connect(diagram, &Diagram::findElementRequired, this, &DiagramView::findElementRequired);
|
connect(diagram, &Diagram::findElementRequired, this, &DiagramView::findElementRequired);
|
||||||
|
|
||||||
|
m_top_ruler = new CellRuler(Qt::Horizontal, this);
|
||||||
|
m_side_ruler = new CellRuler(Qt::Vertical, this);
|
||||||
|
m_cell_rulers_shown = QSettings().value("diagrameditor/cell_rulers", false).toBool();
|
||||||
|
connect(&m_diagram->border_and_titleblock, &BorderTitleBlock::borderChanged, this, &DiagramView::updateCellRulers);
|
||||||
|
connect(&m_diagram->border_and_titleblock, &BorderTitleBlock::displayChanged, this, &DiagramView::updateCellRulers);
|
||||||
|
updateCellRulers();
|
||||||
|
|
||||||
QShortcut *edit_conductor_color_shortcut = new QShortcut(QKeySequence(Qt::Key_F2), this);
|
QShortcut *edit_conductor_color_shortcut = new QShortcut(QKeySequence(Qt::Key_F2), this);
|
||||||
connect(edit_conductor_color_shortcut, &QShortcut::activated, [this]()
|
connect(edit_conductor_color_shortcut, &QShortcut::activated, [this]()
|
||||||
{
|
{
|
||||||
@@ -385,6 +394,23 @@ void DiagramView::zoomReset()
|
|||||||
adjustGridToZoom();
|
adjustGridToZoom();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief DiagramView::zoomToRect
|
||||||
|
Adjust zoom to fit \a rect, in scene coordinate, in the view.
|
||||||
|
@param rect
|
||||||
|
*/
|
||||||
|
void DiagramView::zoomToRect(const QRectF &rect)
|
||||||
|
{
|
||||||
|
fitInView(rect, Qt::KeepAspectRatio);
|
||||||
|
//Zooming in makes the scroll bars appear, which resizes the viewport
|
||||||
|
//from a queued call; that resize is anchored under the mouse and
|
||||||
|
//would scroll away from rect, so center again once it has run.
|
||||||
|
QMetaObject::invokeMethod(this, [this, rect]() {
|
||||||
|
centerOn(rect.center());
|
||||||
|
}, Qt::QueuedConnection);
|
||||||
|
adjustGridToZoom();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Copie les elements selectionnes du schema dans le presse-papier puis les supprime
|
Copie les elements selectionnes du schema dans le presse-papier puis les supprime
|
||||||
Copies the selected elements from the diagram to the clipboard and then deletes them
|
Copies the selected elements from the diagram to the clipboard and then deletes them
|
||||||
@@ -584,6 +610,7 @@ void DiagramView::mousePressEvent(QMouseEvent *e)
|
|||||||
*/
|
*/
|
||||||
void DiagramView::mouseMoveEvent(QMouseEvent *e)
|
void DiagramView::mouseMoveEvent(QMouseEvent *e)
|
||||||
{
|
{
|
||||||
|
m_last_mouse_pos = e->pos();
|
||||||
setToolTip(tr("X: %1 Y: %2").arg(e->pos().x()).arg(e->pos().y()));
|
setToolTip(tr("X: %1 Y: %2").arg(e->pos().x()).arg(e->pos().y()));
|
||||||
if (m_event_interface && m_event_interface->mouseMoveEvent(e)) return;
|
if (m_event_interface && m_event_interface->mouseMoveEvent(e)) return;
|
||||||
|
|
||||||
@@ -1169,6 +1196,82 @@ void DiagramView::paintingInverted(bool inverted)
|
|||||||
m_diagram->setInvertedLightness(inverted);
|
m_diagram->setInvertedLightness(inverted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief DiagramView::setCellRulersShown
|
||||||
|
Show or hide the rulers that keep the column numbers and the row
|
||||||
|
letters of the folio border in sight along the edges of this view.
|
||||||
|
@param shown
|
||||||
|
*/
|
||||||
|
void DiagramView::setCellRulersShown(bool shown)
|
||||||
|
{
|
||||||
|
m_cell_rulers_shown = shown;
|
||||||
|
updateCellRulers();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief DiagramView::updateCellRulers
|
||||||
|
Show each ruler when the rulers are wanted and the folio shows the
|
||||||
|
matching header, and give it room in the margins of the view. The
|
||||||
|
part of the folio in sight stays in sight when the viewport resizes.
|
||||||
|
*/
|
||||||
|
void DiagramView::updateCellRulers()
|
||||||
|
{
|
||||||
|
const BorderTitleBlock &border = m_diagram->border_and_titleblock;
|
||||||
|
const bool top = m_cell_rulers_shown
|
||||||
|
&& border.borderIsDisplayed() && border.columnsAreDisplayed();
|
||||||
|
const bool side = m_cell_rulers_shown
|
||||||
|
&& border.borderIsDisplayed() && border.rowsAreDisplayed();
|
||||||
|
const int thickness = m_top_ruler->thickness();
|
||||||
|
|
||||||
|
m_top_ruler->setVisible(top);
|
||||||
|
m_side_ruler->setVisible(side);
|
||||||
|
m_side_ruler->setLeadingSpace(top ? thickness : 0);
|
||||||
|
|
||||||
|
const QMargins margins(side ? thickness : 0, top ? thickness : 0, 0, 0);
|
||||||
|
if (margins != viewportMargins()) {
|
||||||
|
const QPointF centre = mapToScene(viewport()->rect().center());
|
||||||
|
setViewportMargins(margins);
|
||||||
|
centerOn(centre);
|
||||||
|
}
|
||||||
|
placeCellRulers();
|
||||||
|
m_top_ruler->update();
|
||||||
|
m_side_ruler->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief DiagramView::placeCellRulers
|
||||||
|
Lay the rulers along the top and the left edges of the viewport, the
|
||||||
|
side ruler covering the corner too when both are shown.
|
||||||
|
*/
|
||||||
|
void DiagramView::placeCellRulers()
|
||||||
|
{
|
||||||
|
if (!m_top_ruler) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const QRect viewport_rect = viewport()->geometry();
|
||||||
|
const int thickness = m_top_ruler->thickness();
|
||||||
|
const int corner = m_top_ruler->isHidden() ? 0 : thickness;
|
||||||
|
m_top_ruler->setGeometry(viewport_rect.left(), viewport_rect.top() - thickness,
|
||||||
|
viewport_rect.width(), thickness);
|
||||||
|
m_side_ruler->setGeometry(viewport_rect.left() - thickness, viewport_rect.top() - corner,
|
||||||
|
thickness, viewport_rect.height() + corner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief DiagramView::viewportEvent
|
||||||
|
Keep the rulers along the viewport when it resizes, which it also does
|
||||||
|
without the view resizing, when the scroll bars come and go.
|
||||||
|
@param event
|
||||||
|
@return what QGraphicsView::viewportEvent() returns
|
||||||
|
*/
|
||||||
|
bool DiagramView::viewportEvent(QEvent *event)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::Resize) {
|
||||||
|
placeCellRulers();
|
||||||
|
}
|
||||||
|
return PaletteGraphicsView::viewportEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief DiagramView::paintEvent
|
@brief DiagramView::paintEvent
|
||||||
Reimplemented from QGraphicsView
|
Reimplemented from QGraphicsView
|
||||||
@@ -1178,6 +1281,13 @@ void DiagramView::paintEvent(QPaintEvent *event)
|
|||||||
{
|
{
|
||||||
PaletteGraphicsView::paintEvent(event);
|
PaletteGraphicsView::paintEvent(event);
|
||||||
|
|
||||||
|
//Scrolling and zooming both repaint the viewport: follow them
|
||||||
|
if (viewportTransform() != m_rulers_transform) {
|
||||||
|
m_rulers_transform = viewportTransform();
|
||||||
|
m_top_ruler->update();
|
||||||
|
m_side_ruler->update();
|
||||||
|
}
|
||||||
|
|
||||||
if (m_free_rubberbanding && m_free_rubberband.count() >= 3)
|
if (m_free_rubberbanding && m_free_rubberband.count() >= 3)
|
||||||
{
|
{
|
||||||
QPainter painter(viewport());
|
QPainter painter(viewport());
|
||||||
@@ -1298,10 +1408,15 @@ QList<QAction *> DiagramView::contextMenuActions() const
|
|||||||
{
|
{
|
||||||
if (m_diagram->selectedItems().isEmpty())
|
if (m_diagram->selectedItems().isEmpty())
|
||||||
{
|
{
|
||||||
|
//Drawing comes first. The row and column actions change
|
||||||
|
//the folio's layout and are rarely wanted, so they sit one
|
||||||
|
//level down where a stray click cannot reach them.
|
||||||
list << m_paste_here;
|
list << m_paste_here;
|
||||||
list << m_separators.at(0);
|
list << m_separators.at(0);
|
||||||
|
list << qde->m_add_item_menu->menuAction();
|
||||||
|
list << m_separators.at(1);
|
||||||
list << qde->m_edit_diagram_properties;
|
list << qde->m_edit_diagram_properties;
|
||||||
list << qde->m_row_column_actions_group.actions();
|
list << qde->m_row_column_menu->menuAction();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1317,11 +1432,19 @@ QList<QAction *> DiagramView::contextMenuActions() const
|
|||||||
list << qde->m_depth_action_group->actions();
|
list << qde->m_depth_action_group->actions();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Remove from the context menu the actions which are disabled.
|
//Remove from the context menu the actions which are disabled,
|
||||||
|
//and the submenus in which every action is disabled.
|
||||||
const QList<QAction *> actions = list;
|
const QList<QAction *> actions = list;
|
||||||
for(QAction *action : actions)
|
for(QAction *action : actions)
|
||||||
{
|
{
|
||||||
if (!action->isEnabled()) {
|
bool usable = action->isEnabled();
|
||||||
|
if (usable && action->menu())
|
||||||
|
{
|
||||||
|
const QList<QAction *> sub_actions = action->menu()->actions();
|
||||||
|
usable = std::any_of(sub_actions.cbegin(), sub_actions.cend(),
|
||||||
|
[](QAction *a) { return a->isEnabled(); });
|
||||||
|
}
|
||||||
|
if (!usable) {
|
||||||
list.removeAll(action);
|
list.removeAll(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1477,7 +1600,7 @@ void DiagramView::createTemplateFromSelection()
|
|||||||
|
|
||||||
collection_node.appendChild(collection_elmt);
|
collection_node.appendChild(collection_elmt);
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Warnung: Konnte XML-Definition für" << old_type << "nicht laden.";
|
qDebug() << "Warning: could not load XML definition for" << old_type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include "palettegraphicsview.h"
|
#include "palettegraphicsview.h"
|
||||||
|
|
||||||
|
class CellRuler;
|
||||||
class Conductor;
|
class Conductor;
|
||||||
class Diagram;
|
class Diagram;
|
||||||
class QETDiagramEditor;
|
class QETDiagramEditor;
|
||||||
@@ -55,12 +56,18 @@ class DiagramView : public PaletteGraphicsView
|
|||||||
QAction *m_multi_paste = nullptr;
|
QAction *m_multi_paste = nullptr;
|
||||||
QAction *m_create_template = nullptr;
|
QAction *m_create_template = nullptr;
|
||||||
QPoint m_paste_here_pos;
|
QPoint m_paste_here_pos;
|
||||||
|
QPoint m_last_mouse_pos = QPoint(-1, -1);
|
||||||
QPointF m_drag_last_pos;
|
QPointF m_drag_last_pos;
|
||||||
bool m_fresh_focus_in,
|
bool m_fresh_focus_in,
|
||||||
m_first_activation = true;
|
m_first_activation = true;
|
||||||
QList<QAction *> m_separators;
|
QList<QAction *> m_separators;
|
||||||
QPolygonF m_free_rubberband;
|
QPolygonF m_free_rubberband;
|
||||||
bool m_free_rubberbanding = false;
|
bool m_free_rubberbanding = false;
|
||||||
|
CellRuler *m_top_ruler = nullptr;
|
||||||
|
CellRuler *m_side_ruler = nullptr;
|
||||||
|
bool m_cell_rulers_shown = false;
|
||||||
|
/// Last viewport transform the rulers were painted for
|
||||||
|
QTransform m_rulers_transform;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -71,6 +78,13 @@ class DiagramView : public PaletteGraphicsView
|
|||||||
void editSelection();
|
void editSelection();
|
||||||
void setEventInterface (DVEventInterface *event_interface);
|
void setEventInterface (DVEventInterface *event_interface);
|
||||||
QList<QAction *> contextMenuActions() const;
|
QList<QAction *> contextMenuActions() const;
|
||||||
|
/// Last mouse position seen by mouseMoveEvent(), in viewport
|
||||||
|
/// coordinates -- (-1, -1) if the mouse hasn't moved over this
|
||||||
|
/// view yet. Filled from ordinary Qt mouse events, not a global
|
||||||
|
/// cursor query (QCursor::pos()/setPos() are silently ignored by
|
||||||
|
/// several window managers and compositors, Wayland included).
|
||||||
|
QPoint lastMousePos() const { return m_last_mouse_pos; }
|
||||||
|
void setCellRulersShown(bool shown);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void mouseDoubleClickEvent(QMouseEvent *) override;
|
void mouseDoubleClickEvent(QMouseEvent *) override;
|
||||||
@@ -84,6 +98,7 @@ class DiagramView : public PaletteGraphicsView
|
|||||||
///Set for one call only, by the Escape handler, to let focus leave the view.
|
///Set for one call only, by the Escape handler, to let focus leave the view.
|
||||||
bool m_releasing_focus = false;
|
bool m_releasing_focus = false;
|
||||||
void paintEvent(QPaintEvent *event) override;
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
bool viewportEvent(QEvent *event) override;
|
||||||
void paintingInverted(bool inverted) override;
|
void paintingInverted(bool inverted) override;
|
||||||
void mousePressEvent(QMouseEvent *) override;
|
void mousePressEvent(QMouseEvent *) override;
|
||||||
void mouseMoveEvent(QMouseEvent *) override;
|
void mouseMoveEvent(QMouseEvent *) override;
|
||||||
@@ -106,6 +121,8 @@ class DiagramView : public PaletteGraphicsView
|
|||||||
QRectF viewedSceneRect() const;
|
QRectF viewedSceneRect() const;
|
||||||
bool mustIntegrateTitleBlockTemplate(const TitleBlockTemplateLocation &) const;
|
bool mustIntegrateTitleBlockTemplate(const TitleBlockTemplateLocation &) const;
|
||||||
bool gestures() const;
|
bool gestures() const;
|
||||||
|
void updateCellRulers();
|
||||||
|
void placeCellRulers();
|
||||||
|
|
||||||
/// Lowest and highest allowed value of the view transform scale (m11).
|
/// Lowest and highest allowed value of the view transform scale (m11).
|
||||||
/// Prevents wheel-zoom from driving the transform to overflow, which
|
/// Prevents wheel-zoom from driving the transform to overflow, which
|
||||||
@@ -133,6 +150,7 @@ class DiagramView : public PaletteGraphicsView
|
|||||||
void zoomFit();
|
void zoomFit();
|
||||||
void zoomContent();
|
void zoomContent();
|
||||||
void zoomReset();
|
void zoomReset();
|
||||||
|
void zoomToRect(const QRectF &rect);
|
||||||
void cut();
|
void cut();
|
||||||
void copy();
|
void copy();
|
||||||
void paste(const QPointF & = QPointF(), QClipboard::Mode = QClipboard::Clipboard);
|
void paste(const QPointF & = QPointF(), QClipboard::Mode = QClipboard::Clipboard);
|
||||||
|
|||||||
@@ -117,6 +117,18 @@ void ElementView::scaleClamped(qreal factor)
|
|||||||
scale(factor, factor);
|
scale(factor, factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief ElementView::zoom
|
||||||
|
Zoom by an arbitrary factor, for a continuous input such as a 3D mouse.
|
||||||
|
Same clamping as the wheel zoom.
|
||||||
|
@param zoom_factor : > 1 zooms in, < 1 zooms out
|
||||||
|
*/
|
||||||
|
void ElementView::zoom(qreal zoom_factor)
|
||||||
|
{
|
||||||
|
adjustSceneRect();
|
||||||
|
scaleClamped(zoom_factor);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Agrandit le schema (+33% = inverse des -25 % de zoomMoins())
|
Agrandit le schema (+33% = inverse des -25 % de zoomMoins())
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ class ElementView : public QGraphicsView {
|
|||||||
ElementScene *scene() const;
|
ElementScene *scene() const;
|
||||||
void setScene(ElementScene *);
|
void setScene(ElementScene *);
|
||||||
QRectF viewedSceneRect() const;
|
QRectF viewedSceneRect() const;
|
||||||
|
void zoom(qreal zoom_factor);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void mousePressEvent(QMouseEvent *) override;
|
void mousePressEvent(QMouseEvent *) override;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "elementpropertieseditorwidget.h"
|
#include "elementpropertieseditorwidget.h"
|
||||||
|
|
||||||
|
#include "../../qet.h"
|
||||||
#include "../../qetapp.h"
|
#include "../../qetapp.h"
|
||||||
#include "../../qetinformation.h"
|
#include "../../qetinformation.h"
|
||||||
#include "ui_elementpropertieseditorwidget.h"
|
#include "ui_elementpropertieseditorwidget.h"
|
||||||
@@ -185,13 +186,13 @@ void ElementPropertiesEditorWidget::upDateInterface()
|
|||||||
|
|
||||||
const DiagramContext &info = m_data.m_informations;
|
const DiagramContext &info = m_data.m_informations;
|
||||||
ui->m_auto_num_locked_cb->setChecked(
|
ui->m_auto_num_locked_cb->setChecked(
|
||||||
info.value(QStringLiteral("auto_num_locked")).toString() == QLatin1String("true"));
|
QET::infoFlagIsTrue(info.value(QStringLiteral("auto_num_locked")).toString()));
|
||||||
ui->m_potential_isolating_cb->setChecked(
|
ui->m_potential_isolating_cb->setChecked(
|
||||||
info.value(QStringLiteral("potential_isolating")).toString() == QLatin1String("true"));
|
QET::infoFlagIsTrue(info.value(QStringLiteral("potential_isolating")).toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->m_exclude_from_bom_cb->setChecked(
|
ui->m_exclude_from_bom_cb->setChecked(
|
||||||
m_data.m_informations.value(QStringLiteral("exclude_from_bom")).toString() == QLatin1String("true"));
|
QET::infoFlagIsTrue(m_data.m_informations.value(QStringLiteral("exclude_from_bom")).toString()));
|
||||||
|
|
||||||
on_m_base_type_cb_currentIndexChanged(ui->m_base_type_cb->currentIndex());
|
on_m_base_type_cb_currentIndexChanged(ui->m_base_type_cb->currentIndex());
|
||||||
}
|
}
|
||||||
@@ -588,6 +589,29 @@ void ElementPropertiesEditorWidget::populateSlaveGroupsTable()
|
|||||||
contact_ct->setValue(group.contactCount);
|
contact_ct->setValue(group.contactCount);
|
||||||
ui->m_slave_groups_table->setCellWidget(i, 2, contact_ct);
|
ui->m_slave_groups_table->setCellWidget(i, 2, contact_ct);
|
||||||
|
|
||||||
|
// When the contact count changes, keep the terminal count in step
|
||||||
|
// with it, otherwise the two drift apart (both are edited
|
||||||
|
// independently): the stored terminals-per-contact ratio is kept,
|
||||||
|
// or the contact type default (2, 3 for a switch) is used when the
|
||||||
|
// stored values don't divide evenly (inconsistent legacy data).
|
||||||
|
const int old_contacts = group.contactCount;
|
||||||
|
const int old_terminals = group.terminalCount;
|
||||||
|
connect(contact_ct, QOverload<int>::of(&QSpinBox::valueChanged),
|
||||||
|
this, [this, i, old_contacts, old_terminals](int val) {
|
||||||
|
if (i < m_data.m_slave_contact_groups.size()) {
|
||||||
|
readSlaveGroupsFromTable();
|
||||||
|
auto &group = m_data.m_slave_contact_groups[i];
|
||||||
|
int per_pole = old_terminals / qMax(1, old_contacts);
|
||||||
|
if (per_pole < 1 || old_terminals % qMax(1, old_contacts) != 0)
|
||||||
|
per_pole = group.type == ElementData::SW ? 3 : 2;
|
||||||
|
else if (group.type == ElementData::SW && per_pole < 3)
|
||||||
|
per_pole = 3; //a switch needs common, NC and NO
|
||||||
|
group.contactCount = val;
|
||||||
|
group.terminalCount = val * per_pole;
|
||||||
|
populateSlaveGroupsTable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Terminal count
|
// Terminal count
|
||||||
auto *terminal_ct = new QSpinBox(ui->m_slave_groups_table);
|
auto *terminal_ct = new QSpinBox(ui->m_slave_groups_table);
|
||||||
terminal_ct->setMinimum(1);
|
terminal_ct->setMinimum(1);
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
#include "../../qetapp.h"
|
#include "../../qetapp.h"
|
||||||
#include "../../qetmainwindow.h"
|
#include "../../qetmainwindow.h"
|
||||||
#include "../../recentfiles.h"
|
#include "../../recentfiles.h"
|
||||||
|
#include "../../elementscollectioncache.h"
|
||||||
|
#include "../../factory/elementpicturefactory.h"
|
||||||
#include "../graphicspart/customelementpart.h"
|
#include "../graphicspart/customelementpart.h"
|
||||||
#include "../elementitemeditor.h"
|
#include "../elementitemeditor.h"
|
||||||
#include "../styleeditor.h"
|
#include "../styleeditor.h"
|
||||||
@@ -348,6 +350,24 @@ bool QETElementEditor::toLocation(const ElementsLocation &location)
|
|||||||
tr("Impossible d'enregistrer l'élément", "message box content"));
|
tr("Impossible d'enregistrer l'élément", "message box content"));
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//setXml() just wrote the new drawing to disk, but the preview shown
|
||||||
|
//in the elements panel comes from two caches keyed by path+uuid that
|
||||||
|
//nothing here has told about the change: ElementPictureFactory's
|
||||||
|
//in-memory picture cache and ElementsCollectionCache's on-disk
|
||||||
|
//SQLite cache (see ElementsLocation::icon()). locationWasSaved()
|
||||||
|
//(elementscollectionwidget.cpp) re-reads the icon right after this
|
||||||
|
//call returns, but both caches still hand back the pre-edit pixmap,
|
||||||
|
//so the panel keeps showing the stale preview until the whole
|
||||||
|
//collection is reloaded. Drop and rebuild them here.
|
||||||
|
ElementPictureFactory::instance()->dropCache(location);
|
||||||
|
if (ElementsCollectionCache *cache = QETApp::collectionCache()) {
|
||||||
|
if (cache->fetchData(location)) {
|
||||||
|
cache->cacheName(location.toString(), location.uuid());
|
||||||
|
cache->cachePixmap(location.toString(), location.uuid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -674,6 +674,27 @@ void ElementsPanelWidget::duplicateDiagram()
|
|||||||
bool erase_labels = settings.value(
|
bool erase_labels = settings.value(
|
||||||
"diagramcommands/erase-label-on-copy", true).toBool();
|
"diagramcommands/erase-label-on-copy", true).toBool();
|
||||||
|
|
||||||
|
// Resolve a linked pair duplicated together against each other
|
||||||
|
// (bugtracker #607) before the loop below renews their uuids or
|
||||||
|
// clears their pending links: at this exact moment a copy's
|
||||||
|
// tmp_uuids_link still holds its source's original partner
|
||||||
|
// uuid, which still equals the not-yet-renewed uuid of that
|
||||||
|
// partner's own copy if both were duplicated together. Scoped
|
||||||
|
// to this diagram's own copies, not a project-wide search, so
|
||||||
|
// this never links back to the source elements the copies were
|
||||||
|
// made from -- if only one half of a linked pair is here, its
|
||||||
|
// link entry simply finds no match and is dropped, same as
|
||||||
|
// clearPendingLinks() used to do unconditionally for every copy.
|
||||||
|
QList<Element *> new_elements;
|
||||||
|
for (QGraphicsItem *item : new_diagram->items()) {
|
||||||
|
if (Element *elmt = dynamic_cast<Element *>(item)) {
|
||||||
|
new_elements << elmt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Element *elmt : new_elements) {
|
||||||
|
elmt->initLink(new_elements);
|
||||||
|
}
|
||||||
|
|
||||||
for (QGraphicsItem *item : new_diagram->items()) {
|
for (QGraphicsItem *item : new_diagram->items()) {
|
||||||
if (Element *elmt = dynamic_cast<Element *>(item)) {
|
if (Element *elmt = dynamic_cast<Element *>(item)) {
|
||||||
// The XML round-trip kept the source elements' uuids. Give the
|
// The XML round-trip kept the source elements' uuids. Give the
|
||||||
@@ -695,9 +716,9 @@ void ElementsPanelWidget::duplicateDiagram()
|
|||||||
new_diagram->restoreText(elmt);
|
new_diagram->restoreText(elmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear pending links so copies don't link back to
|
// initLink() above already cleared tmp_uuids_link for
|
||||||
// the source elements via stale UUIDs.
|
// every copy, matched or not -- nothing left here that
|
||||||
elmt->clearPendingLinks();
|
// could link back to a stale source uuid.
|
||||||
|
|
||||||
// Clean up copied element data:
|
// Clean up copied element data:
|
||||||
// 1. Slaves always lose label/formula/comment/location
|
// 1. Slaves always lose label/formula/comment/location
|
||||||
|
|||||||
@@ -22,8 +22,11 @@
|
|||||||
#include "qetapp.h"
|
#include "qetapp.h"
|
||||||
#include "qetgraphicsitem/dynamicelementtextitem.h"
|
#include "qetgraphicsitem/dynamicelementtextitem.h"
|
||||||
#include "qetgraphicsitem/elementtextitemgroup.h"
|
#include "qetgraphicsitem/elementtextitemgroup.h"
|
||||||
|
#include "qetdiagrameditor.h"
|
||||||
|
#include "textgrid.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief ElementTextsMover::ElementTextsMover
|
@brief ElementTextsMover::ElementTextsMover
|
||||||
@@ -81,6 +84,19 @@ int ElementTextsMover::beginMovement(Diagram *diagram, QGraphicsItem *driver_ite
|
|||||||
|
|
||||||
m_movement_running = true;
|
m_movement_running = true;
|
||||||
|
|
||||||
|
m_status_bar.clear();
|
||||||
|
if (!diagram->views().isEmpty())
|
||||||
|
if (const auto qde = QETApp::diagramEditorAncestorOf(diagram->views().at(0)))
|
||||||
|
m_status_bar = qde->statusBar();
|
||||||
|
if (m_status_bar)
|
||||||
|
{
|
||||||
|
const qreal divisor = QSettings().value(TextGrid::settings_key, 1).toReal();
|
||||||
|
m_status_bar->showMessage(divisor > 0
|
||||||
|
? QObject::tr("Grille des textes %1. Relâcher Maj et maintenir Ctrl pour placer librement.")
|
||||||
|
.arg(TextGrid::ratioLabel(divisor))
|
||||||
|
: QObject::tr("Grille des textes désactivée."));
|
||||||
|
}
|
||||||
|
|
||||||
return m_items_hash.size();
|
return m_items_hash.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +117,7 @@ void ElementTextsMover::continueMovement(QGraphicsSceneMouseEvent *event)
|
|||||||
button_down_parent_pos = qgi->mapToParent(qgi->mapFromScene(event->buttonDownScenePos(Qt::LeftButton)));
|
button_down_parent_pos = qgi->mapToParent(qgi->mapFromScene(event->buttonDownScenePos(Qt::LeftButton)));
|
||||||
|
|
||||||
QPointF new_pos = m_items_hash.value(qgi) + current_parent_pos - button_down_parent_pos;
|
QPointF new_pos = m_items_hash.value(qgi) + current_parent_pos - button_down_parent_pos;
|
||||||
event->modifiers() == Qt::ControlModifier ? qgi->setPos(new_pos) : qgi->setPos(Diagram::snapToGrid(new_pos));
|
event->modifiers() == Qt::ControlModifier ? qgi->setPos(new_pos) : qgi->setPos(Diagram::snapToTextGrid(new_pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,13 +128,19 @@ void ElementTextsMover::continueMovement(QGraphicsSceneMouseEvent *event)
|
|||||||
void ElementTextsMover::endMovement()
|
void ElementTextsMover::endMovement()
|
||||||
{
|
{
|
||||||
//No movement or no items to move
|
//No movement or no items to move
|
||||||
|
if (m_status_bar)
|
||||||
|
m_status_bar->clearMessage();
|
||||||
|
|
||||||
if(!m_movement_running || m_items_hash.isEmpty())
|
if(!m_movement_running || m_items_hash.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//Movement is null
|
//Movement is null
|
||||||
QGraphicsItem *qgi = m_items_hash.keys().first();
|
QGraphicsItem *qgi = m_items_hash.keys().first();
|
||||||
if(qgi->pos() == m_items_hash.value(qgi))
|
if(qgi->pos() == m_items_hash.value(qgi))
|
||||||
|
{
|
||||||
|
m_movement_running = false;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QUndoCommand *undo = new QUndoCommand(undoText());
|
QUndoCommand *undo = new QUndoCommand(undoText());
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QPointF>
|
#include <QPointF>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QStatusBar>
|
||||||
|
|
||||||
class QGraphicsItem;
|
class QGraphicsItem;
|
||||||
class DiagramTextItem;
|
class DiagramTextItem;
|
||||||
@@ -55,6 +57,7 @@ class ElementTextsMover
|
|||||||
QHash <DiagramTextItem *, QPointF> m_texts_hash;
|
QHash <DiagramTextItem *, QPointF> m_texts_hash;
|
||||||
QHash <QGraphicsItemGroup *, QPointF> m_grps_hash;
|
QHash <QGraphicsItemGroup *, QPointF> m_grps_hash;
|
||||||
QHash <QGraphicsItem *, QPointF> m_items_hash;
|
QHash <QGraphicsItem *, QPointF> m_items_hash;
|
||||||
|
QPointer<QStatusBar> m_status_bar;
|
||||||
int m_text_count = 0,
|
int m_text_count = 0,
|
||||||
m_group_count = 0;
|
m_group_count = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
#include "logging/eventloopwatchdog.h"
|
#include "logging/eventloopwatchdog.h"
|
||||||
#include "logging/qetlogger.h"
|
#include "logging/qetlogger.h"
|
||||||
#include "machine_info.h"
|
#include "machine_info.h"
|
||||||
|
#include "diagram.h"
|
||||||
|
#include "palettegraphicsview.h"
|
||||||
#include "qet.h"
|
#include "qet.h"
|
||||||
#include "qetapp.h"
|
#include "qetapp.h"
|
||||||
#include "qetmessagebox.h"
|
#include "qetmessagebox.h"
|
||||||
@@ -31,6 +33,7 @@
|
|||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDomImplementation>
|
#include <QDomImplementation>
|
||||||
|
#include <QFont>
|
||||||
|
|
||||||
#include <QStyleFactory>
|
#include <QStyleFactory>
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
@@ -105,6 +108,19 @@ int main(int argc, char **argv)
|
|||||||
// from Qt 6.12 on; opt in explicitly for older Qt 5/6.
|
// from Qt 6.12 on; opt in explicitly for older Qt 5/6.
|
||||||
QDomImplementation::setInvalidDataPolicy(
|
QDomImplementation::setInvalidDataPolicy(
|
||||||
QDomImplementation::ReturnNullNode);
|
QDomImplementation::ReturnNullNode);
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
// "MS Shell Dlg 2" is not a font but a Windows alias, and many projects
|
||||||
|
// and settings saved on Windows carry it. Qt 5's GDI font backend let
|
||||||
|
// Windows resolve it to Tahoma; Qt 6's DirectWrite backend does not know
|
||||||
|
// the alias and falls back to Arial, so those texts come out heavier on
|
||||||
|
// screen and in exported PDFs (bugtracker #340). Resolve both aliases
|
||||||
|
// the way Windows does. Done before any application object exists so
|
||||||
|
// that the headless export and scripting runs below get it too.
|
||||||
|
QFont::insertSubstitution("MS Shell Dlg 2", "Tahoma");
|
||||||
|
QFont::insertSubstitution("MS Shell Dlg", "Microsoft Sans Serif");
|
||||||
|
#endif
|
||||||
|
|
||||||
//Creation and execution of the application
|
//Creation and execution of the application
|
||||||
//HighDPI
|
//HighDPI
|
||||||
qputenv("QT_ENABLE_HIGHDPI_SCALING", "1");
|
qputenv("QT_ENABLE_HIGHDPI_SCALING", "1");
|
||||||
@@ -144,6 +160,22 @@ int main(int argc, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Re-apply the sheet background last picked in the diagram editor, so
|
||||||
|
// every project opened from here on -- existing or new, whichever one
|
||||||
|
// it is -- draws that background instead of the built-in default that
|
||||||
|
// would otherwise force the user to pick it again after each start.
|
||||||
|
//
|
||||||
|
// Done here rather than in main()'s first lines on purpose: the
|
||||||
|
// headless export and scripting runs above return before reaching
|
||||||
|
// this point and must keep rendering on plain white. It also has to
|
||||||
|
// happen before QETApp is constructed below, since that constructor
|
||||||
|
// already loads the projects given on the command line.
|
||||||
|
{
|
||||||
|
const QetSettings::SheetBackground sheet_background = QetSettings::sheetBackground();
|
||||||
|
PaletteGraphicsView::setCustomBackgroundColor(sheet_background.custom);
|
||||||
|
Diagram::background_color = sheet_background.color;
|
||||||
|
}
|
||||||
|
|
||||||
// Resolve the logger's state (log directory, session filename, open
|
// Resolve the logger's state (log directory, session filename, open
|
||||||
// file handle) explicitly here, immediately before installing the
|
// file handle) explicitly here, immediately before installing the
|
||||||
// handler -- not implicitly on whichever thread happens to log
|
// handler -- not implicitly on whichever thread happens to log
|
||||||
|
|||||||
@@ -388,6 +388,29 @@ void convertUriToGoTo(const QString &pdfPath)
|
|||||||
out.close();
|
out.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void removeUnusedPdfxNamespace(const QString &pdfPath)
|
||||||
|
{
|
||||||
|
QFile f(pdfPath);
|
||||||
|
if (!f.open(QIODevice::ReadOnly)) return;
|
||||||
|
QByteArray data = f.readAll();
|
||||||
|
f.close();
|
||||||
|
|
||||||
|
// Qt only fills the pdfxid namespace in when it writes PDF/X-4.
|
||||||
|
if (data.contains("pdfxid:GTS_PDFXVersion")) return;
|
||||||
|
|
||||||
|
static const QByteArray decl =
|
||||||
|
" xmlns:pdfxid=\"http://www.npes.org/pdfx/ns/id/\"";
|
||||||
|
const int pos = data.indexOf(decl);
|
||||||
|
if (pos == -1) return;
|
||||||
|
|
||||||
|
// Same length, so the stream /Length and the xref offsets stay valid.
|
||||||
|
data.replace(pos, decl.size(), QByteArray(decl.size(), ' '));
|
||||||
|
|
||||||
|
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) return;
|
||||||
|
f.write(data);
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
|
||||||
void convertComponentInfoAnnotations(const QString &pdfPath,
|
void convertComponentInfoAnnotations(const QString &pdfPath,
|
||||||
const QList<ComponentInfo> &annotations)
|
const QList<ComponentInfo> &annotations)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -74,6 +74,15 @@ namespace PdfLinks {
|
|||||||
*/
|
*/
|
||||||
void convertUriToGoTo(const QString &pdfPath);
|
void convertUriToGoTo(const QString &pdfPath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Post-process a Qt-generated PDF file: blank out the PDF/X namespace
|
||||||
|
declaration Qt 6 writes into the XMP metadata of every PDF. Adobe
|
||||||
|
Acrobat draws small text too bold when it is present (bugtracker #340).
|
||||||
|
Replaced in place with spaces, so no offset changes. No-op for a real
|
||||||
|
PDF/X file or when the declaration is absent.
|
||||||
|
*/
|
||||||
|
void removeUnusedPdfxNamespace(const QString &pdfPath);
|
||||||
|
|
||||||
struct ComponentInfo {
|
struct ComponentInfo {
|
||||||
QString contents;
|
QString contents;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -874,6 +874,7 @@ void ProjectPrintWindow::print()
|
|||||||
// Convert URI link annotations into native internal GoTo/FitR
|
// Convert URI link annotations into native internal GoTo/FitR
|
||||||
// actions so cross-references jump inside the document.
|
// actions so cross-references jump inside the document.
|
||||||
PdfLinks::convertUriToGoTo(pdfFile);
|
PdfLinks::convertUriToGoTo(pdfFile);
|
||||||
|
PdfLinks::removeUnusedPdfxNamespace(pdfFile);
|
||||||
|
|
||||||
this->close();
|
this->close();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ XRefProperties::XRefProperties()
|
|||||||
{
|
{
|
||||||
m_show_power_ctc = true;
|
m_show_power_ctc = true;
|
||||||
m_show_terminal_name = true;
|
m_show_terminal_name = true;
|
||||||
|
m_show_all_configured_slaves = false;
|
||||||
m_display = Cross;
|
m_display = Cross;
|
||||||
m_snap_to = Bottom;
|
m_snap_to = Bottom;
|
||||||
m_prefix_keys << "power" << "delay" << "switch";
|
m_prefix_keys << "power" << "delay" << "switch";
|
||||||
@@ -51,6 +52,7 @@ void XRefProperties::toSettings(QSettings &settings,
|
|||||||
{
|
{
|
||||||
settings.setValue(prefix % "showpowerctc", m_show_power_ctc);
|
settings.setValue(prefix % "showpowerctc", m_show_power_ctc);
|
||||||
settings.setValue(prefix % "showterminalname", m_show_terminal_name);
|
settings.setValue(prefix % "showterminalname", m_show_terminal_name);
|
||||||
|
settings.setValue(prefix % "showallconfiguredslaves", m_show_all_configured_slaves);
|
||||||
QString display = m_display == Cross? "cross" : "contacts";
|
QString display = m_display == Cross? "cross" : "contacts";
|
||||||
settings.setValue(prefix % "displayhas", display);
|
settings.setValue(prefix % "displayhas", display);
|
||||||
QString snap = m_snap_to == Bottom? "bottom" : "label";
|
QString snap = m_snap_to == Bottom? "bottom" : "label";
|
||||||
@@ -84,6 +86,7 @@ void XRefProperties::fromSettings(const QSettings &settings,
|
|||||||
{
|
{
|
||||||
m_show_power_ctc = settings.value(prefix % "showpowerctc", true).toBool();
|
m_show_power_ctc = settings.value(prefix % "showpowerctc", true).toBool();
|
||||||
m_show_terminal_name = settings.value(prefix % "showterminalname", true).toBool();
|
m_show_terminal_name = settings.value(prefix % "showterminalname", true).toBool();
|
||||||
|
m_show_all_configured_slaves = settings.value(prefix % "showallconfiguredslaves", false).toBool();
|
||||||
QString display = settings.value(prefix % "displayhas", "cross").toString();
|
QString display = settings.value(prefix % "displayhas", "cross").toString();
|
||||||
display == "cross"? m_display = Cross : m_display = Contacts;
|
display == "cross"? m_display = Cross : m_display = Contacts;
|
||||||
QString snap = settings.value(prefix % "snapto", "label").toString();
|
QString snap = settings.value(prefix % "snapto", "label").toString();
|
||||||
@@ -115,6 +118,7 @@ QDomElement XRefProperties::toXml(QDomDocument &xml_document) const
|
|||||||
|
|
||||||
xml_element.setAttribute("showpowerctc", m_show_power_ctc? "true" : "false");
|
xml_element.setAttribute("showpowerctc", m_show_power_ctc? "true" : "false");
|
||||||
xml_element.setAttribute("showterminalname", m_show_terminal_name? "true" : "false");
|
xml_element.setAttribute("showterminalname", m_show_terminal_name? "true" : "false");
|
||||||
|
xml_element.setAttribute("showallconfiguredslaves", m_show_all_configured_slaves? "true" : "false");
|
||||||
QString display = m_display == Cross? "cross" : "contacts";
|
QString display = m_display == Cross? "cross" : "contacts";
|
||||||
xml_element.setAttribute("displayhas", display);
|
xml_element.setAttribute("displayhas", display);
|
||||||
QString snap = m_snap_to == Bottom? "bottom" : "label";
|
QString snap = m_snap_to == Bottom? "bottom" : "label";
|
||||||
@@ -147,6 +151,7 @@ QDomElement XRefProperties::toXml(QDomDocument &xml_document) const
|
|||||||
bool XRefProperties::fromXml(const QDomElement &xml_element) {
|
bool XRefProperties::fromXml(const QDomElement &xml_element) {
|
||||||
m_show_power_ctc = xml_element.attribute("showpowerctc") == "true";
|
m_show_power_ctc = xml_element.attribute("showpowerctc") == "true";
|
||||||
m_show_terminal_name = xml_element.attribute("showterminalname", "true") == "true";
|
m_show_terminal_name = xml_element.attribute("showterminalname", "true") == "true";
|
||||||
|
m_show_all_configured_slaves = xml_element.attribute("showallconfiguredslaves", "false") == "true";
|
||||||
QString display = xml_element.attribute("displayhas", "cross");
|
QString display = xml_element.attribute("displayhas", "cross");
|
||||||
display == "cross"? m_display = Cross : m_display = Contacts;
|
display == "cross"? m_display = Cross : m_display = Contacts;
|
||||||
QString snap = xml_element.attribute("snapto", "label");
|
QString snap = xml_element.attribute("snapto", "label");
|
||||||
@@ -200,6 +205,7 @@ QHash<QString, XRefProperties> XRefProperties::defaultProperties()
|
|||||||
bool XRefProperties::operator ==(const XRefProperties &xrp) const{
|
bool XRefProperties::operator ==(const XRefProperties &xrp) const{
|
||||||
return (m_show_power_ctc == xrp.m_show_power_ctc
|
return (m_show_power_ctc == xrp.m_show_power_ctc
|
||||||
&& m_show_terminal_name == xrp.m_show_terminal_name
|
&& m_show_terminal_name == xrp.m_show_terminal_name
|
||||||
|
&& m_show_all_configured_slaves == xrp.m_show_all_configured_slaves
|
||||||
&& m_display == xrp.m_display
|
&& m_display == xrp.m_display
|
||||||
&& m_snap_to == xrp.m_snap_to
|
&& m_snap_to == xrp.m_snap_to
|
||||||
&& m_prefix == xrp.m_prefix
|
&& m_prefix == xrp.m_prefix
|
||||||
|
|||||||
@@ -60,6 +60,9 @@ class XRefProperties : public PropertiesInterface
|
|||||||
void setShowTerminalName (const bool a) {m_show_terminal_name = a;}
|
void setShowTerminalName (const bool a) {m_show_terminal_name = a;}
|
||||||
bool showTerminalName () const {return m_show_terminal_name;}
|
bool showTerminalName () const {return m_show_terminal_name;}
|
||||||
|
|
||||||
|
void setShowAllConfiguredSlaves (const bool a) {m_show_all_configured_slaves = a;}
|
||||||
|
bool showAllConfiguredSlaves () const {return m_show_all_configured_slaves;}
|
||||||
|
|
||||||
void setDisplayHas (const DisplayHas dh) {m_display = dh;}
|
void setDisplayHas (const DisplayHas dh) {m_display = dh;}
|
||||||
DisplayHas displayHas () const {return m_display;}
|
DisplayHas displayHas () const {return m_display;}
|
||||||
|
|
||||||
@@ -88,6 +91,7 @@ class XRefProperties : public PropertiesInterface
|
|||||||
private:
|
private:
|
||||||
bool m_show_power_ctc;
|
bool m_show_power_ctc;
|
||||||
bool m_show_terminal_name;
|
bool m_show_terminal_name;
|
||||||
|
bool m_show_all_configured_slaves;
|
||||||
DisplayHas m_display;
|
DisplayHas m_display;
|
||||||
SnapTo m_snap_to;
|
SnapTo m_snap_to;
|
||||||
Qt::AlignmentFlag m_xref_pos;
|
Qt::AlignmentFlag m_xref_pos;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "qeticons.h"
|
#include "qeticons.h"
|
||||||
#include "shortcutmanager.h"
|
#include "shortcutmanager.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
#include <QColorDialog>
|
#include <QColorDialog>
|
||||||
@@ -244,10 +245,33 @@ bool QET::attributeIsAReal(
|
|||||||
bool ok;
|
bool ok;
|
||||||
qreal tmp = e.attribute(nom_attribut).toDouble(&ok);
|
qreal tmp = e.attribute(nom_attribut).toDouble(&ok);
|
||||||
if (!ok) return(false);
|
if (!ok) return(false);
|
||||||
|
// QString::toDouble() sets ok=true for "nan"/"inf"/"-inf" -- these
|
||||||
|
// parse successfully but are not usable coordinates. A non-finite
|
||||||
|
// element/terminal position reaches Conductor::shape() during load
|
||||||
|
// and hangs there at 100% CPU inside QPainterPathStroker::createStroke(),
|
||||||
|
// confirmed with gdb: not a blocked wait, genuine unbounded computation.
|
||||||
|
if (!std::isfinite(tmp)) return(false);
|
||||||
if (reel != nullptr) *reel = tmp;
|
if (reel != nullptr) *reel = tmp;
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief QET::infoFlagIsTrue
|
||||||
|
@see the header comment for why this exists rather than a bare
|
||||||
|
== "true" comparison.
|
||||||
|
@param value the raw elementInformations string to test
|
||||||
|
@return true if @p value, trimmed and case-folded, is one of the
|
||||||
|
truthy spellings this codebase already accepts elsewhere
|
||||||
|
*/
|
||||||
|
bool QET::infoFlagIsTrue(const QString &value)
|
||||||
|
{
|
||||||
|
const QString v = value.trimmed().toLower();
|
||||||
|
return v == QLatin1String("true")
|
||||||
|
|| v == QLatin1String("1")
|
||||||
|
|| v == QLatin1String("yes")
|
||||||
|
|| v == QLatin1String("on");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief QET::ElementsAndConductorsSentence
|
@brief QET::ElementsAndConductorsSentence
|
||||||
Permet de composer rapidement la proposition "x elements et y conducteurs"
|
Permet de composer rapidement la proposition "x elements et y conducteurs"
|
||||||
|
|||||||
@@ -161,6 +161,22 @@ namespace QET {
|
|||||||
bool orthogonalProjection(const QPointF &, const QLineF &, QPointF * = nullptr);
|
bool orthogonalProjection(const QPointF &, const QLineF &, QPointF * = nullptr);
|
||||||
bool attributeIsAnInteger(const QDomElement &, const QString& , int * = nullptr);
|
bool attributeIsAnInteger(const QDomElement &, const QString& , int * = nullptr);
|
||||||
bool attributeIsAReal(const QDomElement &, const QString& , qreal * = nullptr);
|
bool attributeIsAReal(const QDomElement &, const QString& , qreal * = nullptr);
|
||||||
|
/**
|
||||||
|
Whether an elementInformations flag (auto_num_locked,
|
||||||
|
potential_isolating, exclude_from_bom, ...) counts as "on".
|
||||||
|
Case-insensitive and tolerant of surrounding whitespace, and
|
||||||
|
accepts the same set of truthy spellings ("true", "1", "yes",
|
||||||
|
"on") that element_nomenclature_view's SQL predicate for
|
||||||
|
exclude_from_bom already does -- see
|
||||||
|
projectDataBase::createElementNomenclatureView(). These flags
|
||||||
|
are only ever written by this app's own checkboxes as literal
|
||||||
|
"true"/"false" today, but a bare == "true" comparison silently
|
||||||
|
treats anything else -- "True", "TRUE", a trailing space from
|
||||||
|
a hand-edited file, a value some other tool wrote -- as off,
|
||||||
|
with no error and no visible difference from the checkbox
|
||||||
|
being genuinely unticked (discussion #785).
|
||||||
|
*/
|
||||||
|
bool infoFlagIsTrue(const QString &value);
|
||||||
QString ElementsAndConductorsSentence(int elements=0,
|
QString ElementsAndConductorsSentence(int elements=0,
|
||||||
int conductors=0,
|
int conductors=0,
|
||||||
int indi_texts=0,
|
int indi_texts=0,
|
||||||
|
|||||||
@@ -43,6 +43,10 @@
|
|||||||
#include "machine_info.h"
|
#include "machine_info.h"
|
||||||
#include "TerminalStrip/ui/terminalstripeditorwindow.h"
|
#include "TerminalStrip/ui/terminalstripeditorwindow.h"
|
||||||
#include "qetversion.h"
|
#include "qetversion.h"
|
||||||
|
#ifdef QET_SPACEMOUSE_SUPPORT
|
||||||
|
# include "spacemouse/spacemouselistener.h"
|
||||||
|
# include "ui/configpage/spacemouseconfigpage.h"
|
||||||
|
#endif
|
||||||
#include "logging/qetlogger.h"
|
#include "logging/qetlogger.h"
|
||||||
#include "logging/ui/diagnosticsreportdialog.h"
|
#include "logging/ui/diagnosticsreportdialog.h"
|
||||||
|
|
||||||
@@ -164,7 +168,24 @@ QETApp::QETApp() :
|
|||||||
m_splash_screen -> hide();
|
m_splash_screen -> hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef QET_SPACEMOUSE_SUPPORT
|
||||||
|
//Always safe to construct: it silently does nothing when spacenavd
|
||||||
|
//isn't running or no device is attached, which is the common case
|
||||||
|
//even in a build with this feature compiled in. See
|
||||||
|
//SpaceMouseListener's class comment.
|
||||||
|
m_space_mouse_listener = new SpaceMouseListener(this);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Deferred so this constructor returns before the prompts appear.
|
||||||
|
//checkBackupFiles() opens modal dialogs, and main() still has work to
|
||||||
|
//do once we return -- in particular connecting
|
||||||
|
//SingleApplication::receivedMessage to receiveMessage(). While those
|
||||||
|
//prompts were up that connection did not exist yet, so a file handed
|
||||||
|
//to the already-running instance during start-up was accepted by the
|
||||||
|
//socket and then dropped on the floor.
|
||||||
|
QMetaObject::invokeMethod(this, [this]() {
|
||||||
checkBackupFiles();
|
checkBackupFiles();
|
||||||
|
}, Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2192,6 +2213,9 @@ void QETApp::configureQET()
|
|||||||
cd.addPage(new ExportConfigPage());
|
cd.addPage(new ExportConfigPage());
|
||||||
cd.addPage(new PrintConfigPage());
|
cd.addPage(new PrintConfigPage());
|
||||||
cd.addPage(new ShortcutsConfigPage());
|
cd.addPage(new ShortcutsConfigPage());
|
||||||
|
#ifdef QET_SPACEMOUSE_SUPPORT
|
||||||
|
cd.addPage(new SpaceMouseConfigPage());
|
||||||
|
#endif
|
||||||
|
|
||||||
// associates the dialog with a possible parent widget
|
// associates the dialog with a possible parent widget
|
||||||
// associe le dialogue a un eventuel widget parent
|
// associe le dialogue a un eventuel widget parent
|
||||||
@@ -2207,6 +2231,13 @@ void QETApp::configureQET()
|
|||||||
// affiche le dialogue puis evite de le lier a un quelconque widget parent
|
// affiche le dialogue puis evite de le lier a un quelconque widget parent
|
||||||
cd.exec();
|
cd.exec();
|
||||||
cd.setParent(nullptr, cd.windowFlags());
|
cd.setParent(nullptr, cd.windowFlags());
|
||||||
|
emit textGridChanged();
|
||||||
|
|
||||||
|
#ifdef QET_SPACEMOUSE_SUPPORT
|
||||||
|
if (m_space_mouse_listener) {
|
||||||
|
m_space_mouse_listener->reloadSettings();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ class QETProject;
|
|||||||
class QETTitleBlockTemplateEditor;
|
class QETTitleBlockTemplateEditor;
|
||||||
class QTextOrientationSpinBoxWidget;
|
class QTextOrientationSpinBoxWidget;
|
||||||
class RecentFiles;
|
class RecentFiles;
|
||||||
|
#ifdef QET_SPACEMOUSE_SUPPORT
|
||||||
|
class SpaceMouseListener;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief The QETApp class
|
@brief The QETApp class
|
||||||
@@ -229,6 +232,13 @@ class QETApp : public QObject
|
|||||||
static TitleBlockTemplatesFilesCollection *m_company_tbt_collection;
|
static TitleBlockTemplatesFilesCollection *m_company_tbt_collection;
|
||||||
static TitleBlockTemplatesFilesCollection *m_custom_tbt_collection;
|
static TitleBlockTemplatesFilesCollection *m_custom_tbt_collection;
|
||||||
static ElementsCollectionCache *collections_cache_;
|
static ElementsCollectionCache *collections_cache_;
|
||||||
|
#ifdef QET_SPACEMOUSE_SUPPORT
|
||||||
|
/// One per application, not per window: a physical 6-DOF device
|
||||||
|
/// is a single ambient input source, and motion is applied to
|
||||||
|
/// whichever DiagramView is currently active. See
|
||||||
|
/// SpaceMouseListener's class comment.
|
||||||
|
SpaceMouseListener *m_space_mouse_listener = nullptr;
|
||||||
|
#endif
|
||||||
static QMap<uint, QETProject *> registered_projects_;
|
static QMap<uint, QETProject *> registered_projects_;
|
||||||
static uint next_project_id;
|
static uint next_project_id;
|
||||||
static RecentFiles *m_projects_recent_files;
|
static RecentFiles *m_projects_recent_files;
|
||||||
@@ -250,6 +260,10 @@ class QETApp : public QObject
|
|||||||
|
|
||||||
static QString m_interface_language;
|
static QString m_interface_language;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/// The text grid setting changed, see TextGrid.
|
||||||
|
void textGridChanged();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void systray(QSystemTrayIcon::ActivationReason);
|
void systray(QSystemTrayIcon::ActivationReason);
|
||||||
void reduceEveryEditor();
|
void reduceEveryEditor();
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "scripting/qetscripting.h"
|
#include "scripting/qetscripting.h"
|
||||||
#endif
|
#endif
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
#include <QToolButton>
|
||||||
#include "ElementsCollection/elementscollectionwidget.h"
|
#include "ElementsCollection/elementscollectionwidget.h"
|
||||||
#include "QWidgetAnimation/qwidgetanimation.h"
|
#include "QWidgetAnimation/qwidgetanimation.h"
|
||||||
#include "autoNum/ui/autonumberingdockwidget.h"
|
#include "autoNum/ui/autonumberingdockwidget.h"
|
||||||
@@ -48,6 +49,7 @@
|
|||||||
#include "qeticons.h"
|
#include "qeticons.h"
|
||||||
#include "qetmessagebox.h"
|
#include "qetmessagebox.h"
|
||||||
#include "recentfiles.h"
|
#include "recentfiles.h"
|
||||||
|
#include "textgrid.h"
|
||||||
#include "shortcutmanager.h"
|
#include "shortcutmanager.h"
|
||||||
#include "ui/bomexportdialog.h"
|
#include "ui/bomexportdialog.h"
|
||||||
#include "ui/conductorcolortoolbutton.h"
|
#include "ui/conductorcolortoolbutton.h"
|
||||||
@@ -367,10 +369,18 @@ void QETDiagramEditor::setUpActions()
|
|||||||
//original, where it was easy to miss entirely; now it appears
|
//original, where it was easy to miss entirely; now it appears
|
||||||
//under the cursor and follows it until a click, Return, or Escape
|
//under the cursor and follows it until a click, Return, or Escape
|
||||||
//to cancel -- the same interaction as placing a new element.
|
//to cancel -- the same interaction as placing a new element.
|
||||||
const QPoint view_pos = dv->viewport()->mapFromGlobal(QCursor::pos());
|
//
|
||||||
const QPointF start_pos = dv->viewport()->rect().contains(view_pos)
|
//dv->lastMousePos() (an ordinary Qt mouse-move position), not
|
||||||
? dv->mapToScene(view_pos)
|
//QCursor::pos() (a global, OS-level cursor query): several
|
||||||
: dv->mapToScene(dv->viewport()->rect().center());
|
//window managers and compositors -- Wayland in particular --
|
||||||
|
//silently refuse that query, returning a stale or wrong
|
||||||
|
//position, which is exactly what made the pasted content land
|
||||||
|
//far from the cursor instead of under it.
|
||||||
|
const QPoint last_pos = dv->lastMousePos();
|
||||||
|
const QPoint view_pos = (last_pos.x() >= 0 && dv->viewport()->rect().contains(last_pos))
|
||||||
|
? last_pos
|
||||||
|
: dv->viewport()->rect().center();
|
||||||
|
const QPointF start_pos = dv->mapToScene(view_pos);
|
||||||
|
|
||||||
dv->diagram()->setEventInterface(
|
dv->diagram()->setEventInterface(
|
||||||
new DiagramEventAddPaste(dv->diagram(), start_pos));
|
new DiagramEventAddPaste(dv->diagram(), start_pos));
|
||||||
@@ -473,6 +483,33 @@ void QETDiagramEditor::setUpActions()
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//Snap step for dragged texts, as a fraction of the folio grid
|
||||||
|
m_text_grid_menu = new QMenu(tr("Grille des textes"), this);
|
||||||
|
m_text_grid_menu->setIcon(QET::Icons::Grid);
|
||||||
|
m_text_grid_menu->setToolTipsVisible(true);
|
||||||
|
m_text_grid_button = new QToolButton(this);
|
||||||
|
m_text_grid_button->setMenu(m_text_grid_menu);
|
||||||
|
m_text_grid_button->setPopupMode(QToolButton::InstantPopup);
|
||||||
|
m_text_grid_button->setToolButtonStyle(Qt::ToolButtonTextOnly);
|
||||||
|
m_text_grid_button->setToolTip(tr("Grille d'accrochage des textes déplacés à la souris.\n"
|
||||||
|
"Maintenir Ctrl pendant le déplacement pour placer librement."));
|
||||||
|
auto text_grid_group = new QActionGroup(this);
|
||||||
|
for (const qreal divisor : TextGrid::divisors)
|
||||||
|
{
|
||||||
|
QAction *action = m_text_grid_menu->addAction(
|
||||||
|
divisor > 0 ? TextGrid::ratioLabel(divisor) : tr("Désactivée"));
|
||||||
|
action->setCheckable(true);
|
||||||
|
action->setData(divisor);
|
||||||
|
text_grid_group->addAction(action);
|
||||||
|
}
|
||||||
|
connect(text_grid_group, &QActionGroup::triggered, this, [](QAction *action) {
|
||||||
|
QSettings().setValue(TextGrid::settings_key, action->data());
|
||||||
|
emit QETApp::instance()->textGridChanged();
|
||||||
|
});
|
||||||
|
connect(QETApp::instance(), &QETApp::textGridChanged,
|
||||||
|
this, &QETDiagramEditor::updateTextGridButton);
|
||||||
|
updateTextGridButton();
|
||||||
|
|
||||||
// Draw or not the custom guides
|
// Draw or not the custom guides
|
||||||
m_draw_guides = new QAction ( QIcon::fromTheme("guides"), tr("Afficher les guides"), this);
|
m_draw_guides = new QAction ( QIcon::fromTheme("guides"), tr("Afficher les guides"), this);
|
||||||
m_draw_guides->setStatusTip(tr("Affiche ou masque les guides"));
|
m_draw_guides->setStatusTip(tr("Affiche ou masque les guides"));
|
||||||
@@ -485,6 +522,18 @@ void QETDiagramEditor::setUpActions()
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//Keep the column numbers and row letters of the folio in sight
|
||||||
|
m_cell_rulers = new QAction(tr("Garder les en-têtes visibles"), this);
|
||||||
|
m_cell_rulers->setStatusTip(tr("Garde les numéros de colonne et les lettres de ligne du folio visibles au bord de la vue"));
|
||||||
|
m_cell_rulers->setCheckable(true);
|
||||||
|
m_cell_rulers->setChecked(settings.value("diagrameditor/cell_rulers", false).toBool());
|
||||||
|
connect(m_cell_rulers, &QAction::triggered, [this](bool checked) {
|
||||||
|
QSettings().setValue("diagrameditor/cell_rulers", checked);
|
||||||
|
foreach (ProjectView *prjv, this->openedProjects())
|
||||||
|
foreach (DiagramView *dv, prjv->diagram_views())
|
||||||
|
dv->setCellRulersShown(checked);
|
||||||
|
});
|
||||||
|
|
||||||
//Edit current diagram properties
|
//Edit current diagram properties
|
||||||
m_edit_diagram_properties = new QAction(QET::Icons::DialogInformation, tr("Propriétés du folio"), this);
|
m_edit_diagram_properties = new QAction(QET::Icons::DialogInformation, tr("Propriétés du folio"), this);
|
||||||
ShortcutManager::instance().registerAction(m_edit_diagram_properties, "diagrameditor.edit_diagram_properties", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_L);
|
ShortcutManager::instance().registerAction(m_edit_diagram_properties, "diagrameditor.edit_diagram_properties", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_L);
|
||||||
@@ -948,6 +997,7 @@ void QETDiagramEditor::setUpToolBar()
|
|||||||
view_tool_bar -> addWidget(new DiagramEditorHandlerSizeWidget(this));
|
view_tool_bar -> addWidget(new DiagramEditorHandlerSizeWidget(this));
|
||||||
view_tool_bar -> addSeparator();
|
view_tool_bar -> addSeparator();
|
||||||
view_tool_bar -> addAction(m_draw_grid);
|
view_tool_bar -> addAction(m_draw_grid);
|
||||||
|
view_tool_bar -> addWidget(m_text_grid_button);
|
||||||
view_tool_bar -> addAction(m_draw_guides);
|
view_tool_bar -> addAction(m_draw_guides);
|
||||||
view_tool_bar -> addWidget(m_background_color_button);
|
view_tool_bar -> addWidget(m_background_color_button);
|
||||||
view_tool_bar -> addSeparator();
|
view_tool_bar -> addSeparator();
|
||||||
@@ -1036,9 +1086,9 @@ void QETDiagramEditor::setUpMenu()
|
|||||||
//toolbar button has no key, so text fields, images and every drawing
|
//toolbar button has no key, so text fields, images and every drawing
|
||||||
//shape simply could not be added. m_depth_action_group below has
|
//shape simply could not be added. m_depth_action_group below has
|
||||||
//always been in both places; this brings these into line with it.
|
//always been in both places; this brings these into line with it.
|
||||||
QMenu *menu_add_item = menu_edition -> addMenu(tr("A&jouter"));
|
m_add_item_menu = menu_edition -> addMenu(tr("A&jouter"));
|
||||||
menu_add_item -> setIcon(QET::Icons::Add);
|
m_add_item_menu -> setIcon(QET::Icons::Add);
|
||||||
menu_add_item -> addActions(m_add_item_actions_group.actions());
|
m_add_item_menu -> addActions(m_add_item_actions_group.actions());
|
||||||
menu_edition -> addSeparator();
|
menu_edition -> addSeparator();
|
||||||
menu_edition -> addActions(m_select_actions_group.actions());
|
menu_edition -> addActions(m_select_actions_group.actions());
|
||||||
menu_edition -> addSeparator();
|
menu_edition -> addSeparator();
|
||||||
@@ -1048,6 +1098,12 @@ void QETDiagramEditor::setUpMenu()
|
|||||||
menu_edition -> addSeparator();
|
menu_edition -> addSeparator();
|
||||||
menu_edition -> addAction(m_edit_diagram_properties);
|
menu_edition -> addAction(m_edit_diagram_properties);
|
||||||
menu_edition -> addActions(m_row_column_actions_group.actions());
|
menu_edition -> addActions(m_row_column_actions_group.actions());
|
||||||
|
//Not added to a menu here: it exists so the folio's context menu can
|
||||||
|
//hold the row and column actions one level down (see
|
||||||
|
//DiagramView::contextMenuActions()).
|
||||||
|
m_row_column_menu = new QMenu(tr("Lignes et colonnes"), this);
|
||||||
|
m_row_column_menu -> setIcon(QET::Icons::EditTableInsertColumnRight);
|
||||||
|
m_row_column_menu -> addActions(m_row_column_actions_group.actions());
|
||||||
menu_edition -> addSeparator();
|
menu_edition -> addSeparator();
|
||||||
menu_edition -> addActions(m_depth_action_group->actions());
|
menu_edition -> addActions(m_depth_action_group->actions());
|
||||||
menu_edition -> addSeparator();
|
menu_edition -> addSeparator();
|
||||||
@@ -1101,7 +1157,9 @@ void QETDiagramEditor::setUpMenu()
|
|||||||
menu_affichage -> addAction(m_mode_visualise);
|
menu_affichage -> addAction(m_mode_visualise);
|
||||||
menu_affichage -> addSeparator();
|
menu_affichage -> addSeparator();
|
||||||
menu_affichage -> addAction(m_draw_grid);
|
menu_affichage -> addAction(m_draw_grid);
|
||||||
|
menu_affichage -> addMenu(m_text_grid_menu);
|
||||||
menu_affichage -> addAction(m_draw_guides);
|
menu_affichage -> addAction(m_draw_guides);
|
||||||
|
menu_affichage -> addAction(m_cell_rulers);
|
||||||
menu_affichage -> addMenu(m_background_color_button->menu());
|
menu_affichage -> addMenu(m_background_color_button->menu());
|
||||||
menu_affichage -> addSeparator();
|
menu_affichage -> addSeparator();
|
||||||
menu_affichage -> addActions(m_zoom_actions_group.actions());
|
menu_affichage -> addActions(m_zoom_actions_group.actions());
|
||||||
@@ -1856,7 +1914,18 @@ void QETDiagramEditor::selectionGroupTriggered(QAction *action)
|
|||||||
diagram->undoStack().push(c);
|
diagram->undoStack().push(c);
|
||||||
}
|
}
|
||||||
else if (value == "rotate_selected_text")
|
else if (value == "rotate_selected_text")
|
||||||
diagram->undoStack().push(new RotateTextsCommand(diagram));
|
{
|
||||||
|
//Ask for the angle first, then build the command: the command
|
||||||
|
//itself no longer opens a dialog. Guarding on the selection keeps
|
||||||
|
//the previous behaviour of showing no dialog when there is
|
||||||
|
//nothing to rotate.
|
||||||
|
if (RotateTextsCommand::hasSelectedTexts(diagram))
|
||||||
|
{
|
||||||
|
qreal rotation = 0;
|
||||||
|
if (RotateTextsCommand::askRotation(rotation))
|
||||||
|
diagram->undoStack().push(new RotateTextsCommand(diagram, rotation));
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (value == "find_selected_element" && currentElement())
|
else if (value == "find_selected_element" && currentElement())
|
||||||
findElementInPanel(currentElement()->location());
|
findElementInPanel(currentElement()->location());
|
||||||
else if (value == "edit_selected_element")
|
else if (value == "edit_selected_element")
|
||||||
@@ -1922,6 +1991,7 @@ void QETDiagramEditor::slot_updateActions()
|
|||||||
m_background_color_button-> setEnabled(opened_diagram);
|
m_background_color_button-> setEnabled(opened_diagram);
|
||||||
m_draw_grid-> setEnabled(opened_diagram);
|
m_draw_grid-> setEnabled(opened_diagram);
|
||||||
m_draw_guides-> setEnabled(opened_diagram);
|
m_draw_guides-> setEnabled(opened_diagram);
|
||||||
|
m_cell_rulers-> setEnabled(opened_diagram);
|
||||||
|
|
||||||
//Project menu
|
//Project menu
|
||||||
m_project_edit_properties -> setEnabled(opened_project);
|
m_project_edit_properties -> setEnabled(opened_project);
|
||||||
@@ -2319,6 +2389,8 @@ void QETDiagramEditor::openBackupFiles(QList<KAutoSaveFile *> backup_files)
|
|||||||
//Create the project
|
//Create the project
|
||||||
DialogWaiting::instance(this);
|
DialogWaiting::instance(this);
|
||||||
|
|
||||||
|
//QETProject takes ownership of file and deletes it, whether or not it opens
|
||||||
|
const QString file_name = file->managedFile().fileName();
|
||||||
QETProject *project = new QETProject(file, this);
|
QETProject *project = new QETProject(file, this);
|
||||||
if (project->state() != QETProject::Ok)
|
if (project->state() != QETProject::Ok)
|
||||||
{
|
{
|
||||||
@@ -2329,7 +2401,7 @@ void QETDiagramEditor::openBackupFiles(QList<KAutoSaveFile *> backup_files)
|
|||||||
tr("Échec de l'ouverture du projet", "message box title"),
|
tr("Échec de l'ouverture du projet", "message box title"),
|
||||||
QString(tr(
|
QString(tr(
|
||||||
"Une erreur est survenue lors de l'ouverture du fichier %1.",
|
"Une erreur est survenue lors de l'ouverture du fichier %1.",
|
||||||
"message box content")).arg(file->managedFile().fileName()));
|
"message box content")).arg(file_name));
|
||||||
}
|
}
|
||||||
delete project;
|
delete project;
|
||||||
DialogWaiting::dropInstance();
|
DialogWaiting::dropInstance();
|
||||||
@@ -3203,3 +3275,23 @@ void QETDiagramEditor::slot_runScript() {
|
|||||||
QetScripting::runOnProject(script_path, project, currentDiagramView());
|
QetScripting::runOnProject(script_path, project, currentDiagramView());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief QETDiagramEditor::updateTextGridButton
|
||||||
|
Show the current text grid on its toolbar button and check it in its menu.
|
||||||
|
*/
|
||||||
|
void QETDiagramEditor::updateTextGridButton()
|
||||||
|
{
|
||||||
|
const qreal divisor = QSettings().value(TextGrid::settings_key, 1).toReal();
|
||||||
|
for (QAction *action : m_text_grid_menu->actions())
|
||||||
|
{
|
||||||
|
if (qFuzzyCompare(action->data().toReal() + 1, divisor + 1))
|
||||||
|
{
|
||||||
|
action->setChecked(true);
|
||||||
|
m_text_grid_button->setText(tr("Textes %1").arg(action->text()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//A divisor the menu does not offer, set by hand in the config file
|
||||||
|
m_text_grid_button->setText(tr("Textes %1").arg(TextGrid::ratioLabel(divisor)));
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
#include <QSignalMapper>
|
#include <QSignalMapper>
|
||||||
#include <QUndoGroup>
|
#include <QUndoGroup>
|
||||||
|
|
||||||
|
class QToolButton;
|
||||||
|
|
||||||
class QMdiSubWindow;
|
class QMdiSubWindow;
|
||||||
class QETProject;
|
class QETProject;
|
||||||
class QETResult;
|
class QETResult;
|
||||||
@@ -164,6 +166,7 @@ class QETDiagramEditor : public QETMainWindow
|
|||||||
void subWindowActivated(QMdiSubWindow *subWindows);
|
void subWindowActivated(QMdiSubWindow *subWindows);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
void updateTextGridButton();
|
||||||
void selectionChanged();
|
void selectionChanged();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -178,6 +181,10 @@ class QETDiagramEditor : public QETMainWindow
|
|||||||
m_selection_actions_group, ///Action related to edit a selected item
|
m_selection_actions_group, ///Action related to edit a selected item
|
||||||
*m_depth_action_group = nullptr;
|
*m_depth_action_group = nullptr;
|
||||||
|
|
||||||
|
QMenu
|
||||||
|
*m_add_item_menu = nullptr, ///< Submenu of m_add_item_actions_group
|
||||||
|
*m_row_column_menu = nullptr; ///< Submenu of m_row_column_actions_group
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QActionGroup
|
QActionGroup
|
||||||
*grp_visu_sel, ///< Action group for visualisation vs edition mode
|
*grp_visu_sel, ///< Action group for visualisation vs edition mode
|
||||||
@@ -205,6 +212,7 @@ class QETDiagramEditor : public QETMainWindow
|
|||||||
*m_auto_break_conductor, ///< Enable/Disable the use of auto break conductor
|
*m_auto_break_conductor, ///< Enable/Disable the use of auto break conductor
|
||||||
*m_draw_grid, ///< Switch the background grid display or not
|
*m_draw_grid, ///< Switch the background grid display or not
|
||||||
*m_draw_guides = nullptr, ///< Switch the custom guides display or not
|
*m_draw_guides = nullptr, ///< Switch the custom guides display or not
|
||||||
|
*m_cell_rulers = nullptr, ///< Keep the folio column/row headers in sight or not
|
||||||
*m_project_edit_properties, ///< Edit the properties of the current project.
|
*m_project_edit_properties, ///< Edit the properties of the current project.
|
||||||
*m_project_add_diagram, ///< Add a diagram to the current project.
|
*m_project_add_diagram, ///< Add a diagram to the current project.
|
||||||
*m_remove_diagram_from_project, ///< Delete a diagram from the current project
|
*m_remove_diagram_from_project, ///< Delete a diagram from the current project
|
||||||
@@ -244,6 +252,8 @@ class QETDiagramEditor : public QETMainWindow
|
|||||||
ConductorColorToolButton *m_conductor_color_button = nullptr;
|
ConductorColorToolButton *m_conductor_color_button = nullptr;
|
||||||
///< Diagram background color picker, in the "Affichage" toolbar
|
///< Diagram background color picker, in the "Affichage" toolbar
|
||||||
DiagramBgColorToolButton *m_background_color_button = nullptr;
|
DiagramBgColorToolButton *m_background_color_button = nullptr;
|
||||||
|
QMenu *m_text_grid_menu = nullptr; ///< Snap step used when dragging texts
|
||||||
|
QToolButton *m_text_grid_button = nullptr;
|
||||||
|
|
||||||
QList <QAction *> m_zoom_action_toolBar; ///Only zoom action must displayed in the toolbar
|
QList <QAction *> m_zoom_action_toolBar; ///Only zoom action must displayed in the toolbar
|
||||||
|
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ void ConductorTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
|||||||
|
|
||||||
if (parent_conductor_) {
|
if (parent_conductor_) {
|
||||||
if (parent_conductor_->nearShape().contains(intended_pos)) {
|
if (parent_conductor_->nearShape().contains(intended_pos)) {
|
||||||
event->modifiers() == Qt::ControlModifier ? setPos(intended_pos) : setPos(Diagram::snapToGrid(intended_pos));
|
event->modifiers() == Qt::ControlModifier ? setPos(intended_pos) : setPos(Diagram::snapToTextGrid(intended_pos));
|
||||||
parent_conductor_ -> setHighlighted(Conductor::Normal);
|
parent_conductor_ -> setHighlighted(Conductor::Normal);
|
||||||
} else {
|
} else {
|
||||||
parent_conductor_ -> setHighlighted(Conductor::Alert);
|
parent_conductor_ -> setHighlighted(Conductor::Alert);
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
#include "../properties/elementdata.h"
|
#include "../properties/elementdata.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
//define the height of the header.
|
//define the height of the header.
|
||||||
static int header = 5;
|
static int header = 5;
|
||||||
//define the minimal height of the cross (without header)
|
//define the minimal height of the cross (without header)
|
||||||
@@ -194,6 +196,37 @@ QString CrossRefItem::elementPositionText(
|
|||||||
return txt;
|
return txt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief CrossRefItem::showAllConfiguredSlaves
|
||||||
|
@param elmt : the element displaying the cross reference
|
||||||
|
@param xrp : xref properties of that element
|
||||||
|
@return true when the contact comb must show every slave contact the
|
||||||
|
master defines, even those no slave is linked to yet. That is the case
|
||||||
|
when the user asked for it, when the comb (contacts) display is the
|
||||||
|
one in use, and when the master really declares contact groups --
|
||||||
|
an element which declares none behaves exactly as before.
|
||||||
|
*/
|
||||||
|
bool CrossRefItem::showAllConfiguredSlaves(
|
||||||
|
const Element *elmt,
|
||||||
|
const XRefProperties &xrp)
|
||||||
|
{
|
||||||
|
if (!elmt) return false;
|
||||||
|
if (!xrp.showAllConfiguredSlaves()) return false;
|
||||||
|
if (xrp.displayHas() != XRefProperties::Contacts) return false;
|
||||||
|
|
||||||
|
return !elmt->elementData().m_slave_contact_groups.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief CrossRefItem::mustDrawAllConfiguredSlaves
|
||||||
|
@return showAllConfiguredSlaves for the element of this item and the
|
||||||
|
current properties.
|
||||||
|
*/
|
||||||
|
bool CrossRefItem::mustDrawAllConfiguredSlaves() const
|
||||||
|
{
|
||||||
|
return showAllConfiguredSlaves(m_element, m_properties);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief CrossRefItem::updateProperties
|
@brief CrossRefItem::updateProperties
|
||||||
update the current properties
|
update the current properties
|
||||||
@@ -256,8 +289,11 @@ void CrossRefItem::updateLabel()
|
|||||||
QTimer::singleShot(0, this, [this]{ update(); });
|
QTimer::singleShot(0, this, [this]{ update(); });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//Draw cross or contact, only if master element is linked.
|
//Draw cross or contact, if master element is linked, or if the user
|
||||||
else if (! m_element->linkedElements().isEmpty())
|
//asks for the contact comb to show the contact groups of the master
|
||||||
|
//even before they get a slave.
|
||||||
|
else if (! m_element->linkedElements().isEmpty()
|
||||||
|
|| mustDrawAllConfiguredSlaves())
|
||||||
{
|
{
|
||||||
m_update_map = true;
|
m_update_map = true;
|
||||||
XRefProperties::DisplayHas dh = m_properties.displayHas();
|
XRefProperties::DisplayHas dh = m_properties.displayHas();
|
||||||
@@ -358,7 +394,8 @@ void CrossRefItem::paint(
|
|||||||
if (m_element->elementData().m_master_type == ElementData::PLC)
|
if (m_element->elementData().m_master_type == ElementData::PLC)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_element->linkedElements().isEmpty()) return;
|
if (m_element->linkedElements().isEmpty()
|
||||||
|
&& !mustDrawAllConfiguredSlaves()) return;
|
||||||
|
|
||||||
QPen pen_;
|
QPen pen_;
|
||||||
pen_.setWidthF(0.5);
|
pen_.setWidthF(0.5);
|
||||||
@@ -727,6 +764,41 @@ void CrossRefItem::drawAsCross(QPainter &painter)
|
|||||||
fillCrossRef(painter);
|
fillCrossRef(painter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
/**
|
||||||
|
@brief contactOption
|
||||||
|
Map the contact group declared by a master onto the CONTACTS flags
|
||||||
|
used by CrossRefItem::drawContact, so a group no slave is linked to
|
||||||
|
yet is drawn like the slave it waits for.
|
||||||
|
@param group : the contact group of the master
|
||||||
|
@return the flags describing the contact to draw
|
||||||
|
*/
|
||||||
|
int contactOption(const ElementData::SlaveContactGroup &group)
|
||||||
|
{
|
||||||
|
int option = 0;
|
||||||
|
|
||||||
|
switch (group.type)
|
||||||
|
{
|
||||||
|
case ElementData::NO: option = CrossRefItem::NO; break;
|
||||||
|
case ElementData::NC: option = CrossRefItem::NC; break;
|
||||||
|
case ElementData::SW: option = CrossRefItem::SW; break;
|
||||||
|
case ElementData::Other: option = CrossRefItem::Other; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (group.subtype)
|
||||||
|
{
|
||||||
|
case ElementData::Power: option += CrossRefItem::Power; break;
|
||||||
|
case ElementData::DelayOn: option += CrossRefItem::DelayOn; break;
|
||||||
|
case ElementData::DelayOff: option += CrossRefItem::DelayOff; break;
|
||||||
|
case ElementData::delayOnOff: option += CrossRefItem::DelayOnOff; break;
|
||||||
|
case ElementData::SSimple:
|
||||||
|
case ElementData::PLCSlave: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief CrossRefItem::drawAsContacts
|
@brief CrossRefItem::drawAsContacts
|
||||||
Draw this crossref with symbolic contacts
|
Draw this crossref with symbolic contacts
|
||||||
@@ -734,16 +806,117 @@ void CrossRefItem::drawAsCross(QPainter &painter)
|
|||||||
*/
|
*/
|
||||||
void CrossRefItem::drawAsContacts(QPainter &painter)
|
void CrossRefItem::drawAsContacts(QPainter &painter)
|
||||||
{
|
{
|
||||||
if (m_element -> isFree())
|
if (m_element -> isFree() && !mustDrawAllConfiguredSlaves())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_drawed_contacts = 0;
|
m_drawed_contacts = 0;
|
||||||
if (m_update_map) m_hovered_contacts_map.clear();
|
if (m_update_map) m_hovered_contacts_map.clear();
|
||||||
QRectF bounding_rect;
|
QRectF bounding_rect;
|
||||||
|
|
||||||
//Draw each linked contact
|
//Draw every contact group of the master, in the order the master
|
||||||
foreach (Element *elmt, m_element->linkedElements())
|
//defines them, when the user asked for it and the master declares
|
||||||
|
//contact groups. Otherwise the comb keeps its historical behavior:
|
||||||
|
//linked slaves only, in position order.
|
||||||
|
if (mustDrawAllConfiguredSlaves())
|
||||||
{
|
{
|
||||||
|
const QVector<ElementData::SlaveContactGroup> groups =
|
||||||
|
m_element->elementData().m_slave_contact_groups;
|
||||||
|
|
||||||
|
//A contact group waits for exactly one slave: a slave assigned to
|
||||||
|
//a group is drawn where the master puts it, whatever its position
|
||||||
|
//on the diagram.
|
||||||
|
QHash<int, Element *> slotted;
|
||||||
|
QList<Element *> unassigned;
|
||||||
|
foreach (Element *elmt, m_element->linkedElements()) //position order
|
||||||
|
{
|
||||||
|
const int index = m_element->groupIndexForElement(elmt);
|
||||||
|
if (index >= 0 && index < groups.size() && !slotted.contains(index))
|
||||||
|
slotted.insert(index, elmt);
|
||||||
|
else
|
||||||
|
unassigned << elmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < groups.size(); ++i)
|
||||||
|
{
|
||||||
|
if (Element *slave = slotted.value(i, nullptr))
|
||||||
|
bounding_rect = bounding_rect.united(
|
||||||
|
drawLinkedSlaveContacts(painter, slave));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//No slave is linked to this group yet: the contact
|
||||||
|
//symbol of the group is drawn with the terminal names
|
||||||
|
//the master defines for it, there is no cross reference
|
||||||
|
//to show for it.
|
||||||
|
const int option = contactOption(groups.at(i));
|
||||||
|
const int poles = qMax(1, groups.at(i).contactCount);
|
||||||
|
QStringList labels = groups.at(i).labels;
|
||||||
|
|
||||||
|
//A single pole simple contact (NO or NC) reads its two
|
||||||
|
//numbers the other way round (checked against the
|
||||||
|
//diagram). Changeover contacts are not handled here:
|
||||||
|
//their labels are mapped to the right contact half in
|
||||||
|
//drawContact(), per pole, so multi pole changeovers work
|
||||||
|
//too. Groups with several NO/NC poles keep the order the
|
||||||
|
//master defines: a 3 pole power contact already reads
|
||||||
|
//correctly that way.
|
||||||
|
if (poles == 1 && (option & NOC))
|
||||||
|
std::reverse(labels.begin(), labels.end());
|
||||||
|
|
||||||
|
//The declared terminals are distributed over the declared
|
||||||
|
//poles. terminalCount and contactCount are edited
|
||||||
|
//independently in the element editor, so the list can be
|
||||||
|
//shorter than two entries per pole (three for a switch):
|
||||||
|
//every pole then gets its share of what exists, instead
|
||||||
|
//of a fixed 2/3 stride starving all but the first poles.
|
||||||
|
const int per_pole = labels.size() / poles;
|
||||||
|
const int extra = labels.size() % poles;
|
||||||
|
int begin = 0;
|
||||||
|
for (int pole = 0; pole < poles; ++pole)
|
||||||
|
{
|
||||||
|
const int count = per_pole + (pole < extra ? 1 : 0);
|
||||||
|
const QStringList pole_labels = labels.mid(begin, count);
|
||||||
|
begin += count;
|
||||||
|
bounding_rect = bounding_rect.united(
|
||||||
|
drawContact(painter,
|
||||||
|
option,
|
||||||
|
nullptr,
|
||||||
|
pole,
|
||||||
|
pole_labels));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Slaves the master doesn't assign to one of its groups (a link
|
||||||
|
//made before the master declared groups, for example) keep their
|
||||||
|
//usual place: the end of the comb, in position order.
|
||||||
|
foreach (Element *elmt, unassigned)
|
||||||
|
bounding_rect = bounding_rect.united(
|
||||||
|
drawLinkedSlaveContacts(painter, elmt));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Draw each linked contact, in position order
|
||||||
|
foreach (Element *elmt, m_element->linkedElements())
|
||||||
|
bounding_rect = bounding_rect.united(
|
||||||
|
drawLinkedSlaveContacts(painter, elmt));
|
||||||
|
}
|
||||||
|
|
||||||
|
bounding_rect.adjust(-30, -4, 4, 4);
|
||||||
|
prepareGeometryChange();
|
||||||
|
m_bounding_rect = bounding_rect;
|
||||||
|
m_shape_path.addRect(bounding_rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief CrossRefItem::drawLinkedSlaveContacts
|
||||||
|
Draw the contact symbols of one slave linked to this master.
|
||||||
|
@param painter : painter to use
|
||||||
|
@param elmt : the slave element to draw
|
||||||
|
@return the bounding rect of the draw
|
||||||
|
*/
|
||||||
|
QRectF CrossRefItem::drawLinkedSlaveContacts(QPainter &painter, Element *elmt)
|
||||||
|
{
|
||||||
|
QRectF bounding_rect;
|
||||||
DiagramContext info = elmt->kindInformations();
|
DiagramContext info = elmt->kindInformations();
|
||||||
|
|
||||||
for (int i=0; i<info["number"].toInt(); i++)
|
for (int i=0; i<info["number"].toInt(); i++)
|
||||||
@@ -762,15 +935,11 @@ void CrossRefItem::drawAsContacts(QPainter &painter)
|
|||||||
else if (type == "delayOff") option += DelayOff;
|
else if (type == "delayOff") option += DelayOff;
|
||||||
else if (type == "delayOnOff") option += DelayOnOff;
|
else if (type == "delayOnOff") option += DelayOnOff;
|
||||||
|
|
||||||
QRectF br = drawContact(painter, option, elmt, i);
|
bounding_rect = bounding_rect.united(
|
||||||
bounding_rect = bounding_rect.united(br);
|
drawContact(painter, option, elmt, i));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bounding_rect.adjust(-30, -4, 4, 4);
|
return bounding_rect;
|
||||||
prepareGeometryChange();
|
|
||||||
m_bounding_rect = bounding_rect;
|
|
||||||
m_shape_path.addRect(bounding_rect);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -778,12 +947,21 @@ void CrossRefItem::drawAsContacts(QPainter &painter)
|
|||||||
Draw one contact, the type of contact to draw is define in flags.
|
Draw one contact, the type of contact to draw is define in flags.
|
||||||
@param painter : painter to use
|
@param painter : painter to use
|
||||||
@param flags : define how to draw the contact (see enul CONTACTS)
|
@param flags : define how to draw the contact (see enul CONTACTS)
|
||||||
@param elmt : the element to display text (the position of the contact)
|
@param elmt : the element to display text (the position of the contact).
|
||||||
|
It may be nullptr when the contact comes from a contact group the master
|
||||||
|
defines but no slave is linked to yet: no position text, no hover/click
|
||||||
|
support, and the terminal names then come from master_labels.
|
||||||
|
@param pole_index : which contact of the group is drawn (0 based), used
|
||||||
|
to pick the right pair of terminal names of a linked multi-pole contact.
|
||||||
|
@param master_labels : the terminal names the master declares for this
|
||||||
|
pole (sliced from ElementData::SlaveContactGroup::labels by the caller),
|
||||||
|
used when elmt is nullptr so an empty slot shows the numbers the master
|
||||||
|
declares, the same way a linked slave would show them.
|
||||||
@return The bounding rect of the draw (contact + text)
|
@return The bounding rect of the draw (contact + text)
|
||||||
*/
|
*/
|
||||||
QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt, int pole_index)
|
QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt, int pole_index, const QStringList &master_labels)
|
||||||
{
|
{
|
||||||
QString str = elementPositionText(elmt);
|
QString str = elmt ? elementPositionText(elmt) : QString();
|
||||||
|
|
||||||
// Collect terminal names from the element definition (.elmt)
|
// Collect terminal names from the element definition (.elmt)
|
||||||
// e.g. name="13" and name="14" on each terminal
|
// e.g. name="13" and name="14" on each terminal
|
||||||
@@ -791,12 +969,12 @@ QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt, in
|
|||||||
// For SW contacts with typed terminals (No/Nc/Common), filter by role.
|
// For SW contacts with typed terminals (No/Nc/Common), filter by role.
|
||||||
QStringList terminal_names;
|
QStringList terminal_names;
|
||||||
const bool is_power_ctc =
|
const bool is_power_ctc =
|
||||||
elmt->kindInformations()["type"].toString() == "power";
|
elmt && elmt->kindInformations()["type"].toString() == "power";
|
||||||
const bool is_sw = (flags & SW) && !(flags & NOC);
|
const bool is_sw = (flags & SW) && !(flags & NOC);
|
||||||
|
|
||||||
// Check if SW terminals have explicit No/Nc/Common types
|
// Check if SW terminals have explicit No/Nc/Common types
|
||||||
bool sw_has_typed_terminals = false;
|
bool sw_has_typed_terminals = false;
|
||||||
if (is_sw) {
|
if (is_sw && elmt) {
|
||||||
for (Terminal *t : elmt->terminals()) {
|
for (Terminal *t : elmt->terminals()) {
|
||||||
if (!t) continue;
|
if (!t) continue;
|
||||||
if (t->terminalType() == TerminalData::No ||
|
if (t->terminalType() == TerminalData::No ||
|
||||||
@@ -808,12 +986,35 @@ QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt, in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (elmt) {
|
||||||
for (Terminal *t : elmt->terminals()) {
|
for (Terminal *t : elmt->terminals()) {
|
||||||
if (!t) continue;
|
if (!t) continue;
|
||||||
const QString tname = t->name();
|
const QString tname = t->name();
|
||||||
if (!tname.isEmpty())
|
if (!tname.isEmpty())
|
||||||
terminal_names << tname;
|
terminal_names << tname;
|
||||||
}
|
}
|
||||||
|
} else if (!master_labels.isEmpty()) {
|
||||||
|
//Empty slot of the contact comb: the slave is missing but the
|
||||||
|
//master already declares the terminal names, so the slot shows
|
||||||
|
//them instead of staying mute. master_labels contains exactly
|
||||||
|
//the terminals of this pole (the caller slices the declared
|
||||||
|
//terminal list over the declared poles), in the order a linked
|
||||||
|
//slave would receive them.
|
||||||
|
if (is_sw) {
|
||||||
|
//The labels are stored in terminal order (for a typical
|
||||||
|
//changeover contact: common, NC, NO, i.e. 11, 12, 14), while
|
||||||
|
//the symbol draws NC bottom-left, NO top-left and the common
|
||||||
|
//on the right: every stored entry goes to its own position.
|
||||||
|
//Entries the master doesn't declare (terminal count lower
|
||||||
|
//than three) simply stay empty instead of landing on the
|
||||||
|
//wrong contact half like the raw stored order would.
|
||||||
|
terminal_names << master_labels.value(1)
|
||||||
|
<< master_labels.value(2)
|
||||||
|
<< master_labels.value(0);
|
||||||
|
} else {
|
||||||
|
terminal_names = master_labels;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (is_power_ctc) {
|
if (is_power_ctc) {
|
||||||
// Sort terminals alphanumerically so names like "R1","R2"... or "1","2"...
|
// Sort terminals alphanumerically so names like "R1","R2"... or "1","2"...
|
||||||
@@ -860,7 +1061,7 @@ QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt, in
|
|||||||
QRectF bounding_rect = QRectF(0, offset, 24, 10);
|
QRectF bounding_rect = QRectF(0, offset, 24, 10);
|
||||||
|
|
||||||
QPen pen = painter.pen();
|
QPen pen = painter.pen();
|
||||||
m_hovered_contact == elmt ? pen.setColor(Qt::blue) :pen.setColor(Qt::black);
|
elmt && m_hovered_contact == elmt ? pen.setColor(Qt::blue) :pen.setColor(Qt::black);
|
||||||
painter.setPen(pen);
|
painter.setPen(pen);
|
||||||
|
|
||||||
//Draw NO or NC contact
|
//Draw NO or NC contact
|
||||||
@@ -956,11 +1157,18 @@ QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt, in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//The hit rect is registered even when the position text is
|
||||||
|
//empty: a linked contact had (and keeps) its hover/click entry
|
||||||
|
//in that case too, only the drawing is skipped. Free slots
|
||||||
|
//(elmt == nullptr) have nothing to click and stay out of the map.
|
||||||
QRectF text_rect = painter.boundingRect(QRectF(30, offset, 5, 10), Qt::AlignLeft | Qt::AlignVCenter, str);
|
QRectF text_rect = painter.boundingRect(QRectF(30, offset, 5, 10), Qt::AlignLeft | Qt::AlignVCenter, str);
|
||||||
|
if (!str.isEmpty())
|
||||||
|
{
|
||||||
painter.drawText(text_rect, Qt::AlignLeft | Qt::AlignVCenter, str);
|
painter.drawText(text_rect, Qt::AlignLeft | Qt::AlignVCenter, str);
|
||||||
bounding_rect = bounding_rect.united(text_rect);
|
bounding_rect = bounding_rect.united(text_rect);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_update_map)
|
if (m_update_map && elmt)
|
||||||
m_hovered_contacts_map.insert(elmt, text_rect);
|
m_hovered_contacts_map.insert(elmt, text_rect);
|
||||||
|
|
||||||
++m_drawed_contacts;
|
++m_drawed_contacts;
|
||||||
@@ -1038,12 +1246,16 @@ QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt, in
|
|||||||
QRectF(30, offset+4, 5, 10),
|
QRectF(30, offset+4, 5, 10),
|
||||||
Qt::AlignLeft | Qt::AlignVCenter,
|
Qt::AlignLeft | Qt::AlignVCenter,
|
||||||
str);
|
str);
|
||||||
|
if (!str.isEmpty())
|
||||||
|
{
|
||||||
painter.drawText(text_rect,
|
painter.drawText(text_rect,
|
||||||
Qt::AlignLeft | Qt::AlignVCenter,
|
Qt::AlignLeft | Qt::AlignVCenter,
|
||||||
str);
|
str);
|
||||||
bounding_rect = bounding_rect.united(text_rect);
|
bounding_rect = bounding_rect.united(text_rect);
|
||||||
|
}
|
||||||
if (m_update_map)
|
//Hit rect kept even for an empty position text (as before),
|
||||||
|
//free slots are not clickable.
|
||||||
|
if (m_update_map && elmt)
|
||||||
m_hovered_contacts_map.insert(elmt, text_rect);
|
m_hovered_contacts_map.insert(elmt, text_rect);
|
||||||
|
|
||||||
//a switch contact take place of two normal contact
|
//a switch contact take place of two normal contact
|
||||||
@@ -1070,12 +1282,16 @@ QRectF CrossRefItem::drawContact(QPainter &painter, int flags, Element *elmt, in
|
|||||||
QRectF(30, offset, 5, 10),
|
QRectF(30, offset, 5, 10),
|
||||||
Qt::AlignLeft | Qt::AlignVCenter,
|
Qt::AlignLeft | Qt::AlignVCenter,
|
||||||
str);
|
str);
|
||||||
|
if (!str.isEmpty())
|
||||||
|
{
|
||||||
painter.drawText(text_rect,
|
painter.drawText(text_rect,
|
||||||
Qt::AlignLeft | Qt::AlignVCenter,
|
Qt::AlignLeft | Qt::AlignVCenter,
|
||||||
str);
|
str);
|
||||||
bounding_rect = bounding_rect.united(text_rect);
|
bounding_rect = bounding_rect.united(text_rect);
|
||||||
|
}
|
||||||
if (m_update_map)
|
//Hit rect kept even for an empty position text (as before),
|
||||||
|
//free slots are not clickable.
|
||||||
|
if (m_update_map && elmt)
|
||||||
m_hovered_contacts_map.insert(elmt, text_rect);
|
m_hovered_contacts_map.insert(elmt, text_rect);
|
||||||
++m_drawed_contacts;
|
++m_drawed_contacts;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,13 @@ class CrossRefItem : public QGraphicsObject
|
|||||||
enum { Type = UserType + 1009 };
|
enum { Type = UserType + 1009 };
|
||||||
int type() const override { return Type; }
|
int type() const override { return Type; }
|
||||||
|
|
||||||
|
/// Returns true when \a xrp asks the contact comb of \a elmt to show
|
||||||
|
/// every slave contact the master defines, even the ones no slave is
|
||||||
|
/// linked to yet. \a elmt must be a master element.
|
||||||
|
static bool showAllConfiguredSlaves(
|
||||||
|
const Element *elmt,
|
||||||
|
const XRefProperties &xrp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief The CONTACTS enum
|
@brief The CONTACTS enum
|
||||||
*/
|
*/
|
||||||
@@ -121,7 +128,13 @@ class CrossRefItem : public QGraphicsObject
|
|||||||
void drawAsCross(QPainter &painter);
|
void drawAsCross(QPainter &painter);
|
||||||
void drawAsContacts(QPainter &painter);
|
void drawAsContacts(QPainter &painter);
|
||||||
void drawAsPlcTable(QPainter &painter);
|
void drawAsPlcTable(QPainter &painter);
|
||||||
QRectF drawContact(QPainter &painter, int flags, Element *elmt, int pole_index = 0);
|
bool mustDrawAllConfiguredSlaves() const;
|
||||||
|
QRectF drawLinkedSlaveContacts(QPainter &painter, Element *elmt);
|
||||||
|
QRectF drawContact(QPainter &painter,
|
||||||
|
int flags,
|
||||||
|
Element *elmt,
|
||||||
|
int pole_index = 0,
|
||||||
|
const QStringList &master_labels = QStringList());
|
||||||
void fillCrossRef(QPainter &painter);
|
void fillCrossRef(QPainter &painter);
|
||||||
void AddExtraInfo(QPainter &painter, const QString&);
|
void AddExtraInfo(QPainter &painter, const QString&);
|
||||||
QList<Element *> NOElements() const;
|
QList<Element *> NOElements() const;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user