// History:
// Jan 02 13 tcolar Creation
//
**
** Nav : Navigation support ("file / items listings")
**
abstract class Nav
{
abstract ItemList list
abstract File root
Regex[] hideFiles
Int collapseLimit // auto-collapse limit
NavItemBuilder navBuilder
new make(Int collapseLimit, NavItemBuilder navBuilder)
{
this.collapseLimit = collapseLimit
this.navBuilder = navBuilder
Regex[] r := Regex[,]
try
{
Sys.cur.options.hidePatterns.each
{
r.add(Regex.fromStr(it))
}
}
catch(Err e)
{
Sys.log.err("Failed to load the hidden file patterns !", e)
}
hideFiles = r
}
** Highlight a file
Void highlight(File? file)
{
if(file == null) return
Int? index := list.files.eachWhile |item, index -> Int?|
{
return (item as FileItem).file.normalize == file.normalize ? index : null
}
if(index == null) return
list.highlight = list.items[index]
// if not in vieport then scroll to it
if( ! list.viewportLines.contains(index))
list.scrollToLine(index>=5 ? index-5 : 0)
list.repaint
}
** find items
Void findItems(File dir, Item[] results, Bool preserveLayout := false,
Str path:="", Int? cLimit := null,
Uri:Project projects := ProjectRegistry.projects)
{
dir.listFiles.sort |a, b| {a.name <=> b.name}.each |f|
{
if (! hidden(f))
{
results.add(navBuilder.forFile(f, path, 1))
}
}
dir.listDirs.sort |a, b| {a.name <=> b.name}.each |f|
{
if (! hidden(f))
{
if(projects.containsKey(f.normalize.uri))
{
// Not recursing in projects
prj := projects[f.normalize.uri]
item := navBuilder.forProj(prj, path, 1)
item.icon = prj.icon
results.add(item)
}
else
{
sub := f.list.findAll{! hidden(f)}.size
Bool? expandable := sub > (cLimit ?: collapseLimit) && sub != 0
if(preserveLayout)
{
// keep layout of existing item if known
expandable = list.findForFile(f)?.collapsed ?: expandable
}
if(expandable)
{
results.add(navBuilder.forDir(f, path, 0, true))
}
else
{
results.add(navBuilder.forDir(f, path, 0, false))
// recurse
findItems(f, results, preserveLayout, "${path}$f.name/", cLimit, projects)
}
}
}
}
}
private Bool hidden(File f)
{
hideFiles.eachWhile |Regex r -> Bool?| {
r.matches(f.uri.toStr) ? true : null} ?: false
}
virtual Void refresh(File? base := root)
{
if( ! base.isDir)
base = base.parent
FileItem[] newItems := [,]
// Refresh from the first base available in the tree
// because we can create many dirs at once it can be some ways up
while(base != null)
{
item := list.items.find{(it as FileItem).file.normalize == base.normalize}
if (item != null)
break
base = base.parent
}
if(base != null)
{
findItems(base, newItems, true)
list.refresh(base, newItems)
}
}
}