ScolaSync  1.0
 Tout Classes Espaces de nommage Fichiers Fonctions Variables Pages
ownedUsbDisk.py
Aller à la documentation de ce fichier.
1 # -*- coding: utf-8 -*-
2 # $Id: ownedUsbDisk.py 47 2011-06-13 10:20:14Z georgesk $
3 
4 licence={}
5 licence['en']="""
6  file ownedUsbDisk.py
7  this file is part of the project scolasync
8 
9  Copyright (C) 2010 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 import usbDisk, db
27 import os.path, dbus, subprocess, time
28 from PyQt4.QtCore import *
29 from PyQt4.QtGui import *
30 from globaldef import markFileName
31 
32 """
33 liste statique pour éviter de demander chaque seconde le nom d'un
34 propriétaire de clé si on n'a pas souhaité le donner.
35 """
36 
37 ##
38 #
39 # Renvoie le tatouage pour un point de montage donné, quitte à le créer
40 # si nécessaire.
41 # @param mountPoint un point de montage de partition
42 # @return le tatouage
43 #
44 def tattooInDir(mountPoint):
45  tattooFileName = os.path.join(mountPoint,".scolasync-tattoo")
46  tattoo_=""
47  if os.path.exists(tattooFileName):
48  tattoo_=open(tattooFileName,"r").readlines()[0].strip()
49  if tattoo_ != "" :
50  # le tatouage existe déjà, on renvoie sa valeur
51  return tattoo_
52  else:
53  tattoo_="%12.2f" %time.time()
54  time.sleep(0.05)
55  # si on espace deux créations de tatouages de 50 millisecondes
56  # il est impossible d'avoir deux tatouages identiques générés
57  # par le même ordinateur. Les chances que ça arrive avec des
58  # ordinateurs distincts sont minimes
59  outfile=open(tattooFileName,"w")
60  outfile.write(tattoo_)
61  outfile.close()
62  # on renvoie le nouveau tatouage
63  return tattoo_
64 
65 ##
66 #
67 # édition de la base de données
68 # @param owd une instance de ownedUsbDisk
69 # @param hint chaîne vide par défaut. Peut être le nom de l'ancien propriétaire
70 #
71 def editRecord(owd, hint=""):
72  title=QApplication.translate("Dialog", "Choix du propriétaire", None, QApplication.UnicodeUTF8)
73  prompt=QApplication.translate("Dialog", "Nouveau nom du propriétaire du baladeur", None, QApplication.UnicodeUTF8)
74  newStudent, ok = QInputDialog.getText(None, title, prompt, text=hint)
75  if ok:
76  newStudent=u"%s" %newStudent
77  db.writeStudent(owd.stickid, owd.getFatUuid(), owd.tattoo(), newStudent)
78 
79 ##
80 #
81 # une classe qui ajoute un nom de propriétaire aux disque USB,
82 # et qui en même temps ajoute des particularités selon le nom du
83 # vendeur et le modèle.
84 #
86  ##
87  #
88  # @param path un chemin dans le système dbus
89  # @param bus un objet dbus.BusSystem
90  # @param checkable vrai si on fera usage de self.selected
91  #
92  def __init__(self, path, bus, checkable=False):
93  usbDisk.uDisk.__init__(self,path, bus, checkable)
94  QObject.__init__(self)
95  self.owner="" # le propriétaire est déterminé plus tard
96  self.vendor=self.getProp("drive-vendor")
97  self.model=self.getProp("drive-model")
98  self.visibleDirs=self.readQuirks()
99 
100  ##
101  #
102  # @return un identifiant unique, composé du nom du propriétaire
103  # suivi du tatouage
104  #
105  def uniqueId(self):
106  return "%s~%s" %(self.owner, self.tattoo())
107 
108  ##
109  #
110  # Renvoie un tatouage présent sur la clé, quitte à le créer.
111  # @result un tatouage, supposément unique.
112  #
113  def tattoo(self):
114  ff=self.getFirstFat()
115  if ff:
116  fatPath=ff.ensureMounted()
117  return tattooInDir(fatPath)
118  else:
119  return ""
120 
121  ##
122  #
123  # Lit un dictionnaire indexé par le noms de vendeurs et les noms de modèle
124  # pour associer à ces modèles particuliers un répertoire visible.
125  # voir la fonction visibleDir. Ce dictionnaire est dans le fichier
126  # /usr/share/scolasync/marques.py ou dans ${HOME}/.scolasync/marques.py,
127  # (sous Linux) cette dernière place étant prépondérante.
128  #
129  def readQuirks (self):
130  f1="/usr/share/scolasync/marques.py"
131  f2=os.path.expanduser(markFileName)
132  if os.path.exists(f2):
133  f=f2
134  else:
135  f=f1
136  result=eval(open(f,"r").read())
137  return result
138 
139  ##
140  #
141  # Renvoie le répertoire particulier de la partition qui sera visible
142  # quand le baladeur est utilisé par son interface utilisateur. Ce
143  # répertoire peut varier selon les vendeurs et les modèles.
144  #
145  def visibleDir(self):
146  k=self.vendor+":"+self.model
147  if k in self.visibleDirs.keys():
148  return self.visibleDirs[k]
149  else:
150  return "."
151 
152  ##
153  #
154  # Méthode statique
155  # renvoie des titres pour les items obtenus par __getitem__
156  # la deuxième colonne sera toujours le propriétaire
157  # @param checkable vrai si le premier en-tête correspond à une colonne de cases à cocher
158  # @param locale la locale, pour traduire les titres
159  # @return une liste de titres de colonnes
160  #
161  def headers(checkable=False,locale="C"):
162  result=usbDisk.uDisk.headers(checkable, locale)
163  ownerProp=QApplication.translate("uDisk","owner",None, QApplication.UnicodeUTF8)
164  result.insert(1,ownerProp)
165  return result
166 
167  ##
168  #
169  # renvoie un nom de propriétaire dans tous les cas.
170  #
171  def ownerByDb(self):
172  if self.owner != "":
173  return self.owner
174  else:
175  s=db.readStudent(self.stickid, self.getFatUuid(), self.tattoo())
176  if s != None:
177  self.owner=s
178  return s
179  else:
180  return QApplication.translate("Dialog","inconnu",None, QApplication.UnicodeUTF8)
181 
182  ##
183  #
184  # renvoie un élément de listage de données internes au disque
185  # Fait en sorte que la deuxième colonne soit toujours le propriétaire
186  # @param n un nombre
187  # @param checkable vrai si on doit renvoyer une propriété supplémentaire pour n==0
188  # @return si n==-1, renvoie self ; si checkable est vrai, renvoie un élément si n>0, et le drapeau self.selected si n==0 ; sinon un élément de façon ordinaire. Les noms des éléments sont dans la liste self.itemNames
189  #
190  def __getitem__(self,n):
191  propListe=usbDisk.uDisk.headers()
192  if n == -1:
193  return self # pour accéder à toutes les données d'une partition
194  if self.checkable:
195  if n==0:
196  return self.selected
197  elif n==1:
198  return self.ownerByDb()
199  elif n==2:
200  return self.unNumberProp(0)
201  else:
202  return self.unNumberProp(n-1)
203  else:
204  if n==0:
205  return self.unNumberProp(0)
206  elif n==1:
207  return self.ownerByDb()
208  else:
209  return self.unNumberProp(n)
210 
211 
212  headers = staticmethod(headers)
213 
214  ##
215  #
216  # Demande un nom de propriétaire si celui-ci n'est pas encore défini
217  # pour cette clé USB
218  # @param noLoop si True : ne fait pas de dialogue interactif
219  # @return un nom de propriétaire si c'est un disque, sinon None
220  #
221  def ensureOwner(self, noLoop):
222  if self.getProp("device-is-drive") and self.isUsbDisk():
223  if noLoop==False and not db.knowsId(self.stickid, self.getFatUuid(), self.tattoo()) :
224  prompt=QApplication.translate("Dialog","La cle %1<br>n'est pas identifiee, donnez le nom du proprietaire",None, QApplication.UnicodeUTF8).arg(self.stickid)
225  title=QApplication.translate("Dialog","Entrer un nom",None, QApplication.UnicodeUTF8)
226  text,ok = QInputDialog.getText(None, title, prompt)
227  text = u"%s" %text.toUtf8()
228  if ok and len(text)>0 and not db.hasStudent(text):
229  db.writeStudent(self.stickid, self.getFatUuid(), self.tattoo(), text)
230  return db.readStudent(self.stickid, self.getFatUuid(), self.tattoo())
231 
232 ##
233 #
234 # Une classe qui fournit une collection de disques USB connectés,
235 # avec leurs propriétaires. Les propriétaires sont recensés juste
236 # avant le montage des partions FAT.
237 #
239 
240  ##
241  #
242  # Le constructeur est un proxy pour usbDisk.Available.__init__
243  # qui force la classe de disques à utiliser : en effet ici
244  # uDisk désigne ownedUsbDisk.uDisk
245  # @param checkable True si on veut pouvoir sélectionner des disques en cochant
246  # @param access le mode d'accès : 'disk' ou 'firstFat'
247  # @param diskClass la classe d'objets à créer pour chaque disque
248  # @param diskDict un dictionnaire des disque maintenu par deviceListener
249  # @param noLoop doit être True pour éviter de lancer un dialogue
250  #
251  def __init__(self, checkable=False, access="disk", diskClass=uDisk, diskDict=None, noLoop=True):
252  self.noLoop=noLoop
253  usbDisk.Available.__init__(self, checkable, access, diskClass, diskDict)
254 
255  ##
256  #
257  # Fin de l'initialisation : trouve les propriétaires des disques
258  # puis identifie les partitions FAT et les monte
259  #
260  def finishInit(self):
261  self.getFirstFats() # premier passage, pour repérer chaque partition FAT
262  for d in self.disks.keys():
263  d.owner=d.ensureOwner(self.noLoop)
264  self.mountFirstFats()
265 
266