docs: def attachPurrlog(self, purrlog, watchdirs=[]):
          """Attaches Purr to the given purrlog directory. Arguments are passed to Purrer object as is."""
          # check purrer stack for a Purrer already watching this directory
          dprint(1, "attaching to purrlog", purrlog)
          for i, purrer in enumerate(self.purrer_stack):
              if os.path.samefile(purrer.logdir, purrlog):
                  dprint(1, "Purrer object found on stack (#%d),reusing\n", i)
                  # found? move to front of stack
                  self.purrer_stack.pop(i)
                  self.purrer_stack.insert(0, purrer)
                  # update purrer with watched directories, in case they have changed
                  for dd in (watchdirs or []):
                      purrer.addWatchedDirectory(dd, watching=None)
                  break
          # no purrer found, make a new one
          else:
              dprint(1, "creating new Purrer object")
              try:
                  purrer = Purr.Purrer(purrlog, watchdirs)
              except Purr.Purrer.LockedError as err:
                  # check that we could attach, display message if not
                  QMessageBox.warning(self, "Catfight!", """<P><NOBR>It appears that another PURR process (%s)</NOBR>
            is already attached to <tt>%s</tt>, so we're not allowed to touch it. You should exit the other PURR
            process first.</P>""" % (err.args[0], os.path.abspath(purrlog)), QMessageBox.Ok, 0)
                  return False
              except Purr.Purrer.LockFailError as err:
                  QMessageBox.warning(self, "Failed to obtain lock", """<P><NOBR>PURR was unable to obtain a lock</NOBR>
            on directory <tt>%s</tt> (error was "%s"). The most likely cause is insufficient permissions.</P>""" % (
                  os.path.abspath(purrlog), err.args[0]), QMessageBox.Ok, 0)
                  return False
              self.purrer_stack.insert(0, purrer)
              # discard end of stack
              self.purrer_stack = self.purrer_stack[:3]
              # attach signals
              self.connect(purrer, SIGNAL("disappearedFile"),
                           self.new_entry_dialog.dropDataProducts)
              self.connect(purrer, SIGNAL("disappearedFile"),
                           self.view_entry_dialog.dropDataProducts)
          # have we changed the current purrer? Update our state then
          # reopen Purr pipes
          self.purrpipes = {}
          for dd, state in purrer.watchedDirectories():
              self.purrpipes[dd] = Purr.Pipe.open(dd)
          if purrer is not self.purrer:
              self.message("Attached to %s" % purrer.logdir, ms=10000)
              dprint(1, "current Purrer changed, updating state")
              # set window title
              path = Kittens.utils.collapseuser(os.path.join(purrer.logdir, ''))
              self.setWindowTitle("PURR - %s" % path)
              # other init
              self.purrer = purrer
              self.new_entry_dialog.hide()
              self.new_entry_dialog.reset()
              dirs = [path for path, state in purrer.watchedDirectories()]
              self.new_entry_dialog.setDefaultDirs(*dirs)
              self.view_entry_dialog.setDefaultDirs(*dirs)
              self.view_entry_dialog.hide()
              self.viewer_dialog.hide()
              self._viewing_ientry = None
              self._setEntries(self.purrer.getLogEntries())
              #      print self._index_paths
              self._viewer_timestamp = None
              self._updateViewer()
              self._updateNames()
              # update directory widgets
              self.wdirlist.clear()
              for pathname, state in purrer.watchedDirectories():
                  self.wdirlist.add(pathname, state)
              # Reset _pounce to false -- this will cause checkPounceStatus() into a rescan
              self._pounce = False
              self._checkPounceStatus()
          return True