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