mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-05-31 03:33:13 +02:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 34eb6e9f71 | |||
| faf4235bed | |||
| 0a51e22b7d | |||
| 632fba5366 | |||
| 0ca883f114 | |||
| 170d856007 | |||
| 0424eb9fba | |||
| 8210f06919 | |||
| 468618adda | |||
| 8141a75738 | |||
| 8f201a6e5d | |||
| b8745c0a6b | |||
| 7c3bde9118 | |||
| 28cd389695 | |||
| 56bb2a399b | |||
| dc726792d3 | |||
| d8707a4ef2 | |||
| 77710e1cc5 | |||
| 1d2c00819d | |||
| eee0469bd7 | |||
| 5118037cb5 | |||
| 1f53c39290 | |||
| b71aec9548 | |||
| c7798e1a80 | |||
| f97edad75a | |||
| 454b2c8a0f | |||
| b2782bc460 | |||
| 059f0eb1b6 | |||
| ce318ac667 | |||
| be2067148e | |||
| 444f62a1f8 | |||
| 8f85cacb06 | |||
| ffe3d98279 | |||
| dea926e4b4 | |||
| a1779d1a7a | |||
| 252106178b | |||
| a00404bc9f | |||
| e2ebb445a8 | |||
| 24ec94d73e | |||
| edb42caa16 | |||
| c110acc0ac | |||
| 3467c09c1e |
+1
-1
@@ -19,7 +19,7 @@ include(cmake/hoto_update_cmake_message.cmake)
|
||||
cmake_minimum_required(VERSION 3.14...3.19 FATAL_ERROR)
|
||||
|
||||
project(qelectrotech
|
||||
VERSION 0.8.0
|
||||
VERSION 0.9.0
|
||||
DESCRIPTION "QET is a CAD/CAE editor focusing on schematics drawing features."
|
||||
HOMEPAGE_URL "https://qelectrotech.org/"
|
||||
LANGUAGES CXX)
|
||||
|
||||
@@ -1,12 +1,79 @@
|
||||
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__
|
||||
----------
|
||||
|
||||
* Fallback to standard QApplication class on iOS and Android systems where
|
||||
the library is not supported.
|
||||
|
||||
|
||||
* Added Build CI tests to verify the library builds successfully on Linux, Windows and MacOS across multiple Qt versions.
|
||||
|
||||
_Anton Filimonov_
|
||||
|
||||
@@ -1,43 +1,40 @@
|
||||
cmake_minimum_required(VERSION 3.1.0)
|
||||
cmake_minimum_required(VERSION 3.7.0)
|
||||
|
||||
project(SingleApplication)
|
||||
project(SingleApplication LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR 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
|
||||
singleapplication.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_package(Qt5Network)
|
||||
if(QAPPLICATION_CLASS STREQUAL QApplication)
|
||||
find_package(Qt5 COMPONENTS Widgets REQUIRED)
|
||||
elseif(QAPPLICATION_CLASS STREQUAL QGuiApplication)
|
||||
find_package(Qt5 COMPONENTS Gui REQUIRED)
|
||||
else()
|
||||
find_package(Qt5 COMPONENTS Core REQUIRED)
|
||||
endif()
|
||||
add_compile_definitions(QAPPLICATION_CLASS=${QAPPLICATION_CLASS})
|
||||
set(QT_COMPONENTS Core Network)
|
||||
set(QT_LIBRARIES Qt${QT_DEFAULT_MAJOR_VERSION}::Core Qt${QT_DEFAULT_MAJOR_VERSION}::Network)
|
||||
|
||||
# Link dependencies
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Network)
|
||||
if(QAPPLICATION_CLASS STREQUAL QApplication)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets)
|
||||
list(APPEND QT_COMPONENTS Widgets)
|
||||
list(APPEND QT_LIBRARIES Qt${QT_DEFAULT_MAJOR_VERSION}::Widgets)
|
||||
elseif(QAPPLICATION_CLASS STREQUAL QGuiApplication)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Gui)
|
||||
list(APPEND QT_COMPONENTS Gui)
|
||||
list(APPEND QT_LIBRARIES Qt${QT_DEFAULT_MAJOR_VERSION}::Gui)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core)
|
||||
set(QAPPLICATION_CLASS QCoreApplication)
|
||||
endif()
|
||||
|
||||
find_package(Qt${QT_DEFAULT_MAJOR_VERSION} COMPONENTS ${QT_COMPONENTS} REQUIRED)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${QT_LIBRARIES})
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE advapi32)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC QAPPLICATION_CLASS=${QAPPLICATION_CLASS})
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Itay Grudev 2015 - 2016
|
||||
Copyright (c) Itay Grudev 2015 - 2020
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+45
-18
@@ -1,7 +1,8 @@
|
||||
SingleApplication
|
||||
=================
|
||||
[](https://github.com/itay-grudev/SingleApplication/actions)
|
||||
|
||||
This is a replacement of the QtSingleApplication for `Qt5`.
|
||||
This is a replacement of the QtSingleApplication for `Qt5` and `Qt6`.
|
||||
|
||||
Keeps the Primary Instance of your Application and kills each subsequent
|
||||
instances. It can (if enabled) spawn secondary (non-related to the primary)
|
||||
@@ -15,18 +16,6 @@ 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`
|
||||
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
|
||||
class:
|
||||
|
||||
@@ -43,8 +32,7 @@ int main( int argc, char* argv[] )
|
||||
```
|
||||
|
||||
To include the library files I would recommend that you add it as a git
|
||||
submodule to your project and include it's contents with a `.pri` file. Here is
|
||||
how:
|
||||
submodule to your project. Here is how:
|
||||
|
||||
```bash
|
||||
git submodule add git@github.com:itay-grudev/SingleApplication.git singleapplication
|
||||
@@ -66,13 +54,27 @@ Then include the subdirectory in your `CMakeLists.txt` project file.
|
||||
```cmake
|
||||
set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for 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
|
||||
is not `QCoreApplication` as in examples above.
|
||||
|
||||
The `Instance Started` signal
|
||||
------------------------
|
||||
-----------------------------
|
||||
|
||||
The SingleApplication class implements a `instanceStarted()` signal. You can
|
||||
bind to that signal to raise your application's window when a new instance had
|
||||
@@ -137,13 +139,22 @@ app.isSecondary();
|
||||
*__Note:__ If your Primary Instance is terminated a newly launched instance
|
||||
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
|
||||
---
|
||||
|
||||
### Members
|
||||
|
||||
```cpp
|
||||
SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100 )
|
||||
SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100, QString userData = QString() )
|
||||
```
|
||||
|
||||
Depending on whether `allowSecondary` is set, this constructor may terminate
|
||||
@@ -152,7 +163,7 @@ can be specified to set whether the SingleApplication block should work
|
||||
user-wide or system-wide. Additionally the `Mode::SecondaryNotification` may be
|
||||
used to notify the primary instance whenever a secondary instance had been
|
||||
started (disabled by default). `timeout` specifies the maximum time in
|
||||
milliseconds to wait for blocking operations.
|
||||
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.
|
||||
|
||||
*__Note:__ `argc` and `argv` may be changed as Qt removes arguments that it
|
||||
recognizes.*
|
||||
@@ -204,6 +215,22 @@ qint64 SingleApplication::primaryPid()
|
||||
|
||||
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
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#include "singleapplication.h"
|
||||
@@ -0,0 +1,12 @@
|
||||
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)
|
||||
|
||||
Regular → Executable
Regular → Executable
+2
@@ -5,5 +5,7 @@ int main(int argc, char *argv[])
|
||||
// Allow secondary instances
|
||||
SingleApplication app( argc, argv );
|
||||
|
||||
qWarning() << "Started a new instance";
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
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()));
|
||||
}
|
||||
|
||||
Button *pointButton = createButton(tr("."), SLOT(pointClicked()));
|
||||
Button *changeSignButton = createButton(tr("\302\261"), SLOT(changeSignClicked()));
|
||||
Button *pointButton = createButton(".", SLOT(pointClicked()));
|
||||
Button *changeSignButton = createButton("\302\261", SLOT(changeSignClicked()));
|
||||
|
||||
Button *backspaceButton = createButton(tr("Backspace"), SLOT(backspaceClicked()));
|
||||
Button *clearButton = createButton(tr("Clear"), SLOT(clear()));
|
||||
Button *clearAllButton = createButton(tr("Clear All"), SLOT(clearAll()));
|
||||
Button *backspaceButton = createButton("Backspace", SLOT(backspaceClicked()));
|
||||
Button *clearButton = createButton("Clear", SLOT(clear()));
|
||||
Button *clearAllButton = createButton("Clear All", SLOT(clearAll()));
|
||||
|
||||
Button *clearMemoryButton = createButton(tr("MC"), SLOT(clearMemory()));
|
||||
Button *readMemoryButton = createButton(tr("MR"), SLOT(readMemory()));
|
||||
Button *setMemoryButton = createButton(tr("MS"), SLOT(setMemory()));
|
||||
Button *addToMemoryButton = createButton(tr("M+"), SLOT(addToMemory()));
|
||||
Button *clearMemoryButton = createButton("MC", SLOT(clearMemory()));
|
||||
Button *readMemoryButton = createButton("MR", SLOT(readMemory()));
|
||||
Button *setMemoryButton = createButton("MS", SLOT(setMemory()));
|
||||
Button *addToMemoryButton = createButton("M+", SLOT(addToMemory()));
|
||||
|
||||
Button *divisionButton = createButton(tr("\303\267"), SLOT(multiplicativeOperatorClicked()));
|
||||
Button *timesButton = createButton(tr("\303\227"), SLOT(multiplicativeOperatorClicked()));
|
||||
Button *minusButton = createButton(tr("-"), SLOT(additiveOperatorClicked()));
|
||||
Button *plusButton = createButton(tr("+"), SLOT(additiveOperatorClicked()));
|
||||
Button *divisionButton = createButton("\303\267", SLOT(multiplicativeOperatorClicked()));
|
||||
Button *timesButton = createButton("\303\227", SLOT(multiplicativeOperatorClicked()));
|
||||
Button *minusButton = createButton("-", SLOT(additiveOperatorClicked()));
|
||||
Button *plusButton = createButton("+", SLOT(additiveOperatorClicked()));
|
||||
|
||||
Button *squareRootButton = createButton(tr("Sqrt"), SLOT(unaryOperatorClicked()));
|
||||
Button *powerButton = createButton(tr("x\302\262"), SLOT(unaryOperatorClicked()));
|
||||
Button *reciprocalButton = createButton(tr("1/x"), SLOT(unaryOperatorClicked()));
|
||||
Button *equalButton = createButton(tr("="), SLOT(equalClicked()));
|
||||
Button *squareRootButton = createButton("Sqrt", SLOT(unaryOperatorClicked()));
|
||||
Button *powerButton = createButton("x\302\262", SLOT(unaryOperatorClicked()));
|
||||
Button *reciprocalButton = createButton("1/x", SLOT(unaryOperatorClicked()));
|
||||
Button *equalButton = createButton("=", SLOT(equalClicked()));
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
@@ -140,7 +140,7 @@ Calculator::Calculator(QWidget *parent)
|
||||
mainLayout->addWidget(equalButton, 5, 5);
|
||||
setLayout(mainLayout);
|
||||
|
||||
setWindowTitle(tr("Calculator"));
|
||||
setWindowTitle("Calculator");
|
||||
}
|
||||
//! [6]
|
||||
|
||||
@@ -169,15 +169,15 @@ void Calculator::unaryOperatorClicked()
|
||||
double operand = display->text().toDouble();
|
||||
double result = 0.0;
|
||||
|
||||
if (clickedOperator == tr("Sqrt")) {
|
||||
if (clickedOperator == "Sqrt") {
|
||||
if (operand < 0.0) {
|
||||
abortOperation();
|
||||
return;
|
||||
}
|
||||
result = std::sqrt(operand);
|
||||
} else if (clickedOperator == tr("x\302\262")) {
|
||||
} else if (clickedOperator == "x\302\262") {
|
||||
result = std::pow(operand, 2.0);
|
||||
} else if (clickedOperator == tr("1/x")) {
|
||||
} else if (clickedOperator == "1/x") {
|
||||
if (operand == 0.0) {
|
||||
abortOperation();
|
||||
return;
|
||||
@@ -287,7 +287,7 @@ void Calculator::pointClicked()
|
||||
if (waitingForOperand)
|
||||
display->setText("0");
|
||||
if (!display->text().contains('.'))
|
||||
display->setText(display->text() + tr("."));
|
||||
display->setText(display->text() + ".");
|
||||
waitingForOperand = false;
|
||||
}
|
||||
//! [22]
|
||||
@@ -299,7 +299,7 @@ void Calculator::changeSignClicked()
|
||||
double value = text.toDouble();
|
||||
|
||||
if (value > 0.0) {
|
||||
text.prepend(tr("-"));
|
||||
text.prepend("-");
|
||||
} else if (value < 0.0) {
|
||||
text.remove(0, 1);
|
||||
}
|
||||
@@ -383,20 +383,20 @@ Button *Calculator::createButton(const QString &text, const char *member)
|
||||
void Calculator::abortOperation()
|
||||
{
|
||||
clearAll();
|
||||
display->setText(tr("####"));
|
||||
display->setText("####");
|
||||
}
|
||||
//! [36]
|
||||
|
||||
//! [38]
|
||||
bool Calculator::calculate(double rightOperand, const QString &pendingOperator)
|
||||
{
|
||||
if (pendingOperator == tr("+")) {
|
||||
if (pendingOperator == "+") {
|
||||
sumSoFar += rightOperand;
|
||||
} else if (pendingOperator == tr("-")) {
|
||||
} else if (pendingOperator == "-") {
|
||||
sumSoFar -= rightOperand;
|
||||
} else if (pendingOperator == tr("\303\227")) {
|
||||
} else if (pendingOperator == "\303\227") {
|
||||
factorSoFar *= rightOperand;
|
||||
} else if (pendingOperator == tr("\303\267")) {
|
||||
} else if (pendingOperator == "\303\267") {
|
||||
if (rightOperand == 0.0)
|
||||
return false;
|
||||
factorSoFar /= rightOperand;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
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)
|
||||
Regular → Executable
+3
@@ -11,6 +11,9 @@ int main(int argc, char *argv[])
|
||||
// If this is a secondary instance
|
||||
if( app.isSecondary() ) {
|
||||
app.sendMessage( app.arguments().join(' ').toUtf8() );
|
||||
qDebug() << "App already running.";
|
||||
qDebug() << "Primary instance PID: " << app.primaryPid();
|
||||
qDebug() << "Primary instance user: " << app.primaryUser();
|
||||
return 0;
|
||||
} else {
|
||||
QObject::connect(
|
||||
|
||||
Regular → Executable
@@ -1,6 +1,6 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) Itay Grudev 2015 - 2018
|
||||
// Copyright (c) Itay Grudev 2015 - 2020
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -20,176 +20,255 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include <QtCore/QTime>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtCore/QByteArray>
|
||||
#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_p.h"
|
||||
|
||||
/**
|
||||
@brief Constructor. Checks and fires up LocalServer or closes the program
|
||||
if another instance already exists
|
||||
@param argc
|
||||
@param argv
|
||||
@param {bool} allowSecondaryInstances
|
||||
*/
|
||||
SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary, Options options, int timeout )
|
||||
: app_t( argc, argv ), d_ptr( new SingleApplicationPrivate( this ) )
|
||||
* @brief Constructor. Checks and fires up LocalServer or closes the program
|
||||
* if another instance already exists
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param allowSecondary Whether to enable secondary instance support
|
||||
* @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, 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)
|
||||
// On Android and iOS since the library is not supported fallback to
|
||||
// standard QApplication behaviour by simply returning at this point.
|
||||
qWarning() << "SingleApplication is not supported on Android and iOS systems.";
|
||||
return;
|
||||
// On Android and iOS since the library is not supported fallback to
|
||||
// standard QApplication behaviour by simply returning at this point.
|
||||
qWarning() << "SingleApplication is not supported on Android and iOS systems.";
|
||||
return;
|
||||
#endif
|
||||
|
||||
// Store the current mode of the program
|
||||
d->options = options;
|
||||
// Store the current mode of the program
|
||||
d->options = options;
|
||||
|
||||
// Generating an application ID used for identifying the shared memory
|
||||
// block and QLocalServer
|
||||
d->genBlockServerName();
|
||||
// Add any unique user data
|
||||
if ( ! userData.isEmpty() )
|
||||
d->addAppData( userData );
|
||||
|
||||
// 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
|
||||
// By explicitly attaching it and then deleting it we make sure that the
|
||||
// memory is deleted even after the process has crashed on Unix.
|
||||
d->memory = new QSharedMemory( d->blockServerName );
|
||||
d->memory->attach();
|
||||
delete d->memory;
|
||||
// By explicitly attaching it and then deleting it we make sure that the
|
||||
// memory is deleted even after the process has crashed on Unix.
|
||||
d->memory = new QSharedMemory( d->blockServerName );
|
||||
d->memory->attach();
|
||||
delete d->memory;
|
||||
#endif
|
||||
// Guarantee thread safe behaviour with a shared memory block.
|
||||
d->memory = new QSharedMemory( d->blockServerName );
|
||||
// Guarantee thread safe behaviour with a shared memory block.
|
||||
d->memory = new QSharedMemory( d->blockServerName );
|
||||
|
||||
// Create a shared memory block
|
||||
if( d->memory->create( sizeof( InstancesInfo ) ) ) {
|
||||
// Initialize the shared memory block
|
||||
d->memory->lock();
|
||||
d->initializeMemoryBlock();
|
||||
d->memory->unlock();
|
||||
} else {
|
||||
// Attempt to attach to the memory segment
|
||||
if( ! d->memory->attach() ) {
|
||||
qCritical() << "SingleApplication: Unable to attach to shared memory block.";
|
||||
qCritical() << d->memory->errorString();
|
||||
delete d;
|
||||
::exit( EXIT_FAILURE );
|
||||
}
|
||||
}
|
||||
// Create a shared memory block
|
||||
if( d->memory->create( sizeof( InstancesInfo ) )){
|
||||
// Initialize the shared memory block
|
||||
if( ! d->memory->lock() ){
|
||||
qCritical() << "SingleApplication: Unable to lock memory block after create.";
|
||||
abortSafely();
|
||||
}
|
||||
d->initializeMemoryBlock();
|
||||
} else {
|
||||
if( d->memory->error() == QSharedMemory::AlreadyExists ){
|
||||
// Attempt to attach to the memory segment
|
||||
if( ! d->memory->attach() ){
|
||||
qCritical() << "SingleApplication: Unable to attach to shared memory block.";
|
||||
abortSafely();
|
||||
}
|
||||
if( ! d->memory->lock() ){
|
||||
qCritical() << "SingleApplication: Unable to lock memory block after attach.";
|
||||
abortSafely();
|
||||
}
|
||||
} else {
|
||||
qCritical() << "SingleApplication: Unable to create block.";
|
||||
abortSafely();
|
||||
}
|
||||
}
|
||||
|
||||
InstancesInfo* inst = static_cast<InstancesInfo*>( d->memory->data() );
|
||||
QElapsedTimer time;
|
||||
time.start();
|
||||
auto *inst = static_cast<InstancesInfo*>( d->memory->data() );
|
||||
QElapsedTimer time;
|
||||
time.start();
|
||||
|
||||
// Make sure the shared memory block is initialised and in consistent state
|
||||
while( true ) {
|
||||
d->memory->lock();
|
||||
// Make sure the shared memory block is initialised and in consistent state
|
||||
while( true ){
|
||||
// If the shared memory block's checksum is valid continue
|
||||
if( d->blockChecksum() == inst->checksum ) break;
|
||||
|
||||
if( d->blockChecksum() == inst->checksum ) break;
|
||||
// If more than 5s have elapsed, assume the primary instance crashed and
|
||||
// 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();
|
||||
}
|
||||
|
||||
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
|
||||
// limits the probability of a collision between two racing apps and
|
||||
// allows the app to initialise faster
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
d->memory->unlock();
|
||||
if( inst->primary == false ){
|
||||
d->startPrimary();
|
||||
if( ! d->memory->unlock() ){
|
||||
qDebug() << "SingleApplication: Unable to unlock memory after primary start.";
|
||||
qDebug() << d->memory->errorString();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Random sleep here limits the probability of a collision between two racing apps
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) // ### Qt 6: remove
|
||||
qsrand( QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max() );
|
||||
QThread::sleep( 8 + static_cast <unsigned long>( static_cast <float>( qrand() ) / RAND_MAX * 10 ) );
|
||||
#else
|
||||
#if TODO_LIST
|
||||
#pragma message("@TODO remove code for QT 5.10 or later")
|
||||
#endif
|
||||
quint32 value = QRandomGenerator::global()->generate();
|
||||
QThread::sleep(8 + static_cast<unsigned long>(value / RAND_MAX * 10));
|
||||
#endif
|
||||
}
|
||||
// Check if another instance can be started
|
||||
if( allowSecondary ){
|
||||
d->startSecondary();
|
||||
if( d->options & Mode::SecondaryNotification ){
|
||||
d->connectToPrimary( timeout, SingleApplicationPrivate::SecondaryInstance );
|
||||
}
|
||||
if( ! d->memory->unlock() ){
|
||||
qDebug() << "SingleApplication: Unable to unlock memory after secondary start.";
|
||||
qDebug() << d->memory->errorString();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if( inst->primary == false) {
|
||||
d->startPrimary();
|
||||
d->memory->unlock();
|
||||
return;
|
||||
}
|
||||
if( ! d->memory->unlock() ){
|
||||
qDebug() << "SingleApplication: Unable to unlock memory at end of execution.";
|
||||
qDebug() << d->memory->errorString();
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
d->connectToPrimary( timeout, SingleApplicationPrivate::NewInstance );
|
||||
|
||||
d->memory->unlock();
|
||||
delete d;
|
||||
|
||||
d->connectToPrimary( timeout, SingleApplicationPrivate::NewInstance );
|
||||
::exit( EXIT_SUCCESS );
|
||||
}
|
||||
|
||||
delete d;
|
||||
|
||||
::exit( EXIT_SUCCESS );
|
||||
SingleApplication::~SingleApplication()
|
||||
{
|
||||
Q_D( SingleApplication );
|
||||
delete d;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Destructor
|
||||
*/
|
||||
SingleApplication::~SingleApplication()
|
||||
* Checks if the current application instance is primary.
|
||||
* @return Returns true if the instance is primary, false otherwise.
|
||||
*/
|
||||
bool SingleApplication::isPrimary() const
|
||||
{
|
||||
Q_D(SingleApplication);
|
||||
delete d;
|
||||
Q_D( const SingleApplication );
|
||||
return d->server != nullptr;
|
||||
}
|
||||
|
||||
bool SingleApplication::isPrimary()
|
||||
/**
|
||||
* Checks if the current application instance is secondary.
|
||||
* @return Returns true if the instance is secondary, false otherwise.
|
||||
*/
|
||||
bool SingleApplication::isSecondary() const
|
||||
{
|
||||
Q_D(SingleApplication);
|
||||
return d->server != nullptr;
|
||||
Q_D( const SingleApplication );
|
||||
return d->server == nullptr;
|
||||
}
|
||||
|
||||
bool SingleApplication::isSecondary()
|
||||
/**
|
||||
* 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(SingleApplication);
|
||||
return d->server == nullptr;
|
||||
Q_D( const SingleApplication );
|
||||
return d->instanceNumber;
|
||||
}
|
||||
|
||||
quint32 SingleApplication::instanceId()
|
||||
/**
|
||||
* 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(SingleApplication);
|
||||
return d->instanceNumber;
|
||||
Q_D( const SingleApplication );
|
||||
return d->primaryPid();
|
||||
}
|
||||
|
||||
qint64 SingleApplication::primaryPid()
|
||||
/**
|
||||
* 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(SingleApplication);
|
||||
return d->primaryPid();
|
||||
Q_D( const SingleApplication );
|
||||
return d->primaryUser();
|
||||
}
|
||||
|
||||
bool SingleApplication::sendMessage( QByteArray message, int timeout )
|
||||
/**
|
||||
* Returns the username the current instance is running as.
|
||||
* @return Returns the username the current instance is running as.
|
||||
*/
|
||||
QString SingleApplication::currentUser() const
|
||||
{
|
||||
Q_D(SingleApplication);
|
||||
|
||||
// Nobody to connect to
|
||||
if( isPrimary() ) return false;
|
||||
|
||||
// Make sure the socket is connected
|
||||
d->connectToPrimary( timeout, SingleApplicationPrivate::Reconnect );
|
||||
|
||||
d->socket->write( message );
|
||||
bool dataWritten = d->socket->waitForBytesWritten( timeout );
|
||||
d->socket->flush();
|
||||
return dataWritten;
|
||||
return SingleApplicationPrivate::getUsername();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
#include <QtNetwork/QLocalSocket>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#ifndef QAPPLICATION_CLASS
|
||||
#define QAPPLICATION_CLASS QCoreApplication
|
||||
@@ -36,99 +35,118 @@
|
||||
class SingleApplicationPrivate;
|
||||
|
||||
/**
|
||||
@brief The SingleApplication class handles multiple instances of the same
|
||||
Application
|
||||
@see QCoreApplication
|
||||
*/
|
||||
* @brief The SingleApplication class handles multiple instances of the same
|
||||
* Application
|
||||
* @see QCoreApplication
|
||||
*/
|
||||
class SingleApplication : public QAPPLICATION_CLASS
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
typedef QAPPLICATION_CLASS app_t;
|
||||
|
||||
public:
|
||||
/**
|
||||
@brief Mode of operation of SingleApplication.
|
||||
Whether the block should be user-wide or system-wide and whether the
|
||||
primary instance should be notified when a secondary instance had been
|
||||
started.
|
||||
@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
|
||||
block will be user wide.
|
||||
@enum
|
||||
*/
|
||||
enum Mode {
|
||||
User = 1 << 0,
|
||||
System = 1 << 1,
|
||||
SecondaryNotification = 1 << 2,
|
||||
ExcludeAppVersion = 1 << 3,
|
||||
ExcludeAppPath = 1 << 4
|
||||
};
|
||||
Q_DECLARE_FLAGS(Options, Mode)
|
||||
|
||||
/**
|
||||
@brief Intitializes a SingleApplication instance with argc command line
|
||||
arguments in argv
|
||||
@arg {int &} argc - Number of arguments in argv
|
||||
@arg {const char *[]} argv - Supplied command line arguments
|
||||
@arg {bool} allowSecondary - Whether to start the instance as secondary
|
||||
if there is already a primary instance.
|
||||
@arg {Mode} mode - Whether for the SingleApplication block to be applied
|
||||
User wide or System wide.
|
||||
@arg {int} timeout - Timeout to wait in milliseconds.
|
||||
@note argc and argv may be changed as Qt removes arguments that it
|
||||
recognizes
|
||||
@note Mode::SecondaryNotification only works if set on both the primary
|
||||
instance and the secondary instance.
|
||||
@note The timeout is just a hint for the maximum time of blocking
|
||||
operations. It does not guarantee that the SingleApplication
|
||||
initialisation will be completed in given time, though is a good hint.
|
||||
Usually 4*timeout would be the worst case (fail) scenario.
|
||||
@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 );
|
||||
~SingleApplication();
|
||||
|
||||
/**
|
||||
@brief Returns if the instance is the primary instance
|
||||
@returns {bool}
|
||||
*/
|
||||
bool isPrimary();
|
||||
|
||||
/**
|
||||
@brief Returns if the instance is a secondary instance
|
||||
@returns {bool}
|
||||
*/
|
||||
bool isSecondary();
|
||||
|
||||
/**
|
||||
@brief Returns a unique identifier for the current instance
|
||||
@returns {qint32}
|
||||
*/
|
||||
quint32 instanceId();
|
||||
|
||||
/**
|
||||
@brief Returns the process ID (PID) of the primary instance
|
||||
@returns {qint64}
|
||||
*/
|
||||
qint64 primaryPid();
|
||||
|
||||
/**
|
||||
@brief Sends a message to the primary instance. Returns true on success.
|
||||
@param {int} timeout - Timeout for connecting
|
||||
@returns {bool}
|
||||
@note sendMessage() will return false if invoked from the primary
|
||||
instance.
|
||||
*/
|
||||
bool sendMessage( QByteArray message, int timeout = 100 );
|
||||
|
||||
Q_SIGNALS:
|
||||
void instanceStarted();
|
||||
void receivedMessage( quint32 instanceId, QByteArray message );
|
||||
|
||||
private:
|
||||
SingleApplicationPrivate *d_ptr;
|
||||
Q_DECLARE_PRIVATE(SingleApplication)
|
||||
Q_OBJECT
|
||||
|
||||
using app_t = QAPPLICATION_CLASS;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Mode of operation of SingleApplication.
|
||||
* Whether the block should be user-wide or system-wide and whether the
|
||||
* primary instance should be notified when a secondary instance had been
|
||||
* started.
|
||||
* @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
|
||||
* block will be user wide.
|
||||
* @enum
|
||||
*/
|
||||
enum Mode {
|
||||
User = 1 << 0,
|
||||
System = 1 << 1,
|
||||
SecondaryNotification = 1 << 2,
|
||||
ExcludeAppVersion = 1 << 3,
|
||||
ExcludeAppPath = 1 << 4
|
||||
};
|
||||
Q_DECLARE_FLAGS(Options, Mode)
|
||||
|
||||
/**
|
||||
* @brief Intitializes a SingleApplication instance with argc command line
|
||||
* arguments in argv
|
||||
* @arg {int &} argc - Number of arguments in argv
|
||||
* @arg {const char *[]} argv - Supplied command line arguments
|
||||
* @arg {bool} allowSecondary - Whether to start the instance as secondary
|
||||
* if there is already a primary instance.
|
||||
* @arg {Mode} mode - Whether for the SingleApplication block to be applied
|
||||
* User wide or System wide.
|
||||
* @arg {int} timeout - Timeout to wait in milliseconds.
|
||||
* @note argc and argv may be changed as Qt removes arguments that it
|
||||
* recognizes
|
||||
* @note Mode::SecondaryNotification only works if set on both the primary
|
||||
* instance and the secondary instance.
|
||||
* @note The timeout is just a hint for the maximum time of blocking
|
||||
* operations. It does not guarantee that the SingleApplication
|
||||
* initialisation will be completed in given time, though is a good hint.
|
||||
* Usually 4*timeout would be the worst case (fail) scenario.
|
||||
* @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 = {} );
|
||||
~SingleApplication() override;
|
||||
|
||||
/**
|
||||
* @brief Returns if the instance is the primary instance
|
||||
* @returns {bool}
|
||||
*/
|
||||
bool isPrimary() const;
|
||||
|
||||
/**
|
||||
* @brief Returns if the instance is a secondary instance
|
||||
* @returns {bool}
|
||||
*/
|
||||
bool isSecondary() const;
|
||||
|
||||
/**
|
||||
* @brief Returns a unique identifier for the current instance
|
||||
* @returns {qint32}
|
||||
*/
|
||||
quint32 instanceId() const;
|
||||
|
||||
/**
|
||||
* @brief Returns the process ID (PID) of the primary instance
|
||||
* @returns {qint64}
|
||||
*/
|
||||
qint64 primaryPid() const;
|
||||
|
||||
/**
|
||||
* @brief Returns the username of the user running the primary instance
|
||||
* @returns {QString}
|
||||
*/
|
||||
QString primaryUser() const;
|
||||
|
||||
/**
|
||||
* @brief Returns the username of the current user
|
||||
* @returns {QString}
|
||||
*/
|
||||
QString currentUser() const;
|
||||
|
||||
/**
|
||||
* @brief Sends a message to the primary instance. Returns true on success.
|
||||
* @param {int} timeout - Timeout for connecting
|
||||
* @returns {bool}
|
||||
* @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)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
QT += core network
|
||||
CONFIG += c++17
|
||||
CONFIG += c++11
|
||||
|
||||
HEADERS += $$PWD/singleapplication.h \
|
||||
HEADERS += $$PWD/SingleApplication \
|
||||
$$PWD/singleapplication.h \
|
||||
$$PWD/singleapplication_p.h
|
||||
SOURCES += $$PWD/singleapplication.cpp \
|
||||
$$PWD/singleapplication_p.cpp
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) Itay Grudev 2015 - 2018
|
||||
// Copyright (c) Itay Grudev 2015 - 2020
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -33,412 +33,454 @@
|
||||
#include <cstddef>
|
||||
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QDataStream>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtCore/QCryptographicHash>
|
||||
#include <QtNetwork/QLocalServer>
|
||||
#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_p.h"
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h>
|
||||
#include <lmcons.h>
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX 1
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <lmcons.h>
|
||||
#endif
|
||||
|
||||
SingleApplicationPrivate::SingleApplicationPrivate( SingleApplication *q_ptr )
|
||||
: q_ptr( q_ptr )
|
||||
: q_ptr( q_ptr )
|
||||
{
|
||||
server = nullptr;
|
||||
socket = nullptr;
|
||||
memory = nullptr;
|
||||
instanceNumber = -1;
|
||||
server = nullptr;
|
||||
socket = nullptr;
|
||||
memory = nullptr;
|
||||
instanceNumber = 0;
|
||||
}
|
||||
|
||||
SingleApplicationPrivate::~SingleApplicationPrivate()
|
||||
{
|
||||
if( socket != nullptr ) {
|
||||
socket->close();
|
||||
delete socket;
|
||||
}
|
||||
if( socket != nullptr ){
|
||||
socket->close();
|
||||
delete socket;
|
||||
}
|
||||
|
||||
memory->lock();
|
||||
InstancesInfo* inst = static_cast<InstancesInfo*>(memory->data());
|
||||
if( server != nullptr ) {
|
||||
server->close();
|
||||
delete server;
|
||||
inst->primary = false;
|
||||
inst->primaryPid = -1;
|
||||
inst->checksum = blockChecksum();
|
||||
}
|
||||
memory->unlock();
|
||||
if( memory != nullptr ){
|
||||
memory->lock();
|
||||
auto *inst = static_cast<InstancesInfo*>(memory->data());
|
||||
if( server != nullptr ){
|
||||
server->close();
|
||||
delete server;
|
||||
inst->primary = false;
|
||||
inst->primaryPid = -1;
|
||||
inst->primaryUser[0] = '\0';
|
||||
inst->checksum = blockChecksum();
|
||||
}
|
||||
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()
|
||||
{
|
||||
QCryptographicHash appData( QCryptographicHash::Sha256 );
|
||||
appData.addData( "SingleApplication", 17 );
|
||||
appData.addData( SingleApplication::app_t::applicationName().toUtf8() );
|
||||
appData.addData( SingleApplication::app_t::organizationName().toUtf8() );
|
||||
appData.addData( SingleApplication::app_t::organizationDomain().toUtf8() );
|
||||
QCryptographicHash appData( QCryptographicHash::Sha256 );
|
||||
appData.addData( "SingleApplication", 17 );
|
||||
appData.addData( SingleApplication::app_t::applicationName().toUtf8() );
|
||||
appData.addData( SingleApplication::app_t::organizationName().toUtf8() );
|
||||
appData.addData( SingleApplication::app_t::organizationDomain().toUtf8() );
|
||||
|
||||
if( ! (options & SingleApplication::Mode::ExcludeAppVersion) ) {
|
||||
appData.addData( SingleApplication::app_t::applicationVersion().toUtf8() );
|
||||
}
|
||||
if ( ! appDataList.isEmpty() )
|
||||
appData.addData( appDataList.join( "" ).toUtf8() );
|
||||
|
||||
if( ! (options & SingleApplication::Mode::ExcludeAppPath) ) {
|
||||
if( ! (options & SingleApplication::Mode::ExcludeAppVersion) ){
|
||||
appData.addData( SingleApplication::app_t::applicationVersion().toUtf8() );
|
||||
}
|
||||
|
||||
if( ! (options & SingleApplication::Mode::ExcludeAppPath) ){
|
||||
#ifdef Q_OS_WIN
|
||||
appData.addData( SingleApplication::app_t::applicationFilePath().toLower().toUtf8() );
|
||||
appData.addData( SingleApplication::app_t::applicationFilePath().toLower().toUtf8() );
|
||||
#else
|
||||
appData.addData( SingleApplication::app_t::applicationFilePath().toUtf8() );
|
||||
appData.addData( SingleApplication::app_t::applicationFilePath().toUtf8() );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// User level block requires a user specific data in the hash
|
||||
if( options & SingleApplication::Mode::User ) {
|
||||
#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
|
||||
}
|
||||
// User level block requires a user specific data in the hash
|
||||
if( options & SingleApplication::Mode::User ){
|
||||
appData.addData( getUsername().toUtf8() );
|
||||
}
|
||||
|
||||
// Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with
|
||||
// server naming requirements.
|
||||
blockServerName = appData.result().toBase64().replace("/", "_");
|
||||
// Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with
|
||||
// server naming requirements.
|
||||
blockServerName = appData.result().toBase64().replace("/", "_");
|
||||
}
|
||||
|
||||
void SingleApplicationPrivate::initializeMemoryBlock()
|
||||
void SingleApplicationPrivate::initializeMemoryBlock() const
|
||||
{
|
||||
InstancesInfo* inst = static_cast<InstancesInfo*>( memory->data() );
|
||||
inst->primary = false;
|
||||
inst->secondary = 0;
|
||||
inst->primaryPid = -1;
|
||||
inst->checksum = blockChecksum();
|
||||
auto *inst = static_cast<InstancesInfo*>( memory->data() );
|
||||
inst->primary = false;
|
||||
inst->secondary = 0;
|
||||
inst->primaryPid = -1;
|
||||
inst->primaryUser[0] = '\0';
|
||||
inst->checksum = blockChecksum();
|
||||
}
|
||||
|
||||
void SingleApplicationPrivate::startPrimary()
|
||||
{
|
||||
Q_Q(SingleApplication);
|
||||
// Reset the number of connections
|
||||
auto *inst = static_cast <InstancesInfo*>( memory->data() );
|
||||
|
||||
// Successful creation means that no main process exists
|
||||
// So we start a QLocalServer to listen for connections
|
||||
QLocalServer::removeServer( blockServerName );
|
||||
server = new QLocalServer();
|
||||
inst->primary = true;
|
||||
inst->primaryPid = QCoreApplication::applicationPid();
|
||||
qstrncpy( inst->primaryUser, getUsername().toUtf8().data(), sizeof(inst->primaryUser) );
|
||||
inst->checksum = blockChecksum();
|
||||
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
|
||||
// SingleApplication::Mode::User flag on User level or no restrictions
|
||||
if( options & SingleApplication::Mode::User ) {
|
||||
server->setSocketOptions( QLocalServer::UserAccessOption );
|
||||
} else {
|
||||
server->setSocketOptions( QLocalServer::WorldAccessOption );
|
||||
}
|
||||
// Restrict access to the socket according to the
|
||||
// SingleApplication::Mode::User flag on User level or no restrictions
|
||||
if( options & SingleApplication::Mode::User ){
|
||||
server->setSocketOptions( QLocalServer::UserAccessOption );
|
||||
} else {
|
||||
server->setSocketOptions( QLocalServer::WorldAccessOption );
|
||||
}
|
||||
|
||||
server->listen( blockServerName );
|
||||
QObject::connect(
|
||||
server,
|
||||
&QLocalServer::newConnection,
|
||||
this,
|
||||
&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;
|
||||
server->listen( blockServerName );
|
||||
QObject::connect(
|
||||
server,
|
||||
&QLocalServer::newConnection,
|
||||
this,
|
||||
&SingleApplicationPrivate::slotConnectionEstablished
|
||||
);
|
||||
}
|
||||
|
||||
void SingleApplicationPrivate::startSecondary()
|
||||
{
|
||||
auto *inst = static_cast <InstancesInfo*>( memory->data() );
|
||||
|
||||
inst->secondary += 1;
|
||||
inst->checksum = blockChecksum();
|
||||
instanceNumber = inst->secondary;
|
||||
}
|
||||
|
||||
void SingleApplicationPrivate::connectToPrimary( int msecs, ConnectionType connectionType )
|
||||
bool SingleApplicationPrivate::connectToPrimary( int msecs, ConnectionType connectionType )
|
||||
{
|
||||
// Connect to the Local Server of the Primary Instance if not already
|
||||
// connected.
|
||||
if( socket == nullptr ) {
|
||||
socket = new QLocalSocket();
|
||||
}
|
||||
QElapsedTimer time;
|
||||
time.start();
|
||||
|
||||
// If already connected - we are done;
|
||||
if( socket->state() == QLocalSocket::ConnectedState )
|
||||
return;
|
||||
// Connect to the Local Server of the Primary Instance if not already
|
||||
// connected.
|
||||
if( socket == nullptr ){
|
||||
socket = new QLocalSocket();
|
||||
}
|
||||
|
||||
// If not connect
|
||||
if( socket->state() == QLocalSocket::UnconnectedState ||
|
||||
socket->state() == QLocalSocket::ClosingState ) {
|
||||
socket->connectToServer( blockServerName );
|
||||
}
|
||||
if( socket->state() == QLocalSocket::ConnectedState ) return true;
|
||||
|
||||
// Wait for being connected
|
||||
if( socket->state() == QLocalSocket::ConnectingState ) {
|
||||
socket->waitForConnected( msecs );
|
||||
}
|
||||
if( socket->state() != QLocalSocket::ConnectedState ){
|
||||
|
||||
// Initialisation message according to the SingleApplication protocol
|
||||
if( socket->state() == QLocalSocket::ConnectedState ) {
|
||||
// Notify the parent that a new instance had been started;
|
||||
QByteArray initMsg;
|
||||
QDataStream writeStream(&initMsg, QIODevice::WriteOnly);
|
||||
while( true ){
|
||||
randomSleep();
|
||||
|
||||
if( socket->state() != QLocalSocket::ConnectingState )
|
||||
socket->connectToServer( blockServerName );
|
||||
|
||||
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))
|
||||
writeStream.setVersion(QDataStream::Qt_5_6);
|
||||
writeStream.setVersion(QDataStream::Qt_5_6);
|
||||
#endif
|
||||
|
||||
writeStream << blockServerName.toLatin1();
|
||||
writeStream << static_cast<quint8>(connectionType);
|
||||
writeStream << instanceNumber;
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove
|
||||
quint16 checksum =
|
||||
qChecksum(
|
||||
initMsg.constData(),
|
||||
static_cast<quint32>(initMsg.length()));
|
||||
writeStream << blockServerName.toLatin1();
|
||||
writeStream << static_cast<quint8>(connectionType);
|
||||
writeStream << instanceNumber;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
quint16 checksum = qChecksum(QByteArray(initMsg, static_cast<quint32>(initMsg.length())));
|
||||
#else
|
||||
#if TODO_LIST
|
||||
#pragma message("@TODO remove code for QT 6 or later")
|
||||
quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length()));
|
||||
#endif
|
||||
quint16 checksum =
|
||||
qChecksum(
|
||||
QByteArrayView(
|
||||
initMsg.constData(),
|
||||
static_cast<quint32>(initMsg.length())));
|
||||
#endif
|
||||
writeStream << checksum;
|
||||
writeStream << checksum;
|
||||
|
||||
// The header indicates the message length that follows
|
||||
QByteArray header;
|
||||
QDataStream headerStream(&header, QIODevice::WriteOnly);
|
||||
// The header indicates the message length that follows
|
||||
QByteArray header;
|
||||
QDataStream headerStream(&header, QIODevice::WriteOnly);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||
headerStream.setVersion(QDataStream::Qt_5_6);
|
||||
headerStream.setVersion(QDataStream::Qt_5_6);
|
||||
#endif
|
||||
headerStream << static_cast <quint64>( initMsg.length() );
|
||||
headerStream << static_cast <quint64>( initMsg.length() );
|
||||
|
||||
socket->write( header );
|
||||
socket->write( initMsg );
|
||||
socket->flush();
|
||||
socket->waitForBytesWritten( msecs );
|
||||
}
|
||||
socket->write( header );
|
||||
socket->write( initMsg );
|
||||
bool result = socket->waitForBytesWritten( static_cast<int>(msecs - time.elapsed()) );
|
||||
socket->flush();
|
||||
return result;
|
||||
}
|
||||
|
||||
quint16 SingleApplicationPrivate::blockChecksum()
|
||||
quint16 SingleApplicationPrivate::blockChecksum() const
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove
|
||||
return qChecksum(
|
||||
static_cast <const char *>( memory->data() ),
|
||||
offsetof( InstancesInfo, checksum )
|
||||
);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
quint16 checksum = qChecksum(QByteArray(static_cast<const char*>(memory->constData()), offsetof(InstancesInfo, checksum)));
|
||||
#else
|
||||
#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 )));
|
||||
|
||||
quint16 checksum = qChecksum(static_cast<const char*>(memory->constData()), offsetof(InstancesInfo, checksum));
|
||||
#endif
|
||||
return checksum;
|
||||
}
|
||||
|
||||
qint64 SingleApplicationPrivate::primaryPid()
|
||||
qint64 SingleApplicationPrivate::primaryPid() const
|
||||
{
|
||||
qint64 pid;
|
||||
qint64 pid;
|
||||
|
||||
memory->lock();
|
||||
InstancesInfo* inst = static_cast<InstancesInfo*>( memory->data() );
|
||||
pid = inst->primaryPid;
|
||||
memory->unlock();
|
||||
memory->lock();
|
||||
auto *inst = static_cast<InstancesInfo*>( memory->data() );
|
||||
pid = inst->primaryPid;
|
||||
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()
|
||||
{
|
||||
QLocalSocket *nextConnSocket = server->nextPendingConnection();
|
||||
connectionMap.insert(nextConnSocket, ConnectionInfo());
|
||||
QLocalSocket *nextConnSocket = server->nextPendingConnection();
|
||||
connectionMap.insert(nextConnSocket, ConnectionInfo());
|
||||
|
||||
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose,
|
||||
[nextConnSocket, this]() {
|
||||
auto &info = connectionMap[nextConnSocket];
|
||||
Q_EMIT this->slotClientConnectionClosed( nextConnSocket, info.instanceId );
|
||||
}
|
||||
);
|
||||
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose,
|
||||
[nextConnSocket, this](){
|
||||
auto &info = connectionMap[nextConnSocket];
|
||||
Q_EMIT this->slotClientConnectionClosed( nextConnSocket, info.instanceId );
|
||||
}
|
||||
);
|
||||
|
||||
QObject::connect(nextConnSocket, &QLocalSocket::disconnected,
|
||||
[nextConnSocket, this](){
|
||||
connectionMap.remove(nextConnSocket);
|
||||
nextConnSocket->deleteLater();
|
||||
}
|
||||
);
|
||||
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, nextConnSocket, &QLocalSocket::deleteLater);
|
||||
|
||||
QObject::connect(nextConnSocket, &QLocalSocket::readyRead,
|
||||
[nextConnSocket, this]() {
|
||||
auto &info = connectionMap[nextConnSocket];
|
||||
switch(info.stage) {
|
||||
case StageHeader:
|
||||
readInitMessageHeader(nextConnSocket);
|
||||
break;
|
||||
case StageBody:
|
||||
readInitMessageBody(nextConnSocket);
|
||||
break;
|
||||
case StageConnected:
|
||||
Q_EMIT this->slotDataAvailable( nextConnSocket, info.instanceId );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
);
|
||||
QObject::connect(nextConnSocket, &QLocalSocket::destroyed,
|
||||
[nextConnSocket, this](){
|
||||
connectionMap.remove(nextConnSocket);
|
||||
}
|
||||
);
|
||||
|
||||
QObject::connect(nextConnSocket, &QLocalSocket::readyRead,
|
||||
[nextConnSocket, this](){
|
||||
auto &info = connectionMap[nextConnSocket];
|
||||
switch(info.stage){
|
||||
case StageHeader:
|
||||
readInitMessageHeader(nextConnSocket);
|
||||
break;
|
||||
case StageBody:
|
||||
readInitMessageBody(nextConnSocket);
|
||||
break;
|
||||
case StageConnected:
|
||||
Q_EMIT this->slotDataAvailable( nextConnSocket, info.instanceId );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void SingleApplicationPrivate::readInitMessageHeader( QLocalSocket *sock )
|
||||
{
|
||||
if (!connectionMap.contains( sock )) {
|
||||
return;
|
||||
}
|
||||
if (!connectionMap.contains( sock )){
|
||||
return;
|
||||
}
|
||||
|
||||
if( sock->bytesAvailable() < ( qint64 )sizeof( quint64 ) ) {
|
||||
return;
|
||||
}
|
||||
if( sock->bytesAvailable() < ( qint64 )sizeof( quint64 ) ){
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream headerStream( sock );
|
||||
QDataStream headerStream( sock );
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||
headerStream.setVersion( QDataStream::Qt_5_6 );
|
||||
headerStream.setVersion( QDataStream::Qt_5_6 );
|
||||
#endif
|
||||
|
||||
// Read the header to know the message length
|
||||
quint64 msgLen = 0;
|
||||
headerStream >> msgLen;
|
||||
ConnectionInfo &info = connectionMap[sock];
|
||||
info.stage = StageBody;
|
||||
info.msgLen = msgLen;
|
||||
// Read the header to know the message length
|
||||
quint64 msgLen = 0;
|
||||
headerStream >> msgLen;
|
||||
ConnectionInfo &info = connectionMap[sock];
|
||||
info.stage = StageBody;
|
||||
info.msgLen = msgLen;
|
||||
|
||||
if ( sock->bytesAvailable() >= (qint64) msgLen ) {
|
||||
readInitMessageBody( sock );
|
||||
}
|
||||
if ( sock->bytesAvailable() >= (qint64) msgLen ){
|
||||
readInitMessageBody( sock );
|
||||
}
|
||||
}
|
||||
|
||||
void SingleApplicationPrivate::readInitMessageBody( QLocalSocket *sock )
|
||||
{
|
||||
Q_Q(SingleApplication);
|
||||
Q_Q(SingleApplication);
|
||||
|
||||
if (!connectionMap.contains( sock )) {
|
||||
return;
|
||||
}
|
||||
if (!connectionMap.contains( sock )){
|
||||
return;
|
||||
}
|
||||
|
||||
ConnectionInfo &info = connectionMap[sock];
|
||||
if( sock->bytesAvailable() < ( qint64 )info.msgLen ) {
|
||||
return;
|
||||
}
|
||||
ConnectionInfo &info = connectionMap[sock];
|
||||
if( sock->bytesAvailable() < ( qint64 )info.msgLen ){
|
||||
return;
|
||||
}
|
||||
|
||||
// Read the message body
|
||||
QByteArray msgBytes = sock->read(info.msgLen);
|
||||
QDataStream readStream(msgBytes);
|
||||
// Read the message body
|
||||
QByteArray msgBytes = sock->read(info.msgLen);
|
||||
QDataStream readStream(msgBytes);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||
readStream.setVersion( QDataStream::Qt_5_6 );
|
||||
readStream.setVersion( QDataStream::Qt_5_6 );
|
||||
#endif
|
||||
|
||||
// server name
|
||||
QByteArray latin1Name;
|
||||
readStream >> latin1Name;
|
||||
// server name
|
||||
QByteArray latin1Name;
|
||||
readStream >> latin1Name;
|
||||
|
||||
// connection type
|
||||
ConnectionType connectionType = InvalidConnection;
|
||||
quint8 connTypeVal = InvalidConnection;
|
||||
readStream >> connTypeVal;
|
||||
connectionType = static_cast <ConnectionType>( connTypeVal );
|
||||
// connection type
|
||||
ConnectionType connectionType = InvalidConnection;
|
||||
quint8 connTypeVal = InvalidConnection;
|
||||
readStream >> connTypeVal;
|
||||
connectionType = static_cast <ConnectionType>( connTypeVal );
|
||||
|
||||
// instance id
|
||||
quint32 instanceId = 0;
|
||||
readStream >> instanceId;
|
||||
// instance id
|
||||
quint32 instanceId = 0;
|
||||
readStream >> instanceId;
|
||||
|
||||
// checksum
|
||||
quint16 msgChecksum = 0;
|
||||
readStream >> msgChecksum;
|
||||
// checksum
|
||||
quint16 msgChecksum = 0;
|
||||
readStream >> msgChecksum;
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove
|
||||
const quint16 actualChecksum =
|
||||
qChecksum(
|
||||
msgBytes.constData(),
|
||||
static_cast<quint32>( msgBytes.length() - sizeof( quint16 ) ) );
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
const quint16 actualChecksum = qChecksum(QByteArray(msgBytes, static_cast<quint32>(msgBytes.length() - sizeof(quint16))));
|
||||
#else
|
||||
#if TODO_LIST
|
||||
#pragma message("@TODO remove code for QT 6 or later")
|
||||
const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast<quint32>(msgBytes.length() - sizeof(quint16)));
|
||||
#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;
|
||||
|
||||
if( !isValid ) {
|
||||
sock->close();
|
||||
return;
|
||||
}
|
||||
bool isValid = readStream.status() == QDataStream::Ok &&
|
||||
QLatin1String(latin1Name) == blockServerName &&
|
||||
msgChecksum == actualChecksum;
|
||||
|
||||
info.instanceId = instanceId;
|
||||
info.stage = StageConnected;
|
||||
if( !isValid ){
|
||||
sock->close();
|
||||
return;
|
||||
}
|
||||
|
||||
if( connectionType == NewInstance ||
|
||||
( connectionType == SecondaryInstance &&
|
||||
options & SingleApplication::Mode::SecondaryNotification ) )
|
||||
{
|
||||
Q_EMIT q->instanceStarted();
|
||||
}
|
||||
info.instanceId = instanceId;
|
||||
info.stage = StageConnected;
|
||||
|
||||
if (sock->bytesAvailable() > 0) {
|
||||
Q_EMIT this->slotDataAvailable( sock, instanceId );
|
||||
}
|
||||
if( connectionType == NewInstance ||
|
||||
( connectionType == SecondaryInstance &&
|
||||
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 )
|
||||
{
|
||||
Q_Q(SingleApplication);
|
||||
Q_EMIT q->receivedMessage( instanceId, dataSocket->readAll() );
|
||||
Q_Q(SingleApplication);
|
||||
Q_EMIT q->receivedMessage( instanceId, dataSocket->readAll() );
|
||||
}
|
||||
|
||||
void SingleApplicationPrivate::slotClientConnectionClosed( QLocalSocket *closedSocket, quint32 instanceId )
|
||||
{
|
||||
if( closedSocket->bytesAvailable() > 0 )
|
||||
Q_EMIT slotDataAvailable( closedSocket, instanceId );
|
||||
if( closedSocket->bytesAvailable() > 0 )
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) Itay Grudev 2015 - 2016
|
||||
// Copyright (c) Itay Grudev 2015 - 2020
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -38,62 +38,67 @@
|
||||
#include "singleapplication.h"
|
||||
|
||||
struct InstancesInfo {
|
||||
bool primary;
|
||||
quint32 secondary;
|
||||
qint64 primaryPid;
|
||||
quint16 checksum;
|
||||
bool primary;
|
||||
quint32 secondary;
|
||||
qint64 primaryPid;
|
||||
char primaryUser[128];
|
||||
quint16 checksum; // Must be the last field
|
||||
};
|
||||
|
||||
struct ConnectionInfo {
|
||||
explicit ConnectionInfo() :
|
||||
msgLen(0), instanceId(0), stage(0) {}
|
||||
qint64 msgLen;
|
||||
quint32 instanceId;
|
||||
quint8 stage;
|
||||
qint64 msgLen = 0;
|
||||
quint32 instanceId = 0;
|
||||
quint8 stage = 0;
|
||||
};
|
||||
|
||||
class SingleApplicationPrivate : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum ConnectionType : quint8 {
|
||||
InvalidConnection = 0,
|
||||
NewInstance = 1,
|
||||
SecondaryInstance = 2,
|
||||
Reconnect = 3
|
||||
};
|
||||
enum ConnectionStage : quint8 {
|
||||
StageHeader = 0,
|
||||
StageBody = 1,
|
||||
StageConnected = 2,
|
||||
};
|
||||
Q_DECLARE_PUBLIC(SingleApplication)
|
||||
|
||||
SingleApplicationPrivate( SingleApplication *q_ptr );
|
||||
~SingleApplicationPrivate();
|
||||
|
||||
void genBlockServerName();
|
||||
void initializeMemoryBlock();
|
||||
void startPrimary();
|
||||
void startSecondary();
|
||||
void connectToPrimary(int msecs, ConnectionType connectionType );
|
||||
quint16 blockChecksum();
|
||||
qint64 primaryPid();
|
||||
void readInitMessageHeader(QLocalSocket *socket);
|
||||
void readInitMessageBody(QLocalSocket *socket);
|
||||
|
||||
SingleApplication *q_ptr;
|
||||
QSharedMemory *memory;
|
||||
QLocalSocket *socket;
|
||||
QLocalServer *server;
|
||||
quint32 instanceNumber;
|
||||
QString blockServerName;
|
||||
SingleApplication::Options options;
|
||||
QMap<QLocalSocket*, ConnectionInfo> connectionMap;
|
||||
|
||||
public Q_SLOTS:
|
||||
void slotConnectionEstablished();
|
||||
void slotDataAvailable( QLocalSocket*, quint32 );
|
||||
void slotClientConnectionClosed( QLocalSocket*, quint32 );
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum ConnectionType : quint8 {
|
||||
InvalidConnection = 0,
|
||||
NewInstance = 1,
|
||||
SecondaryInstance = 2,
|
||||
Reconnect = 3
|
||||
};
|
||||
enum ConnectionStage : quint8 {
|
||||
StageHeader = 0,
|
||||
StageBody = 1,
|
||||
StageConnected = 2,
|
||||
};
|
||||
Q_DECLARE_PUBLIC(SingleApplication)
|
||||
|
||||
SingleApplicationPrivate( SingleApplication *q_ptr );
|
||||
~SingleApplicationPrivate() override;
|
||||
|
||||
static QString getUsername();
|
||||
void genBlockServerName();
|
||||
void initializeMemoryBlock() const;
|
||||
void startPrimary();
|
||||
void startSecondary();
|
||||
bool connectToPrimary( int msecs, ConnectionType connectionType );
|
||||
quint16 blockChecksum() const;
|
||||
qint64 primaryPid() const;
|
||||
QString primaryUser() const;
|
||||
void readInitMessageHeader(QLocalSocket *socket);
|
||||
void readInitMessageBody(QLocalSocket *socket);
|
||||
static void randomSleep();
|
||||
void addAppData(const QString &data);
|
||||
QStringList appData() const;
|
||||
|
||||
SingleApplication *q_ptr;
|
||||
QSharedMemory *memory;
|
||||
QLocalSocket *socket;
|
||||
QLocalServer *server;
|
||||
quint32 instanceNumber;
|
||||
QString blockServerName;
|
||||
SingleApplication::Options options;
|
||||
QMap<QLocalSocket*, ConnectionInfo> connectionMap;
|
||||
QStringList appDataList;
|
||||
|
||||
public Q_SLOTS:
|
||||
void slotConnectionEstablished();
|
||||
void slotDataAvailable( QLocalSocket*, quint32 );
|
||||
void slotClientConnectionClosed( QLocalSocket*, quint32 );
|
||||
};
|
||||
|
||||
#endif // SINGLEAPPLICATION_P_H
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "org.qelectrotech.QElectroTech",
|
||||
"runtime": "org.kde.Platform",
|
||||
"runtime-version": "5.14",
|
||||
"runtime-version": "5.15",
|
||||
"sdk": "org.kde.Sdk",
|
||||
"command": "qelectrotech",
|
||||
"rename-desktop-file": "qelectrotech.desktop",
|
||||
|
||||
@@ -21,6 +21,6 @@ Include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
pugixml
|
||||
GIT_REPOSITORY https://github.com/zeux/pugixml.git
|
||||
GIT_TAG v1.11.1)
|
||||
GIT_TAG v1.11.4)
|
||||
|
||||
FetchContent_MakeAvailable(pugixml)
|
||||
|
||||
@@ -26,6 +26,6 @@ Include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
SingleApplication
|
||||
GIT_REPOSITORY https://github.com/itay-grudev/SingleApplication.git
|
||||
GIT_TAG v3.1.5)
|
||||
GIT_TAG v3.2.0)
|
||||
|
||||
FetchContent_MakeAvailable(SingleApplication)
|
||||
|
||||
@@ -52,6 +52,8 @@ set(QET_RES_FILES
|
||||
${QET_DIR}/sources/editor/ui/lineeditor.ui
|
||||
${QET_DIR}/sources/editor/ui/polygoneditor.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/factory/ui/addtabledialog.ui
|
||||
${QET_DIR}/sources/NameList/ui/namelistdialog.ui
|
||||
@@ -260,12 +262,8 @@ set(QET_SRC_FILES
|
||||
${QET_DIR}/sources/editor/elementscene.h
|
||||
${QET_DIR}/sources/editor/elementview.cpp
|
||||
${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.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.h
|
||||
@@ -320,8 +318,12 @@ set(QET_SRC_FILES
|
||||
${QET_DIR}/sources/editor/ui/polygoneditor.h
|
||||
${QET_DIR}/sources/editor/ui/rectangleeditor.cpp
|
||||
${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.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.h
|
||||
@@ -371,6 +373,8 @@ set(QET_SRC_FILES
|
||||
${QET_DIR}/sources/print/projectprintwindow.cpp
|
||||
${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.h
|
||||
${QET_DIR}/sources/properties/reportproperties.cpp
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 309 KiB |
+712
-583
File diff suppressed because it is too large
Load Diff
+720
-591
File diff suppressed because it is too large
Load Diff
+712
-583
File diff suppressed because it is too large
Load Diff
+723
-592
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+723
-595
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+1006
-874
File diff suppressed because it is too large
Load Diff
+719
-590
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+721
-590
File diff suppressed because it is too large
Load Diff
+714
-585
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+708
-579
File diff suppressed because it is too large
Load Diff
+711
-582
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+718
-587
File diff suppressed because it is too large
Load Diff
+723
-594
File diff suppressed because it is too large
Load Diff
+712
-583
File diff suppressed because it is too large
Load Diff
+708
-579
File diff suppressed because it is too large
Load Diff
+712
-583
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+722
-591
File diff suppressed because it is too large
Load Diff
+720
-591
File diff suppressed because it is too large
Load Diff
+720
-588
File diff suppressed because it is too large
Load Diff
+714
-585
File diff suppressed because it is too large
Load Diff
+712
-583
File diff suppressed because it is too large
Load Diff
+712
-583
File diff suppressed because it is too large
Load Diff
+708
-579
File diff suppressed because it is too large
Load Diff
+708
-579
File diff suppressed because it is too large
Load Diff
+708
-579
File diff suppressed because it is too large
Load Diff
+712
-583
File diff suppressed because it is too large
Load Diff
+708
-579
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
#include "elementscollectionwidget.h"
|
||||
|
||||
#include "../editor/qetelementeditor.h"
|
||||
#include "../editor/ui/qetelementeditor.h"
|
||||
#include "../elementscategoryeditor.h"
|
||||
#include "../newelementwizard.h"
|
||||
#include "../qetapp.h"
|
||||
@@ -38,6 +38,9 @@
|
||||
#include <QUrl>
|
||||
#include <QVBoxLayout>
|
||||
#include <QtGlobal>
|
||||
#include <QProgressBar>
|
||||
#include <QStatusBar>
|
||||
#include <QLineEdit>
|
||||
|
||||
/**
|
||||
@brief ElementsCollectionWidget::ElementsCollectionWidget
|
||||
|
||||
@@ -368,14 +368,6 @@ void ConductorProperties::fromXml(QDomElement &e)
|
||||
"vertical-alignment",
|
||||
"AlignRight"
|
||||
).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,11 +222,6 @@ void DiagramEventAddElement::addElement()
|
||||
element -> setPos(m_element->pos());
|
||||
element -> setRotation(m_element -> rotation());
|
||||
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()));
|
||||
new AddGraphicsObjectCommand(element, m_diagram, m_element -> pos(), undo_object);
|
||||
|
||||
@@ -282,13 +282,17 @@ ChangeNamesCommand::~ChangeNamesCommand()
|
||||
/// Annule le changement
|
||||
void ChangeNamesCommand::undo()
|
||||
{
|
||||
m_scene -> setNames(names_before);
|
||||
auto data = m_scene->elementData();
|
||||
data.m_names_list = names_before;
|
||||
m_scene->setElementData(data);
|
||||
}
|
||||
|
||||
/// Refait le changement
|
||||
void ChangeNamesCommand::redo()
|
||||
{
|
||||
m_scene -> setNames(names_after);
|
||||
auto data = m_scene->elementData();
|
||||
data.m_names_list = names_after;
|
||||
m_scene->setElementData(data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -453,13 +457,17 @@ ChangeInformationsCommand::~ChangeInformationsCommand()
|
||||
/// Annule le changement d'autorisation pour les connexions internes
|
||||
void ChangeInformationsCommand::undo()
|
||||
{
|
||||
m_scene -> setInformations(old_informations_);
|
||||
auto data = m_scene->elementData();
|
||||
data.m_drawing_information = old_informations_;
|
||||
m_scene->setElementData(data);
|
||||
}
|
||||
|
||||
/// Refait le changement d'autorisation pour les connexions internes
|
||||
void ChangeInformationsCommand::redo()
|
||||
{
|
||||
m_scene -> setInformations(new_informations_);
|
||||
auto data = m_scene->elementData();
|
||||
data.m_drawing_information = new_informations_;
|
||||
m_scene->setElementData(data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -572,45 +580,32 @@ void ScalePartsCommand::adjustText()
|
||||
setText(QObject::tr("redimensionnement de %1 primitives", "undo caption -- %1 always > 1").arg(scaled_primitives_.count()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ChangePropertiesCommand::ChangePropertiesCommand
|
||||
Change the properties of the drawed element
|
||||
@param scene : scene to belong the property
|
||||
@param type : new type of element.
|
||||
@param info
|
||||
@param elmt_info : new info about type.
|
||||
@param parent : parent undo
|
||||
*/
|
||||
ChangePropertiesCommand::ChangePropertiesCommand(
|
||||
ElementScene *scene,
|
||||
const QString& type,
|
||||
const DiagramContext& info,
|
||||
const DiagramContext& elmt_info,
|
||||
QUndoCommand *parent) :
|
||||
ElementEditionCommand(scene, nullptr, parent)
|
||||
* @brief changeElementDataCommand::changeElementDataCommand
|
||||
* Change the properties of the drawed element
|
||||
* @param scene : scene to belong the property
|
||||
* @param old_data : old data
|
||||
* @param new_data : new data
|
||||
* @param parent : parent undo command
|
||||
*/
|
||||
changeElementDataCommand::changeElementDataCommand(ElementScene *scene,
|
||||
ElementData old_data,
|
||||
ElementData new_data,
|
||||
QUndoCommand *parent) :
|
||||
ElementEditionCommand(scene, nullptr, parent),
|
||||
m_old(old_data),
|
||||
m_new(new_data)
|
||||
{
|
||||
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"));
|
||||
setText(QObject::tr("Modifier les propriétées de l'élément"));
|
||||
}
|
||||
|
||||
ChangePropertiesCommand::~ChangePropertiesCommand()
|
||||
{}
|
||||
|
||||
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::undo() {
|
||||
m_scene->setElementData(m_old);
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
void ChangePropertiesCommand::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());
|
||||
void changeElementDataCommand::redo() {
|
||||
m_scene->setElementData(m_new);
|
||||
QUndoCommand::redo();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -262,23 +262,21 @@ class ScalePartsCommand : public ElementEditionCommand {
|
||||
bool first_redo;
|
||||
};
|
||||
|
||||
class ChangePropertiesCommand : public ElementEditionCommand {
|
||||
class changeElementDataCommand : public ElementEditionCommand
|
||||
{
|
||||
public:
|
||||
ChangePropertiesCommand (
|
||||
ElementScene *scene,
|
||||
const QString& type,
|
||||
const DiagramContext& info,
|
||||
const DiagramContext& elmt_info,
|
||||
QUndoCommand *parent=nullptr);
|
||||
~ChangePropertiesCommand () override;
|
||||
changeElementDataCommand(ElementScene *scene,
|
||||
ElementData old_data,
|
||||
ElementData new_data,
|
||||
QUndoCommand *parent = nullptr);
|
||||
~changeElementDataCommand() override {}
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
private:
|
||||
QList <QString> m_type;
|
||||
QList <DiagramContext> m_kind_info;
|
||||
QList < DiagramContext> m_elmt_info;
|
||||
ElementData m_old,
|
||||
m_new;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "elementitemeditor.h"
|
||||
#include "qetelementeditor.h"
|
||||
#include "ui/qetelementeditor.h"
|
||||
#include "editorcommands.h"
|
||||
|
||||
/**
|
||||
|
||||
+55
-105
@@ -33,7 +33,7 @@
|
||||
#include "graphicspart/partrectangle.h"
|
||||
#include "graphicspart/partterminal.h"
|
||||
#include "graphicspart/parttext.h"
|
||||
#include "qetelementeditor.h"
|
||||
#include "ui/qetelementeditor.h"
|
||||
#include "ui/elementpropertieseditorwidget.h"
|
||||
|
||||
#include <QKeyEvent>
|
||||
@@ -51,7 +51,6 @@
|
||||
*/
|
||||
ElementScene::ElementScene(QETElementEditor *editor, QObject *parent) :
|
||||
QGraphicsScene(parent),
|
||||
m_elmt_type("simple"),
|
||||
m_qgi_manager(this),
|
||||
m_element_editor(editor)
|
||||
{
|
||||
@@ -71,7 +70,25 @@ ElementScene::ElementScene(QETElementEditor *editor, QObject *parent) :
|
||||
connect(&m_undo_stack, SIGNAL(indexChanged(int)),
|
||||
this, SLOT(managePrimitivesGroups()));
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -437,7 +454,7 @@ const QDomDocument ElementScene::toXml(bool all_parts)
|
||||
-(qRound(size.y() - (ymargin/2)))));
|
||||
|
||||
root.setAttribute("version", QET::version);
|
||||
root.setAttribute("link_type", m_elmt_type);
|
||||
root.setAttribute("link_type", m_element_data.typeToString(m_element_data.m_type));
|
||||
|
||||
//Uuid used to compare two elements
|
||||
QDomElement uuid = xml_document.createElement("uuid");
|
||||
@@ -445,29 +462,29 @@ const QDomDocument ElementScene::toXml(bool all_parts)
|
||||
root.appendChild(uuid);
|
||||
|
||||
//names of element
|
||||
root.appendChild(m_names_list.toXml(xml_document));
|
||||
root.appendChild(m_element_data.m_names_list.toXml(xml_document));
|
||||
|
||||
if (m_elmt_type == "slave" || m_elmt_type == "master")
|
||||
auto type_ = m_element_data.m_type;
|
||||
if (type_ == ElementData::Slave ||
|
||||
type_ == ElementData::Master ||
|
||||
type_ == ElementData::Terminale)
|
||||
{
|
||||
QDomElement kindInfo = xml_document.createElement("kindInformations");
|
||||
m_elmt_kindInfo.toXml(kindInfo, "kindInformation");
|
||||
root.appendChild(kindInfo);
|
||||
root.appendChild(m_element_data.kindInfoToXml(xml_document));
|
||||
}
|
||||
|
||||
if(
|
||||
m_elmt_type == "simple"
|
||||
|| m_elmt_type == "master"
|
||||
|| m_elmt_type == "terminal")
|
||||
if(type_ == ElementData::Simple ||
|
||||
type_ == ElementData::Master ||
|
||||
type_ == ElementData::Terminale)
|
||||
{
|
||||
QDomElement element_info = xml_document.createElement("elementInformations");
|
||||
m_elmt_information.toXml(element_info, "elementInformation");
|
||||
m_element_data.m_informations.toXml(element_info, "elementInformation");
|
||||
root.appendChild(element_info);
|
||||
}
|
||||
|
||||
//complementary information about the element
|
||||
QDomElement informations_element = xml_document.createElement("informations");
|
||||
root.appendChild(informations_element);
|
||||
informations_element.appendChild(xml_document.createTextNode(informations()));
|
||||
informations_element.appendChild(xml_document.createTextNode(m_element_data.m_drawing_information));
|
||||
|
||||
QDomElement description = xml_document.createElement("description");
|
||||
|
||||
@@ -545,9 +562,16 @@ void ElementScene::fromXml(
|
||||
{
|
||||
bool state = true;
|
||||
|
||||
//Consider the informations of the element
|
||||
if (consider_informations) {
|
||||
state = applyInformations(xml_document);
|
||||
//Consider the informations of the element
|
||||
if (consider_informations)
|
||||
{
|
||||
// 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)
|
||||
@@ -699,19 +723,6 @@ QETElementEditor* ElementScene::editor() const
|
||||
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
|
||||
Select the item in content,
|
||||
@@ -833,7 +844,7 @@ void ElementScene::slot_editAuthorInformations()
|
||||
// ajoute un QTextEdit au dialogue
|
||||
QTextEdit *text_field = new QTextEdit();
|
||||
text_field -> setAcceptRichText(false);
|
||||
text_field -> setPlainText(informations());
|
||||
text_field -> setPlainText(m_element_data.m_drawing_information);
|
||||
text_field -> setReadOnly(is_read_only);
|
||||
dialog_layout -> addWidget(text_field);
|
||||
|
||||
@@ -851,10 +862,10 @@ void ElementScene::slot_editAuthorInformations()
|
||||
if (dialog_author.exec() == QDialog::Accepted && !is_read_only)
|
||||
{
|
||||
QString new_infos = text_field -> toPlainText().remove(QChar(13)); // CR-less text
|
||||
if (new_infos != informations())
|
||||
if (new_infos != m_element_data.m_drawing_information)
|
||||
{
|
||||
undoStack().push(new ChangeInformationsCommand(
|
||||
this, informations(), new_infos));
|
||||
this, m_element_data.m_drawing_information, new_infos));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -865,20 +876,15 @@ void ElementScene::slot_editAuthorInformations()
|
||||
*/
|
||||
void ElementScene::slot_editProperties()
|
||||
{
|
||||
QString type = m_elmt_type;
|
||||
DiagramContext kind_info = m_elmt_kindInfo;
|
||||
DiagramContext elmt_info = m_elmt_information;
|
||||
|
||||
ElementPropertiesEditorWidget epew(type, kind_info, elmt_info);
|
||||
ElementPropertiesEditorWidget epew(m_element_data);
|
||||
epew.exec();
|
||||
|
||||
if (type != m_elmt_type ||
|
||||
kind_info != m_elmt_kindInfo ||
|
||||
elmt_info != m_elmt_information)
|
||||
undoStack().push(new ChangePropertiesCommand(this,
|
||||
type,
|
||||
kind_info,
|
||||
elmt_info));
|
||||
if (m_element_data != epew.editedData())
|
||||
{
|
||||
undoStack().push(new changeElementDataCommand(this,
|
||||
m_element_data,
|
||||
epew.editedData()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -898,15 +904,15 @@ void ElementScene::slot_editNames()
|
||||
dialog_.setInformationText(tr("Vous pouvez spécifier le nom de l'élément dans plusieurs langues."));
|
||||
|
||||
NameListWidget *nlw_ = dialog_.namelistWidget();
|
||||
nlw_->setNames(m_names_list);
|
||||
nlw_->setNames(m_element_data.m_names_list);
|
||||
nlw_->setReadOnly(is_read_only);
|
||||
|
||||
if (dialog_.exec() == QDialog::Accepted && !is_read_only && !nlw_->isEmpty())
|
||||
{
|
||||
NamesList new_names = nlw_->names();
|
||||
if (new_names != m_names_list) {
|
||||
if (new_names != m_element_data. m_names_list) {
|
||||
undoStack().push(new ChangeNamesCommand(this,
|
||||
m_names_list,
|
||||
m_element_data.m_names_list,
|
||||
new_names));
|
||||
}
|
||||
}
|
||||
@@ -1087,62 +1093,6 @@ QRectF ElementScene::elementContentBoundingRect(
|
||||
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
|
||||
Create and load the content describe in the xml document.
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "../diagramcontext.h"
|
||||
#include "../qgimanager.h"
|
||||
#include "elementcontent.h"
|
||||
#include "../properties/elementdata.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QtXml>
|
||||
@@ -65,11 +66,7 @@ class ElementScene : public QGraphicsScene
|
||||
|
||||
// attributes
|
||||
private:
|
||||
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
|
||||
ElementData m_element_data; ///ElementData. Actualy in transition with old data storage
|
||||
QGIManager m_qgi_manager;
|
||||
QUndoStack m_undo_stack;
|
||||
|
||||
@@ -90,21 +87,20 @@ class ElementScene : public QGraphicsScene
|
||||
|
||||
// methods
|
||||
public:
|
||||
ElementData elementData();
|
||||
void setElementData(ElementData data);
|
||||
|
||||
void setEventInterface (ESEventInterface *event_interface);
|
||||
void clearEventInterface();
|
||||
|
||||
void setBehavior (ElementScene::Behavior);
|
||||
ElementScene::Behavior behavior() const;
|
||||
|
||||
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 yGrid() const;
|
||||
virtual void setGrid(int, int);
|
||||
|
||||
virtual const QDomDocument toXml(bool = true);
|
||||
virtual QRectF boundingRectFromXml(const QDomDocument &);
|
||||
virtual void fromXml(const QDomDocument &,
|
||||
@@ -128,7 +124,6 @@ class ElementScene : public QGraphicsScene
|
||||
void cut();
|
||||
void copy();
|
||||
QETElementEditor* editor() const;
|
||||
void setElementInfo(const DiagramContext& dc);
|
||||
|
||||
protected:
|
||||
void mouseMoveEvent (QGraphicsSceneMouseEvent *) override;
|
||||
@@ -137,12 +132,10 @@ class ElementScene : public QGraphicsScene
|
||||
void mouseDoubleClickEvent (QGraphicsSceneMouseEvent *event) override;
|
||||
void keyPressEvent (QKeyEvent *event) override;
|
||||
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
|
||||
|
||||
void drawForeground(QPainter *, const QRectF &) override;
|
||||
|
||||
private:
|
||||
QRectF elementContentBoundingRect(const ElementContent &) const;
|
||||
bool applyInformations(const QDomDocument &);
|
||||
ElementContent loadContent(const QDomDocument &);
|
||||
ElementContent addContent(const ElementContent &);
|
||||
ElementContent addContentAtPos(const ElementContent &, const QPointF &);
|
||||
@@ -180,39 +173,4 @@ class ElementScene : public QGraphicsScene
|
||||
|
||||
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
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "../qetapp.h"
|
||||
#include "UndoCommand/pastepartscommand.h"
|
||||
#include "qetelementeditor.h"
|
||||
#include "ui/qetelementeditor.h"
|
||||
/**
|
||||
Constructeur
|
||||
@param scene ElementScene visualisee par cette ElementView
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "../editorcommands.h"
|
||||
#include "../elementscene.h"
|
||||
#include "../graphicspart/partline.h"
|
||||
#include "../qetelementeditor.h"
|
||||
#include "../ui/qetelementeditor.h"
|
||||
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QObject>
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
#include "eseventinterface.h"
|
||||
|
||||
#include "../elementscene.h"
|
||||
#include "../qetelementeditor.h"
|
||||
#include "../ui/qetelementeditor.h"
|
||||
#include "../elementview.h"
|
||||
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
|
||||
@@ -40,7 +41,7 @@ ESEventInterface::ESEventInterface(ElementScene *scene) :
|
||||
void ESEventInterface::init()
|
||||
{
|
||||
m_scene->setBehavior(ElementScene::Behavior::AddPart);
|
||||
m_editor->slot_setNoDragToView();
|
||||
m_editor->elementView()->setDragMode(QGraphicsView::NoDrag);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,31 +54,31 @@ ESEventInterface::~ESEventInterface()
|
||||
delete m_help_verti;
|
||||
|
||||
m_scene->setBehavior(ElementScene::Behavior::Normal);
|
||||
m_editor->slot_setRubberBandToView();
|
||||
m_editor->elementView()->setDragMode(QGraphicsView::RubberBandDrag);
|
||||
}
|
||||
|
||||
bool ESEventInterface::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {
|
||||
Q_UNUSED (event);
|
||||
Q_UNUSED (event)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ESEventInterface::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||
Q_UNUSED (event);
|
||||
Q_UNUSED (event)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ESEventInterface::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
||||
Q_UNUSED (event);
|
||||
Q_UNUSED (event)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ESEventInterface::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
|
||||
Q_UNUSED (event);
|
||||
Q_UNUSED (event)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ESEventInterface::wheelEvent(QGraphicsSceneWheelEvent *event) {
|
||||
Q_UNUSED (event);
|
||||
Q_UNUSED (event)
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -97,7 +98,7 @@ bool ESEventInterface::keyPressEvent(QKeyEvent *event) {
|
||||
}
|
||||
|
||||
bool ESEventInterface::KeyReleaseEvent(QKeyEvent *event) {
|
||||
Q_UNUSED (event);
|
||||
Q_UNUSED (event)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1264,24 +1264,6 @@ void CustomElementGraphicPart::drawShadowShape(QPainter *painter)
|
||||
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
|
||||
Reimplemented from QGraphicsObject.
|
||||
|
||||
@@ -309,8 +309,6 @@ class CustomElementGraphicPart : public QGraphicsObject, public CustomElementPar
|
||||
void applyStylesToQPainter(QPainter &) const;
|
||||
void drawShadowShape (QPainter *painter);
|
||||
|
||||
QVariant itemChange(GraphicsItemChange change,
|
||||
const QVariant &value) override;
|
||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
*/
|
||||
#include "customelementpart.h"
|
||||
|
||||
#include "../qetelementeditor.h"
|
||||
#include "../ui/qetelementeditor.h"
|
||||
#include "../elementscene.h"
|
||||
|
||||
/// @return le QETElementEditor auquel cet editeur appartient
|
||||
QETElementEditor *CustomElementPart::elementEditor() const
|
||||
|
||||
@@ -318,7 +318,7 @@ void PartDynamicTextField::setText(const QString &text) {
|
||||
void PartDynamicTextField::setInfoName(const QString &info_name) {
|
||||
m_info_name = info_name;
|
||||
if(m_text_from == DynamicElementTextItem::ElementInfo && elementScene())
|
||||
setPlainText(elementScene() -> elementInformation().value(m_info_name).toString());
|
||||
setPlainText(elementScene()->elementData().m_informations.value(m_info_name).toString());
|
||||
emit infoNameChanged(m_info_name);
|
||||
}
|
||||
|
||||
@@ -338,7 +338,7 @@ QString PartDynamicTextField::infoName() const{
|
||||
void PartDynamicTextField::setCompositeText(const QString &text) {
|
||||
m_composite_text = text;
|
||||
if(m_text_from == DynamicElementTextItem::CompositeText && elementScene())
|
||||
setPlainText(autonum::AssignVariables::replaceVariable(m_composite_text, elementScene() -> elementInformation()));
|
||||
setPlainText(autonum::AssignVariables::replaceVariable(m_composite_text, elementScene()->elementData().m_informations));
|
||||
emit compositeTextChanged(m_composite_text);
|
||||
}
|
||||
|
||||
@@ -551,10 +551,10 @@ void PartDynamicTextField::elementInfoChanged()
|
||||
return;
|
||||
|
||||
if(m_text_from == DynamicElementTextItem::ElementInfo)
|
||||
setPlainText(elementScene() -> elementInformation().value(m_info_name).toString());
|
||||
setPlainText(elementScene()->elementData().m_informations.value(m_info_name).toString());
|
||||
else if (m_text_from == DynamicElementTextItem::CompositeText && elementScene())
|
||||
setPlainText(autonum::AssignVariables::replaceVariable(
|
||||
m_composite_text, elementScene() -> elementInformation()));
|
||||
m_composite_text, elementScene()->elementData().m_informations));
|
||||
}
|
||||
|
||||
void PartDynamicTextField::prepareAlignment()
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "../../QetGraphicsItemModeler/qetgraphicshandlerutility.h"
|
||||
#include "../../qeticons.h"
|
||||
#include "../elementscene.h"
|
||||
#include "../qetelementeditor.h"
|
||||
#include "../ui/qetelementeditor.h"
|
||||
|
||||
/**
|
||||
@brief PartPolygon::PartPolygon
|
||||
|
||||
@@ -72,7 +72,7 @@ void PartTerminal::paint(
|
||||
const QStyleOptionGraphicsItem *options,
|
||||
QWidget *widget)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(widget)
|
||||
painter -> save();
|
||||
|
||||
// annulation des renderhints
|
||||
@@ -98,7 +98,7 @@ void PartTerminal::paint(
|
||||
// dessin de la borne en rouge
|
||||
t.setColor(isSelected() ? Terminal::neutralColor : Qt::red);
|
||||
painter -> setPen(t);
|
||||
painter -> drawLine(QPointF(0.0, 0.0), d -> second_point);
|
||||
painter -> drawLine(QPointF(0.0, 0.0), d -> m_second_point);
|
||||
|
||||
// dessin du point d'amarrage au conducteur en bleu
|
||||
t.setColor(isSelected() ? Qt::red : Terminal::neutralColor);
|
||||
@@ -118,7 +118,7 @@ void PartTerminal::paint(
|
||||
QPainterPath PartTerminal::shape() const
|
||||
{
|
||||
QPainterPath shape;
|
||||
shape.lineTo(d -> second_point);
|
||||
shape.lineTo(d -> m_second_point);
|
||||
|
||||
QPainterPathStroker pps;
|
||||
pps.setWidth(1);
|
||||
@@ -132,7 +132,7 @@ QPainterPath PartTerminal::shape() const
|
||||
*/
|
||||
QRectF PartTerminal::boundingRect() const
|
||||
{
|
||||
QRectF br(QPointF(0, 0), d -> second_point);
|
||||
QRectF br(QPointF(0, 0), d -> m_second_point);
|
||||
br = br.normalized();
|
||||
|
||||
qreal adjust = (SHADOWS_HEIGHT + 1) / 2;
|
||||
@@ -161,6 +161,20 @@ void PartTerminal::setName(QString& name) {
|
||||
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()
|
||||
{
|
||||
d -> m_uuid = QUuid::createUuid();
|
||||
@@ -174,10 +188,10 @@ void PartTerminal::updateSecondPoint()
|
||||
{
|
||||
qreal ts = 4.0; // terminal size
|
||||
switch(d -> m_orientation) {
|
||||
case Qet::North: d -> second_point = QPointF(0.0, ts); break;
|
||||
case Qet::East : d -> second_point = QPointF(-ts, 0.0); break;
|
||||
case Qet::South: d -> second_point = QPointF(0.0, -ts); break;
|
||||
case Qet::West : d -> second_point = QPointF(ts, 0.0); break;
|
||||
case Qet::North: d -> m_second_point = QPointF(0.0, ts); break;
|
||||
case Qet::East : d -> m_second_point = QPointF(-ts, 0.0); break;
|
||||
case Qet::South: d -> m_second_point = QPointF(0.0, -ts); break;
|
||||
case Qet::West : d -> m_second_point = QPointF(ts, 0.0); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,10 +27,13 @@
|
||||
This class represents a terminal which may be used to compose the drawing of
|
||||
an electrical element within the element editor.
|
||||
*/
|
||||
class PartTerminal : public CustomElementGraphicPart {
|
||||
class PartTerminal : public CustomElementGraphicPart
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(Qet::Orientation orientation READ orientation WRITE setOrientation)
|
||||
Q_PROPERTY(QString name READ name WRITE setName)
|
||||
Q_PROPERTY(TerminalData::Type terminal_type READ terminalType WRITE setTerminalType)
|
||||
|
||||
public:
|
||||
// constructors, destructor
|
||||
@@ -42,6 +45,7 @@ class PartTerminal : public CustomElementGraphicPart {
|
||||
signals:
|
||||
void orientationChanged();
|
||||
void nameChanged();
|
||||
void terminalTypeChanged();
|
||||
|
||||
// methods
|
||||
public:
|
||||
@@ -51,7 +55,6 @@ class PartTerminal : public CustomElementGraphicPart {
|
||||
@return the QGraphicsItem type
|
||||
*/
|
||||
int type() const override { return Type; }
|
||||
QString name() const override { return d -> m_name; }
|
||||
QString xmlName() const override { return(QString("terminal")); }
|
||||
void fromXml(const QDomElement &) override;
|
||||
const QDomElement toXml(QDomDocument &) const override;
|
||||
@@ -71,7 +74,12 @@ class PartTerminal : public CustomElementGraphicPart {
|
||||
Qet::Orientation orientation() const {return d -> m_orientation;}
|
||||
void setOrientation(Qet::Orientation ori);
|
||||
|
||||
QString name() const override { return d -> m_name; }
|
||||
void setName(QString& name);
|
||||
|
||||
TerminalData::Type terminalType() const {return d->m_type;}
|
||||
void setTerminalType(TerminalData::Type type);
|
||||
|
||||
void setNewUuid();
|
||||
|
||||
private:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
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
|
||||
@@ -1,322 +0,0 @@
|
||||
/*
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
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
|
||||
@@ -24,7 +24,8 @@
|
||||
#include "../../qetinformation.h"
|
||||
#include "../../ui/alignmenttextdialog.h"
|
||||
#include "../../ui/compositetexteditdialog.h"
|
||||
#include "../qetelementeditor.h"
|
||||
#include "../ui/qetelementeditor.h"
|
||||
#include "../elementscene.h"
|
||||
#include "ui_dynamictextfieldeditor.h"
|
||||
|
||||
#include <QColorDialog>
|
||||
@@ -224,9 +225,9 @@ void DynamicTextFieldEditor::fillInfoComboBox()
|
||||
ui -> m_elmt_info_cb -> clear();
|
||||
|
||||
QStringList strl;
|
||||
QString type = elementEditor() -> elementScene() -> elementType();
|
||||
auto type = elementEditor()->elementScene()->elementData().m_type;
|
||||
|
||||
if(type.contains("report")) {
|
||||
if(type & ElementData::AllReport) {
|
||||
strl = QETInformation::folioReportInfoKeys();
|
||||
}
|
||||
else {
|
||||
@@ -332,8 +333,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);
|
||||
undo->setText(tr("Modifier l'information d'un texte"));
|
||||
undoStack().push(undo);
|
||||
m_parts[i] -> setPlainText(
|
||||
elementEditor() -> elementScene() -> elementInformation().value(m_parts[i] -> infoName()).toString());
|
||||
m_parts[i]->setPlainText(
|
||||
elementEditor()->elementScene()->elementData().m_informations.value(m_parts[i] -> infoName()).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
Copyright 2006-2021 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "../../qetapp.h"
|
||||
#include "../../qetinformation.h"
|
||||
#include "ui_elementpropertieseditorwidget.h"
|
||||
#include "../../qetinformation.h"
|
||||
|
||||
#include <QItemDelegate>
|
||||
|
||||
@@ -37,7 +38,7 @@ class EditorDelegate : public QItemDelegate
|
||||
|
||||
QWidget* createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
const QModelIndex &index) const override
|
||||
{
|
||||
if(index.column() == 1)
|
||||
{
|
||||
@@ -50,23 +51,14 @@ class EditorDelegate : public QItemDelegate
|
||||
};
|
||||
|
||||
/**
|
||||
@brief ElementPropertiesEditorWidget::ElementPropertiesEditorWidget
|
||||
Default constructor
|
||||
@param basic_type : QString of the drawed element
|
||||
@param kind_info : DiagramContext to store kindInfo of drawed element
|
||||
@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) :
|
||||
* @brief ElementPropertiesEditorWidget::ElementPropertiesEditorWidget
|
||||
* @param data
|
||||
* @param parent
|
||||
*/
|
||||
ElementPropertiesEditorWidget::ElementPropertiesEditorWidget(ElementData data, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::ElementPropertiesEditorWidget),
|
||||
m_basic_type(basic_type),
|
||||
m_kind_info (kind_info),
|
||||
m_elmt_info (elmt_info)
|
||||
m_data(data)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setUpInterface();
|
||||
@@ -90,22 +82,29 @@ void ElementPropertiesEditorWidget::upDateInterface()
|
||||
{
|
||||
ui->m_base_type_cb->setCurrentIndex(
|
||||
ui->m_base_type_cb->findData(
|
||||
QVariant(m_basic_type)));
|
||||
m_data.m_type));
|
||||
|
||||
if (m_basic_type == "slave")
|
||||
if (m_data.m_type == ElementData::Slave)
|
||||
{
|
||||
ui->m_state_cb->setCurrentIndex(
|
||||
ui->m_state_cb->findData(
|
||||
m_kind_info["state"].toString()));
|
||||
m_data.m_slave_state));
|
||||
ui->m_type_cb->setCurrentIndex (
|
||||
ui->m_type_cb->findData(
|
||||
m_kind_info["type"].toString()));
|
||||
ui->m_number_ctc->setValue(m_kind_info["number"].toInt());
|
||||
m_data.m_slave_type));
|
||||
ui->m_number_ctc->setValue(m_data.m_contact_count);
|
||||
}
|
||||
else if (m_basic_type == "master") {
|
||||
else if (m_data.m_type == ElementData::Master) {
|
||||
ui->m_master_type_cb->setCurrentIndex(
|
||||
ui->m_master_type_cb->findData (
|
||||
m_kind_info["type"]));
|
||||
m_data.m_master_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());
|
||||
@@ -117,33 +116,39 @@ void ElementPropertiesEditorWidget::upDateInterface()
|
||||
void ElementPropertiesEditorWidget::setUpInterface()
|
||||
{
|
||||
// Type combo box
|
||||
ui->m_base_type_cb->addItem (tr("Simple"), QVariant("simple"));
|
||||
ui->m_base_type_cb->addItem (tr("Maître"), QVariant("master"));
|
||||
ui->m_base_type_cb->addItem (tr("Esclave"), QVariant("slave"));
|
||||
ui->m_base_type_cb->addItem (tr("Renvoi de folio suivant"),
|
||||
QVariant("next_report"));
|
||||
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"));
|
||||
ui->m_base_type_cb->addItem (tr("Simple"), ElementData::Simple);
|
||||
ui->m_base_type_cb->addItem (tr("Maître"), ElementData::Master);
|
||||
ui->m_base_type_cb->addItem (tr("Esclave"), ElementData::Slave);
|
||||
ui->m_base_type_cb->addItem (tr("Renvoi de folio suivant"), ElementData::NextReport);
|
||||
ui->m_base_type_cb->addItem (tr("Renvoi de folio précédent"), ElementData::PreviousReport);
|
||||
ui->m_base_type_cb->addItem (tr("Bornier"), ElementData::Terminale);
|
||||
|
||||
// Slave option
|
||||
ui->m_state_cb->addItem(tr("Normalement ouvert"),QVariant("NO"));
|
||||
ui->m_state_cb->addItem(tr("Normalement fermé"), QVariant("NC"));
|
||||
ui->m_state_cb->addItem(tr("Inverseur"), QVariant("SW"));
|
||||
ui->m_type_cb->addItem(tr("Simple"), QVariant("simple"));
|
||||
ui->m_type_cb->addItem(tr("Puissance"), QVariant("power"));
|
||||
ui->m_type_cb->addItem(tr("Temporisé travail"), QVariant("delayOn"));
|
||||
ui->m_type_cb->addItem(tr("Temporisé repos"), QVariant("delayOff"));
|
||||
ui->m_type_cb->addItem(tr("Temporisé travail & repos"),
|
||||
QVariant("delayOnOff"));
|
||||
ui->m_state_cb->addItem(tr("Normalement ouvert"), ElementData::NO);
|
||||
ui->m_state_cb->addItem(tr("Normalement fermé"), ElementData::NC);
|
||||
ui->m_state_cb->addItem(tr("Inverseur"), ElementData::SW);
|
||||
ui->m_type_cb->addItem(tr("Simple"), ElementData::SSimple);
|
||||
ui->m_type_cb->addItem(tr("Puissance"), ElementData::Power);
|
||||
ui->m_type_cb->addItem(tr("Temporisé travail"), ElementData::DelayOn);
|
||||
ui->m_type_cb->addItem(tr("Temporisé repos"), ElementData::DelayOff);
|
||||
ui->m_type_cb->addItem(tr("Temporisé travail & repos"), ElementData::delayOnOff);
|
||||
|
||||
//Master option
|
||||
ui->m_master_type_cb->addItem(tr("Bobine"), QVariant("coil"));
|
||||
ui->m_master_type_cb->addItem(tr("Organe de protection"),
|
||||
QVariant("protection"));
|
||||
ui->m_master_type_cb->addItem(tr("Commutateur / bouton"),
|
||||
QVariant("commutator"));
|
||||
|
||||
ui->m_master_type_cb->addItem(tr("Bobine"), ElementData::Coil);
|
||||
ui->m_master_type_cb->addItem(tr("Organe de protection"), ElementData::Protection);
|
||||
ui->m_master_type_cb->addItem(tr("Commutateur / bouton"), ElementData::Commutator);
|
||||
|
||||
//Terminal option
|
||||
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
|
||||
//by this little workaround
|
||||
ui->m_tree->setItemDelegate(new EditorDelegate(this));
|
||||
@@ -153,21 +158,28 @@ void ElementPropertiesEditorWidget::setUpInterface()
|
||||
|
||||
void ElementPropertiesEditorWidget::updateTree()
|
||||
{
|
||||
QString type = ui->m_base_type_cb->itemData(
|
||||
ui->m_base_type_cb->currentIndex()).toString();
|
||||
|
||||
if (type == "master")
|
||||
ui->m_tree->setEnabled(true);
|
||||
else if (type == "slave")
|
||||
ui->m_tree->setDisabled(true);
|
||||
else if (type == "simple")
|
||||
ui->m_tree->setEnabled(true);
|
||||
else if (type == "next_report")
|
||||
ui->m_tree->setDisabled(true);
|
||||
else if (type == "previous_report")
|
||||
ui->m_tree->setDisabled(true);
|
||||
else if (type == "terminal")
|
||||
ui->m_tree->setEnabled(true);
|
||||
auto type_ = ui->m_base_type_cb->currentData().value<ElementData::Type>();
|
||||
|
||||
switch (type_) {
|
||||
case ElementData::Simple:
|
||||
ui->m_tree->setEnabled(true);
|
||||
break;
|
||||
case ElementData::NextReport:
|
||||
ui->m_tree->setDisabled(true);
|
||||
break;
|
||||
case ElementData::PreviousReport:
|
||||
ui->m_tree->setDisabled(true);
|
||||
break;
|
||||
case ElementData::Master:
|
||||
ui->m_tree->setEnabled(true);
|
||||
break;
|
||||
case ElementData::Slave:
|
||||
ui->m_tree->setDisabled(true);
|
||||
break;
|
||||
case ElementData::Terminale:
|
||||
ui->m_tree->setEnabled(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,20 +187,16 @@ void ElementPropertiesEditorWidget::updateTree()
|
||||
Create QTreeWidgetItem of the tree widget and populate it
|
||||
*/
|
||||
void ElementPropertiesEditorWidget::populateTree()
|
||||
{
|
||||
QStringList keys{"label", "plant", "comment", "description",
|
||||
"designation", "manufacturer",
|
||||
"manufacturer_reference", "supplier", "quantity",
|
||||
"unity", "machine_manufacturer_reference"};
|
||||
|
||||
{
|
||||
const auto keys = QETInformation::elementEditorElementInfoKeys();
|
||||
for(const QString& key : keys)
|
||||
{
|
||||
QTreeWidgetItem *qtwi = new QTreeWidgetItem(ui->m_tree);
|
||||
qtwi->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable);
|
||||
qtwi->setData(0, Qt::DisplayRole,
|
||||
QETInformation::translatedInfoKey(key));
|
||||
QETInformation::translatedInfoKey(key));
|
||||
qtwi->setData(0, Qt::UserRole, key);
|
||||
qtwi->setText(1, m_elmt_info.value(key).toString());
|
||||
qtwi->setText(1, m_data.m_informations.value(key).toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,23 +206,21 @@ void ElementPropertiesEditorWidget::populateTree()
|
||||
*/
|
||||
void ElementPropertiesEditorWidget::on_m_buttonBox_accepted()
|
||||
{
|
||||
m_basic_type = ui->m_base_type_cb->itemData(
|
||||
ui->m_base_type_cb->currentIndex()).toString();
|
||||
if (m_basic_type == "slave")
|
||||
m_data.m_type = ui->m_base_type_cb->currentData().value<ElementData::Type>();
|
||||
|
||||
if (m_data.m_type == ElementData::Slave)
|
||||
{
|
||||
m_kind_info.addValue("state",
|
||||
ui->m_state_cb->itemData(
|
||||
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()));
|
||||
m_data.m_slave_state = ui->m_state_cb->currentData().value<ElementData::SlaveState>();
|
||||
m_data.m_slave_type = ui->m_type_cb->currentData().value<ElementData::SlaveType>();
|
||||
m_data.m_contact_count = ui->m_number_ctc->value();
|
||||
}
|
||||
else if(m_basic_type == "master") {
|
||||
m_kind_info.addValue("type",
|
||||
ui->m_master_type_cb->itemData(
|
||||
ui->m_master_type_cb->currentIndex()));
|
||||
else if (m_data.m_type == ElementData::Master) {
|
||||
m_data.m_master_type = ui->m_master_type_cb->currentData().value<ElementData::MasterType>();
|
||||
}
|
||||
else if (m_data.m_type == ElementData::Terminale)
|
||||
{
|
||||
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())
|
||||
@@ -224,8 +230,8 @@ void ElementPropertiesEditorWidget::on_m_buttonBox_accepted()
|
||||
txt.remove("\r");
|
||||
txt.remove("\n");
|
||||
|
||||
m_elmt_info.addValue(qtwi->data(0, Qt::UserRole).toString(),
|
||||
txt);
|
||||
m_data.m_informations.addValue(qtwi->data(0, Qt::UserRole).toString(),
|
||||
txt);
|
||||
}
|
||||
|
||||
this->close();
|
||||
@@ -235,18 +241,23 @@ void ElementPropertiesEditorWidget::on_m_buttonBox_accepted()
|
||||
@brief ElementPropertiesEditorWidget::on_m_base_type_cb_currentIndexChanged
|
||||
@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;
|
||||
bool slave = false , master = false, terminal = false;
|
||||
|
||||
if (ui->m_base_type_cb->itemData(index).toString() == "slave")
|
||||
auto type_ = ui->m_base_type_cb->itemData(index).value<ElementData::Type>();
|
||||
if (type_ == ElementData::Slave)
|
||||
slave = true;
|
||||
else if (ui->m_base_type_cb->itemData(index).toString() == "master")
|
||||
else if (type_ == ElementData::Master)
|
||||
master = true;
|
||||
else if (type_ == ElementData::Terminale)
|
||||
terminal = true;
|
||||
|
||||
ui->m_slave_gb->setVisible(slave);
|
||||
ui->m_master_gb->setVisible(master);
|
||||
|
||||
ui->m_terminal_gb->setVisible(terminal);
|
||||
ui->tabWidget->setTabVisible(1,
|
||||
(type_ == ElementData::Simple ||
|
||||
type_ == ElementData::Master));
|
||||
updateTree();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define ELEMENTPROPERTIESEDITORWIDGET_H
|
||||
|
||||
#include "../../diagramcontext.h"
|
||||
#include "../../properties/elementdata.h"
|
||||
|
||||
#include <QAbstractButton>
|
||||
#include <QDialog>
|
||||
@@ -38,12 +39,13 @@ class ElementPropertiesEditorWidget : public QDialog
|
||||
|
||||
//METHODS
|
||||
public:
|
||||
explicit ElementPropertiesEditorWidget(QString &basic_type, DiagramContext &kind_info, DiagramContext &elmt_info, QWidget *parent = nullptr);
|
||||
explicit ElementPropertiesEditorWidget(ElementData data, QWidget *parent = nullptr);
|
||||
~ElementPropertiesEditorWidget() override;
|
||||
|
||||
void upDateInterface();
|
||||
ElementData editedData() {return m_data;}
|
||||
|
||||
private:
|
||||
void upDateInterface();
|
||||
void setUpInterface();
|
||||
void updateTree();
|
||||
void populateTree();
|
||||
@@ -56,9 +58,7 @@ class ElementPropertiesEditorWidget : public QDialog
|
||||
//ATTRIBUTES
|
||||
private:
|
||||
Ui::ElementPropertiesEditorWidget *ui;
|
||||
QString &m_basic_type;
|
||||
DiagramContext &m_kind_info,
|
||||
&m_elmt_info;
|
||||
ElementData m_data;
|
||||
};
|
||||
|
||||
#endif // ELEMENTPROPERTIESEDITORWIDGET_H
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>450</width>
|
||||
<height>321</height>
|
||||
<width>527</width>
|
||||
<height>442</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -107,6 +107,35 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</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>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
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 QETELEMENTEDITOR_H
|
||||
#define QETELEMENTEDITOR_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include "../../ElementsCollection/elementslocation.h"
|
||||
|
||||
class ElementScene;
|
||||
class QActionGroup;
|
||||
class ElementItemEditor;
|
||||
class ElementView;
|
||||
class QListWidget;
|
||||
class QStackedWidget;
|
||||
class QLabel;
|
||||
|
||||
namespace Ui {
|
||||
class QETElementEditor;
|
||||
}
|
||||
|
||||
class QETElementEditor : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
signals:
|
||||
void saveToLocation(ElementsLocation loc);
|
||||
|
||||
public:
|
||||
explicit QETElementEditor(QWidget *parent = nullptr);
|
||||
~QETElementEditor() override;
|
||||
|
||||
void contextMenu(QPoint p, QList<QAction *> actions = QList<QAction *>());
|
||||
void setNames(const NamesList &name_list);
|
||||
void setLocation(const ElementsLocation &location);
|
||||
ElementsLocation location() const;
|
||||
void setFileName(const QString &file_name);
|
||||
QString fileName() const;
|
||||
void setReadOnly(bool ro);
|
||||
bool isReadOnly() const;
|
||||
void fromFile(const QString &filepath);
|
||||
bool toFile(const QString &filepath);
|
||||
void fromLocation(const ElementsLocation &location);
|
||||
bool toLocation(const ElementsLocation &location);
|
||||
bool isEditing(const ElementsLocation &location);
|
||||
bool isEditing(const QString &filepath);
|
||||
ElementScene *elementScene() const;
|
||||
ElementView *elementView() const;
|
||||
static QPointF pasteOffset();
|
||||
static QString getOpenElementFileName(QWidget *parent = nullptr, const QString &dir = QString());
|
||||
void updateTitle();
|
||||
void fillPartsList();
|
||||
void UncheckAddPrimitive();
|
||||
void updateCurrentPartEditor();
|
||||
void updateInformations();
|
||||
void updatePartsList();
|
||||
void updateSelectionFromPartsList();
|
||||
void openElement(const QString &filepath);
|
||||
bool checkElement();
|
||||
|
||||
protected:
|
||||
bool event(QEvent *event) override;
|
||||
void closeEvent(QCloseEvent *) override;
|
||||
|
||||
|
||||
private slots:
|
||||
bool on_m_save_action_triggered();
|
||||
bool on_m_save_as_action_triggered();
|
||||
void on_m_select_all_act_triggered();
|
||||
void on_m_edit_element_properties_action_triggered();
|
||||
void on_m_new_action_triggered();
|
||||
void on_m_open_action_triggered();
|
||||
void on_m_open_from_file_action_triggered();
|
||||
void on_m_open_dxf_action_triggered();
|
||||
bool on_m_save_as_file_action_triggered();
|
||||
void on_m_reload_action_triggered();
|
||||
void on_m_quit_action_triggered();
|
||||
void on_m_deselect_all_action_triggered();
|
||||
void on_m_cut_action_triggered();
|
||||
void on_m_copy_action_triggered();
|
||||
void on_m_paste_action_triggered();
|
||||
void on_m_paste_in_area_action_triggered();
|
||||
void on_m_paste_from_file_action_triggered();
|
||||
void on_m_paste_from_element_action_triggered();
|
||||
void on_m_revert_selection_action_triggered();
|
||||
void on_m_delete_action_triggered();
|
||||
void on_m_edit_names_action_triggered();
|
||||
void on_m_edit_author_action_triggered();
|
||||
void on_m_zoom_in_action_triggered();
|
||||
void on_m_zoom_out_action_triggered();
|
||||
void on_m_zoom_fit_best_action_triggered();
|
||||
void on_m_zoom_original_action_triggered();
|
||||
void on_m_about_qet_action_triggered();
|
||||
void on_m_online_manual_triggered();
|
||||
void on_m_youtube_action_triggered();
|
||||
void on_m_donate_action_triggered();
|
||||
void on_m_about_qt_action_triggered();
|
||||
|
||||
private:
|
||||
bool canClose();
|
||||
void readSettings();
|
||||
void writeSettings() const;
|
||||
void setupActions();
|
||||
void updateAction();
|
||||
void setupConnection();
|
||||
void initGui();
|
||||
QWidget *clearToolsDock();
|
||||
void copyAndPasteXml(const QDomDocument &xml_document);
|
||||
|
||||
private:
|
||||
Ui::QETElementEditor *ui;
|
||||
|
||||
bool
|
||||
m_read_only = false,
|
||||
m_opened_from_file = false,
|
||||
m_first_activation = true;
|
||||
|
||||
ElementScene *m_elmt_scene = nullptr;
|
||||
|
||||
QActionGroup
|
||||
*m_add_part_action_grp = nullptr,
|
||||
*m_depth_action_group = nullptr;
|
||||
|
||||
QList<QAction *> m_context_menu_action_list;
|
||||
|
||||
QAction
|
||||
*m_undo_action = nullptr,
|
||||
*m_redo_action = nullptr;
|
||||
|
||||
|
||||
/// Hash associating primitive names with their matching edition widget
|
||||
QHash<QString, ElementItemEditor *> m_editors;
|
||||
|
||||
ElementsLocation m_location;
|
||||
|
||||
QString
|
||||
m_file_name,
|
||||
m_min_title;
|
||||
|
||||
ElementView *m_view = nullptr;
|
||||
|
||||
QListWidget *m_parts_list = nullptr;
|
||||
|
||||
QStackedWidget *m_tools_dock_stack = nullptr;
|
||||
|
||||
QLabel *m_default_informations = nullptr;
|
||||
|
||||
};
|
||||
|
||||
#endif // QETELEMENTEDITOR_H
|
||||
@@ -0,0 +1,496 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QETElementEditor</class>
|
||||
<widget class="QMainWindow" name="QETElementEditor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>QElectroTech - Éditeur d'élément</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/qet.png</normaloff>:/ico/16x16/qet.png</iconset>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget"/>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="m_file_menu">
|
||||
<property name="title">
|
||||
<string>&Fichier</string>
|
||||
</property>
|
||||
<addaction name="m_new_action"/>
|
||||
<addaction name="m_open_action"/>
|
||||
<addaction name="m_open_from_file_action"/>
|
||||
<addaction name="m_open_dxf_action"/>
|
||||
<addaction name="m_save_action"/>
|
||||
<addaction name="m_save_as_action"/>
|
||||
<addaction name="m_save_as_file_action"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="m_reload_action"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="m_quit_action"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="m_edit_menu">
|
||||
<property name="title">
|
||||
<string>&Édition</string>
|
||||
</property>
|
||||
<widget class="QMenu" name="m_paste_from_menu">
|
||||
<property name="title">
|
||||
<string>Coller depuis...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/edit-paste.png</normaloff>:/ico/16x16/edit-paste.png</iconset>
|
||||
</property>
|
||||
<addaction name="m_paste_from_file_action"/>
|
||||
<addaction name="m_paste_from_element_action"/>
|
||||
</widget>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="m_select_all_act"/>
|
||||
<addaction name="m_deselect_all_action"/>
|
||||
<addaction name="m_revert_selection_action"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="m_cut_action"/>
|
||||
<addaction name="m_copy_action"/>
|
||||
<addaction name="m_paste_action"/>
|
||||
<addaction name="m_paste_in_area_action"/>
|
||||
<addaction name="m_paste_from_menu"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="m_delete_action"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="m_edit_names_action"/>
|
||||
<addaction name="m_edit_author_action"/>
|
||||
<addaction name="m_edit_element_properties_action"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="m_display_menu">
|
||||
<property name="title">
|
||||
<string>Afficha&ge</string>
|
||||
</property>
|
||||
<addaction name="m_zoom_in_action"/>
|
||||
<addaction name="m_zoom_out_action"/>
|
||||
<addaction name="m_zoom_fit_best_action"/>
|
||||
<addaction name="m_zoom_original_action"/>
|
||||
<addaction name="separator"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_Aide">
|
||||
<property name="title">
|
||||
<string>&Aide</string>
|
||||
</property>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="m_about_qet_action"/>
|
||||
<addaction name="m_online_manual"/>
|
||||
<addaction name="m_youtube_action"/>
|
||||
<addaction name="m_donate_action"/>
|
||||
<addaction name="m_about_qt_action"/>
|
||||
</widget>
|
||||
<addaction name="m_file_menu"/>
|
||||
<addaction name="m_edit_menu"/>
|
||||
<addaction name="m_display_menu"/>
|
||||
<addaction name="menu_Aide"/>
|
||||
</widget>
|
||||
<widget class="QDockWidget" name="m_undo_dock">
|
||||
<property name="allowedAreas">
|
||||
<set>Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea</set>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Annulations</string>
|
||||
</property>
|
||||
<attribute name="dockWidgetArea">
|
||||
<number>1</number>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="dockWidgetContents"/>
|
||||
</widget>
|
||||
<widget class="QDockWidget" name="m_parts_dock">
|
||||
<property name="allowedAreas">
|
||||
<set>Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea</set>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Parties</string>
|
||||
</property>
|
||||
<attribute name="dockWidgetArea">
|
||||
<number>2</number>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="dockWidgetContents_2"/>
|
||||
</widget>
|
||||
<widget class="QDockWidget" name="m_tools_dock">
|
||||
<property name="allowedAreas">
|
||||
<set>Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea</set>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Informations</string>
|
||||
</property>
|
||||
<attribute name="dockWidgetArea">
|
||||
<number>1</number>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="dockWidgetContents_3"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="m_main_toolbar">
|
||||
<property name="windowTitle">
|
||||
<string>Outils</string>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="m_new_action"/>
|
||||
<addaction name="m_open_action"/>
|
||||
<addaction name="m_save_action"/>
|
||||
<addaction name="m_save_as_action"/>
|
||||
<addaction name="m_reload_action"/>
|
||||
<addaction name="m_delete_action"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="m_view_toolbar">
|
||||
<property name="windowTitle">
|
||||
<string>Affichage</string>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="m_zoom_in_action"/>
|
||||
<addaction name="m_zoom_out_action"/>
|
||||
<addaction name="m_zoom_fit_best_action"/>
|
||||
<addaction name="m_zoom_original_action"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="m_element_toolbar">
|
||||
<property name="windowTitle">
|
||||
<string>Élément</string>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="m_edit_names_action"/>
|
||||
<addaction name="m_edit_element_properties_action"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="m_undo_toolbar">
|
||||
<property name="windowTitle">
|
||||
<string>Annulation</string>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
<action name="m_select_all_act">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/edit-select-all.png</normaloff>:/ico/16x16/edit-select-all.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Tout sélectionner</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_new_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/document-new.png</normaloff>:/ico/22x22/document-new.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Nouveau</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_open_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/folder-open.png</normaloff>:/ico/22x22/folder-open.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Ouvrir</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_open_from_file_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/folder-open.png</normaloff>:/ico/22x22/folder-open.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Ouvrir depuis un fichier</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_open_dxf_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/run-dxf.png</normaloff>:/ico/16x16/run-dxf.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Lancer le plugin convertisseur DXF</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_save_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/document-save.png</normaloff>:/ico/22x22/document-save.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Enregistrer</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_save_as_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/document-save-as.png</normaloff>:/ico/22x22/document-save-as.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enregistrer sous</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_save_as_file_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/document-save.png</normaloff>:/ico/22x22/document-save.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enregistrer dans un fichier</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_reload_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/view-refresh.png</normaloff>:/ico/22x22/view-refresh.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Recharger</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_quit_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/application-exit.png</normaloff>:/ico/16x16/application-exit.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Quitter</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_deselect_all_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/edit-select-none.png</normaloff>:/ico/16x16/edit-select-none.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Désélectionner tout</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_cut_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/edit-cut.png</normaloff>:/ico/16x16/edit-cut.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Co&uper</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_copy_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/edit-copy.png</normaloff>:/ico/16x16/edit-copy.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cop&ier</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_paste_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/edit-paste.png</normaloff>:/ico/16x16/edit-paste.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>C&oller</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_paste_in_area_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/edit-paste.png</normaloff>:/ico/16x16/edit-paste.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>C&oller dans la zone</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_paste_from_file_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/text-xml.png</normaloff>:/ico/16x16/text-xml.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Un fichier</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_paste_from_element_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/element.png</normaloff>:/ico/16x16/element.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Un élément</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_revert_selection_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/edit-select-invert.png</normaloff>:/ico/16x16/edit-select-invert.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Inverser la sélection</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_delete_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/edit-delete.png</normaloff>:/ico/22x22/edit-delete.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Supprimer</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_edit_names_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/names.png</normaloff>:/ico/22x22/names.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Éditer le nom et les traductions de l'élément</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_edit_author_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/preferences-desktop-user.png</normaloff>:/ico/16x16/preferences-desktop-user.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Éditer les informations sur l'auteur</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_edit_element_properties_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/element-edit.png</normaloff>:/ico/22x22/element-edit.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Éditer les propriétés de l'élément</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_zoom_in_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/zoom-in.png</normaloff>:/ico/22x22/zoom-in.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Zoom avant</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_zoom_out_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/zoom-out.png</normaloff>:/ico/22x22/zoom-out.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Zoom arrière</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_zoom_fit_best_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/zoom-fit-best.png</normaloff>:/ico/22x22/zoom-fit-best.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Zoom adapté</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_zoom_original_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/zoom-original.png</normaloff>:/ico/22x22/zoom-original.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Pas de zoom</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_about_qet_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/qet.png</normaloff>:/ico/16x16/qet.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>À &propos de QElectroTech</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Affiche des informations sur QElectroTech</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_online_manual">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/help-contents.png</normaloff>:/ico/16x16/help-contents.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Manuel en ligne</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Lance le navigateur par défaut vers le manuel en ligne de QElectroTech</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_youtube_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/kdenlive-show-video.png</normaloff>:/ico/16x16/kdenlive-show-video.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Chaine Youtube</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Lance le navigateur par défaut vers la chaine Youtube de QElectroTech</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_donate_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/help-donate.png</normaloff>:/ico/16x16/help-donate.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Soutenir le projet par un don</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Soutenir le projet QElectroTech par un don</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_about_qt_action">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/qt.png</normaloff>:/ico/16x16/qt.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>À propos de &Qt</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Affiche des informations sur la bibliothèque Qt</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../../qelectrotech.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
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 "ui_terminaleditor.h"
|
||||
#include "../../qeticons.h"
|
||||
#include "../../qet.h"
|
||||
#include "../graphicspart/partterminal.h"
|
||||
#include "../../QPropertyUndoCommand/qpropertyundocommand.h"
|
||||
|
||||
/**
|
||||
* @brief TerminalEditor::TerminalEditor
|
||||
* Default constructor
|
||||
* @param editor : element editor of which this terminal editor belong
|
||||
* @param parent : parent widget
|
||||
*/
|
||||
TerminalEditor::TerminalEditor(QETElementEditor *editor, QWidget *parent) :
|
||||
ElementItemEditor(editor, parent),
|
||||
ui(new Ui::TerminalEditor)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalEditor::~TerminalEditor
|
||||
* Destructor
|
||||
*/
|
||||
TerminalEditor::~TerminalEditor()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalEditor::updateForm
|
||||
* Reimplemented from ElementItemEditor
|
||||
* Update the content of this widget
|
||||
*/
|
||||
void TerminalEditor::updateForm()
|
||||
{
|
||||
if (!m_part) {
|
||||
return;
|
||||
}
|
||||
activeConnections(false);
|
||||
|
||||
ui->m_x_dsb->setValue(m_part->property("x").toReal());
|
||||
ui->m_y_dsb->setValue(m_part->property("y").toReal());
|
||||
ui->m_orientation_cb->setCurrentIndex(ui->m_orientation_cb->findData(m_part->property("orientation")));
|
||||
ui->m_name_le->setText(m_part->name());
|
||||
ui->m_type_cb->setCurrentIndex(ui->m_orientation_cb->findData(m_part->terminalType()));
|
||||
|
||||
activeConnections(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalEditor::setPart
|
||||
* Set the part to edit.
|
||||
* The part must be a PartTerminal, in other case return false.
|
||||
* @param new_part : the part to edit
|
||||
* @return true if the part can be edited.
|
||||
*/
|
||||
bool TerminalEditor::setPart(CustomElementPart *new_part)
|
||||
{
|
||||
if (m_part == new_part) {
|
||||
return true;
|
||||
}
|
||||
|
||||
activeChangeConnections(false);
|
||||
|
||||
if (!new_part)
|
||||
{
|
||||
m_part = nullptr;
|
||||
return(true);
|
||||
}
|
||||
|
||||
if (PartTerminal *part_terminal = dynamic_cast<PartTerminal *>(new_part))
|
||||
{
|
||||
m_part = part_terminal;
|
||||
updateForm();
|
||||
activeChangeConnections(true);
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalEditor::currentPart
|
||||
* @return the current edited part
|
||||
* or nullptr if there is no part or several part
|
||||
* @see QList<CustomElementPart *> TerminalEditor::currentParts() const
|
||||
*/
|
||||
CustomElementPart *TerminalEditor::currentPart() const
|
||||
{
|
||||
return m_part;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalEditor::init
|
||||
* Some init about this class
|
||||
*/
|
||||
void TerminalEditor::init()
|
||||
{
|
||||
ui->m_orientation_cb->addItem(QET::Icons::North, tr("Nord"), Qet::North);
|
||||
ui->m_orientation_cb->addItem(QET::Icons::East, tr("Est"), Qet::East);
|
||||
ui->m_orientation_cb->addItem(QET::Icons::South, tr("Sud"), Qet::South);
|
||||
ui->m_orientation_cb->addItem(QET::Icons::West, tr("Ouest"), Qet::West);
|
||||
|
||||
ui->m_type_cb->addItem(tr("Générique"), TerminalData::Generic);
|
||||
ui->m_type_cb->addItem(tr("Bornier intérieur"), TerminalData::Inner);
|
||||
ui->m_type_cb->addItem(tr("Bornier extérieur"), TerminalData::Outer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalEditor::posEdited
|
||||
*/
|
||||
void TerminalEditor::posEdited()
|
||||
{
|
||||
if (m_locked) {
|
||||
return;
|
||||
}
|
||||
m_locked = true;
|
||||
|
||||
QPointF new_pos(ui->m_x_dsb->value(),
|
||||
ui->m_y_dsb->value());
|
||||
|
||||
if (m_part->pos() != new_pos)
|
||||
{
|
||||
auto undo = new QPropertyUndoCommand(m_part, "pos", m_part->property("pos"), new_pos);
|
||||
undo->setText(tr("Déplacer une borne"));
|
||||
undo->setAnimated(true, false);
|
||||
undoStack().push(undo);
|
||||
}
|
||||
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalEditor::orientationEdited
|
||||
*/
|
||||
void TerminalEditor::orientationEdited()
|
||||
{
|
||||
if (m_locked) {
|
||||
return;
|
||||
}
|
||||
m_locked = true;
|
||||
|
||||
auto ori_ = ui->m_orientation_cb->currentData();
|
||||
if (m_part->orientation() != ori_)
|
||||
{
|
||||
auto undo = new QPropertyUndoCommand(m_part, "orientation", m_part->property("orientation"), ori_);
|
||||
undo->setText(tr("Modifier l'orientation d'une borne"));
|
||||
undoStack().push(undo);
|
||||
}
|
||||
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalEditor::nameEdited
|
||||
*/
|
||||
void TerminalEditor::nameEdited()
|
||||
{
|
||||
if (m_locked) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_locked = true;
|
||||
QString name_(ui->m_name_le->text());
|
||||
|
||||
if (m_part->name() != name_)
|
||||
{
|
||||
auto undo = new QPropertyUndoCommand(m_part, "name", m_part->property("name"), name_);
|
||||
undo->setText(tr("Modifier le nom du terminal"));
|
||||
undoStack().push(undo);
|
||||
}
|
||||
m_locked=false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalEditor::typeEdited
|
||||
*/
|
||||
void TerminalEditor::typeEdited()
|
||||
{
|
||||
if (m_locked) {
|
||||
return;
|
||||
}
|
||||
m_locked = true;
|
||||
|
||||
auto type = ui->m_type_cb->currentData();
|
||||
if (type != m_part->terminalType()) {
|
||||
auto undo = new QPropertyUndoCommand(m_part, "terminal_type", m_part->terminalType(), type);
|
||||
undo->setText(tr("Modifier le type d'une borne"));
|
||||
undoStack().push(undo);
|
||||
}
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalEditor::activeConnections
|
||||
* Active connection between the widgets used in this editor
|
||||
* and method of this class.
|
||||
* @param active
|
||||
*/
|
||||
void TerminalEditor::activeConnections(bool active)
|
||||
{
|
||||
if (active) {
|
||||
m_editor_connections << connect(ui->m_x_dsb, QOverload<qreal>::of(&QDoubleSpinBox::valueChanged),
|
||||
this, &TerminalEditor::posEdited);
|
||||
m_editor_connections << connect(ui->m_y_dsb, QOverload<qreal>::of(&QDoubleSpinBox::valueChanged),
|
||||
this, &TerminalEditor::posEdited);
|
||||
m_editor_connections << connect(ui->m_orientation_cb, QOverload<int>::of(&QComboBox::activated),
|
||||
this, &TerminalEditor::orientationEdited);
|
||||
m_editor_connections << connect(ui->m_name_le, &QLineEdit::editingFinished,
|
||||
this, &TerminalEditor::nameEdited);
|
||||
m_editor_connections << connect(ui->m_type_cb, QOverload<int>::of(&QComboBox::activated),
|
||||
this, &TerminalEditor::typeEdited);
|
||||
} else {
|
||||
for (auto const & con : qAsConst(m_editor_connections)) {
|
||||
QObject::disconnect(con);
|
||||
}
|
||||
m_editor_connections.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalEditor::activeChangeConnections(bool active)
|
||||
{
|
||||
if (active)
|
||||
{
|
||||
m_change_connections << connect(m_part, &PartTerminal::xChanged, this, &TerminalEditor::updateForm);
|
||||
m_change_connections << connect(m_part, &PartTerminal::yChanged, this, &TerminalEditor::updateForm);
|
||||
m_change_connections << connect(m_part, &PartTerminal::orientationChanged, this, &TerminalEditor::updateForm);
|
||||
m_change_connections << connect(m_part, &PartTerminal::nameChanged, this, &TerminalEditor::updateForm);
|
||||
m_change_connections << connect(m_part, &PartTerminal::terminalTypeChanged, this, &TerminalEditor::updateForm);
|
||||
} else {
|
||||
for (auto &con : m_change_connections) {
|
||||
QObject::disconnect(con);
|
||||
}
|
||||
m_change_connections.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
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 TERMINALEDITOR_H
|
||||
#define TERMINALEDITOR_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "../elementitemeditor.h"
|
||||
|
||||
namespace Ui {
|
||||
class TerminalEditor;
|
||||
}
|
||||
|
||||
class PartTerminal;
|
||||
|
||||
/**
|
||||
* @brief The TerminalEditor class
|
||||
* Provide a widget used to edit the properties of a PartTerminal
|
||||
*/
|
||||
class TerminalEditor : public ElementItemEditor
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TerminalEditor(QETElementEditor *editor, QWidget *parent = nullptr);
|
||||
~TerminalEditor() override;
|
||||
|
||||
void updateForm() override;
|
||||
bool setPart(CustomElementPart *new_part) override;
|
||||
CustomElementPart *currentPart() const override;
|
||||
QList<CustomElementPart *> currentParts() const override {return QList<CustomElementPart *>();}
|
||||
|
||||
private:
|
||||
void init();
|
||||
void posEdited();
|
||||
void orientationEdited();
|
||||
void nameEdited();
|
||||
void typeEdited();
|
||||
void activeConnections(bool active);
|
||||
void activeChangeConnections(bool active);
|
||||
|
||||
private:
|
||||
Ui::TerminalEditor *ui;
|
||||
QVector<QMetaObject::Connection> m_editor_connections,
|
||||
m_change_connections;
|
||||
PartTerminal *m_part = nullptr;
|
||||
bool m_locked = false;
|
||||
};
|
||||
|
||||
#endif // TERMINALEDITOR_H
|
||||
@@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TerminalEditor</class>
|
||||
<widget class="QWidget" name="TerminalEditor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>511</width>
|
||||
<height>236</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>y :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QDoubleSpinBox" name="m_x_dsb">
|
||||
<property name="minimum">
|
||||
<double>-5000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="m_y_dsb">
|
||||
<property name="minimum">
|
||||
<double>-5000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Orientation :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="m_name_le"/>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="m_orientation_cb"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>x :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Nom :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Type :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="m_type_cb"/>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -53,31 +53,6 @@ ElementsCollectionCache::ElementsCollectionCache(const QString &database_path, Q
|
||||
cache_db_.exec("PRAGMA synchronous = OFF");
|
||||
|
||||
#if TODO_LIST
|
||||
#pragma message("@TODO This code remove old table with mtime for create table with uuid, created at version 0,5")
|
||||
#endif
|
||||
//TODO This code remove old table with mtime for create table with uuid, created at version 0,5
|
||||
//see to remove this code at version 0,6 or 0,7 when all users will table with uuid.
|
||||
#if TODO_LIST
|
||||
#pragma message("@TODO remove this code for qet 0.6 or later")
|
||||
#endif
|
||||
QSqlQuery table_name(cache_db_);
|
||||
if (table_name.exec("PRAGMA table_info(names)"))
|
||||
{
|
||||
if (table_name.seek(2))
|
||||
{
|
||||
QString str = table_name.value(1).toString();
|
||||
table_name.finish();
|
||||
if (str == "mtime")
|
||||
{
|
||||
QSqlQuery error;
|
||||
error = cache_db_.exec("DROP TABLE names");
|
||||
error = cache_db_.exec("DROP TABLE pixmaps");
|
||||
}
|
||||
}
|
||||
else
|
||||
table_name.finish();
|
||||
}
|
||||
#if TODO_LIST
|
||||
#pragma message("@TODO the tables could already exist, handle that case.")
|
||||
#endif
|
||||
//@TODO the tables could already exist, handle that case.
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "elementspanelwidget.h"
|
||||
|
||||
#include "diagram.h"
|
||||
#include "editor/qetelementeditor.h"
|
||||
#include "editor/ui/qetelementeditor.h"
|
||||
#include "elementscategoryeditor.h"
|
||||
#include "qetapp.h"
|
||||
#include "qeticons.h"
|
||||
|
||||
+2
-17
@@ -18,10 +18,10 @@
|
||||
#include "machine_info.h"
|
||||
#include "qet.h"
|
||||
#include "qetapp.h"
|
||||
#include "singleapplication.h"
|
||||
#include "utils/macosxopenevent.h"
|
||||
|
||||
#include <QStyleFactory>
|
||||
#include <QApplication>
|
||||
|
||||
/**
|
||||
@brief myMessageOutput
|
||||
@@ -174,7 +174,7 @@ int main(int argc, char **argv)
|
||||
#pragma message("@TODO remove code for QT 6 or later")
|
||||
#endif
|
||||
#endif
|
||||
SingleApplication app(argc, argv, true);
|
||||
QApplication app(argc, argv, true);
|
||||
#ifdef Q_OS_MACOS
|
||||
//Handle the opening of QET when user double click on a .qet .elmt .tbt file
|
||||
//or drop these same files to the QET icon of the dock
|
||||
@@ -182,23 +182,8 @@ int main(int argc, char **argv)
|
||||
app.installEventFilter(&open_event);
|
||||
app.setStyle(QStyleFactory::create("Fusion"));
|
||||
#endif
|
||||
|
||||
if (app.isSecondary())
|
||||
{
|
||||
QStringList arg_list = app.arguments();
|
||||
//Remove the first argument, it's the binary file
|
||||
arg_list.takeFirst();
|
||||
QETArguments qetarg(arg_list);
|
||||
QString message = "launched-with-args: " + QET::joinWithSpaces(
|
||||
QStringList(qetarg.arguments()));
|
||||
app.sendMessage(message.toUtf8());
|
||||
return 0;
|
||||
}
|
||||
|
||||
QETApp qetapp;
|
||||
QETApp::instance()->installEventFilter(&qetapp);
|
||||
QObject::connect(&app, &SingleApplication::receivedMessage,
|
||||
&qetapp, &QETApp::receiveMessage);
|
||||
|
||||
// for debugging
|
||||
qInstallMessageHandler(myMessageOutput);
|
||||
|
||||
@@ -20,10 +20,14 @@
|
||||
#include "ElementsCollection/elementcollectionitem.h"
|
||||
#include "ElementsCollection/elementscollectionmodel.h"
|
||||
#include "NameList/ui/namelistwidget.h"
|
||||
#include "editor/qetelementeditor.h"
|
||||
#include "editor/ui/qetelementeditor.h"
|
||||
#include "qetmessagebox.h"
|
||||
#include "qfilenameedit.h"
|
||||
|
||||
#include <QTreeView>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param parent QWidget parent de ce dialogue
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "autoNum/assignvariables.h"
|
||||
#include "diagram.h"
|
||||
#include "diagramview.h"
|
||||
#include "editor/qetelementeditor.h"
|
||||
#include "editor/ui/qetelementeditor.h"
|
||||
#include "exportdialog.h"
|
||||
#include "qetapp.h"
|
||||
#include "qeticons.h"
|
||||
|
||||
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
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 "elementdata.h"
|
||||
#include "../qetxml.h"
|
||||
#include <QDebug>
|
||||
|
||||
void ElementData::toSettings(QSettings &settings, const QString prefix) const {
|
||||
Q_UNUSED(settings)
|
||||
Q_UNUSED(prefix)
|
||||
}
|
||||
|
||||
void ElementData::fromSettings(const QSettings &settings, const QString prefix) {
|
||||
Q_UNUSED(settings)
|
||||
Q_UNUSED(prefix)
|
||||
}
|
||||
|
||||
QDomElement ElementData::toXml(QDomDocument &xml_element) const {
|
||||
Q_UNUSED(xml_element)
|
||||
return QDomElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ElementData::fromXml
|
||||
* load properties from xml element.
|
||||
* The tag name of xml_element must be definition
|
||||
* and have an attribute "type"
|
||||
* @param xml_element : tagName must be 'definition'
|
||||
* @return true is successfuly loaded
|
||||
*/
|
||||
bool ElementData::fromXml(const QDomElement &xml_element)
|
||||
{
|
||||
if(xml_element.tagName() != "definition" ||
|
||||
xml_element.attribute("type") != "element") {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_type = typeFromString(xml_element.attribute("link_type", "simple"));
|
||||
kindInfoFromXml(xml_element);
|
||||
m_informations.fromXml(xml_element.firstChildElement("elementInformations"),
|
||||
"elementInformation");
|
||||
m_names_list.fromXml(xml_element);
|
||||
|
||||
auto xml_draw_info = xml_element.firstChildElement("informations");
|
||||
if(xml_draw_info.tagName() == "informations") {
|
||||
m_drawing_information = xml_draw_info.text();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QDomElement ElementData::kindInfoToXml(QDomDocument &document)
|
||||
{
|
||||
//kindInformations
|
||||
auto returned_elmt = document.createElement("kindInformations");
|
||||
|
||||
if (m_type == ElementData::Master)
|
||||
{
|
||||
auto xml_type = document.createElement("kindInformation");
|
||||
xml_type.setAttribute("name", "type");
|
||||
auto type_txt = document.createTextNode(masterTypeToString(m_master_type));
|
||||
xml_type.appendChild(type_txt);
|
||||
|
||||
returned_elmt.appendChild(xml_type);
|
||||
}
|
||||
else if (m_type == ElementData::Slave)
|
||||
{
|
||||
//type
|
||||
auto xml_type = document.createElement("kindInformation");
|
||||
xml_type.setAttribute("name", "type");
|
||||
auto type_txt = document.createTextNode(slaveTypeToString(m_slave_type));
|
||||
xml_type.appendChild(type_txt);
|
||||
returned_elmt.appendChild(xml_type);
|
||||
|
||||
//state
|
||||
auto xml_state = document.createElement("kindInformation");
|
||||
xml_state.setAttribute("name", "state");
|
||||
auto state_txt = document.createTextNode(slaveStateToString(m_slave_state));
|
||||
xml_state.appendChild(state_txt);
|
||||
|
||||
returned_elmt.appendChild(xml_state);
|
||||
|
||||
//contact count
|
||||
auto xml_count = document.createElement("kindInformation");
|
||||
xml_count.setAttribute("name", "number");
|
||||
auto count_txt = document.createTextNode(QString::number(m_contact_count));
|
||||
xml_count.appendChild(count_txt);
|
||||
|
||||
returned_elmt.appendChild(xml_count);
|
||||
}
|
||||
else if (m_type == ElementData::Terminale)
|
||||
{
|
||||
//type
|
||||
auto xml_type = document.createElement("kindInformation");
|
||||
xml_type.setAttribute("name", "type");
|
||||
auto type_txt = document.createTextNode(terminalTypeToString(m_terminal_type));
|
||||
xml_type.appendChild(type_txt);
|
||||
returned_elmt.appendChild(xml_type);
|
||||
|
||||
//function
|
||||
auto xml_func = document.createElement("kindInformation");
|
||||
xml_func.setAttribute("name", "function");
|
||||
auto func_txt = document.createTextNode(terminalFunctionToString(m_terminal_function));
|
||||
xml_func.appendChild(func_txt);
|
||||
returned_elmt.appendChild(xml_func);
|
||||
}
|
||||
|
||||
return returned_elmt;
|
||||
}
|
||||
|
||||
bool ElementData::operator==(const ElementData &data) const
|
||||
{
|
||||
if (data.m_type != m_type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data.m_type == ElementData::Master) {
|
||||
if(data.m_master_type != m_master_type) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (data.m_type == ElementData::Slave) {
|
||||
if (data.m_slave_state != m_slave_state ||
|
||||
data.m_slave_type != m_slave_type ||
|
||||
data.m_contact_count != m_contact_count) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (data.m_type == ElementData::Terminale) {
|
||||
if (data.m_terminal_type != m_terminal_type ||
|
||||
data.m_terminal_function != m_terminal_function) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(data.m_informations != m_informations) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data.m_names_list != m_names_list) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_drawing_information != m_drawing_information) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ElementData::operator !=(const ElementData &data) const {
|
||||
return !(*this == data);
|
||||
}
|
||||
|
||||
QString ElementData::typeToString(ElementData::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case ElementData::Simple :
|
||||
return QString("simple");
|
||||
case ElementData::NextReport :
|
||||
return QString ("next_report");
|
||||
case ElementData::PreviousReport :
|
||||
return QString("previous_report");
|
||||
case ElementData::Master :
|
||||
return QString("master");
|
||||
case ElementData::Slave :
|
||||
return QString("slave");
|
||||
case ElementData::Terminale :
|
||||
return QString("terminal");
|
||||
default:
|
||||
qDebug() << "ElementData::typeToString : type don't exist"
|
||||
<< "return failsafe value 'simple'";
|
||||
return QString("simple");
|
||||
}
|
||||
}
|
||||
|
||||
ElementData::Type ElementData::typeFromString(const QString &string)
|
||||
{
|
||||
if (string == "simple") {
|
||||
return ElementData::Simple;
|
||||
} else if (string == "next_report") {
|
||||
return ElementData::NextReport;
|
||||
} else if (string == "previous_report") {
|
||||
return ElementData::PreviousReport;
|
||||
} else if (string == "master") {
|
||||
return ElementData::Master;
|
||||
} else if (string == "slave") {
|
||||
return ElementData::Slave;
|
||||
} else if (string == "terminal") {
|
||||
return ElementData::Terminale;
|
||||
}
|
||||
|
||||
//Return simple if nothing match
|
||||
qDebug() << "ElementData::typeFromString : string "
|
||||
<< string
|
||||
<< " don't exist, return failsafe value 'simple";
|
||||
return ElementData::Simple;
|
||||
}
|
||||
|
||||
QString ElementData::masterTypeToString(ElementData::MasterType type)
|
||||
{
|
||||
switch (type) {
|
||||
case ElementData::Coil:
|
||||
return QString ("coil");
|
||||
case ElementData::Protection:
|
||||
return QString ("protection");
|
||||
case ElementData::Commutator:
|
||||
return QString ("commutator");
|
||||
}
|
||||
}
|
||||
|
||||
ElementData::MasterType ElementData::masterTypeFromString(const QString &string)
|
||||
{
|
||||
if (string == "coil") {
|
||||
return ElementData::Coil;
|
||||
} else if (string == "protection") {
|
||||
return ElementData::Protection;
|
||||
} else if (string == "commutator") {
|
||||
return ElementData::Commutator;
|
||||
}
|
||||
|
||||
qDebug() << "ElementData::masterTypeFromString : string "
|
||||
<< string
|
||||
<< " don't exist, return failsafe value 'coil'";
|
||||
return ElementData::Coil;
|
||||
}
|
||||
|
||||
QString ElementData::slaveTypeToString(ElementData::SlaveType type)
|
||||
{
|
||||
switch (type) {
|
||||
case ElementData::SSimple:
|
||||
return QString ("simple");
|
||||
case ElementData::Power:
|
||||
return QString ("power");
|
||||
case ElementData::DelayOn:
|
||||
return QString("delayOn");
|
||||
case ElementData::DelayOff:
|
||||
return QString("delayOff");
|
||||
case ElementData::delayOnOff:
|
||||
return QString("delayOnOff");
|
||||
}
|
||||
}
|
||||
|
||||
ElementData::SlaveType ElementData::slaveTypeFromString(const QString &string)
|
||||
{
|
||||
if (string == "simple") {
|
||||
return ElementData::SSimple;
|
||||
} else if (string == "power") {
|
||||
return ElementData::Power;
|
||||
} else if (string == "delayOn") {
|
||||
return ElementData::DelayOn;
|
||||
} else if (string == "delayOff") {
|
||||
return ElementData::DelayOff;
|
||||
} else if (string == "delayOnOff") {
|
||||
return ElementData::delayOnOff;
|
||||
}
|
||||
|
||||
qDebug() << "ElementData::slaveTypeFromSting : string "
|
||||
<< string
|
||||
<< " don't exist, return failsafe value 'simple'";
|
||||
return ElementData::SSimple;
|
||||
}
|
||||
|
||||
QString ElementData::slaveStateToString(ElementData::SlaveState type)
|
||||
{
|
||||
switch (type) {
|
||||
case NO:
|
||||
return QString("NO");
|
||||
case NC:
|
||||
return QString("NC");
|
||||
case SW:
|
||||
return QString("SW");
|
||||
}
|
||||
}
|
||||
|
||||
ElementData::SlaveState ElementData::slaveStateFromString(const QString &string)
|
||||
{
|
||||
if (string == "NO") {
|
||||
return ElementData::NO;
|
||||
} else if (string == "NC") {
|
||||
return ElementData::NC;
|
||||
} else if (string == "SW") {
|
||||
return ElementData::SW;
|
||||
}
|
||||
|
||||
qDebug() << "ElementData::slaveStateFromString : string : "
|
||||
<< string
|
||||
<< " don't exist, return failsafe value 'NO'";
|
||||
return ElementData::NO;
|
||||
}
|
||||
|
||||
QString ElementData::terminalTypeToString(ElementData::TerminalType type)
|
||||
{
|
||||
switch (type) {
|
||||
case ElementData::TTGeneric :
|
||||
return QString("generic");
|
||||
case ElementData::Fuse :
|
||||
return QString("fuse");
|
||||
case ElementData::Sectional:
|
||||
return QString("sectional");
|
||||
case ElementData::Diode:
|
||||
return QString("diode");
|
||||
}
|
||||
}
|
||||
|
||||
ElementData::TerminalType ElementData::terminalTypeFromString(const QString &string)
|
||||
{
|
||||
if (string == "generic") {
|
||||
return ElementData::TTGeneric;
|
||||
} else if (string == "fuse") {
|
||||
return ElementData::Fuse;
|
||||
} else if (string == "sectional") {
|
||||
return ElementData::Sectional;
|
||||
} else if (string == "diode") {
|
||||
return ElementData::Diode;
|
||||
}
|
||||
|
||||
qDebug() << "ElementData::terminalTypeFromString : string : "
|
||||
<< string
|
||||
<< " don't exist, return failsafe value 'generic'";
|
||||
return ElementData::TTGeneric;
|
||||
}
|
||||
|
||||
QString ElementData::terminalFunctionToString(ElementData::TerminalFunction function)
|
||||
{
|
||||
switch (function) {
|
||||
case ElementData::TFGeneric:
|
||||
return QString("generic");
|
||||
case ElementData::Phase:
|
||||
return QString ("phase");
|
||||
case ElementData::Neutral:
|
||||
return QString("neutral");
|
||||
case ElementData::PE:
|
||||
return QString("pe");
|
||||
}
|
||||
}
|
||||
|
||||
ElementData::TerminalFunction ElementData::terminalFunctionFromString(const QString &string)
|
||||
{
|
||||
if (string == "generic") {
|
||||
return ElementData::TFGeneric;
|
||||
} else if (string == "phase") {
|
||||
return ElementData::Phase;
|
||||
} else if (string == "neutral") {
|
||||
return ElementData::Neutral;
|
||||
} else if (string == "pe") {
|
||||
return ElementData::PE;
|
||||
}
|
||||
|
||||
qDebug() << "ElementData::terminalFunctionFromString : string : "
|
||||
<< string
|
||||
<< " don't exist, return failsafe value 'generic'";
|
||||
return ElementData::TFGeneric;
|
||||
}
|
||||
|
||||
void ElementData::kindInfoFromXml(const QDomElement &xml_element)
|
||||
{
|
||||
if (m_type == ElementData::Master ||
|
||||
m_type == ElementData::Slave ||
|
||||
m_type == ElementData::Terminale)
|
||||
{
|
||||
auto xml_kind = xml_element.firstChildElement("kindInformations");
|
||||
for (const auto &dom_elmt : QETXML::findInDomElement(xml_kind, "kindInformation"))
|
||||
{
|
||||
if (!dom_elmt.hasAttribute("name")) {
|
||||
continue;
|
||||
}
|
||||
auto name = dom_elmt.attribute("name");
|
||||
|
||||
if (m_type == ElementData::Master &&
|
||||
name == "type") {
|
||||
m_master_type = masterTypeFromString(dom_elmt.text());
|
||||
}
|
||||
else if (m_type == ElementData::Slave ) {
|
||||
if (name == "type") {
|
||||
m_slave_type = slaveTypeFromString(dom_elmt.text());
|
||||
} else if (name == "state") {
|
||||
m_slave_state = slaveStateFromString(dom_elmt.text());
|
||||
} else if (name == "number") {
|
||||
m_contact_count = dom_elmt.text().toInt();
|
||||
}
|
||||
}
|
||||
else if (m_type == ElementData::Terminale) {
|
||||
if (name == "type") {
|
||||
m_terminal_type = terminalTypeFromString(dom_elmt.text());
|
||||
} else if (name == "function") {
|
||||
m_terminal_function = terminalFunctionFromString(dom_elmt.text());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
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 ELEMENTDATA_H
|
||||
#define ELEMENTDATA_H
|
||||
|
||||
#include "propertiesinterface.h"
|
||||
#include "../diagramcontext.h"
|
||||
#include "../NameList/nameslist.h"
|
||||
|
||||
/**
|
||||
* @brief The ElementData class
|
||||
* WARNING
|
||||
* This class inherit from PropertiesInterface but
|
||||
* only fromXml is actually reimplemented.
|
||||
*/
|
||||
class ElementData : public PropertiesInterface
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
enum Type {
|
||||
Simple = 1,
|
||||
NextReport = 2,
|
||||
PreviousReport = 4,
|
||||
AllReport = 6,
|
||||
Master = 8,
|
||||
Slave = 16,
|
||||
Terminale = 32};
|
||||
Q_ENUM(Type)
|
||||
|
||||
enum MasterType {
|
||||
Coil,
|
||||
Protection,
|
||||
Commutator
|
||||
};
|
||||
Q_ENUM(MasterType)
|
||||
|
||||
enum SlaveType {
|
||||
SSimple,
|
||||
Power,
|
||||
DelayOn,
|
||||
DelayOff,
|
||||
delayOnOff
|
||||
};
|
||||
Q_ENUM(SlaveType)
|
||||
|
||||
enum SlaveState {
|
||||
NO,
|
||||
NC,
|
||||
SW
|
||||
};
|
||||
Q_ENUM(SlaveState)
|
||||
|
||||
enum TerminalType {
|
||||
TTGeneric,
|
||||
Fuse,
|
||||
Sectional,
|
||||
Diode
|
||||
};
|
||||
Q_ENUM(TerminalType)
|
||||
|
||||
enum TerminalFunction {
|
||||
TFGeneric,
|
||||
Phase,
|
||||
Neutral,
|
||||
PE
|
||||
};
|
||||
Q_ENUM(TerminalFunction)
|
||||
|
||||
ElementData() {}
|
||||
~ElementData() override {}
|
||||
|
||||
void toSettings(QSettings &settings, const QString prefix = QString()) const override;
|
||||
void fromSettings(const QSettings &settings, const QString prefix = QString()) override;
|
||||
QDomElement toXml(QDomDocument &xml_element) const override;
|
||||
bool fromXml(const QDomElement &xml_element) override;
|
||||
QDomElement kindInfoToXml(QDomDocument &document);
|
||||
|
||||
bool operator==(const ElementData &data) const;
|
||||
bool operator!=(const ElementData &data) const;
|
||||
|
||||
static QString typeToString(ElementData::Type type);
|
||||
static ElementData::Type typeFromString(const QString &string);
|
||||
|
||||
static QString masterTypeToString(ElementData::MasterType type);
|
||||
static ElementData::MasterType masterTypeFromString(const QString &string);
|
||||
|
||||
static QString slaveTypeToString (ElementData::SlaveType type);
|
||||
static ElementData::SlaveType slaveTypeFromString(const QString &string);
|
||||
|
||||
static QString slaveStateToString(ElementData::SlaveState type);
|
||||
static ElementData::SlaveState slaveStateFromString(const QString &string);
|
||||
|
||||
static QString terminalTypeToString(ElementData::TerminalType type);
|
||||
static ElementData::TerminalType terminalTypeFromString(const QString &string);
|
||||
|
||||
static QString terminalFunctionToString(ElementData::TerminalFunction function);
|
||||
static ElementData::TerminalFunction terminalFunctionFromString(const QString &string);
|
||||
|
||||
// must be public, because this class is a private member
|
||||
// of Element/ element editor and they must access this data
|
||||
ElementData::Type m_type = ElementData::Simple;
|
||||
|
||||
ElementData::MasterType m_master_type = ElementData::Coil;
|
||||
|
||||
ElementData::SlaveType m_slave_type = ElementData::SSimple;
|
||||
ElementData::SlaveState m_slave_state = ElementData::NO;
|
||||
|
||||
ElementData::TerminalType m_terminal_type = ElementData::TTGeneric;
|
||||
ElementData::TerminalFunction m_terminal_function = ElementData::TFGeneric;
|
||||
|
||||
int m_contact_count = 1;
|
||||
DiagramContext m_informations;
|
||||
NamesList m_names_list;
|
||||
QString m_drawing_information;
|
||||
|
||||
private:
|
||||
void kindInfoFromXml(const QDomElement &xml_element);
|
||||
};
|
||||
#endif // ELEMENTDATA_H
|
||||
@@ -1,6 +1,24 @@
|
||||
/*
|
||||
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 "terminaldata.h"
|
||||
|
||||
#include <QGraphicsObject>
|
||||
#include <QDebug>
|
||||
|
||||
TerminalData::TerminalData():
|
||||
PropertiesInterface()
|
||||
@@ -44,8 +62,8 @@ void TerminalData::setParent(QGraphicsObject* parent)
|
||||
void TerminalData::toSettings(QSettings &settings, const QString prefix) const
|
||||
|
||||
{
|
||||
Q_UNUSED(settings);
|
||||
Q_UNUSED(prefix);
|
||||
Q_UNUSED(settings)
|
||||
Q_UNUSED(prefix)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,8 +76,8 @@ void TerminalData::toSettings(QSettings &settings, const QString prefix) const
|
||||
*/
|
||||
void TerminalData::fromSettings(const QSettings &settings, const QString prefix)
|
||||
{
|
||||
Q_UNUSED(settings);
|
||||
Q_UNUSED(prefix);
|
||||
Q_UNUSED(settings)
|
||||
Q_UNUSED(prefix)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,20 +96,17 @@ QDomElement TerminalData::toXml(QDomDocument &xml_document) const
|
||||
{
|
||||
QDomElement xml_element = xml_document.createElement("terminal");
|
||||
|
||||
// write the position of the terminal
|
||||
// ecrit la position de la borne
|
||||
xml_element.setAttribute("x", QString("%1").arg(q->scenePos().x()));
|
||||
xml_element.setAttribute("y", QString("%1").arg(q->scenePos().y()));
|
||||
|
||||
// Write name and number to XML
|
||||
xml_element.setAttribute("uuid", m_uuid.toString());
|
||||
xml_element.setAttribute("name", m_name);
|
||||
|
||||
// write the orientation of the terminal
|
||||
// ecrit l'orientation de la borne
|
||||
xml_element.setAttribute("orientation",
|
||||
Qet::orientationToString(m_orientation));
|
||||
|
||||
xml_element.setAttribute("type", typeToString(m_type));
|
||||
|
||||
return(xml_element);
|
||||
}
|
||||
|
||||
@@ -137,5 +152,45 @@ bool TerminalData::fromXml (const QDomElement &xml_element)
|
||||
m_orientation = Qet::orientationFromString(
|
||||
xml_element.attribute("orientation"));
|
||||
|
||||
m_type = typeFromString(xml_element.attribute("type"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalData::typeToString
|
||||
* @param type
|
||||
* @return type into a QString
|
||||
*/
|
||||
QString TerminalData::typeToString(TerminalData::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case Generic:
|
||||
return QString("Generic");
|
||||
case Inner :
|
||||
return QString("Inner");
|
||||
case Outer :
|
||||
return QString("Outer");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalData::typeFromString
|
||||
* @param string
|
||||
* @return The type describe in string to TerminalData::Type.
|
||||
* if string doesn't describe a type, TerminalData::Generic is returned
|
||||
*/
|
||||
TerminalData::Type TerminalData::typeFromString(const QString &string)
|
||||
{
|
||||
if (string == "Generic") {
|
||||
return TerminalData::Generic;
|
||||
} else if (string == "Inner") {
|
||||
return TerminalData::Inner;
|
||||
} else if (string == "Outer") {
|
||||
return TerminalData::Outer;
|
||||
} else {
|
||||
qDebug() << "TerminalData::typeFromString, argument string is invalid"
|
||||
" failsafe type 'TerminalData::Generic' is returned";
|
||||
return TerminalData::Generic;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
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 TERMINALDATA_H
|
||||
#define TERMINALDATA_H
|
||||
|
||||
@@ -18,10 +35,19 @@ class QGraphicsObject;
|
||||
*/
|
||||
class TerminalData : public PropertiesInterface
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
enum Type {
|
||||
Generic,
|
||||
Inner,
|
||||
Outer
|
||||
};
|
||||
Q_ENUM(Type)
|
||||
|
||||
TerminalData();
|
||||
TerminalData(QGraphicsObject* parent);
|
||||
~TerminalData();
|
||||
~TerminalData() override;
|
||||
|
||||
void init();
|
||||
|
||||
@@ -33,6 +59,9 @@ class TerminalData : public PropertiesInterface
|
||||
QDomElement toXml(QDomDocument &xml_element) const override;
|
||||
bool fromXml(const QDomElement &xml_element) override;
|
||||
|
||||
static QString typeToString(TerminalData::Type type);
|
||||
static TerminalData::Type typeFromString(const QString &string);
|
||||
|
||||
// must be public, because this class is a private member
|
||||
// of PartTerminal/Terminal and they must access this data
|
||||
public:
|
||||
@@ -46,7 +75,7 @@ class TerminalData : public PropertiesInterface
|
||||
Position of the second point of the terminal
|
||||
in scene coordinates
|
||||
*/
|
||||
QPointF second_point;
|
||||
QPointF m_second_point;
|
||||
/**
|
||||
@brief m_uuid
|
||||
Uuid of the terminal.
|
||||
@@ -80,6 +109,9 @@ class TerminalData : public PropertiesInterface
|
||||
PartTerminal and Terminal have access to it.
|
||||
*/
|
||||
QPointF m_pos;
|
||||
|
||||
TerminalData::Type m_type = TerminalData::Generic;
|
||||
|
||||
private:
|
||||
QGraphicsObject* q{nullptr};
|
||||
};
|
||||
|
||||
@@ -1,74 +1,77 @@
|
||||
/**
|
||||
* pugixml parser - version 1.10
|
||||
* --------------------------------------------------------
|
||||
* Copyright (C) 2006-2019, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
|
||||
* Report bugs and download new versions at https://pugixml.org/
|
||||
*
|
||||
* This library is distributed under the MIT License. See notice at the end
|
||||
* of this file.
|
||||
*
|
||||
* This work is based on the pugxml parser, which is:
|
||||
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
|
||||
*/
|
||||
|
||||
#ifndef HEADER_PUGICONFIG_HPP
|
||||
#define HEADER_PUGICONFIG_HPP
|
||||
|
||||
// Uncomment this to enable wchar_t mode
|
||||
// #define PUGIXML_WCHAR_MODE
|
||||
|
||||
// Uncomment this to enable compact mode
|
||||
// #define PUGIXML_COMPACT
|
||||
|
||||
// Uncomment this to disable XPath
|
||||
// #define PUGIXML_NO_XPATH
|
||||
|
||||
// Uncomment this to disable STL
|
||||
// #define PUGIXML_NO_STL
|
||||
|
||||
// Uncomment this to disable exceptions
|
||||
// #define PUGIXML_NO_EXCEPTIONS
|
||||
|
||||
// Set this to control attributes for public classes/functions, i.e.:
|
||||
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
|
||||
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
|
||||
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
|
||||
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
|
||||
|
||||
// Tune these constants to adjust memory-related behavior
|
||||
// #define PUGIXML_MEMORY_PAGE_SIZE 32768
|
||||
// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
|
||||
// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
|
||||
|
||||
// Uncomment this to switch to header-only version
|
||||
// #define PUGIXML_HEADER_ONLY
|
||||
|
||||
// Uncomment this to enable long long support
|
||||
// #define PUGIXML_HAS_LONG_LONG
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Copyright (c) 2006-2019 Arseny Kapoulkine
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* pugixml parser - version 1.11
|
||||
* --------------------------------------------------------
|
||||
* Copyright (C) 2006-2020, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
|
||||
* Report bugs and download new versions at https://pugixml.org/
|
||||
*
|
||||
* This library is distributed under the MIT License. See notice at the end
|
||||
* of this file.
|
||||
*
|
||||
* This work is based on the pugxml parser, which is:
|
||||
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
|
||||
*/
|
||||
|
||||
#ifndef HEADER_PUGICONFIG_HPP
|
||||
#define HEADER_PUGICONFIG_HPP
|
||||
|
||||
// Uncomment this to enable wchar_t mode
|
||||
// #define PUGIXML_WCHAR_MODE
|
||||
|
||||
// Uncomment this to enable compact mode
|
||||
// #define PUGIXML_COMPACT
|
||||
|
||||
// Uncomment this to disable XPath
|
||||
// #define PUGIXML_NO_XPATH
|
||||
|
||||
// Uncomment this to disable STL
|
||||
// #define PUGIXML_NO_STL
|
||||
|
||||
// Uncomment this to disable exceptions
|
||||
// #define PUGIXML_NO_EXCEPTIONS
|
||||
|
||||
// Set this to control attributes for public classes/functions, i.e.:
|
||||
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
|
||||
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
|
||||
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
|
||||
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
|
||||
|
||||
// Tune these constants to adjust memory-related behavior
|
||||
// #define PUGIXML_MEMORY_PAGE_SIZE 32768
|
||||
// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
|
||||
// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
|
||||
|
||||
// Tune this constant to adjust max nesting for XPath queries
|
||||
// #define PUGIXML_XPATH_DEPTH_LIMIT 1024
|
||||
|
||||
// Uncomment this to switch to header-only version
|
||||
// #define PUGIXML_HEADER_ONLY
|
||||
|
||||
// Uncomment this to enable long long support
|
||||
// #define PUGIXML_HAS_LONG_LONG
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Copyright (c) 2006-2020 Arseny Kapoulkine
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
+13020
-12948
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
Reference in New Issue
Block a user