mirror of
https://git.salome-platform.org/gitpub/modules/geom.git
synced 2024-12-25 17:00:35 +05:00
[bos #38044][EDF] (2023-T3) Support for automatic reparation. Initial commit for the process implementation.
This commit is contained in:
parent
4e90f531cf
commit
0c71d36f22
@ -35,6 +35,7 @@ IF(SALOME_BUILD_GUI)
|
||||
geomrepairadv_logger.py
|
||||
geomrepairadv_progress.py
|
||||
geomrepairadv_worker.py
|
||||
geomrepairadv_worker_messages.py
|
||||
locate_subshapes.py
|
||||
locate_subshapes_algo.py
|
||||
locate_subshapes_limits.py
|
||||
|
@ -22,30 +22,39 @@
|
||||
import inspect
|
||||
from traceback import format_exc
|
||||
|
||||
from qtsalome import QApplication, pyqtSignal, QThread, Qt, QTimer
|
||||
from qtsalome import QApplication, Qt, QTimer
|
||||
from .geomrepairadv_logger import logger
|
||||
from .geomrepairadv_worker_messages import MessageHandlerFactory
|
||||
from multiprocessing import Process, Pipe
|
||||
|
||||
import CORBA
|
||||
|
||||
|
||||
class Worker(QThread):
|
||||
class Worker(Process):
|
||||
"""
|
||||
Creates a tread to run a given target function with a progress dialog as a parent.
|
||||
Creates a process to run a given target function with a progress dialog as a parent.
|
||||
"""
|
||||
|
||||
progress_update = pyqtSignal(int)
|
||||
thread_failed = pyqtSignal()
|
||||
work_completed = pyqtSignal()
|
||||
|
||||
def __init__(self, parent=None, target=None, args=None):
|
||||
super().__init__(parent)
|
||||
super().__init__()
|
||||
|
||||
# Set target function and it's arguments
|
||||
# Set target function and its arguments
|
||||
self.target = target
|
||||
self.args = args
|
||||
|
||||
# Update a progress bar each time we receive an update signal
|
||||
self.progress_update.connect(parent.setValue)
|
||||
self.thread_failed.connect(parent.on_failed)
|
||||
self.work_completed.connect(parent.on_completed)
|
||||
# Create a pipe for communication
|
||||
self.parent_conn, self.child_conn = Pipe()
|
||||
|
||||
# Set a timer to handle signals non-blocking way
|
||||
self.signals_timer = QTimer()
|
||||
self.signals_timer.timeout.connect(self.handle_signals)
|
||||
self.signals_timer.start(1000)
|
||||
|
||||
# Create a message handler factory
|
||||
self.message_handler_factory = MessageHandlerFactory()
|
||||
|
||||
# Store parent for signal handling
|
||||
self.parent = parent
|
||||
|
||||
# Calculate total amount of lines in executed function
|
||||
source_lines = inspect.getsourcelines(target)
|
||||
@ -53,7 +62,7 @@ class Worker(QThread):
|
||||
first_line = source_lines[1]
|
||||
|
||||
# Set a progress emitter to update the progress from the target
|
||||
self.progress_emitter = ProgressEmitter(self.progress_update, total_lines, first_line)
|
||||
self.progress_emitter = ProgressEmitter(self.child_conn, total_lines, first_line)
|
||||
|
||||
# Set a variable for result
|
||||
self.result = None
|
||||
@ -70,23 +79,17 @@ class Worker(QThread):
|
||||
"""
|
||||
|
||||
try:
|
||||
# Wait mode cursor
|
||||
QApplication.setOverrideCursor(Qt.WaitCursor)
|
||||
|
||||
self.result = self.target(self.args, self.progress_emitter)
|
||||
|
||||
# Reset the progress when finished
|
||||
self.progress_update.emit(100)
|
||||
self.child_conn.send(('progress', 100))
|
||||
|
||||
if not self.is_canceled():
|
||||
self.work_completed.emit()
|
||||
self.child_conn.send(('completed', self.result))
|
||||
|
||||
except Exception:
|
||||
logger.error(format_exc())
|
||||
self.thread_failed.emit()
|
||||
|
||||
finally:
|
||||
QApplication.restoreOverrideCursor()
|
||||
self.child_conn.send(('failed',))
|
||||
|
||||
|
||||
def is_canceled(self):
|
||||
@ -106,9 +109,6 @@ class Worker(QThread):
|
||||
# can return from the running function gracefully.
|
||||
self.progress_emitter.stop()
|
||||
|
||||
# Termination doesn't call a final block inside run()
|
||||
QApplication.restoreOverrideCursor()
|
||||
|
||||
# Set a timer for a case when the running function
|
||||
# doesn't use emitter or does so heavy job that it would take
|
||||
# a lot of time for waiting and we need to terminate it.
|
||||
@ -121,10 +121,26 @@ class Worker(QThread):
|
||||
"""
|
||||
|
||||
# Check if the job is still running and need to be terminated
|
||||
if self.isRunning():
|
||||
logger.warning('Thread will be terminated!')
|
||||
if self.is_alive():
|
||||
logger.warning('Process will be terminated!')
|
||||
|
||||
super().terminate()
|
||||
|
||||
self.on_finished()
|
||||
|
||||
|
||||
def on_finished(self):
|
||||
"""
|
||||
Called when the execution is finished.
|
||||
"""
|
||||
|
||||
logger.debug('on_finished called')
|
||||
|
||||
QApplication.restoreOverrideCursor()
|
||||
self.signals_timer.stop()
|
||||
|
||||
self.join()
|
||||
|
||||
|
||||
def get_result(self):
|
||||
"""
|
||||
@ -134,6 +150,37 @@ class Worker(QThread):
|
||||
return self.result
|
||||
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Starts the process and sets up the communication with the parent.
|
||||
"""
|
||||
super().start()
|
||||
self.handle_signals()
|
||||
|
||||
QApplication.setOverrideCursor(Qt.WaitCursor)
|
||||
|
||||
|
||||
def handle_signals(self):
|
||||
"""
|
||||
Handles signals from the child process.
|
||||
"""
|
||||
|
||||
logger.debug('handle_signals called')
|
||||
|
||||
if not self.parent_conn.poll():
|
||||
return
|
||||
|
||||
msg = self.parent_conn.recv()
|
||||
logger.debug('msg: %s', msg)
|
||||
|
||||
# Get a handler for the message type
|
||||
handler = self.message_handler_factory.get_handler(msg[0])
|
||||
if handler:
|
||||
handler.handle(msg, self)
|
||||
else:
|
||||
logger.error('No handler for message type: %s', msg[0])
|
||||
|
||||
|
||||
class ProgressEmitter():
|
||||
"""
|
||||
Helper class to reduce code repetition while update progress
|
||||
@ -173,6 +220,6 @@ class ProgressEmitter():
|
||||
progress_value = (line - self.first_line) / self.progress_percent
|
||||
logger.debug('progress_value: %d', progress_value)
|
||||
|
||||
self.progress_update.emit(int(progress_value))
|
||||
self.progress_update.send(['progress', int(progress_value)])
|
||||
|
||||
return self.is_running
|
||||
|
119
src/RepairGUIAdv/geomrepairadv_worker_messages.py
Normal file
119
src/RepairGUIAdv/geomrepairadv_worker_messages.py
Normal file
@ -0,0 +1,119 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2014-2024 EDF
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# See https://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
|
||||
#
|
||||
# Author : Konstantin Leontev (OpenCascade S.A.S)
|
||||
|
||||
class MessageHandler:
|
||||
"""
|
||||
MessageHandler is a base class for handling messages
|
||||
between child and worker processes in the progress bar Worker class.
|
||||
"""
|
||||
|
||||
def handle(self, msg, worker):
|
||||
"""
|
||||
Handle the given message.
|
||||
|
||||
This method should be implemented by subclasses to define how to process
|
||||
the given message.
|
||||
|
||||
Args:
|
||||
msg: The message to be handled.
|
||||
worker: The worker context or object related to the message.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: If the method is not implemented by a subclass.
|
||||
"""
|
||||
|
||||
raise NotImplementedError("Subclasses should implement this method")
|
||||
|
||||
|
||||
class ProgressHandler(MessageHandler):
|
||||
"""
|
||||
ProgressHandler updates progress bar with a value from a message.
|
||||
"""
|
||||
|
||||
def handle(self, msg, worker):
|
||||
"""
|
||||
Sets a new value for a worker progress bar.
|
||||
|
||||
Args:
|
||||
msg (tuple): A tuple where the second element is the value to be set.
|
||||
worker (object): The worker object that has a setValue method.
|
||||
"""
|
||||
|
||||
worker.parent.setValue(msg[1])
|
||||
|
||||
|
||||
class CompletedHandler(MessageHandler):
|
||||
"""
|
||||
CompletedHandler handles the completion of the worker process.
|
||||
"""
|
||||
|
||||
def handle(self, msg, worker):
|
||||
"""
|
||||
Handles the given message by performing actions on the worker object.
|
||||
|
||||
Args:
|
||||
msg: The message to handle.
|
||||
worker: The worker object that contains the methods to be called.
|
||||
"""
|
||||
|
||||
worker.result = msg[1]
|
||||
|
||||
worker.parent.on_completed()
|
||||
worker.on_finished()
|
||||
|
||||
|
||||
class FailedHandler(MessageHandler):
|
||||
"""
|
||||
FailedHandler handles the failure of the worker process.
|
||||
"""
|
||||
|
||||
def handle(self, msg, worker):
|
||||
"""
|
||||
Handles the given message by invoking the worker's failure handler,
|
||||
stopping the timer, and joining the worker thread.
|
||||
|
||||
Args:
|
||||
msg: The message to handle.
|
||||
worker: The worker object that contains the failure handler, timer, and worker thread.
|
||||
"""
|
||||
|
||||
worker.parent.on_failed()
|
||||
worker.on_finished()
|
||||
|
||||
|
||||
class MessageHandlerFactory:
|
||||
"""
|
||||
MessageHandlerFactory creates a handler for a given message type.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.handlers = {
|
||||
'progress': ProgressHandler(),
|
||||
'completed': CompletedHandler(),
|
||||
'failed': FailedHandler()
|
||||
}
|
||||
|
||||
def get_handler(self, msg_type):
|
||||
"""
|
||||
Returns a handler for the given message type.
|
||||
"""
|
||||
|
||||
return self.handlers.get(msg_type, None)
|
Loading…
Reference in New Issue
Block a user