//[of]:license //[c] Code Browser - a folding text editor for programmers //[c] Copyright (C) 2004-07 Marc Kerbiquet //[c] //[c] This program is free software; you can redistribute it and/or modify //[c] it under the terms of the GNU General Public License as published by //[c] the Free Software Foundation; either version 2 of the License, or //[c] (at your option) any later version. //[c] //[c] This program is distributed in the hope that it will be useful, //[c] but WITHOUT ANY WARRANTY; without even the implied warranty of //[c] MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //[c] GNU General Public License for more details. //[c] //[c] You should have received a copy of the GNU General Public License //[c] along with this program; if not, write to the Free Software //[c] Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //[cf] //[of]:imports import "base/types" import "base/memory-allocator" import "base/memory-buffer" import "base/memory-reader" import "text/string" import "text/string-buffer" import "collection/vector" import "os" import "swift" //[c] import "editor/text-model" import "utilities/colorizer-interface" import "utilities/text-utils" //[c] //[c]Events are re-used import "editor/text-view" //[cf] //[of]:constants //[c]Constants //[c] //[cf] //[of]structures:structures //[of]:tree view class //[c]Tree View Class //[c] struct tree view class: local tree box class // emit a request to follow a link or enter a folder on enter: {box, event} void // emit a request to leave the current folder on leave: {box, event} void // notify that the page has moved (scrolling) on page changed: {box, event} void end //[cf] //[of]tree-view:tree view //[c] public struct tree view : local tree box has focus : bool // The tree model associated to the text object text tree model : text tree model end //[cf] //[cf] //[c] //[of]tree-view:tree view //[of]:description //[c]The Tree View Widget //[cf] //[l]:definition:#structures/tree-view //[c] //[of]:instance creation //[of]:new tree view (parent box) //[c] public func new tree view (parent: box) def view = allocate memory (sizeof local tree view) : tree view initialize(view, parent) return view end //[cf] //[cf] //[c] //[of]:accessing //[of]:set folder (folder, open) //[c]Changes the Current Edited Folder //[c] public func set folder (m: tree view, text: text object, open: open interface) def new model = not nil (text) -> new text tree model (text, open), nil set tree (m, new model) def old model = text tree model (m) if not nil (old model) delete (old model) end text tree model (m) = new model end //[cf] //[of]:folder //[c]Returns the Current Edited Folder //[c] public func folder (m: tree view) def model = tree (m): text tree model if is nil (model) return nil end return text object (model) end //[cf] //[of]:selection //[c] public func selection (m: tree view) return selection (super (m)) : text tree item end //[cf] //[of]:set title (title) //[c]Notifies that the title of the tree has changed //[c] public func notify title changed (m:tree view) def model = text tree model (m) if is nil (model) return end notify text changed (root (model)) end //[cf] //[cf] //[of]:converting //[of]:as tree view (box) //[c]Get the tree view interface of a box //[c] public equ as tree view (box: box) = get interface (box, tree view interface) : tree view //[cf] //[cf] //[c] //[of]:restricted //[of]:tree view class public func tree view class def c = the tree view class if ~ initialized initialized = true // initialize with parent class copy (c, tree box class) // patch some methods mem size (c) = sizeof local tree view class release (c) = ^actual release (tree view) get interface (c) = ^actual get interface (tree view, interface id) on focus (c) = ^handle focus (tree view, event) on blur (c) = ^handle blur (tree view, event) accept focus (c) = ^yes (box) on enter (c) = ^notify parent (box, event) on leave (c) = ^notify parent (box, event) end return c end private def initialized = false private def the tree view class: local tree view class //[cf] //[of]:initialize (m, parent box) //[c] public func initialize (m: tree view, parent: box) initialize (super (m), parent) class (m) = tree view class has focus (m) = false text tree model (m) = nil end //[cf] //[c] //[of]:actual get interface (m, interface id, interface) //[c]Get an interface //[c] public func actual get interface (m: tree view, id: interface id) if id == tree view interface return m end return actual get interface (super (m), id) end //[c] private equ tree view interface = the tree view class //[cf] //[of]:actual release (m) //[c] public func actual release (m: tree view) actual release (super (m)) // delete tree model after releasing tree box, // since this one will unsubscribe from model def model = text tree model (m) if not nil (model) delete (model) end end //[cf] //[c] //[of]:handle focus (event) public func handle focus (m: tree view, e: event) has focus (m) = true return handle focus (super (m), e) end //[cf] //[of]:handle blur (event) public func handle blur (m: tree view, e: event) has focus (m) = false return handle blur (super (m), e) end //[cf] //[cf] //[cf] //[of]:text tree item //[of]:definition //[c] public struct text tree item : local tree item public model: text tree model public text object : text object public text line : text line private parent item : text tree item private next sibling item : text tree item private open count: int private first child item : text tree item // Listen to the events of the currently edited folder private observed text : text object private text listener : local text listener end //[cf] //[c] //[of]:instance creation //[of]:new text tree item (text object) //[c] public func new text tree item (model: text tree model, text: text object) def m = allocate memory (sizeof local text tree item) : text tree item initialize(m, model, text) return m end //[cf] //[of]:new text tree item (parent, text, line) //[c] func new text tree item ( model: text tree model, parent: text tree item, text: text object, line: text line) def m = allocate memory (sizeof local text tree item) : text tree item initialize(m, model, parent, text, line) return m end //[cf] //[of]:delete //[c] func delete (m: text tree item) release (m) free memory (m) end //[cf] //[cf] //[of]:initialize - release //[of]:initialize (model, text) //[c] func initialize ( m: text tree item, model: text tree model, text: text object) initialize (m, model, nil, text, nil) end //[cf] //[of]:initialize (model, parent, line) //[c] func initialize ( m: text tree item, model: text tree model, parent: text tree item, line: text line) initialize (m, model, parent, nil, line) end //[cf] //[of]:initialize (parent, text, line) //[c] func initialize ( m: text tree item, model: text tree model, parent: text tree item, text: text object, line: text line) : void class (m) = text tree item class model (m) = model text object (m) = text text line (m) = line parent item (m) = parent next sibling item (m) = nil open count (m) = 0 first child item (m) = nil observed text (m) = nil recipient (text listener (m)) = m text changed (text listener (m)) = ^handle replace event (text tree item, text object, replace text event) prop changed (text listener (m)) = ^handle prop changed (text tree item, text object, replace prop event) group changed (text listener (m)) = ^ignore group event (object, text object, bool) destroyed (text listener (m)) = ^handle destroyed (text tree item, text object) marker added (text listener (m)) = ^ignore marker (object, text object, text marker) marker removed (text listener (m)) = ^ignore marker (object, text object, text marker) // always open the root item to catch notifications if is nil (parent) actual open (m) end end //[c] def text tree item class = const tree item class ( ^actual append text (text tree item, string buffer), ^actual parent (text tree item), ^actual first child (text tree item), ^actual next sibling (text tree item), ^actual open (text tree item), ^actual close (text tree item), ^actual has children (text tree item), ^actual image (text tree item) ) //[cf] //[of]:release //[c] func release (m: text tree item) : void delete children (m) end //[cf] //[cf] //[c] //[c]private: //[of]:observing text //[of]:handle replace event (folder, event) //[c] private func handle replace event ( m: text tree item, o: text object, e: replace text event) // ignore event from different folders if o <> observed text (m) if observed text (m) == parent folder (o) def parent line = parent line (o) def child = first child item (m) while not nil (child) if text line (child) == parent line notify has children changed (child) break end child = next sibling item (child) end end return end // Find the replacement point in the list of items def start ln = line number (new start (e)) def index = 0 def ln = 0 def tl = first line (o) def child = first child item (m) def previous = nil : text tree item while not nil (child) && ln <> start ln if tl == text line (child) previous = child child = next sibling item (child) index += 1 end ln++ tl = next (tl) end // Remove old items tl = next (text line (new limit (e))) while not nil (tl) if is headline (tl) break end tl = next (tl) end def removed = 0 while not nil (child) && text line (child) <> tl def next = next sibling item (child) // delete item if is nil (previous) first child item (m) = next else next sibling item (previous) = next end delete (child) child = next removed += 1 end // Insert new items def inserted = 0 def next = child tl = text line (new start (e)) def n = new lines (e) while n > 0 if is headline (tl) child = new text tree item (model (m), m, o, tl) next sibling item (child) = next if is nil (previous) first child item (m) = child else next sibling item (previous) = child end previous = child inserted += 1 end tl = next (tl) n -= 1 end // Dispatch event def tre : local tree replace event parent (tre) = m index (tre) = index removed (tre) = removed inserted (tre) = inserted notify children replaced (m, tre) // if the item is the root item, there is no parent if is nil (parent item (m)) notify has children changed (m) end end //[c] func notify text changed (m: text tree item) each (listeners (model (m))) ? l text changed (l : tree listener, m) end end //[c] func notify data changed (m: text tree item) each (listeners (model (m))) ? l data changed (l : tree listener, m) end end //[c] func notify has children changed (m: text tree item) each (listeners (model (m))) ? l has children changed (l : tree listener, m) end end //[c] func notify children replaced (m: text tree item, e: tree replace event) each (listeners (model (m))) ? l children replaced (l : tree listener, e) end end //[cf] //[of]:handle prop changed (folder, event) //[c] private func handle prop changed ( m: text tree item, o: text object, e: replace prop event) // ignore event from different folders if o <> observed text (m) return end // search child item def child = first child item (m) def text line = line object (e) while not nil (child) if text line (child) == text line notify text changed (child) if open count (child) > 0 && is link (text line) def link line = link object (text line) if ~ is equal (original path (e), path (link line)) rebuild children (child) end end break end child = next sibling item (child) end end //[cf] //[of]:handle destroyed ( folder) //[c]Handle destruction of the text object //[c] private func handle destroyed ( m: text tree item, o: text object) // ignore event from different folders if o <> observed text (m) return end def text line = text line (m) if is nil (text line) return end if open count (m) > 0 && is link (text line) rebuild children (m) end end //[cf] //[cf] //[of]:accessing //[of]:actual append text (s) //[c] func actual append text (m: text tree item, s: string buffer) def line = text line (m) if not nil (line) def p = display text (line) // skip tabs and spaces while p[] == tab char || p[] == space char p += 1 end // append all chars, replace tabs by spaces repeat def c = p++[] if is nul (c) break end if c == tab char c = space char end s << c end else append title (open interface (model (m)), s) end end //[c] //[cf] //[of]:actual parent func actual parent (m: text tree item) return parent item (m) end //[cf] //[of]:actual first child func actual first child (m: text tree item) return first child item (m) end //[cf] //[of]:actual next sibling func actual next sibling (m: text tree item) return next sibling item (m) end //[cf] //[of]:actual open func actual open (m: text tree item) if open count (m) == 0 insert children (m) end open count (m) += 1 end //[cf] //[of]:actual close func actual close (m: text tree item) open count (m) -= 1 if open count (m) == 0 delete children (m) first child item (m) = nil observed text (m) = nil end end //[cf] //[of]:actual has children //[c] func actual has children (m: text tree item) if open count (m) > 0 return not nil (first child item (m)) end def text object = nil : text object if is nil (text line (m)) text object = text object (m) elsif is folder (text line (m)) text object = text object (text line (m)) elsif is link (text line (m)) return true end if not nil (text object) each line (text object) ? line if is headline (line) return true end end end return false end //[cf] //[of]:actual image //[c] equ folder index = 0 equ link index = 1 //[c] func actual image (m: text tree item) def text line = text line (m) if is nil (text line) || is folder (text line) return folder index else return link index end end //[cf] //[cf] //[of]:misc //[of]:rebuild children //[c] private func rebuild children (m: text tree item) def removed = count children (m) delete children (m) insert children (m) def inserted = count children (m) if (removed > 0) || (inserted > 0) // Dispatch event def tre : local tree replace event parent (tre) = m index (tre) = 0 removed (tre) = removed inserted (tre) = inserted notify children replaced (m, tre) end notify has children changed (m) notify data changed (m) end //[cf] //[of]:insert children //[c] func insert children (m: text tree item) def text object = nil : text object if is nil (text line (m)) text object = text object (m) elsif is headline (text line (m)) text object = open (open interface (model (m)), text object (m), text line (m)) end if not nil (text object) def first = nil: text tree item def last = nil: text tree item each line (text object) ? line if is headline (line) def child = new text tree item (model (m), m, text object, line) if is nil (first) first = child else next sibling item (last) = child end last = child end end first child item (m) = first add listener (text object, text listener (m)) end observed text (m) = text object end //[cf] //[of]:delete children //[c] func delete children (m: text tree item) if not nil (observed text (m)) remove listener (observed text (m), text listener (m)) observed text (m) = nil end def child = first child item (m) while not nil (child) def next = next sibling item (child) delete (child) child = next end first child item (m) = nil end //[cf] //[of]:count children //[c] private func count children (m: text tree item) def n = 0 def child = first child item (m) while not nil (child) n+=1 child = next sibling item (child) end return n end //[cf] //[cf] //[cf] //[of]:text tree model //[of]:definition //[c] struct text tree model : local tree model // What I'm editing text object: text object // Root item root item: local text tree item // Interface to open links open interface: open interface // listeners listeners: local vector end //[cf] //[c] //[of]:instance creation //[of]:new text tree model (text object) //[c] public func new text tree model (text: text object, open: open interface) def model = allocate memory (sizeof local text tree model) : text tree model initialize(model, text, open) return model end //[cf] //[of]:delete //[c] func delete (m: text tree model) release (m) free memory (m) end //[cf] //[cf] //[of]:initialize - release //[of]:initialize (text, open) //[c] func initialize ( m: text tree model, text: text object, open: open interface) class (m) = text tree model class text object (m) = text open interface (m) = open initialize (root item (m), m, text) initialize (listeners (m), 2) end //[c] def text tree model class = const tree model class ( ^root (text tree model), ^add listener (text tree model, tree listener), ^remove listener (text tree model, tree listener) ) //[cf] //[of]:release //[c] func release (m: text tree model) release (root item (m)) release (listeners (m)) end //[cf] //[cf] //[of]:adding - removing //[of]:add listener (m, listener) func add listener (m: text tree model, listener: tree listener) add (listeners (m), listener) end //[cf] //[of]:remove listener (m, listener) func remove listener (m: text tree model, listener: tree listener) remove (listeners (m), listener) end //[cf] //[cf] //[c] //[c]private: //[of]:accessing //[of]:root //[c] func root (m: text tree model) return root item (m) end //[c] //[cf] //[cf] //[cf] //[of]:open interface //[c] public struct open interface data: object open: {object, text object, text line} text object append title: {object, string buffer} void end public func open (m: open interface, o: text object, l: text line) return open (m) {data (m), o, l} end public func append title (m: open interface, s: string buffer) append title (m) {data (m), s} end //[cf]