def __init__(self): super().__init__() self.setLayout(QVBoxLayout()) vsplit = QSplitter(QtCore.Qt.Vertical) hsplit = QSplitter(QtCore.Qt.Horizontal) self.layout().addWidget(vsplit) self.layout().setMargin(0) self.layout().setSpacing(0) self.unity_area = UnityWidget() self.prop_area = Properties() self.timeline = Timeline() hsplit.addWidget(self.unity_area) hsplit.setCollapsible(0, False) hsplit.addWidget(self.prop_area) hsplit.setStretchFactor(0, 1) hsplit.setSizes([hsplit.width() - 400, 400]) vsplit.addWidget(hsplit) vsplit.setCollapsible(0, False) vsplit.addWidget(self.timeline) vsplit.setStretchFactor(0, 1) vsplit.setSizes([vsplit.height() - 150, 150])
class ManageRelationshipsDialog(AddOrManageRelationshipsDialog): """A dialog to query user's preferences for managing relationships. """ def __init__(self, parent, db_mngr, *db_maps, relationship_class_key=None): """ Args: parent (SpineDBEditor): data store widget db_mngr (SpineDBManager): the manager to do the removal *db_maps: DiffDatabaseMapping instances relationship_class_key (str, optional): relationships class name, object_class name list string. """ super().__init__(parent, db_mngr, *db_maps) self.setWindowTitle("Manage relationships") self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows) self.remove_rows_button.setToolButtonStyle(Qt.ToolButtonIconOnly) self.remove_rows_button.setToolTip( "<p>Remove selected relationships.</p>") self.remove_rows_button.setIconSize(QSize(24, 24)) self.db_map = db_maps[0] self.relationship_ids = dict() layout = self.header_widget.layout() self.db_combo_box = QComboBox(self) layout.addSpacing(32) layout.addWidget(QLabel("Database")) layout.addWidget(self.db_combo_box) self.splitter = QSplitter(self) self.add_button = QToolButton(self) self.add_button.setToolTip( "<p>Add relationships by combining selected available objects.</p>" ) self.add_button.setIcon(QIcon(":/icons/menu_icons/cubes_plus.svg")) self.add_button.setIconSize(QSize(24, 24)) self.add_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.add_button.setText(">>") label_available = QLabel("Available objects") label_existing = QLabel("Existing relationships") self.layout().addWidget(self.header_widget, 0, 0, 1, 4, Qt.AlignHCenter) self.layout().addWidget(label_available, 1, 0) self.layout().addWidget(label_existing, 1, 2) self.layout().addWidget(self.splitter, 2, 0) self.layout().addWidget(self.add_button, 2, 1) self.layout().addWidget(self.table_view, 2, 2) self.layout().addWidget(self.remove_rows_button, 2, 3) self.layout().addWidget(self.button_box, 3, 0, -1, -1) self.hidable_widgets = [ self.add_button, label_available, label_existing, self.table_view, self.remove_rows_button, ] for widget in self.hidable_widgets: widget.hide() self.existing_items_model = MinimalTableModel(self, lazy=False) self.new_items_model = MinimalTableModel(self, lazy=False) self.model.sub_models = [ self.new_items_model, self.existing_items_model ] self.db_combo_box.addItems([db_map.codename for db_map in db_maps]) self.reset_relationship_class_combo_box(db_maps[0].codename, relationship_class_key) self.connect_signals() def make_model(self): return CompoundTableModel(self) def splitter_widgets(self): return [self.splitter.widget(i) for i in range(self.splitter.count())] def connect_signals(self): """Connect signals to slots.""" super().connect_signals() self.db_combo_box.currentTextChanged.connect( self.reset_relationship_class_combo_box) self.add_button.clicked.connect(self.add_relationships) @Slot(str) def reset_relationship_class_combo_box(self, database, relationship_class_key=None): self.db_map = self.keyed_db_maps[database] self.relationship_class_keys = list( self.db_map_rel_cls_lookup[self.db_map]) self.rel_cls_combo_box.addItems( [f"{name}" for name, _ in self.relationship_class_keys]) try: current_index = self.relationship_class_keys.index( relationship_class_key) self.reset_model(current_index) self._handle_model_reset() except ValueError: current_index = -1 self.rel_cls_combo_box.setCurrentIndex(current_index) @Slot(bool) def add_relationships(self, checked=True): object_names = [[item.text(0) for item in wg.selectedItems()] for wg in self.splitter_widgets()] candidate = list(product(*object_names)) existing = self.new_items_model._main_data + self.existing_items_model._main_data to_add = list(set(candidate) - set(existing)) count = len(to_add) self.new_items_model.insertRows(0, count) self.new_items_model._main_data[0:count] = to_add self.model.refresh() @Slot(int) def reset_model(self, index): """Setup model according to current relationship_class selected in combobox. """ self.class_name, self.object_class_name_list = self.relationship_class_keys[ index] object_class_name_list = self.object_class_name_list.split(",") self.model.set_horizontal_header_labels(object_class_name_list) self.existing_items_model.set_horizontal_header_labels( object_class_name_list) self.new_items_model.set_horizontal_header_labels( object_class_name_list) self.relationship_ids.clear() for db_map in self.db_maps: relationship_classes = self.db_map_rel_cls_lookup[db_map] rel_cls = relationship_classes.get( (self.class_name, self.object_class_name_list), None) if rel_cls is None: continue for relationship in self.db_mngr.get_items_by_field( db_map, "relationship", "class_id", rel_cls["id"]): key = tuple(relationship["object_name_list"].split(",")) self.relationship_ids[key] = relationship["id"] existing_items = list(self.relationship_ids) self.existing_items_model.reset_model(existing_items) self.model.refresh() self.model.modelReset.emit() for wg in self.splitter_widgets(): wg.deleteLater() for name in object_class_name_list: tree_widget = QTreeWidget(self) tree_widget.setSelectionMode(QAbstractItemView.ExtendedSelection) tree_widget.setColumnCount(1) tree_widget.setIndentation(0) header_item = QTreeWidgetItem([name]) header_item.setTextAlignment(0, Qt.AlignHCenter) tree_widget.setHeaderItem(header_item) objects = self.db_mngr.get_items_by_field(self.db_map, "object", "class_name", name) items = [QTreeWidgetItem([obj["name"]]) for obj in objects] tree_widget.addTopLevelItems(items) tree_widget.resizeColumnToContents(0) self.splitter.addWidget(tree_widget) sizes = [wg.columnWidth(0) for wg in self.splitter_widgets()] self.splitter.setSizes(sizes) for widget in self.hidable_widgets: widget.show() def resize_window_to_columns(self, height=None): table_view_width = (self.table_view.frameWidth() * 2 + self.table_view.verticalHeader().width() + self.table_view.horizontalHeader().length()) self.table_view.setMinimumWidth(table_view_width) self.table_view.setMinimumHeight( self.table_view.verticalHeader().defaultSectionSize() * 16) margins = self.layout().contentsMargins() if height is None: height = self.sizeHint().height() self.resize( margins.left() + margins.right() + table_view_width + self.add_button.width() + self.splitter.width(), height, ) @Slot() def accept(self): """Collect info from dialog and try to add items.""" keys_to_remove = set(self.relationship_ids) - set( self.existing_items_model._main_data) to_remove = [self.relationship_ids[key] for key in keys_to_remove] self.db_mngr.remove_items({self.db_map: {"relationship": to_remove}}) to_add = [[self.class_name, object_name_list] for object_name_list in self.new_items_model._main_data] self.db_mngr.import_data({self.db_map: { "relationships": to_add }}, command_text="Add relationships") super().accept()
class FileSystemWidget(QWidget): def __init__(self, parent, *args, **kwargs): super().__init__(*args, **kwargs) self.currentRootPath = '/' self.currentPath = QDir.currentPath() self.mainWindow = parent self.chooseDirAction = QAction(IconFactory.getIcon('folder'), 'Root directory', self, statusTip="Change root directory", triggered=self.chooseRootDir) self.showOFAction = QAction(IconFactory.getIcon('filter_alt'), 'Show only FITS files', self, statusTip="Show only FITS/all files", triggered=self.showOFFiles) self.showOFAction.setCheckable(True) self.showOFAction.toggled.connect(self.showOFFiles) self.chooseDirBtn = QToolButton() self.chooseDirBtn.setDefaultAction(self.chooseDirAction) self.showOFBtn = QToolButton() self.showOFBtn.setDefaultAction(self.showOFAction) iconlayout = QHBoxLayout() iconlayout.setAlignment(Qt.AlignLeft) iconlayout.addWidget(self.chooseDirBtn) iconlayout.addWidget(self.showOFBtn) self.viewsSplitter = QSplitter(Qt.Horizontal) self.viewsSplitter.splitterMoved.connect(self.splitterMoved) self.dirsModel = QFileSystemModel(self) self.dirsModel.setOption(QFileSystemModel.DontWatchForChanges, True) self.dirsModel.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs) self.dirsModel.setNameFilterDisables(False) self.dirs = QTreeView() self.dirs.setModel(self.dirsModel) self.dirs.hideColumn(1) self.dirs.hideColumn(2) self.dirs.hideColumn(3) self.dirs.clicked.connect(self.onDirsClick) self.dirs.doubleClicked.connect(self.onDirsDoubleClick) self.filesModel = QFileSystemModel(self) self.filesModel.setOption(QFileSystemModel.DontWatchForChanges, True) self.filesModel.setFilter(QDir.NoDotAndDotDot | QDir.Files) self.filesModel.setNameFilterDisables(False) self.files = QListView() self.files.setModel(self.filesModel) self.files.doubleClicked.connect(self.onFilesDoubleClick) self.viewsSplitter.addWidget(self.dirs) self.viewsSplitter.addWidget(self.files) viewslayout = QHBoxLayout() viewslayout.addWidget(self.viewsSplitter) layout = QVBoxLayout() layout.addLayout(iconlayout) layout.addLayout(viewslayout) self.setLayout(layout) self.dirsModel.setRootPath(self.currentRootPath) self.dirs.setRootIndex(self.dirsModel.index(self.currentRootPath)) index = self.dirsModel.index(self.currentPath) self.dirs.setCurrentIndex(index) self.dirs.setExpanded(index, True) self.filesModel.setRootPath(self.currentPath) self.files.setRootIndex(self.filesModel.index(self.currentPath)) def splitterMoved(self, pos, index): if pos == 0: self.filesModel.setFilter(QDir.NoDot | QDir.AllEntries | QDir.DirsFirst | QDir.Type) elif pos == self.viewsSplitter.width( ) - self.viewsSplitter.handleWidth(): self.dirsModel.setFilter(QDir.NoDotAndDotDot | QDir.AllEntries) else: self.dirsModel.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs) self.filesModel.setFilter(QDir.NoDotAndDotDot | QDir.Files) def onDirsClick(self, item): index = self.dirs.selectedIndexes()[0] info = self.dirsModel.fileInfo(index) if info.isDir(): self.currentPath = info.filePath() self.files.setRootIndex( self.filesModel.setRootPath(info.filePath())) def onDirsDoubleClick(self, item): index = self.dirs.selectedIndexes()[0] info = self.dirsModel.fileInfo(index) if info.isDir(): self.currentPath = info.filePath() self.files.setRootIndex( self.filesModel.setRootPath(info.filePath())) else: self.mainWindow.open_fits(info.filePath()) def onFilesDoubleClick(self, item): index = self.files.selectedIndexes()[0] info = self.filesModel.fileInfo(index) if info.isDir(): self.setPath(info.filePath()) else: try: self.mainWindow.open_fits(info.filePath()) except FileNotFoundError: self.setPath(self.currentPath) # refesh maybe? def setPath(self, path): self.currentPath = path index = self.dirsModel.index(self.currentPath) self.dirs.setCurrentIndex(index) self.dirs.setExpanded(index, True) self.files.setRootIndex(self.filesModel.setRootPath(self.currentPath)) def chooseRootDir(self): dir = QFileDialog.getExistingDirectory(self, 'Select directory') if dir: self.setRootPath(dir) def setRootPath(self, dir): self.currentRootPath = dir self.dirsModel.setRootPath(self.currentRootPath) self.dirs.setRootIndex(self.dirsModel.index(self.currentRootPath)) self.setPath(self.currentRootPath) def showOFFiles(self): if self.showOFAction.isChecked(): self.dirsModel.setNameFilters(["*.FITS", "*.fits"]) self.filesModel.setNameFilters(["*.FITS", "*.fits"]) else: self.dirsModel.setNameFilters(["*"]) self.filesModel.setNameFilters(["*"]) def writeSettings(self, settings): settings.beginGroup("fileWidget") settings.setValue('splitterGeometry', self.viewsSplitter.saveGeometry()) settings.setValue('splitterState', self.viewsSplitter.saveState()) settings.setValue('rootPath', self.currentRootPath) settings.setValue('path', self.currentPath) settings.endGroup() def readSettings(self, settings): settings.beginGroup("fileWidget") self.viewsSplitter.restoreGeometry(settings.value("splitterGeometry")) self.viewsSplitter.restoreState(settings.value("splitterState")) rootPath = settings.value("rootPath") path = settings.value("path") settings.endGroup() if rootPath is None: rootPath = '/' self.setRootPath(rootPath) if path is None: path = QDir.currentPath() self.setPath(path) self.splitterMoved(self.viewsSplitter.handle(1).pos().x(), 0)