Source code for brainvisa.processing.qt4gui.neuroLogGUI

# -*- coding: utf-8 -*-
#  This software and supporting documentation are distributed by
#      Institut Federatif de Recherche 49
#      CEA/NeuroSpin, Batiment 145,
#      91191 Gif-sur-Yvette cedex
#      France
#
# This software is governed by the CeCILL license version 2 under
# French law and abiding by the rules of distribution of free software.
# You can  use, modify and/or redistribute the software under the
# terms of the CeCILL license version 2 as circulated by CEA, CNRS
# and INRIA at the following URL "http://www.cecill.info".
#
# As a counterpart to the access to the source code and  rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty  and the software's author,  the holder of the
# economic rights,  and the successive licensors  have only  limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading,  using,  modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean  that it is complicated to manipulate,  and  that  also
# therefore means  that it is reserved for developers  and  experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and,  more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license version 2 and that you accept its terms.

from __future__ import absolute_import
import time
import os
from soma.qt_gui.qt_backend.Qt import QWidget, QVBoxLayout, QIcon, QSplitter, Qt, QSizePolicy, QSize, QTreeWidget, QTreeWidgetItem, QTreeWidgetItemIterator, QHBoxLayout, QPushButton, QObject, QFileDialog, QKeySequence, QInputDialog, QLineEdit
from soma.qt_gui.qt_backend.Qt import QApplication
from brainvisa.processing import neuroLog
from brainvisa.processing import neuroException
from brainvisa.configuration import neuroConfig
from soma.qtgui.api import TextEditWithSearch
from soma.qt_gui import qt_backend
import sys
import sip
import six

[docs]class LogItemsViewer(QWidget): """ Widget to visualize a list of :py:class:`neuroLog.LogFile.Item`. It is compound of a splitter with the list of items displayed as a QTreeWidget at the left and the text of the content of the selected item at the right side. A contextual menu is available on the content panel to search a string in the text. """ def __init__(self, logitems=[], parent=None): QWidget.__init__(self, parent) layout = QVBoxLayout() self.setLayout(layout) self._pixmaps = {} splitter = QSplitter(Qt.Horizontal) splitter.setSizePolicy( QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)) layout.addWidget(splitter) self._list = QTreeWidget(splitter) self._list.setColumnCount(2) self._list.setHeaderLabels([_t_('Description'), _t_('Date')]) self._list.setAllColumnsShowFocus(1) self._list.setIconSize(QSize(32, 32)) self._list.setSizePolicy( QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)) self._list.setRootIsDecorated(1) self.searchResults = None self.searchText = "" self._content = TextEditWithSearch(splitter) # QTextView( splitter ) self._content.setReadOnly(True) self._content.setSizePolicy( QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)) splitter.setStretchFactor(0, 1) splitter.setStretchFactor(1, 2) self._list.currentItemChanged.connect(self._updateContent) self.refresh(logitems) firstItem = self._list.topLevelItem(0) if firstItem: self._updateContent(firstItem) def refresh(self, logitems): # Save list state itemIndex = 0 currentItemIndex = -1 listState = [] it = QTreeWidgetItemIterator(self._list) while it.value(): currentItem = it.value() listState.append(currentItem.isExpanded()) if self._list.currentItem() is currentItem: currentItemIndex = itemIndex it += 1 itemIndex += 1 # Erase list self._list.clear() self._contents = {} # Reread log and restore list state after = None currentItemList = [] itemIndex = -1 for item in logitems: (after, itemIndex) = self._addLogItem(item, self._list, after, itemIndex, listState, currentItemIndex, currentItemList) if currentItemList: self._list.setCurrentItem(currentItemList[0]) self._list.resizeColumnToContents(0) def _addLogItem(self, item, parent, after, itemIndex, listState, currentItemIndex, currentItemList): viewItem = QTreeWidgetItem(parent) if viewItem.__class__.__hash__ is None: viewItem.__class__.__hash__ = lambda self: sip.unwrapinstance(self) viewItem.setText(0, item.what()) viewItem.setText(1, time.asctime(time.localtime(item.when()))) if item.icon(): pixmap = self._pixmaps.get(item.icon()) if pixmap is None: pixmap = QIcon( os.path.join(neuroConfig.iconPath, item.icon())) self._pixmaps[item.icon()] = pixmap viewItem.setIcon(0, pixmap) content = item.html() if content: self._contents[viewItem] = content itemIndex += 1 isOpen = 0 if itemIndex < len(listState): isOpen = listState[itemIndex] if itemIndex == currentItemIndex: currentItemList.append(viewItem) for child in item.children(): (after, itemIndex) = self._addLogItem(child, viewItem, after, itemIndex, listState, currentItemIndex, currentItemList) viewItem.setExpanded(isOpen) return (viewItem, itemIndex) def _updateContent(self, item): self._content.setText(six.text_type(self._contents.get(item, '')))
[docs] def keyPressEvent(self, keyEvent): if (self._list.hasFocus()): if (keyEvent.matches(QKeySequence.Find)): (res, ok) = QInputDialog.getText( self, "Find", "Text to find :", QLineEdit.Normal, self.searchText) if ok: self.searchText = res if self.searchText and ok: self.searchResults = self.findItem(self.searchText) if (self.searchResults): try: item = next(self.searchResults) except StopIteration: item = None elif (keyEvent.matches(QKeySequence.FindNext)): if (self.searchResults is not None): if (self.searchResults): try: item = next(self.searchResults) except StopIteration: item = None if item is None: self.searchResults.close() self.searchResults = None else: QWidget.keyPressEvent(self, keyEvent) else: QWidget.keyPressEvent(self, keyEvent)
[docs] def findItem(self, name): """ Find items that contain the string given in parameters in their name. Each found item is selected and yield (and replace previous selection). Wide search. @type name: string @param name: string searched in items names. @rtype: generator @return: a generator """ it = QTreeWidgetItemIterator(self._list) lastSelection = None while it.value(): item = it.value() if item.text(0).lower().find(name.lower()) >= 0: self._list.setCurrentItem(item) if lastSelection: lastSelection.setSelected(False) lastSelection = item yield item it += 1 yield None
[docs]class LogViewer(QWidget): """ A viewer for a log file. The file is read and its items are displayed in a LogItemsViewer. Buttons are available at the bottom of the window to refresh the display, close the window or open a new log file. """ def __init__(self, fileName, parent=None, name=None): QWidget.__init__(self, parent) if name: self.setObjectName(name) layout = QVBoxLayout() self.setLayout(layout) if getattr(LogViewer, 'pixIcon', None) is None: setattr(LogViewer, 'pixIcon', QIcon( os.path.join(neuroConfig.iconPath, 'icon_log.png'))) self.setWindowIcon(self.pixIcon) self.logitems_viewer = LogItemsViewer([], self) layout.addWidget(self.logitems_viewer) hb = QHBoxLayout() layout.addLayout(hb) hb.setContentsMargins(5, 5, 5, 5) btn = QPushButton(_t_('&Refresh')) btn.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) hb.addWidget(btn) btn.clicked.connect(self.refresh) btn = QPushButton(_t_('&Close')) hb.addWidget(btn) btn.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) btn.clicked.connect(self.close) btn = QPushButton(_t_('&Open...')) hb.addWidget(btn) btn.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) btn.clicked.connect(self.open) neuroConfig.registerObject(self) self.setLogFile(fileName) if hasattr(self, 'screen'): screen = self.screen() else: screen = QApplication.primaryScreen() ds = screen.size() self.resize(min(1200, ds.width()), min(800, ds.height())) def setLogFile(self, fileName): self._fileName = fileName self.setWindowTitle(self._fileName) self.refresh()
[docs] def closeEvent(self, event): neuroConfig.unregisterObject(self) QWidget.closeEvent(self, event) event.accept()
def refresh(self): try: reader = neuroLog.LogFileReader(self._fileName) except IOError: neuroException.showException() reader = None # Reread log and restore list state logitems = reader.read() self.logitems_viewer.refresh(logitems) def open(self): # QFileDialog.getOpenFileName( QWidget * parent = 0, const QString & caption = QString(), const QString & dir = QString(), const QString & filter = QString(), QString * selectedFilter = 0, Options options = 0) # workaround a bug in PyQt ? Param 5 doesn't work; try to use kwargs import sipconfig if sipconfig.Configuration().sip_version >= 0x040a00: logFileName = six.text_type(qt_backend.getOpenFileName( None, _t_('Open log file'), self._fileName, '', options=QFileDialog.DontUseNativeDialog)) else: logFileName = six.text_type(qt_backend.getOpenFileName( None, _t_('Open log file'), self._fileName, '', None, QFileDialog.DontUseNativeDialog)) if logFileName: try: self.setLogFile(logFileName) except Exception: neuroException.showException()
def showLog(fileName): l = LogViewer(fileName) l.show()