class SqlConnectionWidget(QWidget):
    """
    Class implementing a widget showing the SQL connections.
    
    @signal tableActivated(str) emitted after the entry for a table has been
        activated
    @signal schemaRequested(str) emitted when the schema display is requested
    @signal cleared() emitted after the connection tree has been cleared
    """
    tableActivated = pyqtSignal(str)
    schemaRequested = pyqtSignal(str)
    cleared = pyqtSignal()

    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget (QWidget)
        """
        super(SqlConnectionWidget, self).__init__(parent)

        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)

        self.__connectionTree = QTreeWidget(self)
        self.__connectionTree.setObjectName("connectionTree")
        self.__connectionTree.setHeaderLabels([self.tr("Database")])
        if qVersion() >= "5.0.0":
            self.__connectionTree.header().setSectionResizeMode(
                QHeaderView.Stretch)
        else:
            self.__connectionTree.header().setResizeMode(QHeaderView.Stretch)
        refreshAction = QAction(self.tr("Refresh"), self.__connectionTree)
        self.__schemaAction = QAction(self.tr("Show Schema"),
                                      self.__connectionTree)

        refreshAction.triggered.connect(self.refresh)
        self.__schemaAction.triggered.connect(self.showSchema)

        self.__connectionTree.addAction(refreshAction)
        self.__connectionTree.addAction(self.__schemaAction)
        self.__connectionTree.setContextMenuPolicy(Qt.ActionsContextMenu)

        layout.addWidget(self.__connectionTree)

        self.__activating = False

        self.__connectionTree.itemActivated.connect(self.__itemActivated)
        self.__connectionTree.currentItemChanged.connect(
            self.__currentItemChanged)

        self.__activeDb = ""

    def refresh(self):
        """
        Public slot to refresh the connection tree.
        """
        self.__connectionTree.clear()
        self.cleared.emit()

        connectionNames = QSqlDatabase.connectionNames()

        foundActiveDb = False
        for name in connectionNames:
            root = QTreeWidgetItem(self.__connectionTree)
            db = QSqlDatabase.database(name, False)
            root.setText(0, self.__dbCaption(db))
            if name == self.__activeDb:
                foundActiveDb = True
                self.__setActive(root)
            if db.isOpen():
                tables = db.tables()
                for table in tables:
                    itm = QTreeWidgetItem(root)
                    itm.setText(0, table)

        if not foundActiveDb and connectionNames:
            self.__activeDb = connectionNames[0]
            self.__setActive(self.__connectionTree.topLevelItem(0))

    def showSchema(self):
        """
        Public slot to show schema data of a database.
        """
        cItm = self.__connectionTree.currentItem()
        if cItm is None or cItm.parent() is None:
            return
        self.__setActive(cItm.parent())
        self.schemaRequested.emit(cItm.text(0))

    def __itemActivated(self, itm, column):
        """
        Private slot handling the activation of an item.
        
        @param itm reference to the item (QTreeWidgetItem)
        @param column column that was activated (integer)
        """
        if itm is None:
            return

        if not self.__activating:
            self.__activating = True
            if itm.parent() is None:
                self.__setActive(itm)
            else:
                self.__setActive(itm.parent())
                self.tableActivated.emit(itm.text(0))
            self.__activating = False

    def __currentItemChanged(self, current, previous):
        """
        Private slot handling a change of the current item.
        
        @param current reference to the new current item (QTreeWidgetItem)
        @param previous reference to the previous current item
            (QTreeWidgetItem)
        """
        self.__schemaAction.setEnabled(current is not None
                                       and current.parent() is not None)

    def __dbCaption(self, db):
        """
        Private method to assemble a string for the caption.
        
        @param db reference to the database object (QSqlDatabase)
        @return caption string (string)
        """
        nm = db.driverName()
        nm += ":"
        if db.userName():
            nm += db.userName()
            nm += "@"
        nm += db.databaseName()
        return nm

    def __setBold(self, itm, bold):
        """
        Private slot to set the font to bold.
        
        @param itm reference to the item to be changed (QTreeWidgetItem)
        @param bold flag indicating bold (boolean)
        """
        font = itm.font(0)
        font.setBold(bold)
        itm.setFont(0, font)

    def currentDatabase(self):
        """
        Public method to get the current database.
        
        @return reference to the current database (QSqlDatabase)
        """
        return QSqlDatabase.database(self.__activeDb)

    def __setActive(self, itm):
        """
        Private slot to set an item to active.
        
        @param itm reference to the item to set as the active item
            (QTreeWidgetItem)
        """
        for index in range(self.__connectionTree.topLevelItemCount()):
            if self.__connectionTree.topLevelItem(index).font(0).bold():
                self.__setBold(self.__connectionTree.topLevelItem(index),
                               False)

        if itm is None:
            return

        self.__setBold(itm, True)
        self.__activeDb = QSqlDatabase.connectionNames()[
            self.__connectionTree.indexOfTopLevelItem(itm)]
Beispiel #2
0
class PugdebugExpressionViewer(QWidget):

    expression_added_signal = pyqtSignal(int, str)
    expression_changed_signal = pyqtSignal(int, str)

    def __init__(self):
        super(PugdebugExpressionViewer, self).__init__()

        # Action for adding a new expression
        self.add_action = QAction(QIcon.fromTheme('list-add'), "&Add", self)
        self.add_action.triggered.connect(self.handle_add_action)

        # Action for deleting selected expressions
        self.delete_action = QAction(QIcon.fromTheme('list-remove'), "&Delete",
                                     self)
        self.delete_action.setShortcut(QKeySequence("Del"))
        self.delete_action.setShortcutContext(Qt.WidgetShortcut)
        self.delete_action.triggered.connect(self.handle_delete_action)

        self.toolbar = QToolBar()
        self.toolbar.setIconSize(QSize(16, 16))
        self.toolbar.addAction(self.add_action)
        self.toolbar.addAction(self.delete_action)

        self.tree = QTreeWidget()
        self.tree.setColumnCount(3)
        self.tree.setHeaderLabels(['Expression', 'Type', 'Value'])
        self.tree.setSelectionMode(QAbstractItemView.ContiguousSelection)
        self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tree.customContextMenuRequested.connect(self.show_context_menu)
        self.tree.addAction(self.delete_action)

        layout = QVBoxLayout()
        layout.addWidget(self.toolbar)
        layout.addWidget(self.tree)
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

        self.restore_state()

        self.tree.itemChanged.connect(self.handle_item_changed)

    def show_context_menu(self, point):
        # Remove all actions from the tree widget
        # while the context menu is visible
        self.__tree_actions = self.tree.actions()
        for action in self.__tree_actions:
            self.tree.removeAction(action)

        # Create the context menu on the tree widget
        context_menu = QMenu(self)
        context_menu.aboutToHide.connect(self.hide_context_menu)

        # Add action is always visible
        context_menu.addAction(self.add_action)

        # If clicked on an row, offer to delete it
        if self.tree.itemAt(point):
            context_menu.addAction(self.delete_action)

        point = self.tree.mapToGlobal(point)
        context_menu.popup(point)

    def hide_context_menu(self):
        # Restore all actions on the tree widget
        self.tree.addActions(self.__tree_actions)

    def add_expression(self, expression):
        item = QTreeWidgetItem([expression, '', ''])
        item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable
                      | Qt.ItemIsSelectable)
        self.tree.addTopLevelItem(item)

        #  Emit the signal to evaluate the expression
        index = self.tree.indexOfTopLevelItem(item)
        self.expression_added_signal.emit(index, expression)

    def delete_selected(self):
        """Deletes currently selected items from the tree"""
        for item in self.tree.selectedItems():
            index = self.tree.indexOfTopLevelItem(item)
            self.delete_expression(item)
            self.select_next(index)

    def select_next(self, index):
        """Selects the next item after an item has been deleted"""
        prev_item = self.tree.topLevelItem(index - 1)
        next_item = self.tree.topLevelItem(index)

        if prev_item:
            prev_item.setSelected(True)
        elif next_item:
            next_item.setSelected(True)

    def clear_values(self):
        """Deletes values for all expressions"""
        count = self.tree.topLevelItemCount()
        for index in range(0, count):
            item = self.tree.topLevelItem(index)
            item.setData(1, Qt.DisplayRole, '')
            item.setData(2, Qt.DisplayRole, '')
            item.takeChildren()

    def delete_expression(self, item):
        """Deletes the given item from the tree"""
        index = self.tree.indexOfTopLevelItem(item)
        self.tree.takeTopLevelItem(index)

    def get_expressions(self):
        """Returns a list of expressions which are to be evaluated"""
        expressions = []
        for x in range(0, self.tree.topLevelItemCount()):
            expression = self.tree.topLevelItem(x).text(0)
            expressions.append(expression)

        return expressions

    def set_evaluated(self, index, result):
        """Displays an evaluated expression result"""
        type = self.decode_type(result)
        value = self.decode_value(result)

        item = self.tree.topLevelItem(index)
        item.setText(1, type)
        item.setText(2, value)

        variables = result['variables'] if 'variables' in result else []
        self.set_variables(item, variables)

    def set_variables(self, parent, variables):
        """Display an array of variables for the given parent item"""
        for index, variable in enumerate(variables):
            self.set_variable(parent, index, variable)

        # Delete any children which no longer exist
        # Last displayed index should be len(variables) - 1
        index = len(variables)
        while parent.child(index):
            parent.takeChild(index)

    def set_variable(self, parent, index, variable):
        """Display a single variable within the given parent item"""
        name = variable['name']
        type = self.decode_type(variable)
        value = self.decode_value(variable)

        item = parent.child(index)
        if item is None:
            # Item does not exist, create it
            item = QTreeWidgetItem([name, type, value])
            parent.insertChild(index, item)
        else:
            # Item exists, modify it
            item.setData(0, Qt.DisplayRole, name)
            item.setData(1, Qt.DisplayRole, type)
            item.setData(2, Qt.DisplayRole, value)

        # Recurse (we need to go deeper)
        if 'variables' in variable:
            self.set_variables(item, variable['variables'])

    def decode_type(self, result):
        if 'type' not in result:
            return ''

        # Display the class name instead of type for objects
        if result['type'] == 'object':
            return result['classname']

        return result['type']

    def decode_value(self, result):
        value = None

        if 'value' in result:
            value = result['value']

        if 'encoding' in result and value is not None:
            value = base64.b64decode(value)
            try:
                value = value.decode()
            except Exception:
                value = repr(value)

        if result['type'] == 'bool':
            value = 'false' if value == '0' else 'true'

        return value

    def save_state(self):
        """Save current expressions to settings"""
        settings.set_value('expressions_viewer/expressions',
                           self.get_expressions())

    def restore_state(self):
        """Load expressions from settings"""
        expressions = settings.value('expressions_viewer/expressions')

        if type(expressions) is list:
            for expression in expressions:
                self.add_expression(str(expression))

    def handle_add_action(self):
        self.add_expression('$x')
        self.save_state()

    def handle_delete_action(self):
        self.delete_selected()
        self.save_state()

    def handle_item_changed(self, item, column):
        """Called when the user changes an item"""

        # Only check top level items
        if item.parent():
            return

        # Only check changes to the first column which contains the expressions
        if column > 0:
            return

        index = self.tree.indexOfTopLevelItem(item)
        expression = item.text(0)

        self.expression_changed_signal.emit(index, expression)
        self.save_state()
Beispiel #3
0
class SqlConnectionWidget(QWidget):
    """
    Class implementing a widget showing the SQL connections.
    
    @signal tableActivated(str) emitted after the entry for a table has been
        activated
    @signal schemaRequested(str) emitted when the schema display is requested
    @signal cleared() emitted after the connection tree has been cleared
    """
    tableActivated = pyqtSignal(str)
    schemaRequested = pyqtSignal(str)
    cleared = pyqtSignal()
    
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget (QWidget)
        """
        super(SqlConnectionWidget, self).__init__(parent)
        
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        
        self.__connectionTree = QTreeWidget(self)
        self.__connectionTree.setObjectName("connectionTree")
        self.__connectionTree.setHeaderLabels([self.tr("Database")])
        if qVersion() >= "5.0.0":
            self.__connectionTree.header().setSectionResizeMode(
                QHeaderView.Stretch)
        else:
            self.__connectionTree.header().setResizeMode(QHeaderView.Stretch)
        refreshAction = QAction(self.tr("Refresh"), self.__connectionTree)
        self.__schemaAction = QAction(
            self.tr("Show Schema"), self.__connectionTree)
        
        refreshAction.triggered.connect(self.refresh)
        self.__schemaAction.triggered.connect(self.showSchema)
        
        self.__connectionTree.addAction(refreshAction)
        self.__connectionTree.addAction(self.__schemaAction)
        self.__connectionTree.setContextMenuPolicy(Qt.ActionsContextMenu)
        
        layout.addWidget(self.__connectionTree)
        
        self.__activating = False
        
        self.__connectionTree.itemActivated.connect(self.__itemActivated)
        self.__connectionTree.currentItemChanged.connect(
            self.__currentItemChanged)
        
        self.__activeDb = ""
    
    def refresh(self):
        """
        Public slot to refresh the connection tree.
        """
        self.__connectionTree.clear()
        self.cleared.emit()
        
        connectionNames = QSqlDatabase.connectionNames()
        
        foundActiveDb = False
        for name in connectionNames:
            root = QTreeWidgetItem(self.__connectionTree)
            db = QSqlDatabase.database(name, False)
            root.setText(0, self.__dbCaption(db))
            if name == self.__activeDb:
                foundActiveDb = True
                self.__setActive(root)
            if db.isOpen():
                tables = db.tables()
                for table in tables:
                    itm = QTreeWidgetItem(root)
                    itm.setText(0, table)
        
        if not foundActiveDb and connectionNames:
            self.__activeDb = connectionNames[0]
            self.__setActive(self.__connectionTree.topLevelItem(0))
    
    def showSchema(self):
        """
        Public slot to show schema data of a database.
        """
        cItm = self.__connectionTree.currentItem()
        if cItm is None or cItm.parent() is None:
            return
        self.__setActive(cItm.parent())
        self.schemaRequested.emit(cItm.text(0))
    
    def __itemActivated(self, itm, column):
        """
        Private slot handling the activation of an item.
        
        @param itm reference to the item (QTreeWidgetItem)
        @param column column that was activated (integer)
        """
        if itm is None:
            return
        
        if not self.__activating:
            self.__activating = True
            if itm.parent() is None:
                self.__setActive(itm)
            else:
                self.__setActive(itm.parent())
                self.tableActivated.emit(itm.text(0))
            self.__activating = False
    
    def __currentItemChanged(self, current, previous):
        """
        Private slot handling a change of the current item.
        
        @param current reference to the new current item (QTreeWidgetItem)
        @param previous reference to the previous current item
            (QTreeWidgetItem)
        """
        self.__schemaAction.setEnabled(
            current is not None and current.parent() is not None)
    
    def __dbCaption(self, db):
        """
        Private method to assemble a string for the caption.
        
        @param db reference to the database object (QSqlDatabase)
        @return caption string (string)
        """
        nm = db.driverName()
        nm += ":"
        if db.userName():
            nm += db.userName()
            nm += "@"
        nm += db.databaseName()
        return nm
    
    def __setBold(self, itm, bold):
        """
        Private slot to set the font to bold.
        
        @param itm reference to the item to be changed (QTreeWidgetItem)
        @param bold flag indicating bold (boolean)
        """
        font = itm.font(0)
        font.setBold(bold)
        itm.setFont(0, font)
    
    def currentDatabase(self):
        """
        Public method to get the current database.
        
        @return reference to the current database (QSqlDatabase)
        """
        return QSqlDatabase.database(self.__activeDb)
    
    def __setActive(self, itm):
        """
        Private slot to set an item to active.
        
        @param itm reference to the item to set as the active item
            (QTreeWidgetItem)
        """
        for index in range(self.__connectionTree.topLevelItemCount()):
            if self.__connectionTree.topLevelItem(index).font(0).bold():
                self.__setBold(
                    self.__connectionTree.topLevelItem(index), False)
        
        if itm is None:
            return
        
        self.__setBold(itm, True)
        self.__activeDb = QSqlDatabase.connectionNames()[
            self.__connectionTree.indexOfTopLevelItem(itm)]
Beispiel #4
0
class ModelManager(QWidget):
    """
    The main window for MolaQT. It manages optimisation models optionally using an openLCA database.
    """

    def __init__(self, system):
        super().__init__()
        self.system = system

        # model config file
        self.controller_config_file = None

        # workflow for building model
        self.controller = QLabel()

        # db tree
        self.db_tree = QTreeWidget()
        self.db_tree.setHeaderLabels(['Database'])
        self.db_tree.setMinimumWidth(250)
        self.db_tree.itemDoubleClicked.connect(self.load_model)

        # context menu for db tree
        self.db_tree.setContextMenuPolicy(Qt.ActionsContextMenu)
        self.duplicate_model_action = QAction("Duplicate model")
        self.duplicate_model_action.triggered.connect(lambda: self.rename_model(copy=True))
        self.db_tree.addAction(self.duplicate_model_action)
        self.rename_model_action = QAction("Rename model")
        self.rename_model_action.triggered.connect(self.rename_model)
        self.db_tree.addAction(self.rename_model_action)
        self.delete_model_action = QAction("Delete model")
        self.delete_model_action.triggered.connect(self.delete_model)
        self.db_tree.addAction(self.delete_model_action)

        # model configurations that don't use a database
        self.no_db = QTreeWidgetItem(self.db_tree, ['None'])
        self.no_db.setExpanded(True)

        # find the user sqlite databases and add them to db_tree
        self.db_items = {}
        db_files = list(system['data_path'].glob('*.sqlite'))
        for db_file in db_files:
            self.db_items[db_file] = QTreeWidgetItem(self.db_tree, [db_file.stem])
            self.db_items[db_file].setExpanded(True)

        # add each model config to its database item by examining db_file entry
        config_item = []
        for cf in system['config_path'].glob('*.json'):
            with open(str(cf)) as fp:
                config_json = json.load(fp)
            if 'db_file' in config_json and config_json['db_file'] is not None:
                config_db = Path(config_json['db_file'])
                if config_db.exists():
                    config_item.append(QTreeWidgetItem(self.db_items[config_db], [cf.stem]))
            else:
                config_item.append(QTreeWidgetItem(self.no_db, [cf.stem]))

        # arrange widgets in splitter
        box = QHBoxLayout()
        self.splitter = QSplitter()
        self.splitter.addWidget(self.db_tree)
        self.splitter.addWidget(self.controller)
        self.splitter.setStretchFactor(1, 2)
        box.addWidget(self.splitter)

        self.setLayout(box)

    def load_model(self, item, col):
        if self.db_tree.indexOfTopLevelItem(item) == -1:
            config_file = self.system['config_path'].joinpath(item.text(0))
            logging.info('Loading model %s' % config_file)
            self.set_controller(config_file.with_suffix('.json'))

    def new_model(self):
        dialog = md.NewModelDialog(system=self.system, parent=self, db_files=self.db_items.keys())
        if dialog.exec():
            name, specification_class, controller_class, database, doc_file = dialog.get_inputs()
            config_file = self.system['config_path'].joinpath(name + '.json')
            if config_file.exists():
                QMessageBox.about(self, "Error", "Configuration file " + str(config_file.absolute()) +
                                  " already exists")
            else:
                if database:
                    item = QTreeWidgetItem(self.db_items[database], [config_file.stem])
                else:
                    item = QTreeWidgetItem(self.no_db, [config_file.stem])

                self.db_tree.clearSelection()
                item.setSelected(True)

                self.controller_config_file = config_file

                # get a new config dict
                new_config = mqu.get_new_config(specification_class, database, doc_file, controller_class)

                # instantiate controller using config
                new_controller = controller_class(new_config, self.system)

                # open new controller widget
                self.replace_controller(new_controller)

                return config_file

        return None

    def save_model(self):
        try:
            if self.is_model_loaded():
                config = self.controller.get_config()
                with open(str(self.controller_config_file), 'w') as fp:
                    json.dump(config, fp, indent=4)
                self.controller.saved = True

                logging.info('Saved model configuration to %s' % self.controller_config_file)

                return self.controller_config_file
            else:
                logging.info("Nothing to save")

        except Exception as e:
            md.critical_error_box('Critical error', str(e))

        return None

    def close_model(self):
        if self.controller_config_file is not None:
            choice = None
            if not self.controller.saved:
                choice = QMessageBox.question(self, 'Model not saved', "Confirm close?",
                                              QMessageBox.Yes | QMessageBox.No)

            if choice == QMessageBox.Yes or self.controller.saved:
                self.replace_controller(QLabel())
                logging.info('Closed model %s' % self.controller_config_file)
                return True

        return False

    def build_model(self):
        if self.is_model_loaded():
            # TODO: this requires the controller to have a model_build widget and button clicked method
            if hasattr(self.controller, 'model_build') and hasattr(self.controller.model_build, 'build_button_clicked'):
                ok = self.controller.model_build.build_button_clicked()
                return ok

    def run_model(self):
        if self.is_model_loaded():
            # TODO: this requires the controller to have a model_solve widget and button clicked method
            if hasattr(self.controller, 'model_solve') and hasattr(self.controller.model_solve, 'run_button_clicked'):
                ok = self.controller.model_solve.run_button_clicked()
                return ok

    def start_console(self):
        self.qt_console = QtConsoleWindow(manager=self)
        self.qt_console.show()

    def delete_model(self):
        index = self.db_tree.selectedItems()[0]
        if index.parent() is not None:
            db_index = index.parent()
            model_name = index.text(0)
            choice = QMessageBox.question(
                self,
                'Delete model',
                'Confirm delete ' + model_name + ' from ' + db_index.text(0) + '?',
                QMessageBox.Yes | QMessageBox.No
            )
            if choice == QMessageBox.Yes:
                db_index.removeChild(index)
                self.replace_controller(QLabel())
                self.system['config_path'].joinpath(model_name).with_suffix('.json').unlink()
                logging.info("Deleted %s" % model_name)
            else:
                pass

    def rename_model(self, copy=False):
        index = self.db_tree.selectedItems()[0]
        if index.parent() is not None:
            db_index = index.parent()
            model_name = index.text(0)
            dialog = md.RenameModelDialog(current_model_name=model_name, parent=self)
            if dialog.exec():
                old_config_path = self.system['config_path'].joinpath(model_name).with_suffix('.json')
                new_model_name = dialog.new_model_name.text()
                new_config_path = self.system['config_path'].joinpath(new_model_name).with_suffix('.json')
                if new_config_path.exists():
                    QMessageBox.about(self, "Error", "Configuration file " + str(new_config_path.absolute()) +
                                      " already exists")
                elif self.is_model_load() and not self.controller.saved:
                    QMessageBox.about(self, "Error", "Model not saved")
                else:
                    if self.controller is not None:
                        self.replace_controller(QLabel())
                    if copy:

                        new_config_path.write_text(old_config_path.read_text())
                    else:
                        db_index.removeChild(index)
                        old_config_path.rename(new_config_path)
                    qtw = QTreeWidgetItem(db_index, [new_model_name])
                    db_index.addChild(qtw)
                    self.db_tree.clearSelection()
                    qtw.setSelected(True)
                    logging.info('Renamed {} to {}'.format(model_name, dialog.new_model_name.text()))

    def set_controller(self, config_file):
        self.controller_config_file = config_file
        if self.parent() is not None:
            self.parent().setWindowTitle(config_file.stem + ' - molaqt')

        if not config_file.exists():
            logging.error("Cannot find configuration file %s" % config_file)
            return False

        # get configuration
        with open(config_file) as fp:
            user_config = json.load(fp)

        # instantiate controller using config if available otherwise default to StandardController
        if 'controller' in user_config:
            search = re.search("<class '(.*?)\.(.*?)\.(.*?)'>", user_config['controller'])
            class_name = search.group(3)
            class_ = getattr(mc, class_name)
            new_controller = class_(user_config, self.system)
        else:
            new_controller = mc.StandardController(user_config, self.system)

        self.replace_controller(new_controller)
        return True

    def replace_controller(self, new_controller):
        self.controller.deleteLater()  # ensures Qt webengine process gets shutdown
        self.splitter.replaceWidget(1, new_controller)
        self.splitter.update()
        self.splitter.setStretchFactor(1, 2)
        self.controller = new_controller

    def add_database(self, db_path):
        db_item = QTreeWidgetItem(self.db_tree, [db_path.stem])
        self.db_items[db_path] = db_item
        db_item.setSelected(True)

    def is_model_loaded(self):
        return not isinstance(self.controller, QLabel)