def init_fields(self, data): """Prepare and insert fields in the form.""" self.fields['name'] = TextField(_("Name"), data.get('name', '')) self.addRow(self.fields['name'].label, self.fields['name'].widget) # Insert the modules table view with its buttons table_buttons = QtGui.QHBoxLayout() table_buttons.setContentsMargins(0, 0, 0, 0) table_buttons.addWidget(self.button_module_add) table_buttons.addWidget(self.button_module_rm) self.addRow(table_buttons) self.addRow(self.table_modules) # Insert a separator separator = QtGui.QFrame() #separator.setFrameShape(QtGui.QFrame.HLine) separator.setFrameStyle(QtGui.QFrame.HLine | QtGui.QFrame.Sunken) self.addRow(separator) # Insert the models table view with its buttons table_buttons = QtGui.QHBoxLayout() table_buttons.setContentsMargins(0, 0, 0, 0) table_buttons.addWidget(self.button_model_add) table_buttons.addWidget(self.button_model_rm) self.addRow(table_buttons) self.addRow(self.table_models) # Restrict models checkbox self.fields['restrict'] = BoolField(_("Restrict to models"), data.get('restrict', False)) self.addRow(self.fields['restrict'].label, self.fields['restrict'].widget) # Insert data in fields and tables self.set_data(data)
def init_fields(self, data): """Prepare and insert fields in the form.""" self.fields['name'] = TextField(_("Name"), data.get('name', '')) self.addRow( self.fields['name'].label, self.fields['name'].widget) self.fields['maxdepth'] = IntField( _(u"Level"), data.get('maxdepth', 1), range_=(0, 42)) self.fields['autocompletion'] = BoolField( _("Autocompletion"), data.get('autocompletion', True)) # Insert the table view with its buttons table_buttons = QtGui.QHBoxLayout() table_buttons.setContentsMargins(0, 0, 0, 0) table_buttons.addWidget(self.button_add) table_buttons.addWidget(self.button_rm) label = QtGui.QLabel(self.fields['maxdepth'].label) label.setAlignment(QtCore.Qt.AlignCenter) table_buttons.addWidget(label) table_buttons.addWidget(self.fields['maxdepth'].widget) label = QtGui.QLabel(self.fields['autocompletion'].label) label.setAlignment(QtCore.Qt.AlignCenter) table_buttons.addWidget(label) table_buttons.addWidget(self.fields['autocompletion'].widget) self.addRow(table_buttons) self.addRow(self.table) # Insert data in fields and tables self.set_data(data)
def setData(self, index, value, role=QtCore.Qt.EditRole): """Overloaded to dynamically update other columns accordingly.""" if index.column() == 0: value = value.strip().lower() if ' ' in value: raise ValueError( _(u"Space characters are not allowed.")) res = super(RelationTableModel, self).setData(index, value, role) if res: index_root_ok = self.index(index.row(), 1) index_show_ok = self.index(index.row(), 2) index_attr_ok = self.index(index.row(), 3) # 'name' contains the joker character => 'root_ok' = False if index.column() == 0 and '*' in value: self.setData(index_root_ok, False) self.dataChanged.emit(index_root_ok, index_root_ok) # 'root_ok' == True => 'show_ok' = True if index.column() == 1: if value: self.setData(index_show_ok, True) self.dataChanged.emit(index_show_ok, index_show_ok) # 'show_ok' updated => update 'attr_ok' if index.column() == 2: self.dataChanged.emit(index_attr_ok, index_attr_ok) return res
def __init__(self, app): UI.__init__(self, app) QtGui.QToolBar.__init__(self) self.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) self.action_functions = QtGui.QAction(Icons['function'], _("Functions"), self) self.action_functions.setDisabled(True) # Add actions to the toolbar self.addAction(Action['new_group']) self.addAction(Action['new_server']) self.addAction(self.action_functions) separator = QtGui.QWidget() separator.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.addWidget(separator) #self.addAction(self._actions['settings']) self.addAction(Action['about']) self.addAction(Action['quit']) # Add a submenu on the 'functions' tool button fmenu = QtGui.QMenu() fmenu.addAction(Action['new_relation']) fmenu.addAction(Action['new_dependency']) self.action_functions.setMenu(fmenu) for widget in self.action_functions.associatedWidgets(): if isinstance(widget, QtGui.QToolButton): widget.setPopupMode(QtGui.QToolButton.InstantPopup)
def setData(self, index, value, role=QtCore.Qt.EditRole): """Overloaded to dynamically update other columns accordingly.""" if index.column() == 0: value = value.strip().lower() if ' ' in value: raise ValueError(_(u"Space characters are not allowed.")) return super(DependencyModelTableModel, self).setData(index, value, role)
def _function_deleted(self, model, id_): """Update title of the corresponding tab when a function is deleted.""" if id_ in self.tabs: content = self.tabs.pop(id_) self.tabs_tmp[id_] = content sdata = Controller['server'].read(content.server_id) title = "%s - %s" % (sdata['name'], _(u"New")) index = self.indexOf(content) self.setTabText(index, title)
def delete_confirm(self, id_): """Display a confirmation dialog to the user before delete.""" data = self.read(id_) response = confirm( UI['main_window'], _(u"Are you sure you want to delete the server " u"<strong>%s</strong>?") % (data['name'])) if response: self.delete(id_)
def confirm_quit(self): """Return `True` if the application can be closed. If there is unsaved work, ask the user to confirm its action. """ # Check unsaved work. confirm = True for content in UI['workbook'].tabs.itervalues(): if content.unsaved: confirm = False for content in UI['workbook'].tabs_tmp.itervalues(): if content.unsaved: confirm = False # Ask the user to confirm if unsaved work has been detected if not confirm: confirm = dialog.confirm( UI['main_window'], _(u"Unsaved work detected. Quit anyway?"), _(u"Unsaved work")) return confirm
def close_tab(self, index): """Close a tab at the given `index`.""" widget = self.widget(index) close = True if widget.unsaved: close = dialog.confirm( self, _(u"This function has been modified. Close anyway?"), _(u"Modified function")) if close: self.removeTab(index) widget.deleteLater() for id_, tab_content in self.tabs.iteritems(): if tab_content == widget: del self.tabs[id_] break for id_, tab_content in self.tabs_tmp.iteritems(): if tab_content == widget: del self.tabs_tmp[id_] break
def confirm(parent, message, title=None): """Display a confirmation dialog (Yes/No response) and returns the boolean response. """ if title is None: title = _(u"Confirmation") response = QtGui.QMessageBox.question( parent, title, message, QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) return response == QtGui.QMessageBox.Yes
class About(Action): """Action to display the 'about' dialog.""" __metadata__ = { 'name': 'about', 'icon': 'about', 'string': _(u"About"), } def run(self): """Display the 'about' dialog.""" about.display()
class NewGroup(Action): """Action to add a new group.""" __metadata__ = { 'name': 'new_group', 'icon': 'group', 'string': _(u"New group"), 'shortcut': 'Ctrl+G', } def run(self): """Display the form to add a new group.""" Controller['group'].display_form()
class Quit(Action): """Action to quit the application.""" __metadata__ = { 'name': 'quit', 'icon': 'quit', 'string': _(u"Quit"), 'shortcut': QtGui.QKeySequence.Quit, } def run(self): """Ask the user to confirm, and quit the application.""" self.app.confirm_quit() and self.app.quit()
def __init__(self, workarea, id_=None): # Table view self.table = QtGui.QTableView() self.table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self.table.setItemDelegateForColumn(1, CheckBoxDelegate(self.table)) self.table.setItemDelegateForColumn(2, CheckBoxDelegate(self.table)) self.table.setItemDelegateForColumn(3, CheckBoxDelegate(self.table)) #self.table.setSizePolicy( # QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.table.verticalHeader().hide() #self.table.setSortingEnabled(True) #self.table.setSelectionMode(QtGui.QTableWidget.NoSelection) self.table.setMinimumHeight(300) # Table data model table_model = RelationTableModel( self.table, header=[_(u"Model"), _(u"Base"), _(u"Show"), _(u"Attr.")], default=[u"", False, True, True]) self.table.setModel(table_model) # Buttons to add add/remove rows self.button_add = QtGui.QPushButton( Icons['add'], _(u"Add")) self.button_add.clicked.connect(self._button_add_clicked) self.button_rm = QtGui.QPushButton( Icons['remove'], _(u"Remove")) self.button_rm.clicked.connect(self._button_rm_clicked) self.button_rm.setEnabled(False) # Super first super(RelationFormLayout, self).__init__(workarea, id_) # Then connect to signals table_model.dataChanged.connect(lambda item: self.data_changed.emit()) table_model.dataChanged.connect(self._function_unsaved) table_model.modelReset.connect(self._update_buttons) selection_model = self.table.selectionModel() selection_model.selectionChanged.connect(self._update_buttons)
class RemoveGroup(Action): """Action to remove a group.""" __metadata__ = { 'name': 'remove_group', 'icon': 'remove', 'string': _(u"Remove"), } def run(self): """Remove the group.""" id_ = UI['tree'].current.get('group') if id_: Controller['group'].delete_confirm(id_)
class RemoveDependency(Action): """Action to remove a dependencies graph.""" __metadata__ = { 'name': 'remove_dependency', 'icon': 'remove', 'string': _(u"Remove"), } def run(self): """Display the form to edit a dependencies graph.""" id_ = UI['tree'].current.get('dependency') if id_: Controller['dependency'].delete_confirm(id_)
class RemoveServer(Action): """Action to remove a server.""" __metadata__ = { 'name': 'remove_server', 'icon': 'remove', 'string': _(u"Remove"), } def run(self): """Remove the server.""" id_ = UI['tree'].current.get('server') if id_: Controller['server'].delete_confirm(id_)
class RemoveRelation(Action): """Action to remove a relation graph.""" __metadata__ = { 'name': 'remove_relation', 'icon': 'remove', 'string': _(u"Remove"), } def run(self): """Display the form to edit a relational graph.""" id_ = UI['tree'].current.get('relation') if id_: Controller['relation'].delete_confirm(id_)
class EditGroup(Action): """Action to edit a group.""" __metadata__ = { 'name': 'edit_group', 'icon': 'edit', 'string': _(u"Modify"), } def run(self): """Display the form to edit a group.""" id_ = UI['tree'].current.get('group') if id_: Controller['group'].display_form(id_)
class EditRelation(Action): """Action to edit a relation graph.""" __metadata__ = { 'name': 'edit_relation', 'icon': 'edit', 'string': _(u"Modify"), } def run(self): """Display the form to edit a relational graph.""" id_ = UI['tree'].current.get('relation') if id_: Controller['relation'].display_form(id_)
class EditDependency(Action): """Action to edit a dependencies graph.""" __metadata__ = { 'name': 'edit_dependency', 'icon': 'edit', 'string': _(u"Modify"), } def run(self): """Display the form to edit a dependencies graph.""" id_ = UI['tree'].current.get('dependency') if id_: Controller['dependency'].display_form(id_)
class EditServer(Action): """Action to edit a server.""" __metadata__ = { 'name': 'edit_server', 'icon': 'edit', 'string': _(u"Modify"), } def run(self): """Display the form to edit a server.""" id_ = UI['tree'].current.get('server') if id_: Controller['server'].display_form(id_)
def __init__(self, workarea, id_=None): QtGui.QFormLayout.__init__(self) self.workarea = workarea ctl = self.workarea.ctl data = id_ and ctl.read(id_) \ or ctl.default_get({'server_id': workarea.server_id}) # Fields self.fields = {} self.init_fields(data) # Buttons self.button_save = QtGui.QPushButton(Icons['save'], _(u"Save")) self.button_save.clicked.connect(self.workarea.save) self.button_save.setEnabled(self.workarea.unsaved) self.button_restore = QtGui.QPushButton(Icons['undo'], _(u"Undo")) self.button_restore.clicked.connect(self.workarea.restore) self.button_restore.setEnabled(False) self.button_close = QtGui.QPushButton(Icons['ok'], _(u"Close")) self.button_close.clicked.connect( lambda: self.workarea.show_panel(False)) self.button_execute = QtGui.QPushButton(Icons['exe'], _(u"Execute")) self.button_execute.clicked.connect(self.workarea.execute) self.buttons_box = QtGui.QHBoxLayout() self.buttons_box.addWidget(self.button_save) self.buttons_box.addWidget(self.button_restore) self.buttons_box.addWidget(self.button_close) self.buttons_box.addWidget(self.button_execute) self.addRow(self.buttons_box) # Default focus self.fields['name'].widget.setFocus() # Connect signals for field in self.fields.itervalues(): field.changed.connect(self.data_changed.emit) field.changed.connect(self._function_unsaved) ctl.created.connect(self._function_saved) ctl.updated.connect(self._function_saved) ctl.deleted.connect(self._function_unsaved) self.data_restored.connect(self._function_restored)
def new_function(self, model, server_id): """Add a new workarea which can be saved later.""" sdata = Controller['server'].read(server_id) title = u"%s - %s" % (sdata['name'], _(u"New")) id_tmp = uuid.uuid4().hex self.tabs_tmp[id_tmp] = WorkArea[model](self.app, server_id, id_tmp, new=True) self.addTab(self.tabs_tmp[id_tmp], Icons[model], title) self.tabs_tmp[id_tmp].created.connect(self._function_created) self.tabs_tmp[id_tmp].data_changed.connect(self._function_unsaved) self.tabs_tmp[id_tmp].data_restored.connect(self._function_restored) self.tabs_tmp[id_tmp].show_panel() self.setCurrentWidget(self.tabs_tmp[id_tmp])
def __init__(self, app, server_id, parent): TreeItem.__init__(self, app) parent.addChild(self) self.server_id = server_id self.setText(0, _("Relations")) self.setIcon(0, Icons['group']) sdata = Controller['server'].read(self.server_id) relations = sdata.get('relations', {}) for rid in sorted(relations, key=lambda rid: relations[rid]['name']): self._add('relation', rid, select=False) # Set the visual state if self.childCount(): self.setExpanded(True) self.set_icon_expanded(True) else: self.setHidden(True)
def __init__(self, app, server_id, parent): TreeItem.__init__(self, app) parent.addChild(self) self.server_id = server_id self.setText(0, _("Dependencies")) self.setIcon(0, Icons['group']) sdata = Controller['server'].read(self.server_id) dependencies = sdata.get('dependencies', {}) for did in sorted(dependencies, key=lambda did: dependencies[did]['name']): self._add('dependency', did, select=False) # Set the visual state if self.childCount(): self.setExpanded(True) self.set_icon_expanded(True) else: self.setHidden(True)
class NewServer(Action): """Action to add a new server.""" __metadata__ = { 'name': 'new_server', 'icon': 'server', 'string': _(u"New server"), 'shortcut': 'Ctrl+H', } def run(self): """Display the form to add a new server.""" Controller['server'].display_form() def __connect__(self): UI['tree'].currentItemChanged.connect(self._tree_item_changed) def _tree_item_changed(self, current, previous): """Enable/disable the action according to the current item selected in the main tree. """ self.setDisabled(not current)
def __init__(self, app, id_=None, data=None): QtGui.QDialog.__init__(self) self.app = app self.id_ = id_ self.data = data self.fields = {} self.setLayout(QtGui.QFormLayout()) # Fields self.fields['name'] = TextField(_("Name"), data.get('name', '')) self.layout().addRow( self.fields['name'].label, self.fields['name'].widget) # Buttons buttons = QtGui.QDialogButtonBox( QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel, parent=self) self.layout().addWidget(buttons) # Default focus self.fields['name'].widget.setFocus() # Responses buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject)
def export(self): """Export the graph (image) in a format among (some of) those supported by Graphviz. """ formats = [ # images (u"%s (*.bmp)" % _(u"Image Windows BMP"), [u'.bmp']), (u"%s (*.jpg *.jpeg *.jpe)" % _(u"Image JPEG"), [ u'.jpg', u'.jpeg', u'jpe']), (u"%s (*.gif)" % _(u"Image GIF"), [u'.gif']), (u"%s (*.png)" % _(u"Image PNG"), [u'.png']), # other (u"%s (*.dot)" % (u"DOT"), [u'.dot']), (u"%s (*.pdf)" % (u"PDF"), [u'.pdf']), (u"%s (*.ps)" % (u"PostScript"), [u'.ps']), (u"%s (*.eps)" % (u"Encapsulated PostScript"), [u'.eps']), (u"%s (*.svg)" % (u"SVG"), [u'.svg']), (u"%s (*.svgz)" % (u"SVGz"), [u'.svgz']), ] default_format = u"%s (*.png)" % _(u"Image PNG") if self.graph: data = self.panel.get_data() name = data.get('name', u"%s" % self._model).replace('.', '_') path, format_ = QtGui.QFileDialog.getSaveFileName( self, _(u"Export"), name, u';;'.join([fmt[0] for fmt in formats]), default_format) if path: # Detect the extension from the file name without taking into # account the selected extension in the list path_ext = None for fmt in formats: exts = fmt[1] for ext in exts: if path.endswith(ext): path_ext = ext break if path_ext: break # If no extension was typed in the file name, we take the # selected one in the list if not path_ext: for fmt in formats: if fmt[0] == format_: path_ext = fmt[1][0] path += path_ext break # Save the graph (pydot/Graphviz manages that for us) self.graph.write(path, format=path_ext[1:])
class NewRelation(Action): """Action to add a new relation graph.""" __metadata__ = { 'name': 'new_relation', 'icon': 'relation', 'string': _(u"Add relational graph"), 'shortcut': 'Ctrl+R', 'server_menu': True, } def __connect__(self): UI['tree'].itemActivated.connect(self._update_state) def _update_state(self, item): if UI['tree'].current.get('server'): self.setDisabled(False) else: self.setDisabled(True) def run(self): """Display the form to add a relational graph.""" if UI['tree'].current.get('server'): Controller['relation'].display_form()