]> code.delx.au - gnu-emacs/blobdiff - lisp/net/newst-treeview.el
Spelling fixes.
[gnu-emacs] / lisp / net / newst-treeview.el
index 0df89b8b29929c3d1df65f19f4e215c17963afd4..7cfdd2cb89d6528200b39140b565ec1b4585aa69 100644 (file)
@@ -1,13 +1,13 @@
 ;;; newst-treeview.el --- Treeview frontend for newsticker.
 
-;; Copyright (C) 2008 Free Software Foundation, Inc.
+;; Copyright (C) 2008-2011 Free Software Foundation, Inc.
 
 ;; Author:      Ulf Jasper <ulf.jasper@web.de>
 ;; Filename:    newst-treeview.el
 ;; URL:         http://www.nongnu.org/newsticker
 ;; Created:     2007
 ;; Keywords:    News, RSS, Atom
-;; Time-stamp:  "31. Oktober 2008, 20:44:46 (ulf)"
+;; Package:     newsticker
 
 ;; ======================================================================
 
 ;;; History:
 ;;
 
-
 ;; ======================================================================
 ;;; Code:
-(require 'newsticker-reader "newst-reader")
+(require 'newst-reader)
 (require 'widget)
 (require 'tree-widget)
 (require 'wid-edit)
@@ -52,9 +51,9 @@
 
 (defface newsticker-treeview-face
   '((((class color) (background dark))
-     (:family "helvetica" :foreground "misty rose" :bold nil))
+     (:family "sans" :foreground "white" :bold nil))
     (((class color) (background light))
-     (:family "helvetica" :foreground "black" :bold nil)))
+     (:family "sans" :foreground "black" :bold nil)))
   "Face for newsticker tree."
   :group 'newsticker-treeview)
 
   30
   "Width of tree window in treeview layout.
 See also `newsticker-treeview-listwindow-height'."
-  :type 'int
+  :type 'integer
   :group 'newsticker-treeview)
 
 (defcustom newsticker-treeview-listwindow-height
   10
   "Height of list window in treeview layout.
 See also `newsticker-treeview-treewindow-width'."
-  :type 'int
+  :type 'integer
   :group 'newsticker-treeview)
 
 (defcustom newsticker-treeview-automatically-mark-displayed-items-as-old
@@ -143,13 +142,15 @@ Example: (\"Topmost group\" \"feed1\" (\"subgroup1\" \"feed 2\")
   "Name of the newsticker groups settings file."
   :type 'string
   :group 'newsticker-treeview)
+(make-obsolete 'newsticker-groups-filename 'newsticker-dir "23.1")
 
 ;; ======================================================================
 ;;; internal variables
 ;; ======================================================================
 (defvar newsticker--treeview-windows nil)
 (defvar newsticker--treeview-buffers nil)
-(defvar newsticker--treeview-current-feed nil)
+(defvar newsticker--treeview-current-feed nil
+  "Feed name of currently shown item.")
 (defvar newsticker--treeview-current-vfeed nil)
 (defvar newsticker--treeview-list-show-feed nil)
 (defvar newsticker--saved-window-config nil)
@@ -226,7 +227,7 @@ their id stays constant."
         (string= (widget-get node1 :tag) (widget-get node2 :tag)))))
 
 (defun newsticker--treeview-do-get-node-of-feed (feed-name startnode)
-   "Recursivly search node for feed FEED-NAME starting from STARTNODE."
+   "Recursively search node for feed FEED-NAME starting from STARTNODE."
    ;;(message "%s/%s" feed-name (widget-get startnode :nt-feed))
    (if (string= feed-name (or (widget-get startnode :nt-feed)
                               (widget-get startnode :nt-vfeed)))
@@ -244,7 +245,7 @@ their id stays constant."
                                               newsticker--treeview-vfeed-tree)))
 
 (defun newsticker--treeview-do-get-node (id startnode)
-   "Recursivly search node with ID starting from STARTNODE."
+   "Recursively search node with ID starting from STARTNODE."
    (if (newsticker--treeview-ids-eq id (widget-get startnode :nt-id))
        (throw 'found startnode)
      (let ((children (widget-get startnode :children)))
@@ -305,8 +306,7 @@ their id stays constant."
   "Add news ITEM for FEED to newsticker treeview list window.
 If string SHOW-FEED is non-nil it is shown in the item string."
   (setq newsticker--treeview-list-show-feed show-feed)
-  (save-excursion
-    (set-buffer (newsticker--treeview-list-buffer))
+  (with-current-buffer (newsticker--treeview-list-buffer)
     (let* ((inhibit-read-only t)
            pos1 pos2)
       (goto-char (point-max))
@@ -348,8 +348,7 @@ If string SHOW-FEED is non-nil it is shown in the item string."
 
 (defun newsticker--treeview-list-clear ()
   "Clear the newsticker treeview list window."
-  (save-excursion
-    (set-buffer (newsticker--treeview-list-buffer))
+  (with-current-buffer (newsticker--treeview-list-buffer)
     (let ((inhibit-read-only t))
       (erase-buffer)
       (kill-all-local-variables)
@@ -547,41 +546,40 @@ The sort function is chosen according to the value of
 (defun newsticker--treeview-list-update-faces ()
   "Update faces in the treeview list buffer."
   (let (pos-sel)
-    (save-excursion
-      (set-buffer (newsticker--treeview-list-buffer))
-      (let ((inhibit-read-only t))
-        (goto-char (point-min))
-        (while (not (eobp))
-          (let* ((pos (save-excursion (end-of-line) (point)))
-                 (item (get-text-property (point) :nt-item))
-                 (age (newsticker--age item))
-                 (selected (get-text-property (point) :nt-selected))
-                 (face (cond ((eq age 'new)
-                              'newsticker-treeview-new-face)
-                             ((eq age 'old)
-                              'newsticker-treeview-old-face)
-                             ((eq age 'immortal)
-                              'newsticker-treeview-immortal-face)
-                             ((eq age 'obsolete)
-                              'newsticker-treeview-obsolete-face)
-                             (t
-                              'bold))))
-            (put-text-property (point) pos 'face face)
-            (if selected
-                (move-overlay newsticker--selection-overlay (point)
-                              (1+ pos) ;include newline
-                              (current-buffer)))
-            (if selected (setq pos-sel (point)))
-            (forward-line 1)
-            (beginning-of-line))))) ;; FIXME!?
+    (with-current-buffer (newsticker--treeview-list-buffer)
+      (save-excursion
+        (let ((inhibit-read-only t))
+          (goto-char (point-min))
+          (while (not (eobp))
+            (let* ((pos (point-at-eol))
+                   (item (get-text-property (point) :nt-item))
+                   (age (newsticker--age item))
+                   (selected (get-text-property (point) :nt-selected))
+                   (face (cond ((eq age 'new)
+                                'newsticker-treeview-new-face)
+                               ((eq age 'old)
+                                'newsticker-treeview-old-face)
+                               ((eq age 'immortal)
+                                'newsticker-treeview-immortal-face)
+                               ((eq age 'obsolete)
+                                'newsticker-treeview-obsolete-face)
+                               (t
+                                'bold))))
+              (put-text-property (point) pos 'face face)
+              (if selected
+                  (move-overlay newsticker--selection-overlay (point)
+                                (1+ pos) ;include newline
+                                (current-buffer)))
+              (if selected (setq pos-sel (point)))
+              (forward-line 1)
+              (beginning-of-line)))))) ;; FIXME!?
     (when pos-sel
       (if (window-live-p (newsticker--treeview-list-window))
           (set-window-point (newsticker--treeview-list-window) pos-sel)))))
 
 (defun newsticker--treeview-list-clear-highlight ()
   "Clear the highlight in the treeview list buffer."
-  (save-excursion
-    (set-buffer (newsticker--treeview-list-buffer))
+  (with-current-buffer (newsticker--treeview-list-buffer)
     (let ((inhibit-read-only t))
       (put-text-property (point-min) (point-max) :nt-selected nil))
     (newsticker--treeview-list-update-faces)))
@@ -590,20 +588,17 @@ The sort function is chosen according to the value of
   "Update the highlight in the treeview list buffer."
   (newsticker--treeview-list-clear-highlight)
     (let (pos num-lines)
-      (save-excursion
-        (set-buffer (newsticker--treeview-list-buffer))
+      (with-current-buffer (newsticker--treeview-list-buffer)
         (let ((inhibit-read-only t))
-          (put-text-property (save-excursion (beginning-of-line) (point))
-                             (save-excursion (end-of-line) (point))
-                             :nt-selected t))
+          (put-text-property (point-at-bol) (point-at-eol) :nt-selected t))
         (newsticker--treeview-list-update-faces))))
 
 (defun newsticker--treeview-list-highlight-start ()
   "Return position of selection in treeview list buffer."
-  (save-excursion
-    (set-buffer (newsticker--treeview-list-buffer))
-    (goto-char (point-min))
-    (next-single-property-change (point) :nt-selected)))
+  (with-current-buffer (newsticker--treeview-list-buffer)
+    (save-excursion
+      (goto-char (point-min))
+      (next-single-property-change (point) :nt-selected))))
 
 (defun newsticker--treeview-list-update (clear-buffer)
   "Update the faces and highlight in the treeview list buffer.
@@ -670,13 +665,33 @@ for the button."
                 'face face
                 'keymap newsticker-treeview-list-sort-button-map)))
 
+(defun newsticker--treeview-list-select (item)
+  "Select ITEM in treeview's list buffer."
+  (newsticker--treeview-list-clear-highlight)
+    (let (pos num-lines)
+      (save-current-buffer
+        (set-buffer (newsticker--treeview-list-buffer))
+        (goto-char (point-min))
+        (catch 'found
+          (while t
+            (let ((it (get-text-property (point) :nt-item)))
+              (when (eq it item)
+                (newsticker--treeview-list-update-highlight)
+                (newsticker--treeview-list-update-faces)
+                (newsticker--treeview-item-show
+                 item (get-text-property (point) :nt-feed))
+                (throw 'found t)))
+            (forward-line 1)
+            (when (eobp)
+              (goto-char (point-min))
+              (throw 'found nil)))))))
+
 ;; ======================================================================
 ;;; item window
 ;; ======================================================================
 (defun newsticker--treeview-item-show-text (title description)
   "Show text in treeview item buffer consisting of TITLE and DESCRIPTION."
-  (save-excursion
-    (set-buffer (newsticker--treeview-item-buffer))
+  (with-current-buffer (newsticker--treeview-item-buffer)
     (when (fboundp 'w3m-process-stop)
       (w3m-process-stop (current-buffer)))
     (let ((inhibit-read-only t))
@@ -688,13 +703,13 @@ for the button."
       (insert "\n\n" description)
       (when newsticker-justification
         (fill-region (point-min) (point-max) newsticker-justification))
-      (newsticker-treeview-mode)
+      (newsticker-treeview-item-mode)
       (goto-char (point-min)))))
 
-(defun newsticker--treeview-item-show (item feed)
-  "Show news ITEM coming from FEED in treeview item buffer."
-  (save-excursion
-    (set-buffer (newsticker--treeview-item-buffer))
+(defun newsticker--treeview-item-show (item feed-name-symbol)
+  "Show news ITEM coming from FEED-NAME-SYMBOL in treeview item buffer."
+  (setq newsticker--treeview-current-feed (symbol-name feed-name-symbol))
+  (with-current-buffer (newsticker--treeview-item-buffer)
     (when (fboundp 'w3m-process-stop)
       (w3m-process-stop (current-buffer)))
     (let ((inhibit-read-only t)
@@ -706,7 +721,7 @@ for the button."
       (kill-all-local-variables)
       (remove-overlays)
 
-      (when (and item feed)
+      (when (and item feed-name-symbol)
         (let ((wwidth (1- (window-width (newsticker--treeview-item-window)))))
           (if newsticker-use-full-width
               (set (make-local-variable 'fill-column) wwidth))
@@ -722,14 +737,14 @@ for the button."
                    (not is-rendered-HTML))
           (fill-region marker1 marker2 newsticker-justification))
 
-        (newsticker-treeview-mode)
+        (newsticker-treeview-item-mode)
         (goto-char (point-min))
         ;; insert logo at top
         (let* ((newsticker-enable-logo-manipulations nil)
-               (img (newsticker--image-read feed nil)))
+               (img (newsticker--image-read feed-name-symbol nil)))
           (if (and (display-images-p) img)
               (newsticker--insert-image img (car item))
-            (insert (newsticker--real-feed-name feed))))
+            (insert (newsticker--real-feed-name feed-name-symbol))))
         (add-text-properties (point-min) (point)
                              (list 'face 'newsticker-feed-face
                                    'mouse-face 'highlight
@@ -793,7 +808,7 @@ for the button."
     (set-buffer (newsticker--treeview-item-buffer))
     (let ((inhibit-read-only t))
       (erase-buffer))
-    (newsticker-treeview-mode)))
+    (newsticker-treeview-item-mode)))
 
 ;; ======================================================================
 ;;; Tree window
@@ -989,8 +1004,6 @@ If RECURSIVE is non-nil recursively update parent widgets as
 well.  Argument IGNORE is ignored.  Note that this function, if
 called recursively, makes w invalid.  You should keep w's nt-id in
 that case."
-  ;;(message "newsticker--treeview-tree-update-tag %s, %s" (widget-get w :tag)
-    ;;       (widget-type w))
   (let* ((parent (widget-get w :parent))
          (feed (or (widget-get w :nt-feed) (widget-get parent :nt-feed)))
          (vfeed (or (widget-get w :nt-vfeed) (widget-get parent :nt-vfeed)))
@@ -1011,8 +1024,7 @@ that case."
         (let ((p (point))
               (notify (widget-get w :notify)))
           ;; FIXME: This moves point!!!!
-          (save-excursion
-            (set-buffer (newsticker--treeview-tree-buffer))
+          (with-current-buffer (newsticker--treeview-tree-buffer)
             (widget-value-set w (widget-value w)))
           (goto-char p))))))
 
@@ -1044,12 +1056,10 @@ Arguments IGNORE are ignored."
                              (newsticker--treeview-get-current-node)
                                         :parent) :from)))
     (when (or (integerp pos) (and (markerp pos) (marker-position pos)))
-      (save-excursion
-        (set-buffer (newsticker--treeview-tree-buffer))
+      (with-current-buffer (newsticker--treeview-tree-buffer)
         (goto-char pos)
         (move-overlay newsticker--tree-selection-overlay
-                      (save-excursion (beginning-of-line) (point))
-                      (save-excursion (end-of-line) (1+ (point)))
+                      (point-at-bol) (1+ (point-at-eol))
                       (current-buffer)))
       (if (window-live-p (newsticker--treeview-tree-window))
           (set-window-point (newsticker--treeview-tree-window) pos)))))
@@ -1057,86 +1067,63 @@ Arguments IGNORE are ignored."
 ;; ======================================================================
 ;;; Toolbar
 ;; ======================================================================
-;;(makunbound 'newsticker-treeview-tool-bar-map)
 (defvar newsticker-treeview-tool-bar-map
   (if (featurep 'xemacs)
       nil
     (if (boundp 'tool-bar-map)
         (let ((tool-bar-map (make-sparse-keymap)))
+          (tool-bar-add-item "newsticker/prev-feed"
+                             'newsticker-treeview-prev-feed
+                             'newsticker-treeview-prev-feed
+                             :help "Go to previous feed"
+                             ;;:enable '(newsticker-previous-feed-available-p) FIXME
+                             )
+          (tool-bar-add-item "newsticker/prev-item"
+                             'newsticker-treeview-prev-item
+                             'newsticker-treeview-prev-item
+                             :help "Go to previous item"
+                             ;;:enable '(newsticker-previous-item-available-p) FIXME
+                             )
+          (tool-bar-add-item "newsticker/next-item"
+                             'newsticker-treeview-next-item
+                             'newsticker-treeview-next-item
+                             :visible t
+                             :help "Go to next item"
+                             ;;:enable '(newsticker-next-item-available-p) FIXME
+                             )
+          (tool-bar-add-item "newsticker/next-feed"
+                             'newsticker-treeview-next-feed
+                             'newsticker-treeview-next-feed
+                             :help "Go to next feed"
+                             ;;:enable '(newsticker-next-feed-available-p) FIXME
+                             )
+          (tool-bar-add-item "newsticker/mark-immortal"
+                             'newsticker-treeview-toggle-item-immortal
+                             'newsticker-treeview-toggle-item-immortal
+                             :help "Toggle current item as immortal"
+                             ;;:enable '(newsticker-item-not-immortal-p) FIXME
+                             )
+          (tool-bar-add-item "newsticker/mark-read"
+                             'newsticker-treeview-mark-item-old
+                             'newsticker-treeview-mark-item-old
+                             :help "Mark current item as read"
+                             ;;:enable '(newsticker-item-not-old-p) FIXME
+                             )
+          (tool-bar-add-item "newsticker/get-all"
+                             'newsticker-get-all-news
+                             'newsticker-get-all-news
+                             :help "Get news for all feeds")
+          (tool-bar-add-item "newsticker/update"
+                             'newsticker-treeview-update
+                             'newsticker-treeview-update
+                             :help "Update newsticker buffer")
+          (tool-bar-add-item "newsticker/browse-url"
+                             'newsticker-browse-url
+                             'newsticker-browse-url
+                             :help "Browse URL for item at point")
+          ;; standard icons / actions
           (define-key tool-bar-map [newsticker-sep-1]
             (list 'menu-item "--double-line"))
-          (define-key tool-bar-map [newsticker-browse-url]
-            (list 'menu-item "newsticker-browse-url"
-                  'newsticker-browse-url
-                  :visible t
-                  :help "Browse URL for item at point"
-                  :image newsticker--browse-image))
-          (define-key tool-bar-map [newsticker-buffer-force-update]
-            (list 'menu-item "newsticker-treeview-update"
-                  'newsticker-treeview-update
-                  :visible t
-                  :help "Update newsticker buffer"
-                  :image newsticker--update-image
-                  :enable t))
-          (define-key tool-bar-map [newsticker-get-all-news]
-            (list 'menu-item "newsticker-get-all-news" 'newsticker-get-all-news
-                  :visible t
-                  :help "Get news for all feeds"
-                  :image newsticker--get-all-image))
-          (define-key tool-bar-map [newsticker-mark-item-at-point-as-read]
-            (list 'menu-item "newsticker-treeview-mark-item-old"
-                  'newsticker-treeview-mark-item-old
-                  :visible t
-                  :image newsticker--mark-read-image
-                  :help "Mark current item as read"
-                  ;;:enable '(newsticker-item-not-old-p) FIXME
-                  ))
-          (define-key tool-bar-map [newsticker-mark-item-at-point-as-immortal]
-            (list 'menu-item "newsticker-treeview-toggle-item-immortal"
-                  'newsticker-treeview-toggle-item-immortal
-                  :visible t
-                  :image newsticker--mark-immortal-image
-                  :help "Toggle current item as immortal"
-                  :enable t
-                  ;;'(newsticker-item-not-immortal-p) FIXME
-                  ))
-          (define-key tool-bar-map [newsticker-next-feed]
-            (list 'menu-item "newsticker-treeview-next-feed"
-                  'newsticker-treeview-next-feed
-                  :visible t
-                  :help "Go to next feed"
-                  :image newsticker--next-feed-image
-                  :enable t
-                  ;;'(newsticker-next-feed-available-p) FIXME
-                  ))
-          (define-key tool-bar-map [newsticker-treeview-next-item]
-            (list 'menu-item "newsticker-treeview-next-item"
-                  'newsticker-treeview-next-item
-                  :visible t
-                  :help "Go to next item"
-                  :image newsticker--next-item-image
-                  :enable t
-                  ;;'(newsticker-next-item-available-p) FIXME
-                  ))
-          (define-key tool-bar-map [newsticker-treeview-prev-item]
-            (list 'menu-item "newsticker-treeview-prev-item"
-                  'newsticker-treeview-prev-item
-                  :visible t
-                  :help "Go to previous item"
-                  :image newsticker--previous-item-image
-                  :enable t
-                  ;;'(newsticker-previous-item-available-p) FIXME
-                  ))
-          (define-key tool-bar-map [newsticker-treeview-prev-feed]
-            (list 'menu-item "newsticker-treeview-prev-feed"
-                  'newsticker-treeview-prev-feed
-                  :visible t
-                  :help "Go to previous feed"
-                  :image newsticker--previous-feed-image
-                  :enable t
-                  ;;'(newsticker-previous-feed-available-p) FIXME
-                  ))
-          ;; standard icons / actions
           (tool-bar-add-item "close"
                              'newsticker-treeview-quit
                              'newsticker-treeview-quit
@@ -1166,8 +1153,7 @@ Arguments IGNORE are ignored."
 (defun newsticker-treeview-browse-url ()
   "Call `browse-url' for the link of the item at point."
   (interactive)
-  (save-excursion
-    (set-buffer (newsticker--treeview-list-buffer))
+  (with-current-buffer (newsticker--treeview-list-buffer)
     (let ((url (get-text-property (point) :nt-link)))
       (when url
         (browse-url url)
@@ -1185,15 +1171,13 @@ Arguments IGNORE are ignored."
                (get-buffer-create "*Newsticker Item*") t)
 
   (unless newsticker--selection-overlay
-    (save-excursion
-      (set-buffer (newsticker--treeview-list-buffer))
+    (with-current-buffer (newsticker--treeview-list-buffer)
       (setq newsticker--selection-overlay (make-overlay (point-min)
                                                         (point-max)))
       (overlay-put newsticker--selection-overlay 'face
                    'newsticker-treeview-selection-face)))
   (unless newsticker--tree-selection-overlay
-    (save-excursion
-      (set-buffer (newsticker--treeview-tree-buffer))
+    (with-current-buffer (newsticker--treeview-tree-buffer)
       (setq newsticker--tree-selection-overlay (make-overlay (point-min)
                                                              (point-max)))
       (overlay-put newsticker--tree-selection-overlay 'face
@@ -1207,23 +1191,27 @@ Arguments IGNORE are ignored."
   "Update all treeview buffers and windows.
 Note: does not update the layout."
   (interactive)
-  (newsticker--cache-update)
-  (newsticker--group-manage-orphan-feeds)
-  (newsticker--treeview-list-update t)
-  (newsticker--treeview-item-update)
-  (newsticker--treeview-tree-update-tags)
-  (cond (newsticker--treeview-current-feed
-         (newsticker--treeview-list-items newsticker--treeview-current-feed))
-        (newsticker--treeview-current-vfeed
-         (newsticker--treeview-list-items-with-age
-          (intern newsticker--treeview-current-vfeed))))
-  (newsticker--treeview-tree-update-highlight)
-  (newsticker--treeview-list-update-highlight))
+  (let ((cur-item (newsticker--treeview-get-selected-item)))
+    (if (newsticker--group-manage-orphan-feeds)
+      (newsticker--treeview-tree-update))
+    (newsticker--treeview-list-update t)
+    (newsticker--treeview-item-update)
+    (newsticker--treeview-tree-update-tags)
+    (cond (newsticker--treeview-current-feed
+           (newsticker--treeview-list-items newsticker--treeview-current-feed))
+          (newsticker--treeview-current-vfeed
+           (newsticker--treeview-list-items-with-age
+            (intern newsticker--treeview-current-vfeed))))
+    (newsticker--treeview-tree-update-highlight)
+    (newsticker--treeview-list-update-highlight)
+    (let ((cur-feed (or newsticker--treeview-current-feed
+                        newsticker--treeview-current-vfeed)))
+      (if (and cur-feed cur-item)
+          (newsticker--treeview-list-select cur-item)))))
 
 (defun newsticker-treeview-quit ()
   "Quit newsticker treeview."
   (interactive)
-  (newsticker-treeview-save)
   (setq newsticker--sentinel-callback nil)
   (bury-buffer "*Newsticker Tree*")
   (bury-buffer "*Newsticker List*")
@@ -1232,28 +1220,38 @@ Note: does not update the layout."
   (when newsticker--frame
     (if (frame-live-p newsticker--frame)
       (delete-frame newsticker--frame))
-    (setq newsticker--frame nil)))
+    (setq newsticker--frame nil))
+  (newsticker-treeview-save))
 
 (defun newsticker-treeview-save ()
   "Save newsticker data including treeview settings."
   (interactive)
-  (newsticker--cache-save)
-  (save-excursion
-    (let ((coding-system-for-write 'utf-8)
-          (buf (find-file-noselect newsticker-groups-filename)))
-      (when buf
-        (set-buffer buf)
+  (let ((coding-system-for-write 'utf-8)
+        (buf (find-file-noselect (concat newsticker-dir "/groups"))))
+    (when buf
+      (with-current-buffer buf
         (setq buffer-undo-list t)
         (erase-buffer)
         (insert ";; -*- coding: utf-8 -*-\n")
         (insert (prin1-to-string newsticker-groups))
-        (save-buffer)))))
+        (save-buffer)
+        (kill-buffer)))))
 
 (defun newsticker--treeview-load ()
   "Load treeview settings."
   (let* ((coding-system-for-read 'utf-8)
-         (buf (and (file-exists-p newsticker-groups-filename)
-                   (find-file-noselect newsticker-groups-filename))))
+         (filename
+          (or (and (file-exists-p newsticker-groups-filename)
+                   (y-or-n-p
+                    (format "Old newsticker groups (%s) file exists.  Read it? "
+                            newsticker-groups-filename))
+                   newsticker-groups-filename)
+              (concat newsticker-dir "/groups")))
+         (buf (and (file-exists-p filename)
+                   (find-file-noselect filename))))
+    (and (file-exists-p newsticker-groups-filename)
+        (y-or-n-p (format "Delete old newsticker groups file? "))
+        (delete-file newsticker-groups-filename))
     (when buf
       (set-buffer buf)
       (goto-char (point-min))
@@ -1261,7 +1259,8 @@ Note: does not update the layout."
           (setq newsticker-groups (read buf))
         (error
          (message "Error while reading newsticker groups file!")
-         (setq newsticker-groups nil))))))
+         (setq newsticker-groups nil)))
+      (kill-buffer buf))))
 
 
 (defun newsticker-treeview-scroll-item ()
@@ -1276,8 +1275,7 @@ Note: does not update the layout."
   (interactive)
   (newsticker--treeview-restore-layout)
   (newsticker--treeview-list-update-highlight)
-  (save-excursion
-    (set-buffer (newsticker--treeview-list-buffer))
+  (with-current-buffer (newsticker--treeview-list-buffer)
     (beginning-of-line)
     (let ((item (get-text-property (point) :nt-item))
           (feed (get-text-property (point) :nt-feed)))
@@ -1307,47 +1305,65 @@ Note: does not update the layout."
     (forward-line -1))
   (newsticker-treeview-show-item))
 
-(defun newsticker-treeview-next-new-or-immortal-item ()
-  "Move to next new or immortal item."
+(defun newsticker-treeview-next-new-or-immortal-item (&optional
+                                                      current-item-counts
+                                                      dont-wrap-trees)
+  "Move to next new or immortal item.
+Will move to next feed until an item is found.  Will not move if
+optional argument CURRENT-ITEM-COUNTS is t and current item is
+new or immortal.  Will not move from virtual to ordinary feed
+tree or vice versa if optional argument DONT-WRAP-TREES is non-nil."
   (interactive)
   (newsticker--treeview-restore-layout)
   (newsticker--treeview-list-clear-highlight)
-  (catch 'found
-    (let ((index (newsticker-treeview-next-item)))
-      (while t
-        (save-current-buffer
-          (set-buffer (newsticker--treeview-list-buffer))
-          (forward-line 1)
-          (when (eobp)
-            (forward-line -1)
-            (throw 'found nil)))
-        (when (memq (newsticker--age
-                     (newsticker--treeview-get-selected-item)) '(new immortal))
-            (newsticker-treeview-show-item)
-            (throw 'found t))))))
+  (unless (catch 'found
+            (let ((move (not current-item-counts)))
+              (while t
+                (save-current-buffer
+                  (set-buffer (newsticker--treeview-list-buffer))
+                  (when move (forward-line 1)
+                        (when (eobp)
+                          (forward-line -1)
+                          (throw 'found nil))))
+                (when (memq (newsticker--age
+                             (newsticker--treeview-get-selected-item))
+                            '(new immortal))
+                  (newsticker-treeview-show-item)
+                  (throw 'found t))
+                (setq move t))))
+    (let ((wrap-trees (not dont-wrap-trees)))
+      (when (or (newsticker-treeview-next-feed t)
+                (and wrap-trees (newsticker--treeview-first-feed)))
+        (newsticker-treeview-next-new-or-immortal-item t t)))))
 
 (defun newsticker-treeview-prev-new-or-immortal-item ()
-  "Move to previous new or immortal item."
+  "Move to previous new or immortal item.
+Will move to previous feed until an item is found."
   (interactive)
   (newsticker--treeview-restore-layout)
   (newsticker--treeview-list-clear-highlight)
-  (catch 'found
-    (let ((index (newsticker-treeview-next-item)))
-      (while t
-        (save-current-buffer
-          (set-buffer (newsticker--treeview-list-buffer))
-          (forward-line -1)
-          (when (bobp)
-            (throw 'found nil)))
-        (when (memq (newsticker--age
-                     (newsticker--treeview-get-selected-item)) '(new immortal))
-            (newsticker-treeview-show-item)
-            (throw 'found t))))))
+  (unless (catch 'found
+            (while t
+              (save-current-buffer
+                (set-buffer (newsticker--treeview-list-buffer))
+                (when (bobp)
+                  (throw 'found nil))
+                (forward-line -1))
+              (when (memq (newsticker--age
+                           (newsticker--treeview-get-selected-item))
+                          '(new immortal))
+                (newsticker-treeview-show-item)
+                (throw 'found t))
+                (when (bobp)
+                  (throw 'found nil))))
+    (when (newsticker-treeview-prev-feed t)
+      (set-buffer (newsticker--treeview-list-buffer))
+      (goto-char (point-max))
+      (newsticker-treeview-prev-new-or-immortal-item))))
 
 (defun newsticker--treeview-get-selected-item ()
   "Return item that is currently selected in list buffer."
-  (save-excursion
-    (set-buffer (newsticker--treeview-list-buffer))
+  (with-current-buffer (newsticker--treeview-list-buffer)
     (beginning-of-line)
     (get-text-property (point) :nt-item)))
 
@@ -1377,15 +1393,16 @@ Move to next item unless DONT-PROCEED is non-nil."
     (setcar (nthcdr 4 item) new-age)
     ;; clean up ticker FIXME
     )
-  (newsticker--cache-update))
+  (newsticker--cache-save-feed
+   (newsticker--cache-get-feed (intern newsticker--treeview-current-feed)))
+  (newsticker--treeview-tree-do-update-tags newsticker--treeview-vfeed-tree))
 
 (defun newsticker-treeview-mark-list-items-old ()
   "Mark all listed items as old."
   (interactive)
   (let ((current-feed (or newsticker--treeview-current-feed
                           newsticker--treeview-current-vfeed)))
-    (save-excursion
-      (set-buffer (newsticker--treeview-list-buffer))
+    (with-current-buffer (newsticker--treeview-list-buffer)
       (goto-char (point-min))
       (while (not (eobp))
         (let ((item (get-text-property (point) :nt-item)))
@@ -1412,8 +1429,7 @@ Move to next item unless DONT-PROCEED is non-nil."
 
 (defun newsticker--treeview-set-current-node (node)
   "Make NODE the current node."
-  (save-excursion
-    (set-buffer (newsticker--treeview-tree-buffer))
+  (with-current-buffer (newsticker--treeview-tree-buffer)
     (setq newsticker--treeview-current-node-id
           (widget-get node :nt-id))
     (setq newsticker--treeview-current-feed (widget-get node :nt-feed))
@@ -1519,37 +1535,59 @@ is activated."
           (node
            (widget-apply-action node)))))
 
-(defun newsticker-treeview-next-feed ()
-  "Move to next feed."
+(defun newsticker--treeview-first-feed ()
+  "Jump to the depth-first feed in the `newsticker-groups' tree."
+  (newsticker-treeview-jump
+   (car (reverse (newsticker--group-get-feeds newsticker-groups t)))))
+
+(defun newsticker-treeview-next-feed (&optional stay-in-tree)
+  "Move to next feed.
+Optional argument STAY-IN-TREE prevents moving from real feed
+tree to virtual feed tree or vice versa.
+Return t if a new feed was activated, nil otherwise."
   (interactive)
   (newsticker--treeview-restore-layout)
-  (let ((cur (newsticker--treeview-get-current-node)))
-    ;;(message "newsticker-treeview-next-feed from %s"
-    ;;       (widget-get cur :tag))
-    (if cur
-        (let ((new (or (newsticker--treeview-get-next-sibling cur)
-                       (newsticker--treeview-get-next-uncle cur)
-                       (newsticker--treeview-get-other-tree))))
-          (newsticker--treeview-activate-node new))
-      (newsticker--treeview-activate-node
-       (car (widget-get newsticker--treeview-feed-tree :children)))))
-  (newsticker--treeview-tree-update-highlight))
+  (let ((cur (newsticker--treeview-get-current-node))
+        (new nil))
+    (setq new
+          (if cur
+              (or (newsticker--treeview-get-next-sibling cur)
+                  (newsticker--treeview-get-next-uncle cur)
+                  (and (not stay-in-tree)
+                       (newsticker--treeview-get-other-tree)))
+            (car (widget-get newsticker--treeview-feed-tree :children))))
+    (if new
+        (progn
+          (newsticker--treeview-activate-node new)
+          (newsticker--treeview-tree-update-highlight)
+          (not (eq new cur)))
+      nil)))
 
-(defun newsticker-treeview-prev-feed ()
-  "Move to previous feed."
+(defun newsticker-treeview-prev-feed (&optional stay-in-tree)
+  "Move to previous feed.
+Optional argument STAY-IN-TREE prevents moving from real feed
+tree to virtual feed tree or vice versa.
+Return t if a new feed was activated, nil otherwise."
   (interactive)
   (newsticker--treeview-restore-layout)
-  (let ((cur (newsticker--treeview-get-current-node)))
-    (message "newsticker-treeview-prev-feed from %s"
-             (widget-get cur :tag))
+  (let ((cur (newsticker--treeview-get-current-node))
+        (new nil))
     (if cur
-        (let ((new (or (newsticker--treeview-get-prev-sibling cur)
-                       (newsticker--treeview-get-prev-uncle cur)
-                       (newsticker--treeview-get-other-tree))))
-          (newsticker--treeview-activate-node new t))
-      (newsticker--treeview-activate-node
-       (car (widget-get newsticker--treeview-feed-tree :children)) t)))
-  (newsticker--treeview-tree-update-highlight))
+      (progn
+        (setq new
+              (if cur
+                  (or (newsticker--treeview-get-prev-sibling cur)
+                      (newsticker--treeview-get-prev-uncle cur)
+                      (and (not stay-in-tree)
+                           (newsticker--treeview-get-other-tree)))
+                (car (widget-get newsticker--treeview-feed-tree :children))))
+        (if new
+            (progn
+              (newsticker--treeview-activate-node new t)
+              (newsticker--treeview-tree-update-highlight)
+              (not (eq new cur)))
+          nil))
+      nil)))
 
 (defun newsticker-treeview-next-page ()
   "Scroll item buffer."
@@ -1573,8 +1611,7 @@ is activated."
         (newsticker--treeview-unfold-node group-name))
       (setq node (newsticker--treeview-get-node-of-feed feed-name)))
     (when node
-      (save-excursion
-        (set-buffer (newsticker--treeview-tree-buffer))
+      (with-current-buffer (newsticker--treeview-tree-buffer)
         (widget-put node :nt-selected t)
         (widget-apply-action node)
         (newsticker--treeview-set-current-node node)))))
@@ -1585,9 +1622,10 @@ is activated."
    (list (let ((completion-ignore-case t))
            (completing-read
             "Jump to feed: "
-            (mapcar 'car (append newsticker-url-list
-                                 newsticker-url-list-defaults))
-                            nil t))))
+            (append '("new" "obsolete" "immortal" "all")
+                    (mapcar 'car (append newsticker-url-list
+                                         newsticker-url-list-defaults)))
+            nil t))))
   (newsticker--treeview-unfold-node feed-name))
 
 ;; ======================================================================
@@ -1676,7 +1714,7 @@ return a nested list."
                   (let ((subfeeds (newsticker--group-get-feeds n t)))
                     (when subfeeds
                       (setq result (append subfeeds result)))))))
-          group)
+          (cdr group))
     result))
 
 (defun newsticker-group-add-group (name parent)
@@ -1773,7 +1811,8 @@ Update teeview afterwards unless NO-UPDATE is non-nil."
 
 (defun newsticker--group-manage-orphan-feeds ()
   "Put unmanaged feeds into `newsticker-groups'.
-Remove obsolete feeds as well."
+Remove obsolete feeds as well.
+Return t if groups have changed, nil otherwise."
   (unless newsticker-groups
     (setq newsticker-groups '("Feeds")))
   (let ((new-feed nil)
@@ -1785,10 +1824,9 @@ Remove obsolete feeds as well."
           (append newsticker-url-list-defaults newsticker-url-list))
     (setq newsticker-groups
           (newsticker--group-remove-obsolete-feeds newsticker-groups))
-    (if (or new-feed
-            (not (= grouped-feeds
-                    (newsticker--count-grouped-feeds newsticker-groups))))
-        (newsticker--treeview-tree-update))))
+    (or new-feed
+        (not (= grouped-feeds
+                (newsticker--count-grouped-feeds newsticker-groups))))))
 
 ;; ======================================================================
 ;;; Modes
@@ -1830,8 +1868,31 @@ Remove obsolete feeds as well."
     (define-key menu [newsticker-treeview-mark-list-items-old]
       (list 'menu-item "Mark all items old"
             'newsticker-treeview-mark-list-items-old))
+    (define-key menu [newsticker-treeview-mark-item-old]
+      (list 'menu-item "Mark current item old"
+            'newsticker-treeview-mark-item-old))
+    (define-key menu [newsticker-treeview-toggle-item-immortal]
+      (list 'menu-item "Mark current item immortal (toggle)"
+            'newsticker-treeview-toggle-item-immortal))
+    (define-key menu [newsticker-treeview-get-news]
+      (list 'menu-item "Get news for current feed"
+            'newsticker-treeview-get-news))
     menu)
-  "Map for newsticker tree menu.")
+  "Map for newsticker list menu.")
+
+(defvar newsticker-treeview-item-menu
+  (let ((menu (make-sparse-keymap "Newsticker Item")))
+    (define-key menu [newsticker-treeview-mark-item-old]
+      (list 'menu-item "Mark current item old"
+            'newsticker-treeview-mark-item-old))
+    (define-key menu [newsticker-treeview-toggle-item-immortal]
+      (list 'menu-item "Mark current item immortal (toggle)"
+            'newsticker-treeview-toggle-item-immortal))
+    (define-key menu [newsticker-treeview-get-news]
+      (list 'menu-item "Get news for current feed"
+            'newsticker-treeview-get-news))
+    menu)
+  "Map for newsticker item menu.")
 
 (defvar newsticker-treeview-mode-map
   (let ((map (make-sparse-keymap 'newsticker-treeview-mode-map)))
@@ -1896,6 +1957,11 @@ Remove obsolete feeds as well."
   (define-key newsticker-treeview-list-mode-map [down-mouse-3]
     newsticker-treeview-list-menu))
 
+(define-derived-mode newsticker-treeview-item-mode newsticker-treeview-mode
+  "Item"
+  (define-key newsticker-treeview-item-mode-map [down-mouse-3]
+    newsticker-treeview-item-menu))
+
 (defun newsticker-treeview-tree-click (event)
   "Handle click EVENT on a tag in the newsticker tree."
   (interactive "e")
@@ -1908,10 +1974,9 @@ Remove obsolete feeds as well."
   "Actually handle click event.
 POS gives the position where EVENT occurred."
   (interactive)
-  (unless pos (setq pos (point)))
-  (let ((pos (or pos (point)))
-        (nt-id (get-text-property pos :nt-id))
-        (item (get-text-property pos :nt-item)))
+  (let* ((pos (or pos (point)))
+         (nt-id (get-text-property pos :nt-id))
+         (item (get-text-property pos :nt-item)))
     (cond (item
            ;; click in list buffer
            (newsticker-treeview-show-item))
@@ -1953,10 +2018,10 @@ POS gives the position where EVENT occurred."
   (setq newsticker--treeview-windows nil)
   (setq newsticker--treeview-buffers nil)
   (delete-other-windows)
-  (split-window-horizontally newsticker-treeview-treewindow-width)
+  (split-window-right newsticker-treeview-treewindow-width)
   (add-to-list 'newsticker--treeview-windows (selected-window) t)
   (other-window 1)
-  (split-window-vertically newsticker-treeview-listwindow-height)
+  (split-window-below newsticker-treeview-listwindow-height)
   (add-to-list 'newsticker--treeview-windows (selected-window) t)
   (other-window 1)
   (add-to-list 'newsticker--treeview-windows (selected-window) t)
@@ -1971,7 +2036,8 @@ POS gives the position where EVENT occurred."
   (newsticker--treeview-frame-init)
   (newsticker--treeview-window-init)
   (newsticker--treeview-buffer-init)
-  (newsticker--group-manage-orphan-feeds)
+  (if (newsticker--group-manage-orphan-feeds)
+      (newsticker--treeview-tree-update))
   (newsticker--treeview-set-current-node newsticker--treeview-feed-tree)
   (newsticker-start t) ;; will start only if not running
   (newsticker-treeview-update)
@@ -1985,7 +2051,6 @@ POS gives the position where EVENT occurred."
   (when newsticker--treeview-current-feed
     (newsticker-get-news newsticker--treeview-current-feed)))
 
-(provide 'newsticker-treeview)
+(provide 'newst-treeview)
 
-;; arch-tag: 5dbaff48-1f3e-4fc6-8ebd-e966fc90d2d4
 ;;; newst-treeview.el ends here