@@ -15,8 +15,8 @@ class CreditsTool(tk.Toplevel):
15
15
def __init__ (self , master = None , * args , ** kwargs ):
16
16
"""Initializes Toplevel object and builds credit interface."""
17
17
super ().__init__ (master , * args , ** kwargs )
18
- # hide window in background during drawing and load, to prevent flickering and glitches as per
19
- # https://stackoverflow.com/questions/48492273/preloading-windows-to-avoid-tkinter-visual-glitches-during-frame-load
18
+ # hide window in background during drawing and load, to prevent flickering and glitches during frame load
19
+ #
20
20
self .withdraw ()
21
21
# build and draw the window
22
22
self .build ()
@@ -40,23 +40,82 @@ def build(self):
40
40
self .lbl_author .grid (row = 1 , column = 0 , sticky = 'w' , padx = 1 , pady = 1 )
41
41
self .lbl_author .bind ("<Button-1>" , lambda e : callback ("https://twitter.com/netevert" ))
42
42
43
+ class SaveTool (tk .Toplevel ):
44
+ """Opens a window to store investigation data"""
45
+ def __init__ (self , master = None , investigation_id = None , data = None , * args , ** kwargs ):
46
+ """Initializes Toplevel object and builds interface"""
47
+ super ().__init__ (master , * args , ** kwargs )
48
+ # initialize variables
49
+ self .investigation_id = investigation_id
50
+ self .data = data
51
+ # initialize database
52
+ self .db_handler = Database ()
53
+ # hide window in background during drawing and load, to prevent flickering and glitches during frame load
54
+ self .withdraw ()
55
+ # build and draw the window
56
+ self .build ()
57
+ # unhide the Toplevel window immediately after draw and load
58
+ self .after (0 , self .deiconify )
59
+
60
+ def build (self ):
61
+ """Initializes and builds application widgets"""
62
+ # create input labelframe
63
+ labelframe_1 = tk .LabelFrame (self , fg = 'brown' )
64
+ labelframe_1 .pack (side = "top" , expand = 'yes' , fill = 'both' , padx = 2 , pady = 2 , anchor = "n" )
65
+
66
+ # create explanation label
67
+ self .label = tk .Label (labelframe_1 , text = 'Save As...' )
68
+ self .label .pack (expand = True , fill = 'x' , side = "left" , padx = 2 , pady = 2 )
69
+
70
+ # create data input entry widget
71
+ self .entry = tk .Entry (labelframe_1 )
72
+ self .entry .pack (expand = True , fill = 'x' , side = "left" , padx = 2 , pady = 2 )
73
+
74
+ # create save button
75
+ self .save_button = tk .Button (labelframe_1 , text = "Save" , command = self .save_data )
76
+ self .save_button .pack (expand = False , side = "left" , padx = 2 , pady = 2 , anchor = "e" )
77
+
78
+ # create cancel button
79
+ self .cancel_button = tk .Button (labelframe_1 , text = "Cancel" , command = self .quit_save )
80
+ self .cancel_button .pack (expand = False , side = "left" , padx = 2 , pady = 2 , anchor = "e" )
81
+
82
+ self .entry .insert (0 , self .investigation_id )
83
+
84
+ def save_data (self ):
85
+ """Stores investigation data within database"""
86
+ if self .data :
87
+ try :
88
+ self .db_handler .store_investigation (self .investigation_id , self .data )
89
+ messagebox .showinfo ("Success" , "Successfully saved investigation" )
90
+ self .quit_save ()
91
+
92
+ except Exception :
93
+ messagebox .showerror ("Error saving data" , "Failed to save data!" )
94
+ self .quit_save ()
95
+ else :
96
+ messagebox .showinfo ("No data" , "There is no data to save" )
97
+
98
+ def quit_save (self ):
99
+ """Quits the save window"""
100
+ self .db_handler .close_connection ()
101
+ self .destroy ()
102
+
43
103
class ApiTool (tk .Toplevel ):
44
104
"""Opens a new window providing users ability to input api keys"""
45
105
46
106
def __init__ (self , master = None , * args , ** kwargs ):
47
- """Initializes Toplevel object and builds credit interface. """
107
+ """Initializes Toplevel object and builds interface"""
48
108
super ().__init__ (master , * args , ** kwargs )
49
109
self .db_handler = Database ()
50
- # hide window in background during drawing and load, to prevent flickering and glitches as per
51
- # https://stackoverflow.com/questions/48492273/preloading-windows-to-avoid-tkinter-visual-glitches-during-frame-load
110
+ # hide window in background during drawing and load, to prevent flickering and glitches during frame load
52
111
self .withdraw ()
53
112
# build and draw the window
54
113
self .build ()
55
114
# unhide the Toplevel window immediately after draw and load
56
115
self .after (0 , self .deiconify )
57
116
58
117
def build (self ):
59
- """Initializes and builds application widgets. """
118
+ """Initializes and builds application widgets"""
60
119
# create input labelframe
61
120
labelframe_1 = tk .LabelFrame (self , text = "api key manager" , fg = 'brown' )
62
121
labelframe_1 .pack (side = "top" , expand = 'yes' , fill = 'both' , padx = 2 , pady = 2 , anchor = "n" )
@@ -120,27 +179,36 @@ def __init__(self, master=None, *args, **kwargs):
120
179
self .build_interface ()
121
180
self .id_tracker = dict ()
122
181
self .transforms_tracker = set ()
182
+ self .investigation_id_tracker = ""
123
183
124
184
def build_menu (self ):
125
185
"""Initializes and builds program menu bar"""
126
186
self .top = tk .Menu (self )
127
187
128
- # create run menu
129
- self .run = tk .Menu (self .top , tearoff = False )
130
- self .run .add_checkbutton (label = "Multi-Select" , onvalue = True , offvalue = False , variable = self .multi_select , command = self .config_menu )
131
- self .run .add_command (label = 'Run Transform' , accelerator = 'Ctrl+R' ,
132
- command = self .run_data_mining , compound = tk .LEFT , underline = 0 )
133
- self .run .add_separator ()
134
- self .run .add_command (label = 'Exit' , command = self .quit_program ,
188
+ # create file menu
189
+ self .file = tk .Menu (self .top , tearoff = False )
190
+ self .file .add_command (label = "Open investigation..." , compound = tk .LEFT , underline = 0 , command = None )
191
+ self .file .add_command (label = "Save investigation..." , compound = tk .LEFT , underline = 0 , command = self .save_investigation )
192
+ self .file .add_separator ()
193
+ self .file .add_command (label = 'Exit' , command = self .quit_program ,
135
194
underline = 0 )
136
- self .top .add_cascade (label = 'Run' , menu = self .run , underline = 0 )
195
+
196
+ self .top .add_cascade (label = "File" , menu = self .file , underline = 0 )
137
197
138
198
# create edit menu
139
199
self .edit = tk .Menu (self .top , tearoff = False )
140
200
self .edit .add_command (label = 'API keys' , command = self .manage_apis ,
141
201
compound = tk .LEFT , underline = 0 )
142
202
self .top .add_cascade (label = 'Edit' , menu = self .edit , underline = 0 )
143
203
204
+ # create run menu
205
+ self .run = tk .Menu (self .top , tearoff = False )
206
+ self .run .add_checkbutton (label = "Multi-Select" , onvalue = True , offvalue = False , variable = self .multi_select , command = self .config_menu )
207
+ self .run .add_command (label = 'Run Transform' , accelerator = 'Ctrl+R' ,
208
+ command = self .run_data_mining , compound = tk .LEFT , underline = 0 )
209
+
210
+ self .top .add_cascade (label = 'Run' , menu = self .run , underline = 0 )
211
+
144
212
# create about menu
145
213
self .info = tk .Menu (self .top , tearoff = False )
146
214
self .info .add_command (label = 'About ...' , command = self .view_credits ,
@@ -167,12 +235,6 @@ def build_interface(self):
167
235
self .selector = ttk .Combobox (labelframe_1 , values = ["" ], state = "readonly" )
168
236
self .selector .pack (expand = True , fill = 'x' , side = "top" , padx = 2 , pady = 2 )
169
237
170
- #self.checkBox1 = tk.Checkbutton(labelframe_1, variable=None, onvalue=1, offvalue=0, text="Multi-select")
171
- #self.checkBox1.pack(expand=False, side="left", padx=2, pady=2, anchor="w")
172
-
173
- #self.entry2 = tk.Entry(labelframe_1)
174
- #self.entry2.pack(expand=True, fill='x', side="left", padx=2, pady=2, anchor="w")
175
-
176
238
# create results frame
177
239
frame_2 = tk .Frame ()
178
240
frame_2 .pack (expand = True , fill = 'both' , anchor = "n" )
@@ -261,10 +323,6 @@ def run_data_mining(self, event=None):
261
323
data = self .validator .execute_transform (i , transform )
262
324
for item in data :
263
325
self .treeview .insert (self .getID (i ), "end" , values = (transform , item ))
264
- # todo: focus on last treeview output to be able to hit enter and iterate
265
- # item = self.treeview.insert('', 'end', text=_input, values=(transform, data))
266
- # self.treeview.focus_set()
267
- # self.treeview.selection_set(item)
268
326
self .entry .focus ()
269
327
self .status ['text' ] = "ready"
270
328
self .transforms_tracker .clear ()
@@ -332,6 +390,37 @@ def manage_apis(self):
332
390
# start mainloop
333
391
self .api_tool .mainloop ()
334
392
393
+ def grab_investigation_data (self ):
394
+ """"Stores investigation data"""
395
+ data = {}
396
+ for Parent in self .treeview .get_children ():
397
+ data [self .treeview .item (Parent )["text" ]]= []
398
+ for child in self .treeview .get_children (Parent ):
399
+ if self .treeview .item (child )["values" ] not in data [self .treeview .item (Parent )["text" ]]:
400
+ data [self .treeview .item (Parent )["text" ]].append (self .treeview .item (child )["values" ])
401
+ return data
402
+
403
+ def save_investigation (self ):
404
+ """Saves investigation data"""
405
+ if not self .investigation_id_tracker :
406
+ self .investigation_id_tracker = datetime .datetime .now ().strftime ("%Y%m%d%H%M" )
407
+ data = self .grab_investigation_data ()
408
+
409
+ self .save = SaveTool (investigation_id = self .investigation_id_tracker , data = data )
410
+ self .save .title ('Save investigation' )
411
+ self .save .geometry ('+%d+%d' % (root .winfo_x () +
412
+ 20 , root .winfo_y () + 20 ))
413
+ if sys .platform == "win32" :
414
+ self .save .iconbitmap (self .icon )
415
+ self .save .resizable (width = False , height = False )
416
+ self .save .protocol ('WM_DELETE_WINDOW' , self .save .quit_save )
417
+ # set focus on window
418
+ self .save .grab_set ()
419
+ self .save .focus ()
420
+
421
+ # start mainloop
422
+ self .save .mainloop ()
423
+
335
424
@staticmethod
336
425
def quit_program ():
337
426
"""Quits main program window"""
0 commit comments