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