Hi,
Recently I wanted to create some very simple concept maps. Since I already
had CEDET installed, I thought I would try to create them using COGRE.
However there was no way to create a simple node containing text, and to
edit that text. So I wrote a node class to create (word-wrapped) text nodes
for COGRE.
This proved to be quite a usable method for creating these concept maps, so
I thought I would post the code for the text node on here, in case anyone
else wanted to use COGRE for something similar.
Regards,
Leo
----------------------------------
(defun wrap-string (str width)
"Wrap a string to a given width."
(let ((tail str)
(result))
(while (> (length tail) width)
(let ((head (substring tail 0 width)))
(cond
((string-match "\\`[ \t]+" (substring tail width))
(setq tail (substring tail (+ (match-end 0) width))))
((string-match "[ \t]\\([^ \t]*\\)\\'" head)
(setq head (substring tail 0 (match-beginning 1)))
(setq tail (substring tail (match-beginning 1))))
(t (setq tail (substring tail width))))
(setq result (append result (list head)))))
(append result (list tail))))
;; From shell-quote-argument in subr.el
(defun quote-string (str)
"Quote any strange characters in string."
(let ((result "") (start 0) end)
(while (string-match "[^-0-9a-zA-Z_./ ]" str start)
(setq end (match-beginning 0)
result (concat result (substring str start end)
"\\" (substring str end (1+ end)))
start (1+ end)))
(concat result (substring str start))))
(defclass cogre-text (cogre-node)
((name-default :initform "Text")
(blank-lines-top :initform 0)
(blank-lines-bottom :initform 0)
(alignment :initform left)
(show-name :initarg :show-name
:initform nil
:type boolean
:custom (choice (const :tag "Yes" t)
(const :tag "No" nil))
:documentation
"Whether to show the name of this node.")
(text :initarg :text
:initform ""
:type string
:custom string
:documentation
"The body text of the node.")
(line-wrap :initarg :line-wrap
:initform nil
:type (or null integer)
:custom (choice (integer :tag "Number of columns")
(const :tag "None" nil))
:documentation
"The number of columns to wrap the text.")
)
"A Text node.
Text nodes contain a text string")
(defmethod cogre-node-title ((node cogre-text))
"Return a list of strings representing the title of the NODE.
For example: ( \"Title\" ) or ( \"<Type>\" \"Title\" )"
(when (oref node show-name) (list (oref node object-name))))
(defmethod cogre-node-slots ((node cogre-text))
"For NODE, return a list of slot lists.
Slots are individual lines of text appearing in the body of a node.
Each list will be prefixed with a line before it."
(list
(if (and (eieio-object-p cogre-graph) (= (oref cogre-graph :detail) 3))
(list nil)
(let ((lines (split-string (oref node text) "[\f\n\r\v]")))
(if (oref node line-wrap)
(apply 'append (mapcar '(lambda (l) (wrap-string l (oref node
line-wrap))) lines))
lines)))))
(defmethod cogre-export-dot-shape ((node cogre-text))
"Convert NODE into DOT syntax of semantic tags."
"record")
(defmethod cogre-export-dot-label ((node cogre-text))
"Convert NODE into DOT syntax of semantic tags."
(let ((titles (cogre-node-title node))
(lines (apply 'append (cogre-node-slots node))))
(concat "{"
(mapconcat 'quote-string titles "\\n")
(if titles "|" "")
(mapconcat 'quote-string lines "\\n")
"}")))
(defmethod cogre-node-rebuild-ascii ((node cogre-text))
"Create the text rectangle for the COGRE package.
Calls the base method then removes the extra line if needed."
(let ((titles (cogre-node-title node))
(rect (call-next-method)))
(if titles
rect
(oset node rectangle (cdr rect))
(cdr rect))))
|