Skip to content

Commit d1c9cae

Browse files
author
Ezequiel Torres
committed
Added edit config button functionality
* QFileSystemWatcher was used to track if the config file was modified #40
1 parent 981f739 commit d1c9cae

File tree

6 files changed

+532
-430
lines changed

6 files changed

+532
-430
lines changed

MLC/GUI/Autogenerated/autogenerated.py

Lines changed: 426 additions & 421 deletions
Large diffs are not rendered by default.

MLC/GUI/Autogenerated/mlc_qtcreator/experiment.ui

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<x>0</x>
1111
<y>0</y>
1212
<width>961</width>
13-
<height>552</height>
13+
<height>568</height>
1414
</rect>
1515
</property>
1616
<property name="windowTitle">
@@ -24,7 +24,7 @@
2424
<enum>QTabWidget::North</enum>
2525
</property>
2626
<property name="currentIndex">
27-
<number>0</number>
27+
<number>2</number>
2828
</property>
2929
<widget class="QWidget" name="experiment_tab">
3030
<property name="layoutDirection">
@@ -591,28 +591,35 @@
591591
<property name="frameShadow">
592592
<enum>QFrame::Raised</enum>
593593
</property>
594-
<layout class="QHBoxLayout" name="horizontalLayout_7">
595-
<item>
594+
<layout class="QGridLayout" name="gridLayout_7">
595+
<item row="0" column="0">
596596
<widget class="QPushButton" name="import_config_button">
597597
<property name="text">
598598
<string>Import</string>
599599
</property>
600600
</widget>
601601
</item>
602-
<item>
602+
<item row="0" column="1">
603603
<widget class="QPushButton" name="export_config_button">
604604
<property name="text">
605605
<string>Export</string>
606606
</property>
607607
</widget>
608608
</item>
609-
<item>
609+
<item row="1" column="0">
610610
<widget class="QPushButton" name="save_config_button">
611611
<property name="text">
612612
<string>Save</string>
613613
</property>
614614
</widget>
615615
</item>
616+
<item row="1" column="1">
617+
<widget class="QPushButton" name="edit_config_button">
618+
<property name="text">
619+
<string>Edit</string>
620+
</property>
621+
</widget>
622+
</item>
616623
</layout>
617624
</widget>
618625
</item>
@@ -1012,6 +1019,22 @@
10121019
</hint>
10131020
</hints>
10141021
</connection>
1022+
<connection>
1023+
<sender>edit_config_button</sender>
1024+
<signal>clicked()</signal>
1025+
<receiver>ExperimentWindow</receiver>
1026+
<slot>on_edit_config_button_clicked()</slot>
1027+
<hints>
1028+
<hint type="sourcelabel">
1029+
<x>702</x>
1030+
<y>517</y>
1031+
</hint>
1032+
<hint type="destinationlabel">
1033+
<x>480</x>
1034+
<y>283</y>
1035+
</hint>
1036+
</hints>
1037+
</connection>
10151038
</connections>
10161039
<slots>
10171040
<slot>on_closed_dialog()</slot>
@@ -1035,5 +1058,6 @@
10351058
<slot>on_convergence_button_clicked()</slot>
10361059
<slot>on_genealogy_button_clicked()</slot>
10371060
<slot>on_board_config_button_clicked()</slot>
1061+
<slot>on_edit_config_button_clicked()</slot>
10381062
</slots>
10391063
</ui>

MLC/GUI/Experiment/ExperimentWindow.py

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import numpy as np
55
import sys
66
import time
7-
sys.path.append(os.path.abspath(".") + "/../..")
7+
# sys.path.append(os.path.abspath(".") + "/../..")
88

99
from MLC.Log.log import get_gui_logger
1010
from MLC.GUI.Autogenerated.autogenerated import Ui_ExperimentWindow
@@ -23,6 +23,7 @@
2323
from PyQt5.QtCore import pyqtSignal
2424
from PyQt5.QtCore import Qt
2525
from PyQt5.QtCore import QUrl
26+
from PyQt5.QtCore import QFileSystemWatcher
2627
from PyQt5.QtGui import QDesktopServices
2728
from PyQt5.QtWidgets import QAbstractItemView
2829
from PyQt5.QtWidgets import QMainWindow
@@ -73,6 +74,16 @@ def __init__(self, mlc_local,
7374
# Signal to be emitted when the experiment is closed
7475
self._experiment_closed_signal = experiment_closed_signal
7576

77+
# Watch changes in the experiment config file
78+
self._file_watcher = QFileSystemWatcher()
79+
conf_path_list = [self._mlc_local.get_working_dir(),
80+
self._experiment_name,
81+
self._experiment_name + ".conf"]
82+
# Use the splat operator to dearrange the list
83+
self._experiment_conf_path = os.path.join(*conf_path_list)
84+
self._file_watcher.addPath(self._experiment_conf_path)
85+
self._file_watcher.fileChanged.connect(self._reload_experiment_config)
86+
7687
# Experiment in progress chart configuration
7788
self._chart_conf = ChartConfiguration(self._autogenerated_object)
7889
indivs_per_gen = Config.get_instance().getint("POPULATION", "size")
@@ -204,7 +215,12 @@ def on_dimension_check_clicked(self):
204215
def on_save_config_button_clicked(self):
205216
logger.debug('[EXPERIMENT {0}] [SAVE_CONFIG_BUTTON_CLICKED] - Executing on_save_config_button_clicked function'
206217
.format(self._experiment_name))
218+
219+
# Remove the config file from the Qt File watcher momentarily
220+
# to avoid rendering unnecesary warnings
221+
self._file_watcher.removePath(self._experiment_conf_path)
207222
self._persist_experiment_config()
223+
self._file_watcher.addPath(self._experiment_conf_path)
208224

209225
def on_tab_changed(self, tab_index):
210226
logger.debug('[EXPERIMENT {0}] [TAB_CHANGED] - Executing on_tab_changed function'
@@ -313,6 +329,12 @@ def on_board_config_button_clicked(self):
313329
board_config_window = BoardConfigurationWindow(parent=self)
314330
board_config_window.show()
315331

332+
def on_edit_config_button_clicked(self):
333+
logger.debug('[EXPERIMENT {0}] [EDIT_CONFIG_BUTTON] - '
334+
'Executing on_edit_config_button_clicked function'
335+
.format(self._experiment_name))
336+
QDesktopServices.openUrl(QUrl(self._experiment_conf_path))
337+
316338
def _config_table_edited(self, left, right):
317339
config_table = self._autogenerated_object.config_table
318340
table_model = config_table.model()
@@ -472,15 +494,23 @@ def _update_experiment_info(self):
472494
number_of_gens = experiment_info["generations"]
473495
if number_of_gens == 0:
474496
from_gen_combo.addItems([str(1)])
475-
to_gen_combo.addItems([str(x) for x in xrange(2, ExperimentWindow.MAX_GENERATIONS)])
497+
to_gen_combo.addItems([str(x) for x in xrange(2, ExperimentWindow.MAX_GENERATIONS + 1)])
476498
else:
477499
from_gen_combo.addItems([str(x) for x in xrange(1, number_of_gens + 1)])
478-
to_gen_combo.addItems([str(x) for x in xrange(2, ExperimentWindow.MAX_GENERATIONS)])
500+
to_gen_combo.addItems([str(x) for x in xrange(2, ExperimentWindow.MAX_GENERATIONS + 1)])
479501

480502
# Set the from gen combo to the last generation evaluated
481503
index = from_gen_combo.findText(str(number_of_gens), Qt.MatchFixedString)
482504
from_gen_combo.setCurrentIndex(index)
483505

506+
# set the to_gen_combo to the lest generation evaluated + 1
507+
to_gen_index = number_of_gens + 1
508+
if number_of_gens == ExperimentWindow.MAX_GENERATIONS:
509+
to_gen_index = ExperimentWindow.MAX_GENERATIONS
510+
511+
index = to_gen_combo.findText(str(to_gen_index), Qt.MatchFixedString)
512+
to_gen_combo.setCurrentIndex(index)
513+
484514
# Fill the db_view
485515
gen_count_group = self._autogenerated_object.gen_count_group
486516
if number_of_gens != 0:
@@ -557,6 +587,23 @@ def _update_individuals_figure(self):
557587
# Add the Indiv Canvas
558588
chart_layout.addWidget(indiv_canvas)
559589

590+
def _reload_experiment_config(self, some_string):
591+
logger.debug('[EXPERIMENT {0}] [EXPERIMENT_CONF_FILE_CHANGED] - '
592+
'Executing _experiment_conf_file_changed function'
593+
.format(self._experiment_name))
594+
595+
self._mlc_local.reload_experiment_configuration(self._experiment_name)
596+
self._load_experiment_config()
597+
598+
QMessageBox.warning(self, "Experiment Config Changed", "The Experiment config file "
599+
"has changed. The configuration will be reloaded. "
600+
"The changes made will be discarded")
601+
logger.info('[EXPERIMENT {0}] [RELOAD_CONFIG] - Config file has changed. Configuration will be reloaded')
602+
self._autogenerated_object.save_config_button.setDisabled(True)
603+
# FIXME: Dunno why?, but I have to add the config file to the
604+
# watcher in order to work again the next time
605+
self._file_watcher.addPath(self._experiment_conf_path)
606+
560607
def _persist_experiment_config(self):
561608
try:
562609
self._mlc_local.set_experiment_configuration(self._experiment_name, self._experiment_config)
@@ -579,7 +626,9 @@ def _ask_if_experiment_config_must_be_saved(self):
579626
QMessageBox.Yes | QMessageBox.No,
580627
QMessageBox.Yes)
581628
if response == QMessageBox.Yes:
629+
self._file_watcher.removePath(self._experiment_conf_path)
582630
self._persist_experiment_config()
631+
self._file_watcher.addPath(self._experiment_conf_path)
583632
else:
584633
self._load_experiment_config()
585634

MLC/api/Experiment.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
logger = get_gui_logger()
2020

21+
2122
class Experiment:
2223
# FIXME: one simulation at a time
2324
__last_simulation = None
@@ -48,6 +49,15 @@ def get_simulation(self):
4849
def get_configuration(self):
4950
return Config.to_dictionary(self._configuration)
5051

52+
def reload_configuration(self):
53+
"""
54+
Load again the experiment configuration, reading the config file from disk
55+
"""
56+
self._configuration = ConfigParser.ConfigParser()
57+
self._configuration.read(self._config_file)
58+
Config.get_instance().read(self._config_file)
59+
return Config.to_dictionary(self._configuration)
60+
5161
def set_configuration(self, new_configuration):
5262
self._configuration = Config.from_dictionary(new_configuration, config_type=ConfigParser.ConfigParser)
5363
self._configuration.write(open(self._config_file, "wt"))

MLC/api/MLCLocal.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ def get_experiment_configuration(self, experiment_name):
7474

7575
return self._open_experiments[experiment_name].get_configuration()
7676

77+
def reload_experiment_configuration(self, experiment_name):
78+
if experiment_name not in self._open_experiments:
79+
raise ClosedExperimentException("get_experiment_configuration", experiment_name)
80+
81+
return self._open_experiments[experiment_name].reload_configuration()
82+
7783
def open_experiment(self, experiment_name):
7884
if experiment_name not in self._experiments:
7985
raise ExperimentNotExistException(experiment_name)

MLC/api/mlc.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ def get_experiment_configuration(self, experiment_name):
108108
"""
109109
raise NotImplementedError("MLC::get_experiment_configuration not implemented")
110110

111+
def reload_experiment_configuration(self, experiment_name):
112+
"""
113+
Load again the experiment configuration.
114+
:param experiment_name:
115+
:return: experiment configuration.
116+
"""
117+
raise NotImplementedError("MLC::reload_experiment_configuration not implemented")
118+
111119
def set_experiment_configuration_parameter(self, experiment_name, param_section, param_name, value):
112120
"""
113121
Set a specific parameter value in the experiment configuration.

0 commit comments

Comments
 (0)