00001
00002
00003
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
00029 import diskFull, preferences
00030 import os.path, operator, subprocess, dbus, re, time, copy
00031 from notification import Notification
00032 import db
00033 import deviceListener
00034 from globaldef import logFileName, _dir
00035
00036
00037 qApp.diskData=ownedUsbDisk.Available(True,access="firstFat")
00038
00039 activeThreads={}
00040
00041
00042 pastCommands={}
00043 lastCommand=None
00044
00045
00046
00047
00048
00049
00050
00051 def registerCmd(cmd,partition):
00052 global pastCommands, lastCommand
00053 if pastCommands.has_key(cmd):
00054 pastCommands[cmd].append(partition.owner)
00055 else:
00056 pastCommands[cmd]=[partition.owner]
00057 lastCommand=cmd
00058
00059 class mainWindow(QMainWindow):
00060
00061
00062
00063
00064
00065
00066
00067 def __init__(self, parent, opts, locale="fr_FR"):
00068 QMainWindow.__init__(self)
00069 QWidget.__init__(self, parent)
00070 self.locale=locale
00071 from Ui_mainWindow import Ui_MainWindow
00072 self.ui = Ui_MainWindow()
00073 self.ui.setupUi(self)
00074
00075 self.initRedoStuff()
00076
00077 self.t=self.ui.tableView
00078 self.proxy=QSortFilterProxyModel()
00079 self.proxy.setSourceModel(self.t.model())
00080 self.opts=opts
00081 self.timer=QTimer()
00082 self.applyPreferences()
00083 self.listener=deviceListener.DeviceListener(self)
00084 self.updateButtons()
00085 self.operations=[]
00086 self.oldThreads=set()
00087 self.flashTimer=QTimer()
00088 self.flashTimer.setSingleShot(True)
00089 self.checkDisksLock=False
00090 QObject.connect(self.ui.forceCheckButton, SIGNAL("clicked()"), self.checkDisks)
00091 QObject.connect(self.timer, SIGNAL("timeout()"), self.checkDisks)
00092 QObject.connect(self.flashTimer, SIGNAL("timeout()"), self.normalLCD);
00093 QObject.connect(self.ui.helpButton, SIGNAL("clicked()"), self.help)
00094 QObject.connect(self.ui.umountButton, SIGNAL("clicked()"), self.umount)
00095 QObject.connect(self.ui.toButton, SIGNAL("clicked()"), self.copyTo)
00096 QObject.connect(self.ui.fromButton, SIGNAL("clicked()"), self.copyFrom)
00097 QObject.connect(self.ui.delButton, SIGNAL("clicked()"), self.delFiles)
00098 QObject.connect(self.ui.redoButton, SIGNAL("clicked()"), self.redoCmd)
00099 QObject.connect(self.ui.preferenceButton, SIGNAL("clicked()"), self.preference)
00100 QObject.connect(self.ui.tableView, SIGNAL("doubleClicked(const QModelIndex&)"), self.tableClicked)
00101 QObject.connect(self,SIGNAL("deviceAdded(QString)"), self.deviceAdded)
00102 QObject.connect(self,SIGNAL("deviceRemoved(QString)"), self.deviceRemoved)
00103
00104
00105
00106
00107
00108
00109
00110 def deviceAdded(self, s):
00111
00112 if self.listener.vfatUsbPath(str(s)):
00113 self.checkDisks(noLoop=True)
00114
00115
00116
00117
00118
00119
00120 def deviceRemoved(self, s):
00121
00122 if qApp.diskData.hasDev(s):
00123 self.checkDisks()
00124
00125
00126
00127
00128
00129 def initRedoStuff(self):
00130
00131 self.iconRedo = QIcon()
00132 self.iconRedo.addPixmap(QPixmap("/usr/share/icons/Tango/scalable/actions/go-jump.svg"), QIcon.Normal, QIcon.Off)
00133 self.iconStop = QIcon()
00134 self.iconStop.addPixmap(QPixmap("/usr/share/icons/Tango/scalable/actions/stop.svg"), QIcon.Normal, QIcon.Off)
00135
00136 self.redoToolTip=QApplication.translate("MainWindow", "Refaire à nouveau", None, QApplication.UnicodeUTF8)
00137 self.redoStatusTip=QApplication.translate("MainWindow", "Refaire à nouveau la dernière opération réussie, avec les baladeurs connectés plus récemment", None, QApplication.UnicodeUTF8)
00138 self.stopToolTip=QApplication.translate("MainWindow", "Arrêter les opérations en cours", None, QApplication.UnicodeUTF8)
00139 self.stopStatusTip=QApplication.translate("MainWindow", "Essaie d'arrêter les opérations en cours. À faire seulement si celles-ci durent trop longtemps", None, QApplication.UnicodeUTF8)
00140
00141
00142
00143
00144
00145
00146
00147 def showEvent (self, ev):
00148 result=QMainWindow.showEvent(self, ev)
00149 self.setTimer()
00150 self.checkDisks(force=True)
00151 return result
00152
00153
00154
00155
00156
00157 def setTimer(self, enabled=True):
00158 if self.refreshEnabled:
00159 self.timer.start(self.refreshDelay*1000)
00160 else:
00161 self.timer.stop()
00162
00163
00164
00165
00166
00167 def applyPreferences(self):
00168 prefs=db.readPrefs()
00169 self.workdir=prefs["workdir"]
00170 self.refreshEnabled=prefs["refreshEnabled"]
00171 self.refreshDelay=prefs["refreshDelay"]
00172 self.setTimer()
00173 self.manFileLocation=prefs["manfile"]
00174
00175
00176 self.checkable=("--check","") in self.opts or ("-c","") in self.opts or prefs["checkable"]
00177 self.mv=prefs["mv"]
00178 other=ownedUsbDisk.Available(self.checkable,access="firstFat")
00179 qApp.diskData=other
00180 self.header=ownedUsbDisk.uDisk.headers(self.checkable)
00181 self.connectTableModel(other)
00182
00183
00184
00185
00186
00187
00188 def changeWd(self, newDir):
00189 self.workdir=newDir
00190 db.setWd(newDir)
00191
00192
00193
00194
00195
00196
00197 def tableClicked(self, idx):
00198 c=idx.column()
00199 mappedIdx=self.proxy.mapFromSource(idx)
00200 r=mappedIdx.row()
00201
00202 h=self.header[c]
00203 if c==0 and self.checkable:
00204
00205 pass
00206 elif c==1:
00207
00208 self.editOwner(mappedIdx)
00209 elif "device-mount-paths" in h:
00210 cmd=u"nautilus '%s'" %idx.data().toString ()
00211 subprocess.call(cmd, shell=True)
00212 elif "device-size" in h:
00213 mount=idx.model().partition(idx).mountPoint()
00214 dev,total,used,remain,pcent,path = self.diskSizeData(mount)
00215 pcent=int(pcent[:-1])
00216 w=diskFull.mainWindow(self,pcent,title=path, total=total, used=used)
00217 w.show()
00218 else:
00219 QMessageBox.warning(None,
00220 QApplication.translate("Dialog","Double-clic non pris en compte",None, QApplication.UnicodeUTF8),
00221 QApplication.translate("Dialog","pas d'action pour l'attribut %1",None, QApplication.UnicodeUTF8).arg(h))
00222
00223
00224
00225
00226
00227
00228
00229
00230 def diskSizeData(self, rowOrDev):
00231 if type(rowOrDev)==type(0):
00232 path=qApp.diskData[rowOrDev][self.header.index("1device-mount-paths")]
00233 else:
00234 path=rowOrDev
00235 cmd =u"df '%s'" %path
00236 dfOutput=subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).communicate()[0].split("\n")[-2]
00237 m = re.match("(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+).*", dfOutput).groups()
00238 return m
00239
00240
00241
00242
00243
00244
00245
00246
00247 def diskFromOwner(self,student):
00248 found=False
00249 for d in qApp.diskData.disks.keys():
00250 if d.owner==student:
00251 found=True
00252 break
00253
00254
00255 if d.owner==None or len(d.owner)==0:
00256 found=True
00257 break
00258 if found:
00259 return d
00260 else:
00261 return None
00262
00263
00264
00265
00266
00267
00268 def editOwner(self, idx):
00269 student=u"%s" %self.tm.data(idx,Qt.DisplayRole).toString()
00270 ownedUsbDisk.editRecord(self.diskFromOwner(student), prompt=student)
00271 other=ownedUsbDisk.Available(self.checkable,access="firstFat")
00272 qApp.diskData=other
00273 self.connectTableModel(other)
00274 self.checkDisks()
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284 def updateButtons(self):
00285 global activeThreads, lastCommand
00286 active = len(qApp.diskData)>0
00287 for button in (self.ui.toButton,
00288 self.ui.fromButton,
00289 self.ui.delButton,
00290 self.ui.umountButton):
00291 button.setEnabled(active)
00292
00293
00294
00295
00296 if len(activeThreads) > 0:
00297 self.ui.redoButton.setIcon(self.iconStop)
00298 self.ui.redoButton.setToolTip(self.stopToolTip)
00299 self.ui.redoButton.setStatusTip(self.stopStatusTip)
00300 self.ui.redoButton.setEnabled(True)
00301 else:
00302 self.oldThreads=set()
00303 self.ui.redoButton.setIcon(self.iconRedo)
00304 self.ui.redoButton.setToolTip(self.redoToolTip)
00305 self.ui.redoButton.setStatusTip(self.redoStatusTip)
00306 self.ui.redoButton.setEnabled(lastCommand!=None)
00307
00308
00309
00310
00311
00312 def preference(self):
00313 pref=preferences.preferenceWindow()
00314 pref.setValues(db.readPrefs())
00315 pref.show()
00316 pref.exec_()
00317 if pref.result()==QDialog.Accepted:
00318 db.writePrefs(pref.values())
00319
00320 self.applyPreferences()
00321
00322
00323
00324
00325
00326 def delFiles(self):
00327 titre1=QApplication.translate("Dialog","Choix de fichiers à supprimer",None, QApplication.UnicodeUTF8)
00328 titre2=QApplication.translate("Dialog","Choix de fichiers à supprimer (jokers autorisés)",None, QApplication.UnicodeUTF8)
00329 d=chooseInSticks.chooseDialog(self, titre1, titre2)
00330 ok = d.exec_()
00331 if ok:
00332 pathList=map(lambda x: u"%s" %x, d.pathList())
00333 buttons=QMessageBox.Ok|QMessageBox.Cancel
00334 defaultButton=QMessageBox.Cancel
00335 reply=QMessageBox.warning(
00336 None,
00337 QApplication.translate("Dialog","Vous allez effacer plusieurs baladeurs",None, QApplication.UnicodeUTF8),
00338 QApplication.translate("Dialog","Etes-vous certain de vouloir effacer : "+"\n".join(pathList),None, QApplication.UnicodeUTF8),
00339 buttons, defaultButton)
00340 if reply == QMessageBox.Ok:
00341 cmd='t=usbThread.threadDeleteInUSB(p,%s,subdir="Travail", logfile="%s", parent=self.tm)' %(pathList,logFileName)
00342 for p in qApp.diskData:
00343 if not p.selected: continue
00344 registerCmd(cmd,p)
00345 exec(compile(cmd,'<string>','exec'))
00346 t.setDaemon(True)
00347 t.start()
00348 self.oldThreads.add(t)
00349 return True
00350 else:
00351 msgBox=QMessageBox.warning(
00352 None,
00353 QApplication.translate("Dialog","Aucun fichier sélectionné",None, QApplication.UnicodeUTF8),
00354 QApplication.translate("Dialog","Veuillez choisir au moins un fichier",None, QApplication.UnicodeUTF8))
00355 return True
00356
00357
00358
00359
00360
00361 def copyTo(self):
00362 d=copyToDialog1.copyToDialog1(parent=self, workdir=self.workdir)
00363 d.exec_()
00364 if d.ok==True:
00365 cmd='t=usbThread.threadCopyToUSB(p,%s,subdir="%s", logfile="%s", parent=self.tm)' %(d.selectedList(), self.workdir, logFileName)
00366 for p in qApp.diskData:
00367 if not p.selected: continue
00368 registerCmd(cmd,p)
00369 exec(compile(cmd,'<string>','exec'))
00370 t.setDaemon(True)
00371 t.start()
00372 self.oldThreads.add(t)
00373 return True
00374 else:
00375 msgBox=QMessageBox.warning(
00376 None,
00377 QApplication.translate("Dialog","Aucun fichier sélectionné",None, QApplication.UnicodeUTF8),
00378 QApplication.translate("Dialog","Veuillez choisir au moins un fichier",None, QApplication.UnicodeUTF8))
00379 return True
00380
00381
00382
00383
00384
00385 def copyFrom(self):
00386 titre1=QApplication.translate("Dialog","Choix de fichiers à copier",None, QApplication.UnicodeUTF8)
00387 titre2=QApplication.translate("Dialog", "Choix de fichiers à copier depuis les baladeurs", None, QApplication.UnicodeUTF8)
00388 ok=QApplication.translate("Dialog", "Choix de la destination ...", None, QApplication.UnicodeUTF8)
00389 d=chooseInSticks.chooseDialog(self, title1=titre1, title2=titre2, ok=ok)
00390 ok = d.exec_()
00391 if not ok or len(d.pathList())==0 :
00392 msgBox=QMessageBox.warning(None,
00393 QApplication.translate("Dialog","Aucun fichier sélectionné",None, QApplication.UnicodeUTF8),
00394 QApplication.translate("Dialog","Veuillez choisir au moins un fichier",None, QApplication.UnicodeUTF8))
00395 return True
00396
00397 pathList=map(lambda x: u"%s" %x, d.pathList())
00398 mp=d.selectedDiskMountPoint()
00399 initialPath=os.path.expanduser("~")
00400 destDir = QFileDialog.getExistingDirectory(
00401 None,
00402 QApplication.translate("Dialog","Choisir un répertoire de destination",None, QApplication.UnicodeUTF8),
00403 initialPath)
00404 if destDir and len(destDir)>0 :
00405 if self.mv:
00406 cmd=u"""t=usbThread.threadMoveFromUSB(
00407 p,%s,subdir=self.workdir,
00408 rootPath="%s", dest="%s", logfile="%s",
00409 parent=self.tm)""" %(pathList, mp, destDir, logFileName)
00410 else:
00411 cmd=u"""t=usbThread.threadCopyFromUSB(
00412 p,%s,subdir=self.workdir,
00413 rootPath="%s", dest="%s", logfile="%s",
00414 parent=self.tm)""" %(pathList, mp, destDir, logFileName)
00415
00416 for p in qApp.diskData:
00417 if not p.selected: continue
00418
00419
00420
00421
00422
00423 registerCmd(cmd,p)
00424 exec(compile(cmd,'<string>','exec'))
00425 t.setDaemon(True)
00426 t.start()
00427 self.oldThreads.add(t)
00428
00429 buttons=QMessageBox.Ok|QMessageBox.Cancel
00430 defaultButton=QMessageBox.Cancel
00431 if QMessageBox.question(
00432 None,
00433 QApplication.translate("Dialog","Voir les copies",None, QApplication.UnicodeUTF8),
00434 QApplication.translate("Dialog","Voulez-vous voir les fichiers copiés ?",None, QApplication.UnicodeUTF8),
00435 buttons, defaultButton)==QMessageBox.Ok:
00436 subprocess.call("nautilus '%s'" %destDir,shell=True)
00437 return True
00438 else:
00439 msgBox=QMessageBox.warning(
00440 None,
00441 QApplication.translate("Dialog","Destination manquante",None, QApplication.UnicodeUTF8),
00442 QApplication.translate("Dialog","Veuillez choisir une destination pour la copie des fichiers",None, QApplication.UnicodeUTF8))
00443 return True
00444
00445
00446
00447
00448
00449
00450 def redoCmd(self):
00451 global lastCommand, pastCommands, activeThreads
00452 if len(activeThreads)>0:
00453 print "GRRRR il faut stopper des threads", self.oldThreads
00454 for thread in self.oldThreads:
00455 if thread.isAlive():
00456 try:
00457 thread._Thread__stop()
00458 print str(thread.getName()) + ' is terminated'
00459 except:
00460 print str(thread.getName()) + ' could not be terminated'
00461 else:
00462 if lastCommand==None:
00463 return
00464 if QMessageBox.question(
00465 None,
00466 QApplication.translate("Dialog","Réitérer la dernière commande",None, QApplication.UnicodeUTF8),
00467 QApplication.translate("Dialog","La dernière commande était<br>%1<br>Voulez-vous la relancer avec les nouveaux baladeurs ?",None, QApplication.UnicodeUTF8).arg(lastCommand))==QMessageBox.Cancel:
00468 return
00469 for p in qApp.diskData:
00470 if p.owner in pastCommands[lastCommand] : continue
00471 exec(compile(lastCommand,'<string>','exec'))
00472 t.setDaemon(True)
00473 t.start()
00474 self.oldThreads.add(t)
00475 pastCommands[lastCommand].append(p.owner)
00476
00477
00478
00479
00480
00481
00482 def help(self):
00483 w=help.helpWindow(self)
00484 w.show()
00485 w.exec_()
00486
00487
00488
00489
00490
00491 def umount(self):
00492 buttons=QMessageBox.Ok|QMessageBox.Cancel
00493 defaultButton=QMessageBox.Cancel
00494 button=QMessageBox.question (
00495 self,
00496 QApplication.translate("Main","Démontage des baladeurs",None, QApplication.UnicodeUTF8),
00497 QApplication.translate("Main","Êtes-vous sûr de vouloir démonter tous les baladeurs cochés de la liste ?",None, QApplication.UnicodeUTF8),
00498 buttons,defaultButton)
00499 if button!=QMessageBox.Ok:
00500 return
00501
00502 for p in qApp.diskData:
00503
00504 for d in qApp.diskData.disks.keys():
00505 if p in qApp.diskData.disks[d] and p.selected:
00506
00507 for partition in qApp.diskData.disks[d]:
00508 devfile=partition.getProp("device-file-by-id")
00509 if isinstance(devfile, dbus.Array):
00510 devfile=devfile[0]
00511 if partition.isMounted():
00512 subprocess.call("udisks --unmount %s" %devfile, shell=True)
00513
00514 devfile_disk=d.getProp("device-file-by-id")
00515 if isinstance(devfile_disk, dbus.Array):
00516 devfile_disk=devfile_disk[0]
00517 subprocess.call("udisks --detach %s" %devfile_disk, shell=True)
00518 break
00519 self.checkDisks()
00520 self.operations=[]
00521
00522
00523
00524
00525
00526
00527
00528 def connectTableModel(self, data):
00529 self.visibleheader=[]
00530 for h in self.header:
00531 if h in ownedUsbDisk.uDisk._itemNames:
00532 self.visibleheader.append(self.tr(ownedUsbDisk.uDisk._itemNames[h]))
00533 else:
00534 self.visibleheader.append(h)
00535 self.tm=usbTableModel(self, self.visibleheader,data,self.checkable)
00536 self.t.setModel(self.tm)
00537 if self.checkable:
00538 self.t.setItemDelegateForColumn(0, CheckBoxDelegate(self))
00539 self.t.setItemDelegateForColumn(1, UsbDiskDelegate(self))
00540 self.t.setItemDelegateForColumn(3, DiskSizeDelegate(self))
00541 else:
00542 self.t.setItemDelegateForColumn(0, UsbDiskDelegate(self))
00543 self.t.setItemDelegateForColumn(2, DiskSizeDelegate(self))
00544 self.proxy.setSourceModel(self.t.model())
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559 def checkDisks(self, force=False, noLoop=False):
00560 if self.checkDisksLock:
00561
00562 return
00563 self.checkDisksLock=True
00564 other=ownedUsbDisk.Available(
00565 self.checkable,
00566 access="firstFat",
00567 diskDict=self.listener.connectedVolumes,
00568 noLoop=noLoop)
00569 if force or not self.sameDiskData(qApp.diskData, other):
00570 qApp.diskData=other
00571 connectedCount=int(other)
00572 self.connectTableModel(other)
00573 self.updateButtons()
00574 self.t.resizeColumnsToContents()
00575 self.ui.lcdNumber.display(connectedCount)
00576 self.flashLCD()
00577
00578 if self.checkable:
00579 col=1
00580 else:
00581 col=0
00582 self.t.horizontalHeader().setSortIndicator(1, Qt.AscendingOrder);
00583 self.t.setSortingEnabled(True)
00584 self.t.resizeColumnsToContents()
00585 self.checkDisksLock=False
00586
00587
00588
00589
00590
00591
00592 def sameDiskData(self, one, two):
00593 return set([p.uniqueId() for p in one]) == set([p.uniqueId() for p in two])
00594
00595
00596
00597
00598
00599 def flashLCD(self):
00600 self.ui.lcdNumber.setBackgroundRole(QPalette.Highlight)
00601 self.flashTimer.start(250)
00602
00603
00604
00605
00606
00607 def normalLCD(self):
00608 self.ui.lcdNumber.setBackgroundRole(QPalette.Window)
00609
00610
00611
00612
00613
00614 class usbTableModel(QAbstractTableModel):
00615
00616
00617
00618
00619
00620
00621
00622
00623 def __init__(self, parent=None, header=[], donnees=None, checkable=False):
00624 QAbstractTableModel.__init__(self,parent)
00625 self.header=header
00626 self.donnees=donnees
00627 self.checkable=checkable
00628 self.pere=parent
00629 self.connect(self, SIGNAL("pushCmd(QString, QString)"), self.pushCmd)
00630 self.connect(self, SIGNAL("popCmd(QString, QString)"), self.popCmd)
00631
00632
00633
00634
00635
00636
00637
00638 def pushCmd(self,owner,cmd):
00639 global activeThreads, pastCommands, lastCommand
00640 owner=u"%s" %owner
00641 owner=owner.encode("utf-8")
00642 if activeThreads.has_key(owner):
00643 activeThreads[owner].append(cmd)
00644 else:
00645 activeThreads[owner]=[cmd]
00646 self.updateOwnerColumn()
00647 self.pere.updateButtons()
00648
00649
00650
00651
00652
00653
00654
00655 def popCmd(self,owner, cmd):
00656 global activeThreads, pastCommands, lastCommand
00657 owner=u"%s" %owner
00658 owner=owner.encode("utf-8")
00659 if activeThreads.has_key(owner):
00660 cmd0=activeThreads[owner].pop()
00661 if cmd0 in cmd:
00662 msg=cmd.replace(cmd0,"")+"\n"
00663 logFile=open(os.path.expanduser(logFileName),"a")
00664 logFile.write(msg)
00665 logFile.close()
00666 else:
00667 raise Exception, (u"mismatched commands\n%s\n%s" %(cmd,cmd0)).encode("utf-8")
00668 if len(activeThreads[owner])==0:
00669 activeThreads.pop(owner)
00670 else:
00671 raise Exception, "End of command without a begin."
00672
00673 self.updateOwnerColumn()
00674 if len(activeThreads)==0 :
00675 self.pere.updateButtons()
00676
00677
00678
00679
00680
00681 def updateOwnerColumn(self):
00682 if self.checkable:
00683 column=1
00684 else:
00685 column=0
00686 self.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"), self.index(0,column), self.index(len(self.donnees)-1, column))
00687 self.pere.t.viewport().update()
00688
00689
00690
00691
00692
00693 def rowCount(self, parent):
00694 return len(self.donnees)
00695
00696
00697
00698
00699
00700 def columnCount(self, parent):
00701 return len(self.header)
00702
00703 def setData(self, index, value, role):
00704 if index.column()==0 and self.checkable:
00705 self.donnees[index.row()].selected=value
00706 return True
00707 else:
00708 return QAbstractTableModel.setData(self, index, role)
00709
00710
00711
00712
00713
00714
00715 def partition(self, index):
00716 return self.donnees[index.row()][-1]
00717
00718 def data(self, index, role):
00719 if not index.isValid():
00720 return QVariant()
00721 elif role==Qt.ToolTipRole:
00722 c=index.column()
00723 h=self.pere.header[c]
00724 if c==0 and self.checkable:
00725 return QApplication.translate("Main","Cocher ou décocher cette case en cliquant.",None, QApplication.UnicodeUTF8)
00726 elif c==1:
00727 return QApplication.translate("Main","Propriétaire de la clé USB ou du baladeur ;<br><b>Double-clic</b> pour modifier.",None, QApplication.UnicodeUTF8)
00728 elif "device-mount-paths" in h:
00729 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)
00730 elif "device-size" in h:
00731 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)
00732 elif "drive-vendor" in h:
00733 return QApplication.translate("Main","Fabricant de la clé USB ou du baladeur.",None, QApplication.UnicodeUTF8)
00734 elif "drive-model" in h:
00735 return QApplication.translate("Main","Modèle de la clé USB ou du baladeur.",None, QApplication.UnicodeUTF8)
00736 elif "drive-serial" in h:
00737 return QApplication.translate("Main","Numéro de série de la clé USB ou du baladeur.",None, QApplication.UnicodeUTF8)
00738 else:
00739 return ""
00740 elif role != Qt.DisplayRole:
00741 return QVariant()
00742 if index.row()<len(self.donnees):
00743 return QVariant(self.donnees[index.row()][index.column()])
00744 else:
00745 return QVariant()
00746
00747 def headerData(self, section, orientation, role):
00748 if orientation == Qt.Horizontal and role == Qt.DisplayRole:
00749 return QVariant(self.header[section])
00750 elif orientation == Qt.Vertical and role == Qt.DisplayRole:
00751 return QVariant(section+1)
00752 return QVariant()
00753
00754
00755
00756
00757
00758
00759 def sort(self, Ncol, order=Qt.DescendingOrder):
00760 self.emit(SIGNAL("layoutAboutToBeChanged()"))
00761 self.donnees = sorted(self.donnees, key=operator.itemgetter(Ncol))
00762 if order == Qt.DescendingOrder:
00763 self.donnees.reverse()
00764 self.emit(SIGNAL("layoutChanged()"))
00765
00766 def CheckBoxRect(view_item_style_options):
00767 check_box_style_option=QStyleOptionButton()
00768 check_box_rect = QApplication.style().subElementRect(QStyle.SE_CheckBoxIndicator,check_box_style_option)
00769 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)
00770 return QRect(check_box_point, check_box_rect.size())
00771
00772 class CheckBoxDelegate(QStyledItemDelegate):
00773 def __init__(self, parent):
00774 QStyledItemDelegate.__init__(self,parent)
00775
00776 def paint(self, painter, option, index):
00777 checked = index.model().data(index, Qt.DisplayRole).toBool()
00778 check_box_style_option=QStyleOptionButton()
00779 check_box_style_option.state |= QStyle.State_Enabled
00780 if checked:
00781 check_box_style_option.state |= QStyle.State_On
00782 else:
00783 check_box_style_option.state |= QStyle.State_Off
00784 check_box_style_option.rect = CheckBoxRect(option);
00785 QApplication.style().drawControl(QStyle.CE_CheckBox, check_box_style_option, painter)
00786
00787 def editorEvent(self, event, model, option, index):
00788 if ((event.type() == QEvent.MouseButtonRelease) or (event.type() == QEvent.MouseButtonDblClick)):
00789 if (event.button() != Qt.LeftButton or not CheckBoxRect(option).contains(event.pos())):
00790 return False
00791 if (event.type() == QEvent.MouseButtonDblClick):
00792 return True
00793 elif (event.type() == QEvent.KeyPress):
00794 if event.key() != Qt.Key_Space and event.key() != Qt.Key_Select:
00795 return False
00796 else:
00797 return False
00798 checked = index.model().data(index, Qt.DisplayRole).toBool()
00799 result = model.setData(index, not checked, Qt.EditRole)
00800 return result
00801
00802
00803
00804
00805
00806
00807
00808
00809 class UsbDiskDelegate(QStyledItemDelegate):
00810 def __init__(self, parent):
00811 QStyledItemDelegate.__init__(self,parent)
00812 self.okPixmap=QPixmap("/usr/share/icons/Tango/16x16/status/weather-clear.png")
00813 self.busyPixmap=QPixmap("/usr/share/icons/Tango/16x16/actions/view-refresh.png")
00814
00815 def paint(self, painter, option, index):
00816 global activeThreads
00817 text = index.model().data(index, Qt.DisplayRole).toString()
00818 rect0=QRect(option.rect)
00819 rect1=QRect(option.rect)
00820 h=rect0.height()
00821 w=rect0.width()
00822 rect0.setSize(QSize(h,h))
00823 rect1.translate(h,0)
00824 rect1.setSize(QSize(w-h,h))
00825 QApplication.style().drawItemText (painter, rect1, Qt.AlignLeft+Qt.AlignVCenter, option.palette, True, text)
00826 QApplication.style().drawItemText (painter, rect0, Qt.AlignCenter, option.palette, True, QString("O"))
00827 text=(u"%s" %text).encode("utf-8")
00828 if activeThreads.has_key(text):
00829 QApplication.style().drawItemPixmap (painter, rect0, Qt.AlignCenter, self.busyPixmap)
00830 else:
00831 QApplication.style().drawItemPixmap (painter, rect0, Qt.AlignCenter, self.okPixmap)
00832
00833
00834
00835
00836
00837
00838
00839 class DiskSizeDelegate(QStyledItemDelegate):
00840 def __init__(self, parent):
00841 QStyledItemDelegate.__init__(self,parent)
00842
00843
00844 def paint(self, painter, option, index):
00845 value = int(index.model().data(index, Qt.DisplayRole).toString())
00846 text = self.val2txt(value)
00847 rect0=QRect(option.rect)
00848 rect1=QRect(option.rect)
00849 rect0.translate(2,(rect0.height()-16)/2)
00850 rect0.setSize(QSize(16,16))
00851 rect1.translate(20,0)
00852 rect1.setWidth(rect1.width()-20)
00853 QApplication.style().drawItemText (painter, rect1, Qt.AlignLeft+Qt.AlignVCenter, option.palette, True, text)
00854
00855 mount=index.model().partition(index).mountPoint()
00856 dev,total,used,remain,pcent,path = self.parent().diskSizeData(mount)
00857 pcent=int(pcent[:-1])
00858 painter.setBrush(QBrush(QColor("slateblue")))
00859 painter.drawPie(rect0,0,16*360*pcent/100)
00860
00861
00862
00863
00864
00865 def val2txt(self, val):
00866 suffixes=["B", "KB", "MB", "GB", "TB"]
00867 val*=1.0
00868 i=0
00869 while val > 1024 and i < len(suffixes):
00870 i+=1
00871 val/=1024
00872 return "%4.1f %s" %(val, suffixes[i])
00873
00874