# 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