Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. ;;; weekly-view.el --- bar graph view of the week's diary events
  2.  
  3. ;; Copyright (C) 2003 Doug Alcorn <doug@lathi.net>
  4.  
  5. ;; Author: Doug Alcorn <doug@lathi.net>
  6. ;; Keywords: calendar, diary, week, view
  7.  
  8. ;; This program is NOT part of GNU Emacs
  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. ;;; Commentary:
  26.  
  27. ;; Version: 2
  28. ;; X-URL: http://www.lathi.net/twiki-bin/view/Main/EmacsWeeklyView
  29.  
  30. ;; This package makes a bar graph of the week's diary events
  31. ;;
  32. ;; Usage:
  33. ;;   (require 'weekly-view)
  34. ;;   (add-hook 'diary-display-hook 'fancy-diary-display-week-graph)
  35.  
  36. ;; Now when you view your diary it will display the weekly graph.
  37.  
  38. ;;; History:
  39. ;; version 1: original code, mostly worked
  40. ;; version 2: patch from Nemeth Felician <f_nemeth@index.hu> fixes lots of bugs
  41.  
  42. ;;; Code:
  43.  
  44. (require 'cal-desk-calendar)
  45.  
  46. (define-key calendar-mode-map "w" 'week-graph-view-diary-entries)
  47.  
  48.  
  49. ;;; User Variables:
  50.  
  51. (defcustom week-graph-work-week nil
  52.   "*If non-nil, only the 5 workdays are displayed (instead of 7)."
  53.   :type 'boolean)
  54.  
  55. (defcustom week-graph-dynamic-width t
  56.   "*If non-nil, the graph fully fills the window.
  57. If nil, `weekly-graph-day-width' is used."
  58.   :type 'boolean)
  59.  
  60.  
  61. ;;; Compatibility:
  62. ;;
  63. ;; emacs doesn't have replace-in-string
  64. ;; from gnus-util.el
  65. (eval-and-compile
  66.   (cond
  67.    ((fboundp 'replace-in-string)
  68.     (defalias 'weekly-view-replace-in-string 'replace-in-string))
  69.    ((fboundp 'replace-regexp-in-string)
  70.     (defun replace-in-string  (string regexp newtext &optional literal)
  71.       (replace-regexp-in-string regexp newtext string nil literal)))
  72.    (t
  73.     (defun replace-in-string (string regexp newtext &optional literal)
  74.       (let ((start 0) tail)
  75.     (while (string-match regexp string start)
  76.       (setq tail (- (length string) (match-end 0)))
  77.       (setq string (replace-match newtext nil literal string))
  78.       (setq start (- (length string) tail))))
  79.       string))))
  80.  
  81.  
  82. ;;;###autoload
  83. (defun week-graph-view-diary-entries ()
  84.   "Prepare and display a buffer with diary entries of the current week.
  85. See `view-diary-entries' for more."
  86.   (interactive)
  87.   (save-excursion
  88.     (calendar-cursor-to-nearest-date)
  89.     (let ((diary-display-hook 'fancy-diary-display-week-graph)
  90.       (day (calendar-day-of-week (calendar-cursor-to-date))))
  91.       (unless (= day calendar-week-start-day)
  92.     (calendar-beginning-of-week 1))
  93.       (view-diary-entries 7))))
  94.  
  95. (defun week-graph-convert-time (time)
  96.   (let ((hour (/ time 100))
  97.     (mins (% time 100)))
  98.     (+ (* hour 3600) (* mins 60))))
  99.  
  100. (defun weekly-graph-display-time-format (time)
  101.   (format "%2d:%02d" (/ cur 3600) (% (/ cur 60) 60)))
  102.  
  103. (defun week-graph-day-titles (&optional width)
  104.   "Return of a vector whose members are the day names.  If WIDTH is
  105. non-nil and non-zero, truncate the day name to that width."
  106.   (mapcar
  107.    (lambda (s)
  108.      (let* ((extra (- width (length s)))
  109.         (pre (/ extra 2))
  110.         (post (- extra pre)))
  111.        (cond
  112.     ((= extra 0) s)
  113.     ((> extra 0) (format (format "%%%ds%%%ds" (- width post) post) s ""))
  114.     (t (substring s 0 width)))))
  115.    calendar-day-name-array))
  116.  
  117. (defvar weekly-graph-day-width 10
  118.   "Width of the each day in the bar graph")
  119.  
  120. (defvar weekly-graph-day-start  800
  121.   "Time to start each day's view in military style integers (i.e. \"8:00am\" is 800)")
  122. (defvar weekly-graph-day-end 1800
  123.   "Time to end each day's view in military style integers (i.e. \"8:00am\" is 800)")
  124. (defvar weekly-graph-increment 30
  125.   "Increment in minutes for each row on the weekly graph of diary entries")
  126. (defvar weekly-graph-use-hash-marks t
  127.   "If non-nill use hash marks '\#' to graph events rather than pertinent event text")
  128. (defvar weekly-graph-default-event-length 60
  129.   "Length of events that don't specify an end time in minutes.")
  130.  
  131. (defvar diary-time-regexp-list
  132.   `(
  133.  
  134.     "^[     ]*\\([0-9]?[0-9]\\)-\\([0-9]?[0-9]\\)\\([ap]\\)m\\>" ; HH-HH[ap]m
  135.     "^[     ]*\\([0-9]?[0-9]\\):?\\([0-9][0-9]\\)-\\([0-9]?[0-9]\\):?\\([0-9][0-9]\\)\\(\\|[^ap]\\)" ; military range
  136.     "^[     ]*\\([0-9]?[0-9]\\):?\\([0-9][0-9]\\)\\(\\>\\|[^ap]\\)" ; military time
  137.     "^[     ]*\\([0-9]?[0-9]\\):\\([0-9][0-9]\\)-\\([0-9]?[0-9]\\):\\([0-9][0-9]\\)\\([ap]\\)m\\>" ; hh:mm range
  138.     "^[     ]*\\([0-9]?[0-9]\\):\\([0-9][0-9]\\)\\([ap]\\)m-\\([0-9]?[0-9]\\):\\([0-9][0-9]\\)\\([ap]\\)m\\>"
  139.     "^[     ]*\\([0-9]?[0-9]\\):\\([0-9][0-9]\\)\\([ap]\\)m-\\([0-9]?[0-9]\\):\\([0-9][0-9]\\)\\([ap]\\)m\\>" ; h/m range
  140.     "^[     ]*\\([0-9]?[0-9]\\):\\([0-9][0-9]\\)\\([ap]\\)m\\>" ; hh:mm
  141.     "^[     ]*\\([0-9]?[0-9]\\)\\([ap]\\)m-\\([0-9]?[0-9]\\)\\([ap]\\)m\\>" ; HH[ap]m-HH[ap]m
  142.     "^[     ]*\\([0-9]?[0-9]\\)\\([ap]\\)m\\>" ; hour only
  143.     ,diary-schedule-sunrise-sunset-pattern
  144.     ,diary-schedule-lunar-phase-pattern
  145.     ,diary-schedule-equinox-solstice-pattern
  146.     ,diary-schedule-morning-pattern
  147.     ;,diary-schedule-afternoon-patern
  148.     ,diary-schedule-workday-pattern
  149.     ,diary-schedule-all-day-pattern))
  150.  
  151. (defun fancy-diary-display-week-graph ()
  152.   "Given a set of appointment DATA, draw a weekly bar graph of it.
  153. DATA must be a vector of seven elements (for each day of the week),
  154. where each element is a list of cons cells representing the beginning
  155. and ending seconds of each appointment within the day, where midnight
  156. begins at 0 seconds.  For example, an appointment for one hour on
  157. Monday at 10am would look like:
  158.  
  159.  [nil ((36000 . 39600)) nil nil nil nil nil]"
  160.   (save-excursion ;; Prepare the fancy diary buffer.
  161.     ;; setup
  162.     (message "Preparing diary...")
  163.     (set-buffer (get-buffer-create fancy-diary-buffer))
  164.     (setq buffer-read-only nil)
  165.     (make-local-variable 'mode-line-format)
  166.     (calendar-set-mode-line " Desk Calendar ")
  167.     (erase-buffer)
  168.  
  169.     ;; get ready to insert schedule
  170.     (let* ((num-days (if week-graph-work-week 5 7))
  171.        (day-width (if week-graph-dynamic-width
  172.               (/ (- (window-width) 7 num-days) num-days)
  173.             weekly-graph-day-width))
  174.        (begin (week-graph-convert-time weekly-graph-day-start))
  175.        (end (week-graph-convert-time weekly-graph-day-end))
  176.        (incr (* weekly-graph-increment 60))
  177.        (cur begin)
  178.        (day-titles (vconcat (week-graph-day-titles day-width)))
  179.        (data (make-vector 7 nil)))
  180.       ;; "cook" the diary-entries-list into a more regular form
  181.       (dolist (elem diary-entries-list)
  182.     (let* ((dow (calendar-day-of-week (car elem)))
  183.            (day-of-week-ref (aref data dow))
  184.            (entry-times (diary-entry-times (cadr elem)))
  185.            (entry-text (cadr elem))
  186.            (beginning-time (week-graph-convert-time (car entry-times)))
  187.            (ending-time (week-graph-convert-time (cadr entry-times)))
  188.            entry-alist)
  189.       (if (= beginning-time ending-time)
  190.           (setq ending-time (+ ending-time (* weekly-graph-default-event-length 60))))
  191.       (mapcar (lambda (regexp) (setq entry-text (replace-in-string entry-text regexp "")))
  192.           diary-time-regexp-list)
  193.       (setq entry-text (replace-in-string entry-text "^[    ]+" ""))
  194.       (setq entry-text (replace-in-string entry-text "[ \t\n]+" " "))
  195.       (setq entry-text (replace-in-string entry-text "[ \t]+$" ""))
  196.       (setq entry-plist `(:beginning ,beginning-time
  197.                   :ending ,ending-time
  198.                   :text ,entry-text
  199.                   :marker ,(nth 3 elem)))
  200.       (unless (= (car entry-times) -9999)
  201.         (if day-of-week-ref
  202.         (nconc day-of-week-ref (list entry-plist))
  203.           (aset data dow (list entry-plist))))))
  204.  
  205.       ;; insert day of week headers
  206.       (dotimes (j 7)
  207.     (if (= j 0)
  208.         (insert "     "))
  209.     (setq i (% (+ j calendar-week-start-day) 7))
  210.     (unless (and week-graph-work-week (or (= i 0) (= i 6)))
  211.       (insert "|" (aref day-titles i))))
  212.       (insert "|\n"
  213.           (make-string (+ 6 (* day-width num-days) num-days) ?-) ?\n)
  214.  
  215.       ;; now handle entries
  216.       (while (< cur end)
  217.     (dotimes (j 7)
  218.       (setq i (% (+ j calendar-week-start-day) 7))
  219.       ;; insert time on lieft
  220.       (if (= j 0) (insert (weekly-graph-display-time-format cur)))
  221.       (unless (and week-graph-work-week (or (= i 0) (= i 6)))
  222.         (insert "|")
  223.         (let ((day-of-week-list (aref data i)) (print-text nil) (print-marker nil))
  224.           (setq day-of-week-list
  225.             (mapcar
  226.              (lambda (appt)
  227.                (let* ((appt-text (plist-get appt :text))
  228.                   (beginning (plist-get appt :beginning))
  229.                   (ending (plist-get appt :ending))
  230.                   (times-printed (plist-get appt :times-printed))
  231.                   (start (if times-printed (* times-printed day-width) 0))
  232.                   (end (if times-printed (* (1+ times-printed) day-width) day-width)))
  233.              (message "times printed: %s start: %s end: %s appt: %s" times-printed start end appt-text)
  234.              (if (and (>= cur beginning) (< cur ending))
  235.                  (progn
  236.                    (unless times-printed
  237.                  (setq print-marker (plist-get appt :marker)))
  238.                    (setq print-text
  239.                      (if (> (length appt-text) end)
  240.                      (substring appt-text start end)
  241.                        (if (> start (length appt-text))
  242.                        (make-string day-width ?#)
  243.                      (concat
  244.                       (substring appt-text start (length appt-text))
  245.                       (make-string (- day-width (- (length appt-text) start)) ?#)))))
  246.                    
  247.                    (setq appt (plist-put appt :times-printed (if times-printed (1+ times-printed) 1))))
  248.                     ;(setq print-text nil)
  249.                )
  250.              appt))
  251.              day-of-week-list))
  252.           (aset data i day-of-week-list)
  253.           (if print-text
  254.           (if print-marker
  255.               (insert-button print-text 'marker print-marker :type 'diary-entry)
  256.             (insert print-text))
  257.         (insert (make-string day-width ? ))))))
  258.     (insert "|\n")
  259.     (setq cur (+ cur incr)))
  260.       (insert (make-string (+ 6 (* day-width num-days) num-days) ?-) ?\n))
  261.    
  262.     ;; clean-up
  263.     (set-buffer-modified-p nil)
  264.     (setq buffer-read-only t)
  265.     (display-buffer fancy-diary-buffer)
  266.     (message "Preparing diary...done")))
  267.  
  268. (provide 'weekly-view)
  269.  
  270. ;;; weekly-view.el ends here