import os from PyQt5.QtWidgets import QComboBox, QFrame, QGroupBox, QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QSplitter, QStackedLayout, QAbstractItemView, QTextEdit, QVBoxLayout, QWidget, QGridLayout from PyQt5.QtGui import QPixmap from PyQt5.QtCore import QItemSelectionModel, Qt, QSettings, pyqtSignal from nixview.file_handler import FileHandler, ItemDescriptor from nixview.plot_screen import PlotScreen import nixview.communicator as comm import nixview.constants as cnst from nixview.tree_model import NixTreeView, TreeModel, TreeType class CentralWidget(QWidget): def __init__(self, parent=None) -> None: super().__init__(parent=parent) self._splash = SplashScreen() self._file_view = FileView(self) self._plot_screen = PlotScreen(self) self._plot_screen.close_signal.connect(self.on_plot_close) self._stack = QStackedLayout(self) self._stack.addWidget(self._splash) self._stack.addWidget(self._file_view) self._stack.addWidget(self._plot_screen) self.setLayout(self._stack) def show_file_content(self): self._stack.setCurrentIndex(1) self._file_view.update() def plot_item(self, item): self._stack.setCurrentIndex(2) self._plot_screen.plot(item) def on_plot_close(self): self._stack.setCurrentIndex(1) def reset(self): self._file_view.reset() self._splash.reset() self._stack.setCurrentIndex(0) class FileView(QWidget): def __init__(self, parent=None) -> None: super().__init__(parent=parent) self._file_handler = FileHandler() vbox = QVBoxLayout() self.setLayout(vbox) main_splitter = QSplitter(Qt.Vertical) self.layout().addWidget(main_splitter) self._info = EntityInfo(self) main_splitter.addWidget(self._info) self._data_tree = NixTreeView(self) self._tree_type_combo = QComboBox() self._tree_type_combo.adjustSize() self._tree_type_combo.addItems([TreeType.Data.value, TreeType.Full.value, TreeType.Metadata.value]) self._tree_type_combo.currentTextChanged.connect(self.update) hbox = QHBoxLayout() hbox.addWidget(QLabel("Tree type:")) hbox.addWidget(self._tree_type_combo) hbox.addStretch() data_group = QGroupBox("Data") data_vbox = QVBoxLayout() data_vbox.setContentsMargins(1, 10, 1, 1) data_vbox.addLayout(hbox) data_vbox.addWidget(self._data_tree) data_group.setLayout(data_vbox) main_splitter.addWidget(data_group) main_splitter.setSizes([200, 600]) vbox.addWidget(main_splitter) def dataTreeSelection(self, current_index, last_index): if not current_index.isValid(): return item = current_index.internalPointer() comm.communicator.item_selected.emit(item) self._info.setEntityInfo(item.node_descriptor) def update(self): tt = TreeType.Data if self._tree_type_combo.currentText() == TreeType.Data.value: tt = TreeType.Data elif self._tree_type_combo.currentText() == TreeType.Full.value: tt = TreeType.Full elif self._tree_type_combo.currentText() == TreeType.Metadata.value: tt = TreeType.Metadata self._info.setEntityInfo(None) data_model = TreeModel(self._file_handler, tt) self._data_tree.setModel(data_model) selection_model = QItemSelectionModel(data_model) self._data_tree.setSelectionModel(selection_model) selection_model.currentChanged.connect(self.dataTreeSelection) for i in range(data_model.columnCount(None)): self._data_tree.resizeColumnToContents(i) self._info.setFileInfo(self._file_handler.file_descriptor) def reset(self): pass class EntityInfo(QWidget): def __init__(self, parent): super().__init__(parent=parent) self._file_handler = FileHandler() self.setLayout(QHBoxLayout()) self._metadata_tree = NixTreeView() mdata_grp = QGroupBox("Metadata") mdata_grp.setLayout(QVBoxLayout()) mdata_grp.layout().setContentsMargins(1, 10, 1, 1) mdata_grp.layout().addWidget(self._metadata_tree) file_info_grp = QGroupBox("File info") file_info_grp.setLayout(QVBoxLayout()) file_info_grp.layout().setContentsMargins(1, 10, 1, 1) self._file_info = QTextEdit("File information") self._file_info.setEnabled(True) self._file_info.setTextInteractionFlags(Qt.TextSelectableByKeyboard | Qt.TextSelectableByMouse) self._file_info.setFrameShape(QFrame.NoFrame) self._file_info.setLineWrapMode(QTextEdit.WidgetWidth) file_info_grp.layout().addWidget(self._file_info) entity_info_grp = QGroupBox("Entity info") entity_info_grp.setLayout(QVBoxLayout()) entity_info_grp.layout().setContentsMargins(1, 10, 1, 1) self._entity_info = QTextEdit("Entity information") self._file_info.setEnabled(True) self._file_info.setTextInteractionFlags(Qt.TextSelectableByKeyboard | Qt.TextSelectableByMouse) self._file_info.setFrameShape(QFrame.NoFrame) self._file_info.setLineWrapMode(QTextEdit.WidgetWidth) entity_info_grp.layout().addWidget(self._entity_info) self._splitter = QSplitter(Qt.Horizontal) self._splitter.addWidget(file_info_grp) self._splitter.addWidget(entity_info_grp) self._splitter.addWidget(mdata_grp) self._splitter.setSizes([200, 400, 0]) self._splitter.setStretchFactor(0, 0) self._splitter.setStretchFactor(1, 1) self._splitter.setStretchFactor(2, 1) self.layout().addWidget(self._splitter) def setFileInfo(self, file_info): if file_info is not None: self._file_info.setText(file_info.toHtml()) def setEntityInfo(self, entity_info): if entity_info is None or not isinstance(entity_info, ItemDescriptor): self._splitter.setSizes([200, 400, 0]) self._entity_info.setText("") self._metadata_tree.setModel(None) return if entity_info.metadata_id is not None: self._splitter.setSizes([200, 400, 400]) else: self._splitter.setSizes([200, 400, 0]) self._entity_info.setText(entity_info.to_html()) metadata_model = TreeModel(self._file_handler, TreeType.Metadata, root_section_id=entity_info.metadata_id) self._metadata_tree.setModel(metadata_model) for i in range(metadata_model.columnCount(None)): self._metadata_tree.resizeColumnToContents(i) class SplashScreen(QWidget): keyPressed = pyqtSignal(int) def __init__(self, parent=None) -> None: super().__init__(parent=parent) #self.setStyleSheet("background-color: white;") layout = QGridLayout() layout.setColumnStretch(0, 2) layout.setColumnStretch(1, 1) layout.setColumnStretch(2, 1) layout.setColumnStretch(3, 1) layout.setColumnStretch(4, 2) layout.setRowStretch(0, 1) layout.setRowStretch(1, 0) layout.setRowStretch(2, 1) layout.setRowStretch(3, 2) self.setLayout(layout) label = QLabel() label.setPixmap(QPixmap(os.path.join(cnst.ICONS_FOLDER, "nixview_transparent.png"))) label.setMaximumWidth(300) label.setAlignment(Qt.AlignCenter) layout.addWidget(label, 1, 1, 1, 3, Qt.AlignCenter) frame = QFrame() l = QVBoxLayout() l.addWidget(QLabel("Recently opened files:")) self._file_list = QListWidget(self) self._file_list.setSelectionMode(QAbstractItemView.SingleSelection) self._file_list.itemClicked.connect(self._on_file_clicked) self._file_list.setFrameShape(QFrame.NoFrame) self.keyPressed.connect(self._on_key_pressed) l.addWidget(self._file_list) frame.setLayout(l) layout.addWidget(frame, 3, 1, 1, 3) self._file_map = {} self._read_recent_files() def keyPressEvent(self, event): super(SplashScreen, self).keyPressEvent(event) if event.key() == Qt.Key_Return: self.keyPressed.emit(event.key()) def _create_short_filename(self, original, index, max_len=40): short = original parts = original.split(os.sep) if len(parts) == 1: short = "%i: %s" % (index, short[:max_len]) else: post = parts[-1] if len(post) > max_len - 4: post = post[:max_len - 4] short = str("%i: " % index) + "... " + post else: short = str("%i: " % index) + " ... ".join([original[:max_len - len(post) - 4], post]) return short def _read_recent_files(self): settings = QSettings(cnst.organization, cnst.application) filenames = settings.value(cnst.settings_recent_files_key, []) del settings for i, f in enumerate(filenames): shortname = self._create_short_filename(f, i + 1, max_len=38) self._file_map[shortname] = f item = QListWidgetItem(shortname) item.setToolTip(f) self._file_list.addItem(item) def reset(self): self._file_list.clear() self._read_recent_files() def _on_file_clicked(self, item): comm.communicator.open_recent.emit(self._file_map[item.text()]) def _on_key_pressed(self, key): item = self._file_list.currentItem() if item is not None and key == Qt.Key_Return: comm.communicator.open_recent.emit(self._file_map[item.text()])