a97e8496c6d13eb5996d43c6f1f9b575d694209d
[minwii.git] / src / minwii / logapp.py
1 # -*- coding: utf-8 -*-
2 """
3 Interface graphique pour l'analyse des fichiers de log minwii.
4
5 $Id$
6 $URL$
7 """
8
9 from Tkinter import *
10 import tkFileDialog
11 from glob import glob
12 import os
13 from os.path import join as pjoin
14 from os.path import basename
15 from os.path import getsize
16 import os.path
17 from minwii.loganalyse import LogFileAnalyser
18 from minwii.config import LOGS_DIR
19 from pprint import pprint
20
21 class Application(Frame) :
22 def __init__(self, master=None) :
23 Frame.__init__(self, master)
24 self.configureStretching()
25 self.createWidgets()
26 self.logDir = ''
27 self.logFiles = []
28 self.currentFilePath = ''
29 self.resultsFrame = None
30
31 if os.path.exists(LOGS_DIR) :
32 self.chooseDirDialog(dir=LOGS_DIR)
33
34 def configureStretching(self) :
35 top=self.winfo_toplevel()
36 top.rowconfigure(0, weight=1)
37 top.columnconfigure(0, weight=1)
38
39 self.grid(sticky=N+S+E+W, padx=10, pady=10)
40 self.rowconfigure(0, weight=1)
41 self.columnconfigure(0, weight=1)
42
43 def createWidgets(self) :
44 # zone d'affichage des données'
45 self.dataFrame = df = Frame(self)
46
47 self.identFrame = Identification(df)
48 self.identFrame.grid(sticky=NW)
49
50 # barre de boutons
51 self.btnFrame = bf = Frame(self)
52 bf.grid(row=1, column=0, sticky=W+S+E)
53 bf.rowconfigure(0, weight=1)
54 for i in range(3) :
55 bf.columnconfigure(i, weight=1)
56
57 self.chooseLogDir = Button(bf, text="Parcourir…", command=self.chooseDirDialog)
58 self.chooseLogDir.grid(row=0, column=0, sticky=W)
59
60 self.nav = Navbar(bf, incCallback=self.loadLogFile, decCallback=self.loadLogFile)
61
62 self.quitButton = Button(bf, text='Terminer', command=self.quit)
63 self.quitButton.grid(row=0, column=2, sticky=E)
64
65 def chooseDirDialog(self, dir=None) :
66 if dir is None :
67 self.logDir = tkFileDialog.askdirectory(title='Sélectionnez un dossier de fichiers de logs')
68 else :
69 self.logDir = dir
70 if self.logDir :
71 self.logFiles = glob(pjoin(self.logDir, '*.log'))
72 self._cleanupJunkFiles()
73 self.logFiles.sort()
74 self.logFiles.reverse()
75 self.dataFrame.grid(row=0, column=0, sticky=NW)
76 self.nav.setSize(len(self.logFiles))
77 self.nav.grid(row=0, column=1)
78 self.loadLogFile(self.nav)
79
80 def _cleanupJunkFiles(self) :
81 files = []
82 while self.logFiles :
83 f = self.logFiles.pop()
84 if not getsize(f) :
85 os.remove(f)
86 continue
87 else :
88 of = open(f)
89 lfa = LogFileAnalyser(of)
90 if lfa.getLastEventTicks() is None :
91 of.close()
92 os.remove(f)
93 continue
94 else :
95 of.close()
96
97 files.append(f)
98
99 self.logFiles = files
100
101
102 def loadLogFile(self, nav) :
103 index = nav.index - 1
104 filepath = self.logFiles[index]
105 self.currentFilePath = filepath
106 lfa = LogFileAnalyser(self.currentFilePath)
107 self.identFrame.refresh(lfa)
108 if self.resultsFrame :
109 self.resultsFrame.destroy()
110 self.resultsFrame = ResultsFrame(self.dataFrame)
111 self.resultsFrame.layResults(lfa)
112 lfa.close()
113 self.resultsFrame.grid()
114
115
116 class Navbar(Frame) :
117 def __init__(self, master=None, size=1, incCallback=None, decCallback=None) :
118 Frame.__init__(self, master)
119 self.caption = StringVar()
120 self.createWidgets()
121 self.setSize(size)
122 self.incCallback = incCallback if incCallback else lambda x : None
123 self.decCallback = decCallback if decCallback else lambda x : None
124 self.caption.set('%d / %d' % (self.index, self.to))
125
126 def createWidgets(self) :
127 self.backBtn = Button(self,
128 text='◀',
129 command = self.dec
130 )
131 self.backBtn.grid(row=0, column=0)
132
133 self.lbl = Label(self, textvariable=self.caption)
134 self.lbl.grid(row=0, column=1)
135
136 self.nextBtn = Button(self,
137 text='▶',
138 command = self.inc)
139 self.nextBtn.grid(row=0, column=2)
140
141 def refreshStates(self) :
142 if self.index == self.from_ :
143 self.backBtn.configure(state=DISABLED)
144 else :
145 self.backBtn.configure(state=NORMAL)
146
147 if self.index < self.to :
148 self.nextBtn.configure(state=NORMAL)
149 else :
150 self.nextBtn.configure(state=DISABLED)
151
152 self.caption.set('%d / %d' % (self.index, self.to))
153
154
155 def dec(self) :
156 self.index = self.index - 1
157 self.refreshStates()
158 self.decCallback(self)
159
160 def inc(self) :
161 self.index = self.index + 1
162 self.refreshStates()
163 self.incCallback(self)
164
165 def setSize(self, size) :
166 self.from_ = 1
167 self.to = size
168 self.index = 1
169 self.refreshStates()
170
171
172 class Identification(Frame) :
173 def __init__(self, master=None) :
174 Frame.__init__(self, master)
175 self.fileName = StringVar()
176 self.patientName = StringVar()
177 self.createWidgets()
178
179 #def setFileName(self, name) :
180 # self.fileName.set(name)
181
182 def refresh(self, lfa) :
183 filename = basename(lfa.logfile.name)
184 self.fileName.set(filename)
185 metadata = lfa.getMetadata()
186 self.patientName.set(metadata.get('PatientName', ''))
187 self.commentsText.delete(1.0, END)
188 self.commentsText.insert(1.0, metadata.get('Comments', ''))
189
190 def createWidgets(self) :
191 fileLbl = Label(self, text='Fichier :')
192 fileLbl.grid(row=0, column=0, sticky=E)
193
194 fileNameLbl = Label(self, textvariable=self.fileName)
195 fileNameLbl.grid(row=0, column=1, sticky=W)
196
197 nameLbl = Label(self, text='Patient :')
198 nameLbl.grid(row=1, column=0, sticky=E)
199
200 self.nameEntry = Entry(self, width=40, textvariable=self.patientName)
201 self.nameEntry.grid(row=1, column=1, sticky=W)
202
203 commentsLbl = Label(self, text='Commentaires :')
204 commentsLbl.grid(row=2, column=0, sticky=E)
205
206 self.commentsText = Text(self, width=40, height=4, undo=True, wrap=WORD)
207 self.commentsText.grid(row=2, column=1, sticky=W)
208
209 self.saveBtn = Button(self, text='Enregistrer', command=self.saveMetadata)
210 self.saveBtn.grid(row=3, column=1, sticky=E)
211
212 def saveMetadata(self):
213 app = self.master.master
214 filepath = app.currentFilePath
215 lfa = LogFileAnalyser(filepath, mode='r+')
216 patientName = '%s\n' % self.nameEntry.get().replace('\n', ' ').strip()
217 comments = '%s\n' % self.commentsText.get(1.0, END).replace('\n', ' ').strip()
218 metadata = (('PatientName', self.nameEntry.get()),
219 ('Comments', comments))
220 lfa.setMetadata(metadata)
221
222
223 class ResultsFrame(Frame) :
224
225 def layResults(self, lfa) :
226 results = lfa.analyse()
227 if results :
228 for i, kv in enumerate(results) :
229 k, v = kv
230 kl = Label(self, text='%s :' % k)
231 kl.grid(row=i, column=0, sticky=E)
232
233 vl = Label(self, text=v)
234 vl.grid(row=i, column=1, sticky=W)
235 else :
236 msg = Label(self, text="Pas de données exploitables.")
237 msg.grid()
238
239
240
241 app = Application()
242 app.master.title("Analyseur des sessions MINWii")
243 app.mainloop()