-
-
Notifications
You must be signed in to change notification settings - Fork 35
/
Copy pathprofile_ui.py
687 lines (585 loc) · 27.4 KB
/
profile_ui.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
"""Profile module.
Regroup all required classes to manage Profiles in UI.
Module : profile_ui
Authors : vincent
"""
import os
import json
import copy
import PyQt6.QtCore
import PyQt6.QtWidgets
import PyQt6.QtGui
import base_ui
import helper
class ProfileUI(base_ui.WidgetUI, base_ui.CommunicationHandler):
"""Manage the Profile selector and the board communication about them."""
__RELEASE = 2
__PROFILES_FILENAME = "profiles.json"
__PROFILESSETUP_FILENAME = helper.res_path("profile.cfg")
__PROFILES_TEMPLATE = {
"release": __RELEASE,
"global":{},
"profiles": [{"name": "None", "data": {}}],
}
FLASH_PROFILE_NAME = "Flash profile"
NONE_PROFILE_NAME = "None"
profiles_updated_event = PyQt6.QtCore.pyqtSignal(list)
profile_selected_event = PyQt6.QtCore.pyqtSignal(str)
def __init__(self, main=None):
"""Initialize profile without UI."""
self.main = main
self.profiles_dlg = None # ProfilesDialog is not initialized yet
self.profile_setup = {}
self.profiles = {}
self._current_class = -1
self._current_command = -1
self._current_instance = -1
self._map_class_running = []
self._running_profile = []
self._profilename_tosave: str = None
self.ui_initialized = False
self.load_profile_settings()
self.load_profiles()
def initialize_ui(self):
"""Init the UI and link the event."""
base_ui.WidgetUI.__init__(self, self.main, "profile.ui")
base_ui.CommunicationHandler.__init__(self)
self.profiles_dlg = ProfilesDialog(self)
self.profiles_dlg.closeSignal.connect(self.close_profile_manager)
self.pushButton_save.clicked.connect(self.save_clicked)
icon_save = PyQt6.QtGui.QIcon(
self.style().standardIcon(PyQt6.QtWidgets.QStyle.StandardPixmap.SP_DialogSaveButton)
)
self.toolButton_save.setIcon(icon_save)
self.toolButton_save.clicked.connect(self.save_config_in_profile)
self.comboBox_profiles.currentIndexChanged.connect(self.apply_config)
icon_manage = PyQt6.QtGui.QIcon(
self.style().standardIcon(
PyQt6.QtWidgets.QStyle.StandardPixmap.SP_FileDialogDetailedView
)
)
self.toolButton_manage.setIcon(icon_manage)
self.toolButton_manage.clicked.connect(self.open_profile_manager)
self.profiles_updated_event.connect(self.main.systray.refresh_profile_list)
self.profile_selected_event.connect(
self.main.systray.refresh_profile_action_status
)
self.setEnabled(False)
def save_clicked(self):
"""Save current seeting in Flash and replace the 'Flash profile' settings by the new one."""
def log_save_cb(res):
"""Display the confirmation in log."""
self.log("Save in flash: " + str(res))
self.save_config_in_profile(self.FLASH_PROFILE_NAME)
self.get_value_async("sys", "save", callback=log_save_cb)
def onclose(self):
"""Remove the serial call backs on close."""
self.remove_callbacks()
def setEnabled(self, a0: bool) -> None: # pylint: disable=invalid-name
"""Refresh the combo box content with profile when connection is up."""
if a0 and self.comboBox_profiles.count() == 0:
self.refresh_combox_list()
return super().setEnabled(a0)
def set_save_btn(self, status):
"""Enable the save button based on status."""
self.pushButton_save.setEnabled(status)
def open_profile_manager(self):
"""Open the profile list manager."""
self.profiles_dlg.set_profiles(self.profiles)
self.profiles_dlg.show()
def close_profile_manager(self, profile_name:str = ''):
"""Close the profile list manager."""
self.comboBox_profiles.currentIndexChanged.disconnect(self.apply_config)
self.refresh_combox_list()
self.comboBox_profiles.currentIndexChanged.connect(self.apply_config)
if (profile_name):
self.select_profile(profile_name)
self.create_or_update_profile_file()
self.log('Profile: profiles list updated')
def load_profile_settings(self):
"""Load the settings for the profile manager in profile.cfg file."""
check = os.path.exists(self.__PROFILESSETUP_FILENAME)
if check:
with open(self.__PROFILESSETUP_FILENAME, "r", encoding="utf_8") as file:
self.profile_setup = json.load(file)
def load_profiles(self):
"""Load profiles data in memory : from file if exits, or create a new file."""
check = os.path.exists(self.__PROFILES_FILENAME)
if check:
self.load_profiles_from_file()
else:
self.create_or_update_profile_file(create=True)
def load_profiles_from_file(self):
"""Load profiles from file profiles.json ."""
with open(self.__PROFILES_FILENAME, "r", encoding="utf_8") as profile_file:
self.profiles = json.load(profile_file)
if self.profiles['release'] < self.__RELEASE :
os.rename(self.__PROFILES_FILENAME, self.__PROFILES_FILENAME + '.' + str(self.profiles['release']) + '.old')
self.create_or_update_profile_file(create=True)
self.log("Profile: profiles are not compatible, need to redo them")
else:
self.log("Profile: profiles loaded")
if self.ui_initialized:
self.refresh_combox_list()
def create_or_update_profile_file(self, create: bool = False):
"""Create a profile file if not exist, else update the existing one."""
if create:
self.profiles = self.__PROFILES_TEMPLATE
self.log("Profile: profile file created")
try:
file = open(self.__PROFILES_FILENAME, "w", encoding="utf_8")
except OSError:
return False
with file as profile_file:
json.dump(self.profiles, profile_file)
return True
def get_global_setting(self,key : str, default = None):
"""Returns an entry of the global section or saves a default if set and not found"""
if "global" in self.profiles:
if (key not in self.profiles['global']) and default != None:
self.set_global_setting(key,default)
return self.profiles['global'].get(key,None)
return None
def set_global_setting(self,key : str, entry, save : bool = True):
"""Adds an item to the global section of the profile file. Set save true to write file immediately"""
self.profiles['global'][key] = entry
if save:
self.create_or_update_profile_file()
def refresh_combox_list(self):
"""Refresh the combo list of profile when init UI or when list change."""
self.comboBox_profiles.clear()
listprofile = []
data = self.profiles["profiles"]
for profilename in data:
listprofile.append(profilename["name"])
try:
listprofile.index(ProfileUI.FLASH_PROFILE_NAME)
listprofile.remove(ProfileUI.NONE_PROFILE_NAME)
except ValueError:
pass
self.comboBox_profiles.addItems(listprofile)
self.profiles_updated_event.emit(listprofile)
current_name_selected = self.comboBox_profiles.currentText()
if current_name_selected is not None:
self.profile_selected_event.emit(current_name_selected)
def select_profile(self, profilename: str):
"""Change the current selection with the specified profile name."""
if profilename == "":
return
if profilename != str(self.comboBox_profiles.currentText()):
index = self.comboBox_profiles.findText(
profilename, PyQt6.QtCore.Qt.MatchFlag.MatchFixedString
)
if index >= 0 and index != self.comboBox_profiles.currentIndex():
self.comboBox_profiles.setCurrentIndex(index)
def apply_config(self):
"""Apply the config of the current profile to the board.
Read active class in board
Send the paramter for active class to the board.
"""
# if not enabled, don't select profile
if not self.isEnabled():
return
# read the selected profile name, if profile is None, remove the last message
profilename = str(self.comboBox_profiles.currentText())
if profilename == "" or profilename == ProfileUI.NONE_PROFILE_NAME:
return
# get the Running Active class and process result with the write config profile
try:
self._read_running_class_and_go_cb(self._write_profile_cb)
self.profile_selected_event.emit(profilename)
except OSError:
self.log(F"Profile: can't apply profile '{profilename}', connection is closed.")
def save_config_in_profile(self, profile_name: str = ""):
"""Save the current config in the selected profile.
If the method is called without parameter, save order come from Save-Icon click :
1- read the profile name in the dropbox.
2- if the name is 'None' or 'Profile flash', store in flash before all
When the profile_name is pass, we don't check if "None or Flash Profile", else we have recursivity with method
'save_clicked'.
"""
if not(profile_name) or profile_name == "":
self._profilename_tosave = str(self.comboBox_profiles.currentText())
if self._profilename_tosave == self.NONE_PROFILE_NAME or \
self._profilename_tosave == self.FLASH_PROFILE_NAME:
# if profile to save is "None" or "Profile Flash", we first save in flash and save in profile after
self.save_clicked()
else:
self._profilename_tosave = profile_name
# get the Running Active class and process result with the read config profile
try:
self._read_running_class_and_go_cb(self._read_profile_cb)
except OSError:
self.log(F"Profile: can't save the profile '{self._profilename_tosave}'" +
", connection is closed.")
def _read_running_class_and_go_cb(self, call_back):
"""Get the running class from board, and process the call_back when board respond."""
# refresh the global var when starting to read value from board
self._current_class = -1
self._current_command = -1
self._current_instance = -1
self._map_class_running = []
self._running_profile = []
# get the list active class from board, after that the the callBack call recursively
self.get_value_async("sys", "lsactive", call_back)
############### method helper to construct and go through struct definition ###############
def _build_running_map(self, buffer: str):
self._map_class_running = []
# Split the string buffer into array
splitted_running_class = [x.split(":") for x in buffer.split("\n")]
# Format the arrray in array of object {classname, fullname, instance}
formated_iterator = list(
map(
lambda tab: {
"classname": tab[1],
"fullname": tab[0],
"instance": int(tab[2]),
},
splitted_running_class,
)
)
# For each class to saved declared in the cfg file,
# we filter the running instance to keep only those
for call_order in self.profile_setup["callOrder"]:
filtered_iterator = filter(
lambda x, call=call_order: x["classname"] == call["classname"]
and x["fullname"] == call["fullname"],
formated_iterator,
)
self._map_class_running.extend(list(filtered_iterator))
def _get_instance_running(self, indexclass: int, indexinstance: int):
if indexclass > len(self.profile_setup["callOrder"]):
return None
classname = self.profile_setup["callOrder"][indexclass]["classname"]
fullname = self.profile_setup["callOrder"][indexclass]["fullname"]
classes_running = list(
filter(
lambda x: x["classname"] == classname and x["fullname"] == fullname,
self._map_class_running,
)
)
# To test
# the request instance is not on a running classes
if len(classes_running) == 0 or indexinstance >= len(classes_running):
return None
else: # else return the instance number
return int(classes_running[indexinstance]["instance"])
def _get_next_element_to_request(self):
is_another_element = False
# if it's the start
if (
self._current_class == -1
and self._current_command == -1
and self._current_instance == -1
):
self._current_class = 0
self._current_command = 0
self._current_instance = 0
is_another_element = True
# if there is another command for this class, go to next command
elif (self._current_command + 1) < len(
self.profile_setup["callOrder"][self._current_class]["key"]
):
self._current_command += 1
is_another_element = True
else:
# if there is not next command,
# we check if there is another instance of this class to request
next_instance = self._get_instance_running(
self._current_class, self._current_instance + 1
)
if (
next_instance is not None
): # a next instance exist, we move index to this and restart on 1st dmd
self._current_instance += 1
self._current_command = 0
is_another_element = True
elif (self._current_class + 1) < len(
self.profile_setup["callOrder"]
): # there isn't next instance, we move too next class if exist
self._current_class += 1
self._current_command = 0
self._current_instance = 0
is_another_element = True
else:
is_another_element = False
# if the next computed class/instance is not running, we go to the next
if (
is_another_element
and self._get_instance_running(self._current_class, self._current_instance)
is None
):
return self._get_next_element_to_request()
return is_another_element
def _read_value(self, indexclass: int, indexcmd: int, indexinstance: int):
if indexclass < len(self.profile_setup["callOrder"]) and indexcmd < len(
self.profile_setup["callOrder"][indexclass]["key"]
):
classname = self.profile_setup["callOrder"][self._current_class][
"classname"
]
cmd = self.profile_setup["callOrder"][self._current_class]["key"][
self._current_command
]
instance = self._get_instance_running(indexclass, indexinstance)
self.get_value_async(classname, cmd, self._read_profile_cb, instance)
def _save_profile_in_file(self, profile_data: str, profilename: str):
# search the profile in the json profiles and replace is content
profile_json_entry = next(
filter(lambda x: x["name"] == profilename, self.profiles["profiles"]), None
)
# if profile is not exist, we copy a new one from "None" profile and
# return the profile_json_entry which reference the new profile entry
if profile_json_entry is None:
profile_json_entry = next(
filter(
lambda x: x["name"] == 'None',
self.profiles["profiles"],
),
None,
)
new_profile = copy.deepcopy(profile_json_entry)
if new_profile is not None:
new_profile["name"] = profilename
self.profiles["profiles"].append(new_profile)
profile_json_entry = new_profile
if profile_json_entry is not None:
profile_json_entry["data"] = profile_data
else:
self.log(F"Profile: can't save profile '{profilename}', it doesn't exist")
# store new config in file
self.create_or_update_profile_file()
self.log("Profile: '" + profilename + "' is successfully updated")
self.select_profile(profilename)
####################### Call Back for Async Serial Communication #######################
def _read_profile_cb(self, buffer: str):
# process the incoming buffer
if self._current_class == -1:
# first call is sys.lsactive to get all active class
# that running and we extract a map of class/instances
self._build_running_map(buffer)
else:
# each time we received a value, we store the value
# and awe asked the next one in the config file,
# for each instance read in the firt call
fullname = self.profile_setup["callOrder"][self._current_class]["fullname"]
classname = self.profile_setup["callOrder"][self._current_class][
"classname"
]
cmd = self.profile_setup["callOrder"][self._current_class]["key"][
self._current_command
]
instance = self._get_instance_running(
self._current_class, self._current_instance
)
self._running_profile.append(
{
"fullname": fullname,
"cls": classname,
"instance": instance,
"cmd": cmd,
"value": buffer,
}
)
# if there is another command for this class, go to next command
if self._get_next_element_to_request():
self._read_value(
self._current_class, self._current_command, self._current_instance
)
elif self._profilename_tosave is not False:
self._save_profile_in_file(self._running_profile, self._profilename_tosave)
else:
self.log("Profiles: profile read from board")
def _write_profile_cb(self, buffer: str):
# process the incoming buffer
if self._current_class == -1:
# first call is sys.lsactive to get all active class
# that running and we extract a map of class/instances
self._build_running_map(buffer)
else:
return
# read the selected profile name
profilename = str(self.comboBox_profiles.currentText())
if profilename == "":
return
# From the profile, filter parameters that are running
parameters_running = []
profile_json_entry = next(
filter(lambda x: x["name"] == profilename, self.profiles["profiles"]), None
)
for running_class in self._map_class_running:
parameters_running.extend(
list(
filter(
lambda x, running=running_class: x["fullname"]
== running["fullname"]
and x["cls"] == running["classname"]
and x["instance"] == running["instance"],
profile_json_entry["data"],
)
)
)
# sent the filter running parameter to the board
# and after, read a new time values to refresh UI
if len(parameters_running) > 0:
for pararmeter in parameters_running:
self.send_value(
cls=pararmeter["cls"],
cmd=pararmeter["cmd"],
val=pararmeter["value"],
instance=pararmeter["instance"],
)
# axis.0.degrees?|900
replytext = (
"["
+ pararmeter["cls"]
+ "."
+ str(pararmeter["instance"])
+ "."
+ pararmeter["cmd"]
+ "?|"
+ str(pararmeter["value"])
+ "]"
)
self.process_virtual_comms_buffer(replytext)
# self.sendCommand(cls=pararmeter["cls"],
# cmd=pararmeter["cmd"], instance=pararmeter["instance"])
# send message that announce new profile is selected
self.profile_selected_event.emit(profilename)
self.log("Profile: '" + profilename + "' is active")
class ProfilesDialog(PyQt6.QtWidgets.QDialog):
"""This class manage the dialog box which contain the list profile manager."""
closeSignal = PyQt6.QtCore.pyqtSignal(str)
def __init__(self, profile_ui=None):
"""Create and attach the DLG to the profile_ui and store locally the profiles list."""
PyQt6.QtWidgets.QDialog.__init__(self, profile_ui)
self.profiles = None
self.profile_manager_ui = ProfilesManagerUI(self)
self.layout = PyQt6.QtWidgets.QVBoxLayout()
self.layout.setContentsMargins(0, 0, 0, 0)
self.layout.addWidget(self.profile_manager_ui)
self.setLayout(self.layout)
self.setWindowTitle(self.tr("Profiles manager"))
self.setModal(True)
def set_profiles(self, profiles):
"""Update the profiles stored in the DLG."""
self.profiles = profiles
def closeEvent(self, a0: PyQt6.QtGui.QCloseEvent) -> None: # pylint: disable=invalid-name
"""Emit the close signal before to close, this help parent to resfresh combobox."""
# get the current selection item to push it to the main UI on closing action
name = None
if self.profile_manager_ui.selection_model.selection() and \
len(self.profile_manager_ui.selection_model.selection().indexes()) != 0:
name = self.profile_manager_ui.selection_model.selection().indexes()[0].data()
self.closeSignal.emit(name)
return super().closeEvent(a0)
class ProfilesManagerUI(base_ui.WidgetUI, base_ui.CommunicationHandler):
"""Init the UI in the dialog box to manage profile from a list box."""
def __init__(self, parent: ProfilesDialog = None):
"""Attach the UI to the dialog box and keep a reference to get profiles."""
base_ui.WidgetUI.__init__(self, parent, "profile_list.ui")
base_ui.CommunicationHandler.__init__(self)
self.profile_dlg = parent
self.model = PyQt6.QtGui.QStandardItemModel(self.listView)
self.listView.setModel(self.model)
self.selection_model = self.listView.selectionModel()
self.selection_model.selectionChanged.connect(self.onClicked)
self.pushButton_refresh.clicked.connect(self.read_profiles)
self.pushButton_close.clicked.connect(self.profile_dlg.close)
self.pushButton_delete.clicked.connect(self.delete)
self.pushButton_copyas.clicked.connect(self.copy_as)
self.pushButton_rename.clicked.connect(self.rename)
def showEvent(self, a0): # pylint: disable=invalid-name, unused-argument
"""Init the profile list on the show event."""
self.read_profiles()
def onClicked(self, index): # pylint: disable=invalid-name, unused-argument
"""Activate all button if it's not the "None" or "Flash profile" one."""
if len(self.selection_model.selection().indexes()) <= 0:
self.pushButton_delete.setEnabled(False)
self.pushButton_rename.setEnabled(False)
self.pushButton_copyas.setEnabled(False)
return
item = self.selection_model.selection().indexes()[0]
if item.data() == ProfileUI.NONE_PROFILE_NAME:
self.pushButton_delete.setEnabled(False)
self.pushButton_rename.setEnabled(False)
self.pushButton_copyas.setEnabled(False)
elif item.data() == ProfileUI.FLASH_PROFILE_NAME:
self.pushButton_delete.setEnabled(False)
self.pushButton_rename.setEnabled(False)
self.pushButton_copyas.setEnabled(True)
else:
self.pushButton_delete.setEnabled(True)
self.pushButton_rename.setEnabled(True)
self.pushButton_copyas.setEnabled(True)
def delete(self):
"""Remove the selected item when click on remove, and refresh profiles list."""
if len(self.selection_model.selection().indexes()) <= 0:
return
item_name = self.selection_model.selection().indexes()[0].data()
for i in range(len(self.profile_dlg.profiles["profiles"])):
if self.profile_dlg.profiles["profiles"][i]["name"] == item_name:
self.profile_dlg.profiles["profiles"].pop(i)
break
self.read_profiles()
def copy_as(self):
"""Prompt the new name, copy the selected item and refresh profiles list."""
if len(self.selection_model.selection().indexes()) <= 0:
return
item_name = self.selection_model.selection().indexes()[0].data()
name, status = PyQt6.QtWidgets.QInputDialog.getText(self, "Copy as", "new name")
if status and (name != "") and (name not in self.get_profiles_name()):
profile_json_entry = next(
filter(
lambda x: x["name"] == item_name,
self.profile_dlg.profiles["profiles"],
),
None,
)
new_profile = copy.deepcopy(profile_json_entry)
if profile_json_entry is not None:
new_profile["name"] = name
self.profile_dlg.profiles["profiles"].append(new_profile)
self.read_profiles()
def rename(self):
"""Prompt the new name, rename the selected item and refresh profiles list."""
if len(self.selection_model.selection().indexes()) <= 0:
return
item_name = self.selection_model.selection().indexes()[0].data()
name, status = PyQt6.QtWidgets.QInputDialog.getText(
self, "Copy as", "new name", text=item_name
)
if status and (name != "") and (name not in self.get_profiles_name()):
profile_json_entry = next(
filter(
lambda x: x["name"] == item_name,
self.profile_dlg.profiles["profiles"],
),
None,
)
if profile_json_entry is not None:
profile_json_entry["name"] = name
self.read_profiles()
def read_profiles(self):
"""Update the list box with element read in the profiles list store in the dialog box."""
self.model.clear()
for profile in self.get_profiles_name():
item = PyQt6.QtGui.QStandardItem(profile)
item.setEditable(False)
self.model.appendRow(item)
item = self.model.item(0, 0)
index = self.model.indexFromItem(item)
self.selection_model.select(
index, PyQt6.QtCore.QItemSelectionModel.SelectionFlag.Select
)
def get_profiles_name(self):
"""Create the list of profiles name from the profiles list store in the dialog box."""
list_name = []
data = self.profile_dlg.profiles['profiles']
nb_profile = len(data)
# return the list of name profile without the None one if there is more than one profile.
for profile in data:
list_name.append(profile["name"])
if nb_profile > 1:
list_name.remove(ProfileUI.NONE_PROFILE_NAME)
return list_name