Пример #1
0
    def _run_queue(self, progress_callback):
        """Runs item's execution.

        :param PyQt5.QtCore.pyqtSignal.pyqtSignal progress_callback: signal to emit queue progress.
        """
        queue = self.queue_fifo
        index = -1
        while queue:
            item = queue.popleft()
            if not item.was_cloned:
                index += 1
            if self.stop_queue_flag:
                break
            progress_callback.emit(index)
            executor, settings = item.get_executor()
            if item.mode_name == "RUN QUEUE" and item.is_checked:
                self.add_queue_by_index(queue=queue, **settings)
                continue
            if not executor:
                logger.debug(f"Skipping queue item: {item.mode_name}")
                continue
            logger.debug(f"Running {item.mode_name} with settings: {settings}")
            self.process = Process(target=executor, kwargs=settings)
            self.process.start()
            self.process.join()
        self.stop_queue_flag = False
        self.widget.setDragDropMode(QAbstractItemView.InternalMove)
        self.game.clear_modes()
        logger.debug("Queue completed.")
Пример #2
0
class SingleTask:
    """Class for working with single task of execution."""
    def __init__(self, button, task_func, parameters):
        """Class initialization.

        :param TwoStateButton button: button that activates task.
        :param task_func: function to execute.
        :param dict parameters: function's parameters.
        """
        self.run_and_stop_button = button
        self.task_func = task_func
        self.parameters = parameters
        self.threads = ThreadPool()
        self.process = None
        self.run_and_stop_button.connect_first_state(self.execute)
        self.run_and_stop_button.connect_second_state(self.abort)

    def execute(self):
        """Execute function in safe thread."""
        logger.debug(
            f"Executing single task: {self.__class__.__name__} {self.task_func.__name__}"
        )
        from lib.gui.widgets.main import MainWindow
        MainWindow.resume_recorder()
        worker = self.threads.run_thread(target=self._execute)
        worker.signals.finished.connect(
            self.run_and_stop_button.set_first_state)
        worker.signals.finished.connect(MainWindow.pause_recorder)
        self.run_and_stop_button.set_second_state()

    @safe_process_stop
    def abort(self):
        """Abort function's execution."""
        if self.process:
            logger.debug("Task was forcibly stopped.")
            self.process.terminate()
        self.threads.thread_pool.clear()
        self.run_and_stop_button.set_first_state()
        from lib.gui.widgets.main import MainWindow
        MainWindow.pause_recorder()

    def _execute(self):
        """Execute function."""
        self.process = Process(target=self.task_func, kwargs=self.parameters)
        self.process.start()
        self.process.join()
        logger.debug("Task completed.")
Пример #3
0
    def __init__(self, ip_addr="127.0.0.1", port=3333, connect=False, dashboard_modules=True, dashboard_update_interval=3, log_filename="log_file.csv"):
        """
        Parameters
        ----------
        ip_addr: str
            Ip address of server to connect/start
        port: int
            Port of server to connect/start
        connect: bool
            False sets Agent network to connect mode and will connect to specified address
            True (Default) sets Agent network to initially try to connect and if it cant find one, it will start a new server at specified address
        dashboard_modules : list of modules , modules or bool
            Accepts list of modules which contains the AgentMET4FOF and DataStreamMET4FOF derived classes
            If set to True, will initiate the dashboard with default agents in AgentMET4FOF
        dashboard_update_interval : int
            Regular interval (seconds) to update the dashboard graphs
        logfile: str
            Name of log file, acceptable csv format. If set to None or False, then will not save file
        """

        self.ip_addr= ip_addr
        self.port = port
        self._controller = None
        self.log_filename= log_filename

        if type(self.log_filename) == str and '.csv' in self.log_filename:
            self.save_logfile = True
        else:
            self.save_logfile = False

        if connect:
            self.connect(ip_addr,port)
        else:
            self.connect(ip_addr,port, verbose=False)
            if self.ns == 0:
                self.start_server(ip_addr,port)

        if dashboard_modules is not False:
            self.dashboard_proc = Process(target=run_dashboard, args=(dashboard_modules,dashboard_update_interval))
            self.dashboard_proc.start()
        else:
            self.dashboard_proc = None
Пример #4
0
    def _run_queue(self, progress_callback):
        """Run item's execution.

        :param pyqtSignal progress_callback: signal to emit queue progress.
        """
        for index, item in enumerate(self.queue()):
            if self.stop_queue_flag:
                break
            progress_callback.emit(index)
            executor, settings = item.get_executor()
            if not executor:
                logger.debug(f"Skipping queue item: {item.mode_name}")
                continue
            logger.debug(f"Running {item.mode_name} with settings: {settings}")
            self.process = Process(target=executor, kwargs=settings)
            self.process.start()
            self.process.join()
        self.stop_queue_flag = False
        self.widget.setDragDropMode(QAbstractItemView.InternalMove)
        logger.debug("Queue completed.")
Пример #5
0
class AgentNetwork:
    """
    Object for starting a new Agent Network or connect to an existing Agent Network specified by ip & port

    Provides function to add agents, (un)bind agents, query agent network state, set global agent states
    Interfaces with an internal _AgentController which is hidden from user

    """
    def __init__(self, ip_addr="127.0.0.1", port=3333, connect=False, dashboard_modules=True, dashboard_update_interval=3, log_filename="log_file.csv"):
        """
        Parameters
        ----------
        ip_addr: str
            Ip address of server to connect/start
        port: int
            Port of server to connect/start
        connect: bool
            False sets Agent network to connect mode and will connect to specified address
            True (Default) sets Agent network to initially try to connect and if it cant find one, it will start a new server at specified address
        dashboard_modules : list of modules , modules or bool
            Accepts list of modules which contains the AgentMET4FOF and DataStreamMET4FOF derived classes
            If set to True, will initiate the dashboard with default agents in AgentMET4FOF
        dashboard_update_interval : int
            Regular interval (seconds) to update the dashboard graphs
        logfile: str
            Name of log file, acceptable csv format. If set to None or False, then will not save file
        """

        self.ip_addr= ip_addr
        self.port = port
        self._controller = None
        self.log_filename= log_filename

        if type(self.log_filename) == str and '.csv' in self.log_filename:
            self.save_logfile = True
        else:
            self.save_logfile = False

        if connect:
            self.connect(ip_addr,port)
        else:
            self.connect(ip_addr,port, verbose=False)
            if self.ns == 0:
                self.start_server(ip_addr,port)

        if dashboard_modules is not False:
            self.dashboard_proc = Process(target=run_dashboard, args=(dashboard_modules,dashboard_update_interval))
            self.dashboard_proc.start()
        else:
            self.dashboard_proc = None


    def connect(self,ip_addr="127.0.0.1", port = 3333,verbose=True):
        """
        Parameters
        ----------
        ip_addr: str
            IP Address of server to connect to

        port: int
            Port of server to connect to
        """
        try:
            self.ns = NSProxy(nsaddr=ip_addr+':' + str(port))
        except:
            if verbose:
                print("Unable to connect to existing NameServer...")
            self.ns = 0

    def start_server(self,ip_addr="127.0.0.1", port=3333):
        """
        Parameters
        ----------
        ip_addr: str
            IP Address of server to start

        port: int
            Port of server to start
        """

        print("Starting NameServer...")
        self.ns = run_nameserver(addr=ip_addr+':' + str(port))
        if len(self.ns.agents()) != 0:
            self.ns.shutdown()
            self.ns = run_nameserver(addr=ip_addr+':' + str(port))
        controller = run_agent("AgentController", base=_AgentController, attributes=dict(log_mode=True), nsaddr=self.ns.addr())
        logger = run_agent("Logger", base=_Logger, nsaddr=self.ns.addr())

        controller.init_parameters(self.ns)
        logger.init_parameters(log_filename=self.log_filename,save_logfile=self.save_logfile)

    def _set_mode(self, state):
        """
        Internal method to set mode of Agent Controller
        Parameters
        ----------
        state: str
            State of AgentController to set.
        """

        self._get_controller().set_attr(current_state=state)

    def _get_mode(self):
        """
        Returns
        -------
        state: str
            State of Agent Network
        """

        return self._get_controller().get_attr('current_state')

    def set_running_state(self, filter_agent=None):
        """
        Blanket operation on all agents to set their `current_state` attribute to "Running"

        Users will need to define their own flow of handling each type of `self.current_state` in the `agent_loop`

        Parameters
        ----------
        filter_agent : str
            (Optional) Filter name of agents to set the states

        """

        self.set_agents_state(filter_agent=filter_agent,state="Running")

    def update_networkx(self):
        self._get_controller().update_networkx()

    def get_networkx(self):
        return self._get_controller().get_attr('G')

    def get_nodes_edges(self):
        G = self.get_networkx()
        return G.nodes, G.edges

    def get_nodes(self):
        G = self.get_networkx()
        return G.nodes

    def get_edges(self):
        G = self.get_networkx()
        return G.edges

    def set_stop_state(self, filter_agent=None):
        """
        Blanket operation on all agents to set their `current_state` attribute to "Stop"

        Users will need to define their own flow of handling each type of `self.current_state` in the `agent_loop`

        Parameters
        ----------
        filter_agent : str
            (Optional) Filter name of agents to set the states

        """

        self.set_agents_state(filter_agent=filter_agent, state="Stop")

    def set_agents_state(self, filter_agent=None, state="Idle"):
        """
        Blanket operation on all agents to set their `current_state` attribute to given state

        Can be used to define different states of operation such as "Running", "Idle, "Stop", etc..
        Users will need to define their own flow of handling each type of `self.current_state` in the `agent_loop`

        Parameters
        ----------
        filter_agent : str
            (Optional) Filter name of agents to set the states

        state : str
            State of agents to set

        """

        self._set_mode(state)
        for agent_name in self.agents():
            if (filter_agent is not None and filter_agent in agent_name) or (filter_agent is None):
                agent = self.get_agent(agent_name)
                agent.set_attr(current_state=state)
        print("SET STATE:  ", state)
        return 0

    def reset_agents(self):
        for agent_name in self.agents():
                agent = self.get_agent(agent_name)
                agent.reset()
                agent.set_attr(current_state="Reset")
        self._set_mode("Reset")
        return 0

    def remove_agent(self, agent):
        if type(agent) == str:
            agent_proxy = self.get_agent(agent)
        else:
            agent_proxy = agent

        for input_agent in agent_proxy.get_attr("Inputs"):
            self.get_agent(input_agent).unbind_output(agent_proxy)
        for output_agent in agent_proxy.get_attr("Outputs"):
            agent_proxy.unbind_output(self.get_agent(output_agent))
        agent_proxy.shutdown()

    def bind_agents(self, source, target):
        """
        Binds two agents communication channel in a unidirectional manner from `source` Agent to `target` Agent

        Any subsequent calls of `source.send_output()` will reach `target` Agent's message queue.

        Parameters
        ----------
        source : AgentMET4FOF
            Source agent whose Output channel will be binded to `target`

        target : AgentMET4FOF
            Target agent whose Input channel will be binded to `source`
        """
        source.bind_output(target)
        return 0

    def unbind_agents(self, source, target):
        """
        Unbinds two agents communication channel in a unidirectional manner from `source` Agent to `target` Agent

        This is the reverse of `bind_agents()`

        Parameters
        ----------
        source : AgentMET4FOF
            Source agent whose Output channel will be unbinded from `target`

        target : AgentMET4FOF
            Target agent whose Input channel will be unbinded from `source`
        """

        source.unbind_output(target)
        return 0

    def _get_controller(self):
        """
        Internal method to access the AgentController relative to the nameserver

        """
        if self._controller is None:
            self._controller = self.ns.proxy('AgentController')
        return self._controller

    def get_agent(self,agent_name):
        """
        Returns a particular agent connected to Agent Network.

        Parameters
        ----------
        agent_name : str
            Name of agent to search for in the network

        """

        return self._get_controller().get_attr('ns').proxy(agent_name)

    def agents(self):
        """
        Returns all agent names connected to Agent Network.

        Returns
        -------
        list : names of all agents

        """
        agent_names = self._get_controller().agents()
        return agent_names

    def add_agent(self, name=" ", agentType= AgentMET4FOF, log_mode=True):
        """
        Instantiates a new agent in the network.

        Parameters
        ----------
        name : str
            Unique name of agent. If left empty, the name will be automatically set to its class name.
            There cannot be more than one agent with the same name.

        agentType : AgentMET4FOF
            Agent class to be instantiated in the network.

        log_mode : bool
            Default is True. Determines if messages will be logged to background Logger Agent.

        Returns
        -------
        AgentMET4FOF : Newly instantiated agent

        """

        agent = self._get_controller().add_module(name=name, agentType= agentType, log_mode=log_mode)

        return agent

    def shutdown(self):
        """
        Shutdowns the entire agent network and all agents
        """

        self._get_controller().get_attr('ns').shutdown()

        if self.dashboard_proc is not None:
            self.dashboard_proc.terminate()
        return 0
Пример #6
0
class SingleTaskWithOptions:
    def __init__(self, button, task_func, task_options):
        """Class initialization.

        :param TwoStateButton button: button that activates task.
        :param task_func: function to execute.
        :param dict task_options: function's parameters by option's key.
        """
        self.run_and_stop_button = button
        self.task_func = task_func
        self.task_options = task_options
        self.threads = ThreadPool()
        self.process = None
        for task_name, task_parameters in task_options.items():

            def add_action(parameters):
                self.run_and_stop_button.add_action(
                    task_name, lambda: self.execute(parameters))

            add_action(task_parameters)
        self.menu = self.run_and_stop_button.button.menu()
        self.run_and_stop_button.connect_second_state(self.abort)

    def execute(self, parameters):
        """Execute function in safe thread."""
        logger.debug(
            f"Executing single task: {self.__class__.__name__} {self.task_func.__name__} "
            f"with parameters {parameters}")
        from lib.gui.widgets.main import MainWindow
        MainWindow.resume_recorder()
        worker = self.threads.run_thread(
            target=lambda: self._execute(parameters=parameters))
        worker.signals.finished.connect(
            self.run_and_stop_button.set_first_state)
        worker.signals.finished.connect(self._set_menu)
        worker.signals.finished.connect(MainWindow.pause_recorder)
        self._clear_menu()
        self.run_and_stop_button.set_second_state()

    def _clear_menu(self):
        """Clear button menu."""
        self.run_and_stop_button.button.setMenu(None)

    def _set_menu(self):
        """Set button menu from cache."""
        self.run_and_stop_button.button.setMenu(self.menu)

    @safe_process_stop
    def abort(self):
        """Abort function's execution."""
        if self.process:
            logger.debug("Task was forcibly stopped.")
            self.process.terminate()
        self.threads.thread_pool.clear()
        self._set_menu()
        self.run_and_stop_button.set_first_state()
        from lib.gui.widgets.main import MainWindow
        MainWindow.pause_recorder()

    def _execute(self, parameters):
        """Execute function."""
        self.process = Process(target=self.task_func, kwargs=parameters)
        self.process.start()
        self.process.join()
        logger.debug("Task completed.")
Пример #7
0
 def _execute(self):
     """Execute function."""
     self.process = Process(target=self.task_func, kwargs=self.parameters)
     self.process.start()
     self.process.join()
     logger.debug("Task completed.")
Пример #8
0
class QueueList:
    """Class for working with queue list."""

    def __init__(self, game, list_widget, run_and_stop_button, add_button, edit_button, remove_button,
                 queue_selector_buttons):
        """Class initialization.

        :param PyQt5.QtWidgets.QListWidget.QListWidget list_widget: list widget.
        :param lib.gui.helper.TwoStateButton run_and_stop_button: button for running the queue.
        :param PyQt5.QtWidgets.QPushButton.QPushButton add_button: button for adding new element to queue.
        :param PyQt5.QtWidgets.QPushButton.QPushButton edit_button: button for editing existing element in the queue.
        :param PyQt5.QtWidgets.QPushButton.QPushButton remove_button:
            button for removing existing element from the queue.
        :param list[PyQt5.QtWidgets.QPushButton.QPushButton] queue_selector_buttons:
            list of buttons for selecting different queues.
        """
        self.game = game
        self.widget = list_widget
        self.run_and_stop_button = run_and_stop_button
        self.add_button = add_button
        self.edit_button = edit_button
        self.remove_button = remove_button
        self.queue_selector_buttons = queue_selector_buttons
        self.stored_queues = [[], ] * len(self.queue_selector_buttons)  # type: List[List[QueueItem]]
        self.current_queue_index = 0
        self.setup_buttons()
        self.threads = ThreadPool()
        self.process = None
        self.add_button.clicked.connect(self.add)
        if self.widget.count() == 0:
            self.run_and_stop_button.button.setEnabled(False)
        self.select_all_item = self.add_select_all_checkbox()
        self.widget.itemChanged.connect(self.on_item_change)
        self.load_queue_from_file()
        self.change_select_all_state()
        self.stop_queue_flag = False

    def queue(self):
        """Queue iterator."""
        for i in range(self.widget.count()):
            item = self.widget.item(i)
            if isinstance(item, QueueItem):
                yield item

    @property
    def queue_fifo(self):
        """Creates FIFO representation of current queue.

        :rtype: deque[QueueItem]
        """
        return deque(list(self.queue()))

    def clear_queue(self):
        """Clears queue."""
        for _ in range(self.widget.count()):
            item = self.widget.item(0)
            self.widget.takeItem(self.widget.row(item))

    def store_current_queue(self):
        """Stores currently selected queue to variable."""
        self.stored_queues[self.current_queue_index] = [*self.queue()]

    def change_queue(self, index):
        """Changes queue by index.

        :param int index: queue's index.
        """
        if index != self.current_queue_index:
            self.store_current_queue()
        self.current_queue_index = index
        self.clear_queue()
        self.select_all_item = self.add_select_all_checkbox()
        for item in self.stored_queues[index]:
            self._add(item)
        for button in self.queue_selector_buttons:
            button.setChecked(False)
        self.queue_selector_buttons[index].setChecked(True)

    def add_select_all_checkbox(self):
        """Creates 'Select All' checkbox with empty line below."""
        select_all = QListWidgetItem()
        select_all.setText("[Select All]")
        select_all.setCheckState(Qt.Checked)
        select_all.setFlags(select_all.flags() | Qt.ItemIsUserCheckable)
        select_all.setFlags(select_all.flags() ^ Qt.ItemIsDragEnabled)
        select_all.setFlags(select_all.flags() ^ Qt.ItemIsSelectable)
        blank_line = QListWidgetItem()
        blank_line.setFlags(blank_line.flags() ^ Qt.ItemIsDragEnabled)
        blank_line.setFlags(blank_line.flags() ^ Qt.ItemIsSelectable)
        self.widget.addItem(select_all)
        self.widget.addItem(blank_line)
        return select_all

    def change_select_all_state(self):
        """Changes 'Select All' checkbox state by queue item's states."""
        queue_states = [queue_item.checkState() for queue_item in self.queue()]
        all_checked = [state for state in queue_states if state == Qt.Checked]
        all_unchecked = [state for state in queue_states if state == Qt.Unchecked]
        partially_checked = all_checked and all_unchecked
        if all_checked and not all_unchecked:
            self.select_all_item.setCheckState(Qt.Checked)
        if all_unchecked and not all_checked:
            self.select_all_item.setCheckState(Qt.Unchecked)
        if partially_checked:
            self.select_all_item.setCheckState(Qt.PartiallyChecked)

    def on_item_change(self, item):
        """Selects or deselects items when some item was checked.

        :param QListWidgetItem item: changed item.
        """
        if item == self.select_all_item:
            state = item.checkState()
            if state == Qt.Checked:
                self.select_all()
            if state == Qt.Unchecked:
                self.deselect_all()
        if isinstance(item, QueueItem):
            if len(self.widget.selectedItems()) > 1:
                for selected_item in self.widget.selectedItems():
                    selected_item.setCheckState(item.checkState())
            self.change_select_all_state()

    def load_queue_from_file(self):
        """Loads queue list and apply it to GUI."""
        queues_list = load_queue_list()
        if not queues_list:
            return
        for queue_index, queue in enumerate(queues_list):
            logger.debug(f"Loading {len(queue)} items to queue list #{queue_index + 1}.")
            queue_items = []
            for settings in queue:
                editor = QueueItemEditor.from_settings(game=self.game, settings=settings)
                if editor:
                    item = editor.render_queue_item()
                    item.set_checked(settings.get("checked", False))
                    queue_items.append(item)
            self.stored_queues[queue_index] = queue_items
        self.change_queue(index=0)

    def save_queue_to_file(self):
        """Saves existing queue to JSON-file."""
        self.store_current_queue()
        queues_list = []
        for queue_index, queue in enumerate(self.stored_queues):
            queue_items = []
            for item in queue:
                settings = {
                    "mode_name": item.mode_name,
                    "checked": item.is_checked,
                    **item.parameters
                }
                queue_items.append(settings)
            queues_list.append(queue_items)
            logger.debug(f"Saving queue #{queue_index + 1} list with {len(queue)} items.")
        save_queue_list(queues_list)

    def setup_buttons(self):
        """Setups button's events."""
        self.run_and_stop_button.connect_first_state(self.run_queue)
        self.run_and_stop_button.connect_second_state(self.stop_queue)
        self.run_and_stop_button.connect_first_state(self.widget.setDragDropMode, QAbstractItemView.NoDragDrop)
        self.run_and_stop_button.connect_second_state(self.widget.setDragDropMode, QAbstractItemView.InternalMove)
        self.remove_button.clicked.connect(self.remove_current_item)
        self.edit_button.clicked.connect(self.edit_current_item)

        # Setup Queue #1 and etc. buttons to change queue
        def change_queue_on_click(button, queue_index):
            button.clicked.connect(lambda: self.change_queue(queue_index))

        for index in range(len(self.queue_selector_buttons)):
            change_queue_on_click(button=self.queue_selector_buttons[index], queue_index=index)

    def add(self):
        """Creates editor window and add queue item from it."""
        editor = QueueItemEditor(game=self.game)
        editor.setWindowTitle("Add queue item")
        result = editor.exec_()
        if result and editor.queue_item:
            self._add(editor.queue_item)

    def _add(self, item):
        """Adds item to queue.

        :param QListWidgetItem item: item to add.
        """
        if self.widget.count() == 2:
            self.run_and_stop_button.button.setEnabled(True)
        self.widget.addItem(item)
        self.change_select_all_state()
        return item

    def edit_current_item(self):
        """Edits current selected item."""
        item = self.widget.currentItem()
        if item and isinstance(item, QueueItem):
            editor = QueueItemEditor.from_result_item(game=self.game, queue_item=item)
            editor.setWindowTitle("Edit queue item")
            result = editor.exec_()
            if result and editor.queue_item:
                self.edit_item(old_item=item, new_item=editor.queue_item)

    def edit_item(self, old_item, new_item):
        """Edits queue item.

        :param QListWidgetItem old_item: item before editing.
        :param QListWidgetItem new_item: item after editing.
        """
        widget_index = self.widget.row(old_item)
        self.widget.takeItem(widget_index)
        self.widget.insertItem(widget_index, new_item)
        self.widget.setCurrentRow(widget_index)

    def remove_current_item(self):
        """Removes current selected item from queue."""
        item = self.widget.currentItem()
        if item and isinstance(item, QueueItem):
            if len(self.widget.selectedItems()) > 1:
                for selected_item in self.widget.selectedItems():
                    self.remove_item(selected_item)
            self.remove_item(item)

    def remove_item(self, item):
        """Removes item from queue.

        :param QListWidgetItem item: queue item.
        """
        self.widget.takeItem(self.widget.row(item))
        self.change_select_all_state()
        if self.widget.count() == 2:
            self.run_and_stop_button.button.setEnabled(False)

    def add_queue_by_index(self, queue, queue_index):
        """Adds items from queue to current queue by queue index.

        :param deque[QueueItem] queue: current FIFO queue.
        :param queue_index: index of queue to add.
        """
        logger.debug(f"Running queue by index = {queue_index}")
        for item in reversed(self.stored_queues[queue_index - 1]):
            clone = item.clone(mark=True)
            queue.appendleft(clone)

    def run_queue(self):
        """Runs and executes all items in queue."""
        logger.debug("Running queue.")
        self.store_current_queue()
        from lib.gui.widgets.main import MainWindow
        MainWindow.resume_recorder()
        self.run_and_stop_button.set_second_state()
        self.widget.setDragDropMode(QAbstractItemView.NoDragDrop)
        self.threads.run_thread(func=self._run_queue,
                                on_finish=[self.run_and_stop_button.set_first_state,
                                           self.reset_background,
                                           MainWindow.pause_recorder],
                                on_progress=self.mark_execution_background,
                                with_progress=True)

    def mark_execution_background(self, cur_index):
        """Marks execution queue items with color.

        :param int cur_index: index for current item in queue.
        """
        for index, item in enumerate(self.queue()):
            if index == cur_index:
                item.setBackground(Qt.yellow)
                break
            color = Qt.green if item.is_checked else Qt.gray
            item.setBackground(color)

    def reset_background(self):
        """Resets queue colors."""
        for item in self.queue():
            item.setBackground(Qt.transparent)

    @safe_process_stop
    def stop_queue(self):
        """Stops queue execution."""
        from lib.gui.widgets.main import MainWindow
        MainWindow.pause_recorder()
        self.game.clear_modes()
        self.widget.setDragDropMode(QAbstractItemView.InternalMove)
        self.stop_queue_flag = True
        if self.process:
            logger.debug("Queue was forcibly stopped.")
            self.process.terminate()
        self.threads.thread_pool.clear()
        self.run_and_stop_button.set_first_state()

    def _run_queue(self, progress_callback):
        """Runs item's execution.

        :param PyQt5.QtCore.pyqtSignal.pyqtSignal progress_callback: signal to emit queue progress.
        """
        queue = self.queue_fifo
        index = -1
        while queue:
            item = queue.popleft()
            if not item.was_cloned:
                index += 1
            if self.stop_queue_flag:
                break
            progress_callback.emit(index)
            executor, settings = item.get_executor()
            if item.mode_name == "RUN QUEUE" and item.is_checked:
                self.add_queue_by_index(queue=queue, **settings)
                continue
            if not executor:
                logger.debug(f"Skipping queue item: {item.mode_name}")
                continue
            logger.debug(f"Running {item.mode_name} with settings: {settings}")
            self.process = Process(target=executor, kwargs=settings)
            self.process.start()
            self.process.join()
        self.stop_queue_flag = False
        self.widget.setDragDropMode(QAbstractItemView.InternalMove)
        self.game.clear_modes()
        logger.debug("Queue completed.")

    def select_all(self):
        """Selects all items in queue."""
        for item in self.queue():
            item.set_checked(True)

    def deselect_all(self):
        """Deselects all items in queue."""
        for item in self.queue():
            item.set_checked(False)