Add 2012 to FSF copyright years for Emacs files (do not merge to trunk)
[emacs.git] / lisp / mh-e / mh-tool-bar.el
blobfa285de23a8cef43666122598aa583d49d483b18
1 ;;; mh-tool-bar.el --- MH-E tool bar support
3 ;; Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 ;; Free Software Foundation, Inc.
6 ;; Author: Satyaki Das <satyaki@theforce.stanford.edu>
7 ;; Maintainer: Bill Wohler <wohler@newt.com>
8 ;; Keywords: mail
9 ;; See: mh-e.el
11 ;; This file is part of GNU Emacs.
13 ;; GNU Emacs is free software: you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation, either version 3 of the License, or
16 ;; (at your option) any later version.
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
26 ;;; Commentary:
28 ;;; Change Log:
30 ;;; Code:
32 (require 'mh-e)
33 (mh-do-in-gnu-emacs
34 (require 'tool-bar))
35 (mh-do-in-xemacs
36 (require 'toolbar))
38 ;;; Tool Bar Commands
40 (defun mh-tool-bar-search (&optional arg)
41 "Interactively call `mh-tool-bar-search-function'.
42 Optional argument ARG is not used."
43 (interactive "P")
44 (call-interactively mh-tool-bar-search-function))
46 (defun mh-tool-bar-customize ()
47 "Call `mh-customize' from the tool bar."
48 (interactive)
49 (mh-customize t))
51 (defun mh-tool-bar-folder-help ()
52 "Visit \"(mh-e)Top\"."
53 (interactive)
54 (info "(mh-e)Top")
55 (delete-other-windows))
57 (defun mh-tool-bar-letter-help ()
58 "Visit \"(mh-e)Editing Drafts\"."
59 (interactive)
60 (info "(mh-e)Editing Drafts")
61 (delete-other-windows))
63 (defmacro mh-tool-bar-reply-generator (function recipient folder-buffer-flag)
64 "Generate FUNCTION that replies to RECIPIENT.
65 If FOLDER-BUFFER-FLAG is nil then the function generated...
66 When INCLUDE-FLAG is non-nil, include message body being replied to."
67 `(defun ,function (&optional arg)
68 ,(format "Reply to \"%s\".\nWhen ARG is non-nil include message in reply."
69 recipient)
70 (interactive "P")
71 ,(if folder-buffer-flag nil '(set-buffer mh-show-folder-buffer))
72 (mh-reply (mh-get-msg-num nil) ,recipient arg)))
74 (mh-tool-bar-reply-generator mh-tool-bar-reply-from "from" t)
75 (mh-tool-bar-reply-generator mh-show-tool-bar-reply-from "from" nil)
76 (mh-tool-bar-reply-generator mh-tool-bar-reply-to "to" t)
77 (mh-tool-bar-reply-generator mh-show-tool-bar-reply-to "to" nil)
78 (mh-tool-bar-reply-generator mh-tool-bar-reply-all "all" t)
79 (mh-tool-bar-reply-generator mh-show-tool-bar-reply-all "all" nil)
83 ;;; Tool Bar Creation
85 ;; Shush compiler.
86 (defvar image-load-path)
88 (defmacro mh-tool-bar-define (defaults &rest buttons)
89 "Define a tool bar for MH-E.
90 DEFAULTS is the list of buttons that are present by default. It
91 is a list of lists where the sublists are of the following form:
93 (:KEYWORD FUNC1 FUNC2 FUNC3 ...)
95 Here :KEYWORD is one of :folder or :letter. If it is :folder then
96 the default buttons in the folder and show mode buffers are being
97 specified. If it is :letter then the default buttons in the
98 letter mode are listed. FUNC1, FUNC2, FUNC3, ... are the names of
99 the functions that the buttons would execute.
101 Each element of BUTTONS is a list consisting of four mandatory
102 items and one optional item as follows:
104 (FUNCTION MODES ICON DOC &optional ENABLE-EXPR)
106 where,
108 FUNCTION is the name of the function that will be executed when
109 the button is clicked.
111 MODES is a list of symbols. List elements must be from \"folder\",
112 \"letter\" and \"sequence\". If \"folder\" is present then the button is
113 available in the folder and show buffer. If the name of FUNCTION is
114 of the form \"mh-foo\", where foo is some arbitrary string, then we
115 check if the function `mh-show-foo' exists. If it exists then that
116 function is used in the show buffer. Otherwise the original function
117 `mh-foo' is used in the show buffer as well. Presence of \"sequence\"
118 is handled similar to the above. The only difference is that the
119 button is shown only when the folder is narrowed to a sequence. If
120 \"letter\" is present in MODES, then the button is available during
121 draft editing and runs FUNCTION when clicked.
123 ICON is the icon that is drawn in the button.
125 DOC is the documentation for the button. It is used in tool-tips and
126 in providing other help to the user. GNU Emacs uses only the first
127 line of the string. So the DOC should be formatted such that the
128 first line is useful and complete without the rest of the string.
130 Optional item ENABLE-EXPR is an arbitrary lisp expression. If it
131 evaluates to nil, then the button is deactivated, otherwise it is
132 active. If it isn't present then the button is always active."
133 ;; The following variable names have been carefully chosen to make code
134 ;; generation easier. Modifying the names should be done carefully.
135 (let (folder-buttons folder-docs folder-button-setter sequence-button-setter
136 show-buttons show-button-setter show-seq-button-setter
137 letter-buttons letter-docs letter-button-setter
138 folder-defaults letter-defaults
139 folder-vectors show-vectors letter-vectors)
140 (dolist (x defaults)
141 (cond ((eq (car x) :folder) (setq folder-defaults (cdr x)))
142 ((eq (car x) :letter) (setq letter-defaults (cdr x)))))
143 (dolist (button buttons)
144 (unless (and (listp button)
145 (or (equal (length button) 4) (equal (length button) 5)))
146 (error "Incorrect MH-E tool-bar button specification: %s" button))
147 (let* ((name (nth 0 button))
148 (name-str (symbol-name name))
149 (icon (nth 2 button))
150 (xemacs-icon (mh-do-in-xemacs
151 `(cdr (assoc (quote ,(intern icon)) mh-xemacs-icon-map))))
152 (full-doc (nth 3 button))
153 (doc (if (string-match "\\(.*\\)\n" full-doc)
154 (match-string 1 full-doc)
155 full-doc))
156 (enable-expr (if (eql (length button) 4) t (nth 4 button)))
157 (modes (nth 1 button))
158 functions show-sym)
159 (when (memq 'letter modes) (setq functions `(:letter ,name)))
160 (when (or (memq 'folder modes) (memq 'sequence modes))
161 (setq functions
162 (append `(,(if (memq 'folder modes) :folder :sequence) ,name)
163 functions))
164 (setq show-sym
165 (if (string-match "^mh-\\(.*\\)$" name-str)
166 (intern (concat "mh-show-" (match-string 1 name-str)))
167 name))
168 (setq functions
169 (append `(,(if (memq 'folder modes) :show :show-seq)
170 ,(if (fboundp show-sym) show-sym name))
171 functions)))
172 (do ((functions functions (cddr functions)))
173 ((null functions))
174 (let* ((type (car functions))
175 (function (cadr functions))
176 (type1 (substring (symbol-name type) 1))
177 (vector-list (cond ((eq type :show) 'show-vectors)
178 ((eq type :show-seq) 'show-vectors)
179 ((eq type :letter) 'letter-vectors)
180 (t 'folder-vectors)))
181 (list (cond ((eq type :letter) 'mh-tool-bar-letter-buttons)
182 (t 'mh-tool-bar-folder-buttons)))
183 (key (intern (concat "mh-" type1 "-tool-bar-" name-str)))
184 (setter (intern (concat type1 "-button-setter")))
185 (mbuttons (cond ((eq type :letter) 'letter-buttons)
186 ((eq type :show) 'show-buttons)
187 ((eq type :show-seq) 'show-buttons)
188 (t 'folder-buttons)))
189 (docs (cond ((eq mbuttons 'letter-buttons) 'letter-docs)
190 ((eq mbuttons 'folder-buttons) 'folder-docs))))
191 (add-to-list vector-list `(vector ,xemacs-icon ',function t ,full-doc))
192 (add-to-list
193 setter `(when (member ',name ,list)
194 (mh-funcall-if-exists
195 tool-bar-add-item ,icon ',function ',key
196 :help ,doc :enable ',enable-expr)))
197 (add-to-list mbuttons name)
198 (if docs (add-to-list docs doc))))))
199 (setq folder-buttons (nreverse folder-buttons)
200 letter-buttons (nreverse letter-buttons)
201 show-buttons (nreverse show-buttons)
202 letter-docs (nreverse letter-docs)
203 folder-docs (nreverse folder-docs)
204 folder-vectors (nreverse folder-vectors)
205 show-vectors (nreverse show-vectors)
206 letter-vectors (nreverse letter-vectors))
207 (dolist (x folder-defaults)
208 (unless (memq x folder-buttons)
209 (error "Folder defaults contains unknown button %s" x)))
210 (dolist (x letter-defaults)
211 (unless (memq x letter-buttons)
212 (error "Letter defaults contains unknown button %s" x)))
213 `(eval-when (compile load eval)
214 ;; GNU Emacs tool bar specific code
215 (mh-do-in-gnu-emacs
216 (defun mh-buffer-exists-p (mode)
217 "Test whether a buffer with major mode MODE is present."
218 (loop for buf in (buffer-list)
219 when (with-current-buffer buf
220 (eq major-mode mode))
221 return t))
222 ;; Tool bar initialization functions
223 (defun mh-tool-bar-folder-buttons-init ()
224 (when (mh-buffer-exists-p 'mh-folder-mode)
225 (let* ((load-path (mh-image-load-path-for-library "mh-e"
226 "mh-logo.xpm"))
227 (image-load-path (cons (car load-path)
228 (when (boundp 'image-load-path)
229 image-load-path))))
230 (setq mh-folder-tool-bar-map
231 (let ((tool-bar-map (make-sparse-keymap)))
232 ,@(nreverse folder-button-setter)
233 tool-bar-map))
234 (setq mh-folder-seq-tool-bar-map
235 (let ((tool-bar-map (copy-keymap mh-folder-tool-bar-map)))
236 ,@(nreverse sequence-button-setter)
237 tool-bar-map))
238 (setq mh-show-tool-bar-map
239 (let ((tool-bar-map (make-sparse-keymap)))
240 ,@(nreverse show-button-setter)
241 tool-bar-map))
242 (setq mh-show-seq-tool-bar-map
243 (let ((tool-bar-map (copy-keymap mh-show-tool-bar-map)))
244 ,@(nreverse show-seq-button-setter)
245 tool-bar-map)))))
246 (defun mh-tool-bar-letter-buttons-init ()
247 (when (mh-buffer-exists-p 'mh-letter-mode)
248 (let* ((load-path (mh-image-load-path-for-library "mh-e"
249 "mh-logo.xpm"))
250 (image-load-path (cons (car load-path)
251 (when (boundp 'image-load-path)
252 image-load-path))))
253 (setq mh-letter-tool-bar-map
254 (let ((tool-bar-map (make-sparse-keymap)))
255 ,@(nreverse letter-button-setter)
256 tool-bar-map)))))
257 ;; Custom setter functions
258 (defun mh-tool-bar-update (mode default-map sequence-map)
259 "Update `tool-bar-map' in all buffers of MODE.
260 Use SEQUENCE-MAP if display is limited; DEFAULT-MAP otherwise."
261 (loop for buf in (buffer-list)
262 do (with-current-buffer buf
263 (if (eq mode major-mode)
264 (let ((map (if mh-folder-view-stack
265 sequence-map
266 default-map)))
267 ;; Yes, make-local-variable is necessary since we
268 ;; get here during initialization when loading
269 ;; mh-e.el, after the +inbox buffer has been
270 ;; created, but before mh-folder-mode has run and
271 ;; created the local map.
272 (set (make-local-variable 'tool-bar-map) map))))))
273 (defun mh-tool-bar-folder-buttons-set (symbol value)
274 "Construct tool bar for `mh-folder-mode' and `mh-show-mode'."
275 (set-default symbol value)
276 (mh-tool-bar-folder-buttons-init)
277 (mh-tool-bar-update 'mh-folder-mode mh-folder-tool-bar-map
278 mh-folder-seq-tool-bar-map)
279 (mh-tool-bar-update 'mh-show-mode mh-show-tool-bar-map
280 mh-show-seq-tool-bar-map))
281 (defun mh-tool-bar-letter-buttons-set (symbol value)
282 "Construct tool bar for `mh-letter-mode'."
283 (set-default symbol value)
284 (mh-tool-bar-letter-buttons-init)
285 (mh-tool-bar-update 'mh-letter-mode mh-letter-tool-bar-map
286 mh-letter-tool-bar-map)))
287 ;; XEmacs specific code
288 (mh-do-in-xemacs
289 (defvar mh-tool-bar-folder-vector-map
290 (list ,@(loop for button in folder-buttons
291 for vector in folder-vectors
292 collect `(cons ',button ,vector))))
293 (defvar mh-tool-bar-show-vector-map
294 (list ,@(loop for button in show-buttons
295 for vector in show-vectors
296 collect `(cons ',button ,vector))))
297 (defvar mh-tool-bar-letter-vector-map
298 (list ,@(loop for button in letter-buttons
299 for vector in letter-vectors
300 collect `(cons ',button ,vector))))
301 (defvar mh-tool-bar-folder-buttons)
302 (defvar mh-tool-bar-show-buttons)
303 (defvar mh-tool-bar-letter-buttons)
304 ;; Custom setter functions
305 (defun mh-tool-bar-letter-buttons-set (symbol value)
306 (set-default symbol value)
307 (when mh-xemacs-has-tool-bar-flag
308 (setq mh-tool-bar-letter-buttons
309 (loop for b in value
310 collect (cdr
311 (assoc b mh-tool-bar-letter-vector-map))))))
312 (defun mh-tool-bar-folder-buttons-set (symbol value)
313 (set-default symbol value)
314 (when mh-xemacs-has-tool-bar-flag
315 (setq mh-tool-bar-folder-buttons
316 (loop for b in value
317 collect (cdr (assoc b mh-tool-bar-folder-vector-map))))
318 (setq mh-tool-bar-show-buttons
319 (loop for b in value
320 collect (cdr (assoc b mh-tool-bar-show-vector-map))))))
321 (defun mh-tool-bar-init (mode)
322 "Install tool bar in MODE."
323 (when mh-xemacs-use-tool-bar-flag
324 (let ((tool-bar (cond ((eq mode :folder)
325 mh-tool-bar-folder-buttons)
326 ((eq mode :letter)
327 mh-tool-bar-letter-buttons)
328 ((eq mode :show)
329 mh-tool-bar-show-buttons)))
330 (height 37)
331 (width 40)
332 (buffer (current-buffer)))
333 (cond
334 ((eq mh-xemacs-tool-bar-position 'top)
335 (set-specifier top-toolbar tool-bar buffer)
336 (set-specifier top-toolbar-visible-p t)
337 (set-specifier top-toolbar-height height))
338 ((eq mh-xemacs-tool-bar-position 'bottom)
339 (set-specifier bottom-toolbar tool-bar buffer)
340 (set-specifier bottom-toolbar-visible-p t)
341 (set-specifier bottom-toolbar-height height))
342 ((eq mh-xemacs-tool-bar-position 'left)
343 (set-specifier left-toolbar tool-bar buffer)
344 (set-specifier left-toolbar-visible-p t)
345 (set-specifier left-toolbar-width width))
346 ((eq mh-xemacs-tool-bar-position 'right)
347 (set-specifier right-toolbar tool-bar buffer)
348 (set-specifier right-toolbar-visible-p t)
349 (set-specifier right-toolbar-width width))
350 (t (set-specifier default-toolbar tool-bar buffer)))))))
351 ;; Declare customizable tool bars
352 (custom-declare-variable
353 'mh-tool-bar-folder-buttons
354 '(list ,@(mapcar (lambda (x) `(quote ,x)) folder-defaults))
355 "List of buttons to include in MH-Folder tool bar."
356 :group 'mh-tool-bar
357 :set 'mh-tool-bar-folder-buttons-set
358 :type '(set ,@(loop for x in folder-buttons
359 for y in folder-docs
360 collect `(const :tag ,y ,x)))
361 ;;:package-version '(MH-E "7.1")
363 (custom-declare-variable
364 'mh-tool-bar-letter-buttons
365 '(list ,@(mapcar (lambda (x) `(quote ,x)) letter-defaults))
366 "List of buttons to include in MH-Letter tool bar."
367 :group 'mh-tool-bar
368 :set 'mh-tool-bar-letter-buttons-set
369 :type '(set ,@(loop for x in letter-buttons
370 for y in letter-docs
371 collect `(const :tag ,y ,x)))
372 ;;:package-version '(MH-E "7.1")
373 ))))
375 ;; The icon names are duplicated in the Makefile and mh-xemacs.el.
376 (mh-tool-bar-define
377 ((:folder mh-inc-folder mh-mime-save-parts
378 mh-previous-undeleted-msg mh-page-msg
379 mh-next-undeleted-msg mh-delete-msg mh-refile-msg
380 mh-undo mh-execute-commands mh-toggle-tick mh-reply
381 mh-alias-grab-from-field mh-send mh-rescan-folder
382 mh-tool-bar-search mh-visit-folder
383 mh-tool-bar-customize mh-tool-bar-folder-help
384 mh-widen)
385 (:letter mh-send-letter save-buffer mh-fully-kill-draft
386 mh-compose-insertion ispell-message undo
387 clipboard-kill-region clipboard-kill-ring-save
388 clipboard-yank mh-tool-bar-customize
389 mh-tool-bar-letter-help))
390 ;; Folder/Show buffer buttons
391 (mh-inc-folder (folder) "mail/inbox" "Incorporate new mail in Inbox
392 This button runs `mh-inc-folder' which drags any
393 new mail into your Inbox folder")
394 (mh-mime-save-parts (folder) "attach" "Save MIME parts from this message
395 This button runs `mh-mime-save-parts' which saves a message's
396 different parts into separate files")
397 (mh-previous-undeleted-msg (folder) "left-arrow"
398 "Go to the previous undeleted message
399 This button runs `mh-previous-undeleted-msg'")
400 (mh-page-msg (folder) "next-page" "Page the current message forwards
401 This button runs `mh-page-msg'")
402 (mh-next-undeleted-msg (folder) "right-arrow" "Go to the next undeleted message
403 The button runs `mh-next-undeleted-msg'")
404 (mh-delete-msg (folder) "delete" "Mark this message for deletion
405 This button runs `mh-delete-msg'")
406 (mh-refile-msg (folder) "mail/move" "Refile this message
407 This button runs `mh-refile-msg'")
408 (mh-undo (folder) "undo" "Undo last operation
409 This button runs `undo'"
410 (mh-outstanding-commands-p))
411 (mh-execute-commands (folder) "data-save" "Perform moves and deletes
412 This button runs `mh-execute-commands'"
413 (mh-outstanding-commands-p))
414 (mh-toggle-tick (folder) "mail/flag-for-followup" "Toggle tick mark
415 This button runs `mh-toggle-tick'")
416 (mh-toggle-showing (folder) "show" "Toggle showing message
417 This button runs `mh-toggle-showing'")
418 (mh-reply (folder) "mail/reply" "Reply to this message
419 This button runs `mh-reply'")
420 (mh-tool-bar-reply-from (folder) "mail/reply-from" "Reply to \"from\"")
421 (mh-tool-bar-reply-to (folder) "mail/reply-to" "Reply to \"to\"")
422 (mh-tool-bar-reply-all (folder) "mail/reply-all" "Reply to \"all\"")
423 (mh-alias-grab-from-field (folder) "contact" "Create alias for sender
424 This button runs `mh-alias-grab-from-field'"
425 (and (mh-extract-from-header-value)
426 (not (mh-alias-for-from-p))))
427 (mh-send (folder) "mail/compose" "Compose new message
428 This button runs `mh-send'")
429 (mh-rescan-folder (folder) "refresh" "Rescan this folder
430 This button runs `mh-rescan-folder'")
431 (mh-pack-folder (folder) "mail/repack" "Repack this folder
432 This button runs `mh-pack-folder'")
433 (mh-tool-bar-search (folder) "search" "Search
434 This button runs `mh-tool-bar-search-function'")
435 (mh-visit-folder (folder) "open" "Visit other folder
436 This button runs `mh-visit-folder'")
437 ;; Letter buffer buttons
438 (mh-send-letter (letter) "mail/send" "Send this letter")
439 (save-buffer (letter) "save" "Save current buffer to its file"
440 (buffer-modified-p))
441 (mh-fully-kill-draft (letter) "delete" "Kill this draft")
442 (mh-compose-insertion (letter) "attach" "Insert attachment")
443 (ispell-message (letter) "spell" "Check spelling")
444 (undo (letter) "undo" "Undo last operation")
445 (clipboard-kill-region (letter) "cut"
446 "Cut (kill) text in region")
447 (clipboard-kill-ring-save (letter) "copy"
448 "Copy text in region")
449 (clipboard-yank (letter) "paste"
450 "Paste (yank) text cut or copied earlier")
451 ;; Common buttons
452 (mh-tool-bar-customize (folder letter) "preferences" "MH-E Preferences")
453 (mh-tool-bar-folder-help (folder) "help" "Help! (general help)
454 This button runs `info'")
455 (mh-tool-bar-letter-help (letter) "help" "Help! (general help)
456 This button runs `info'")
457 ;; Folder narrowed to sequence buttons
458 (mh-widen (sequence) "zoom-out" "Widen from the sequence
459 This button runs `mh-widen'"))
461 (provide 'mh-tool-bar)
463 ;; Local Variables:
464 ;; indent-tabs-mode: nil
465 ;; sentence-end-double-space: nil
466 ;; End:
468 ;; arch-tag: 28c2436d-bb8d-486a-a8d7-5a4d9cae3513
469 ;;; mh-tool-bar.el ends here