mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 11:41:49 +02:00
refactor: config_dialog.py clean up
This commit is contained in:
@ -435,7 +435,9 @@ class PlotApp(QWidget):
|
|||||||
curve.setData(data_x, data_y)
|
curve.setData(data_x, data_y)
|
||||||
|
|
||||||
@pyqtSlot(dict, dict)
|
@pyqtSlot(dict, dict)
|
||||||
def on_scan_segment(self, msg, metadata) -> None:
|
def on_scan_segment(
|
||||||
|
self, msg, metadata
|
||||||
|
) -> None: # TODO the logic should be separated from GUI operation
|
||||||
"""
|
"""
|
||||||
Handle new scan segments and saves data to a dictionary. Linked through bec_dispatcher.
|
Handle new scan segments and saves data to a dictionary. Linked through bec_dispatcher.
|
||||||
|
|
||||||
@ -566,7 +568,7 @@ class PlotApp(QWidget):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"An error occurred while saving the settings to {file_path}: {e}")
|
print(f"An error occurred while saving the settings to {file_path}: {e}")
|
||||||
|
|
||||||
def load_settings_from_yaml(self) -> dict:
|
def load_settings_from_yaml(self) -> dict: # TODO can be replace by the qt_utils function
|
||||||
"""Load settings from a .yaml file using a file dialog and update the current settings."""
|
"""Load settings from a .yaml file using a file dialog and update the current settings."""
|
||||||
options = QFileDialog.Options()
|
options = QFileDialog.Options()
|
||||||
options |= QFileDialog.DontUseNativeDialog
|
options |= QFileDialog.DontUseNativeDialog
|
||||||
|
@ -150,7 +150,7 @@ config_scan_mode = {
|
|||||||
"label": "Multi",
|
"label": "Multi",
|
||||||
"signals": [
|
"signals": [
|
||||||
{"name": "gauss_bpm", "entry": "gauss_bpm"},
|
{"name": "gauss_bpm", "entry": "gauss_bpm"},
|
||||||
{"name": "samx", "entry": ["samx", "samx_setpoint"]},
|
{"name": "samx", "entry": "samx"},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -161,7 +161,7 @@ config_scan_mode = {
|
|||||||
"label": "Multi",
|
"label": "Multi",
|
||||||
"signals": [
|
"signals": [
|
||||||
{"name": "gauss_bpm", "entry": "gauss_bpm"},
|
{"name": "gauss_bpm", "entry": "gauss_bpm"},
|
||||||
{"name": "samx", "entry": ["samx", "samx_setpoint"]},
|
{"name": "samx", "entry": "samx"},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -13,7 +13,6 @@ from PyQt5.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from bec_widgets.qt_utils.yaml_dialog import load_yaml, save_yaml
|
from bec_widgets.qt_utils.yaml_dialog import load_yaml, save_yaml
|
||||||
from bec_widgets.qt_utils.widget_hierarchy import print_widget_hierarchy, export_config_to_dict
|
|
||||||
|
|
||||||
current_path = os.path.dirname(__file__)
|
current_path = os.path.dirname(__file__)
|
||||||
Ui_Form, BaseClass = uic.loadUiType(os.path.join(current_path, "config_dialog.ui"))
|
Ui_Form, BaseClass = uic.loadUiType(os.path.join(current_path, "config_dialog.ui"))
|
||||||
@ -164,14 +163,6 @@ class ConfigDialog(QWidget, Ui_Form):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Debug buttons
|
|
||||||
self.pushButton_hirarchy.clicked.connect(self.debug_hierarchy)
|
|
||||||
|
|
||||||
# Test button configuration to load configs from dict
|
|
||||||
self.pushButton_def.clicked.connect(lambda: self.load_config(config=config_default))
|
|
||||||
self.pushButton_scan.clicked.connect(lambda: self.load_config(config=config_scan))
|
|
||||||
# self.pushButton_hierarchy.clicked.connect(lambda: print_widget_hierarchy(self))
|
|
||||||
|
|
||||||
# Load/save yaml file buttons
|
# Load/save yaml file buttons
|
||||||
self.pushButton_import.clicked.connect(self.load_config_from_yaml)
|
self.pushButton_import.clicked.connect(self.load_config_from_yaml)
|
||||||
self.pushButton_export.clicked.connect(self.save_config_to_yaml)
|
self.pushButton_export.clicked.connect(self.save_config_to_yaml)
|
||||||
@ -182,24 +173,21 @@ class ConfigDialog(QWidget, Ui_Form):
|
|||||||
# Make scan tabs closable
|
# Make scan tabs closable
|
||||||
self.tabWidget_scan_types.tabCloseRequested.connect(self.handle_tab_close_request)
|
self.tabWidget_scan_types.tabCloseRequested.connect(self.handle_tab_close_request)
|
||||||
|
|
||||||
# Default configuration
|
# Init functions to make a default dialog
|
||||||
# Init functions to make a default dialog #TODO this is useful, but has to be made better
|
|
||||||
if default_config is None:
|
if default_config is None:
|
||||||
self._init_default()
|
self._init_default()
|
||||||
# self.load_config()
|
else:
|
||||||
|
self.load_config(default_config)
|
||||||
def debug_hierarchy(self):
|
|
||||||
self.hierarchy_dict = export_config_to_dict(self, grab_values=True, print_hierarchy=True)
|
|
||||||
print(self.hierarchy_dict)
|
|
||||||
|
|
||||||
def _init_default(self):
|
def _init_default(self):
|
||||||
if self.comboBox_scanTypes.currentText() == "Disabled":
|
"""Init default dialog"""
|
||||||
|
|
||||||
|
if self.comboBox_scanTypes.currentText() == "Disabled": # Default mode
|
||||||
self.add_new_scan(self.tabWidget_scan_types, "Default")
|
self.add_new_scan(self.tabWidget_scan_types, "Default")
|
||||||
self.add_new_plot(self.tabWidget_scan_types.widget(0))
|
self.add_new_plot(self.tabWidget_scan_types.widget(0))
|
||||||
self.pushButton_new_scan_type.setEnabled(False)
|
self.pushButton_new_scan_type.setEnabled(False)
|
||||||
self.lineEdit_scan_type.setEnabled(False)
|
self.lineEdit_scan_type.setEnabled(False)
|
||||||
else:
|
else: # Scan mode with clear tab
|
||||||
print("scan mode from _init")
|
|
||||||
self.pushButton_new_scan_type.setEnabled(True)
|
self.pushButton_new_scan_type.setEnabled(True)
|
||||||
self.lineEdit_scan_type.setEnabled(True)
|
self.lineEdit_scan_type.setEnabled(True)
|
||||||
self.tabWidget_scan_types.clear()
|
self.tabWidget_scan_types.clear()
|
||||||
@ -214,16 +202,18 @@ class ConfigDialog(QWidget, Ui_Form):
|
|||||||
parent_tab(QTabWidget): Parent tab widget, where to add scan tab
|
parent_tab(QTabWidget): Parent tab widget, where to add scan tab
|
||||||
scan_name(str): Scan name
|
scan_name(str): Scan name
|
||||||
closable(bool): If True, the scan tab will be closable
|
closable(bool): If True, the scan tab will be closable
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
scan_tab(QWidget): Scan tab widget
|
scan_tab(QWidget): Scan tab widget
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Create a new scan tab
|
# Create a new scan tab
|
||||||
scan_tab = QWidget()
|
scan_tab = QWidget()
|
||||||
scan_tab_layout = QVBoxLayout(scan_tab)
|
scan_tab_layout = QVBoxLayout(scan_tab)
|
||||||
|
|
||||||
# Set a tab widget for plots
|
# Set a tab widget for plots
|
||||||
tabWidget_plots = QTabWidget()
|
tabWidget_plots = QTabWidget()
|
||||||
tabWidget_plots.setObjectName("tabWidget_plots")
|
tabWidget_plots.setObjectName("tabWidget_plots") # TODO decide if needed to give a name
|
||||||
tabWidget_plots.setTabsClosable(True)
|
tabWidget_plots.setTabsClosable(True)
|
||||||
tabWidget_plots.tabCloseRequested.connect(self.handle_tab_close_request)
|
tabWidget_plots.tabCloseRequested.connect(self.handle_tab_close_request)
|
||||||
scan_tab_layout.addWidget(tabWidget_plots)
|
scan_tab_layout.addWidget(tabWidget_plots)
|
||||||
@ -231,23 +221,23 @@ class ConfigDialog(QWidget, Ui_Form):
|
|||||||
# Add scan tab
|
# Add scan tab
|
||||||
parent_tab.addTab(scan_tab, scan_name)
|
parent_tab.addTab(scan_tab, scan_name)
|
||||||
|
|
||||||
# Optionally, connect the tabCloseRequested signal to a slot to handle the tab close request
|
# Make tabs closable
|
||||||
if closable:
|
if closable:
|
||||||
parent_tab.setTabsClosable(closable)
|
parent_tab.setTabsClosable(closable)
|
||||||
# Add first plot #TODO decide if useful for both modes
|
|
||||||
# self.add_new_plot(scan_tab)
|
|
||||||
return scan_tab
|
return scan_tab
|
||||||
|
|
||||||
def add_new_plot(self, scan_tab: QWidget) -> QWidget:
|
def add_new_plot(self, scan_tab: QWidget) -> QWidget:
|
||||||
"""
|
"""
|
||||||
Add a new plot tab to the scan tab
|
Add a new plot tab to the scan tab
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
scan_tab (QWidget): Scan tab widget
|
scan_tab (QWidget): Scan tab widget
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
plot_tab (QWidget): Plot tab
|
plot_tab (QWidget): Plot tab
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Create a new plot tab from .ui template
|
# Create a new plot tab from .ui template
|
||||||
plot_tab = QWidget()
|
plot_tab = QWidget()
|
||||||
plot_tab_ui = Tab_Ui_Form()
|
plot_tab_ui = Tab_Ui_Form()
|
||||||
@ -255,7 +245,9 @@ class ConfigDialog(QWidget, Ui_Form):
|
|||||||
plot_tab.ui = plot_tab_ui
|
plot_tab.ui = plot_tab_ui
|
||||||
|
|
||||||
# Add plot to current scan tab
|
# Add plot to current scan tab
|
||||||
tabWidget_plots = scan_tab.findChild(QTabWidget, "tabWidget_plots")
|
tabWidget_plots = scan_tab.findChild(
|
||||||
|
QTabWidget, "tabWidget_plots"
|
||||||
|
) # TODO decide if putting name is needed
|
||||||
plot_name = f"Plot {tabWidget_plots.count() + 1}"
|
plot_name = f"Plot {tabWidget_plots.count() + 1}"
|
||||||
tabWidget_plots.addTab(plot_tab, plot_name)
|
tabWidget_plots.addTab(plot_tab, plot_name)
|
||||||
|
|
||||||
@ -281,9 +273,11 @@ class ConfigDialog(QWidget, Ui_Form):
|
|||||||
def add_new_signal(self, table: QTableWidget) -> None:
|
def add_new_signal(self, table: QTableWidget) -> None:
|
||||||
"""
|
"""
|
||||||
Add a new signal to the table
|
Add a new signal to the table
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
table(QTableWidget): Table widget
|
table(QTableWidget): Table widget
|
||||||
"""
|
"""
|
||||||
|
|
||||||
row_position = table.rowCount()
|
row_position = table.rowCount()
|
||||||
table.insertRow(row_position)
|
table.insertRow(row_position)
|
||||||
table.setItem(row_position, 0, QTableWidgetItem(""))
|
table.setItem(row_position, 0, QTableWidgetItem(""))
|
||||||
@ -296,17 +290,21 @@ class ConfigDialog(QWidget, Ui_Form):
|
|||||||
Args:
|
Args:
|
||||||
index(int): Index of the tab to be closed
|
index(int): Index of the tab to be closed
|
||||||
"""
|
"""
|
||||||
|
|
||||||
parent_tab = self.sender()
|
parent_tab = self.sender()
|
||||||
parent_tab.removeTab(index)
|
if parent_tab.count() > 1: # ensure there is at least one tab
|
||||||
|
parent_tab.removeTab(index)
|
||||||
|
|
||||||
def generate_empty_scan_tab(self, parent_tab: QTabWidget, scan_name: str):
|
def generate_empty_scan_tab(self, parent_tab: QTabWidget, scan_name: str):
|
||||||
"""
|
"""
|
||||||
Generate an empty scan tab
|
Generate an empty scan tab
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
parent_tab (QTabWidget): Parent tab widget where to add the scan tab
|
parent_tab (QTabWidget): Parent tab widget where to add the scan tab
|
||||||
scan_name(str): name of the scan tab
|
scan_name(str): name of the scan tab
|
||||||
"""
|
"""
|
||||||
scan_tab = self.add_new_scan(parent_tab, scan_name, True)
|
|
||||||
|
scan_tab = self.add_new_scan(parent_tab, scan_name, closable=True)
|
||||||
self.add_new_plot(scan_tab)
|
self.add_new_plot(scan_tab)
|
||||||
|
|
||||||
def get_plot_config(self, plot_tab: QWidget) -> dict:
|
def get_plot_config(self, plot_tab: QWidget) -> dict:
|
||||||
@ -346,6 +344,7 @@ class ConfigDialog(QWidget, Ui_Form):
|
|||||||
"signals": signals,
|
"signals": signals,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return plot_data
|
return plot_data
|
||||||
|
|
||||||
def apply_config(self) -> dict:
|
def apply_config(self) -> dict:
|
||||||
@ -353,9 +352,10 @@ class ConfigDialog(QWidget, Ui_Form):
|
|||||||
Apply configuration from the whole configuration window
|
Apply configuration from the whole configuration window
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Configuration
|
dict: Current configuration
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# General settings
|
# General settings
|
||||||
config = {
|
config = {
|
||||||
"plot_settings": {
|
"plot_settings": {
|
||||||
@ -369,13 +369,8 @@ class ConfigDialog(QWidget, Ui_Form):
|
|||||||
|
|
||||||
# Iterate through the plot tabs - Device monitor mode
|
# Iterate through the plot tabs - Device monitor mode
|
||||||
if config["plot_settings"]["scan_types"] == False:
|
if config["plot_settings"]["scan_types"] == False:
|
||||||
plot_tab = self.tabWidget_scan_types.widget(0).findChild(
|
plot_tab = self.tabWidget_scan_types.widget(0).findChild(QTabWidget)
|
||||||
QTabWidget
|
|
||||||
) # , "tabWidget_plots") #TODO bug was here?
|
|
||||||
print(f"number of tabs: {plot_tab.count()}")
|
|
||||||
for index in range(plot_tab.count()):
|
for index in range(plot_tab.count()):
|
||||||
print(f"plot MODE tab index: {index}")
|
|
||||||
# export_config_to_dict(plot_tab.widget(index), print_hierarchy=True, grab_values=True)
|
|
||||||
plot_data = self.get_plot_config(plot_tab.widget(index))
|
plot_data = self.get_plot_config(plot_tab.widget(index))
|
||||||
config["plot_data"].append(plot_data)
|
config["plot_data"].append(plot_data)
|
||||||
|
|
||||||
@ -383,54 +378,50 @@ class ConfigDialog(QWidget, Ui_Form):
|
|||||||
elif config["plot_settings"]["scan_types"] == True:
|
elif config["plot_settings"]["scan_types"] == True:
|
||||||
# Iterate through the scan tabs
|
# Iterate through the scan tabs
|
||||||
for index in range(self.tabWidget_scan_types.count()):
|
for index in range(self.tabWidget_scan_types.count()):
|
||||||
print(f"scan tab index: {index}")
|
|
||||||
scan_tab = self.tabWidget_scan_types.widget(index)
|
scan_tab = self.tabWidget_scan_types.widget(index)
|
||||||
scan_name = self.tabWidget_scan_types.tabText(index)
|
scan_name = self.tabWidget_scan_types.tabText(index)
|
||||||
plot_tab = scan_tab.findChild(QTabWidget) # TODO here bug?
|
plot_tab = scan_tab.findChild(QTabWidget)
|
||||||
config["plot_data"][scan_name] = []
|
config["plot_data"][scan_name] = []
|
||||||
|
# Iterate through the plot tabs
|
||||||
for index in range(plot_tab.count()):
|
for index in range(plot_tab.count()):
|
||||||
print(f"plot tab index: {index}")
|
|
||||||
plot_data = self.get_plot_config(plot_tab.widget(index))
|
plot_data = self.get_plot_config(plot_tab.widget(index))
|
||||||
config["plot_data"][scan_name].append(plot_data)
|
config["plot_data"][scan_name].append(plot_data)
|
||||||
|
|
||||||
print(f"applied config: {config})")
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def load_config(self, config: dict) -> None:
|
def load_config(self, config: dict) -> None:
|
||||||
|
"""
|
||||||
|
Load configuration to the configuration window
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config(dict): Configuration to be loaded
|
||||||
|
"""
|
||||||
|
|
||||||
# Plot setting General box
|
# Plot setting General box
|
||||||
plot_settings = config.get("plot_settings", {})
|
plot_settings = config.get("plot_settings", {})
|
||||||
|
|
||||||
# TODO implement more robust logic for color apply/select
|
self.comboBox_appearance.setCurrentText(plot_settings.get("background_color", "black"))
|
||||||
self.comboBox_appearance.setCurrentText(plot_settings.get("background_color", ""))
|
|
||||||
self.spinBox_n_column.setValue(plot_settings.get("num_columns", 1))
|
self.spinBox_n_column.setValue(plot_settings.get("num_columns", 1))
|
||||||
self.comboBox_colormap.setCurrentText(plot_settings.get("colormap", ""))
|
self.comboBox_colormap.setCurrentText(plot_settings.get("colormap", "magma"))
|
||||||
self.comboBox_scanTypes.setCurrentText(
|
self.comboBox_scanTypes.setCurrentText(
|
||||||
"Enabled" if plot_settings.get("scan_types", False) else "Disabled"
|
"Enabled" if plot_settings.get("scan_types", False) else "Disabled"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Clear exiting scan tabs
|
# Clear exiting scan tabs
|
||||||
self.tabWidget_scan_types.clear() # TODO can cause var leak?
|
self.tabWidget_scan_types.clear()
|
||||||
|
|
||||||
# Get what mode is active - scan vs default device monitor
|
# Get what mode is active - scan vs default device monitor
|
||||||
mode = plot_settings.get("scan_types", False)
|
scan_mode = plot_settings.get("scan_types", False)
|
||||||
|
|
||||||
print(f"scan mode:{mode}")
|
if scan_mode is False: # default mode:
|
||||||
|
|
||||||
# default mode
|
|
||||||
if mode is False:
|
|
||||||
plot_data = config.get("plot_data", [])
|
plot_data = config.get("plot_data", [])
|
||||||
self.add_new_scan(self.tabWidget_scan_types, "Default")
|
self.add_new_scan(self.tabWidget_scan_types, "Default")
|
||||||
for plot_config in plot_data: # TODO iterate through all plots
|
for plot_config in plot_data: # Create plot tab for each plot and populate GUI
|
||||||
print(f"plot_config: {plot_config}")
|
|
||||||
|
|
||||||
# Create plot tab for each plot and populate GUI
|
|
||||||
plot = self.add_new_plot(self.tabWidget_scan_types.widget(0))
|
plot = self.add_new_plot(self.tabWidget_scan_types.widget(0))
|
||||||
self.load_plot_setting(plot, plot_config)
|
self.load_plot_setting(plot, plot_config)
|
||||||
elif mode is True:
|
elif scan_mode is True: # scan mode
|
||||||
plot_data = config.get("plot_data", {})
|
plot_data = config.get("plot_data", {})
|
||||||
for scan_name, scan_config in plot_data.items():
|
for scan_name, scan_config in plot_data.items():
|
||||||
print(f"scan name: {scan_name}")
|
|
||||||
print(f"scan config: {scan_config}")
|
|
||||||
scan_tab = self.add_new_scan(self.tabWidget_scan_types, scan_name)
|
scan_tab = self.add_new_scan(self.tabWidget_scan_types, scan_name)
|
||||||
for plot_config in scan_config:
|
for plot_config in scan_config:
|
||||||
plot = self.add_new_plot(scan_tab)
|
plot = self.add_new_plot(scan_tab)
|
||||||
@ -439,6 +430,7 @@ class ConfigDialog(QWidget, Ui_Form):
|
|||||||
def load_plot_setting(self, plot: QWidget, plot_config: dict) -> None:
|
def load_plot_setting(self, plot: QWidget, plot_config: dict) -> None:
|
||||||
"""
|
"""
|
||||||
Load plot setting from config
|
Load plot setting from config
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
plot (QWidget): plot tab widget
|
plot (QWidget): plot tab widget
|
||||||
plot_config (dict): config for single plot tab
|
plot_config (dict): config for single plot tab
|
||||||
@ -480,7 +472,6 @@ class ConfigDialog(QWidget, Ui_Form):
|
|||||||
Save configuration to yaml file
|
Save configuration to yaml file
|
||||||
"""
|
"""
|
||||||
config = self.apply_config()
|
config = self.apply_config()
|
||||||
print(f"confgi to save:{config}")
|
|
||||||
save_yaml(self, config)
|
save_yaml(self, config)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -496,7 +487,8 @@ class ConfigDialog(QWidget, Ui_Form):
|
|||||||
return "" if line_edit is None else line_edit.text()
|
return "" if line_edit is None else line_edit.text()
|
||||||
|
|
||||||
def apply_and_close(self):
|
def apply_and_close(self):
|
||||||
self.apply_config()
|
new_config = self.apply_config()
|
||||||
|
self.config_updated.emit(new_config)
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>585</width>
|
<width>597</width>
|
||||||
<height>769</height>
|
<height>769</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@ -141,27 +141,6 @@
|
|||||||
<string>Configuration</string>
|
<string>Configuration</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="pushButton_hirarchy">
|
|
||||||
<property name="text">
|
|
||||||
<string>Hiearchy</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="pushButton_def">
|
|
||||||
<property name="text">
|
|
||||||
<string>ImpDef</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="pushButton_scan">
|
|
||||||
<property name="text">
|
|
||||||
<string>ImpScan</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pushButton_import">
|
<widget class="QPushButton" name="pushButton_import">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
Reference in New Issue
Block a user