* wl-summary.el (wl-summary-update-mark-and-highlight-window): New function.
[elisp/wanderlust.git] / wl / wl-summary.el
index f791318..2c6c870 100644 (file)
@@ -90,6 +90,8 @@
 (defvar wl-summary-buffer-temp-mark-column nil)
 (defvar wl-summary-buffer-persistent-mark-column nil)
 
+(defvar wl-summary-buffer-unsync-mark-number-list nil)
+
 (defvar wl-summary-buffer-persistent nil)
 (defvar wl-summary-buffer-thread-nodes nil)
 (defvar wl-summary-buffer-target-mark-list nil)
 (make-variable-buffer-local 'wl-summary-buffer-number-column)
 (make-variable-buffer-local 'wl-summary-buffer-temp-mark-column)
 (make-variable-buffer-local 'wl-summary-buffer-persistent-mark-column)
+(make-variable-buffer-local 'wl-summary-buffer-unsync-mark-number-list)
 (make-variable-buffer-local 'wl-summary-buffer-persistent)
 (make-variable-buffer-local 'wl-summary-buffer-thread-nodes)
 (make-variable-buffer-local 'wl-summary-buffer-prev-refile-destination)
@@ -552,6 +555,45 @@ See also variable `wl-use-petname'."
       (not (wl-thread-entity-parent-invisible-p
            (wl-thread-get-entity number)))))
 
+(defvar wl-summary-window-scroll-functions nil)
+
+(defun wl-summary-update-mark-and-highlight-window (&optional win beg)
+  "A function to be called as window-scroll-functions."
+  (with-current-buffer (window-buffer win)
+    (when (eq major-mode 'wl-summary-mode)
+      (let ((start (window-start win))
+           (end (condition-case nil
+                    (window-end win t) ; old emacsen doesn't support 2nd arg.
+                  (error (window-end win))))
+           number flags
+           wl-summary-highlight)
+       (save-excursion
+         (goto-char beg)
+         (while (and (< (point) end) (not (eobp)))
+           (when (null (get-text-property (point) 'face))
+             (setq number (wl-summary-message-number)
+                   flags (elmo-message-flags wl-summary-buffer-elmo-folder
+                                             number))
+             (setq wl-summary-highlight nil)
+             (wl-summary-update-persistent-mark number flags)
+             (setq wl-summary-highlight t)
+             (wl-highlight-summary-current-line number flags))
+           (forward-line 1)))))))
+
+(defun wl-summary-window-scroll-functions ()
+  (or wl-summary-window-scroll-functions
+      (setq wl-summary-window-scroll-functions
+           (cond
+            ((and wl-summary-lazy-highlight
+                  wl-summary-lazy-update-mark)
+             (list 'wl-summary-update-mark-and-highlight-window))
+            (t
+             (append
+              (and wl-summary-lazy-highlight
+                   '(wl-highlight-summary-window))
+              (and wl-summary-lazy-update-mark
+                   '(wl-summary-update-mark-window))))))))
+
 (defun wl-status-update ()
   (interactive)
   (wl-address-init))
@@ -675,7 +717,7 @@ you."
       (insert
        (wl-summary-create-line
        (elmo-msgdb-make-message-entity
-        (luna-make-entity 'modb-generic)
+        (luna-make-entity 'modb-entity-handler)
         :number 10000
         :from "foo"
         :subject "bar"
@@ -780,13 +822,12 @@ Entering Folder mode calls the value of `wl-summary-mode-hook'."
        selective-display-ellipses nil)
   (wl-mode-line-buffer-identification '(wl-summary-buffer-mode-line))
   (easy-menu-add wl-summary-mode-menu)
-  (when wl-summary-lazy-highlight
-    (if wl-on-xemacs
-       (progn
-         (make-local-variable 'pre-idle-hook)
-         (add-hook 'pre-idle-hook 'wl-highlight-summary-window))
-      (make-local-variable 'window-scroll-functions)
-      (add-hook 'window-scroll-functions 'wl-highlight-summary-window)))
+  (when (wl-summary-window-scroll-functions)
+    (let ((variable (if wl-on-xemacs
+                       (make-local-variable 'pre-idle-hook)
+                     (make-local-variable 'window-scroll-functions))))
+      (dolist (function (wl-summary-window-scroll-functions))
+       (add-hook variable function))))
   ;; This hook may contain the function `wl-setup-summary' for reasons
   ;; of system internal to accord facilities for the Emacs variants.
   (run-hooks 'wl-summary-mode-hook))
@@ -812,10 +853,10 @@ Entering Folder mode calls the value of `wl-summary-mode-hook'."
   "Compare entity X and Y by from."
   (string<
    (wl-address-header-extract-address
-    (or (elmo-message-entity-field x 'from)
+    (or (elmo-message-entity-field x 'from t)
        wl-summary-no-from-message))
    (wl-address-header-extract-address
-    (or (elmo-message-entity-field y 'from)
+    (or (elmo-message-entity-field y 'from t)
        wl-summary-no-from-message))))
 
 (defun wl-summary-overview-entity-compare-by-subject (x y)
@@ -918,6 +959,7 @@ Entering Folder mode calls the value of `wl-summary-mode-hook'."
          wl-thread-entities nil
          wl-summary-scored nil
          wl-summary-buffer-number-list nil
+         wl-summary-buffer-unsync-mark-number-list nil
          wl-summary-buffer-target-mark-list nil
          wl-summary-buffer-temp-mark-list nil
          wl-summary-delayed-update nil)
@@ -1007,18 +1049,9 @@ Entering Folder mode calls the value of `wl-summary-mode-hook'."
       "folder mode"))
 
 (defun wl-summary-set-message-modified ()
-  (elmo-folder-set-message-modified
-   wl-summary-buffer-elmo-folder t)
-  (setq wl-summary-buffer-message-modified t)
-  (wl-summary-set-mark-modified))
+  (setq wl-summary-buffer-message-modified t))
 (defun wl-summary-message-modified-p ()
   wl-summary-buffer-message-modified)
-(defun wl-summary-set-mark-modified ()
-  (elmo-folder-set-flag-modified-internal
-   wl-summary-buffer-elmo-folder t))
-(defun wl-summary-mark-modified-p ()
-  (elmo-folder-flag-modified-internal
-   wl-summary-buffer-elmo-folder))
 (defun wl-summary-set-thread-modified ()
   (setq wl-summary-buffer-thread-modified t))
 (defun wl-summary-thread-modified-p ()
@@ -1045,7 +1078,6 @@ Entering Folder mode calls the value of `wl-summary-mode-hook'."
     ;; save the current summary buffer view.
     (if (and wl-summary-cache-use
             (or (wl-summary-message-modified-p)
-                (wl-summary-mark-modified-p)
                 (wl-summary-thread-modified-p)))
        (wl-summary-save-view-cache))))
 
@@ -1353,8 +1385,10 @@ If ARG is non-nil, checking is omitted."
                               ?\"
                               (or
                                (elmo-message-field
-                                wl-summary-buffer-elmo-folder
-                                number 'from)
+                                (elmo-message-entity
+                                 wl-summary-buffer-elmo-folder
+                                 number)
+                                'from t)
                                "??")))))) " ]")
                        size))))
              (message ""))             ; flush.
@@ -1627,21 +1661,35 @@ If ARG is non-nil, checking is omitted."
       ;;(message (concat deleting-info "done"))
       (wl-summary-count-unread)
       (wl-summary-update-modeline)
-      (wl-folder-set-folder-updated
-       (elmo-folder-name-internal wl-summary-buffer-elmo-folder)
-       (list 0
-            (+ wl-summary-buffer-unread-count wl-summary-buffer-new-count)
-            (elmo-folder-length wl-summary-buffer-elmo-folder))))))
+      (wl-summary-folder-info-update))))
 
-(defun wl-summary-update-status-marks ()
+(defun wl-summary-update-status-marks (beg end &optional check)
   "Synchronize status marks on current buffer to the msgdb."
-  (interactive)
+  (interactive "r")
   (save-excursion
-    (goto-char (point-min))
-    (while (not (eobp))
-      (wl-summary-update-persistent-mark)
+    (goto-char beg)
+    (while (and (< (point) end) (not (eobp)))
+      (when (or (not check)
+               (let ((number (wl-summary-message-number)))
+                 (when (memq number wl-summary-buffer-unsync-mark-number-list)
+                   (setq wl-summary-buffer-unsync-mark-number-list
+                         (delq number
+                               wl-summary-buffer-unsync-mark-number-list))
+                   t)))
+       (wl-summary-update-persistent-mark))
       (forward-line 1))))
 
+(defun wl-summary-update-mark-window (&optional win beg)
+  "Update persistent mark in visible summary window.
+This function is defined for `window-scroll-functions'"
+  (with-current-buffer (window-buffer win)
+    (when (eq major-mode 'wl-summary-mode)
+      (let ((start (window-start win))
+           (end (condition-case nil
+                    (window-end win t) ; old emacsen doesn't support 2nd arg.
+                  (error (window-end win)))))
+       (wl-summary-update-status-marks start end 'check)))))
+
 (defun wl-summary-insert-message (&rest args)
   (if (eq wl-summary-buffer-view 'thread)
       (apply 'wl-summary-insert-thread args)
@@ -1775,7 +1823,8 @@ If ARG is non-nil, checking is omitted."
 
                (when delete-list
                  (wl-summary-delete-messages-on-buffer delete-list))
-               (wl-summary-update-status-marks)
+               (unless wl-summary-lazy-update-mark
+                 (wl-summary-update-status-marks (point-min) (point-max)))
                (setq num (length append-list))
                (setq i 0)
                (setq wl-summary-delayed-update nil)
@@ -2078,6 +2127,7 @@ If ARG, without confirm."
                   wl-summary-buffer-message-modified
                   wl-summary-buffer-thread-modified
                   wl-summary-buffer-number-list
+                  wl-summary-buffer-unsync-mark-number-list
                   wl-summary-buffer-folder-name
                   wl-summary-buffer-line-formatter)
                 (and (eq wl-summary-buffer-view 'thread)
@@ -2240,6 +2290,8 @@ If ARG, without confirm."
            (wl-summary-update-modeline)))
       (unless (eq wl-summary-buffer-view 'thread)
        (wl-summary-make-number-list))
+      (setq wl-summary-buffer-unsync-mark-number-list
+           (copy-sequence wl-summary-buffer-number-list))
       (when (and wl-summary-cache-use
                 (or (and wl-summary-check-line-format
                          (wl-summary-line-format-changed-p))
@@ -2333,7 +2385,7 @@ If ARG, without confirm."
       ;; entity-id is unknown.
       (wl-folder-set-current-entity-id
        (wl-folder-get-entity-id entity)))
-    (when (and wl-summary-lazy-highlight
+    (when (and (wl-summary-window-scroll-functions)
               wl-on-xemacs)
       (sit-for 0))
     (unwind-protect
@@ -2418,7 +2470,7 @@ If ARG, without confirm."
                        wl-summary-alike-hashtb)))
 
 (defun wl-summary-insert-headers (folder func mime-decode)
-  (let ((numbers (elmo-folder-list-messages folder nil t))
+  (let ((numbers (elmo-folder-list-messages folder 'visible t))
        ov this last alike)
     (buffer-disable-undo (current-buffer))
     (make-local-variable 'wl-summary-alike-hashtb)
@@ -2677,9 +2729,9 @@ If ARG, exit virtual folder."
       (setq wl-summary-buffer-target-mark-list nil)
       (setq wl-summary-buffer-temp-mark-list nil))))
 
-(defsubst wl-summary-temp-mark ()
+(defsubst wl-summary-temp-mark (&optional number)
   "Return temp-mark string of current line."
-  (let ((number (wl-summary-message-number))
+  (let ((number (or number (wl-summary-message-number)))
        info)
     (or (and (wl-summary-have-target-mark-p number)
             "*")
@@ -2715,18 +2767,20 @@ The mark is decided according to the FOLDER, FLAGS and CACHED."
            nil
          wl-summary-read-uncached-mark))))
 
-(defsubst wl-summary-message-mark (folder number)
+(defsubst wl-summary-message-mark (folder number &optional flags)
   "Return mark of the message."
   (ignore-errors
     (wl-summary-persistent-mark-string
      folder
-     (elmo-message-flags folder number)
-     (elmo-message-cached-p folder number))))
+     (or flags (setq flags (elmo-message-flags folder number)))
+     (memq 'cached flags) ; XXX for speed-up.
+     )))
 
-(defsubst wl-summary-persistent-mark ()
+(defsubst wl-summary-persistent-mark (&optional number flags)
   "Return persistent-mark string of current line."
   (or (wl-summary-message-mark wl-summary-buffer-elmo-folder
-                              (wl-summary-message-number))
+                              (or number (wl-summary-message-number))
+                              flags)
       " "))
 
 (defun wl-summary-put-temp-mark (mark)
@@ -2814,23 +2868,22 @@ The mark is decided according to the FOLDER, FLAGS and CACHED."
   (interactive)
   (wl-summary-pick wl-summary-buffer-target-mark-list 'delete))
 
-(defun wl-summary-update-persistent-mark ()
+(defun wl-summary-update-persistent-mark (&optional number flags)
   "Synch up persistent mark of current line with msgdb's.
 Return non-nil if the mark is updated"
-  (if wl-summary-buffer-persistent-mark-column
-      (save-excursion
-       (move-to-column wl-summary-buffer-persistent-mark-column)
-       (let ((inhibit-read-only t)
-             (buffer-read-only nil)
-             (mark (buffer-substring (- (point) 1) (point)))
-             (new-mark (wl-summary-persistent-mark)))
-         (unless (string= new-mark mark)
-           (delete-backward-char 1)
-           (insert new-mark))
-         (when wl-summary-highlight
-           (wl-highlight-summary-current-line))
-         (set-buffer-modified-p nil)
-         t))
+  (prog1
+      (when wl-summary-buffer-persistent-mark-column
+       (save-excursion
+         (move-to-column wl-summary-buffer-persistent-mark-column)
+         (let ((inhibit-read-only t)
+               (buffer-read-only nil)
+               (mark (buffer-substring (- (point) 1) (point)))
+               (new-mark (wl-summary-persistent-mark number flags)))
+           (unless (string= new-mark mark)
+             (delete-backward-char 1)
+             (insert new-mark)
+             (wl-summary-set-message-modified)
+             t))))
     (when wl-summary-highlight
       (wl-highlight-summary-current-line))
     (set-buffer-modified-p nil)))
@@ -3261,45 +3314,46 @@ Return non-nil if the mark is updated"
           (tmp-buffer (get-buffer-create " *wl-summary-save-view-cache*"))
           (temp-column wl-summary-buffer-temp-mark-column)
           (charset wl-summary-buffer-mime-charset))
-      (if (file-directory-p dir)
-         (); ok.
-       (if (file-exists-p dir)
-           (error "File %s already exists" dir)
-         (elmo-make-directory dir)))
-      (if (eq save-view 'thread)
-         (wl-thread-save-entity dir))
-      (when wl-summary-check-line-format
-       (wl-summary-line-format-save))
-      (unwind-protect
-         (progn
-           (when (file-writable-p cache)
-             (copy-to-buffer tmp-buffer (point-min) (point-max))
-             (with-current-buffer tmp-buffer
-               (widen)
-               (make-local-variable 'wl-summary-highlight)
-               (setq wl-summary-highlight nil
-                     wl-summary-buffer-target-mark-list mark-list
-                     wl-summary-buffer-temp-mark-list temp-list
-                     wl-summary-buffer-temp-mark-column temp-column)
-               (wl-summary-delete-all-temp-marks 'no-msg 'force)
-               (encode-coding-region
-                (point-min) (point-max)
-                (or (and wl-on-mule
-                         ;; one in mcs-ltn1(apel<10.4) cannot take 2 arg.
-                         (mime-charset-to-coding-system charset 'LF))
-                    ;; Mule 2 doesn't have `*ctext*unix'.
-                    (mime-charset-to-coding-system charset)))
-               (write-region-as-binary (point-min)(point-max)
-                                       cache nil 'no-msg)))
-           (when (file-writable-p view) ; 'thread or 'sequence
-             (save-excursion
-               (set-buffer tmp-buffer)
-               (erase-buffer)
-               (prin1 save-view tmp-buffer)
-               (princ "\n" tmp-buffer)
-               (write-region (point-min) (point-max) view nil 'no-msg))))
-       ;; kill tmp buffer.
-       (kill-buffer tmp-buffer)))))
+      (when dir
+       (if (file-directory-p dir)
+           (); ok.
+         (if (file-exists-p dir)
+             (error "File %s already exists" dir)
+           (elmo-make-directory dir)))
+       (if (eq save-view 'thread)
+           (wl-thread-save-entity dir))
+       (when wl-summary-check-line-format
+         (wl-summary-line-format-save))
+       (unwind-protect
+           (progn
+             (when (file-writable-p cache)
+               (copy-to-buffer tmp-buffer (point-min) (point-max))
+               (with-current-buffer tmp-buffer
+                 (widen)
+                 (make-local-variable 'wl-summary-highlight)
+                 (setq wl-summary-highlight nil
+                       wl-summary-buffer-target-mark-list mark-list
+                       wl-summary-buffer-temp-mark-list temp-list
+                       wl-summary-buffer-temp-mark-column temp-column)
+                 (wl-summary-delete-all-temp-marks 'no-msg 'force)
+                 (encode-coding-region
+                  (point-min) (point-max)
+                  (or (and wl-on-mule
+                           ;; one in mcs-ltn1(apel<10.4) cannot take 2 arg.
+                           (mime-charset-to-coding-system charset 'LF))
+                      ;; Mule 2 doesn't have `*ctext*unix'.
+                      (mime-charset-to-coding-system charset)))
+                 (write-region-as-binary (point-min)(point-max)
+                                         cache nil 'no-msg)))
+             (when (file-writable-p view) ; 'thread or 'sequence
+               (save-excursion
+                 (set-buffer tmp-buffer)
+                 (erase-buffer)
+                 (prin1 save-view tmp-buffer)
+                 (princ "\n" tmp-buffer)
+                 (write-region (point-min) (point-max) view nil 'no-msg))))
+         ;; kill tmp buffer.
+         (kill-buffer tmp-buffer))))))
 
 (defsubst wl-summary-get-sync-range (folder)
   (intern (or (and
@@ -4412,11 +4466,11 @@ If ASK-CODING is non-nil, coding-system for the message is asked."
                              (wl-summary-message-number))))
                   (wl-ps-subject
                    (and entity
-                        (or (elmo-message-entity-field entity 'subject)
+                        (or (elmo-message-entity-field entity 'subject t)
                             "")))
                   (wl-ps-from
                    (and entity
-                        (or (elmo-message-entity-field entity 'from) "")))
+                        (or (elmo-message-entity-field entity 'from t) "")))
                   (wl-ps-date
                    (and entity
                         (or (elmo-message-entity-field entity 'date) ""))))