scripts/gestion/affich_tools.py
glondu c0084562e0 Encodage, Unicode.
darcs-hash:20060218162406-68412-09f830e1b1124d493ea43d4e36d8f6745327ba5d.gz
2006-02-18 17:24:06 +01:00

331 lines
10 KiB
Python
Executable file

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
""" Collection de fonction/classe pour avoir un bel affichage
Copyright (C) Frédéric Pauget
Licence : GPLv2
"""
import sys, sre, os, tempfile
# Détermination de l'encodage
try:
from locale import getpreferredencoding
encoding = getpreferredencoding()
except:
encoding = sys.stdin.encoding or "ISO-8859-15"
if 'TERM' in os.environ and os.environ['TERM'] != 'unknown':
el = os.popen('tput cr ; tput el').read()
else:
el = os.popen('tput -Tvt100 cr ; tput -Tvt100 el').read()
def dialog(backtitle,arg) :
""" Affiche la boite de dialogue défine avec les arguments fournis
(cf man dialog)
si tout se déroule bien retourne :
[ 0, [ reponse(s) ] ]
si annulatin retourne :
[ 1, [] ]
si appui sur ESC demande confirmation de l'abandon et exécute sys.exit(0)
si erreur dans les arguments raise RuntimeError
"""
f = tempfile.NamedTemporaryFile()
cmd = u'LANG=fr_FR@euro /usr/bin/dialog --backtitle "%s" --cancel-label "Retour" %s 2>%s' % (backtitle,arg,f.name)
res = os.system(cmd.encode('iso-8859-15','ignore'))
if res == 256 :
# Annuler
f.close()
return [ 1, [] ]
# Lecture du fichier de résultat et effacement
try:
result=f.readlines()
f.close()
except :
result = [ "n'importe quoi", '']
res = 65280
# Traitement
if res==65280 and result:
# Erreur dans les arguments
raise RuntimeError( arg, result[1].strip() )
elif res==65280 :
# Appui sur ESC
arg1 = u'--title "Annulation" --yesno "Quitter ?\nLes dernières modifications seront perdues." 6 48'
print backtitle
cmd = u'/usr/bin/dialog --backtitle "%s" %s' % (backtitle,arg1)
res = os.system(cmd.encode('iso-8859-15','ignore') )
if res==0 : sys.exit(0)
else : return dialog(backtitle,arg)
elif not result : result=['']
return [ 0, result ]
def coul(txt,col):
"""
Retourne la chaine donnée encadrée des séquences qui
vont bien pour obtenir la couleur souhaitée
Les couleur sont celles de codecol
Il est possible de changer la couleur de fond grace aux couleur f_<couleur>
"""
codecol={'rouge' : 31 , 'vert' : 32 , 'jaune' : 33 , 'bleu': 34 , 'violet' : 35 , 'cyan' : 36 , 'gris' : 30, 'gras' : 50}
try :
if col[:2]=='f_' : add=10; col=col[2:]
else : add=0
txt = "\033[1;%sm%s\033[1;0m" % (codecol[col]+add,txt)
finally :
return txt
OK = coul('OK','vert')
WARNING = coul('WARNING','jaune')
ERREUR = coul('ERREUR','rouge')
def cprint(txt,col):
print coul(txt,col)
def tableau(largeurs,data) :
"""
retourne une chaine formatée repésentant un tableau
largeur est la liste des largeurs des colones
data est une liste de tuples :
[ ( données entète), (données ligne1), .... ]
"""
sep_col = u'|'
# Si l'une des largeurs est '*', alors on la met la plus grande possible
if '*' in largeurs:
rows, cols = get_screen_size()
nlargeurs = []
for n in largeurs:
if n != '*':
nlargeurs.append(n)
else:
nlargeurs.append(max(cols - sum(filter(lambda x:x!='*',largeurs)) - len(largeurs) - 1, 3))
largeurs = nlargeurs
# Ligne de séparation entète corps
s=u'\n'
for l in largeurs :
s+= sep_col + u'-'*l
s += sep_col + u'\n'
nb_cols = len(largeurs)
# Remplissage tableau
f=u''
for ligne in data :
for i in range(0, nb_cols) :
f+= sep_col
# Centrage
l = len(sre.sub('\x1b\[1;([0-9]|[0-9][0-9])m','',ligne[i])) # Longeur sans les chaines de formatage
if l >= largeurs[i] :
f += ligne[i]
else :
n = largeurs[i] - l
f += u' '*(n/2) + ligne[i] + u' '*(n/2 + n%2)
f+= sep_col + u'\n'
# Final
f = f.replace(u'\n',s,1) # Insertion du séparateur entète - corps
return f[:-1] # Supression du \n final
def tableau_ng(data,titre=None,largeur=None,alignement=None,format=None) :
"""
Retourne une chaine formatée repésentant un tableau
data : liste de listes, chacune contenant les valeurs d'une ligne
titre : liste des titres
Si none, n'affiche pas de ligne de titre
largeur : liste des largeurs des colonnes, '*' met la plus grande
largeur possible.
Si None, réduit aux max chaque colonne
alignement : liste des alignements : c = centrer
g = gauche
d = droit
Si None, met c pour chaque colonne
format : liste des formats : s = string
o = octet
Si None, s pour chaque colonne
"""
sep_col = u'|'
if data :
nbcols = len(data[0])
elif titre :
nbcols = len(titre)
else :
return u'Aucune donnée'
# Formats
#########
if not format :
format = ['s'] * nbcols
def reformate (data, format) :
if format == 's' :
return str(data)
elif format == 'o' :
data = float(data)
if data > 1024**3 :
return str(round(data/1024**3,1))+'Go'
elif data > 1024**2 :
return str(round(data/1024**2,1))+'Mo'
elif data > 1024 :
return str(round(data/1024,1))+'ko'
else :
return str(round(data,1))+'o'
data = [ [ reformate(ligne[i],format[i]) for i in range(nbcols) ] for ligne in data ]
# Largeurs
##########
if not largeur :
largeur = [ max([len(sre.sub('\x1b\[1;([0-9]|[0-9][0-9])m','',ligne[i])) for ligne in data]) for i in range(nbcols) ]
elif '*' in largeur:
rows, cols = get_screen_size()
for i in range(nbcols) :
if largeur[i] in ['*',-1] :
largeur[i] = max(cols - sum([l for l in largeur if l != '*']) - nbcols - 1, 3)
break
# Alignement
############
if not alignement :
alignement = ['c'] * nbcols
def aligne (data, alignement, largeur) :
# Longeur sans les chaines de formatage
l = len(sre.sub('\x1b\[1;([0-9]|[0-9][0-9])m','',data))
# Alignement
if l > largeur :
# découpage d'une chaine trop longue
regexp = sre.compile('\x1b\[1;([0-9]|[0-9][0-9])m')
new_data = u''
new_len = 0
# On laisse la mise en forme et on coupe les caratères affichés
while True :
s = regexp.search(data)
if s and not s.start() :
# c'est de la mise en forme
new_data += data[:s.end()]
data = data[s.end():]
elif new_len < largeur - 1 :
# c'est un caratère normal, et il y a la place
new_data += data[0]
data = data[1:]
new_len += 1
else :
# c'est un caratère normal mais on a dépassé le max
data = data[1:]
if not data :
return new_data + '*'
elif l == largeur :
return data
elif alignement == 'g' :
return u' ' + data + u' '*(largeur-l-1)
elif alignement == 'd' :
return u' '*(largeur-l-1) + data + u' '
else :
return u' '*((largeur-l)/2) + data + u' '*((largeur-l+1)/2)
data = [ [ aligne(ligne[i],alignement[i],largeur[i]) for i in range(nbcols) ] for ligne in data ]
# Le titre
##########
if titre :
# ligne de titre
chaine = sep_col + sep_col.join([aligne(titre[i],'c',largeur[i]) for i in range(nbcols)]) + sep_col + u'\n'
# ligne de séparation
chaine += sep_col + u'+'.join([u'-'*largeur[i] for i in range(nbcols)]) + sep_col + u'\n'
else :
chaine = u''
# Les données
#############
chaine += u'\n'.join([sep_col + sep_col.join([ligne[i] for i in range(nbcols)]) + sep_col for ligne in data])
return chaine
def get_screen_size():
"""Retourne la taille de l'écran.
Sous la forme d'un tuble (lignes, colonnes)"""
try:
from termios import TIOCGWINSZ
from struct import pack, unpack
from fcntl import ioctl
s = pack("HHHH", 0, 0, 0, 0)
rows, cols = unpack("HHHH", ioctl(sys.stdout.fileno(), TIOCGWINSZ, s))[:2]
return (rows, cols)
except:
return (24, 80)
def prompt(prompt, defaut='', couleur='gras'):
u"""
Pose la question prompt en couleur (défaut gras), retourne la réponse.
"""
sys.stdout.write(coul(prompt, couleur).encode(encoding))
if defaut :
sys.stdout.write((" [%s]" % defaut).encode(encoding))
sys.stdout.write(" ".encode(encoding))
v = sys.stdin.readline().decode(encoding).strip()
if not v: v = defaut
return v
class anim :
""" Permet de créer une animation :
truc................./
truc.................-
truc.................\
truc.................|
ou une barre de progression si le nombre total d'itérations est founi.
"""
def __init__(self,truc,iter=0) :
""" Affichage de :
truc................."""
self.txt = truc + '.'*(45-len(truc))
self.c = 1
self.iter = iter
sys.stdout.write(self.txt)
sys.stdout.flush()
def reinit(self) :
""" Efface la ligne courrante et
affiche : truc................. """
sys.stdout.write(el + self.txt)
if self.iter :
sys.stdout.write(' '*28)
sys.stdout.write(el + self.txt)
sys.stdout.flush()
def cycle(self) :
""" Efface la ligne courrante et
affiche : truc..................?
? caratère variant à chaque appel """
sys.stdout.write(el + self.txt)
if self.iter!=0 :
sys.stdout.write('[')
av = float(self.c) / float(self.iter)
n = int(20 * av)
sys.stdout.write('='*n)
sys.stdout.write('>')
sys.stdout.write(' '*(20 - n))
sys.stdout.write('] %3i%%' % int(100 * av) )
else :
sys.stdout.write('/-\|'[self.c%4])
sys.stdout.flush()
self.c += 1