coriolis/crlcore/python/helpers/io.py

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