//[of]:license //[c]Code Browser - a folding text editor for programmers //[c]Copyright (C) 2003-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 "text/string" import "text/string-buffer" import "swift" import "editor/text-model" import "editor/text-view" //[c] import "application/strings-en" import "application/code-browser-application" import "application/text-file" //[c] import "multi-pane-window" import "zoom-edit-window" //[cf] //[c] //[of]:code browser window //[of]:description //[c]A single window object //[c] //[c]A code browser window wraps a group of text views that can be //[c]organized using different layouts, it adds to it the notion of //[c]stacked views. It can display one or more panes. //[c] //[c]It handles the navigation between folders and link. //[c]It has access to the file-database, it is able to open files when //[c]requesting the traversal of an hyperlink. //[cf] //[of]:definition private struct window class current text file: {object} text file active folder: {object} text object active view: {object} text view active line: {object, [] text object} text line open: {object, text file, text object} void enter: {object} void xleave: {object} void zoom: {object} void activate tree: {object} void goto page: {object, int} void goto local line: {object, int} void goto absolute line: {object, int} void cancel: {object, bool} void last visible page number: {object} int can activate tree: {object} bool can enter: {object} bool can leave: {object} bool has preview: {object} bool has first item: {object} bool has next item: {object} bool has prev item: {object} bool selection matches: {object, find data} bool show item: {object, bool} void show folder: {object, text object} void settings changed: {object, code browser settings, code browser settings} void end def multi pane class := const window class ( ^current text file (multi pane window), ^active folder (multi pane window), ^active view (multi pane window), ^active line (multi pane window, [] text object), ^open (multi pane window, text file, text object), ^enter (multi pane window), ^leave (multi pane window), ^do nothing (box), ^activate tree (multi pane window), ^goto page (multi pane window, int), ^goto local line (multi pane window, int), ^goto absolute line (multi pane window, int), ^cancel (multi pane window, bool), ^last visible page number (multi pane window), ^can activate tree (multi pane window), ^can enter (multi pane window), ^can leave (multi pane window), ^has preview (multi pane window), ^has first item (multi pane window), ^has next item (multi pane window), ^has prev item (multi pane window), ^selection matches (multi pane window, find data), ^show item (multi pane window, bool), ^show folder (multi pane window, text object), ^settings changed(multi pane window, code browser settings, code browser settings) ) def zoom edit class := const window class ( ^current text file (zoom edit window), ^active folder (zoom edit window), ^active view (zoom edit window), ^active line (zoom edit window, [] text object), ^open (zoom edit window, text file, text object) , ^enter (zoom edit window), ^leave (zoom edit window), ^zoom (zoom edit window), ^do nothing (box), ^goto page (zoom edit window, int), ^goto local line (zoom edit window, int), ^goto absolute line (zoom edit window, int), ^cancel (zoom edit window, bool), ^last visible page number (zoom edit window), ^can activate tree (zoom edit window), ^can enter (zoom edit window), ^can leave (zoom edit window), ^has preview (zoom edit window), ^has first item (zoom edit window), ^has next item (zoom edit window), ^has prev item (zoom edit window), ^selection matches (zoom edit window, find data), ^show item (zoom edit window, bool), ^show folder (zoom edit window, text object), ^settings changed(zoom edit window, code browser settings, code browser settings) ) //[c] public struct code browser window : local container box private // the application // to get language and file databases application : application mp : multi pane window ze : zoom edit window current window : box current class : window class mode: paned box mode a child has focus : bool end public struct code browser window class : local container box class end //[c] //[c]Internal aliases: //[c] private typedef window = code browser window private typedef application = code browser application //[cf] //[c] //[of]:instance creation //[of]:new code browser window (parent box, application) //[c] public func new code browser window (parent: box, application: application) def m = allocate memory (sizeof local code browser window) : window initialize (m, parent, application) return m end //[cf] //[of]:new code browser window (parent box, application, src window) //[c]Creates a new window by cloning an existing window: //[c]- same layout //[c]- same content in panes (including stack) //[c] public func new code browser window (parent: box, application: application, src: window) def m = allocate memory (sizeof local code browser window) : window initialize (m, parent, application, src) return m end //[cf] //[cf] //[of]:opening //[of]:open (text file) //[c]Opens the window on an existing text file //[c] //[c]This method can be used for the initial opening and //[c]also invoked later to recycle its content. //[c] public func open (m: window, text file: text file) open (m, text file, text (text file)) end //[cf] //[of]:open (text file, folder) //[c]Opens the window on an existing text file //[c] //[c]This method can be used for the initial opening and also invoked later //[c]to recycle its content. //[c] public func open (m: window, text file: text file, folder: text object) open (current class (m)) {current window (m), text file, folder} end //[cf] //[cf] //[of]:notifying //[of]:settings changed //[c]The user preferences have changed, requiring to update //[c]formats //[c] public func settings changed ( m: window, old settings: code browser settings, new settings: code browser settings) settings changed (current class (m)) { current window (m), old settings, new settings} end //[cf] //[cf] //[of]:browsing //[of]:enter //[c]Enters the current line //[c] public func enter (m: window) enter (current class (m)) {current window (m)} end //[cf] //[of]:leave //[c]Leaves the current folder //[c] public func leave (m: window) xleave (current class (m)) {current window (m)} end //[cf] //[of]:zoom public func zoom (m: window) zoom (current class (m)) {current window (m)} end //[cf] //[c] //[of]:first item //[c] public func first item (m: window) first headline (active view (m)) end //[cf] //[of]:next item //[c] public equ next item (m: window) = // the method is defined in the private area show item (m, false) //[cf] //[of]:prev item //[c] public equ prev item (m: window) = // the method is defined in the private area show item (m, true) //[cf] //[c] //[of]:goto page //[c]Goto local line //[c] //[c] Note: line number starts to 0. //[c] public func goto page (m: window, n: int) goto page (current class (m)) {current window (m), n} end //[cf] //[of]:goto local line //[c]Goto local line //[c] //[c] Note: line number starts to 0. //[c] public func goto local line (m: window, n: int) goto local line (current class (m)) {current window (m), n} end //[cf] //[of]:goto absolute line //[c]Goto absolute line //[c] //[c] Note: line number starts to 0. //[c] public func goto absolute line (m: window, n: int) goto absolute line (current class (m)) {current window (m), n} end //[cf] //[c] //[of]:show folder //[c]Make a folder visible at the best position //[c] public func show folder (m: window, folder: text object) show folder (current class (m)) {current window (m), folder} end //[cf] //[cf] //[of]:editing //[of]:undo public func undo (m: window) cancel (m, false) end //[cf] //[of]:redo public func redo (m: window) cancel (m, true) end //[cf] //[of]:cancel //[c]Cancel last operation //[c] //[c] This is the common method for undo and redo //[c] public func cancel (m: window, redo: bool) cancel (current class (m)) {current window (m), redo} end //[cf] //[c] //[of]:replace all public func replace all (m: window, data: find data) def replaced count = 0 def view = active view (m) def folder = (scope (data) == find in local folder -> active folder (m), root folder (current text file (m))) def start folder = folder def pos := top left position (folder) def text line = text line (pos) def buf = buf (text line) def col = column (pos) def limit = search limit (data, size (text line)) start group (start folder) // macro to test if search can go trough folder equ can go up (f: text object, d: find data) = not nil (parent folder (f)) && scope (d) <> find in local folder repeat // search in current line if col < limit def n = match (data, buf, col) : int if n > 0 def res := replace (data, folder, text line, col) col = col (res) - 1 text line = line (res) buf = buf (text line) limit = search limit (data, size (text line)) ++ replaced count end end ++ col if col >= limit // get next search line if scope (data) <> find in local folder && is folder (text line) folder = text object (text line) text line = first line (folder) else text line = next (text line) // go up if no more lines if is nil (text line) while is nil (text line) && can go up (folder, data) text line = next (parent line (folder)) folder = parent folder (folder) end end // end of folder reached if is nil (text line) break end end limit = search limit (data, size (text line)) buf = buf (text line) col = 0 end end stop group (start folder) return replaced count end //[cf] //[of]:replace selection public func replace selection (m: window, s: string) replace selection (active view (m), s) end //[cf] //[cf] //[of]:accessing //[of]:current text file //[c]Returns the active text file of the window //[c]i.e. the text file of the folder currently edited by this window. //[c] public func current text file (m: window) return current text file (current class (m)) {current window (m)} end //[cf] //[of]:active folder //[c]Returns the current edited folder //[c] public func active folder (m: window) return active folder (current class (m)) {current window (m)} end //[cf] //[of]:active view //[c]Returns the view of the active pane //[c] public func active view (m: window) return active view (current class (m)) {current window (m)} end //[cf] //[of]:active line //[c]Returns the view of the active pane //[c] public func active line (m: window, folder: [] text object) return active line (current class (m)) {current window (m), folder} end //[cf] //[c] //[of]:append description //[c]Appends a description of the window to the string buffer //[c] public func append description ( m: window, s: string buffer) def text file = current text file (m) if is nil (text file) return end append description (text file, s) def folder = active folder (m) if not empty (title (folder)) s << " - " // the description must not contain any tab char // initial blanks (tab or spaces) are ignored, other // tabs are replaced by space chars def p = title (folder) while is blank (p[]) ++p end repeat def c = p++ [] if is nul (c) break end if c == \t c == \w end s << c end end end //[cf] //[of]:append filename public func append filename (m: window, t: string buffer) def text file = current text file (m) if not nil (text file) append description (text file, t) end end //[cf] //[c] //[of]:set layout //[c]Changes the layout //[c] public func set layout (m: window, mode: paned box mode) if mode (m) == mode return end mode (m) = mode if mode == pbm page if is nil (ze (m)) ze (m) = new zoom edit window (m, application (m)) if activated (m) activate (ze (m)) invalidate min size (m) invalidate (m) end end current window (m) = ze (m) current class (m) = zoom edit class def mp = mp (m) if not nil (mp) def text file = current text file (mp) def view = active view (mp) def folder = text (view) open (ze (m), text file, folder) delete (mp) mp (m) = nil end else if is nil (mp (m)) mp (m) = new multi pane window (m, application (m)) if activated (m) activate (mp (m)) invalidate min size (m) invalidate (m) end end current window (m) = mp (m) current class (m) = multi pane class def ze = ze (m) if not nil (ze) def text file = current text file (ze) def view = active view (ze) def folder = text (view) open (mp (m), text file, folder) delete (ze) ze (m) = nil end set layout (mp (m), mode) end show (current window (m)) if a child has focus (m) set focus (current window (m)) end end //[cf] //[of]:layout //[c] public func layout (m: window) return mode (m) end //[cf] //[of]:activate tree public func activate tree (m: window) activate tree (current class (m)) {current window (m)} end //[cf] //[of]:last visible page number //[c]Returns the page number of the last visible pane //[c] public func last visible page number (m: window) return last visible page number (current class (m)) {current window (m)} end //[cf] //[cf] //[of]:testing //[of]:can activate tree //[c]Returns true if 'activate tree' action is valid //[c] public func can activate tree (m: window) return can activate tree (current class (m)) {current window (m)} end //[cf] //[of]:can enter //[c]Returns true if enter action is valid //[c] public func can enter (m: window) return can enter (current class (m)) {current window (m)} end //[cf] //[of]:can leave //[c]Returns true if leave action is valid //[c] public func can leave (m: window) return can leave (current class (m)) {current window (m)} end //[cf] //[c] //[of]:has preview public func has preview (m: window) return has preview (current class (m)) {current window (m)} end //[cf] //[of]:has first item //[c]Tests if there is a first item //[c] public func has first item (m: window) return has first item (current class (m)) {current window (m)} end //[cf] //[of]:has next item //[c]Tests if there is a next item //[c] public func has next item (m: window) return has next item (current class (m)) {current window (m)} end //[cf] //[of]:has prev item //[c]Tests if there is a next item //[c] public func has prev item (m: window) return has prev item (current class (m)) {current window (m)} end //[cf] //[c] //[of]:selection matches //[c]Returns true if the current selection in the active pane matches with the //[c]searched string (find data). //[c] public func selection matches (m: window, data: find data) return selection matches (current class (m)) {current window (m), data} end //[cf] //[cf] //[c] //[of]:restricted //[of]:class accessing //[of]:code browser window class public func code browser window class def c = the code browser window class if ~ initialized initialized = true copy (c, container box class) mem size (c) = sizeof local code browser window class release (c) = ^actual release (window) compute min size (c) = ^min size of union (box) on size (c) = ^adjust to parent (box) on focus (c) = ^focus to first visible (box, event) adjust (c) = ^adjust to parent (box) on child event (c) = ^handle child event (window, box, event) accept focus (c) = ^yes (box) on focus (c) = ^handle focus (window, event) end return c end private def initialized = false private def the code browser window class : local code browser window class //[cf] //[cf] //[of]:initializing //[of]:initialize (parent box, application) public func initialize ( m: window, parent: box, application: application) initialize (super (m), parent) class (m) = code browser window class application (m) = application mp (m) = nil ze (m) = nil current window (m) = nil current class (m) = nil mode (m) = -1 : paned box mode a child has focus (m) = false end //[cf] //[of]:initialize (parent box, application, src window) public func initialize ( m: window, parent: box, application: application, src: window) initialize (m, parent, application) mode (m) = mode (src) if not nil (mp (src)) mp (m) = new multi pane window (m, application (m), mp (src)) current window (m) = mp (m) current class (m) = multi pane class else ze (m) = new zoom edit window (m, application (m), ze (src)) current window (m) = ze (m) current class (m) = zoom edit class end if activated (m) activate (current window (m)) invalidate min size (m) invalidate (m) end end //[cf] //[cf] //[of]:box interface implementation //[of]:actual relase public func actual release (m: window) actual release (super (m)) end //[cf] //[of]:handle focus //[c]The notebook receives the focus: transfer the focus to the current page //[c] public func handle focus (m: window, e: event) set focus (current window (m)) return true end //[cf] //[of]:handle child event public func handle child event (m: window, child: box, e: event) def t = type (e) if t == focus event type a child has focus (m) = true elsif t == blur event type a child has focus (m) = false elsif t == folder destroyed event type // re-emit the event notify parent (m, e) return true end return handle child event (super (m), child, e) end //[cf] //[cf] //[cf] //[of]:private //[of]:browsing //[of]:show item //[c]Selects the next or previous item //[c] func show item (m: window, reverse: bool) show item (current class (m)) {current window (m), reverse} end //[c] //[cf] //[cf] //[cf] //[cf] //[c] //[c]private: //[l]:multi pane window:multi-pane-window.zc //[l]:zoom edit window:zoom-edit-window.zc