add cfg-editor
Change-Id: I68b8ba9311ec0487d7a2676095a7170a2447b3d0 Reviewed-on: https://forge.frm2.tum.de/review/20206 Tested-by: JenkinsCodeReview <bjoern_pedersen@frm2.tum.de> Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
46
bin/cfg-editor
Executable file
@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# *****************************************************************************
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Module authors:
|
||||||
|
# Sandra Seger <sandra.seger@frm2.tum.de>
|
||||||
|
#
|
||||||
|
# *****************************************************************************
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
# Add import path for inplace usage
|
||||||
|
sys.path.insert(0, path.abspath(path.join(path.dirname(__file__), '..')))
|
||||||
|
|
||||||
|
from secop.gui.qt import QApplication
|
||||||
|
from secop.gui.cfg_editor.mainwindow import MainWindow
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv=None):
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('-f', '--file', help='Configuration file to open.')
|
||||||
|
args = parser.parse_args()
|
||||||
|
app = QApplication(argv)
|
||||||
|
window = MainWindow(args.file)
|
||||||
|
window.show()
|
||||||
|
return app.exec_()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(sys.argv))
|
0
secop/gui/cfg_editor/__init__.py
Normal file
273
secop/gui/cfg_editor/config_file.py
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# *****************************************************************************
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Module authors:
|
||||||
|
# Sandra Seger <sandra.seger@frm2.tum.de>
|
||||||
|
#
|
||||||
|
# *****************************************************************************
|
||||||
|
|
||||||
|
import configparser
|
||||||
|
from configparser import NoOptionError
|
||||||
|
from collections import OrderedDict
|
||||||
|
from secop.gui.cfg_editor.tree_widget_item import TreeWidgetItem
|
||||||
|
from secop.gui.cfg_editor.utils import get_all_items, get_params, get_props,\
|
||||||
|
get_all_children_with_names, get_module_class_from_name, \
|
||||||
|
get_interface_class_from_name
|
||||||
|
|
||||||
|
|
||||||
|
NODE = 'node'
|
||||||
|
INTERFACE = 'interface'
|
||||||
|
MODULE = 'module'
|
||||||
|
PARAMETER = 'parameter'
|
||||||
|
PROPERTY = 'property'
|
||||||
|
COMMENT = 'comment'
|
||||||
|
|
||||||
|
SECTIONS = {NODE: 'description',
|
||||||
|
INTERFACE: 'type',
|
||||||
|
MODULE: 'class'}
|
||||||
|
|
||||||
|
|
||||||
|
def write_config(file_name, tree_widget):
|
||||||
|
itms = get_all_items(tree_widget)
|
||||||
|
itm_lines = OrderedDict()
|
||||||
|
value_str = '%s = %s'
|
||||||
|
blank_lines = 0
|
||||||
|
for itm in itms:
|
||||||
|
if itm.kind is None:
|
||||||
|
continue
|
||||||
|
par = itm.parent()
|
||||||
|
value = str(itm.get_value())
|
||||||
|
if itm.kind in SECTIONS:
|
||||||
|
if itm.kind in [MODULE, INTERFACE]:
|
||||||
|
itm_lines[blank_lines] = ''
|
||||||
|
blank_lines += 1
|
||||||
|
value = value.replace('\n\n', '\n.\n')
|
||||||
|
value = value.replace('\n', '\n ')
|
||||||
|
itm_lines[itm] = '[%s %s]\n' % (itm.kind, itm.name) +\
|
||||||
|
value_str % (SECTIONS[itm.kind], value)
|
||||||
|
# TODO params and props
|
||||||
|
elif itm.kind == PARAMETER and value:
|
||||||
|
itm_lines[itm] = value_str % (itm.name, value)
|
||||||
|
elif itm.kind == PROPERTY:
|
||||||
|
prop_name = '.%s' % itm.name
|
||||||
|
if par.kind == PARAMETER:
|
||||||
|
prop_name = par.name + prop_name
|
||||||
|
itm_lines[itm] = value_str % (prop_name, value)
|
||||||
|
elif itm.kind == COMMENT:
|
||||||
|
temp_itm_lines = OrderedDict()
|
||||||
|
for key, dict_value in itm_lines.items():
|
||||||
|
if key == par:
|
||||||
|
value = value.replace('\n', '\n# ')
|
||||||
|
temp_itm_lines[itm] = '# %s' % value
|
||||||
|
temp_itm_lines[key] = dict_value
|
||||||
|
itm_lines.clear()
|
||||||
|
itm_lines.update(temp_itm_lines)
|
||||||
|
with open(file_name, 'w') as configfile:
|
||||||
|
configfile.write('\n'.join(itm_lines.values()))
|
||||||
|
|
||||||
|
|
||||||
|
def read_config(file_path):
|
||||||
|
# TODO datatype of params and properties
|
||||||
|
node = TreeWidgetItem(NODE)
|
||||||
|
ifs = TreeWidgetItem(name='interfaces')
|
||||||
|
mods = TreeWidgetItem(name='modules')
|
||||||
|
node.addChild(ifs)
|
||||||
|
node.addChild(mods)
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config.read_file(open(file_path))
|
||||||
|
|
||||||
|
for section in config.sections():
|
||||||
|
kind = section.split(' ', 1)[0]
|
||||||
|
name = section.split(' ', 1)[1]
|
||||||
|
try:
|
||||||
|
section_value = get_value(config, section, SECTIONS[kind])
|
||||||
|
section_value = section_value.replace('\n.\n', '\n\n') \
|
||||||
|
if kind == NODE else section_value
|
||||||
|
except NoOptionError:
|
||||||
|
# TODO invalid configuration
|
||||||
|
continue
|
||||||
|
if kind == NODE:
|
||||||
|
node.set_name(name)
|
||||||
|
act_item = node
|
||||||
|
act_item.set_value(section_value)
|
||||||
|
act_item.parameters = get_params(kind)
|
||||||
|
act_item.properties = get_props(kind)
|
||||||
|
else:
|
||||||
|
act_item = TreeWidgetItem(kind, name)
|
||||||
|
act_item.set_value(section_value)
|
||||||
|
if kind == MODULE:
|
||||||
|
mods.addChild(act_item)
|
||||||
|
act_class = get_module_class_from_name(section_value)
|
||||||
|
act_item.set_class_object(act_class)
|
||||||
|
else:
|
||||||
|
act_class = get_interface_class_from_name(section_value)
|
||||||
|
act_item.set_class_object(act_class)
|
||||||
|
ifs.addChild(act_item)
|
||||||
|
act_item.parameters = get_params(act_class)
|
||||||
|
act_item.properties = get_props(act_class)
|
||||||
|
|
||||||
|
# TODO rewrite so Parameters and Properties get class_object and
|
||||||
|
# properties, needed information in act_item.parameters/properties
|
||||||
|
for option in config.options(section):
|
||||||
|
if option != SECTIONS[kind]:
|
||||||
|
if option[0] == '.':
|
||||||
|
prop = TreeWidgetItem(PROPERTY, option[1:],
|
||||||
|
get_value(config, section, option))
|
||||||
|
act_item.addChild(prop)
|
||||||
|
else:
|
||||||
|
separated = option.split('.')
|
||||||
|
act_children = get_all_children_with_names(act_item)
|
||||||
|
# TODO find param / props in params, props and add datatype
|
||||||
|
if separated[0] in act_children:
|
||||||
|
param = act_children[separated[0]]
|
||||||
|
else:
|
||||||
|
param = TreeWidgetItem(PARAMETER, separated[0])
|
||||||
|
act_item.addChild(param)
|
||||||
|
if len(separated) == 1:
|
||||||
|
param.set_value(get_value(config, section, option))
|
||||||
|
else:
|
||||||
|
param.addChild(TreeWidgetItem(PROPERTY,
|
||||||
|
separated[1], get_value(config, section,
|
||||||
|
option)))
|
||||||
|
node = get_comments(node, ifs, mods, file_path)
|
||||||
|
return node, ifs, mods
|
||||||
|
|
||||||
|
|
||||||
|
def get_value(config, section, option):
|
||||||
|
value = config.get(section, option)
|
||||||
|
if value.find('#') != -1:
|
||||||
|
value = value[:value.find('#')]
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def get_comments(node, ifs, mods, file_path):
|
||||||
|
configfile = open(file_path, 'r')
|
||||||
|
all_lines = configfile.readlines()
|
||||||
|
current_comment = None
|
||||||
|
all_ifs = get_all_children_with_names(ifs)
|
||||||
|
all_mods = get_all_children_with_names(mods)
|
||||||
|
for index, line in enumerate(all_lines):
|
||||||
|
line = line[:-1]
|
||||||
|
if line.startswith('#'):
|
||||||
|
line = line[1:].strip()
|
||||||
|
if index and all_lines[index-1][0] == '#':
|
||||||
|
current_comment.set_value('%s\n%s' % (current_comment.
|
||||||
|
get_value(), line))
|
||||||
|
else:
|
||||||
|
current_comment = TreeWidgetItem(COMMENT, '#', line)
|
||||||
|
next_line = get_next_line(index, all_lines)
|
||||||
|
if not next_line:
|
||||||
|
node.insertChild(0, current_comment)
|
||||||
|
continue
|
||||||
|
insert_comment(index, next_line, all_lines, current_comment,
|
||||||
|
node, all_ifs, all_mods)
|
||||||
|
elif line.find('#') != -1:
|
||||||
|
comment_index = line.find('#')
|
||||||
|
current_comment = TreeWidgetItem(COMMENT, '#',
|
||||||
|
line[comment_index+1:].strip())
|
||||||
|
line = line[:comment_index]
|
||||||
|
insert_comment(index, line, all_lines, current_comment, node,
|
||||||
|
all_ifs, all_mods)
|
||||||
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
def insert_comment(index, line, all_lines, current_comment, node, all_ifs, all_mods):
|
||||||
|
if not insert_section_comment(line, current_comment, node, all_ifs,
|
||||||
|
all_mods):
|
||||||
|
insert_param_prop_comment(index, line, all_lines, current_comment, node,
|
||||||
|
all_ifs, all_mods)
|
||||||
|
|
||||||
|
|
||||||
|
def insert_section_comment(line, current_comment, node, all_ifs, all_mods):
|
||||||
|
try:
|
||||||
|
if line.startswith('[%s' % NODE):
|
||||||
|
node.insertChild(0, current_comment)
|
||||||
|
elif line.startswith('[%s' % INTERFACE):
|
||||||
|
all_ifs[get_name_of_section(line)]. \
|
||||||
|
insertChild(0, current_comment)
|
||||||
|
elif line.startswith('[%s' % MODULE):
|
||||||
|
all_mods[get_name_of_section(line)]. \
|
||||||
|
insertChild(0, current_comment)
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
except KeyError:
|
||||||
|
# TODO invalid file
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def insert_param_prop_comment(index, line, all_lines, current_comment,
|
||||||
|
node, all_ifs, all_mods):
|
||||||
|
try:
|
||||||
|
parent = get_previous_line(index, all_lines)
|
||||||
|
if not parent:
|
||||||
|
# TODO invalid file
|
||||||
|
pass
|
||||||
|
if parent.startswith('[%s' % NODE):
|
||||||
|
parent_item = node
|
||||||
|
elif parent.startswith('[%s' % INTERFACE):
|
||||||
|
parent_item = all_ifs[get_name_of_section(parent)]
|
||||||
|
else:
|
||||||
|
parent_item = all_mods[get_name_of_section(parent)]
|
||||||
|
parent_children = get_all_children_with_names(
|
||||||
|
parent_item)
|
||||||
|
line = line.replace(' ', '')
|
||||||
|
line = line.split('=')[0]
|
||||||
|
dot_i = line.find('.')
|
||||||
|
if dot_i == -1:
|
||||||
|
# parameter
|
||||||
|
parent_children[line].insertChild(
|
||||||
|
0, current_comment)
|
||||||
|
elif dot_i == 0:
|
||||||
|
# .property
|
||||||
|
parent_children[line[1:]].insertChild(
|
||||||
|
0, current_comment)
|
||||||
|
else:
|
||||||
|
# parameter.property
|
||||||
|
sub_childs = get_all_children_with_names(
|
||||||
|
parent_children[line[:dot_i]])
|
||||||
|
sub_childs[line[dot_i + 1:]].insertChild(
|
||||||
|
0, current_comment)
|
||||||
|
except KeyError:
|
||||||
|
# TODO invalid file
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def get_next_line(index, all_lines):
|
||||||
|
next_index = index + 1
|
||||||
|
try:
|
||||||
|
while all_lines[next_index][0] == '#' or \
|
||||||
|
all_lines[next_index][:-1].strip() == '':
|
||||||
|
next_index += 1
|
||||||
|
except IndexError:
|
||||||
|
return ''
|
||||||
|
return all_lines[next_index][:-1].strip()
|
||||||
|
|
||||||
|
|
||||||
|
def get_previous_line(index, all_lines):
|
||||||
|
prev_index = index - 1
|
||||||
|
try:
|
||||||
|
while all_lines[prev_index].strip()[0] != '[':
|
||||||
|
prev_index -= 1
|
||||||
|
except IndexError:
|
||||||
|
return ''
|
||||||
|
return all_lines[prev_index]
|
||||||
|
|
||||||
|
|
||||||
|
def get_name_of_section(line):
|
||||||
|
line = line[line.find('['):line.rfind(']')]
|
||||||
|
return ' '.join(line.split(' ', 1)[1:])
|
226
secop/gui/cfg_editor/mainwindow.py
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# *****************************************************************************
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Module authors:
|
||||||
|
# Sandra Seger <sandra.seger@frm2.tum.de>
|
||||||
|
#
|
||||||
|
# *****************************************************************************
|
||||||
|
|
||||||
|
import os
|
||||||
|
from secop.gui.qt import QMainWindow, QMessageBox
|
||||||
|
from secop.gui.cfg_editor.node_display import NodeDisplay
|
||||||
|
from secop.gui.cfg_editor.utils import loadUi, get_file_paths
|
||||||
|
from secop.gui.cfg_editor.widgets import TabBar
|
||||||
|
|
||||||
|
|
||||||
|
# TODO move secop mainwinodw to gui/client and all specific stuff
|
||||||
|
NODE = 'node'
|
||||||
|
MODULE = 'module'
|
||||||
|
INTERFACE = 'interface'
|
||||||
|
PARAMETER = 'parameter'
|
||||||
|
PROPERTY = 'property'
|
||||||
|
COMMENT = 'comment'
|
||||||
|
|
||||||
|
|
||||||
|
class MainWindow(QMainWindow):
|
||||||
|
|
||||||
|
def __init__(self, file_path=None, parent=None):
|
||||||
|
QMainWindow.__init__(self, parent)
|
||||||
|
loadUi(self, 'mainwindow.ui')
|
||||||
|
self.tabWidget.currentChanged.connect(self.tab_relevant_btns_disable)
|
||||||
|
if file_path is None:
|
||||||
|
self.tab_relevant_btns_disable(-1)
|
||||||
|
else:
|
||||||
|
self.duplicate_btn.setEnabled(False)
|
||||||
|
self.delete_btn.setEnabled(False)
|
||||||
|
self.tabWidget.setTabBar(TabBar())
|
||||||
|
self.tabWidget.tabBar().tabCloseRequested.connect(self.close_tab)
|
||||||
|
self.open_file(file_path)
|
||||||
|
self.new_files = 0
|
||||||
|
|
||||||
|
def on_actionNew(self):
|
||||||
|
name = 'unnamed_%i.cfg' % self.new_files if self.new_files else \
|
||||||
|
'unnamed.cfg'
|
||||||
|
self.new_node(name)
|
||||||
|
self.new_files += 1
|
||||||
|
|
||||||
|
def on_actionOpen(self):
|
||||||
|
file_paths = get_file_paths(self)
|
||||||
|
for file_path in file_paths:
|
||||||
|
self.open_file(file_path)
|
||||||
|
|
||||||
|
def on_actionSave(self):
|
||||||
|
self.save_tab(self.tabWidget.currentIndex())
|
||||||
|
|
||||||
|
def on_actionSave_as(self):
|
||||||
|
self.save_tab(self.tabWidget.currentIndex(), True)
|
||||||
|
|
||||||
|
def on_action_Close(self):
|
||||||
|
self.close_tab(self.tabWidget.currentIndex())
|
||||||
|
|
||||||
|
def on_actionQuit(self):
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def on_actionAbout(self):
|
||||||
|
QMessageBox.about(
|
||||||
|
self, 'About cfg-editor',
|
||||||
|
'''
|
||||||
|
<h2>About cfg-editor</h2>
|
||||||
|
<p style="font-style: italic">
|
||||||
|
(C) 2019 MLZ instrument control
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
cfg-editor is a graphical interface for editing
|
||||||
|
FRAPPY-configuration-files.
|
||||||
|
</p>
|
||||||
|
<h3>Author:</h3>
|
||||||
|
<ul>
|
||||||
|
<li>Copyright (C) 2019
|
||||||
|
<a href="mailto:sandra.seger@frm2.tum.de">Sandra Seger</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
cfg-editor is published under the
|
||||||
|
<a href="http://www.gnu.org/licenses/gpl.html">GPL
|
||||||
|
(GNU General Public License)</a>
|
||||||
|
</p>
|
||||||
|
''')
|
||||||
|
|
||||||
|
def on_add_module(self):
|
||||||
|
self.tabWidget.currentWidget().tree_widget.add_module()
|
||||||
|
|
||||||
|
def on_add_interface(self):
|
||||||
|
self.tabWidget.currentWidget().tree_widget.add_interface()
|
||||||
|
|
||||||
|
def on_add_parameter(self):
|
||||||
|
self.tabWidget.currentWidget().tree_widget.add_parameter()
|
||||||
|
|
||||||
|
def on_add_property(self):
|
||||||
|
self.tabWidget.currentWidget().tree_widget.add_property()
|
||||||
|
|
||||||
|
def on_add_comment(self):
|
||||||
|
self.tabWidget.currentWidget().tree_widget.add_comment()
|
||||||
|
|
||||||
|
def on_duplicate(self):
|
||||||
|
self.tabWidget.currentWidget().tree_widget.duplicate()
|
||||||
|
|
||||||
|
def on_delete(self):
|
||||||
|
self.tabWidget.currentWidget().tree_widget.delete()
|
||||||
|
|
||||||
|
def open_file(self, file_path):
|
||||||
|
for i in range(0, self.tabWidget.count()):
|
||||||
|
if self.tabWidget.widget(i).tree_widget.file_path == file_path:
|
||||||
|
self.tabWidget.setCurrentIndex(i)
|
||||||
|
return
|
||||||
|
if file_path:
|
||||||
|
self.new_node(os.path.basename(file_path), file_path)
|
||||||
|
|
||||||
|
def close_tab(self, index):
|
||||||
|
if self.tabWidget.widget(index).saved:
|
||||||
|
reply = QMessageBox.Close
|
||||||
|
else:
|
||||||
|
reply = self.show_save_message(self.tabWidget.tabText(index))
|
||||||
|
if reply == QMessageBox.Cancel:
|
||||||
|
return
|
||||||
|
elif reply == QMessageBox.Save:
|
||||||
|
self.save_tab(index)
|
||||||
|
self.tabWidget.removeTab(index)
|
||||||
|
|
||||||
|
def save_tab(self, index, save_as=False):
|
||||||
|
widget = self.tabWidget.widget(index)
|
||||||
|
if widget.tree_widget.save(save_as):
|
||||||
|
self.tabWidget.setTabText(index, os.path.basename(
|
||||||
|
widget.tree_widget.file_path))
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
if self.tabWidget.count():
|
||||||
|
reply = None
|
||||||
|
for i in range(0, self.tabWidget.count()):
|
||||||
|
if not self.tabWidget.widget(i).saved:
|
||||||
|
reply = self.show_save_message()
|
||||||
|
break
|
||||||
|
if not reply:
|
||||||
|
reply = QMessageBox.Close
|
||||||
|
if reply == QMessageBox.Cancel:
|
||||||
|
event.ignore()
|
||||||
|
return
|
||||||
|
elif reply == QMessageBox.Save:
|
||||||
|
for i in range(0, self.tabWidget.count()):
|
||||||
|
self.save_tab(i)
|
||||||
|
event.accept()
|
||||||
|
|
||||||
|
def show_save_message(self, file_name=''):
|
||||||
|
if file_name:
|
||||||
|
file_name = ' in "%s"' % file_name
|
||||||
|
return QMessageBox.question(self, 'Save file?', '''
|
||||||
|
<h2>Do you want to save changes%s?</h2>
|
||||||
|
<p>
|
||||||
|
Your changes will be lost if you don't save them!
|
||||||
|
</p>
|
||||||
|
''' % file_name,
|
||||||
|
QMessageBox.Cancel | QMessageBox.Close |
|
||||||
|
QMessageBox.Save, QMessageBox.Save)
|
||||||
|
|
||||||
|
def new_node(self, name, file_path=None):
|
||||||
|
node = NodeDisplay(file_path)
|
||||||
|
if node.created:
|
||||||
|
node.tree_widget.currentItemChanged.connect(self.disable_btns)
|
||||||
|
self.tabWidget.setCurrentIndex(self.tabWidget.addTab(node, name))
|
||||||
|
|
||||||
|
def disable_btns(self, current, previous):
|
||||||
|
cur_kind = current.kind if current else None
|
||||||
|
self.add_parameter_btn.setEnabled(True)
|
||||||
|
self.add_property_btn.setEnabled(True)
|
||||||
|
self.add_comment_btn.setEnabled(True)
|
||||||
|
self.duplicate_btn.setEnabled(True)
|
||||||
|
self.delete_btn.setEnabled(True)
|
||||||
|
if cur_kind is None:
|
||||||
|
self.add_parameter_btn.setEnabled(False)
|
||||||
|
self.add_property_btn.setEnabled(False)
|
||||||
|
self.add_comment_btn.setEnabled(False)
|
||||||
|
self.duplicate_btn.setEnabled(False)
|
||||||
|
self.delete_btn.setEnabled(False)
|
||||||
|
elif cur_kind not in [MODULE, INTERFACE]:
|
||||||
|
self.duplicate_btn.setEnabled(False)
|
||||||
|
if cur_kind == NODE:
|
||||||
|
self.duplicate_btn.setEnabled(False)
|
||||||
|
self.delete_btn.setEnabled(False)
|
||||||
|
elif cur_kind == INTERFACE:
|
||||||
|
self.add_parameter_btn.setEnabled(False)
|
||||||
|
elif cur_kind == PARAMETER:
|
||||||
|
self.add_parameter_btn.setEnabled(False)
|
||||||
|
elif cur_kind == PROPERTY:
|
||||||
|
self.add_parameter_btn.setEnabled(False)
|
||||||
|
self.add_property_btn.setEnabled(False)
|
||||||
|
elif cur_kind == COMMENT:
|
||||||
|
self.add_parameter_btn.setEnabled(False)
|
||||||
|
self.add_property_btn.setEnabled(False)
|
||||||
|
self.add_comment_btn.setEnabled(False)
|
||||||
|
|
||||||
|
def tab_relevant_btns_disable(self, index):
|
||||||
|
if index == -1:
|
||||||
|
enable = False
|
||||||
|
self.duplicate_btn.setEnabled(enable)
|
||||||
|
self.delete_btn.setEnabled(enable)
|
||||||
|
else:
|
||||||
|
enable = True
|
||||||
|
self.save_btn.setEnabled(enable)
|
||||||
|
self.add_module_btn.setEnabled(enable)
|
||||||
|
self.add_interface_btn.setEnabled(enable)
|
||||||
|
self.add_parameter_btn.setEnabled(enable)
|
||||||
|
self.add_property_btn.setEnabled(enable)
|
||||||
|
self.add_comment_btn.setEnabled(enable)
|
67
secop/gui/cfg_editor/node_display.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# *****************************************************************************
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Module authors:
|
||||||
|
# Sandra Seger <sandra.seger@frm2.tum.de>
|
||||||
|
#
|
||||||
|
# *****************************************************************************
|
||||||
|
|
||||||
|
from secop.gui.qt import QWidget, Qt, QHBoxLayout, QSpacerItem, QSizePolicy
|
||||||
|
from secop.gui.cfg_editor.utils import loadUi
|
||||||
|
|
||||||
|
|
||||||
|
class NodeDisplay(QWidget):
|
||||||
|
def __init__(self, file_path=None, parent=None):
|
||||||
|
QWidget.__init__(self, parent)
|
||||||
|
loadUi(self, 'node_display.ui')
|
||||||
|
self.saved = True if file_path else False
|
||||||
|
self.created = self.tree_widget.set_file(file_path)
|
||||||
|
self.tree_widget.save_status_changed.connect(self.change_save_status)
|
||||||
|
self.tree_widget.currentItemChanged.connect(self.set_scroll_area)
|
||||||
|
self.scroll_area_layout.setAlignment(Qt.AlignTop)
|
||||||
|
self.set_scroll_area(self.tree_widget.get_selected_item(), None)
|
||||||
|
self.splitter.setSizes([1, 1])
|
||||||
|
|
||||||
|
def change_save_status(self, saved):
|
||||||
|
self.saved = saved
|
||||||
|
|
||||||
|
def set_scroll_area(self, current, previous):
|
||||||
|
self.remove_all_from_scroll_area(self.scroll_area_layout)
|
||||||
|
self.scroll_area_layout.addWidget(current.widget)
|
||||||
|
for index in range(0, current.childCount()):
|
||||||
|
child_layout = QHBoxLayout()
|
||||||
|
spacer = QSpacerItem(30, 0, QSizePolicy.Fixed,
|
||||||
|
QSizePolicy.Minimum)
|
||||||
|
child_layout.addSpacerItem(spacer)
|
||||||
|
child_layout.addWidget(current.child(index).widget)
|
||||||
|
self.scroll_area_layout.addLayout(child_layout)
|
||||||
|
for sub_index in range(0, current.child(index).childCount()):
|
||||||
|
sub_child_layout = QHBoxLayout()
|
||||||
|
sub_spacer = QSpacerItem(60, 0, QSizePolicy.Fixed,
|
||||||
|
QSizePolicy.Minimum)
|
||||||
|
sub_child_layout.addSpacerItem(sub_spacer)
|
||||||
|
sub_child_layout.addWidget(
|
||||||
|
current.child(index).child(sub_index).widget)
|
||||||
|
self.scroll_area_layout.addLayout(sub_child_layout)
|
||||||
|
|
||||||
|
def remove_all_from_scroll_area(self, layout):
|
||||||
|
for index in range(layout.count()-1, -1, -1):
|
||||||
|
item = layout.itemAt(index)
|
||||||
|
if item.widget():
|
||||||
|
item.widget().setParent(None)
|
||||||
|
elif item.layout():
|
||||||
|
self.remove_all_from_scroll_area(item.layout())
|
222
secop/gui/cfg_editor/tree_widget_item.py
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# *****************************************************************************
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Module authors:
|
||||||
|
# Sandra Seger <sandra.seger@frm2.tum.de>
|
||||||
|
#
|
||||||
|
# *****************************************************************************
|
||||||
|
|
||||||
|
from secop.gui.qt import QTreeWidgetItem, QFont, QWidget, QVBoxLayout, QLabel, \
|
||||||
|
QHBoxLayout, QPushButton, QSize, QSizePolicy, QDialog, QTextEdit, pyqtSignal
|
||||||
|
from secop.gui.cfg_editor.utils import setTreeIcon, setIcon, loadUi, \
|
||||||
|
set_name_edit_style
|
||||||
|
from secop.gui.valuewidgets import get_widget
|
||||||
|
from secop.properties import Property
|
||||||
|
|
||||||
|
NODE = 'node'
|
||||||
|
INTERFACE = 'interface'
|
||||||
|
MODULE = 'module'
|
||||||
|
PARAMETER = 'parameter'
|
||||||
|
PROPERTY = 'property'
|
||||||
|
COMMENT = 'comment'
|
||||||
|
|
||||||
|
|
||||||
|
class TreeWidgetItem(QTreeWidgetItem):
|
||||||
|
def __init__(self, kind=None, name='', value=None, class_object=None,
|
||||||
|
parameters=None, properties=None, parent=None):
|
||||||
|
"""object_class: for interfaces and modules = class
|
||||||
|
for parameter and properties = their objects
|
||||||
|
the datatype passed onto ValueWidget should be on of secop.datatypes"""
|
||||||
|
# TODO: like stated in docstring the datatype for parameters and
|
||||||
|
# properties must be found out through their object
|
||||||
|
QTreeWidgetItem.__init__(self, parent)
|
||||||
|
self.kind = kind
|
||||||
|
self.name = name
|
||||||
|
self.class_object = class_object
|
||||||
|
self.parameters = parameters or {}
|
||||||
|
self.properties = properties or {}
|
||||||
|
if self.kind and self.kind != 'node':
|
||||||
|
setTreeIcon(self, '%s.png' % self.kind)
|
||||||
|
else:
|
||||||
|
setTreeIcon(self, 'empty.png')
|
||||||
|
font = QFont()
|
||||||
|
font.setWeight(QFont.Bold)
|
||||||
|
self.setFont(0, font)
|
||||||
|
self.setText(0, self.name)
|
||||||
|
self.duplicates = 0
|
||||||
|
datatype = None if type(class_object) != Property else \
|
||||||
|
class_object.datatype
|
||||||
|
self.widget = ValueWidget(name, value, datatype, kind)
|
||||||
|
if kind in [NODE, MODULE, INTERFACE]:
|
||||||
|
self.widget.edit_btn.clicked.connect(self.change_name)
|
||||||
|
|
||||||
|
def addChild(self, item):
|
||||||
|
QTreeWidgetItem.addChild(self, item)
|
||||||
|
item.setExpanded(True)
|
||||||
|
|
||||||
|
def duplicate(self):
|
||||||
|
self.duplicates += 1
|
||||||
|
duplicate = TreeWidgetItem(self.kind, '%s_%i' % (self.name,
|
||||||
|
self.duplicates), self.get_value(),
|
||||||
|
self.class_object)
|
||||||
|
self.parent().addChild(duplicate)
|
||||||
|
for i in range(self.childCount()):
|
||||||
|
child = self.child(i)
|
||||||
|
duplicate.addChild(TreeWidgetItem(child.kind,
|
||||||
|
child.name, child.widget.get_value()))
|
||||||
|
for k in range(child.childCount()):
|
||||||
|
sub_child = child.child(k)
|
||||||
|
duplicate.child(i).addChild(TreeWidgetItem(sub_child.kind,
|
||||||
|
sub_child.name,
|
||||||
|
sub_child.widget.get_value(),
|
||||||
|
sub_child.datatype))
|
||||||
|
|
||||||
|
def set_name(self, name):
|
||||||
|
self.name = name
|
||||||
|
self.setText(0, self.name)
|
||||||
|
self.widget.set_name(name)
|
||||||
|
|
||||||
|
def get_value(self):
|
||||||
|
return self.widget.get_value()
|
||||||
|
|
||||||
|
def set_value(self, value):
|
||||||
|
self.widget.set_value(value)
|
||||||
|
|
||||||
|
def set_class_object(self, class_obj, value=''):
|
||||||
|
# TODO: should do stuff here if module or interface class is changed or
|
||||||
|
# datatype
|
||||||
|
self.class_object = class_obj
|
||||||
|
datatype = None if type(self.class_object) != Property else \
|
||||||
|
self.class_object.datatype
|
||||||
|
self.widget.set_datatype(datatype, value)
|
||||||
|
|
||||||
|
def get_children_names(self):
|
||||||
|
children = []
|
||||||
|
for i in range(0, self.childCount()):
|
||||||
|
children.append(self.child(i).name)
|
||||||
|
return children
|
||||||
|
|
||||||
|
def change_name(self):
|
||||||
|
if self.parent():
|
||||||
|
invalid_names = self.parent().get_children_names()
|
||||||
|
invalid_names.remove(self.name)
|
||||||
|
else:
|
||||||
|
invalid_names = ['']
|
||||||
|
dialog = ChangeNameDialog(self.name, invalid_names)
|
||||||
|
new_name = dialog.get_values()
|
||||||
|
if new_name:
|
||||||
|
self.set_name(new_name)
|
||||||
|
|
||||||
|
|
||||||
|
class ValueWidget(QWidget):
|
||||||
|
|
||||||
|
save_status_changed = pyqtSignal(bool)
|
||||||
|
|
||||||
|
def __init__(self, name='', value='', datatype=None, kind='', parent=None):
|
||||||
|
# TODO: implement: change module/interface class
|
||||||
|
QWidget.__init__(self, parent)
|
||||||
|
self.datatype = datatype
|
||||||
|
self.layout = QVBoxLayout()
|
||||||
|
self.name_label = QLabel(name)
|
||||||
|
self.name_label.setStyleSheet('font-weight: bold')
|
||||||
|
self.kind = kind
|
||||||
|
if self.kind in [NODE, MODULE, INTERFACE]:
|
||||||
|
self.edit_btn = QPushButton()
|
||||||
|
setIcon(self.edit_btn, 'edit.png')
|
||||||
|
self.edit_btn.setIconSize(QSize(18, 18))
|
||||||
|
self.edit_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
||||||
|
self.edit_btn.setFlat(True)
|
||||||
|
layout = QHBoxLayout()
|
||||||
|
layout.addWidget(self.name_label)
|
||||||
|
layout.addWidget(self.edit_btn)
|
||||||
|
self.layout.addLayout(layout)
|
||||||
|
else:
|
||||||
|
self.layout.addWidget(self.name_label)
|
||||||
|
# TODO value_display.valueChanged.connect(emit_save_status_changed) ->
|
||||||
|
# implement or map a valueChanged signal for all possible
|
||||||
|
# value_displays:
|
||||||
|
# String = QLineEdit = textChanged
|
||||||
|
# Enum = QComboBox = editTextChanged
|
||||||
|
# Bool = QCheckBox = stateChanged
|
||||||
|
# Int, Float = Q(Double)SpinBox = ValueChanged
|
||||||
|
# Struct, Array = QGroupBox = clicked
|
||||||
|
# Tuple = QFrame = ???
|
||||||
|
if self.kind == PROPERTY and datatype and name != 'datatype':
|
||||||
|
# TODO what to do if property is datatype
|
||||||
|
self.value_display = get_widget(datatype)
|
||||||
|
self.value_display.set_value(value)
|
||||||
|
elif self.kind in [NODE, COMMENT]:
|
||||||
|
self.value_display = QTextEdit()
|
||||||
|
self.value_display.text = self.value_display.toPlainText
|
||||||
|
self.value_display.setText = self.value_display.setPlainText
|
||||||
|
self.value_display.textChanged.connect(self.emit_save_status_changed)
|
||||||
|
self.set_value(value)
|
||||||
|
else:
|
||||||
|
self.value_display = QLabel(value)
|
||||||
|
self.layout.addWidget(self.value_display)
|
||||||
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
|
def get_value(self):
|
||||||
|
if self.datatype:
|
||||||
|
return self.value_display.get_value()
|
||||||
|
return self.value_display.text()
|
||||||
|
|
||||||
|
def set_value(self, value):
|
||||||
|
# TODO try block
|
||||||
|
if self.datatype:
|
||||||
|
self.value_display.set_value(value)
|
||||||
|
else:
|
||||||
|
self.value_display.setText(value)
|
||||||
|
|
||||||
|
def set_name(self, name):
|
||||||
|
if name != self.name_label.text():
|
||||||
|
self.emit_save_status_changed(False)
|
||||||
|
self.name_label.setText(name)
|
||||||
|
|
||||||
|
def set_datatype(self, datatype, value=''):
|
||||||
|
if datatype == self.datatype:
|
||||||
|
return
|
||||||
|
# TODO: remove old value_display
|
||||||
|
self.datatype = datatype
|
||||||
|
if self.kind == PROPERTY and datatype:
|
||||||
|
self.value_display = get_widget(datatype)
|
||||||
|
self.value_display.set_value(value)
|
||||||
|
else:
|
||||||
|
self.value_display = QLabel(value)
|
||||||
|
|
||||||
|
def emit_save_status_changed(self, status=False):
|
||||||
|
self.save_status_changed.emit(status)
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeNameDialog(QDialog):
|
||||||
|
def __init__(self, current_name='', invalid_names=None, parent=None):
|
||||||
|
QWidget.__init__(self, parent)
|
||||||
|
loadUi(self, 'change_name_dialog.ui')
|
||||||
|
self.invalid_names = invalid_names
|
||||||
|
self.name.setText(current_name)
|
||||||
|
self.name.selectAll()
|
||||||
|
# TODO: input mask
|
||||||
|
self.name.textChanged.connect(self.check_input)
|
||||||
|
|
||||||
|
def get_values(self):
|
||||||
|
if self.exec_() == QDialog.Accepted:
|
||||||
|
return self.name.text()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def check_input(self, name):
|
||||||
|
set_name_edit_style(name in self.invalid_names or name == '', self.name,
|
||||||
|
self.button_box)
|
70
secop/gui/cfg_editor/ui/add_dialog.ui
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>add_dialog</class>
|
||||||
|
<widget class="QDialog" name="add_dialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>250</width>
|
||||||
|
<height>136</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>add dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="add_layout"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="button_box">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>button_box</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>button_box</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>add_dialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>button_box</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>add_dialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
74
secop/gui/cfg_editor/ui/change_name_dialog.ui
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>change_name_dialog</class>
|
||||||
|
<widget class="QDialog" name="change_name_dialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>239</width>
|
||||||
|
<height>81</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>change name</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="name"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>name:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QDialogButtonBox" name="button_box">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>button_box</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>change_name_dialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>button_box</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>change_name_dialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
BIN
secop/gui/cfg_editor/ui/icons/add_comment.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
secop/gui/cfg_editor/ui/icons/add_interface.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
secop/gui/cfg_editor/ui/icons/add_module.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
secop/gui/cfg_editor/ui/icons/add_parameter.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
secop/gui/cfg_editor/ui/icons/add_property.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
20
secop/gui/cfg_editor/ui/icons/cfg-editor.qrc
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource>
|
||||||
|
<file>delete.png</file>
|
||||||
|
<file>duplicate.png</file>
|
||||||
|
<file>add_comment.png</file>
|
||||||
|
<file>add_interface.png</file>
|
||||||
|
<file>add_module.png</file>
|
||||||
|
<file>add_parameter.png</file>
|
||||||
|
<file>add_property.png</file>
|
||||||
|
<file>comment.png</file>
|
||||||
|
<file>interface.png</file>
|
||||||
|
<file>module.png</file>
|
||||||
|
<file>parameter.png</file>
|
||||||
|
<file>property.png</file>
|
||||||
|
<file>edit.png</file>
|
||||||
|
<file>new.png</file>
|
||||||
|
<file>open.png</file>
|
||||||
|
<file>save.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
BIN
secop/gui/cfg_editor/ui/icons/comment.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
secop/gui/cfg_editor/ui/icons/delete.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
secop/gui/cfg_editor/ui/icons/duplicate.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
secop/gui/cfg_editor/ui/icons/edit.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
secop/gui/cfg_editor/ui/icons/empty.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
secop/gui/cfg_editor/ui/icons/interface.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
secop/gui/cfg_editor/ui/icons/module.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
secop/gui/cfg_editor/ui/icons/new.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
secop/gui/cfg_editor/ui/icons/open.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
secop/gui/cfg_editor/ui/icons/parameter.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
secop/gui/cfg_editor/ui/icons/property.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
secop/gui/cfg_editor/ui/icons/save.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
969
secop/gui/cfg_editor/ui/mainwindow.ui
Normal file
@ -0,0 +1,969 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>977</width>
|
||||||
|
<height>799</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>9</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>cfg-editor</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="icon_layout">
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="new_btn">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>create new SEC node</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>new</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons/cfg-editor.qrc">
|
||||||
|
<normaloff>:/new.png</normaloff>
|
||||||
|
<normalon>:/new.png</normalon>:/new.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>60</width>
|
||||||
|
<height>60</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolButtonStyle">
|
||||||
|
<enum>Qt::ToolButtonTextUnderIcon</enum>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="open_btn">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>open file</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>open</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons/cfg-editor.qrc">
|
||||||
|
<normaloff>:/open.png</normaloff>
|
||||||
|
<normalon>:/open.png</normalon>:/open.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>60</width>
|
||||||
|
<height>60</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolButtonStyle">
|
||||||
|
<enum>Qt::ToolButtonTextUnderIcon</enum>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="save_btn">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>save</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>save</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons/cfg-editor.qrc">
|
||||||
|
<normaloff>:/save.png</normaloff>
|
||||||
|
<normalon>:/save.png</normalon>:/save.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>60</width>
|
||||||
|
<height>60</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolButtonStyle">
|
||||||
|
<enum>Qt::ToolButtonTextUnderIcon</enum>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="add_interface_btn">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>add interface</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>add interface</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons/cfg-editor.qrc">
|
||||||
|
<normaloff>:/add_interface.png</normaloff>
|
||||||
|
<normalon>:/add_interface.png</normalon>:/add_interface.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>60</width>
|
||||||
|
<height>60</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolButtonStyle">
|
||||||
|
<enum>Qt::ToolButtonTextUnderIcon</enum>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="add_module_btn">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>add module</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>add module</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons/cfg-editor.qrc">
|
||||||
|
<normaloff>:/add_module.png</normaloff>
|
||||||
|
<normalon>:/add_module.png</normalon>:/add_module.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>60</width>
|
||||||
|
<height>60</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolButtonStyle">
|
||||||
|
<enum>Qt::ToolButtonTextUnderIcon</enum>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="add_parameter_btn">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>add parameter</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>add parameter</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons/cfg-editor.qrc">
|
||||||
|
<normaloff>:/add_parameter.png</normaloff>
|
||||||
|
<normalon>:/add_parameter.png</normalon>:/add_parameter.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>60</width>
|
||||||
|
<height>60</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolButtonStyle">
|
||||||
|
<enum>Qt::ToolButtonTextUnderIcon</enum>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="add_property_btn">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>add property</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>add property</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normalon>:/add_property.png</normalon>
|
||||||
|
</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>60</width>
|
||||||
|
<height>60</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolButtonStyle">
|
||||||
|
<enum>Qt::ToolButtonTextUnderIcon</enum>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="add_comment_btn">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>add comment</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>add comment</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons/cfg-editor.qrc">
|
||||||
|
<normaloff>:/add_comment.png</normaloff>:/add_comment.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>60</width>
|
||||||
|
<height>60</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolButtonStyle">
|
||||||
|
<enum>Qt::ToolButtonTextUnderIcon</enum>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_2">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>9</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="lineWidth">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="duplicate_btn">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>duplicate module or interface</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>duplicate</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons/cfg-editor.qrc">
|
||||||
|
<normaloff>:/duplicate.png</normaloff>
|
||||||
|
<normalon>:/duplicate.png</normalon>:/duplicate.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>60</width>
|
||||||
|
<height>60</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolButtonStyle">
|
||||||
|
<enum>Qt::ToolButtonTextUnderIcon</enum>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="delete_btn">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>delete</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>delete</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons/cfg-editor.qrc">
|
||||||
|
<normaloff>:/delete.png</normaloff>
|
||||||
|
<normalon>:/delete.png</normalon>:/delete.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>60</width>
|
||||||
|
<height>60</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolButtonStyle">
|
||||||
|
<enum>Qt::ToolButtonTextUnderIcon</enum>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="main_layout">
|
||||||
|
<item>
|
||||||
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
|
<property name="contextMenuPolicy">
|
||||||
|
<enum>Qt::DefaultContextMenu</enum>
|
||||||
|
</property>
|
||||||
|
<property name="tabShape">
|
||||||
|
<enum>QTabWidget::Rounded</enum>
|
||||||
|
</property>
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
<property name="documentMode">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="tabsClosable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="movable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>977</width>
|
||||||
|
<height>20</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuFile">
|
||||||
|
<property name="title">
|
||||||
|
<string>&File</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionNew"/>
|
||||||
|
<addaction name="actionOpen"/>
|
||||||
|
<addaction name="actionSave"/>
|
||||||
|
<addaction name="actionSave_as"/>
|
||||||
|
<addaction name="action_Close"/>
|
||||||
|
<addaction name="actionQuit"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_Help">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Help</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionAbout"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_Edit">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Edit</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionAdd_interface"/>
|
||||||
|
<addaction name="actionAdd_module"/>
|
||||||
|
<addaction name="actionAdd_parameter"/>
|
||||||
|
<addaction name="actionAdd_property"/>
|
||||||
|
<addaction name="actionAdd_comment"/>
|
||||||
|
<addaction name="actionDuplicate"/>
|
||||||
|
<addaction name="actionDelete"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menuFile"/>
|
||||||
|
<addaction name="menu_Edit"/>
|
||||||
|
<addaction name="menu_Help"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
<action name="actionNew">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons/cfg-editor.qrc">
|
||||||
|
<normaloff>:/new.png</normaloff>
|
||||||
|
<normalon>:/new.png</normalon>:/new.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&New</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Create new file</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+N</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionOpen">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons/cfg-editor.qrc">
|
||||||
|
<normaloff>:/open.png</normaloff>
|
||||||
|
<normalon>:/open.png</normalon>:/open.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Open ...</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+O</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSave">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons/cfg-editor.qrc">
|
||||||
|
<normaloff>:/save.png</normaloff>
|
||||||
|
<normalon>:/save.png</normalon>:/save.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Save</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+S</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSave_as">
|
||||||
|
<property name="text">
|
||||||
|
<string>Save &as ...</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Shift+S</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAbout">
|
||||||
|
<property name="text">
|
||||||
|
<string>&About</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+A</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionQuit">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Quit</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Q</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAdd_SEC_node">
|
||||||
|
<property name="text">
|
||||||
|
<string>add SEC node</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAdd_interface">
|
||||||
|
<property name="text">
|
||||||
|
<string>add interface</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAdd_module">
|
||||||
|
<property name="text">
|
||||||
|
<string>add module</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAdd_parameter">
|
||||||
|
<property name="text">
|
||||||
|
<string>add parameter</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAdd_property">
|
||||||
|
<property name="text">
|
||||||
|
<string>add property</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAdd_comment">
|
||||||
|
<property name="text">
|
||||||
|
<string>add comment</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDuplicate">
|
||||||
|
<property name="text">
|
||||||
|
<string>duplicate</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDelete">
|
||||||
|
<property name="text">
|
||||||
|
<string>delete</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_Close">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Close</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+F4</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="icons/cfg-editor.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>new_btn</sender>
|
||||||
|
<signal>clicked()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_actionNew()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>39</x>
|
||||||
|
<y>76</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>3</x>
|
||||||
|
<y>91</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>open_btn</sender>
|
||||||
|
<signal>clicked()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_actionOpen()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>132</x>
|
||||||
|
<y>81</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>3</x>
|
||||||
|
<y>45</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>save_btn</sender>
|
||||||
|
<signal>clicked()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_actionSave()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>222</x>
|
||||||
|
<y>59</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>0</x>
|
||||||
|
<y>25</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>add_interface_btn</sender>
|
||||||
|
<signal>clicked()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_add_interface()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>346</x>
|
||||||
|
<y>83</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>328</x>
|
||||||
|
<y>24</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>add_module_btn</sender>
|
||||||
|
<signal>clicked()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_add_module()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>432</x>
|
||||||
|
<y>61</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>401</x>
|
||||||
|
<y>24</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>add_parameter_btn</sender>
|
||||||
|
<signal>clicked()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_add_parameter()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>527</x>
|
||||||
|
<y>76</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>499</x>
|
||||||
|
<y>24</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>add_property_btn</sender>
|
||||||
|
<signal>clicked()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_add_property()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>644</x>
|
||||||
|
<y>71</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>613</x>
|
||||||
|
<y>24</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>add_comment_btn</sender>
|
||||||
|
<signal>clicked()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_add_comment()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>732</x>
|
||||||
|
<y>74</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>708</x>
|
||||||
|
<y>20</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>duplicate_btn</sender>
|
||||||
|
<signal>clicked()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_duplicate()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>831</x>
|
||||||
|
<y>87</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>818</x>
|
||||||
|
<y>24</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>delete_btn</sender>
|
||||||
|
<signal>clicked()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_delete()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>919</x>
|
||||||
|
<y>55</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>909</x>
|
||||||
|
<y>21</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>actionNew</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_actionNew()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>488</x>
|
||||||
|
<y>399</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>actionOpen</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_actionOpen()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>488</x>
|
||||||
|
<y>399</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>actionSave</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_actionSave()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>488</x>
|
||||||
|
<y>399</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>actionSave_as</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_actionSave_as()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>488</x>
|
||||||
|
<y>399</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>actionQuit</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_actionQuit()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>488</x>
|
||||||
|
<y>399</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>actionAbout</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_actionAbout()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>488</x>
|
||||||
|
<y>399</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>actionAdd_interface</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_add_interface()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>488</x>
|
||||||
|
<y>399</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>actionAdd_module</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_add_module()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>488</x>
|
||||||
|
<y>399</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>actionAdd_parameter</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_add_parameter()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>488</x>
|
||||||
|
<y>399</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>actionAdd_property</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_add_property()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>488</x>
|
||||||
|
<y>399</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>actionAdd_comment</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_add_comment()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>488</x>
|
||||||
|
<y>399</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>actionDuplicate</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_duplicate()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>488</x>
|
||||||
|
<y>399</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>actionDelete</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_delete()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>488</x>
|
||||||
|
<y>399</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>action_Close</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>on_action_Close()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>488</x>
|
||||||
|
<y>399</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
<slots>
|
||||||
|
<slot>on_actionNew()</slot>
|
||||||
|
<slot>on_add_module()</slot>
|
||||||
|
<slot>on_add_interface()</slot>
|
||||||
|
<slot>on_add_parameter()</slot>
|
||||||
|
<slot>on_add_property()</slot>
|
||||||
|
<slot>on_add_comment()</slot>
|
||||||
|
<slot>on_actionOpen()</slot>
|
||||||
|
<slot>on_actionSave()</slot>
|
||||||
|
<slot>on_duplicate()</slot>
|
||||||
|
<slot>on_delete()</slot>
|
||||||
|
<slot>on_actionSave_as()</slot>
|
||||||
|
<slot>on_actionQuit()</slot>
|
||||||
|
<slot>on_actionAbout()</slot>
|
||||||
|
<slot>on_action_Close()</slot>
|
||||||
|
</slots>
|
||||||
|
</ui>
|
89
secop/gui/cfg_editor/ui/node_display.ui
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="Form">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>945</width>
|
||||||
|
<height>671</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QSplitter" name="splitter">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="opaqueResize">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="handleWidth">
|
||||||
|
<number>8</number>
|
||||||
|
</property>
|
||||||
|
<property name="childrenCollapsible">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="TreeWidget" name="tree_widget">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="autoExpandDelay">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
<property name="columnCount">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<attribute name="headerVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">1</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
|
<widget class="QScrollArea" name="scrollArea">
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scrollAreaWidgetContent">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>73</width>
|
||||||
|
<height>651</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="scroll_area_layout"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>TreeWidget</class>
|
||||||
|
<extends>QTreeWidget</extends>
|
||||||
|
<header>secop.gui.cfg_editor.widgets</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
193
secop/gui/cfg_editor/utils.py
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# *****************************************************************************
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Module authors:
|
||||||
|
# Sandra Seger <sandra.seger@frm2.tum.de>
|
||||||
|
#
|
||||||
|
# *****************************************************************************
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
from os import path, listdir
|
||||||
|
import sys
|
||||||
|
import inspect
|
||||||
|
from secop.gui.qt import uic, QIcon, QSize, QFileDialog, QDialogButtonBox
|
||||||
|
from secop.server import getGeneralConfig
|
||||||
|
from secop.modules import Module
|
||||||
|
from secop.params import Parameter
|
||||||
|
from secop.properties import Property
|
||||||
|
from secop.protocol.interface.tcp import TCPServer
|
||||||
|
|
||||||
|
uipath = path.dirname(__file__)
|
||||||
|
|
||||||
|
|
||||||
|
def loadUi(widget, uiname, subdir='ui'):
|
||||||
|
uic.loadUi(path.join(uipath, subdir, uiname), widget)
|
||||||
|
|
||||||
|
|
||||||
|
def setIcon(widget, icon_name, subdir='ui', icondir='icons'):
|
||||||
|
widget.setIcon(QIcon(path.join(uipath, subdir, icondir, icon_name)))
|
||||||
|
widget.setIconSize(QSize(60, 60))
|
||||||
|
|
||||||
|
|
||||||
|
def set_name_edit_style(invalid, name_edit, button_box=None):
|
||||||
|
if invalid:
|
||||||
|
name_edit.setStyleSheet("color: red")
|
||||||
|
name_edit.setToolTip('Invalid name: name already taken')
|
||||||
|
if button_box:
|
||||||
|
button_box.button(QDialogButtonBox.Ok).setEnabled(False)
|
||||||
|
else:
|
||||||
|
name_edit.setStyleSheet("color: black")
|
||||||
|
name_edit.setToolTip('')
|
||||||
|
if button_box:
|
||||||
|
button_box.button(QDialogButtonBox.Ok).setEnabled(True)
|
||||||
|
|
||||||
|
|
||||||
|
def setTreeIcon(widget, icon_name, subdir='ui', icondir='icons'):
|
||||||
|
widget.setIcon(0, QIcon(path.join(uipath, subdir, icondir, icon_name)))
|
||||||
|
|
||||||
|
|
||||||
|
def setActionIcon(widget, icon_name, subdir='ui', icondir='icons'):
|
||||||
|
widget.setIcon(QIcon(path.join(uipath, subdir, icondir, icon_name)))
|
||||||
|
|
||||||
|
|
||||||
|
def get_subtree_nodes(tree_widget_item):
|
||||||
|
nodes = []
|
||||||
|
nodes.append(tree_widget_item)
|
||||||
|
for i in range(tree_widget_item.childCount()):
|
||||||
|
nodes.extend(get_subtree_nodes(tree_widget_item.child(i)))
|
||||||
|
return nodes
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_children_with_names(tree_widget_item):
|
||||||
|
children = {}
|
||||||
|
for i in range(0, tree_widget_item.childCount()):
|
||||||
|
children[tree_widget_item.child(i).name] = tree_widget_item.child(i)
|
||||||
|
return children
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_items(tree_widget):
|
||||||
|
all_items = []
|
||||||
|
for i in range(tree_widget.topLevelItemCount()):
|
||||||
|
top_item = tree_widget.topLevelItem(i)
|
||||||
|
all_items.extend(get_subtree_nodes(top_item))
|
||||||
|
return all_items
|
||||||
|
|
||||||
|
|
||||||
|
def get_file_paths(widget, open_file=True):
|
||||||
|
dialog = QFileDialog(widget)
|
||||||
|
if open_file:
|
||||||
|
title = 'Open file'
|
||||||
|
dialog.setAcceptMode(QFileDialog.AcceptOpen)
|
||||||
|
dialog.setFileMode(QFileDialog.ExistingFiles)
|
||||||
|
else:
|
||||||
|
title = 'Save file'
|
||||||
|
dialog.setAcceptMode(QFileDialog.AcceptSave)
|
||||||
|
dialog.setFileMode(QFileDialog.AnyFile)
|
||||||
|
dialog.setWindowTitle(title)
|
||||||
|
dialog.setNameFilter('*.cfg')
|
||||||
|
dialog.setDefaultSuffix('.cfg')
|
||||||
|
dialog.exec_()
|
||||||
|
return dialog.selectedFiles()
|
||||||
|
|
||||||
|
|
||||||
|
def get_modules():
|
||||||
|
modules = {}
|
||||||
|
base_path = getGeneralConfig()['basedir']
|
||||||
|
# pylint: disable=too-many-nested-blocks
|
||||||
|
for dirname in listdir(base_path):
|
||||||
|
if dirname.startswith('secop_'):
|
||||||
|
modules[dirname] = {}
|
||||||
|
for filename in listdir(path.join(base_path, dirname)):
|
||||||
|
if not path.isfile(path.join(base_path, dirname, filename)) or \
|
||||||
|
filename == '__init__.py' or filename[-3:] != '.py':
|
||||||
|
continue
|
||||||
|
module = '%s.%s' % (dirname, filename[:-3])
|
||||||
|
module_in_file = False
|
||||||
|
try:
|
||||||
|
__import__(module)
|
||||||
|
for name, obj in inspect.getmembers(sys.modules[module]):
|
||||||
|
if inspect.isclass(obj) and \
|
||||||
|
obj.__module__.startswith('secop_') and \
|
||||||
|
issubclass(obj, Module):
|
||||||
|
# full_name = '%s.%s' % (obj.__module__, name)
|
||||||
|
if not module_in_file:
|
||||||
|
modules[dirname][filename[:-3]] = []
|
||||||
|
module_in_file = True
|
||||||
|
modules[dirname][filename[:-3]].append(name)
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
return modules
|
||||||
|
|
||||||
|
|
||||||
|
def get_module_class_from_name(name):
|
||||||
|
try:
|
||||||
|
last_dot = name.rfind('.')
|
||||||
|
class_name = name[last_dot+1:]
|
||||||
|
module = name[:last_dot]
|
||||||
|
__import__(module)
|
||||||
|
for cls_name, obj in inspect.getmembers(sys.modules[module]):
|
||||||
|
if inspect.isclass(obj) and obj.__module__.startswith('secop_') \
|
||||||
|
and issubclass(obj, Module) and cls_name == class_name:
|
||||||
|
return obj
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
return -1
|
||||||
|
|
||||||
|
|
||||||
|
def get_interface_class_from_name(name):
|
||||||
|
# TODO: return the class of name and not TCPServer hard coded
|
||||||
|
return TCPServer
|
||||||
|
|
||||||
|
|
||||||
|
def get_interfaces():
|
||||||
|
# TODO class must be found out like for modules
|
||||||
|
interfaces = []
|
||||||
|
interface_path = path.join(getGeneralConfig()['basedir'], 'secop',
|
||||||
|
'protocol', 'interface')
|
||||||
|
for filename in listdir(interface_path):
|
||||||
|
if path.isfile(path.join(interface_path, filename)) and \
|
||||||
|
filename != '__init__.py' and filename[-3:] == '.py':
|
||||||
|
interfaces.append(filename[:-3])
|
||||||
|
return interfaces
|
||||||
|
|
||||||
|
|
||||||
|
def get_params(info):
|
||||||
|
"""returns all parameter of a module with all properties of all parameter
|
||||||
|
as dictionary: {parameter name: [Parameter object, {property name, Property object}], ...}"""
|
||||||
|
params = {}
|
||||||
|
try:
|
||||||
|
conf = info.configurables
|
||||||
|
for access in info.accessibles:
|
||||||
|
if type(info.accessibles[access]) == Parameter:
|
||||||
|
params[access] = [info.accessibles[access], conf[access]]
|
||||||
|
except AttributeError:
|
||||||
|
return {}
|
||||||
|
return params
|
||||||
|
|
||||||
|
|
||||||
|
def get_props(info):
|
||||||
|
"""returns all properties of a module class, interface class or parameter
|
||||||
|
as dictionary: {property name: Property object, ...}"""
|
||||||
|
props = {}
|
||||||
|
try:
|
||||||
|
conf = info.configurables
|
||||||
|
for name, value in conf.items():
|
||||||
|
if type(value) == Property:
|
||||||
|
props[name] = value
|
||||||
|
except AttributeError:
|
||||||
|
return {}
|
||||||
|
return props
|
481
secop/gui/cfg_editor/widgets.py
Normal file
@ -0,0 +1,481 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# *****************************************************************************
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Module authors:
|
||||||
|
# Sandra Seger <sandra.seger@frm2.tum.de>
|
||||||
|
#
|
||||||
|
# *****************************************************************************
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from secop.gui.cfg_editor.config_file import write_config, read_config
|
||||||
|
from secop.gui.cfg_editor.tree_widget_item import TreeWidgetItem
|
||||||
|
from secop.gui.cfg_editor.utils import get_file_paths, get_modules, \
|
||||||
|
get_interfaces, loadUi, set_name_edit_style, get_module_class_from_name, \
|
||||||
|
get_all_items, get_interface_class_from_name, get_params, get_props, \
|
||||||
|
setActionIcon
|
||||||
|
from secop.gui.qt import QWidget, QDialog, QLabel, QTabBar, Qt, QPoint, QMenu, \
|
||||||
|
QTreeWidget, QSize, pyqtSignal, QLineEdit, QComboBox, QDialogButtonBox, \
|
||||||
|
QTextEdit, QTreeView, QStandardItemModel, QStandardItem
|
||||||
|
|
||||||
|
NODE = 'node'
|
||||||
|
MODULE = 'module'
|
||||||
|
INTERFACE = 'interface'
|
||||||
|
PARAMETER = 'parameter'
|
||||||
|
PROPERTY = 'property'
|
||||||
|
COMMENT = 'comment'
|
||||||
|
|
||||||
|
|
||||||
|
class TreeWidget(QTreeWidget):
|
||||||
|
|
||||||
|
save_status_changed = pyqtSignal(bool)
|
||||||
|
add_canceled = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
QTreeWidget.__init__(self, parent)
|
||||||
|
self.file_path = None
|
||||||
|
self.setIconSize(QSize(24, 24))
|
||||||
|
self.setSelectionMode(QTreeWidget.SingleSelection)
|
||||||
|
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||||
|
self.context_pos = QPoint(0, 0)
|
||||||
|
self.menu = QMenu()
|
||||||
|
self.context_actions = []
|
||||||
|
self.invalid_context_actions = {}
|
||||||
|
self.setup_context_actions()
|
||||||
|
self.customContextMenuRequested.connect(self.on_context_menu_requested)
|
||||||
|
|
||||||
|
def setup_context_actions(self):
|
||||||
|
edit = self.menu.addAction('rename')
|
||||||
|
a_m = self.menu.addAction('add module')
|
||||||
|
a_i = self.menu.addAction('add interface')
|
||||||
|
a_pa = self.menu.addAction('add parameter')
|
||||||
|
a_pr = self.menu.addAction('add property')
|
||||||
|
a_c = self.menu.addAction('add comment')
|
||||||
|
dup = self.menu.addAction('duplicate')
|
||||||
|
dele = self.menu.addAction('delete')
|
||||||
|
self.context_actions = [edit, a_m, a_i, a_pa, a_pr, a_c, dup, dele]
|
||||||
|
setActionIcon(edit, 'edit.png')
|
||||||
|
setActionIcon(a_m, 'add_module.png')
|
||||||
|
setActionIcon(a_i, 'add_interface.png')
|
||||||
|
setActionIcon(a_pa, 'add_parameter.png')
|
||||||
|
setActionIcon(a_pr, 'add_property.png')
|
||||||
|
setActionIcon(a_c, 'add_comment.png')
|
||||||
|
setActionIcon(dup, 'duplicate.png')
|
||||||
|
setActionIcon(dele, 'delete.png')
|
||||||
|
self.invalid_context_actions = {NODE: [a_pa, dup, dele],
|
||||||
|
MODULE: [],
|
||||||
|
INTERFACE: [a_pa],
|
||||||
|
PARAMETER: [edit, a_pa, dup],
|
||||||
|
PROPERTY: [edit, a_pa, a_pr, dup],
|
||||||
|
COMMENT: [edit, a_pa, a_pr, a_c, dup],
|
||||||
|
None: [edit, a_pa, a_pr, a_c, dup,
|
||||||
|
dele]}
|
||||||
|
edit.triggered.connect(self.change_name_via_context)
|
||||||
|
a_m.triggered.connect(self.add_module)
|
||||||
|
a_i.triggered.connect(self.add_interface)
|
||||||
|
a_pa.triggered.connect(self.add_parameter)
|
||||||
|
a_pr.triggered.connect(self.add_property)
|
||||||
|
a_c.triggered.connect(self.add_comment)
|
||||||
|
dup.triggered.connect(self.duplicate)
|
||||||
|
dele.triggered.connect(self.delete)
|
||||||
|
|
||||||
|
def emit_save_status_changed(self, status):
|
||||||
|
self.save_status_changed.emit(status)
|
||||||
|
|
||||||
|
def set_file(self, file_path):
|
||||||
|
self.file_path = file_path
|
||||||
|
if self.file_path:
|
||||||
|
if os.path.isfile(file_path):
|
||||||
|
self.set_tree(read_config(self.file_path))
|
||||||
|
self.emit_save_status_changed(True)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.file_path = None
|
||||||
|
return self.new_tree()
|
||||||
|
|
||||||
|
def new_tree(self):
|
||||||
|
dialog = AddDialog(NODE)
|
||||||
|
values = dialog.get_values()
|
||||||
|
if values:
|
||||||
|
sec_node = self.get_tree_widget_item(NODE, values[0], values[1],
|
||||||
|
None)
|
||||||
|
self.addTopLevelItem(sec_node)
|
||||||
|
sec_node.setExpanded(True)
|
||||||
|
self.mods = self.get_tree_widget_item(name='modules')
|
||||||
|
self.ifs = self.get_tree_widget_item(name='interfaces')
|
||||||
|
sec_node.addChild(self.ifs)
|
||||||
|
sec_node.addChild(self.mods)
|
||||||
|
self.emit_save_status_changed(False)
|
||||||
|
self.setCurrentItem(sec_node)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def set_tree(self, tree_items):
|
||||||
|
self.clear()
|
||||||
|
self.addTopLevelItem(tree_items[0])
|
||||||
|
self.ifs = tree_items[1]
|
||||||
|
self.mods = tree_items[2]
|
||||||
|
self.expandAll()
|
||||||
|
self.setCurrentItem(tree_items[0])
|
||||||
|
for item in get_all_items(self):
|
||||||
|
item.widget.save_status_changed.connect(self.emit_save_status_changed)
|
||||||
|
|
||||||
|
def add_module(self):
|
||||||
|
dialog = AddDialog(MODULE, get_modules(),
|
||||||
|
self.mods.get_children_names())
|
||||||
|
values = dialog.get_values()
|
||||||
|
if values:
|
||||||
|
module_class = get_module_class_from_name(values[1])
|
||||||
|
params = get_params(module_class)
|
||||||
|
props = get_props(module_class)
|
||||||
|
mod = self.get_tree_widget_item(MODULE, values[0], values[1],
|
||||||
|
module_class, params, props)
|
||||||
|
self.mods.addChild(mod)
|
||||||
|
|
||||||
|
# add all mandatory properties
|
||||||
|
for pr, pr_o in props.items():
|
||||||
|
# TODO: mandatory to must_be_configured
|
||||||
|
if pr_o.mandatory is True:
|
||||||
|
pr_i = self.get_tree_widget_item(PROPERTY, pr,
|
||||||
|
pr_o.default, pr_o)
|
||||||
|
mod.addChild(pr_i)
|
||||||
|
# add all mandatory properties of parameter
|
||||||
|
for pa, pa_o in params.items():
|
||||||
|
pa_i = None
|
||||||
|
for pr, pr_o in pa_o[1].items():
|
||||||
|
# TODO: mandatory to must_be_configured
|
||||||
|
if pr_o.mandatory is True:
|
||||||
|
pr_i = self.get_tree_widget_item(PROPERTY, pr,
|
||||||
|
pr_o.default, pr_o)
|
||||||
|
if not pa_i:
|
||||||
|
pa_i = self.get_tree_widget_item(PARAMETER, pa,
|
||||||
|
class_object=pa_o[0],
|
||||||
|
properties=pa_o[1])
|
||||||
|
mod.addChild(pa_i)
|
||||||
|
pa_i.addChild(pr_i)
|
||||||
|
|
||||||
|
self.setCurrentItem(mod)
|
||||||
|
self.emit_save_status_changed(False)
|
||||||
|
|
||||||
|
def add_interface(self):
|
||||||
|
dialog = AddDialog(INTERFACE, get_interfaces(),
|
||||||
|
self.ifs.get_children_names())
|
||||||
|
values = dialog.get_values()
|
||||||
|
if values:
|
||||||
|
interface_class = get_interface_class_from_name(values[1])
|
||||||
|
props = get_props(interface_class)
|
||||||
|
interface = self.get_tree_widget_item(INTERFACE, values[0],
|
||||||
|
values[1], interface_class,
|
||||||
|
properties=props)
|
||||||
|
self.ifs.addChild(interface)
|
||||||
|
# add all mandatory properties
|
||||||
|
for pr, pr_o in props.items():
|
||||||
|
# TODO: mandatory to must_be_configured
|
||||||
|
if pr_o.mandatory is True:
|
||||||
|
pr_i = self.get_tree_widget_item(PROPERTY, pr,
|
||||||
|
pr_o.default, pr_o)
|
||||||
|
interface.addChild(pr_i)
|
||||||
|
self.setCurrentItem(interface)
|
||||||
|
self.emit_save_status_changed(False)
|
||||||
|
|
||||||
|
def add_parameter(self):
|
||||||
|
selected_item = self.get_selected_item()
|
||||||
|
if not selected_item or self.is_heading(selected_item) or \
|
||||||
|
self.is_not_extendable(selected_item) or \
|
||||||
|
selected_item.kind in [PARAMETER, INTERFACE]:
|
||||||
|
return
|
||||||
|
params = selected_item.parameters
|
||||||
|
if params:
|
||||||
|
dialog = AddDialog(PARAMETER, params.keys())
|
||||||
|
values = dialog.get_values()
|
||||||
|
current_children = selected_item.get_children_names()
|
||||||
|
if values:
|
||||||
|
if values[0] in current_children:
|
||||||
|
self.setCurrentItem(selected_item.child(current_children.index(
|
||||||
|
values[0])))
|
||||||
|
else:
|
||||||
|
param = self.get_tree_widget_item(PARAMETER, values[0],
|
||||||
|
class_object=params[values[0]][0],
|
||||||
|
properties=params[values[0]][1])
|
||||||
|
selected_item.insertChild(0, param)
|
||||||
|
self.setCurrentItem(param)
|
||||||
|
self.emit_save_status_changed(False)
|
||||||
|
else:
|
||||||
|
# TODO: warning
|
||||||
|
pass
|
||||||
|
|
||||||
|
def add_property(self):
|
||||||
|
selected_item = self.get_selected_item()
|
||||||
|
if not selected_item or self.is_heading(selected_item) or \
|
||||||
|
self.is_not_extendable(selected_item):
|
||||||
|
return
|
||||||
|
props = selected_item.properties
|
||||||
|
if props:
|
||||||
|
dialog = AddDialog(PROPERTY, props.keys())
|
||||||
|
values = dialog.get_values()
|
||||||
|
current_children = selected_item.get_children_names()
|
||||||
|
if values:
|
||||||
|
if values[0] in current_children:
|
||||||
|
self.setCurrentItem(selected_item.child(current_children.index(
|
||||||
|
values[0])))
|
||||||
|
else:
|
||||||
|
prop = self.get_tree_widget_item(PROPERTY, values[0],
|
||||||
|
props[values[0]].default,
|
||||||
|
props[values[0]])
|
||||||
|
selected_item.insertChild(0, prop)
|
||||||
|
self.setCurrentItem(prop)
|
||||||
|
self.emit_save_status_changed(False)
|
||||||
|
else:
|
||||||
|
# TODO: warning
|
||||||
|
pass
|
||||||
|
|
||||||
|
def add_comment(self):
|
||||||
|
selected_item = self.get_selected_item()
|
||||||
|
if not selected_item or self.is_heading(selected_item) or \
|
||||||
|
selected_item.kind == COMMENT:
|
||||||
|
return
|
||||||
|
dialog = AddDialog(COMMENT)
|
||||||
|
values = dialog.get_values()
|
||||||
|
if values:
|
||||||
|
comm = self.get_tree_widget_item(COMMENT, '#', values[0])
|
||||||
|
selected_item.insertChild(0, comm)
|
||||||
|
self.setCurrentItem(comm)
|
||||||
|
self.emit_save_status_changed(False)
|
||||||
|
|
||||||
|
def duplicate(self):
|
||||||
|
selected_item = self.get_selected_item()
|
||||||
|
if not selected_item or selected_item.kind not in [MODULE, INTERFACE]:
|
||||||
|
return
|
||||||
|
selected_item.duplicate()
|
||||||
|
# TODO set duplicated selected
|
||||||
|
self.emit_save_status_changed(False)
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
selected_item = self.get_selected_item()
|
||||||
|
if not selected_item or self.is_heading(selected_item) \
|
||||||
|
or selected_item == NODE:
|
||||||
|
return
|
||||||
|
selected_item.parent().removeChild(selected_item)
|
||||||
|
self.emit_save_status_changed(False)
|
||||||
|
|
||||||
|
def save(self, save_as=False):
|
||||||
|
file_name = self.file_path
|
||||||
|
if not self.file_path or save_as:
|
||||||
|
file_name = get_file_paths(self, False)[-1]
|
||||||
|
if file_name[-4:] == '.cfg':
|
||||||
|
self.file_path = file_name
|
||||||
|
write_config(self.file_path, self)
|
||||||
|
self.emit_save_status_changed(True)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_heading(self, item):
|
||||||
|
return item is self.ifs or item is self.mods
|
||||||
|
|
||||||
|
def is_not_extendable(self, item):
|
||||||
|
return item.kind in [PROPERTY, COMMENT]
|
||||||
|
|
||||||
|
def get_selected_item(self):
|
||||||
|
selected_item = self.selectedItems()
|
||||||
|
if not selected_item:
|
||||||
|
return None
|
||||||
|
return selected_item[-1]
|
||||||
|
|
||||||
|
def is_valid_name(self, name, kind):
|
||||||
|
if kind == MODULE:
|
||||||
|
if name in self.mods.get_children_names():
|
||||||
|
return False
|
||||||
|
elif kind == INTERFACE:
|
||||||
|
if name in self.ifs.get_children_names():
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
selected_item = self.get_selected_item()
|
||||||
|
if not selected_item:
|
||||||
|
return False
|
||||||
|
if name in selected_item.get_children_names():
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_tree_widget_item(self, kind=None, name='', value=None,
|
||||||
|
class_object=None, parameters=None, properties=None):
|
||||||
|
item = TreeWidgetItem(kind, name, value, class_object, parameters or {}, properties or {})
|
||||||
|
item.widget.save_status_changed.connect(self.emit_save_status_changed)
|
||||||
|
return item
|
||||||
|
|
||||||
|
def change_name_via_context(self):
|
||||||
|
self.itemAt(self.context_pos).change_name()
|
||||||
|
|
||||||
|
def on_context_menu_requested(self, pos):
|
||||||
|
self.context_pos = pos
|
||||||
|
self.menu.move(self.mapToGlobal(pos))
|
||||||
|
self.menu.show()
|
||||||
|
for action in self.context_actions:
|
||||||
|
action.setEnabled(True)
|
||||||
|
for action in self.invalid_context_actions[self.itemAt(self.context_pos).kind]:
|
||||||
|
action.setEnabled(False)
|
||||||
|
|
||||||
|
|
||||||
|
class AddDialog(QDialog):
|
||||||
|
def __init__(self, kind, possible_values=None, invalid_names=None,
|
||||||
|
parent=None):
|
||||||
|
"""Notes:
|
||||||
|
self.get_value: is mapped to the specific method for getting
|
||||||
|
the value from self.value"""
|
||||||
|
QWidget.__init__(self, parent)
|
||||||
|
loadUi(self, 'add_dialog.ui')
|
||||||
|
self.setWindowTitle('add %s' % kind)
|
||||||
|
self.kind = kind
|
||||||
|
self.invalid_names = invalid_names
|
||||||
|
if self.invalid_names:
|
||||||
|
for i, name in enumerate(self.invalid_names):
|
||||||
|
self.invalid_names[i] = name.lower()
|
||||||
|
if kind in [NODE, MODULE, INTERFACE]:
|
||||||
|
self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
|
||||||
|
self.name = QLineEdit()
|
||||||
|
# TODO: input mask
|
||||||
|
self.name.textChanged.connect(self.check_input)
|
||||||
|
self.add_layout.addWidget(QLabel('name:'), 0, 0)
|
||||||
|
self.add_layout.addWidget(self.name, 0, 1)
|
||||||
|
if kind == NODE:
|
||||||
|
label_text = 'description:'
|
||||||
|
self.value = QTextEdit()
|
||||||
|
self.get_value = self.value.toPlainText
|
||||||
|
self.value.text = self.value.toPlainText
|
||||||
|
else:
|
||||||
|
label_text = 'kind:'
|
||||||
|
self.value = QComboBox()
|
||||||
|
self.get_value = self.value.currentText
|
||||||
|
if type(possible_values) == dict:
|
||||||
|
# TODO disable OK Button if TreeComboBox is empty
|
||||||
|
self.value = TreeComboBox(possible_values)
|
||||||
|
self.get_value = self.value.get_value
|
||||||
|
else:
|
||||||
|
self.value.addItems(possible_values)
|
||||||
|
self.value.setCurrentIndex(len(possible_values)-1)
|
||||||
|
self.add_layout.addWidget(QLabel(label_text), 1, 0)
|
||||||
|
self.add_layout.addWidget(self.value, 1, 1)
|
||||||
|
else:
|
||||||
|
if kind in [PARAMETER, PROPERTY]:
|
||||||
|
label_text = 'kind:'
|
||||||
|
self.value = QComboBox()
|
||||||
|
self.get_value = self.value.currentText
|
||||||
|
self.value.addItems(possible_values)
|
||||||
|
else:
|
||||||
|
label_text = 'comment:'
|
||||||
|
self.value = QTextEdit()
|
||||||
|
self.get_value = self.value.toPlainText
|
||||||
|
self.add_layout.addWidget(QLabel(label_text), 0, 0)
|
||||||
|
self.add_layout.addWidget(self.value, 0, 1)
|
||||||
|
if self.add_layout.rowCount() == 2:
|
||||||
|
self.setTabOrder(self.name, self.value)
|
||||||
|
self.setTabOrder(self.value, self.button_box.button(QDialogButtonBox.Ok))
|
||||||
|
self.setTabOrder(self.button_box.button(QDialogButtonBox.Ok),
|
||||||
|
self.button_box.button(QDialogButtonBox.Cancel))
|
||||||
|
|
||||||
|
def get_values(self):
|
||||||
|
if self.exec_() == QDialog.Accepted:
|
||||||
|
if self.kind in [NODE, MODULE, INTERFACE]:
|
||||||
|
return [self.name.text(), self.get_value()]
|
||||||
|
elif self.kind in [PARAMETER, PROPERTY, COMMENT]:
|
||||||
|
return [self.get_value()]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def check_input(self, name):
|
||||||
|
set_name_edit_style((self.kind in [MODULE, INTERFACE] and
|
||||||
|
name.lower() in self.invalid_names) or name == '',
|
||||||
|
self.name, self.button_box)
|
||||||
|
|
||||||
|
|
||||||
|
class TabBar(QTabBar):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
QTabBar.__init__(self, parent)
|
||||||
|
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||||
|
self.context_pos = QPoint(0, 0)
|
||||||
|
self.menu = QMenu()
|
||||||
|
close = self.menu.addAction('&Close')
|
||||||
|
close_all = self.menu.addAction('&Close all')
|
||||||
|
close.triggered.connect(self.close_tab_via_context)
|
||||||
|
close_all.triggered.connect(self.close_all)
|
||||||
|
self.customContextMenuRequested.connect(self.on_context_menu_requested)
|
||||||
|
self.setMovable(True)
|
||||||
|
|
||||||
|
def mouseReleaseEvent(self, event):
|
||||||
|
if event.button() == Qt.MidButton:
|
||||||
|
self.close_tab_at_pos(event.pos())
|
||||||
|
QTabBar.mouseReleaseEvent(self, event)
|
||||||
|
|
||||||
|
def on_context_menu_requested(self, pos):
|
||||||
|
self.context_pos = pos
|
||||||
|
self.menu.move(self.mapToGlobal(pos))
|
||||||
|
self.menu.show()
|
||||||
|
|
||||||
|
def close_tab_via_context(self):
|
||||||
|
self.close_tab_at_pos(self.context_pos)
|
||||||
|
|
||||||
|
def close_all(self):
|
||||||
|
for i in range(self.count()-1, -1, -1):
|
||||||
|
self.tabCloseRequested.emit(i)
|
||||||
|
|
||||||
|
def close_tab_at_pos(self, pos):
|
||||||
|
self.tabCloseRequested.emit(self.tabAt(pos))
|
||||||
|
|
||||||
|
|
||||||
|
class TreeComboBox(QComboBox):
|
||||||
|
def __init__(self, value_dict, parent=None):
|
||||||
|
QComboBox.__init__(self, parent)
|
||||||
|
self.tree_view = QTreeView()
|
||||||
|
self.tree_view.setHeaderHidden(True)
|
||||||
|
self.tree_view.expanded.connect(self.resize_length)
|
||||||
|
self.tree_view.collapsed.connect(self.resize_length)
|
||||||
|
self.model = QStandardItemModel()
|
||||||
|
self.insert_dict(value_dict)
|
||||||
|
self.setModel(self.model)
|
||||||
|
self.setView(self.tree_view)
|
||||||
|
self.setStyleSheet('QTreeView::item:has-children{color: black;'
|
||||||
|
'font: bold;}')
|
||||||
|
|
||||||
|
def insert_dict(self, value_dict, parent=None):
|
||||||
|
for not_selectable in value_dict:
|
||||||
|
act_item = QStandardItem(not_selectable)
|
||||||
|
act_item.setEnabled(False)
|
||||||
|
font = act_item.font()
|
||||||
|
font.setBold(True)
|
||||||
|
act_item.setFont(font)
|
||||||
|
if parent:
|
||||||
|
parent.appendRow([act_item])
|
||||||
|
else:
|
||||||
|
self.model.appendRow([act_item])
|
||||||
|
if type(value_dict[not_selectable]) == dict:
|
||||||
|
self.insert_dict(value_dict[not_selectable], act_item)
|
||||||
|
else:
|
||||||
|
for item in value_dict[not_selectable]:
|
||||||
|
act_item.appendRow([QStandardItem(item)])
|
||||||
|
|
||||||
|
def get_value(self):
|
||||||
|
value = ''
|
||||||
|
act_index = self.tree_view.selectedIndexes()[0]
|
||||||
|
act_item = act_index.model().itemFromIndex(act_index)
|
||||||
|
value += act_item.text()
|
||||||
|
while act_item.parent():
|
||||||
|
value = '%s.%s' % (act_item.parent().text(), value)
|
||||||
|
act_item = act_item.parent()
|
||||||
|
return value
|
||||||
|
|
||||||
|
def resize_length(self):
|
||||||
|
self.showPopup()
|
5915
secop/gui/icon_rc_qt4.py
Normal file
5960
secop/gui/icon_rc_qt5.py
Normal file
@ -33,25 +33,32 @@ try:
|
|||||||
|
|
||||||
from PyQt5 import uic
|
from PyQt5 import uic
|
||||||
from PyQt5.QtCore import Qt, QObject, pyqtSignal, pyqtSlot, QSize, QPointF, \
|
from PyQt5.QtCore import Qt, QObject, pyqtSignal, pyqtSlot, QSize, QPointF, \
|
||||||
QRectF
|
QRectF, QPoint
|
||||||
from PyQt5.QtGui import QFont, QTextCursor, QFontMetrics, QColor, QBrush, \
|
from PyQt5.QtGui import QFont, QTextCursor, QFontMetrics, QColor, QBrush, \
|
||||||
QPainter, QPolygonF, QPen
|
QPainter, QPolygonF, QPen, QIcon, QStandardItemModel, QStandardItem
|
||||||
from PyQt5.QtWidgets import QLabel, QWidget, QDialog, QLineEdit, QCheckBox, \
|
from PyQt5.QtWidgets import QLabel, QWidget, QDialog, QLineEdit, QCheckBox, \
|
||||||
QPushButton, QSizePolicy, QMainWindow, QMessageBox, QInputDialog, \
|
QPushButton, QSizePolicy, QMainWindow, QMessageBox, QInputDialog, \
|
||||||
QTreeWidgetItem, QApplication, QGroupBox, QSpinBox, QDoubleSpinBox, \
|
QTreeWidgetItem, QApplication, QGroupBox, QSpinBox, QDoubleSpinBox, \
|
||||||
QComboBox, QRadioButton, QVBoxLayout, QHBoxLayout, QGridLayout, \
|
QComboBox, QRadioButton, QVBoxLayout, QHBoxLayout, QGridLayout, \
|
||||||
QScrollArea, QFrame
|
QScrollArea, QFrame, QTreeWidget, QFileDialog, QTabBar, QAction, QMenu,\
|
||||||
|
QDialogButtonBox, QTextEdit, QAbstractItemView, QSpacerItem, QTreeView
|
||||||
|
|
||||||
from xml.sax.saxutils import escape as toHtmlEscaped
|
from xml.sax.saxutils import escape as toHtmlEscaped
|
||||||
|
|
||||||
|
import secop.gui.icon_rc_qt5
|
||||||
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from PyQt4 import uic
|
from PyQt4 import uic
|
||||||
from PyQt4.QtCore import Qt, QObject, pyqtSignal, pyqtSlot, QSize, QPointF, QRectF
|
from PyQt4.QtCore import Qt, QObject, pyqtSignal, pyqtSlot, QSize, QPointF, QRectF, QPoint
|
||||||
from PyQt4.QtGui import QFont, QTextCursor, QFontMetrics, \
|
from PyQt4.QtGui import QFont, QTextCursor, QFontMetrics, \
|
||||||
QLabel, QWidget, QDialog, QLineEdit, QCheckBox, QPushButton, \
|
QLabel, QWidget, QDialog, QLineEdit, QCheckBox, QPushButton, QTextEdit,\
|
||||||
QSizePolicy, QMainWindow, QMessageBox, QInputDialog, QTreeWidgetItem, QApplication, \
|
QSizePolicy, QMainWindow, QMessageBox, QInputDialog, QTreeWidgetItem, QApplication, \
|
||||||
QGroupBox, QSpinBox, QDoubleSpinBox, QComboBox, QRadioButton, QVBoxLayout, QHBoxLayout, \
|
QGroupBox, QSpinBox, QDoubleSpinBox, QComboBox, QRadioButton, QVBoxLayout, QHBoxLayout, \
|
||||||
QGridLayout, QScrollArea, QFrame, QColor, QBrush, QPainter, QPolygonF, QPen
|
QGridLayout, QScrollArea, QFrame, QColor, QBrush, QPainter, QPolygonF, QPen, QIcon, \
|
||||||
|
QTreeWidget, QFileDialog, QTabBar, QAction, QMenu, QDialogButtonBox, QAbstractItemView, \
|
||||||
|
QSpacerItem, QTreeView, QStandardItemModel, QStandardItem
|
||||||
|
|
||||||
|
import secop.gui.icon_rc_qt4
|
||||||
|
|
||||||
def toHtmlEscaped(s):
|
def toHtmlEscaped(s):
|
||||||
return Qt.escape(s)
|
return Qt.escape(s)
|
||||||
|
@ -179,7 +179,7 @@ class StructWidget(QGroupBox):
|
|||||||
class ArrayWidget(QGroupBox):
|
class ArrayWidget(QGroupBox):
|
||||||
def __init__(self, datatype, readonly=False, parent=None):
|
def __init__(self, datatype, readonly=False, parent=None):
|
||||||
super(ArrayWidget, self).__init__(parent)
|
super(ArrayWidget, self).__init__(parent)
|
||||||
self.datatype = datatype.subtype
|
self.datatype = datatype.members
|
||||||
|
|
||||||
self.layout = QVBoxLayout()
|
self.layout = QVBoxLayout()
|
||||||
self.subwidgets = []
|
self.subwidgets = []
|
||||||
|
@ -41,10 +41,12 @@ CONFIG = {
|
|||||||
u'piddir': os.path.join(repodir, u'pid'),
|
u'piddir': os.path.join(repodir, u'pid'),
|
||||||
u'logdir': os.path.join(repodir, u'log'),
|
u'logdir': os.path.join(repodir, u'log'),
|
||||||
u'confdir': os.path.join(repodir, u'etc'),
|
u'confdir': os.path.join(repodir, u'etc'),
|
||||||
|
u'basedir': repodir,
|
||||||
} if os.path.exists(os.path.join(repodir, u'.git')) else {
|
} if os.path.exists(os.path.join(repodir, u'.git')) else {
|
||||||
u'piddir': u'/var/run/secop',
|
u'piddir': u'/var/run/secop',
|
||||||
u'logdir': u'/var/log',
|
u'logdir': u'/var/log',
|
||||||
u'confdir': u'/etc/secop',
|
u'confdir': u'/etc/secop',
|
||||||
|
u'basedir': repodir,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|