Replace qetsingleapplication by singleApplication.

See : https://github.com/itay-grudev/SingleApplication


git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@5481 bfdf4180-ca20-0410-9c96-a3a8aa849046
This commit is contained in:
blacksun
2018-08-15 12:45:55 +00:00
parent d2a6c23360
commit 2ba5be7ecd
27 changed files with 2165 additions and 277 deletions

View File

@@ -16,6 +16,8 @@
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qetapp.h"
#include "singleapplication.h"
#include "qet.h"
/**
* @brief main
@@ -37,5 +39,21 @@ int main(int argc, char **argv)
#else
qputenv("QT_DEVICE_PIXEL_RATIO", QByteArray("auto"));
#endif
return(QETApp(argc, argv).exec());
SingleApplication app(argc, argv);
if (app.isSecondary())
{
QStringList strl = app.arguments();
//Remove the first argument, it's the binary file
strl.takeFirst();
QString message = "launched-with-args: " + QET::joinWithSpaces(strl);
app.sendMessage(message.toUtf8());
return 0;
}
QETApp qetapp;
QObject::connect(&app, &SingleApplication::receivedMessage, &qetapp, &QETApp::receiveMessage);
return app.exec();
}

View File

@@ -60,50 +60,28 @@ RecentFiles *QETApp::m_elements_recent_files = nullptr;
TitleBlockTemplate *QETApp::default_titleblock_template_ = nullptr;
QString QETApp::m_user_common_elements_dir = QString();
QString QETApp::m_user_custom_elements_dir = QString();
QETApp *QETApp::m_qetapp = nullptr;
/**
Constructeur
@param argc Nombre d'arguments passes a l'application
@param argv Arguments passes a l'application
*/
QETApp::QETApp(int &argc, char **argv) :
QETSingleApplication(argc, argv, QString("qelectrotech-" + QETApp::userName())),
* @brief QETApp::QETApp
*/
QETApp::QETApp() :
m_splash_screen(nullptr),
non_interactive_execution_(false)
{
m_qetapp = this;
parseArguments();
initConfiguration();
initLanguage();
QET::Icons::initIcons();
initStyle();
if (!non_interactive_execution_ && isRunning()) {
// envoie les arguments a l'instance deja existante
non_interactive_execution_ = sendMessage(
"launched-with-args: " +
QET::joinWithSpaces(QStringList(qet_arguments_.arguments()))
);
}
if (non_interactive_execution_) {
std::exit(EXIT_SUCCESS);
}
initSplashScreen();
initSystemTray();
// prise en compte des messages des autres instances
connect(this, SIGNAL(messageAvailable(QString)), this, SLOT(messageReceived(const QString&)));
// nettoyage avant de quitter l'application
connect(this, SIGNAL(aboutToQuit()), this, SLOT(cleanup()));
// connexion pour le signalmapper
connect(&signal_map, SIGNAL(mapped(QWidget *)), this, SLOT(invertMainWindowVisibility(QWidget *)));
setQuitOnLastWindowClosed(false);
connect(this, SIGNAL(lastWindowClosed()), this, SLOT(checkRemainingWindows()));
qApp->setQuitOnLastWindowClosed(false);
connect(qApp, &QApplication::lastWindowClosed, this, &QETApp::checkRemainingWindows);
setSplashScreenStep(tr("Chargement... Initialisation du cache des collections d'éléments", "splash screen caption"));
if (!collections_cache_) {
@@ -112,14 +90,16 @@ QETApp::QETApp(int &argc, char **argv) :
collections_cache_->setLocale(langFromSetting());
}
// on ouvre soit les fichiers passes en parametre soit un nouvel editeur de projet
if (qet_arguments_.files().isEmpty()) {
if (qet_arguments_.files().isEmpty())
{
setSplashScreenStep(tr("Chargement... Éditeur de schéma", "splash screen caption"));
new QETDiagramEditor();
} else {
} else
{
setSplashScreenStep(tr("Chargement... Ouverture des fichiers", "splash screen caption"));
openFiles(qet_arguments_);
}
buildSystemTrayMenu();
m_splash_screen -> hide();
@@ -160,8 +140,9 @@ QETApp::~QETApp()
/**
@return l'instance de la QETApp
*/
QETApp *QETApp::instance() {
return(static_cast<QETApp *>(qApp));
QETApp *QETApp::instance()
{
return m_qetapp;
}
/**
@@ -176,7 +157,7 @@ void QETApp::setLanguage(const QString &desired_language) {
if (!qtTranslator.load("qt_" + desired_language, qt_l10n_path)) {
qtTranslator.load("qt_" + desired_language, languages_path);
}
installTranslator(&qtTranslator);
qApp->installTranslator(&qtTranslator);
// charge les traductions pour l'application QET
if (!qetTranslator.load("qet_" + desired_language, languages_path)) {
@@ -186,7 +167,7 @@ void QETApp::setLanguage(const QString &desired_language) {
qetTranslator.load("qet_en", languages_path);
}
}
installTranslator(&qetTranslator);
qApp->installTranslator(&qetTranslator);
QString ltr_special_string = tr(
"LTR",
@@ -211,7 +192,7 @@ QString QETApp::langFromSetting()
Switches the application to the provided layout.
*/
void QETApp::switchLayout(Qt::LayoutDirection direction) {
setLayoutDirection(direction);
qApp->setLayoutDirection(direction);
}
/**
@@ -440,26 +421,6 @@ TitleBlockTemplatesCollection *QETApp::titleBlockTemplatesCollection(const QStri
return(nullptr);
}
/**
@return le nom de l'utilisateur courant
*/
QString QETApp::userName() {
QProcess * process = new QProcess();
QString str;
#ifndef Q_OS_WIN32
// return(QString(getenv("USER")));
str = (process->processEnvironment()).value("USER", "UNKNOWN");
delete process;
return(str);
#else
// return(QString(getenv("USERNAME")));
str = (process->processEnvironment()).value("USERNAME", "UNKNOWN");
delete process;
return(str);
#endif
}
/**
* @brief QETApp::commonElementsDir
* @return the dir path of the common elements collection.
@@ -1015,11 +976,18 @@ QList<QETElementEditor *> QETApp::elementEditors(QETProject *project) {
return(editors);
}
/**
Nettoie certaines choses avant que l'application ne quitte
*/
void QETApp::cleanup() {
m_qsti -> hide();
void QETApp::receiveMessage(int instanceId, QByteArray message)
{
Q_UNUSED(instanceId);
QString str(message);
if (str.startsWith("launched-with-args: "))
{
QString my_message(str.mid(20));
QStringList args_list = QET::splitWithSpaces(my_message);
openFiles(QETArguments(args_list));
}
}
/**
@@ -1028,7 +996,7 @@ void QETApp::cleanup() {
*/
template <class T> QList<T *> QETApp::detectWindows() const {
QList<T *> windows;
foreach(QWidget *widget, topLevelWidgets()) {
foreach(QWidget *widget, qApp->topLevelWidgets()) {
if (!widget -> isWindow()) continue;
if (T *window = qobject_cast<T *>(widget)) {
windows << window;
@@ -1118,8 +1086,8 @@ if defined(Q_OS_WIN)
*/
void QETApp::useSystemPalette(bool use) {
if (use) {
setPalette(initial_palette_);
setStyleSheet(
qApp->setPalette(initial_palette_);
qApp->setStyleSheet(
"QTabBar::tab:!selected { background-color: transparent; }"
"QAbstractScrollArea#mdiarea {"
"background-color -> setPalette(initial_palette_);"
@@ -1129,7 +1097,7 @@ void QETApp::useSystemPalette(bool use) {
QFile file(configDir() + "style.css");
file.open(QFile::ReadOnly);
QString styleSheet = QLatin1String(file.readAll());
setStyleSheet(styleSheet);
qApp->setStyleSheet(styleSheet);
file.close();
}
}
@@ -1140,7 +1108,7 @@ void QETApp::useSystemPalette(bool use) {
*/
void QETApp::quitQET() {
if (closeEveryEditor()) {
quit();
qApp->quit();
}
}
@@ -1158,25 +1126,12 @@ void QETApp::checkRemainingWindows() {
QTimer::singleShot(500, this, SLOT(checkRemainingWindows()));
} else {
if (!diagramEditors().count() && !elementEditors().count()) {
quit();
qApp->quit();
}
}
sleep = !sleep;
}
/**
Gere les messages recus
@param message Message recu
*/
void QETApp::messageReceived(const QString &message) {
if (message.startsWith("launched-with-args: ")) {
QString my_message(message.mid(20));
// les arguments sont separes par des espaces non echappes
QStringList args_list = QET::splitWithSpaces(my_message);
openFiles(QETArguments(args_list));
}
}
/**
Ouvre les fichiers passes en arguments
@param args Objet contenant des arguments ; les fichiers
@@ -1371,7 +1326,7 @@ void QETApp::openTitleBlockTemplateFiles(const QStringList &files_list) {
*/
void QETApp::configureQET() {
// determine le widget parent a utiliser pour le dialogue
QWidget *parent_widget = activeWindow();
QWidget *parent_widget = qApp->activeWindow();
// cree le dialogue
ConfigDialog cd;
@@ -1399,7 +1354,7 @@ void QETApp::configureQET() {
*/
void QETApp::aboutQET()
{
AboutQET aq(activeWindow());
AboutQET aq(qApp->activeWindow());
#ifdef Q_OS_MACOS
aq.setWindowFlags(Qt::Sheet);
@@ -1413,7 +1368,7 @@ void QETApp::aboutQET()
*/
QList<QWidget *> QETApp::floatingToolbarsAndDocksForMainWindow(QMainWindow *window) const {
QList<QWidget *> widgets;
foreach(QWidget *qw, topLevelWidgets()) {
foreach(QWidget *qw, qApp->topLevelWidgets()) {
if (!qw -> isWindow()) continue;
if (qobject_cast<QToolBar *>(qw) || qobject_cast<QDockWidget *>(qw)) {
if (qw -> parent() == window) widgets << qw;
@@ -1436,7 +1391,7 @@ QList<QWidget *> QETApp::floatingToolbarsAndDocksForMainWindow(QMainWindow *wind
*/
void QETApp::parseArguments() {
// recupere les arguments
QList<QString> arguments_list(arguments());
QList<QString> arguments_list(qApp->arguments());
// enleve le premier argument : il s'agit du fichier binaire
arguments_list.takeFirst();
@@ -1499,7 +1454,7 @@ void QETApp::setSplashScreenStep(const QString &message) {
if (!message.isEmpty()) {
m_splash_screen -> showMessage(message, Qt::AlignBottom | Qt::AlignLeft);
}
processEvents();
qApp->processEvents();
}
/**
@@ -1514,7 +1469,7 @@ void QETApp::initLanguage() {
* Setup the gui style
*/
void QETApp::initStyle() {
initial_palette_ = palette();
initial_palette_ = qApp->palette();
//Apply or not the system style
QSettings settings;
@@ -1823,7 +1778,7 @@ bool QETApp::event(QEvent *e) {
*/
void QETApp::printHelp() {
QString help(
tr("Usage : ") + QFileInfo(applicationFilePath()).fileName() + tr(" [options] [fichier]...\n\n") +
tr("Usage : ") + QFileInfo(qApp->applicationFilePath()).fileName() + tr(" [options] [fichier]...\n\n") +
tr("QElectroTech, une application de réalisation de schémas électriques.\n\n"
"Options disponibles : \n"
" --help Afficher l'aide sur les options\n"

View File

@@ -21,8 +21,8 @@
#include <QTranslator>
#include <QSystemTrayIcon>
#include <QPalette>
#include <QByteArray>
#include "qetsingleapplication.h"
#include "elementslocation.h"
#include "templatelocation.h"
#include "qetarguments.h"
@@ -50,12 +50,12 @@ class RecentFiles;
/**
This class represents the QElectroTech application.
*/
class QETApp : public QETSingleApplication
class QETApp : public QObject
{
Q_OBJECT
// constructors, destructor
public:
QETApp(int &, char **);
QETApp();
~QETApp() override;
private:
@@ -81,7 +81,6 @@ class QETApp : public QETSingleApplication
static QList<TitleBlockTemplatesCollection *> availableTitleBlockTemplatesCollections();
static TitleBlockTemplatesCollection *titleBlockTemplatesCollection(const QString &);
static QString userName();
static QString commonElementsDir();
static QString customElementsDir();
static QString commonElementsDirN();
@@ -148,6 +147,7 @@ class QETApp : public QETSingleApplication
// attributes
private:
static QETApp *m_qetapp;
QTranslator qtTranslator;
QTranslator qetTranslator;
QSystemTrayIcon *m_qsti;
@@ -207,7 +207,6 @@ class QETApp : public QETSingleApplication
void useSystemPalette(bool);
void quitQET();
void checkRemainingWindows();
void messageReceived(const QString &);
void openFiles(const QETArguments &);
void openProjectFiles(const QStringList &);
void openElementFiles(const QStringList &);
@@ -217,9 +216,7 @@ class QETApp : public QETSingleApplication
void openTitleBlockTemplateFiles(const QStringList &);
void configureQET();
void aboutQET();
private slots:
void cleanup();
void receiveMessage(int instanceId, QByteArray message);
private:
template <class T> QList<T *> detectWindows() const;

View File

@@ -1,120 +0,0 @@
/*
Copyright 2006-2017 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
MERCHANTAvBILITY 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 "qetsingleapplication.h"
#include <QLocalSocket>
const int QETSingleApplication::timeout_ = 10000;
/**
Constructeur
@param argc Nombre d'arguments passes au programme par le systeme
@param argv Tableau des arguments passes au programme par le systeme
@param unique_key Cle unique
*/
QETSingleApplication::QETSingleApplication(int &argc, char **argv, const QString& unique_key) :
QApplication(argc, argv),
unique_key_(unique_key)
{
// verifie s'il y a un segment de memoire partage correspondant a la cle unique
#if defined (Q_OS_OS2)
#define QT_NO_SHAREDMEMORY
{
#else
shared_memory_.setKey(unique_key_);
if (shared_memory_.attach()) {
// oui : l'application est deja en cours d'execution
is_running_ = true;
} else {
// non : il s'agit du premier demarrage de l'application pour cette cle unique
is_running_ = false;
// initialisation du segment de memoire partage
if (!shared_memory_.create(1)) {
qDebug() << "QETSingleApplication::QETSingleApplication() : Impossible de créer l'instance unique" << qPrintable(unique_key_);
return;
}
#endif
// initialisation d'un serveur local pour recevoir les messages des autres instances
local_server_ = new QLocalServer(this);
connect(local_server_, SIGNAL(newConnection()), this, SLOT(receiveMessage()));
// la cle unique est egalement utilise pour le serveur
local_server_ -> listen(unique_key_);
}
}
/**
Destructeur
*/
QETSingleApplication::~QETSingleApplication() {
}
/**
Slot gerant la reception des messages.
Lorsque l'application recoit un message, ce slot emet le signal
messageAvailable avec le message recu.
*/
void QETSingleApplication::receiveMessage() {
QLocalSocket *local_socket = local_server_ -> nextPendingConnection();
if (!local_socket -> waitForReadyRead(timeout_)) {
qDebug() << "QETSingleApplication::receiveMessage() :" << qPrintable(local_socket -> errorString()) << "(" << qPrintable(unique_key_) << ")";
return;
}
QByteArray byteArray = local_socket -> readAll();
QString message = QString::fromUtf8(byteArray.constData());
emit(messageAvailable(message));
local_socket -> disconnectFromServer();
}
/**
@return true si l'application est deja en cours d'execution
*/
bool QETSingleApplication::isRunning() {
return(is_running_);
}
/**
Envoie un message a l'application. Si celle-ci n'est pas en cours
d'execution, cette methode ne fait rien.
@param message Message a transmettre a l'application
@return true si le message a ete tranmis, false sinon
*/
bool QETSingleApplication::sendMessage(const QString &message) {
// l'application doit etre en cours d'execution
if (!is_running_) {
return(false);
}
// se connecte a l'application, avec gestion du timeout
QLocalSocket local_socket(this);
local_socket.connectToServer(unique_key_, QIODevice::WriteOnly);
if (!local_socket.waitForConnected(timeout_)) {
qDebug() << "QETSingleApplication::sendMessage() :" << qPrintable(local_socket.errorString()) << "(" << qPrintable(unique_key_) << ")";
return(false);
}
// envoi du message, avec gestion du timeout
local_socket.write(message.toUtf8());
if (!local_socket.waitForBytesWritten(timeout_)) {
qDebug() << "QETSingleApplication::sendMessage() :" << qPrintable(local_socket.errorString()) << "(" << qPrintable(unique_key_) << ")";
return(false);
}
// deconnexion
local_socket.disconnectFromServer();
return(true);
}

View File

@@ -1,60 +0,0 @@
/*
Copyright 2006-2017 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 QET_SINGLE_APPLICATION_H
#define QET_SINGLE_APPLICATION_H
#include <QApplication>
#include <QSharedMemory>
#include <QLocalServer>
/**
This class represents a Qt Application executing only a single instance
depending on a unique string key.
*/
class QETSingleApplication : public QApplication {
Q_OBJECT
// constructors, destructor
public:
QETSingleApplication(int &, char **, const QString&);
~QETSingleApplication() override;
private:
QETSingleApplication(const QETSingleApplication &);
// methods
public:
bool isRunning();
bool sendMessage(const QString &);
public slots:
void receiveMessage();
signals:
void messageAvailable(QString);
// attributes
private:
bool is_running_;
QString unique_key_;
#if defined (Q_OS_OS2)
#define QT_NO_SHAREDMEMORY
#else
QSharedMemory shared_memory_;
#endif
QLocalServer *local_server_;
static const int timeout_;
};
#endif