mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-24 16:04:16 +02:00
Merge branch 'master' into feature-3dmouse-spnav
This commit is contained in:
@@ -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 libsqlite3-dev 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
|
||||||
@@ -53,7 +53,9 @@ jobs:
|
|||||||
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||||
cmake -B build -G Ninja \
|
cmake -B build -G Ninja \
|
||||||
-DCMAKE_BUILD_TYPE=Debug \
|
-DCMAKE_BUILD_TYPE=Debug \
|
||||||
-DQT_VERSION_MAJOR=6
|
-DQT_VERSION_MAJOR=6 \
|
||||||
|
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
|
||||||
|
-DQET_EXPORT_PROJECT_DB=ON
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cmake --build build --parallel $(nproc)
|
run: cmake --build build --parallel $(nproc)
|
||||||
|
|||||||
+3
-9
@@ -1,5 +1,7 @@
|
|||||||
*.snap
|
*.snap
|
||||||
.flatpak-builder
|
.flatpak-builder
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
# Qt build output
|
# Qt build output
|
||||||
*.user
|
*.user
|
||||||
# doxygen Doxyfile output
|
# doxygen Doxyfile output
|
||||||
@@ -7,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
|
|
||||||
|
|||||||
@@ -62,7 +62,9 @@ if(WIN32)
|
|||||||
# puts the .qm files (see build-aux/windows/QElectroTech.wxs and the
|
# puts the .qm files (see build-aux/windows/QElectroTech.wxs and the
|
||||||
# windows-build workflow), and what the shortcuts pass as --lang-dir.
|
# windows-build workflow), and what the shortcuts pass as --lang-dir.
|
||||||
set(QET_LANG_PATH "lang/")
|
set(QET_LANG_PATH "lang/")
|
||||||
|
set(QET_EXAMPLES_PATH "examples/")
|
||||||
set(QET_LICENSE_PATH "./")
|
set(QET_LICENSE_PATH "./")
|
||||||
|
set(QET_ICONS_PATH "icons/hicolor/")
|
||||||
# Liste des ressources Windows
|
# Liste des ressources Windows
|
||||||
#RC_FILE = qelectrotech.rc
|
#RC_FILE = qelectrotech.rc
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -297,6 +297,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,11 +309,15 @@ 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
|
||||||
|
|
||||||
${QET_DIR}/sources/dataBase/projectdatabase.cpp
|
${QET_DIR}/sources/dataBase/projectdatabase.cpp
|
||||||
${QET_DIR}/sources/dataBase/projectdatabase.h
|
${QET_DIR}/sources/dataBase/projectdatabase.h
|
||||||
|
${QET_DIR}/sources/dataBase/sqlreadonly.cpp
|
||||||
|
${QET_DIR}/sources/dataBase/sqlreadonly.h
|
||||||
|
|
||||||
${QET_DIR}/sources/dataBase/ui/elementquerywidget.cpp
|
${QET_DIR}/sources/dataBase/ui/elementquerywidget.cpp
|
||||||
${QET_DIR}/sources/dataBase/ui/elementquerywidget.h
|
${QET_DIR}/sources/dataBase/ui/elementquerywidget.h
|
||||||
@@ -721,6 +727,8 @@ set(QET_SRC_FILES
|
|||||||
${QET_DIR}/sources/ui/backupdialog.h
|
${QET_DIR}/sources/ui/backupdialog.h
|
||||||
${QET_DIR}/sources/ui/dialogwaiting.cpp
|
${QET_DIR}/sources/ui/dialogwaiting.cpp
|
||||||
${QET_DIR}/sources/ui/dialogwaiting.h
|
${QET_DIR}/sources/ui/dialogwaiting.h
|
||||||
|
${QET_DIR}/sources/ui/duplicateoffsetdialog.cpp
|
||||||
|
${QET_DIR}/sources/ui/duplicateoffsetdialog.h
|
||||||
${QET_DIR}/sources/ui/dynamicelementtextitemeditor.cpp
|
${QET_DIR}/sources/ui/dynamicelementtextitemeditor.cpp
|
||||||
${QET_DIR}/sources/ui/dynamicelementtextitemeditor.h
|
${QET_DIR}/sources/ui/dynamicelementtextitemeditor.h
|
||||||
${QET_DIR}/sources/ui/dynamicelementtextmodel.cpp
|
${QET_DIR}/sources/ui/dynamicelementtextmodel.cpp
|
||||||
|
|||||||
+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>
|
||||||
+242
-23
@@ -30,14 +30,20 @@ here read the model.
|
|||||||
| `qet_project_info` | title, format version, folios, element and conductor counts |
|
| `qet_project_info` | title, format version, folios, element and conductor counts |
|
||||||
| `qet_elements` | placed elements: uuid, type, position, label, information bag |
|
| `qet_elements` | placed elements: uuid, type, position, label, information bag |
|
||||||
| `qet_conductors` | conductors and their documentation fields; filter by attribute |
|
| `qet_conductors` | conductors and their documentation fields; filter by attribute |
|
||||||
| `qet_diff` | **what an edit actually changed** — moves with deltas, adds, removes, relabels, conductor field changes |
|
| `qet_diff` | **what an edit actually changed** — element moves, adds, removes, relabels; conductor changes; and folio fields, texts, shapes, images, symbol text fields and terminal strips |
|
||||||
| `qet_scan` | sweep a directory of projects, counting nodes carrying an attribute |
|
| `qet_scan` | sweep a directory of projects, counting nodes carrying an attribute |
|
||||||
| `qet_element_info` | a `.elmt`: translated names, terminals, info fields, part counts |
|
| `qet_element_info` | a `.elmt`: translated names, terminals, info fields, part counts |
|
||||||
| `qet_export` | run a headless export (pdf, png, svg, bom, cables, wires, wiring, nets, links, info) |
|
| `qet_export` | run a headless export (pdf, png, svg, bom, cables, wires, wiring, nets, links, info) |
|
||||||
|
| `qet_edit` | **change a project** — place, move, rotate, label, wire, number, cross-reference, add text, shapes and images, restyle a symbol's text fields, delete; then diff the result |
|
||||||
|
| `qet_element_build` | **author a `.elmt`** — draw a new symbol, with terminals to wire it by |
|
||||||
|
| `qet_project_new` | **start from nothing** — an empty project with a title and folios |
|
||||||
|
| `qet_element_search` | **find a symbol** in a collection by name (any language), type or terminal count |
|
||||||
|
| `qet_check` | **design-rule checks** — duplicate labels, unlabelled masters, unnumbered conductors, empty folios |
|
||||||
|
| `qet_query` | **ask the project database** — read-only SQL over the views and tables |
|
||||||
|
|
||||||
Only `qet_export` launches QElectroTech. Everything else parses the file
|
`qet_export` and `qet_edit` launch QElectroTech. Everything else parses the
|
||||||
directly, which is faster, needs no display, and cannot be confused by a
|
file directly, which is faster, needs no display, and cannot be confused by
|
||||||
dialog.
|
a dialog.
|
||||||
|
|
||||||
## Running it
|
## Running it
|
||||||
|
|
||||||
@@ -56,12 +62,80 @@ Register it with an MCP client, for example:
|
|||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"qet": {
|
"qet": {
|
||||||
"command": "python3",
|
"command": "python3",
|
||||||
"args": ["/path/to/qelectrotech/misc/qet-mcp/qet_mcp.py"]
|
"args": ["/path/to/qelectrotech/misc/qet-mcp/qet_mcp.py"],
|
||||||
|
"env": {
|
||||||
|
"QET_MCP_WORKSPACE": "/home/you/drawings",
|
||||||
|
"QET_ENABLE_SCRIPTING": "1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Five tools need scripting switched on
|
||||||
|
|
||||||
|
A QElectroTech with JavaScript scripting switched off refuses `--run`, and
|
||||||
|
off is the default from
|
||||||
|
[#984](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/984)
|
||||||
|
onwards. Five tools here drive it that way and stop working until it is
|
||||||
|
turned on:
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| need `QET_ENABLE_SCRIPTING=1` | `qet_query`, `qet_continuity`, `qet_check`, `qet_project_new`, `qet_edit` |
|
||||||
|
| unaffected | everything else — they read the `.qet` directly, or, in `qet_export`'s case, use a plain CLI flag |
|
||||||
|
|
||||||
|
The variable goes in the environment this server is started in, which for an
|
||||||
|
MCP client is the `env` block above; the server passes its environment
|
||||||
|
straight through to QElectroTech. It does not set the variable itself, on
|
||||||
|
purpose — a switch a program turns on for itself is not a switch. Whoever
|
||||||
|
configured this server and pointed it at a QElectroTech binary made that
|
||||||
|
choice, and their interactive QElectroTech keeps whatever its own setting
|
||||||
|
says.
|
||||||
|
|
||||||
|
Without it, those five come back `"ok": false` with a `hint` naming the
|
||||||
|
variable. Older builds, from before the setting existed, need nothing.
|
||||||
|
|
||||||
|
## What the server is allowed to touch
|
||||||
|
|
||||||
|
Every path in a tool call is chosen by the model, so without a policy this
|
||||||
|
server would be a read/write primitive for anything the operating system
|
||||||
|
lets the process reach: read any project on the disk, export one somewhere
|
||||||
|
else, overwrite an unrelated file, embed an arbitrary local image or PDF.
|
||||||
|
|
||||||
|
So **data paths are confined to a workspace**:
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| `QET_MCP_WORKSPACE` | the directories tool calls may read and write, separated by `:` (`;` on Windows) |
|
||||||
|
| unset | the directory the server was started in |
|
||||||
|
| `QET_MCP_ALLOW_ANY_PATH=1` | turns the check off entirely |
|
||||||
|
|
||||||
|
Set the workspace to the folder your drawings live in. A path outside it is
|
||||||
|
refused with an error naming what was allowed; symlinks are resolved first,
|
||||||
|
so a link planted inside the workspace is judged by where it points.
|
||||||
|
|
||||||
|
Two arguments are deliberately **not** confined: `binary` (the
|
||||||
|
`qelectrotech` executable) and `elements_dir` (the element collection).
|
||||||
|
Those are configuration, chosen once by whoever runs the server, and both
|
||||||
|
normally live in `/usr` or a build tree — outside any sensible workspace.
|
||||||
|
Confining them would reject the ordinary case while stopping nothing.
|
||||||
|
|
||||||
|
`QET_MCP_ALLOW_ANY_PATH=1` is equivalent to granting the client local
|
||||||
|
filesystem access with this process's privileges. It exists so that is a
|
||||||
|
deliberate choice rather than the default.
|
||||||
|
|
||||||
|
**Nothing is overwritten unasked.** `qet_export`, `qet_edit`,
|
||||||
|
`qet_project_new` and `qet_element_build` refuse an `output` that already
|
||||||
|
exists unless the call passes `"overwrite": true`. Replacing a file is the
|
||||||
|
one step this server cannot undo, so it is the one step it will not take on
|
||||||
|
its own.
|
||||||
|
|
||||||
|
The confinement is applied where tool arguments enter the server, not inside
|
||||||
|
each tool. Importing `qet_mcp` and calling `tool_export()` from your own
|
||||||
|
Python is not confined and is not meant to be — that is your code calling a
|
||||||
|
library, and you already chose the paths.
|
||||||
|
|
||||||
## Worked examples
|
## Worked examples
|
||||||
|
|
||||||
**What did that edit change?**
|
**What did that edit change?**
|
||||||
@@ -79,6 +153,74 @@ Register it with an MCP client, for example:
|
|||||||
Four elements moved by one uniform delta; nothing was relabelled. That is
|
Four elements moved by one uniform delta; nothing was relabelled. That is
|
||||||
the answer a screenshot gave wrongly.
|
the answer a screenshot gave wrongly.
|
||||||
|
|
||||||
|
**Draw something, and check it landed**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"name": "qet_edit", "arguments": {
|
||||||
|
"binary": "/path/to/qelectrotech",
|
||||||
|
"project": "in.qet", "output": "out.qet",
|
||||||
|
"elements_dir": "/path/to/qelectrotech/elements",
|
||||||
|
"operations": [
|
||||||
|
{"op": "add_folio", "id": "f"},
|
||||||
|
{"op": "set_folio_title", "folio": "$f", "title": "Starter"},
|
||||||
|
{"op": "add_element", "id": "k1", "folio": "$f", "path": "common://.../coil.elmt", "x": 100, "y": 100},
|
||||||
|
{"op": "add_element", "id": "k2", "folio": "$f", "path": "common://.../coil.elmt", "x": 320, "y": 100},
|
||||||
|
{"op": "add_conductor", "folio": "$f", "from": "$k1", "from_terminal": 0, "to": "$k2", "to_terminal": 0},
|
||||||
|
{"op": "set_conductor", "folio": "$f", "element": "$k1", "terminal": 0, "property": "num", "value": "W7"},
|
||||||
|
{"op": "set_label", "folio": "$f", "element": "$k1", "label": "KM1"}
|
||||||
|
]}}
|
||||||
|
```
|
||||||
|
|
||||||
|
An op that creates something takes an `"id"`; later ops name it as `"$id"`.
|
||||||
|
Terminals are addressed by index — top to bottom, then left to right, **not**
|
||||||
|
the order the `.elmt` lists them. `qet_element_info` and `qet_element_search`
|
||||||
|
both report that index order. The answer carries a per-operation result
|
||||||
|
*and* a `qet_diff`, because "addConductor → true" says the call was
|
||||||
|
accepted, not that the file came out right:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"diff": {"elements": {"before": 11, "after": 13, "added": ["{0aa3…}", "{6f63…}"]},
|
||||||
|
"conductors": {"before": 47, "after": 48, "added": ["4:{0aa3…}/{2904…}--{6f63…}/{2904…}"],
|
||||||
|
"removed": []}}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Draw a symbol that does not exist yet**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"name": "qet_element_build", "arguments": {
|
||||||
|
"output": "/path/to/collection/99_custom/my_resistor.elmt",
|
||||||
|
"names": {"en": "Test resistor", "fr": "Résistance de test"},
|
||||||
|
"parts": [
|
||||||
|
{"type": "rect", "x": -10, "y": -20, "width": 20, "height": 40},
|
||||||
|
{"type": "line", "x1": 0, "y1": -30, "x2": 0, "y2": -20},
|
||||||
|
{"type": "line", "x1": 0, "y1": 20, "x2": 0, "y2": 30},
|
||||||
|
{"type": "text", "x": 14, "y": -4, "text": "R"}
|
||||||
|
],
|
||||||
|
"terminals": [{"x": 0, "y": -30, "orientation": "n", "name": "1"},
|
||||||
|
{"x": 0, "y": 30, "orientation": "s", "name": "2"}]}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then place it with `qet_edit` like any catalogue element. Unlike a
|
||||||
|
project, a `.elmt` is not rewritten by QElectroTech on a round trip, so
|
||||||
|
generating one here is safe in a way that generating a `.qet` would not
|
||||||
|
be — there is no `toXml()` waiting to drop what this writer did not know
|
||||||
|
to emit.
|
||||||
|
|
||||||
|
**Ask a question the XML cannot answer**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"name": "qet_query", "arguments": {
|
||||||
|
"binary": "/path/to/qelectrotech", "project": "industrial.qet",
|
||||||
|
"sql": "SELECT label, COUNT(*) AS n FROM element_nomenclature_view WHERE label <> '' GROUP BY label HAVING n > 1 ORDER BY n DESC"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
"rows": [{"label": "V6", "n": 7}, {"label": "V5", "n": 6}, {"label": "V4", "n": 6}]
|
||||||
|
```
|
||||||
|
|
||||||
|
Duplicate element labels in a shipped example — a design-rule question,
|
||||||
|
answered by the database that already knew it.
|
||||||
|
|
||||||
**How much of a corpus uses a field?**
|
**How much of a corpus uses a field?**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -92,14 +234,43 @@ the answer a screenshot gave wrongly.
|
|||||||
|
|
||||||
Across the shipped examples: 3190 conductors, not one with a cable value.
|
Across the shipped examples: 3190 conductors, not one with a cable value.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 test_qet_mcp.py # unit + protocol, no QElectroTech needed
|
||||||
|
QET_BINARY=/path/to/qelectrotech \
|
||||||
|
QET_ELEMENTS=/path/to/qelectrotech/elements \
|
||||||
|
QET_EXAMPLES=/path/to/qelectrotech/examples \
|
||||||
|
QET_ENABLE_SCRIPTING=1 \
|
||||||
|
python3 test_qet_mcp.py # everything
|
||||||
|
```
|
||||||
|
|
||||||
|
`QET_ENABLE_SCRIPTING=1` matters from #984 onwards: without it the
|
||||||
|
integration tests that drive QElectroTech through a script all fail, and
|
||||||
|
they fail as "the edit did nothing" rather than as "scripting is off", which
|
||||||
|
reads like a regression in the thing under test.
|
||||||
|
|
||||||
|
176 tests in three layers: unit (validation, script generation, the terminal
|
||||||
|
order rule, the diff, the part schema), the real stdio transport, and
|
||||||
|
integration against a built QElectroTech. Several exist because the
|
||||||
|
behaviour they pin was once wrong and looked right, and say so in their
|
||||||
|
docstrings. To check the suite itself rather than trust it, each of those
|
||||||
|
bugs was reintroduced in turn and the suite confirmed to fail: ten in the
|
||||||
|
Python, plus the hang guard on `addConductor` and the database refresh in
|
||||||
|
`ConductorCreator` in the C++.
|
||||||
|
|
||||||
## Notes and limits
|
## Notes and limits
|
||||||
|
|
||||||
- **The project database is not reachable from outside the application.**
|
- **The project database is reachable now, through `qet_query`.** It was
|
||||||
`projectDataBase::newQuery()` and `isReadOnlySelect()` are C++-internal
|
not when this server was written, which is why every other structural
|
||||||
and the JavaScript scripting API exposes no SQL binding, so structural
|
tool here re-derives its answer from the XML. Prefer the views —
|
||||||
queries here are done over the XML. A `--query` CLI verb, or a scripting
|
`element_nomenclature_view`, `project_summary_view`, `wiring_list_view`
|
||||||
binding, would let this server expose the guarded read-only SQL surface
|
— which exist to be queried; the underlying tables are how the cache is
|
||||||
instead, and would be a better foundation.
|
arranged today and a column may move. Call `qet_query` with no `sql` to
|
||||||
|
list both. Only `SELECT` and `WITH` are accepted, which is the rule
|
||||||
|
QElectroTech applies to its own custom-query box, not one invented here.
|
||||||
|
An empty result and a failed query are told apart: `row_count` 0 with no
|
||||||
|
`error` means nothing matched, and a typo'd column name says so.
|
||||||
- **`qet_export` isolates its launch.** SingleApplication keys its socket
|
- **`qet_export` isolates its launch.** SingleApplication keys its socket
|
||||||
on `applicationFilePath()`, so a second launch of the same binary path
|
on `applicationFilePath()`, so a second launch of the same binary path
|
||||||
forwards its request to an already-running instance and returns *that*
|
forwards its request to an already-running instance and returns *that*
|
||||||
@@ -115,16 +286,64 @@ Across the shipped examples: 3190 conductors, not one with a cable value.
|
|||||||
its ends with `terminal1`/`terminal2`, and the project format has two
|
its ends with `terminal1`/`terminal2`, and the project format has two
|
||||||
schemes: folio-scoped integer ids in older files, terminal-definition
|
schemes: folio-scoped integer ids in older files, terminal-definition
|
||||||
uuids plus `element1`/`element2` in newer ones. The integer ids are
|
uuids plus `element1`/`element2` in newer ones. The integer ids are
|
||||||
**renumbered on every save**, so keying on them made all 47 conductors of
|
**renumbered on every save**, so keying on them — which this tool did at
|
||||||
an untouched `ArduinoLCD.qet` read as 29 removed and 29 re-added the
|
first — made all 47 conductors of an untouched folio read as removed and
|
||||||
moment the other side had been through QElectroTech. Ends are now keyed
|
re-added the moment the other side had been through QElectroTech, which
|
||||||
by owning element uuid plus terminal, which is stable across a save:
|
is exactly what `qet_edit` produces. They are now keyed by owning element
|
||||||
measured at 0 colliding keys over 3190 conductors in the 24 shipped
|
uuid plus terminal, which is stable across a save: measured at 0 colliding
|
||||||
examples, and 0 churn on a re-saved but otherwise untouched project.
|
keys over 3190 conductors in the 24 shipped examples, and 0 churn on a
|
||||||
Where an element predates persisted uuids the end cannot be resolved and
|
no-op edit. Where an element predates persisted uuids the end cannot be
|
||||||
keeps a `#`-marked unstable key; the diff then reports `unstable_keys`
|
resolved and keeps a `#`-marked unstable key; the diff then reports
|
||||||
and says so rather than pretending to be comparable.
|
`unstable_keys` and says so rather than pretending to be comparable.
|
||||||
|
- **Texts, shapes and images have no uuid**, so `qet_diff` cannot say "the same
|
||||||
|
text, edited": an edited text reads as the old one removed and a new one
|
||||||
|
added, both shown. Shapes and images are keyed by position, so a restyle
|
||||||
|
or rescale *is* reported as a change to that item, but a move reads as a
|
||||||
|
removal plus an addition. The folio `version` attribute is left out of the
|
||||||
|
comparison on purpose: QElectroTech rewrites it on every save, and
|
||||||
|
including it made every folio of any re-saved project look edited.
|
||||||
- **Elements** written before persisted uuids fall back to a positional key,
|
- **Elements** written before persisted uuids fall back to a positional key,
|
||||||
which makes a move in such a file read as a remove plus an add rather
|
which makes a move in such a file read as a remove plus an add.
|
||||||
than as a move.
|
- **`qet_edit` needs a build whose scripting API carries the drawing verbs.**
|
||||||
- Read-only by design. Nothing here writes to a project.
|
Against an older one it reports exactly which methods are missing and
|
||||||
|
changes nothing. `addElement` and the move/delete verbs shipped with the
|
||||||
|
scripting API; `addConductor`, `rotateElement`, `setElementLabel`,
|
||||||
|
`setElementInfo` and `setFolioTitle` are newer.
|
||||||
|
- **`elements_dir` is not optional for `common://` paths.** The sandboxed
|
||||||
|
run has its own empty HOME, so QElectroTech falls back to the compiled-in
|
||||||
|
collection path, which on a machine that never ran `make install` does not
|
||||||
|
exist. The only symptom is `addElement` reporting that a file plainly
|
||||||
|
present "does not resolve to an element". An absolute `.elmt` path works
|
||||||
|
without it.
|
||||||
|
- **`set_conductor` changes the whole potential, not one segment.** That is
|
||||||
|
what the application does — a wire number describes a potential — so name
|
||||||
|
a terminal carrying exactly one conductor and the change reaches every
|
||||||
|
conductor electrically joined to it. A terminal several conductors meet
|
||||||
|
at names none of them and is refused, so address a potential from one of
|
||||||
|
its leaves. Property names are the file's own, so `qet_conductors` reads
|
||||||
|
back exactly what was set.
|
||||||
|
- **`link_elements` takes a folio for each end**, because a master and its
|
||||||
|
slave are normally on different folios. Whether a pair may be linked is
|
||||||
|
decided by QElectroTech's own `isLinkable()`, so a script cannot make a
|
||||||
|
link the GUI would refuse.
|
||||||
|
- **An element must live inside a collection to be placeable.** This is
|
||||||
|
not about the path syntax: an absolute `.elmt` path works, but only if
|
||||||
|
the file sits under a directory QElectroTech knows as a collection.
|
||||||
|
Write it under the tree you pass as `elements_dir` and `qet_edit` can
|
||||||
|
place it, by absolute path or as `common://…`; write it anywhere else
|
||||||
|
and `add_element` reports only "does not resolve to an element".
|
||||||
|
- **`qet_element_build` computes the `.elmt` size header, and checks it.**
|
||||||
|
`width`/`height`/`hotspot_x`/`hotspot_y` relate to the drawing by a
|
||||||
|
containment constraint, not a formula — the declared box runs from
|
||||||
|
`(-hotspot_x, -hotspot_y)` to `(width - hotspot_x, height - hotspot_y)`
|
||||||
|
and the drawing must fit inside it. The shipped collection shows authors
|
||||||
|
picking their own margins (one element pads 2 units left and 3 right,
|
||||||
|
another 8 and 2), so there is no convention to copy, only an invariant
|
||||||
|
to satisfy. A drawing that escaped its box is the classic way a
|
||||||
|
hand-written element renders clipped in the collection panel while
|
||||||
|
looking fine in XML.
|
||||||
|
- **QElectroTech interrupts a script at 30 s** of its own accord, separately
|
||||||
|
from this tool's `timeout`. A very long operation list will hit that
|
||||||
|
first.
|
||||||
|
- **`qet_edit` never writes the input.** It saves to a separate file and
|
||||||
|
diffs the two, so the original is always the thing the diff is against.
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,44 @@
|
|||||||
|
<definition version="0.100.0" type="element" link_type="master" width="40" height="60" hotspot_x="17" hotspot_y="32">
|
||||||
|
<uuid uuid="{6d3714f6-a0e1-71b3-e4bd-5a35d4cbbec1}"/>
|
||||||
|
<names>
|
||||||
|
<name lang="ar">ملف KA بمحتفظ مغناطيسي</name>
|
||||||
|
<name lang="ca">Bobina</name>
|
||||||
|
<name lang="cs">Bistabilní remanentní relé</name>
|
||||||
|
<name lang="de">Remanenzrelais</name>
|
||||||
|
<name lang="el">Πηνίο με μανδάλωση</name>
|
||||||
|
<name lang="en">Coil</name>
|
||||||
|
<name lang="es">Bobina KA de remanencia</name>
|
||||||
|
<name lang="fr">Bobine KA à rémanence</name>
|
||||||
|
<name lang="hu">Tekercs</name>
|
||||||
|
<name lang="it">Bobina</name>
|
||||||
|
<name lang="nl">spoel remanent</name>
|
||||||
|
<name lang="nl_BE">Spoel KA remanent</name>
|
||||||
|
<name lang="pl">Cewka przekaźnika remanencyjnego</name>
|
||||||
|
<name lang="pt_BR">Bobina</name>
|
||||||
|
<name lang="ru">Обмотка</name>
|
||||||
|
<name lang="zh">剩磁保持线圈</name>
|
||||||
|
</names>
|
||||||
|
<kindInformations>
|
||||||
|
<kindInformation name="type">plc</kindInformation>
|
||||||
|
</kindInformations>
|
||||||
|
<informations>Author: The QElectroTech team
|
||||||
|
License: see http://qelectrotech.org/wiki/doc/elements_license</informations>
|
||||||
|
<description>
|
||||||
|
<rect x="14" y="-8" width="6" height="16" rx="0" ry="0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="false"/>
|
||||||
|
<line x1="0" y1="-20" x2="0" y2="-8" end1="none" end2="none" length1="1.5" length2="1.5" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="false"/>
|
||||||
|
<dynamic_text x="2" y="11.33" z="5" text_width="-1" Halignment="AlignLeft" Valignment="AlignTop" frame="false" rotation="0" keep_visual_rotation="false" text_from="UserText" uuid="{647e33ed-520b-4d80-bbc4-7b31177b8f26}" font="Liberation Sans,4,-1,5,25,0,0,0,0,0,Regular">
|
||||||
|
<text>A2</text>
|
||||||
|
</dynamic_text>
|
||||||
|
<dynamic_text x="2" y="-24.67" z="6" text_width="-1" Halignment="AlignLeft" Valignment="AlignTop" frame="false" rotation="0" keep_visual_rotation="false" text_from="UserText" uuid="{fb1f8de9-70c0-4801-8dc7-12e6bf88d8f5}" font="Liberation Sans,4,-1,5,25,0,0,0,0,0,Regular">
|
||||||
|
<text>A1</text>
|
||||||
|
</dynamic_text>
|
||||||
|
<line x1="0" y1="8" x2="0" y2="20" end1="none" end2="none" length1="1.5" length2="1.5" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="false"/>
|
||||||
|
<dynamic_text x="30" y="-9.17" z="8" text_width="-1" Halignment="AlignLeft" Valignment="AlignTop" frame="false" rotation="0" keep_visual_rotation="false" text_from="ElementInfo" uuid="{b7fccfc3-05f1-459c-9766-f49a481bd0ff}" font="Liberation Sans,9,-1,5,50,0,0,0,0,0,Regular">
|
||||||
|
<text></text>
|
||||||
|
<info_name>label</info_name>
|
||||||
|
</dynamic_text>
|
||||||
|
<polygon x1="-14" y1="-8" x2="14" y2="-8" x3="20" y3="8" x4="-14" y4="8" antialias="false" style="line-style:normal;line-weight:normal;filling:none;color:black"/>
|
||||||
|
<terminal uuid="{6a87c921-6f5d-4f5c-8673-228a6d13c5c8}" name="A2" x="0" y="20" orientation="s" type="Generic"/>
|
||||||
|
<terminal uuid="{2904e5fa-6bbe-4127-acdd-f92feadd6ece}" name="A1" x="0" y="-20" orientation="n" type="Generic"/>
|
||||||
|
</description>
|
||||||
|
</definition>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<definition version="0.100.0" type="element" link_type="slave" width="20" height="60" hotspot_x="9" hotspot_y="30">
|
||||||
|
<uuid uuid="{94d56f06-6814-5561-9148-2da3a9c4f900}"/>
|
||||||
|
<names>
|
||||||
|
<name lang="en">PLC Slave Test</name>
|
||||||
|
</names>
|
||||||
|
<kindInformations>
|
||||||
|
<kindInformation name="type">plc</kindInformation>
|
||||||
|
<kindInformation name="state">NO</kindInformation>
|
||||||
|
<kindInformation name="number">1</kindInformation>
|
||||||
|
</kindInformations>
|
||||||
|
<description>
|
||||||
|
<rect x="0" y="-8" width="6" height="16" rx="0" ry="0" style="line-style:normal;line-weight:normal;filling:none;color:black" antialias="false"/>
|
||||||
|
<terminal uuid="{6a87c921-6f5d-4f5c-8673-228a6d13c500}" name="1" x="0" y="20" orientation="s" type="Generic"/>
|
||||||
|
<terminal uuid="{2904e5fa-6bbe-4127-acdd-f92feadd6e00}" name="2" x="0" y="-20" orientation="n" type="Generic"/>
|
||||||
|
</description>
|
||||||
|
</definition>
|
||||||
+2060
-8
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||||
|
|
||||||
@@ -647,7 +655,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()) ||
|
||||||
|
|||||||
@@ -653,9 +653,16 @@ 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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -896,10 +896,20 @@ void BorderTitleBlock::updateDiagramContextForTitleBlock(
|
|||||||
// An empty page-level value means the variable was auto-added to the
|
// An empty page-level value means the variable was auto-added to the
|
||||||
// folio's Custom tab (#495) but never actually set by the user, so it
|
// folio's Custom tab (#495) but never actually set by the user, so it
|
||||||
// must not shadow a real project-level value of the same name (#531).
|
// must not shadow a real project-level value of the same name (#531).
|
||||||
|
//
|
||||||
|
// That guard has to stop short of removing the key outright, though
|
||||||
|
// (#973). TitleBlockTemplate::interpreteVariables() only replaces a
|
||||||
|
// "%name"/"%{name}" placeholder when "name" is a key in this context at
|
||||||
|
// all -- an unset variable that never makes it in is left as its own
|
||||||
|
// literal placeholder text in the rendered title block, not blank.
|
||||||
|
// So an empty page-level value is skipped only when a real project-level
|
||||||
|
// one is already there to show through; otherwise it still goes in
|
||||||
|
// empty, which is what makes the placeholder resolve to nothing.
|
||||||
DiagramContext context = initial_context;
|
DiagramContext context = initial_context;
|
||||||
foreach (QString key, additional_fields_.keys()) {
|
foreach (QString key, additional_fields_.keys()) {
|
||||||
if (!additional_fields_[key].toString().isEmpty())
|
const QVariant value = additional_fields_[key];
|
||||||
context.addValue(key, additional_fields_[key]);
|
if (!value.toString().isEmpty() || !context.contains(key))
|
||||||
|
context.addValue(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... overridden by the historical and/or dynamically generated fields
|
// ... overridden by the historical and/or dynamically generated fields
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
#include "projectdatabase.h"
|
#include "projectdatabase.h"
|
||||||
|
|
||||||
|
#include "sqlreadonly.h"
|
||||||
|
|
||||||
#include "../diagram.h"
|
#include "../diagram.h"
|
||||||
#include "../diagramposition.h"
|
#include "../diagramposition.h"
|
||||||
#include "../elementprovider.h"
|
#include "../elementprovider.h"
|
||||||
@@ -28,13 +30,15 @@
|
|||||||
#include "../qetproject.h"
|
#include "../qetproject.h"
|
||||||
|
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
|
#include <QFile>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QSqlError>
|
|
||||||
|
|
||||||
#include <QSqlDriver>
|
#include <QSqlDriver>
|
||||||
|
#include <QSqlError>
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief projectDataBase::projectDataBase
|
@brief projectDataBase::projectDataBase
|
||||||
Default constructor
|
Default constructor
|
||||||
@@ -208,6 +212,12 @@ bool projectDataBase::isReadOnlySelect(const QString &query, QString *error)
|
|||||||
*/
|
*/
|
||||||
QSqlQuery projectDataBase::newQuery(const QString &query, QString *error) {
|
QSqlQuery projectDataBase::newQuery(const QString &query, QString *error) {
|
||||||
QString reason;
|
QString reason;
|
||||||
|
|
||||||
|
// First gate: which kind of statement is acceptable here at all. A
|
||||||
|
// textual check is the right tool for that and the wrong tool for
|
||||||
|
// anything else -- see isReadOnlySelect()'s own comment. It is what
|
||||||
|
// keeps ATTACH, BEGIN and PRAGMA out, none of which SQLite itself
|
||||||
|
// considers writes.
|
||||||
if (!isReadOnlySelect(query, &reason)) {
|
if (!isReadOnlySelect(query, &reason)) {
|
||||||
qWarning().noquote() << "projectDataBase::newQuery: rejected query:" << reason << "--" << query;
|
qWarning().noquote() << "projectDataBase::newQuery: rejected query:" << reason << "--" << query;
|
||||||
if (error) {
|
if (error) {
|
||||||
@@ -215,6 +225,24 @@ QSqlQuery projectDataBase::newQuery(const QString &query, QString *error) {
|
|||||||
}
|
}
|
||||||
return QSqlQuery(m_data_base);
|
return QSqlQuery(m_data_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Second gate, and the one that actually enforces read-only: SQLite is
|
||||||
|
// asked about the statement it compiled, instead of the text being read
|
||||||
|
// for clues. The first gate cannot see through a CTE prefix --
|
||||||
|
// "WITH x AS (SELECT 1) DELETE FROM element" starts with WITH, contains
|
||||||
|
// no semicolon, and deletes every row. That matters beyond the
|
||||||
|
// custom-query box, because this path is reachable from a file: a
|
||||||
|
// <graphics_table>'s saved <query> is read straight out of the .qet by
|
||||||
|
// ProjectDBModel::fromXml() and executed by fillValue(), so opening or
|
||||||
|
// exporting a project someone else produced would have been enough.
|
||||||
|
if (!QETSql::isSingleReadOnlyStatement(sqliteHandle(&m_data_base), query, &reason)) {
|
||||||
|
qWarning().noquote() << "projectDataBase::newQuery: rejected query:" << reason << "--" << query;
|
||||||
|
if (error) {
|
||||||
|
*error = reason;
|
||||||
|
}
|
||||||
|
return QSqlQuery(m_data_base);
|
||||||
|
}
|
||||||
|
|
||||||
return QSqlQuery(query, m_data_base);
|
return QSqlQuery(query, m_data_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1131,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()) {
|
||||||
@@ -1245,7 +1301,6 @@ void projectDataBase::bindDiagramInfoValues(QSqlQuery &query, Diagram *diagram)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef QET_EXPORT_PROJECT_DB
|
|
||||||
/**
|
/**
|
||||||
@brief projectDataBase::sqliteHandle
|
@brief projectDataBase::sqliteHandle
|
||||||
@param db
|
@param db
|
||||||
@@ -1263,6 +1318,7 @@ sqlite3 *projectDataBase::sqliteHandle(QSqlDatabase *db)
|
|||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef QET_EXPORT_PROJECT_DB
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief projectDataBase::exportDb
|
* @brief projectDataBase::exportDb
|
||||||
@@ -1298,27 +1354,19 @@ void projectDataBase::exportDb(projectDataBase *db,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString connection_name("export_project_db_" % db->project()->uuid().toString());
|
// VACUUM INTO requires the destination not to exist. QFileDialog may ask
|
||||||
|
// about overwriting, but it does not remove the existing file for us.
|
||||||
if (true) //Enter in a scope only to nicely use QSqlDatabase::removeDatabase just after the end of the scope
|
if (QFile::exists(path_) && !QFile::remove(path_)) {
|
||||||
{
|
qWarning() << "Unable to replace project database export:" << path_;
|
||||||
auto file_db = QSqlDatabase::addDatabase("QSQLITE", connection_name);
|
return;
|
||||||
file_db.setDatabaseName(path_);
|
}
|
||||||
if (!file_db.open()) {
|
|
||||||
return;
|
// VACUUM INTO creates a standalone copy of the current database without
|
||||||
}
|
// requiring access to the SQLite driver's native connection handle.
|
||||||
|
const auto escaped_path = path_.replace("'", "''");
|
||||||
auto memory_db_handle = sqliteHandle(&db->m_data_base);
|
QSqlQuery query(db->m_data_base);
|
||||||
auto file_db_handle = sqliteHandle(&file_db);
|
if (!query.exec("VACUUM INTO '" % escaped_path % "'")) {
|
||||||
|
qWarning() << "Unable to export project database:" << query.lastError().text();
|
||||||
auto sqlite_backup = sqlite3_backup_init(file_db_handle, "main", memory_db_handle, "main");
|
|
||||||
if (sqlite_backup)
|
|
||||||
{
|
|
||||||
sqlite3_backup_step(sqlite_backup, -1);
|
|
||||||
sqlite3_backup_finish(sqlite_backup);
|
|
||||||
}
|
|
||||||
file_db.close();
|
|
||||||
}
|
}
|
||||||
QSqlDatabase::removeDatabase(connection_name);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -61,6 +61,26 @@ class projectDataBase : public QObject
|
|||||||
QETProject *project() const;
|
QETProject *project() const;
|
||||||
QSqlQuery newQuery(const QString &query = QString(), QString *error = nullptr);
|
QSqlQuery newQuery(const QString &query = QString(), QString *error = nullptr);
|
||||||
static bool isReadOnlySelect(const QString &query, QString *error = nullptr);
|
static bool isReadOnlySelect(const QString &query, QString *error = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
The most rows any caller reads out of one query result.
|
||||||
|
|
||||||
|
A SELECT is not bounded by how much data the project holds:
|
||||||
|
SQLite produces rows lazily, so a query that never stops
|
||||||
|
producing them makes the loop that reads them never stop
|
||||||
|
either. A recursive CTE does exactly that in one line, and
|
||||||
|
a <graphics_table>'s <query> is stored in the .qet and run
|
||||||
|
on load -- so the text can arrive from a file rather than
|
||||||
|
from the person at the keyboard, and opening that file is
|
||||||
|
the whole attack.
|
||||||
|
|
||||||
|
100000 is far above any real result: the largest table in
|
||||||
|
the shipped examples is 396 rows. It is a backstop, not a
|
||||||
|
page size -- a caller that hits it has almost certainly
|
||||||
|
been handed something it should not run to completion, and
|
||||||
|
says so rather than truncating quietly.
|
||||||
|
*/
|
||||||
|
static constexpr int MaxResultRows = 100000;
|
||||||
QSqlDatabase database() const {return m_data_base;}
|
QSqlDatabase database() const {return m_data_base;}
|
||||||
int excludedConductorCount() const;
|
int excludedConductorCount() const;
|
||||||
|
|
||||||
@@ -119,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,
|
||||||
@@ -135,9 +156,14 @@ class projectDataBase : public QObject
|
|||||||
m_cascade_remove_conductor_query,
|
m_cascade_remove_conductor_query,
|
||||||
m_cascade_remove_element_query;
|
m_cascade_remove_element_query;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Deliberately outside the QET_EXPORT_PROJECT_DB guard below:
|
||||||
|
// newQuery() needs the raw connection to ask SQLite whether a
|
||||||
|
// query only reads, and that check runs in every build.
|
||||||
|
static sqlite3 *sqliteHandle(QSqlDatabase *db);
|
||||||
|
|
||||||
#ifdef QET_EXPORT_PROJECT_DB
|
#ifdef QET_EXPORT_PROJECT_DB
|
||||||
public:
|
public:
|
||||||
static sqlite3 *sqliteHandle(QSqlDatabase *db);
|
|
||||||
static void exportDb(projectDataBase *db,
|
static void exportDb(projectDataBase *db,
|
||||||
QWidget *parent = nullptr,
|
QWidget *parent = nullptr,
|
||||||
const QString &caption = QString(),
|
const QString &caption = QString(),
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
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 "sqlreadonly.h"
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
namespace QETSql {
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief QETSql::isSingleReadOnlyStatement
|
||||||
|
Ask SQLite itself whether @p query is exactly one statement, and whether
|
||||||
|
that statement only reads.
|
||||||
|
|
||||||
|
Why SQLite is asked rather than the text inspected: a check on the
|
||||||
|
query's first keyword cannot see what the statement actually does.
|
||||||
|
SQLite has allowed a CTE prefix in front of a data-modifying statement
|
||||||
|
since 3.8.3, so
|
||||||
|
|
||||||
|
@code
|
||||||
|
WITH x AS (SELECT 1) DELETE FROM element
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
begins with WITH, contains no semicolon, and deletes every row.
|
||||||
|
sqlite3_stmt_readonly() reports on the statement SQLite compiled, not
|
||||||
|
on how it was spelled, so the same query is correctly refused here
|
||||||
|
while an ordinary WITH ... SELECT still passes.
|
||||||
|
|
||||||
|
The statement is compiled and immediately finalised; sqlite3_prepare_v2()
|
||||||
|
does not run it, so nothing is executed to reach this verdict.
|
||||||
|
|
||||||
|
This is a read-only test, NOT a statement-type allowlist: SQLite
|
||||||
|
considers ATTACH, BEGIN and several PRAGMAs read-only too, because none
|
||||||
|
of them change the contents of the database. Callers that need to
|
||||||
|
restrict which *kind* of statement is acceptable must say so separately
|
||||||
|
-- projectDataBase::newQuery() keeps isReadOnlySelect() in front of this
|
||||||
|
for exactly that reason.
|
||||||
|
|
||||||
|
@param handle the connection the query would run on. A null handle is
|
||||||
|
refused rather than waved through: without it there is nothing to ask,
|
||||||
|
and guessing from the text is the weakness this exists to replace.
|
||||||
|
@param query the raw SQL text
|
||||||
|
@param error set to a human-readable reason when this returns false
|
||||||
|
@return true if @p query is a single, read-only statement
|
||||||
|
*/
|
||||||
|
bool isSingleReadOnlyStatement(sqlite3 *handle, const QString &query, QString *error)
|
||||||
|
{
|
||||||
|
if (error) {
|
||||||
|
error->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!handle) {
|
||||||
|
if (error) {
|
||||||
|
*error = QCoreApplication::translate("QETSql",
|
||||||
|
"Impossible de vérifier la requête : "
|
||||||
|
"aucune connexion SQLite disponible.");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QByteArray utf8 = query.toUtf8();
|
||||||
|
sqlite3_stmt *statement = nullptr;
|
||||||
|
const char *tail = nullptr;
|
||||||
|
|
||||||
|
if (sqlite3_prepare_v2(handle, utf8.constData(), utf8.size(),
|
||||||
|
&statement, &tail) != SQLITE_OK)
|
||||||
|
{
|
||||||
|
if (error) {
|
||||||
|
*error = QCoreApplication::translate("QETSql",
|
||||||
|
"Requête SQL invalide : %1")
|
||||||
|
.arg(QString::fromUtf8(sqlite3_errmsg(handle)));
|
||||||
|
}
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whitespace or a bare comment compiles successfully to no statement
|
||||||
|
// at all, and sqlite3_stmt_readonly() must not be handed that.
|
||||||
|
if (!statement) {
|
||||||
|
if (error) {
|
||||||
|
*error = QCoreApplication::translate("QETSql",
|
||||||
|
"La requête ne contient aucune instruction.");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool read_only = sqlite3_stmt_readonly(statement) != 0;
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
|
||||||
|
if (!read_only) {
|
||||||
|
if (error) {
|
||||||
|
*error = QCoreApplication::translate("QETSql",
|
||||||
|
"Seules les requêtes en lecture seule sont autorisées : "
|
||||||
|
"cette requête modifierait la base de données.");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tail points just past the first statement, semicolon included.
|
||||||
|
// Anything left once semicolons and spacing are stripped is a second
|
||||||
|
// statement -- caught structurally here, where "SELECT ';'" is a
|
||||||
|
// perfectly ordinary query rather than a suspicious string.
|
||||||
|
if (tail) {
|
||||||
|
QString rest = QString::fromUtf8(tail);
|
||||||
|
rest.remove(QLatin1Char(';'));
|
||||||
|
if (!rest.trimmed().isEmpty()) {
|
||||||
|
if (error) {
|
||||||
|
*error = QCoreApplication::translate("QETSql",
|
||||||
|
"Une seule requête est autorisée.");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QETSql
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
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 SQLREADONLY_H
|
||||||
|
#define SQLREADONLY_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
struct sqlite3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Deciding whether a piece of SQL only reads.
|
||||||
|
|
||||||
|
Deliberately its own translation unit, depending on nothing but QString
|
||||||
|
and SQLite: it is the enforcement point for every query QElectroTech
|
||||||
|
runs against a project database, including queries that arrive from
|
||||||
|
outside the application (a .qet file's saved report/table query), so it
|
||||||
|
is worth being able to test it in isolation -- see
|
||||||
|
tests/qttest/tst_sqlreadonly.cpp, which links this file and nothing
|
||||||
|
else of QElectroTech.
|
||||||
|
*/
|
||||||
|
namespace QETSql {
|
||||||
|
|
||||||
|
bool isSingleReadOnlyStatement(sqlite3 *handle,
|
||||||
|
const QString &query,
|
||||||
|
QString *error = nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SQLREADONLY_H
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -151,8 +151,8 @@ bool DiagramContext::operator!=(const DiagramContext &dc) const
|
|||||||
void DiagramContext::toXml(QDomElement &e, const QString &tag_name) const
|
void DiagramContext::toXml(QDomElement &e, const QString &tag_name) const
|
||||||
{
|
{
|
||||||
foreach (QString key, keys()) {
|
foreach (QString key, keys()) {
|
||||||
if ((tag_name == "elementInformation") &&
|
const QString raw = m_content[key].toString();
|
||||||
(m_content[key].toString().trimmed().isEmpty())) {
|
if ((tag_name == "elementInformation") && raw.trimmed().isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QDomElement property = e.ownerDocument().createElement(tag_name);
|
QDomElement property = e.ownerDocument().createElement(tag_name);
|
||||||
@@ -161,7 +161,15 @@ void DiagramContext::toXml(QDomElement &e, const QString &tag_name) const
|
|||||||
property.removeAttribute("name");
|
property.removeAttribute("name");
|
||||||
property.setAttribute("show", m_content_show[key]);
|
property.setAttribute("show", m_content_show[key]);
|
||||||
property.setAttribute("name", key);
|
property.setAttribute("name", key);
|
||||||
QDomText value = e.ownerDocument().createTextNode(m_content[key].toString().trimmed());
|
// Trim stray leading/trailing whitespace around real content, but
|
||||||
|
// not a value that IS whitespace: unconditionally trimming an
|
||||||
|
// all-whitespace string collapses it to "", which is silently
|
||||||
|
// indistinguishable from a value that was never set. A title-block
|
||||||
|
// custom variable set to a single space -- a workaround for #973,
|
||||||
|
// where an unset variable renders as its own literal placeholder --
|
||||||
|
// would otherwise vanish on the very next save.
|
||||||
|
const QString stored = raw.trimmed().isEmpty() ? raw : raw.trimmed();
|
||||||
|
QDomText value = e.ownerDocument().createTextNode(stored);
|
||||||
property.appendChild(value);
|
property.appendChild(value);
|
||||||
e.appendChild(property);
|
e.appendChild(property);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "../qetapp.h"
|
#include "../qetapp.h"
|
||||||
#include "../qetdiagrameditor.h"
|
#include "../qetdiagrameditor.h"
|
||||||
#include "../qetgraphicsitem/conductor.h"
|
#include "../qetgraphicsitem/conductor.h"
|
||||||
|
#include "../qetproject.h"
|
||||||
|
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
|
||||||
@@ -40,6 +41,7 @@
|
|||||||
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.
|
||||||
@@ -51,8 +53,25 @@
|
|||||||
QDomDocument document_xml;
|
QDomDocument document_xml;
|
||||||
if (!document_xml.setContent(clipboard_text)) return;
|
if (!document_xml.setContent(clipboard_text)) return;
|
||||||
|
|
||||||
|
//Batch the database work the same way project loading does
|
||||||
|
//(QETProject::readProjectXml): without this, every addItem()
|
||||||
|
//below emits dataBaseUpdated(), which makes each connected
|
||||||
|
//table model re-run its full SQL query -- ~77 queries for a
|
||||||
|
//typical paste, i.e. the multi-second stall on Ctrl+V.
|
||||||
|
auto *db = m_diagram->project() ? m_diagram->project()->dataBase() : nullptr;
|
||||||
|
if (db) {
|
||||||
|
db->blockSignals(true);
|
||||||
|
db->setUpdateBlocked(true);
|
||||||
|
}
|
||||||
|
|
||||||
//Load items at their original XML coordinates.
|
//Load items at their original XML coordinates.
|
||||||
m_diagram->fromXml(document_xml, QPointF(), false, &m_content);
|
m_diagram->fromXml(document_xml, QPointF(), false, &m_content);
|
||||||
|
|
||||||
|
if (db) {
|
||||||
|
db->blockSignals(false);
|
||||||
|
db->setUpdateBlocked(false);
|
||||||
|
db->updateDB();
|
||||||
|
}
|
||||||
if (!m_content.count()) return;
|
if (!m_content.count()) return;
|
||||||
|
|
||||||
const QList<QGraphicsItem *> movable = m_content.items(MovableItems);
|
const QList<QGraphicsItem *> movable = m_content.items(MovableItems);
|
||||||
@@ -85,33 +104,23 @@
|
|||||||
};
|
};
|
||||||
const QPointF grid_origin = snapGrid(top_left);
|
const QPointF grid_origin = snapGrid(top_left);
|
||||||
|
|
||||||
//Move the group to the cursor, rather than the cursor to the
|
//Store each item's original position. moveTo() applies a
|
||||||
//group. Both put the copy under the pointer, but warping the
|
|
||||||
//pointer also drags it back to the original's position, so the
|
|
||||||
//copy appears exactly on top of what was copied until the mouse
|
|
||||||
//is moved -- which is the thing pasting under the cursor was
|
|
||||||
//meant to avoid (issue #913). Taking the pointer away from
|
|
||||||
//where the user put it is also its own surprise.
|
|
||||||
m_group_origin = snapGrid(start_pos);
|
|
||||||
const QPointF offset = m_group_origin - grid_origin;
|
|
||||||
|
|
||||||
//Store each item's position after the move. 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) {
|
||||||
item->setPos(item->pos() + offset);
|
|
||||||
m_relative_pos.insert(item, item->pos());
|
m_relative_pos.insert(item, item->pos());
|
||||||
}
|
}
|
||||||
|
m_group_origin = grid_origin;
|
||||||
|
|
||||||
//The conductors were laid out against the old terminal
|
//The conductors were laid out against the original terminal
|
||||||
//positions, so re-route them before anything is drawn.
|
//positions, so re-route them before anything is drawn.
|
||||||
const QList<Conductor *> conductors = m_content.conductors(DiagramContent::AnyConductor);
|
const QList<Conductor *> conductors = m_content.conductors(DiagramContent::AnyConductor);
|
||||||
for (auto *conductor : conductors) {
|
for (auto *conductor : conductors) {
|
||||||
conductor->updatePath();
|
conductor->updatePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
//The baseline is known now, so moveTo() does not have to
|
//The baseline is the group's grid-snapped origin, so moveTo()
|
||||||
//capture one from the first mouse movement.
|
//does not have to capture one from the first mouse movement.
|
||||||
m_initial_cursor = m_group_origin;
|
m_initial_cursor = m_group_origin;
|
||||||
m_baseline_captured = true;
|
m_baseline_captured = true;
|
||||||
|
|
||||||
@@ -125,6 +134,14 @@
|
|||||||
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();
|
||||||
|
|||||||
+77
-1
@@ -445,6 +445,82 @@ void DiagramView::pasteHere()
|
|||||||
paste(mapToScene(m_paste_here_pos));
|
paste(mapToScene(m_paste_here_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief DiagramView::duplicate
|
||||||
|
Copy the current selection and place the copy at @p stepOffset grid
|
||||||
|
steps from it, landing immediately rather than following the cursor
|
||||||
|
like Ctrl+V does (bugtracker #991). @p stepOffset comes from
|
||||||
|
DuplicateOffsetDialog: (1, 0) is one grid step right, (0, -1) is one
|
||||||
|
grid step up, and so on -- QET's own scene axes, X right and Y down.
|
||||||
|
|
||||||
|
No interactive placement step on purpose: the point of a duplicate
|
||||||
|
shortcut is unattended, repeatable stamping (configure the offset
|
||||||
|
once, then tap Ctrl+D to lay out a row), which following the cursor
|
||||||
|
would interrupt on every press. QET already reselects whatever a
|
||||||
|
paste just added (see PasteDiagramCommand::redo()), so the next
|
||||||
|
Ctrl+D naturally continues from the copy just placed, not the
|
||||||
|
original -- a press-and-hold row falls out of that for free, with no
|
||||||
|
special-casing needed here for "keep going from the last one".
|
||||||
|
|
||||||
|
The offset is applied by hand rather than by asking paste()/
|
||||||
|
Diagram::fromXml() to place the copy at a target position. Both of
|
||||||
|
those feed the position through Diagram::snapToGrid(), which reads
|
||||||
|
QApplication::keyboardModifiers() and rounds to the nearest PIXEL
|
||||||
|
instead of the grid whenever Ctrl is held -- and Ctrl is always held
|
||||||
|
here, this action's own shortcut being Ctrl+D. Measured the hard way
|
||||||
|
before settling on this: routing the offset through paste() first
|
||||||
|
produced copies off-grid on both axes, by an amount that tracked the
|
||||||
|
selection's own bounding-box geometry rather than being a fixed
|
||||||
|
error. fromXml() is instead called with no position at all, which
|
||||||
|
leaves every item at its source coordinates (landing the copy
|
||||||
|
exactly on top of the originals -- (0, 0) is not a position, this is
|
||||||
|
"keep the source coordinates"), and the offset is added directly
|
||||||
|
with setPos(). A plain addition cannot be off by a rounding rule
|
||||||
|
that never runs.
|
||||||
|
|
||||||
|
Conductors are not in the translated set: fromXml() itself does not
|
||||||
|
reposition them either -- they are loaded from XML after elements
|
||||||
|
are already in their final place and take their geometry from their
|
||||||
|
terminals, which have already moved with the elements that own
|
||||||
|
them. Likewise dynamic element texts are not translated separately:
|
||||||
|
they are children of their element and move with it under Qt's
|
||||||
|
normal parent-child transform.
|
||||||
|
*/
|
||||||
|
void DiagramView::duplicate(const QPoint &stepOffset)
|
||||||
|
{
|
||||||
|
if (!isInteractive() || m_diagram->isReadOnly()) return;
|
||||||
|
|
||||||
|
const QList<QGraphicsItem *> selection = m_diagram->selectedItems();
|
||||||
|
if (selection.isEmpty()) return;
|
||||||
|
|
||||||
|
QSettings settings;
|
||||||
|
const int x_grid = settings.value(QStringLiteral("diagrameditor/Xgrid"),
|
||||||
|
Diagram::xGrid).toInt();
|
||||||
|
const int y_grid = settings.value(QStringLiteral("diagrameditor/Ygrid"),
|
||||||
|
Diagram::yGrid).toInt();
|
||||||
|
const QPointF offset(stepOffset.x() * x_grid, stepOffset.y() * y_grid);
|
||||||
|
|
||||||
|
// Mirrors copy(), but does not touch the system clipboard: Ctrl+D
|
||||||
|
// should not clobber whatever the user last copied with Ctrl+C.
|
||||||
|
QDomDocument document = m_diagram->toXml(false, true);
|
||||||
|
|
||||||
|
DiagramContent pasted;
|
||||||
|
// No position argument -- see the function comment above for why
|
||||||
|
// the offset is not passed here.
|
||||||
|
m_diagram->fromXml(document, QPointF(), false, &pasted);
|
||||||
|
if (!pasted.count()) return;
|
||||||
|
|
||||||
|
const int movable = DiagramContent::Elements | DiagramContent::TextFields
|
||||||
|
| DiagramContent::Images | DiagramContent::Shapes
|
||||||
|
| DiagramContent::Tables | DiagramContent::TerminalStrip;
|
||||||
|
for (QGraphicsItem *item : pasted.items(movable))
|
||||||
|
item->setPos(item->pos() + offset);
|
||||||
|
|
||||||
|
m_diagram->clearSelection();
|
||||||
|
m_diagram->undoStack().push(new PasteDiagramCommand(m_diagram, pasted));
|
||||||
|
adjustSceneRect();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Manage the events press click :
|
Manage the events press click :
|
||||||
* click to add an independent text field
|
* click to add an independent text field
|
||||||
@@ -1401,7 +1477,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ class DiagramView : public PaletteGraphicsView
|
|||||||
void copy();
|
void copy();
|
||||||
void paste(const QPointF & = QPointF(), QClipboard::Mode = QClipboard::Clipboard);
|
void paste(const QPointF & = QPointF(), QClipboard::Mode = QClipboard::Clipboard);
|
||||||
void pasteHere();
|
void pasteHere();
|
||||||
|
void duplicate(const QPoint &stepOffset);
|
||||||
void adjustSceneRect();
|
void adjustSceneRect();
|
||||||
void updateWindowTitle();
|
void updateWindowTitle();
|
||||||
void resetConductors();
|
void resetConductors();
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -32,8 +32,14 @@ class QetGraphicsTableFactory
|
|||||||
|
|
||||||
static void createAndAddNomenclature(Diagram *diagram);
|
static void createAndAddNomenclature(Diagram *diagram);
|
||||||
static void createAndAddSummary(Diagram *diagram);
|
static void createAndAddSummary(Diagram *diagram);
|
||||||
private:
|
// Public so a caller that has already built and configured an
|
||||||
|
// AddTableDialog itself (never shown or exec'd -- the two
|
||||||
|
// methods above always exec() one, which the scripting API
|
||||||
|
// cannot use headlessly) can create a table from it directly.
|
||||||
|
// create() only reads settings already on the dialog; nothing
|
||||||
|
// about it depends on the dialog having been shown.
|
||||||
static void create(Diagram *diagram, AddTableDialog *dialog);
|
static void create(Diagram *diagram, AddTableDialog *dialog);
|
||||||
|
private:
|
||||||
static QetGraphicsTableItem *newTable(
|
static QetGraphicsTableItem *newTable(
|
||||||
Diagram *diagram,
|
Diagram *diagram,
|
||||||
AddTableDialog *dialog,
|
AddTableDialog *dialog,
|
||||||
|
|||||||
@@ -72,6 +72,15 @@ bool AddTableDialog::adjustTableToFolio() const
|
|||||||
return ui->m_adjust_table_size_cb->isChecked();
|
return ui->m_adjust_table_size_cb->isChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief AddTableDialog::setAdjustTableToFolio
|
||||||
|
@param set
|
||||||
|
*/
|
||||||
|
void AddTableDialog::setAdjustTableToFolio(bool set)
|
||||||
|
{
|
||||||
|
ui->m_adjust_table_size_cb->setChecked(set);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief AddTableDialog::addNewTableToNewDiagram
|
@brief AddTableDialog::addNewTableToNewDiagram
|
||||||
@return
|
@return
|
||||||
@@ -81,6 +90,15 @@ bool AddTableDialog::addNewTableToNewDiagram() const
|
|||||||
return ui->m_add_table_and_folio->isChecked();
|
return ui->m_add_table_and_folio->isChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief AddTableDialog::setAddNewTableToNewDiagram
|
||||||
|
@param set
|
||||||
|
*/
|
||||||
|
void AddTableDialog::setAddNewTableToNewDiagram(bool set)
|
||||||
|
{
|
||||||
|
ui->m_add_table_and_folio->setChecked(set);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief AddTableDialog::tableName
|
@brief AddTableDialog::tableName
|
||||||
@return
|
@return
|
||||||
@@ -90,6 +108,18 @@ QString AddTableDialog::tableName() const
|
|||||||
return ui->m_table_name_le->text();
|
return ui->m_table_name_le->text();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief AddTableDialog::setTableName
|
||||||
|
Set the name field directly, so a caller that builds this dialog to
|
||||||
|
read from (never shows or execs it -- the scripting API's addTable())
|
||||||
|
does not need a name typed by a user who was never there to type one.
|
||||||
|
@param name
|
||||||
|
*/
|
||||||
|
void AddTableDialog::setTableName(const QString &name)
|
||||||
|
{
|
||||||
|
ui->m_table_name_le->setText(name);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief AddTableDialog::headerMargins
|
@brief AddTableDialog::headerMargins
|
||||||
@return
|
@return
|
||||||
|
|||||||
@@ -44,9 +44,12 @@ class AddTableDialog : public QDialog
|
|||||||
|
|
||||||
void setQueryWidget(QWidget *widget);
|
void setQueryWidget(QWidget *widget);
|
||||||
bool adjustTableToFolio() const;
|
bool adjustTableToFolio() const;
|
||||||
|
void setAdjustTableToFolio(bool set);
|
||||||
bool addNewTableToNewDiagram() const;
|
bool addNewTableToNewDiagram() const;
|
||||||
|
void setAddNewTableToNewDiagram(bool set);
|
||||||
|
|
||||||
QString tableName() const;
|
QString tableName() const;
|
||||||
|
void setTableName(const QString &name);
|
||||||
|
|
||||||
QMargins headerMargins() const;
|
QMargins headerMargins() const;
|
||||||
Qt::Alignment headerAlignment() const;
|
Qt::Alignment headerAlignment() const;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
+94
-4
@@ -167,9 +167,7 @@ QETApp::QETApp() :
|
|||||||
if (m_splash_screen) {
|
if (m_splash_screen) {
|
||||||
m_splash_screen -> hide();
|
m_splash_screen -> hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
checkBackupFiles();
|
|
||||||
|
|
||||||
#ifdef QET_SPACEMOUSE_SUPPORT
|
#ifdef QET_SPACEMOUSE_SUPPORT
|
||||||
//Always safe to construct: it silently does nothing when spacenavd
|
//Always safe to construct: it silently does nothing when spacenavd
|
||||||
//isn't running or no device is attached, which is the common case
|
//isn't running or no device is attached, which is the common case
|
||||||
@@ -177,6 +175,17 @@ QETApp::QETApp() :
|
|||||||
//SpaceMouseListener's class comment.
|
//SpaceMouseListener's class comment.
|
||||||
m_space_mouse_listener = new SpaceMouseListener(this);
|
m_space_mouse_listener = new SpaceMouseListener(this);
|
||||||
#endif
|
#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();
|
||||||
|
}, Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1828,6 +1837,81 @@ void QETApp::useSystemPalette(bool use) {
|
|||||||
QET::Palette::refreshStyleSheets();
|
QET::Palette::refreshStyleSheets();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief QETApp::useCustomPalette
|
||||||
|
Apply a user-chosen color as the application-wide palette.
|
||||||
|
Builds a full QPalette from \a color, keeping the system palette
|
||||||
|
as a fallback for roles we don't touch.
|
||||||
|
@param color the user-chosen base color
|
||||||
|
*/
|
||||||
|
void QETApp::useCustomPalette(const QColor &color) {
|
||||||
|
if (!color.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Derive readable text colors from the chosen color.
|
||||||
|
const bool dark = color.lightness() < 128;
|
||||||
|
const QColor text = dark ? QColor(220, 220, 220) : QColor(30, 30, 30);
|
||||||
|
const QColor disabled_text = dark ? QColor(175, 175, 175) : QColor(128, 128, 128);
|
||||||
|
|
||||||
|
// Slightly lighter/darker for button and window shading.
|
||||||
|
QColor button = color;
|
||||||
|
button = QColor::fromHslF(color.hslHueF(),
|
||||||
|
color.hslSaturationF(),
|
||||||
|
dark ? qMin(color.lightnessF() + 0.08, 1.0)
|
||||||
|
: qMax(color.lightnessF() - 0.08, 0.0));
|
||||||
|
QColor light = QColor::fromHslF(color.hslHueF(),
|
||||||
|
color.hslSaturationF(),
|
||||||
|
dark ? qMin(color.lightnessF() + 0.15, 1.0)
|
||||||
|
: qMax(color.lightnessF() - 0.15, 0.0));
|
||||||
|
QColor mid = QColor::fromHslF(color.hslHueF(),
|
||||||
|
color.hslSaturationF(),
|
||||||
|
dark ? qMin(color.lightnessF() + 0.04, 1.0)
|
||||||
|
: qMax(color.lightnessF() - 0.04, 0.0));
|
||||||
|
QColor dark_c = QColor::fromHslF(color.hslHueF(),
|
||||||
|
color.hslSaturationF(),
|
||||||
|
dark ? qMin(color.lightnessF() - 0.04, 1.0)
|
||||||
|
: qMax(color.lightnessF() - 0.12, 0.0));
|
||||||
|
QColor shadow = QColor::fromHslF(color.hslHueF(),
|
||||||
|
color.hslSaturationF(),
|
||||||
|
dark ? qMin(color.lightnessF() - 0.10, 1.0)
|
||||||
|
: qMax(color.lightnessF() - 0.20, 0.0));
|
||||||
|
|
||||||
|
QPalette p;
|
||||||
|
// Active and Inactive get the same colors; only Disabled differs.
|
||||||
|
for (auto group : {QPalette::Active, QPalette::Inactive}) {
|
||||||
|
p.setColor(group, QPalette::Window, color);
|
||||||
|
p.setColor(group, QPalette::WindowText, text);
|
||||||
|
p.setColor(group, QPalette::Base, color);
|
||||||
|
p.setColor(group, QPalette::AlternateBase, button);
|
||||||
|
p.setColor(group, QPalette::Text, text);
|
||||||
|
p.setColor(group, QPalette::Button, button);
|
||||||
|
p.setColor(group, QPalette::ButtonText, text);
|
||||||
|
p.setColor(group, QPalette::BrightText, dark ? QColor(255,90,90) : Qt::white);
|
||||||
|
p.setColor(group, QPalette::Highlight, QColor(30, 96, 176));
|
||||||
|
p.setColor(group, QPalette::HighlightedText, Qt::white);
|
||||||
|
p.setColor(group, QPalette::ToolTipBase, button);
|
||||||
|
p.setColor(group, QPalette::ToolTipText, text);
|
||||||
|
p.setColor(group, QPalette::Light, light);
|
||||||
|
p.setColor(group, QPalette::Midlight, mid);
|
||||||
|
p.setColor(group, QPalette::Mid, mid);
|
||||||
|
p.setColor(group, QPalette::Dark, dark_c);
|
||||||
|
p.setColor(group, QPalette::Shadow, shadow);
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
|
||||||
|
p.setColor(group, QPalette::Accent, QColor(30, 96, 176));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::WindowText, disabled_text);
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::Text, disabled_text);
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::ButtonText, disabled_text);
|
||||||
|
|
||||||
|
qApp->setPalette(p);
|
||||||
|
qApp->setStyleSheet(QString());
|
||||||
|
|
||||||
|
// Switch icon theme to match light/dark.
|
||||||
|
applyIconTheme(p);
|
||||||
|
QET::Palette::refreshStyleSheets();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief QETApp::quitQET
|
@brief QETApp::quitQET
|
||||||
Request the closing of all windows;
|
Request the closing of all windows;
|
||||||
@@ -2419,7 +2503,13 @@ void QETApp::initStyle()
|
|||||||
|
|
||||||
//Apply or not the system style
|
//Apply or not the system style
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
useSystemPalette(settings.value("usesystemcolors", true).toBool());
|
if (settings.value("usesystemcolors", true).toBool()) {
|
||||||
|
useSystemPalette(true);
|
||||||
|
} else if (settings.contains("customapplicationcolor")) {
|
||||||
|
useCustomPalette(QColor(settings.value("customapplicationcolor").toString()));
|
||||||
|
} else {
|
||||||
|
useSystemPalette(false);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(Q_OS_MACOS) && QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
#if defined(Q_OS_MACOS) && QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
||||||
// Setting an application palette stops Qt from following the OS
|
// Setting an application palette stops Qt from following the OS
|
||||||
|
|||||||
@@ -276,6 +276,7 @@ class QETApp : public QObject
|
|||||||
void setMainWindowVisible(QMainWindow *, bool);
|
void setMainWindowVisible(QMainWindow *, bool);
|
||||||
void invertMainWindowVisibility(QWidget *);
|
void invertMainWindowVisibility(QWidget *);
|
||||||
void useSystemPalette(bool);
|
void useSystemPalette(bool);
|
||||||
|
void useCustomPalette(const QColor &color);
|
||||||
void quitQET();
|
void quitQET();
|
||||||
void checkRemainingWindows();
|
void checkRemainingWindows();
|
||||||
void openFiles(const QETArguments &);
|
void openFiles(const QETArguments &);
|
||||||
|
|||||||
@@ -52,11 +52,13 @@
|
|||||||
#include "ui/bomexportdialog.h"
|
#include "ui/bomexportdialog.h"
|
||||||
#include "ui/conductorcolortoolbutton.h"
|
#include "ui/conductorcolortoolbutton.h"
|
||||||
#include "ui/diagrambgcolorbutton.h"
|
#include "ui/diagrambgcolorbutton.h"
|
||||||
|
#include "ui/duplicateoffsetdialog.h"
|
||||||
#include "ui/jumptoelementdialog.h"
|
#include "ui/jumptoelementdialog.h"
|
||||||
#include "ui/diagrampropertieseditordockwidget.h"
|
#include "ui/diagrampropertieseditordockwidget.h"
|
||||||
#include "ui/backupdialog.h"
|
#include "ui/backupdialog.h"
|
||||||
#include "ui/dialogwaiting.h"
|
#include "ui/dialogwaiting.h"
|
||||||
#include "undocommand/addelementtextcommand.h"
|
#include "undocommand/addelementtextcommand.h"
|
||||||
|
#include "utils/qetsettings.h"
|
||||||
#include "utils/qetutils.h"
|
#include "utils/qetutils.h"
|
||||||
#include "undocommand/rotateselectioncommand.h"
|
#include "undocommand/rotateselectioncommand.h"
|
||||||
#include "undocommand/rotatetextscommand.h"
|
#include "undocommand/rotatetextscommand.h"
|
||||||
@@ -374,6 +376,46 @@ void QETDiagramEditor::setUpActions()
|
|||||||
new DiagramEventAddPaste(dv->diagram(), start_pos));
|
new DiagramEventAddPaste(dv->diagram(), start_pos));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//Duplicate: copy the selection and place it at a configured,
|
||||||
|
//grid-step offset immediately -- no interactive follow-the-
|
||||||
|
//cursor step, unlike Ctrl+V above. That is deliberate (#991):
|
||||||
|
//the point of a duplicate shortcut is repeatable, unattended
|
||||||
|
//stamping (configure the offset once, then tap Ctrl+D to lay
|
||||||
|
//out a row), which an interactive placement would interrupt on
|
||||||
|
//every press.
|
||||||
|
m_duplicate = new QAction(QET::Icons::EditCopy, tr("Dupli&quer"), this);
|
||||||
|
ShortcutManager::instance().registerAction(m_duplicate, "diagrameditor.duplicate", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_D);
|
||||||
|
m_duplicate->setStatusTip(tr("Copie la sélection, décalée de l'espacement configuré", "status bar tip"));
|
||||||
|
connect(m_duplicate, &QAction::triggered, [this]() {
|
||||||
|
auto *dv = currentDiagramView();
|
||||||
|
if (!dv || !dv->diagram()) return;
|
||||||
|
|
||||||
|
//Ask the first time only -- every later press reuses whatever
|
||||||
|
//was confirmed then, so the shortcut can be tapped repeatedly
|
||||||
|
//without an interruption each time. m_configure_duplicate
|
||||||
|
//below is the deliberate way back into this dialog.
|
||||||
|
if (!DuplicateOffsetDialog::hasSavedStepOffset()) {
|
||||||
|
DuplicateOffsetDialog dialog(this);
|
||||||
|
if (dialog.exec() != QDialog::Accepted) return;
|
||||||
|
DuplicateOffsetDialog::saveStepOffset(dialog.stepOffset());
|
||||||
|
}
|
||||||
|
dv->duplicate(DuplicateOffsetDialog::savedStepOffset());
|
||||||
|
});
|
||||||
|
|
||||||
|
//Reopens the dialog above on demand, to change the spacing or
|
||||||
|
//direction a later Ctrl+D should use. Enabled unconditionally
|
||||||
|
//(see slot_updateComplexActions()): it only ever writes a
|
||||||
|
//setting, so it does not need a diagram open or anything
|
||||||
|
//selected the way m_duplicate itself does.
|
||||||
|
m_configure_duplicate = new QAction(tr("Configurer la duplication..."), this);
|
||||||
|
m_configure_duplicate->setStatusTip(tr("Choisir l'espacement et la direction utilisés par Dupliquer", "status bar tip"));
|
||||||
|
connect(m_configure_duplicate, &QAction::triggered, [this]() {
|
||||||
|
DuplicateOffsetDialog dialog(this);
|
||||||
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
|
DuplicateOffsetDialog::saveStepOffset(dialog.stepOffset());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
//Reset conductor path
|
//Reset conductor path
|
||||||
m_conductor_reset = new QAction(QET::Icons::ConductorSettings, tr("Réinitialiser les conducteurs"), this);
|
m_conductor_reset = new QAction(QET::Icons::ConductorSettings, tr("Réinitialiser les conducteurs"), this);
|
||||||
ShortcutManager::instance().registerAction(m_conductor_reset, "diagrameditor.conductor_reset", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_K);
|
ShortcutManager::instance().registerAction(m_conductor_reset, "diagrameditor.conductor_reset", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_K);
|
||||||
@@ -894,6 +936,7 @@ void QETDiagramEditor::setUpToolBar()
|
|||||||
main_tool_bar -> addAction(m_cut);
|
main_tool_bar -> addAction(m_cut);
|
||||||
main_tool_bar -> addAction(m_copy);
|
main_tool_bar -> addAction(m_copy);
|
||||||
main_tool_bar -> addAction(m_paste);
|
main_tool_bar -> addAction(m_paste);
|
||||||
|
main_tool_bar -> addAction(m_duplicate);
|
||||||
main_tool_bar -> addSeparator();
|
main_tool_bar -> addSeparator();
|
||||||
main_tool_bar -> addAction(m_delete_selection);
|
main_tool_bar -> addAction(m_delete_selection);
|
||||||
main_tool_bar -> addAction(m_rotate_selection);
|
main_tool_bar -> addAction(m_rotate_selection);
|
||||||
@@ -985,6 +1028,8 @@ void QETDiagramEditor::setUpMenu()
|
|||||||
menu_edition -> addAction(m_cut);
|
menu_edition -> addAction(m_cut);
|
||||||
menu_edition -> addAction(m_copy);
|
menu_edition -> addAction(m_copy);
|
||||||
menu_edition -> addAction(m_paste);
|
menu_edition -> addAction(m_paste);
|
||||||
|
menu_edition -> addAction(m_duplicate);
|
||||||
|
menu_edition -> addAction(m_configure_duplicate);
|
||||||
menu_edition -> addSeparator();
|
menu_edition -> addSeparator();
|
||||||
//The same actions the "Ajouter" toolbar holds. They were toolbar-only,
|
//The same actions the "Ajouter" toolbar holds. They were toolbar-only,
|
||||||
//which left them unreachable for anyone working without a mouse: a
|
//which left them unreachable for anyone working without a mouse: a
|
||||||
@@ -1811,7 +1856,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")
|
||||||
@@ -1947,6 +2003,7 @@ void QETDiagramEditor::slot_updateComplexActions()
|
|||||||
<< m_find_element
|
<< m_find_element
|
||||||
<< m_cut
|
<< m_cut
|
||||||
<< m_copy
|
<< m_copy
|
||||||
|
<< m_duplicate
|
||||||
<< m_delete_selection
|
<< m_delete_selection
|
||||||
<< m_rotate_selection
|
<< m_rotate_selection
|
||||||
<< m_rotate_group_selection
|
<< m_rotate_group_selection
|
||||||
@@ -1976,6 +2033,7 @@ void QETDiagramEditor::slot_updateComplexActions()
|
|||||||
bool deletable_items = dc.hasDeletableItems();
|
bool deletable_items = dc.hasDeletableItems();
|
||||||
m_cut -> setEnabled(!ro && copiable_items);
|
m_cut -> setEnabled(!ro && copiable_items);
|
||||||
m_copy -> setEnabled(copiable_items);
|
m_copy -> setEnabled(copiable_items);
|
||||||
|
m_duplicate -> setEnabled(!ro && copiable_items);
|
||||||
m_delete_selection -> setEnabled(!ro && deletable_items);
|
m_delete_selection -> setEnabled(!ro && deletable_items);
|
||||||
m_rotate_selection -> setEnabled(!ro && diagram_->canRotateSelection());
|
m_rotate_selection -> setEnabled(!ro && diagram_->canRotateSelection());
|
||||||
m_rotate_group_selection -> setEnabled(!ro && diagram_->canRotateSelection());
|
m_rotate_group_selection -> setEnabled(!ro && diagram_->canRotateSelection());
|
||||||
@@ -3122,6 +3180,29 @@ void QETDiagramEditor::slot_runScript() {
|
|||||||
QETProject *project = currentProject();
|
QETProject *project = currentProject();
|
||||||
if (!project) return;
|
if (!project) return;
|
||||||
|
|
||||||
|
// Scripting is off until somebody says otherwise, so the first use has
|
||||||
|
// to ask. Asking here rather than greying the action out keeps the
|
||||||
|
// feature discoverable: a disabled menu entry tells a user that
|
||||||
|
// something exists and nothing about how to have it.
|
||||||
|
if (!QetSettings::scriptingEnabled()) {
|
||||||
|
const QMessageBox::StandardButton answer = QET::QetMessageBox::question(
|
||||||
|
this,
|
||||||
|
tr("Exécuter un script"),
|
||||||
|
tr("Les scripts sont désactivés.\n\n"
|
||||||
|
"Un script s'exécute avec vos droits : il peut lire et "
|
||||||
|
"modifier le projet ouvert et écrire des fichiers. "
|
||||||
|
"N'exécutez que des scripts dont vous connaissez "
|
||||||
|
"l'origine.\n\n"
|
||||||
|
"Activer les scripts ? Ce réglage est modifiable dans "
|
||||||
|
"Configurer QElectroTech > Général > Projets."),
|
||||||
|
QMessageBox::Yes | QMessageBox::Cancel,
|
||||||
|
QMessageBox::Cancel);
|
||||||
|
if (answer != QMessageBox::Yes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QetSettings::setScriptingEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
const QString script_path = QFileDialog::getOpenFileName(
|
const QString script_path = QFileDialog::getOpenFileName(
|
||||||
this,
|
this,
|
||||||
tr("Exécuter un script"),
|
tr("Exécuter un script"),
|
||||||
|
|||||||
@@ -199,6 +199,8 @@ class QETDiagramEditor : public QETMainWindow
|
|||||||
*undo, ///< Cancel the latest action
|
*undo, ///< Cancel the latest action
|
||||||
*redo, ///< Redo the latest cancelled operation
|
*redo, ///< Redo the latest cancelled operation
|
||||||
*m_paste, ///< Paste clipboard content on the current diagram
|
*m_paste, ///< Paste clipboard content on the current diagram
|
||||||
|
*m_duplicate, ///< Copy selection, offset by the configured step (#991)
|
||||||
|
*m_configure_duplicate, ///< Reopen the duplicate offset/direction dialog (#991)
|
||||||
*m_auto_conductor, ///< Enable/Disable the use of auto conductor
|
*m_auto_conductor, ///< Enable/Disable the use of auto conductor
|
||||||
*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
|
||||||
|
|||||||
@@ -379,6 +379,21 @@ void ProjectDBModel::fillValue()
|
|||||||
|
|
||||||
while (query_.next())
|
while (query_.next())
|
||||||
{
|
{
|
||||||
|
//This query text comes out of the project file, so its result is
|
||||||
|
//not bounded by anything the project actually contains: a
|
||||||
|
//recursive CTE produces rows for as long as anyone reads them.
|
||||||
|
//Without this, opening such a file hangs QElectroTech at 100% CPU
|
||||||
|
//while m_record grows until memory runs out. @see
|
||||||
|
//projectDataBase::MaxResultRows.
|
||||||
|
if (m_record.size() >= projectDataBase::MaxResultRows) {
|
||||||
|
qWarning().noquote()
|
||||||
|
<< "ProjectDBModel: query stopped after"
|
||||||
|
<< projectDataBase::MaxResultRows
|
||||||
|
<< "rows, which is far more than a folio table can show."
|
||||||
|
<< "The table is incomplete. Query:" << m_query;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
QStringList record_;
|
QStringList record_;
|
||||||
auto i=0;
|
auto i=0;
|
||||||
while (query_.value(i).isValid())
|
while (query_.value(i).isValid())
|
||||||
|
|||||||
@@ -1310,6 +1310,34 @@ const QList<ConductorSegment *> Conductor::segmentsList() const
|
|||||||
return(segments_vector);
|
return(segments_vector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Conductor::moveSegment
|
||||||
|
Move one segment of this conductor by (dx, dy), the same primitive
|
||||||
|
handlerMouseMoveEvent()/handlerMouseReleaseEvent() apply on a manual
|
||||||
|
drag -- moveX()/moveY() each silently no-op on the wrong axis or a
|
||||||
|
static (terminal-anchored) segment, so both are always called and
|
||||||
|
whichever applies takes effect. Unlike a drag this commits the whole
|
||||||
|
move as a single undo step.
|
||||||
|
@param index a segmentsList() index
|
||||||
|
@param dx @param dy the movement, in the diagram's own coordinates
|
||||||
|
@return false if index is out of range
|
||||||
|
*/
|
||||||
|
bool Conductor::moveSegment(int index, qreal dx, qreal dy)
|
||||||
|
{
|
||||||
|
const QList<ConductorSegment *> segs = segmentsList();
|
||||||
|
if (index < 0 || index >= segs.count()) return false;
|
||||||
|
|
||||||
|
before_mov_text_pos_ = m_text_item->pos();
|
||||||
|
ConductorSegment *seg = segs.at(index);
|
||||||
|
seg->moveX(dx);
|
||||||
|
seg->moveY(dy);
|
||||||
|
modified_path = true;
|
||||||
|
segmentsToPath();
|
||||||
|
calculateTextItemPosition();
|
||||||
|
saveProfile();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Conductor::length
|
@brief Conductor::length
|
||||||
@return the length of this conductor
|
@return the length of this conductor
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ class Conductor : public QGraphicsObject
|
|||||||
public:
|
public:
|
||||||
QVector <QPointF> handlerPoints() const;
|
QVector <QPointF> handlerPoints() const;
|
||||||
const QList<ConductorSegment *> segmentsList() const;
|
const QList<ConductorSegment *> segmentsList() const;
|
||||||
|
bool moveSegment(int index, qreal dx, qreal dy);
|
||||||
|
|
||||||
void setPropertyToPotential(
|
void setPropertyToPotential(
|
||||||
const ConductorProperties &property,
|
const ConductorProperties &property,
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include <QDomElement>
|
#include <QDomElement>
|
||||||
#include <QtCore/qnumeric.h>
|
#include <QtCore/qnumeric.h>
|
||||||
#include <QGraphicsSceneMouseEvent>
|
#include <QGraphicsSceneMouseEvent>
|
||||||
|
#include <QAbstractTextDocumentLayout>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief DynamicElementTextItem::DynamicElementTextItem
|
@brief DynamicElementTextItem::DynamicElementTextItem
|
||||||
@@ -732,19 +733,6 @@ void DynamicElementTextItem::paint(QPainter *painter, const QStyleOptionGraphics
|
|||||||
{
|
{
|
||||||
DiagramTextItem::paint(painter, option, widget);
|
DiagramTextItem::paint(painter, option, widget);
|
||||||
|
|
||||||
//Only ever repositions already-existing sibling items here --
|
|
||||||
//never adds or removes one. paint() runs while QGraphicsScene is
|
|
||||||
//iterating its item list to draw it, and mutating that list mid
|
|
||||||
//-iteration (which addResizeHandles()/removeResizeHandles() do,
|
|
||||||
//through QGraphicsScene::addItem()/removeItem()) crashes. An
|
|
||||||
//earlier version of this fix called them from here and crashed
|
|
||||||
//qelectrotech reproducibly on deselecting a text (SIGABRT); see
|
|
||||||
//refreshResizeHandlesVisibility() for where that now happens
|
|
||||||
//instead -- itemChange(), Qt's own safe hook for exactly this,
|
|
||||||
//already used below for this item's own selection.
|
|
||||||
if (m_left_resize_handle || m_right_resize_handle)
|
|
||||||
updateResizeHandlesPos();
|
|
||||||
|
|
||||||
if (m_frame)
|
if (m_frame)
|
||||||
{
|
{
|
||||||
painter->save();
|
painter->save();
|
||||||
@@ -927,11 +915,17 @@ void DynamicElementTextItem::addResizeHandles()
|
|||||||
|
|
||||||
for (QetGraphicsHandlerItem *handle : {m_left_resize_handle, m_right_resize_handle})
|
for (QetGraphicsHandlerItem *handle : {m_left_resize_handle, m_right_resize_handle})
|
||||||
{
|
{
|
||||||
scene()->addItem(handle);
|
//Children of this text, not free scene items: Qt then carries
|
||||||
|
//them along when the parent element moves, rotates or is
|
||||||
|
//zoomed, and repaints their old and new area in the same
|
||||||
|
//update as this text. Moving free items from paint() instead
|
||||||
|
//left green fragments behind (qelectrotech#1002).
|
||||||
|
handle->setParentItem(this);
|
||||||
handle->setColor(Qt::darkGreen);
|
handle->setColor(Qt::darkGreen);
|
||||||
handle->setZValue(zValue() + 1);
|
|
||||||
handle->installSceneEventFilter(this);
|
handle->installSceneEventFilter(this);
|
||||||
}
|
}
|
||||||
|
m_resize_handles_con = connect(document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged,
|
||||||
|
this, &DynamicElementTextItem::updateResizeHandlesPos);
|
||||||
|
|
||||||
updateResizeHandlesPos();
|
updateResizeHandlesPos();
|
||||||
}
|
}
|
||||||
@@ -941,6 +935,7 @@ void DynamicElementTextItem::addResizeHandles()
|
|||||||
*/
|
*/
|
||||||
void DynamicElementTextItem::removeResizeHandles()
|
void DynamicElementTextItem::removeResizeHandles()
|
||||||
{
|
{
|
||||||
|
disconnect(m_resize_handles_con);
|
||||||
delete m_left_resize_handle;
|
delete m_left_resize_handle;
|
||||||
delete m_right_resize_handle;
|
delete m_right_resize_handle;
|
||||||
m_left_resize_handle = nullptr;
|
m_left_resize_handle = nullptr;
|
||||||
@@ -973,8 +968,8 @@ void DynamicElementTextItem::updateResizeHandlesPos()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
QRectF br = boundingRect();
|
QRectF br = boundingRect();
|
||||||
m_left_resize_handle->setPos(mapToScene(QPointF(br.left(), br.center().y())));
|
m_left_resize_handle->setPos(br.left(), br.center().y());
|
||||||
m_right_resize_handle->setPos(mapToScene(QPointF(br.right(), br.center().y())));
|
m_right_resize_handle->setPos(br.right(), br.center().y());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -200,6 +200,7 @@ class DynamicElementTextItem : public DiagramTextItem
|
|||||||
qreal m_resize_original_width = -1;
|
qreal m_resize_original_width = -1;
|
||||||
qreal m_resize_baseline_width = -1;
|
qreal m_resize_baseline_width = -1;
|
||||||
qreal m_resize_start_local_x = 0;
|
qreal m_resize_start_local_x = 0;
|
||||||
|
QMetaObject::Connection m_resize_handles_con;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DYNAMICELEMENTTEXTITEM_H
|
#endif // DYNAMICELEMENTTEXTITEM_H
|
||||||
|
|||||||
@@ -39,7 +39,9 @@
|
|||||||
#include "elementtextitemgroup.h"
|
#include "elementtextitemgroup.h"
|
||||||
#include "iostream"
|
#include "iostream"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
#include <QCollator>
|
#include <QCollator>
|
||||||
|
#include <QScreen>
|
||||||
|
|
||||||
static const QString plcTerminalKeys[] = {
|
static const QString plcTerminalKeys[] = {
|
||||||
QETInformation::ELMT_PLC_T1,
|
QETInformation::ELMT_PLC_T1,
|
||||||
@@ -209,6 +211,21 @@ void Element::editProperty()
|
|||||||
//with the "text" tab of ElementPropertiesWidget,
|
//with the "text" tab of ElementPropertiesWidget,
|
||||||
//the ui freeze, until user press escape key
|
//the ui freeze, until user press escape key
|
||||||
dialog.setWindowModality(Qt::WindowModal);
|
dialog.setWindowModality(Qt::WindowModal);
|
||||||
|
|
||||||
|
// A PLC master carries a 6-column IO table: without an explicit
|
||||||
|
// size the dialog falls back to its (cramped) sizeHint, so open it
|
||||||
|
// at three times its natural width instead. The height stays at
|
||||||
|
// the natural one, and the width never exceeds the screen.
|
||||||
|
const ElementData data = elementData();
|
||||||
|
if (data.m_type == ElementData::Master
|
||||||
|
&& data.m_master_type == ElementData::PLC) {
|
||||||
|
const QSize natural = dialog.sizeHint();
|
||||||
|
int width = natural.width() * 3;
|
||||||
|
if (QScreen *screen = QApplication::primaryScreen())
|
||||||
|
width = qMin(width, screen->availableGeometry().width());
|
||||||
|
dialog.resize(width, natural.height());
|
||||||
|
}
|
||||||
|
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1369,6 +1386,33 @@ void Element::initLink(QETProject *prj)
|
|||||||
tmp_uuids_link.clear();
|
tmp_uuids_link.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Element::initLink
|
||||||
|
Overload resolving tmp_uuids_link against @p candidates instead of a
|
||||||
|
project-wide ElementProvider search -- see the header comment for
|
||||||
|
why the search has to be scoped this way right after a paste or
|
||||||
|
folio-duplication XML round-trip, before uuids are renewed.
|
||||||
|
@param candidates the elements to search for a link partner in
|
||||||
|
*/
|
||||||
|
void Element::initLink(const QList<Element *> &candidates)
|
||||||
|
{
|
||||||
|
// if nothing to link return now
|
||||||
|
if (tmp_uuids_link.isEmpty()) return;
|
||||||
|
|
||||||
|
for (int i = 0; i < tmp_uuids_link.size(); ++i) {
|
||||||
|
for (Element *elmt : candidates) {
|
||||||
|
if (elmt->uuid() == tmp_uuids_link[i].uuid) {
|
||||||
|
elmt->linkToElement(this);
|
||||||
|
if (tmp_uuids_link[i].group_index >= 0) {
|
||||||
|
m_group_index_map[elmt] = tmp_uuids_link[i].group_index;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tmp_uuids_link.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Element::linkTypeToString
|
* @brief Element::linkTypeToString
|
||||||
* \deprecated use instead ElementData::typeToString
|
* \deprecated use instead ElementData::typeToString
|
||||||
|
|||||||
@@ -207,6 +207,25 @@ class Element : public QetGraphicsItem
|
|||||||
virtual void unlinkAllElements() {}
|
virtual void unlinkAllElements() {}
|
||||||
virtual void unlinkElement(Element *) {}
|
virtual void unlinkElement(Element *) {}
|
||||||
virtual void initLink(QETProject *);
|
virtual void initLink(QETProject *);
|
||||||
|
/**
|
||||||
|
Resolve tmp_uuids_link against a caller-supplied candidate
|
||||||
|
list instead of a project-wide search (bugtracker #607).
|
||||||
|
Used right after an XML round-trip (paste, folio
|
||||||
|
duplication) and before the pasted/duplicated elements'
|
||||||
|
uuids are renewed: at that moment a copy's tmp_uuids_link
|
||||||
|
still holds its source's original partner uuid, which
|
||||||
|
still matches the not-yet-renewed uuid of that partner's
|
||||||
|
own copy if it was carried along in the same batch.
|
||||||
|
Resolving only within @p candidates -- not the whole
|
||||||
|
project -- is what stops a linked pair pasted together
|
||||||
|
from matching 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 is in
|
||||||
|
@p candidates, its entry finds no match and is dropped,
|
||||||
|
same as initLink(QETProject *) leaving an unresolvable
|
||||||
|
link unlinked.
|
||||||
|
*/
|
||||||
|
void initLink(const QList<Element *> &candidates);
|
||||||
QList<Element *> linkedElements ();
|
QList<Element *> linkedElements ();
|
||||||
|
|
||||||
int groupIndexForElement(Element *elmt) const;
|
int groupIndexForElement(Element *elmt) const;
|
||||||
|
|||||||
@@ -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 "../qetgraphicsitem/terminal.h"
|
#include "../qetgraphicsitem/terminal.h"
|
||||||
|
#include "../qet.h"
|
||||||
#include "../qetproject.h"
|
#include "../qetproject.h"
|
||||||
#include "../conductorautonumerotation.h"
|
#include "../conductorautonumerotation.h"
|
||||||
#include "../diagram.h"
|
#include "../diagram.h"
|
||||||
@@ -986,7 +987,7 @@ QList<Terminal *> relatedPotentialTerminal (
|
|||||||
else if (terminal -> parentElement() -> linkType() & Element::Terminale)
|
else if (terminal -> parentElement() -> linkType() & Element::Terminale)
|
||||||
{
|
{
|
||||||
// English: Check if the user activated the potential isolation checkbox for this terminal
|
// English: Check if the user activated the potential isolation checkbox for this terminal
|
||||||
if (terminal->parentElement()->elementInformations().value(QStringLiteral("potential_isolating")).toString() == QLatin1String("true")) {
|
if (QET::infoFlagIsTrue(terminal->parentElement()->elementInformations().value(QStringLiteral("potential_isolating")).toString())) {
|
||||||
// English: Potential is isolated. Return an empty list so it does not propagate to the other side.
|
// English: Potential is isolated. Return an empty list so it does not propagate to the other side.
|
||||||
return QList<Terminal *>();
|
return QList<Terminal *>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,9 @@
|
|||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
#include <QMdiArea>
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
|
#include <QTabBar>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
@@ -307,4 +309,10 @@ void QET::Palette::refreshStyleSheets()
|
|||||||
for (QWidget *widget : widgets)
|
for (QWidget *widget : widgets)
|
||||||
if (!widget->styleSheet().isEmpty())
|
if (!widget->styleSheet().isEmpty())
|
||||||
widget->setStyleSheet(widget->styleSheet());
|
widget->setStyleSheet(widget->styleSheet());
|
||||||
|
|
||||||
|
// Force an immediate repaint on tab bars and MDI areas so their text
|
||||||
|
// updates together with the rest of the UI, not one event loop later.
|
||||||
|
for (QWidget *widget : widgets)
|
||||||
|
if (qobject_cast<QTabBar *>(widget) || qobject_cast<QMdiArea *>(widget))
|
||||||
|
widget->update();
|
||||||
}
|
}
|
||||||
|
|||||||
+165
-1
@@ -22,7 +22,9 @@
|
|||||||
#include "autoNum/assignvariables.h"
|
#include "autoNum/assignvariables.h"
|
||||||
#include "autoNum/numerotationcontext.h"
|
#include "autoNum/numerotationcontext.h"
|
||||||
#include "autoNum/numerotationcontextcommands.h"
|
#include "autoNum/numerotationcontextcommands.h"
|
||||||
|
#include "autoNum/renumberelementscommand.h"
|
||||||
#include "diagram.h"
|
#include "diagram.h"
|
||||||
|
#include "qetgraphicsitem/element.h"
|
||||||
#include "qetapp.h"
|
#include "qetapp.h"
|
||||||
#include "qetmessagebox.h"
|
#include "qetmessagebox.h"
|
||||||
#include "qetresult.h"
|
#include "qetresult.h"
|
||||||
@@ -40,7 +42,30 @@
|
|||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset numeric fields of a NumerotationContext so renumbering starts at 1.
|
||||||
|
* Keeps non-numeric parts (string/idfolio/folio/plant/locmach/elementline/elementcolumn/elementprefix) unchanged.
|
||||||
|
*/
|
||||||
|
NumerotationContext resetContextForRenumber(const NumerotationContext &tmpl)
|
||||||
|
{
|
||||||
|
NumerotationContext out = tmpl;
|
||||||
|
for (int i = 0; i < out.size(); ++i) {
|
||||||
|
const QStringList parts = out.itemAt(i);
|
||||||
|
if (parts.isEmpty()) continue;
|
||||||
|
const QString type = parts.at(0);
|
||||||
|
if (out.keyIsNumber(type)) {
|
||||||
|
out.replaceValue(i, QStringLiteral("1"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
#include <QtDebug>
|
#include <QtDebug>
|
||||||
|
#include <algorithm>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
static int BACKUP_INTERVAL = 1200000; //interval in ms of backup = 20min
|
static int BACKUP_INTERVAL = 1200000; //interval in ms of backup = 20min
|
||||||
@@ -132,6 +157,9 @@ QETProject::QETProject(const QString &path, QObject *parent) :
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//The file just read already holds everything a crash could lose, so
|
||||||
|
//there is nothing to back up until the project is changed.
|
||||||
|
m_backup_needed = false;
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,6 +286,19 @@ void QETProject::init()
|
|||||||
m_undo_stack = new QUndoStack(this);
|
m_undo_stack = new QUndoStack(this);
|
||||||
connect(m_undo_stack, &QUndoStack::cleanChanged, this, &QETProject::undoStackChanged);
|
connect(m_undo_stack, &QUndoStack::cleanChanged, this, &QETProject::undoStackChanged);
|
||||||
|
|
||||||
|
//What counts as a change for writeBackup(): the undo stack moving,
|
||||||
|
//setModified(true), and the embedded collections, which can change
|
||||||
|
//without going through either.
|
||||||
|
const auto backup_needed = [this]() { m_backup_needed = true; };
|
||||||
|
connect(m_undo_stack, &QUndoStack::indexChanged, this, backup_needed);
|
||||||
|
connect(&m_titleblocks_collection, &TitleBlockTemplatesCollection::changed, this, backup_needed);
|
||||||
|
connect(&m_titleblocks_collection, &TitleBlockTemplatesCollection::aboutToRemove, this, backup_needed);
|
||||||
|
connect(m_elements_collection, &XmlElementCollection::elementAdded, this, backup_needed);
|
||||||
|
connect(m_elements_collection, &XmlElementCollection::elementChanged, this, backup_needed);
|
||||||
|
connect(m_elements_collection, &XmlElementCollection::elementRemoved, this, backup_needed);
|
||||||
|
connect(m_elements_collection, &XmlElementCollection::directorieAdded, this, backup_needed);
|
||||||
|
connect(m_elements_collection, &XmlElementCollection::directoryRemoved, this, backup_needed);
|
||||||
|
|
||||||
m_save_backup_timer.setInterval(BACKUP_INTERVAL);
|
m_save_backup_timer.setInterval(BACKUP_INTERVAL);
|
||||||
connect(&m_save_backup_timer, &QTimer::timeout, this, &QETProject::writeBackup);
|
connect(&m_save_backup_timer, &QTimer::timeout, this, &QETProject::writeBackup);
|
||||||
m_save_backup_timer.start();
|
m_save_backup_timer.start();
|
||||||
@@ -334,7 +375,18 @@ QETProject::ProjectState QETProject::openFile(QFile *file)
|
|||||||
//file without a persisted uuid derives its uuid from them.
|
//file without a persisted uuid derives its uuid from them.
|
||||||
const QByteArray content = file->readAll();
|
const QByteArray content = file->readAll();
|
||||||
QDomDocument xml_project;
|
QDomDocument xml_project;
|
||||||
if (!xml_project.setContent(content))
|
// PreserveSpacingOnlyNodes: without it, a text node that is entirely
|
||||||
|
// whitespace -- e.g. a title-block custom variable deliberately set to
|
||||||
|
// a single space, the only way to give it a value other than blank
|
||||||
|
// (bugtracker #973) -- is silently dropped by Qt's default parsing,
|
||||||
|
// and QDomElement::text() then returns "" for it exactly as if it had
|
||||||
|
// never been set. Confirmed in isolation: <a> </a> parses to text()=="",
|
||||||
|
// this option makes it text()==" ". Every place in this codebase that
|
||||||
|
// walks a QDomNode's children already filters on isElement() (see
|
||||||
|
// QET::findInDomElement()), so the extra whitespace-only text nodes
|
||||||
|
// this keeps around are inert everywhere but the two elements that
|
||||||
|
// call .text() on themselves -- which is exactly where the bug was.
|
||||||
|
if (!xml_project.setContent(content, QDomDocument::ParseOption::PreserveSpacingOnlyNodes))
|
||||||
{
|
{
|
||||||
if(opened_here) {
|
if(opened_here) {
|
||||||
file->close();
|
file->close();
|
||||||
@@ -782,6 +834,109 @@ void QETProject::setCurrrentElementAutonum(QString autoNum) {
|
|||||||
m_current_element_autonum = std::move(autoNum);
|
m_current_element_autonum = std::move(autoNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief QETProject::renumberElementsBySchemeTitle
|
||||||
|
Renumber existing elements by element autonumbering scheme title.
|
||||||
|
|
||||||
|
Elements do not store the scheme title; they store a "formula" (elementInformations["formula"]).
|
||||||
|
This method matches elements to schemes by comparing the stored formula with the formula derived
|
||||||
|
from each scheme's NumerotationContext.
|
||||||
|
|
||||||
|
If scheme_title is empty, all schemes are renumbered. Otherwise only that scheme is renumbered.
|
||||||
|
The operation is undoable.
|
||||||
|
*/
|
||||||
|
void QETProject::renumberElementsBySchemeTitle(const QString &scheme_title)
|
||||||
|
{
|
||||||
|
if (!m_undo_stack) return;
|
||||||
|
if (isReadOnly()) return;
|
||||||
|
|
||||||
|
// Build map: scheme title -> canonical formula
|
||||||
|
QHash<QString, QString> scheme_formula;
|
||||||
|
for (const QString &k : m_element_autonum.keys()) {
|
||||||
|
if (!scheme_title.isEmpty() && k != scheme_title) continue;
|
||||||
|
scheme_formula.insert(k, autonum::numerotationContextToFormula(m_element_autonum.value(k)));
|
||||||
|
}
|
||||||
|
if (scheme_formula.isEmpty()) return;
|
||||||
|
|
||||||
|
// Collect elements per scheme by formula match
|
||||||
|
QHash<QString, QVector<Element*>> by_key;
|
||||||
|
for (Diagram *d : diagrams()) {
|
||||||
|
if (!d) continue;
|
||||||
|
const auto items = d->items();
|
||||||
|
for (QGraphicsItem *it : items) {
|
||||||
|
auto *el = qgraphicsitem_cast<Element*>(it);
|
||||||
|
if (!el) continue;
|
||||||
|
if (el->linkType() == Element::Slave || (el->linkType() & Element::AllReport))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const QString el_formula = el->elementInformations().value(QStringLiteral("formula")).toString();
|
||||||
|
if (el_formula.isEmpty()) continue;
|
||||||
|
|
||||||
|
QString matched_key;
|
||||||
|
for (auto itf = scheme_formula.constBegin(); itf != scheme_formula.constEnd(); ++itf) {
|
||||||
|
if (itf.value() == el_formula) { matched_key = itf.key(); break; }
|
||||||
|
}
|
||||||
|
if (matched_key.isEmpty()) continue;
|
||||||
|
by_key[matched_key].append(el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (by_key.isEmpty()) return;
|
||||||
|
|
||||||
|
QVector<RenumberElementsCommand::ElementChange> changes;
|
||||||
|
QHash<QString, NumerotationContext> old_ctx;
|
||||||
|
QHash<QString, NumerotationContext> new_ctx;
|
||||||
|
|
||||||
|
for (auto it = by_key.constBegin(); it != by_key.constEnd(); ++it) {
|
||||||
|
old_ctx.insert(it.key(), m_element_autonum.value(it.key()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = by_key.begin(); it != by_key.end(); ++it) {
|
||||||
|
const QString key = it.key();
|
||||||
|
auto &elements = it.value();
|
||||||
|
std::sort(elements.begin(), elements.end(), [](Element *a, Element *b){ return comparPos(a, b); });
|
||||||
|
|
||||||
|
NumerotationContext base_tmpl = m_element_autonum.value(key);
|
||||||
|
NumerotationContext nc = resetContextForRenumber(base_tmpl);
|
||||||
|
NumerotationContextCommands ncc(nc);
|
||||||
|
|
||||||
|
for (Element *el : elements) {
|
||||||
|
RenumberElementsCommand::ElementChange ch;
|
||||||
|
ch.element = el;
|
||||||
|
ch.old_infos = el->elementInformations();
|
||||||
|
ch.old_seq = el->sequenceStruct();
|
||||||
|
ch.old_frozen = el->isFreezeLabel();
|
||||||
|
ch.new_frozen = ch.old_frozen; // preserve frozen state
|
||||||
|
|
||||||
|
const QString formula = ch.old_infos.value(QStringLiteral("formula")).toString();
|
||||||
|
autonum::sequentialNumbers new_seq;
|
||||||
|
new_seq.clear();
|
||||||
|
autonum::setSequential(formula, new_seq, nc, el->diagram(), key);
|
||||||
|
|
||||||
|
DiagramContext new_infos = ch.old_infos;
|
||||||
|
new_infos.addValue(QStringLiteral("label"), autonum::AssignVariables::formulaToLabel(formula, new_seq, el->diagram(), el, nullptr));
|
||||||
|
ch.new_infos = new_infos;
|
||||||
|
ch.new_seq = new_seq;
|
||||||
|
changes.append(ch);
|
||||||
|
|
||||||
|
// advance
|
||||||
|
nc = ncc.next();
|
||||||
|
ncc = NumerotationContextCommands(nc);
|
||||||
|
}
|
||||||
|
|
||||||
|
new_ctx.insert(key, nc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changes.isEmpty()) return;
|
||||||
|
|
||||||
|
auto *cmd = new RenumberElementsCommand(
|
||||||
|
this,
|
||||||
|
changes,
|
||||||
|
old_ctx,
|
||||||
|
new_ctx,
|
||||||
|
scheme_title.isEmpty() ? tr("Renumber elements") : tr("Renumber elements (%1)").arg(scheme_title));
|
||||||
|
m_undo_stack->push(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief QETProject::conductorAutoNumFormula
|
@brief QETProject::conductorAutoNumFormula
|
||||||
@param key : autonum title
|
@param key : autonum title
|
||||||
@@ -1553,6 +1708,9 @@ void QETProject::diagramOrderChanged(int old_index, int new_index) {
|
|||||||
Mark this project as modified and emit the projectModified() signal.
|
Mark this project as modified and emit the projectModified() signal.
|
||||||
*/
|
*/
|
||||||
void QETProject::setModified(bool modified) {
|
void QETProject::setModified(bool modified) {
|
||||||
|
if (modified) {
|
||||||
|
m_backup_needed = true;
|
||||||
|
}
|
||||||
if (m_modified != modified) {
|
if (m_modified != modified) {
|
||||||
m_modified = modified;
|
m_modified = modified;
|
||||||
emit projectModified(this, m_modified);
|
emit projectModified(this, m_modified);
|
||||||
@@ -2135,6 +2293,12 @@ void QETProject::writeBackup()
|
|||||||
//both would write through &m_backup_file on different threads.
|
//both would write through &m_backup_file on different threads.
|
||||||
if (m_backup_future.isRunning())
|
if (m_backup_future.isRunning())
|
||||||
return;
|
return;
|
||||||
|
//toXml() walks the whole project on the GUI thread, which freezes
|
||||||
|
//big projects for seconds (bugtracker #273, #329). A backup of an
|
||||||
|
//unchanged project would be identical to the last one, so skip it.
|
||||||
|
if (!m_backup_needed)
|
||||||
|
return;
|
||||||
|
m_backup_needed = false;
|
||||||
//Capture the document by value (implicitly shared, so cheap): the
|
//Capture the document by value (implicitly shared, so cheap): the
|
||||||
//Qt5-style QtConcurrent::run(function, reference-args) call did not
|
//Qt5-style QtConcurrent::run(function, reference-args) call did not
|
||||||
//survive the Qt6 API change, a lambda behaves identically on both.
|
//survive the Qt6 API change, a lambda behaves identically on both.
|
||||||
|
|||||||
@@ -169,6 +169,20 @@ class QETProject : public QObject
|
|||||||
QString elementCurrentAutoNum() const;
|
QString elementCurrentAutoNum() const;
|
||||||
void setCurrrentElementAutonum(QString autoNum);
|
void setCurrrentElementAutonum(QString autoNum);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Renumber existing elements by element autonumbering scheme.
|
||||||
|
*
|
||||||
|
* Elements do not store the scheme title but they store the corresponding formula.
|
||||||
|
* This operation matches elements to schemes by comparing the stored formula
|
||||||
|
* with the formula derived from the scheme's NumerotationContext.
|
||||||
|
*
|
||||||
|
* If @p scheme_title is empty, all schemes are renumbered.
|
||||||
|
* If @p scheme_title is non-empty, only that scheme is renumbered.
|
||||||
|
*
|
||||||
|
* The operation is undoable.
|
||||||
|
*/
|
||||||
|
void renumberElementsBySchemeTitle(const QString &scheme_title = QString());
|
||||||
|
|
||||||
//Element
|
//Element
|
||||||
void freezeExistentElementLabel(bool freeze, int from, int to);
|
void freezeExistentElementLabel(bool freeze, int from, int to);
|
||||||
void freezeNewElementLabel(bool freeze, int from, int to);
|
void freezeNewElementLabel(bool freeze, int from, int to);
|
||||||
@@ -297,6 +311,8 @@ class QETProject : public QObject
|
|||||||
private:
|
private:
|
||||||
/// When false, writeBackup() is a no-op (set by the headless CLI)
|
/// When false, writeBackup() is a no-op (set by the headless CLI)
|
||||||
static bool m_backup_enabled;
|
static bool m_backup_enabled;
|
||||||
|
/// Something changed since the last backup, see writeBackup()
|
||||||
|
bool m_backup_needed = true;
|
||||||
/// File path this project is saved to
|
/// File path this project is saved to
|
||||||
QString m_file_path;
|
QString m_file_path;
|
||||||
/// Current state of the project
|
/// Current state of the project
|
||||||
|
|||||||
+2780
-11
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,7 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QVariantList>
|
#include <QVariantList>
|
||||||
|
#include <QVariantMap>
|
||||||
|
|
||||||
class QETProject;
|
class QETProject;
|
||||||
class DiagramView;
|
class DiagramView;
|
||||||
@@ -30,6 +31,9 @@ class Terminal;
|
|||||||
class Conductor;
|
class Conductor;
|
||||||
class IndependentTextItem;
|
class IndependentTextItem;
|
||||||
class QetShapeItem;
|
class QetShapeItem;
|
||||||
|
class DiagramImageItem;
|
||||||
|
class DynamicElementTextItem;
|
||||||
|
class QetGraphicsTableItem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief The QetScriptApi class
|
@brief The QetScriptApi class
|
||||||
@@ -93,13 +97,18 @@ class QetShapeItem;
|
|||||||
|
|
||||||
Terminals are addressed by their @b index in Element::terminals(),
|
Terminals are addressed by their @b index in Element::terminals(),
|
||||||
not by uuid, and elementTerminals() prints that indexing so a script
|
not by uuid, and elementTerminals() prints that indexing so a script
|
||||||
can see what it is about to wire. Terminal uuids look like the
|
can see what it is about to wire. The index is the terminal's place
|
||||||
|
in the element's own top-to-bottom, left-to-right ordering, not the
|
||||||
|
order its definition file lists them. Terminal uuids look like the
|
||||||
obvious key and are not one: Terminal::uuid() is a property of the
|
obvious key and are not one: Terminal::uuid() is a property of the
|
||||||
catalog .elmt definition, empty for most of the installed base and,
|
catalog .elmt definition, empty for most of the installed base and,
|
||||||
where present, identical across every instance of that element -- so
|
where present, identical across every instance of that element -- so
|
||||||
it does not distinguish one placed coil's A1 from another's.
|
it does not distinguish one placed coil's A1 from another's.
|
||||||
- @b Conductor properties and @b cross-references: set a conductor's
|
- @b Conductor properties and @b cross-references: set a conductor's
|
||||||
number, formula, colour or section, and link a master to a slave or
|
number, formula, colour or section (and its look: style normal/
|
||||||
|
dashed/dashdotted, two-colour mode and second colour, dash size,
|
||||||
|
line width, text size, whether its number is shown -- all under the
|
||||||
|
names the .qet file uses for them), and link a master to a slave or
|
||||||
one report to another. Both follow the application's own rules rather
|
one report to another. Both follow the application's own rules rather
|
||||||
than writing the field: a conductor property is applied to every
|
than writing the field: a conductor property is applied to every
|
||||||
conductor of the same electrical potential, which is what the GUI and
|
conductor of the same electrical potential, which is what the GUI and
|
||||||
@@ -123,7 +132,11 @@ class QetShapeItem;
|
|||||||
its circuit -- a free-standing note, a line, a rectangle, an ellipse
|
its circuit -- a free-standing note, a line, a rectangle, an ellipse
|
||||||
-- added with the same AddGraphicsObjectCommand the corresponding GUI
|
-- added with the same AddGraphicsObjectCommand the corresponding GUI
|
||||||
tools use, and changed through the plainText/color/rotation
|
tools use, and changed through the plainText/color/rotation
|
||||||
properties those items already publish.
|
properties those items already publish. A shape's look is set with
|
||||||
|
setShapeProperty(): color and fill (a colour name, or "none" for no
|
||||||
|
fill), width, line-style (solid, dashed, dotted, dashdot) and
|
||||||
|
rotation, through the pen/brush/rotation properties the shape's own
|
||||||
|
style editor changes.
|
||||||
|
|
||||||
These are addressed by @b index into a listing sorted by position
|
These are addressed by @b index into a listing sorted by position
|
||||||
(top to bottom, then left to right), because unlike an element they
|
(top to bottom, then left to right), because unlike an element they
|
||||||
@@ -150,6 +163,157 @@ class QetShapeItem;
|
|||||||
depend on. The underlying tables are how the cache happens to be
|
depend on. The underlying tables are how the cache happens to be
|
||||||
arranged today, and a column may move. tables() lists both so a
|
arranged today, and a column may move. tables() lists both so a
|
||||||
script can see what it is querying rather than guess.
|
script can see what it is querying rather than guess.
|
||||||
|
- @b Terminal @b strips: create a strip, put terminal-type elements on
|
||||||
|
it, remove it. Strips are addressed by index into terminalStrips(),
|
||||||
|
which is the project's own order (unlike texts and shapes it is not
|
||||||
|
re-sorted) and does shift when one is removed. Only elements whose
|
||||||
|
link type is "terminal" can be added, the same restriction the
|
||||||
|
editor enforces by construction.
|
||||||
|
|
||||||
|
stripRealTerminals() lists the strip's real terminals -- the actual
|
||||||
|
wire-ends added by addTerminalToStrip(), one per index -- which
|
||||||
|
physical position (clamp) each currently sits on and how many
|
||||||
|
neighbours share it, since that is what groupTerminals() and
|
||||||
|
bridgeTerminals() address by index into.
|
||||||
|
|
||||||
|
groupTerminals() merges several real terminals onto one physical
|
||||||
|
position, choosing the receiving position the same way the terminal
|
||||||
|
strip editor's own "group" button does: the position among the ones
|
||||||
|
named that already carries the most real terminals, not necessarily
|
||||||
|
the first one given -- a script asking to group indices [0, 1] is not
|
||||||
|
guaranteed index 0's position is where they end up. bridgeTerminals()
|
||||||
|
wires several real terminals together electrically without merging
|
||||||
|
their positions, refused (TerminalStrip::isBridgeable()) when they
|
||||||
|
are not all at the same level -- the same check the editor's bridge
|
||||||
|
button applies, not a rule reimplemented here. sortTerminalStrip()
|
||||||
|
reorders the strip's physical positions into the canonical order the
|
||||||
|
editor's own sort button computes.
|
||||||
|
- @b Tables: a BOM/nomenclature or a summary (table of contents) placed
|
||||||
|
on a folio, through QetGraphicsTableFactory::create() -- the same
|
||||||
|
factory call the "add table" menu action makes, minus the modal
|
||||||
|
AddTableDialog it collects its settings from first. That dialog is
|
||||||
|
still built here, off-screen and never shown or exec'd: addTable()
|
||||||
|
calls setTableName() and the query widget's setQuery() on it, the
|
||||||
|
same as a user filling in the form, and forces its two checkboxes
|
||||||
|
("adjust table to folio" and "add a new folio if the table overflows"
|
||||||
|
it) off regardless of their .ui-file default of checked -- a script
|
||||||
|
calling addTable() once should create exactly the one table it asked
|
||||||
|
for, not possibly several spread across folios it never asked to add.
|
||||||
|
A script that wants either behaviour can resize the result itself or
|
||||||
|
add its own folio.
|
||||||
|
|
||||||
|
Neither creating nor deleting a table is undoable:
|
||||||
|
QetGraphicsTableFactory::newTable(), which create() calls, calls
|
||||||
|
Diagram::addItem() directly, with no undo command of its own, in the
|
||||||
|
stock "add table" action as much as here -- a pre-existing gap in the
|
||||||
|
application, not something introduced by this API. Tables are
|
||||||
|
addressed by index in a position-sorted listing, like texts, shapes
|
||||||
|
and images.
|
||||||
|
- @b Auto-numbering: define a named numbering context of kind
|
||||||
|
"conductor", "element" or "folio", built from parts written
|
||||||
|
"type[:value[:increase]]" -- types are the ones the auto-numbering
|
||||||
|
dialog offers (string, unit, ten, hundred, alpha, idfolio, folio,
|
||||||
|
plant, locmach, elementline, elementcolumn, elementprefix, wrap,
|
||||||
|
unitfolio, tenfolio, hundredfolio) -- and select which one a folio's
|
||||||
|
new conductors use. Defining or removing a context is not undoable,
|
||||||
|
because the application itself does it through direct project calls
|
||||||
|
and only the counter advance is on the undo stack; the numbering
|
||||||
|
actually applied to a conductor is.
|
||||||
|
|
||||||
|
For elements, useElementAutoNum() selects the current context and
|
||||||
|
numberElement() applies it to one element, as the "add element" tool
|
||||||
|
does right after placing one. addElement() deliberately does not
|
||||||
|
number what it places: doing it silently would change what an existing
|
||||||
|
script produces the moment its project happens to have a context
|
||||||
|
selected, so it is a separate, explicit call. Folio auto-numbering is
|
||||||
|
not offered: in the application it spawns whole new folios from a
|
||||||
|
context, which is a different operation from labelling.
|
||||||
|
- @b Duplicating: copy elements, together with the conductors that run
|
||||||
|
between them, to a position on the same or another folio, through
|
||||||
|
Diagram::toXml() and fromXml() and PasteDiagramCommand -- what Ctrl+C
|
||||||
|
and Ctrl+V do, so a paste behaves as a paste does there: the copies
|
||||||
|
come without their labels and without their conductors' wire numbers,
|
||||||
|
which the application clears on paste (measured: '' on both).
|
||||||
|
The position is the top left of the pasted group's bounding rectangle,
|
||||||
|
so an element's own origin ends up offset from it by its hotspot
|
||||||
|
(measured: +20, +30 for a coil); (0, 0) is not a position but means
|
||||||
|
"keep the source coordinates", as Diagram::fromXml() treats it. The
|
||||||
|
result lists the copies in the order the elements were named --
|
||||||
|
the application's own list is in scene order, and a caller pairing by
|
||||||
|
index would otherwise be wired to the wrong copies -- paired by
|
||||||
|
position, which a paste preserves, so two elements at the same point
|
||||||
|
cannot be told apart. A conductor is copied
|
||||||
|
only if both its ends are among the copied elements. The previous
|
||||||
|
selection is put back afterwards, since copying works by selecting.
|
||||||
|
- @b Project title and folio frame: setProjectTitle(), and the grid that
|
||||||
|
frames each folio -- columns and rows, their size, and whether the
|
||||||
|
headers show (columns, column-width, display-columns, rows, row-height,
|
||||||
|
display-rows) -- through ChangeBorderCommand. These are the six fields
|
||||||
|
the folio properties panel offers; the title block's header sizes,
|
||||||
|
which it does not, are left alone. Changing the project title is not
|
||||||
|
undoable: the application sets it directly too.
|
||||||
|
|
||||||
|
A folio's title block @b template is a seventh, separate case:
|
||||||
|
Diagram::setTitleBlockTemplate() resolves a name only against
|
||||||
|
QETProject::embeddedTitleBlockTemplatesCollection() -- the same
|
||||||
|
copy-into-the-project step addElement() already does for elements,
|
||||||
|
and for the same reason (a project opened on another machine must not
|
||||||
|
depend on files only this one has). titleBlockTemplates() lists what
|
||||||
|
is embedded and what is available to embed from the common/company
|
||||||
|
/custom collections, each name suffixed with its source;
|
||||||
|
embedTitleBlockTemplate() does the copy (QDomElement in, unmodified,
|
||||||
|
via *TemplatesCollection::get/setTemplateXmlDescription() -- neither
|
||||||
|
side is scripting-specific code, both already exist for the template
|
||||||
|
editor to call). setFolioProperty(folio, "template", name) then
|
||||||
|
embeds it first if it is not already, refusing only if no collection
|
||||||
|
has that name at all. Embedding is not undoable, the same as defining
|
||||||
|
an auto-numbering context is not: the application does both through
|
||||||
|
direct collection/project calls with no undo command of their own.
|
||||||
|
A template literally named "default" reads back as folioProperty()
|
||||||
|
"" afterwards, not "default": BorderTitleBlock::titleBlockTemplateName()
|
||||||
|
treats the two as the same thing, since "no override" already renders
|
||||||
|
with the template named "default".
|
||||||
|
- @b Geometry and folio order: elementGeometry() reads where an element
|
||||||
|
is -- x, y (its origin), rotation, and the box it occupies on the folio
|
||||||
|
(left, top, right, bottom) -- so a script can lay one thing out relative
|
||||||
|
to another instead of only setting absolute coordinates, and can check
|
||||||
|
that a move landed. insertFolio() puts a new folio at a position
|
||||||
|
instead of at the end, which is what reordering is mostly for while
|
||||||
|
moving an existing folio still needs the application's project view.
|
||||||
|
- @b Images: place a picture from a file. The pixels are copied into
|
||||||
|
the project, which stores them inline in the .qet -- the saved file
|
||||||
|
does not refer to the original path, so it opens on another machine,
|
||||||
|
and it grows by roughly the size of the image, which is why files
|
||||||
|
over 10 MB are refused. Images are addressed by index in a
|
||||||
|
position-sorted listing, like texts and shapes -- by the on-screen
|
||||||
|
bounding box, so scaling or rotating an image, which turns about its
|
||||||
|
centre, can change where it sorts. Re-list after either.
|
||||||
|
- @b Element @b texts: the text fields drawn on a symbol -- its label,
|
||||||
|
the names beside its terminals, any value the definition placed there.
|
||||||
|
A symbol arrives with the fields its definition gives it; setElementLabel()
|
||||||
|
fills the value one of them shows, and these methods control the fields
|
||||||
|
themselves: where each sits, its size, whether it draws a frame, what it
|
||||||
|
shows, and adding or deleting one. Addressed by index in the element's
|
||||||
|
own list, which follows the definition's order and shifts when one is
|
||||||
|
deleted -- and undoing a deletion puts the field back at the end, so
|
||||||
|
list again after either.
|
||||||
|
|
||||||
|
Two things called text, which differ for a field bound to an
|
||||||
|
information key: the @b "text" property is the field's stored string,
|
||||||
|
which for an information-bound field is an unused placeholder (empty,
|
||||||
|
or "Texte" once one has been added), and @b "shows" is what is drawn,
|
||||||
|
which follows the element's information straight away -- compared
|
||||||
|
against elementInfo() at seven points across relabel, rebinding,
|
||||||
|
setting and undo, with no difference. Read "shows".
|
||||||
|
|
||||||
|
Consecutive setElementInfo()/setElementLabel() calls on one element
|
||||||
|
merge into a single undo step, as ChangeElementInformationCommand
|
||||||
|
does, so one undo can revert several.
|
||||||
|
|
||||||
|
A field's @b source is "text" (a fixed string), "info" (the value of one
|
||||||
|
of the element's information keys, so it follows setElementInfo() and
|
||||||
|
setElementLabel()) or "composite" (a formula over several). Position is in
|
||||||
|
the element's own coordinates, not the folio's.
|
||||||
- @b Navigating and @b messaging: select an element, zoom the active
|
- @b Navigating and @b messaging: select an element, zoom the active
|
||||||
view, and show the user a message. Deliberately narrow: selection and
|
view, and show the user a message. Deliberately narrow: selection and
|
||||||
messaging work with no view at all (headless `--run`); zoom is a no-op
|
messaging work with no view at all (headless `--run`); zoom is a no-op
|
||||||
@@ -238,16 +402,38 @@ class QetScriptApi : public QObject
|
|||||||
int terminalIndex, const QString &property,
|
int terminalIndex, const QString &property,
|
||||||
const QString &value);
|
const QString &value);
|
||||||
|
|
||||||
|
// -- a conductor's own drawn path, not the whole potential's
|
||||||
|
// properties above -- one conductor only, addressed the same way --
|
||||||
|
Q_INVOKABLE QStringList conductorSegments(int folioIndex, const QString &elementUuid,
|
||||||
|
int terminalIndex) const;
|
||||||
|
Q_INVOKABLE bool moveConductorSegment(int folioIndex, const QString &elementUuid,
|
||||||
|
int terminalIndex, int segmentIndex,
|
||||||
|
double dx, double dy);
|
||||||
|
|
||||||
// -- cross-references: master/slave and report links --
|
// -- cross-references: master/slave and report links --
|
||||||
Q_INVOKABLE QString elementLinkType(int folioIndex, const QString &elementUuid) const;
|
Q_INVOKABLE QString elementLinkType(int folioIndex, const QString &elementUuid) const;
|
||||||
Q_INVOKABLE QStringList linkedElements(int folioIndex, const QString &elementUuid) const;
|
Q_INVOKABLE QStringList linkedElements(int folioIndex, const QString &elementUuid) const;
|
||||||
Q_INVOKABLE bool linkElements(int folioIndexA, const QString &elementUuidA,
|
Q_INVOKABLE bool linkElements(int folioIndexA, const QString &elementUuidA,
|
||||||
int folioIndexB, const QString &elementUuidB);
|
int folioIndexB, const QString &elementUuidB,
|
||||||
|
int groupIndex = -1);
|
||||||
Q_INVOKABLE bool unlinkElement(int folioIndex, const QString &elementUuid);
|
Q_INVOKABLE bool unlinkElement(int folioIndex, const QString &elementUuid);
|
||||||
|
Q_INVOKABLE int elementLinkGroupIndex(int folioIndex, const QString &elementUuid,
|
||||||
|
int otherFolioIndex, const QString &otherElementUuid) const;
|
||||||
|
|
||||||
|
// -- a PLC master's IO table: address/function/comment rows a PLC
|
||||||
|
// slave links onto via linkElements()'s groupIndex --
|
||||||
|
Q_INVOKABLE QStringList plcIOs(int folioIndex, const QString &elementUuid) const;
|
||||||
|
Q_INVOKABLE int addPlcIO(int folioIndex, const QString &elementUuid, const QString &type,
|
||||||
|
const QString &address, const QString &functionText,
|
||||||
|
const QString &comment);
|
||||||
|
Q_INVOKABLE bool setPlcIO(int folioIndex, const QString &elementUuid, int ioIndex,
|
||||||
|
const QString &property, const QString &value);
|
||||||
|
Q_INVOKABLE bool removePlcIO(int folioIndex, const QString &elementUuid, int ioIndex);
|
||||||
|
|
||||||
// -- independent text and drawing shapes --
|
// -- independent text and drawing shapes --
|
||||||
Q_INVOKABLE QStringList texts(int folioIndex) const;
|
Q_INVOKABLE QStringList texts(int folioIndex) const;
|
||||||
Q_INVOKABLE int addText(int folioIndex, const QString &text, double x, double y);
|
Q_INVOKABLE int addText(int folioIndex, const QString &text, double x, double y);
|
||||||
|
Q_INVOKABLE QString textContent(int folioIndex, int textIndex) const;
|
||||||
Q_INVOKABLE bool setTextContent(int folioIndex, int textIndex, const QString &text);
|
Q_INVOKABLE bool setTextContent(int folioIndex, int textIndex, const QString &text);
|
||||||
Q_INVOKABLE bool setTextColor(int folioIndex, int textIndex, const QString &color);
|
Q_INVOKABLE bool setTextColor(int folioIndex, int textIndex, const QString &color);
|
||||||
Q_INVOKABLE bool setTextRotation(int folioIndex, int textIndex, double angle);
|
Q_INVOKABLE bool setTextRotation(int folioIndex, int textIndex, double angle);
|
||||||
@@ -257,14 +443,97 @@ class QetScriptApi : public QObject
|
|||||||
Q_INVOKABLE int addShape(int folioIndex, const QString &type,
|
Q_INVOKABLE int addShape(int folioIndex, const QString &type,
|
||||||
double x1, double y1, double x2, double y2);
|
double x1, double y1, double x2, double y2);
|
||||||
Q_INVOKABLE bool deleteShape(int folioIndex, int shapeIndex);
|
Q_INVOKABLE bool deleteShape(int folioIndex, int shapeIndex);
|
||||||
|
Q_INVOKABLE QString shapeProperty(int folioIndex, int shapeIndex, const QString &property) const;
|
||||||
|
Q_INVOKABLE bool setShapeProperty(int folioIndex, int shapeIndex,
|
||||||
|
const QString &property, const QString &value);
|
||||||
|
|
||||||
|
// -- polygon and path shapes: more than addShape()'s two-point box --
|
||||||
|
Q_INVOKABLE int addPolygon(int folioIndex, const QVariantList &points, bool closed);
|
||||||
|
Q_INVOKABLE QVariantList shapePolygon(int folioIndex, int shapeIndex) const;
|
||||||
|
Q_INVOKABLE bool setShapePolygon(int folioIndex, int shapeIndex, const QVariantList &points);
|
||||||
|
Q_INVOKABLE int addPath(int folioIndex, const QVariantList &nodes, bool closed);
|
||||||
|
Q_INVOKABLE QVariantList shapePathNodes(int folioIndex, int shapeIndex) const;
|
||||||
|
Q_INVOKABLE bool setShapePathNodes(int folioIndex, int shapeIndex, const QVariantList &nodes);
|
||||||
|
Q_INVOKABLE bool setShapeClosed(int folioIndex, int shapeIndex, bool closed);
|
||||||
|
|
||||||
// -- query the project database --
|
// -- query the project database --
|
||||||
Q_INVOKABLE QStringList tables() const;
|
Q_INVOKABLE QStringList tables() const;
|
||||||
Q_INVOKABLE QVariantList query(const QString &sql);
|
Q_INVOKABLE QVariantList query(const QString &sql);
|
||||||
Q_INVOKABLE QString queryError() const;
|
Q_INVOKABLE QString queryError() const;
|
||||||
|
|
||||||
|
// -- removing a conductor or a folio; folio properties beyond the title --
|
||||||
|
Q_INVOKABLE bool deleteConductor(int folioIndex, const QString &elementUuid, int terminalIndex);
|
||||||
|
Q_INVOKABLE bool removeFolio(int folioIndex);
|
||||||
|
Q_INVOKABLE bool setFolioProperty(int folioIndex, const QString &property, const QString &value);
|
||||||
|
Q_INVOKABLE QString folioProperty(int folioIndex, const QString &property) const;
|
||||||
|
|
||||||
|
// -- terminal strips (borniers) --
|
||||||
|
Q_INVOKABLE QStringList terminalStrips() const;
|
||||||
|
Q_INVOKABLE int addTerminalStrip(const QString &installation, const QString &location,
|
||||||
|
const QString &name);
|
||||||
|
Q_INVOKABLE bool removeTerminalStrip(int stripIndex);
|
||||||
|
Q_INVOKABLE bool addTerminalToStrip(int stripIndex, int folioIndex,
|
||||||
|
const QString &elementUuid);
|
||||||
|
Q_INVOKABLE QStringList stripRealTerminals(int stripIndex) const;
|
||||||
|
Q_INVOKABLE bool groupTerminals(int stripIndex, const QVariantList &realTerminalIndices);
|
||||||
|
Q_INVOKABLE bool bridgeTerminals(int stripIndex, const QVariantList &realTerminalIndices);
|
||||||
|
Q_INVOKABLE bool sortTerminalStrip(int stripIndex);
|
||||||
|
|
||||||
|
// -- a BOM/nomenclature or summary table placed on a folio --
|
||||||
|
Q_INVOKABLE QStringList tables(int folioIndex) const;
|
||||||
|
Q_INVOKABLE int addTable(int folioIndex, const QString &kind, const QString &name,
|
||||||
|
const QString &query);
|
||||||
|
Q_INVOKABLE bool deleteTable(int folioIndex, int tableIndex);
|
||||||
|
Q_INVOKABLE bool setTablePosition(int folioIndex, int tableIndex, double x, double y);
|
||||||
|
|
||||||
|
// -- auto-numbering contexts (conductor, element, folio) --
|
||||||
|
Q_INVOKABLE QStringList autoNums(const QString &kind) const;
|
||||||
|
Q_INVOKABLE bool addAutoNum(const QString &kind, const QString &name, const QStringList &parts);
|
||||||
|
Q_INVOKABLE bool removeAutoNum(const QString &kind, const QString &name);
|
||||||
|
Q_INVOKABLE bool useConductorAutoNum(int folioIndex, const QString &name);
|
||||||
|
Q_INVOKABLE bool useElementAutoNum(const QString &name);
|
||||||
|
Q_INVOKABLE bool numberElement(int folioIndex, const QString &elementUuid);
|
||||||
|
|
||||||
|
// -- images, embedded in the project --
|
||||||
|
Q_INVOKABLE QStringList images(int folioIndex) const;
|
||||||
|
Q_INVOKABLE int addImage(int folioIndex, const QString &filePath, double x, double y);
|
||||||
|
Q_INVOKABLE bool setImageScale(int folioIndex, int imageIndex, double factor);
|
||||||
|
Q_INVOKABLE bool setImageRotation(int folioIndex, int imageIndex, double angle);
|
||||||
|
Q_INVOKABLE bool deleteImage(int folioIndex, int imageIndex);
|
||||||
|
Q_INVOKABLE int addPdfPage(int folioIndex, const QString &pdfPath, int pageNumber,
|
||||||
|
int dpi, double x, double y);
|
||||||
|
|
||||||
|
// -- the text fields shown on a symbol (label, terminal names, ...) --
|
||||||
|
Q_INVOKABLE QStringList elementTexts(int folioIndex, const QString &elementUuid) const;
|
||||||
|
Q_INVOKABLE int addElementText(int folioIndex, const QString &elementUuid,
|
||||||
|
const QString &source, const QString &value,
|
||||||
|
double x, double y);
|
||||||
|
Q_INVOKABLE bool setElementTextProperty(int folioIndex, const QString &elementUuid,
|
||||||
|
int textIndex, const QString &property,
|
||||||
|
const QString &value);
|
||||||
|
Q_INVOKABLE QString elementTextProperty(int folioIndex, const QString &elementUuid,
|
||||||
|
int textIndex, const QString &property) const;
|
||||||
|
Q_INVOKABLE bool deleteElementText(int folioIndex, const QString &elementUuid, int textIndex);
|
||||||
|
|
||||||
|
// -- copy elements (with the conductors between them) to a position --
|
||||||
|
Q_INVOKABLE QStringList duplicateElements(int fromFolioIndex, const QStringList &elementUuids,
|
||||||
|
int toFolioIndex, double x, double y);
|
||||||
|
|
||||||
|
// -- the project title, and each folio's frame (grid of columns and rows) --
|
||||||
|
Q_INVOKABLE bool setProjectTitle(const QString &title);
|
||||||
|
Q_INVOKABLE QString folioBorder(int folioIndex, const QString &property) const;
|
||||||
|
Q_INVOKABLE bool setFolioBorder(int folioIndex, const QString &property, const QString &value);
|
||||||
|
|
||||||
|
// -- title block templates: which exist, embedding one into the project --
|
||||||
|
Q_INVOKABLE QStringList titleBlockTemplates() const;
|
||||||
|
Q_INVOKABLE bool embedTitleBlockTemplate(const QString &name);
|
||||||
|
|
||||||
|
// -- read an element's geometry --
|
||||||
|
Q_INVOKABLE QVariantMap elementGeometry(int folioIndex, const QString &elementUuid) const;
|
||||||
|
|
||||||
// -- folios --
|
// -- folios --
|
||||||
Q_INVOKABLE int addFolio();
|
Q_INVOKABLE int addFolio();
|
||||||
|
Q_INVOKABLE int insertFolio(int position);
|
||||||
Q_INVOKABLE bool setFolioTitle(int folioIndex, const QString &title);
|
Q_INVOKABLE bool setFolioTitle(int folioIndex, const QString &title);
|
||||||
|
|
||||||
Q_INVOKABLE bool undo();
|
Q_INVOKABLE bool undo();
|
||||||
@@ -272,9 +541,21 @@ class QetScriptApi : public QObject
|
|||||||
Q_INVOKABLE bool canUndo() const;
|
Q_INVOKABLE bool canUndo() const;
|
||||||
Q_INVOKABLE bool canRedo() const;
|
Q_INVOKABLE bool canRedo() const;
|
||||||
|
|
||||||
|
// -- project-wide text search & replace, one undo step for the
|
||||||
|
// whole run, in the same spirit as the "Search and replace" panel --
|
||||||
|
Q_INVOKABLE int searchAndReplace(const QString &kind, const QString &field,
|
||||||
|
const QString &pattern, const QString &replacement,
|
||||||
|
bool useRegex, bool caseSensitive);
|
||||||
|
|
||||||
|
// -- electrical continuity / ERC: read-only, structural checks
|
||||||
|
// against the live object graph rather than the XML -- see the
|
||||||
|
// .cpp doc comment for exactly what is and is not covered --
|
||||||
|
Q_INVOKABLE QVariantList checkContinuity(int folioIndex);
|
||||||
|
|
||||||
// -- navigate and message --
|
// -- navigate and message --
|
||||||
Q_INVOKABLE bool selectElement(const QString &elementUuid);
|
Q_INVOKABLE bool selectElement(const QString &elementUuid);
|
||||||
Q_INVOKABLE void deselectAll(int folioIndex);
|
Q_INVOKABLE void deselectAll(int folioIndex);
|
||||||
|
Q_INVOKABLE QStringList selectedElements(int folioIndex) const;
|
||||||
Q_INVOKABLE bool zoomFit();
|
Q_INVOKABLE bool zoomFit();
|
||||||
Q_INVOKABLE bool zoomToContent();
|
Q_INVOKABLE bool zoomToContent();
|
||||||
Q_INVOKABLE bool zoomReset();
|
Q_INVOKABLE bool zoomReset();
|
||||||
@@ -292,6 +573,10 @@ class QetScriptApi : public QObject
|
|||||||
const QString &caller);
|
const QString &caller);
|
||||||
QList<IndependentTextItem *> sortedTexts(int folioIndex) const;
|
QList<IndependentTextItem *> sortedTexts(int folioIndex) const;
|
||||||
QList<QetShapeItem *> sortedShapes(int folioIndex) const;
|
QList<QetShapeItem *> sortedShapes(int folioIndex) const;
|
||||||
|
QList<QetGraphicsTableItem *> sortedTables(int folioIndex) const;
|
||||||
|
QList<DiagramImageItem *> sortedImages(int folioIndex) const;
|
||||||
|
DynamicElementTextItem *findElementText(int folioIndex, const QString &elementUuid,
|
||||||
|
int textIndex, const QString &caller) const;
|
||||||
IndependentTextItem *findText(int folioIndex, int textIndex, const QString &caller);
|
IndependentTextItem *findText(int folioIndex, int textIndex, const QString &caller);
|
||||||
bool setInfoKey(int folioIndex, const QString &elementUuid,
|
bool setInfoKey(int folioIndex, const QString &elementUuid,
|
||||||
const QString &key, const QString &value, const QString &caller);
|
const QString &key, const QString &value, const QString &caller);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "qetscriptapi.h"
|
#include "qetscriptapi.h"
|
||||||
#include "../qetmessagebox.h"
|
#include "../qetmessagebox.h"
|
||||||
#include "../qetproject.h"
|
#include "../qetproject.h"
|
||||||
|
#include "../utils/qetsettings.h"
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
@@ -48,8 +49,33 @@ bool isRunRequest(const QStringList &args)
|
|||||||
|
|
||||||
#ifdef QET_HAS_SCRIPTING
|
#ifdef QET_HAS_SCRIPTING
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
/**
|
||||||
|
@brief refusalMessage
|
||||||
|
What to tell somebody whose script was not run, and how to change
|
||||||
|
that. Written once because the command line and the graphical
|
||||||
|
editor both need to say it, and an explanation that names only one
|
||||||
|
of the two ways out sends half the people down the wrong path.
|
||||||
|
*/
|
||||||
|
QString refusalMessage()
|
||||||
|
{
|
||||||
|
return QObject::tr(
|
||||||
|
"Les scripts sont désactivés.\n\n"
|
||||||
|
"Un script a accès à l'ensemble du projet et peut écrire des "
|
||||||
|
"fichiers, aussi cette fonction est-elle désactivée par défaut.\n\n"
|
||||||
|
"Pour l'activer : Configurer QElectroTech > Général > Projets, "
|
||||||
|
"ou définir la variable d'environnement QET_ENABLE_SCRIPTING=1 "
|
||||||
|
"pour une exécution sans interface (CI, traitement par lot).");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int run(const QStringList &args)
|
int run(const QStringList &args)
|
||||||
{
|
{
|
||||||
|
if (!QetSettings::scriptingEnabled()) {
|
||||||
|
err << refusalMessage() << "\n";
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
const int idx = args.indexOf(QStringLiteral("--run"));
|
const int idx = args.indexOf(QStringLiteral("--run"));
|
||||||
const QString script_path = args.value(idx + 1);
|
const QString script_path = args.value(idx + 1);
|
||||||
const QString project_path = args.value(idx + 2);
|
const QString project_path = args.value(idx + 2);
|
||||||
@@ -88,6 +114,20 @@ namespace {
|
|||||||
|
|
||||||
bool runOnProject(const QString &scriptPath, QETProject *project, DiagramView *view)
|
bool runOnProject(const QString &scriptPath, QETProject *project, DiagramView *view)
|
||||||
{
|
{
|
||||||
|
// Checked here as well as at each caller, deliberately: this is the
|
||||||
|
// one function that actually evaluates JavaScript, so it is the one
|
||||||
|
// place a future caller cannot forget to ask. The callers check first
|
||||||
|
// only to give a better answer than this one can -- a usable exit code
|
||||||
|
// on the command line, an offer to switch the setting on in the editor.
|
||||||
|
if (!QetSettings::scriptingEnabled()) {
|
||||||
|
err << refusalMessage() << "\n";
|
||||||
|
if (view) {
|
||||||
|
QET::QetMessageBox::warning(nullptr, QObject::tr("Script"),
|
||||||
|
refusalMessage());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QFile file(scriptPath);
|
QFile file(scriptPath);
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
err << "Cannot open script: " << scriptPath << "\n";
|
err << "Cannot open script: " << scriptPath << "\n";
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
|
#include <QSet>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
/**
|
/**
|
||||||
@@ -167,11 +168,22 @@ void ConductorColorToolButton::applyColor(const QColor &color)
|
|||||||
}
|
}
|
||||||
|
|
||||||
DiagramContent dc(diagram);
|
DiagramContent dc(diagram);
|
||||||
const auto conductors = dc.conductors(DiagramContent::AnyConductor);
|
const auto selected_conductors = dc.conductors(DiagramContent::AnyConductor);
|
||||||
if (conductors.isEmpty()) {
|
if (selected_conductors.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//A wire drawn across a junction is several Conductor objects
|
||||||
|
//sharing one electrical potential; selecting one segment must
|
||||||
|
//still recolour the whole potential, the way the F2 dialog's
|
||||||
|
//"apply to all" already does.
|
||||||
|
QSet<Conductor *> conductors;
|
||||||
|
for (Conductor *conductor : selected_conductors)
|
||||||
|
{
|
||||||
|
conductors << conductor;
|
||||||
|
conductors += conductor->relatedPotentialConductors();
|
||||||
|
}
|
||||||
|
|
||||||
QUndoCommand *undo = new QUndoCommand(tr("Modifier la couleur de %n conducteur(s)",
|
QUndoCommand *undo = new QUndoCommand(tr("Modifier la couleur de %n conducteur(s)",
|
||||||
"undo caption", conductors.count()));
|
"undo caption", conductors.count()));
|
||||||
int changed = 0;
|
int changed = 0;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "../../utils/qetsettings.h"
|
#include "../../utils/qetsettings.h"
|
||||||
#include "../../utils/qetutils.h"
|
#include "../../utils/qetutils.h"
|
||||||
#include "../../qetmessagebox.h"
|
#include "../../qetmessagebox.h"
|
||||||
|
#include "../nokde/kcolorbutton.h"
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QFontDialog>
|
#include <QFontDialog>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
@@ -74,6 +75,12 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) :
|
|||||||
ui->DiagramEditor_Grid_PointSize_min_sb->setValue(settings.value("diagrameditor/grid_pointsize_min", 1).toInt());
|
ui->DiagramEditor_Grid_PointSize_min_sb->setValue(settings.value("diagrameditor/grid_pointsize_min", 1).toInt());
|
||||||
ui->DiagramEditor_Grid_PointSize_max_sb->setValue(settings.value("diagrameditor/grid_pointsize_max", 1).toInt());
|
ui->DiagramEditor_Grid_PointSize_max_sb->setValue(settings.value("diagrameditor/grid_pointsize_max", 1).toInt());
|
||||||
ui->m_use_system_color_cb->setChecked(settings.value("usesystemcolors", "true").toBool());
|
ui->m_use_system_color_cb->setChecked(settings.value("usesystemcolors", "true").toBool());
|
||||||
|
bool sysColors = ui->m_use_system_color_cb->isChecked();
|
||||||
|
ui->m_custom_app_color_kpb->setEnabled(!sysColors);
|
||||||
|
if (settings.contains("customapplicationcolor"))
|
||||||
|
ui->m_custom_app_color_kpb->setColor(QColor(settings.value("customapplicationcolor").toString()));
|
||||||
|
else
|
||||||
|
ui->m_custom_app_color_kpb->setColor(QApplication::palette().color(QPalette::Window));
|
||||||
bool tabbed = settings.value("diagrameditor/viewmode", "tabbed") == "tabbed";
|
bool tabbed = settings.value("diagrameditor/viewmode", "tabbed") == "tabbed";
|
||||||
if(tabbed)
|
if(tabbed)
|
||||||
ui->m_use_tab_mode_rb->setChecked(true);
|
ui->m_use_tab_mode_rb->setChecked(true);
|
||||||
@@ -82,6 +89,25 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) :
|
|||||||
ui->m_zoom_out_beyond_folio->setChecked(settings.value("diagrameditor/zoom-out-beyond-of-folio", false).toBool());
|
ui->m_zoom_out_beyond_folio->setChecked(settings.value("diagrameditor/zoom-out-beyond-of-folio", false).toBool());
|
||||||
ui->m_use_gesture_trackpad->setChecked(settings.value("diagramview/gestures", false).toBool());
|
ui->m_use_gesture_trackpad->setChecked(settings.value("diagramview/gestures", false).toBool());
|
||||||
ui->m_save_label_paste->setChecked(settings.value("diagramcommands/erase-label-on-copy", true).toBool());
|
ui->m_save_label_paste->setChecked(settings.value("diagramcommands/erase-label-on-copy", true).toBool());
|
||||||
|
ui->m_enable_scripting->setChecked(QetSettings::scriptingEnabled());
|
||||||
|
#ifdef QET_HAS_SCRIPTING
|
||||||
|
if (QetSettings::scriptingForcedByEnvironment()) {
|
||||||
|
//QET_ENABLE_SCRIPTING wins over the stored value, so let the box
|
||||||
|
//say so rather than offer a tick that changes nothing.
|
||||||
|
ui->m_enable_scripting->setEnabled(false);
|
||||||
|
ui->m_enable_scripting->setToolTip(
|
||||||
|
tr("Activé par la variable d'environnement "
|
||||||
|
"QET_ENABLE_SCRIPTING ; ce réglage est sans effet "
|
||||||
|
"tant qu'elle est définie."));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
//Built without Qt Qml: there is no scripting to allow. Disabled as
|
||||||
|
//well as hidden, so applyConf() leaves the stored value alone --
|
||||||
|
//a hidden box still reports its state, and writing it here would
|
||||||
|
//quietly clear a preference set on a build that does have Qml.
|
||||||
|
ui->m_enable_scripting->setVisible(false);
|
||||||
|
ui->m_enable_scripting->setEnabled(false);
|
||||||
|
#endif
|
||||||
ui->m_use_folio_label->setChecked(settings.value("genericpanel/folio", true).toBool());
|
ui->m_use_folio_label->setChecked(settings.value("genericpanel/folio", true).toBool());
|
||||||
ui->m_border_0->setChecked(settings.value("border-columns_0", false).toBool());
|
ui->m_border_0->setChecked(settings.value("border-columns_0", false).toBool());
|
||||||
ui->m_autosave_sb->setValue(settings.value("diagrameditor/autosave-interval", 0).toInt());
|
ui->m_autosave_sb->setValue(settings.value("diagrameditor/autosave-interval", 0).toInt());
|
||||||
@@ -206,7 +232,17 @@ void GeneralConfigurationPage::applyConf()
|
|||||||
bool must_use_system_colors = ui->m_use_system_color_cb->isChecked();
|
bool must_use_system_colors = ui->m_use_system_color_cb->isChecked();
|
||||||
settings.setValue("usesystemcolors", must_use_system_colors);
|
settings.setValue("usesystemcolors", must_use_system_colors);
|
||||||
if (was_using_system_colors != must_use_system_colors) {
|
if (was_using_system_colors != must_use_system_colors) {
|
||||||
QETApp::instance()->useSystemPalette(must_use_system_colors);
|
if (must_use_system_colors) {
|
||||||
|
QETApp::instance()->useSystemPalette(true);
|
||||||
|
} else {
|
||||||
|
QColor custom_color = ui->m_custom_app_color_kpb->color();
|
||||||
|
settings.setValue("customapplicationcolor", custom_color.name());
|
||||||
|
QETApp::instance()->useCustomPalette(custom_color);
|
||||||
|
}
|
||||||
|
} else if (!must_use_system_colors) {
|
||||||
|
QColor custom_color = ui->m_custom_app_color_kpb->color();
|
||||||
|
settings.setValue("customapplicationcolor", custom_color.name());
|
||||||
|
QETApp::instance()->useCustomPalette(custom_color);
|
||||||
}
|
}
|
||||||
settings.setValue("border-columns_0",ui->m_border_0->isChecked());
|
settings.setValue("border-columns_0",ui->m_border_0->isChecked());
|
||||||
settings.setValue("lang", ui->m_lang_cb->itemData(ui->m_lang_cb->currentIndex()).toString());
|
settings.setValue("lang", ui->m_lang_cb->itemData(ui->m_lang_cb->currentIndex()).toString());
|
||||||
@@ -227,6 +263,14 @@ void GeneralConfigurationPage::applyConf()
|
|||||||
//DIAGRAM COMMAND
|
//DIAGRAM COMMAND
|
||||||
settings.setValue("diagramcommands/erase-label-on-copy", ui->m_save_label_paste->isChecked());
|
settings.setValue("diagramcommands/erase-label-on-copy", ui->m_save_label_paste->isChecked());
|
||||||
|
|
||||||
|
//SCRIPTING
|
||||||
|
//Left alone while the environment forces it on: the box is disabled
|
||||||
|
//in that case and writing its state would silently clear the user's
|
||||||
|
//real preference the first time this dialog is accepted.
|
||||||
|
if (ui->m_enable_scripting->isEnabled()) {
|
||||||
|
QetSettings::setScriptingEnabled(ui->m_enable_scripting->isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
//GENERIC PANEL
|
//GENERIC PANEL
|
||||||
settings.setValue("genericpanel/folio",ui->m_use_folio_label->isChecked());
|
settings.setValue("genericpanel/folio",ui->m_use_folio_label->isChecked());
|
||||||
|
|
||||||
@@ -625,3 +669,14 @@ void GeneralConfigurationPage::on_m_hdpi_round_cb_clicked(bool checked)
|
|||||||
ui->m_hdpi_round_policy_cb->setEnabled(checked);
|
ui->m_hdpi_round_policy_cb->setEnabled(checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief GeneralConfigurationPage::on_m_use_system_color_cb_toggled
|
||||||
|
Enable/disable the custom color picker when the system color
|
||||||
|
checkbox is toggled.
|
||||||
|
@param checked
|
||||||
|
*/
|
||||||
|
void GeneralConfigurationPage::on_m_use_system_color_cb_toggled(bool checked)
|
||||||
|
{
|
||||||
|
ui->m_custom_app_color_kpb->setEnabled(!checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ class GeneralConfigurationPage : public ConfigPage
|
|||||||
void on_ElementEditor_Grid_PointSize_min_sb_valueChanged(int value);
|
void on_ElementEditor_Grid_PointSize_min_sb_valueChanged(int value);
|
||||||
|
|
||||||
void on_m_hdpi_round_cb_clicked(bool checked);
|
void on_m_hdpi_round_cb_clicked(bool checked);
|
||||||
|
void on_m_use_system_color_cb_toggled(bool checked);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void fillLang();
|
void fillLang();
|
||||||
|
|||||||
@@ -23,15 +23,26 @@
|
|||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Apparence</string>
|
<string>Apparence</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="m_use_system_color_cb">
|
<layout class="QHBoxLayout" name="m_system_color_layout">
|
||||||
<property name="text">
|
<item>
|
||||||
<string>Utiliser les couleurs du système</string>
|
<widget class="QCheckBox" name="m_use_system_color_cb">
|
||||||
</property>
|
<property name="text">
|
||||||
</widget>
|
<string>Utiliser les couleurs du système</string>
|
||||||
</item>
|
</property>
|
||||||
<item>
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="KColorButton" name="m_custom_app_color_kpb">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Couleur de l'application</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
<widget class="Line" name="line">
|
<widget class="Line" name="line">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
@@ -207,6 +218,16 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="4" column="0">
|
||||||
|
<widget class="QCheckBox" name="m_enable_scripting">
|
||||||
|
<property name="text">
|
||||||
|
<string>Autoriser l'exécution de scripts JavaScript (Projet > Exécuter un script, et --run)</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Un script s'exécute avec vos droits : il peut lire et modifier le projet ouvert et écrire des fichiers. Désactivé par défaut ; n'exécutez que des scripts dont vous connaissez l'origine.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
<spacer name="verticalSpacer_2">
|
<spacer name="verticalSpacer_2">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
@@ -1161,4 +1182,11 @@ Vous pouvez spécifier ici la valeur par défaut de ce champ pour les éléments
|
|||||||
</tabstops>
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>KColorButton</class>
|
||||||
|
<extends>QPushButton</extends>
|
||||||
|
<header>nokde/kcolorbutton.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
</ui>
|
</ui>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "../qetdiagrameditor.h"
|
#include "../qetdiagrameditor.h"
|
||||||
#include "../projectview.h"
|
#include "../projectview.h"
|
||||||
#include "../qetproject.h"
|
#include "../qetproject.h"
|
||||||
|
#include "../utils/qetsettings.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QColorDialog>
|
#include <QColorDialog>
|
||||||
@@ -62,8 +63,28 @@ DiagramBgColorToolButton::DiagramBgColorToolButton(QETDiagramEditor *editor, QWi
|
|||||||
setStatusTip(tr("Choisir la couleur de fond du folio",
|
setStatusTip(tr("Choisir la couleur de fond du folio",
|
||||||
"status bar tip"));
|
"status bar tip"));
|
||||||
|
|
||||||
m_is_system_color = true;
|
//main() already restored the stored choice onto the global
|
||||||
m_current = QApplication::palette().color(QPalette::Base);
|
//Diagram::background_color and PaletteGraphicsView flag; mirror it
|
||||||
|
//here so the button opens on what the editor actually draws, rather
|
||||||
|
//than always claiming "system colour" as it used to.
|
||||||
|
if (PaletteGraphicsView::customBackgroundColor()) {
|
||||||
|
m_is_system_color = false;
|
||||||
|
m_current = Diagram::background_color;
|
||||||
|
} else {
|
||||||
|
m_is_system_color = true;
|
||||||
|
m_current = QApplication::palette().color(QPalette::Base);
|
||||||
|
}
|
||||||
|
for (const QString &name : QetSettings::sheetBackgroundRecentColors())
|
||||||
|
{
|
||||||
|
const QColor c(name);
|
||||||
|
if (c.isValid()) {
|
||||||
|
m_recent.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (m_recent.size() > MAX_RECENT) {
|
||||||
|
m_recent.removeLast();
|
||||||
|
}
|
||||||
|
|
||||||
setMenu(new QMenu(this));
|
setMenu(new QMenu(this));
|
||||||
rebuildMenu();
|
rebuildMenu();
|
||||||
setSwatch(m_current);
|
setSwatch(m_current);
|
||||||
@@ -123,6 +144,7 @@ void DiagramBgColorToolButton::applyColor(const QColor &color)
|
|||||||
|
|
||||||
PaletteGraphicsView::setCustomBackgroundColor(true);
|
PaletteGraphicsView::setCustomBackgroundColor(true);
|
||||||
Diagram::background_color = color;
|
Diagram::background_color = color;
|
||||||
|
QetSettings::setSheetBackground(QetSettings::SheetBackground{color, true});
|
||||||
|
|
||||||
QETDiagramEditor *editor = m_editor;
|
QETDiagramEditor *editor = m_editor;
|
||||||
if (!editor) {
|
if (!editor) {
|
||||||
@@ -146,6 +168,8 @@ void DiagramBgColorToolButton::applySystemColor()
|
|||||||
|
|
||||||
PaletteGraphicsView::setCustomBackgroundColor(false);
|
PaletteGraphicsView::setCustomBackgroundColor(false);
|
||||||
Diagram::background_color = Qt::white;
|
Diagram::background_color = Qt::white;
|
||||||
|
QetSettings::setSheetBackground(
|
||||||
|
QetSettings::SheetBackground{QColor(Qt::white), false});
|
||||||
|
|
||||||
QETDiagramEditor *editor = m_editor;
|
QETDiagramEditor *editor = m_editor;
|
||||||
if (!editor) {
|
if (!editor) {
|
||||||
@@ -187,6 +211,21 @@ void DiagramBgColorToolButton::rememberRecent(const QColor &color)
|
|||||||
m_recent.removeLast();
|
m_recent.removeLast();
|
||||||
}
|
}
|
||||||
rebuildMenu();
|
rebuildMenu();
|
||||||
|
persistRecent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief DiagramBgColorToolButton::persistRecent
|
||||||
|
Write the "recently used" colours back to the settings, so they are
|
||||||
|
still there on the next start instead of starting out empty.
|
||||||
|
*/
|
||||||
|
void DiagramBgColorToolButton::persistRecent()
|
||||||
|
{
|
||||||
|
QStringList names;
|
||||||
|
for (const QColor &c : std::as_const(m_recent)) {
|
||||||
|
names << c.name();
|
||||||
|
}
|
||||||
|
QetSettings::setSheetBackgroundRecentColors(names);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ class DiagramBgColorToolButton : public QToolButton
|
|||||||
void applySystemColor();
|
void applySystemColor();
|
||||||
void chooseOtherColor();
|
void chooseOtherColor();
|
||||||
void rememberRecent(const QColor &color);
|
void rememberRecent(const QColor &color);
|
||||||
|
void persistRecent();
|
||||||
void setSwatch(const QColor &color);
|
void setSwatch(const QColor &color);
|
||||||
static QIcon swatchIcon(const QColor &color);
|
static QIcon swatchIcon(const QColor &color);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
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 "duplicateoffsetdialog.h"
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QFormLayout>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Stored as one integer per axis, in grid steps -- not pixels, so the
|
||||||
|
// remembered offset still makes sense if the grid size ever changes.
|
||||||
|
const QString kOffsetXKey = QStringLiteral("diagrameditor/duplicate_offset_x");
|
||||||
|
const QString kOffsetYKey = QStringLiteral("diagrameditor/duplicate_offset_y");
|
||||||
|
}
|
||||||
|
|
||||||
|
DuplicateOffsetDialog::DuplicateOffsetDialog(QWidget *parent) :
|
||||||
|
QDialog(parent)
|
||||||
|
{
|
||||||
|
setWindowTitle(tr("Dupliquer"));
|
||||||
|
|
||||||
|
auto *form = new QFormLayout;
|
||||||
|
|
||||||
|
m_spacing = new QSpinBox(this);
|
||||||
|
m_spacing->setRange(1, 1000);
|
||||||
|
m_spacing->setSuffix(tr(" pas de grille"));
|
||||||
|
form->addRow(tr("Espacement :"), m_spacing);
|
||||||
|
|
||||||
|
m_direction = new QComboBox(this);
|
||||||
|
// Order matches the Direction enum, so currentIndex() can be used
|
||||||
|
// directly wherever Direction is needed.
|
||||||
|
m_direction->addItem(tr("Haut"));
|
||||||
|
m_direction->addItem(tr("Bas"));
|
||||||
|
m_direction->addItem(tr("Gauche"));
|
||||||
|
m_direction->addItem(tr("Droite"));
|
||||||
|
form->addRow(tr("Direction :"), m_direction);
|
||||||
|
|
||||||
|
const QPoint saved = savedStepOffset();
|
||||||
|
// The saved value is a signed (dx, dy) pair, not itself a
|
||||||
|
// spacing+direction pair, so it has to be decomposed back into the
|
||||||
|
// two the dialog shows. Exactly one axis is ever non-zero (see
|
||||||
|
// stepOffset()), so whichever one is picks the direction; a value
|
||||||
|
// that somehow has neither (only possible if QSettings was hand-
|
||||||
|
// edited) falls back to the same default stepOffset() would.
|
||||||
|
int spacing = 1;
|
||||||
|
Direction direction = Right;
|
||||||
|
if (saved.x() > 0) { direction = Right; spacing = saved.x(); }
|
||||||
|
else if (saved.x() < 0) { direction = Left; spacing = -saved.x(); }
|
||||||
|
else if (saved.y() > 0) { direction = Down; spacing = saved.y(); }
|
||||||
|
else if (saved.y() < 0) { direction = Up; spacing = -saved.y(); }
|
||||||
|
m_spacing->setValue(spacing);
|
||||||
|
m_direction->setCurrentIndex(static_cast<int>(direction));
|
||||||
|
|
||||||
|
auto *buttons = new QDialogButtonBox(
|
||||||
|
QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
||||||
|
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||||
|
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
|
||||||
|
auto *layout = new QVBoxLayout(this);
|
||||||
|
layout->addLayout(form);
|
||||||
|
layout->addWidget(buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPoint DuplicateOffsetDialog::stepOffset() const
|
||||||
|
{
|
||||||
|
const int spacing = m_spacing->value();
|
||||||
|
switch (static_cast<Direction>(m_direction->currentIndex())) {
|
||||||
|
case Up: return QPoint(0, -spacing);
|
||||||
|
case Down: return QPoint(0, spacing);
|
||||||
|
case Left: return QPoint(-spacing, 0);
|
||||||
|
case Right: return QPoint(spacing, 0);
|
||||||
|
}
|
||||||
|
return QPoint(spacing, 0); // unreachable; keeps -Wreturn-type quiet
|
||||||
|
}
|
||||||
|
|
||||||
|
QPoint DuplicateOffsetDialog::savedStepOffset()
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
if (!hasSavedStepOffset()) {
|
||||||
|
return QPoint(1, 0); // default: one grid step to the right
|
||||||
|
}
|
||||||
|
return QPoint(settings.value(kOffsetXKey).toInt(),
|
||||||
|
settings.value(kOffsetYKey).toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DuplicateOffsetDialog::saveStepOffset(const QPoint &steps)
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
settings.setValue(kOffsetXKey, steps.x());
|
||||||
|
settings.setValue(kOffsetYKey, steps.y());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DuplicateOffsetDialog::hasSavedStepOffset()
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
return settings.contains(kOffsetXKey) && settings.contains(kOffsetYKey);
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
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 DUPLICATEOFFSETDIALOG_H
|
||||||
|
#define DUPLICATEOFFSETDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QPoint>
|
||||||
|
|
||||||
|
class QSpinBox;
|
||||||
|
class QComboBox;
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief The DuplicateOffsetDialog class
|
||||||
|
Asks how far, and in which of the four cardinal directions, Ctrl+D
|
||||||
|
(DiagramView::duplicate(), bugtracker #991) should offset a copy from
|
||||||
|
its source. Shown once, then remembered: the answer is stored in
|
||||||
|
QSettings and reused by every later Ctrl+D press without asking
|
||||||
|
again, until this dialog is reopened deliberately.
|
||||||
|
*/
|
||||||
|
class DuplicateOffsetDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Direction { Up, Down, Left, Right };
|
||||||
|
|
||||||
|
explicit DuplicateOffsetDialog(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
/// The offset in grid steps, positive along X to the right
|
||||||
|
/// and positive along Y downward -- QET's own scene axes,
|
||||||
|
/// matching the sign convention setPos() already uses
|
||||||
|
/// everywhere else in this codebase.
|
||||||
|
QPoint stepOffset() const;
|
||||||
|
|
||||||
|
/// Reads the last-confirmed spacing/direction from QSettings,
|
||||||
|
/// or the default (1 step, right) if none was ever set.
|
||||||
|
static QPoint savedStepOffset();
|
||||||
|
/// Writes @p steps to QSettings, in the same X/Y convention
|
||||||
|
/// as stepOffset().
|
||||||
|
static void saveStepOffset(const QPoint &steps);
|
||||||
|
/// Whether a direction/spacing has already been confirmed
|
||||||
|
/// once, i.e. whether Ctrl+D can skip the dialog.
|
||||||
|
static bool hasSavedStepOffset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSpinBox *m_spacing = nullptr;
|
||||||
|
QComboBox *m_direction = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DUPLICATEOFFSETDIALOG_H
|
||||||
@@ -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 "elementinfowidget.h"
|
#include "elementinfowidget.h"
|
||||||
|
#include "../qet.h"
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include "../diagram.h"
|
#include "../diagram.h"
|
||||||
@@ -366,18 +367,18 @@ void ElementInfoWidget::updateUi()
|
|||||||
// Load the lock status for auto numbering
|
// Load the lock status for auto numbering
|
||||||
if (m_element->elementData().m_type == ElementData::Terminal) {
|
if (m_element->elementData().m_type == ElementData::Terminal) {
|
||||||
QString lock_value = element_info.value(QStringLiteral("auto_num_locked")).toString();
|
QString lock_value = element_info.value(QStringLiteral("auto_num_locked")).toString();
|
||||||
ui->m_auto_num_locked_cb->setChecked(lock_value == QLatin1String("true"));
|
ui->m_auto_num_locked_cb->setChecked(QET::infoFlagIsTrue(lock_value));
|
||||||
|
|
||||||
// English: Load the potential isolating status from the element information mapping
|
// English: Load the potential isolating status from the element information mapping
|
||||||
if (m_potential_isolating_cb) {
|
if (m_potential_isolating_cb) {
|
||||||
QString isolating_value = element_info.value(QStringLiteral("potential_isolating")).toString();
|
QString isolating_value = element_info.value(QStringLiteral("potential_isolating")).toString();
|
||||||
m_potential_isolating_cb->setChecked(isolating_value == QLatin1String("true"));
|
m_potential_isolating_cb->setChecked(QET::infoFlagIsTrue(isolating_value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// English: Load the BOM exclusion status from the element information mapping
|
// English: Load the BOM exclusion status from the element information mapping
|
||||||
if (m_exclude_from_bom_cb) {
|
if (m_exclude_from_bom_cb) {
|
||||||
QString exclude_bom_value = element_info.value(QStringLiteral("exclude_from_bom")).toString();
|
QString exclude_bom_value = element_info.value(QStringLiteral("exclude_from_bom")).toString();
|
||||||
m_exclude_from_bom_cb->setChecked(exclude_bom_value == QLatin1String("true"));
|
m_exclude_from_bom_cb->setChecked(QET::infoFlagIsTrue(exclude_bom_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_live_edit) {
|
if (m_live_edit) {
|
||||||
|
|||||||
@@ -539,7 +539,35 @@ void MasterPropertiesWidget::updateUi()
|
|||||||
tr("Type"), tr("Adresse"), tr("Fonction"),
|
tr("Type"), tr("Adresse"), tr("Fonction"),
|
||||||
tr("Commentaire"), tr("Réf. croisée"), tr("Bornes")
|
tr("Commentaire"), tr("Réf. croisée"), tr("Bornes")
|
||||||
});
|
});
|
||||||
m_plc_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
m_plc_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
|
||||||
|
m_plc_table->horizontalHeader()->setSectionsMovable(true);
|
||||||
|
m_plc_table->horizontalHeader()->resizeSection(0, 120);
|
||||||
|
m_plc_table->horizontalHeader()->resizeSection(1, 100);
|
||||||
|
m_plc_table->horizontalHeader()->resizeSection(2, 150);
|
||||||
|
m_plc_table->horizontalHeader()->resizeSection(3, 150);
|
||||||
|
m_plc_table->horizontalHeader()->resizeSection(4, 100);
|
||||||
|
m_plc_table->horizontalHeader()->resizeSection(5, 120);
|
||||||
|
|
||||||
|
// Restore a previously saved column layout, if any
|
||||||
|
auto *plc_hdr = m_plc_table->horizontalHeader();
|
||||||
|
QSettings plc_settings;
|
||||||
|
const QVariant plc_hdr_state = plc_settings.value(
|
||||||
|
QStringLiteral("masterpropertieswidget/plc-table-header-state"));
|
||||||
|
if (!plc_hdr_state.isNull())
|
||||||
|
plc_hdr->restoreState(plc_hdr_state.toByteArray());
|
||||||
|
|
||||||
|
// Persist the column layout whenever the user resizes or moves a column
|
||||||
|
auto save_plc_header_state = [plc_hdr]()
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
settings.setValue(QStringLiteral("masterpropertieswidget/plc-table-header-state"),
|
||||||
|
plc_hdr->saveState());
|
||||||
|
};
|
||||||
|
connect(plc_hdr, &QHeaderView::sectionResized,
|
||||||
|
this, save_plc_header_state);
|
||||||
|
connect(plc_hdr, &QHeaderView::sectionMoved,
|
||||||
|
this, save_plc_header_state);
|
||||||
|
|
||||||
m_plc_table->setSelectionBehavior(QAbstractItemView::SelectItems);
|
m_plc_table->setSelectionBehavior(QAbstractItemView::SelectItems);
|
||||||
m_plc_table->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
m_plc_table->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
m_plc_table->setMinimumHeight(200);
|
m_plc_table->setMinimumHeight(200);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user