(wl-message-overload-functions): Do nothing if `current-local-map' is not
[elisp/wanderlust.git] / wl / wl-xmas.el
1 ;;; wl-xmas.el -- Wanderlust modules for XEmacsen.
2
3 ;; Copyright 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
4
5 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
6 ;; Keywords: mail, net news
7
8 ;; This file is part of Wanderlust (Yet Another Message Interface on Emacsen).
9
10 ;; This program is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14 ;;
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;; GNU General Public License for more details.
19 ;;
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24 ;;
25
26 ;;; Commentary:
27 ;;
28
29 ;;; Code:
30 ;;
31
32 (eval-when-compile
33   (require 'wl-folder)
34   (require 'wl-summary)
35   (require 'wl-draft)
36   (require 'wl-message)
37   (require 'wl-highlight)
38   (defvar-maybe wl-draft-mode-map (make-sparse-keymap))
39   (defalias-maybe 'toolbar-make-button-list 'ignore))
40
41 (add-hook 'wl-folder-mode-hook 'wl-setup-folder)
42 (add-hook 'wl-folder-mode-hook 'wl-folder-init-icons)
43
44 (add-hook 'wl-make-plugged-hook 'wl-biff-init-icons)
45 (add-hook 'wl-make-plugged-hook 'wl-plugged-init-icons)
46
47 (add-hook 'wl-summary-mode-hook 'wl-setup-summary)
48
49 (defvar wl-use-toolbar (if (featurep 'toolbar) 'default-toolbar nil))
50 (defvar wl-plugged-glyph nil)
51 (defvar wl-unplugged-glyph nil)
52 (defvar wl-biff-mail-glyph nil)
53 (defvar wl-biff-nomail-glyph nil)
54
55 (defvar wl-folder-toolbar
56   '([wl-folder-jump-to-current-entity
57      wl-folder-jump-to-current-entity t "Enter Current Folder"]
58     [wl-folder-next-entity
59      wl-folder-next-entity t "Next Folder"]
60     [wl-folder-prev-entity
61      wl-folder-prev-entity t "Previous Folder"]
62     [wl-folder-check-current-entity
63      wl-folder-check-current-entity t "Check Current Folder"]
64 ;;; [wl-draft
65 ;;;  wl-draft t "Write a New Message"]
66     [wl-folder-sync-current-entity
67      wl-folder-sync-current-entity t "Sync Current Folder"]
68     [wl-draft
69      wl-draft t "Write a New Message"]
70     [wl-folder-empty-trash
71      wl-folder-empty-trash t "Empty Trash"]
72     [wl-exit
73      wl-exit t "Quit Wanderlust"]
74     )
75   "The Folder buffer toolbar.")
76
77 (defvar wl-summary-toolbar
78   '([wl-summary-read
79      wl-summary-read t "Read Messages"]
80     [wl-summary-next
81      wl-summary-next t "Next Message"]
82     [wl-summary-prev
83      wl-summary-prev t "Previous Message"]
84     [wl-summary-jump-to-current-message
85      wl-summary-jump-to-current-message t "Jump to Current Message"]
86     [wl-summary-sync-force-update
87      wl-summary-sync-force-update t "Sync Current Folder"]
88     [wl-summary-delete
89      wl-summary-delete t "Delete Current Message"]
90     [wl-summary-mark-as-important
91      wl-summary-mark-as-important t "Mark Current Message as Important"]
92     [wl-draft
93      wl-draft t "Write a New Message"]
94     [wl-summary-reply
95      wl-summary-reply t "Reply to Current Message" ]
96     [wl-summary-reply-with-citation
97      wl-summary-reply-with-citation t "Reply to Current Message with Citation"]
98     [wl-summary-forward
99      wl-summary-forward t "Forward Current Message"]
100     [wl-summary-exit
101      wl-summary-exit t "Exit Current Summary"]
102     )
103   "The Summary buffer toolbar.")
104
105 (defvar wl-message-toolbar
106   '([wl-message-read
107      wl-message-read t "Read Contents"]
108     [wl-message-next-content
109      wl-message-next-content t "Next Content"]
110     [wl-message-prev-content
111      wl-message-prev-content t "Previous Content"]
112     [wl-message-quit
113      wl-message-quit t "Back to Summary"]
114     [wl-message-play-content
115      wl-message-play-content t "Play Content"]
116     [wl-message-extract-content
117      wl-message-extract-content t "Extract Content"]
118     )
119   "The Message buffer toolbar.")
120
121 (defalias 'wl-draft-insert-signature 'insert-signature);; for draft toolbar.
122
123 (defvar wl-draft-toolbar
124   '([wl-draft-send-from-toolbar
125      wl-draft-send-from-toolbar t "Send Current Draft"]
126     [wl-draft-yank-original
127      wl-draft-yank-original t "Yank Displaying Message"]
128     [wl-draft-insert-signature
129      wl-draft-insert-signature t "Insert Signature"]
130     [wl-draft-kill
131      wl-draft-kill t "Kill Current Draft"]
132     )
133   "The Draft buffer toolbar.")
134
135 (defun wl-xmas-setup-toolbar (bar)
136   (let ((dir wl-icon-dir)
137         icon up down disabled name)
138     (when dir
139       (while bar
140         (setq icon (aref (car bar) 0)
141               name (symbol-name icon)
142               bar (cdr bar))
143         (unless (boundp icon)
144           (setq up (expand-file-name (concat name "-up.xpm") dir)
145                 down (expand-file-name (concat name "-down.xpm") dir)
146                 disabled (expand-file-name (concat name "-disabled.xpm") dir))
147           (if (file-exists-p up)
148               (set icon (toolbar-make-button-list
149                          up (and (file-exists-p down) down)
150                          (and (file-exists-p disabled) disabled)))
151             (setq bar nil
152                   dir nil)))))
153     dir))
154
155 (defun wl-xmas-make-icon-glyph (icon-string icon-file
156                                             &optional locale tag-set)
157   (let ((glyph (make-glyph (vector 'string :data icon-string))))
158     (when wl-highlight-folder-with-icon
159       (set-glyph-image glyph
160                        (vector 'xpm :file (expand-file-name
161                                            icon-file wl-icon-dir))
162                        locale tag-set 'prepend))
163     glyph))
164
165 (eval-when-compile
166   (defsubst wl-xmas-setup-folder-toolbar ()
167     (and wl-use-toolbar
168          (wl-xmas-setup-toolbar wl-folder-toolbar)
169          (set-specifier (symbol-value wl-use-toolbar)
170                         (cons (current-buffer) wl-folder-toolbar))))
171
172   (defsubst wl-xmas-setup-summary-toolbar ()
173     (and wl-use-toolbar
174          (wl-xmas-setup-toolbar wl-summary-toolbar)
175          (set-specifier (symbol-value wl-use-toolbar)
176                         (cons (current-buffer) wl-summary-toolbar))))
177
178   (defsubst wl-xmas-setup-message-toolbar ()
179     (and wl-use-toolbar
180          (wl-xmas-setup-toolbar wl-message-toolbar)
181          (set-specifier (symbol-value wl-use-toolbar)
182                         (cons (current-buffer) wl-message-toolbar))))
183
184   (defsubst wl-xmas-setup-draft-toolbar ()
185     (and wl-use-toolbar
186          (wl-xmas-setup-toolbar wl-draft-toolbar)
187          (set-specifier (symbol-value wl-use-toolbar)
188                         (cons (current-buffer) wl-draft-toolbar)))))
189
190 (defvar wl-folder-toggle-icon-list
191   '((wl-folder-opened-glyph       . wl-opened-group-folder-icon)
192     (wl-folder-closed-glyph       . wl-closed-group-folder-icon)))
193
194 (eval-when-compile
195   (defsubst wl-xmas-highlight-folder-group-line (glyph text-face numbers)
196     (let ((start (match-beginning 1))
197           (end (match-end 1)))
198       (let (extent)
199         (while (and (setq extent (extent-at start nil nil extent 'at))
200                     (not (and (eq start (extent-start-position extent))
201                               (eq end (extent-end-position extent))
202                               (extent-end-glyph extent)))))
203         (unless extent
204           (setq extent (make-extent start end)))
205         (set-extent-properties extent `(end-open t start-closed t invisible t))
206         (set-extent-end-glyph
207          extent
208          (or (get glyph 'glyph)
209              (put glyph 'glyph
210                   (wl-xmas-make-icon-glyph
211                    (buffer-substring-no-properties start end)
212                    (symbol-value
213                     (cdr (assq glyph wl-folder-toggle-icon-list))))))))
214       (let ((inhibit-read-only t))
215         (when wl-use-highlight-mouse-line
216           (put-text-property start (point-at-eol) 'mouse-face 'highlight))
217         (setq start end
218               end (point-at-eol))
219         (if (and wl-highlight-folder-by-numbers
220                  numbers (nth 0 numbers) (nth 1 numbers)
221                  (re-search-forward "[0-9-]+/[0-9-]+/[0-9-]+" end t))
222             (let* ((unsync (nth 0 numbers))
223                    (unread (nth 1 numbers))
224                    (face (cond ((and unsync (zerop unsync))
225                                 (if (and unread (zerop unread))
226                                     'wl-highlight-folder-zero-face
227                                   'wl-highlight-folder-unread-face))
228                                ((and unsync
229                                      (>= unsync
230                                          wl-folder-many-unsync-threshold))
231                                 'wl-highlight-folder-many-face)
232                                (t
233                                 'wl-highlight-folder-few-face))))
234               (if (numberp wl-highlight-folder-by-numbers)
235                   (progn
236                     (put-text-property start (match-beginning 0)
237                                        'face text-face)
238                     (put-text-property (match-beginning 0) (point) 'face face))
239                 (put-text-property start end 'face face)))
240           (put-text-property start end 'face text-face))))))
241
242 (defun wl-highlight-folder-current-line (&optional numbers)
243   (interactive)
244   (save-excursion
245     (beginning-of-line)
246     (let (fld-name)
247       (cond
248        (;; opened folder group
249         (looking-at wl-highlight-folder-opened-regexp)
250         (wl-xmas-highlight-folder-group-line 'wl-folder-opened-glyph
251                                              'wl-highlight-folder-opened-face
252                                              numbers))
253        (;; closed folder group
254         (looking-at wl-highlight-folder-closed-regexp)
255         (wl-xmas-highlight-folder-group-line 'wl-folder-closed-glyph
256                                              'wl-highlight-folder-closed-face
257                                              numbers))
258        (;; basic folder
259         (and (setq fld-name (wl-folder-get-folder-name-by-id
260                              (get-text-property (point) 'wl-folder-entity-id)))
261              (looking-at "[ \t]+\\([^ \t]+\\)"))
262         (let ((start (match-beginning 1)))
263           (let (extent)
264             (while (and (setq extent (extent-at start nil nil extent 'at))
265                         (not (and (eq start (extent-start-position extent))
266                                   (eq start (extent-end-position extent))
267                                   (extent-begin-glyph extent)))))
268             (unless extent
269               (setq extent (make-extent start start)))
270             (let (type)
271               (set-extent-begin-glyph
272                extent
273                (cond
274                 ((string= fld-name wl-trash-folder);; trash folder
275                  (let ((num (nth 2 numbers)));; number of messages
276                    (get (if (or (not num) (zerop num))
277                             'wl-folder-trash-empty-glyph
278                           'wl-folder-trash-glyph)
279                         'glyph)))
280                 ((string= fld-name wl-draft-folder);; draft folder
281                  (get 'wl-folder-draft-glyph 'glyph))
282                 ((string= fld-name wl-queue-folder);; queue folder
283                  (get 'wl-folder-queue-glyph 'glyph))
284                 (;; and one of many other folders
285                  (setq type (elmo-folder-get-type fld-name))
286                  (get (intern (format "wl-folder-%s-glyph" type)) 'glyph))))))
287           (let ((end (point-at-eol)))
288             (when wl-use-highlight-mouse-line
289               (put-text-property start end 'mouse-face 'highlight))
290             (let ((text-face
291                    (if (looking-at (format "^[ \t]*\\(%s\\|%s\\)"
292                                            wl-folder-unsubscribe-mark
293                                            wl-folder-removed-mark))
294                        'wl-highlight-folder-killed-face
295                      'wl-highlight-folder-unknown-face)))
296               (if (and wl-highlight-folder-by-numbers
297                        numbers (nth 0 numbers) (nth 1 numbers)
298                        (re-search-forward "[0-9-]+/[0-9-]+/[0-9-]+" end t))
299                   (let* ((unsync (nth 0 numbers))
300                          (unread (nth 1 numbers))
301                          (face (cond
302                                 ((and unsync (zerop unsync))
303                                  (if (and unread (zerop unread))
304                                      'wl-highlight-folder-zero-face
305                                    'wl-highlight-folder-unread-face))
306                                 ((and unsync
307                                       (>= unsync
308                                           wl-folder-many-unsync-threshold))
309                                  'wl-highlight-folder-many-face)
310                                 (t
311                                  'wl-highlight-folder-few-face))))
312                     (if (numberp wl-highlight-folder-by-numbers)
313                         (progn
314                           (put-text-property start (match-beginning 0)
315                                              'face text-face)
316                           (put-text-property (match-beginning 0)
317                                              (match-end 0)
318                                              'face face))
319                       ;; Remove previous face.
320                       (put-text-property start (match-end 0) 'face nil)
321                       (put-text-property start (match-end 0) 'face face)))
322                 (put-text-property start end 'face text-face))))))))))
323
324 (defun wl-highlight-plugged-current-line ()
325   (interactive)
326   (save-excursion
327     (let ((inhibit-read-only t)
328           extent switch)
329       (beginning-of-line)
330       (when (looking-at "[ \t]*\\(\\[\\([^]]+\\)\\]\\)")
331         (setq switch (elmo-match-buffer 2))
332         (when (and (setq extent (extent-at (match-end 1) nil nil nil 'at))
333                    (extent-end-glyph extent))
334           (delete-extent extent))
335         (setq extent (make-extent (match-beginning 1) (match-end 1)))
336         (set-extent-property extent 'end-open t)
337         (set-extent-property extent 'start-closed t)
338         (set-extent-property extent 'invisible t)
339         (set-extent-end-glyph extent (if (string= switch wl-plugged-plug-on)
340                                          wl-plugged-glyph
341                                        wl-unplugged-glyph))))))
342
343 (defun wl-plugged-set-folder-icon (folder string)
344   (let ((string (copy-sequence string))
345         (len (length string))
346         type)
347     (if (string= folder wl-queue-folder)
348         (put-text-property 0 len 'begin-glyph
349                            (get 'wl-folder-queue-glyph 'glyph)
350                            string)
351       (if (setq type (elmo-folder-get-type folder))
352           (put-text-property 0 len
353                              'begin-glyph
354                              (get (intern (format "wl-folder-%s-glyph" type))
355                                   'glyph)
356                              string)))
357     string))
358
359 (defvar wl-folder-internal-icon-list
360   ;; alist of (glyph . icon-file)
361   '((wl-folder-nntp-glyph         . wl-nntp-folder-icon)
362     (wl-folder-imap4-glyph        . wl-imap-folder-icon)
363     (wl-folder-pop3-glyph         . wl-pop-folder-icon)
364     (wl-folder-localdir-glyph     . wl-localdir-folder-icon)
365     (wl-folder-localnews-glyph    . wl-localnews-folder-icon)
366     (wl-folder-internal-glyph     . wl-internal-folder-icon)
367     (wl-folder-multi-glyph        . wl-multi-folder-icon)
368     (wl-folder-filter-glyph       . wl-filter-folder-icon)
369     (wl-folder-archive-glyph      . wl-archive-folder-icon)
370     (wl-folder-pipe-glyph         . wl-pipe-folder-icon)
371     (wl-folder-maildir-glyph      . wl-maildir-folder-icon)
372     (wl-folder-trash-empty-glyph  . wl-empty-trash-folder-icon)
373     (wl-folder-draft-glyph        . wl-draft-folder-icon)
374     (wl-folder-queue-glyph        . wl-queue-folder-icon)
375     (wl-folder-trash-glyph        . wl-trash-folder-icon)))
376
377 (defun wl-folder-init-icons ()
378   (dolist (icon wl-folder-internal-icon-list)
379     (unless (get (car icon) 'glyph)
380       (put (car icon) 'glyph
381            (wl-xmas-make-icon-glyph "" (symbol-value (cdr icon)))))))
382
383 (defun wl-plugged-init-icons ()
384   (unless wl-plugged-glyph
385     (setq wl-plugged-glyph (wl-xmas-make-icon-glyph
386                             wl-plug-state-indicator-on wl-plugged-icon)
387           wl-unplugged-glyph (wl-xmas-make-icon-glyph
388                               wl-plug-state-indicator-off wl-unplugged-icon))
389     (let ((extent (make-extent nil nil)))
390       (let ((keymap (make-sparse-keymap)))
391         (define-key keymap 'button2
392           (make-modeline-command-wrapper 'wl-toggle-plugged))
393         (set-extent-keymap extent keymap)
394         (set-extent-property extent 'help-echo
395                              "button2 toggles plugged status"))
396       (setq wl-modeline-plug-state-on (cons extent wl-plugged-glyph)
397             wl-modeline-plug-state-off (cons extent wl-unplugged-glyph)))))
398
399 (defun wl-biff-init-icons ()
400   (unless wl-biff-mail-glyph
401     (setq wl-biff-mail-glyph (wl-xmas-make-icon-glyph
402                               wl-biff-state-indicator-on
403                               wl-biff-mail-icon)
404           wl-biff-nomail-glyph (wl-xmas-make-icon-glyph
405                                 wl-biff-state-indicator-off
406                                 wl-biff-nomail-icon))
407     (let ((extent (make-extent nil nil)))
408       (let ((keymap (make-sparse-keymap)))
409         (define-key keymap 'button2
410           (make-modeline-command-wrapper 'wl-biff-check-folders))
411         (set-extent-keymap extent keymap)
412         (set-extent-property extent 'help-echo "button2 checks new mails"))
413       (setq wl-modeline-biff-state-on (cons extent wl-biff-mail-glyph)
414             wl-modeline-biff-state-off (cons extent wl-biff-nomail-glyph)))))
415
416 (defun wl-make-date-string ()
417   (let ((s (current-time-string)))
418     (string-match "\\`\\([A-Z][a-z][a-z]\\) +[A-Z][a-z][a-z] +[0-9][0-9]? *[0-9][0-9]?:[0-9][0-9]:[0-9][0-9] *[0-9]?[0-9]?[0-9][0-9]"
419                   s)
420     (concat (wl-match-string 1 s) ", "
421             (timezone-make-date-arpa-standard s (current-time-zone)))))
422
423 (defun wl-setup-folder ()
424   (and (featurep 'scrollbar)
425        (set-specifier scrollbar-height (cons (current-buffer) 0)))
426   (wl-xmas-setup-folder-toolbar))
427
428 (defvar dragdrop-drop-functions)
429
430 (defun wl-setup-summary ()
431   (make-local-variable 'dragdrop-drop-functions)
432   (setq dragdrop-drop-functions '((wl-dnd-default-drop-message t t)))
433   (and (featurep 'scrollbar)
434        (set-specifier scrollbar-height (cons (current-buffer) 0)))
435   (wl-xmas-setup-summary-toolbar))
436
437 (defun wl-message-overload-functions ()
438   (wl-xmas-setup-message-toolbar)
439   (local-set-key "l" 'wl-message-toggle-disp-summary)
440   (local-set-key 'button2 'wl-message-refer-article-or-url)
441   (local-set-key 'button4 'wl-message-wheel-down)
442   (local-set-key 'button5 'wl-message-wheel-up)
443   (local-set-key [(shift button4)] 'wl-message-wheel-down)
444   (local-set-key [(shift button5)] 'wl-message-wheel-up)
445   (set-keymap-parent wl-message-button-map (current-local-map))
446   (define-key wl-message-button-map 'button2
447     'wl-message-button-dispatcher))
448
449 (defun wl-message-wheel-up (event)
450   (interactive "e")
451   (let ((cur-buf (current-buffer))
452         proceed)
453     (save-selected-window
454       (select-window (event-window event))
455       (set-buffer cur-buf)
456       (setq proceed (wl-message-next-page)))
457     (when proceed
458       (if (memq 'shift (event-modifiers event))
459           (wl-summary-down t)
460         (wl-summary-next t)))))
461
462 (defun wl-message-wheel-down (event)
463   (interactive "e")
464   (let ((cur-buf (current-buffer))
465         proceed)
466     (save-selected-window
467       (select-window (event-window event))
468       (set-buffer cur-buf)
469       (setq proceed (wl-message-prev-page)))
470     (when proceed
471       (if (memq 'shift (event-modifiers event))
472           (wl-summary-up t)
473         (wl-summary-prev t)))))
474
475 (defun wl-draft-overload-menubar ()
476   (when (featurep 'menubar)
477     (add-menu-item '("Mail") "Send, Keep Editing"
478                    'wl-draft-send t "Send Mail")
479     (add-menu-item '("Mail") "Send Message"
480                    'wl-draft-send-and-exit t "Send and Exit")
481     (delete-menu-item '("Mail" "Send Mail"))
482     (delete-menu-item '("Mail" "Send and Exit"))))
483
484 (defun wl-draft-mode-setup ()
485   (require 'derived)
486   (define-derived-mode wl-draft-mode mail-mode "Draft"
487     "draft mode for Wanderlust derived from mail mode.
488 See info under Wanderlust for full documentation.
489
490 Special commands:
491 \\{wl-draft-mode-map}"))
492
493 (defun wl-draft-key-setup ()
494   (define-key wl-draft-mode-map "\C-c\C-y" 'wl-draft-yank-original)
495   (define-key wl-draft-mode-map "\C-c\C-s" 'wl-draft-send)
496   (define-key wl-draft-mode-map "\C-c\C-a" 'wl-draft-insert-x-face-field)
497   (define-key wl-draft-mode-map "\C-c\C-c" 'wl-draft-send-and-exit)
498   (define-key wl-draft-mode-map "\C-c\C-z" 'wl-draft-save-and-exit)
499   (define-key wl-draft-mode-map "\C-c\C-k" 'wl-draft-kill)
500   (define-key wl-draft-mode-map "\C-l" 'wl-draft-highlight-and-recenter)
501   (define-key wl-draft-mode-map "\C-i" 'wl-complete-field-body-or-tab)
502   (define-key wl-draft-mode-map "\C-c\C-r" 'wl-draft-caesar-region)
503   (define-key wl-draft-mode-map "\M-t" 'wl-toggle-plugged)
504   (define-key wl-draft-mode-map "\C-c\C-o" 'wl-jump-to-draft-buffer)
505   (define-key wl-draft-mode-map "\C-c\C-e" 'wl-draft-config-exec)
506   (define-key wl-draft-mode-map "\C-c\C-j" 'wl-template-select)
507   (define-key wl-draft-mode-map "\C-c\C-p" 'wl-draft-preview-message)
508   (define-key wl-draft-mode-map "\C-x\C-s" 'wl-draft-save)
509   (define-key wl-draft-mode-map "\C-xk"    'wl-draft-mimic-kill-buffer))
510
511 (defun wl-draft-overload-functions ()
512   (wl-mode-line-buffer-identification)
513   (local-set-key "\C-c\C-s" 'wl-draft-send);; override
514   (wl-xmas-setup-draft-toolbar)
515   (wl-draft-overload-menubar))
516
517 (defalias 'wl-defface 'defface)
518
519 (require 'product)
520 (product-provide (provide 'wl-xmas) (require 'wl-version))
521
522 ;;; wl-xmas.el ends here