Code_TYMPAN  4.4.0
Industrial site acoustic simulation
os.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) <2012-2024> <EDF-DTG> <FRANCE>
3  * This file is part of Code_TYMPAN (R).
4  * Code_TYMPAN (R) is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * Code_TYMPAN (R) is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  * See the GNU General Public License for more details.
12  * You should have received a copy of the GNU General Public License along
13  * with Code_TYMPAN (R). If not, see <https://www.gnu.org/licenses/>.
14  */
15 
21 #include <QCoreApplication>
22 #include <qmessagebox.h>
23 #include <QTimer>
24 
27 #include "Tympan/core/logging.h"
29 #include "Tympan/gui/app/PythonRunner.h" // <— NEW include
30 #include "os.h"
31 
32 #include <QThread>
33 #include <QEventLoop>
34 #include <QElapsedTimer>
35 #include <QProgressBar>
37 
38 // Helper: update label with elapsed time (French user-facing text)
39 static void set_elapsed_label_seconds(qint64 seconds)
40 {
41  const QString msg = QStringLiteral("Calcul acoustique en cours…\nTemps écoulé : %1 s").arg(seconds);
42  TYProgressManager::setMessage(msg.toUtf8().constData());
43 }
44 
45 bool python_gui(QStringList args)
46 {
48 
49 #if TY_USE_IHM
50  // Lazily create the progress dialog
51  if (!TYProgressManager::getProgressDialog())
52  TYProgressManager::create(getTYMainWnd(), "Calcul acoustique");
53  auto* dlg = TYProgressManager::getProgressDialog();
54  if (dlg)
55  dlg->setWindowModality(Qt::ApplicationModal);
56 
57  // Show a static (non-animated) progress bar + elapsed time label
58  TYProgressManager::set(100); // ensures the dialog is shown (0..100 range)
59  TYProgressManager::setProgress(0); // keep it fixed (no spinner)
60  // Hide the “%” text on the progress bar
61  if (dlg)
62  {
63  if (auto* bar = dlg->findChild<QProgressBar*>())
64  {
65  bar->setTextVisible(false);
66  }
67  else
68  {
69  auto* bar2 = new QProgressBar(dlg);
70  bar2->setRange(0, 100);
71  bar2->setValue(0);
72  bar2->setTextVisible(false);
73  dlg->setBar(bar2);
74  }
75  }
76  set_elapsed_label_seconds(0); // initial label
77 
78  // Elapsed time updater (1 Hz)
79  QElapsedTimer chrono;
80  chrono.start();
81  QTimer elapsedTimer;
82  elapsedTimer.setInterval(1000);
83  QObject::connect(&elapsedTimer, &QTimer::timeout,
84  [&] { set_elapsed_label_seconds(chrono.elapsed() / 1000); });
85  elapsedTimer.start();
86 
87  // Cancellation: hide dialog and propagate cancel to subprocess
88  bool userCanceled = false;
89  if (dlg)
90  {
91  QObject::connect(dlg, &QProgressDialog::canceled,
92  [&]
93  {
94  userCanceled = true;
95  elapsedTimer.stop();
96  dlg->hide();
98  });
99  dlg->raise();
100  dlg->activateWindow();
101  qApp->processEvents();
102  }
103 #endif // TY_USE_IHM
104 
105  // Run python() in a worker thread (keeps UI responsive)
106  QThread* thread = new QThread;
107  PythonRunner* runner = new PythonRunner(args);
108  runner->moveToThread(thread);
109 
110  bool computation_ok = false;
111  QString error_msg_qs;
112  QEventLoop waitLoop;
113 
114  QObject::connect(thread, &QThread::started, runner, &PythonRunner::run);
115  QObject::connect(runner, &PythonRunner::finished,
116  [&](bool ok, const QString& msg)
117  {
118  computation_ok = ok;
119  error_msg_qs = msg;
120  waitLoop.quit();
121  });
122  QObject::connect(runner, &PythonRunner::finished, thread, &QThread::quit);
123  QObject::connect(thread, &QThread::finished, runner, &QObject::deleteLater);
124  QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);
125 
126  thread->start();
127  waitLoop.exec(); // UI remains responsive; only the label is updated each second
128 
129 #if TY_USE_IHM
130  // Cleanup timers/UI
131  elapsedTimer.stop();
132  const bool cancelled = python_cancel_was_requested();
133 
134  if (!computation_ok)
135  {
136  if (dlg)
137  dlg->hide();
138  if (cancelled || userCanceled)
139  {
140  QMessageBox msgBox;
141  msgBox.setIcon(QMessageBox::Information);
142  msgBox.setText("Calcul acoustique interrompu par l'utilisateur.");
143  msgBox.exec();
144  }
145  else
146  {
148  logger.error("Echec du calcul acoustique: %s", error_msg_qs.toStdString().c_str());
149  QMessageBox msgBox;
150  msgBox.setIcon(QMessageBox::Critical);
151  msgBox.setText("Echec du calcul acoustique. Veuillez consulter le journal d'erreurs.\n");
152  msgBox.exec();
153  }
154  }
155  else
156  {
157  TYProgressManager::stepToEnd(); // success → close cleanly
158  }
159 #endif // TY_USE_IHM
160 
161  return computation_ok;
162 }
Worker object that runs the blocking python(...) call off the GUI thread.
TYMainWindow * getTYMainWnd()
Retourne le pointeur sur la fenetre principale.
pour l'application Tympan (fichier header)
virtual void error(const char *message,...)
Definition: logging.cpp:127
static OMessageManager * get()
Definition: logging.cpp:108
Runs the blocking python(...) computation in a worker thread.
Definition: PythonRunner.h:36
void finished(bool ok, QString errorMsg)
Emitted when the computation completes.
void run()
Call this slot to start the computation (meant to be invoked from the worker thread).
static void setCurrentQtDir()
Indique Ã&#160; Qt le chemin du répertoire courant.
static void set(int totalSteps, int stepSize=1)
static void create(QWidget *pParent, const char *name=0)
static void stepToEnd()
bool python_gui(QStringList args)
Launch a Python-driven computation with a GUI progress dialog.
Definition: os.cpp:45
Utilities for interactions between the GUI and the operating system (headers).
void python_request_cancel()
Request cancellation of the currently running Python subprocess (UI hook, stage A).
bool python_cancel_was_requested()
Query whether a cancellation was requested since the last call to python().
Utilities to interact with Python subprocesses from the Tympan application.