306 lines
10 KiB
Python
306 lines
10 KiB
Python
# -*- mode:Python -*-
|
|
#
|
|
# This file is part of the Coriolis Software.
|
|
# Copyright (c) SU 2012-2020, All Rights Reserved
|
|
#
|
|
# +-----------------------------------------------------------------+
|
|
# | C O R I O L I S |
|
|
# | Alliance / Hurricane Interface |
|
|
# | |
|
|
# | Author : Jean-Paul Chaput |
|
|
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
|
# | =============================================================== |
|
|
# | Python : "./crlcore/helpers/io.py" |
|
|
# +-----------------------------------------------------------------+
|
|
|
|
from __future__ import print_function
|
|
import sys
|
|
import os
|
|
import os.path
|
|
import re
|
|
import traceback
|
|
try:
|
|
from PyQt4.QtCore import Qt
|
|
from PyQt4.QtGui import QSizePolicy
|
|
from PyQt4.QtGui import QDialog
|
|
from PyQt4.QtGui import QPalette
|
|
from PyQt4.QtGui import QColor
|
|
from PyQt4.QtGui import QFont
|
|
from PyQt4.QtGui import QFontMetrics
|
|
from PyQt4.QtGui import QWidget
|
|
from PyQt4.QtGui import QFrame
|
|
from PyQt4.QtGui import QLabel
|
|
from PyQt4.QtGui import QPixmap
|
|
from PyQt4.QtGui import QPushButton
|
|
from PyQt4.QtGui import QTextEdit
|
|
from PyQt4.QtGui import QVBoxLayout
|
|
from PyQt4.QtGui import QHBoxLayout
|
|
from PyQt4.QtGui import QAction
|
|
from PyQt4.QtGui import QKeySequence
|
|
except Exception, e:
|
|
try:
|
|
from PyQt5.QtCore import Qt
|
|
from PyQt5.QtWidgets import QSizePolicy
|
|
from PyQt5.QtWidgets import QDialog
|
|
from PyQt5.QtGui import QPalette
|
|
from PyQt5.QtGui import QColor
|
|
from PyQt5.QtGui import QFont
|
|
from PyQt5.QtGui import QFontMetrics
|
|
from PyQt5.QtWidgets import QWidget
|
|
from PyQt5.QtWidgets import QFrame
|
|
from PyQt5.QtWidgets import QLabel
|
|
from PyQt5.QtGui import QPixmap
|
|
from PyQt5.QtWidgets import QPushButton
|
|
from PyQt5.QtWidgets import QTextEdit
|
|
from PyQt5.QtWidgets import QVBoxLayout
|
|
from PyQt5.QtWidgets import QHBoxLayout
|
|
from PyQt5.QtWidgets import QAction
|
|
from PyQt5.QtGui import QKeySequence
|
|
except e:
|
|
print( '[ERROR] helpers.io, neither PyQt4 nor PyQt5 is available.' )
|
|
sys.exit( 1 )
|
|
import Cfg
|
|
import helpers
|
|
from Hurricane import UpdateSession
|
|
import Viewer
|
|
|
|
|
|
# -------------------------------------------------------------------
|
|
# Class : "ErrorWidget".
|
|
|
|
class ErrorWidget ( QDialog ):
|
|
|
|
def __init__ ( self, e ):
|
|
QWidget.__init__ ( self, None )
|
|
|
|
self.setWindowTitle( 'Error' )
|
|
|
|
message = QLabel( e.getLinesAsString() )
|
|
message.setAlignment( Qt.AlignLeft )
|
|
message.setFont( QFont('Courier',10,QFont.Bold) )
|
|
|
|
error = QLabel( '[ERROR]' )
|
|
error.setAlignment( Qt.AlignLeft )
|
|
font = error.font()
|
|
font.setWeight( QFont.Bold )
|
|
error.setFont( font )
|
|
|
|
self._tryCont = QPushButton()
|
|
self._tryCont.setSizePolicy( QSizePolicy.Fixed, QSizePolicy.Fixed )
|
|
self._tryCont.setText ( 'Try to continue' )
|
|
self._abort = QPushButton()
|
|
self._abort.setSizePolicy( QSizePolicy.Fixed, QSizePolicy.Fixed )
|
|
self._abort.setText ( 'Abort' )
|
|
self._abort.setDefault ( True )
|
|
|
|
traceFont = QFont('Courier',10,QFont.Normal)
|
|
lineHeight = QFontMetrics( traceFont ).height()
|
|
traceText = helpers.textStackTrace( e.trace, False, e.scriptPath )
|
|
lineCount = traceText.count( '\n' ) + 2
|
|
minimumWidth = 400
|
|
if Viewer.Graphics.isHighDpi(): minimumWidth = 2100
|
|
self._trace = QTextEdit()
|
|
self._trace.setReadOnly ( True );
|
|
self._trace.setLineWrapMode( QTextEdit.NoWrap );
|
|
self._trace.setMinimumSize ( minimumWidth, lineCount*lineHeight );
|
|
self._trace.setFont ( traceFont )
|
|
self._trace.setText ( traceText )
|
|
|
|
buttonLayout = QHBoxLayout()
|
|
buttonLayout.addStretch( 1 )
|
|
buttonLayout.addWidget ( self._tryCont )
|
|
buttonLayout.addStretch( 1 )
|
|
buttonLayout.addWidget ( self._abort )
|
|
buttonLayout.addStretch( 1 )
|
|
|
|
vLayout = QVBoxLayout()
|
|
vLayout.addWidget ( error )
|
|
vLayout.addStretch( 1 )
|
|
vLayout.addWidget ( message )
|
|
vLayout.addStretch( 1 )
|
|
vLayout.addWidget ( self._trace )
|
|
vLayout.addStretch( 1 )
|
|
vLayout.addLayout ( buttonLayout )
|
|
|
|
pixmapWidth = 150
|
|
if not Viewer.Graphics.isHighDpi(): pixmapWidth = 70
|
|
pixmap = QPixmap( ':/images/angry-birds-red.png' )
|
|
pixmap = pixmap.scaledToWidth( pixmapWidth )
|
|
icon = QLabel()
|
|
icon.setPixmap( pixmap )
|
|
|
|
hLayout = QHBoxLayout()
|
|
hLayout.addWidget( icon )
|
|
hLayout.addLayout( vLayout )
|
|
self.setLayout( hLayout )
|
|
|
|
self._tryCont.clicked.connect( self.accept )
|
|
self._abort .clicked.connect( self.reject )
|
|
|
|
self._exitAction = QAction( '&Exit', self )
|
|
self._exitAction.setStatusTip( 'Exit Coriolis' )
|
|
self._exitAction.setShortcut ( QKeySequence('CTRL+Q') )
|
|
self._exitAction.triggered.connect( self.reject )
|
|
self.addAction( self._exitAction )
|
|
|
|
self._closeAction = QAction( '&Close', self )
|
|
self._closeAction.setStatusTip( 'Try to continue' )
|
|
self._closeAction.setShortcut ( QKeySequence('CTRL+W') )
|
|
self._closeAction.triggered.connect( self.reject )
|
|
self.addAction( self._closeAction )
|
|
|
|
return
|
|
|
|
def closeEvent ( self, event ):
|
|
self.setResult( QDialog.Rejected )
|
|
event.accept()
|
|
return
|
|
|
|
|
|
# -------------------------------------------------------------------
|
|
# Class : "ErrorMessage".
|
|
|
|
class ErrorMessage ( Exception ):
|
|
|
|
def __init__ ( self, code, *arguments ):
|
|
self.scriptPath = None
|
|
self.trace = traceback.extract_stack()
|
|
self.code = code
|
|
self.errors = [ 'Malformed call to ErrorMessage().'
|
|
, 'args:"{}"'.format(arguments) ]
|
|
|
|
if not isinstance(self.code,int):
|
|
self.errors = [ 'Malformed call to ErrorMessage(), first argument (code) must be an integer.'
|
|
, 'code:"{}"'.format(code)
|
|
, 'args:"{}"'.format(arguments) ]
|
|
return
|
|
|
|
text = None
|
|
if len(arguments) == 1:
|
|
if isinstance(arguments[0],Exception): text = str(arguments[0]).split('\n')
|
|
else:
|
|
self.errors = arguments[0]
|
|
elif len(arguments) > 1:
|
|
sys.stdout.flush()
|
|
text = list(arguments)
|
|
|
|
if text:
|
|
self.errors = []
|
|
while len(text[0]) == 0: del text[0]
|
|
|
|
lstrip = 0
|
|
if text[0].startswith('[ERROR]'): lstrip = 8
|
|
|
|
for line in text:
|
|
if line[0:lstrip] == ' '*lstrip or \
|
|
line[0:lstrip-1] == '[ERROR]':
|
|
self.errors += [ line[lstrip:] ]
|
|
else:
|
|
self.errors += [ line.lstrip() ]
|
|
sys.stdout.flush()
|
|
return
|
|
|
|
def __str__ ( self ):
|
|
if not isinstance(self.errors,list):
|
|
return "[ERROR] %s" % self.errors
|
|
|
|
formatted = "\n"
|
|
for i in range(len(self.errors)):
|
|
if i == 0: formatted += "[ERROR] %s" % self.errors[i]
|
|
else: formatted += " %s" % self.errors[i]
|
|
if i+1 < len(self.errors): formatted += "\n"
|
|
return formatted
|
|
|
|
def getLinesAsString ( self ):
|
|
if not isinstance(self.errors,list): return self.errors
|
|
|
|
lines = ''
|
|
for line in self.errors: lines += line + '\n'
|
|
return lines
|
|
|
|
def addMessage ( self, message ):
|
|
if not isinstance(self.errors,list):
|
|
self.errors = [ self.errors ]
|
|
if isinstance(message,list):
|
|
for line in message:
|
|
self.errors += [ line ]
|
|
else:
|
|
self.errors += [ message ]
|
|
return
|
|
|
|
def terminate ( self ):
|
|
print( self )
|
|
sys.exit( self.code )
|
|
|
|
@staticmethod
|
|
def show ( code, *arguments ):
|
|
e = ErrorMessage( code, *arguments )
|
|
if Viewer.Graphics.get().isEnabled():
|
|
tryCont = ErrorWidget( e ).exec_()
|
|
if not tryCont: raise e
|
|
else:
|
|
raise e
|
|
return
|
|
|
|
|
|
# -------------------------------------------------------------------
|
|
# Function : "catch()".
|
|
#
|
|
# Try to smartly display any exception on the TTY and the graphic
|
|
# display, if available.
|
|
|
|
def catch ( errorObject ):
|
|
if isinstance(errorObject,ErrorMessage):
|
|
em = errorObject
|
|
else:
|
|
em = ErrorMessage( 2, errorObject )
|
|
em.trace = traceback.extract_tb( sys.exc_info()[2] )
|
|
#em.scriptPath = __file__
|
|
|
|
print( em )
|
|
print( helpers.textStackTrace( em.trace, True, em.scriptPath ) )
|
|
|
|
if Viewer.Graphics.get().isEnabled():
|
|
tryCont = ErrorWidget( em ).exec_()
|
|
|
|
if UpdateSession.getStackSize() > 0: UpdateSession.close()
|
|
return
|
|
|
|
|
|
# -------------------------------------------------------------------
|
|
# Class : "WarningMessage".
|
|
|
|
class WarningMessage ( Exception ):
|
|
|
|
def __init__ ( self, message ):
|
|
self._warnings = message
|
|
return
|
|
|
|
def __str__ ( self ):
|
|
if not isinstance(self._warnings,list):
|
|
return "[WARNING] %s" % self._warnings
|
|
|
|
formatted = "\n"
|
|
for i in range(len(self._warnings)):
|
|
if i == 0: formatted += "[WARNING] %s" % self._warnings[i]
|
|
else: formatted += " %s" % self._warnings[i]
|
|
if i+1 < len(self._warnings): formatted += "\n"
|
|
return formatted
|
|
|
|
|
|
# -------------------------------------------------------------------
|
|
# Function : "vprint()".
|
|
#
|
|
# Small wrap around print to make use of the verbosity levels.
|
|
|
|
def isVL ( level ):
|
|
confLevel = 0
|
|
if Cfg.getParamBool('misc.verboseLevel1').asBool(): confLevel = 1
|
|
if Cfg.getParamBool('misc.verboseLevel2').asBool(): confLevel = 2
|
|
return confLevel >= level
|
|
|
|
|
|
def vprint ( level, message ):
|
|
if isVL(level): print( message )
|
|
return
|