Completed
Push — master ( 87fb07...159278 )
by Jerome
01:13
created

MainApplication   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 33
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 33
rs 10
wmc 7

5 Methods

Rating   Name   Duplication   Size   Complexity  
A notice() 0 3 1
A __init__() 0 13 1
A add_callback() 0 4 1
A handle_callback() 0 6 3
A get_callbacks() 0 2 1
1
import logging
2
import os
3
from sys import version_info
4
5
import yaml
6
7
if version_info[0] == 2:
8
    # We are using Python 2.x
9
    import Tkinter as tk
10
    import tkFileDialog as filedialog
11
elif version_info[0] == 3:
12
    # We are using Python 3.x
13
    import tkinter as tk
14
    from tkinter import filedialog
15
from msquaredc import persistence, utils
16
from msquaredc.gui.widgets import ScaleWidget
17
18
class MainFrame: #pragma no cover
19
    def __init__(self, widgets):
20
        self.widgets = widgets
21
        self.tk = tk.Tk()
22
        self.tk.title("msquaredc")
23
        self.q = self.a = None
24
        self.__is_fullscreen = False
25
        self.frame = tk.Frame(self.tk)
26
        self.frame.grid(row=0, column=0)
27
        self.init_keybindings()
28
        self.init_menubar()
29
        self.init_content()
30
        self.open_files = {"save": None, "open": None}
31
        self.__input = None
32
        self.showResults("<No file loaded!>", "<Please open a file!>")
33
        self.act = None
34
        self.prev = []
35
        self.user = None
36
37
    def init(self):
38
        #Show NameDialog
39
        #validate output
40
        #draw gui
41
        pass
42
43
    def init_menubar(self):
44
        menubar = tk.Menu(self.tk)
45
        self.tk.config(menu=menubar)
46
47
        fileMenu = tk.Menu(menubar)
48
49
        fileMenu.add_command(label="Open", command=persistence.open_file)
50
        fileMenu.add_command(label="Save", command=self.save_file)
51
52
        fileMenu.add_separator()
53
54
        fileMenu.add_command(label="Exit", underline=0, command=self.onExit)
55
        menubar.add_cascade(label="File", underline=0, menu=fileMenu)
56
57
    def showResults(self, q, a):
58
        self.q = tk.Label(self.tk, text=q)
59
        self.q.grid(column=2, row=1, sticky=tk.NSEW, columnspan=1)
60
        self.a = tk.Label(self.tk, text=a)
61
        self.a.grid(column=2, row=2, sticky=tk.NSEW, columnspan=1)
62
63
    def init_content(self):
64
        for i, j in enumerate(self.widgets):
65
            j.draw(self.tk, i + 3)
66
        self.tk.grid_rowconfigure(0, weight=1)
67
        self.tk.grid_rowconfigure(len(self.widgets) + 3, weight=1)
68
        self.tk.grid_columnconfigure(0, weight=1)
69
        self.tk.grid_columnconfigure(len(self.widgets) + 3, weight=1)
70
71
    def init_keybindings(self):
72
        self.tk.bind("<F11>", self.toggle_fullscreen)
73
        self.tk.bind("<Escape>", self.end_fullscreen)
74
75
    def toggle_fullscreen(self, event=None):
76
        self.__is_fullscreen = not self.__is_fullscreen  # Just toggling the boolean
77
        self.tk.attributes('-fullscreen', self.__is_fullscreen)
78
        self.tk.overrideredirect(self.__is_fullscreen)
79
        return "break"
80
81
    def end_fullscreen(self, event=None):
82
        self.__is_fullscreen = False
83
        self.tk.attributes("-fullscreen", False)
84
        self.tk.overrideredirect(False)
85
        return "break"
86
87
    def save_file(self):
88
        filename = tk.filedialog.asksaveasfilename()
89
        try:
90
            file = open(filename, 'w')
91
            self.open_files["save"].append(file)
92
        except FileNotFoundError:
93
            pass
94
95
    def onExit(self):
96
        for category in self.open_files:
97
            self.open_files[category].close()
98
        self.tk.quit()
99
100
    def start(self):
101
        self.tk.mainloop()
102
103
class MainApplication(tk.Frame):
104
    def __init__(self, parent, *args, **kwargs):
105
        tk.Frame.__init__(self, parent, *args, **kwargs)
106
        self.parent = parent
107
        self.callbacks = {}
108
        self.statusbar = StatusBar(self)
109
        self.toolbar = ToolBar(parent,self)
110
        self.navbar = NavBar(self)
111
        self.main = Main(self,"config.yml","jerome.txt")
112
113
        self.statusbar.pack(side="bottom", fill="x")
114
        #self.toolbar.pack(side="top", fill="x")
115
        self.navbar.pack(side="bottom", anchor="se")
116
        self.main.pack(side="top", expand=True) #fill removed
117
118
    def add_callback(self,name,function):
119
        callbacks = self.get_callbacks(name)
120
        callbacks.append(function)
121
        self.callbacks[name] = callbacks
122
123
    def get_callbacks(self, name):
124
        return self.callbacks.get(name,[])
125
126
    def handle_callback(self,name):
127
        if self.get_callbacks(name):
128
            for i in self.get_callbacks(name):
129
                i()
130
        else:
131
            self.notice("".join(["The event ",name," has been unhandled!"]))
132
133
    def notice(self,string):
134
        logging.log(logging.INFO,string)
135
        self.statusbar.variable.set(string)
136
137
class StatusBar(tk.Frame):
138
    def __init__(self, master):
139
        tk.Frame.__init__(self, master)
140
        self.variable=tk.StringVar()
141
        self.label=tk.Label(self, bd=1, relief=tk.SUNKEN, anchor=tk.W,
142
                           textvariable=self.variable,
143
                           font=('arial',10,'normal'))
144
        self.variable.set('Status Bar')
145
        self.label.pack(fill=tk.X)
146
147
class NavBar(tk.Frame):
148
    def __init__(self, master):
149
150
        tk.Frame.__init__(self, master)
151
        self.next = tk.Button(text="Next >",command=lambda: master.handle_callback("next"))
152
        self.prev = tk.Button(text="< Previous",command=lambda: master.handle_callback("prev"))
153
        self.prev.grid(column=0,row=0,in_=self,pady=5)
154
        self.next.grid(column=1,row=0,in_=self,padx=5,pady=5)
155
156
class ToolBar(tk.Menu):
157
    def __init__(self,master,handler):
158
        tk.Menu.__init__(self,master)
159
        master.config(menu=self)
160
161
        fileMenu = tk.Menu(self,tearoff=False)
162
163
        fileMenu.add_command(label="Open", command=lambda: handler.handle_callback("open"))
164
        fileMenu.add_command(label="Save", command=lambda: handler.handle_callback("save"))
165
166
        fileMenu.add_separator()
167
168
        fileMenu.add_command(label="Exit", underline=0, command=lambda: handler.handle_callback("exit"))
169
        self.add_cascade(label="File", underline=0, menu=fileMenu)
170
171
class Main(tk.Frame):
172
    def __init__(self,master,paper,data):
173
        tk.Frame.__init__(self,master)
174
        master.add_callback("next",lambda: Main.get_next(self))
175
        self.master = master
176
        # Get paper information
177
        ci = None
178
        with open(paper) as stream:
179
            ci = yaml.load(stream)
180
        self.questions = ci["questions"]
181
        self.title = ci["title"]
182
        self.order = ci["order"]
183
        self.show = ci["show"]
184
        self.user = ci["user"]
185
186
        # Get Data
187
        self.data = persistence.obtain(data)
188
189
        self.infofield = InfoField(self)
190
        self.infofield.grid(row=0)
191
        self.infofield.title = self.title
192
        self.widgetfield = WidgetField(self,{})
193
194
        self.current_question_index = 0
195
        self.current_answerer_index = 0
196
        self.start()
197
198
    def run(self):
199
        questions = [i["text"] for i in self.questions]
200
        for i,question in enumerate(self.questions):
201
            # Collect answers to code
202
            coded = []
203
            if "out{}.txt".format(i) in os.listdir(os.getcwd()):
204
                coded = persistence.obtain("out{}.txt".format(i))
205
            for answerer in self.data:
206
                for column in answerer:
207
                    if column not in questions:
208
                        pass
209
210
211
    def start(self):
212
        # Pick question + solution
213
214
        # Build and display
215
        self.infofield.question = self.questions[self.current_question_index]["text"]
216
        self.infofield.answer = self.data[self.current_answerer_index][self.infofield.question]
217
218
        self.widgetfield = WidgetField(self,self.questions[self.current_question_index]["coding"])
219
        self.widgetfield.show()
220
        self.widgetfield.grid(row=1)
221
222
    def get_next(self):
223
        #store previous
224
        used = [i["text"] for i in self.questions]
225
        sample = {i:self.data[self.current_answerer_index][i] for i in self.data[self.current_answerer_index]
226
                  if i not in used}
227
        sample["question"] = self.questions[self.current_question_index]["text"]
228
229
        sample.update(self.widgetfield.get_res_dict())
230
        print(sample)
231
        persistence.persist("out{}.txt".format(self.current_question_index),sample,"a+")
232
233
        self.current_answerer_index += 1
234
        if self.current_answerer_index >= len(self.data):
235
            self.current_answerer_index = 0
236
            self.current_question_index += 1
237
        # Check for resumables
238
239
        if self.current_question_index >= len(self.questions):
240
            self.infofield.question = "Finished"
241
            self.infofield.answer = "You may now leave"
242
        else:
243
            self.infofield.question = self.questions[self.current_question_index]["text"]
244
            if self.infofield.question in self.data[self.current_answerer_index]:
245
                self.infofield.answer = self.data[self.current_answerer_index][self.infofield.question]
246
            else:
247
                best = -1
248
                element = None
249
                for i in self.data[self.current_answerer_index]:
250
                    res = utils.lcs(i,self.infofield.question)
251
                    if len(res) > best:
252
                        element = i
253
                        best = len(res)
254
                self.infofield.answer = self.data[self.current_answerer_index][element]
255
            self.widgetfield.grid_forget()
256
            self.widgetfield.destroy()
257
            self.widgetfield = WidgetField(self,self.questions[self.current_question_index]["coding"])
258
            self.widgetfield.show()
259
            self.widgetfield.grid(row=1)
260
261
class InfoField(tk.Frame):
262
    def __init__(self,master):
263
        font = ("serif", 16)
264
        padding = 5
265
        tk.Frame.__init__(self,master)
266
        self.__titlevar = tk.StringVar(self,"Title")
267
        self.__title = tk.Label(master, textvariable=self.__titlevar, font=("Helvetica", 18), pady=10)
268
        self.__questionvar =  tk.StringVar(self,"Question")
269
        self.__question = tk.Label(master, textvariable=self.__questionvar, anchor=tk.W, font=("serif", 16, "bold"),
270
                                   pady=5)
271
        self.__answervar =  tk.StringVar(self,"Answer")
272
        self.__answer = tk.Label(master, textvariable=self.__answervar, anchor=tk.W, font=("Times", 16), pady=5,
273
                                 relief="groove")
274
        self.__lengthvar =  tk.StringVar(self,"Length")
275
        self.__length = tk.Label(master, textvariable=self.__lengthvar, anchor=tk.W, font=font, pady=5)
276
        self.q = tk.Label(self, text="Question:", anchor=tk.E, font=font, pady=5)
277
        self.a = tk.Label(self, text="Answer:", anchor=tk.E, font=font, pady=10)
278
        self.l = tk.Label(self, text="Length:", anchor=tk.E, font=font, pady=5)
279
        self.__title.grid(in_=self,row=0,columnspan=2)
280
        self.q.grid(in_=self,column=0,row=1)
281
        self.__question.grid(in_=self,column=1,row=1)
282
        self.a.grid(in_=self,column=0,row=2)
283
        self.__answer.grid(in_=self,column=1,row=2)
284
        # self.l.grid(in_=self,column=0,row=3)
285
        # self.__length.grid(in_=self,column=1,row=3)
286
287
    @property
288
    def title(self):
289
        return self.__titlevar.get()
290
291
    @title.setter
292
    def title(self,value):
293
        self.__titlevar.set(value)
294
295
    @property
296
    def question(self):
297
        return self.__questionvar.get()
298
299
    @question.setter
300
    def question(self,value):
301
        self.__questionvar.set(value)
302
303
    @property
304
    def answer(self):
305
        return self.__answervar.get()
306
307
    @answer.setter
308
    def answer(self,value):
309
        self.__answervar.set(value)
310
        self.__lengthvar.set(" ".join(["Symbols",str(len(self.answer)),"Words",str(len(self.answer.split(" ")))]))
311
312
    @property
313
    def length(self):
314
        return self.__lengthvar.get()
315
316
    @length.setter
317
    def length(self,value):
318
        self.__lengthvar.set(value)
319
320
class WidgetField(tk.Frame):
321
    def __init__(self, master,criterias):
322
        tk.Frame.__init__(self,master)
323
        self.criterias = criterias
324
        self.widgets = []
325
        for i in criterias:
326
            self.widgets.append(ScaleWidget(master,i["criteria"],i["min"],i["max"]))
327
328
    def show(self):
329
        for i,element in enumerate(self.widgets):
330
            element.variables[0].grid(column=0,row=i,in_=self)
331
        for i,element in enumerate(self.widgets):
332
            element.label.grid(column=1,row=i,in_=self)
333
        for i,element in enumerate(self.widgets):
334
            index = 2
335
            for k,j in enumerate(element.variables[1:]):
336
                j.grid(column=index+k,row=i,in_=self)
337
338
    def get_res_dict(self):
339
        return {element.label.cget('text'):element.variables[0].get() for element in self.widgets}
340
341
342
343
344
if __name__ == "__main__":
345
    root = tk.Tk()
346
    MainApplication(root).pack(side="top", fill="both", expand=True)
347
    root.geometry("640x480")
348
    root.mainloop()
349