Affichage, déjà plus « user-friendly ».
[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()
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.dataFrame.grid(row=0, column=0, sticky=NW)
72 self.nav.setSize(len(self.logFiles))
73 self.nav.grid(row=0, column=1)
74 self.loadLogFile(self.nav)
75
76 def _cleanupJunkFiles(self) :
77 files = []
78 while self.logFiles :
79 f = self.logFiles.pop()
80 if not getsize(f) :
81 os.remove(f)
82 continue
83 # TODO : vérifier qu'il existe des événements
84 else :
85 files.append(f)
86
87 self.logFiles = files
88
89
90 def loadLogFile(self, nav) :
91 index = nav.index - 1
92 filepath = self.logFiles[index]
93 filename = basename(filepath)
94 self.identFrame.setFileName(filename)
95 if self.resultsFrame :
96 self.resultsFrame.destroy()
97 self.resultsFrame = ResultsFrame(self.dataFrame, filepath)
98 self.resultsFrame.layResults()
99 self.resultsFrame.grid()
100
101
102 class Navbar(Frame) :
103 def __init__(self, master=None, size=1, incCallback=None, decCallback=None) :
104 Frame.__init__(self, master)
105 self.caption = StringVar()
106 self.createWidgets()
107 self.setSize(size)
108 self.incCallback = incCallback if incCallback else lambda x : None
109 self.decCallback = decCallback if decCallback else lambda x : None
110 self.caption.set('%d / %d' % (self.index, self.to))
111
112 def createWidgets(self) :
113 self.backBtn = Button(self,
114 text='◀',
115 command = self.dec
116 )
117 self.backBtn.grid(row=0, column=0)
118
119 self.lbl = Label(self, textvariable=self.caption)
120 self.lbl.grid(row=0, column=1)
121
122 self.nextBtn = Button(self,
123 text='▶',
124 command = self.inc)
125 self.nextBtn.grid(row=0, column=2)
126
127 def refreshStates(self) :
128 if self.index == self.from_ :
129 self.backBtn.configure(state=DISABLED)
130 else :
131 self.backBtn.configure(state=NORMAL)
132
133 if self.index < self.to :
134 self.nextBtn.configure(state=NORMAL)
135 else :
136 self.nextBtn.configure(state=DISABLED)
137
138 self.caption.set('%d / %d' % (self.index, self.to))
139
140
141 def dec(self) :
142 self.index = self.index - 1
143 self.refreshStates()
144 self.decCallback(self)
145
146 def inc(self) :
147 self.index = self.index + 1
148 self.refreshStates()
149 self.incCallback(self)
150
151 def setSize(self, size) :
152 self.from_ = 1
153 self.to = size
154 self.index = 1
155 self.refreshStates()
156
157
158 class Identification(Frame) :
159 def __init__(self, master=None) :
160 Frame.__init__(self, master)
161 self.fileName = StringVar()
162 self.createWidgets()
163
164 def setFileName(self, name) :
165 self.fileName.set(name)
166
167 def createWidgets(self) :
168 fileLbl = Label(self, text='Fichier :')
169 fileLbl.grid(row=0, column=0, sticky=E)
170
171 fileNameLbl = Label(self, textvariable=self.fileName)
172 fileNameLbl.grid(row=0, column=1, sticky=W)
173
174 nameLbl = Label(self, text='Patient :')
175 nameLbl.grid(row=1, column=0, sticky=E)
176
177 self.nameEntry = Entry(self, width=40)
178 self.nameEntry.grid(row=1, column=1, sticky=W)
179
180 commentsLbl = Label(self, text='Commentaires :')
181 commentsLbl.grid(row=2, column=0, sticky=E)
182
183 self.commentsText = Text(self, width=40, height=4, undo=True, wrap=WORD)
184 self.commentsText.grid(row=2, column=1, sticky=W)
185
186 class ResultsFrame(Frame) :
187 def __init__(self, master, logFilePath) :
188 Frame.__init__(self, master)
189 self.logFilePath = logFilePath
190
191 def layResults(self) :
192 lfa = LogFileAnalyser(self.logFilePath)
193 results = lfa.analyse()
194 if results :
195 for i, kv in enumerate(results) :
196 k, v = kv
197 kl = Label(self, text='%s :' % k)
198 kl.grid(row=i, column=0, sticky=E)
199
200 vl = Label(self, text=v)
201 vl.grid(row=i, column=1, sticky=W)
202 else :
203 msg = Label(self, text="Pas de données exploitables.")
204 msg.grid()
205
206
207
208 app = Application()
209 app.master.title("Analyseur des sessions MINWii")
210 app.mainloop()