diff --git a/gui/Mainwindow.py b/gui/Mainwindow.py index ce1217a..fb3420d 100644 --- a/gui/Mainwindow.py +++ b/gui/Mainwindow.py @@ -67,34 +67,20 @@ class MainWindow(wx.Frame): ''' Create "interior" window components. In this case it is just a simple multiline text control. ''' - self.splitter = wx.SplitterWindow(self,-1) - self.splitter.daddy = self - # Top: input - self.top = wx.Notebook(self.splitter,-1) + self.top = wx.Notebook(self,-1) self.control = wx.TextCtrl(self.top, style=wx.TE_MULTILINE) if self.load: textfile = open(os.path.join(self.dirname, self.filename), 'r') self.control.SetValue(textfile.read()) os.chdir(self.dirname) textfile.close() - self.top.AddPage(self.control,"Protocol") + self.top.AddPage(self.control,"Protocol description") self.settings = SettingsWindow(self.top,self) - self.top.AddPage(self.settings,"Settings") - - # Bottom: output - self.bottom = wx.Notebook(self.splitter,-1) - self.report = SummaryWindow(self.bottom,self) - self.bottom.AddPage(self.report,"Claim summary") - self.errors = ErrorWindow(self.bottom,self) - self.bottom.AddPage(self.errors,"Detailed output") + self.top.AddPage(self.settings,"Verification parameters") #self.report.SetValue("Welcome.") - # Combine - self.splitter.SetMinimumPaneSize(20) - self.splitter.SplitHorizontally(self.top, self.bottom) - self.splitter.SetSashPosition(510) self.Show(1) @@ -328,91 +314,6 @@ class SettingsWindow(wx.Panel): #--------------------------------------------------------------------------- -class SummaryWindow(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin): - - def __init__(self,parent,daddy): - wx.ListCtrl.__init__(self,parent,-1, style=wx.LC_REPORT - | wx.BORDER_NONE - | wx.LC_SORT_ASCENDING - | wx.LC_SINGLE_SEL - ) - listmix.ListCtrlAutoWidthMixin.__init__(self) - - self.win = daddy - self.currentItem = -1 - - self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) - - self.InsertColumn(0, "Protocol") - self.InsertColumn(1, "Role") - self.InsertColumn(2, "Claim") - self.InsertColumn(3, "Label") - self.InsertColumn(4, "Parameters") - self.InsertColumn(5, "Status") - self.InsertColumn(6, "Attacks") - self.InsertColumn(7, "Comments") - - def update(self): - self.DeleteAllItems() - claims = self.win.claims - for key in range(0,len(claims)): - cl = claims[key] - index = self.InsertStringItem(sys.maxint,str(cl.protocol)) - - def addThing(i,x): - self.SetStringItem(index,i,str(x)) - - addThing(1,cl.role) - addThing(2,cl.claimtype) - addThing(3,cl.shortlabel) - addThing(4,cl.parameter) - if cl.okay: - addThing(5,"Ok") - else: - addThing(5,"Fail") - addThing(6,cl.failed) - addThing(7,"Comments") - - self.SetItemData(index,key) - key += 1 - - # if cl.okay == "Fail": - # # Failed :( - # item = self.GetItem(key) - # item.SetTextColour(wx.RED) - # self.SetItem(item) - # else: - # # Okay! But with bound? - # if cl.comments.find("bounds") == -1: - # # No bounds, great :) - # item = self.GetItem(key) - # item.SetTextColour(wx.GREEN) - # self.SetItem(item) - - #for i in range(0,7): - # self.SetColumnWidth(i,wx.LIST_AUTOSIZE) - - def OnItemSelected(self, event): - self.currentItem = event.m_itemIndex - cl = self.win.claims[self.currentItem] - if len(cl.attacks) > 0: - display = Attackwindow.AttackWindow(cl) - display.Show(1) - self.Refresh() - event.Skip() - -#--------------------------------------------------------------------------- - -class ErrorWindow(wx.TextCtrl): - - def __init__(self,parent,daddy): - wx.TextCtrl.__init__(self,parent,-1, style=wx.TE_MULTILINE) - self.win = daddy - - def update(self,summary): - self.SetValue(summary) - -#--------------------------------------------------------------------------- diff --git a/gui/Scytherthread.py b/gui/Scytherthread.py index 9e63072..a0dae8a 100644 --- a/gui/Scytherthread.py +++ b/gui/Scytherthread.py @@ -33,9 +33,10 @@ busy = threading.Semaphore() class ScytherThread(threading.Thread): # Override Thread's __init__ method to accept the parameters needed: - def __init__ ( self, win, spdl, details ): + def __init__ ( self, mainwin, spdl, details, verifywin ): - self.win = win + self.mainwin = mainwin + self.verifywin = verifywin self.spdl = spdl self.details = details @@ -45,50 +46,59 @@ class ScytherThread(threading.Thread): def run(self): - global busy - evt = UpdateAttackEvent(status="Running Scyther...") - wx.PostEvent(self.win, evt) + wx.PostEvent(self.mainwin, evt) self.claimResults() # Results are done (claimstatus can be reported) evt = UpdateAttackEvent(status="Done.") - wx.PostEvent(self.win, evt) + wx.PostEvent(self.mainwin, evt) - # And create the images in the background - self.makeImages() - - # Cursor back to normal - self.win.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) - - busy.release() + # Shoot down the verification window and let the RunScyther function handle the rest + self.mainwin.verified = True + self.verifywin.Destroy() def claimResults(self): """ Convert spdl to result (using Scyther) - The list of claim goes back to self.win.claims, which is a + The list of claim goes back to self.mainwin.claims, which is a property of the main window """ scyther = Scyther.Scyther() - scyther.options = self.win.settings.ScytherArguments() + scyther.options = self.mainwin.settings.ScytherArguments() if sys.platform.startswith('win'): scyther.program = "c:\\Scyther.exe" if not os.path.isfile(scyther.program): print "I can't find the Scyther executable %s" % (scyther.program) scyther.setInput(self.spdl) - self.win.claims = scyther.verify() + self.mainwin.claims = scyther.verify() self.summary = str(scyther) - self.win.errors.update(self.summary) - self.win.report.update() + +class AttackThread(threading.Thread): + # Override Thread's __init__ method to accept the parameters needed: + def __init__ ( self, mainwin, resultwin ): + + self.mainwin = mainwin + self.resultwin = resultwin + + threading.Thread.__init__ ( self ) + + def run(self): + + evt = UpdateAttackEvent(status="Generating attack graphs...") + wx.PostEvent(self.mainwin, evt) + + # create the images in the background + self.makeImages() def makeImages(self): """ create images """ - for cl in self.win.claims: + for cl in self.mainwin.claims: for attack in cl.attacks: self.makeImage(attack) @@ -101,19 +111,214 @@ class ScytherThread(threading.Thread): pw.close() attack.pngfile = fpname2 # this is where the file name is stored +class VerificationWindow(wx.Dialog): + def __init__( + self, parent, ID, title, size=wx.DefaultSize, pos=wx.DefaultPosition, + style=wx.DEFAULT_DIALOG_STYLE + ): -def RunScyther(win,mode): + # Instead of calling wx.Dialog.__init__ we precreate the dialog + # so we can set an extra style that must be set before + # creation, and then we create the GUI dialog using the Create + # method. + pre = wx.PreDialog() + pre.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP) + pre.Create(parent, ID, title, pos, size, style) + + # This next step is the most important, it turns this Python + # object into the real wrapper of the dialog (instead of pre) + # as far as the wxPython extension is concerned. + self.PostCreate(pre) + + # Now continue with the normal construction of the dialog + # contents + sizer = wx.BoxSizer(wx.VERTICAL) + + label = wx.StaticText(self, -1, "This is a wx.Dialog") + label.SetHelpText("This is the help text for the label") + sizer.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + box = wx.BoxSizer(wx.HORIZONTAL) + + label = wx.StaticText(self, -1, "Field #1:") + label.SetHelpText("This is the help text for the label") + box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + text = wx.TextCtrl(self, -1, "", size=(80,-1)) + text.SetHelpText("Here's some help text for field #1") + box.Add(text, 1, wx.ALIGN_CENTRE|wx.ALL, 5) + + sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + + box = wx.BoxSizer(wx.HORIZONTAL) + + label = wx.StaticText(self, -1, "Field #2:") + label.SetHelpText("This is the help text for the label") + box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + text = wx.TextCtrl(self, -1, "", size=(80,-1)) + text.SetHelpText("Here's some help text for field #2") + box.Add(text, 1, wx.ALIGN_CENTRE|wx.ALL, 5) + + sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + + line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL) + sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, 5) + + btnsizer = wx.StdDialogButtonSizer() + + if wx.Platform != "__WXMSW__": + btn = wx.ContextHelpButton(self) + btnsizer.AddButton(btn) + + btn = wx.Button(self, wx.ID_OK) + btn.SetHelpText("The OK button completes the dialog") + btn.SetDefault() + btnsizer.AddButton(btn) + + btn = wx.Button(self, wx.ID_CANCEL) + btn.SetHelpText("The Cancel button cnacels the dialog. (Cool, huh?)") + btnsizer.AddButton(btn) + btnsizer.Realize() + + sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + + self.SetSizer(sizer) + sizer.Fit(self) + +#--------------------------------------------------------------------------- + +class ResultWindow(wx.Dialog): + def __init__( + self, parent, ID, title, size=wx.DefaultSize, pos=wx.DefaultPosition, + style=wx.DEFAULT_DIALOG_STYLE + ): + + # Instead of calling wx.Dialog.__init__ we precreate the dialog + # so we can set an extra style that must be set before + # creation, and then we create the GUI dialog using the Create + # method. + pre = wx.PreDialog() + pre.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP) + pre.Create(parent, ID, title, pos, size, style) + + # This next step is the most important, it turns this Python + # object into the real wrapper of the dialog (instead of pre) + # as far as the wxPython extension is concerned. + self.PostCreate(pre) + + # Now continue with the normal construction of the dialog + # contents + sizer = wx.BoxSizer(wx.VERTICAL) + + label = wx.StaticText(self, -1, "This is a wx.Dialog") + label.SetHelpText("This is the help text for the label") + sizer.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + box = wx.BoxSizer(wx.HORIZONTAL) + + label = wx.StaticText(self, -1, "Field #1:") + label.SetHelpText("This is the help text for the label") + box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + text = wx.TextCtrl(self, -1, "", size=(80,-1)) + text.SetHelpText("Here's some help text for field #1") + box.Add(text, 1, wx.ALIGN_CENTRE|wx.ALL, 5) + + sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + + box = wx.BoxSizer(wx.HORIZONTAL) + + label = wx.StaticText(self, -1, "Field #2:") + label.SetHelpText("This is the help text for the label") + box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + text = wx.TextCtrl(self, -1, "", size=(80,-1)) + text.SetHelpText("Here's some help text for field #2") + box.Add(text, 1, wx.ALIGN_CENTRE|wx.ALL, 5) + + sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + + line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL) + sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, 5) + + btnsizer = wx.StdDialogButtonSizer() + + if wx.Platform != "__WXMSW__": + btn = wx.ContextHelpButton(self) + btnsizer.AddButton(btn) + + btn = wx.Button(self, wx.ID_OK) + btn.SetHelpText("The OK button completes the dialog") + btn.SetDefault() + btnsizer.AddButton(btn) + + btn = wx.Button(self, wx.ID_CANCEL) + btn.SetHelpText("The Cancel button cnacels the dialog. (Cool, huh?)") + btnsizer.AddButton(btn) + btnsizer.Realize() + + sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + + self.SetSizer(sizer) + sizer.Fit(self) + +#--------------------------------------------------------------------------- + + +def RunScyther(mainwin,mode): global busy if (busy.acquire(False)): + # Verification window + + verifywin = VerificationWindow(mainwin,-1,mode) + verifywin.CenterOnScreen() + # start the thread - win.SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) + + mainwin.SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) - win.settings.mode = mode - t = ScytherThread(win,win.control.GetValue(),"") + mainwin.verified = False + mainwin.settings.mode = mode + t = ScytherThread(mainwin,mainwin.control.GetValue(),"",verifywin) t.start() - win.threads = [ t ] + + # start the window and show until something happens + # if it terminates, this is a cancel, and should also kill the thread. (what happens to a spawned Scyther in that case?) + # if the thread terminames, it should close the window normally, and we end up here as well. + + val = verifywin.ShowModal() + verifywin.Destroy() + # kill thread anyway + del(t) + + # Cursor back to normal + mainwin.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) + + if mainwin.verified: + # Great, we verified stuff, progress to the claim report + print "We verified stuff, hooray" + resultwin = ResultWindow(mainwin,-1,mode) + + t = AttackThread(mainwin,resultwin) + t.start() + + resultwin.CenterOnScreen() + val = resultwin.ShowModal() + resultwin.Destroy() + + # kill thread anyway + del(t) + + else: + # Verification was cancelled + print "We wuz cancelled!" + + busy.release() + +