Bizarrerie Windows : il n'arrive pas à virer un fichier immédiatement après lui avoir...
[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 from minwii.loganalyse import LogFileAnalyser
17 from pprint import pprint
18
19 class Application(Frame) :
20 def __init__(self, master=None) :
21 Frame.__init__(self, master)
22 self.configureStretching()
23 self.createWidgets()
24 self.logDir = ''
25 self.logFiles = []
26 self.resultsFrame = None
27
28 # debug
29 #self.chooseDirDialog(dir='/Users/pinbe/minwii_logs')
30
31 def configureStretching(self) :
32 top=self.winfo_toplevel()
33 top.rowconfigure(0, weight=1)
34 top.columnconfigure(0, weight=1)
35
36 self.grid(sticky=N+S+E+W, padx=10, pady=10)
37 self.rowconfigure(0, weight=1)
38 self.columnconfigure(0, weight=1)
39
40 def createWidgets(self) :
41 # zone d'affichage des données'
42 self.dataFrame = df = Frame(self)
43
44 self.identFrame = Identification(df)
45 self.identFrame.grid(sticky=NW)
46
47 # barre de boutons
48 self.btnFrame = bf = Frame(self)
49 bf.grid(row=1, column=0, sticky=W+S+E)
50 bf.rowconfigure(0, weight=1)
51 for i in range(3) :
52 bf.columnconfigure(i, weight=1)
53
54 self.chooseLogDir = Button(bf, text="Parcourir…", command=self.chooseDirDialog)
55 self.chooseLogDir.grid(row=0, column=0, sticky=W)
56
57 self.nav = Navbar(bf, incCallback=self.loadLogFile, decCallback=self.loadLogFile)
58
59 self.quitButton = Button(bf, text='Terminer', command=self.quit)
60 self.quitButton.grid(row=0, column=2, sticky=E)
61
62 def chooseDirDialog(self, dir=None) :
63 if dir is None :
64 self.logDir = tkFileDialog.askdirectory(title='Sélectionnez un dossier de fichiers de logs')
65 else :
66 self.logDir = dir
67 if self.logDir :
68 self.logFiles = glob(pjoin(self.logDir, '*.log'))
69 self._cleanupJunkFiles()
70 self.logFiles.sort()
71 self.logFiles.reverse()
72 self.dataFrame.grid(row=0, column=0, sticky=NW)
73 self.nav.setSize(len(self.logFiles))
74 self.nav.grid(row=0, column=1)
75 self.loadLogFile(self.nav)
76
77 def _cleanupJunkFiles(self) :
78 files = []
79 junk = []
80 while self.logFiles :
81 f = self.logFiles.pop()
82 if not getsize(f) :
83 junk.append(f)
84 continue
85 else :
86 lfa = LogFileAnalyser(f)
87 if lfa.getLastEventTicks() is None :
88 junk.append(f)
89 continue
90
91 files.append(f)
92
93 for f in junk :
94 os.remove(f)
95
96 self.logFiles = files
97
98
99 def loadLogFile(self, nav) :
100 index = nav.index - 1
101 filepath = self.logFiles[index]
102 filename = basename(filepath)
103 self.identFrame.setFileName(filename)
104 if self.resultsFrame :
105 self.resultsFrame.destroy()
106 self.resultsFrame = ResultsFrame(self.dataFrame, filepath)
107 self.resultsFrame.layResults()
108 self.resultsFrame.grid()
109
110
111 class Navbar(Frame) :
112 def __init__(self, master=None, size=1, incCallback=None, decCallback=None) :
113 Frame.__init__(self, master)
114 self.caption = StringVar()
115 self.createWidgets()
116 self.setSize(size)
117 self.incCallback = incCallback if incCallback else lambda x : None
118 self.decCallback = decCallback if decCallback else lambda x : None
119 self.caption.set('%d / %d' % (self.index, self.to))
120
121 def createWidgets(self) :
122 self.backBtn = Button(self,
123 text='◀',
124 command = self.dec
125 )
126 self.backBtn.grid(row=0, column=0)
127
128 self.lbl = Label(self, textvariable=self.caption)
129 self.lbl.grid(row=0, column=1)
130
131 self.nextBtn = Button(self,
132 text='▶',
133 command = self.inc)
134 self.nextBtn.grid(row=0, column=2)
135
136 def refreshStates(self) :
137 if self.index == self.from_ :
138 self.backBtn.configure(state=DISABLED)
139 else :
140 self.backBtn.configure(state=NORMAL)
141
142 if self.index < self.to :
143 self.nextBtn.configure(state=NORMAL)
144 else :
145 self.nextBtn.configure(state=DISABLED)
146
147 self.caption.set('%d / %d' % (self.index, self.to))
148
149
150 def dec(self) :
151 self.index = self.index - 1
152 self.refreshStates()
153 self.decCallback(self)
154
155 def inc(self) :
156 self.index = self.index + 1
157 self.refreshStates()
158 self.incCallback(self)
159
160 def setSize(self, size) :
161 self.from_ = 1
162 self.to = size
163 self.index = 1
164 self.refreshStates()
165
166
167 class Identification(Frame) :
168 def __init__(self, master=None) :
169 Frame.__init__(self, master)
170 self.fileName = StringVar()
171 self.createWidgets()
172
173 def setFileName(self, name) :
174 self.fileName.set(name)
175
176 def createWidgets(self) :
177 fileLbl = Label(self, text='Fichier :')
178 fileLbl.grid(row=0, column=0, sticky=E)
179
180 fileNameLbl = Label(self, textvariable=self.fileName)
181 fileNameLbl.grid(row=0, column=1, sticky=W)
182
183 nameLbl = Label(self, text='Patient :')
184 nameLbl.grid(row=1, column=0, sticky=E)
185
186 self.nameEntry = Entry(self, width=40)
187 self.nameEntry.grid(row=1, column=1, sticky=W)
188
189 commentsLbl = Label(self, text='Commentaires :')
190 commentsLbl.grid(row=2, column=0, sticky=E)
191
192 self.commentsText = Text(self, width=40, height=4, undo=True, wrap=WORD)
193 self.commentsText.grid(row=2, column=1, sticky=W)
194
195 class ResultsFrame(Frame) :
196 def __init__(self, master, logFilePath) :
197 Frame.__init__(self, master)
198 self.logFilePath = logFilePath
199
200 def layResults(self) :
201 lfa = LogFileAnalyser(self.logFilePath)
202 results = lfa.analyse()
203 if results :
204 for i, kv in enumerate(results) :
205 k, v = kv
206 kl = Label(self, text='%s :' % k)
207 kl.grid(row=i, column=0, sticky=E)
208
209 vl = Label(self, text=v)
210 vl.grid(row=i, column=1, sticky=W)
211 else :
212 msg = Label(self, text="Pas de données exploitables.")
213 msg.grid()
214
215
216
217 app = Application()
218 app.master.title("Analyseur des sessions MINWii")
219 app.mainloop()