12

I have several items that I need to perform the same tasks on. To get an overview, I wanted to use a table, where the columns would show me how many are done, something like this:

+------+--------------+--------------+--------------+
| Item | Task 1 [2/2] | Task 2 [1/2] | Task 3 [0/2] |
+------+--------------+--------------+--------------+
| I 1  | DONE         | DONE         | TODO         |
| I 2  | DONE         | TODO         | TODO         |
+------+--------------+--------------+--------------+

Can this be done, and if yes, how?

Shylock
  • 199
  • 1
  • 6

2 Answers2

7

Org mode is so flexible that you have, in addition to the previous answer, a bunch of additional possibilities, if you don't file like coding. This requires a little modification of your setup, but not much.

One of the simplest solutions is to use properties. If we define the properties I-1, I-2, I-3 and I-4 and set them the value TODO, ONGOING or DONE (by pressing C-C C-x p over the desired task) for those items (properties) that have to be executed for each task, we set effectively the list of items for each task. For example, we could have:

* All tasks
** DONE Task 1
   :PROPERTIES:
   :I-1:      DONE
   :I-2:      DONE
   :END:
** TODO Task 2
   :PROPERTIES:
   :I-2:      DONE
   :I-3:      ONGOING
   :END:
** TODO Task 3
   :PROPERTIES:
   :I-1:      TODO
   :I-2:      ONGOING
   :I-4:      TODO
   :END:

* config :noexport:
#+COLUMNS: %35ITEM %3PRIORITY %7I-1 %7I-2 %7I-3 %7I-4
#+PROPERTY: I-1_ALL TODO ONGOING DONE
#+PROPERTY: I-2_ALL TODO ONGOING DONE
#+PROPERTY: I-3_ALL TODO ONGOING DONE
#+PROPERTY: I-4_ALL TODO ONGOING DONE

The last lines under the config heading are there to set up the heading in table view mode, and to define the valid values of the properties I-1..4.

Pressing C-c C-x C-c (edited, thanks for the comment!) in the All tasks heading will show you this in form of table:

ITEM______________________________|_PRI_|_I-1_____|_I-2_____|_I-3_____|_I-4_____|
* All tasks                       |     |         |         |         |         |
** DONE Task 1                    |     | DONE    | DONE    |         |         |
** TODO Task 2                    |     |         | DONE    | ONGOING |         |
** TODO Task 3                    |     | TODO    | ONGOING |         | TODO    |

The nice thing about this is that when placed over a given value of a property, pressing S-left/right moves the value over the valid values of that property. Press q to exit column view mode.

J C Gonzalez
  • 365
  • 4
  • 9
6

The functions org-element-parse and org-element-map make this task relatively easy. org-element-parse generates an abstract syntax tree of the org buffer. You can iterate over the headlines of the buffer with org-element-map.

The elisp code in the following org file is documented. The result is shown as block output.

* Task 1 [2/2]
** DONE I 1
** DONE I 2
* Task 2 [1/2]
** DONE I 1
** TODO I 2
** TODO I 3
* Task 3 [0/2]
** TODO I 1
** TODO I 2

  #+NAME: todoOverview
  #+BEGIN_SRC emacs-lisp
;; (org-src-debug) ;;< Remove first comment starters to use the debugging code from https://emacs.stackexchange.com/questions/13244/edebug-orgmode-source-code-blocks-with-input-variables
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; The following wrapper enables us to run the code
;; - by evaluating the source code block within the org-file and also
;; - by evaluating the form in the source edit buffer.
(with-current-buffer
    (or (and (org-src-edit-buffer-p) (org-src--source-buffer))
        (current-buffer))
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; The actual code starts here:
  (let* ((ast (org-element-parse-buffer)) ;; built up the abstract syntax tree of the org buffer
         item-types ; all occuring item types. It could be that some task has more item types than another.
         tasks ; accumulation list for the tasks
         current-task ; name of the current task (header of level 1)
         task-items) ; items of the current task
    (org-element-map ast 'headline
      (lambda (hl)
        (cl-case (org-element-property :level hl)
          (1 ; We assume here that headers of level 1 are tasks.
           (when current-task ; registering the old task
             (setq tasks (cons (cons current-task (nreverse task-items)) tasks)))
           (setq current-task (org-element-property :raw-value hl) ; preparing the new task
                 task-items nil))
          (2 ; item
           (let ((item-type (org-element-property :raw-value hl)))
             (setq item-types (cons item-type item-types))
             (setq task-items (cons (cons item-type (org-element-property :todo-keyword hl))
                                    task-items)))))))
    (setq tasks (nreverse (cons (cons current-task (nreverse task-items)) tasks)) ;< add the last task
          item-types (sort (cl-remove-duplicates (nreverse item-types) :test 'string-equal) ; list of unique item types
                           #'string<)) ;;< Sorting the items lexicographical. Other criteria could be applied.
    ;;;;;;;;;;
    ;; generating the output table:
    (apply
     #'list
     (cons "Item" (mapcar #'car tasks)) ; header
     'hline
     ;; rows:
     (mapcar
      ;; mapping the items to the todo states associated to the tasks:
      (lambda (item-type)
        (cons item-type
              (mapcar
               (lambda (task)
                 (let ((todo-status (cdr (assoc-string item-type task))))
                   todo-status))
               tasks)))
      item-types))))
  #+END_SRC

  #+RESULTS: todoOverview
  | Item | Task 1 [2/2] | Task 2 [1/2] | Task 3 [0/2] |
  |------+--------------+--------------+--------------|
  | I 1  | DONE         | DONE         | TODO         |
  | I 2  | DONE         | TODO         | TODO         |
  | I 3  | nil          | TODO         | nil          |
Tobias
  • 32,569
  • 1
  • 34
  • 75