Compare commits

..

6 Commits

Author SHA1 Message Date
Maximilian Federle 4f1567ec97 projectview: Only append .qet if not snap or flatpak 2022-01-26 17:04:17 +01:00
Maximilian Federle e152717a05 add workflow for building candidate snap 2022-01-20 10:09:35 +01:00
Maximilian Federle 0f645e9b76 snap: set version manually 2022-01-20 09:53:17 +01:00
Maximilian Federle 821e681520 projectview: Re-enable appending qet suffix if not running as flatpak
It was removed in b121dad for all platforms.
Only disable appending the suffix for the flatpak platform
by testing for the FLATPAK_ID environment variable.
2022-01-20 09:46:19 +01:00
Maximilian Federle d27bc35022 snap: Remove framework snap prompt
Now that https://github.com/snapcore/snapcraft/pull/3596 has been
released in snapcraft 6.0.1, drop the prompt that tells users to
disconnect the old framework snap.

Also drop --enable-experimental-extensions from CI  because kde-neon
has been declared stable for core20.
2022-01-20 09:45:43 +01:00
Maximilian Federle 61d3adad9b snap: Port to core20 2022-01-20 09:44:33 +01:00
139 changed files with 34658 additions and 39081 deletions
@@ -0,0 +1,20 @@
name: Publish Candidate Snap
on:
push:
branches:
- "snap/latest/candidate"
workflow_dispatch:
jobs:
publish_amd64:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: snapcore/action-build@v1
id: build
- uses: snapcore/action-publish@v1
with:
store_login: ${{ secrets.STORE_LOGIN }}
snap: ${{ steps.build.outputs.snap }}
release: candidate
+1 -1
View File
@@ -19,7 +19,7 @@ include(cmake/hoto_update_cmake_message.cmake)
cmake_minimum_required(VERSION 3.14...3.19 FATAL_ERROR) cmake_minimum_required(VERSION 3.14...3.19 FATAL_ERROR)
project(qelectrotech project(qelectrotech
VERSION 0.9.0 VERSION 0.8.0
DESCRIPTION "QET is a CAD/CAE editor focusing on schematics drawing features." DESCRIPTION "QET is a CAD/CAE editor focusing on schematics drawing features."
HOMEPAGE_URL "https://qelectrotech.org/" HOMEPAGE_URL "https://qelectrotech.org/"
LANGUAGES CXX) LANGUAGES CXX)
+1 -68
View File
@@ -1,79 +1,12 @@
Changelog Changelog
========= =========
If by accident I have forgotten to credit someone in the CHANGELOG, email me and I will fix it.
__3.2.0__
---------
* Added support for Qt 6 - _Jonas Kvinge_
* Fixed warning in `Qt 5.9` with `min`/`max` functions on Windows - _Nick Korotysh_
* Fix return value of connectToPrimary() when connect is successful - _Jonas Kvinge_
* Fix build issue with MinGW GCC pedantic mode - _Iakov Kirilenko_
* Fixed conversion from `int` to `quint32` and Clang Tidy warnings - _Hennadii Chernyshchyk_
__3.1.5__
---------
* Improved library stability in edge cases and very rapid process initialisation
* Fixed Bug where the shared memory block may have been modified without a lock
* Fixed Bug causing `instanceStarted()` to not get emitted when a second instance
has been started before the primary has initiated it's `QLocalServer`.
__3.1.4__
---------
* Officially supporting and build-testing against Qt 5.15
* Fixed an MSVC C4996 warning that suggests using `strncpy_s`.
_Hennadii Chernyshchyk_
__3.1.3.1__
---------
* CMake build system improvements
* Fixed Clang Tidy warnings
_Hennadii Chernyshchyk_
__3.1.3__
---------
* Improved `CMakeLists.txt`
_Hennadii Chernyshchyk_
__3.1.2__
---------
* Fix a crash when exiting an application on Android and iOS
_Emeric Grange_
__3.1.1a__
----------
* Added currentUser() method that returns the user the current instance is running as.
_Leander Schulten_
__3.1.0a__
----------
* Added primaryUser() method that returns the user the primary instance is running as.
__3.0.19__
----------
* Fixed code warning for depricated functions in Qt 5.10 related to `QTime` and `qrand()`.
_Hennadii Chernyshchyk_
_Anton Filimonov_
_Jonas Kvinge_
__3.0.18__ __3.0.18__
---------- ----------
* Fallback to standard QApplication class on iOS and Android systems where * Fallback to standard QApplication class on iOS and Android systems where
the library is not supported. the library is not supported.
* Added Build CI tests to verify the library builds successfully on Linux, Windows and MacOS across multiple Qt versions. * Added Build CI tests to verify the library builds successfully on Linux, Windows and MacOS across multiple Qt versions.
_Anton Filimonov_ _Anton Filimonov_
+23 -20
View File
@@ -1,40 +1,43 @@
cmake_minimum_required(VERSION 3.7.0) cmake_minimum_required(VERSION 3.1.0)
project(SingleApplication LANGUAGES CXX) project(SingleApplication)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
# SingleApplication base class
set(QAPPLICATION_CLASS QCoreApplication CACHE STRING "Inheritance class for SingleApplication")
set_property(CACHE QAPPLICATION_CLASS PROPERTY STRINGS QApplication QGuiApplication QCoreApplication)
# Libary target
add_library(${PROJECT_NAME} STATIC add_library(${PROJECT_NAME} STATIC
singleapplication.cpp singleapplication.cpp
singleapplication_p.cpp singleapplication_p.cpp
) )
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
if(NOT QT_DEFAULT_MAJOR_VERSION)
set(QT_DEFAULT_MAJOR_VERSION 5 CACHE STRING "Qt version to use (5 or 6), defaults to 5")
endif()
# Find dependencies # Find dependencies
set(QT_COMPONENTS Core Network) find_package(Qt5Network)
set(QT_LIBRARIES Qt${QT_DEFAULT_MAJOR_VERSION}::Core Qt${QT_DEFAULT_MAJOR_VERSION}::Network)
if(QAPPLICATION_CLASS STREQUAL QApplication) if(QAPPLICATION_CLASS STREQUAL QApplication)
list(APPEND QT_COMPONENTS Widgets) find_package(Qt5 COMPONENTS Widgets REQUIRED)
list(APPEND QT_LIBRARIES Qt${QT_DEFAULT_MAJOR_VERSION}::Widgets)
elseif(QAPPLICATION_CLASS STREQUAL QGuiApplication) elseif(QAPPLICATION_CLASS STREQUAL QGuiApplication)
list(APPEND QT_COMPONENTS Gui) find_package(Qt5 COMPONENTS Gui REQUIRED)
list(APPEND QT_LIBRARIES Qt${QT_DEFAULT_MAJOR_VERSION}::Gui)
else() else()
set(QAPPLICATION_CLASS QCoreApplication) find_package(Qt5 COMPONENTS Core REQUIRED)
endif() endif()
add_compile_definitions(QAPPLICATION_CLASS=${QAPPLICATION_CLASS})
find_package(Qt${QT_DEFAULT_MAJOR_VERSION} COMPONENTS ${QT_COMPONENTS} REQUIRED) # Link dependencies
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Network)
target_link_libraries(${PROJECT_NAME} PUBLIC ${QT_LIBRARIES}) if(QAPPLICATION_CLASS STREQUAL QApplication)
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets)
elseif(QAPPLICATION_CLASS STREQUAL QGuiApplication)
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Gui)
else()
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core)
endif()
if(WIN32) if(WIN32)
target_link_libraries(${PROJECT_NAME} PRIVATE advapi32) target_link_libraries(${PROJECT_NAME} PRIVATE advapi32)
endif() endif()
target_compile_definitions(${PROJECT_NAME} PUBLIC QAPPLICATION_CLASS=${QAPPLICATION_CLASS})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) Itay Grudev 2015 - 2020 Copyright (c) Itay Grudev 2015 - 2016
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+18 -45
View File
@@ -1,8 +1,7 @@
SingleApplication SingleApplication
================= =================
[![CI](https://github.com/itay-grudev/SingleApplication/workflows/CI:%20Build%20Test/badge.svg)](https://github.com/itay-grudev/SingleApplication/actions)
This is a replacement of the QtSingleApplication for `Qt5` and `Qt6`. This is a replacement of the QtSingleApplication for `Qt5`.
Keeps the Primary Instance of your Application and kills each subsequent Keeps the Primary Instance of your Application and kills each subsequent
instances. It can (if enabled) spawn secondary (non-related to the primary) instances. It can (if enabled) spawn secondary (non-related to the primary)
@@ -16,6 +15,18 @@ class you specify via the `QAPPLICATION_CLASS` macro (`QCoreApplication` is the
default). Further usage is similar to the use of the `Q[Core|Gui]Application` default). Further usage is similar to the use of the `Q[Core|Gui]Application`
classes. classes.
The library sets up a `QLocalServer` and a `QSharedMemory` block. The first
instance of your Application is your Primary Instance. It would check if the
shared memory block exists and if not it will start a `QLocalServer` and listen
for connections. Each subsequent instance of your application would check if the
shared memory block exists and if it does, it will connect to the QLocalServer
to notify the primary instance that a new instance had been started, after which
it would terminate with status code `0`. In the Primary Instance
`SingleApplication` would emit the `instanceStarted()` signal upon detecting
that a new instance had been started.
The library uses `stdlib` to terminate the program with the `exit()` function.
You can use the library as if you use any other `QCoreApplication` derived You can use the library as if you use any other `QCoreApplication` derived
class: class:
@@ -32,7 +43,8 @@ int main( int argc, char* argv[] )
``` ```
To include the library files I would recommend that you add it as a git To include the library files I would recommend that you add it as a git
submodule to your project. Here is how: submodule to your project and include it's contents with a `.pri` file. Here is
how:
```bash ```bash
git submodule add git@github.com:itay-grudev/SingleApplication.git singleapplication git submodule add git@github.com:itay-grudev/SingleApplication.git singleapplication
@@ -54,27 +66,13 @@ Then include the subdirectory in your `CMakeLists.txt` project file.
```cmake ```cmake
set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication") set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")
add_subdirectory(src/third-party/singleapplication) add_subdirectory(src/third-party/singleapplication)
target_link_libraries(${PROJECT_NAME} SingleApplication::SingleApplication)
``` ```
The library sets up a `QLocalServer` and a `QSharedMemory` block. The first
instance of your Application is your Primary Instance. It would check if the
shared memory block exists and if not it will start a `QLocalServer` and listen
for connections. Each subsequent instance of your application would check if the
shared memory block exists and if it does, it will connect to the QLocalServer
to notify the primary instance that a new instance had been started, after which
it would terminate with status code `0`. In the Primary Instance
`SingleApplication` would emit the `instanceStarted()` signal upon detecting
that a new instance had been started.
The library uses `stdlib` to terminate the program with the `exit()` function.
Also don't forget to specify which `QCoreApplication` class your app is using if it Also don't forget to specify which `QCoreApplication` class your app is using if it
is not `QCoreApplication` as in examples above. is not `QCoreApplication` as in examples above.
The `Instance Started` signal The `Instance Started` signal
----------------------------- ------------------------
The SingleApplication class implements a `instanceStarted()` signal. You can The SingleApplication class implements a `instanceStarted()` signal. You can
bind to that signal to raise your application's window when a new instance had bind to that signal to raise your application's window when a new instance had
@@ -139,22 +137,13 @@ app.isSecondary();
*__Note:__ If your Primary Instance is terminated a newly launched instance *__Note:__ If your Primary Instance is terminated a newly launched instance
will replace the Primary one even if the Secondary flag has been set.* will replace the Primary one even if the Secondary flag has been set.*
Examples
--------
There are three examples provided in this repository:
* Basic example that prevents a secondary instance from starting [`examples/basic`](https://github.com/itay-grudev/SingleApplication/tree/master/examples/basic)
* An example of a graphical application raising it's parent window [`examples/calculator`](https://github.com/itay-grudev/SingleApplication/tree/master/examples/calculator)
* A console application sending the primary instance it's command line parameters [`examples/sending_arguments`](https://github.com/itay-grudev/SingleApplication/tree/master/examples/sending_arguments)
API API
--- ---
### Members ### Members
```cpp ```cpp
SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100, QString userData = QString() ) SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100 )
``` ```
Depending on whether `allowSecondary` is set, this constructor may terminate Depending on whether `allowSecondary` is set, this constructor may terminate
@@ -163,7 +152,7 @@ can be specified to set whether the SingleApplication block should work
user-wide or system-wide. Additionally the `Mode::SecondaryNotification` may be user-wide or system-wide. Additionally the `Mode::SecondaryNotification` may be
used to notify the primary instance whenever a secondary instance had been used to notify the primary instance whenever a secondary instance had been
started (disabled by default). `timeout` specifies the maximum time in started (disabled by default). `timeout` specifies the maximum time in
milliseconds to wait for blocking operations. Setting `userData` provides additional data that will isolate this instance from other instances that do not have the same (or any) user data set. milliseconds to wait for blocking operations.
*__Note:__ `argc` and `argv` may be changed as Qt removes arguments that it *__Note:__ `argc` and `argv` may be changed as Qt removes arguments that it
recognizes.* recognizes.*
@@ -215,22 +204,6 @@ qint64 SingleApplication::primaryPid()
Returns the process ID (PID) of the primary instance. Returns the process ID (PID) of the primary instance.
---
```cpp
QString SingleApplication::primaryUser()
```
Returns the username the primary instance is running as.
---
```cpp
QString SingleApplication::currentUser()
```
Returns the username the current instance is running as.
### Signals ### Signals
```cpp ```cpp
-1
View File
@@ -1 +0,0 @@
#include "singleapplication.h"
@@ -1,12 +0,0 @@
cmake_minimum_required(VERSION 3.7.0)
project(basic LANGUAGES CXX)
# SingleApplication base class
set(QAPPLICATION_CLASS QCoreApplication)
add_subdirectory(../.. SingleApplication)
add_executable(basic main.cpp)
target_link_libraries(${PROJECT_NAME} SingleApplication::SingleApplication)
View File
-2
View File
@@ -5,7 +5,5 @@ int main(int argc, char *argv[])
// Allow secondary instances // Allow secondary instances
SingleApplication app( argc, argv ); SingleApplication app( argc, argv );
qWarning() << "Started a new instance";
return app.exec(); return app.exec();
} }
@@ -1,21 +0,0 @@
cmake_minimum_required(VERSION 3.7.0)
project(calculator LANGUAGES CXX)
set(CMAKE_AUTOMOC ON)
# SingleApplication base class
set(QAPPLICATION_CLASS QApplication)
add_subdirectory(../.. SingleApplication)
find_package(Qt${QT_DEFAULT_MAJOR_VERSION} COMPONENTS Core REQUIRED)
add_executable(${PROJECT_NAME}
button.h
calculator.h
button.cpp
calculator.cpp
main.cpp
)
target_link_libraries(${PROJECT_NAME} SingleApplication::SingleApplication)
@@ -82,27 +82,27 @@ Calculator::Calculator(QWidget *parent)
digitButtons[i] = createButton(QString::number(i), SLOT(digitClicked())); digitButtons[i] = createButton(QString::number(i), SLOT(digitClicked()));
} }
Button *pointButton = createButton(".", SLOT(pointClicked())); Button *pointButton = createButton(tr("."), SLOT(pointClicked()));
Button *changeSignButton = createButton("\302\261", SLOT(changeSignClicked())); Button *changeSignButton = createButton(tr("\302\261"), SLOT(changeSignClicked()));
Button *backspaceButton = createButton("Backspace", SLOT(backspaceClicked())); Button *backspaceButton = createButton(tr("Backspace"), SLOT(backspaceClicked()));
Button *clearButton = createButton("Clear", SLOT(clear())); Button *clearButton = createButton(tr("Clear"), SLOT(clear()));
Button *clearAllButton = createButton("Clear All", SLOT(clearAll())); Button *clearAllButton = createButton(tr("Clear All"), SLOT(clearAll()));
Button *clearMemoryButton = createButton("MC", SLOT(clearMemory())); Button *clearMemoryButton = createButton(tr("MC"), SLOT(clearMemory()));
Button *readMemoryButton = createButton("MR", SLOT(readMemory())); Button *readMemoryButton = createButton(tr("MR"), SLOT(readMemory()));
Button *setMemoryButton = createButton("MS", SLOT(setMemory())); Button *setMemoryButton = createButton(tr("MS"), SLOT(setMemory()));
Button *addToMemoryButton = createButton("M+", SLOT(addToMemory())); Button *addToMemoryButton = createButton(tr("M+"), SLOT(addToMemory()));
Button *divisionButton = createButton("\303\267", SLOT(multiplicativeOperatorClicked())); Button *divisionButton = createButton(tr("\303\267"), SLOT(multiplicativeOperatorClicked()));
Button *timesButton = createButton("\303\227", SLOT(multiplicativeOperatorClicked())); Button *timesButton = createButton(tr("\303\227"), SLOT(multiplicativeOperatorClicked()));
Button *minusButton = createButton("-", SLOT(additiveOperatorClicked())); Button *minusButton = createButton(tr("-"), SLOT(additiveOperatorClicked()));
Button *plusButton = createButton("+", SLOT(additiveOperatorClicked())); Button *plusButton = createButton(tr("+"), SLOT(additiveOperatorClicked()));
Button *squareRootButton = createButton("Sqrt", SLOT(unaryOperatorClicked())); Button *squareRootButton = createButton(tr("Sqrt"), SLOT(unaryOperatorClicked()));
Button *powerButton = createButton("x\302\262", SLOT(unaryOperatorClicked())); Button *powerButton = createButton(tr("x\302\262"), SLOT(unaryOperatorClicked()));
Button *reciprocalButton = createButton("1/x", SLOT(unaryOperatorClicked())); Button *reciprocalButton = createButton(tr("1/x"), SLOT(unaryOperatorClicked()));
Button *equalButton = createButton("=", SLOT(equalClicked())); Button *equalButton = createButton(tr("="), SLOT(equalClicked()));
//! [4] //! [4]
//! [5] //! [5]
@@ -140,7 +140,7 @@ Calculator::Calculator(QWidget *parent)
mainLayout->addWidget(equalButton, 5, 5); mainLayout->addWidget(equalButton, 5, 5);
setLayout(mainLayout); setLayout(mainLayout);
setWindowTitle("Calculator"); setWindowTitle(tr("Calculator"));
} }
//! [6] //! [6]
@@ -169,15 +169,15 @@ void Calculator::unaryOperatorClicked()
double operand = display->text().toDouble(); double operand = display->text().toDouble();
double result = 0.0; double result = 0.0;
if (clickedOperator == "Sqrt") { if (clickedOperator == tr("Sqrt")) {
if (operand < 0.0) { if (operand < 0.0) {
abortOperation(); abortOperation();
return; return;
} }
result = std::sqrt(operand); result = std::sqrt(operand);
} else if (clickedOperator == "x\302\262") { } else if (clickedOperator == tr("x\302\262")) {
result = std::pow(operand, 2.0); result = std::pow(operand, 2.0);
} else if (clickedOperator == "1/x") { } else if (clickedOperator == tr("1/x")) {
if (operand == 0.0) { if (operand == 0.0) {
abortOperation(); abortOperation();
return; return;
@@ -287,7 +287,7 @@ void Calculator::pointClicked()
if (waitingForOperand) if (waitingForOperand)
display->setText("0"); display->setText("0");
if (!display->text().contains('.')) if (!display->text().contains('.'))
display->setText(display->text() + "."); display->setText(display->text() + tr("."));
waitingForOperand = false; waitingForOperand = false;
} }
//! [22] //! [22]
@@ -299,7 +299,7 @@ void Calculator::changeSignClicked()
double value = text.toDouble(); double value = text.toDouble();
if (value > 0.0) { if (value > 0.0) {
text.prepend("-"); text.prepend(tr("-"));
} else if (value < 0.0) { } else if (value < 0.0) {
text.remove(0, 1); text.remove(0, 1);
} }
@@ -383,20 +383,20 @@ Button *Calculator::createButton(const QString &text, const char *member)
void Calculator::abortOperation() void Calculator::abortOperation()
{ {
clearAll(); clearAll();
display->setText("####"); display->setText(tr("####"));
} }
//! [36] //! [36]
//! [38] //! [38]
bool Calculator::calculate(double rightOperand, const QString &pendingOperator) bool Calculator::calculate(double rightOperand, const QString &pendingOperator)
{ {
if (pendingOperator == "+") { if (pendingOperator == tr("+")) {
sumSoFar += rightOperand; sumSoFar += rightOperand;
} else if (pendingOperator == "-") { } else if (pendingOperator == tr("-")) {
sumSoFar -= rightOperand; sumSoFar -= rightOperand;
} else if (pendingOperator == "\303\227") { } else if (pendingOperator == tr("\303\227")) {
factorSoFar *= rightOperand; factorSoFar *= rightOperand;
} else if (pendingOperator == "\303\267") { } else if (pendingOperator == tr("\303\267")) {
if (rightOperand == 0.0) if (rightOperand == 0.0)
return false; return false;
factorSoFar /= rightOperand; factorSoFar /= rightOperand;
@@ -1,20 +0,0 @@
cmake_minimum_required(VERSION 3.7.0)
project(sending_arguments LANGUAGES CXX)
set(CMAKE_AUTOMOC ON)
# SingleApplication base class
set(QAPPLICATION_CLASS QCoreApplication)
add_subdirectory(../.. SingleApplication)
find_package(Qt${QT_DEFAULT_MAJOR_VERSION} COMPONENTS Core REQUIRED)
add_executable(${PROJECT_NAME}
main.cpp
messagereceiver.cpp
messagereceiver.h
main.cpp
)
target_link_libraries(${PROJECT_NAME} SingleApplication::SingleApplication)
-3
View File
@@ -11,9 +11,6 @@ int main(int argc, char *argv[])
// If this is a secondary instance // If this is a secondary instance
if( app.isSecondary() ) { if( app.isSecondary() ) {
app.sendMessage( app.arguments().join(' ').toUtf8() ); app.sendMessage( app.arguments().join(' ').toUtf8() );
qDebug() << "App already running.";
qDebug() << "Primary instance PID: " << app.primaryPid();
qDebug() << "Primary instance user: " << app.primaryUser();
return 0; return 0;
} else { } else {
QObject::connect( QObject::connect(
View File
+128 -207
View File
@@ -1,6 +1,6 @@
// The MIT License (MIT) // The MIT License (MIT)
// //
// Copyright (c) Itay Grudev 2015 - 2020 // Copyright (c) Itay Grudev 2015 - 2018
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -20,255 +20,176 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
#include <QtCore/QElapsedTimer> #include <QtCore/QTime>
#include <QtCore/QThread>
#include <QtCore/QDateTime>
#include <QtCore/QByteArray> #include <QtCore/QByteArray>
#include <QtCore/QSharedMemory> #include <QtCore/QSharedMemory>
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) // ### Qt 6: remove
#else
#if TODO_LIST
#pragma message("@TODO remove code for QT 5.10 or later")
#endif
#include <QRandomGenerator>
#endif
#include "singleapplication.h" #include "singleapplication.h"
#include "singleapplication_p.h" #include "singleapplication_p.h"
/** /**
* @brief Constructor. Checks and fires up LocalServer or closes the program @brief Constructor. Checks and fires up LocalServer or closes the program
* if another instance already exists if another instance already exists
* @param argc @param argc
* @param argv @param argv
* @param allowSecondary Whether to enable secondary instance support @param {bool} allowSecondaryInstances
* @param options Optional flags to toggle specific behaviour */
* @param timeout Maximum time blocking functions are allowed during app load SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary, Options options, int timeout )
*/ : app_t( argc, argv ), d_ptr( new SingleApplicationPrivate( this ) )
SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary, Options options, int timeout, const QString &userData )
: app_t( argc, argv ), d_ptr( new SingleApplicationPrivate( this ) )
{ {
Q_D( SingleApplication ); Q_D(SingleApplication);
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
// On Android and iOS since the library is not supported fallback to // On Android and iOS since the library is not supported fallback to
// standard QApplication behaviour by simply returning at this point. // standard QApplication behaviour by simply returning at this point.
qWarning() << "SingleApplication is not supported on Android and iOS systems."; qWarning() << "SingleApplication is not supported on Android and iOS systems.";
return; return;
#endif #endif
// Store the current mode of the program // Store the current mode of the program
d->options = options; d->options = options;
// Add any unique user data // Generating an application ID used for identifying the shared memory
if ( ! userData.isEmpty() ) // block and QLocalServer
d->addAppData( userData ); d->genBlockServerName();
// Generating an application ID used for identifying the shared memory
// block and QLocalServer
d->genBlockServerName();
// To mitigate QSharedMemory issues with large amount of processes
// attempting to attach at the same time
SingleApplicationPrivate::randomSleep();
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
// By explicitly attaching it and then deleting it we make sure that the // By explicitly attaching it and then deleting it we make sure that the
// memory is deleted even after the process has crashed on Unix. // memory is deleted even after the process has crashed on Unix.
d->memory = new QSharedMemory( d->blockServerName ); d->memory = new QSharedMemory( d->blockServerName );
d->memory->attach(); d->memory->attach();
delete d->memory; delete d->memory;
#endif #endif
// Guarantee thread safe behaviour with a shared memory block. // Guarantee thread safe behaviour with a shared memory block.
d->memory = new QSharedMemory( d->blockServerName ); d->memory = new QSharedMemory( d->blockServerName );
// Create a shared memory block // Create a shared memory block
if( d->memory->create( sizeof( InstancesInfo ) )){ if( d->memory->create( sizeof( InstancesInfo ) ) ) {
// Initialize the shared memory block // Initialize the shared memory block
if( ! d->memory->lock() ){ d->memory->lock();
qCritical() << "SingleApplication: Unable to lock memory block after create."; d->initializeMemoryBlock();
abortSafely(); d->memory->unlock();
} } else {
d->initializeMemoryBlock(); // Attempt to attach to the memory segment
} else { if( ! d->memory->attach() ) {
if( d->memory->error() == QSharedMemory::AlreadyExists ){ qCritical() << "SingleApplication: Unable to attach to shared memory block.";
// Attempt to attach to the memory segment qCritical() << d->memory->errorString();
if( ! d->memory->attach() ){ delete d;
qCritical() << "SingleApplication: Unable to attach to shared memory block."; ::exit( EXIT_FAILURE );
abortSafely(); }
} }
if( ! d->memory->lock() ){
qCritical() << "SingleApplication: Unable to lock memory block after attach.";
abortSafely();
}
} else {
qCritical() << "SingleApplication: Unable to create block.";
abortSafely();
}
}
auto *inst = static_cast<InstancesInfo*>( d->memory->data() ); InstancesInfo* inst = static_cast<InstancesInfo*>( d->memory->data() );
QElapsedTimer time; QElapsedTimer time;
time.start(); time.start();
// Make sure the shared memory block is initialised and in consistent state // Make sure the shared memory block is initialised and in consistent state
while( true ){ while( true ) {
// If the shared memory block's checksum is valid continue d->memory->lock();
if( d->blockChecksum() == inst->checksum ) break;
// If more than 5s have elapsed, assume the primary instance crashed and if( d->blockChecksum() == inst->checksum ) break;
// assume it's position
if( time.elapsed() > 5000 ){
qWarning() << "SingleApplication: Shared memory block has been in an inconsistent state from more than 5s. Assuming primary instance failure.";
d->initializeMemoryBlock();
}
// Otherwise wait for a random period and try again. The random sleep here if( time.elapsed() > 5000 ) {
// limits the probability of a collision between two racing apps and qWarning() << "SingleApplication: Shared memory block has been in an inconsistent state from more than 5s. Assuming primary instance failure.";
// allows the app to initialise faster d->initializeMemoryBlock();
if( ! d->memory->unlock() ){ }
qDebug() << "SingleApplication: Unable to unlock memory for random wait.";
qDebug() << d->memory->errorString();
}
SingleApplicationPrivate::randomSleep();
if( ! d->memory->lock() ){
qCritical() << "SingleApplication: Unable to lock memory after random wait.";
abortSafely();
}
}
if( inst->primary == false ){ d->memory->unlock();
d->startPrimary();
if( ! d->memory->unlock() ){
qDebug() << "SingleApplication: Unable to unlock memory after primary start.";
qDebug() << d->memory->errorString();
}
return;
}
// Check if another instance can be started // Random sleep here limits the probability of a collision between two racing apps
if( allowSecondary ){ #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) // ### Qt 6: remove
d->startSecondary(); qsrand( QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max() );
if( d->options & Mode::SecondaryNotification ){ QThread::sleep( 8 + static_cast <unsigned long>( static_cast <float>( qrand() ) / RAND_MAX * 10 ) );
d->connectToPrimary( timeout, SingleApplicationPrivate::SecondaryInstance ); #else
} #if TODO_LIST
if( ! d->memory->unlock() ){ #pragma message("@TODO remove code for QT 5.10 or later")
qDebug() << "SingleApplication: Unable to unlock memory after secondary start."; #endif
qDebug() << d->memory->errorString(); quint32 value = QRandomGenerator::global()->generate();
} QThread::sleep(8 + static_cast<unsigned long>(value / RAND_MAX * 10));
return; #endif
} }
if( ! d->memory->unlock() ){ if( inst->primary == false) {
qDebug() << "SingleApplication: Unable to unlock memory at end of execution."; d->startPrimary();
qDebug() << d->memory->errorString(); d->memory->unlock();
} return;
}
d->connectToPrimary( timeout, SingleApplicationPrivate::NewInstance ); // Check if another instance can be started
if( allowSecondary ) {
inst->secondary += 1;
inst->checksum = d->blockChecksum();
d->instanceNumber = inst->secondary;
d->startSecondary();
if( d->options & Mode::SecondaryNotification ) {
d->connectToPrimary( timeout, SingleApplicationPrivate::SecondaryInstance );
}
d->memory->unlock();
return;
}
delete d; d->memory->unlock();
::exit( EXIT_SUCCESS ); d->connectToPrimary( timeout, SingleApplicationPrivate::NewInstance );
delete d;
::exit( EXIT_SUCCESS );
} }
/**
@brief Destructor
*/
SingleApplication::~SingleApplication() SingleApplication::~SingleApplication()
{ {
Q_D( SingleApplication ); Q_D(SingleApplication);
delete d; delete d;
} }
/** bool SingleApplication::isPrimary()
* Checks if the current application instance is primary.
* @return Returns true if the instance is primary, false otherwise.
*/
bool SingleApplication::isPrimary() const
{ {
Q_D( const SingleApplication ); Q_D(SingleApplication);
return d->server != nullptr; return d->server != nullptr;
} }
/** bool SingleApplication::isSecondary()
* Checks if the current application instance is secondary.
* @return Returns true if the instance is secondary, false otherwise.
*/
bool SingleApplication::isSecondary() const
{ {
Q_D( const SingleApplication ); Q_D(SingleApplication);
return d->server == nullptr; return d->server == nullptr;
} }
/** quint32 SingleApplication::instanceId()
* Allows you to identify an instance by returning unique consecutive instance
* ids. It is reset when the first (primary) instance of your app starts and
* only incremented afterwards.
* @return Returns a unique instance id.
*/
quint32 SingleApplication::instanceId() const
{ {
Q_D( const SingleApplication ); Q_D(SingleApplication);
return d->instanceNumber; return d->instanceNumber;
} }
/** qint64 SingleApplication::primaryPid()
* Returns the OS PID (Process Identifier) of the process running the primary
* instance. Especially useful when SingleApplication is coupled with OS.
* specific APIs.
* @return Returns the primary instance PID.
*/
qint64 SingleApplication::primaryPid() const
{ {
Q_D( const SingleApplication ); Q_D(SingleApplication);
return d->primaryPid(); return d->primaryPid();
} }
/** bool SingleApplication::sendMessage( QByteArray message, int timeout )
* Returns the username the primary instance is running as.
* @return Returns the username the primary instance is running as.
*/
QString SingleApplication::primaryUser() const
{ {
Q_D( const SingleApplication ); Q_D(SingleApplication);
return d->primaryUser();
} // Nobody to connect to
if( isPrimary() ) return false;
/**
* Returns the username the current instance is running as. // Make sure the socket is connected
* @return Returns the username the current instance is running as. d->connectToPrimary( timeout, SingleApplicationPrivate::Reconnect );
*/
QString SingleApplication::currentUser() const d->socket->write( message );
{ bool dataWritten = d->socket->waitForBytesWritten( timeout );
return SingleApplicationPrivate::getUsername(); d->socket->flush();
} return dataWritten;
/**
* Sends message to the Primary Instance.
* @param message The message to send.
* @param timeout the maximum timeout in milliseconds for blocking functions.
* @return true if the message was sent successfuly, false otherwise.
*/
bool SingleApplication::sendMessage( const QByteArray &message, int timeout )
{
Q_D( SingleApplication );
// Nobody to connect to
if( isPrimary() ) return false;
// Make sure the socket is connected
if( ! d->connectToPrimary( timeout, SingleApplicationPrivate::Reconnect ) )
return false;
d->socket->write( message );
bool dataWritten = d->socket->waitForBytesWritten( timeout );
d->socket->flush();
return dataWritten;
}
/**
* Cleans up the shared memory block and exits with a failure.
* This function halts program execution.
*/
void SingleApplication::abortSafely()
{
Q_D( SingleApplication );
qCritical() << "SingleApplication: " << d->memory->error() << d->memory->errorString();
delete d;
::exit( EXIT_FAILURE );
}
QStringList SingleApplication::userData() const
{
Q_D( const SingleApplication );
return d->appData();
} }
+92 -110
View File
@@ -25,6 +25,7 @@
#include <QtCore/QtGlobal> #include <QtCore/QtGlobal>
#include <QtNetwork/QLocalSocket> #include <QtNetwork/QLocalSocket>
#include <QElapsedTimer>
#ifndef QAPPLICATION_CLASS #ifndef QAPPLICATION_CLASS
#define QAPPLICATION_CLASS QCoreApplication #define QAPPLICATION_CLASS QCoreApplication
@@ -35,118 +36,99 @@
class SingleApplicationPrivate; class SingleApplicationPrivate;
/** /**
* @brief The SingleApplication class handles multiple instances of the same @brief The SingleApplication class handles multiple instances of the same
* Application Application
* @see QCoreApplication @see QCoreApplication
*/ */
class SingleApplication : public QAPPLICATION_CLASS class SingleApplication : public QAPPLICATION_CLASS
{ {
Q_OBJECT Q_OBJECT
using app_t = QAPPLICATION_CLASS; typedef QAPPLICATION_CLASS app_t;
public: public:
/** /**
* @brief Mode of operation of SingleApplication. @brief Mode of operation of SingleApplication.
* Whether the block should be user-wide or system-wide and whether the Whether the block should be user-wide or system-wide and whether the
* primary instance should be notified when a secondary instance had been primary instance should be notified when a secondary instance had been
* started. started.
* @note Operating system can restrict the shared memory blocks to the same @note Operating system can restrict the shared memory blocks to the same
* user, in which case the User/System modes will have no effect and the user, in which case the User/System modes will have no effect and the
* block will be user wide. block will be user wide.
* @enum @enum
*/ */
enum Mode { enum Mode {
User = 1 << 0, User = 1 << 0,
System = 1 << 1, System = 1 << 1,
SecondaryNotification = 1 << 2, SecondaryNotification = 1 << 2,
ExcludeAppVersion = 1 << 3, ExcludeAppVersion = 1 << 3,
ExcludeAppPath = 1 << 4 ExcludeAppPath = 1 << 4
}; };
Q_DECLARE_FLAGS(Options, Mode) Q_DECLARE_FLAGS(Options, Mode)
/** /**
* @brief Intitializes a SingleApplication instance with argc command line @brief Intitializes a SingleApplication instance with argc command line
* arguments in argv arguments in argv
* @arg {int &} argc - Number of arguments in argv @arg {int &} argc - Number of arguments in argv
* @arg {const char *[]} argv - Supplied command line arguments @arg {const char *[]} argv - Supplied command line arguments
* @arg {bool} allowSecondary - Whether to start the instance as secondary @arg {bool} allowSecondary - Whether to start the instance as secondary
* if there is already a primary instance. if there is already a primary instance.
* @arg {Mode} mode - Whether for the SingleApplication block to be applied @arg {Mode} mode - Whether for the SingleApplication block to be applied
* User wide or System wide. User wide or System wide.
* @arg {int} timeout - Timeout to wait in milliseconds. @arg {int} timeout - Timeout to wait in milliseconds.
* @note argc and argv may be changed as Qt removes arguments that it @note argc and argv may be changed as Qt removes arguments that it
* recognizes recognizes
* @note Mode::SecondaryNotification only works if set on both the primary @note Mode::SecondaryNotification only works if set on both the primary
* instance and the secondary instance. instance and the secondary instance.
* @note The timeout is just a hint for the maximum time of blocking @note The timeout is just a hint for the maximum time of blocking
* operations. It does not guarantee that the SingleApplication operations. It does not guarantee that the SingleApplication
* initialisation will be completed in given time, though is a good hint. initialisation will be completed in given time, though is a good hint.
* Usually 4*timeout would be the worst case (fail) scenario. Usually 4*timeout would be the worst case (fail) scenario.
* @see See the corresponding QAPPLICATION_CLASS constructor for reference @see See the corresponding QAPPLICATION_CLASS constructor for reference
*/ */
explicit SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 1000, const QString &userData = {} ); explicit SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 1000 );
~SingleApplication() override; ~SingleApplication();
/** /**
* @brief Returns if the instance is the primary instance @brief Returns if the instance is the primary instance
* @returns {bool} @returns {bool}
*/ */
bool isPrimary() const; bool isPrimary();
/** /**
* @brief Returns if the instance is a secondary instance @brief Returns if the instance is a secondary instance
* @returns {bool} @returns {bool}
*/ */
bool isSecondary() const; bool isSecondary();
/** /**
* @brief Returns a unique identifier for the current instance @brief Returns a unique identifier for the current instance
* @returns {qint32} @returns {qint32}
*/ */
quint32 instanceId() const; quint32 instanceId();
/** /**
* @brief Returns the process ID (PID) of the primary instance @brief Returns the process ID (PID) of the primary instance
* @returns {qint64} @returns {qint64}
*/ */
qint64 primaryPid() const; qint64 primaryPid();
/** /**
* @brief Returns the username of the user running the primary instance @brief Sends a message to the primary instance. Returns true on success.
* @returns {QString} @param {int} timeout - Timeout for connecting
*/ @returns {bool}
QString primaryUser() const; @note sendMessage() will return false if invoked from the primary
instance.
/** */
* @brief Returns the username of the current user bool sendMessage( QByteArray message, int timeout = 100 );
* @returns {QString}
*/ Q_SIGNALS:
QString currentUser() const; void instanceStarted();
void receivedMessage( quint32 instanceId, QByteArray message );
/**
* @brief Sends a message to the primary instance. Returns true on success. private:
* @param {int} timeout - Timeout for connecting SingleApplicationPrivate *d_ptr;
* @returns {bool} Q_DECLARE_PRIVATE(SingleApplication)
* @note sendMessage() will return false if invoked from the primary
* instance.
*/
bool sendMessage( const QByteArray &message, int timeout = 100 );
/**
* @brief Get the set user data.
* @returns {QStringList}
*/
QStringList userData() const;
Q_SIGNALS:
void instanceStarted();
void receivedMessage( quint32 instanceId, QByteArray message );
private:
SingleApplicationPrivate *d_ptr;
Q_DECLARE_PRIVATE(SingleApplication)
void abortSafely();
}; };
Q_DECLARE_OPERATORS_FOR_FLAGS(SingleApplication::Options) Q_DECLARE_OPERATORS_FOR_FLAGS(SingleApplication::Options)
+2 -3
View File
@@ -1,8 +1,7 @@
QT += core network QT += core network
CONFIG += c++11 CONFIG += c++17
HEADERS += $$PWD/SingleApplication \ HEADERS += $$PWD/singleapplication.h \
$$PWD/singleapplication.h \
$$PWD/singleapplication_p.h $$PWD/singleapplication_p.h
SOURCES += $$PWD/singleapplication.cpp \ SOURCES += $$PWD/singleapplication.cpp \
$$PWD/singleapplication_p.cpp $$PWD/singleapplication_p.cpp
+285 -327
View File
@@ -1,6 +1,6 @@
// The MIT License (MIT) // The MIT License (MIT)
// //
// Copyright (c) Itay Grudev 2015 - 2020 // Copyright (c) Itay Grudev 2015 - 2018
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -33,454 +33,412 @@
#include <cstddef> #include <cstddef>
#include <QtCore/QDir> #include <QtCore/QDir>
#include <QtCore/QThread>
#include <QtCore/QByteArray> #include <QtCore/QByteArray>
#include <QtCore/QDataStream> #include <QtCore/QDataStream>
#include <QtCore/QElapsedTimer>
#include <QtCore/QCryptographicHash> #include <QtCore/QCryptographicHash>
#include <QtNetwork/QLocalServer> #include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket> #include <QtNetwork/QLocalSocket>
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
#include <QtCore/QRandomGenerator>
#else
#include <QtCore/QDateTime>
#endif
#include "singleapplication.h" #include "singleapplication.h"
#include "singleapplication_p.h" #include "singleapplication_p.h"
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <pwd.h> #include <pwd.h>
#endif #endif
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#ifndef NOMINMAX #include <windows.h>
#define NOMINMAX 1 #include <lmcons.h>
#endif
#include <windows.h>
#include <lmcons.h>
#endif #endif
SingleApplicationPrivate::SingleApplicationPrivate( SingleApplication *q_ptr ) SingleApplicationPrivate::SingleApplicationPrivate( SingleApplication *q_ptr )
: q_ptr( q_ptr ) : q_ptr( q_ptr )
{ {
server = nullptr; server = nullptr;
socket = nullptr; socket = nullptr;
memory = nullptr; memory = nullptr;
instanceNumber = 0; instanceNumber = -1;
} }
SingleApplicationPrivate::~SingleApplicationPrivate() SingleApplicationPrivate::~SingleApplicationPrivate()
{ {
if( socket != nullptr ){ if( socket != nullptr ) {
socket->close(); socket->close();
delete socket; delete socket;
} }
if( memory != nullptr ){ memory->lock();
memory->lock(); InstancesInfo* inst = static_cast<InstancesInfo*>(memory->data());
auto *inst = static_cast<InstancesInfo*>(memory->data()); if( server != nullptr ) {
if( server != nullptr ){ server->close();
server->close(); delete server;
delete server; inst->primary = false;
inst->primary = false; inst->primaryPid = -1;
inst->primaryPid = -1; inst->checksum = blockChecksum();
inst->primaryUser[0] = '\0'; }
inst->checksum = blockChecksum(); memory->unlock();
}
memory->unlock();
delete memory; delete memory;
}
}
QString SingleApplicationPrivate::getUsername()
{
#ifdef Q_OS_WIN
wchar_t username[UNLEN + 1];
// Specifies size of the buffer on input
DWORD usernameLength = UNLEN + 1;
if( GetUserNameW( username, &usernameLength ) )
return QString::fromWCharArray( username );
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
return QString::fromLocal8Bit( qgetenv( "USERNAME" ) );
#else
return qEnvironmentVariable( "USERNAME" );
#endif
#endif
#ifdef Q_OS_UNIX
QString username;
uid_t uid = geteuid();
struct passwd *pw = getpwuid( uid );
if( pw )
username = QString::fromLocal8Bit( pw->pw_name );
if ( username.isEmpty() ){
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
username = QString::fromLocal8Bit( qgetenv( "USER" ) );
#else
username = qEnvironmentVariable( "USER" );
#endif
}
return username;
#endif
} }
void SingleApplicationPrivate::genBlockServerName() void SingleApplicationPrivate::genBlockServerName()
{ {
QCryptographicHash appData( QCryptographicHash::Sha256 ); QCryptographicHash appData( QCryptographicHash::Sha256 );
appData.addData( "SingleApplication", 17 ); appData.addData( "SingleApplication", 17 );
appData.addData( SingleApplication::app_t::applicationName().toUtf8() ); appData.addData( SingleApplication::app_t::applicationName().toUtf8() );
appData.addData( SingleApplication::app_t::organizationName().toUtf8() ); appData.addData( SingleApplication::app_t::organizationName().toUtf8() );
appData.addData( SingleApplication::app_t::organizationDomain().toUtf8() ); appData.addData( SingleApplication::app_t::organizationDomain().toUtf8() );
if ( ! appDataList.isEmpty() ) if( ! (options & SingleApplication::Mode::ExcludeAppVersion) ) {
appData.addData( appDataList.join( "" ).toUtf8() ); appData.addData( SingleApplication::app_t::applicationVersion().toUtf8() );
}
if( ! (options & SingleApplication::Mode::ExcludeAppVersion) ){ if( ! (options & SingleApplication::Mode::ExcludeAppPath) ) {
appData.addData( SingleApplication::app_t::applicationVersion().toUtf8() );
}
if( ! (options & SingleApplication::Mode::ExcludeAppPath) ){
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
appData.addData( SingleApplication::app_t::applicationFilePath().toLower().toUtf8() ); appData.addData( SingleApplication::app_t::applicationFilePath().toLower().toUtf8() );
#else #else
appData.addData( SingleApplication::app_t::applicationFilePath().toUtf8() ); appData.addData( SingleApplication::app_t::applicationFilePath().toUtf8() );
#endif #endif
} }
// User level block requires a user specific data in the hash // User level block requires a user specific data in the hash
if( options & SingleApplication::Mode::User ){ if( options & SingleApplication::Mode::User ) {
appData.addData( getUsername().toUtf8() ); #ifdef Q_OS_WIN
} wchar_t username [ UNLEN + 1 ];
// Specifies size of the buffer on input
DWORD usernameLength = UNLEN + 1;
if( GetUserNameW( username, &usernameLength ) ) {
appData.addData( QString::fromWCharArray(username).toUtf8() );
} else {
appData.addData( qgetenv("USERNAME") );
}
#endif
#ifdef Q_OS_UNIX
QByteArray username;
uid_t uid = geteuid();
struct passwd *pw = getpwuid(uid);
if( pw ) {
username = pw->pw_name;
}
if( username.isEmpty() ) {
username = qgetenv("USER");
}
appData.addData(username);
#endif
}
// Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with // Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with
// server naming requirements. // server naming requirements.
blockServerName = appData.result().toBase64().replace("/", "_"); blockServerName = appData.result().toBase64().replace("/", "_");
} }
void SingleApplicationPrivate::initializeMemoryBlock() const void SingleApplicationPrivate::initializeMemoryBlock()
{ {
auto *inst = static_cast<InstancesInfo*>( memory->data() ); InstancesInfo* inst = static_cast<InstancesInfo*>( memory->data() );
inst->primary = false; inst->primary = false;
inst->secondary = 0; inst->secondary = 0;
inst->primaryPid = -1; inst->primaryPid = -1;
inst->primaryUser[0] = '\0'; inst->checksum = blockChecksum();
inst->checksum = blockChecksum();
} }
void SingleApplicationPrivate::startPrimary() void SingleApplicationPrivate::startPrimary()
{ {
// Reset the number of connections Q_Q(SingleApplication);
auto *inst = static_cast <InstancesInfo*>( memory->data() );
inst->primary = true; // Successful creation means that no main process exists
inst->primaryPid = QCoreApplication::applicationPid(); // So we start a QLocalServer to listen for connections
qstrncpy( inst->primaryUser, getUsername().toUtf8().data(), sizeof(inst->primaryUser) ); QLocalServer::removeServer( blockServerName );
inst->checksum = blockChecksum(); server = new QLocalServer();
instanceNumber = 0;
// Successful creation means that no main process exists
// So we start a QLocalServer to listen for connections
QLocalServer::removeServer( blockServerName );
server = new QLocalServer();
// Restrict access to the socket according to the // Restrict access to the socket according to the
// SingleApplication::Mode::User flag on User level or no restrictions // SingleApplication::Mode::User flag on User level or no restrictions
if( options & SingleApplication::Mode::User ){ if( options & SingleApplication::Mode::User ) {
server->setSocketOptions( QLocalServer::UserAccessOption ); server->setSocketOptions( QLocalServer::UserAccessOption );
} else { } else {
server->setSocketOptions( QLocalServer::WorldAccessOption ); server->setSocketOptions( QLocalServer::WorldAccessOption );
} }
server->listen( blockServerName ); server->listen( blockServerName );
QObject::connect( QObject::connect(
server, server,
&QLocalServer::newConnection, &QLocalServer::newConnection,
this, this,
&SingleApplicationPrivate::slotConnectionEstablished &SingleApplicationPrivate::slotConnectionEstablished
); );
// Reset the number of connections
InstancesInfo* inst = static_cast <InstancesInfo*>( memory->data() );
inst->primary = true;
inst->primaryPid = q->applicationPid();
inst->checksum = blockChecksum();
instanceNumber = 0;
} }
void SingleApplicationPrivate::startSecondary() void SingleApplicationPrivate::startSecondary()
{ {
auto *inst = static_cast <InstancesInfo*>( memory->data() );
inst->secondary += 1;
inst->checksum = blockChecksum();
instanceNumber = inst->secondary;
} }
bool SingleApplicationPrivate::connectToPrimary( int msecs, ConnectionType connectionType ) void SingleApplicationPrivate::connectToPrimary( int msecs, ConnectionType connectionType )
{ {
QElapsedTimer time; // Connect to the Local Server of the Primary Instance if not already
time.start(); // connected.
if( socket == nullptr ) {
socket = new QLocalSocket();
}
// Connect to the Local Server of the Primary Instance if not already // If already connected - we are done;
// connected. if( socket->state() == QLocalSocket::ConnectedState )
if( socket == nullptr ){ return;
socket = new QLocalSocket();
}
if( socket->state() == QLocalSocket::ConnectedState ) return true; // If not connect
if( socket->state() == QLocalSocket::UnconnectedState ||
socket->state() == QLocalSocket::ClosingState ) {
socket->connectToServer( blockServerName );
}
if( socket->state() != QLocalSocket::ConnectedState ){ // Wait for being connected
if( socket->state() == QLocalSocket::ConnectingState ) {
socket->waitForConnected( msecs );
}
while( true ){ // Initialisation message according to the SingleApplication protocol
randomSleep(); if( socket->state() == QLocalSocket::ConnectedState ) {
// Notify the parent that a new instance had been started;
if( socket->state() != QLocalSocket::ConnectingState ) QByteArray initMsg;
socket->connectToServer( blockServerName ); QDataStream writeStream(&initMsg, QIODevice::WriteOnly);
if( socket->state() == QLocalSocket::ConnectingState ){
socket->waitForConnected( static_cast<int>(msecs - time.elapsed()) );
}
// If connected break out of the loop
if( socket->state() == QLocalSocket::ConnectedState ) break;
// If elapsed time since start is longer than the method timeout return
if( time.elapsed() >= msecs ) return false;
}
}
// Initialisation message according to the SingleApplication protocol
QByteArray initMsg;
QDataStream writeStream(&initMsg, QIODevice::WriteOnly);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
writeStream.setVersion(QDataStream::Qt_5_6); writeStream.setVersion(QDataStream::Qt_5_6);
#endif #endif
writeStream << blockServerName.toLatin1(); writeStream << blockServerName.toLatin1();
writeStream << static_cast<quint8>(connectionType); writeStream << static_cast<quint8>(connectionType);
writeStream << instanceNumber; writeStream << instanceNumber;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
quint16 checksum = qChecksum(QByteArray(initMsg, static_cast<quint32>(initMsg.length()))); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove
quint16 checksum =
qChecksum(
initMsg.constData(),
static_cast<quint32>(initMsg.length()));
#else #else
quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length())); #if TODO_LIST
#pragma message("@TODO remove code for QT 6 or later")
#endif #endif
writeStream << checksum; quint16 checksum =
qChecksum(
QByteArrayView(
initMsg.constData(),
static_cast<quint32>(initMsg.length())));
#endif
writeStream << checksum;
// The header indicates the message length that follows // The header indicates the message length that follows
QByteArray header; QByteArray header;
QDataStream headerStream(&header, QIODevice::WriteOnly); QDataStream headerStream(&header, QIODevice::WriteOnly);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
headerStream.setVersion(QDataStream::Qt_5_6); headerStream.setVersion(QDataStream::Qt_5_6);
#endif #endif
headerStream << static_cast <quint64>( initMsg.length() ); headerStream << static_cast <quint64>( initMsg.length() );
socket->write( header ); socket->write( header );
socket->write( initMsg ); socket->write( initMsg );
bool result = socket->waitForBytesWritten( static_cast<int>(msecs - time.elapsed()) ); socket->flush();
socket->flush(); socket->waitForBytesWritten( msecs );
return result; }
} }
quint16 SingleApplicationPrivate::blockChecksum() const quint16 SingleApplicationPrivate::blockChecksum()
{ {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove
quint16 checksum = qChecksum(QByteArray(static_cast<const char*>(memory->constData()), offsetof(InstancesInfo, checksum))); return qChecksum(
static_cast <const char *>( memory->data() ),
offsetof( InstancesInfo, checksum )
);
#else #else
quint16 checksum = qChecksum(static_cast<const char*>(memory->constData()), offsetof(InstancesInfo, checksum)); #if TODO_LIST
#pragma message("@TODO remove code for QT 6 or later")
#endif
return qChecksum(
QByteArrayView(
static_cast <const char *>( memory->data() ),
offsetof( InstancesInfo, checksum )));
#endif #endif
return checksum;
} }
qint64 SingleApplicationPrivate::primaryPid() const qint64 SingleApplicationPrivate::primaryPid()
{ {
qint64 pid; qint64 pid;
memory->lock(); memory->lock();
auto *inst = static_cast<InstancesInfo*>( memory->data() ); InstancesInfo* inst = static_cast<InstancesInfo*>( memory->data() );
pid = inst->primaryPid; pid = inst->primaryPid;
memory->unlock(); memory->unlock();
return pid; return pid;
}
QString SingleApplicationPrivate::primaryUser() const
{
QByteArray username;
memory->lock();
auto *inst = static_cast<InstancesInfo*>( memory->data() );
username = inst->primaryUser;
memory->unlock();
return QString::fromUtf8( username );
} }
/** /**
* @brief Executed when a connection has been made to the LocalServer @brief Executed when a connection has been made to the LocalServer
*/ */
void SingleApplicationPrivate::slotConnectionEstablished() void SingleApplicationPrivate::slotConnectionEstablished()
{ {
QLocalSocket *nextConnSocket = server->nextPendingConnection(); QLocalSocket *nextConnSocket = server->nextPendingConnection();
connectionMap.insert(nextConnSocket, ConnectionInfo()); connectionMap.insert(nextConnSocket, ConnectionInfo());
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose,
[nextConnSocket, this](){ [nextConnSocket, this]() {
auto &info = connectionMap[nextConnSocket]; auto &info = connectionMap[nextConnSocket];
Q_EMIT this->slotClientConnectionClosed( nextConnSocket, info.instanceId ); Q_EMIT this->slotClientConnectionClosed( nextConnSocket, info.instanceId );
} }
); );
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, nextConnSocket, &QLocalSocket::deleteLater); QObject::connect(nextConnSocket, &QLocalSocket::disconnected,
[nextConnSocket, this](){
connectionMap.remove(nextConnSocket);
nextConnSocket->deleteLater();
}
);
QObject::connect(nextConnSocket, &QLocalSocket::destroyed, QObject::connect(nextConnSocket, &QLocalSocket::readyRead,
[nextConnSocket, this](){ [nextConnSocket, this]() {
connectionMap.remove(nextConnSocket); auto &info = connectionMap[nextConnSocket];
} switch(info.stage) {
); case StageHeader:
readInitMessageHeader(nextConnSocket);
QObject::connect(nextConnSocket, &QLocalSocket::readyRead, break;
[nextConnSocket, this](){ case StageBody:
auto &info = connectionMap[nextConnSocket]; readInitMessageBody(nextConnSocket);
switch(info.stage){ break;
case StageHeader: case StageConnected:
readInitMessageHeader(nextConnSocket); Q_EMIT this->slotDataAvailable( nextConnSocket, info.instanceId );
break; break;
case StageBody: default:
readInitMessageBody(nextConnSocket); break;
break; };
case StageConnected: }
Q_EMIT this->slotDataAvailable( nextConnSocket, info.instanceId ); );
break;
default:
break;
};
}
);
} }
void SingleApplicationPrivate::readInitMessageHeader( QLocalSocket *sock ) void SingleApplicationPrivate::readInitMessageHeader( QLocalSocket *sock )
{ {
if (!connectionMap.contains( sock )){ if (!connectionMap.contains( sock )) {
return; return;
} }
if( sock->bytesAvailable() < ( qint64 )sizeof( quint64 ) ){ if( sock->bytesAvailable() < ( qint64 )sizeof( quint64 ) ) {
return; return;
} }
QDataStream headerStream( sock ); QDataStream headerStream( sock );
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
headerStream.setVersion( QDataStream::Qt_5_6 ); headerStream.setVersion( QDataStream::Qt_5_6 );
#endif #endif
// Read the header to know the message length // Read the header to know the message length
quint64 msgLen = 0; quint64 msgLen = 0;
headerStream >> msgLen; headerStream >> msgLen;
ConnectionInfo &info = connectionMap[sock]; ConnectionInfo &info = connectionMap[sock];
info.stage = StageBody; info.stage = StageBody;
info.msgLen = msgLen; info.msgLen = msgLen;
if ( sock->bytesAvailable() >= (qint64) msgLen ){ if ( sock->bytesAvailable() >= (qint64) msgLen ) {
readInitMessageBody( sock ); readInitMessageBody( sock );
} }
} }
void SingleApplicationPrivate::readInitMessageBody( QLocalSocket *sock ) void SingleApplicationPrivate::readInitMessageBody( QLocalSocket *sock )
{ {
Q_Q(SingleApplication); Q_Q(SingleApplication);
if (!connectionMap.contains( sock )){ if (!connectionMap.contains( sock )) {
return; return;
} }
ConnectionInfo &info = connectionMap[sock]; ConnectionInfo &info = connectionMap[sock];
if( sock->bytesAvailable() < ( qint64 )info.msgLen ){ if( sock->bytesAvailable() < ( qint64 )info.msgLen ) {
return; return;
} }
// Read the message body // Read the message body
QByteArray msgBytes = sock->read(info.msgLen); QByteArray msgBytes = sock->read(info.msgLen);
QDataStream readStream(msgBytes); QDataStream readStream(msgBytes);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
readStream.setVersion( QDataStream::Qt_5_6 ); readStream.setVersion( QDataStream::Qt_5_6 );
#endif #endif
// server name // server name
QByteArray latin1Name; QByteArray latin1Name;
readStream >> latin1Name; readStream >> latin1Name;
// connection type // connection type
ConnectionType connectionType = InvalidConnection; ConnectionType connectionType = InvalidConnection;
quint8 connTypeVal = InvalidConnection; quint8 connTypeVal = InvalidConnection;
readStream >> connTypeVal; readStream >> connTypeVal;
connectionType = static_cast <ConnectionType>( connTypeVal ); connectionType = static_cast <ConnectionType>( connTypeVal );
// instance id // instance id
quint32 instanceId = 0; quint32 instanceId = 0;
readStream >> instanceId; readStream >> instanceId;
// checksum // checksum
quint16 msgChecksum = 0; quint16 msgChecksum = 0;
readStream >> msgChecksum; readStream >> msgChecksum;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove
const quint16 actualChecksum = qChecksum(QByteArray(msgBytes, static_cast<quint32>(msgBytes.length() - sizeof(quint16)))); const quint16 actualChecksum =
qChecksum(
msgBytes.constData(),
static_cast<quint32>( msgBytes.length() - sizeof( quint16 ) ) );
#else #else
const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast<quint32>(msgBytes.length() - sizeof(quint16))); #if TODO_LIST
#pragma message("@TODO remove code for QT 6 or later")
#endif #endif
const quint16 actualChecksum =
qChecksum(
QByteArrayView(
msgBytes.constData(),
static_cast<quint32>(msgBytes.length() - sizeof(quint16))));
#endif
bool isValid = readStream.status() == QDataStream::Ok &&
QLatin1String(latin1Name) == blockServerName &&
msgChecksum == actualChecksum;
bool isValid = readStream.status() == QDataStream::Ok && if( !isValid ) {
QLatin1String(latin1Name) == blockServerName && sock->close();
msgChecksum == actualChecksum; return;
}
if( !isValid ){ info.instanceId = instanceId;
sock->close(); info.stage = StageConnected;
return;
}
info.instanceId = instanceId; if( connectionType == NewInstance ||
info.stage = StageConnected; ( connectionType == SecondaryInstance &&
options & SingleApplication::Mode::SecondaryNotification ) )
{
Q_EMIT q->instanceStarted();
}
if( connectionType == NewInstance || if (sock->bytesAvailable() > 0) {
( connectionType == SecondaryInstance && Q_EMIT this->slotDataAvailable( sock, instanceId );
options & SingleApplication::Mode::SecondaryNotification ) ) }
{
Q_EMIT q->instanceStarted();
}
if (sock->bytesAvailable() > 0){
Q_EMIT this->slotDataAvailable( sock, instanceId );
}
} }
void SingleApplicationPrivate::slotDataAvailable( QLocalSocket *dataSocket, quint32 instanceId ) void SingleApplicationPrivate::slotDataAvailable( QLocalSocket *dataSocket, quint32 instanceId )
{ {
Q_Q(SingleApplication); Q_Q(SingleApplication);
Q_EMIT q->receivedMessage( instanceId, dataSocket->readAll() ); Q_EMIT q->receivedMessage( instanceId, dataSocket->readAll() );
} }
void SingleApplicationPrivate::slotClientConnectionClosed( QLocalSocket *closedSocket, quint32 instanceId ) void SingleApplicationPrivate::slotClientConnectionClosed( QLocalSocket *closedSocket, quint32 instanceId )
{ {
if( closedSocket->bytesAvailable() > 0 ) if( closedSocket->bytesAvailable() > 0 )
Q_EMIT slotDataAvailable( closedSocket, instanceId ); Q_EMIT slotDataAvailable( closedSocket, instanceId );
}
void SingleApplicationPrivate::randomSleep()
{
#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
QThread::msleep( QRandomGenerator::global()->bounded( 8u, 18u ));
#else
qsrand( QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max() );
QThread::msleep( 8 + static_cast <unsigned long>( static_cast <float>( qrand() ) / RAND_MAX * 10 ));
#endif
}
void SingleApplicationPrivate::addAppData(const QString &data)
{
appDataList.push_back(data);
}
QStringList SingleApplicationPrivate::appData() const
{
return appDataList;
} }
+51 -56
View File
@@ -1,6 +1,6 @@
// The MIT License (MIT) // The MIT License (MIT)
// //
// Copyright (c) Itay Grudev 2015 - 2020 // Copyright (c) Itay Grudev 2015 - 2016
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -38,67 +38,62 @@
#include "singleapplication.h" #include "singleapplication.h"
struct InstancesInfo { struct InstancesInfo {
bool primary; bool primary;
quint32 secondary; quint32 secondary;
qint64 primaryPid; qint64 primaryPid;
char primaryUser[128]; quint16 checksum;
quint16 checksum; // Must be the last field
}; };
struct ConnectionInfo { struct ConnectionInfo {
qint64 msgLen = 0; explicit ConnectionInfo() :
quint32 instanceId = 0; msgLen(0), instanceId(0), stage(0) {}
quint8 stage = 0; qint64 msgLen;
quint32 instanceId;
quint8 stage;
}; };
class SingleApplicationPrivate : public QObject { class SingleApplicationPrivate : public QObject {
Q_OBJECT Q_OBJECT
public: public:
enum ConnectionType : quint8 { enum ConnectionType : quint8 {
InvalidConnection = 0, InvalidConnection = 0,
NewInstance = 1, NewInstance = 1,
SecondaryInstance = 2, SecondaryInstance = 2,
Reconnect = 3 Reconnect = 3
}; };
enum ConnectionStage : quint8 { enum ConnectionStage : quint8 {
StageHeader = 0, StageHeader = 0,
StageBody = 1, StageBody = 1,
StageConnected = 2, StageConnected = 2,
}; };
Q_DECLARE_PUBLIC(SingleApplication) Q_DECLARE_PUBLIC(SingleApplication)
SingleApplicationPrivate( SingleApplication *q_ptr ); SingleApplicationPrivate( SingleApplication *q_ptr );
~SingleApplicationPrivate() override; ~SingleApplicationPrivate();
static QString getUsername(); void genBlockServerName();
void genBlockServerName(); void initializeMemoryBlock();
void initializeMemoryBlock() const; void startPrimary();
void startPrimary(); void startSecondary();
void startSecondary(); void connectToPrimary(int msecs, ConnectionType connectionType );
bool connectToPrimary( int msecs, ConnectionType connectionType ); quint16 blockChecksum();
quint16 blockChecksum() const; qint64 primaryPid();
qint64 primaryPid() const; void readInitMessageHeader(QLocalSocket *socket);
QString primaryUser() const; void readInitMessageBody(QLocalSocket *socket);
void readInitMessageHeader(QLocalSocket *socket);
void readInitMessageBody(QLocalSocket *socket); SingleApplication *q_ptr;
static void randomSleep(); QSharedMemory *memory;
void addAppData(const QString &data); QLocalSocket *socket;
QStringList appData() const; QLocalServer *server;
quint32 instanceNumber;
SingleApplication *q_ptr; QString blockServerName;
QSharedMemory *memory; SingleApplication::Options options;
QLocalSocket *socket; QMap<QLocalSocket*, ConnectionInfo> connectionMap;
QLocalServer *server;
quint32 instanceNumber; public Q_SLOTS:
QString blockServerName; void slotConnectionEstablished();
SingleApplication::Options options; void slotDataAvailable( QLocalSocket*, quint32 );
QMap<QLocalSocket*, ConnectionInfo> connectionMap; void slotClientConnectionClosed( QLocalSocket*, quint32 );
QStringList appDataList;
public Q_SLOTS:
void slotConnectionEstablished();
void slotDataAvailable( QLocalSocket*, quint32 );
void slotClientConnectionClosed( QLocalSocket*, quint32 );
}; };
#endif // SINGLEAPPLICATION_P_H #endif // SINGLEAPPLICATION_P_H
@@ -1,7 +1,7 @@
{ {
"id": "org.qelectrotech.QElectroTech", "id": "org.qelectrotech.QElectroTech",
"runtime": "org.kde.Platform", "runtime": "org.kde.Platform",
"runtime-version": "5.15", "runtime-version": "5.14",
"sdk": "org.kde.Sdk", "sdk": "org.kde.Sdk",
"command": "qelectrotech", "command": "qelectrotech",
"rename-desktop-file": "qelectrotech.desktop", "rename-desktop-file": "qelectrotech.desktop",
@@ -1,15 +1,5 @@
#!/bin/sh #!/bin/sh
# a KDE session forces the KDE Plasma platformtheme which is incompatible with QET
# unset the ENV vars in that case to prevent loading of the theme
if [ ! -z "$KDE_FULL_SESSION" ]; then
unset KDE_FULL_SESSION
fi
if echo "$XDG_CURRENT_DESKTOP" | grep -q KDE; then
unset XDG_CURRENT_DESKTOP
fi
# migrate .qet directory from SNAP_USER_DATA to SNAP_USER_COMMON # migrate .qet directory from SNAP_USER_DATA to SNAP_USER_COMMON
from="$SNAP_USER_DATA/.qet" from="$SNAP_USER_DATA/.qet"
to="$SNAP_USER_COMMON/.qet" to="$SNAP_USER_COMMON/.qet"
@@ -23,12 +13,4 @@ fi
mkdir -p "$HOME/.qet" mkdir -p "$HOME/.qet"
ln -snf "$SNAP/bin/DXFtoQET" "$HOME/.qet/DXFtoQET" ln -snf "$SNAP/bin/DXFtoQET" "$HOME/.qet/DXFtoQET"
# start desktop portal. Open & save dialogs might fail if it is not running
dbus-send --print-reply \
--dest=org.freedesktop.DBus \
/org/freedesktop/DBus \
org.freedesktop.DBus.StartServiceByName \
string:org.freedesktop.portal.Desktop \
uint32:0
exec "${@}" exec "${@}"
+24 -29
View File
@@ -1,7 +1,7 @@
name: qelectrotech name: qelectrotech
title: QElectroTech title: QElectroTech
base: core18 base: core20
adopt-info: qelectrotech version: "0.8.0"
license: GPL-2.0 license: GPL-2.0
summary: Electrical diagram editor summary: Electrical diagram editor
description: | description: |
@@ -10,10 +10,7 @@ description: |
grade: stable grade: stable
confinement: strict confinement: strict
compression: lzo
architectures:
- build-on: amd64
run-on: amd64
layout: layout:
/usr/local/share/qelectrotech: /usr/local/share/qelectrotech:
@@ -30,15 +27,14 @@ apps:
extensions: [kde-neon] extensions: [kde-neon]
plugs: &plugs [opengl, unity7, home, removable-media, gsettings, network, cups-control] plugs: &plugs [opengl, unity7, home, removable-media, gsettings, network, cups-control]
environment: &env environment: &env
__EGL_VENDOR_LIBRARY_DIRS: $SNAP/kf5/usr/share/glvnd/egl_vendor.d:$SNAP/usr/share/glvnd/egl_vendor.d
TCL_LIBRARY: $SNAP/usr/share/tcltk/tcl8.6 TCL_LIBRARY: $SNAP/usr/share/tcltk/tcl8.6
QT_QPA_PLATFORMTHEME: gtk3
QT_AUTO_SCREEN_SCALE_FACTOR: 1
HOME: $SNAP_USER_COMMON HOME: $SNAP_USER_COMMON
PYTHONPATH: $SNAP:$SNAP/lib/python3.6/site-packages:$SNAP/usr/lib/python3.6:$SNAP/usr/lib/python3.6/lib-dynload PYTHONPATH: $SNAP:$SNAP/lib/python3.8/site-packages:$SNAP/usr/lib/python3.8:$SNAP/usr/lib/python3.8/lib-dynload
qet-tb-generator: qet-tb-generator:
command: bin/qelectrotech-launch $SNAP/bin/qet_tb_generator command: bin/qet_tb_generator
command-chain:
- bin/qelectrotech-launch
extensions: [kde-neon] extensions: [kde-neon]
plugs: *plugs plugs: *plugs
environment: *env environment: *env
@@ -58,8 +54,8 @@ parts:
qet-tb-generator: qet-tb-generator:
plugin: python plugin: python
python-version: python3 source: https://github.com/raulroda/qet_tb_generator-plugin.git
source: https://github.com/qelectrotech/qet_tb_generator.git python-packages: [PySimpleGUI]
stage-packages: stage-packages:
- python3-lxml - python3-lxml
- python3-tk - python3-tk
@@ -68,15 +64,15 @@ parts:
kde-sdk-setup: kde-sdk-setup:
plugin: nil plugin: nil
build-snaps: build-snaps:
- kde-frameworks-5-core18-sdk - kde-frameworks-5-qt-5-15-3-core20-sdk
build-packages: build-packages:
- g++ - g++
- mesa-common-dev - mesa-common-dev
- libglvnd-dev - libglvnd-dev
- rsync - rsync
override-build: | override-build: |
rsync -a --ignore-existing /snap/kde-frameworks-5-core18-sdk/current/ / rsync -a --ignore-existing /snap/kde-frameworks-5-qt-5-15-3-core20-sdk/current/ /
dxf-to-qet: dxf-to-qet:
after: [kde-sdk-setup] after: [kde-sdk-setup]
plugin: nil plugin: nil
@@ -91,19 +87,15 @@ parts:
after: [kde-sdk-setup] after: [kde-sdk-setup]
plugin: nil plugin: nil
source: . source: .
stage-packages: [ git, sqlite3 ] stage-packages: [ git, sqlite3, xdg-user-dirs ]
build-packages: build-packages:
- git - git
- libsqlite3-dev - libsqlite3-dev
override-pull: |
snapcraftctl pull
snap_version=$(git describe --dirty)
modified_displayed_version=$snap_version".snap"
sed -i -E "s|const QString displayedVersion =.*|const QString displayedVersion =\"$modified_displayed_version\";|" sources/qet.h
snapcraftctl set-version "$snap_version"
override-build: | override-build: |
modified_displayed_version="${SNAPCRAFT_PROJECT_VERSION}.snap"
sed -i -E "s|const QString displayedVersion =.*|const QString displayedVersion =\"$modified_displayed_version\";|" sources/qet.h
qmake "$SNAPCRAFT_PART_SRC/qelectrotech.pro" qmake "$SNAPCRAFT_PART_SRC/qelectrotech.pro"
make -j$(nproc) make -j${SNAPCRAFT_PARALLEL_BUILD_COUNT}
make install INSTALL_ROOT="$SNAPCRAFT_PART_INSTALL" make install INSTALL_ROOT="$SNAPCRAFT_PART_INSTALL"
override-stage: | override-stage: |
snapcraftctl stage snapcraftctl stage
@@ -114,11 +106,14 @@ parts:
cleanup: cleanup:
after: [qelectrotech, dxf-to-qet, qet-tb-generator] after: [qelectrotech, dxf-to-qet, qet-tb-generator]
plugin: nil plugin: nil
build-snaps: [core18, kde-frameworks-5-core18] build-snaps: [kde-frameworks-5-qt-5-15-3-core20]
override-prime: | override-prime: |
# Remove all files from snap that are already included in the base snap or in
# any connected content snaps
set -eux set -eux
for snap in "core18" "kde-frameworks-5-core18"; do # List all content-snaps and base snaps you're using here for snap in "kde-frameworks-5-qt-5-15-3-core20"; do # List all content-snaps you're using here
cd "/snap/$snap/current" && find . -type f,l -exec rm -f "$SNAPCRAFT_PRIME/{}" \; cd "/snap/$snap/current" && find . -type f,l -exec rm -f "$SNAPCRAFT_PRIME/{}" "$SNAPCRAFT_PRIME/usr/{}" \;
done done
for cruft in bug lintian man; do
rm -rf $SNAPCRAFT_PRIME/usr/share/$cruft
done
find $SNAPCRAFT_PRIME/usr/share/doc/ -type f -not -name 'copyright' -delete
find $SNAPCRAFT_PRIME/usr/share -type d -empty -delete
+1 -1
View File
@@ -21,6 +21,6 @@ Include(FetchContent)
FetchContent_Declare( FetchContent_Declare(
pugixml pugixml
GIT_REPOSITORY https://github.com/zeux/pugixml.git GIT_REPOSITORY https://github.com/zeux/pugixml.git
GIT_TAG v1.11.4) GIT_TAG v1.11.1)
FetchContent_MakeAvailable(pugixml) FetchContent_MakeAvailable(pugixml)
+1 -1
View File
@@ -26,6 +26,6 @@ Include(FetchContent)
FetchContent_Declare( FetchContent_Declare(
SingleApplication SingleApplication
GIT_REPOSITORY https://github.com/itay-grudev/SingleApplication.git GIT_REPOSITORY https://github.com/itay-grudev/SingleApplication.git
GIT_TAG v3.2.0) GIT_TAG v3.1.5)
FetchContent_MakeAvailable(SingleApplication) FetchContent_MakeAvailable(SingleApplication)
+4 -8
View File
@@ -52,8 +52,6 @@ set(QET_RES_FILES
${QET_DIR}/sources/editor/ui/lineeditor.ui ${QET_DIR}/sources/editor/ui/lineeditor.ui
${QET_DIR}/sources/editor/ui/polygoneditor.ui ${QET_DIR}/sources/editor/ui/polygoneditor.ui
${QET_DIR}/sources/editor/ui/rectangleeditor.ui ${QET_DIR}/sources/editor/ui/rectangleeditor.ui
${QET_DIR}/sources/editor/ui/qetelementeditor.ui
${QET_DIR}/sources/editor/ui/terminaleditor.ui
${QET_DIR}/sources/ElementsCollection/ui/renamedialog.ui ${QET_DIR}/sources/ElementsCollection/ui/renamedialog.ui
${QET_DIR}/sources/factory/ui/addtabledialog.ui ${QET_DIR}/sources/factory/ui/addtabledialog.ui
${QET_DIR}/sources/NameList/ui/namelistdialog.ui ${QET_DIR}/sources/NameList/ui/namelistdialog.ui
@@ -262,8 +260,12 @@ set(QET_SRC_FILES
${QET_DIR}/sources/editor/elementscene.h ${QET_DIR}/sources/editor/elementscene.h
${QET_DIR}/sources/editor/elementview.cpp ${QET_DIR}/sources/editor/elementview.cpp
${QET_DIR}/sources/editor/elementview.h ${QET_DIR}/sources/editor/elementview.h
${QET_DIR}/sources/editor/qetelementeditor.cpp
${QET_DIR}/sources/editor/qetelementeditor.h
${QET_DIR}/sources/editor/styleeditor.cpp ${QET_DIR}/sources/editor/styleeditor.cpp
${QET_DIR}/sources/editor/styleeditor.h ${QET_DIR}/sources/editor/styleeditor.h
${QET_DIR}/sources/editor/terminaleditor.cpp
${QET_DIR}/sources/editor/terminaleditor.h
${QET_DIR}/sources/editor/esevent/eseventaddarc.cpp ${QET_DIR}/sources/editor/esevent/eseventaddarc.cpp
${QET_DIR}/sources/editor/esevent/eseventaddarc.h ${QET_DIR}/sources/editor/esevent/eseventaddarc.h
@@ -318,12 +320,8 @@ set(QET_SRC_FILES
${QET_DIR}/sources/editor/ui/polygoneditor.h ${QET_DIR}/sources/editor/ui/polygoneditor.h
${QET_DIR}/sources/editor/ui/rectangleeditor.cpp ${QET_DIR}/sources/editor/ui/rectangleeditor.cpp
${QET_DIR}/sources/editor/ui/rectangleeditor.h ${QET_DIR}/sources/editor/ui/rectangleeditor.h
${QET_DIR}/sources/editor/ui/terminaleditor.cpp
${QET_DIR}/sources/editor/ui/terminaleditor.h
${QET_DIR}/sources/editor/ui/texteditor.cpp ${QET_DIR}/sources/editor/ui/texteditor.cpp
${QET_DIR}/sources/editor/ui/texteditor.h ${QET_DIR}/sources/editor/ui/texteditor.h
${QET_DIR}/sources/editor/ui/qetelementeditor.h
${QET_DIR}/sources/editor/ui/qetelementeditor.cpp
${QET_DIR}/sources/editor/UndoCommand/pastepartscommand.cpp ${QET_DIR}/sources/editor/UndoCommand/pastepartscommand.cpp
${QET_DIR}/sources/editor/UndoCommand/pastepartscommand.h ${QET_DIR}/sources/editor/UndoCommand/pastepartscommand.h
@@ -373,8 +371,6 @@ set(QET_SRC_FILES
${QET_DIR}/sources/print/projectprintwindow.cpp ${QET_DIR}/sources/print/projectprintwindow.cpp
${QET_DIR}/sources/print/projectprintwindow.h ${QET_DIR}/sources/print/projectprintwindow.h
${QET_DIR}/sources/properties/elementdata.cpp
${QET_DIR}/sources/properties/elementdata.h
${QET_DIR}/sources/properties/propertiesinterface.cpp ${QET_DIR}/sources/properties/propertiesinterface.cpp
${QET_DIR}/sources/properties/propertiesinterface.h ${QET_DIR}/sources/properties/propertiesinterface.h
${QET_DIR}/sources/properties/reportproperties.cpp ${QET_DIR}/sources/properties/reportproperties.cpp
@@ -1,4 +1,4 @@
<definition hotspot_y="52" version="0.51" hotspot_x="56" link_type="master" width="70" type="element" height="100"> <definition hotspot_y="52" version="0.51" hotspot_x="56" link_type="simple" width="70" type="element" height="100">
<uuid uuid="{2d6c186b-0578-4682-90c9-f77843432e9f}"/> <uuid uuid="{2d6c186b-0578-4682-90c9-f77843432e9f}"/>
<names> <names>
<name lang="cs">Motorový spouštěč 1P+N</name> <name lang="cs">Motorový spouštěč 1P+N</name>
@@ -12,9 +12,6 @@
<name lang="ar">قاطع مغناطيسي-حراري GV</name> <name lang="ar">قاطع مغناطيسي-حراري GV</name>
<name lang="hu">Motorvédő kapcsoló 1 pólusú GV</name> <name lang="hu">Motorvédő kapcsoló 1 pólusú GV</name>
</names> </names>
<kindInformations>
<kindInformation name="type" show="1">protection</kindInformation>
</kindInformations>
<informations></informations> <informations></informations>
<description> <description>
<polygon x1="0" y1="14" x5="0" y4="4" y5="4" x6="0" y7="-25" x2="0" y6="-6" y2="10" y3="10" x7="-7" antialias="true" x3="5" closed="false" x4="5" style="line-style:normal;line-weight:normal;filling:none;color:black"/> <polygon x1="0" y1="14" x5="0" y4="4" y5="4" x6="0" y7="-25" x2="0" y6="-6" y2="10" y3="10" x7="-7" antialias="true" x3="5" closed="false" x4="5" style="line-style:normal;line-weight:normal;filling:none;color:black"/>
@@ -1,4 +1,4 @@
<definition hotspot_y="52" width="70" version="0.51" type="element" height="100" hotspot_x="56" link_type="master"> <definition hotspot_y="52" width="70" version="0.51" type="element" height="100" hotspot_x="56" link_type="simple">
<uuid uuid="{ec5fa3cd-6769-4a35-aaa9-6bc5ba4fc779}"/> <uuid uuid="{ec5fa3cd-6769-4a35-aaa9-6bc5ba4fc779}"/>
<names> <names>
<name lang="fr">Disjoncteur Magnéto-thermique GV 2P</name> <name lang="fr">Disjoncteur Magnéto-thermique GV 2P</name>
@@ -8,9 +8,6 @@
<name lang="cs">Motorový spouštěč 2P</name> <name lang="cs">Motorový spouštěč 2P</name>
<name lang="hu">Motorvédő kapcsoló 2 pólusú GV</name> <name lang="hu">Motorvédő kapcsoló 2 pólusú GV</name>
</names> </names>
<kindInformations>
<kindInformation name="type" show="1">protection</kindInformation>
</kindInformations>
<informations></informations> <informations></informations>
<description> <description>
<polygon y2="10" x3="-15" y4="4" x2="-20" y3="10" x5="-20" style="line-style:normal;line-weight:normal;filling:none;color:black" x1="-20" x4="-15" closed="false" y1="14" y6="-6" x7="-27" y5="4" antialias="true" y7="-25" x6="-20"/> <polygon y2="10" x3="-15" y4="4" x2="-20" y3="10" x5="-20" style="line-style:normal;line-weight:normal;filling:none;color:black" x1="-20" x4="-15" closed="false" y1="14" y6="-6" x7="-27" y5="4" antialias="true" y7="-25" x6="-20"/>
@@ -1,4 +1,4 @@
<definition hotspot_y="52" version="0.51" hotspot_x="56" link_type="master" width="110" type="element" height="100"> <definition hotspot_y="52" version="0.51" hotspot_x="56" link_type="simple" width="110" type="element" height="100">
<uuid uuid="{2424a938-847f-447f-a4ad-d9b6ef730fd9}"/> <uuid uuid="{2424a938-847f-447f-a4ad-d9b6ef730fd9}"/>
<names> <names>
<name lang="de">Motorschutzschalter</name> <name lang="de">Motorschutzschalter</name>
@@ -12,9 +12,6 @@
<name lang="ar">قاطع مغناطيسي-حراري GV</name> <name lang="ar">قاطع مغناطيسي-حراري GV</name>
<name lang="hu">Motorvédő kapcsoló 3F + N pólusú</name> <name lang="hu">Motorvédő kapcsoló 3F + N pólusú</name>
</names> </names>
<kindInformations>
<kindInformation name="type" show="1">protection</kindInformation>
</kindInformations>
<informations></informations> <informations></informations>
<description> <description>
<line end1="none" x1="40" y1="39" x2="40" length1="1.5" y2="28" antialias="false" end2="none" length2="1.5" style="line-style:normal;line-weight:normal;filling:none;color:black"/> <line end1="none" x1="40" y1="39" x2="40" length1="1.5" y2="28" antialias="false" end2="none" length2="1.5" style="line-style:normal;line-weight:normal;filling:none;color:black"/>
@@ -1,4 +1,4 @@
<definition hotspot_y="50" width="110" version="0.51" type="element" height="100" hotspot_x="56" link_type="master"> <definition hotspot_y="50" width="110" version="0.51" type="element" height="100" hotspot_x="56" link_type="simple">
<uuid uuid="{686e19c6-6bce-4ced-8c01-2d7f58a78386}"/> <uuid uuid="{686e19c6-6bce-4ced-8c01-2d7f58a78386}"/>
<names> <names>
<name lang="el">Θερμομαγνητικό</name> <name lang="el">Θερμομαγνητικό</name>
@@ -12,9 +12,6 @@
<name lang="de">Motorschutzschalter</name> <name lang="de">Motorschutzschalter</name>
<name lang="hu">Motorvédő kapcsoló 4 pólusú GV</name> <name lang="hu">Motorvédő kapcsoló 4 pólusú GV</name>
</names> </names>
<kindInformations>
<kindInformation name="type" show="1">protection</kindInformation>
</kindInformations>
<informations></informations> <informations></informations>
<description> <description>
<line y2="28" end1="none" length2="1.5" x2="40" style="line-style:normal;line-weight:normal;filling:none;color:black" x1="40" length1="1.5" y1="39" end2="none" antialias="false"/> <line y2="28" end1="none" length2="1.5" x2="40" style="line-style:normal;line-weight:normal;filling:none;color:black" x1="40" length1="1.5" y1="39" end2="none" antialias="false"/>
@@ -1,4 +1,4 @@
<definition type="element" link_type="master" hotspot_x="31" hotspot_y="4" version="0.5" width="90" height="70"> <definition type="element" link_type="simple" hotspot_x="31" hotspot_y="4" version="0.5" width="90" height="70">
<uuid uuid="{98ADF831-42F0-4EDE-9267-6733EEBEAF62}"/><names> <uuid uuid="{98ADF831-42F0-4EDE-9267-6733EEBEAF62}"/><names>
<name lang="en">Motor circuit breaker</name> <name lang="en">Motor circuit breaker</name>
<name lang="es">Disyuntor termico magnetico 3P mando manual con auto retorno y boton de desenclave</name> <name lang="es">Disyuntor termico magnetico 3P mando manual con auto retorno y boton de desenclave</name>
@@ -10,9 +10,6 @@
<name lang="pl">Wyłącznik silnikowy</name> <name lang="pl">Wyłącznik silnikowy</name>
<name lang="hu">Motorvédő kapcsoló 3 pólusú</name> <name lang="hu">Motorvédő kapcsoló 3 pólusú</name>
</names> </names>
<kindInformations>
<kindInformation name="type" show="1">protection</kindInformation>
</kindInformations>
<informations>Author: The QElectroTech team <informations>Author: The QElectroTech team
License: see http://qelectrotech.org/wiki/doc/elements_license</informations> License: see http://qelectrotech.org/wiki/doc/elements_license</informations>
<description> <description>
@@ -1,4 +1,4 @@
<definition type="element" link_type="master" hotspot_x="33" hotspot_y="5" version="0.5" width="110" height="70"> <definition type="element" link_type="simple" hotspot_x="33" hotspot_y="5" version="0.5" width="110" height="70">
<uuid uuid="{C33FE39E-B2EE-4EC0-BC3F-4EB76E9BCEA0}"/><names> <uuid uuid="{C33FE39E-B2EE-4EC0-BC3F-4EB76E9BCEA0}"/><names>
<name lang="en">Motor circuit breaker with neutral</name> <name lang="en">Motor circuit breaker with neutral</name>
<name lang="es">Disyuntor termico magnetico 3P+N mando manual con auto retorno y boton de desenclave</name> <name lang="es">Disyuntor termico magnetico 3P+N mando manual con auto retorno y boton de desenclave</name>
@@ -10,9 +10,6 @@
<name lang="pl">Wyłącznik silnikowy</name> <name lang="pl">Wyłącznik silnikowy</name>
<name lang="hu">Motorvédő kapcsoló 3F + N pólusú</name> <name lang="hu">Motorvédő kapcsoló 3F + N pólusú</name>
</names> </names>
<kindInformations>
<kindInformation name="type" show="1">protection</kindInformation>
</kindInformations>
<informations>Author: The QElectroTech team <informations>Author: The QElectroTech team
License: see http://qelectrotech.org/wiki/doc/elements_license</informations> License: see http://qelectrotech.org/wiki/doc/elements_license</informations>
<description> <description>
@@ -1,4 +1,4 @@
<definition hotspot_y="50" version="0.51" hotspot_x="56" link_type="master" width="70" type="element" height="110"> <definition hotspot_y="50" version="0.51" hotspot_x="56" link_type="simple" width="70" type="element" height="110">
<uuid uuid="{68830151-5901-40f6-b94d-dc68b85165a2}"/> <uuid uuid="{68830151-5901-40f6-b94d-dc68b85165a2}"/>
<names> <names>
<name lang="fr">Disjoncteur differentiel 1P+N</name> <name lang="fr">Disjoncteur differentiel 1P+N</name>
@@ -8,9 +8,6 @@
<name lang="cs">Jističochránič 2P</name> <name lang="cs">Jističochránič 2P</name>
<name lang="hu">Differenciál-védőkapcsoló 1P+N termikus és zárlatvédelemmel</name> <name lang="hu">Differenciál-védőkapcsoló 1P+N termikus és zárlatvédelemmel</name>
</names> </names>
<kindInformations>
<kindInformation name="type" show="1">protection</kindInformation>
</kindInformations>
<informations></informations> <informations></informations>
<description> <description>
<line end1="none" x1="-29.6203" y1="28" x2="10" length1="1.5" y2="28" antialias="false" end2="none" length2="1.5" style="line-style:normal;line-weight:normal;filling:none;color:black"/> <line end1="none" x1="-29.6203" y1="28" x2="10" length1="1.5" y2="28" antialias="false" end2="none" length2="1.5" style="line-style:normal;line-weight:normal;filling:none;color:black"/>
@@ -1,4 +1,4 @@
<definition hotspot_y="50" version="0.51" hotspot_x="56" link_type="master" width="110" type="element" height="110"> <definition hotspot_y="50" version="0.51" hotspot_x="56" link_type="simple" width="110" type="element" height="110">
<uuid uuid="{3fa48846-98c0-43e1-8a96-330d4dc11ceb}"/> <uuid uuid="{3fa48846-98c0-43e1-8a96-330d4dc11ceb}"/>
<names> <names>
<name lang="cs">Jističochránič 3P+N</name> <name lang="cs">Jističochránič 3P+N</name>
@@ -12,9 +12,6 @@
<name lang="ar">قاطع مغناطيسي-حراري GV</name> <name lang="ar">قاطع مغناطيسي-حراري GV</name>
<name lang="hu">Differenciál-védőkapcsoló 3P+N termikus és zárlatvédelemmel</name> <name lang="hu">Differenciál-védőkapcsoló 3P+N termikus és zárlatvédelemmel</name>
</names> </names>
<kindInformations>
<kindInformation name="type" show="1">protection</kindInformation>
</kindInformations>
<informations></informations> <informations></informations>
<description> <description>
<line end1="none" x1="-29.6203" y1="28" x2="49.5887" length1="1.5" y2="28" antialias="false" end2="none" length2="1.5" style="line-style:normal;line-weight:normal;filling:none;color:black"/> <line end1="none" x1="-29.6203" y1="28" x2="49.5887" length1="1.5" y2="28" antialias="false" end2="none" length2="1.5" style="line-style:normal;line-weight:normal;filling:none;color:black"/>
@@ -1,4 +1,4 @@
<definition hotspot_y="50" version="0.51" hotspot_x="56" link_type="master" width="70" type="element" height="110"> <definition hotspot_y="50" version="0.51" hotspot_x="56" link_type="simple" width="70" type="element" height="110">
<uuid uuid="{20f65431-6f1f-4e09-9c73-68a1431c40a1}"/> <uuid uuid="{20f65431-6f1f-4e09-9c73-68a1431c40a1}"/>
<names> <names>
<name lang="fr">Disjoncteur differentiel 2P</name> <name lang="fr">Disjoncteur differentiel 2P</name>
@@ -8,9 +8,6 @@
<name lang="cs">Jističochránič 2P</name> <name lang="cs">Jističochránič 2P</name>
<name lang="hu">Differenciál-védőkapcsoló 2P termikus és zárlatvédelemmel</name> <name lang="hu">Differenciál-védőkapcsoló 2P termikus és zárlatvédelemmel</name>
</names> </names>
<kindInformations>
<kindInformation name="type" show="1">protection</kindInformation>
</kindInformations>
<informations></informations> <informations></informations>
<description> <description>
<polygon x1="-20" y1="14" x5="-20" y4="4" y5="4" x6="-20" y7="-25" x2="-20" y6="-6" y2="10" y3="10" x7="-27" antialias="true" x3="-15" closed="false" x4="-15" style="line-style:normal;line-weight:normal;filling:none;color:black"/> <polygon x1="-20" y1="14" x5="-20" y4="4" y5="4" x6="-20" y7="-25" x2="-20" y6="-6" y2="10" y3="10" x7="-27" antialias="true" x3="-15" closed="false" x4="-15" style="line-style:normal;line-weight:normal;filling:none;color:black"/>
@@ -1,4 +1,4 @@
<definition hotspot_y="50" version="0.51" hotspot_x="56" link_type="master" width="90" type="element" height="110"> <definition hotspot_y="50" version="0.51" hotspot_x="56" link_type="simple" width="90" type="element" height="110">
<uuid uuid="{1e746e43-1906-4ea0-99a6-261e3c862dba}"/> <uuid uuid="{1e746e43-1906-4ea0-99a6-261e3c862dba}"/>
<names> <names>
<name lang="cs">Jističochránič 3P</name> <name lang="cs">Jističochránič 3P</name>
@@ -12,9 +12,6 @@
<name lang="ar">قاطع مغناطيسي-حراري GV</name> <name lang="ar">قاطع مغناطيسي-حراري GV</name>
<name lang="hu">Differenciál-védőkapcsoló 3P termikus és zárlatvédelemmel</name> <name lang="hu">Differenciál-védőkapcsoló 3P termikus és zárlatvédelemmel</name>
</names> </names>
<kindInformations>
<kindInformation name="type" show="1">protection</kindInformation>
</kindInformations>
<informations></informations> <informations></informations>
<description> <description>
<text text="I>" size="9" y="25" x="-24"/> <text text="I>" size="9" y="25" x="-24"/>
@@ -1,4 +1,4 @@
<definition hotspot_y="50" version="0.51" hotspot_x="56" link_type="master" width="110" type="element" height="110"> <definition hotspot_y="50" version="0.51" hotspot_x="56" link_type="simple" width="110" type="element" height="110">
<uuid uuid="{fee3faef-5f4a-4a0b-bf0e-b6e93d9f9425}"/> <uuid uuid="{fee3faef-5f4a-4a0b-bf0e-b6e93d9f9425}"/>
<names> <names>
<name lang="de">Motorschutzschalter</name> <name lang="de">Motorschutzschalter</name>
@@ -12,9 +12,6 @@
<name lang="ar">قاطع مغناطيسي-حراري GV</name> <name lang="ar">قاطع مغناطيسي-حراري GV</name>
<name lang="hu">Differenciál-védőkapcsoló 4P termikus és zárlatvédelemmel</name> <name lang="hu">Differenciál-védőkapcsoló 4P termikus és zárlatvédelemmel</name>
</names> </names>
<kindInformations>
<kindInformation name="type" show="1">protection</kindInformation>
</kindInformations>
<informations></informations> <informations></informations>
<description> <description>
<polygon x1="-20" y1="14" x5="-20" y4="4" y5="4" x6="-20" y7="-25" x2="-20" y6="-6" y2="10" y3="10" x7="-27" antialias="true" x3="-15" closed="false" x4="-15" style="line-style:normal;line-weight:normal;filling:none;color:black"/> <polygon x1="-20" y1="14" x5="-20" y4="4" y5="4" x6="-20" y7="-25" x2="-20" y6="-6" y2="10" y3="10" x7="-27" antialias="true" x3="-15" closed="false" x4="-15" style="line-style:normal;line-weight:normal;filling:none;color:black"/>
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 309 KiB

After

Width:  |  Height:  |  Size: 112 KiB

+583 -712
View File
File diff suppressed because it is too large Load Diff
+591 -720
View File
File diff suppressed because it is too large Load Diff
+583 -712
View File
File diff suppressed because it is too large Load Diff
+592 -723
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+595 -723
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+874 -1006
View File
File diff suppressed because it is too large Load Diff
+590 -719
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+590 -721
View File
File diff suppressed because it is too large Load Diff
+585 -714
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+579 -708
View File
File diff suppressed because it is too large Load Diff
+582 -711
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+587 -718
View File
File diff suppressed because it is too large Load Diff
+594 -723
View File
File diff suppressed because it is too large Load Diff
+583 -712
View File
File diff suppressed because it is too large Load Diff
+579 -708
View File
File diff suppressed because it is too large Load Diff
+583 -712
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+591 -722
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+600 -732
View File
File diff suppressed because it is too large Load Diff
+588 -720
View File
File diff suppressed because it is too large Load Diff
+585 -714
View File
File diff suppressed because it is too large Load Diff
+583 -712
View File
File diff suppressed because it is too large Load Diff
+583 -712
View File
File diff suppressed because it is too large Load Diff
+579 -708
View File
File diff suppressed because it is too large Load Diff
+579 -708
View File
File diff suppressed because it is too large Load Diff
+579 -708
View File
File diff suppressed because it is too large Load Diff
+583 -712
View File
File diff suppressed because it is too large Load Diff
+579 -708
View File
File diff suppressed because it is too large Load Diff
@@ -17,7 +17,7 @@
*/ */
#include "elementscollectionwidget.h" #include "elementscollectionwidget.h"
#include "../editor/ui/qetelementeditor.h" #include "../editor/qetelementeditor.h"
#include "../elementscategoryeditor.h" #include "../elementscategoryeditor.h"
#include "../newelementwizard.h" #include "../newelementwizard.h"
#include "../qetapp.h" #include "../qetapp.h"
@@ -38,9 +38,6 @@
#include <QUrl> #include <QUrl>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QtGlobal> #include <QtGlobal>
#include <QProgressBar>
#include <QStatusBar>
#include <QLineEdit>
/** /**
@brief ElementsCollectionWidget::ElementsCollectionWidget @brief ElementsCollectionWidget::ElementsCollectionWidget
+8
View File
@@ -368,6 +368,14 @@ void ConductorProperties::fromXml(QDomElement &e)
"vertical-alignment", "vertical-alignment",
"AlignRight" "AlignRight"
).toStdString().data())); ).toStdString().data()));
//Keep retrocompatible with version older than 0,4
//If the propertie @type is simple (removed since QET 0,4), we set text no visible.
//@TODO remove this code for qet 0.6 or later
#if TODO_LIST
#pragma message("@TODO remove this code for qet 0.6 or later")
#endif
if (e.attribute("type") == "simple") m_show_text = false;
} }
/** /**
@@ -222,6 +222,11 @@ void DiagramEventAddElement::addElement()
element -> setPos(m_element->pos()); element -> setPos(m_element->pos());
element -> setRotation(m_element -> rotation()); element -> setRotation(m_element -> rotation());
m_diagram -> addItem(element); m_diagram -> addItem(element);
//The element is dropped by the user, the dynamic text field stored in m_converted_text_from_xml_description
//can be moved to m_dynamic_text_list, because we are sure fromXml will be not called.
element->m_dynamic_text_list.append(element->m_converted_text_from_xml_description.keys());
element->m_converted_text_from_xml_description.clear();
QUndoCommand *undo_object = new QUndoCommand(tr("Ajouter %1").arg(element->name())); QUndoCommand *undo_object = new QUndoCommand(tr("Ajouter %1").arg(element->name()));
new AddGraphicsObjectCommand(element, m_diagram, m_element -> pos(), undo_object); new AddGraphicsObjectCommand(element, m_diagram, m_element -> pos(), undo_object);
+1 -1
View File
@@ -501,7 +501,7 @@ void DiagramView::mousePressEvent(QMouseEvent *e)
*/ */
void DiagramView::mouseMoveEvent(QMouseEvent *e) void DiagramView::mouseMoveEvent(QMouseEvent *e)
{ {
setToolTip(tr("X: %1 Y: %2").arg(e->pos().x()).arg(e->pos().y())); setToolTip(tr("(Dev) X: %1 Y: %2").arg(e->pos().x()).arg(e->pos().y()));
if (m_event_interface && m_event_interface->mouseMoveEvent(e)) return; if (m_event_interface && m_event_interface->mouseMoveEvent(e)) return;
// Drag the view // Drag the view
+39 -34
View File
@@ -282,17 +282,13 @@ ChangeNamesCommand::~ChangeNamesCommand()
/// Annule le changement /// Annule le changement
void ChangeNamesCommand::undo() void ChangeNamesCommand::undo()
{ {
auto data = m_scene->elementData(); m_scene -> setNames(names_before);
data.m_names_list = names_before;
m_scene->setElementData(data);
} }
/// Refait le changement /// Refait le changement
void ChangeNamesCommand::redo() void ChangeNamesCommand::redo()
{ {
auto data = m_scene->elementData(); m_scene -> setNames(names_after);
data.m_names_list = names_after;
m_scene->setElementData(data);
} }
/** /**
@@ -457,17 +453,13 @@ ChangeInformationsCommand::~ChangeInformationsCommand()
/// Annule le changement d'autorisation pour les connexions internes /// Annule le changement d'autorisation pour les connexions internes
void ChangeInformationsCommand::undo() void ChangeInformationsCommand::undo()
{ {
auto data = m_scene->elementData(); m_scene -> setInformations(old_informations_);
data.m_drawing_information = old_informations_;
m_scene->setElementData(data);
} }
/// Refait le changement d'autorisation pour les connexions internes /// Refait le changement d'autorisation pour les connexions internes
void ChangeInformationsCommand::redo() void ChangeInformationsCommand::redo()
{ {
auto data = m_scene->elementData(); m_scene -> setInformations(new_informations_);
data.m_drawing_information = new_informations_;
m_scene->setElementData(data);
} }
/** /**
@@ -580,32 +572,45 @@ void ScalePartsCommand::adjustText()
setText(QObject::tr("redimensionnement de %1 primitives", "undo caption -- %1 always > 1").arg(scaled_primitives_.count())); setText(QObject::tr("redimensionnement de %1 primitives", "undo caption -- %1 always > 1").arg(scaled_primitives_.count()));
} }
} }
/** /**
* @brief changeElementDataCommand::changeElementDataCommand @brief ChangePropertiesCommand::ChangePropertiesCommand
* Change the properties of the drawed element Change the properties of the drawed element
* @param scene : scene to belong the property @param scene : scene to belong the property
* @param old_data : old data @param type : new type of element.
* @param new_data : new data @param info
* @param parent : parent undo command @param elmt_info : new info about type.
*/ @param parent : parent undo
changeElementDataCommand::changeElementDataCommand(ElementScene *scene, */
ElementData old_data, ChangePropertiesCommand::ChangePropertiesCommand(
ElementData new_data, ElementScene *scene,
QUndoCommand *parent) : const QString& type,
ElementEditionCommand(scene, nullptr, parent), const DiagramContext& info,
m_old(old_data), const DiagramContext& elmt_info,
m_new(new_data) QUndoCommand *parent) :
ElementEditionCommand(scene, nullptr, parent)
{ {
setText(QObject::tr("Modifier les propriétées de l'élément")); m_type << scene->m_elmt_type << type;
m_kind_info << scene->m_elmt_kindInfo << info;
m_elmt_info << scene->m_elmt_information << elmt_info;
setText(QObject::tr("Modifier les propriétés"));
} }
void changeElementDataCommand::undo() { ChangePropertiesCommand::~ChangePropertiesCommand()
m_scene->setElementData(m_old); {}
QUndoCommand::undo();
void ChangePropertiesCommand::undo()
{
m_scene->m_elmt_type = m_type.first();
m_scene->m_elmt_kindInfo = m_kind_info.first();
m_scene->setElementInfo(m_elmt_info.first());
} }
void changeElementDataCommand::redo() { void ChangePropertiesCommand::redo()
m_scene->setElementData(m_new); {
QUndoCommand::redo(); m_scene->m_elmt_type = m_type.last();
m_scene->m_elmt_kindInfo = m_kind_info.last();
m_scene->setElementInfo(m_elmt_info.last());
} }
+13 -11
View File
@@ -262,21 +262,23 @@ class ScalePartsCommand : public ElementEditionCommand {
bool first_redo; bool first_redo;
}; };
class changeElementDataCommand : public ElementEditionCommand class ChangePropertiesCommand : public ElementEditionCommand {
{
public: public:
changeElementDataCommand(ElementScene *scene, ChangePropertiesCommand (
ElementData old_data, ElementScene *scene,
ElementData new_data, const QString& type,
QUndoCommand *parent = nullptr); const DiagramContext& info,
~changeElementDataCommand() override {} const DiagramContext& elmt_info,
QUndoCommand *parent=nullptr);
~ChangePropertiesCommand () override;
void undo() override; void undo() override;
void redo() override; void redo() override;
private: private:
ElementData m_old, QList <QString> m_type;
m_new; QList <DiagramContext> m_kind_info;
QList < DiagramContext> m_elmt_info;
}; };
#endif #endif
+1 -1
View File
@@ -16,7 +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 "elementitemeditor.h" #include "elementitemeditor.h"
#include "ui/qetelementeditor.h" #include "qetelementeditor.h"
#include "editorcommands.h" #include "editorcommands.h"
/** /**
+105 -55
View File
@@ -33,7 +33,7 @@
#include "graphicspart/partrectangle.h" #include "graphicspart/partrectangle.h"
#include "graphicspart/partterminal.h" #include "graphicspart/partterminal.h"
#include "graphicspart/parttext.h" #include "graphicspart/parttext.h"
#include "ui/qetelementeditor.h" #include "qetelementeditor.h"
#include "ui/elementpropertieseditorwidget.h" #include "ui/elementpropertieseditorwidget.h"
#include <QKeyEvent> #include <QKeyEvent>
@@ -51,6 +51,7 @@
*/ */
ElementScene::ElementScene(QETElementEditor *editor, QObject *parent) : ElementScene::ElementScene(QETElementEditor *editor, QObject *parent) :
QGraphicsScene(parent), QGraphicsScene(parent),
m_elmt_type("simple"),
m_qgi_manager(this), m_qgi_manager(this),
m_element_editor(editor) m_element_editor(editor)
{ {
@@ -70,25 +71,7 @@ ElementScene::ElementScene(QETElementEditor *editor, QObject *parent) :
connect(&m_undo_stack, SIGNAL(indexChanged(int)), connect(&m_undo_stack, SIGNAL(indexChanged(int)),
this, SLOT(managePrimitivesGroups())); this, SLOT(managePrimitivesGroups()));
connect(this, SIGNAL(selectionChanged()), connect(this, SIGNAL(selectionChanged()),
this, SLOT(managePrimitivesGroups())); this, SLOT(managePrimitivesGroups()));
}
/**
* @brief ElementScene::elementData
* @return the elementdata using by the scene
*/
ElementData ElementScene::elementData() {
return m_element_data;
}
void ElementScene::setElementData(ElementData data)
{
bool emit_ = m_element_data.m_informations != data.m_informations;
m_element_data = data;
if (emit_)
emit elementInfoChanged();
} }
/** /**
@@ -454,7 +437,7 @@ const QDomDocument ElementScene::toXml(bool all_parts)
-(qRound(size.y() - (ymargin/2))))); -(qRound(size.y() - (ymargin/2)))));
root.setAttribute("version", QET::version); root.setAttribute("version", QET::version);
root.setAttribute("link_type", m_element_data.typeToString(m_element_data.m_type)); root.setAttribute("link_type", m_elmt_type);
//Uuid used to compare two elements //Uuid used to compare two elements
QDomElement uuid = xml_document.createElement("uuid"); QDomElement uuid = xml_document.createElement("uuid");
@@ -462,29 +445,29 @@ const QDomDocument ElementScene::toXml(bool all_parts)
root.appendChild(uuid); root.appendChild(uuid);
//names of element //names of element
root.appendChild(m_element_data.m_names_list.toXml(xml_document)); root.appendChild(m_names_list.toXml(xml_document));
auto type_ = m_element_data.m_type; if (m_elmt_type == "slave" || m_elmt_type == "master")
if (type_ == ElementData::Slave ||
type_ == ElementData::Master ||
type_ == ElementData::Terminale)
{ {
root.appendChild(m_element_data.kindInfoToXml(xml_document)); QDomElement kindInfo = xml_document.createElement("kindInformations");
m_elmt_kindInfo.toXml(kindInfo, "kindInformation");
root.appendChild(kindInfo);
} }
if(type_ == ElementData::Simple || if(
type_ == ElementData::Master || m_elmt_type == "simple"
type_ == ElementData::Terminale) || m_elmt_type == "master"
|| m_elmt_type == "terminal")
{ {
QDomElement element_info = xml_document.createElement("elementInformations"); QDomElement element_info = xml_document.createElement("elementInformations");
m_element_data.m_informations.toXml(element_info, "elementInformation"); m_elmt_information.toXml(element_info, "elementInformation");
root.appendChild(element_info); root.appendChild(element_info);
} }
//complementary information about the element //complementary information about the element
QDomElement informations_element = xml_document.createElement("informations"); QDomElement informations_element = xml_document.createElement("informations");
root.appendChild(informations_element); root.appendChild(informations_element);
informations_element.appendChild(xml_document.createTextNode(m_element_data.m_drawing_information)); informations_element.appendChild(xml_document.createTextNode(informations()));
QDomElement description = xml_document.createElement("description"); QDomElement description = xml_document.createElement("description");
@@ -562,16 +545,9 @@ void ElementScene::fromXml(
{ {
bool state = true; bool state = true;
//Consider the informations of the element //Consider the informations of the element
if (consider_informations) if (consider_informations) {
{ state = applyInformations(xml_document);
// Root must be an element definition
QDomElement root = xml_document.documentElement();
if (root.tagName() == "definition" &&
root.attribute("type") == "element") {
m_element_data.fromXml(root);
}
} }
if (state) if (state)
@@ -723,6 +699,19 @@ QETElementEditor* ElementScene::editor() const
return m_element_editor; return m_element_editor;
} }
/**
@brief ElementScene::setElementInfo
@param dc
*/
void ElementScene::setElementInfo(const DiagramContext& dc)
{
if(m_elmt_information != dc)
{
m_elmt_information = dc;
emit elementInfoChanged();
}
}
/** /**
@brief ElementScene::slot_select @brief ElementScene::slot_select
Select the item in content, Select the item in content,
@@ -844,7 +833,7 @@ void ElementScene::slot_editAuthorInformations()
// ajoute un QTextEdit au dialogue // ajoute un QTextEdit au dialogue
QTextEdit *text_field = new QTextEdit(); QTextEdit *text_field = new QTextEdit();
text_field -> setAcceptRichText(false); text_field -> setAcceptRichText(false);
text_field -> setPlainText(m_element_data.m_drawing_information); text_field -> setPlainText(informations());
text_field -> setReadOnly(is_read_only); text_field -> setReadOnly(is_read_only);
dialog_layout -> addWidget(text_field); dialog_layout -> addWidget(text_field);
@@ -862,10 +851,10 @@ void ElementScene::slot_editAuthorInformations()
if (dialog_author.exec() == QDialog::Accepted && !is_read_only) if (dialog_author.exec() == QDialog::Accepted && !is_read_only)
{ {
QString new_infos = text_field -> toPlainText().remove(QChar(13)); // CR-less text QString new_infos = text_field -> toPlainText().remove(QChar(13)); // CR-less text
if (new_infos != m_element_data.m_drawing_information) if (new_infos != informations())
{ {
undoStack().push(new ChangeInformationsCommand( undoStack().push(new ChangeInformationsCommand(
this, m_element_data.m_drawing_information, new_infos)); this, informations(), new_infos));
} }
} }
} }
@@ -876,15 +865,20 @@ void ElementScene::slot_editAuthorInformations()
*/ */
void ElementScene::slot_editProperties() void ElementScene::slot_editProperties()
{ {
ElementPropertiesEditorWidget epew(m_element_data); QString type = m_elmt_type;
DiagramContext kind_info = m_elmt_kindInfo;
DiagramContext elmt_info = m_elmt_information;
ElementPropertiesEditorWidget epew(type, kind_info, elmt_info);
epew.exec(); epew.exec();
if (m_element_data != epew.editedData()) if (type != m_elmt_type ||
{ kind_info != m_elmt_kindInfo ||
undoStack().push(new changeElementDataCommand(this, elmt_info != m_elmt_information)
m_element_data, undoStack().push(new ChangePropertiesCommand(this,
epew.editedData())); type,
} kind_info,
elmt_info));
} }
/** /**
@@ -904,15 +898,15 @@ void ElementScene::slot_editNames()
dialog_.setInformationText(tr("Vous pouvez spécifier le nom de l'élément dans plusieurs langues.")); dialog_.setInformationText(tr("Vous pouvez spécifier le nom de l'élément dans plusieurs langues."));
NameListWidget *nlw_ = dialog_.namelistWidget(); NameListWidget *nlw_ = dialog_.namelistWidget();
nlw_->setNames(m_element_data.m_names_list); nlw_->setNames(m_names_list);
nlw_->setReadOnly(is_read_only); nlw_->setReadOnly(is_read_only);
if (dialog_.exec() == QDialog::Accepted && !is_read_only && !nlw_->isEmpty()) if (dialog_.exec() == QDialog::Accepted && !is_read_only && !nlw_->isEmpty())
{ {
NamesList new_names = nlw_->names(); NamesList new_names = nlw_->names();
if (new_names != m_element_data. m_names_list) { if (new_names != m_names_list) {
undoStack().push(new ChangeNamesCommand(this, undoStack().push(new ChangeNamesCommand(this,
m_element_data.m_names_list, m_names_list,
new_names)); new_names));
} }
} }
@@ -1093,6 +1087,62 @@ QRectF ElementScene::elementContentBoundingRect(
return(bounding_rect); return(bounding_rect);
} }
/**
@brief ElementScene::applyInformations
Applies the information (dimensions, hostpot, orientations,
internal connections, names and additional information)
contained in an XML document.
\~French Applique les informations (dimensions, hostpot, orientations,
connexions internes, noms et informations complementaires)
contenu dans un document XML.
\~ @param xml_document : Document XML a analyser
\~ @return
true if reading and applying the information went well, false otherwise.
\~French true si la lecture et l'application
des informations s'est bien passee, false sinon.
*/
bool ElementScene::applyInformations(const QDomDocument &xml_document)
{
// Root must be an element definition
QDomElement root = xml_document.documentElement();
if (
root.tagName() != "definition"
||
root.attribute("type") != "element")
return(false);
//Extract info about element type
m_elmt_type = root.attribute("link_type", "simple");
m_elmt_kindInfo.fromXml(
root.firstChildElement("kindInformations"),
"kindInformation");
//Extract info of element
m_elmt_information.fromXml(
root.firstChildElement("elementInformations"),
"elementInformation");
//Extract names of xml definition
m_names_list.fromXml(root);
//extract additional informations
setInformations(QString());
for (QDomNode node = root.firstChild() ;
!node.isNull() ;
node = node.nextSibling())
{
QDomElement elmt = node.toElement();
if (elmt.isNull()) continue;
if (elmt.tagName() == "informations")
{
setInformations(elmt.text());
break;
}
}
return(true);
}
/** /**
@brief ElementScene::loadContent @brief ElementScene::loadContent
Create and load the content describe in the xml document. Create and load the content describe in the xml document.
+50 -8
View File
@@ -21,7 +21,6 @@
#include "../diagramcontext.h" #include "../diagramcontext.h"
#include "../qgimanager.h" #include "../qgimanager.h"
#include "elementcontent.h" #include "elementcontent.h"
#include "../properties/elementdata.h"
#include <QtWidgets> #include <QtWidgets>
#include <QtXml> #include <QtXml>
@@ -66,7 +65,11 @@ class ElementScene : public QGraphicsScene
// attributes // attributes
private: private:
ElementData m_element_data; ///ElementData. Actualy in transition with old data storage NamesList m_names_list; /// List of localized names
QString m_informations; /// Extra informations
QString m_elmt_type; /// element type
DiagramContext m_elmt_kindInfo,
m_elmt_information; /// element kind info
QGIManager m_qgi_manager; QGIManager m_qgi_manager;
QUndoStack m_undo_stack; QUndoStack m_undo_stack;
@@ -87,20 +90,21 @@ class ElementScene : public QGraphicsScene
// methods // methods
public: public:
ElementData elementData();
void setElementData(ElementData data);
void setEventInterface (ESEventInterface *event_interface); void setEventInterface (ESEventInterface *event_interface);
void clearEventInterface(); void clearEventInterface();
void setBehavior (ElementScene::Behavior); void setBehavior (ElementScene::Behavior);
ElementScene::Behavior behavior() const; ElementScene::Behavior behavior() const;
QPointF snapToGrid(QPointF point); QPointF snapToGrid(QPointF point);
void setNames(const NamesList &);
NamesList names() const;
QString informations() const;
void setInformations(const QString &);
QString elementType () const {return m_elmt_type;}
DiagramContext elementKindInfo () const {return m_elmt_kindInfo;}
DiagramContext elementInformation() const {return m_elmt_information;}
virtual int xGrid() const; virtual int xGrid() const;
virtual int yGrid() const; virtual int yGrid() const;
virtual void setGrid(int, int); virtual void setGrid(int, int);
virtual const QDomDocument toXml(bool = true); virtual const QDomDocument toXml(bool = true);
virtual QRectF boundingRectFromXml(const QDomDocument &); virtual QRectF boundingRectFromXml(const QDomDocument &);
virtual void fromXml(const QDomDocument &, virtual void fromXml(const QDomDocument &,
@@ -124,6 +128,7 @@ class ElementScene : public QGraphicsScene
void cut(); void cut();
void copy(); void copy();
QETElementEditor* editor() const; QETElementEditor* editor() const;
void setElementInfo(const DiagramContext& dc);
protected: protected:
void mouseMoveEvent (QGraphicsSceneMouseEvent *) override; void mouseMoveEvent (QGraphicsSceneMouseEvent *) override;
@@ -132,10 +137,12 @@ class ElementScene : public QGraphicsScene
void mouseDoubleClickEvent (QGraphicsSceneMouseEvent *event) override; void mouseDoubleClickEvent (QGraphicsSceneMouseEvent *event) override;
void keyPressEvent (QKeyEvent *event) override; void keyPressEvent (QKeyEvent *event) override;
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
void drawForeground(QPainter *, const QRectF &) override; void drawForeground(QPainter *, const QRectF &) override;
private: private:
QRectF elementContentBoundingRect(const ElementContent &) const; QRectF elementContentBoundingRect(const ElementContent &) const;
bool applyInformations(const QDomDocument &);
ElementContent loadContent(const QDomDocument &); ElementContent loadContent(const QDomDocument &);
ElementContent addContent(const ElementContent &); ElementContent addContent(const ElementContent &);
ElementContent addContentAtPos(const ElementContent &, const QPointF &); ElementContent addContentAtPos(const ElementContent &, const QPointF &);
@@ -173,4 +180,39 @@ class ElementScene : public QGraphicsScene
Q_DECLARE_OPERATORS_FOR_FLAGS(ElementScene::ItemOptions) Q_DECLARE_OPERATORS_FOR_FLAGS(ElementScene::ItemOptions)
/**
@brief ElementScene::setNames
@param nameslist New set of naes for the currently edited element
*/
inline void ElementScene::setNames(const NamesList &nameslist) {
m_names_list = nameslist;
}
/**
@brief ElementScene::names
@return the list of names of the currently edited element
*/
inline NamesList ElementScene::names() const
{
return(m_names_list);
}
/**
@brief ElementScene::informations
@return extra informations of the currently edited element
*/
inline QString ElementScene::informations() const
{
return(m_informations);
}
/**
@brief ElementScene::setInformations
@param infos new extra information for the currently edited element
*/
inline void ElementScene::setInformations(const QString &infos) {
m_informations = infos;
}
#endif #endif
+1 -1
View File
@@ -19,7 +19,7 @@
#include "../qetapp.h" #include "../qetapp.h"
#include "UndoCommand/pastepartscommand.h" #include "UndoCommand/pastepartscommand.h"
#include "ui/qetelementeditor.h" #include "qetelementeditor.h"
/** /**
Constructeur Constructeur
@param scene ElementScene visualisee par cette ElementView @param scene ElementScene visualisee par cette ElementView
+1 -1
View File
@@ -20,7 +20,7 @@
#include "../editorcommands.h" #include "../editorcommands.h"
#include "../elementscene.h" #include "../elementscene.h"
#include "../graphicspart/partline.h" #include "../graphicspart/partline.h"
#include "../ui/qetelementeditor.h" #include "../qetelementeditor.h"
#include <QGraphicsSceneMouseEvent> #include <QGraphicsSceneMouseEvent>
#include <QObject> #include <QObject>
+9 -10
View File
@@ -18,8 +18,7 @@
#include "eseventinterface.h" #include "eseventinterface.h"
#include "../elementscene.h" #include "../elementscene.h"
#include "../ui/qetelementeditor.h" #include "../qetelementeditor.h"
#include "../elementview.h"
#include <QGraphicsSceneMouseEvent> #include <QGraphicsSceneMouseEvent>
@@ -41,7 +40,7 @@ ESEventInterface::ESEventInterface(ElementScene *scene) :
void ESEventInterface::init() void ESEventInterface::init()
{ {
m_scene->setBehavior(ElementScene::Behavior::AddPart); m_scene->setBehavior(ElementScene::Behavior::AddPart);
m_editor->elementView()->setDragMode(QGraphicsView::NoDrag); m_editor->slot_setNoDragToView();
} }
/** /**
@@ -54,31 +53,31 @@ ESEventInterface::~ESEventInterface()
delete m_help_verti; delete m_help_verti;
m_scene->setBehavior(ElementScene::Behavior::Normal); m_scene->setBehavior(ElementScene::Behavior::Normal);
m_editor->elementView()->setDragMode(QGraphicsView::RubberBandDrag); m_editor->slot_setRubberBandToView();
} }
bool ESEventInterface::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { bool ESEventInterface::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {
Q_UNUSED (event) Q_UNUSED (event);
return false; return false;
} }
bool ESEventInterface::mousePressEvent(QGraphicsSceneMouseEvent *event) { bool ESEventInterface::mousePressEvent(QGraphicsSceneMouseEvent *event) {
Q_UNUSED (event) Q_UNUSED (event);
return false; return false;
} }
bool ESEventInterface::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { bool ESEventInterface::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
Q_UNUSED (event) Q_UNUSED (event);
return false; return false;
} }
bool ESEventInterface::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { bool ESEventInterface::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
Q_UNUSED (event) Q_UNUSED (event);
return false; return false;
} }
bool ESEventInterface::wheelEvent(QGraphicsSceneWheelEvent *event) { bool ESEventInterface::wheelEvent(QGraphicsSceneWheelEvent *event) {
Q_UNUSED (event) Q_UNUSED (event);
return false; return false;
} }
@@ -98,7 +97,7 @@ bool ESEventInterface::keyPressEvent(QKeyEvent *event) {
} }
bool ESEventInterface::KeyReleaseEvent(QKeyEvent *event) { bool ESEventInterface::KeyReleaseEvent(QKeyEvent *event) {
Q_UNUSED (event) Q_UNUSED (event);
return false; return false;
} }
@@ -1264,6 +1264,24 @@ void CustomElementGraphicPart::drawShadowShape(QPainter *painter)
painter -> restore (); painter -> restore ();
} }
/**
@brief CustomElementGraphicPart::itemChange
Reimplemented from QGraphicsObject.
If the item position change call updateCurrentPartEditor()
the change is always send to QGraphicsObject
@param change
@param value
@return the returned value of QGraphicsObject::itemChange
*/
QVariant CustomElementGraphicPart::itemChange(GraphicsItemChange change, const QVariant &value)
{
if (scene())
if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged)
updateCurrentPartEditor();
return(QGraphicsObject::itemChange(change, value));
}
/** /**
@brief CustomElementGraphicPart::hoverEnterEvent @brief CustomElementGraphicPart::hoverEnterEvent
Reimplemented from QGraphicsObject. Reimplemented from QGraphicsObject.
@@ -309,6 +309,8 @@ class CustomElementGraphicPart : public QGraphicsObject, public CustomElementPar
void applyStylesToQPainter(QPainter &) const; void applyStylesToQPainter(QPainter &) const;
void drawShadowShape (QPainter *painter); void drawShadowShape (QPainter *painter);
QVariant itemChange(GraphicsItemChange change,
const QVariant &value) override;
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override; void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
@@ -17,8 +17,7 @@
*/ */
#include "customelementpart.h" #include "customelementpart.h"
#include "../ui/qetelementeditor.h" #include "../qetelementeditor.h"
#include "../elementscene.h"
/// @return le QETElementEditor auquel cet editeur appartient /// @return le QETElementEditor auquel cet editeur appartient
QETElementEditor *CustomElementPart::elementEditor() const QETElementEditor *CustomElementPart::elementEditor() const
@@ -318,7 +318,7 @@ void PartDynamicTextField::setText(const QString &text) {
void PartDynamicTextField::setInfoName(const QString &info_name) { void PartDynamicTextField::setInfoName(const QString &info_name) {
m_info_name = info_name; m_info_name = info_name;
if(m_text_from == DynamicElementTextItem::ElementInfo && elementScene()) if(m_text_from == DynamicElementTextItem::ElementInfo && elementScene())
setPlainText(elementScene()->elementData().m_informations.value(m_info_name).toString()); setPlainText(elementScene() -> elementInformation().value(m_info_name).toString());
emit infoNameChanged(m_info_name); emit infoNameChanged(m_info_name);
} }
@@ -338,7 +338,7 @@ QString PartDynamicTextField::infoName() const{
void PartDynamicTextField::setCompositeText(const QString &text) { void PartDynamicTextField::setCompositeText(const QString &text) {
m_composite_text = text; m_composite_text = text;
if(m_text_from == DynamicElementTextItem::CompositeText && elementScene()) if(m_text_from == DynamicElementTextItem::CompositeText && elementScene())
setPlainText(autonum::AssignVariables::replaceVariable(m_composite_text, elementScene()->elementData().m_informations)); setPlainText(autonum::AssignVariables::replaceVariable(m_composite_text, elementScene() -> elementInformation()));
emit compositeTextChanged(m_composite_text); emit compositeTextChanged(m_composite_text);
} }
@@ -551,10 +551,10 @@ void PartDynamicTextField::elementInfoChanged()
return; return;
if(m_text_from == DynamicElementTextItem::ElementInfo) if(m_text_from == DynamicElementTextItem::ElementInfo)
setPlainText(elementScene()->elementData().m_informations.value(m_info_name).toString()); setPlainText(elementScene() -> elementInformation().value(m_info_name).toString());
else if (m_text_from == DynamicElementTextItem::CompositeText && elementScene()) else if (m_text_from == DynamicElementTextItem::CompositeText && elementScene())
setPlainText(autonum::AssignVariables::replaceVariable( setPlainText(autonum::AssignVariables::replaceVariable(
m_composite_text, elementScene()->elementData().m_informations)); m_composite_text, elementScene() -> elementInformation()));
} }
void PartDynamicTextField::prepareAlignment() void PartDynamicTextField::prepareAlignment()
+1 -1
View File
@@ -22,7 +22,7 @@
#include "../../QetGraphicsItemModeler/qetgraphicshandlerutility.h" #include "../../QetGraphicsItemModeler/qetgraphicshandlerutility.h"
#include "../../qeticons.h" #include "../../qeticons.h"
#include "../elementscene.h" #include "../elementscene.h"
#include "../ui/qetelementeditor.h" #include "../qetelementeditor.h"
/** /**
@brief PartPolygon::PartPolygon @brief PartPolygon::PartPolygon
+8 -22
View File
@@ -72,7 +72,7 @@ void PartTerminal::paint(
const QStyleOptionGraphicsItem *options, const QStyleOptionGraphicsItem *options,
QWidget *widget) QWidget *widget)
{ {
Q_UNUSED(widget) Q_UNUSED(widget);
painter -> save(); painter -> save();
// annulation des renderhints // annulation des renderhints
@@ -98,7 +98,7 @@ void PartTerminal::paint(
// dessin de la borne en rouge // dessin de la borne en rouge
t.setColor(isSelected() ? Terminal::neutralColor : Qt::red); t.setColor(isSelected() ? Terminal::neutralColor : Qt::red);
painter -> setPen(t); painter -> setPen(t);
painter -> drawLine(QPointF(0.0, 0.0), d -> m_second_point); painter -> drawLine(QPointF(0.0, 0.0), d -> second_point);
// dessin du point d'amarrage au conducteur en bleu // dessin du point d'amarrage au conducteur en bleu
t.setColor(isSelected() ? Qt::red : Terminal::neutralColor); t.setColor(isSelected() ? Qt::red : Terminal::neutralColor);
@@ -118,7 +118,7 @@ void PartTerminal::paint(
QPainterPath PartTerminal::shape() const QPainterPath PartTerminal::shape() const
{ {
QPainterPath shape; QPainterPath shape;
shape.lineTo(d -> m_second_point); shape.lineTo(d -> second_point);
QPainterPathStroker pps; QPainterPathStroker pps;
pps.setWidth(1); pps.setWidth(1);
@@ -132,7 +132,7 @@ QPainterPath PartTerminal::shape() const
*/ */
QRectF PartTerminal::boundingRect() const QRectF PartTerminal::boundingRect() const
{ {
QRectF br(QPointF(0, 0), d -> m_second_point); QRectF br(QPointF(0, 0), d -> second_point);
br = br.normalized(); br = br.normalized();
qreal adjust = (SHADOWS_HEIGHT + 1) / 2; qreal adjust = (SHADOWS_HEIGHT + 1) / 2;
@@ -161,20 +161,6 @@ void PartTerminal::setName(QString& name) {
emit nameChanged(); emit nameChanged();
} }
/**
* @brief PartTerminal::setTerminalType
* Set the type of terminal to 'type'
* @param type
*/
void PartTerminal::setTerminalType(TerminalData::Type type)
{
if (d->m_type == type) {
return;
}
d->m_type = type;
emit terminalTypeChanged();
}
void PartTerminal::setNewUuid() void PartTerminal::setNewUuid()
{ {
d -> m_uuid = QUuid::createUuid(); d -> m_uuid = QUuid::createUuid();
@@ -188,10 +174,10 @@ void PartTerminal::updateSecondPoint()
{ {
qreal ts = 4.0; // terminal size qreal ts = 4.0; // terminal size
switch(d -> m_orientation) { switch(d -> m_orientation) {
case Qet::North: d -> m_second_point = QPointF(0.0, ts); break; case Qet::North: d -> second_point = QPointF(0.0, ts); break;
case Qet::East : d -> m_second_point = QPointF(-ts, 0.0); break; case Qet::East : d -> second_point = QPointF(-ts, 0.0); break;
case Qet::South: d -> m_second_point = QPointF(0.0, -ts); break; case Qet::South: d -> second_point = QPointF(0.0, -ts); break;
case Qet::West : d -> m_second_point = QPointF(ts, 0.0); break; case Qet::West : d -> second_point = QPointF(ts, 0.0); break;
} }
} }
+2 -10
View File
@@ -27,13 +27,10 @@
This class represents a terminal which may be used to compose the drawing of This class represents a terminal which may be used to compose the drawing of
an electrical element within the element editor. an electrical element within the element editor.
*/ */
class PartTerminal : public CustomElementGraphicPart class PartTerminal : public CustomElementGraphicPart {
{
Q_OBJECT Q_OBJECT
Q_PROPERTY(Qet::Orientation orientation READ orientation WRITE setOrientation) Q_PROPERTY(Qet::Orientation orientation READ orientation WRITE setOrientation)
Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(TerminalData::Type terminal_type READ terminalType WRITE setTerminalType)
public: public:
// constructors, destructor // constructors, destructor
@@ -45,7 +42,6 @@ class PartTerminal : public CustomElementGraphicPart
signals: signals:
void orientationChanged(); void orientationChanged();
void nameChanged(); void nameChanged();
void terminalTypeChanged();
// methods // methods
public: public:
@@ -55,6 +51,7 @@ class PartTerminal : public CustomElementGraphicPart
@return the QGraphicsItem type @return the QGraphicsItem type
*/ */
int type() const override { return Type; } int type() const override { return Type; }
QString name() const override { return d -> m_name; }
QString xmlName() const override { return(QString("terminal")); } QString xmlName() const override { return(QString("terminal")); }
void fromXml(const QDomElement &) override; void fromXml(const QDomElement &) override;
const QDomElement toXml(QDomDocument &) const override; const QDomElement toXml(QDomDocument &) const override;
@@ -74,12 +71,7 @@ class PartTerminal : public CustomElementGraphicPart
Qet::Orientation orientation() const {return d -> m_orientation;} Qet::Orientation orientation() const {return d -> m_orientation;}
void setOrientation(Qet::Orientation ori); void setOrientation(Qet::Orientation ori);
QString name() const override { return d -> m_name; }
void setName(QString& name); void setName(QString& name);
TerminalData::Type terminalType() const {return d->m_type;}
void setTerminalType(TerminalData::Type type);
void setNewUuid(); void setNewUuid();
private: private:
File diff suppressed because it is too large Load Diff
+189
View File
@@ -0,0 +1,189 @@
/*
Copyright 2006-2021 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 CUSTOM_ELEMENT_EDITOR_H
#define CUSTOM_ELEMENT_EDITOR_H
#include "../ElementsCollection/elementslocation.h"
#include "../qet.h"
#include "../qetmainwindow.h"
#include "elementscene.h"
class ElementItemEditor;
class ElementView;
/**
This class represents an element editor, allowing users to draw, change and
configure a particular electrical element.
*/
class QETElementEditor : public QETMainWindow {
Q_OBJECT
// constructor, destructor
public:
QETElementEditor(QWidget * = nullptr);
~QETElementEditor() override;
private:
QETElementEditor(const QETElementEditor &);
void setupActions();
void setupMenus();
void setupInterface();
// attributes
private:
/// whether the editor is "read-only"
bool read_only;
/// menus
QMenu *file_menu, *edit_menu, *paste_from_menu, *display_menu, *tools_menu;
/// view widget for the editing scene
ElementView *m_view;
/// editing scene
ElementScene *m_elmt_scene;
/// container for widgets dedicated to primitive edition
QDockWidget *m_tools_dock;
/// Stack of widgets for tools_dock
QStackedWidget *m_tools_dock_stack;
/// label displayed when several primitives are selected
QLabel *m_default_informations;
/// Hash associating primitive names with their matching edition widget
QHash<QString, ElementItemEditor *> m_editors;
/// container for the undo list
QDockWidget *m_undo_dock;
/// Container for the list of existing primitives
QDockWidget *m_parts_dock;
/// List of primitives
QListWidget *m_parts_list;
/// actions for the "file" menu
QAction *new_element, *open, *open_dxf, *open_file, *save, *save_as, *save_as_file, *reload, *quit;
/// actions for the "edit" menu
QAction *selectall, *deselectall, *inv_select;
QAction *cut, *copy, *paste, *paste_in_area, *paste_from_file, *paste_from_elmt;
QAction *undo, *redo;
QAction *edit_delete, *edit_size_hs, *edit_names, *edit_author, *m_edit_properties;
/// toolbars
QToolBar *parts_toolbar, *main_toolbar, *view_toolbar, *depth_toolbar, *element_toolbar;
/// Action group
QActionGroup *parts, *m_zoom_ag, *m_depth_action_group;
/// minimum window title
QString min_title;
/// filename of the currently edited element
QString filename_;
/// location of the currently edited element
ElementsLocation location_;
/// whether the currently edited element comes from a file or a location
bool opened_from_file;
// methods
public:
void setNames(const NamesList &);
void setLocation(const ElementsLocation &);
ElementsLocation location() const;
void setFileName(const QString &);
QString fileName() const;
void setReadOnly(bool);
bool isReadOnly() const;
void fromFile(const QString &);
void fromLocation(const ElementsLocation &);
bool toFile(const QString &);
bool toLocation(const ElementsLocation &location);
bool isEditing(const ElementsLocation &);
bool isEditing(const QString &);
ElementScene *elementScene() const;
void readSettings();
void writeSettings();
static QPointF pasteOffset();
static QString getOpenElementFileName(QWidget * = nullptr, const QString & = QString());
void contextMenu(QPoint p, QList<QAction *> actions = QList<QAction*>());
signals:
void saveToLocation(ElementsLocation loc);
protected:
void closeEvent(QCloseEvent *) override;
void firstActivation(QEvent *) override;
private:
bool canClose();
QWidget *clearToolsDock();
void copyAndPasteXml(const QDomDocument &);
public slots:
void addLine();
void addRect();
void addEllipse();
void addPolygon();
void addArc();
void addText();
void addTerminal();
void addDynamicTextField();
void UncheckAddPrimitive();
void slot_new();
void slot_open();
void slot_openDxf();
void slot_openFile();
void openRecentFile(const QString &);
void openElement(const QString &);
void slot_reload();
bool slot_save();
bool slot_saveAs();
bool slot_saveAsFile();
void slot_setRubberBandToView();
void slot_setNoDragToView();
void slot_updateInformations();
void slot_updateMenus();
void slot_updateTitle();
void slot_createPartsList();
void slot_updatePartsList();
void slot_updateSelectionFromPartsList();
bool checkElement();
void pasteFromFile();
void pasteFromElement();
void updateCurrentPartEditor();
};
/**
@param nameslist the new list of names for the currently edited element
*/
inline void QETElementEditor::setNames(const NamesList &nameslist) {
m_elmt_scene -> setNames(nameslist);
}
/**
@return the location of the currently edited element
*/
inline ElementsLocation QETElementEditor::location() const
{
return(location_);
}
/**
@return the filename of the currently edited element
*/
inline QString QETElementEditor::fileName() const
{
return(filename_);
}
/**
@return the editing scene
*/
inline ElementScene *QETElementEditor::elementScene() const
{
return(m_elmt_scene);
}
#endif
+322
View File
@@ -0,0 +1,322 @@
/*
Copyright 2006-2021 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 "terminaleditor.h"
#include "../QPropertyUndoCommand/qpropertyundocommand.h"
#include "../editor/graphicspart/partterminal.h"
#include "../qeticons.h"
#include <QComboBox>
#include <QDoubleSpinBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QVBoxLayout>
/**
@brief TerminalEditor::TerminalEditor
@param editor
@param parent
*/
TerminalEditor::TerminalEditor(QETElementEditor* editor, QWidget* parent):
ElementItemEditor(editor, parent) {
m_part = nullptr;
m_terminals.clear();
init();
}
/**
@brief TerminalEditor::TerminalEditor
Constructeur
@param editor :
L'editeur d'element concerne
@param terms :
La borne a editer
@param parent :
QWidget parent de ce widget
*/
TerminalEditor::TerminalEditor(
QETElementEditor *editor,
QList<PartTerminal *> &terms,
QWidget *parent) :
ElementItemEditor(editor, parent),
m_terminals(terms),
m_part(terms.first()) {
init();
}
/**
@brief TerminalEditor::init
*/
void TerminalEditor::init()
{
qle_x = new QDoubleSpinBox();
qle_y = new QDoubleSpinBox();
name = new QLineEdit();
qle_x -> setRange(-5000, 5000);
qle_y -> setRange(-5000, 5000);
orientation = new QComboBox();
orientation -> addItem(QET::Icons::North, tr("Nord"), Qet::North);
orientation -> addItem(QET::Icons::East, tr("Est"), Qet::East);
orientation -> addItem(QET::Icons::South, tr("Sud"), Qet::South);
orientation -> addItem(QET::Icons::West, tr("Ouest"), Qet::West);
QVBoxLayout *main_layout = new QVBoxLayout();
main_layout -> addWidget(new QLabel(tr("Position : ")));
QHBoxLayout *position = new QHBoxLayout();
position -> addWidget(new QLabel(tr("x : ")));
position -> addWidget(qle_x );
position -> addWidget(new QLabel(tr("y : ")));
position -> addWidget(qle_y );
main_layout -> addLayout(position);
QHBoxLayout *ori = new QHBoxLayout();
ori -> addWidget(new QLabel(tr("Orientation : ")));
ori -> addWidget(orientation );
main_layout -> addLayout(ori);
QHBoxLayout *lay_name = new QHBoxLayout();
lay_name -> addWidget(new QLabel(tr("Name : ")));
lay_name -> addWidget(name);
main_layout -> addLayout(lay_name);
main_layout -> addStretch();
setLayout(main_layout);
activeConnections(true);
updateForm();
}
/**
@brief TerminalEditor::~TerminalEditor
Destructeur
*/
TerminalEditor::~TerminalEditor()
{
}
/**
Permet de specifier a cet editeur quelle primitive il doit editer. A noter
qu'un editeur peut accepter ou refuser d'editer une primitive.
L'editeur de borne acceptera d'editer la primitive new_part s'il s'agit d'un
objet de la classe PartTerminal.
@param new_part Nouvelle primitive a editer
@return true si l'editeur a accepter d'editer la primitive, false sinon
*/
bool TerminalEditor::setPart(CustomElementPart* new_part) {
m_terminals.clear();
if (!new_part) {
if (m_part) {
disconnect(m_part, &PartTerminal::orientationChanged, this, &TerminalEditor::updateForm);
}
m_part = nullptr;
return(true);
}
if (PartTerminal *part_terminal = static_cast<PartTerminal *>(new_part)) {
if(m_part == part_terminal) return true;
if (m_part) {
disconnect(m_part, &PartTerminal::orientationChanged, this, &TerminalEditor::updateForm);
}
m_part = part_terminal;
updateForm();
connect(m_part, &PartTerminal::orientationChanged, this, &TerminalEditor::updateForm);
return(true);
}
return(false);
}
bool TerminalEditor::setParts(QList<CustomElementPart *> parts) {
if (parts.isEmpty()) {
m_terminals.clear();
if (m_part) {
disconnect(m_part, &PartTerminal::orientationChanged, this, &TerminalEditor::updateForm);
}
m_part = nullptr;
return(true);
}
if (PartTerminal *part_terminal = static_cast<PartTerminal *>(parts.first())) {
if (m_part) {
disconnect(m_part, &PartTerminal::orientationChanged, this, &TerminalEditor::updateForm);
}
m_part = part_terminal;
m_terminals.clear();
m_terminals.append(part_terminal);
for (int i=1; i < parts.length(); i++) {
m_terminals.append(static_cast<PartTerminal*>(parts[i]));
}
updateForm();
connect(m_part, &PartTerminal::orientationChanged, this, &TerminalEditor::updateForm);
return(true);
}
return(false);
}
/**
@return la primitive actuellement editee, ou 0 si ce widget n'en edite pas
*/
CustomElementPart *TerminalEditor::currentPart() const
{
return(m_part);
}
QList<CustomElementPart*> TerminalEditor::currentParts() const
{
QList<CustomElementPart*> parts;
for (auto term: m_terminals) {
parts.append(static_cast<CustomElementPart*>(term));
}
return parts;
}
/// Met a jour l'orientation de la borne et cree un objet d'annulation
void TerminalEditor::updateTerminalO()
{
if (m_locked) return;
m_locked = true;
QVariant var(orientation -> itemData(orientation -> currentIndex()));
for (int i=0; i < m_terminals.length(); i++) {
PartTerminal* term = m_terminals[i];
if (var != term->property("orientation"))
{
QPropertyUndoCommand *undo = new QPropertyUndoCommand(term, "orientation", term->property("orientation"), var);
undo->setText(tr("Modifier l'orientation d'une borne"));
undoStack().push(undo);
}
}
m_locked = false;
}
/**
@brief TerminalEditor::updateXPos
*/
void TerminalEditor::updateXPos()
{
if (m_locked) return;
m_locked = true;
QPointF new_pos(qle_x->value(), 0);
for (int i=0; i < m_terminals.length(); i++) {
PartTerminal* term = m_terminals[i];
new_pos.setY(term->pos().y()); // change only x value
if (term->pos() != new_pos) {
QPropertyUndoCommand *undo = new QPropertyUndoCommand(term, "pos", term->property("pos"), new_pos);
undo->setText(tr("Déplacer une borne"));
undo->enableAnimation();
undoStack().push(undo);
}
}
m_locked=false;
}
/**
@brief TerminalEditor::updateYPos
*/
void TerminalEditor::updateYPos()
{
if (m_locked) return;
m_locked = true;
QPointF new_pos(0, qle_y->value()); // change only y value
for (int i=0; i < m_terminals.length(); i++) {
PartTerminal* term = m_terminals[i];
new_pos.setX(term->pos().x());
if (term->pos() != new_pos) {
QPropertyUndoCommand *undo = new QPropertyUndoCommand(term, "pos", term->property("pos"), new_pos);
undo->setText(tr("Déplacer une borne"));
undo->enableAnimation();
undoStack().push(undo);
}
}
m_locked=false;
}
/**
@brief TerminalEditor::updateName
SLOT set name to Terminal
*/
void TerminalEditor::updateName() {
if (m_locked) return;
m_locked = true;
QVariant var(name->text());
for (int i=0; i < m_terminals.length(); i++) {
PartTerminal* term = m_terminals[i];
if (var != term->property("name"))
{
QPropertyUndoCommand *undo;
undo = new QPropertyUndoCommand(term,
"name",
term->property("name"),
var);
undo->setText(tr("Modifier le nom du terminal"));
undoStack().push(undo);
}
}
m_locked=false;
}
/// update Number and name, create cancel object
/**
Met a jour le formulaire d'edition
*/
void TerminalEditor::updateForm()
{
if (!m_part) return;
activeConnections(false);
qle_x -> setValue(m_part->property("x").toReal());
qle_y -> setValue(m_part->property("y").toReal());
orientation -> setCurrentIndex(orientation->findData(m_part->property("orientation")));
name -> setText(m_part->name());
activeConnections(true);
}
/**
Active ou desactive les connexionx signaux/slots entre les widgets internes.
@param active true pour activer les connexions, false pour les desactiver
*/
void TerminalEditor::activeConnections(bool active) {
if (active) {
connect(qle_x,
&QDoubleSpinBox::editingFinished,
this, &TerminalEditor::updateXPos);
connect(qle_y,
&QDoubleSpinBox::editingFinished,
this, &TerminalEditor::updateYPos);
connect(orientation,
QOverload<int>::of(&QComboBox::activated),
this, &TerminalEditor::updateTerminalO);
connect(name, &QLineEdit::editingFinished,
this, &TerminalEditor::updateName);
}
else {
disconnect(qle_x, &QDoubleSpinBox::editingFinished,
this, &TerminalEditor::updateXPos);
disconnect(qle_y, &QDoubleSpinBox::editingFinished,
this, &TerminalEditor::updateYPos);
disconnect(orientation, QOverload<int>::of(&QComboBox::activated),
this, &TerminalEditor::updateTerminalO);
disconnect(name, &QLineEdit::editingFinished,
this, &TerminalEditor::updateName);
}
}
+76
View File
@@ -0,0 +1,76 @@
/*
Copyright 2006-2021 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 TERMINAL_EDITOR_H
#define TERMINAL_EDITOR_H
#include "elementitemeditor.h"
#include <QLineEdit>
class PartTerminal;
class QDoubleSpinBox;
class QComboBox;
/**
@brief The TerminalEditor class
This class provides a widget to edit terminals within the element editor.
The class is capable to change the values of multiple parts of the same time.
The displayed values are from the first selected element
*/
class TerminalEditor : public ElementItemEditor {
Q_OBJECT
// Constructors, destructor
public:
TerminalEditor(
QETElementEditor *,
QList<PartTerminal *>& terms,
QWidget * = nullptr);
TerminalEditor(QETElementEditor *, QWidget * = nullptr);
~TerminalEditor() override;
private:
TerminalEditor(const TerminalEditor &);
void init();
// attributes
private:
QList<PartTerminal *> m_terminals;
PartTerminal *m_part{nullptr};
QDoubleSpinBox *qle_x, *qle_y;
QComboBox *orientation;
QLineEdit *name;
bool m_locked{false};
// methods
public:
bool setPart(CustomElementPart *) override;
bool setParts(QList<CustomElementPart *> parts) override;
CustomElementPart *currentPart() const override;
QList<CustomElementPart*> currentParts() const override;
public slots:
void updateTerminalO();
void updateXPos();
void updateYPos();
void updateName();
void updateForm() override;
private:
void activeConnections(bool);
};
#endif
+5 -6
View File
@@ -24,8 +24,7 @@
#include "../../qetinformation.h" #include "../../qetinformation.h"
#include "../../ui/alignmenttextdialog.h" #include "../../ui/alignmenttextdialog.h"
#include "../../ui/compositetexteditdialog.h" #include "../../ui/compositetexteditdialog.h"
#include "../ui/qetelementeditor.h" #include "../qetelementeditor.h"
#include "../elementscene.h"
#include "ui_dynamictextfieldeditor.h" #include "ui_dynamictextfieldeditor.h"
#include <QColorDialog> #include <QColorDialog>
@@ -225,9 +224,9 @@ void DynamicTextFieldEditor::fillInfoComboBox()
ui -> m_elmt_info_cb -> clear(); ui -> m_elmt_info_cb -> clear();
QStringList strl; QStringList strl;
auto type = elementEditor()->elementScene()->elementData().m_type; QString type = elementEditor() -> elementScene() -> elementType();
if(type & ElementData::AllReport) { if(type.contains("report")) {
strl = QETInformation::folioReportInfoKeys(); strl = QETInformation::folioReportInfoKeys();
} }
else { else {
@@ -333,8 +332,8 @@ void DynamicTextFieldEditor::on_m_elmt_info_cb_activated(const QString &arg1) {
QPropertyUndoCommand *undo = new QPropertyUndoCommand(m_parts[i], "infoName", m_parts[i] -> infoName(), info); QPropertyUndoCommand *undo = new QPropertyUndoCommand(m_parts[i], "infoName", m_parts[i] -> infoName(), info);
undo->setText(tr("Modifier l'information d'un texte")); undo->setText(tr("Modifier l'information d'un texte"));
undoStack().push(undo); undoStack().push(undo);
m_parts[i]->setPlainText( m_parts[i] -> setPlainText(
elementEditor()->elementScene()->elementData().m_informations.value(m_parts[i] -> infoName()).toString()); elementEditor() -> elementScene() -> elementInformation().value(m_parts[i] -> infoName()).toString());
} }
} }
} }
@@ -1,4 +1,4 @@
/* /*
Copyright 2006-2021 The QElectroTech Team Copyright 2006-2021 The QElectroTech Team
This file is part of QElectroTech. This file is part of QElectroTech.
@@ -20,7 +20,6 @@
#include "../../qetapp.h" #include "../../qetapp.h"
#include "../../qetinformation.h" #include "../../qetinformation.h"
#include "ui_elementpropertieseditorwidget.h" #include "ui_elementpropertieseditorwidget.h"
#include "../../qetinformation.h"
#include <QItemDelegate> #include <QItemDelegate>
@@ -38,7 +37,7 @@ class EditorDelegate : public QItemDelegate
QWidget* createEditor(QWidget *parent, QWidget* createEditor(QWidget *parent,
const QStyleOptionViewItem &option, const QStyleOptionViewItem &option,
const QModelIndex &index) const override const QModelIndex &index) const
{ {
if(index.column() == 1) if(index.column() == 1)
{ {
@@ -51,14 +50,23 @@ class EditorDelegate : public QItemDelegate
}; };
/** /**
* @brief ElementPropertiesEditorWidget::ElementPropertiesEditorWidget @brief ElementPropertiesEditorWidget::ElementPropertiesEditorWidget
* @param data Default constructor
* @param parent @param basic_type : QString of the drawed element
*/ @param kind_info : DiagramContext to store kindInfo of drawed element
ElementPropertiesEditorWidget::ElementPropertiesEditorWidget(ElementData data, QWidget *parent) : @param elmt_info : the information of element (label, manufacturer etc...]
@param parent : parent widget
*/
ElementPropertiesEditorWidget::ElementPropertiesEditorWidget(
QString &basic_type,
DiagramContext &kind_info,
DiagramContext &elmt_info,
QWidget *parent) :
QDialog(parent), QDialog(parent),
ui(new Ui::ElementPropertiesEditorWidget), ui(new Ui::ElementPropertiesEditorWidget),
m_data(data) m_basic_type(basic_type),
m_kind_info (kind_info),
m_elmt_info (elmt_info)
{ {
ui->setupUi(this); ui->setupUi(this);
setUpInterface(); setUpInterface();
@@ -82,29 +90,22 @@ void ElementPropertiesEditorWidget::upDateInterface()
{ {
ui->m_base_type_cb->setCurrentIndex( ui->m_base_type_cb->setCurrentIndex(
ui->m_base_type_cb->findData( ui->m_base_type_cb->findData(
m_data.m_type)); QVariant(m_basic_type)));
if (m_data.m_type == ElementData::Slave) if (m_basic_type == "slave")
{ {
ui->m_state_cb->setCurrentIndex( ui->m_state_cb->setCurrentIndex(
ui->m_state_cb->findData( ui->m_state_cb->findData(
m_data.m_slave_state)); m_kind_info["state"].toString()));
ui->m_type_cb->setCurrentIndex ( ui->m_type_cb->setCurrentIndex (
ui->m_type_cb->findData( ui->m_type_cb->findData(
m_data.m_slave_type)); m_kind_info["type"].toString()));
ui->m_number_ctc->setValue(m_data.m_contact_count); ui->m_number_ctc->setValue(m_kind_info["number"].toInt());
} }
else if (m_data.m_type == ElementData::Master) { else if (m_basic_type == "master") {
ui->m_master_type_cb->setCurrentIndex( ui->m_master_type_cb->setCurrentIndex(
ui->m_master_type_cb->findData ( ui->m_master_type_cb->findData (
m_data.m_master_type)); m_kind_info["type"]));
} else if (m_data.m_type == ElementData::Terminale) {
ui->m_terminal_type_cb->setCurrentIndex(
ui->m_terminal_type_cb->findData(
m_data.m_terminal_type));
ui->m_terminal_func_cb->setCurrentIndex(
ui->m_terminal_func_cb->findData(
m_data.m_terminal_function));
} }
on_m_base_type_cb_currentIndexChanged(ui->m_base_type_cb->currentIndex()); on_m_base_type_cb_currentIndexChanged(ui->m_base_type_cb->currentIndex());
@@ -116,39 +117,33 @@ void ElementPropertiesEditorWidget::upDateInterface()
void ElementPropertiesEditorWidget::setUpInterface() void ElementPropertiesEditorWidget::setUpInterface()
{ {
// Type combo box // Type combo box
ui->m_base_type_cb->addItem (tr("Simple"), ElementData::Simple); ui->m_base_type_cb->addItem (tr("Simple"), QVariant("simple"));
ui->m_base_type_cb->addItem (tr("Maître"), ElementData::Master); ui->m_base_type_cb->addItem (tr("Maître"), QVariant("master"));
ui->m_base_type_cb->addItem (tr("Esclave"), ElementData::Slave); ui->m_base_type_cb->addItem (tr("Esclave"), QVariant("slave"));
ui->m_base_type_cb->addItem (tr("Renvoi de folio suivant"), ElementData::NextReport); ui->m_base_type_cb->addItem (tr("Renvoi de folio suivant"),
ui->m_base_type_cb->addItem (tr("Renvoi de folio précédent"), ElementData::PreviousReport); QVariant("next_report"));
ui->m_base_type_cb->addItem (tr("Bornier"), ElementData::Terminale); ui->m_base_type_cb->addItem (tr("Renvoi de folio précédent"),
QVariant("previous_report"));
ui->m_base_type_cb->addItem (tr("Bornier"), QVariant("terminal"));
// Slave option // Slave option
ui->m_state_cb->addItem(tr("Normalement ouvert"), ElementData::NO); ui->m_state_cb->addItem(tr("Normalement ouvert"),QVariant("NO"));
ui->m_state_cb->addItem(tr("Normalement fermé"), ElementData::NC); ui->m_state_cb->addItem(tr("Normalement fermé"), QVariant("NC"));
ui->m_state_cb->addItem(tr("Inverseur"), ElementData::SW); ui->m_state_cb->addItem(tr("Inverseur"), QVariant("SW"));
ui->m_type_cb->addItem(tr("Simple"), ElementData::SSimple); ui->m_type_cb->addItem(tr("Simple"), QVariant("simple"));
ui->m_type_cb->addItem(tr("Puissance"), ElementData::Power); ui->m_type_cb->addItem(tr("Puissance"), QVariant("power"));
ui->m_type_cb->addItem(tr("Temporisé travail"), ElementData::DelayOn); ui->m_type_cb->addItem(tr("Temporisé travail"), QVariant("delayOn"));
ui->m_type_cb->addItem(tr("Temporisé repos"), ElementData::DelayOff); ui->m_type_cb->addItem(tr("Temporisé repos"), QVariant("delayOff"));
ui->m_type_cb->addItem(tr("Temporisé travail & repos"), ElementData::delayOnOff); ui->m_type_cb->addItem(tr("Temporisé travail & repos"),
QVariant("delayOnOff"));
//Master option //Master option
ui->m_master_type_cb->addItem(tr("Bobine"), ElementData::Coil); ui->m_master_type_cb->addItem(tr("Bobine"), QVariant("coil"));
ui->m_master_type_cb->addItem(tr("Organe de protection"), ElementData::Protection); ui->m_master_type_cb->addItem(tr("Organe de protection"),
ui->m_master_type_cb->addItem(tr("Commutateur / bouton"), ElementData::Commutator); QVariant("protection"));
ui->m_master_type_cb->addItem(tr("Commutateur / bouton"),
//Terminal option QVariant("commutator"));
ui->m_terminal_type_cb->addItem(tr("Générique"), ElementData::TTGeneric);
ui->m_terminal_type_cb->addItem(tr("Fusible"), ElementData::Fuse);
ui->m_terminal_type_cb->addItem(tr("Séctionnable"), ElementData::Sectional);
ui->m_terminal_type_cb->addItem(tr("Diode"), ElementData::Diode);
ui->m_terminal_func_cb->addItem(tr("Générique"), ElementData::TFGeneric);
ui->m_terminal_func_cb->addItem(tr("Phase"), ElementData::Phase);
ui->m_terminal_func_cb->addItem(tr("Neutre"), ElementData::Neutral);
ui->m_terminal_func_cb->addItem(tr("Terre"), ElementData::PE);
//Disable the edition of the first column of the information tree //Disable the edition of the first column of the information tree
//by this little workaround //by this little workaround
ui->m_tree->setItemDelegate(new EditorDelegate(this)); ui->m_tree->setItemDelegate(new EditorDelegate(this));
@@ -158,28 +153,21 @@ void ElementPropertiesEditorWidget::setUpInterface()
void ElementPropertiesEditorWidget::updateTree() void ElementPropertiesEditorWidget::updateTree()
{ {
auto type_ = ui->m_base_type_cb->currentData().value<ElementData::Type>(); QString type = ui->m_base_type_cb->itemData(
ui->m_base_type_cb->currentIndex()).toString();
switch (type_) {
case ElementData::Simple: if (type == "master")
ui->m_tree->setEnabled(true); ui->m_tree->setEnabled(true);
break; else if (type == "slave")
case ElementData::NextReport: ui->m_tree->setDisabled(true);
ui->m_tree->setDisabled(true); else if (type == "simple")
break; ui->m_tree->setEnabled(true);
case ElementData::PreviousReport: else if (type == "next_report")
ui->m_tree->setDisabled(true); ui->m_tree->setDisabled(true);
break; else if (type == "previous_report")
case ElementData::Master: ui->m_tree->setDisabled(true);
ui->m_tree->setEnabled(true); else if (type == "terminal")
break; ui->m_tree->setEnabled(true);
case ElementData::Slave:
ui->m_tree->setDisabled(true);
break;
case ElementData::Terminale:
ui->m_tree->setEnabled(true);
break;
}
} }
/** /**
@@ -187,16 +175,20 @@ void ElementPropertiesEditorWidget::updateTree()
Create QTreeWidgetItem of the tree widget and populate it Create QTreeWidgetItem of the tree widget and populate it
*/ */
void ElementPropertiesEditorWidget::populateTree() void ElementPropertiesEditorWidget::populateTree()
{ {
const auto keys = QETInformation::elementEditorElementInfoKeys(); QStringList keys{"label", "plant", "comment", "description",
"designation", "manufacturer",
"manufacturer_reference", "supplier", "quantity",
"unity", "machine_manufacturer_reference"};
for(const QString& key : keys) for(const QString& key : keys)
{ {
QTreeWidgetItem *qtwi = new QTreeWidgetItem(ui->m_tree); QTreeWidgetItem *qtwi = new QTreeWidgetItem(ui->m_tree);
qtwi->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable); qtwi->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable);
qtwi->setData(0, Qt::DisplayRole, qtwi->setData(0, Qt::DisplayRole,
QETInformation::translatedInfoKey(key)); QETInformation::translatedInfoKey(key));
qtwi->setData(0, Qt::UserRole, key); qtwi->setData(0, Qt::UserRole, key);
qtwi->setText(1, m_data.m_informations.value(key).toString()); qtwi->setText(1, m_elmt_info.value(key).toString());
} }
} }
@@ -206,21 +198,23 @@ void ElementPropertiesEditorWidget::populateTree()
*/ */
void ElementPropertiesEditorWidget::on_m_buttonBox_accepted() void ElementPropertiesEditorWidget::on_m_buttonBox_accepted()
{ {
m_data.m_type = ui->m_base_type_cb->currentData().value<ElementData::Type>(); m_basic_type = ui->m_base_type_cb->itemData(
ui->m_base_type_cb->currentIndex()).toString();
if (m_data.m_type == ElementData::Slave) if (m_basic_type == "slave")
{ {
m_data.m_slave_state = ui->m_state_cb->currentData().value<ElementData::SlaveState>(); m_kind_info.addValue("state",
m_data.m_slave_type = ui->m_type_cb->currentData().value<ElementData::SlaveType>(); ui->m_state_cb->itemData(
m_data.m_contact_count = ui->m_number_ctc->value(); ui->m_state_cb->currentIndex()));
m_kind_info.addValue("type",
ui->m_type_cb->itemData(
ui->m_type_cb->currentIndex()));
m_kind_info.addValue("number",
QVariant(ui->m_number_ctc->value()));
} }
else if (m_data.m_type == ElementData::Master) { else if(m_basic_type == "master") {
m_data.m_master_type = ui->m_master_type_cb->currentData().value<ElementData::MasterType>(); m_kind_info.addValue("type",
} ui->m_master_type_cb->itemData(
else if (m_data.m_type == ElementData::Terminale) ui->m_master_type_cb->currentIndex()));
{
m_data.m_terminal_type = ui->m_terminal_type_cb->currentData().value<ElementData::TerminalType>();
m_data.m_terminal_function = ui->m_terminal_func_cb->currentData().value<ElementData::TerminalFunction>();
} }
for (QTreeWidgetItem *qtwi : ui->m_tree->invisibleRootItem()->takeChildren()) for (QTreeWidgetItem *qtwi : ui->m_tree->invisibleRootItem()->takeChildren())
@@ -230,8 +224,8 @@ void ElementPropertiesEditorWidget::on_m_buttonBox_accepted()
txt.remove("\r"); txt.remove("\r");
txt.remove("\n"); txt.remove("\n");
m_data.m_informations.addValue(qtwi->data(0, Qt::UserRole).toString(), m_elmt_info.addValue(qtwi->data(0, Qt::UserRole).toString(),
txt); txt);
} }
this->close(); this->close();
@@ -241,23 +235,18 @@ void ElementPropertiesEditorWidget::on_m_buttonBox_accepted()
@brief ElementPropertiesEditorWidget::on_m_base_type_cb_currentIndexChanged @brief ElementPropertiesEditorWidget::on_m_base_type_cb_currentIndexChanged
@param index : Action when combo-box base type index change @param index : Action when combo-box base type index change
*/ */
void ElementPropertiesEditorWidget::on_m_base_type_cb_currentIndexChanged(int index) void ElementPropertiesEditorWidget::on_m_base_type_cb_currentIndexChanged(
int index)
{ {
bool slave = false , master = false, terminal = false; bool slave = false , master = false;
auto type_ = ui->m_base_type_cb->itemData(index).value<ElementData::Type>(); if (ui->m_base_type_cb->itemData(index).toString() == "slave")
if (type_ == ElementData::Slave)
slave = true; slave = true;
else if (type_ == ElementData::Master) else if (ui->m_base_type_cb->itemData(index).toString() == "master")
master = true; master = true;
else if (type_ == ElementData::Terminale)
terminal = true;
ui->m_slave_gb->setVisible(slave); ui->m_slave_gb->setVisible(slave);
ui->m_master_gb->setVisible(master); ui->m_master_gb->setVisible(master);
ui->m_terminal_gb->setVisible(terminal);
ui->tabWidget->setTabVisible(1,
(type_ == ElementData::Simple ||
type_ == ElementData::Master));
updateTree(); updateTree();
} }
@@ -19,7 +19,6 @@
#define ELEMENTPROPERTIESEDITORWIDGET_H #define ELEMENTPROPERTIESEDITORWIDGET_H
#include "../../diagramcontext.h" #include "../../diagramcontext.h"
#include "../../properties/elementdata.h"
#include <QAbstractButton> #include <QAbstractButton>
#include <QDialog> #include <QDialog>
@@ -39,13 +38,12 @@ class ElementPropertiesEditorWidget : public QDialog
//METHODS //METHODS
public: public:
explicit ElementPropertiesEditorWidget(ElementData data, QWidget *parent = nullptr); explicit ElementPropertiesEditorWidget(QString &basic_type, DiagramContext &kind_info, DiagramContext &elmt_info, QWidget *parent = nullptr);
~ElementPropertiesEditorWidget() override; ~ElementPropertiesEditorWidget() override;
ElementData editedData() {return m_data;} void upDateInterface();
private: private:
void upDateInterface();
void setUpInterface(); void setUpInterface();
void updateTree(); void updateTree();
void populateTree(); void populateTree();
@@ -58,7 +56,9 @@ class ElementPropertiesEditorWidget : public QDialog
//ATTRIBUTES //ATTRIBUTES
private: private:
Ui::ElementPropertiesEditorWidget *ui; Ui::ElementPropertiesEditorWidget *ui;
ElementData m_data; QString &m_basic_type;
DiagramContext &m_kind_info,
&m_elmt_info;
}; };
#endif // ELEMENTPROPERTIESEDITORWIDGET_H #endif // ELEMENTPROPERTIESEDITORWIDGET_H
@@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>527</width> <width>450</width>
<height>442</height> <height>321</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -107,35 +107,6 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QGroupBox" name="m_terminal_gb">
<property name="title">
<string>Élément bornier</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Fonction</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="m_terminal_type_cb"/>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="m_terminal_func_cb"/>
</item>
</layout>
</widget>
</item>
<item> <item>
<spacer name="verticalSpacer_2"> <spacer name="verticalSpacer_2">
<property name="orientation"> <property name="orientation">
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More