Added dialog for existing configs and server config dialog, improved config.py

This commit is contained in:
Artem30801
2020-02-04 15:52:58 +03:00
parent ed9041d04a
commit 67b86d303b
3 changed files with 92 additions and 47 deletions

View File

@@ -158,14 +158,14 @@ class ConfigModelItem:
if self.spec_default is not None and self.data(1) == self.spec_default \
and self.data(0) == self.default_values[0] and self.type != 'section':
self.set_state('default')
print('def', self.data(1), self.data(0), self.spec_default)
# print('def', self.data(1), self.data(0), self.spec_default)
child_states = [child.state for child in self.childItems]
if any(state in child_states for state in ['edited', 'added', 'deleted']):
self.state = 'edited'
if len(set(child_states)) == 1: # if all states equal
self.set_state(child_states[0], set_children=False)
print(child_states)
# print(child_states)
if self.parentItem is not None:
self.parentItem.check_state()
@@ -285,7 +285,7 @@ class ConfigModel(QtCore.QAbstractItemModel):
childItem = index.internalPointer()
if not isinstance(childItem, ConfigModelItem):
print(childItem, index.column()), # index.row(), index.parent().internalPointer())
# print(childItem, index.column()), # index.row(), index.parent().internalPointer())
return QtCore.QModelIndex()
parentItem = childItem.parent()
@@ -744,10 +744,15 @@ class ConfigDialog(QtWidgets.QDialog):
super(ConfigDialog, self).__init__(parent)
self.ui = config_editor.Ui_config_dialog()
self.model = ConfigModel(widget=self)
self._filename = None
self.unsaved = False
self.setupUi()
self.copter_editor_signal.connect(self._call_copter_dialog)
@property
def filename(self):
return self._filename or 'Untitled.ini'
def setupModel(self, data, pure_dict=False, convert_types=False):
if pure_dict:
self.model.dict_setup(data, convert_types=convert_types)
@@ -774,10 +779,12 @@ class ConfigDialog(QtWidgets.QDialog):
# self.ui.delete_button.pressed.connect(self.remove_selected)
def update_title(self):
self.setWindowTitle(f"Config editor - {self.filename}" + "*"*self.unsaved)
def unsaved_call(self):
name = self.windowTitle()+'*'
self.setWindowTitle(name)
self.unsaved = True
self.update_title()
self.model.dataChanged.disconnect(self.unsaved_call)
def closeEvent(self, event):
@@ -803,13 +810,14 @@ class ConfigDialog(QtWidgets.QDialog):
return reply == QMessageBox.Yes
def save_as(self):
cfg = config.ConfigManager()
cfg.load_from_dict(self.model.to_config_dict())
save_path = QFileDialog.getSaveFileName(self, "Save as configuration file",
directory=self.filename,
filter="Config files (*.ini)")[0]
if not save_path:
return
cfg = config.ConfigManager()
cfg.load_from_dict(self.model.to_config_dict())
cfg.config.filename = save_path
cfg.write()
@@ -841,21 +849,36 @@ class ConfigDialog(QtWidgets.QDialog):
@pyqtSlot(object, object)
def _call_copter_dialog(self, client, value):
logging.info("Opening dialog")
logging.info("Opening copter config dialog")
config_dict, spec_dict = value["config"], value["configspec"]
cfg = config.ConfigManager()
cfg.load_from_dict(config_dict, spec_dict)
self.setupModel(cfg.full_dict(include_defaults=True))
if not self.validation_loop(cfg, spec_dict):
return False
def save_callback():
edited_dict = cfg.full_dict(include_defaults=False)
client.send_message("config", {"config": edited_dict, "mode": "rewrite"})
edited_dict = self.model.to_config_dict()
client.send_message("config", {"config": edited_dict, "mode": "rewrite"})
if self.ui.do_restart.isChecked():
def restart_callback():
client.send_message("service_restart", {"name": "clever-show"})
if not self.call_config_dialog(cfg, save_callback, restart_callback, f"{client.copter_id}"):
return False
return True
def call_config_dialog(self, cfg: config.ConfigManager, on_save=None, on_restart=None, name="Untitled.ini"):
self.setupModel(cfg.full_dict(include_defaults=True), convert_types=(not cfg.validated))
self.ui.do_restart.setEnabled(on_restart is not None)
self._filename = name
self.update_title()
if not self.validation_loop(cfg, cfg.config.configspec):
return False
if on_save is not None:
on_save()
if on_restart is not None and self.ui.do_restart.isChecked():
on_restart()
return True
def call_standalone_dialog(self):
@@ -872,26 +895,26 @@ class ConfigDialog(QtWidgets.QDialog):
"Config cannot be opened or validated: {}".format(error))
return False
self.setupModel(cfg.full_dict(include_defaults=True), convert_types=(not cfg.validated))
self.ui.do_restart.setDisabled(True)
def save_callback():
if cfg.config.filename is None:
save_path = QFileDialog.getSaveFileName(self, "Save configuration file",
directory=self.filename,
filter="Config files (*.ini)")[0]
if not save_path:
return False
else:
save_path = cfg.config.filename
filename = cfg.config.filename
validation_path = path if cfg.config.filename is None else cfg.config.filename
validation_path = validation_path if cfg.validated else None
cfg.config.filename = save_path
cfg.write()
if not self.validation_loop(cfg, validation_path):
if cfg.config.filename is not None:
name = os.path.split(cfg.config.filename)[1]
else: # when editing only configspec-based file
name = os.path.split(path)[1]
if not self.call_config_dialog(cfg, on_save=save_callback, name=name):
return False
if filename is None:
save_path = QFileDialog.getSaveFileName(self, "Save configuration file",
filter="Config files (*.ini)")[0]
if not save_path:
return False
else:
save_path = filename
cfg.config.filename = save_path
cfg.write()
return True

View File

@@ -41,6 +41,7 @@ def b_partial(func, *args, **kwargs): # call argument blocker partial
def restart(): # move to core
# ANY prints will break restarting or opening new windows after restart
os.execl(sys.executable, os.path.abspath(__file__), *sys.argv)
@@ -135,6 +136,10 @@ class MainWindow(QtWidgets.QMainWindow):
self.ui.action_play_music.triggered.connect(self.play_music)
self.ui.action_stop_music.triggered.connect(self.stop_music)
self.ui.action_edit_any_config.triggered.connect(ConfigDialog.call_standalone_dialog)
self.ui.action_edit_server_config.triggered.connect(self.edit_server_config)
self.ui.action_restart_server.triggered.connect(restart)
self.ui.action_update_server_git.triggered.connect(update_server)
@@ -589,6 +594,15 @@ class MainWindow(QtWidgets.QMainWindow):
def configure_columns(self):
HeaderEditDialog(self.ui.copter_table, self.server.config).exec()
@pyqtSlot()
def edit_server_config(self):
config = self.server.config
def save_callback():
config.write()
ConfigDialog().call_config_dialog(config, save_callback, restart, name="Server config")
def register_callbacks(self):
@messaging.message_callback("telemetry")
def get_telem_data(client, value, **kwargs):

View File

@@ -48,7 +48,6 @@ class ValidationError(ValueError):
class ConfigManager:
def __init__(self, config=None):
self.config = ConfigObj() if config is None else config
self.validated = False
self._name_dict = {}
@@ -75,13 +74,16 @@ class ConfigManager:
def write(self):
self.config.write()
@property
def validated(self):
return self.config.configspec is not None
def set_config(self, config):
self.config = config
self._name_dict = self.flatten_keys(config)
self.validated = False
def validate_config(self, config=None, copy_defaults=False):
config = config or self.config
config = self.config if config is None else config
vdt = Validator()
test = config.validate(vdt, copy=copy_defaults, preserve_errors=True)
@@ -89,7 +91,6 @@ class ConfigManager:
raise ValidationError('Some config values are wrong', config, test)
self.set_config(config)
self.validated = True
@classmethod
def _full_dict(cls, item, include_defaults=False):
@@ -263,21 +264,27 @@ class ConfigManager:
final_comment = d.pop('final_comment', [''])
kwargs = {'infile': self._extract_values(d), 'indent_type': ''}
filename = None
if isinstance(configspec, dict):
kwargs.update({'configspec': configspec})
elif isinstance(configspec, str):
spec_path = self._get_spec_path(configspec) # check for /spec, then for config
if not self._config_exists(spec_path):
spec_path = configspec
if self._config_exists(spec_path):
spec_path = self._get_spec_path(configspec)
if self._config_exists(spec_path): # when 'configspec' points to configuration file and configspec exists
kwargs.update({'configspec': spec_path})
filename = configspec
elif self._config_exists(configspec): # when 'configspec' points to configspec file
kwargs.update({'configspec': configspec})
if parent_dir(configspec) == 'spec':
filename = self._get_config_path(configspec)
else:
raise ValueError("Configspec does not exist")
config = ConfigObj(**kwargs)
config.filename = configspec if isinstance(configspec, str) else None
config.filename = filename
config.initial_comment = initial_comment
config.final_comment = final_comment
if configspec is not None:
if config.configspec is not None:
self.validate_config(config)
else:
self.set_config(config)
@@ -318,13 +325,14 @@ if __name__ == '__main__':
import pprint
#pprint.pprint(cfg.full_dict)
cfg2 = ConfigManager()
cfg2.load_from_dict({"PRIVATE": {"offset": [1, 2, 3]}}, configspec='Drone/config/spec/configspec_client.ini')
#cfg2.load_from_dict({"PRIVATE": {"id": 123132}})
#cfg2.load_from_dict({"PRIVATE": {"offset": [1, 2, 3]}}, configspec='Drone/config/spec/configspec_client.ini')
cfg2.load_from_dict({"PRIVATE": {"id": "heh"}})
#pprint.pprint(cfg2.full_dict)
cfg.merge(cfg2)
#cfg.merge(cfg2)
#pprint.pprint(cfg.full_dict)
print(cfg.full_dict(include_defaults=True))
print(dict(cfg.config.configspec))
print(cfg2.full_dict(include_defaults=True))
#print(dict(cfg2.config.configspec))
print(cfg2.config.PRIVATE)
#print(dict(ConfigManager(cfg.config.configspec).config))
# #print(cfg.full_dict)