-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTestingNew.PY
3381 lines (2638 loc) · 168 KB
/
TestingNew.PY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
try:
import Tkinter as tk
from tkFileDialog import askopenfilename
import cgi
print('Using Python 2')
except:
import tkinter as tk
from tkinter.filedialog import askopenfilename
import html as cgi
print('Using Python 3')
import math
import numpy
import random
import os
import re
import UI_Settings
from UI_Settings import *
### Main
class UI_Master_Class(tk.Tk):
'''Master UI: Contains all TDX_Editor UI elements (except some Tab-specific UI classes)'''
def __init__(self, FileDirectory = r'C:\Users\GEX\Desktop\testing'):
tk.Tk.__init__(self)
self.InitialDirectory = FileDirectory
self.Create_Center()
self.Open_TDX_File()
print('WAIT: start self.mainloop()')
self.mainloop()
print('EXIT: end self.mainloop()\n')
###
###
### Center window
def Create_Center(self):
'''The UI Center contains all other UI elements. It contains two windows Window_Buttons, which is static and Window_Tab, which changes depending on the active Tab'''
self.UI_Settings = UI_Settings()
self.title("TDX Editor")
# Tab Order determined by order of the tuples (Lookup name, Displayed name) from Tab_Names_Combined.
# Do not change "Lookup name" ("tab_XXX" in self.Tab_lookups), unless it is changed throughout the file.
# See Create_Tabs() or Update_TDX_File() for implementation of the ordering.
Tab_Names_Combined = [('tab_INTRO','Intro'), ('tab_RENAME','Rename'), ('tab_DATA','Data Gen'), ('tab_TABLE','Add Table'), ('tab_FB','Multi-Part FB'), ('tab_SP','Clean/SP Gen')]
self.Tab_lookups, self.Tab_Names = zip(*Tab_Names_Combined)
# Initialize values
self.ACTIVE_TAB_ROW = 12 # Constant
self.ACTIVE_TAB_COL = 0 # Constant
self.ActivePageN = 0
self.ActiveTabN = 0
self.RecentEdits = False
# Creates two main windows
self.Window_Buttons = tk.Frame(self, bg=self.UI_Settings.ColorBGdkGrey) # bg color is between tab buttons
self.Window_Tab = tk.Frame(self, bg=self.UI_Settings.ColorBack1)
self.Window_Buttons.grid(row=0, column=0, sticky=tk.NSEW)
self.Window_Tab.grid( row=1, column=0, sticky=tk.NSEW)
# Expands self.Window_Tab
self.columnconfigure(0, weight=1)
self.rowconfigure( 1, weight=1)
# Setup Tab_Buttons inside Window_Buttons
Max_Tab_Name_Spacing = max([len(X) for X in self.Tab_Names]) + 4
self.Tab_Buttons = [tk.Button(self.Window_Buttons,
bd=4,
text='{NM: ^{L}}'.format(NM=NAME, L=Max_Tab_Name_Spacing),
bg=self.UI_Settings.ColorBGltGrey) \
for index, NAME in enumerate(self.Tab_Names)]
[B.grid(row=0, column=index, sticky=tk.EW+tk.S, padx=3, pady=5, ipady=1) for index, B in enumerate(self.Tab_Buttons)]
# Setup additional Window_Buttons buttons (save, load, exit)
self.Button_Load = tk.Button(self.Window_Buttons,
text="Load File",
bg=self.UI_Settings.ColorLoad,
fg = 'white',
command=self.Open_TDX_File,
bd=5, relief="ridge")
self.Button_Save = tk.Button(self.Window_Buttons,
text="Save File",
bg=self.UI_Settings.ColorSave,
fg = 'white',
command=self.Save_Process,
bd=5, relief="ridge",
state=tk.DISABLED)
self.Button_Quit = tk.Button(self.Window_Buttons,
text="Exit",
bg=self.UI_Settings.ColorExit,
fg = 'white',
command=self.QUIT,
bd=5, relief="ridge")
Spacing = 3
self.Button_Quit.grid(row=0, column=101, padx=Spacing*2, pady=Spacing, sticky=tk.NSEW, ipadx=15)
self.Button_Load.grid(row=0, column=102, padx=Spacing*1, pady=Spacing, sticky=tk.NSEW, ipadx=5, ipady=3)
self.Button_Save.grid(row=0, column=103, padx=Spacing*1, pady=Spacing, sticky=tk.NSEW, ipadx=5)
# Horizontally expand Window_Buttons (includes: additional and Tab_Buttons)
[self.Window_Buttons.columnconfigure(COLUMN, weight=1) for COLUMN in range(len(self.Tab_Names)+2)]
# Expands Window_Tab (includes: active Tab)
self.Window_Tab.columnconfigure(self.ACTIVE_TAB_COL, weight=1)
self.Window_Tab.rowconfigure( self.ACTIVE_TAB_ROW, weight=11)
self.Size_Window()
def Size_Window(self):
'''Sets minimum size, current size, and forces active window'''
self.minsize(800, 700)
w, h = max(10,self.winfo_screenwidth()-100), max(10,self.winfo_screenheight()-200)
self.geometry("%dx%d+30+30" % (w, h))
self.lift()
self.focus_force()
### Tabs
def Create_Tabs(self):
'''Activates each Tab Creation method, self.Create_Tab_xxx'''
# Creates self.Show_CMD_closure() command and tk.Frame for each Tab
self.Tabs_List = [tk.Frame(self.Window_Tab, bg=self.UI_Settings.ColorBGdkGrey) for NAME in self.Tab_Names]
self.ActiveTabCMD = [self.Show_CMD_closure('Tab', index, self.Tabs_List, self.Tab_Buttons) for index in range(len(self.Tab_Names))]
[TAB.grid(
row=self.ACTIVE_TAB_ROW,
column=self.ACTIVE_TAB_COL,
padx=0, pady=0,
sticky=tk.NSEW) for index, TAB in enumerate(self.Tabs_List)]
[TAB.columnconfigure(self.ACTIVE_TAB_COL, weight=1) for TAB in self.Tabs_List]
[TAB.rowconfigure( self.ACTIVE_TAB_ROW, weight=1) for TAB in self.Tabs_List]
# Implementation of the ordering for Tabs
self.Create_Tab_Splash( self.Tab_lookups.index('tab_INTRO'))
self.Create_Tab_Renamer( self.Tab_lookups.index('tab_RENAME'))
self.Create_Tab_Table( self.Tab_lookups.index('tab_TABLE'))
self.Create_Tab_Generator(self.Tab_lookups.index('tab_DATA'))
self.Create_Tab_SPgen( self.Tab_lookups.index('tab_SP'))
self.Create_Tab_MPart( self.Tab_lookups.index('tab_FB'))
# Sets active tab to N=[self.ActiveTabN] (N=0, 'tab_INTRO' for first run)
self.ActiveTabCMD[self.ActiveTabN]()
# Sets self.Button_Save to inactive (until Commit)
[XXX.configure(state=tk.NORMAL) for XXX in self.Tab_Buttons]
self.RecentlyUpdated(False)
def Create_Tab_Splash(self, N):
''' The Splash Tab contains introduction data, a sample button legend, and TDX step/interaction data'''
#self.Window_Tab.bind_all("<MouseWheel>", self._on_mousewheel) # Enables mousewheel scrolling in tab_INTRO
self.Splash_Tab = tk.Frame(self.Tabs_List[N], bg=self.UI_Settings.ColorBack1) #VerticalScrolled
self.Splash_Tab.grid(row=self.ACTIVE_TAB_ROW, column=self.ACTIVE_TAB_COL, padx=0, pady=0, sticky=tk.NSEW)
self.Splash_Button_Region = tk.LabelFrame(self.Tabs_List[N], text='Select type of Intro information', bg=self.UI_Settings.ColorBGltGrey)
self.Splash_Button_Region.grid(row=0, column=0, padx=0, pady=0, sticky=tk.NSEW)
self.Splash_Page_Names = ['Program', 'File', 'None']
self.Splash_Pages = [tk.LabelFrame(self.Splash_Tab, bg=self.UI_Settings.ColorBack1, text=NAME) for NAME in self.Splash_Page_Names]
[XXX.grid(row=0, column=0, sticky=tk.NSEW) for XXX in self.Splash_Pages]
self.Splash_Tab.columnconfigure(0, weight=1)
self.Splash_Tab.rowconfigure( 0, weight=1)
Max_Splash_Name_Spacing = max([len(X) for X in self.Splash_Page_Names]) + 4
self.Splash_Buttons = [tk.Button(self.Splash_Button_Region, bd=4, text='{NM: ^{L}}'.format(NM=NAME, L=Max_Splash_Name_Spacing), bg=self.UI_Settings.ColorBGltGrey) for index, NAME in enumerate(self.Splash_Page_Names)]
[BUTTON.grid(row=0, column=index, padx=2, pady=2) for index, BUTTON in enumerate(self.Splash_Buttons)]
self.ActiveSplashCMD = [self.Show_CMD_closure('Splash', index, self.Splash_Pages, self.Splash_Buttons) for index in range(len(self.Splash_Page_Names))]
self.ActiveSplashCMD[0]()
self.Splash_Program = self.Splash_Pages[self.Splash_Page_Names.index('Program')]
self.Splash_File = self.Splash_Pages[self.Splash_Page_Names.index('File')]
self.Splash_None = self.Splash_Pages[self.Splash_Page_Names.index('None')]
# Introduction Data
chars = ['_','*']
Input_Data = [
(self.Splash_Program, ['***Basic Program Information'],0,'light blue'),
(self.Splash_Program, ['*Only the "Save" button will edit the actual TDX file.'.format(chars[0]*3), '*Each "Commit" button updates information from the active tab to all others.', '*Non-Committed data will not be saved. Commit before saving or before editing another tab.', '*A Commit will clear most inputs (not Table/dataGen). A Load/Save will clear all inputs'],1,'lemon chiffon'),
(self.Splash_Program, ['{}Tab Descriptions'.format(chars[1]*3)],0,'light blue'),
(self.Splash_Program, ['Rename: Rename any item (var, array,...). \n\t*Makes edits manually, with regex, or using a common root (plus an index number)', 'Add Table: Add a table or a data table, or arrays. \n\t*Set the row separator (tab, comma, space), transpose the data, or view a test table.', 'Data Generator: Creates TDX variables from a list of values. \n\t*Set name stem, type, format, and an equation for min/max from value. \n\t*Shift data using equation, min/max, mean/standard deviation.\n\t*Generate data from an equation, a sample, or a distribution function.','Clean/SP generator: Combination of common SP preparations\n\t*Deletes feedbacks\n\t*Pauses all steps, except first and last\n\t*Removes unused interactions\n\t*Removes import from steps', 'Multi-Part Feedback: Automatically generates feedbacks (Your first answer is correct, but...) for 2 to 8 parts\n\t*Set part names (1st, 2nd,...) and general or part specific feedbacks\n\t*Displays interaction names in selected step and has copy buttons for "Interaction Names" and paste buttons for "Input Names"'],1,'lemon chiffon'),
(self.Splash_Program, ['{}Button Legend (Sample button colors)'.format(chars[1]*3)],0,'light blue'),
]
# TDX step/interaction data
Input_Data += [(self.Splash_File, ['{}Unused interactions: List'.format(chars[1]*3)], 0,'light green'),]
if len(self.DISINTEGRATE.RemovableInteractions)==0:
Inter_Unused = [(self.Splash_File, ('__None__',), 1,'white'),]
else:
REMOVABLE = self.DISINTEGRATE.RemovableInteractions
Inter_Unused = [(self.Splash_File, [', '.join(REMOVABLE),], 1,'white')]
Input_Data += Inter_Unused
Input_Data +=[(self.Splash_File, ['{}Used interactions: By step'.format(chars[1]*3)],0,'light green')]
if len(self.DISINTEGRATE.D_Step_to_Inter.items())==0:
Inter_used = [(self.Splash_File, ('__None__',), 1,'white'),]
else:
USED = self.DISINTEGRATE.D_Step_to_Inter.items()
Inter_used = [(self.Splash_File, ['{}: '.format(A)+', '.join(B),], 1,'white') for A,B in USED]
Input_Data += Inter_used
indent_len = 40
for index, (LOC, DATA, INDENT_VAL, COLOR) in enumerate(Input_Data):
A = tk.Label(LOC, bg=COLOR) #, justify=tk.LEFT)
A.grid(row=index, column=0, padx=10+indent_len*INDENT_VAL, pady=(2*(1-index%2)), sticky=tk.NSEW)
A.rowconfigure(0, weight=1)
A.columnconfigure(0, weight=1)
for ROW, DATUM in enumerate(DATA):
B = tk.Label(A,
text=DATUM,
bg=COLOR,
anchor=tk.W,
justify=tk.LEFT)
B.grid(row=ROW+1,
column=0,
padx=5,
pady=0,
sticky=tk.NSEW)
# sample button legend
Button_Info = [
('Tab (in-Active)', 'black', self.UI_Settings.ColorPassive, 4, "raised", (0,0)),
('Tab (Active)', 'black', self.UI_Settings.ColorActive, 4, "raised", (0,1)),
('Exit', 'white', self.UI_Settings.ColorExit, 5, "ridge", (1,0)),
('Load', 'white', self.UI_Settings.ColorLoad, 5, "ridge", (1,1)),
('Save', 'white', self.UI_Settings.ColorSave, 5, "ridge", (1,2)),
('Commit', 'black', self.UI_Settings.ColorCommit, 5, "ridge", (1,3)),
('Clear or Reset inputs', 'black', self.UI_Settings.ColorClear, 2, "raised", (2,0)),
('View/test', 'black', self.UI_Settings.ColorTest , 2, "raised", (2,1)),
('Copy output', 'black', self.UI_Settings.ColorCopy, 2, "raised", (2,2)),
('Edit inputs', 'black', self.UI_Settings.ColorEdit, 2, "raised", (2,3)),
]
ABC = tk.Frame(self.Splash_Pages[self.Splash_Page_Names.index('Program')], bg=self.UI_Settings.ColorText) #, bg='red')
ABC.grid(row=100, column=0, padx=5+indent_len*1, pady=5, ipadx=0, ipady=2, sticky=tk.NSEW)
### relief = flat, raised, sunken, groove, ridge
Max_Button_Name_Length = max( [len(X) for X in list(zip(*Button_Info))[0]] )
for index, (Button_Name, Button_FG, Button_COLOR, Button_BD, Button_relief, (ROW,COL)) in enumerate(Button_Info):
Button_New = tk.Button(ABC,
text = '{NM: ^{L}}'.format(NM=Button_Name, L=Max_Button_Name_Length),
bg = Button_COLOR,
fg = Button_FG,
bd = Button_BD,
relief = Button_relief)
Button_New.grid(row=ROW, column=COL, padx=5, pady=5, sticky=tk.NSEW, ipadx=10, ipady=0)
def Create_Tab_Renamer(self, N):
# Button Frame
self.PG_name_Buttons = tk.LabelFrame(self.Tabs_List[N], text='Select Rename type:', bg=self.UI_Settings.ColorBGltGrey)
self.PG_name_Buttons.grid(row=0, column=0,ipadx=5, pady=0, sticky=tk.NSEW)
# Pages
self.Page_Colors = ['light cyan', 'sky blue', 'light yellow', 'khaki']
self.Pages = [tk.Frame(self.Tabs_List[N], bg=COLOR) for COLOR in self.Page_Colors]
[XXX.grid(
row=self.ACTIVE_TAB_ROW,
column=self.ACTIVE_TAB_COL,
padx=0, pady=0,
sticky=tk.NSEW) for XXX in self.Pages]
[XXX.rowconfigure( self.ACTIVE_TAB_ROW, weight=1) for XXX in self.Pages]
[XXX.columnconfigure(self.ACTIVE_TAB_COL, weight=1) for XXX in self.Pages]
self.PG_name_Buttons.columnconfigure(4, weight=1)
# Buttons
self.Rename_Apply_Button = tk.Button(self.PG_name_Buttons, bg=self.UI_Settings.ColorCommit, text='Commit: Rename all', bd=5, relief="ridge", command=self.Rename_All)
self.Page_Names = ['Variables', 'Steps', 'Interactions', 'Other']
self.Rename_Buttons = [tk.Button(self.PG_name_Buttons, text=NAME, bd=4) for NAME in self.Page_Names]
[BUTTON.grid(row=0, column=index, ipadx=20, padx=10*((1+index)%2), pady=5, sticky=tk.EW+tk.S) for index, BUTTON in enumerate(self.Rename_Buttons)]
self.Rename_Apply_Button.grid(row=0, column=5, ipadx=20, padx=10, pady=5, sticky=tk.EW, ipady=5)
# Fill Pages
self.Create_Pages()
def Create_Pages(self):
'''Creates Pages in tab_RENAME. Uses ScrolledNameListsREGEX() to create a Page for each list of [list of Names].
First [list of [lists]]==[Vars, Arrays, Formulas]'''
self.EX_Page_Var = ScrolledNameListsREGEX(self.Pages[self.Page_Names.index('Variables')], self.UI_Settings, Data_Lists = self.DISINTEGRATE.Lists_Names_VAFxy, Data_Labels=['Variable', 'Array', 'Formula'])
self.EX_Page_Var.grid(row=self.ACTIVE_TAB_ROW, column=self.ACTIVE_TAB_COL, padx=5, pady=5, sticky=tk.NSEW)
self.EX_Page_Step = ScrolledNameListsREGEX(self.Pages[self.Page_Names.index('Steps')], self.UI_Settings,
Data_Lists = [self.DISINTEGRATE.List_Steps, self.DISINTEGRATE.List_Feedbacks, self.DISINTEGRATE.List_Popups],
Data_Labels=['Step', 'Feedback', 'Popup'])
self.EX_Page_Step.grid(row=self.ACTIVE_TAB_ROW, column=self.ACTIVE_TAB_COL, padx=5, pady=5, sticky=tk.NSEW)
try:
LIST1, DATA1 = zip(*[XXX for XXX in zip(self.DISINTEGRATE.Lists_Names_Inter, self.DISINTEGRATE.Search_Inter) if len(XXX[0])>0])
except:
LIST1, DATA1 = (), ()
self.EX_Page_Other = ScrolledNameListsREGEX(self.Pages[self.Page_Names.index('Interactions')], self.UI_Settings, Data_Lists = LIST1, Data_Labels= DATA1)
self.EX_Page_Other.grid(row=self.ACTIVE_TAB_ROW, column=self.ACTIVE_TAB_COL, padx=5, pady=5, sticky=tk.NSEW)
try:
LIST2, DATA2 = zip(*[XXX for XXX in zip(self.DISINTEGRATE.Lists_Names_Other, self.DISINTEGRATE.Search_Other) if len(XXX[0])>0])
except:
LIST2, DATA2 = (), ()
self.EX_Page_Inter = ScrolledNameListsREGEX(self.Pages[self.Page_Names.index('Other')], self.UI_Settings, Data_Lists = LIST2, Data_Labels= DATA2)
self.EX_Page_Inter.grid(row=self.ACTIVE_TAB_ROW, column=self.ACTIVE_TAB_COL, padx=5, pady=5, sticky=tk.NSEW)
self.ActivePageCMD = [self.Show_CMD_closure('Page', index, self.Pages, self.Rename_Buttons) for index in range(len(self.Rename_Buttons))]
self.ActivePageCMD[0]()
def Create_Tab_Table(self, N):
# Largely self contained TableInput UI and Table_Gen algorithm, except self.master.Update_TDX_File()
self.TBL = TableInput(self.Tabs_List[N], self, self.DISINTEGRATE.Text_Input, self.UI_Settings)
self.TBL.grid(row=self.ACTIVE_TAB_ROW, column=self.ACTIVE_TAB_COL, sticky=tk.NSEW)
def Create_Tab_Generator(self, N):
# Largely self contained DataGen UI and Data_Gen algorithm, except self.master.Update_TDX_File()
self.GEN = DataGen(self.Tabs_List[N], self, self.DISINTEGRATE.Text_Input, self.UI_Settings)
self.GEN.grid(row=self.ACTIVE_TAB_ROW, column=self.ACTIVE_TAB_COL, sticky=tk.NSEW)
def Create_Tab_SPgen(self, N):
'''Deletes all feedbacks and feedback links from steps.
Removes import_from_excercise.
Pauses all steps except first and last.
Deletes all unused student interactions.
Sets variables initial value, if there is one.'''
# Creates Create_Tab_SPgen UI
self.SPgen_Frame = tk.LabelFrame(self.Tabs_List[N], text='SPgen_Frame', bg=self.UI_Settings.ColorBack1)
self.SPgen_Frame.grid(row=self.ACTIVE_TAB_ROW, column=self.ACTIVE_TAB_COL, sticky=tk.NSEW)
SP_Gen_Button = tk.Button(self.SPgen_Frame, command=self.Generate_SP_from_GS, bd=5, relief="ridge", padx=5, pady=5, justify=tk.LEFT)
SP_Gen_Button.grid(row=0, column=10, sticky=tk.NSEW, columnspan=2)
CleanUp_Button = tk.Button(self.SPgen_Frame, bg=self.UI_Settings.ColorCommit, bd=5, relief="ridge", command=self.Clean_TDX, justify=tk.LEFT)
CleanUp_Button.grid(row=0, column=0, sticky=tk.NSEW)
Spacing = tk.Label(self.SPgen_Frame, text='', bg=self.UI_Settings.ColorBack1)
Spacing.grid(row=1, column=1, sticky=tk.NSEW, ipadx=10)
# Controls button label/Disable, depending on filetype (self.File_Just_Extension).
if 'tdxex' in self.File_Just_Extension:
SP_Gen_Button.config(state=tk.DISABLED, bg=self.UI_Settings.ColorDisabled, text=u'Convert GS\u2192SP\n***Not a GS file')
CleanUp_Button.config(text='Commit: (EX)\n Clean unused')
elif 'tdxgs' in self.File_Just_Extension:
SP_Gen_Button.config(state=tk.NORMAL, bg=self.UI_Settings.ColorSave, text=u'Commit/Save as SP:\nConvert GS\u2192SP\n\nClean unused\nClean Import/Pause Steps\nSet values to initial')
CleanUp_Button.config(text='Commit: (GS)\n Clean unused')
elif 'tdxsp' in self.File_Just_Extension:
SP_Gen_Button.config(state=tk.DISABLED, bg=self.UI_Settings.ColorDisabled, text=u'Convert GS\u2192SP\n***Not a GS file')
CleanUp_Button.config(text='Commit: (SP) \nClean Unused interactions\nClean Import/Pause Step\nClean/Set initial values')
# Shows List of Un-used interactions
Num_Inter = len(self.DISINTEGRATE.RemovableInteractions)
Header = tk.Label(self.SPgen_Frame,
text=u'\u2193 {N} unused interaction{PLURAL} \u2193'.format(N=Num_Inter,
PLURAL='' if Num_Inter==1 else 's'),
bd=5,
relief='ridge',
bg=self.UI_Settings.ColorBack1)
Header.grid(row=2, column=0, sticky=tk.NSEW)
self.Label_Unused = [tk.Label(self.SPgen_Frame, text=INTER, bg=self.UI_Settings.ColorBack1) for INTER in self.DISINTEGRATE.RemovableInteractions]
[XXX.grid(row=index+10, column=0, sticky=tk.W) for index, XXX in enumerate(self.Label_Unused)]
# Shows List of Used interactions
D_Step_to_Inter = self.DISINTEGRATE.D_Step_to_Inter.items()
D_Step_to_Inter_lengths = [len(X) for X in self.DISINTEGRATE.D_Step_to_Inter.values()]
D_Step_to_Inter_length_max = max([0]+list(D_Step_to_Inter_lengths))
Num_Inter2 = sum(D_Step_to_Inter_lengths)
Header2 = tk.Label(self.SPgen_Frame, text=u'\u2193 {N} used interaction{PLURAL} \u2193'.format(N=Num_Inter2, PLURAL='' if Num_Inter2==1 else 's'), bd=5, relief='ridge', bg=self.UI_Settings.ColorBack1)
Header2.grid(row=2, column=10, sticky=tk.EW, columnspan=D_Step_to_Inter_length_max+1)
self.Label_Used = [tk.Label(self.SPgen_Frame, text=INTER, bg=self.UI_Settings.ColorBack1) for INTER in self.DISINTEGRATE.RemovableInteractions]
[XXX.grid(row=index+10, column=0, sticky=tk.W) for index, XXX in enumerate(self.Label_Used)]
for index, (KEY, VALUE) in enumerate(D_Step_to_Inter):
Row_Header = tk.Label(self.SPgen_Frame, text=u'\u2192 {STEP}'.format(STEP = KEY), bd=2, relief='ridge', anchor=tk.W, bg=self.UI_Settings.ColorText)
Row_Header.grid(row=10+index, column=10, sticky=tk.EW, padx=5, ipadx=5)
self.Label_Unused2 = [tk.Label(self.SPgen_Frame, text=INTER, bg=self.UI_Settings.ColorText, anchor=tk.W) for INTER in VALUE]
[XXX.grid(row=10+index, column=11+index2, sticky=tk.NSEW, padx=1, pady=2) for index2, XXX in enumerate(self.Label_Unused2)]
self.SPgen_Frame.columnconfigure(0, weight=1)
for index in range(10,50):
self.SPgen_Frame.columnconfigure(index, weight=1)
def Create_Tab_MPart(self, N):
# Largely self contained TableInput UI and Table_Gen algorithm, except self.MASTERui.Update_TDX_File()
self.MultiPart = FB_MultiPart(self.Tabs_List[N], self, self.DISINTEGRATE.Text_Input, self.DISINTEGRATE.List_Steps, self.DISINTEGRATE.D_Step_to_Inter, self.UI_Settings)
self.MultiPart.grid(row=self.ACTIVE_TAB_ROW, column=self.ACTIVE_TAB_COL, sticky=tk.NSEW)
### File operations
def Open_TDX_File(self, Set_FileLocation = None):
if self.RecentEdits:
print('Error: Load with current TDX_Edits')
TEXTpop = 'Unsaved TDX_Edits have been made in the editor.\nAre you sure you want to load a new file?'
TEXTyes = 'Yes.\nLoad new file: Cancel any TDX_Edits'
COLORyes = self.UI_Settings.ColorLoad,
TEXTno = 'No.\nCancel: Keep TDX_Edits and return to editor'
COLORno = self.UI_Settings.ColorClear
A = ForcePopup(self, TEXTpop, [(TEXTyes, COLORyes), (TEXTno, COLORno)] )
A_SELECTION = A.SELECTION
if A_SELECTION==None:
print('Error interaction: No selection made')
elif A_SELECTION==0:
print('Error interaction: User selected load and clear unsaved TDX_Edits')
self.Open_TDX_File_operations(Set_FileLocation)
elif A_SELECTION==1:
print('Error interaction: User selected return to file with unsaved TDX_Edits')
pass
else:
print('Error: ForcePopup() return value')
else:
self.Open_TDX_File_operations(Set_FileLocation)
def Open_TDX_File_operations(self, Set_FileLocation):
'''Opens a TDX file (using askopenfilename to locate) and sends its text to self.Disintegrate_TDX_File(), after passing basic checks'''
if Set_FileLocation==None:
self.FileLocation = askopenfilename(initialdir = self.InitialDirectory, filetypes = (("TDX files","*.tdx*"),("all files","*.*")))
else:
self.FileLocation = Set_FileLocation
self.FileName = self.FileLocation.split("/")[-1]
self.FolderName = "/".join(self.FileLocation.split("/")[:-1])
self.File_Just_Name, self.File_Just_Extension = os.path.splitext(self.FileName)
print('OPEN: FileType= {TYPE}\t"{NAME}"'.format(
NAME=self.File_Just_Name,
TYPE=self.File_Just_Extension[4:].upper()))
if self.FileLocation=='':
print ('No file selected')
elif 'tdx' not in self.File_Just_Extension:
self.Clear_Tabs()
print ('Not a TDX file')
else:
#print('self.FileLocation FILE_OPEN', self.FileLocation)
self.Clear_Tabs()
self.InitialDirectory = self.FileLocation[:]
with open(self.FileLocation) as FILE_OPEN:
self.ORIGINAL_TEXT = FILE_OPEN.read()
if len(self.ORIGINAL_TEXT)==0:
print('No data in file')
else:
self.Disintegrate_TDX_File(self.ORIGINAL_TEXT)
self.Create_Tabs()
def Disable_Tabs(self):
[XXX.configure(state=tk.DISABLED) for XXX in self.Tab_Buttons]
def Clear_Tabs(self):
self.Disable_Tabs()
try:
[TAB.grid_remove() for TAB in self.Tabs_List]
except:
try:
self.Load_Count += 1
print('Clear_Tabs(self)": Probably an error for Loading #{}'.format(self.Load_Count))
except:
self.Load_Count = 1
#print('Clear_Tabs(self)": First loading')
def Disintegrate_TDX_File(self, Load_File):
'''DisintegrateTDX finds steps, interactions, and other TDX file components'''
self.DISINTEGRATE = DisintegrateTDX(FILE=Load_File)
self.title("TDX Editor ({})".format(self.FileName))
def Update_TDX_File(self, Load_File):
'''Updates each Tab to use most recent file. Occurs after Commit'''
# Passes edited Load_File to update all UI Tabs
self.Disintegrate_TDX_File(Load_File)
self.RecentlyUpdated(True)
# Splash Tab update
self.Splash_Tab.grid_forget()
self.Create_Tab_Splash(self.Tab_lookups.index('tab_INTRO'))
# Rename Tab update
self.PG_name_Buttons.grid_forget()
N = self.ActivePageN
self.Create_Tab_Renamer(self.Tab_lookups.index('tab_RENAME'))
self.ActivePageCMD[N]() # Resets active Page, when refreshing
#Table Tab update
self.TBL.Update_Table(Load_File)
#Data Gen Tab update
self.GEN.Update_TDX(Load_File)
#SP Gen Tab update
self.SPgen_Frame.grid_forget()
self.Create_Tab_SPgen(self.Tab_lookups.index('tab_SP'))
#MultiPart FB Tab update
self.MultiPart.grid_forget()
self.Create_Tab_MPart(self.Tab_lookups.index('tab_FB'))
### Save file operations
def Save_Get_Backup_Name(self):
### Get self.copy_Name and basic data
Files_In_Folder = os.listdir(self.FolderName)
#print('Saved 1.1', Files_In_Folder)
version_Prefix = r'_V' # _Version
Similar_FileNames = ['.'.join(XXX.split('.')[:-1]) for XXX in Files_In_Folder if self.File_Just_Name in XXX]
#print('Saved 1.2', Similar_FileNames)
File_Numbers = [re.findall('(?<={NAME}{EDIT})\d+'.format(NAME=re.escape(self.File_Just_Name), EDIT=re.escape(version_Prefix)), XXX) for XXX in Similar_FileNames]
#print('Saved 1.3', File_Numbers)
File_Nums_INT = [-1,]
for NUM in File_Numbers:
try:
File_Nums_INT.append(int(NUM[0]))
except:
pass
File_Num_Integer = max(File_Nums_INT)+1
#print('Saved 1.4', File_Num_Integer, File_Nums_INT)
self.copy_Name = (
self.FolderName + r'/' +
self.File_Just_Name +
version_Prefix +
str(File_Num_Integer) +
self.File_Just_Extension)
# This asserts that the .copy_Name is unique, which the File_Num_Integer should guarantee
assert (not os.path.exists(self.copy_Name)), 'Backup copy: potential-overwrite error in Save_Get_Backup_Name()'
def CreateBackup(self):
#print('Saved 1.0', self.FolderName)
self.Save_Get_Backup_Name()
#print('Saved 1.5', self.copy_Name)
with open(self.copy_Name, 'w+') as BACKUP_FILE:
BACKUP_FILE.write(self.ORIGINAL_TEXT)
print("Created backup of original text:\t\t[#print('Saved 1.9')]\n\t{}".format(self.copy_Name))
def Save_Process_Inputs(self, Text_to_Write, fileType_override):
#print('Saved 2.0', Text_to_Write==False)
if Text_to_Write==False:
self.Text_to_Write = self.DISINTEGRATE.Text_Input
else:
self.Text_to_Write = Text_to_Write
#print('Saved 2.1', fileType_override!=False)
if fileType_override!=False:
#print('Saved 2.1a', self.FolderName, self.File_Just_Name, fileType_override)
self.NewFileLocation = r'{PATH}/{NAME}.{TYPE}'.format(
PATH=self.FolderName,
NAME=self.File_Just_Name,
TYPE=fileType_override)
else:
self.NewFileLocation = self.FileLocation
#print('Saved 2.9', self.NewFileLocation)
pass
def Save_Check_No_Edits(self):
### Check for No_Edits
#print('Saved 3.0')
OLD = self.ORIGINAL_TEXT
#print('Saved 3.1')
with open(self.FileLocation, 'r') as NEW_FILE:
NEW = NEW_FILE.read()
#print('Saved 3.2')
CHECK = (NEW==OLD)
#print('Saved 3.9', CHECK)
return (CHECK)
def Save_TDX_File(self):
#print('Saved 9.0')
with open(self.NewFileLocation, 'w') as NEW_FILE:
#print('Saved 9.1')
NEW_FILE.write(self.Text_to_Write)
#print('Saved 9.2')
self.ORIGINAL_TEXT = self.Text_to_Write
self.RecentlyUpdated(False)
#print('Saved 9.3')
print("Save Complete:\t\t\t\t[#print('Saved 9.9')]\n\t{}".format(self.NewFileLocation))
def Save_Process(self, Text_to_Write=False, fileType_override=False):
'Saves the edited TDX file, and makes a copy of the original file (with version_Prefix(#File_Num_Integer#) appended to name)'
# For debugging
# REGEX Search ===> #(print\('Saved.*?\d\.\d\w*)'
# REGEX replace ===> \1 OR #\1
self.CreateBackup() # Saved 1.#
try:
self.Save_Process_Inputs(Text_to_Write, fileType_override) # Saved 2.#
if self.Save_Check_No_Edits(): # Saved 3.#
self.Save_TDX_File() # Saved 9.#
else:
print('Error: File has been edited since loading.')
TEXTpop = 'The current TDX file has been edited outside this program since it was loaded.\nDo you want to keep the TDX_Edits made in this editor?'
TEXTyes = 'Yes.\nSave: Overwrite current file with these TDX_Edits'
COLORyes = self.UI_Settings.ColorCommit
TEXTno = 'No.\nCancel: Cancel TDX_Edits and load in the current file'
COLORno = self.UI_Settings.ColorLoad
A = ForcePopup(self, TEXTpop, [(TEXTyes, COLORyes), (TEXTno, COLORno), ] )
A_SELECTION = A.SELECTION
if A_SELECTION==None:
print('Error interaction: No selection made')
elif A_SELECTION==0:
print('Error interaction: User selected clear TDX_Edits')
self.Open_TDX_File(self.FileLocation)
elif A_SELECTION==1:
print('Error interaction: User selected overwrite')
self.Save_TDX_File()
else:
print('Error: ForcePopup() return value')
except:
print('Error: General save-exception; check Save_Process()')
### Helper operations
def QUIT(self):
if self.RecentEdits:
print('Error: Quit with current TDX_Edits')
TEXTpop = 'Unsaved TDX_Edits have been made in the editor.\nAre you sure you want to quit?'
TEXTyes = 'Yes.\nQuit: Cancel any TDX_Edits'
COLORyes = self.UI_Settings.ColorExit
TEXTno = 'No.\nCancel: Keep TDX_Edits and return to editor'
COLORno = self.UI_Settings.ColorCommit
A = ForcePopup(self, TEXTpop, [(TEXTyes, COLORyes), (TEXTno, COLORno)] )
A_SELECTION = A.SELECTION
if A_SELECTION==None:
print('Error interaction: No selection made')
elif A_SELECTION==0:
print('Error interaction: User selected quit and clear unsaved TDX_Edits')
self.DESTROY()
elif A_SELECTION==1:
print('Error interaction: User selected return to file with unsaved TDX_Edits')
pass
else:
print('Error: ForcePopup() return value')
else:
self.DESTROY()
def DESTROY(self):
self.destroy()
def Duplicate_Check_TDX(self, TDXtext):
'''Creates a list of duplicate named objects in the TDX, object types listed in NamedSearches'''
# Generates list of REGEX searches using object types listed in NamedSearches
NamedSearches = ["var", "array", "formula", "figure", "collection", "xygraph", "NumberLine", "BarChart",
"piechart", "field", "multchoice", "sdgrapher", "xycursor", "nlcursor", "fillin", "Timeline", "image",
"datatable", "realtimedata", "acctable", "essay", "draganddrop"]
# Performs REGEX Searches
SEARCH2 = '(?:{}) name=\"(\w+)\"'.format('|'.join(NamedSearches))
ListSearches2 = [re.findall(SEARCH2 , TDXtext , flags=re.IGNORECASE)][0]
ListSearches2.sort()
return self.Duplicate_Check_list(ListSearches2)
def Duplicate_Check_list(self, CheckList):
CheckList = [NAME.lower() for NAME in CheckList]
singles = set()
doubles = set()
for name in CheckList:
if name in singles:
doubles.add(name)
else:
singles.add(name)
DoublesList = sorted(list(doubles))
return DoublesList
def Test_Print(self):
try:
self.EX_Page_Var.GET_names()
#A = [zip(XXX.names_old_flat, XXX.names_new_flat) for XXX in self.EX_Page_Var]
print (zip(self.EX_Page_Var.names_old_flat, self.EX_Page_Var.names_new_flat))
except:
print ('No Data')
def _on_mousewheel(self, event):
'''Enables scrolling in Splash_Tab: Deprecated'''
self.Splash_Tab.canvas.yview_scroll(-1*int((event.delta/120)), "units")
def Show_CMD_closure(self,
ACTIVE_TYPE, N,
TABS_List, TAB_Buttons, ):
'Uses closure to create functions to display each Tab in TABS_List and colors active Button in TAB_Buttons'
#ERROR: consider creating/linking CMDs, windows, and buttons here
def Tab_Show_closed():
[TAB.grid() if (N==index) else TAB.grid_remove() for index, TAB in enumerate(TABS_List)]
[TAB.configure(bg=self.UI_Settings.ColorActive) if N==index else TAB.configure(bg=self.UI_Settings.ColorPassive) for index, TAB in enumerate(TAB_Buttons)]
if ACTIVE_TYPE == 'Tab':
self.ActiveTabN = N
elif ACTIVE_TYPE == 'Page':
self.ActivePageN = N
TAB_Buttons[N].configure(command=Tab_Show_closed)
return Tab_Show_closed
def RecentlyUpdated(self, EditState):
if EditState == self.RecentEdits:
pass
else:
self.RecentEdits = EditState
if EditState==True:
# active save button
self.Button_Save.configure(state=tk.NORMAL, bg=self.UI_Settings.ColorSave)
else:
# disabled save button
self.Button_Save.configure(state=tk.DISABLED, bg=self.UI_Settings.ColorDisabled)
pass
### Main operations
def Clean_TDX(self):
'''Uses SP_Cleaner() to prepare file. Has different operations, depending on filetype (Extension_lower)'''
print('Loading new SP data')
Extension_lower = self.File_Just_Extension.lower()
# Passes edited TEXT to parent class, to update all UI Tabs
if 'tdxex' in Extension_lower:
TEXT = SP_Cleaner(self.DISINTEGRATE.Text_Input, self.DISINTEGRATE.RemovableInteractions)
self.Update_TDX_File(TEXT)
print('Commit: Clean_TDX: filetype = EX')
elif 'tdxgs' in Extension_lower:
TEXT = SP_Cleaner(self.DISINTEGRATE.Text_Input, self.DISINTEGRATE.RemovableInteractions)
self.Update_TDX_File(TEXT)
print('Commit: Clean_TDX: filetype = GS')
elif 'tdxsp' in Extension_lower:
TEXT = SP_Cleaner(self.DISINTEGRATE.Text_Input, self.DISINTEGRATE.RemovableInteractions, SPtype=True)
self.Update_TDX_File(TEXT)
print('Commit: Clean_TDX: filetype = SP')
else:
print('filetype error')
self.ActiveTabCMD[self.Tab_lookups.index('tab_SP')]
def Generate_SP_from_GS(self):
'''Applies all SP_Cleaner() operations and saves a GS file as an SP'''
self.Clean_TDX()
Extension_lower = self.File_Just_Extension.lower()
TEXT = SP_Cleaner(self.DISINTEGRATE.Text_Input, self.DISINTEGRATE.RemovableInteractions, SPtype=True)
# Passes edited TEXT to parent class, to update all UI Tabs
self.Update_TDX_File(TEXT)
self.Save_Process(Text_to_Write=TEXT, fileType_override='tdxsp')
print('Commit: Generate_SP_from_GS')
def Rename_All(self):
'''Renames all items listed in rename pages (self.List_of_Pages)'''
self.List_of_Pages = [self.EX_Page_Var, self.EX_Page_Step, self.EX_Page_Other, self.EX_Page_Inter]
[XXX.GET_names() for XXX in self.List_of_Pages]
#### Uses VAF_Renamer() function to rename all Variables, Arrays, Formulas
###Data001 = VAF_Renamer(self.DISINTEGRATE.Text_Input, self.EX_Page_Var.names_old_flat, self.EX_Page_Var.names_new_flat)
# Uses OTHER_Renamer() function to rename all other items
Other_Names_Old = tuple(self.EX_Page_Step.names_old_flat) + tuple(self.EX_Page_Other.names_old_flat) + tuple(self.EX_Page_Inter.names_old_flat)
Other_Names_New = tuple(self.EX_Page_Step.names_new_flat) + tuple(self.EX_Page_Other.names_new_flat) + tuple(self.EX_Page_Inter.names_new_flat)
###Data002 = OTHER_Renamer(Data001, Other_Names_Old, Other_Names_New)
Renamed_Data = Complete_Renamer(self.DISINTEGRATE.Text_Input, self.EX_Page_Var.names_old_flat, self.EX_Page_Var.names_new_flat, Other_Names_Old, Other_Names_New)
# Updates file, if there are no duplicates
dupes = self.Duplicate_Check_TDX(Renamed_Data)
print('dupes', dupes)
if len(dupes)==0:
# Passes edited Data002 to parent class, to update all UI Tabs
self.Update_TDX_File(Renamed_Data)
self.ActiveTabCMD[self.Tab_lookups.index('tab_RENAME')]
print('Commit: Rename_All()')
else:
[XXX.Highlight_Dupes(dupes) for XXX in self.List_of_Pages]
class DisintegrateTDX():
'Disintegrates a TDX and extracts relevant information (step names, interactions...)'
#ERROR: add extract array data, DT_data, table_data, show (original/edited text)
def __init__(self, FILE):
self.Text_Input = FILE
print('LOADING: DisintegrateTDX')
self.Update_Data()
### Main functions
def Update_Data(self):
self.Extract_Names()
self.Extract_Steps()
self.Extract_Interactions()
self.GetAllUsedNames()
def Extract_Names(self):
# Lists of object names
self.Search_VAFxy = ["var", "array", "formula"]
self.Search_Inter = ["field", "multchoice", "fillin", "draganddrop",
"nlcursor", "xycursor", "sdgrapher",
"acctable", "realtimedata", "essay"]
self.Search_Other = ["figure", "image", "datatable",
"xygraph", "BarChart", "piechart", "NumberLine",
"Timeline", "collection"]
# Creates lists of [var, array, formula] , [inter-actions], [other] from the tdx FILE
self.Lists_Names_VAFxy = [self.Search_This(search) for search in self.Search_VAFxy]
self.Lists_Names_Inter = [self.Search_This(search) for search in self.Search_Inter]
self.Lists_Names_Other = [self.Search_This(search) for search in self.Search_Other]
self.List_Names_V, self.List_Names_A, self.List_Names_F = self.Lists_Names_VAFxy
self.List_Flat_TDXsort = [str(item).lower() for sublist in [self.Lists_Names_VAFxy + self.Lists_Names_Other + self.Lists_Names_Inter] for item in sublist]
self.List_Flat_TDXsort.sort()
self.List_Flat_TDXsort.sort(key=len, reverse=True)
def GetAllUsedNames(self):
self.UsedNames = re.findall('(?<=name=\")(\w+)', self.Text_Input, flags=re.IGNORECASE)
self.UsedNames = [name.lower() for name in self.UsedNames]
def Extract_Steps(self):
Windows = re.findall('(?<=<window name=\")\w+(?=\")', self.Text_Input)
Window_Locations = [self.Text_Input.find('<window name=\"{}\"'.format(Name)) for Name in Windows] + [self.Text_Input.find('</windows>')]
Steps_by_Window = [re.findall("(?<=<step name=\")\w+(?=\")" ,
self.Text_Input[a:b] ,
flags=re.IGNORECASE
) for (a,b) in zip(Window_Locations,Window_Locations[1:])]
Window_Step_Lists = [(a,b) for (a,b) in zip(Windows, Steps_by_Window)]
self.List_Feedbacks = Steps_by_Window[Windows.index('feedback')] if 'feedback' in Windows else ['']
self.List_Popups = Steps_by_Window[Windows.index('popups')] if 'popups' in Windows else ['']
self.List_Steps = re.findall(
"(?<=<display step=\")\w+(?=\")" ,
self.Text_Input[self.Text_Input.find("<controller>"):self.Text_Input.find("</controller>")] ,
flags=re.IGNORECASE)
self.List_All_Steps = self.List_Steps + self.List_Feedbacks + self.List_Popups
def Extract_Interactions(self):
'''Given text from a TDX file, finds (unused interactions) along with (used interactions and what step they appear)'''
self.List_Flat_Inter = [item for sublist in self.Lists_Names_Inter for item in sublist]
self.List_Flat_Inter = [X.lower() for X in self.List_Flat_Inter]
self.List_Inter_byType = [(TYPE,INTER) for TYPE,INTER in zip(self.Search_Inter,self.Lists_Names_Inter) if len(INTER)!=0]
self.Used_Inter = [b for b in self.Lists_Names_Inter if len(b)>0]
self.Used_Inter_by_type = [(a,b) for a,b in zip(self.Search_Inter, self.Lists_Names_Inter) if len(b)>0]
# A list of all step names (and MCs that could contain a FR) in the tdx file
AllSteps = re.findall('<step name=\"(\w+)".*?</step>', self.Text_Input, flags=re.DOTALL)
StepText = [re.findall('<step name=\"({}".*?)</step>'.format(STEP), self.Text_Input, flags=re.DOTALL)[0] for STEP in AllSteps]
AllMultC = self.Lists_Names_Inter[self.Search_Inter.index("multchoice")]
StepMult = [re.findall('<multchoice name=\"({}".*?)</multchoice>'.format(MULT), self.Text_Input, flags=re.DOTALL)[0] for MULT in AllMultC]
AllSteps += AllMultC
StepText += StepMult
# A list of interactions, for each step
Items_All_ByStep = [re.findall('>(\w+)(?:\.output)?(?:\.response)?</control>',ST, flags=re.DOTALL) for ST in StepText]
#print(Items_All_ByStep)
#print(self.List_Flat_Inter)
Interactions_by_Step = [[item for item in List if item.lower() in self.List_Flat_Inter] for List in Items_All_ByStep]
#print(Interactions_by_Step)
Interactions_by_Step_Flat = [item for List in Interactions_by_Step for item in List]
# A dictionary of {step : [interactions in the step]} trimmed to only those actually used in the tdx file
self.D_Step_to_Inter = {a: b for a,b in zip(AllSteps,Interactions_by_Step) if len(b)!=0}
# A dictionary of {interaction : [step(s) it appears in]}
self.D_Inter_to_Step = {a: [] for a in Interactions_by_Step_Flat}
for STEP in self.D_Step_to_Inter.keys():
for inter in self.D_Step_to_Inter[STEP]:
self.D_Inter_to_Step[inter] += [STEP]
# A list of interactions that do not appear in any step
self.RemovableInteractions = list(set(self.List_Flat_Inter)-set([XXX.lower() for XXX in Interactions_by_Step_Flat]))
### Helper functions
def Search_This(self,NAME):
#print('self.Text_Input XXX', self.Text_Input)
Found_Names = re.findall('(?<={} name=\")\w+(?=\")'.format(NAME), self.Text_Input, flags=re.IGNORECASE)
Found_Names.sort(key=str.lower)
return (Found_Names)
def duplicates(self, DUPES):
#*** Used to create list of duplicate named objects
ListNamesAll = [XXX.lower() for XXX in DUPES]
singles = set()
doubles = set()
for name in ListNamesAll:
if name in singles:
doubles.add(name)
else:
singles.add(name)
doubles = sorted(list(doubles))
return doubles
### Tab internals
class TableInput(tk.Frame):
'Defines and launches TableInput UI in Table-Tab (plus table creation methods)'
def __init__(self, parent, master, TEXT, SELF_SETTINGS, *args, **kw):
tk.Frame.__init__(self, parent)
parent.master.bind_class("Text","<Control-a>", self.selectall)
self.UI_Settings = SELF_SETTINGS
self.InputText = TEXT
self.master = master
self.DTnames = self.master.DISINTEGRATE.Lists_Names_Other[self.master.DISINTEGRATE.Search_Other.index("datatable")]
self.index = 1
self.Create_UI()
def Create_UI(self):
self.SeparatorDict = {'Tab':'\t', 'Space':' ', 'Comma':','}
self.OptionMenuValueSet = 'Tab'
### Main section
self.configure(bg=self.UI_Settings.ColorBack1)
Page_Left = tk.LabelFrame(self, bg=self.UI_Settings.ColorBack1, text='Data Input')
Page_Right = tk.LabelFrame(self, bg=self.UI_Settings.ColorBack1, text='Data Output')
Page_Lower = tk.LabelFrame(self, bg=self.UI_Settings.ColorBack1, text=u'\u2193\u2193\u2193 \tEnter Data\t \u2193\u2193\u2193')
Page_Left.grid( row=0, column=0, ipady=5, padx=5, sticky=tk.NSEW)
Page_Right.grid(row=0, column=1, ipady=5, padx=5, sticky=tk.NSEW)
Page_Lower.grid(row=1, column=0, ipady=5, padx=5, sticky=tk.NSEW, columnspan=2)
self.columnconfigure(0, weight=1)
self.columnconfigure(1, weight=4)
self.rowconfigure(1, weight=1)
### Page_Left
# Tab seperator
self.Separate = tk.StringVar(self.master)
self.Separate.set('Tab')
self.SeparateEnter = tk.OptionMenu(Page_Left, self.Separate, *(self.SeparatorDict.keys()), command=self.func)
self.SeparateEnter.configure(bg=self.UI_Settings.ColorInputFL)
self.SepLabel = tk.Label(Page_Left, text=u"Each newline is a Row-Separator.\n\u2193\u2193 Choose a Column-Separator \u2193\u2193", justify=tk.LEFT, bg=self.UI_Settings.ColorBack1)
# Transpose Box
self.BoxVarTranspose = tk.IntVar()
self.TransBoxToggle = tk.Checkbutton(Page_Left, highlightcolor='green', selectcolor="white", text='Transpose Data', variable=self.BoxVarTranspose, bg=self.UI_Settings.ColorBack1, anchor=tk.W)
self.Test_button = tk.Button(Page_Left, text="View Test Table", bg=self.UI_Settings.ColorTest , command=self.Sample_Popup)
# locations
self.SepLabel.grid( row=0, column=0, ipady=0, sticky=tk.W)
self.SeparateEnter.grid( row=1, column=0, ipady=3, sticky=tk.NSEW)
self.TransBoxToggle.grid(row=3, column=0, ipady=0, sticky=tk.NSEW, padx=5)
self.Test_button.grid( row=4, column=0, pady=3, sticky=tk.NSEW, padx=5)
Page_Left.columnconfigure(0, weight=1)
Page_Left.rowconfigure( 2, weight=1)
### Page_Right
# insert
self.orig_color = self.SeparateEnter.cget("background")
self.Insert_Table_button = tk.Button(Page_Right, text="Commit: Insert Table", bg=self.UI_Settings.ColorDisabled, state=tk.DISABLED, command=self.InsertTable, bd=5, relief="ridge")
self.Insert_Table_button.grid(row=0, column=3, pady=0, padx=2, sticky=tk.EW)
self.Insert_Array_button = tk.Button(Page_Right, text="Commit: Insert Array(s)", bg=self.UI_Settings.ColorCommit, command=self.InsertArray, bd=5, relief="ridge")
self.Insert_Array_button.grid(row=1, column=3, pady=0, padx=2, sticky=tk.EW)
self.Insert_DT_button = tk.Button(Page_Right, text="Commit: Insert Data Table", bg=self.UI_Settings.ColorCommit, command=self.InsertDT, bd=5, relief="ridge")
self.Insert_DT_button.grid(row=2, column=3, pady=0, padx=2, sticky=tk.EW)
# select step, dropdown
self.ListedVar = tk.StringVar(self)
self.ListedVar.set('Select a step')