ScolaSync: Fichier source de src/mainWindow.py

ScolaSync 5.1 |

mainWindow.py
Aller à la documentation de ce fichier.
1 #!/usr/bin/python
2 # $Id: mainWindow.py 47 2011-06-13 10:20:14Z georgesk $
3
4 licence={}
5 licence['en']="""
6 file mainWindow.py
7 this file is part of the project scolasync
8
9 Copyright (C) 2010-2014 Georges Khaznadar <georgesk@ofset.org>
10
11 This program is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version3 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 """
24
25
26 from PyQt5.QtGui import *
27 from PyQt5.QtCore import *
28 from PyQt5.QtWidgets import *
29 import ownedUsbDisk, help, copyToDialog1, chooseInSticks, usbThread
30 import diskFull, preferences, checkBoxDialog
31 import os.path, operator, subprocess, dbus, re, time, copy
32 from notification import Notification
33 from usbDisk2 import safePath
34 import db
35 import choixEleves
36 import nameAdrive
37 from globaldef import logFileName, _dir
38
39 # cette donnée est globale, pour être utilisé depuis n'importe quel objet
40 qApp.available=ownedUsbDisk.Available(access="firstFat")
41
42 activeThreads={} # donnée globale : les threads actifs
43 # cette donnée est mise à jour par des signaux émis au niveau des threads
44 # et elle est utilisée par la routine de traçage des cases du tableau
45 pastCommands={} # donnée globale : les commandes réalisées dans le passé
46 lastCommand=None # donnée globale : la toute dernière commande
47
48 ##
49 #
50 # enregistre la commande cmd pour la partition donnée
51 # @param cmd une commande pour créer un thread t
52 # @param partition une partition
53 #
54 def registerCmd(cmd,partition):
55 global pastCommands, lastCommand
56 if cmd in pastCommands:
57 pastCommands[cmd].append(partition.owner)
58 else:
59 pastCommands[cmd]=[partition.owner]
60 lastCommand=cmd
61
62 ##
63 #
64 # defines the main window of the application.
65 #
66 class mainWindow(QMainWindow):
67 ############# custom signals ########################
68 checkAllSignal=pyqtSignal()
69 checkToggleSignal=pyqtSignal()
70 checkNoneSignal=pyqtSignal()
71 shouldNameDrive=pyqtSignal()
72 pushCmdSignal=pyqtSignal(str, str)
73 popCmdSignal=pyqtSignal(str, str)
74
75 ##
76 #
77 # Le constructeur
78 # @param parent un QWidget
79 # @param locale la langue de l'application
80 #
81 def __init__(self, parent, locale="fr_FR"):
82 QMainWindow.__init__(self)
83 QWidget.__init__(self, parent)
84 self.locale=locale
85 from Ui_mainWindow import Ui_MainWindow
86 self.ui = Ui_MainWindow()
87 self.ui.setupUi(self)
88 QIcon.setThemeName("Tango")
89 icon=self.setThemedIcon(self.ui.fromButton,"back")
90 self.copyfromIcon=icon
91 self.movefromIcon=QIcon.fromTheme("movefrom",QIcon("/usr/share/scolasync/images/movefrom.png"))
92 self.setThemedIcon(self.ui.toButton,"forward")
93 self.setThemedIcon(self.ui.delButton,"edit-clear")
94 self.setThemedIcon(self.ui.umountButton,"top")
95 self.setThemedIcon(self.ui.redoButton,"go-jump")
96 self.setThemedIcon(self.ui.namesButton,"gtk-find")
97 self.setThemedIcon(self.ui.forceCheckButton,"multimedia-player")
98 self.setThemedIcon(self.ui.preferenceButton,"package_settings")
99 self.setThemedIcon(self.ui.helpButton,"info")
100 # crée le dialogue des nouveaux noms
101 self.namesFullIcon=QIcon.fromTheme("gtk-find-and-replace.svg")
102 self.namesEmptyIcon=QIcon.fromTheme("gtk-find")
103 self.namesFullTip=QApplication.translate("MainWindow", "<br />Des noms sont disponibles pour renommer les prochains baladeurs que vous brancherez", None)
104 self.namesEmptyTip=QApplication.translate("MainWindow", "<br />Cliquez sur ce bouton pour préparer une liste de noms afin de renommer les prochains baladeurs que vous brancherez", None)
105 self.namesDialog=choixEleves.choixElevesDialog(parent =self)
106 self.recentConnect="" # chemin dbus pour un baladeur récemment connecté
107 # initialise deux icônes
108 self.initRedoStuff()
109 # initialise le tableau
110 self.t=self.ui.tableView
111 self.proxy=QSortFilterProxyModel()
112 self.proxy.setSourceModel(self.t.model())
113 self.applyPreferences()
114 self.updateButtons()
115 self.setAvailableNames(False)
116 self.operations=[] # liste des opérations précédemment "réussies"
117 self.oldThreads=set() # threads lancés éventuellement encore vivants
118 self.ui.helpButton.clicked.connect(self.help)
119 self.ui.umountButton.clicked.connect(self.umount)
120 self.ui.toButton.clicked.connect(self.copyTo)
121 self.ui.fromButton.clicked.connect(self.copyFrom)
122 self.ui.delButton.clicked.connect(self.delFiles)
123 self.ui.redoButton.clicked.connect(self.redoCmd)
124 self.ui.namesButton.clicked.connect(self.namesCmd)
125 self.ui.preferenceButton.clicked.connect(self.preference)
126 self.ui.tableView.doubleClicked.connect(self.tableClicked)
127 self.checkAllSignal.connect(self.checkAll)
128 self.checkToggleSignal.connect(self.checkToggle)
129 self.checkNoneSignal.connect(self.checkNone)
130 self.shouldNameDrive.connect(self.namingADrive)
131 ## accrochage d'une fonction de rappel pour les disque ajoutés
132 qApp.available.addHook('object-added', self.cbAdded())
133 qApp.available.addHook('object-removed', self.cbRemoved())
134 self.pushCmdSignal.connect(self.pushCmd)
135 self.popCmdSignal.connect(self.popCmd)
136 return
137
138 ##
139 #
140 # Associe une icone à un bouton, dans le thème courant
141 # @param button le bouton à décorer
142 # @param name le nom de l'icone
143 # @param default un fichier PNG ; si rien n'est donné, il aura
144 # comme valeur par défaut "images/icons32/"+name+".png"
145 # @return l'objet de type QIcon qui a été associé au bouton
146 #
147 def setThemedIcon(self, button, name, default=None):
148 icon=QIcon()
149 try:
150 icon.addPixmap(QIcon.fromTheme(name).pixmap(32))
151 except:
152 icon.addPixmap("images/icons32/"+name+".png")
153 button.setIcon(icon)
154 return button.icon()
155
156 ##
157 #
158 # fonction de rappel déclenchée par les threads (au commencement)
159 # @param owner le propriétaire du baladeur associé au thread
160 # @param cmd la commande shell effectuée sur ce baladeur
161 #
162 def pushCmd(self,owner,cmd):
163 global activeThreads, pastCommands, lastCommand
164 if owner in activeThreads:
165 activeThreads[owner].append(cmd)
166 else:
167 activeThreads[owner]=[cmd]
168 self.tm.updateOwnerColumn()
169 self.updateButtons()
170
171 ##
172 #
173 # fonction de rappel déclenchée par les threads (à la fin)
174 # @param owner le propriétaire du baladeur associé au thread
175 # @param cmd la commande shell effectuée sur ce baladeur
176 #
177 def popCmd(self,owner, cmd):
178 global activeThreads, pastCommands, lastCommand
179 if owner in activeThreads:
180 cmd0=activeThreads[owner].pop()
181 if cmd0 in cmd:
182 msg=cmd.replace(cmd0,"")+"\n"
183 logFile=open(os.path.expanduser(logFileName),"a")
184 logFile.write(msg)
185 logFile.close()
186 else:
187 raise Exception(("mismatched commands\n%s\n%s" %(cmd,cmd0)))
188 if len(activeThreads[owner])==0:
189 activeThreads.pop(owner)
190 else:
191 raise Exception("End of command without a begin.")
192 self.tm.updateOwnerColumn()
193 if len(activeThreads)==0 :
194 self.updateButtons()
195
196 ##
197 #
198 # @param boolfunc une fonction pour décider du futur état de la coche
199 # étant donné l'état antérieur
200 # Modifie les coches des baladeurs
201 #
202 def checkModify(self, boolFunc):
203 model=self.tm
204 index0=model.createIndex(0,0)
205 index1=model.createIndex(len(model.donnees)-1,0)
206 srange=QItemSelectionRange(index0,index1)
207 for i in srange.indexes():
208 checked=bool(i.model().data(i,Qt.DisplayRole))
209 model.setData(i, boolFunc(checked),Qt.EditRole)
210
211 ##
212 #
213 # Coche tous les baladeurs
214 #
215 def checkAll(self):
216 self.checkModify(lambda x: True)
217
218 ##
219 #
220 # Inverse la coche des baladeurs
221 #
222 def checkToggle(self):
223 self.checkModify(lambda x: not x)
224
225 ##
226 #
227 # Décoche tous les baladeurs
228 #
229 def checkNone(self):
230 self.checkModify(lambda x: False)
231
232 ##
233 #
234 # Gère un dialogue pour renommer un baladeur désigné par
235 # self.recentConnect
236 #
237 def namingADrive(self):
238 if self.availableNames:
239 if self.recentConnect not in qApp.available.targets:
240 return
241 disk=qApp.available.targets[self.recentConnect]
242 hint=db.readStudent(disk.serial, disk.uuid, ownedUsbDisk.tattooInDir(disk.mp))
243 if hint != None:
244 oldName=hint
245 else:
246 oldName=""
247 d=nameAdrive.nameAdriveDialog(self, oldName=oldName,
248 nameList=self.namesDialog.itemStrings(),
249 driveIdent=(stickId, uuid, tattoo))
250 d.show()
251 result=d.exec_()
252 return
253
254 ##
255 #
256 # Renvoie une fonction de rappel pour l'abonnement aux évènements de l'arrière-boutique.
257 # Il s'agit de la fonction pour les disques branchés
258 #
259 def cbAdded(self):
260 def _cbAdded(man, obj):
261 if qApp.available.modified:
262 path=safePath(obj)
263 self.recentConnect=str(path)
264 delai=0.5 # petit délai pour que targets soit à jour
265 QTimer.singleShot(delai, self.deviceAdded)
266 qApp.available.modified=False
267 return _cbAdded
268
269 ##
270 #
271 # Renvoie une fonction de rappel pour l'abonnement aux évènements de l'arrière-boutique.
272 # Il s'agit de la fonction pour les disques débranchés
273 #
274 def cbRemoved(self):
275 def _cbRemoved(man, obj):
276 if qApp.available.modified:
277 path=safePath(obj)
278 if path in qApp.available.targets:
279 self.recentDisConnect=path
280 delai=0.5 # petit délai pour que targets soit à jour
281 QTimer.singleShot(delai, self.deviceRemoved)
282 qApp.available.modified=False
283 return _cbRemoved
284
285 ##
286 #
287 # Fonction de rappel pour un medium ajouté ; se base sur la valeur de self.recentConnect
288 #
289 def deviceAdded(self):
290 if self.recentConnect not in qApp.available.targets:
291 return
292 disk=qApp.available.targets[self.recentConnect]
293 if disk.parent: # c'est une partition
294 QTimer.singleShot(0, self.namingADrive)
295 self.findAllDisks()
296
297 ##
298 #
299 # fonction de rappel pour un medium retiré ; se base sur la valeur de self.recentDisConnect
300 #
301 def deviceRemoved(self):
302 self.findAllDisks()
303
304 ##
305 #
306 # Initialise des données pour le bouton central (refaire/stopper)
307 #
308 def initRedoStuff(self):
309 # réserve les icônes
310 self.iconRedo = QIcon()
311 self.iconRedo.addPixmap(QIcon.fromTheme("go-jump").pixmap(32), QIcon.Normal, QIcon.Off)
312 self.iconStop = QIcon()
313 self.iconStop.addPixmap(QIcon.fromTheme("stop").pixmap(32), QIcon.Normal, QIcon.Off)
314 # réserve les phrases d'aide
315 self.redoToolTip=QApplication.translate("MainWindow", "Refaire à nouveau", None)
316 self.redoStatusTip=QApplication.translate("MainWindow", "Refaire à nouveau la dernière opération réussie, avec les baladeurs connectés plus récemment", None)
317 self.stopToolTip=QApplication.translate("MainWindow", "Arrêter les opérations en cours", None)
318 self.stopStatusTip=QApplication.translate("MainWindow", "Essaie d'arrêter les opérations en cours. À faire seulement si celles-ci durent trop longtemps", None)
319
320 ##
321 #
322 # Applique les préférences et les options de ligne de commande
323 #
324 def applyPreferences(self):
325 prefs=db.readPrefs()
326 self.schoolFile=prefs["schoolFile"]
327 self.workdir=prefs["workdir"]
328 self.manFileLocation=prefs["manfile"]
329 self.mv=prefs["mv"]
330 self.header=ownedUsbDisk.uDisk2.headers()
331 self.findAllDisks()
332 return
333
334 ##
335 #
336 # Initialisation du catalogue des disques USB connectés, et
337 # maintenance de l'interface graphique.
338 # @param other un catalogue déjà tout prêt de disques (None par défaut)
339 #
340 def findAllDisks(self, other=None):
341 if other:
342 qApp.available=other
343 else:
344 qApp.available=ownedUsbDisk.Available(access="firstFat")
345 self.connectTableModel(qApp.available)
346 connectedCount=int(qApp.available)
347 self.ui.lcdNumber.display(connectedCount)
348 self.t.resizeColumnsToContents()
349 self.updateButtons()
350 return
351
352 ##
353 #
354 # change le répertoire par défaut contenant les fichiers de travail
355 # @param newDir le nouveau nom de répertoire
356 #
357 def changeWd(self, newDir):
358 self.workdir=newDir
359 db.setWd(newDir)
360
361 ##
362 #
363 # fonction de rappel pour un double clic sur un élément de la table
364 # @param idx un QModelIndex
365 #
366 def tableClicked(self, idx):
367 c=idx.column()
368 mappedIdx=self.proxy.mapFromSource(idx)
369 r=mappedIdx.row()
370 h=self.header[c]
371 if c==0:
372 self.manageCheckBoxes()
373 pass
374 elif c==1:
375 # case du propriétaire
376 self.editOwner(mappedIdx)
377 elif "mp" in h:
378 cmd="xdg-open '%s'" %idx.data()
379 subprocess.call(cmd, shell=True)
380 elif "capacity" in h:
381 mount=idx.model().partition(idx).mountPoint()
382 dev,total,used,remain,pcent,path = self.diskSizeData(mount)
383 pcent=int(pcent[:-1])
384 w=diskFull.mainWindow(self,pcent,title=path, total=total, used=used)
385 w.show()
386 else:
387 QMessageBox.warning(None,
388 QApplication.translate("Dialog","Double-clic non pris en compte",None),
389 QApplication.translate("Dialog","pas d'action pour l'attribut {a}",None).format(a=h))
390
391 ##
392 #
393 # ouvre un dialogue pour permettre de gérer les cases à cocher globalement
394 #
395 def manageCheckBoxes(self):
396 cbDialog=checkBoxDialog.CheckBoxDialog(self)
397 cbDialog.exec_()
398
399 ##
400 #
401 # @param rowOrDev a row number in the tableView, or a device string
402 # @return a tuple dev,total,used,remain,pcent,path for the
403 # disk in the given row of the tableView
404 # (the tuple comes from the command df)
405 #
406 def diskSizeData(self, rowOrDev):
407 if type(rowOrDev)==type(0):
408 path=qApp.available[rowOrDev][self.header.index("1mp")]
409 else:
410 path=rowOrDev
411 cmd ="df '%s'" %path
412 dfOutput=subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).communicate()[0]
413 dfOutput=str(dfOutput.split(b"\n")[-2])
414 m = re.match("(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+).*", dfOutput).groups()
415 return m
416
417
418 ##
419 #
420 # trouve le disque qui correspond à un propriétaire, ou alors
421 # renvoie le premier disque inconnu.
422 # @param student le propriétaire du disque
423 # @return le disque correspondant à l'étudiant
424 #
425 def diskFromOwner(self,student):
426 defaultDisk=None
427 for d in ownedUsbDisk.Available(access="firstFat"):
428 s=db.readStudent(d.stickid, d.uuid, d.tattoo())
429 if s==student :
430 return d
431 elif s==None and defaultDisk==None :
432 # premier disque inconnu
433 defaultDisk=d
434 return defaultDisk
435
436
437 ##
438 #
439 # Édition du propriétaire d'une clé.
440 # @param idx un QModelIndex qui pointe sur le propriétaire d'une clé
441 #
442 def editOwner(self, idx):
443 student="%s" %self.tm.data(idx,Qt.DisplayRole).value()
444 # on fait une modification dans la base de donnée des propriétaires de clés
445 ownedUsbDisk.editRecord(self.diskFromOwner(student), hint=student)
446 # après quoi on relit brutalement toute la list des clés connectées
447 self.findAllDisks()
448
449 ##
450 #
451 # Met à jour l'icône qui reflète la disponibilité de noms pour
452 # renommer automatiquement des baladeurs
453 # @param available vrai s'il y a des noms disponibles pour
454 # renommer des baladeurs.
455 #
456 def setAvailableNames(self, available):
457 self.availableNames=available
458 if available:
459 icon=self.namesFullIcon
460 msg=self.namesFullTip
461 else:
462 icon=self.namesEmptyIcon
463 msg=self.namesEmptyTip
464 self.ui.namesButton.setIcon(icon)
465 self.ui.namesButton.setToolTip(msg)
466 self.ui.namesButton.setStatusTip(msg.replace("<br />",""))
467
468 ##
469 #
470 # Désactive ou active les flèches selon que l'option correspondante
471 # est possible ou non. Pour les flèches : ça aurait du sens de préparer
472 # une opération de copie avant même de brancher des clés, donc on les
473 # active. Par contre démonter les clés quand elles sont absentes ça
474 # n'a pas d'utilité.
475 # Change l'icône du dialogue des noms selon qu'il reste ou non des
476 # noms disponibles dans le dialogue des noms.
477 #
478 def updateButtons(self):
479 global activeThreads, lastCommand
480 active = len(qApp.available)>0
481 for button in (self.ui.toButton,
482 self.ui.fromButton,
483 self.ui.delButton,
484 self.ui.umountButton):
485 button.setEnabled(active)
486 #modifie l'icone copyfrom/movefrom
487 if self.mv:
488 self.ui.fromButton.setIcon(self.movefromIcon)
489 else:
490 self.ui.fromButton.setIcon(self.copyfromIcon)
491 # l'état du redoButton dépend de plusieurs facteurs
492 # si un thread au moins est en cours, on y affiche un STOP actif
493 # sinon on y met l'icône de lastCommand, et celle-ci sera active
494 # seulement s'il y a une commande déjà validée
495 if len(activeThreads) > 0:
496 self.ui.redoButton.setIcon(self.iconStop)
497 self.ui.redoButton.setToolTip(self.stopToolTip)
498 self.ui.redoButton.setStatusTip(self.stopStatusTip)
499 self.ui.redoButton.setEnabled(True)
500 else:
501 self.oldThreads=set() # vide l'ensemble puisque tout est fini
502 self.ui.redoButton.setIcon(self.iconRedo)
503 self.ui.redoButton.setToolTip(self.redoToolTip)
504 self.ui.redoButton.setStatusTip(self.redoStatusTip)
505 self.ui.redoButton.setEnabled(lastCommand!=None)
506 l=self.namesDialog.ui.listWidget.findItems("*",Qt.MatchWildcard)
507 if len(l)>0:
508 self.ui.namesButton.setIcon(self.namesFullIcon)
509 else:
510 self.ui.namesButton.setIcon(self.namesEmptyIcon)
511
512 ##
513 #
514 # lance le dialogue des préférences
515 #
516 def preference(self):
517 pref=preferences.preferenceWindow()
518 pref.setValues(db.readPrefs())
519 pref.show()
520 pref.exec_()
521 if pref.result()==QDialog.Accepted:
522 db.writePrefs(pref.values())
523 # on applique les préférences tout de suite sans redémarrer
524 self.applyPreferences()
525
526 ##
527 #
528 # Lance l'action de supprimer des fichiers ou des répertoires dans les clés USB
529 #
530 def delFiles(self):
531 titre1=QApplication.translate("Dialog","Choix de fichiers à supprimer",None)
532 titre2=QApplication.translate("Dialog","Choix de fichiers à supprimer (jokers autorisés)",None)
533 d=chooseInSticks.chooseDialog(self, titre1, titre2)
534 ok = d.exec_()
535 if ok:
536 pathList=d.pathList()
537 buttons=QMessageBox.Ok|QMessageBox.Cancel
538 defaultButton=QMessageBox.Cancel
539 reply=QMessageBox.warning(
540 None,
541 QApplication.translate("Dialog","Vous allez effacer plusieurs baladeurs",None),
542 QApplication.translate("Dialog","Etes-vous certain de vouloir effacer : "+"\n".join(pathList),None),
543 buttons, defaultButton)
544 if reply == QMessageBox.Ok:
545 cmd="usbThread.threadDeleteInUSB(p,{paths},subdir='Travail', logfile='{log}', parent=self)".format(paths=pathList,log=logFileName)
546 for p in qApp.available:
547 if not p.selected: continue # pas les médias désélectionnés
548 registerCmd(cmd,p)
549 t=eval(cmd)
550 t.setDaemon(True)
551 t.start()
552 self.oldThreads.add(t)
553 return True
554 else:
555 msgBox=QMessageBox.warning(
556 None,
557 QApplication.translate("Dialog","Aucun fichier sélectionné",None),
558 QApplication.translate("Dialog","Veuillez choisir au moins un fichier",None))
559 return True
560
561 ##
562 #
563 # Lance l'action de copier vers les clés USB
564 #
565 def copyTo(self):
566 d=copyToDialog1.copyToDialog1(parent=self, workdir=self.workdir)
567 d.exec_()
568 if d.ok==True:
569 cmd="usbThread.threadCopyToUSB(p,{selected},subdir='{subdir}', logfile='{logfile}', parent=self)".format(selected=list(d.selectedList()), subdir=self.workdir, logfile=logFileName)
570 ## !!!!!!!!!!!!!!!!! itérations dans qApp.available à revoir !
571 for p in qApp.available:
572 if not p.selected: continue # pas les médias désélectionnés
573 registerCmd(cmd,p)
574 t=eval(cmd)
575 t.setDaemon(True)
576 t.start()
577 self.oldThreads.add(t)
578 return True
579 else:
580 msgBox=QMessageBox.warning(
581 None,
582 QApplication.translate("Dialog","Aucun fichier sélectionné",None),
583 QApplication.translate("Dialog","Veuillez choisir au moins un fichier",None))
584 return True
585
586 ##
587 #
588 # Lance l'action de copier depuis les clés USB
589 #
590 def copyFrom(self):
591 titre1=QApplication.translate("Dialog","Choix de fichiers à copier",None)
592 titre2=QApplication.translate("Dialog", "Choix de fichiers à copier depuis les baladeurs", None)
593 okPrompt=QApplication.translate("Dialog", "Choix de la destination ...", None)
594 d=chooseInSticks.chooseDialog(self, title1=titre1, title2=titre2, okPrompt=okPrompt)
595 d.exec_()
596 if not d.ok :
597 msgBox=QMessageBox.warning(None,
598 QApplication.translate("Dialog","Aucun fichier sélectionné",None),
599 QApplication.translate("Dialog","Veuillez choisir au moins un fichier",None))
600 return True
601 # bon, alors c'est OK pour le choix des fichiers à envoyer
602 pathList=d.pathList()
603 mp=d.selectedDiskMountPoint()
604 initialPath=os.path.expanduser("~")
605 destDir = QFileDialog.getExistingDirectory(
606 None,
607 QApplication.translate("Dialog","Choisir un répertoire de destination",None),
608 initialPath)
609 if destDir and len(destDir)>0 :
610 if self.mv:
611 cmd="""usbThread.threadMoveFromUSB(
612 p,{paths},subdir=self.workdir,
613 rootPath='{mp}', dest='{dest}', logfile='{log}',
614 parent=self)""".format(paths=pathList, mp=mp, dest=destDir, log=logFileName)
615 else:
616 cmd="""usbThread.threadCopyFromUSB(
617 p,{paths},subdir=self.workdir,
618 rootPath='{mp}', dest='{dest}', logfile='{log}',
619 parent=self)""".format(paths=pathList, mp=mp, dest=destDir, log=logFileName)
620
621 for p in qApp.available:
622 if not p.selected: continue # pas les médias désélectionnés
623 # on devrait vérifier s'il y a des données à copier
624 # et s'il n'y en a pas, ajouter des lignes au journal
625 # mais on va laisser faire ça dans le thread
626 # inconvénient : ça crée quelquefois des sous-répertoires
627 # vides inutiles dans le répertoire de destination.
628 registerCmd(cmd,p)
629 t=eval(cmd)
630 t.setDaemon(True)
631 t.start()
632 self.oldThreads.add(t)
633 # on ouvre un gestionnaire de fichiers pour voir le résultat
634 buttons=QMessageBox.Ok|QMessageBox.Cancel
635 defaultButton=QMessageBox.Cancel
636 if QMessageBox.question(
637 None,
638 QApplication.translate("Dialog","Voir les copies",None),
639 QApplication.translate("Dialog","Voulez-vous voir les fichiers copiés ?",None),
640 buttons, defaultButton)==QMessageBox.Ok:
641 subprocess.call("xdg-open '%s'" %destDir,shell=True)
642 return True
643 else:
644 msgBox=QMessageBox.warning(
645 None,
646 QApplication.translate("Dialog","Destination manquante",None),
647 QApplication.translate("Dialog","Veuillez choisir une destination pour la copie des fichiers",None))
648 return True
649
650 ##
651 #
652 # Relance la dernière commande, mais en l'appliquant seulement aux
653 # baladeurs nouvellement branchés.
654 #
655 def redoCmd(self):
656 global lastCommand, pastCommands, activeThreads
657 if len(activeThreads)>0:
658 for thread in self.oldThreads:
659 if thread.isAlive():
660 try:
661 thread._Thread__stop()
662 print (str(thread.getName()) + ' is terminated')
663 except:
664 print (str(thread.getName()) + ' could not be terminated')
665 else:
666 if lastCommand==None:
667 return
668 if QMessageBox.question(
669 None,
670 QApplication.translate("Dialog","Réitérer la dernière commande",None),
671 QApplication.translate("Dialog","La dernière commande était<br>{cmd}<br>Voulez-vous la relancer avec les nouveaux baladeurs ?",None).format(cmd=lastCommand))==QMessageBox.Cancel:
672 return
673 for p in qApp.available:
674 if p.owner in pastCommands[lastCommand] : continue
675 exec(compile(lastCommand,'<string>','exec'))
676 t.setDaemon(True)
677 t.start()
678 self.oldThreads.add(t)
679 pastCommands[lastCommand].append(p.owner)
680
681 ##
682 #
683 # montre le dialogue de choix de nouveaux noms à partir d'un
684 # fichier administratif.
685 #
686 def namesCmd(self):
687 self.namesDialog.show()
688
689 ##
690 #
691 # Affiche le widget d'aide
692 #
693 def help(self):
694 w=help.helpWindow(self)
695 w.show()
696 w.exec_()
697
698 ##
699 #
700 # Démonte et détache les clés USB affichées
701 #
702 def umount(self):
703 buttons=QMessageBox.Ok|QMessageBox.Cancel
704 defaultButton=QMessageBox.Cancel
705 button=QMessageBox.question (
706 self,
707 QApplication.translate("Main","Démontage des baladeurs",None),
708 QApplication.translate("Main","Êtes-vous sûr de vouloir démonter tous les baladeurs cochés de la liste ?",None),
709 buttons,defaultButton)
710 if button!=QMessageBox.Ok:
711 return
712 for d in qApp.available.disks_ud():
713 for partition in qApp.available.parts_ud(d.path):
714 if partition.mp:
715 cmd="umount {0}".format(partition.mp)
716 subprocess.call(cmd, shell=True)
717 cmd= "udisks --detach {0}".format(d.devStuff)
718 subprocess.call(cmd, shell=True)
719 self.findAllDisks() # remet à jour le compte de disques
720 self.operations=[] # remet à zéro la liste des opérations
721
722
723 ##
724 #
725 # Connecte le modèle de table à la table
726 # @param data les données de la table
727 #
728 def connectTableModel(self, data):
729 self.visibleheader=[]
730 for h in self.header:
731 if h in ownedUsbDisk.uDisk2._itemNames:
732 self.visibleheader.append(self.tr(ownedUsbDisk.uDisk2._itemNames[h]))
733 else:
734 self.visibleheader.append(h)
735 self.tm=usbTableModel(self, self.visibleheader, data)
736 self.t.setModel(self.tm)
737 self.t.setItemDelegateForColumn(0, CheckBoxDelegate(self))
738 self.t.setItemDelegateForColumn(1, UsbDiskDelegate(self))
739 self.t.setItemDelegateForColumn(3, DiskSizeDelegate(self))
740 self.proxy.setSourceModel(self.t.model())
741
742
743 ##
744 #
745 # @return True si les ensembles de uniqueId de one et two sont identiques
746 #
747 def sameDiskData(self, one, two):
748 return len(one.targets) == len(two.targets) and \
749 set([p.uniqueId() for p in one]) == set([p.uniqueId() for p in two])
750
751 ##
752 #
753 # Un modèle de table pour des séries de clés USB
754 #
755 class usbTableModel(QAbstractTableModel):
756
757 ##
758 #
759 # @param parent un QObject
760 # @param header les en-têtes de colonnes
761 # @param donnees les données
762 #
763 def __init__(self, parent=None, header=[], donnees=None):
764 QAbstractTableModel.__init__(self,parent)
765 self.header=header
766 self.donnees=donnees
767 self.pere=parent
768
769 ##
770 #
771 # force la mise à jour de la colonne des propriétaires
772 #
773 def updateOwnerColumn(self):
774 column=1
775 self.dataChanged.emit(self.index(0,column), self.index(len(self.donnees)-1, column))
776 self.pere.t.viewport().update()
777
778 ##
779 #
780 # @parent un QModelIndex
781 #
782 def rowCount(self, parent):
783 return len(self.donnees)
784
785 ##
786 #
787 # @parent un QModelIndex
788 #
789 def columnCount(self, parent):
790 return len(self.header)
791
792 def setData(self, index, value, role):
793 if index.column()==0:
794 self.donnees[index.row()].selected=value
795 return True
796 else:
797 return QAbstractTableModel.setData(self, index, role)
798
799 ##
800 #
801 # @param index in QModelIndex
802 # @return la partition pointée par index
803 #
804 def partition(self, index):
805 return self.donnees[index.row()][-1]
806
807 def data(self, index, role):
808 if not index.isValid():
809 return QVariant()
810 elif role==Qt.ToolTipRole:
811 c=index.column()
812 h=self.pere.header[c]
813 if c==0:
814 return QApplication.translate("Main","Cocher ou décocher cette case en cliquant.<br><b>Double-clic</b> pour agir sur plusieurs baladeurs.",None)
815 elif c==1:
816 return QApplication.translate("Main","Propriétaire de la clé USB ou du baladeur ;<br><b>Double-clic</b> pour modifier.",None)
817 elif "mp" in h:
818 return QApplication.translate("Main","Point de montage de la clé USB ou du baladeur ;<br><b>Double-clic</b> pour voir les fichiers.",None)
819 elif "capacity" in h:
820 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)
821 elif "vendor" in h:
822 return QApplication.translate("Main","Fabricant de la clé USB ou du baladeur.",None)
823 elif "model" in h:
824 return QApplication.translate("Main","Modèle de la clé USB ou du baladeur.",None)
825 elif "stickid" in h:
826 return QApplication.translate("Main","Numéro de série de la clé USB ou du baladeur.",None)
827 else:
828 return ""
829 elif role != Qt.DisplayRole:
830 return QVariant()
831 if index.row()<len(self.donnees):
832 try:
833 return QVariant(self.donnees[index.row()][index.column()])
834 except KeyError:
835 print("Le bug du retrait de clé non détecté a encore frappé, quand sera-t-il éliminé ?")
836 self.pere.findAllDisks()
837 return QVariant("")
838
839 else:
840 return QVariant()
841
842 def headerData(self, section, orientation, role):
843 if orientation == Qt.Horizontal and role == Qt.DisplayRole:
844 return QVariant(self.header[section])
845 elif orientation == Qt.Vertical and role == Qt.DisplayRole:
846 return QVariant(section+1)
847 return QVariant()
848
849 ##
850 # Sort table by given column number.
851 # @param Ncol numéro de la colonne de tri
852 # @param order l'odre de tri, Qt.DescendingOrder par défaut
853 #
854 def sort(self, Ncol, order=Qt.DescendingOrder):
855 self.layoutAboutToBeChanged.emit()
856 self.donnees = sorted(self.donnees, key=operator.itemgetter(Ncol))
857 if order == Qt.DescendingOrder:
858 self.donnees.reverse()
859 self.layoutChanged.emit()
860
861 ##
862 #
863 # @param view_item_style_options des options permettant de décider de
864 # la taille d'un rectangle
865 # @return un QRect dimensionné selon les bonnes options
866 #
867 def CheckBoxRect(view_item_style_options):
868 check_box_style_option=QStyleOptionButton()
869 check_box_rect = QApplication.style().subElementRect(QStyle.SE_CheckBoxIndicator,check_box_style_option)
870 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)
871 return QRect(check_box_point, check_box_rect.size())
872
873 class CheckBoxDelegate(QStyledItemDelegate):
874 def __init__(self, parent):
875 QStyledItemDelegate.__init__(self,parent)
876
877 def paint(self, painter, option, index):
878 checked = bool(index.model().data(index, Qt.DisplayRole))
879 check_box_style_option=QStyleOptionButton()
880 check_box_style_option.state |= QStyle.State_Enabled
881 if checked:
882 check_box_style_option.state |= QStyle.State_On
883 else:
884 check_box_style_option.state |= QStyle.State_Off
885 check_box_style_option.rect = CheckBoxRect(option);
886 QApplication.style().drawControl(QStyle.CE_CheckBox, check_box_style_option, painter)
887
888 def editorEvent(self, event, model, option, index):
889 if ((event.type() == QEvent.MouseButtonRelease) or (event.type() == QEvent.MouseButtonDblClick)):
890 if (event.button() != Qt.LeftButton or not CheckBoxRect(option).contains(event.pos())):
891 return False
892 if (event.type() == QEvent.MouseButtonDblClick):
893 return True
894 elif (event.type() == QEvent.KeyPress):
895 if event.key() != Qt.Key_Space and event.key() != Qt.Key_Select:
896 return False
897 else:
898 return False
899 checked = bool(index.model().data(index, Qt.DisplayRole))
900 result = model.setData(index, not checked, Qt.EditRole)
901 return result
902
903
904 ##
905 #
906 # Classe pour identifier le baladeur dans le tableau.
907 # La routine de rendu à l'écran trace une petite icône et le nom du
908 # propriétaire à côté.
909 #
910 class UsbDiskDelegate(QStyledItemDelegate):
911 def __init__(self, parent):
912 QStyledItemDelegate.__init__(self,parent)
913 self.okPixmap=QPixmap("/usr/share/icons/Tango/16x16/status/weather-clear.png")
914 self.busyPixmap=QPixmap("/usr/share/icons/Tango/16x16/actions/view-refresh.png")
915
916 def paint(self, painter, option, index):
917 global activeThreads
918 text = index.model().data(index, Qt.DisplayRole).value()
919 rect0=QRect(option.rect)
920 rect1=QRect(option.rect)
921 h=rect0.height()
922 w=rect0.width()
923 rect0.setSize(QSize(h,h))
924 rect1.translate(h,0)
925 rect1.setSize(QSize(w-h,h))
926 QApplication.style().drawItemText (painter, rect1, Qt.AlignLeft+Qt.AlignVCenter, option.palette, True, text)
927 QApplication.style().drawItemText (painter, rect0, Qt.AlignCenter, option.palette, True, "O")
928 if text in activeThreads:
929 QApplication.style().drawItemPixmap (painter, rect0, Qt.AlignCenter, self.busyPixmap)
930 else:
931 QApplication.style().drawItemPixmap (painter, rect0, Qt.AlignCenter, self.okPixmap)
932
933 ##
934 #
935 # Classe pour figurer la taille de la mémoire du baladeur. Trace un petit
936 # secteur représentant la place occupée, puis affiche la place avec l'unité
937 # le plus parropriée.
938 #
939 class DiskSizeDelegate(QStyledItemDelegate):
940 def __init__(self, parent):
941 QStyledItemDelegate.__init__(self,parent)
942
943
944 def paint(self, painter, option, index):
945 v=index.model().data(index, Qt.DisplayRole)
946 value = v.value()
947 text = self.val2txt(value)
948 rect0=QRect(option.rect)
949 rect1=QRect(option.rect)
950 rect0.translate(2,(rect0.height()-16)/2)
951 rect0.setSize(QSize(16,16))
952 rect1.translate(20,0)
953 rect1.setWidth(rect1.width()-20)
954 QApplication.style().drawItemText (painter, rect1, Qt.AlignLeft+Qt.AlignVCenter, option.palette, True, text)
955 # dessin d'un petit cercle pour l'occupation
956 mount=index.model().partition(index).mountPoint()
957 dev,total,used,remain,pcent,path = self.parent().diskSizeData(mount)
958 pcent=int(pcent[:-1])
959 painter.setBrush(QBrush(QColor("slateblue")))
960 painter.drawPie(rect0,0,16*360*pcent/100)
961
962 ##
963 #
964 # @return a string with a value with unit K, M, or G
965 #
966 def val2txt(self, val):
967 suffixes=["B", "KB", "MB", "GB", "TB"]
968 val*=1.0 # calcul flottant
969 i=0
970 while val > 1024 and i < len(suffixes):
971 i+=1
972 val/=1024
973 return "%4.1f %s" %(val, suffixes[i])
974
src.mainWindow.usbTableModel.columnCount
def columnCount(self, parent)
un QModelIndex
Definition: mainWindow.py:789
src.mainWindow.usbTableModel.partition
def partition(self, index)
Definition: mainWindow.py:804
src.mainWindow.mainWindow
defines the main window of the application.
Definition: mainWindow.py:66
src.mainWindow.mainWindow.updateButtons
def updateButtons(self)
Désactive ou active les flèches selon que l'option correspondante est possible ou non...
Definition: mainWindow.py:478
src.preferences.preferenceWindow
Definition: preferences.py:28
src.mainWindow.registerCmd
def registerCmd(cmd, partition)
enregistre la commande cmd pour la partition donnée
Definition: mainWindow.py:54
QtCore
QtWidgets
src.mainWindow.mainWindow.tm
tm
Definition: mainWindow.py:735
src.help.helpWindow
Definition: help.py:31
src.mainWindow.CheckBoxDelegate.paint
def paint(self, painter, option, index)
Definition: mainWindow.py:877
src.mainWindow.mainWindow.pushCmd
def pushCmd(self, owner, cmd)
fonction de rappel déclenchée par les threads (au commencement)
Definition: mainWindow.py:162
src.mainWindow.mainWindow.editOwner
def editOwner(self, idx)
Édition du propriétaire d'une clé.
Definition: mainWindow.py:442
src.mainWindow.mainWindow.workdir
workdir
Definition: mainWindow.py:327
src.mainWindow.mainWindow.checkAll
def checkAll(self)
Coche tous les baladeurs.
Definition: mainWindow.py:215
src.mainWindow.mainWindow.ui
ui
Definition: mainWindow.py:86
src.mainWindow.mainWindow.checkNone
def checkNone(self)
Décoche tous les baladeurs.
Definition: mainWindow.py:229
src.mainWindow.mainWindow.findAllDisks
def findAllDisks
Initialisation du catalogue des disques USB connectés, et maintenance de l'interface graphique...
Definition: mainWindow.py:340
src.mainWindow.mainWindow.visibleheader
visibleheader
Definition: mainWindow.py:729
src.mainWindow.mainWindow.checkModify
def checkModify(self, boolFunc)
Definition: mainWindow.py:202
src.ownedUsbDisk.Available
Une classe qui fournit une collection de disques USB connectés, avec leurs propriétaires.
Definition: ownedUsbDisk.py:288
src.mainWindow.mainWindow.diskSizeData
def diskSizeData(self, rowOrDev)
Definition: mainWindow.py:406
src.mainWindow.usbTableModel.setData
def setData(self, index, value, role)
Definition: mainWindow.py:792
src.mainWindow.mainWindow.operations
operations
Definition: mainWindow.py:116
src.mainWindow.CheckBoxDelegate
Definition: mainWindow.py:873
src.mainWindow.mainWindow.diskFromOwner
def diskFromOwner(self, student)
trouve le disque qui correspond à un propriétaire, ou alors renvoie le premier disque inconnu...
Definition: mainWindow.py:425
src.mainWindow.mainWindow.connectTableModel
def connectTableModel(self, data)
Connecte le modèle de table à la table.
Definition: mainWindow.py:728
src.mainWindow.usbTableModel.updateOwnerColumn
def updateOwnerColumn(self)
force la mise à jour de la colonne des propriétaires
Definition: mainWindow.py:773
src.mainWindow.mainWindow.copyTo
def copyTo(self)
Lance l'action de copier vers les clés USB.
Definition: mainWindow.py:565
src.mainWindow.mainWindow.tableClicked
def tableClicked(self, idx)
fonction de rappel pour un double clic sur un élément de la table
Definition: mainWindow.py:366
QStyledItemDelegate
src.diskFull.mainWindow
Definition: diskFull.py:29
src.copyToDialog1.copyToDialog1
Un dialogue pour choisir un ensemble de fichiers à transférer vers une collection de clés USB...
Definition: copyToDialog1.py:37
src.mainWindow.mainWindow.copyFrom
def copyFrom(self)
Lance l'action de copier depuis les clés USB.
Definition: mainWindow.py:590
src.mainWindow.mainWindow.namingADrive
def namingADrive(self)
Gère un dialogue pour renommer un baladeur désigné par self.recentConnect.
Definition: mainWindow.py:237
src.mainWindow.mainWindow.__init__
def __init__
Le constructeur.
Definition: mainWindow.py:81
src.mainWindow.mainWindow.availableNames
availableNames
Definition: mainWindow.py:457
src.checkBoxDialog.CheckBoxDialog
Un dialogue pour gérer les cases à cocher de l'application.
Definition: checkBoxDialog.py:30
src.mainWindow.mainWindow.manFileLocation
manFileLocation
Definition: mainWindow.py:328
src.mainWindow.mainWindow.movefromIcon
movefromIcon
Definition: mainWindow.py:91
src.choixEleves.choixElevesDialog
implémente un dialogue permettant de choisir des élèves les propriétés importantes sont self...
Definition: choixEleves.py:39
src.mainWindow.mainWindow.t
t
Definition: mainWindow.py:110
src.mainWindow.DiskSizeDelegate.__init__
def __init__(self, parent)
Definition: mainWindow.py:940
src.mainWindow.usbTableModel.headerData
def headerData(self, section, orientation, role)
Definition: mainWindow.py:842
src.mainWindow.mainWindow.proxy
proxy
Definition: mainWindow.py:111
src.mainWindow.mainWindow.namesEmptyTip
namesEmptyTip
Definition: mainWindow.py:104
src.mainWindow.mainWindow.sameDiskData
def sameDiskData(self, one, two)
Definition: mainWindow.py:747
src.mainWindow.mainWindow.iconRedo
iconRedo
Definition: mainWindow.py:310
src.mainWindow.mainWindow.recentConnect
recentConnect
Definition: mainWindow.py:106
src.mainWindow.mainWindow.redoStatusTip
redoStatusTip
Definition: mainWindow.py:316
src.mainWindow.usbTableModel.rowCount
def rowCount(self, parent)
un QModelIndex
Definition: mainWindow.py:782
src.mainWindow.mainWindow.initRedoStuff
def initRedoStuff(self)
Initialise des données pour le bouton central (refaire/stopper)
Definition: mainWindow.py:308
src.nameAdrive.nameAdriveDialog
un dialogue pour renommer un baladeur, compte tenu d'une liste de noms disponibles ...
Definition: nameAdrive.py:35
src.mainWindow.usbTableModel.pere
pere
Definition: mainWindow.py:767
src.mainWindow.mainWindow.popCmd
def popCmd(self, owner, cmd)
fonction de rappel déclenchée par les threads (à la fin)
Definition: mainWindow.py:177
src.mainWindow.mainWindow.schoolFile
schoolFile
Definition: mainWindow.py:326
src.mainWindow.UsbDiskDelegate.busyPixmap
busyPixmap
Definition: mainWindow.py:914
src.mainWindow.CheckBoxDelegate.__init__
def __init__(self, parent)
Definition: mainWindow.py:874
src.mainWindow.mainWindow.setAvailableNames
def setAvailableNames(self, available)
Met à jour l'icône qui reflète la disponibilité de noms pour renommer automatiquement des baladeurs...
Definition: mainWindow.py:456
src.mainWindow.mainWindow.deviceRemoved
def deviceRemoved(self)
fonction de rappel pour un medium retiré ; se base sur la valeur de self.recentDisConnect ...
Definition: mainWindow.py:301
src.mainWindow.mainWindow.preference
def preference(self)
lance le dialogue des préférences
Definition: mainWindow.py:516
src.mainWindow.mainWindow.namesFullIcon
namesFullIcon
Definition: mainWindow.py:101
src.mainWindow.mainWindow.setThemedIcon
def setThemedIcon
Associe une icone à un bouton, dans le thème courant.
Definition: mainWindow.py:147
src.mainWindow.mainWindow.mv
mv
Definition: mainWindow.py:329
src.mainWindow.mainWindow.redoToolTip
redoToolTip
Definition: mainWindow.py:315
src.mainWindow.usbTableModel.donnees
donnees
Definition: mainWindow.py:766
src.usbDisk2.safePath
def safePath(obj)
Récupère de façon sûre le path d'une instance de UDisksObjectProxy.
Definition: usbDisk2.py:60
src.mainWindow.mainWindow.namesDialog
namesDialog
Definition: mainWindow.py:105
src.mainWindow.mainWindow.changeWd
def changeWd(self, newDir)
change le répertoire par défaut contenant les fichiers de travail
Definition: mainWindow.py:357
src.mainWindow.mainWindow.applyPreferences
def applyPreferences(self)
Applique les préférences et les options de ligne de commande.
Definition: mainWindow.py:324
src.mainWindow.UsbDiskDelegate.__init__
def __init__(self, parent)
Definition: mainWindow.py:911
src.mainWindow.mainWindow.locale
locale
Definition: mainWindow.py:84
src.mainWindow.mainWindow.header
header
Definition: mainWindow.py:330
src.mainWindow.usbTableModel.data
def data(self, index, role)
Definition: mainWindow.py:807
src.mainWindow.CheckBoxRect
def CheckBoxRect(view_item_style_options)
Definition: mainWindow.py:867
src.mainWindow.mainWindow.iconStop
iconStop
Definition: mainWindow.py:312
src.mainWindow.mainWindow.help
def help(self)
Affiche le widget d'aide.
Definition: mainWindow.py:693
src.mainWindow.mainWindow.umount
def umount(self)
Démonte et détache les clés USB affichées.
Definition: mainWindow.py:702
src.mainWindow.UsbDiskDelegate.okPixmap
okPixmap
Definition: mainWindow.py:913
src.mainWindow.usbTableModel.__init__
def __init__
Definition: mainWindow.py:763
QMainWindow
src.mainWindow.usbTableModel.header
header
Definition: mainWindow.py:765
src.mainWindow.mainWindow.oldThreads
oldThreads
Definition: mainWindow.py:117
src.mainWindow.usbTableModel.sort
def sort
Sort table by given column number.
Definition: mainWindow.py:854
src.mainWindow.CheckBoxDelegate.editorEvent
def editorEvent(self, event, model, option, index)
Definition: mainWindow.py:888
src.mainWindow.mainWindow.namesFullTip
namesFullTip
Definition: mainWindow.py:103
src.mainWindow.mainWindow.cbRemoved
def cbRemoved(self)
Renvoie une fonction de rappel pour l'abonnement aux évènements de l'arrière-boutique.
Definition: mainWindow.py:274
src.mainWindow.UsbDiskDelegate
Classe pour identifier le baladeur dans le tableau.
Definition: mainWindow.py:910
src.mainWindow.mainWindow.stopToolTip
stopToolTip
Definition: mainWindow.py:317
src.mainWindow.mainWindow.namesCmd
def namesCmd(self)
montre le dialogue de choix de nouveaux noms à partir d'un fichier administratif. ...
Definition: mainWindow.py:686
src.mainWindow.mainWindow.recentDisConnect
recentDisConnect
Definition: mainWindow.py:279
src.mainWindow.mainWindow.redoCmd
def redoCmd(self)
Relance la dernière commande, mais en l'appliquant seulement aux baladeurs nouvellement branchés...
Definition: mainWindow.py:655
src.mainWindow.mainWindow.manageCheckBoxes
def manageCheckBoxes(self)
ouvre un dialogue pour permettre de gérer les cases à cocher globalement
Definition: mainWindow.py:395
src.mainWindow.UsbDiskDelegate.paint
def paint(self, painter, option, index)
Definition: mainWindow.py:916
src.mainWindow.DiskSizeDelegate.paint
def paint(self, painter, option, index)
Definition: mainWindow.py:944
QtGui
src.mainWindow.mainWindow.stopStatusTip
stopStatusTip
Definition: mainWindow.py:318
src.mainWindow.mainWindow.namesEmptyIcon
namesEmptyIcon
Definition: mainWindow.py:102
src.mainWindow.mainWindow.checkToggle
def checkToggle(self)
Inverse la coche des baladeurs.
Definition: mainWindow.py:222
src.mainWindow.DiskSizeDelegate
Classe pour figurer la taille de la mémoire du baladeur.
Definition: mainWindow.py:939
QAbstractTableModel
src.mainWindow.DiskSizeDelegate.val2txt
def val2txt(self, val)
Definition: mainWindow.py:966
src.mainWindow.mainWindow.copyfromIcon
copyfromIcon
Definition: mainWindow.py:90
src.mainWindow.mainWindow.delFiles
def delFiles(self)
Lance l'action de supprimer des fichiers ou des répertoires dans les clés USB.
Definition: mainWindow.py:530
src.mainWindow.usbTableModel
Un modèle de table pour des séries de clés USB.
Definition: mainWindow.py:755
src.mainWindow.mainWindow.cbAdded
def cbAdded(self)
Renvoie une fonction de rappel pour l'abonnement aux évènements de l'arrière-boutique.
Definition: mainWindow.py:259
src.mainWindow.mainWindow.deviceAdded
def deviceAdded(self)
Fonction de rappel pour un medium ajouté ; se base sur la valeur de self.recentConnect.
Definition: mainWindow.py:289
src.chooseInSticks.chooseDialog
Un dialogue pour choisir un ensemble de fichiers à copier depuis une clé USB.
Definition: chooseInSticks.py:34