# # Project: MXCuBE # https://github.com/mxcube. # # This file is part of MXCuBE software. # # MXCuBE 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 3 of the License, or # (at your option) any later version. # # MXCuBE 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 MXCuBE. If not, see <http://www.gnu.org/licenses/>. import os import re import sys import imp import types import weakref import logging import subprocess from PyQt4 import QtCore from PyQt4 import QtGui import BlissFramework from BlissFramework import Qt4_Configuration from BlissFramework import Qt4_Icons from BlissFramework.Utils import Qt4_PropertyEditor from BlissFramework.Utils import Qt4_ConnectionEditor from BlissFramework.Bricks import Qt4_LogViewBrick from BlissFramework.Qt4_BaseLayoutItems import ContainerCfg from BlissFramework.Utils import Qt4_GUIDisplay try: from HardwareRepository import HardwareRepository except ImportError: logging.getLogger().warning("no Hardware Repository client module could be found") try: from PyQt4.QtCore import QString except ImportError: QtCore.QString = str #else: # from HardwareRepository import HardwareRepositoryBrowser class HorizontalSpacer(QtGui.QWidget): """ Descript. : """ def __init__(self, *args, **kwargs): """ Descript. : """ QtGui.QWidget.__init__(self, *args) h_size = kwargs.get("size", None) if h_size is not None: self.setFixedWidth(h_size) self.setSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) else: self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed) class MyListView(QtGui.QListWidget): """ Descript. : """ def __init__(self, *args): """ Descript. : """ QtGui.QListView.__init__(self, *args) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) def addToolTip(self, item, text): """ Descript. : """ self.setToolTip(text) class GUITreeWidget(QtGui.QTreeWidget): """ Descript. : """ def __init__(self, *args): """ Descript. : """ QtGui.QTreeWidget.__init__(self, *args) self._presspos = None self._mousePressed = False self.setColumnCount(2) self.setColumnWidth(0, 200) self.setColumnWidth(1, 200) self.setHeaderLabels(["Element", "Type"]) self.setAcceptDrops(True) self.viewport().setAcceptDrops(True) self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) self.setItemsExpandable(True) self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.drag_source_item = None self.drag_target_item = None def dragEnterEvent(self, event): """ Descript. : """ self.drag_source_item = self.itemAt(event.pos()) event.accept() def dropEvent(self, event): """ Descript. : """ self.drag_target_item = self.itemAt(event.pos()) if self.drag_source_item and self.drag_target_item: self.emit(QtCore.SIGNAL("dragdrop"), self.drag_source_item, self.drag_target_item) event.accept() class ToolboxWindow(QtGui.QWidget): """ Descript. : """ def __init__(self, *args, **kwargs): """ Descript. : """ QtGui.QWidget.__init__(self, *args) # Internal variables -------------------------------------------------- self.bricks_tab_dict = {} self.bricks_dict = {} # Graphic elements ---------------------------------------------------- _top_frame = QtGui.QFrame(self) _refresh_toolbutton = QtGui.QToolButton(_top_frame) _refresh_toolbutton.setIcon(QtGui.QIcon(Qt4_Icons.load("reload"))) self.setToolTip("refresh bricks list") self._bricks_toolbox = QtGui.QToolBox(self) # Layout -------------------------------------------------------------- _main_vlayout = QtGui.QVBoxLayout() _main_vlayout.addWidget(QtGui.QLabel("Available bricks", _top_frame)) _main_vlayout.addWidget(_refresh_toolbutton) _main_vlayout.addWidget(self._bricks_toolbox) _main_vlayout.setSpacing(0) _main_vlayout.setContentsMargins(0,0,0,0) self.setLayout(_main_vlayout) # SizePolicies -------------------------------------------------------- # Qt signal/slot connections ------------------------------------------ _refresh_toolbutton.clicked.connect(self.refresh_clicked) # Other --------------------------------------------------------------- self.setWindowTitle("Toolbox") def addBrickTab(self, name): """ Descript. : Add a new brick tab called 'name' """ newBricksList = MyListView(self._bricks_toolbox) newBricksList.itemDoubleClicked.connect(self.brick_selected) self._bricks_toolbox.addItem(newBricksList, name) self.bricks_tab_dict[name] = newBricksList return newBricksList def refresh_clicked(self): """ Descript. : Refresh bricks window """ while self._bricks_toolbox.currentWidget(): self._bricks_toolbox.removeItem(self._bricks_toolbox.currentIndex()) self.bricks_dict = {} self.bricks_tab_dict = {} list(map(self.addBricks, (BlissFramework.getStdBricksPath(), ) + \ tuple(BlissFramework.getCustomBricksDirs()))) def brickTextLabel(self, brickName): """ Descript. : """ if brickName.endswith("Brick"): brickTextLabel = brickName[:-5] else: brickTextLabel = brickName for i in range(len(brickTextLabel)): if brickTextLabel[i].isalpha() or brickTextLabel[i].isdigit(): if i > 0 and brickTextLabel[i].isupper() and brickTextLabel[i-1].islower(): brickTextLabel = brickTextLabel[0:i] + " " + brickTextLabel[i].lower() + brickTextLabel[i+1:] else: brickTextLabel=brickTextLabel[0:i]+" "+brickTextLabel[i+1:] return brickTextLabel def addBricks(self, brickDir): """ Descript. : Add the bricks found in the 'brickDir' directory to the bricks tab widget""" findCategoryRE = re.compile("^__category__\s*=\s*['\"](.*)['\"]$", re.M) findDocstringRE = re.compile('^"""(.*?)"""?$', re.M | re.S) full_filenames = [] for fileordir in os.listdir(brickDir) : full_path = os.path.join(brickDir,fileordir) if os.path.isdir(full_path) : path_with_trunk = os.path.join(full_path,'trunk') # SVN structure if os.path.isdir(path_with_trunk) : full_path = path_with_trunk filesNames = [os.path.join(full_path,filename) for filename in os.listdir(full_path)] full_filenames.extend(filesNames) else: full_filenames.append(full_path) full_filenames.sort() processedBricks = [] bricksCategories = {} for full_filename in full_filenames: filename = os.path.basename(full_filename) if [x for x in [x[0] for x in imp.get_suffixes()] if filename.endswith(x)]: brickName = filename[:filename.rfind('.')] if (not brickName == '__init__' and brickName.startswith('Qt4') and not brickName in processedBricks): processedBricks.append(brickName) dirname = os.path.dirname(full_filename) brick_module_file = None try: brick_module_file, path, description = imp.find_module(brickName, [dirname]) except: if brick_module_file: brick_module_file.close() continue moduleContents = brick_module_file.read() checkIfItsBrick = re.compile('^\s*class\s+%s.+?:\s*$' % brickName,re.M) if not checkIfItsBrick.search(moduleContents) : continue match = findCategoryRE.search(moduleContents) if match is None: category = "" else: category = match.group(1) match = findDocstringRE.search(moduleContents) if match is None: description = "" else: description = match.group(1) try: bricksCategories[category].append( (brickName, dirname, description) ) except KeyError: bricksCategories[category] = [ (brickName, dirname, description) ] if len(bricksCategories) == 0: return categoryKeys = list(bricksCategories.keys()) categoryKeys.sort() for category in categoryKeys: bricksList = bricksCategories[category] try: bricksListWidget = self.bricks_tab_dict[category] except KeyError: bricksListWidget = self.addBrickTab(category) for brickName, dirname, description in bricksList: newBrick = QtGui.QListWidgetItem(QtCore.QString(self.brickTextLabel(brickName)), bricksListWidget) bricksListWidget.addToolTip(newBrick, description) self.bricks_dict[id(newBrick)] = (dirname, brickName) def brick_selected(self, item): """ Descript. : """ dir_name, brick_name = self.bricks_dict[id(item)] self.emit(QtCore.SIGNAL("addBrick"), brick_name) class Qt4_PropertyEditorWindow(QtGui.QWidget): """ Descript. : """ def __init__(self, *args, **kwargs): """ Descript. : """ QtGui.QWidget.__init__(self, *args) self.setWindowTitle("Properties") self.properties_table = Qt4_PropertyEditor.Qt4_ConfigurationTable(self) self.__property_changed_cb = weakref.WeakKeyDictionary() QtCore.QObject.connect(self.properties_table, QtCore.SIGNAL("propertyChanged"), self.property_changed) _main_vlayout = QtGui.QHBoxLayout() _main_vlayout.addWidget(self.properties_table) _main_vlayout.setSpacing(0) _main_vlayout.setContentsMargins(0,0,0,0) self.setLayout(_main_vlayout) self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) def editProperties(self, property_bag): """ Descript. : """ self.properties_table.setPropertyBag(property_bag) def property_changed(self, *args): """ Descript. : """ try: cb = self.__property_changed_cb[self.properties_table.propertyBag] except KeyError as err: return else: cb(*args) def addProperties(self, propertyBag, property_changed_cb): """ Descript. : """ self.__property_changed_cb[propertyBag] = property_changed_cb self.editProperties(propertyBag) class ToolButton(QtGui.QToolButton): """ Descript. : """ def __init__(self, parent, icon, text = None, callback = None, tooltip = None): """ Descript. : """ QtGui.QToolButton.__init__(self, parent) self.setIcon(QtGui.QIcon(Qt4_Icons.load(icon))) if type(text) != bytes: tooltip = callback callback = text else: self.setTextLabel(text) self.setTextPosition(qt.QToolButton.BesideIcon) self.setUsesTextLabel(True) if callback is not None: self.clicked.connect(callback) if tooltip is not None: self.setToolTip(tooltip) #QtGui.QToolTip.add(self, tooltip) self.setSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) class GUIEditorWindow(QtGui.QWidget): """ Descript. : """ def __init__(self, *args, **kwargs): """ Descript. : """ QtGui.QWidget.__init__(self, *args) # Internal values ----------------------------------------------------- self.configuration = Qt4_Configuration.Configuration() # Graphic elements ---------------------------------------------------- _tools_widget = QtGui.QWidget(self) _add_window_toolbutton = ToolButton(_tools_widget, "window_new", \ self.add_window_clicked, "add a new window (container)") _add_tab_toolbutton = ToolButton(_tools_widget, "tab", \ self.add_tab_clicked, "add a new tab (container)") _add_hbox_toolbutton = ToolButton(_tools_widget, "add_hbox", \ self.add_hbox_clicked, "add a new horizontal box (container)") _add_vbox_toolbutton = ToolButton(_tools_widget, "add_vbox", \ self.add_vbox_clicked, "add a new vertical box (container)") _add_hgroupbox_toolbutton = ToolButton(_tools_widget, "hgroupbox", \ self.add_hgroupbox_clicked, "add a new horizontal group box (container)") _add_vgroupbox_toolbutton = ToolButton(_tools_widget, "vgroupbox", \ self.add_vgroupbox_clicked, "add a new vertical group box (container)") _add_hspacer_toolbutton = ToolButton(_tools_widget, "add_hspacer", \ self.add_hspacer_clicked, "add a new horizontal spacer") _add_vspacer_toolbutton = ToolButton(_tools_widget, "add_vspacer", \ self.add_vspacer_clicked, "add a new vertical spacer") _add_hsplitter_toolbutton = ToolButton(_tools_widget, "hsplitter", \ self.add_hsplitter_clicked, "add a new horizontal splitter (container)") _add_vsplitter_toolbutton = ToolButton(_tools_widget, "vsplitter", \ self.add_vsplitter_clicked, "add a new vertical splitter (container)") _add_icon_toolbutton = ToolButton(_tools_widget, "icon", \ self.add_icon_clicked, "add a new icon") _add_label_toolbutton = ToolButton(_tools_widget, "label", \ self.add_label_clicked, "add a new label") _tree_handling_widget = QtGui.QWidget(self) _show_connections_toolbutton = ToolButton(_tree_handling_widget, "connect_creating", \ self.show_connections_clicked, "manage connections between items") _move_up_toolbutton = ToolButton(_tree_handling_widget, "Up2", \ self.move_up_clicked, "move an item up") _move_down_toolbutton = ToolButton(_tree_handling_widget, "Down2", \ self.move_down_clicked, "move an item down") _remove_item_toolbutton = ToolButton(_tree_handling_widget, "delete_small", \ self.remove_item_clicked, "delete an item") self.tree_widget = GUITreeWidget(self) self.root_element = QtGui.QTreeWidgetItem(self.tree_widget) self.root_element.setText(0, QtCore.QString("GUI tree")) self.root_element.setExpanded(True) # Layout -------------------------------------------------------------- _toolbox_hlayout = QtGui.QHBoxLayout() _toolbox_hlayout.addWidget(_add_window_toolbutton) _toolbox_hlayout.addWidget(_add_tab_toolbutton) _toolbox_hlayout.addWidget(_add_hbox_toolbutton) _toolbox_hlayout.addWidget(_add_vbox_toolbutton) _toolbox_hlayout.addWidget(_add_hgroupbox_toolbutton) _toolbox_hlayout.addWidget(_add_vgroupbox_toolbutton) _toolbox_hlayout.addWidget(_add_hspacer_toolbutton) _toolbox_hlayout.addWidget(_add_vspacer_toolbutton) _toolbox_hlayout.addWidget(_add_hsplitter_toolbutton) _toolbox_hlayout.addWidget(_add_vsplitter_toolbutton) _toolbox_hlayout.addWidget(_add_icon_toolbutton) _toolbox_hlayout.addWidget(_add_label_toolbutton) _toolbox_hlayout.addStretch(0) _toolbox_hlayout.setSpacing(2) _toolbox_hlayout.setContentsMargins(2, 2, 2, 2) _tools_widget.setLayout(_toolbox_hlayout) _tree_handling_widget_hlayout = QtGui.QHBoxLayout() _tree_handling_widget_hlayout.addWidget(_show_connections_toolbutton) _tree_handling_widget_hlayout.addWidget(_move_up_toolbutton) _tree_handling_widget_hlayout.addWidget(_move_down_toolbutton) _tree_handling_widget_hlayout.addWidget(_remove_item_toolbutton) _tree_handling_widget_hlayout.addStretch(0) _tree_handling_widget_hlayout.setSpacing(2) _tree_handling_widget_hlayout.setContentsMargins(2, 2, 2, 2) _tree_handling_widget.setLayout(_tree_handling_widget_hlayout) _main_vlayout = QtGui.QVBoxLayout() _main_vlayout.addWidget(_tools_widget) _main_vlayout.addWidget(_tree_handling_widget) _main_vlayout.addWidget(self.tree_widget) _main_vlayout.setSpacing(2) _main_vlayout.setContentsMargins(2,2,2,2) self.setLayout(_main_vlayout) # SizePolicies -------------------------------------------------------- _tools_widget.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed) # Qt signal/slot connections ------------------------------------------ self.tree_widget.itemSelectionChanged.connect(self.item_selected) self.tree_widget.itemDoubleClicked.connect(self.item_double_clicked) self.tree_widget.itemChanged.connect(self.item_changed) self.connect(self.tree_widget, QtCore.SIGNAL('dragdrop'), self.item_drag_dropped) self.connect(self.tree_widget, QtCore.SIGNAL('contextMenuRequested'), self.item_right_clicked) # Other --------------------------------------------------------------- self.item_rename_started = None self.setWindowTitle("GUI Editor") def create_action(self, text, slot = None, shortcut = None, icon = None, tip = None, checkable = False, signal = "triggered()"): """ Descript. : """ action = QtGui.QAction(text, self) if icon is not None: action.setIcon(QtGui.QIcon(Qt4_Icons.load(icon))) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: self.connect(action, QtCore.SIGNAL(signal), slot) if checkable: action.setCheckable(True) return action def add_actions(self, target, actions): """ Descript. : """ for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def set_configuration(self, configuration): """ Descript. : """ self.configuration = configuration self.tree_widget.blockSignals(True) self.emit(QtCore.SIGNAL('hidePropertyEditorWindow'), ()) def addChildren(children, parentItem): parent_name = str(parentItem.text(0)) parent = self.configuration.findContainer(parent_name) for child in children: if self.configuration.isContainer(child): new_list_item = self.appendItem(parentItem, child["name"], child["type"], icon=child["type"]) addChildren(child["children"], new_list_item) self.configuration.items[child["name"]].updateSlots() elif self.configuration.isSpacer(child): new_list_item = self.appendItem(parentItem, child["name"], "spacer", icon=child["type"]) elif self.configuration.isBrick(child): new_list_item = self.appendItem(parentItem, child["name"], child["type"], icon="brick") else: new_list_item = self.appendItem(parentItem, child["name"], child["type"], icon=child["type"]) self.connectItem(parent, child, new_list_item) for window in self.configuration.windows_list: parentWindowItem = self.appendItem(self.root_element, window.name, "window", icon="window_small") self.connectItem(None, window, parentWindowItem) addChildren(window["children"], parentWindowItem) self.tree_widget.blockSignals(False) #self.tree_widget.triggerUpdate() self.tree_widget.update() self.tree_widget.setCurrentItem(self.root_element.child(0)) self.emit(QtCore.SIGNAL('showProperyEditorWindow'), ()) def show_connections_clicked(self): """ Descript. : """ self.connection_editor_window = Qt4_ConnectionEditor.Qt4_ConnectionEditor(self.configuration) width = QtGui.QApplication.desktop().width() height = QtGui.QApplication.desktop().height() #self.connection_editor_window.resize(0.85 * width, 0.7 * height) self.connection_editor_window.show() def updateProperties(self, item_cfg): """ Descript. : """ self.emit(QtCore.SIGNAL("editProperties"), item_cfg["properties"]) def _getParentWindowName(self, item): """ Descript. : """ while item: if str(item.text(1)) == "window": return str(item.text(0)) else: item = item.parent() def appendItem(self, parentItem, column1_text, column2_text, icon = None): """ Descript. : """ newListItem = QtGui.QTreeWidgetItem(parentItem) newListItem.setText(0, QtCore.QString(str(column1_text))) newListItem.setText(1, QtCore.QString(str(column2_text))) newListItem.setExpanded(True) self.tree_widget.setDragEnabled(True) self.tree_widget.setAcceptDrops(True) if isinstance(icon, str): newListItem.setIcon(0, QtGui.QIcon(Qt4_Icons.load(icon))) self.tree_widget.setCurrentItem(newListItem) self.tree_widget.scrollToItem(newListItem, QtGui.QAbstractItemView.EnsureVisible) return newListItem def remove_item_clicked(self): """ Descript. : """ currentItem = self.tree_widget.currentItem() if currentItem: item_parent_name = str(currentItem.parent().text(0)) item_name = str(currentItem.text(0)) children = currentItem.childCount() if children > 0: if QtGui.QMessageBox.warning(self, "Please confirm", "Are you sure you want to remove %s ?\nRemoving item will remove its %d children." % (item_name, children), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) == QtGui.QMessageBox.No: return item_cfg = self.configuration.findItem(item_name) children_name_list = [] for child in item_cfg['children']: children_name_list.append(child['name']) self.emit(QtCore.SIGNAL("removeWidget"), item_name, children_name_list) if self.configuration.remove(item_name): root = self.tree_widget.invisibleRootItem() for item in self.tree_widget.selectedItems(): (item.parent() or root).removeChild(item) def draw_window_preview(self): """ Descript. : """ container_name = self.root_element.child(0).text(0) container_cfg, window_id, container_ids, selected_item = \ self.prepare_window_preview(container_name, None, "") self.emit(QtCore.SIGNAL("drawPreview"), container_cfg, window_id, container_ids, selected_item) def update_window_preview(self, container_name, container_cfg = None, selected_item = ""): """ Descript. : """ upd_container_cfg, upd_window_id, upd_container_ids, upd_selected_item = \ self.prepare_window_preview(container_name, container_cfg, selected_item) self.emit(QtCore.SIGNAL("updatePreview"), upd_container_cfg, upd_window_id, upd_container_ids, selected_item) def prepare_window_preview(self, item_name, item_cfg = None, selected_item = ""): """ Descript. : """ item_list = self.tree_widget.findItems(QtCore.QString(item_name), QtCore.Qt.MatchRecursive, 0) item = item_list[0] item_type = str(item.text(1)) window_id = None if item_type == "window": window_id = str(item.text(0)) else: # find parent window parent = item.parent() while (parent): if str(parent.text(1)) == "window": window_id = str(parent.text(0)) break parent = parent.parent() if item_type != "window" and item.childCount() == 0: item = item.parent() item_name = str(item.text(0)) item_cfg = None if item_cfg is None: item_cfg = self.configuration.findItem(item_name) item_ids = [] current_item = self.root_element while self.tree_widget.itemBelow(current_item): current_item = self.tree_widget.itemBelow(current_item) item_ids.append(str(current_item.text(0))) return item_cfg, window_id, item_ids, selected_item def connectItem(self, parent, new_item, new_list_item): """ Descript. : """ if self.configuration.isBrick(new_item): self.emit(QtCore.SIGNAL("newItem"), new_item["brick"].propertyBag, new_item["brick"]._propertyChanged) else: if parent is not None: parentref = weakref.ref(parent) else: parentref=None def property_changed_cb(property, old_value, new_value, itemref=weakref.ref(new_list_item), parentref=parentref): item = itemref() if item is None: return item_name = str(item.text(0)) item_type = str(item.text(1)) try: klass = Qt4_Configuration.Configuration.classes[item_type] except KeyError: self.update_window_preview(item_name) else: if issubclass(klass, ContainerCfg): # we should update the container itself, # not just its contents so we trigger an # update of the parent instead if parentref is not None: parent = parentref() if parent is not None: self.update_window_preview(parent["name"], parent) else: self.update_window_preview(item_name) if parentref is not None: parent = parentref() if parent is None: return parent.childPropertyChanged(item_name, property, old_value, new_value) self.emit(QtCore.SIGNAL("newItem"), new_item["properties"], property_changed_cb) def add_window_clicked(self): """ Descript. : """ self._addItem(self.root_element, "window") def _addItem(self, parentListItem, item_type, *args): """ Descript. : """ parent_name = str(parentListItem.text(0)) parent = self.configuration.findContainer(parent_name) new_item = None new_list_item = None try: QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor)) if item_type == "window": new_item = self.configuration.addWindow() if type(new_item) == bytes: QtGui.QMessageBox.warning(self, "Cannot add", new_item, QtGui.QMessageBox.Ok) else: new_item["properties"].getProperty("w").setValue(QtGui.QApplication.desktop().width()) new_item["properties"].getProperty("h").setValue(QtGui.QApplication.desktop().height()) new_list_item = self.appendItem(parentListItem, new_item["name"], "window", icon="window_small") elif item_type == "brick": brick_type = args[0] new_item = self.configuration.addBrick(brick_type, parent) if type(new_item) == bytes: QtGui.QMessageBox.warning(self, "Cannot add", new_item, QtGui.QMessageBox.Ok) else: brick_name = new_item["name"] brick = new_item["brick"] new_list_item = self.appendItem(parentListItem, brick_name, brick_type, icon="brick") elif item_type == "tab": new_item = self.configuration.addItem(item_type, parent) if type(new_item) == bytes: QtGui.QMessageBox.warning(self, "Cannot add", new_item, QtGui.QMessageBox.Ok) else: item_name = new_item["name"] new_list_item = self.appendItem(parentListItem, item_name, item_type, icon=item_type) else: item_subtype = args[0] new_item = self.configuration.addItem(item_subtype, parent) if type(new_item) == bytes: QtGui.QMessageBox.warning(self, "Cannot add", new_item, QtGui.QMessageBox.Ok) else: item_name = new_item["name"] new_list_item = self.appendItem(parentListItem, item_name, item_type, icon=item_subtype) if type(new_item) != bytes and new_item is not None: self.connectItem(parent, new_item, new_list_item) self.emit(QtCore.SIGNAL("addWidget"), new_item, parent) finally: QtGui.QApplication.restoreOverrideCursor() def addBrick(self, brick_type): """ Descript. : """ self.addItem("brick", brick_type) def addContainer(self, container_type, container_subtype=None): """ Descript. : """ self.addItem(container_type, container_subtype) def addItem(self, item_type, item_subtype): """ Descript. : """ currentItem = self.tree_widget.currentItem() if currentItem: item_cfg = self.configuration.findItem(str(currentItem.text(0))) try: if self.configuration.isContainer(item_cfg): self._addItem(currentItem, item_type, item_subtype) else: # try to add to parent instead parentItem = currentItem.parent() self._addItem(parentItem, item_type, item_subtype) except: QtGui.QMessageBox.warning(self, "Cannot add %s" % item_type, "Please select a suitable parent container", QtGui.QMessageBox.Ok) def add_hbox_clicked(self): """ Descript. : """ self.addContainer("hbox", "hbox") def add_vbox_clicked(self): """ Descript. : """ self.addContainer("vbox", "vbox") def add_hgroupbox_clicked(self): """ Descript. : """ self.addContainer("hgroupbox", "hgroupbox") def add_vgroupbox_clicked(self): """ Descript. : """ self.addContainer("vgroupbox", "vgroupbox") def add_hspacer_clicked(self): """ Descript. : """ self.addItem("hspacer", "hspacer") def add_vspacer_clicked(self): """ Descript. : """ self.addItem("vspacer", "vspacer") def add_tab_clicked(self): """ Descript. : """ self.addContainer("tab") def add_vsplitter_clicked(self): """ Descript. : """ self.addContainer("vsplitter", "vsplitter") def add_hsplitter_clicked(self): """ Descript. : """ self.addContainer("hsplitter", "hsplitter") def add_icon_clicked(self): """ Descript. : """ self.addItem("icon", "icon") def add_label_clicked(self): """ Descript. : """ self.addItem("label", "label") def selectItem(self, item_name): """ Descript. : """ item = self.tree_widget.findItems(QtCore.QString(item_name), QtCore.Qt.MatchRecursive, 0) if item is not None: self.tree_widget.setCurrentItem(item[0]) self.tree_widget.scrollToItem(item[0], QtGui.QAbstractItemView.EnsureVisible) def item_double_clicked(self, item, column): """ Descript. : """ if item and column == 0: item_name = str(item.text(0)) item_cfg = self.configuration.findItem(item_name) if item_cfg: item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable) self.item_rename_started = True self.tree_widget.editItem(item) item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) def item_selected(self): """ Descript. : """ self.item_rename_started = None item = self.tree_widget.currentItem() if not item == self.root_element: item_name = str(item.text(0)) item_cfg = self.configuration.findItem(item_name) self.update_window_preview(item_name, item_cfg, selected_item=item_name) self.updateProperties(item_cfg) self.emit(QtCore.SIGNAL('showProperyEditorWindow'), ()) def item_changed(self, item, col): """ Descript. : Item changed even. Used when item text in column 0 has been changed """ if self.item_rename_started: item_parent_name = str(item.parent().text(0)) new_item_name = str(item.text(0)) old_name = self.configuration.rename(item_parent_name, item.parent().indexOfChild(item), new_item_name) if old_name is not None: item.setText(0, old_name) QtGui.QMessageBox.warning(self, "Cannot rename item", "New name %s conflicts\nwith another item name." % \ new_item_name, QtGui.QMessageBox.Ok) def item_right_clicked(self, item): """ Descript. : """ item_name = str(item.text(0)) item_cfg = self.configuration.findItem(item_name) if self.configuration.isBrick(item_cfg): popup_menu = QtGui.QPopupMenu() def _itemRightClicked(id, item_name=item_name): item_cfg=self.configuration.reload_brick(item_name) item = self.tree_widget.findItem(item_name, 0) self.emit(QtCore.SIGNAL("newItem"), (item_cfg["brick"].propertyBag, item_cfg["brick"]._propertyChanged)) self.item_selected(item) QtCore.QObject.connect(popup_menu, QtCore.SIGNAL("activated(int)"), _itemRightClicked) popup_menu.insertItem("reload brick", 0) popup_menu.exec_loop(QtCore.QCursor.pos()) def item_drag_dropped(self, source_item, target_item): """ Descript. : """ dragged_item_name = source_item.text(0) dropped_on_item_name = target_item.text(0) source_item_parent_name = str(source_item.parent().text(0)) target_item_parent_name = str(target_item.parent().text(0)) # find common ancestor target_item_ancestors = [target_item.parent()] source_item_ancestors = [source_item.parent()] while target_item_ancestors[0]: target_item_ancestors.insert(0, target_item_ancestors[0].parent()) while source_item_ancestors[0]: source_item_ancestors.insert(0, source_item_ancestors[0].parent()) common_ancestor = zip(target_item_ancestors, source_item_ancestors)[-1][0] if common_ancestor != self.root_element: common_ancestor_name = str(common_ancestor.text(0)) else: common_ancestor_name = "" # move item in configuration if not self.configuration.moveItem(dragged_item_name, dropped_on_item_name): #self.tree_widget.setSelected(source_item, True) source_item.setSelected(True) self.tree_widget.setCurrentItem(source_item) return # move item in the GUI tree #source_item.parent().takeItem(source_item) source_item.parent().takeChild(source_item.parent().indexOfChild(source_item)) target_cfg_item = self.configuration.findItem(dropped_on_item_name) if self.configuration.isContainer(target_cfg_item): # have to insert in the container target_item.addChild(source_item) else: target_item.parent().addChild(source_item) #source_item.moveItem(target_item) #if source_item_parent_name != target_item_parent_name: # self.update_window_preview(source_item_parent_name) if len(common_ancestor_name): self.update_window_preview(common_ancestor_name) #source_item.setSelected(True) source_item.setSelected(True) self.tree_widget.setCurrentItem(source_item) self.tree_widget.scrollToItem(source_item, QtGui.QAbstractItemView.EnsureVisible) def move_item(self, direction): """ Descript. : """ item = self.tree_widget.currentItem() if item: item_name = str(item.text(0)) oldParentItem = item.parent() if direction == "up": newParent = self.configuration.moveUp(item_name) if newParent is not None: new_parent_item_list = self.tree_widget.findItems(QtCore.QString(newParent), QtCore.Qt.MatchRecursive, 0) new_parent_item = new_parent_item_list[0] item_index = oldParentItem.indexOfChild(item) oldParentItem.takeChild(item_index) if new_parent_item == oldParentItem: item_index -= 1 oldParentItem.insertChild(item_index, item) else: new_parent_item.insertChild(0, item) else: newParent = self.configuration.moveDown(item_name) if newParent is not None: new_parent_item_list = self.tree_widget.findItems(QtCore.QString(newParent), QtCore.Qt.MatchRecursive, 0) new_parent_item = new_parent_item_list[0] item_index = oldParentItem.indexOfChild(item) oldParentItem.takeChild(item_index) if new_parent_item == oldParentItem: item_index += 1 oldParentItem.insertChild(item_index, item) else: new_parent_item.addChild(item) if newParent is not None: self.update_window_preview(newParent) #item.setSelected(True) self.tree_widget.setCurrentItem(item) self.tree_widget.scrollToItem(item, QtGui.QAbstractItemView.EnsureVisible) self.emit(QtCore.SIGNAL("moveWidget"), item_name, direction) def move_up_clicked(self): """ Descript. : """ self.move_item("up") def move_down_clicked(self): """ Descript. : """ self.move_item("down") class GUIPreviewWindow(QtGui.QWidget): """ Descript. : """ def __init__(self, *args, **kwargs): """ Descript. : """ QtGui.QWidget.__init__(self, *args) self.setWindowTitle("GUI Preview") self.window_preview_box = QtGui.QGroupBox("Preview window", self) self.window_preview = Qt4_GUIDisplay.WindowDisplayWidget(self.window_preview_box) self.window_preview_box_layout = QtGui.QVBoxLayout() self.window_preview_box_layout.addWidget(self.window_preview) self.window_preview_box.setLayout(self.window_preview_box_layout) _main_vlayout = QtGui.QVBoxLayout(self) _main_vlayout.addWidget(self.window_preview_box) _main_vlayout.setContentsMargins(0, 0, 0, 0) _main_vlayout.setSpacing(2) QtCore.QObject.connect(self.window_preview, QtCore.SIGNAL("itemClicked"), self.preview_item_clicked) self.resize(630,480) def renew(self): """ Descript. : """ return self.window_preview_box.close() self.window_preview_box = QtGui.QGroupBox("Preview window", self) self.window_preview = Qt4_GUIDisplay.WindowDisplayWidget(self.window_preview_box) self.window_preview_box_layout = QtGui.QVBoxLayout() self.window_preview_box_layout.addWidget(self.window_preview) self.window_preview_box.setLayout(self.window_preview_box_layout) _main_vlayout = QtGui.QVBoxLayout(self) _main_vlayout.addWidget(self.window_preview_box) _main_vlayout.setContentsMargins(0, 0, 0, 0) _main_vlayout.setSpacing(0) QtCore.QObject.connect(self.window_preview, QtCore.SIGNAL("itemClicked"), self.preview_item_clicked) self.resize(650,480) self.window_preview_box.show() def preview_item_clicked(self, item_name): """ Descript. : """ self.emit(QtCore.SIGNAL("previewItemClicked"), item_name) def drawWindow(self, container_cfg, window_id, container_ids, selected_item): """ Descript. : """ if container_cfg["type"] == "window": caption = container_cfg["properties"]["caption"] s = caption and " - %s" % caption or "" self.window_preview_box.setTitle("Window preview: %s%s" % (container_cfg["name"], s)) self.window_preview.drawPreview(container_cfg, window_id, container_ids, selected_item) def updateWindow(self, container_cfg, window_id, container_ids, selected_item): """ Descript. : """ if container_cfg["type"] == "window": caption = container_cfg["properties"]["caption"] s = caption and " - %s" % caption or "" self.window_preview_box.setTitle("Window preview: %s%s" % (container_cfg["name"], s)) self.window_preview.updatePreview(container_cfg, window_id, container_ids, selected_item) def add_window_widget(self, window_cfg): """ Descript. : """ self.window_preview.add_window(window_cfg) def remove_item_widget(self, item_widget, children_name_list): """ Descript. : """ self.window_preview.remove_widget(item_widget, children_name_list) def add_item_widget(self, item_widget, parent_widget): """ Descript. : """ self.window_preview.add_widget(item_widget, parent_widget) def move_item_widget(self, item_widget, direction): """ Descript. : """ self.window_preview.move_widget(item_widget, direction) class HWRWindow(QtGui.QWidget): """ Descript. : """ def __init__(self, *args, **kwargs): """ Descript. : """ QtGui.QWidget.__init__(self, *args) self.setWindowTitle("Hardware Repository browser") tb = QtGui.QWidget(self) tb_layout = QtGui.QHBoxLayout() _refresh_toolbutton = QtGui.QToolButton(tb) _refresh_toolbutton.setIcon(QtGui.QIcon(Qt4_Icons.load("reload"))) _refresh_toolbutton.setToolTip("refresh HWR objects tree") _close_toolbutton = QtGui.QToolButton(tb) _close_toolbutton.setIcon(QtGui.QIcon(Qt4_Icons.load("button_cancel"))) _close_toolbutton.setToolTip("close HWR browser") horizontal_spacer = HorizontalSpacer(tb) tb_layout.addWidget(_refresh_toolbutton) tb_layout.addWidget(_close_toolbutton) tb_layout.addWidget(horizontal_spacer) tb.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed) tb.setLayout(tb_layout) QtCore.QObject.connect(_refresh_toolbutton, QtCore.SIGNAL("clicked()"), self.refresh) QtCore.QObject.connect(_close_toolbutton, QtCore.SIGNAL("clicked()"), self.close) _main_vlayout = QtGui.QVBoxLayout() _main_vlayout.addWidget(tb) self.setLayout(_main_vlayout) self.add_hwr_browser() def add_hwr_browser(self): """ Descript. : """ return """try: _hwr_widget = HardwareRepositoryBrowser.HardwareRepositoryBrowser except AttributeError: logging.getLogger().error("No Hardware Repository client found") else: self.hwr_widget = _hwr_widget(self) self.layout().addWidget(self.hwr_widget) self.hwr_widget.show()""" def refresh(self): """ Descript. : """ self.hwr_widget.close(True) self.add_hwr_browser() class GUIBuilder(QtGui.QMainWindow): """ Descript. : """ def __init__(self, *args, **kwargs): """ Descript. : """ QtGui.QMainWindow.__init__(self, *args) self.filename = None self.setWindowTitle("GUI Builder") self.main_widget = QtGui.QSplitter(self) self.setCentralWidget(self.main_widget) self.statusbar = self.statusBar() self.gui_editor_window = GUIEditorWindow(self.main_widget) self.toolbox_window = ToolboxWindow(self.main_widget) self.log_window = Qt4_LogViewBrick.Qt4_LogViewBrick(None) self.log_window.setWindowTitle("Log window") sw = QtGui.QApplication.desktop().screen().width() sh = QtGui.QApplication.desktop().screen().height() self.log_window.resize(QtCore.QSize(sw * 0.8, sh * 0.2)) self.property_editor_window = Qt4_PropertyEditorWindow(None) self.gui_preview_window = GUIPreviewWindow(None) self.hwr_window = HWRWindow(None) self.configuration = self.gui_editor_window.configuration file_new_action = self.create_action("&New...", self.new_clicked, QtGui.QKeySequence.New, None, "Create new GUI") file_open_action = self.create_action("&Open...", self.open_clicked, QtGui.QKeySequence.Open, None, "Open an existing GUI file") file_save_action = self.create_action("&Save", self.save_clicked, QtGui.QKeySequence.Save, None, "Save the gui file") file_save_as_action = self.create_action("Save &As...", self.save_as_clicked, None, tip = "Save the gui file using a new name") file_quit_action = self.create_action("&Quit", self.quit_clicked, "Ctrl+Q", None, "Close the application") self.fileMenu = self.menuBar().addMenu("&File") self.file_menu_actions = (file_new_action, file_open_action, file_save_action, file_save_as_action, file_quit_action) self.add_actions(self.fileMenu, self.file_menu_actions) show_propery_editor_windowAction = self.create_action("Properties", self.show_property_editor_window, tip = "Show properties") show_gui_preview_action = self.create_action("GUI preview", self.show_gui_preview_window, tip = "GUI preview") show_log_windowAction = self.create_action( "Log", self.show_log_window, tip = "Show log") show_gui_action = self.create_action("Launch GUI", self.launch_gui_cicked, tip = "launch GUI (as a separate process)") show_hwr_window = self.create_action("HWR", self.show_hwr_window, tip = "Show Hardware Repository") window_menu = self.menuBar().addMenu("&Window") window_menu_actions = (show_propery_editor_windowAction, show_gui_preview_action, show_log_windowAction, show_gui_action, show_hwr_window) self.add_actions(window_menu, window_menu_actions[:-1]) self.connect(self.toolbox_window, QtCore.SIGNAL("addBrick"), self.gui_editor_window.addBrick) self.connect(self.gui_editor_window, QtCore.SIGNAL("editProperties"), self.property_editor_window.editProperties) self.connect(self.gui_editor_window, QtCore.SIGNAL("newItem"), self.property_editor_window.addProperties) self.connect(self.gui_editor_window, QtCore.SIGNAL("drawPreview"), self.gui_preview_window.drawWindow) self.connect(self.gui_editor_window, QtCore.SIGNAL("updatePreview"), self.gui_preview_window.updateWindow) self.connect(self.gui_editor_window, QtCore.SIGNAL("addWidget"), self.gui_preview_window.add_item_widget) self.connect(self.gui_editor_window, QtCore.SIGNAL("removeWidget"), self.gui_preview_window.remove_item_widget) self.connect(self.gui_editor_window, QtCore.SIGNAL("moveWidget"), self.gui_preview_window.move_item_widget) self.connect(self.gui_preview_window, QtCore.SIGNAL("previewItemClicked"), self.gui_editor_window.selectItem) self.connect(self.gui_editor_window, QtCore.SIGNAL("showProperyEditorWindow"), self.show_property_editor_window) self.connect(self.gui_editor_window, QtCore.SIGNAL("hidePropertyEditorWindow"), self.hide_property_editor_window) self.connect(self.gui_editor_window, QtCore.SIGNAL("showPreview"), self.show_gui_preview_window) self.toolbox_window.refresh_clicked() self.gui_preview_window.show() self.resize(480, 800) def create_action(self, text, slot = None, shortcut = None, icon = None, tip = None, checkable = False, signal = "triggered()"): """ Descript. : """ action = QtGui.QAction(text, self) if icon is not None: action.setIcon(icon) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: self.connect(action, QtCore.SIGNAL(signal), slot) if checkable: action.setCheckable(True) return action def add_actions(self, target, actions): """ Descript. : """ for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def new_clicked(self, filename = None): """ Descript. : """ self.configuration = Qt4_Configuration.Configuration() self.filename = filename if self.filename: self.setWindowTitle("GUI Builder - %s" % filename) else: self.setWindowTitle("GUI Builder") self.gui_preview_window.renew() self.gui_editor_window.set_configuration(self.configuration) def open_clicked(self): """ Descript. : """ filename = str(QtGui.QFileDialog.getOpenFileName(os.environ["HOME"], "GUI file (*.gui)", self, "Save file", "Choose a GUI file to open")) if len(filename) > 0: try: f = open(filename) except: logging.getLogger().exception("Cannot open file %s", filename) QtGui.QMessageBox.warning(self, "Error", "Could not open file %s !" % \ filename, QtGui.QMessageBox.Ok) else: try: raw_config = eval(f.read()) try: new_config = Qt4_Configuration.Configuration(raw_config) except: logging.getLogger().exception("Cannot read configuration from file %s", filename) QtGui.QMessageBox.warning(self, "Error", "Could not read configuration\nfrom file %s" % \ filename, QtGui.QMessageBox.Ok) else: self.filename = filename self.configuration = new_config self.setCaption("GUI Builder - %s" % filename) self.gui_preview_window.renew() self.gui_editor_window.set_configuration(new_config) finally: f.close() def save_clicked(self): """ Descript. : """ if True: #try: QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor)) if self.filename is not None: if os.path.exists(self.filename): should_create_startup_script=False else: should_create_startup_script=True if self.configuration.save(self.filename): self.setWindowTitle("GUI Builder - %s" % self.filename) QtGui.QApplication.restoreOverrideCursor() QtGui.QMessageBox.information(self, "Success", "Qt4_Configuration have been saved successfully to\n%s" % self.filename, QtGui.QMessageBox.Ok) if should_create_startup_script: if QtGui.QMessageBox.question(self, "Launch script", "Do you want to create a startup script for the new GUI ?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) == QtGui.QMessageBox.Yes: try: hwr_server = HardwareRepository.HardwareRepository().serverAddress except: hwr_server = "" else: pid = subprocess.Popen("newGUI --just-script %s %s" % (self.filename, hwr_server), shell=True).pid return True else: QtGui.QApplication.restoreOverrideCursor() QtGui.QMessageBox.warning(self, "Error", "Could not save configuration to file %s !" % self.filename, QtGui.QMessageBox.Ok) return False else: QtGui.QApplication.restoreOverrideCursor() self.save_as_clicked() #finally: # QtGui.QApplication.restoreOverrideCursor() def save_as_clicked(self): """ Descript. : """ f = self.filename self.filename = str(QtGui.QFileDialog.getSaveFileName(self, os.environ["HOME"], "GUI file (*.gui)", "Save file", "Choose a filename to save under")) if len(self.filename) == 0: self.filename = f return elif not self.filename.endswith(os.path.extsep+"gui"): self.filename += os.path.extsep + 'gui' return self.save_clicked() def quit_clicked(self): """ Descript. : """ if self.gui_editor_window.configuration.hasChanged: if QtGui.QMessageBox.warning(self, "Please confirm", "Are you sure you want to quit ?\nYour changes will be lost.", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) == QtGui.QMessageBox.No: return exit(0) def show_property_editor_window(self): """ Descript. : """ self.property_editor_window.show() def hide_property_editor_window(self): """ Descript. : """ self.property_editor_window.close() def show_gui_preview_window(self): """ Descript. : """ self.gui_preview_window.show() def show_log_window(self): """ Descript. : """ self.log_window.show() def show_hwr_window(self): """ Descript. : """ self.hwr_window.show() def closeEvent(self,event): """ Descript. : """ event.ignore() self.quit_clicked() def launch_gui_cicked(self): """ Descript. : """ if self.gui_editor_window.configuration.hasChanged or self.filename is None: if QtGui.QMessageBox.warning(self, "GUI file not saved yet", "Before starting the GUI, the file needs to be saved.\nContinue ?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) == QtGUi.QMessageBox.No: return self.save_clicked() terminal = os.environ["TERM"] or "xterm" try: hwr_server = HardwareRepository.HardwareRepository().serverAddress except: logging.getLogger().error("Sorry, could not find Hardware Repository server") else: customBricksDirs = os.path.pathsep.join(BlissFramework.getCustomBricksDirs()) pid = subprocess.Popen("%s -title %s -e startGUI --bricksDirs=%s %s%s" % (terminal,os.path.basename(self.filename),customBricksDirs, (hwr_server and "--hardwareRepository=%s " % hwr_server or ""), self.filename), shell=True).pid logging.getLogger().debug("GUI launched, pid is %d", pid) if __name__ == '__main__': app = GtGui.QApplication([]) mainwin = GUIBuilder() app.setMainWidget(mainwin) mainwin.show() app.exec_loop()