14710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#! /usr/bin/env python 24710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 34710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"""GUI interface to webchecker. 44710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 54710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmThis works as a Grail applet too! E.g. 64710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 74710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm <APPLET CODE=wcgui.py NAME=CheckerWindow></APPLET> 84710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 94710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmCheckpoints are not (yet??? ever???) supported. 104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmUser interface: 124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmEnter a root to check in the text entry box. To enter more than one root, 144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmenter them one at a time and press <Return> for each one. 154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmCommand buttons Start, Stop and "Check one" govern the checking process in 174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmthe obvious way. Start and "Check one" also enter the root from the text 184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmentry box if one is present. There's also a check box (enabled by default) 194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmto decide whether actually to follow external links (since this can slow 204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmthe checking down considerably). Finally there's a Quit button. 214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmA series of checkbuttons determines whether the corresponding output panel 234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmis shown. List panels are also automatically shown or hidden when their 244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatus changes between empty to non-empty. There are six panels: 254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmLog -- raw output from the checker (-v, -q affect this) 274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmTo check -- links discovered but not yet checked 284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmChecked -- links that have been checked 294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmBad links -- links that failed upon checking 304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmErrors -- pages containing at least one bad link 314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmDetails -- details about one URL; double click on a URL in any of 324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm the above list panels (not in Log) will show details 334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for that URL 344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmUse your window manager's Close command to quit. 364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmCommand line options: 384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm-m bytes -- skip HTML pages larger than this size (default %(MAXPAGE)d) 404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm-q -- quiet operation (also suppresses external links report) 414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm-v -- verbose operation; repeating -v will increase verbosity 424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm-t root -- specify root dir which should be treated as internal (can repeat) 434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm-a -- don't check name anchors 444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmCommand line arguments: 464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmrooturl -- URL to start checking 484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm (default %(DEFROOT)s) 494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmXXX The command line options (-m, -q, -v) should be GUI accessible. 514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmXXX The roots should be visible as a list (?). 534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmXXX The multipanel user interface is clumsy. 554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm""" 574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# ' Emacs bait 594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport sys 624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport getopt 634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmfrom Tkinter import * 644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport tktools 654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport webchecker 664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef main(): 684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm opts, args = getopt.getopt(sys.argv[1:], 't:m:qva') 704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except getopt.error, msg: 714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm sys.stdout = sys.stderr 724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print msg 734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print __doc__%vars(webchecker) 744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm sys.exit(2) 754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm webchecker.verbose = webchecker.VERBOSE 764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm webchecker.nonames = webchecker.NONAMES 774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm webchecker.maxpage = webchecker.MAXPAGE 784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm extra_roots = [] 794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for o, a in opts: 804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if o == '-m': 814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm webchecker.maxpage = int(a) 824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if o == '-q': 834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm webchecker.verbose = 0 844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if o == '-v': 854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm webchecker.verbose = webchecker.verbose + 1 864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if o == '-t': 874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm extra_roots.append(a) 884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if o == '-a': 894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm webchecker.nonames = not webchecker.nonames 904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm root = Tk(className='Webchecker') 914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm root.protocol("WM_DELETE_WINDOW", root.quit) 924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm c = CheckerWindow(root) 934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm c.setflags(verbose=webchecker.verbose, maxpage=webchecker.maxpage, 944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm nonames=webchecker.nonames) 954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if args: 964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for arg in args[:-1]: 974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm c.addroot(arg) 984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm c.suggestroot(args[-1]) 994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Usually conditioned on whether external links 1004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # will be checked, but since that's not a command 1014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # line option, just toss them in. 1024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for url_root in extra_roots: 1034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Make sure it's terminated by a slash, 1044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # so that addroot doesn't discard the last 1054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # directory component. 1064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if url_root[-1] != "/": 1074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm url_root = url_root + "/" 1084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm c.addroot(url_root, add_to_do = 0) 1094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm root.mainloop() 1104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass CheckerWindow(webchecker.Checker): 1134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __init__(self, parent, root=webchecker.DEFROOT): 1154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__parent = parent 1164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__topcontrols = Frame(parent) 1184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__topcontrols.pack(side=TOP, fill=X) 1194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__label = Label(self.__topcontrols, text="Root URL:") 1204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__label.pack(side=LEFT) 1214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__rootentry = Entry(self.__topcontrols, width=60) 1224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__rootentry.pack(side=LEFT) 1234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__rootentry.bind('<Return>', self.enterroot) 1244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__rootentry.focus_set() 1254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__controls = Frame(parent) 1274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__controls.pack(side=TOP, fill=X) 1284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__running = 0 1294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__start = Button(self.__controls, text="Run", command=self.start) 1304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__start.pack(side=LEFT) 1314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__stop = Button(self.__controls, text="Stop", command=self.stop, 1324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm state=DISABLED) 1334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__stop.pack(side=LEFT) 1344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__step = Button(self.__controls, text="Check one", 1354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm command=self.step) 1364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__step.pack(side=LEFT) 1374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__cv = BooleanVar(parent) 1384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__cv.set(self.checkext) 1394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__checkext = Checkbutton(self.__controls, variable=self.__cv, 1404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm command=self.update_checkext, 1414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm text="Check nonlocal links",) 1424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__checkext.pack(side=LEFT) 1434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__reset = Button(self.__controls, text="Start over", command=self.reset) 1444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__reset.pack(side=LEFT) 1454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if __name__ == '__main__': # No Quit button under Grail! 1464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__quit = Button(self.__controls, text="Quit", 1474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm command=self.__parent.quit) 1484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__quit.pack(side=RIGHT) 1494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__status = Label(parent, text="Status: initial", anchor=W) 1514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__status.pack(side=TOP, fill=X) 1524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__checking = Label(parent, text="Idle", anchor=W) 1534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__checking.pack(side=TOP, fill=X) 1544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__mp = mp = MultiPanel(parent) 1554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm sys.stdout = self.__log = LogPanel(mp, "Log") 1564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__todo = ListPanel(mp, "To check", self, self.showinfo) 1574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__done = ListPanel(mp, "Checked", self, self.showinfo) 1584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__bad = ListPanel(mp, "Bad links", self, self.showinfo) 1594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__errors = ListPanel(mp, "Pages w/ bad links", self, self.showinfo) 1604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__details = LogPanel(mp, "Details") 1614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.root_seed = None 1624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm webchecker.Checker.__init__(self) 1634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if root: 1644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm root = str(root).strip() 1654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if root: 1664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.suggestroot(root) 1674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.newstatus() 1684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def reset(self): 1704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm webchecker.Checker.reset(self) 1714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for p in self.__todo, self.__done, self.__bad, self.__errors: 1724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm p.clear() 1734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self.root_seed: 1744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.suggestroot(self.root_seed) 1754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def suggestroot(self, root): 1774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__rootentry.delete(0, END) 1784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__rootentry.insert(END, root) 1794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__rootentry.select_range(0, END) 1804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.root_seed = root 1814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def enterroot(self, event=None): 1834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm root = self.__rootentry.get() 1844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm root = root.strip() 1854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if root: 1864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__checking.config(text="Adding root "+root) 1874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__checking.update_idletasks() 1884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.addroot(root) 1894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__checking.config(text="Idle") 1904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 1914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm i = self.__todo.items.index(root) 1924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except (ValueError, IndexError): 1934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pass 1944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 1954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__todo.list.select_clear(0, END) 1964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__todo.list.select_set(i) 1974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__todo.list.yview(i) 1984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__rootentry.delete(0, END) 1994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def start(self): 2014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__start.config(state=DISABLED, relief=SUNKEN) 2024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__stop.config(state=NORMAL) 2034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__step.config(state=DISABLED) 2044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.enterroot() 2054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__running = 1 2064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.go() 2074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def stop(self): 2094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__stop.config(state=DISABLED, relief=SUNKEN) 2104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__running = 0 2114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def step(self): 2134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__start.config(state=DISABLED) 2144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__step.config(state=DISABLED, relief=SUNKEN) 2154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.enterroot() 2164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__running = 0 2174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.dosomething() 2184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def go(self): 2204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self.__running: 2214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__parent.after_idle(self.dosomething) 2224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 2234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__checking.config(text="Idle") 2244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__start.config(state=NORMAL, relief=RAISED) 2254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__stop.config(state=DISABLED, relief=RAISED) 2264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__step.config(state=NORMAL, relief=RAISED) 2274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm __busy = 0 2294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def dosomething(self): 2314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self.__busy: return 2324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__busy = 1 2334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self.todo: 2344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm l = self.__todo.selectedindices() 2354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if l: 2364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm i = l[0] 2374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 2384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm i = 0 2394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__todo.list.select_set(i) 2404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__todo.list.yview(i) 2414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm url = self.__todo.items[i] 2424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__checking.config(text="Checking "+self.format_url(url)) 2434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__parent.update() 2444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.dopage(url) 2454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 2464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.stop() 2474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__busy = 0 2484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.go() 2494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def showinfo(self, url): 2514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d = self.__details 2524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d.clear() 2534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d.put("URL: %s\n" % self.format_url(url)) 2544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self.bad.has_key(url): 2554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d.put("Error: %s\n" % str(self.bad[url])) 2564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if url in self.roots: 2574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d.put("Note: This is a root URL\n") 2584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self.done.has_key(url): 2594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d.put("Status: checked\n") 2604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm o = self.done[url] 2614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm elif self.todo.has_key(url): 2624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d.put("Status: to check\n") 2634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm o = self.todo[url] 2644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 2654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d.put("Status: unknown (!)\n") 2664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm o = [] 2674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if (not url[1]) and self.errors.has_key(url[0]): 2684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d.put("Bad links from this page:\n") 2694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for triple in self.errors[url[0]]: 2704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm link, rawlink, msg = triple 2714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d.put(" HREF %s" % self.format_url(link)) 2724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self.format_url(link) != rawlink: d.put(" (%s)" %rawlink) 2734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d.put("\n") 2744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d.put(" error %s\n" % str(msg)) 2754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__mp.showpanel("Details") 2764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for source, rawlink in o: 2774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d.put("Origin: %s" % source) 2784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if rawlink != self.format_url(url): 2794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d.put(" (%s)" % rawlink) 2804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d.put("\n") 2814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm d.text.yview("1.0") 2824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def setbad(self, url, msg): 2844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm webchecker.Checker.setbad(self, url, msg) 2854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__bad.insert(url) 2864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.newstatus() 2874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def setgood(self, url): 2894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm webchecker.Checker.setgood(self, url) 2904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__bad.remove(url) 2914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.newstatus() 2924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def newlink(self, url, origin): 2944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm webchecker.Checker.newlink(self, url, origin) 2954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self.done.has_key(url): 2964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__done.insert(url) 2974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm elif self.todo.has_key(url): 2984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__todo.insert(url) 2994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.newstatus() 3004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def markdone(self, url): 3024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm webchecker.Checker.markdone(self, url) 3034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__done.insert(url) 3044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__todo.remove(url) 3054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.newstatus() 3064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def seterror(self, url, triple): 3084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm webchecker.Checker.seterror(self, url, triple) 3094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__errors.insert((url, '')) 3104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.newstatus() 3114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def newstatus(self): 3134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__status.config(text="Status: "+self.status()) 3144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.__parent.update() 3154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def update_checkext(self): 3174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.checkext = self.__cv.get() 3184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass ListPanel: 3214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __init__(self, mp, name, checker, showinfo=None): 3234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.mp = mp 3244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.name = name 3254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.showinfo = showinfo 3264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.checker = checker 3274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.panel = mp.addpanel(name) 3284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.list, self.frame = tktools.make_list_box( 3294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.panel, width=60, height=5) 3304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.list.config(exportselection=0) 3314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if showinfo: 3324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.list.bind('<Double-Button-1>', self.doubleclick) 3334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.items = [] 3344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def clear(self): 3364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.items = [] 3374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.list.delete(0, END) 3384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.mp.hidepanel(self.name) 3394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def doubleclick(self, event): 3414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm l = self.selectedindices() 3424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if l: 3434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.showinfo(self.items[l[0]]) 3444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def selectedindices(self): 3464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm l = self.list.curselection() 3474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if not l: return [] 3484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return map(int, l) 3494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def insert(self, url): 3514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if url not in self.items: 3524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if not self.items: 3534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.mp.showpanel(self.name) 3544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # (I tried sorting alphabetically, but the display is too jumpy) 3554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm i = len(self.items) 3564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.list.insert(i, self.checker.format_url(url)) 3574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.list.yview(i) 3584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.items.insert(i, url) 3594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def remove(self, url): 3614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 3624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm i = self.items.index(url) 3634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except (ValueError, IndexError): 3644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pass 3654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 3664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm was_selected = i in self.selectedindices() 3674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.list.delete(i) 3684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm del self.items[i] 3694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if not self.items: 3704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.mp.hidepanel(self.name) 3714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm elif was_selected: 3724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if i >= len(self.items): 3734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm i = len(self.items) - 1 3744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.list.select_set(i) 3754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass LogPanel: 3784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __init__(self, mp, name): 3804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.mp = mp 3814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.name = name 3824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.panel = mp.addpanel(name) 3834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.text, self.frame = tktools.make_text_box(self.panel, height=10) 3844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.text.config(wrap=NONE) 3854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def clear(self): 3874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.text.delete("1.0", END) 3884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.text.yview("1.0") 3894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def put(self, s): 3914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.text.insert(END, s) 3924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if '\n' in s: 3934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.text.yview(END) 3944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def write(self, s): 3964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.text.insert(END, s) 3974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if '\n' in s: 3984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.text.yview(END) 3994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.panel.update() 4004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass MultiPanel: 4034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __init__(self, parent): 4054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.parent = parent 4064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.frame = Frame(self.parent) 4074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.frame.pack(expand=1, fill=BOTH) 4084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.topframe = Frame(self.frame, borderwidth=2, relief=RAISED) 4094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.topframe.pack(fill=X) 4104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.botframe = Frame(self.frame) 4114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.botframe.pack(expand=1, fill=BOTH) 4124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.panelnames = [] 4134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.panels = {} 4144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def addpanel(self, name, on=0): 4164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm v = StringVar(self.parent) 4174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if on: 4184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm v.set(name) 4194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 4204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm v.set("") 4214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm check = Checkbutton(self.topframe, text=name, 4224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm offvalue="", onvalue=name, variable=v, 4234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm command=self.checkpanel) 4244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm check.pack(side=LEFT) 4254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm panel = Frame(self.botframe) 4264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm label = Label(panel, text=name, borderwidth=2, relief=RAISED, anchor=W) 4274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm label.pack(side=TOP, fill=X) 4284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm t = v, check, panel 4294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.panelnames.append(name) 4304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.panels[name] = t 4314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if on: 4324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm panel.pack(expand=1, fill=BOTH) 4334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return panel 4344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def showpanel(self, name): 4364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm v, check, panel = self.panels[name] 4374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm v.set(name) 4384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm panel.pack(expand=1, fill=BOTH) 4394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def hidepanel(self, name): 4414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm v, check, panel = self.panels[name] 4424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm v.set("") 4434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm panel.pack_forget() 4444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def checkpanel(self): 4464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for name in self.panelnames: 4474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm v, check, panel = self.panels[name] 4484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm panel.pack_forget() 4494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for name in self.panelnames: 4504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm v, check, panel = self.panels[name] 4514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if v.get(): 4524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm panel.pack(expand=1, fill=BOTH) 4534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmif __name__ == '__main__': 4564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm main() 457