mainWindow.py

Aller à la documentation de ce fichier.
00001 #!/usr/bin/python
00002 # -*- coding: utf-8 -*-
00003 #       $Id: mainWindow.py 47 2011-06-13 10:20:14Z georgesk $   
00004 
00005 licence={}
00006 licence['en']="""
00007     file mainWindow.py
00008     this file is part of the project scolasync
00009     
00010     Copyright (C) 2010 Georges Khaznadar <georgesk@ofset.org>
00011 
00012     This program is free software: you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation, either version3 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00024 """
00025 
00026 from PyQt4.QtCore import *
00027 from PyQt4.QtGui import *
00028 import ownedUsbDisk, help, copyToDialog1, chooseInSticks, usbThread, preferences
00029 import os.path, operator, subprocess, dbus, re, time
00030 from notification import Notification
00031 import db
00032 from globaldef import logFileName
00033 
00034 # cette donnée est globale, pour être utilisé depuis n'importe quel objet
00035 globalDiskData=ownedUsbDisk.Available(True,access="firstFat")
00036 
00037 ##
00038 # 
00039 #     Renvoie le premier répertoire existant d'une liste de propositions
00040 #     @param l la liste de propositions
00041 #     
00042 def firstdir(l):
00043     for d in l:
00044         if os.path.isdir(d): return d
00045     return None
00046    
00047 ##
00048 # 
00049 #     Renvoie le répertoire où trouver telle ou telle ressource
00050 #     @param which le type de ressource
00051 #     
00052 def _dir(which):
00053     if which=="lang":
00054         return firstdir(["/usr/share/scolasync/lang", "lang"])
00055     elif which=="help":
00056         return firstdir(["/usr/share/scolasync/help", "help"])
00057     elif which=="share":
00058         return firstdir(["/usr/share/scolasync/","share"])
00059     return None
00060 
00061 
00062 class mainWindow(QMainWindow):
00063     ##
00064     # 
00065     #         Le constructeur
00066     #         @param parent un QWidget
00067     #         @param opts une liste d'options extraite à l'aide de getopts
00068     #         @param locale la langue de l'application
00069     #         
00070     def __init__(self, parent, opts, locale="fr_FR"):
00071         QMainWindow.__init__(self)
00072         QWidget.__init__(self, parent)
00073         self.locale=locale
00074         from Ui_mainWindow  import Ui_MainWindow
00075         self.ui = Ui_MainWindow()
00076         self.ui.setupUi(self)
00077         self.t=self.ui.tableView
00078         self.opts=opts
00079         self.applyPreferences()
00080         self.timer=QTimer()
00081         self.updateButtons()
00082         self.timer.start(2000)
00083         self.threads=[]
00084         QObject.connect(self.timer, SIGNAL("timeout()"), self.checkDisks)
00085         QObject.connect(self.ui.helpButton, SIGNAL("clicked()"), self.help)
00086         QObject.connect(self.ui.umountButton, SIGNAL("clicked()"), self.umount)
00087         QObject.connect(self.ui.toButton, SIGNAL("clicked()"), self.copyTo)
00088         QObject.connect(self.ui.fromButton, SIGNAL("clicked()"), self.copyFrom)
00089         QObject.connect(self.ui.delButton, SIGNAL("clicked()"), self.delFiles)
00090         QObject.connect(self.ui.preferenceButton, SIGNAL("clicked()"), self.preference)
00091         QObject.connect(self.ui.tableView, SIGNAL("doubleClicked(const QModelIndex&)"), self.tableClicked)
00092 
00093     ##
00094     # 
00095     #         Applique les préférences et les options de ligne de commande
00096     #         
00097     def applyPreferences(self):
00098         global globalDiskData
00099         prefs=db.readPrefs()
00100         self.workdir=prefs["workdir"]
00101         # on active les cases à cocher si ça a été réclamé par les options
00102         # ou par les préférences
00103         self.checkable=("--check","") in self.opts or ("-c","") in self.opts or prefs["checkable"]
00104         other=ownedUsbDisk.Available(self.checkable,access="firstFat")
00105         globalDiskData=other
00106         self.header=ownedUsbDisk.uDisk.headers(self.checkable)
00107         self.connectTableModel(other)
00108         self.t.setSortingEnabled(True)
00109         self.t.resizeColumnsToContents()
00110 
00111     ##
00112     # 
00113     #         change le répertoire par défaut contenant les fichiers de travail
00114     #         @param newDir le nouveau nom de répertoire
00115     #         
00116     def changeWd(self, newDir):
00117         self.workdir=newDir
00118         db.setWd(newDir)
00119 
00120     ##
00121     # 
00122     #         fonction de rappel pour un double clic sur un élément de la table
00123     #         @param idx un QModelIndex
00124     #         
00125     def tableClicked(self, idx):
00126         global globalDiskData
00127         c=idx.column()
00128         r=idx.row()
00129         h=self.header[c]
00130         if c==0 and self.checkable:
00131             # case à cocher
00132             pass
00133         elif c==1:
00134             # case du propriétaire
00135             self.editOwner(r)
00136         elif "device-mount-paths" in h:
00137             cmd=u"nautilus '%s'" %idx.data().toString ()
00138             subprocess.call(cmd, shell=True)
00139         elif "device-size" in h:
00140             path=globalDiskData[r][self.header.index("1device-mount-paths")]
00141             cmd =u"df '%s'" %path
00142             dfOutput=subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).communicate()[0].split("\n")[-2]
00143             m = re.match("(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+).*", dfOutput).groups()
00144             print m
00145             dev,total,used,remain,pcent,path=m
00146             pcent=int(pcent[:-1])
00147             from diskFull import mainWindow
00148             w=mainWindow(self,pcent,title=path, total=total, used=used)
00149             w.show()
00150         else:
00151             QMessageBox.warning(None,
00152                                 QApplication.translate("Dialog","Double-clic non pris en compte",None, QApplication.UnicodeUTF8),
00153                                 QApplication.translate("Dialog","pas d'action pour l'attribut %1",None, QApplication.UnicodeUTF8).arg(h))
00154 
00155     ##
00156     # 
00157     #         trouve le disque qui correspond à une ligne du tableau
00158     #         @param ligne la ligne du tableau qui concerne une clé
00159     #         @return le disque correspondant à la ligne de tableau (type uDisk)
00160     #         
00161     def diskFromTableRow(self,ligne):
00162         global globalDiskData
00163         stickid=globalDiskData[ligne][self.header.index("5drive-serial")]
00164         found=False
00165         for d in globalDiskData.disks.keys():
00166             if d.showableProp("drive-serial")==stickid:
00167                 found=True
00168                 break
00169         if found:
00170             return d
00171         else:
00172             return None
00173         
00174     ##
00175     # 
00176     #         Édition du propriétaire d'une clé.
00177     #         @param ligne la ligne du tableau qui concerne une clé
00178     #         
00179     def editOwner(self, ligne):
00180         global globalDiskData
00181         student=globalDiskData[ligne][1]
00182         ownedUsbDisk.editRecord(self.diskFromTableRow(ligne), student)
00183         other=ownedUsbDisk.Available(self.checkable,access="firstFat")
00184         globalDiskData=other
00185         self.connectTableModel(other)
00186         
00187     ##
00188     # 
00189     #         Désactive ou active les flèches selon que l'option correspondante
00190     #         est possible ou non. Pour les flèches : ça aurait du sens de préparer
00191     #         une opération de copie avant même de brancher des clés, donc on les
00192     #         active. Par contre démonter les clés quand elles sont absentes ça
00193     #         n'a pas d'utilité.
00194     #         
00195     def updateButtons(self):
00196         global globalDiskData
00197         if len(globalDiskData)>0:
00198             self.ui.toButton.setEnabled(True)
00199             self.ui.fromButton.setEnabled(True)
00200             self.ui.umountButton.setEnabled(True)
00201         else:
00202             self.ui.toButton.setEnabled(False)
00203             self.ui.fromButton.setEnabled(False)
00204             self.ui.umountButton.setEnabled(False)
00205 
00206     ##
00207     # 
00208     #         lance le dialogue des préférences
00209     #         
00210     def preference(self):
00211         pref=preferences.preferenceWindow()
00212         pref.setValues(db.readPrefs())
00213         pref.show()
00214         pref.exec_()
00215         if pref.result()==QDialog.Accepted:
00216             db.writePrefs(pref.values())
00217             # on applique les préférences tout de suite sans redémarrer
00218             self.applyPreferences()
00219             
00220     ##
00221     # 
00222     #         Lance l'action de supprimer des fichiers ou des répertoires dans les clés USB
00223     #         
00224     def delFiles(self):
00225         global globalDiskData
00226         titre1=QApplication.translate("Dialog","Choix de fichiers à supprimer",None, QApplication.UnicodeUTF8)
00227         titre2=QApplication.translate("Dialog","Choix de fichiers à supprimer (jokers autorisés)",None, QApplication.UnicodeUTF8)
00228         d=chooseInSticks.chooseDialog(self, titre1, titre2)
00229         ok = d.exec_()
00230         if ok:
00231             pathList=map(lambda x: u"%s" %x, d.pathList())
00232             reply=QMessageBox.critical(None,
00233                                        QApplication.translate("Dialog","Vous allez effacer plusieurs baladeurs",None, QApplication.UnicodeUTF8),
00234                                        QApplication.translate("Dialog","Etes-vous certain de vouloir effacer : "+",".join(pathList),None, QApplication.UnicodeUTF8))
00235             if reply == QMessageBox.Ok:
00236                 for p in globalDiskData:
00237                     t=usbThread.threadDeleteInUSB(p,pathList,subdir="Travail", logfile=logFileName)
00238                     t.setDaemon(True)
00239                     self.threads.append(t)
00240                     t.start()
00241         else:
00242             msgBox=QMessageBox.warning(None,
00243                                        QApplication.translate("Dialog","Aucun fichier sélectionné",None, QApplication.UnicodeUTF8),
00244                                        QApplication.translate("Dialog","Veuillez choisir au moins un fichier",None, QApplication.UnicodeUTF8))
00245 
00246     ##
00247     # 
00248     #         Lance l'action de copier vers les clés USB
00249     #         
00250     def copyTo(self):
00251         global globalDiskData
00252         d=copyToDialog1.copyToDialog1(parent=self, workdir=self.workdir)
00253         d.exec_()
00254         if d.ok==True:
00255             for p in globalDiskData:
00256                 subdir=self.workdir
00257                 t=usbThread.threadCopyToUSB(p,d.selectedList(),subdir=subdir, logfile=logFileName)
00258                 t.setDaemon(True)
00259                 self.threads.append(t)
00260                 t.start()
00261         else:
00262             msgBox=QMessageBox.warning(None,
00263                                        QApplication.translate("Dialog","Aucun fichier sélectionné",None, QApplication.UnicodeUTF8),
00264                                        QApplication.translate("Dialog","Veuillez choisir au moins un fichier",None, QApplication.UnicodeUTF8))
00265 
00266     ##
00267     # 
00268     #         Lance l'action de copier depuis les clés USB
00269     #         
00270     def copyFrom(self):
00271         global globalDiskData
00272         titre1=QApplication.translate("Dialog","Choix de fichiers à copier",None, QApplication.UnicodeUTF8)
00273         titre2=QApplication.translate("Dialog", "Choix de fichiers à copier depuis les baladeurs", None, QApplication.UnicodeUTF8)
00274         ok=QApplication.translate("Dialog", "Choix de la destination ...", None, QApplication.UnicodeUTF8)
00275         d=chooseInSticks.chooseDialog(self, title1=titre1, title2=titre2, ok=ok)
00276         ok = d.exec_()
00277         if not ok or len(d.pathList())==0 :
00278             msgBox=QMessageBox.warning(None,
00279                                        QApplication.translate("Dialog","Aucun fichier sélectionné",None, QApplication.UnicodeUTF8),
00280                                        QApplication.translate("Dialog","Veuillez choisir au moins un fichier",None, QApplication.UnicodeUTF8))
00281             return
00282         # bon, alors c'est OK pour le choix des fichiers à envoyer
00283         pathList=map(lambda x: u"%s" %x, d.pathList())
00284         mp=d.selectedDiskMountPoint()
00285         initialPath=os.path.expanduser("~")
00286         destDir = QFileDialog.getExistingDirectory(None,
00287                                                    QApplication.translate("Dialog","Choisir un répertoire de destination",None, QApplication.UnicodeUTF8),
00288                                                    initialPath)
00289         if destDir and len(destDir)>0 :
00290             dest=u"%s" %destDir
00291             for p in globalDiskData:
00292                 # on devrait vérifier s'il y a des données à copier
00293                 # et s'il n'y en a pas, ajouter des lignes au journal
00294                 # mais on va laisser faire ça dans le thread
00295                 # inconvénient : ça crée quelquefois des sous-répertoires
00296                 # vides inutiles dans le répertoire de destination.
00297                 t=usbThread.threadCopyFromUSB(p,pathList,subdir=self.workdir,
00298                                               rootPath=mp,
00299                                               dest=dest,
00300                                               logfile=logFileName)
00301                 t.setDaemon(True)
00302                 self.threads.append(t)
00303                 t.start()
00304             # on ouvre nautilus pour voir le résultat des copies
00305             if QMessageBox.question(None,
00306                                     QApplication.translate("Dialog","Voir les copies",None, QApplication.UnicodeUTF8),
00307                                     QApplication.translate("Dialog","Voulez-vous voir les fichiers copiés ?",None, QApplication.UnicodeUTF8)):
00308                 subprocess.call("nautilus '%s'" %dest,shell=True)
00309         else:
00310             msgBox=QMessageBox.warning(None,
00311                                        QApplication.translate("Dialog","Destination manquante",None, QApplication.UnicodeUTF8),
00312                                        QApplication.translate("Dialog","Veuillez choisir une destination pour la copie des fichiers",None, QApplication.UnicodeUTF8))
00313 
00314     
00315 
00316     ##
00317     # 
00318     #         Affiche le widget d'aide
00319     #         
00320     def help(self):
00321         w=help.helpWindow(None)
00322         w.loadBrowsers(_dir("help"),self.locale)
00323         w.show()
00324         w.exec_()
00325 
00326     ##
00327     # 
00328     #         Démonte et détache les clés USB affichées
00329     #         
00330     def umount(self):
00331         global globalDiskData
00332         buttons=QMessageBox.StandardButtons(QMessageBox.Ok+QMessageBox.Cancel)
00333         button=QMessageBox.critical ( self,
00334                                       QApplication.translate("Main","Démontage des baladeurs",None, QApplication.UnicodeUTF8),
00335                                       QApplication.translate("Main","Êtes-vous sûr de vouloir démonter tous les baladeurs cochés de la liste ?",None, QApplication.UnicodeUTF8),
00336                                       buttons=buttons)
00337         if button!=QMessageBox.Ok:
00338             return
00339         # on parcourt les premières partition FAT
00340         for p in globalDiskData:
00341             # on trouve leurs disques parents
00342             for d in globalDiskData.disks.keys():
00343                 if p in globalDiskData.disks[d] and p.selected:
00344                     # démontage de toutes les partitions du même disque parent
00345                     for partition in globalDiskData.disks[d]:
00346                         devfile=partition.getProp("device-file-by-id")
00347                         if isinstance(devfile, dbus.Array):
00348                             devfile=devfile[0]
00349                         subprocess.call("udisks --unmount %s" %devfile, shell=True)
00350                     # détachement du disque parent
00351                     devfile_disk=d.getProp("device-file-by-id")
00352                     if isinstance(devfile_disk, dbus.Array):
00353                         devfile_disk=devfile_disk[0]
00354                     subprocess.call("udisks --detach %s" %devfile_disk, shell=True)
00355                     break
00356                 
00357 
00358     ##
00359     # 
00360     #         Connecte le modèle de table à la table
00361     #         @param data les données de la table
00362     #         
00363     def connectTableModel(self, data):
00364         self.visibleheader=[]
00365         for h in self.header:
00366             if h in ownedUsbDisk.uDisk._itemNames:
00367                 self.visibleheader.append(self.tr(ownedUsbDisk.uDisk._itemNames[h]))
00368             else:
00369                 self.visibleheader.append(h)
00370         self.tm=usbTableModel(self, self.visibleheader,data,self.checkable)
00371         self.t.setModel(self.tm)
00372         if self.checkable:
00373             self.t.setItemDelegateForColumn(0, CheckBoxDelegate(self))
00374             self.t.setItemDelegateForColumn(1, UsbDiskDelegate(self))
00375         else:
00376             self.t.setItemDelegateForColumn(0, UsbDiskDelegate(self))
00377         
00378     ##
00379     # 
00380     #         fonction relancée périodiquement pour vérifier s'il y a un changement
00381     #         dans le baladeurs, et signaler dans le tableau les threads en cours.
00382     #         Le tableau est complètement régénéré à chaque fois, ce qui n'est pas
00383     #         toujours souhaitable.
00384     #         
00385     def checkDisks(self):
00386         global globalDiskData
00387         other=ownedUsbDisk.Available(self.checkable,access="firstFat")
00388         globalDiskData=other
00389         self.connectTableModel(other)
00390         self.updateButtons()
00391         self.t.resizeColumnsToContents()
00392 
00393 
00394 
00395 ##
00396 # 
00397 #     Un modèle de table pour des séries de clés USB
00398 #     
00399 class usbTableModel(QAbstractTableModel):
00400 
00401     ##
00402     # 
00403     #         @param parent un QObject
00404     #         @param header les en-têtes de colonnes
00405     #         @param donnees les données
00406     #         @param checkable vrai si la première colonne est composée de boîtes à cocher. Faux par défaut
00407     #         
00408     def __init__(self, parent=None, header=[], donnees=None, checkable=False):
00409         QAbstractTableModel.__init__(self,parent)
00410         self.header=header
00411         self.donnees=donnees
00412         self.checkable=checkable
00413         self.pere=parent
00414 
00415     ##
00416     # 
00417     #         @parent un QModelIndex
00418     #         
00419     def rowCount(self, parent):
00420         return len(self.donnees)
00421     
00422     ##
00423     # 
00424     #         @parent un QModelIndex
00425     #         
00426     def columnCount(self, parent): 
00427         return len(self.header) 
00428 
00429     def setData(self, index, value, role):
00430         if index.column()==0 and self.checkable:
00431             self.donnees[index.row()].selected=value
00432             return True
00433         else:
00434             return QAbstractTableModel.setData(self, index, role)
00435         
00436     def data(self, index, role): 
00437         if not index.isValid(): 
00438             return QVariant()
00439         elif role==Qt.ToolTipRole:
00440             c=index.column()
00441             h=self.pere.header[c]
00442             if c==0 and self.checkable:
00443                 return QApplication.translate("Main","Cocher ou décocher cette case en cliquant.",None, QApplication.UnicodeUTF8)
00444             elif c==1:
00445                 return QApplication.translate("Main","Propriétaire de la clé USB ou du baladeur ;<br><b>Double-clic</b> pour modifier.",None, QApplication.UnicodeUTF8)
00446             elif "device-mount-paths" in h:
00447                 return QApplication.translate("Main","Point de montage de la clé USB ou du baladeur ;<br><b>Double-clic</b> pour voir les fichiers.",None, QApplication.UnicodeUTF8)
00448             elif "device-size" in h:
00449                 return QApplication.translate("Main","Capacité de la clé USB ou du baladeur en kO ;<br><b>Double-clic</b> pour voir la place occupée.",None, QApplication.UnicodeUTF8)
00450             elif "drive-vendor" in h:
00451                 return QApplication.translate("Main","Fabricant de la clé USB ou du baladeur.",None, QApplication.UnicodeUTF8)
00452             elif "drive-model" in h:
00453                 return QApplication.translate("Main","Modèle de la clé USB ou du baladeur.",None, QApplication.UnicodeUTF8)
00454             elif "drive-serial" in h:
00455                 return QApplication.translate("Main","Numéro de série de la clé USB ou du baladeur.",None, QApplication.UnicodeUTF8)
00456             else:
00457                 return ""
00458         elif role != Qt.DisplayRole: 
00459             return QVariant()
00460         if index.row()<len(self.donnees):
00461             return QVariant(self.donnees[index.row()][index.column()])
00462         else:
00463             return QVariant()
00464 
00465     def headerData(self, section, orientation, role):
00466         if orientation == Qt.Horizontal and role == Qt.DisplayRole:
00467             return QVariant(self.header[section])
00468         elif orientation == Qt.Vertical and role == Qt.DisplayRole:
00469             return QVariant(section+1)
00470         return QVariant()
00471 
00472     ##
00473     # Sort table by given column number.
00474     #         @param Ncol numéro de la colonne de tri
00475     #         @param order l'odre de tri, Qt.DescendingOrder par défaut
00476     #         
00477     def sort(self, Ncol, order=Qt.DescendingOrder):
00478         self.emit(SIGNAL("layoutAboutToBeChanged()"))
00479         self.donnees = sorted(self.donnees, key=operator.itemgetter(Ncol))        
00480         if order == Qt.DescendingOrder:
00481             self.donnees.reverse()
00482         self.emit(SIGNAL("layoutChanged()"))
00483 
00484 def CheckBoxRect(view_item_style_options):
00485   check_box_style_option=QStyleOptionButton()
00486   check_box_rect = QApplication.style().subElementRect(QStyle.SE_CheckBoxIndicator,check_box_style_option)
00487   check_box_point=QPoint(view_item_style_options.rect.x() + view_item_style_options.rect.width() / 2 - check_box_rect.width() / 2, view_item_style_options.rect.y() + view_item_style_options.rect.height() / 2 - check_box_rect.height() / 2)
00488   return QRect(check_box_point, check_box_rect.size())
00489 
00490 class CheckBoxDelegate(QStyledItemDelegate):
00491     def __init__(self, parent):
00492         QStyledItemDelegate.__init__(self,parent)
00493 
00494     def paint(self, painter, option, index):
00495         checked = index.model().data(index, Qt.DisplayRole).toBool()
00496         check_box_style_option=QStyleOptionButton()
00497         check_box_style_option.state |= QStyle.State_Enabled
00498         if checked:
00499             check_box_style_option.state |= QStyle.State_On
00500         else:
00501             check_box_style_option.state |= QStyle.State_Off
00502         check_box_style_option.rect = CheckBoxRect(option);
00503         QApplication.style().drawControl(QStyle.CE_CheckBox, check_box_style_option, painter)
00504 
00505     def editorEvent(self, event, model, option, index):
00506         if ((event.type() == QEvent.MouseButtonRelease) or (event.type() == QEvent.MouseButtonDblClick)):
00507             if (event.button() != Qt.LeftButton or not CheckBoxRect(option).contains(event.pos())):
00508                 return False
00509             if (event.type() == QEvent.MouseButtonDblClick):
00510                 return True
00511         elif (event.type() == QEvent.KeyPress):
00512             if event.key() != Qt.Key_Space and event.key() != Qt.Key_Select:
00513                 return False
00514         else:
00515             return False
00516         checked = index.model().data(index, Qt.DisplayRole).toBool()
00517         result = model.setData(index, not checked, Qt.EditRole)
00518         return result
00519 
00520         
00521 class UsbDiskDelegate(QStyledItemDelegate):
00522     def __init__(self, parent):
00523         QStyledItemDelegate.__init__(self,parent)
00524         self.okPixmap=QPixmap("/usr/share/icons/Tango/16x16/status/weather-clear.png")
00525         self.busyPixmap=QPixmap("/usr/share/icons/Tango/16x16/actions/view-refresh.png")
00526 
00527     def paint(self, painter, option, index):
00528         global globalDiskData
00529         text = index.model().data(index, Qt.DisplayRole).toString()
00530         rect0=QRect(option.rect)
00531         rect1=QRect(option.rect)
00532         h=rect0.height()
00533         w=rect0.width()
00534         rect0.setSize(QSize(h,h))
00535         rect1.translate(h,0)
00536         rect1.setSize(QSize(w-h,h))
00537         QApplication.style().drawItemText (painter, rect1, Qt.AlignLeft+Qt.AlignVCenter, option.palette, True, text)
00538         QApplication.style().drawItemText (painter, rect0, Qt.AlignCenter, option.palette, True, QString("O"))
00539         if usbThread.globalThreads.busy(u"%s" %text):
00540             QApplication.style().drawItemPixmap (painter, rect0, Qt.AlignCenter, self.busyPixmap)
00541         else:
00542             QApplication.style().drawItemPixmap (painter, rect0, Qt.AlignCenter, self.okPixmap)
00543         
00544