Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 1 | #! /usr/bin/env python |
| 2 | |
| 3 | """GUI interface to webchecker. |
| 4 | |
| 5 | This works as a Grail applet too! E.g. |
| 6 | |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 7 | <APPLET CODE=wcgui.py NAME=CheckerWindow></APPLET> |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 8 | |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 9 | Checkpoints are not (yet??? ever???) supported. |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 10 | |
| 11 | User interface: |
| 12 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 13 | Enter a root to check in the text entry box. To enter more than one root, |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 14 | enter them one at a time and press <Return> for each one. |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 15 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 16 | Command buttons Start, Stop and "Check one" govern the checking process in |
| 17 | the obvious way. Start and "Check one" also enter the root from the text |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 18 | entry box if one is present. There's also a check box (enabled by default) |
| 19 | to decide whether actually to follow external links (since this can slow |
| 20 | the checking down considerably). Finally there's a Quit button. |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 21 | |
Tim Peters | 182b5ac | 2004-07-18 06:16:08 +0000 | [diff] [blame] | 22 | A series of checkbuttons determines whether the corresponding output panel |
| 23 | is shown. List panels are also automatically shown or hidden when their |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 24 | status changes between empty to non-empty. There are six panels: |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 25 | |
| 26 | Log -- raw output from the checker (-v, -q affect this) |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 27 | To check -- links discovered but not yet checked |
| 28 | Checked -- links that have been checked |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 29 | Bad links -- links that failed upon checking |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 30 | Errors -- pages containing at least one bad link |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 31 | Details -- details about one URL; double click on a URL in any of |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 32 | the above list panels (not in Log) will show details |
| 33 | for that URL |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 34 | |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 35 | Use your window manager's Close command to quit. |
| 36 | |
| 37 | Command line options: |
| 38 | |
| 39 | -m bytes -- skip HTML pages larger than this size (default %(MAXPAGE)d) |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 40 | -q -- quiet operation (also suppresses external links report) |
| 41 | -v -- verbose operation; repeating -v will increase verbosity |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 42 | -t root -- specify root dir which should be treated as internal (can repeat) |
| 43 | -a -- don't check name anchors |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 44 | |
| 45 | Command line arguments: |
| 46 | |
| 47 | rooturl -- URL to start checking |
| 48 | (default %(DEFROOT)s) |
| 49 | |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 50 | XXX The command line options (-m, -q, -v) should be GUI accessible. |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 51 | |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 52 | XXX The roots should be visible as a list (?). |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 53 | |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 54 | XXX The multipanel user interface is clumsy. |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 55 | |
| 56 | """ |
| 57 | |
| 58 | # ' Emacs bait |
| 59 | |
| 60 | |
| 61 | import sys |
| 62 | import getopt |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 63 | from Tkinter import * |
| 64 | import tktools |
Guido van Rossum | 497a198 | 1999-11-17 15:40:48 +0000 | [diff] [blame] | 65 | import webchecker |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 66 | import random |
| 67 | |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 68 | # Override some for a weaker platform |
| 69 | if sys.platform == 'mac': |
| 70 | webchecker.DEFROOT = "http://grail.cnri.reston.va.us/" |
| 71 | webchecker.MAXPAGE = 50000 |
| 72 | webchecker.verbose = 4 |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 73 | |
| 74 | def main(): |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 75 | try: |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 76 | opts, args = getopt.getopt(sys.argv[1:], 't:m:qva') |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 77 | except getopt.error, msg: |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 78 | sys.stdout = sys.stderr |
| 79 | print msg |
| 80 | print __doc__%vars(webchecker) |
| 81 | sys.exit(2) |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 82 | webchecker.verbose = webchecker.VERBOSE |
| 83 | webchecker.nonames = webchecker.NONAMES |
| 84 | webchecker.maxpage = webchecker.MAXPAGE |
| 85 | extra_roots = [] |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 86 | for o, a in opts: |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 87 | if o == '-m': |
Walter Dörwald | aaab30e | 2002-09-11 20:36:02 +0000 | [diff] [blame] | 88 | webchecker.maxpage = int(a) |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 89 | if o == '-q': |
| 90 | webchecker.verbose = 0 |
| 91 | if o == '-v': |
| 92 | webchecker.verbose = webchecker.verbose + 1 |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 93 | if o == '-t': |
| 94 | extra_roots.append(a) |
| 95 | if o == '-a': |
| 96 | webchecker.nonames = not webchecker.nonames |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 97 | root = Tk(className='Webchecker') |
| 98 | root.protocol("WM_DELETE_WINDOW", root.quit) |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 99 | c = CheckerWindow(root) |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 100 | c.setflags(verbose=webchecker.verbose, maxpage=webchecker.maxpage, |
| 101 | nonames=webchecker.nonames) |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 102 | if args: |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 103 | for arg in args[:-1]: |
| 104 | c.addroot(arg) |
| 105 | c.suggestroot(args[-1]) |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 106 | # Usually conditioned on whether external links |
| 107 | # will be checked, but since that's not a command |
| 108 | # line option, just toss them in. |
| 109 | for url_root in extra_roots: |
| 110 | # Make sure it's terminated by a slash, |
| 111 | # so that addroot doesn't discard the last |
| 112 | # directory component. |
| 113 | if url_root[-1] != "/": |
| 114 | url_root = url_root + "/" |
| 115 | c.addroot(url_root, add_to_do = 0) |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 116 | root.mainloop() |
| 117 | |
| 118 | |
| 119 | class CheckerWindow(webchecker.Checker): |
| 120 | |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 121 | def __init__(self, parent, root=webchecker.DEFROOT): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 122 | self.__parent = parent |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 123 | |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 124 | self.__topcontrols = Frame(parent) |
| 125 | self.__topcontrols.pack(side=TOP, fill=X) |
| 126 | self.__label = Label(self.__topcontrols, text="Root URL:") |
| 127 | self.__label.pack(side=LEFT) |
| 128 | self.__rootentry = Entry(self.__topcontrols, width=60) |
| 129 | self.__rootentry.pack(side=LEFT) |
| 130 | self.__rootentry.bind('<Return>', self.enterroot) |
| 131 | self.__rootentry.focus_set() |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 132 | |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 133 | self.__controls = Frame(parent) |
| 134 | self.__controls.pack(side=TOP, fill=X) |
| 135 | self.__running = 0 |
| 136 | self.__start = Button(self.__controls, text="Run", command=self.start) |
| 137 | self.__start.pack(side=LEFT) |
| 138 | self.__stop = Button(self.__controls, text="Stop", command=self.stop, |
| 139 | state=DISABLED) |
| 140 | self.__stop.pack(side=LEFT) |
| 141 | self.__step = Button(self.__controls, text="Check one", |
| 142 | command=self.step) |
| 143 | self.__step.pack(side=LEFT) |
| 144 | self.__cv = BooleanVar(parent) |
| 145 | self.__cv.set(self.checkext) |
| 146 | self.__checkext = Checkbutton(self.__controls, variable=self.__cv, |
| 147 | command=self.update_checkext, |
| 148 | text="Check nonlocal links",) |
| 149 | self.__checkext.pack(side=LEFT) |
| 150 | self.__reset = Button(self.__controls, text="Start over", command=self.reset) |
| 151 | self.__reset.pack(side=LEFT) |
| 152 | if __name__ == '__main__': # No Quit button under Grail! |
| 153 | self.__quit = Button(self.__controls, text="Quit", |
| 154 | command=self.__parent.quit) |
| 155 | self.__quit.pack(side=RIGHT) |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 156 | |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 157 | self.__status = Label(parent, text="Status: initial", anchor=W) |
| 158 | self.__status.pack(side=TOP, fill=X) |
| 159 | self.__checking = Label(parent, text="Idle", anchor=W) |
| 160 | self.__checking.pack(side=TOP, fill=X) |
| 161 | self.__mp = mp = MultiPanel(parent) |
| 162 | sys.stdout = self.__log = LogPanel(mp, "Log") |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 163 | self.__todo = ListPanel(mp, "To check", self, self.showinfo) |
| 164 | self.__done = ListPanel(mp, "Checked", self, self.showinfo) |
| 165 | self.__bad = ListPanel(mp, "Bad links", self, self.showinfo) |
| 166 | self.__errors = ListPanel(mp, "Pages w/ bad links", self, self.showinfo) |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 167 | self.__details = LogPanel(mp, "Details") |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 168 | self.root_seed = None |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 169 | webchecker.Checker.__init__(self) |
| 170 | if root: |
Walter Dörwald | aaab30e | 2002-09-11 20:36:02 +0000 | [diff] [blame] | 171 | root = str(root).strip() |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 172 | if root: |
| 173 | self.suggestroot(root) |
| 174 | self.newstatus() |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 175 | |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 176 | def reset(self): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 177 | webchecker.Checker.reset(self) |
| 178 | for p in self.__todo, self.__done, self.__bad, self.__errors: |
| 179 | p.clear() |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 180 | if self.root_seed: |
| 181 | self.suggestroot(self.root_seed) |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 182 | |
| 183 | def suggestroot(self, root): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 184 | self.__rootentry.delete(0, END) |
| 185 | self.__rootentry.insert(END, root) |
| 186 | self.__rootentry.select_range(0, END) |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 187 | self.root_seed = root |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 188 | |
| 189 | def enterroot(self, event=None): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 190 | root = self.__rootentry.get() |
Walter Dörwald | aaab30e | 2002-09-11 20:36:02 +0000 | [diff] [blame] | 191 | root = root.strip() |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 192 | if root: |
| 193 | self.__checking.config(text="Adding root "+root) |
| 194 | self.__checking.update_idletasks() |
| 195 | self.addroot(root) |
| 196 | self.__checking.config(text="Idle") |
| 197 | try: |
| 198 | i = self.__todo.items.index(root) |
| 199 | except (ValueError, IndexError): |
| 200 | pass |
| 201 | else: |
| 202 | self.__todo.list.select_clear(0, END) |
| 203 | self.__todo.list.select_set(i) |
| 204 | self.__todo.list.yview(i) |
| 205 | self.__rootentry.delete(0, END) |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 206 | |
| 207 | def start(self): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 208 | self.__start.config(state=DISABLED, relief=SUNKEN) |
| 209 | self.__stop.config(state=NORMAL) |
| 210 | self.__step.config(state=DISABLED) |
| 211 | self.enterroot() |
| 212 | self.__running = 1 |
| 213 | self.go() |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 214 | |
| 215 | def stop(self): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 216 | self.__stop.config(state=DISABLED, relief=SUNKEN) |
| 217 | self.__running = 0 |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 218 | |
| 219 | def step(self): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 220 | self.__start.config(state=DISABLED) |
| 221 | self.__step.config(state=DISABLED, relief=SUNKEN) |
| 222 | self.enterroot() |
| 223 | self.__running = 0 |
| 224 | self.dosomething() |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 225 | |
| 226 | def go(self): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 227 | if self.__running: |
| 228 | self.__parent.after_idle(self.dosomething) |
| 229 | else: |
| 230 | self.__checking.config(text="Idle") |
| 231 | self.__start.config(state=NORMAL, relief=RAISED) |
| 232 | self.__stop.config(state=DISABLED, relief=RAISED) |
| 233 | self.__step.config(state=NORMAL, relief=RAISED) |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 234 | |
| 235 | __busy = 0 |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 236 | |
| 237 | def dosomething(self): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 238 | if self.__busy: return |
| 239 | self.__busy = 1 |
| 240 | if self.todo: |
| 241 | l = self.__todo.selectedindices() |
| 242 | if l: |
| 243 | i = l[0] |
| 244 | else: |
| 245 | i = 0 |
| 246 | self.__todo.list.select_set(i) |
| 247 | self.__todo.list.yview(i) |
| 248 | url = self.__todo.items[i] |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 249 | self.__checking.config(text="Checking "+self.format_url(url)) |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 250 | self.__parent.update() |
| 251 | self.dopage(url) |
| 252 | else: |
| 253 | self.stop() |
| 254 | self.__busy = 0 |
| 255 | self.go() |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 256 | |
| 257 | def showinfo(self, url): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 258 | d = self.__details |
| 259 | d.clear() |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 260 | d.put("URL: %s\n" % self.format_url(url)) |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 261 | if self.bad.has_key(url): |
| 262 | d.put("Error: %s\n" % str(self.bad[url])) |
| 263 | if url in self.roots: |
| 264 | d.put("Note: This is a root URL\n") |
| 265 | if self.done.has_key(url): |
| 266 | d.put("Status: checked\n") |
| 267 | o = self.done[url] |
| 268 | elif self.todo.has_key(url): |
| 269 | d.put("Status: to check\n") |
| 270 | o = self.todo[url] |
| 271 | else: |
| 272 | d.put("Status: unknown (!)\n") |
| 273 | o = [] |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 274 | if (not url[1]) and self.errors.has_key(url[0]): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 275 | d.put("Bad links from this page:\n") |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 276 | for triple in self.errors[url[0]]: |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 277 | link, rawlink, msg = triple |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 278 | d.put(" HREF %s" % self.format_url(link)) |
| 279 | if self.format_url(link) != rawlink: d.put(" (%s)" %rawlink) |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 280 | d.put("\n") |
| 281 | d.put(" error %s\n" % str(msg)) |
| 282 | self.__mp.showpanel("Details") |
| 283 | for source, rawlink in o: |
| 284 | d.put("Origin: %s" % source) |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 285 | if rawlink != self.format_url(url): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 286 | d.put(" (%s)" % rawlink) |
| 287 | d.put("\n") |
| 288 | d.text.yview("1.0") |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 289 | |
| 290 | def setbad(self, url, msg): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 291 | webchecker.Checker.setbad(self, url, msg) |
| 292 | self.__bad.insert(url) |
| 293 | self.newstatus() |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 294 | |
| 295 | def setgood(self, url): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 296 | webchecker.Checker.setgood(self, url) |
| 297 | self.__bad.remove(url) |
| 298 | self.newstatus() |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 299 | |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 300 | def newlink(self, url, origin): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 301 | webchecker.Checker.newlink(self, url, origin) |
| 302 | if self.done.has_key(url): |
| 303 | self.__done.insert(url) |
| 304 | elif self.todo.has_key(url): |
| 305 | self.__todo.insert(url) |
| 306 | self.newstatus() |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 307 | |
| 308 | def markdone(self, url): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 309 | webchecker.Checker.markdone(self, url) |
| 310 | self.__done.insert(url) |
| 311 | self.__todo.remove(url) |
| 312 | self.newstatus() |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 313 | |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 314 | def seterror(self, url, triple): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 315 | webchecker.Checker.seterror(self, url, triple) |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 316 | self.__errors.insert((url, '')) |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 317 | self.newstatus() |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 318 | |
| 319 | def newstatus(self): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 320 | self.__status.config(text="Status: "+self.status()) |
| 321 | self.__parent.update() |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 322 | |
Guido van Rossum | 88b02cf | 1998-03-05 20:12:18 +0000 | [diff] [blame] | 323 | def update_checkext(self): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 324 | self.checkext = self.__cv.get() |
Guido van Rossum | 88b02cf | 1998-03-05 20:12:18 +0000 | [diff] [blame] | 325 | |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 326 | |
| 327 | class ListPanel: |
| 328 | |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 329 | def __init__(self, mp, name, checker, showinfo=None): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 330 | self.mp = mp |
| 331 | self.name = name |
| 332 | self.showinfo = showinfo |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 333 | self.checker = checker |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 334 | self.panel = mp.addpanel(name) |
| 335 | self.list, self.frame = tktools.make_list_box( |
| 336 | self.panel, width=60, height=5) |
| 337 | self.list.config(exportselection=0) |
| 338 | if showinfo: |
| 339 | self.list.bind('<Double-Button-1>', self.doubleclick) |
| 340 | self.items = [] |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 341 | |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 342 | def clear(self): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 343 | self.items = [] |
| 344 | self.list.delete(0, END) |
| 345 | self.mp.hidepanel(self.name) |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 346 | |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 347 | def doubleclick(self, event): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 348 | l = self.selectedindices() |
| 349 | if l: |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 350 | self.showinfo(self.items[l[0]]) |
Guido van Rossum | 4f6ecda | 1997-02-01 05:17:29 +0000 | [diff] [blame] | 351 | |
| 352 | def selectedindices(self): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 353 | l = self.list.curselection() |
| 354 | if not l: return [] |
Walter Dörwald | aaab30e | 2002-09-11 20:36:02 +0000 | [diff] [blame] | 355 | return map(int, l) |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 356 | |
| 357 | def insert(self, url): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 358 | if url not in self.items: |
| 359 | if not self.items: |
| 360 | self.mp.showpanel(self.name) |
| 361 | # (I tried sorting alphabetically, but the display is too jumpy) |
| 362 | i = len(self.items) |
Guido van Rossum | a894640 | 1999-11-17 15:03:52 +0000 | [diff] [blame] | 363 | self.list.insert(i, self.checker.format_url(url)) |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 364 | self.list.yview(i) |
| 365 | self.items.insert(i, url) |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 366 | |
| 367 | def remove(self, url): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 368 | try: |
| 369 | i = self.items.index(url) |
| 370 | except (ValueError, IndexError): |
| 371 | pass |
| 372 | else: |
| 373 | was_selected = i in self.selectedindices() |
| 374 | self.list.delete(i) |
| 375 | del self.items[i] |
| 376 | if not self.items: |
| 377 | self.mp.hidepanel(self.name) |
| 378 | elif was_selected: |
| 379 | if i >= len(self.items): |
| 380 | i = len(self.items) - 1 |
| 381 | self.list.select_set(i) |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 382 | |
| 383 | |
| 384 | class LogPanel: |
| 385 | |
| 386 | def __init__(self, mp, name): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 387 | self.mp = mp |
| 388 | self.name = name |
| 389 | self.panel = mp.addpanel(name) |
| 390 | self.text, self.frame = tktools.make_text_box(self.panel, height=10) |
| 391 | self.text.config(wrap=NONE) |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 392 | |
| 393 | def clear(self): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 394 | self.text.delete("1.0", END) |
| 395 | self.text.yview("1.0") |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 396 | |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 397 | def put(self, s): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 398 | self.text.insert(END, s) |
| 399 | if '\n' in s: |
| 400 | self.text.yview(END) |
Guido van Rossum | af310c1 | 1997-02-02 23:30:32 +0000 | [diff] [blame] | 401 | |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 402 | def write(self, s): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 403 | self.text.insert(END, s) |
| 404 | if '\n' in s: |
| 405 | self.text.yview(END) |
| 406 | self.panel.update() |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 407 | |
| 408 | |
| 409 | class MultiPanel: |
| 410 | |
| 411 | def __init__(self, parent): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 412 | self.parent = parent |
| 413 | self.frame = Frame(self.parent) |
| 414 | self.frame.pack(expand=1, fill=BOTH) |
| 415 | self.topframe = Frame(self.frame, borderwidth=2, relief=RAISED) |
| 416 | self.topframe.pack(fill=X) |
| 417 | self.botframe = Frame(self.frame) |
| 418 | self.botframe.pack(expand=1, fill=BOTH) |
| 419 | self.panelnames = [] |
| 420 | self.panels = {} |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 421 | |
| 422 | def addpanel(self, name, on=0): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 423 | v = StringVar(self.parent) |
| 424 | if on: |
| 425 | v.set(name) |
| 426 | else: |
| 427 | v.set("") |
| 428 | check = Checkbutton(self.topframe, text=name, |
| 429 | offvalue="", onvalue=name, variable=v, |
| 430 | command=self.checkpanel) |
| 431 | check.pack(side=LEFT) |
| 432 | panel = Frame(self.botframe) |
| 433 | label = Label(panel, text=name, borderwidth=2, relief=RAISED, anchor=W) |
| 434 | label.pack(side=TOP, fill=X) |
| 435 | t = v, check, panel |
| 436 | self.panelnames.append(name) |
| 437 | self.panels[name] = t |
| 438 | if on: |
| 439 | panel.pack(expand=1, fill=BOTH) |
| 440 | return panel |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 441 | |
| 442 | def showpanel(self, name): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 443 | v, check, panel = self.panels[name] |
| 444 | v.set(name) |
| 445 | panel.pack(expand=1, fill=BOTH) |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 446 | |
| 447 | def hidepanel(self, name): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 448 | v, check, panel = self.panels[name] |
| 449 | v.set("") |
| 450 | panel.pack_forget() |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 451 | |
| 452 | def checkpanel(self): |
Guido van Rossum | 986abac | 1998-04-06 14:29:28 +0000 | [diff] [blame] | 453 | for name in self.panelnames: |
| 454 | v, check, panel = self.panels[name] |
| 455 | panel.pack_forget() |
| 456 | for name in self.panelnames: |
| 457 | v, check, panel = self.panels[name] |
| 458 | if v.get(): |
| 459 | panel.pack(expand=1, fill=BOTH) |
Guido van Rossum | 06981c3 | 1997-01-31 18:58:12 +0000 | [diff] [blame] | 460 | |
| 461 | |
| 462 | if __name__ == '__main__': |
| 463 | main() |