L'application se lance desormais une seule fois par utilisateur

git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@348 bfdf4180-ca20-0410-9c96-a3a8aa849046
This commit is contained in:
xavierqet 2008-07-17 19:25:57 +00:00
parent f4b828a3cd
commit 429d7e55a2
7 changed files with 307 additions and 34 deletions

View File

@ -76,6 +76,7 @@ HEADERS += aboutqet.h \
qet.h \
qetapp.h \
qetdiagrameditor.h \
qetsingleapplication.h \
qgimanager.h \
terminal.h \
editor/arceditor.h \
@ -142,6 +143,7 @@ SOURCES += aboutqet.cpp \
qet.cpp \
qetapp.cpp \
qetdiagrameditor.cpp \
qetsingleapplication.cpp \
qgimanager.cpp \
terminal.cpp \
editor/arceditor.cpp \
@ -171,7 +173,7 @@ SOURCES += aboutqet.cpp \
RESOURCES += qelectrotech.qrc
TRANSLATIONS += lang/qet_en.ts lang/qt_fr.ts
RC_FILE = ico/windows_icon/application_icon/qelectrotech.rc
QT += xml svg
QT += xml svg network
CONFIG += debug_and_release warn_on
TARGET = qelectrotech

View File

@ -32,13 +32,37 @@ QString QETApp::diagram_texts_font = QString();
@param argc Nombre d'arguments passes a l'application
@param argv Arguments passes a l'application
*/
QETApp::QETApp(int &argc, char **argv) : QApplication(argc, argv) {
QETApp::QETApp(int &argc, char **argv) :
QETSingleApplication(argc, argv, QString("qelectrotech-" + QETApp::userName()))
{
// selectionne le langage du systeme
QString system_language = QLocale::system().name().left(2);
setLanguage(system_language);
// parse les arguments
foreach(QString argument, arguments()) {
// booleen indiquant si l'application va se terminer immediatement apres un court traitement
bool must_exit = false;
// parse les arguments en
QStringList files; // liste des fichiers
QStringList options; // liste des options
// recupere les arguments
QStringList arguments_list(arguments());
arguments_list.pop_front(); // ignore le premier (= chemin de l'executable)
// separe les fichiers des options
foreach(QString argument, arguments_list) {
QFileInfo argument_info(argument);
if (argument_info.exists()) {
// on exprime les chemins des fichiers en absolu
files << argument_info.canonicalFilePath();
} else {
options << argument;
}
}
// parse les options
foreach(QString argument, options) {
#ifdef QET_ALLOW_OVERRIDE_CED_OPTION
QString ced_arg("--common-elements-dir=");
if (argument.startsWith(ced_arg)) {
@ -53,7 +77,7 @@ QETApp::QETApp(int &argc, char **argv) : QApplication(argc, argv) {
overrideConfigDir(cd_value);
}
#endif
bool must_exit = false;
if (argument == QString("--help")) {
printHelp();
must_exit = true;
@ -64,11 +88,23 @@ QETApp::QETApp(int &argc, char **argv) : QApplication(argc, argv) {
printLicense();
must_exit = true;
}
if (must_exit) {
std::exit(EXIT_SUCCESS);
}
}
if (!must_exit && isRunning()) {
QStringList abs_arg_list(options);
abs_arg_list << files;
// envoie les arguments a l'instance deja existante
must_exit = sendMessage("launched-with-args: " + abs_arg_list.join(" "));
}
if (must_exit) {
std::exit(EXIT_SUCCESS);
}
// 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()));
@ -125,10 +161,6 @@ QETApp::QETApp(int &argc, char **argv) : QApplication(argc, argv) {
diagram_texts_font = qet_settings -> value("diagramfont", "Sans Serif").toString();
// Creation et affichage d'un editeur de schema
QStringList files;
foreach(QString argument, arguments()) {
if (QFileInfo(argument).exists()) files << argument;
}
new QETDiagramEditor(files);
buildSystemTrayMenu();
}
@ -227,6 +259,17 @@ void QETApp::newElementEditor() {
new QETElementEditor();
}
/**
@return le nom de l'utilisateur courant
*/
QString QETApp::userName() {
#ifndef Q_OS_WIN32
return(QString(getenv("USER")));
#else
return(QString(getenv("USERNAME")));
#endif
}
/**
Renvoie le dossier des elements communs, c-a-d le chemin du dossier dans
lequel QET doit chercher les definitions XML des elements de la collection QET.
@ -471,6 +514,58 @@ void QETApp::checkRemainingWindows() {
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));
QStringList files_list = my_message.split(' ');
openFiles(files_list);
}
}
/**
Ouvre une liste de fichiers.
Les fichiers sont ouverts dans le premier editeur de schemas visible venu.
Sinon, le premier editeur de schemas existant venu devient visible et est
utilise. S'il n'y a aucun editeur de schemas ouvert, un nouveau est cree et
utilise.
@param files_list Liste des fichiers a ouvrir
*/
void QETApp::openFiles(const QStringList &files_list) {
if (files_list.isEmpty()) return;
// liste des editeurs de schema ouverts
QList<QETDiagramEditor *> diagrams_editors = diagramEditors();
// s'il y a des editeur de schemas ouvert, on cherche ceux qui sont visibles
if (diagrams_editors.count()) {
QList<QETDiagramEditor *> visible_diagrams_editors;
foreach(QETDiagramEditor *de, diagrams_editors) {
if (de -> isVisible()) visible_diagrams_editors << de;
}
// on choisit soit le premier visible soit le premier tout court
QETDiagramEditor *de_open;
if (visible_diagrams_editors.count()) {
de_open = visible_diagrams_editors.first();
} else {
de_open = diagrams_editors.first();
de_open -> setVisible(true);
}
// ouvre les fichiers dans l'editeur ainsi choisi
foreach(QString file, files_list) {
de_open -> openAndAddDiagram(file);
}
} else {
// cree un nouvel editeur qui ouvrira les fichiers
new QETDiagramEditor(files_list);
}
}
/**
@param window fenetre dont il faut trouver les barres d'outils et dock flottants
@return les barres d'outils et dock flottants de la fenetre
@ -553,8 +648,9 @@ void QETApp::fetchWindowStats(const QList<QETDiagramEditor *> &diagrams, const Q
every_editor_reduced = every_element_reduced && every_diagram_reduced;
}
#ifdef Q_OS_DARWIN
/**
Gere les evenement
Gere les evenements, en particulier l'evenement FileOpen sous MacOs.
@param e Evenement a gerer
*/
bool QETApp::event(QEvent *e) {
@ -562,30 +658,13 @@ bool QETApp::event(QEvent *e) {
if (e -> type() == QEvent::FileOpen) {
// nom du fichier a ouvrir
QString filename = static_cast<QFileOpenEvent *>(e) -> file();
// liste des editeurs de schema ouverts
QList<QETDiagramEditor *> diagrams_editors = diagramEditors();
if (diagrams_editors.count()) {
// s'il y a des editeur de schemas ouvert, on cherche ceux qui sont visibles
QList<QETDiagramEditor *> visible_diagrams_editors;
foreach(QETDiagramEditor *de, diagrams_editors) {
if (de -> isVisible()) visible_diagrams_editors << de;
}
// on choisit soit le premier visible soit le premier tout court
QETDiagramEditor *de_open;
if (visible_diagrams_editors.count()) {
de_open = visible_diagrams_editors.first();
} else {
de_open = diagrams_editors.first();
de_open -> setVisible(true);
}
} else {
new QETDiagramEditor(QStringList() << filename);
}
openFiles(QStringList() << filename);
return(true);
} else {
return(QApplication::event(e));
}
}
#endif
/**
Affiche l'aide et l'usage sur la sortie standard

View File

@ -17,7 +17,7 @@
*/
#ifndef QET_APP_H
#define QET_APP_H
#include <QApplication>
#include "qetsingleapplication.h"
#include <QTranslator>
#include <QtGui>
class QETDiagramEditor;
@ -26,7 +26,7 @@ class QETElementEditor;
Cette classe represente l'application QElectroTech.
*/
class QETApp : public QApplication {
class QETApp : public QETSingleApplication {
Q_OBJECT
// constructeurs, destructeur
public:
@ -43,6 +43,7 @@ class QETApp : public QApplication {
static void printVersion();
static void printLicense();
static QString userName();
static QString commonElementsDir();
static QString customElementsDir();
static QString configDir();
@ -66,7 +67,9 @@ class QETApp : public QApplication {
static QString diagramTextsFont();
protected:
#ifdef Q_OS_DARWIN
bool event(QEvent *);
#endif
// attributs
private:
@ -109,6 +112,8 @@ class QETApp : public QApplication {
void invertMainWindowVisibility(QWidget *);
void quitQET();
void checkRemainingWindows();
void messageReceived(const QString &);
void openFiles(const QStringList &);
// methodes privees
private slots:

View File

@ -569,6 +569,16 @@ bool QETDiagramEditor::openDiagram() {
open_dialog_dir.absolutePath(),
tr("Sch\351mas QElectroTech (*.qet);;Fichiers XML (*.xml);;Tous les fichiers (*)")
);
return(openAndAddDiagram(nom_fichier));
}
/**
Cette methode ouvre un fichier.
@param nom_fichier Chemin du fichier a ouvrir
@return true si l'ouverture a reussi, false sinon
*/
bool QETDiagramEditor::openAndAddDiagram(const QString &nom_fichier) {
if (nom_fichier.isEmpty()) return(false);
open_dialog_dir = QDir(nom_fichier);

View File

@ -63,6 +63,7 @@ class QETDiagramEditor : public QMainWindow {
bool save();
bool newDiagram();
bool openDiagram();
bool openAndAddDiagram(const QString &);
bool closeDiagram();
void slot_editInfos();
void slot_cut();

120
qetsingleapplication.cpp Normal file
View File

@ -0,0 +1,120 @@
/*
Copyright 2006-2008 Xavier Guerrin
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
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() << "Impossible de cr\351er l'instance unique.";
qDebug() << "Used key is:" << unique_key_;
return;
}
// 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() << local_socket -> errorString().toLatin1();
qDebug() << "Used key is:" << 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() << local_socket.errorString().toLatin1();
qDebug() << "Used key is:" << unique_key_;
return(false);
}
// envoi du message, avec gestion du timeout
local_socket.write(message.toUtf8());
if (!local_socket.waitForBytesWritten(timeout_)) {
qDebug() << local_socket.errorString().toLatin1();
qDebug() << "Used key is:" << unique_key_;
return(false);
}
// deconnexion
local_socket.disconnectFromServer();
return(true);
}

56
qetsingleapplication.h Normal file
View File

@ -0,0 +1,56 @@
/*
Copyright 2006-2008 Xavier Guerrin
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>
/**
Cette classe represente une application Qt ne s'executant qu'en un seul
exemplaire en fonction d'une cle unique (de type QString).
*/
class QETSingleApplication : public QApplication {
Q_OBJECT
// constructeurs, destructeur
public:
QETSingleApplication(int &, char **, const QString);
virtual ~QETSingleApplication();
private:
QETSingleApplication(const QETSingleApplication &);
// methodes
public:
bool isRunning();
bool sendMessage(const QString &);
public slots:
void receiveMessage();
signals:
void messageAvailable(QString);
// attributs
private:
bool is_running_;
QString unique_key_;
QSharedMemory shared_memory_;
QLocalServer *local_server_;
static const int timeout_;
};
#endif