class ErrorLogDialog(QDialog):
    def __init__(self, parent):
        super(ErrorLogDialog, self).__init__(parent, Qt.WindowStaysOnTopHint)
        self._empty = True
        
        self._initUI()
        self.setWindowTitle("Error")
        get_notification_center().connectLogMessage(self._checkLogMessage)
        
        for record in getCachedLogRecords():
            self._checkLogMessage(record)
        
    def sizeHint(self):
        return QSize(400, 200)
        
    def _initUI(self):
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 10, 0, 0)
        layout.setSpacing(0)
        
        labelLayout = QHBoxLayout()
        labelLayout.addWidget(QLabel(u"Sorry, something went wrong:", self))
        labelLayout.setContentsMargins(10, 0, 0, 0)
        layout.addLayout(labelLayout)
        layout.addSpacing(5)
        self._errorLog = QTextEdit(self)
        self._errorLog.setReadOnly(True)
        self._errorLog.setWordWrapMode(QTextOption.NoWrap)
        self._errorLog.setTextColor(QColor(180, 0, 0))
        self._errorLog.setObjectName(u"__ERROR_LOG_")
        
        self._errorLog.setFrameShape(QFrame.StyledPanel)
        if getPlatform() == PLATFORM_MAC:
            self._errorLog.setStyleSheet("QFrame#__ERROR_LOG_{border-width: 1px; border-top-style: solid; border-right-style: none; border-bottom-style: solid; border-left-style: none; border-color:palette(mid)}");
            
        layout.addWidget(self._errorLog)
        
        bottomWidget = QWidget(self)
        bottomLayout = QHBoxLayout(bottomWidget)
        
        self._notAgain = QCheckBox(u"Please, no more error messages!", self)
        bottomLayout.addWidget(self._notAgain, 1, Qt.AlignTop)
        
        buttonBox = QDialogButtonBox(QDialogButtonBox.Close, Qt.Horizontal, self)
        buttonBox.rejected.connect(self.reject)
        bottomLayout.addWidget(buttonBox)
        
        layout.addWidget(bottomWidget)
        
    @loggingSlot()
    def reject(self):
        self._errorLog.clear()
        self._empty = True
        return QDialog.reject(self)
    
    @loggingSlot(object)
    def _checkLogMessage(self, record):
        try:
            if self._notAgain.checkState() == Qt.Checked:
                return
            if record.levelno >= logging.ERROR:
                recMsg = record.msg
                if not isinstance(recMsg, basestring):
                    recMsg = unicode(recMsg)
                err = convert_string(recMsg) % record.args
                component = record.name
                if component.startswith("lunchinator."):
                    component = component[12:]
                    
                msg = u"%s - In component %s (%s:%d):\n%s" % (strftime("%H:%M:%S", localtime(record.created)),
                                                              component,
                                                              record.pathname,
                                                              record.lineno,
                                                              err)
                if record.exc_info:
                    out = StringIO()
                    traceback.print_tb(record.exc_info[2], file=out)
                    msg += u"\nStack trace:\n" + out.getvalue() + formatException(record.exc_info) + u"\n"
                    
                self._errorLog.append(msg)
                self._empty = False
                if not self.isVisible():
                    self.showNormal()
                    self.raise_()
                    self.activateWindow()
        except:
            from lunchinator.log import getCoreLogger
            getCoreLogger().info(formatException())
class ConsoleWidget(QWidget):
    _RECORD_ROLE = Qt.UserRole + 1
    
    def __init__(self, parent, logger):
        super(ConsoleWidget, self).__init__(parent)
        
        self.logger = logger
        self._errorColor = QVariant(QColor(180, 0, 0))
        self._warningColor = QVariant(QColor(170, 100, 0))
        self._records = []
        
        self._initModel()
        self._initUI()
        
        get_notification_center().connectLogMessage(self._addLogMessage)
        
    def _initUI(self):
        layout = QVBoxLayout(self)
        
        split = QSplitter(Qt.Vertical, self)
        
        layout.setContentsMargins(0, 0, 0, 0)
        
        console = QTreeView(self)
        console.setSortingEnabled(False)
        console.setHeaderHidden(False)
        console.setAlternatingRowColors(True)
        console.setIndentation(0)
        console.setUniformRowHeights(True)
        console.setObjectName(u"__console_log")
        
        console.setFrameShape(QFrame.StyledPanel)
        #if getPlatform() == PLATFORM_MAC:
        #    console.setStyleSheet("QFrame#__console_log{border-width: 1px; border-top-style: none; border-right-style: none; border-bottom-style: solid; border-left-style: none; border-color:palette(mid)}");
        
        console.setModel(self._logModel)
        console.header().setStretchLastSection(False)
        console.header().setResizeMode(3, QHeaderView.Stretch)
        console.selectionModel().selectionChanged.connect(self._selectionChanged)
        split.addWidget(console)
        
        detailsWidget = QWidget(self)
        detailsLayout = QVBoxLayout(detailsWidget)
        detailsLayout.setContentsMargins(0, 0, 0, 0)
        detailsLayout.setSpacing(0)
        
        detailsLayout.addWidget(QLabel(u"Details:", self))
        
        self._detailsView = QTextEdit(self)
        self._detailsView.setReadOnly(True)
        self._detailsView.setWordWrapMode(QTextOption.NoWrap)
        
        detailsLayout.addWidget(self._detailsView, 1)
        
        split.addWidget(detailsWidget)
        
        layout.addWidget(split, 1)
        
    @loggingSlot(QItemSelection, QItemSelection)
    def _selectionChanged(self, newSel, _oldSel):
        if len(newSel.indexes()) == 0:
            self._detailsView.clear()
        else:
            index = newSel.indexes()[0]
            record = self._records[index.row()]
            
            try:
                logMsg = convert_string(record.msg) % record.args
            except:
                logMsg = convert_string(record.msg) + ', '.join(str(arg) for arg in record.args)
            
            msg = u"%s - In %s:%d: %s" % (strftime("%H:%M:%S", localtime(record.created)),
                                          record.pathname,
                                          record.lineno,
                                          logMsg)
            if record.exc_info:
                out = StringIO()
                traceback.print_tb(record.exc_info[2], file=out)
                msg += u"\nStack trace:\n" + out.getvalue() + formatException(record.exc_info) + u"\n"
                
            self._detailsView.setPlainText(msg)
        
    def _initModel(self):
        self._logModel = QStandardItemModel(self)
        self._logModel.setColumnCount(5)
        self._logModel.setHorizontalHeaderLabels([u"Time", u"Level", u"Component", u"Message", u"Source"])
        for record in getCachedLogRecords():
            self._addLogMessage(record)
    
    def _createItem(self, text, error, toolTip=None):
        item = QStandardItem()
        item.setEditable(False)
        item.setText(text)
        if error is 1:
            item.setData(self._warningColor, Qt.ForegroundRole)
        elif error is 2:
            item.setData(self._errorColor, Qt.ForegroundRole)
        if toolTip is None:
            toolTip = text
        item.setData(QVariant(toolTip), Qt.ToolTipRole)
        return item
        
    @loggingSlot(object)
    def _addLogMessage(self, record):
        self._records.append(record)
        
        msg = record.msg
        if not isinstance(msg, basestring):
            msg = unicode(msg)
        try:
            msg = convert_string(msg) % record.args
        except:
            msg = u"(Error formatting log message) " +\
             convert_string(msg) +\
             ', '.join(unicode(v) for v in record.args)
            
        dirname = os.path.dirname(record.pathname)
        source = u"%s:%d" % (os.path.join(os.path.basename(dirname), os.path.basename(record.pathname)), record.lineno)
        fullsource = u"%s:%d" % (record.pathname, record.lineno)
        component = record.name
        if component.startswith("lunchinator."):
            component = component[12:]
        error = 1 if record.levelno == logging.WARNING else 2 if record.levelno == logging.ERROR else 0
        self._logModel.appendRow([self._createItem(strftime("%H:%M:%S", localtime(record.created)), error),
                                  self._createItem(record.levelname, error),
                                  self._createItem(component, error),
                                  self._createItem(msg, error),
                                  self._createItem(source, error, fullsource)])