def _create_terminal(self): assert self._terminal is None, \ "should only call _create_terminal once" self._terminal_button = QToolButton(None) self._terminal_button.setToolTip("Toggle command line") self._ui.layerWidget.button_row.addWidget(self._terminal_button) self._terminal_button.setArrowType(Qt.DownArrow) try: from .widgets.terminal import glue_terminal widget = glue_terminal(data_collection=self._data, dc=self._data, hub=self._hub, **vars(env)) self._terminal_button.clicked.connect(self._toggle_terminal) except Exception as e: # pylint: disable=W0703 import traceback self._terminal_exception = traceback.format_exc() self._setup_terminal_error_dialog(e) return splitter = QSplitter(self) splitter.setOrientation(Qt.Vertical) splitter.addWidget(self._ui.centralwidget) splitter.addWidget(widget) splitter.setStretchFactor(0, 5) splitter.setStretchFactor(1, 1) self.setCentralWidget(splitter) self._terminal = widget self._hide_terminal()
def _initMainWidget(self): split = QSplitter(Qt.Horizontal, self) split.addWidget(self._peerList) split.addWidget(self._historyTable) split.setStretchFactor(0, 0) split.setStretchFactor(1, 1) return split
def __setup_ui(self): self.resize(1024, 768) self.__setup_menu() split = QSplitter() self.__mib_tree_widget = MibTreeWidget() split.addWidget(self.__mib_tree_widget) # self.__data_widget = DataWidget() split.addWidget(self.__data_widget) split.setHandleWidth(2) split.setStretchFactor(0, 1) split.setStretchFactor(1, 200) la = QVBoxLayout() self.__progress_bar = QProgressBar() self.__progress_bar.setValue(0) self.__progress_bar.setVisible(False) la.addWidget(self.__progress_bar, 1) la.addWidget(split, 1) cw = QWidget() cw.setLayout(la) self.setCentralWidget(cw)
def _create_central_widget(self): tabs = QTabWidget() splitter = QSplitter() self.treeview = QTreeView() self.treeview.header().hide() self.treeview.resize(500, 0) splitter.addWidget(self.treeview) self.editwidget = QWidget() self.editwidget.setLayout(QVBoxLayout()) self.editwidget.resize(300, 300) self.editwidget.setMinimumSize(300, 100) splitter.addWidget(self.editwidget) self.glwidget = GLWidget() splitter.addWidget(self.glwidget) splitter.setStretchFactor(0, 2) splitter.setStretchFactor(1, 2) splitter.setStretchFactor(2, 4) tabs.addTab(splitter, "Mesh") tabs.addTab(self._create_run(), "Run") self.setCentralWidget(tabs)
class PostProcessConfigWidget(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.tree = PostProcessModulesTreeWidget() self.config = PostProcessModulesConfig() self.connect(self.tree, SIGNAL("moduleClicked"), self.config.update) self.connect(self.tree, SIGNAL("moduleStateChanged"), self.config.updateState) sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.MinimumExpanding) sizePolicy.setVerticalStretch(1) self.setSizePolicy(sizePolicy) layout = QHBoxLayout() layout.setMargin(0) self.__splitter = QSplitter(Qt.Horizontal, self) layout.addWidget(self.__splitter) self.__splitter.addWidget(self.tree) self.__splitter.addWidget(self.config) self.__splitter.setStretchFactor(0, 0) self.__splitter.setStretchFactor(1, 80) self.setLayout(layout) def fillFromAnalyse(self): TaskManager().addAnalyseDependencies() self.tree.update()
def _initMainWidget(self): split = QSplitter(Qt.Horizontal, self) split.addWidget(self._actionList) split.addWidget(self._settingsWidget) split.setStretchFactor(0, 0) split.setStretchFactor(1, 1) return split
def createWidget(self): """ Create the widget """ self.diagramScene = QGraphicsScene(self) self.view = QGraphicsView(self.diagramScene) self.view.setRenderHint(QPainter.Antialiasing) # set the main layout layout = QVBoxLayout() self.logEdit = QTextEdit() self.logEdit.setReadOnly(True) hSplitter2 = QSplitter(self) hSplitter2.setOrientation(Qt.Vertical) hSplitter2.addWidget(self.view) hSplitter2.addWidget(self.logEdit) hSplitter2.setStretchFactor(0, 1) layout.addWidget(hSplitter2) self.setLayout(layout)
class Help(QDockWidget): def __init__(self, parent=None, path=None): QDockWidget.__init__(self, parent) self.name = self.tr("Help") self.setFloating(False) self.setFeatures(QDockWidget.NoDockWidgetFeatures) self.__mainWidget = QSplitter(Qt.Horizontal) self.__uname = QWidget() mainWidgetLayout = QVBoxLayout(self.__uname) mainWidgetLayout.setContentsMargins(0, 0, 0, 0) # create helper + search engine self.__helper = QHelpEngine(path, self) if not self.__helper.setupData() is True: dialog = QMessageBox() msg = QString(self.tr("An error occurred while setting help engine up :\n")) msg += (self.__helper.error() + "\n") msg += self.tr("It might mean that the format of your help file is not correct.\n") msg += self.tr("You can check on-line help at http://wiki.digital-forensic.org") dialog.setText(msg) dialog.setIcon(QMessageBox.Warning) dialog.setWindowTitle(self.tr("Error while loading help")) dialog.exec_() return self.__toc = self.__helper.contentWidget() self.__helpBrowser = HelpBrowser(self.__helper) # build main widget self.__toolbar = QWidget() self.__toolbarLayout = QHBoxLayout(self.__toolbar) home = QPushButton(QIcon(":home.png"), "") previous = QPushButton(QIcon(":previous.png"), "") next = QPushButton(QIcon(":next.png"), "") # building toolbar self.__toolbarLayout.addWidget(home) self.__toolbarLayout.addWidget(previous) self.__toolbarLayout.addWidget(next) self.__toolbarLayout.setContentsMargins(0, 0, 0, 0) mainWidgetLayout.addWidget(self.__toolbar) mainWidgetLayout.addWidget(self.__helpBrowser) self.__mainWidget.insertWidget(0, self.__toc) self.__mainWidget.insertWidget(1, self.__uname) self.__mainWidget.setStretchFactor(1, 1) self.setWidget(self.__mainWidget) #connecting `previous`, `home` and `next` buttons self.connect(next, SIGNAL("clicked(bool)"), self.__helpBrowser.nextPage) self.connect(previous, SIGNAL("clicked(bool)"), self.__helpBrowser.prevPage) self.connect(home, SIGNAL("clicked(bool)"), self.__helpBrowser.goHome) self.connect(self.__helper.contentWidget(), SIGNAL("linkActivated(const QUrl &)"), self.__helpBrowser.setSource)
def setupViews(self): splitter = QSplitter() self.setupTaskTable() splitter.addWidget(self.taskTableWidget) self.taskViewWidget = taskviewwidget.TaskViewWidget() splitter.addWidget(self.taskViewWidget) splitter.setStretchFactor(0, 0) splitter.setStretchFactor(1, 1) self.setCentralWidget(splitter) self.taskViewWidget.hide() self.msgLabel = QLabel() self.statusBar().addWidget(self.msgLabel)
def setupViews(self): splitter = QSplitter() self.setupTaskTable() splitter.addWidget(self.taskTableWidget) self.taskViewWidget = taskviewwidget.TaskViewWidget() splitter.addWidget(self.taskViewWidget) splitter.setStretchFactor(0, 0) splitter.setStretchFactor(1, 1) self.setCentralWidget(splitter) self.taskViewWidget.hide() self.msgLabel = QLabel() self.statusBar().addWidget(self.msgLabel)
def __setup_ui(self): self.resize(1024, 768) self.__setup_menu() split = QSplitter() self.__yt_tree_widget = YtTreeWidget() split.addWidget(self.__yt_tree_widget) self.__data_widget = DataWidget() split.addWidget(self.__data_widget) split.setHandleWidth(2) split.setStretchFactor(0, 1) split.setStretchFactor(1, 200) self.setCentralWidget(split)
def createWidgets(self): """ QtWidgets creation _______________________ | | | PyEditor | |_______________________| |________QSplitter______| | | | PyEditor | |_______________________| """ self.srcWidget = EditorWidget( self.TEST_DEF_EDITOR, "Test Definition:", self, wrappingText=QtHelper.str2bool( Settings.instance().readValue(key='Editor/code-wrapping'))) self.execWidget = EditorWidget( self.TEST_EXEC_EDITOR, "Test Execution:", self, wrappingText=QtHelper.str2bool( Settings.instance().readValue(key='Editor/code-wrapping')), toolbar=False) self.srcEditor = self.srcWidget.editor self.execEditor = self.execWidget.editor layout = QVBoxLayout() hSplitter = QSplitter(self) hSplitter.setOrientation(Qt.Vertical) hSplitter.addWidget(self.srcWidget) hSplitter.addWidget(self.execWidget) hSplitter.setContentsMargins(0, 0, 0, 0) hSplitter.setStretchFactor(0, 1) layout.addWidget(hSplitter) layout.setContentsMargins(2, 0, 0, 0) self.setLayout(layout)
class NetWorthView(AccountSheetView): def _setup(self): self._setupUi() self.sheet = self.nwsheet = NetWorthSheet(self.model.bsheet, view=self.treeView) self.graph = self.nwgraph = Chart(self.model.nwgraph, view=self.graphView) self.piechart = Chart(self.model.pie, view=self.pieChart) def _setupUi(self): self.resize(558, 447) self.mainLayout = QVBoxLayout(self) self.mainLayout.setSpacing(0) self.mainLayout.setMargin(0) self.splitterView = QSplitter() self.splitterView.setChildrenCollapsible(False) self.splitterView.setOrientation(Qt.Vertical) self.subSplitterView = QSplitter() self.subSplitterView.setChildrenCollapsible(False) self.treeView = TreeView(self) self.treeView.setAcceptDrops(True) self.treeView.setFrameShape(QFrame.NoFrame) self.treeView.setFrameShadow(QFrame.Plain) self.treeView.setEditTriggers(QAbstractItemView.EditKeyPressed|QAbstractItemView.SelectedClicked) self.treeView.setDragEnabled(True) self.treeView.setDragDropMode(QAbstractItemView.InternalMove) self.treeView.setUniformRowHeights(True) self.treeView.setAllColumnsShowFocus(True) self.treeView.setSelectionMode(QAbstractItemView.ExtendedSelection) self.treeView.header().setStretchLastSection(False) self.subSplitterView.addWidget(self.treeView) self.pieChart = PieChartView(self) self.pieChart.setMinimumSize(300, 0) self.subSplitterView.addWidget(self.pieChart) self.splitterView.addWidget(self.subSplitterView) self.graphView = LineGraphView(self) self.graphView.setMinimumSize(0, 200) self.splitterView.addWidget(self.graphView) self.splitterView.setStretchFactor(0, 1) self.splitterView.setStretchFactor(1, 0) self.subSplitterView.setStretchFactor(0, 1) self.subSplitterView.setStretchFactor(1, 0) self.mainLayout.addWidget(self.splitterView)
def g_display(self): QWidget.__init__(self) layout = QHBoxLayout(self) splitter = QSplitter() layout.addWidget(splitter) splitter.setOrientation(Qt.Horizontal) if self.node is not None: processus_manager = ModuleProcessusManager() evt = processus_manager.get('evt') if not self.preview: self.evtWidget = evt.getAllEvtFiles() if self.evtWidget: splitter.addWidget(self.evtWidget) splitter.setStretchFactor(1, 2) else: self.evtWidget = evt.previewWidget(long(self.node.this)) if self.evtWidget: splitter.addWidget(self.evtWidget)
class StatusBarWidget(QWidget): SplitterHandleStyle = """QSplitter::handle:horizontal {background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #eee, stop:1 #ccc); border: 1px solid #777; width: 14px; margin-right: 4px; margin-left: 4px;}""" def __init__(self, parent=None): super(QWidget, self).__init__(parent) sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(1) self.setSizePolicy(sizePolicy) self.__hlayout = QHBoxLayout(self) self.__hlayout.setSpacing(6) self.__hlayout.setSizeConstraint(QLayout.SetMinimumSize) self.__hlayout.setMargin(0) self.__splitter = QSplitter(Qt.Horizontal, parent) self.__splitter.setHandleWidth(12) self.__hlayout.addWidget(self.__splitter) def addStatusWidget(self, widget, stretch): self.__splitter.setStyleSheet(StatusBarWidget.SplitterHandleStyle) self.__splitter.addWidget(widget) idx = self.__splitter.indexOf(widget) self.__splitter.setStretchFactor(idx, stretch)
def setup_layout(self): outer_layout = QVBoxLayout() outer_layout.addWidget(self.menu_bar) outer_layout.setStretch(0, 1) h_splitter = QSplitter(self) h_splitter.setOrientation(Qt.Horizontal) # FIRST COLUMN of h_splitter is chromatogram + peakmap: ############################ v_splitter1 = QSplitter(self) v_splitter1.setOrientation(Qt.Vertical) v_splitter1.addWidget(self.eic_plotter) v_splitter1.addWidget(self.peakmap_plotter) self.peakmap_plotter.setMinimumSize(250, 200) v_splitter1.setStretchFactor(0, 1) v_splitter1.setStretchFactor(1, 3) h_splitter.addWidget(v_splitter1) h_splitter.setStretchFactor(0, 2) # SECOND COLUMN of h_splittier holds controlx boxes + mz plot ####################### v_splitter2 = QSplitter(self) v_splitter2.setOrientation(Qt.Vertical) v_splitter2.addWidget(self.image_scaling_widget) v_splitter2.addWidget(self.spectra_selector_widget) v_splitter2.addWidget(self.view_range_widget) v_splitter2.addWidget(self.history_list) v_splitter2.addWidget(self.mz_plotter) v_splitter2.setStretchFactor(0, 0) v_splitter2.setStretchFactor(1, 0) v_splitter2.setStretchFactor(2, 0) v_splitter2.setStretchFactor(3, 0) v_splitter2.setStretchFactor(4, 1) h_splitter.addWidget(v_splitter2) h_splitter.setStretchFactor(1, 1) # THIRD COLUMN of h_splittier holds control table + buttons ########################## if self.table: frame = QFrame(self) layout = QVBoxLayout(frame) frame.setLayout(layout) layout.addWidget(self.table_widget) button_row_layout = QHBoxLayout(frame) button_row_layout.addWidget(self.select_all_peaks) button_row_layout.addWidget(self.unselect_all_peaks) button_row_layout.addWidget(self.done_button) layout.addLayout(button_row_layout) h_splitter.addWidget(frame) h_splitter.setStretchFactor(2, 2) outer_layout.addWidget(h_splitter) self.setLayout(outer_layout) outer_layout.setStretch(1, 99)
class Window(QMainWindow): def __init__(self): super(Window, self).__init__() central_widget = QWidget() self._current_path = None self._use_suffix = False self._file_model = QFileSystemModel() self._file_model.setNameFilters(['*.jpg', '*.png']) self._file_model.setNameFilterDisables(False) self._file_model.setRootPath(QDir.rootPath()) self._file_selection_model = QItemSelectionModel(self._file_model) self._file_selection_model.currentChanged.connect(self._on_current_file_changed) self._file_tree = QTreeView(parent=self) self._file_tree.collapsed.connect(self._on_tree_expanded_collapsed) self._file_tree.expanded.connect(self._on_tree_expanded_collapsed) self._file_tree.setModel(self._file_model) self._file_tree.setSelectionModel(self._file_selection_model) self._file_tree.setColumnHidden(1, True) self._file_tree.setColumnHidden(2, True) self._file_tree.setColumnHidden(3, True) self._file_tree.header().hide() self._viewer = Viewer(Loader(24)) self._splitter = QSplitter(); self._splitter.addWidget(self._file_tree) self._splitter.addWidget(self._viewer) self._splitter.setStretchFactor(0, 0) self._splitter.setStretchFactor(1, 1) self._splitter.setCollapsible(0, False) self._layout = QGridLayout() self._layout.addWidget(self._splitter) self._switch_to_normal() central_widget.setLayout(self._layout) self._file_tree.installEventFilter(self); self.resize(800, 600) self.setWindowTitle('pyQtures') self.setCentralWidget(central_widget) self.show() def eventFilter(self, widget, event): if event.type() == QEvent.KeyPress: if event.key() == Qt.Key_Tab: self._toggle_path_suffix() return True return QMainWindow.eventFilter(self, widget, event) def _toggle_path_suffix(self): self._use_suffix = not self._use_suffix self._update_path() def _switch_to_fullscreen(self): self._splitter.widget(0).hide() self._layout.setMargin(0) self.showFullScreen() def _switch_to_normal(self): self._splitter.widget(0).show() self._layout.setMargin(4) self.showNormal() def keyPressEvent(self, key_event): # Signal handler. key = key_event.key() if self.isFullScreen(): self._full_screen_key_handler(key) else: self._normal_key_handler(key) def _full_screen_key_handler(self, key): if Qt.Key_Escape == key: self._switch_to_normal() elif Qt.Key_Return == key: self._switch_to_normal() elif Qt.Key_Up == key: self._go_to_sibling_image(-1) elif Qt.Key_Down == key: self._go_to_sibling_image(1) elif Qt.Key_Tab == key: self._toggle_path_suffix() def _go_to_sibling_image(self, offset): current = self._file_selection_model.currentIndex() nxt = current.sibling(current.row() + offset, current.column()) if (nxt.parent() != current.parent()): return # TODO(eustas): Iterate through dirs? self._file_selection_model.setCurrentIndex(nxt, QItemSelectionModel.SelectCurrent) def _normal_key_handler(self, key): if Qt.Key_Escape == key: QCoreApplication.instance().quit() elif Qt.Key_Return == key: self._switch_to_fullscreen() def _on_current_file_changed(self, new_current): new_path = self._file_model.filePath(new_current) if not self._current_path == new_path: self._current_path = new_path self._update_path() def _update_path(self): if not self._use_suffix: self._viewer.set_path(self._current_path) return self._viewer.reset_path() if not self._current_path: return selected_file = QFileInfo(self._current_path) if not selected_file.exists(): return selected_dir = selected_file.absoluteDir() file_name = selected_file.fileName() if not selected_dir.exists(): return if not selected_dir.cd('converted'): return suffixed_path = selected_dir.absoluteFilePath(file_name) self._viewer.set_path(suffixed_path) def _on_tree_expanded_collapsed(self, unused_index): QTimer.singleShot(1, lambda: self._file_tree.resizeColumnToContents(0))
def __init__(self): super(CMakeToolView, self).__init__(None) self.toolView = kate.mainInterfaceWindow().createToolView( 'cmake_utils' , kate.Kate.MainWindow.Bottom , KIcon('cmake').pixmap(32, 32) , i18nc('@title:tab', 'CMake') ) self.toolView.installEventFilter(self) # By default, the toolview has box layout, which is not easy to delete. # For now, just add an extra widget. tabs = QTabWidget(self.toolView) # Make a page to view cmake cache self.cacheViewPage = uic.loadUi( os.path.join(os.path.dirname(__file__), settings.CMAKE_TOOLVIEW_CACHEVIEW_UI) ) self.cacheViewPage.buildDir.setText(kate.sessionConfiguration[settings.PROJECT_DIR]) # TODO It seems not only KTextEditor's SIP files are damn out of date... # KUrlRequester actually *HAS* setPlaceholderText() method... but damn SIP # files for KIO are damn out of date either! A NEW BUG NEEDS TO BE ADDED! # (but I have fraking doubts that it will be closed next few damn years) # #self.buildDir.setPlaceholderText(i18nc('@info', 'Project build directory')) self.cacheViewPage.buildDir.lineEdit().setPlaceholderText( i18nc('@info/plain', 'Project build directory') ) self.cacheViewPage.buildDir.setMode( KFile.Mode(KFile.Directory | KFile.ExistingOnly | KFile.LocalOnly) ) self.cacheViewPage.cacheItems.sortItems(0, Qt.AscendingOrder) self.cacheViewPage.cacheFilter.setTreeWidget(self.cacheViewPage.cacheItems) tabs.addTab(self.cacheViewPage, i18nc('@title:tab', 'CMake Cache Viewer')) # Make a page w/ cmake help splitter = QSplitter(Qt.Horizontal, tabs) self.vewHelpPage = uic.loadUi( os.path.join(os.path.dirname(__file__), settings.CMAKE_TOOLVIEW_HELP_UI) ) self.vewHelpPage.helpFilter.setTreeWidget(self.vewHelpPage.helpTargets) self.updateHelpIndex() # Prepare Help view self.helpPage = QTextBrowser(splitter) self.helpPage.setReadOnly(True) self.helpPage.setOpenExternalLinks(False) self.helpPage.setOpenLinks(False) splitter.addWidget(self.vewHelpPage) splitter.addWidget(self.helpPage) splitter.setStretchFactor(0, 10) splitter.setStretchFactor(1, 20) tabs.addTab(splitter, i18nc('@title:tab', 'CMake Help')) # Make a page w/ some instant settings self.cfgPage = uic.loadUi( os.path.join(os.path.dirname(__file__), settings.CMAKE_TOOLVIEW_SETTINGS_UI) ) self.cfgPage.mode.setChecked(kate.sessionConfiguration[settings.TOOLVIEW_ADVANCED_MODE]) self.cfgPage.htmlize.setChecked(kate.sessionConfiguration[settings.TOOLVIEW_BEAUTIFY]) tabs.addTab(self.cfgPage, i18nc('@title:tab', 'Tool View Settings')) # Connect signals self.cacheViewPage.cacheItems.itemActivated.connect(self.insertIntoCurrentDocument) self.cacheViewPage.buildDir.returnPressed.connect(self.updateCacheView) self.cacheViewPage.buildDir.urlSelected.connect(self.updateCacheView) self.cfgPage.mode.toggled.connect(self.updateCacheView) self.cfgPage.mode.toggled.connect(self.saveSettings) self.cfgPage.htmlize.toggled.connect(self.updateHelpText) self.cfgPage.htmlize.toggled.connect(self.saveSettings) self.vewHelpPage.helpTargets.itemActivated.connect(self.updateHelpText) self.vewHelpPage.helpTargets.itemDoubleClicked.connect(self.insertHelpItemIntoCurrentDocument) self.helpPage.anchorClicked.connect(openDocument) # Refresh the cache view self._updateCacheView(self.cacheViewPage.buildDir.text())
class DSBrowser(QWidget): """browser for datastorage databases Nodes are identified by a string, containing fields separated by '|'. - first filed is a capital letter: 'R'oot, 'P'roject, sensor'G'roup, 'S'ensor and 'C'hart - second field is the database folder - third filed is the path of the node in the database - for charts the fourth field is the chart name (third is path of sensorgroup in this case) """ def __init__(self): QWidget.__init__(self) self.layout = QVBoxLayout(self) self.layout.setSpacing(0) self.layout.setMargin(0) self.toolBar = QFrame(self) self.toolBarLayout = QHBoxLayout(self.toolBar) self.toolBarLayout.setMargin(2) self.toolBarLayout.setSpacing(2) self.layout.addWidget(self.toolBar) self.loadButton = QToolButton(self.toolBar) self.loadButton.setText(QCoreApplication.translate('DataStorageBrowser', 'Open...')) self.loadButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.fileOpen))) self.loadButton.setToolTip(QCoreApplication.translate('DataStorageBrowser', 'Open a datastorage database')) self.toolBarLayout.addWidget(self.loadButton) self.connect(self.loadButton, SIGNAL('pressed()'), self.loadDatabase) self.dropButton = QToolButton(self.toolBar) self.dropButton.setText(QCoreApplication.translate('DataStorageBrowser', 'Close All')) self.dropButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.clear))) self.dropButton.setToolTip(QCoreApplication.translate('DataStorageBrowser', 'Drop all open databases')) self.toolBarLayout.addWidget(self.dropButton) self.connect(self.dropButton, SIGNAL('pressed()'), self.dropDatabases) self.dropButton.setEnabled(False) self.toolBarLayout.addStretch(100) self.splitter = QSplitter(self) self.splitter.setOrientation(Qt.Vertical) self.treeView = QTreeView(self.splitter) self.treeView.setAlternatingRowColors(True) self.treeView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.treeView.setAutoExpandDelay(500) self.textBrowser = QTextBrowser(self.splitter) self.layout.addWidget(self.splitter) self.splitter.setStretchFactor(0, 60) self.splitter.setStretchFactor(1, 40) self.model = DSModel() self.treeView.setModel(self.model) self.treeView.setSortingEnabled(True) self.treeView.expandAll() self.connect(self.treeView.selectionModel(), SIGNAL("currentChanged(QModelIndex, QModelIndex)"), self.showItem) self.connect(self.treeView, SIGNAL("doubleClicked(QModelIndex)"), self.itemAction) self.connect(self.treeView, SIGNAL("customContextMenuRequested(QPoint)"), self.showContextMenu) self.selectedNode = None self.selectedMI = None def loadDatabase(self, dn=None): """load a database""" if not dn: dn = QFileDialog.getExistingDirectory(self, QCoreApplication.translate('DataStorageBrowser', "Select a folder containing a datastorage database"), SimuVis4.Globals.defaultFolder) if not dn.isEmpty(): dn = unicode(dn) SimuVis4.Globals.defaultFolder = dn else: return self.model.addDatabase(dn) self.treeView.expandToDepth(1) def dropDatabases(self): # FIXME: implement it pass def showItem(self, mi, pr): """show the item at model index mi""" t, n = self.model.dsNode(mi) txt = "" if t == 'R': # FIXME: no metadata? txt = rootInfo.substitute(name=n.name, title=escape(n.title), folder=n.h5dir, projects=len(n)) # + formatMetaData(n) elif t == 'P': txt = projectInfo.substitute(name=n.name, title=escape(n.title), groups=len(n)) + formatMetaData(n) elif t == 'G': txt = groupInfo.substitute(name=n.name, title=escape(n.title), sensors=len(n), charts=len(n.charts)) + formatMetaData(n) elif t == 'S': txt = sensorInfo.substitute(name=n.name, title=escape(n.title), start=n.timegrid.start, stop=n.timegrid.stop, step=n.timegrid.step, length=n.datalen()) + formatMetaData(n) elif t == 'C': txt = chartInfo.substitute(name=n.name) self.textBrowser.setText(txt) def itemAction(self, mi): """default action (on doubleclick) for item at model index mi""" t, n = self.model.dsNode(mi) if t == 'R': pass elif t == 'P': pass elif t == 'G': pass elif t == 'S': print n self.showQwtPlot(n) elif t == 'C': self.showMplChart(n) def showContextMenu(self, pos): """show context menu for item at pos""" mi = self.treeView.indexAt(pos) t, n = self.model.dsNode(mi) self.selectedNode = n self.selectedMI = mi m = QMenu() if t in 'RPGS': p = m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Edit metadata'), self.editMetadata) if t == 'R': pass elif t == 'P': pass elif t == 'G': m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Add Chart'), self.newChart) elif t == 'S': m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Plot (Qwt)'), self.showQwtPlot) elif t == 'C': m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Show'), self.showMplChart) m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Delete'), self.deleteItem) a = m.exec_(self.treeView.mapToGlobal(pos)) def showMplChart(self, node=None): if node is None: node = self.selectedNode showChartMplWindow(node, maximized=showChartMaximized) def showQwtPlot(self, node=None): if node is None: node = self.selectedNode showQwtPlotWindow(node, maximized=showChartMaximized) def editMetadata(self, node=None): if node is None: node = self.selectedNode editMetadata(node) def newChart(self, mi=None): """add a chart to sensorgroup at mi using the wizard""" if mi is None: mi = self.selectedMI showNewChartWizard(self.model, mi) def deleteItem(self, mi=None): """delete the item at mi""" if mi is None: mi = self.selectedMI self.model.deleteItem(mi)
def __init__(self, parent, logger): super(MembersWidget, self).__init__(parent) self.logger = logger layout = QVBoxLayout(self) layout.setSpacing(0) self.dropdown_members_dict = {} self.dropdown_members_model = DropdownModel(get_peers(), self.logger) self.dropdown_members = QComboBox(self) self.dropdown_members.setModel(self.dropdown_members_model) topLayout = QHBoxLayout() topLayout.setSpacing(10) topLayout.addWidget(self.dropdown_members, 1) self.requestLogsButton = QPushButton("Request Logfiles", self) topLayout.addWidget(self.requestLogsButton) layout.addLayout(topLayout) layout.addWidget(QLabel("Member Information:", self)) self.memberInformationTable = QTreeWidget(self) self.memberInformationTable.setMaximumHeight(65) self.memberInformationTable.setSelectionMode(QTreeWidget.NoSelection) layout.addWidget(self.memberInformationTable, 0) layout.addWidget(QLabel("Send Message:", self)) sendMessageLayout = QHBoxLayout() sendMessageLayout.setSpacing(10) messageInput = HistoryLineEdit(self, "Enter a message") self.sendMessageButton = QPushButton("Send", self) sendMessageLayout.addWidget(messageInput, 1) sendMessageLayout.addWidget(self.sendMessageButton) layout.addLayout(sendMessageLayout) layout.addWidget(QLabel("Log files:", self)) logSplitter = QSplitter(Qt.Horizontal, self) logListWidget = QWidget(self) logListLayout = QVBoxLayout(logListWidget) logListLayout.setContentsMargins(0, 0, 0, 0) self.log_tree_view = QTreeWidget(logSplitter) self.log_tree_view.setAlternatingRowColors(True) self.log_tree_view.setColumnCount(1) self.log_tree_view.setHeaderHidden(True) self.log_tree_view.setItemsExpandable(False) self.log_tree_view.setIndentation(0) logListLayout.addWidget(self.log_tree_view, 1) logListBottomLayout = QHBoxLayout() self.logSizeLabel = QLabel(logListWidget) logListBottomLayout.addWidget(self.logSizeLabel, 1) self.clearLogsButton = QPushButton("Clear", logListWidget) self.clearLogsButton.setEnabled(False) self.clearLogsButton.clicked.connect(self.clearLogs) logListBottomLayout.addWidget(self.clearLogsButton, 0) logListLayout.addLayout(logListBottomLayout) logSplitter.addWidget(logListWidget) self.log_area = QTextEdit(logListWidget) self.log_area.setLineWrapMode(QTextEdit.WidgetWidth) self.log_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.log_area.setReadOnly(True) logSplitter.addWidget(self.log_area) logSplitter.setStretchFactor(0, 0) logSplitter.setStretchFactor(1, 1) layout.addWidget(logSplitter, 1) self.memberSelectionChanged() self.log_tree_view.selectionModel().selectionChanged.connect(self.displaySelectedLogfile) self.dropdown_members.currentIndexChanged.connect(self.memberSelectionChanged) self.requestLogsButton.clicked.connect(self.requestLogClicked) self.sendMessageButton.clicked.connect(partial(self.sendMessageToMember, messageInput)) messageInput.returnPressed.connect(partial(self.sendMessageToMember, messageInput)) get_notification_center().connectPeerAppended(self.dropdown_members_model.externalRowAppended) get_notification_center().connectPeerUpdated(self.dropdown_members_model.externalRowUpdated) get_notification_center().connectPeerRemoved(self.dropdown_members_model.externalRowRemoved) get_notification_center().connectPeerUpdated(self.updateMemberInformation)
def setup_layout(self): outer_layout = QVBoxLayout() outer_layout.addWidget(self.menu_bar) outer_layout.setStretch(0, 1) h_splitter = QSplitter(self) h_splitter.setOrientation(Qt.Horizontal) # FIRST COLUMN of h_splitter is chromatogram + peakmap: ############################ v_splitter1 = QSplitter(self) v_splitter1.setOrientation(Qt.Vertical) v_splitter1.addWidget(self.eic_plotter) v_splitter1.addWidget(self.peakmap_plotter) self.peakmap_plotter.setMinimumSize(250, 200) v_splitter1.setStretchFactor(0, 1) v_splitter1.setStretchFactor(1, 3) h_splitter.addWidget(v_splitter1) h_splitter.setStretchFactor(0, 2) # SECOND COLUMN of h_splittier holds controlx boxes + mz plot ####################### v_splitter2 = QSplitter(self) v_splitter2.setOrientation(Qt.Vertical) v_splitter2.addWidget(self.image_scaling_widget) v_splitter2.addWidget(self.spectra_selector_widget) v_splitter2.addWidget(self.view_range_widget) v_splitter2.addWidget(self.history_list) v_splitter2.addWidget(self.mz_plotter) v_splitter2.setStretchFactor(0, 0) v_splitter2.setStretchFactor(1, 0) v_splitter2.setStretchFactor(2, 0) v_splitter2.setStretchFactor(3, 0) v_splitter2.setStretchFactor(4, 1) h_splitter.addWidget(v_splitter2) h_splitter.setStretchFactor(1, 1) # THIRD COLUMN of h_splittier holds control table + buttons ########################## if self.table: frame = QFrame(self) layout = QVBoxLayout(frame) frame.setLayout(layout) layout.addWidget(self.table_widget) button_row_layout = QHBoxLayout(frame) button_row_layout.addWidget(self.select_all_peaks) button_row_layout.addWidget(self.unselect_all_peaks) button_row_layout.addWidget(self.done_button) layout.addLayout(button_row_layout) h_splitter.addWidget(frame) h_splitter.setStretchFactor(2, 2) outer_layout.addWidget(h_splitter) self.setLayout(outer_layout) outer_layout.setStretch(1, 99)
class WWorkspace(QWidget): """ Workspace widget """ WORKSPACE = 0 UpdateWindowTitle = pyqtSignal(str) RecentFile = pyqtSignal(dict) BusyCursor = pyqtSignal() ArrowCursor = pyqtSignal() def __init__(self, parent=None): """ Constructs WWorkspace widget Signals emited: * updateWindowTitle @param parent: @type parent: """ QWidget.__init__(self, parent) self.parent = parent self.type = self.WORKSPACE self.name = self.tr('Workspace') # create each part WRepositories.initialize(parent=self) WDocumentViewer.initialize(parent=self, iRepo=WRepositories.instance(), lRepo=WRepositories.LocalRepository, rRepo=WRepositories.RemoteRepository) WDocumentProperties.initialize(parent=self, iRepo=WRepositories.instance(), lRepo=WRepositories.LocalRepository, rRepo=WRepositories.RemoteRepository) WHelper.initialize(parent=self) # splitter state self.splitterState = None self.splitterHelperState = None # create widget self.createWidgets() self.createActions() self.creationConnections() def createWidgets(self): """ QtWidgets creation _________ _______________________ _________ / \__________ | | / \__ | | Q | | Q | | | WRepositories | S | | S | | | | p | | p | | |_____________________| l | | l | | _____QSplitter i | WDocumentViewer | i | WHelper | / \__________ t | | t | | | | t | | t | | | WDocumentProperties | e | | e | | | | r | | r | | |_____________________| |_______________________| |_____________| """ self.wCursorPosition = WCursorPosition(self) self.parent.addWidgetToStatusBar(self.wCursorPosition) WDocumentProperties.instance().setDisabled(True) layout = QHBoxLayout(self) # properties | viewer | helper self.vSplitter = QSplitter(self) if not QtHelper.str2bool( Settings.instance().readValue(key='View/tab-left')): self.hSplitter = QSplitter(self) self.hSplitter.setOrientation(Qt.Vertical) self.hSplitter.addWidget(WRepositories.instance()) self.hSplitter.addWidget(WDocumentProperties.instance()) self.hSplitter.setContentsMargins(0, 0, 0, 0) self.vSplitter.addWidget(self.hSplitter) else: WRepositories.instance().hideWidgetsHeader() WDocumentProperties.instance().hideWidgetsHeader() self.leftTab = QTabWidget(self) self.leftTab.addTab(WRepositories.instance(), QIcon(":/folders.png"), self.tr("Repositories")) self.leftTab.addTab(WDocumentProperties.instance(), QIcon(":/controls.png"), self.tr("Test Properties")) self.vSplitter.addWidget(self.leftTab) self.vSplitter.addWidget(WDocumentViewer.instance()) self.vSplitter.setStretchFactor(1, 1) layout.addWidget(self.vSplitter) self.hSplitter2 = QSplitter(self) self.hSplitter2.setOrientation(Qt.Vertical) self.vSplitter.addWidget(self.hSplitter2) self.hSplitter2.addWidget(WHelper.instance()) self.setLayout(layout) def creationConnections(self): """ QtSignals connection: * WRepositories <=> WDocumentViewer.newTab * WDocumentViewer <=> cursorPositionChanged * WDocumentViewer <=> focusChanged """ WRepositories.instance().local().OpenFile.connect( WDocumentViewer.instance().newTab) WDocumentViewer.instance().CursorPositionChanged.connect( self.cursorPositionChanged) WDocumentViewer.instance().TotalLinesChanged.connect( self.totalLinesChanged) WDocumentViewer.instance().FocusChanged.connect(self.focusChanged) WDocumentViewer.instance().BusyCursor.connect(self.emitBusy) WDocumentViewer.instance().ArrowCursor.connect(self.emitIdle) WDocumentViewer.instance().CurrentDocumentChanged.connect( self.currentDocumentChanged) WDocumentViewer.instance().DocumentOpened.connect(self.documentOpened) WDocumentViewer.instance().UpdateWindowTitle.connect( self.updateWindowTitle) WDocumentViewer.instance().DocumentViewerEmpty.connect( self.documentViewerEmpty) # from testplan when the test selection changed in the tree WDocumentViewer.instance().PropertiesChanged.connect( self.propertiesChanged) if WRepositories.instance().localConfigured != "Undefined": if RCI.instance().isAuthenticated(): WDocumentViewer.instance().RefreshLocalRepository.connect( WRepositories.instance().localRepository.refreshAll) WDocumentProperties.instance().RefreshLocalRepository.connect( WRepositories.instance().localRepository.refreshAll) WDocumentViewer.instance().RecentFile.connect(self.recentFileUpdated) WHelper.instance().ShowAssistant.connect(self.onEnterAssistant) WHelper.instance().HideAssistant.connect(self.onLeaveAssistant) # new in v16 WDocumentViewer.instance().ShowPropertiesTab.connect( self.onShowPropertiesTab) def onShowPropertiesTab(self): """ On show properties tabulation """ if QtHelper.str2bool( Settings.instance().readValue(key='View/tab-left')): self.leftTab.setCurrentIndex(TAB_PROPERTIES) def onEnterAssistant(self): """ On mouse enter in the online helper """ pass def onLeaveAssistant(self): """ On mouse leave in the online helper """ pass def createActions(self): """ Create qt actions """ self.hideDeveloperModeAction = QtHelper.createAction( self, self.tr("Developer"), self.hideDeveloperMode, checkable=True, icon=QIcon(":/window-fit.png"), shortcut=Settings.instance().readValue( key='KeyboardShorcuts/developer'), tip=self.tr('Fit the document viewer to maximize the editor area')) WDocumentViewer.instance().addActionToolbar( action=self.hideDeveloperModeAction) def emitBusy(self): """ Emit busy """ self.BusyCursor.emit() def emitIdle(self): """ Emit idle """ self.ArrowCursor.emit() def hideDeveloperMode(self): """ Hide developer mode """ if not self.hideDeveloperModeAction.isChecked(): Settings.instance().setValue(key='View/developer', value='False') self.deactiveDeveloperView() else: Settings.instance().setValue(key='View/developer', value='True') self.activeDeveloperView() def activeDeveloperView(self): """ Activate developer view """ self.splitterState = self.vSplitter.saveState() self.vSplitter.setSizes([0, self.vSplitter.sizes()[1], 0]) def deactiveDeveloperView(self): """ Deactive developer view """ if self.splitterState is not None: self.vSplitter.restoreState(self.splitterState) def mainSplitterMoved(self, index, pos): """ Memorize the new position of the splitter """ Settings.instance().setValue(key='View/helper-pos', value=self.vSplitter.sizes()[2]) def hideHelper(self): """ Hide assistant """ self.splitterHelperState = self.vSplitter.saveState() self.vSplitter.setSizes( [self.vSplitter.sizes()[0], self.vSplitter.sizes()[1], 0]) def showHelper(self): """ Show assistant """ if self.splitterHelperState is not None: self.vSplitter.restoreState(self.splitterHelperState) def documentViewerEmpty(self): """ Called to deactivate the WDocumentProperties widget Hide the WCursorPosition widget in the status bar """ WDocumentProperties.instance().clear() WDocumentProperties.instance().setDisabled(True) self.hideStatusBar() WDocumentViewer.instance().findWidget.hide() def currentDocumentChanged(self, wdocument): """ Called when the current document is changed @param wdocument: @type wdocument: """ # hide cursor position widget on disconnection or on the welcome page if isinstance(wdocument, WDocumentViewer.WelcomePage): self.hideStatusBar() if not RCI.instance().isAuthenticated(): WDocumentProperties.instance().setDisabled(True) return # test properties uneeded for test config, test adapter and library adapters # and welcome page if isinstance(wdocument, WDocumentViewer.WelcomePage): WDocumentProperties.instance().setDisabled(True) WDocumentProperties.instance().clear() elif isinstance(wdocument, TestConfig.WTestConfig) or isinstance(wdocument, TestAdapter.WTestAdapter) \ or isinstance(wdocument, TestTxt.WTestTxt) or isinstance(wdocument, TestLibrary.WTestLibrary) \ or isinstance(wdocument, TestPng.WTestPng) : WDocumentProperties.instance().setDisabled(True) WDocumentProperties.instance().clear() else: WDocumentProperties.instance().setDocument(wdoc=wdocument) WDocumentProperties.instance().setDisabled(False) WDocumentProperties.instance().addDescriptions(wdoc=wdocument) WDocumentProperties.instance().addParameters(wdoc=wdocument) if not isinstance(wdocument, TestData.WTestData): WDocumentProperties.instance().addParametersOutput( wdoc=wdocument) WDocumentProperties.instance().addProbes(wdoc=wdocument) WDocumentProperties.instance().addAgents(wdoc=wdocument) WDocumentViewer.instance().updateActions(wdocument=wdocument) if isinstance(wdocument, TestData.WTestData): WDocumentProperties.instance().disableOutputParameters() WDocumentProperties.instance().disableAgents() WDocumentProperties.instance().disableProbes() else: WDocumentProperties.instance().enableOutputParameters() WDocumentProperties.instance().enableProbes() WDocumentProperties.instance().enableAgents() if not isinstance(wdocument, TestAbstract.WTestAbstract): WDocumentProperties.instance().disableSteps() WDocumentProperties.instance().disableAdapters() WDocumentProperties.instance().disableLibraries() else: WDocumentProperties.instance().addSteps(wdoc=wdocument) WDocumentProperties.instance().enableSteps() WDocumentProperties.instance().addAdapters(wdoc=wdocument) WDocumentProperties.instance().enableAdapters() WDocumentProperties.instance().addLibraries(wdoc=wdocument) WDocumentProperties.instance().enableLibraries() if isinstance(wdocument, TestUnit.WTestUnit) or isinstance( wdocument, TestSuite.WTestSuite): WDocumentProperties.instance().enableMarkUnused() else: WDocumentProperties.instance().disableMarkUnused() # disable/enable status bar if isinstance(wdocument, TestConfig.WTestConfig) \ or isinstance(wdocument, TestPlan.WTestPlan) \ or isinstance(wdocument, TestPng.WTestPng) \ or isinstance(wdocument, TestAbstract.WTestAbstract) \ or isinstance(wdocument, WDocumentViewer.WelcomePage) : self.hideStatusBar() else: self.showStatusBar() self.wCursorPosition.setNumberLines(nb=wdocument.editor().lines()) def propertiesChanged(self, properties, isRoot, testId): """ Called when document propertis changed @param properties: @param properties: dict @param isRoot: @type isRoot: """ if isRoot: WDocumentProperties.instance().addDescriptions(wdoc=properties) WDocumentProperties.instance().addParameters(wdoc=properties) WDocumentProperties.instance().addParametersOutput(wdoc=properties) WDocumentProperties.instance().addAgents(wdoc=properties) WDocumentProperties.instance().addProbes(wdoc=properties) WDocumentProperties.instance().probes.setEnabled(True) else: WDocumentProperties.instance().addParameters(wdoc=properties) WDocumentProperties.instance().addAgents(wdoc=properties) WDocumentProperties.instance().addParametersOutput(wdoc=properties) WDocumentProperties.instance().probes.clear() WDocumentProperties.instance().probes.setEnabled(False) # new in v19 WDocumentProperties.instance().updateCache(properties, isRoot, testId) def documentOpened(self, wdocument): """ Called when a document is opened @param wdocument: @type wdocument: """ WDocumentProperties.instance().setEnabled(True) self.currentDocumentChanged(wdocument=wdocument) def updateWindowTitle(self, windowTitle): """ Emit the signal "updateWindowTitle" to update the title of the application @param windowTitle: new window title @type windowTitle: string """ self.UpdateWindowTitle.emit(windowTitle) def recentFileUpdated(self, fileDescription): """ Emit the signal "recentFile" to update the title of the application @param windowTitle: file descr with the complete path and type @type windowTitle: string """ self.RecentFile.emit(fileDescription) def focusChanged(self, wdocument): """ Called when the focus of the WDocumentViewer is changed @param wdocument: @type wdocument: """ WDocumentViewer.instance().updateActions(wdocument=wdocument) self.wCursorPosition.setNumberLines(nb=wdocument.editor().lines()) def totalLinesChanged(self, nb): """ This function is automaticaly called when the cursor changed in both editors and enables to update the cursor's position in the widget WCursorPosition @param ln: line index @type ln: Integer @param col: column index @type col: Integer """ self.wCursorPosition.setNumberLines(nb=nb) def cursorPositionChanged(self, ln, col): """ This function is automaticaly called when the cursor changed in both editors and enables to update the cursor's position in the widget WCursorPosition @param ln: line index @type ln: Integer @param col: column index @type col: Integer """ self.wCursorPosition.cursorPositionChanged(ln, col) def showStatusBar(self): """ Show WCursorPosition widget """ self.wCursorPosition.show() def hideStatusBar(self): """ Hide WCursorPosition widget """ self.wCursorPosition.hide()
class DSBrowser(QWidget): """browser for datastorage databases Nodes are identified by a string, containing fields separated by '|'. - first filed is a capital letter: 'R'oot, 'P'roject, sensor'G'roup, 'S'ensor and 'C'hart - second field is the database folder - third filed is the path of the node in the database - for charts the fourth field is the chart name (third is path of sensorgroup in this case) """ def __init__(self): QWidget.__init__(self) self.layout = QVBoxLayout(self) self.layout.setSpacing(0) self.layout.setMargin(0) self.toolBar = QFrame(self) self.toolBarLayout = QHBoxLayout(self.toolBar) self.toolBarLayout.setMargin(2) self.toolBarLayout.setSpacing(2) self.layout.addWidget(self.toolBar) self.loadButton = QToolButton(self.toolBar) self.loadButton.setText(QCoreApplication.translate("DataStorageBrowser", "Open...")) self.loadButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.fileOpen))) self.loadButton.setToolTip(QCoreApplication.translate("DataStorageBrowser", "Open a datastorage database")) self.toolBarLayout.addWidget(self.loadButton) self.connect(self.loadButton, SIGNAL("pressed()"), self.loadDatabase) self.expandButton = QToolButton(self.toolBar) self.expandButton.setText("Expand/Collapse") self.expandButton.setIcon(QIcon(QPixmap(Icons.exp_col))) self.expandButton.setToolTip( QCoreApplication.translate("DataStorageBrowser", "Expand or collapse the whole tree") ) self.toolBarLayout.addWidget(self.expandButton) self.connect(self.expandButton, SIGNAL("pressed()"), self.expandCollapseAll) self.searchInput = MyLineEdit(self.toolBar) self.searchInput.setText(QCoreApplication.translate("DataStorageBrowser", "Enter search text here")) self.searchInput.setToolTip( QCoreApplication.translate( "DataStorageBrowser", "Enter search text using wildcards here, press ENTER again to go to next match!" ) ) self.toolBarLayout.addWidget(self.searchInput, 100) self.connect(self.searchInput, SIGNAL("returnPressed()"), self.searchItem) self.helpButton = QToolButton(self.toolBar) self.helpButton.setText(QCoreApplication.translate("DataStorageBrowser", "Help")) self.helpButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.help))) self.helpButton.setToolTip(QCoreApplication.translate("DataStorageBrowser", "Show help for DataStorageBrowser")) self.toolBarLayout.addWidget(self.helpButton) self.connect(self.helpButton, SIGNAL("pressed()"), self.showHelp) self.splitter = QSplitter(self) self.splitter.setOrientation(Qt.Vertical) self.treeView = QTreeView(self.splitter) self.treeView.setAlternatingRowColors(True) self.treeView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.treeView.setAutoExpandDelay(500) self.textBrowser = QTextBrowser(self.splitter) self.layout.addWidget(self.splitter) self.splitter.setStretchFactor(0, 60) self.splitter.setStretchFactor(1, 40) self.model = DSModel() self.treeView.setModel(self.model) self.treeView.setSortingEnabled(True) self.treeView.expandAll() self.connect(self.treeView.selectionModel(), SIGNAL("currentChanged(QModelIndex, QModelIndex)"), self.showItem) self.connect(self.treeView, SIGNAL("doubleClicked(QModelIndex)"), self.itemAction) self.connect(self.treeView, SIGNAL("customContextMenuRequested(QPoint)"), self.showContextMenu) self.selectedNode = None self.selectedMI = None self.searchText = "" self.searchResults = [] self.collExpand = SimuVis4.Misc.Switcher() self.statusBar = SimuVis4.Globals.mainWin.statusBar() def loadDatabase(self, dn=None): """load a database""" if not dn: dn = QFileDialog.getExistingDirectory( self, QCoreApplication.translate("DataStorageBrowser", "Select a folder containing a datastorage database"), SimuVis4.Globals.defaultFolder, ) if not dn.isEmpty(): dn = unicode(dn) SimuVis4.Globals.defaultFolder = dn else: return self.model.addDatabase(dn) self.treeView.collapseAll() self.treeView.expandToDepth(SimuVis4.Globals.config.getint("datastoragebrowser", "expand_tree_depth")) self.treeView.resizeColumnToContents(0) def showHelp(self): SimuVis4.HelpBrowser.showHelp("/plugin/DataStorageBrowser/index.html") def showItem(self, mi, pr): """show the item at model index mi""" t, n = self.model.dsNode(mi) txt = "" if t == "R": txt = rootInfo.substitute( name=n.name, title=escape(n.title), folder=n.h5dir, projects=len(n) ) + formatMetaData(n) elif t == "P": txt = projectInfo.substitute( name=n.name, path=escape(n.parent.name), title=escape(n.title), groups=len(n) ) + formatMetaData(n) elif t == "G": txt = groupInfo.substitute( name=n.name, path="/".join(n.path.split("/")[:-1]), title=escape(n.title), sensors=len(n), charts=len(n.getCharts()), start=formatTime(n.timegrid.start), stop=formatTime(n.timegrid.stop), step=n.timegrid.step, timezone=n.timegrid.timezone, ) + formatMetaData(n) elif t == "S": txt = sensorInfo.substitute( name=n.name, path="/".join(n.path.split("/")[:-1]), title=escape(n.title), start=formatTime(n.timegrid.start), stop=formatTime(n.timegrid.stop), step=n.timegrid.step, length=n.datalen(), timezone=n.timegrid.timezone, ) + formatMetaData(n) elif t == "C": txt = chartInfo.substitute(name=n.name, path=n.sensorgroup.path) self.textBrowser.setText(txt) msg = ": ".join(str(self.model.itemFromIndex(mi).data().toString()).split("|")[1:]) self.statusBar.showMessage(msg, 5000) def searchItem(self): """execute the search and highlight the (next) result""" txt = str(self.searchInput.text()) if txt != self.searchText: self.searchText = txt tmp = self.model.findItems( txt, Qt.MatchFixedString | Qt.MatchContains | Qt.MatchWildcard | Qt.MatchRecursive ) self.searchList = [i.index() for i in tmp] if self.searchList: mi = self.searchList.pop() self.treeView.setCurrentIndex(mi) self.treeView.expand(mi) self.treeView.scrollTo(mi) else: QMessageBox.information( self, QCoreApplication.translate("DataStorageBrowser", "No (more) matches!"), QCoreApplication.translate( "DataStorageBrowser", "No (more) matches found! Change you search text and try again!" ), ) self.searchText = "" def expandCollapseAll(self): if self.collExpand(): self.treeView.collapseAll() else: self.treeView.expandAll() def itemAction(self, mi): """default action (on doubleclick) for item at model index mi""" t, n = self.model.dsNode(mi) if t == "S": if qwtPlotWindowActive(): self.addToQwtPlot(n) else: self.showQwtPlot(n) elif t == "C": self.showChart(n) def showContextMenu(self, pos): """show context menu for item at pos""" mi = self.treeView.indexAt(pos) t, n = self.model.dsNode(mi) self.selectedNode = n self.selectedMI = mi m = QMenu() if t == "R": m.addAction(QCoreApplication.translate("DataStorageBrowser", "Close"), self.closeDatabase) m.addAction(QCoreApplication.translate("DataStorageBrowser", "Reload"), self.reloadDatabase) elif t == "P": m.addAction(QCoreApplication.translate("DataStorageBrowser", "New sensorgroup"), self.newSensorGroup) elif t == "G": nCharts = len(n.getCharts()) if nCharts > 0: txt = str(QCoreApplication.translate("DataStorageBrowser", "Show all charts (%d)")) % nCharts m.addAction(txt, self.showAllCharts) m.addAction( QCoreApplication.translate("DataStorageBrowser", "Save all charts as images"), self.saveAllChartImages, ) m.addAction(QCoreApplication.translate("DataStorageBrowser", "Add chart"), self.newChart) m.addAction(QCoreApplication.translate("DataStorageBrowser", "Add/update data"), self.importFiles) m.addAction(QCoreApplication.translate("DataStorageBrowser", "Export data"), self.exportSensors) elif t == "S": m.addAction(QCoreApplication.translate("DataStorageBrowser", "New plot (Qwt)"), self.showQwtPlot) if qwtPlotWindowActive(): m.addAction(QCoreApplication.translate("DataStorageBrowser", "Add to plot (Qwt)"), self.addToQwtPlot) elif t == "C": m.addAction(QCoreApplication.translate("DataStorageBrowser", "Show"), self.showChart) m.addAction(QCoreApplication.translate("DataStorageBrowser", "Delete"), self.deleteItem) if t in "RPGS": m.addSeparator() m.addAction(QCoreApplication.translate("DataStorageBrowser", "Edit metadata"), self.editMetadata) a = m.exec_(self.treeView.mapToGlobal(pos)) def newSensorGroup(self, mi=None): if mi is None: mi = self.selectedMI newSensorGroup(self.model, mi) def showChart(self, ch=None): if ch is None: ch = self.selectedNode showChartWindow(ch, maximized=showChartMaximized) def importFiles(self, mi=None): if mi is None: mi = self.selectedMI importFiles(self.model, mi) def showAllCharts(self, sg=None): if sg is None: sg = self.selectedNode showAllChartWindows(sg, maximized=showChartMaximized) def saveAllChartImages(self, sg=None): if sg is None: sg = self.selectedNode saveAllChartImages(sg) def exportSensors(self, sg=None): if sg is None: sg = self.selectedNode exportSensors(sg) def showQwtPlot(self, se=None): if se is None: se = self.selectedNode showQwtPlotWindow(se, maximized=showChartMaximized) def addToQwtPlot(self, se=None): if se is None: se = self.selectedNode addToQwtPlotWindow(se) def editMetadata(self, node=None): if node is None: node = self.selectedNode editMetadata(node) def closeDatabase(self, mi=None): if mi is None: mi = self.selectedMI self.model.closeDatabase(mi) def reloadDatabase(self, mi=None): if mi is None: mi = self.selectedMI dbPath = self.model.dsFolder(mi) self.model.closeDatabase(mi) self.loadDatabase(dbPath) def newChart(self, mi=None): """add a chart to sensorgroup at mi using the wizard""" if mi is None: mi = self.selectedMI showNewChartWizard(self.model, mi, self) def deleteItem(self, mi=None): """delete the item at mi""" if mi is None: mi = self.selectedMI self.model.deleteItem(mi)
class WellPlotMPL(QtCore.QObject): def __init__(self, logs, well, logSet=None, parent=None): super(WellPlotMPL, self).__init__(parent) self._well = well self._logSet = logSet self._logs = logs self.plots = [] self.canvas = None self.depthPlot = None self.headerPlot = None centralWidget = centraltabwidget.CentralTabWidget() #id(self) returns the 'hash' of this object self.uid = (centralWidget.count(), id(self)) self.wellPlotSignals = WellPlotSignals() self.setupUI() self.createTabView() self.connectSlots() self.plotMultiLogs() self.setSplitterStretch() self.createToolWidget() def setupUI(self): self.mainWidget = WellPlotWidget() vBox = QtGui.QVBoxLayout() self.mainWidget.setLayout(vBox) self.headerWidget = QWidget() self.headerLayout = QtGui.QHBoxLayout() self.headerWidget.setLayout(self.headerLayout) self.dataWidget = QWidget() self.dataLayout = QtGui.QHBoxLayout() self.dataWidget.setLayout(self.dataLayout) #if don't set a minimum, get matplotlib error when is very small self.dataWidget.setMinimumHeight(self.getMinimumVerticalHeight()) self.splitter = QSplitter(QtCore.Qt.Vertical) self.headerScrollArea = QScrollArea() self.headerScrollArea.setVerticalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOn) self.headerScrollArea.setHorizontalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff) self.headerScrollArea.setWidgetResizable(False) self.headerScrollArea.setWidget(self.headerWidget) self.scrollArea = QScrollArea() self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) self.scrollArea.setHorizontalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOn) self.scrollArea.setWidgetResizable(False) self.scrollArea.setWidget(self.dataWidget) #see http://stackoverflow.com/questions/29583927/pyqt-qscrollarea-within-qscrollarea/29584939#29584939 self.scrollArea.horizontalScrollBar().valueChanged.connect( self.headerScrollArea.horizontalScrollBar().setValue) self.splitter.addWidget(self.headerScrollArea) self.splitter.addWidget(self.scrollArea) self.splitter.setStretchFactor(1, 10) vBox.addWidget(self.splitter) def getMinimumVerticalHeight(self): screenRect = QtGui.QDesktopWidget().screenGeometry() #need to set a minimum size otherwise get matplotlib error when rezizing to too small twentythOfScreen = int(round(screenRect.width() / 20)) return twentythOfScreen def plotMultiLogs(self): logPlotModelAccess = WellPlotModelAccess() logPlotData = logPlotModelAccess.createWellPlotData(self._logs) self.createCanvas(logPlotData) self.plotHeaderFields(logPlotData) def createCanvas(self, logPlotData): logger.debug(">>createCanvas()") #test for subPlotData in logPlotData.sub_plots: logger.debug( "--createCanvas() plot_index:{0} track_width:{1} track_gap:{2}" .format(subPlotData.plot_index, subPlotData.track_width, subPlotData.track_gap)) for log in subPlotData._logs: logger.debug("--createCanvas id:{0}, name:{1}".format( log.id, log.name)) #end test if len(logPlotData.sub_plots) > 0: WidgetUtils.removeWidgets(self.dataLayout) #test #time.sleep(1) # delays for 1 second #end test #There may be a better way to link plots with the toolbar self.mainWidget.setLogPlotData(logPlotData) self.depthPlot = DepthAxis(logPlotData, self.dataWidget) self.dataLayout.addWidget(self.depthPlot) self.canvas = MultiLogCanvas(logPlotData, self.dataWidget) self.canvas.setAutoFillBackground(True) self.dataLayout.addWidget(self.canvas) spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) self.dataLayout.addItem(spacerItem) else: logger.error("--plotMultiLogs() Error: no logs to plot") if AppSettings.isDebugMode: raise ValueError def plotHeaderFields(self, logPlotData): logger.debug(">>plotMultiLogs()") WidgetUtils.removeWidgets(self.headerLayout) self.headerPlot = HeaderPlotMPL(depthPlot=self.depthPlot, mainPlot=self.canvas, logPlotData=logPlotData) self.headerLayout.addWidget(self.headerPlot) def setSplitterStretch(self): #Minimum size is required for the QScrollArea.setWidgetResizable(False) setting''' headerW = self.headerPlot.width() headerH = self.headerPlot.height() self.headerWidget.setMinimumSize(headerW, headerH) #test (totalW, dataH) = MplUtils.calcFigCanvasWidthHeight(self.canvas.figure) #end test dWidth, dHeight = self.canvas.figure.canvas.get_width_height() self.dataWidget.setMinimumSize(dWidth, dHeight) def connectSlots(self): logger.debug(">>connectSlots") self.wellPlotSignals.logPlotSettingsModified.connect(self.replotLogs) @pyqtSlot(WellPlotData) def replotLogs(self, logPlotData): logger.debug(">>replotLogs len(logPlotData.sub_plots): " + str(len(logPlotData.sub_plots))) #check uid's before accessing them, where uid is a (number widgets in central widget, id) tuple logger.debug( "--replotLogs() len(self.uid):{0}, len(logPlotData.uid):{1}". format(len(self.uid), len(logPlotData.uid))) if (len(self.uid) == 2) and (len(logPlotData.uid) == 2): #ensure this object is associated with the plot object if self.uid[0] == logPlotData.uid[0] and self.uid[ 1] == logPlotData.uid[1]: logger.debug("--replotLogs() match found uid: " + str(self.uid[0])) self.createCanvas(logPlotData) self.plotHeaderFields(logPlotData) def spacePlots(self, bottomLayout): rightSpacer = QtGui.QWidget() rightSpacer.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) #topLayout.addWidget(rightSpacer) bottomLayout.addWidget(rightSpacer) #self.topWidget.setLayout(topLayout) self.dataWidget.setLayout(bottomLayout) def createTabView(self): centralWidget = centraltabwidget.CentralTabWidget() self.mainWidget.setData(self.uid) #centralWidget.addTab(self.scrollArea, "Well plot "+str(self.uid[0])) centralWidget.addTab(self.mainWidget, "Well plot " + str(self.uid[0])) def createToolWidget(self): if len(self._logs) > 0: toolbar = logsettingstoolbar.LogSettingsToolbar() toolbar.setData(self._well, self._logSet, self.canvas, self.depthPlot, self.headerPlot) toolbar.emitShowToolbarSignal() logger.debug("<<createToolWidget() toolbar created")
def createWidgets(self): """ QtWidgets creation ___________ _________________ | | | | | | | | | | | | | TestsItem | | TextualLogView | | | | | | | | | |___________| |_________________| """ layout = QHBoxLayout() self.logsItem = TestsView.TestsView(parent=self, local=self.local) self.resumeView = ResumeView.TextualView(parent=self) if QtHelper.str2bool( Settings.instance().readValue(key='TestRun/hide-resume-view')): self.hideResumeView() self.graphView = GraphView.FlowChartView(parent=self) self.logsView = TextualView.TextualView2(parent=self) self.hexLogsView = DetailedView.DetailedView(parent=self) self.displayTab = QTabWidget() hSplitter = QSplitter(self) hSplitter.setOrientation(Qt.Vertical) hSplitter.addWidget(self.resumeView) hSplitter.addWidget(self.logsView) hSplitter.addWidget(self.hexLogsView) self.displayTab.addTab(hSplitter, self.tr('Events')) self.displayTab.addTab(self.graphView, self.tr('Diagram')) defaultTab = Settings.instance().readValue( key='TestRun/default-tab-run') self.displayTab.setCurrentIndex(int(defaultTab)) self.currentEdit = QLineEdit() self.currentEdit.setReadOnly(True) self.currentEdit.setStyleSheet( "QLineEdit { background-color : #F0F0F0; color: grey; }") leftFrame = QFrame() leftLayout = QVBoxLayout() leftLayout.setContentsMargins(0, 0, 0, 0) leftFrame.setLayout(leftLayout) leftLayout.addWidget(self.currentEdit) leftLayout.addWidget(self.displayTab) v_splitter = QSplitter(self) v_splitter.addWidget(self.logsItem) v_splitter.addWidget(leftFrame) v_splitter.setStretchFactor(1, 1) layout.addWidget(v_splitter) self.setLayout(layout)
class EntryView(BaseView): def _setup(self): self._setupUi() self.etable = EntryTable(self.model.etable, view=self.tableView) self.efbar = EntryFilterBar(model=self.model.filter_bar, view=self.filterBar) self.bgraph = Chart(self.model.bargraph, view=self.barGraphView) self.lgraph = Chart(self.model.balgraph, view=self.lineGraphView) self._setupColumns() # Can only be done after the model has been connected self.reconciliationButton.clicked.connect(self.model.toggle_reconciliation_mode) def _setupUi(self): self.resize(483, 423) self.verticalLayout = QVBoxLayout(self) self.verticalLayout.setSpacing(0) self.verticalLayout.setMargin(0) self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setSpacing(0) self.filterBar = RadioBox(self) sizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.filterBar.sizePolicy().hasHeightForWidth()) self.filterBar.setSizePolicy(sizePolicy) self.horizontalLayout.addWidget(self.filterBar) self.horizontalLayout.addItem(horizontalSpacer()) self.reconciliationButton = QPushButton(tr("Reconciliation")) self.reconciliationButton.setCheckable(True) self.horizontalLayout.addWidget(self.reconciliationButton) self.verticalLayout.addLayout(self.horizontalLayout) self.splitterView = QSplitter() self.splitterView.setOrientation(Qt.Vertical) self.splitterView.setChildrenCollapsible(False) self.tableView = TableView(self) self.tableView.setAcceptDrops(True) self.tableView.setEditTriggers(QAbstractItemView.DoubleClicked|QAbstractItemView.EditKeyPressed) self.tableView.setDragEnabled(True) self.tableView.setDragDropMode(QAbstractItemView.InternalMove) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tableView.setSortingEnabled(True) self.tableView.horizontalHeader().setHighlightSections(False) self.tableView.horizontalHeader().setMinimumSectionSize(18) self.tableView.verticalHeader().setVisible(False) self.tableView.verticalHeader().setDefaultSectionSize(18) self.splitterView.addWidget(self.tableView) self.graphView = QStackedWidget(self) sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.graphView.sizePolicy().hasHeightForWidth()) self.graphView.setSizePolicy(sizePolicy) self.graphView.setMinimumSize(0, 200) self.lineGraphView = LineGraphView() self.graphView.addWidget(self.lineGraphView) self.barGraphView = BarGraphView() self.graphView.addWidget(self.barGraphView) self.splitterView.addWidget(self.graphView) self.graphView.setCurrentIndex(1) self.splitterView.setStretchFactor(0, 1) self.splitterView.setStretchFactor(1, 0) self.verticalLayout.addWidget(self.splitterView) def _setupColumns(self): h = self.tableView.horizontalHeader() h.setMovable(True) # column drag & drop reorder #--- QWidget override def setFocus(self): self.etable.view.setFocus() #--- Public def fitViewsForPrint(self, viewPrinter): hidden = self.model.mainwindow.hidden_areas viewPrinter.fitTable(self.etable) if PaneArea.BottomGraph not in hidden: viewPrinter.fit(self.graphView.currentWidget(), 300, 150, expandH=True, expandV=True) def restoreSubviewsSize(self): graphHeight = self.model.graph_height_to_restore if graphHeight: splitterHeight = self.splitterView.height() sizes = [splitterHeight-graphHeight, graphHeight] self.splitterView.setSizes(sizes) #--- model --> view def refresh_reconciliation_button(self): if self.model.can_toggle_reconciliation_mode: self.reconciliationButton.setEnabled(True) self.reconciliationButton.setChecked(self.model.reconciliation_mode) else: self.reconciliationButton.setEnabled(False) self.reconciliationButton.setChecked(False) def show_bar_graph(self): self.graphView.setCurrentIndex(1) def show_line_graph(self): self.graphView.setCurrentIndex(0) def update_visibility(self): hidden = self.model.mainwindow.hidden_areas self.graphView.setHidden(PaneArea.BottomGraph in hidden)
class Help(QDockWidget): def __init__(self, parent=None, path=None): QDockWidget.__init__(self, parent) self.name = self.tr("Help") self.setFloating(False) self.setFeatures(QDockWidget.NoDockWidgetFeatures) self.__mainWidget = QSplitter(Qt.Horizontal) self.__uname = QWidget() mainWidgetLayout = QVBoxLayout(self.__uname) mainWidgetLayout.setContentsMargins(0, 0, 0, 0) # create helper + search engine self.__helper = QHelpEngine(path, self) if not self.__helper.setupData() is True: dialog = QMessageBox() msg = QString( self.tr("An error occurred while setting help engine up :\n")) msg += (self.__helper.error() + "\n") msg += self.tr( "It might mean that the format of your help file is not correct.\n" ) msg += self.tr( "You can check on-line help at http://wiki.digital-forensic.org" ) dialog.setText(msg) dialog.setIcon(QMessageBox.Warning) dialog.setWindowTitle(self.tr("Error while loading help")) dialog.exec_() return self.__toc = self.__helper.contentWidget() self.__helpBrowser = HelpBrowser(self.__helper) # build main widget self.__toolbar = QWidget() self.__toolbarLayout = QHBoxLayout(self.__toolbar) home = QPushButton(QIcon(":home.png"), "") previous = QPushButton(QIcon(":previous.png"), "") next = QPushButton(QIcon(":next.png"), "") # building toolbar self.__toolbarLayout.addWidget(home) self.__toolbarLayout.addWidget(previous) self.__toolbarLayout.addWidget(next) self.__toolbarLayout.setContentsMargins(0, 0, 0, 0) mainWidgetLayout.addWidget(self.__toolbar) mainWidgetLayout.addWidget(self.__helpBrowser) self.__mainWidget.insertWidget(0, self.__toc) self.__mainWidget.insertWidget(1, self.__uname) self.__mainWidget.setStretchFactor(1, 1) self.setWidget(self.__mainWidget) #connecting `previous`, `home` and `next` buttons self.connect(next, SIGNAL("clicked(bool)"), self.__helpBrowser.nextPage) self.connect(previous, SIGNAL("clicked(bool)"), self.__helpBrowser.prevPage) self.connect(home, SIGNAL("clicked(bool)"), self.__helpBrowser.goHome) self.connect(self.__helper.contentWidget(), SIGNAL("linkActivated(const QUrl &)"), self.__helpBrowser.setSource)
class Filter(Ui_filterAdd, QDialog): def __init__(self, filtertable, fname=None, query=None): super(QDialog, self).__init__(filtertable) self.filtertable = filtertable self.setupUi(self) self.editable = False self.defaultquery = None self.fname = None sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(1) self.setSizePolicy(sizePolicy) self.requestLayout.setSpacing(6) self.requestLayout.setSizeConstraint(QLayout.SetMinimumSize) self.requestLayout.setMargin(0) self.__splitter = QSplitter(Qt.Vertical) self.__splitter.setHandleWidth(12) self.requestLayout.addWidget(self.__splitter) self.__query = QTextEdit() self.__query.setReadOnly(True) if (fname == None) and (query == None): self.editable = True self.filterRequest = FilterRequests(self) self.connect(self.filterRequest, SIGNAL("queryUpdated"), self.updateQuery) self.__splitter.addWidget(self.filterRequest) self.__splitter.addWidget(self.__query) self.__splitter.setStretchFactor(0, 80) self.__splitter.setStretchFactor(1, 20) else: self.defaultquery = query self.fname = fname def updateQuery(self): query = self.buildRequest() self.__query.setText(query) def reject(self): QDialog.reject(self) def accept(self): if not self.name().isEmpty(): QDialog.accept(self) else: box = QMessageBox(QMessageBox.Critical, self.tr("Error"), self.tr("Please, specify a query name"), \ QMessageBox.NoButton, self) box.exec_() def isEditable(self): return self.editable def name(self): if self.editable: return self.filterName.text() else: return self.fname def buildRequest(self): if self.editable: row = 0 res = "(" while row < self.filterRequest.rowCount(): if row > 0: conj = self.filterRequest.cellWidget(row, 0) res += " " + CONJONCTIONS[ conj.conjunctionCombo.currentIndex()] + " " widget = self.filterRequest.cellWidget(row, 2) res += widget.request() row += 1 res += ")" return res else: return self.defaultquery
class NPhotoMainWindow(QMainWindow): rootAlbum = None currentPage = 0 def __init__(self, parent=None): super(NPhotoMainWindow, self).__init__(parent) self.image = None self.status = self.statusBar() self.status.setSizeGripEnabled(False) fileMenu = self.menuBar().addMenu("&File") fileEditAction = createAction(self, "&Edit", self.doEdit, "Ctrl-E", "fileedit", "Edit photo details") fileDeleteAction = createAction(self, "&Delete", self.doDelete, "Ctrl-D", "filedelete", "Delete selected file(s)") fileImportAction = createAction(self, "&Import", self.doImport, "Ctrl-I", "fileimport", "Import photos into your library") fileRescanLibraryAction = createAction(self, "&Rescan", self.doRescan, "Ctrl-R", "filerescan", "Rescan library folder and update sidecar files, and thumbnails") fileBackupAction = createAction(self, "&Backup", self.doBackup, "Ctrl-B", "filebkup", "Backup your library") fileSettingsAction = createAction(self, "&Settings", self.doSettings, "Ctrl-S", "filesettings", "Settings") fileQuitAction = createAction(self, "&Quit", self.close, "Ctrl+Q", "filequit", "Close the application") helpMenu = self.menuBar().addMenu("&Help") helpAboutAction = createAction(self, "&About", self.doAbout, None, "helpabout", "About nPhoto") addActions(fileMenu, (fileEditAction, fileDeleteAction, None, fileImportAction, fileRescanLibraryAction, fileBackupAction, fileSettingsAction, None, fileQuitAction)) addActions(helpMenu, (helpAboutAction,)) size = getSettingQVar("MainWindow/Size", QSize(600,500)).toSize() self.resize(size) position = getSettingQVar("MainWindow/Position", QPoint(0,0)).toPoint() self.move(position) self.restoreState(getSettingQVar("MainWindow/State").toByteArray()) self.setWindowTitle("nPhoto") self.controlFrame = QFrame() self.controlLayout = QBoxLayout(QBoxLayout.TopToBottom) #TODO Make this a combo box that populates the tree by date or by folder self.viewByCombo = QLabel("PLACEHOLDER") self.tree = QTreeWidget() self.tree.setColumnCount(1) self.tree.setHeaderLabels(["Album"]) self.tree.setItemsExpandable(True) self.connect(self.tree, SIGNAL("itemSelectionChanged()"), self.treeSelection) self.controlLayout.addWidget(self.viewByCombo) self.controlLayout.addWidget(self.tree) self.controlFrame.setLayout(self.controlLayout) self.browserFrame = QFrame() self.browserGrid = QGridLayout() self.imageLabels = [] for row in range(0,BROWSER_GRID_HEIGHT): self.imageLabels.append([]) for col in range(0,BROWSER_GRID_WIDTH): self.imageLabels[row].append(QLabel()) self.imageLabels[row][col].setBackgroundRole(QPalette.Base) self.imageLabels[row][col].setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.imageLabels[row][col].setScaledContents = True self.imageLabels[row][col].setAlignment(Qt.AlignCenter) self.imageLabels[row][col].setStyleSheet("border:2px solid #000") dbl = functools.partial(self.imgDoubleClick, row, col) click = functools.partial(self.imgMouseRelease, row, col) self.imageLabels[row][col].mouseDoubleClickEvent = dbl self.imageLabels[row][col].mouseReleaseEvent = click self.browserGrid.addWidget(self.imageLabels[row][col],row,col) self.prevPage = QPushButton("Prev") self.pageInfoLabel = QLabel("Page 0 of 0") self.pageInfoLabel.setAlignment(Qt.AlignCenter) self.nextPage = QPushButton("Next") self.prevPage.clicked.connect(self.goPreviousPage) self.nextPage.clicked.connect(self.goNextPage) self.browserGrid.addWidget(self.prevPage, row+1, 0) self.browserGrid.addWidget(self.pageInfoLabel, row+1, 1) self.browserGrid.addWidget(self.nextPage, row+1, 2) self.browserFrame.setLayout(self.browserGrid) self.mainSplitter = QSplitter(Qt.Horizontal) self.mainSplitter.addWidget(self.controlFrame) self.mainSplitter.addWidget(self.browserFrame) self.mainSplitter.setStretchFactor(1,4) self.setCentralWidget(self.mainSplitter) self.mainSplitter.restoreState(getSettingQVar("MainWindow/Splitter").toByteArray()) if getSettingStr("Paths/Library") not in (None, ''): QTimer.singleShot(0, self.loadLibrary) else: self.status.showMessage("No Library Path in settings", 10000) def getPhotoByBrowserLocation(self, row, col): idx = ((self.currentPage - 1) * BROWSER_THUMBS_PER_PAGE) + (row * BROWSER_GRID_WIDTH) + col if idx < len(self.currentAlbum.photos): return self.currentAlbum.photos[idx] else: return None def imgDoubleClick(self, row, col, event): if event.button() == Qt.LeftButton: if event.modifiers() & Qt.ControlModifier or event.modifiers() & Qt.AltModifier \ or event.modifiers() & Qt.ShiftModifier: pass else: curr = self.getPhotoByBrowserLocation(row,col) if curr: self.currentSelection = [curr,] self.highlightSelected() self.doEdit() def imgMouseRelease(self, row, col, event): if event.button() == Qt.LeftButton: if event.modifiers() & Qt.ControlModifier or event.modifiers() & Qt.AltModifier \ or event.modifiers() & Qt.ShiftModifier: pass else: curr = self.getPhotoByBrowserLocation(row,col) if curr: if not hasattr(self, "currentSelection"): self.currentSelection = [] if curr in self.currentSelection: self.currentSelection.remove(curr) else: self.currentSelection.append(curr) self.highlightSelected() def highlightSelected(self): if hasattr(self, "currentSelection"): for x in range(0, BROWSER_GRID_HEIGHT): for y in range(0, BROWSER_GRID_WIDTH): ph = self.getPhotoByBrowserLocation(x,y) if ph: if ph in self.currentSelection: self.imageLabels[x][y].setStyleSheet("border:2px solid #FFF") else: self.imageLabels[x][y].setStyleSheet("border:2px solid #000") def regenAlbumThumbnails(self, album): for al in album.albums: self.regenAlbumThumbnails(al) for ph in album.photos: createThumbnail(ph.path, True) def doRescan(self): #TODO Rebuild sidecar files! self.regenAlbumThumbnails(self.rootAlbum) self.reloadLibrary() def treeSelection(self): curr = self.tree.currentItem() path = curr.data(0,0).toString() tmp = curr while tmp.parent() is not None: tmp = tmp.parent() path = tmp.data(0,0).toString() + "." + path album = self.getAlbum(path) if hasattr(self, 'currentAlbum'): if self.currentAlbum != album: self.currentAlbum = album else: self.currentAlbum = album self.changeAlbums() def changeAlbums(self): if len(self.currentAlbum.photos) == 0: self.currentPage = 0 else: self.currentPage = 1 for row in range(0, BROWSER_GRID_HEIGHT): for col in range(0, BROWSER_GRID_WIDTH): if len(self.currentAlbum.photos)<= (row*BROWSER_GRID_WIDTH + col): self.imageLabels[row][col].setPixmap(QPixmap()) else: self.imageLabels[row][col].setPixmap(loadQPixMap(self.image, self.currentAlbum.photos[ (BROWSER_THUMBS_PER_PAGE * (self.currentPage - 1)) + row*BROWSER_GRID_WIDTH+col] .path, self.imageLabels[0][0].width(), self.imageLabels[0][0].height(), True)) self.imageLabels[row][col].adjustSize() self.updatePageInfo() def loadPageThumbs(self): for row in range(0, BROWSER_GRID_HEIGHT): for col in range(0, BROWSER_GRID_WIDTH): if len(self.currentAlbum.photos)<= ( (BROWSER_THUMBS_PER_PAGE * (self.currentPage - 1)) + row*BROWSER_GRID_WIDTH + col): self.imageLabels[row][col].setPixmap(QPixmap()) else: self.imageLabels[row][col].setPixmap(loadQPixMap(self.image, self.currentAlbum.photos[ (BROWSER_THUMBS_PER_PAGE * (self.currentPage - 1)) + row*BROWSER_GRID_WIDTH+col] .path, self.imageLabels[0][0].width(), self.imageLabels[0][0].height(), True)) self.imageLabels[row][col].adjustSize() def goPreviousPage(self): if self.currentPage > 1: self.currentPage -= 1 self.loadPageThumbs() self.updatePageInfo() def goNextPage(self): if self.currentPage < self.getMaxPage(): self.currentPage += 1 self.loadPageThumbs() self.updatePageInfo() def getMaxPage(self): totalPages = len(self.currentAlbum.photos) / BROWSER_THUMBS_PER_PAGE if (len(self.currentAlbum.photos) % BROWSER_THUMBS_PER_PAGE) != 0: totalPages += 1 return totalPages def updatePageInfo(self): if self.currentPage == 0: self.pageInfoLabel.setText("Page 0 of 0") else: self.pageInfoLabel.setText("Page %d of %d" % (self.currentPage, self.getMaxPage())) def getAlbum(self, path): nodes = path.split(".") if nodes[0] != 'Library': print "WTF?!?!?!" else: album = self.rootAlbum for albumName in nodes[1:]: album = album.albums[unicode(albumName)] return album def doBackup(self): libDir = getSettingStr("Paths/Library") bkupPaths = getSettingStr("Paths/Backup") if libDir in (None, ''): QMessageBox.warning(self, "Backup Failed", "You need to specify a library directory in your settings") return if not os.path.exists(libDir) or os.path.isfile(libDir): QMessageBox.warning(self, "Backup Failed", "The library directory in your settings either doesn't exist, or its not a directory") return if bkupPaths in (None, ''): QMessageBox.warning(self, "Backup Failed", "You need to specify at least one backup directory in your settings") return dt = datetime.date.today() bkupDirName = str(dt.year) + str(dt.month) + str(dt.day) for path in bkupPaths.split(","): if not os.path.exists(path.strip()) or os.path.isfile(path.strip()): QMessageBox.warning(self, "Backup Failed", "The backup directory <%s> in your settings either doesn't exist, or its not a directory" % (path)) return if os.path.exists(path.strip() + os.sep + bkupDirName): QMessageBox.warning(self, "Backup Failed", "There is already a backup for today in a backup directory <%s>" % (path.strip())) return for path in bkupPaths.split(","): shutil.copytree(libDir, path.strip() + os.sep + bkupDirName) QMessageBox.information(self, "Backup", "Backup completed!") def doDelete(self): if hasattr(self, "currentSelection"): if len(self.currentSelection) > 0: msg = "Are you sure you want to delete the selected image?" if len(self.currentSelection) > 1: msg = "Are you sure you want to delete the %s selected images?" % len(self.currentSelection) if QMessageBox.warning(self, "Delete Image(s)", msg, QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes: for ph in self.currentSelection: msg = ph.delete() if msg not in (None, ''): QMessageBox.warning(self, "Error while deleting", msg) break self.reloadLibrary() def reloadLibrary(self): self.currentSelection = [] self.highlightSelected() currPage = self.currentPage self.loadLibrary() if currPage > self.getMaxPage(): #Assumes you can't delete more than one page worth of photos at a time currPage = self.getMaxPage() self.currentPage = currPage self.loadPageThumbs() self.updatePageInfo() def doEdit(self): if hasattr(self, "currentSelection"): if len(self.currentSelection) == 1: ph = self.currentSelection[0] comment = ph.comment keywords = (" ".join(ph.keywords)).strip() dialog = EditPhotoDialog(self, ph.path, comment, keywords) if dialog.exec_(): ph.comment = unicode(dialog.commentEdit.text()).strip() ph.keywords = unicode(dialog.keywordEdit.text()).strip().split(" ") ph.save(ph.path) def doSettings(self): libPath = getSettingStr("Paths/Library", "") backupPaths = getSettingStr("Paths/Backup", "") fileExt = getSettingStr("FileExtensions", "jpg, CR2") fileExtOther = getSettingStr("FileExtensionsOther", "mov, avi") dialog = SettingsDialog(self, libPath, backupPaths, fileExt, fileExtOther) if dialog.exec_(): saveSetting("Paths/Library", dialog.libPathEdit.text()) saveSetting("Paths/Backup", dialog.backupPathsEdit.text()) saveSetting("FileExtensions", dialog.fileExtensionEdit.text()) saveSetting("FileExtensionsOther", dialog.fileExtensionOtherEdit.text()) self.status.showMessage("Settings updated", 5000) def buildTree(self, parentNode, parentAlbum): for name in parentAlbum.albums: childNode = QTreeWidgetItem(parentNode, [name]) childAlbum = parentAlbum.albums[name] if childAlbum.albums != None and len(childAlbum.albums) > 0: self.buildTree(childNode, childAlbum) def loadLibrary(self): self.status.showMessage("Loading Photo Library") self.rootAlbum = self.loadAlbum(getSettingStr("Paths/Library"), "Library") if self.rootAlbum == None: self.rootAlbum = Album(name="Library") self.refreshTree() self.status.showMessage("Library successfully loaded", 5000) def refreshTree(self): self.tree.clear() node = QTreeWidgetItem(self.tree, ["Library"]) self.buildTree(node, self.rootAlbum) self.tree.setCurrentItem(node) def loadAlbum(self, path, title = None): album = Album() if title not in (None, ''): album.name = title else: album.name = path[path.rfind(os.sep)+1:] album.albums = {} album.photos = [] album.path = path files = os.listdir(path) files.sort() tmpPhotos = [] for fl in files: if not os.path.isfile(path + os.sep + fl): album.albums[fl] = self.loadAlbum(path + os.sep + fl) else: if self.isImageFile(path + os.sep + fl): ph = None if os.path.exists(path + os.sep + fl + ".sidecar"): ph = Photo.load(path + os.sep + fl + ".sidecar") else: ph = Photo() ph.comment = "" ph.keywords = {} ph.srcPath = None ph.path = path + os.sep + fl exif = loadExif(path + os.sep + fl, EXIF_TAGS) ph.setExif(exif) ph.save(path + os.sep + fl) ph.path = path + os.sep + fl tmpPhotos.append(ph) album.photos = sorted(tmpPhotos, key = lambda photo: photo.date) return album def doImport(self): libPath = getSettingStr("Paths/Library") fileExt = getSettingStr("FileExtensions") if libPath in (None, ''): QMessageBox.warning(self, "Import Failed", "You need to specify a library directory in your settings") return if not os.path.exists(libPath) or os.path.isfile(libPath): QMessageBox.warning(self, "Import Failed", "The library directory in your settings either doesn't exist, or its not a directory") return if not fileExt or fileExt in (None, ''): QMessageBox.warning(self, "Import Failed", "You need to specify file extensions to manage in your settings") return lastImport = getSettingStr("Paths/LastImport") importFrom = QFileDialog.getExistingDirectory(self, "Choose a Path to Import From", lastImport) if importFrom in (None, ''): return if not os.path.exists(importFrom) or os.path.isfile(importFrom): QMessageBox.warning(self, "Import Failed", "The import directory either doesn't exist, or is not a directory") return if importFrom == libPath: QMessageBox.warning(self, "Import Failed", "Your import directory and library directory can not be the same") return imd = ImportMetadataDialog(self) if imd.exec_(): album = imd.albumEdit.text() comments = imd.commentsEdit.text() keywords = imd.keywordsEdit.text() if album and album not in (None, ''): albumpath = album + os.sep else: album = None albumpath = "" if not keywords or keywords in (None, ''): keywords = "" if not comments or comments in (None, ''): comments = "" paths = self.buildFileList(importFrom) numTotal = len(paths) nonDupes = self.removeDuplicates(paths, importFrom, albumpath) numDuplicates = numTotal - len(nonDupes) if QMessageBox.question(self, "Import", "Out of %d files found, %d look to be duplicates. Continue with import?" % (numTotal, numDuplicates), QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes: saveSetting("Paths/LastImport", importFrom) for path in nonDupes: dest = self.buildLibPath(importFrom, path, albumpath) copyFileIncludingDirectories(path, dest) # TODO Handle copy failure exceptions! if not os.path.exists(dest): QMessageBox.warming(self, "Import Failed", "The file <%s> was not imported properly, aborting import" % (path)) return if self.isImageFile(path): exif = loadExif(unicode(path), EXIF_TAGS) ph = Photo() ph.path = dest ph.srcPath = path ph.comment = comments ph.keywords = keywords ph.setExif(exif) ph.save(dest) #Create Thumbnail createThumbnail(unicode(ph.path)) QMessageBox.information(self, "Import", "Import completed") self.loadLibrary() def buildLibPath(self, importFrom, path, albumpath): relPath = path[len(importFrom):] libPath = getSettingStr("Paths/Library") + os.sep + albumpath + relPath return libPath def isImageFile(self, filepath): extensionList = unicode(getSettingStr("FileExtensions")).split(",") for extension in extensionList: if unicode(filepath).upper().endswith(unicode(extension).upper()): return True return False def isOtherManagedFile(self, filepath): #TODO Implement list of other files to import into lib folders and to backup extensionList = unicode(getSettingStr("FileExtensionsOther")).split(",") for extension in extensionList: if unicode(filepath).upper().endswith(unicode(extension).upper()): return True return False def removeDuplicates(self, paths, importFrom, albumpath): nonDupes = [] for path in paths: libPath = self.buildLibPath(importFrom, path, albumpath) if not os.path.exists(libPath): nonDupes.append(path) return nonDupes def buildFileList(self, importFrom): #TODO Can probably be done with Glob or whatever it is? paths = [] for f in os.listdir(importFrom): fullpath = importFrom + os.sep + f if not os.path.isfile(fullpath): paths.extend(self.buildFileList(fullpath)) else: if self.isImageFile(fullpath): paths.append(fullpath) elif self.isOtherManagedFile(fullpath): paths.append(fullpath) return paths def closeEvent(self, event): saveSetting("MainWindow/Size", self.size()) saveSetting("MainWindow/Position", self.pos()) saveSetting("MainWindow/State", self.saveState()) saveSetting("MainWindow/Splitter", self.mainSplitter.saveState()) def doAbout(self): QMessageBox.about(self, "About nPhoto", "<p>nPhoto allows simple reviewing, commenting, and keywording of images, useful for running" " on a netbook while travelling, to then import into programs such as Lightroom" " on return from your holiday</p>")
class EventLogViewer(QWidget): def __init__(self, node=None, chunks=None, parent=None): super(EventLogViewer, self).__init__(parent) self.display_mode = 0 # self.chunks = chunks self.node = node self.evtx_parser = EvtxXml(chunks, self.node) self.level = [ ':/audit_success', ':/audit_failure', ':/error', ':/warning', ':/info', ':/chat.png' ] self.txt = [ 'Audit success', 'Audit failure', 'Error', 'Warning', 'Information', 'Comment' ] self.disp = None self.current_row = 0 self.widget = None self.verticalLayout = QVBoxLayout(self) self.verticalLayout.setMargin(3) self.splitter = QSplitter(self) self.splitter.setOrientation(Qt.Horizontal) #self.evtx_table_view = QTableWidget(self.splitter) self.evtx_table_view = EvtxTableView(self.splitter, self) self.admin_pannel = EvtxAdminPannel(self.splitter, chunks or []) self.verticalLayout.addWidget(self.splitter) self.splitter.setStretchFactor(0, 2) if PYQT_VERSION_STR >= "4.5.0": self.evtx_table_view.cellDoubleClicked.connect(self.dispEvent) self.admin_pannel.admin_events.clicked.connect( self.dispAdminEvents) self.admin_pannel.choose_event_type.activated.connect( self.dispEventType) self.admin_pannel.cb.activated.connect(self.dispIdL) self.admin_pannel.cbs.activated.connect(self.dispSourceL) self.admin_pannel.search_id.clicked.connect(self.dispId) self.admin_pannel.search_source.clicked.connect(self.dispSource) self.admin_pannel.search_date.clicked.connect(self.dispDate) else: QObject.connect(self.evtx_table_view, SIGNAL("cellDoubleClicked(int, int)"), self.dispEvent) QObject.connect(self.admin_pannel.admin_events, SIGNAL("clicked(bool)"), self.dispAdminEvents) QObject.connect(self.admin_pannel.search_id, SIGNAL("clicked(bool)"), self.dispId) QObject.connect(self.admin_pannel.search_source, SIGNAL("clicked(bool)"), self.dispSource) QObject.connect(self.admin_pannel.search_date, SIGNAL("clicked(bool)"), self.dispSource) QObject.connect(self.admin_pannel.choose_event_type, SIGNAL("currentIndexChanged(int)"), self.dispEventType) def addEvents(self, events): self.evtx_table_view.addEvents(events) def display(self, chunks, node=None): self.evtx_table_view.clearContents() self.evtx_table_view.setRowCount(0) nb_chunk = 0 evtxInfos = [] for chunk in chunks: events = chunk.events() for event in events: QCoreApplication.processEvents() if node: nodePtr = node.uid() elif self.node: nodePtr = self.node.uid() else: nodePtr = None evtxInfo = EvtxInfo(event, events[event], nb_chunk, nodePtr) evtxInfos.append(evtxInfo) nb_chunk += 1 self.addEvents(evtxInfos) def display_chunk(self, events): self.evtx_table_view.clearContents() self.evtx_table_view.setRowCount(0) evtxInfos = [] for event in events: for evtx in event: QCoreApplication.processEvents() evtxInfo = EvtxInfo(evtx, event[evtx], event[evtx]['chunk_nb'], self.node.uid()) evtxInfos.append(evtxInfo) def dispAdminEvents(self, checked): self.evtx_table_view.clearContents() if self.display_mode == 0: error_list = self.evtx_parser.getEventBylevel(2) self.admin_pannel.admin_events.setText("All events") tmp_list = self.evtx_parser.getEventBylevel(3) error_list.extend(tmp_list) self.display_mode = 1 self.display_chunk(error_list) elif self.display_mode == 1: self.admin_pannel.admin_events.setText("Admin. events") self.display_mode = 0 processus_manager = ModuleProcessusManager() evtx = processus_manager.get('evtx') chunks = evtx.data(self.node.uid()) self.display(chunks, self.node) def dispId(self, checked): txt = self.admin_pannel.id.text() if txt == "": return try: event_list = self.evtx_parser.getEventById(int(txt)) self.evtx_table_view.clearContents() self.evtx_table_view.setRowCount(0) self.display_chunk(event_list) except ValueError: pass def dispIdL(self): txt = self.admin_pannel.id.text() txt = self.admin_pannel.cb.currentText() try: event_list = self.evtx_parser.getEventById(int(txt)) self.evtx_table_view.clearContents() self.evtx_table_view.setRowCount(0) self.display_chunk(event_list) except ValueError: pass def fill_log_viewer(self, item): ptr = item.data(QListWidgetItem.UserType) node = VFS.Get().getNodeById(ptr.toULongLong()[0]) processus_manager = ModuleProcessusManager() evtx = processus_manager.get('evtx') self.node = node self.evtx_parser.chunks = evtx.data(ptr.toULongLong()[0]) self.evtx_parser.node = node self.admin_pannel.cb = self.admin_pannel.initId( evtx.data(ptr.toULongLong()[0]), 'id') self.admin_pannel.cbs = self.admin_pannel.initId( evtx.data(ptr.toULongLong()[0]), 'source') self.display(evtx.data(ptr.toULongLong()[0]), node) def dispDate(self, checked): date_begin = str(self.admin_pannel.select_date_b.dateTime().toString( "yyyy-MM-ddThh:mm:ss")) date_end = str(self.admin_pannel.select_date_e.dateTime().toString( "yyyy-MM-ddThh:mm:ss")) self.evtx_table_view.clearContents() self.evtx_table_view.setRowCount(0) event_list = self.evtx_parser.getEventsBetween(date_begin, date_end) self.display_chunk(event_list) def dispSource(self, checked): txt = self.admin_pannel.source.text() if txt == "": return self.evtx_table_view.clearContents() self.evtx_table_view.setRowCount(0) event_list = self.evtx_parser.getEventBySource(txt) self.display_chunk(event_list) def dispSourceL(self, checked): txt = self.admin_pannel.cbs.currentText() self.evtx_table_view.clearContents() self.evtx_table_view.setRowCount(0) event_list = self.evtx_parser.getEventBySource(txt) self.display_chunk(event_list) def dispEventType(self, index): if index == 0: processus_manager = ModuleProcessusManager() evtx = processus_manager.get('evtx') chunks = evtx.data(self.node.uid()) self.display(chunks, self.node) else: self.evtx_table_view.clearContents() self.evtx_table_view.setRowCount(0) event_list = self.evtx_parser.getEventBylevel(index - 1) self.display_chunk(event_list) def dispEvent(self, row, column): item = self.evtx_table_view.item(row, 4) offset_str = item.text() offset = int(offset_str) item = self.evtx_table_view.item(row, 5) chunk_str = item.text() chunk_nb = int(chunk_str) if self.evtx_table_view.columnCount() == 7: item = self.evtx_table_view.item(row, 6).data(QTableWidgetItem.Type) n = item.toULongLong()[0] self.evtx_parser.node = VFS.Get().getNodeById(n) xml = self.evtx_parser.getXML(chunk_nb, offset, self.evtx_parser.node) xml_str = tostring(xml, "utf-8") self.disp = ViewEvtx() self.disp.view.setAlternatingRowColors(1) self.disp.view.setSelectionBehavior(QAbstractItemView.SelectRows) self.disp.view.setSelectionMode(QAbstractItemView.SingleSelection) self.current_row = row if not row: self.disp.prev_evtx.setEnabled(False) if row + 1 == self.evtx_table_view.rowCount(): self.disp.next_evtx.setEnabled(False) self.widget = EvtxTree(xml_str, self.disp) self.disp.textEdit.setText(self.widget.doc.toString(3)) self.disp.view.expandAll() self.disp.view.resizeColumnToContents(0) if PYQT_VERSION_STR >= "4.5.0": self.disp.next_evtx.clicked.connect(self.nextEvent) self.disp.prev_evtx.clicked.connect(self.prevEvent) self.disp.exec_() del self.disp self.disp = None def nextEvent(self, checked): row = self.current_row + 1 self.disp.prev_evtx.setEnabled(True) while row + 1 != self.evtx_table_view.rowCount( ) and self.evtx_table_view.isRowHidden(row): row += 1 # row = self.current_row item = self.evtx_table_view.item(row, 4) offset_str = item.text() offset = int(offset_str) item = self.evtx_table_view.item(row, 5) chunk_str = item.text() chunk_nb = int(chunk_str) node = None if self.evtx_table_view.columnCount() == 7: item = self.evtx_table_view.item(row, 6) node = VFS.Get().getNodeById(long(item.text())) else: node = self.node self.evtx_table_view.setCurrentCell(row, 0) xml = self.evtx_parser.getXML(chunk_nb, offset, node) xml_str = tostring(xml, "utf-8") self.widget = EvtxTree(xml_str, self.disp) self.disp.textEdit.setText(self.widget.doc.toString(3)) self.disp.view.expandAll() self.disp.view.resizeColumnToContents(0) self.current_row = row while row + 1 != self.evtx_table_view.rowCount(): row += 1 if not self.evtx_table_view.isRowHidden(row): return self.disp.next_evtx.setEnabled(False) def prevEvent(self, checked): row = self.current_row - 1 self.disp.next_evtx.setEnabled(True) while row != 0 and self.evtx_table_view.isRowHidden(row): row -= 1 item = self.evtx_table_view.item(row, 4) offset_str = item.text() offset = int(offset_str) item = self.evtx_table_view.item(row, 5) chunk_str = item.text() chunk_nb = int(chunk_str) node = None if self.evtx_table_view.columnCount() == 7: item = self.evtx_table_view.item(row, 6) node = VFS.Get().getNodeById(long(item.text())) else: node = self.node self.current_row = row self.evtx_table_view.setCurrentCell(self.current_row, 0) xml = self.evtx_parser.getXML(chunk_nb, offset, node) xml_str = tostring(xml, "utf-8") self.widget = EvtxTree(xml_str, self.disp) self.disp.textEdit.setText(self.widget.doc.toString(3)) self.disp.view.expandAll() self.disp.view.resizeColumnToContents(0) while row != 0: row -= 1 if not self.evtx_table_view.isRowHidden(row): return self.disp.prev_evtx.setEnabled(False)
class NetCDF3Browser(QWidget): """netCDF-Browser""" def __init__(self): QWidget.__init__(self) self.layout = QVBoxLayout(self) self.layout.setSpacing(0) self.layout.setMargin(0) self.toolBar = QFrame(self) self.toolBarLayout = QHBoxLayout(self.toolBar) self.toolBarLayout.setMargin(2) self.toolBarLayout.setSpacing(2) self.layout.addWidget(self.toolBar) self.loadButton = QToolButton(self.toolBar) self.loadButton.setText(QCoreApplication.translate('NetCDF3', 'Open...')) self.loadButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.fileOpen))) self.loadButton.setToolTip(QCoreApplication.translate('NetCDF3', 'Open a netCDF3 file')) self.toolBarLayout.addWidget(self.loadButton) self.connect(self.loadButton, SIGNAL('pressed()'), self.loadFile) self.dropButton = QToolButton(self.toolBar) self.dropButton.setText(QCoreApplication.translate('NetCDF3', 'Close All')) self.dropButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.clear))) self.dropButton.setToolTip(QCoreApplication.translate('NetCDF3', 'Drop all open netCDF3 files')) self.toolBarLayout.addWidget(self.dropButton) self.connect(self.dropButton, SIGNAL('pressed()'), self.dropFiles) self.dropButton.setEnabled(False) self.toolBarLayout.addStretch(100) self.splitter = QSplitter(self) self.splitter.setOrientation(Qt.Vertical) self.treeView = QTreeView(self.splitter) self.treeView.setAlternatingRowColors(True) self.treeView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.textBrowser = QTextBrowser(self.splitter) self.layout.addWidget(self.splitter) self.splitter.setStretchFactor(0, 90) self.splitter.setStretchFactor(1, 10) self.model = NetCDF3Model() self.treeView.setModel(self.model) self.treeView.setSortingEnabled(True) self.treeView.expandAll() self.connect(self.treeView.selectionModel(), SIGNAL("currentChanged(QModelIndex, QModelIndex)"), self.showItem) self.connect(self.treeView, SIGNAL("doubleClicked(QModelIndex)"), self.itemAction) ftActions = SimuVis4.Globals.fileTypeActions ftActions.addAction(self.loadFile, ('application/x-netcdf',), QCoreApplication.translate('NetCDF3', 'Open in netCDF3 browser'), 10) def loadFile(self, fn=None): if not fn: fn = QFileDialog.getOpenFileName(self, QCoreApplication.translate('NetCDF3', "Select netCDF3 file to open"), SimuVis4.Globals.defaultFolder) if not fn.isEmpty(): fn = unicode(fn) SimuVis4.Globals.defaultFolder, tmp = os.path.split(fn) else: return self.model.addNcFile(fn) SimuVis4.Globals.dataBrowser.toolBox.setCurrentWidget(self) def dropFiles(self): # FIXME: ... pass def itemAction(self, mi,): # FIXME: use a MIME-Handler here i = self.model.itemFromIndex(mi) t, nc = i.ncItem QMessageBox.information(self, QCoreApplication.translate('NetCDF3', 'netCDF3: Item clicked'), QCoreApplication.translate('NetCDF3', 'You clicked an item in the netCDF3-browser')) def showItem(self, mi, pr): i = self.model.itemFromIndex(mi) t, nc = i.ncItem txt = "" name = str(i.data().toString()) if t == 'F': p, f = os.path.split(name) txt = "<i>File </i><b>%s</b><br> in %s" % (f, p) elif t == 'A': txt = "<i>Attribute </i><b>%s:</b><br>%s" % (name, escape(unicode(nc))) elif t == 'D': txt = "<i>Dimension </i><b>%s:</b><br>%s" % (name, str(nc)) elif t == 'V': txt = "<i>Variable </i><b>%s:</b><br>Typecode: %s<br>Dimensions: %s<br>Shape: %s" % \ (name, nc.typecode(), '*'.join(d for d in nc.dimensions), nc.shape) else: return self.textBrowser.setText(txt)
class DSBrowser(QWidget): """browser for datastorage databases Nodes are identified by a string, containing fields separated by '|'. - first filed is a capital letter: 'R'oot, 'P'roject, sensor'G'roup, 'S'ensor and 'C'hart - second field is the database folder - third filed is the path of the node in the database - for charts the fourth field is the chart name (third is path of sensorgroup in this case) """ def __init__(self): QWidget.__init__(self) self.layout = QVBoxLayout(self) self.layout.setSpacing(0) self.layout.setMargin(0) self.toolBar = QFrame(self) self.toolBarLayout = QHBoxLayout(self.toolBar) self.toolBarLayout.setMargin(2) self.toolBarLayout.setSpacing(2) self.layout.addWidget(self.toolBar) self.loadButton = QToolButton(self.toolBar) self.loadButton.setText(QCoreApplication.translate('DataStorageBrowser', 'Open...')) self.loadButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.fileOpen))) self.loadButton.setToolTip(QCoreApplication.translate('DataStorageBrowser', 'Open a datastorage database')) self.toolBarLayout.addWidget(self.loadButton) self.connect(self.loadButton, SIGNAL('pressed()'), self.loadDatabase) self.expandButton = QToolButton(self.toolBar) self.expandButton.setText('Expand/Collapse') self.expandButton.setIcon(QIcon(QPixmap(Icons.exp_col))) self.expandButton.setToolTip(QCoreApplication.translate('DataStorageBrowser', 'Expand or collapse the whole tree')) self.toolBarLayout.addWidget(self.expandButton) self.connect(self.expandButton, SIGNAL('pressed()'), self.expandCollapseAll) self.searchInput = QLineEdit(self.toolBar) self.searchInput.setText(QCoreApplication.translate('DataStorageBrowser', 'Enter search text here')) self.searchInput.setToolTip(QCoreApplication.translate('DataStorageBrowser', 'Enter search text using wildcards here, press ENTER again to go to next match!')) self.toolBarLayout.addWidget(self.searchInput, 100) self.connect(self.searchInput, SIGNAL('returnPressed()'), self.searchItem) self.helpButton = QToolButton(self.toolBar) self.helpButton.setText(QCoreApplication.translate('DataStorageBrowser', 'Help')) self.helpButton.setIcon(QIcon(QPixmap(SimuVis4.Icons.help))) self.helpButton.setToolTip(QCoreApplication.translate('DataStorageBrowser', 'Show help for DataStorageBrowser')) self.toolBarLayout.addWidget(self.helpButton) self.connect(self.helpButton, SIGNAL('pressed()'), self.showHelp) self.splitter = QSplitter(self) self.splitter.setOrientation(Qt.Vertical) self.treeView = QTreeView(self.splitter) self.treeView.setAlternatingRowColors(True) self.treeView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.treeView.setContextMenuPolicy(Qt.CustomContextMenu) self.treeView.setAutoExpandDelay(500) self.textBrowser = QTextBrowser(self.splitter) self.layout.addWidget(self.splitter) self.splitter.setStretchFactor(0, 60) self.splitter.setStretchFactor(1, 40) self.model = DSModel() self.treeView.setModel(self.model) self.treeView.setSortingEnabled(True) self.treeView.expandAll() self.connect(self.treeView.selectionModel(), SIGNAL("currentChanged(QModelIndex, QModelIndex)"), self.showItem) self.connect(self.treeView, SIGNAL("doubleClicked(QModelIndex)"), self.itemAction) self.connect(self.treeView, SIGNAL("customContextMenuRequested(QPoint)"), self.showContextMenu) self.selectedNode = None self.selectedMI = None self.searchText = '' self.searchResults = [] self.collExpand = SimuVis4.Misc.Switcher() def loadDatabase(self, dn=None): """load a database""" if not dn: dn = QFileDialog.getExistingDirectory(self, QCoreApplication.translate('DataStorageBrowser', "Select a folder containing a datastorage database"), SimuVis4.Globals.defaultFolder) if not dn.isEmpty(): dn = unicode(dn) SimuVis4.Globals.defaultFolder = dn else: return self.model.addDatabase(dn) self.treeView.expandToDepth(1) self.treeView.resizeColumnToContents(0) def showHelp(self): SimuVis4.HelpBrowser.showHelp('/plugin/DataStorageBrowser/index.html') def showItem(self, mi, pr): """show the item at model index mi""" t, n = self.model.dsNode(mi) txt = "" if t == 'R': # FIXME: no metadata? txt = rootInfo.substitute(name=n.name, title=escape(n.title), folder=n.h5dir, projects=len(n)) + formatMetaData(n) elif t == 'P': txt = projectInfo.substitute(name=n.name, path=escape(n.parent.name), title=escape(n.title), groups=len(n)) + formatMetaData(n) elif t == 'G': txt = groupInfo.substitute(name=n.name, path='/'.join(n.path.split('/')[:-1]), title=escape(n.title), sensors=len(n), charts=len(n.charts)) + formatMetaData(n) elif t == 'S': txt = sensorInfo.substitute(name=n.name, path='/'.join(n.path.split('/')[:-1]), title=escape(n.title), start=n.timegrid.start, stop=n.timegrid.stop, step=n.timegrid.step, length=n.datalen()) + formatMetaData(n) elif t == 'C': txt = chartInfo.substitute(name=n.name, path=n.sensorgroup.path) self.textBrowser.setText(txt) def searchItem(self): """execute the search and highlight the (next) result""" txt = str(self.searchInput.text()) if txt != self.searchText: self.searchText = txt tmp = self.model.findItems(txt, Qt.MatchFixedString | Qt.MatchContains | Qt.MatchWildcard | Qt.MatchRecursive) self.searchList = [i.index() for i in tmp] if self.searchList: mi = self.searchList.pop() self.treeView.setCurrentIndex(mi) self.treeView.expand(mi) self.treeView.scrollTo(mi) else: QMessageBox.information(self, QCoreApplication.translate('DataStorageBrowser', 'No (more) matches!'), QCoreApplication.translate('DataStorageBrowser', 'No (more) matches found! Change you search criteria and try again!')) self.searchText = '' def expandCollapseAll(self): if self.collExpand(): self.treeView.collapseAll() else: self.treeView.expandAll() def itemAction(self, mi): """default action (on doubleclick) for item at model index mi""" t, n = self.model.dsNode(mi) if t == 'R': pass elif t == 'P': pass elif t == 'G': pass elif t == 'S': self.showQwtPlot(n) elif t == 'C': self.showMplChart(n) def showContextMenu(self, pos): """show context menu for item at pos""" mi = self.treeView.indexAt(pos) t, n = self.model.dsNode(mi) self.selectedNode = n self.selectedMI = mi m = QMenu() if t == 'R': m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Close'), self.closeDatabase) elif t == 'P': pass elif t == 'G': nCharts = len(n.charts) if nCharts > 0: txt = str(QCoreApplication.translate('DataStorageBrowser', 'Show all Charts (%d)')) % nCharts m.addAction(txt, self.showAllCharts) m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Add Chart'), self.newChart) elif t == 'S': m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Plot (Qwt)'), self.showQwtPlot) elif t == 'C': m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Show'), self.showMplChart) m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Delete'), self.deleteItem) if t in 'RPGS': m.addSeparator() m.addAction(QCoreApplication.translate('DataStorageBrowser', 'Edit metadata'), self.editMetadata) a = m.exec_(self.treeView.mapToGlobal(pos)) def showMplChart(self, node=None): if node is None: node = self.selectedNode showChartMplWindow(node, maximized=showChartMaximized) def showAllCharts(self, node=None): if node is None: node = self.selectedNode for chart in node.charts.values(): showChartMplWindow(chart, maximized=showChartMaximized) def showQwtPlot(self, node=None): if node is None: node = self.selectedNode showQwtPlotWindow(node, maximized=showChartMaximized) def editMetadata(self, node=None): if node is None: node = self.selectedNode editMetadata(node) def closeDatabase(self, mi=None): if mi is None: mi = self.selectedMI self.model.closeDatabase(mi) def newChart(self, mi=None): """add a chart to sensorgroup at mi using the wizard""" if mi is None: mi = self.selectedMI showNewChartWizard(self.model, mi) def deleteItem(self, mi=None): """delete the item at mi""" if mi is None: mi = self.selectedMI self.model.deleteItem(mi)