Commits

Iñigo Serna committed e6a6967

Clean code. Moved Tree class to messages.py.

* lfm/messages.py (Tree): class moved to messages.py

* lfm/lfm.py (Lfm.run): clean code
* lfm/actions.py (new_tab):
* lfm/actions.py (close_tab):
* lfm/lfm.py (get_filetypecolorpair): refactor the method out of class Pane

* lfm/actions.py (keytable): changed function name
* lfm/actions.py (change_panes_mode): changed function name

Comments (0)

Files changed (5)

+Sun May 22 20:07:27 2011  Iñigo Serna  <inigoserna@gmail.com>
+
+	* lfm/messages.py (Tree): class moved to messages.py
+
+Sun May 22 20:04:26 2011  Iñigo Serna  <inigoserna@gmail.com>
+
+	* lfm/lfm.py (Lfm.run): clean code
+	* lfm/actions.py (new_tab):
+	* lfm/actions.py (close_tab):
+	* lfm/lfm.py (get_filetypecolorpair): refactor the method out of class Pane
+
+Sun May 22 20:03:36 2011  Iñigo Serna  <inigoserna@gmail.com>
+
+	* lfm/actions.py (keytable): changed function name
+	* lfm/actions.py (change_panes_mode): changed function name
+
 Sat May 21 12:13:23 2011  Iñigo Serna  <inigoserna@gmail.com>
 
     * setup.py: updated to v2.3
     - pyview:
       . use mmap
       . tail mode: option -f, document
+        . http://code.activestate.com/recipes/577710-tail-a-continuously-growing-file-like-tail-f-filen/
     - powercli: |: run as tail -f, substitute run sync by default, document
     - diff and sync dirs: use filecmp.dircmp or rsync
 
 
     # panels
     ord('\t'): 'toggle_active_pane',  # tab
-    ord('.'): 'toggle_panes',
+    ord('.'): 'change_panes_mode',
     ord(','): 'swap_panes',
     0x15: 'swap_panes',        # Ctrl-U
     ord('='): 'same_tabs',
         return
     app.act_pane, app.noact_pane = app.noact_pane, app.act_pane
     tab.pane.display()
-    ans = Tree(tab.path, tab.pane.mode).run()
+    ans = messages.Tree(tab.path, tab.pane.mode).run()
     app.act_pane, app.noact_pane = app.noact_pane, app.act_pane
     if ans != -1:
         tab.init(ans)
     if tab.pane.mode in (PANE_MODE_LEFT, PANE_MODE_RIGHT):
         return RET_TOGGLE_PANE
 
-def toggle_panes(tab):
+def change_panes_mode(tab):
     if tab.pane.mode == PANE_MODE_FULL:
         # now => 2-panes mode
         app.lpane.mode, app.rpane.mode = PANE_MODE_LEFT, PANE_MODE_RIGHT
         othertab.vfs, othertab.base, othertab.vbase = pvfs, base, vbase
 
 def new_tab(tab):
-    if len(tab.pane.tabs) >= 4:
-        messages.error('Cannot create more tabs')
-    else:
-        return RET_TAB_NEW
+    return RET_TAB_NEW
 
 def close_tab(tab):
-    if len(tab.pane.tabs) == 1:
-        messages.error('Cannot close last tab')
-    else:
-        if tab.vfs:
-            vfs.exit(tab)
-        return RET_TAB_CLOSE
+    return RET_TAB_CLOSE
 
 def left_tab(tab):
     tabs = tab.pane.tabs
 
 
 ######################################################################
-##### Tree
-class Tree(object):
-    """Tree class"""
 
-    def __init__(self, path=os.sep, panemode=0):
-        if not os.path.exists(path):
-            raise ValueError, 'path does not exist'
-        self.panemode = panemode
-        self.__init_ui()
-        if path[-1] == os.sep and path != os.sep:
-            path = path[:-1]
-        self.path = path
-        self.tree = self.get_tree()
-        self.pos = self.__get_curpos()
-
-
-    def __get_dirs(self, path):
-        """return a list of dirs in path"""
-
-        ds = []
-        try:
-            ds = [d for d in os.listdir(path) \
-                      if os.path.isdir(os.path.join(path, d))]
-        except OSError:
-            pass
-        if not app.prefs.options['show_dotfiles']:
-            ds = [d for d in ds if d[0] != '.']
-        ds.sort()
-        return ds
-
-
-    def __get_graph(self, path):
-        """return 2 dicts with tree structure"""
-
-        tree_n = {}
-        tree_dir = {}
-        expanded = None
-        while path:
-            if path == os.sep and tree_dir.has_key(os.sep):
-                break
-            tree_dir[path] = (self.__get_dirs(path), expanded)
-            expanded = os.path.basename(path)
-            path = os.path.dirname(path)
-        dir_keys = tree_dir.keys()
-        dir_keys.sort()
-        for n, d in enumerate(dir_keys):
-            tree_n[n] = d
-        return tree_n, tree_dir
-
-
-    def __get_node(self, i, tn, td, base):
-        """expand branch"""
-
-        lst2 = []
-        node = tn[i]
-        dirs, expanded_node = td[node]
-        if not expanded_node:
-            return []
-        for d in dirs:
-            if d == expanded_node:
-                lst2.append([d, i, os.path.join(base, d)])
-                lst3 = self.__get_node(i+1, tn, td, os.path.join(base, d))
-                if lst3 is not None:
-                    lst2.extend(lst3)
-            else:
-                lst2.append([d, i, os.path.join(base, d)])
-        return lst2
-
-
-    def get_tree(self):
-        """return list with tree structure"""
-
-        tn, td = self.__get_graph(self.path)
-        tree = [[os.sep, -1, os.sep]]
-        tree.extend(self.__get_node(0, tn, td, os.sep))
-        return tree
-
-
-    def __get_curpos(self):
-        """get position of current dir"""
-
-        for i in xrange(len(self.tree)):
-            if self.path == self.tree[i][2]:
-                return i
-        else:
-            return -1
-
-
-    def regenerate_tree(self, newpos):
-        """regenerate tree when changing to a new directory"""
-
-        self.path = self.tree[newpos][2]
-        self.tree = self.get_tree()
-        self.pos = self.__get_curpos()
-
-
-    def show_tree(self, a=0, z=-1):
-        """show an ascii representation of the tree. Not used in lfm"""
-
-        if z > len(self.tree) or z == -1:
-            z = len(self.tree)
-        for i in xrange(a, z):
-            name, depth, fullname = self.tree[i]
-            if fullname == self.path:
-                name += ' <====='
-            if name == os.sep:
-                print encode(' ' + name)
-            else:
-                print encode(' | ' * depth + ' +- ' + name)
-
-
-    # GUI functions
-    def __init_ui(self):
-        """initialize curses stuff"""
-
-        self.__calculate_dims()
-        try:
-            self.win = curses.newwin(*self.dims)
-        except curses.error:
-            print 'Can\'t create tree window'
-            sys.exit(-1)
-        self.win.keypad(1)
-        if curses.has_colors():
-            self.win.bkgd(curses.color_pair(2))
-
-
-    def __calculate_dims(self):
-        if self.panemode == PANE_MODE_LEFT:
-            self.dims = (app.maxh-2, int(app.maxw/2), 1, int(app.maxw/2))
-        elif self.panemode in (PANE_MODE_RIGHT, PANE_MODE_FULL):
-            self.dims = (app.maxh-2, int(app.maxw/2), 1, 0)
-        else: # PANE_MODE_HIDDEN:
-            self.dims = (app.maxh-2, 0, 0, 0)     # h, w, y, x
-
-
-    def display(self):
-        """show tree panel"""
-
-        self.win.erase()
-        h = app.maxh - 4
-        n = len(self.tree)
-        # box
-        self.win.attrset(curses.color_pair(5))
-        self.win.box()
-        self.win.addstr(0, 2, ' Tree ', curses.color_pair(6) | curses.A_BOLD)
-        # tree
-        self.win.attrset(curses.color_pair(2))
-        j = 0
-        a = int(self.pos/h) * h
-        z = (int(self.pos/h) + 1) * h
-        if z > n:
-            a = max(n-h, 0); z = n
-        for i in xrange(a, z):
-            j += 1
-            name, depth, fullname = self.tree[i]
-            if name == os.sep:
-                self.win.addstr(j, 1, ' ')
-            else:
-                self.win.move(j, 1)
-                for kk in xrange(depth):
-                    self.win.addstr(' ')
-                    self.win.addch(curses.ACS_VLINE)
-                    self.win.addstr(' ')
-                self.win.addstr(' ')
-                if i == n - 1:
-                    self.win.addch(curses.ACS_LLCORNER)
-                elif depth > self.tree[i+1][1]:
-                    self.win.addch(curses.ACS_LLCORNER)
-                else:
-                    self.win.addch(curses.ACS_LTEE)
-                self.win.addch(curses.ACS_HLINE)
-                self.win.addstr(' ')
-            w = int(app.maxw / 2) - 2
-            wd = 3 * depth + 4
-            if fullname == self.path:
-                self.win.addstr(encode(name[:w-wd-3]), curses.color_pair(3))
-                child_dirs = self.__get_dirs(self.path)
-                if len(child_dirs) > 0:
-                    self.win.addstr(' ')
-                    self.win.addch(curses.ACS_HLINE)
-                    self.win.addch(curses.ACS_RARROW)
-            else:
-                self.win.addstr(encode(name[:w-wd]))
-        # scrollbar
-        if n > h:
-            nn = max(int(h*h/n), 1)
-            y0 = min(max(int(int(self.pos/h)*h*h/n), 0), h-nn)
-        else:
-            y0 = nn = 0
-        self.win.attrset(curses.color_pair(5))
-        self.win.vline(y0 + 2, int(app.maxw/2) - 1, curses.ACS_CKBOARD, nn)
-        if a != 0:
-            self.win.vline(1, int(app.maxw/2) - 1, '^', 1)
-            if nn == 1 and (y0 + 2 == 2):
-                self.win.vline(3, int(app.maxw/2) - 1, curses.ACS_CKBOARD, nn)
-        if n - 1 > a + h - 1:
-            self.win.vline(h, int(app.maxw/2) - 1, 'v', 1)
-            if nn == 1 and (y0 + 2 == h + 1):
-                self.win.vline(h, int(app.maxw/2) - 1, curses.ACS_CKBOARD, nn)
-        # status
-        app.statusbar.win.erase()
-        wp = app.maxw - 8
-        if len(self.path) > wp:
-            path = self.path[:int(wp/2) -1] + '~' + self.path[-int(wp/2):]
-        else:
-            path = self.path
-        app.statusbar.win.addstr(' Path: %s' % encode(path))
-        app.statusbar.win.refresh()
-
-
-    def run(self):
-        """manage keys"""
-
-        while True:
-            self.display()
-            chext = 0
-            ch = self.win.getch()
-
-            # to avoid extra chars input
-            if ch == 0x1B:
-                chext = 1
-                ch = self.win.getch()
-                ch = self.win.getch()
-
-            # cursor up
-            if ch in (ord('k'), ord('K'), curses.KEY_UP):
-                if self.pos == 0:
-                    continue
-                if self.tree[self.pos][1] != self.tree[self.pos-1][1]:
-                    continue
-                newpos = self.pos - 1
-            # cursor down
-            elif ch in (ord('j'), ord('j'), curses.KEY_DOWN):
-                if self.pos == len(self.tree) - 1:
-                    continue
-                if self.tree[self.pos][1] != self.tree[self.pos+1][1]:
-                    continue
-                newpos = self.pos + 1
-            # page previous
-            elif ch in (curses.KEY_PPAGE, curses.KEY_BACKSPACE, 0x02):
-                # BackSpace, Ctrl-B
-                depth = self.tree[self.pos][1]
-                if self.pos - (app.maxh-4) >= 0:
-                    if depth  == self.tree[self.pos - (app.maxh-4)][1]:
-                        newpos = self.pos - (app.maxh-4)
-                    else:
-                        newpos = self.pos
-                        while 1:
-                            if newpos - 1 < 0 or self.tree[newpos-1][1] != depth:
-                                break
-                            newpos -= 1
-                else:
-                    newpos = self.pos
-                    while True:
-                        if newpos - 1 < 0 or self.tree[newpos-1][1] != depth:
-                            break
-                        newpos -= 1
-            # page next
-            elif ch in (curses.KEY_NPAGE, ord(' '), 0x06):   # Ctrl-F
-                depth = self.tree[self.pos][1]
-                if self.pos + (app.maxh-4) <= len(self.tree) - 1:
-                    if depth  == self.tree[self.pos + (app.maxh-4)][1]:
-                        newpos = self.pos + (app.maxh-4)
-                    else:
-                        newpos = self.pos
-                        while True:
-                            if newpos + 1 == len(self.tree) or \
-                                    self.tree[newpos+1][1] != depth:
-                                break
-                            newpos += 1
-                else:
-                    newpos = self.pos
-                    while True:
-                        if newpos + 1 == len(self.tree) or \
-                                self.tree[newpos+1][1] != depth:
-                            break
-                        newpos += 1
-            # home
-            elif (ch in (curses.KEY_HOME, 0x01)) or \
-                 (chext == 1) and (ch == 72):  # home, Ctrl-A
-                newpos = 1
-            # end
-            elif (ch in (curses.KEY_END, 0x05)) or \
-                 (chext == 1) and (ch == 70):   # end, Ctrl-E
-                newpos = len(self.tree) - 1
-            # cursor left
-            elif ch == curses.KEY_LEFT:
-                if self.pos == 0:
-                    continue
-                newdepth = self.tree[self.pos][1] - 1
-                for i in xrange(self.pos-1, -1, -1):
-                    if self.tree[i][1] == newdepth:
-                        break
-                newpos = i
-            # cursor right
-            elif ch == curses.KEY_RIGHT:
-                child_dirs = self.__get_dirs(self.path)
-                if len(child_dirs) > 0:
-                    self.path = os.path.join(self.path, child_dirs[0])
-                    self.tree = self.get_tree()
-                    self.pos = self.__get_curpos()
-                continue
-            # enter
-            elif ch in (10, 13):
-                return self.path
-            # resize
-            elif ch == curses.KEY_RESIZE:
-                curses.doupdate()
-                app.resize()
-                self.__calculate_dims()
-                self.win.resize(self.dims[0], self.dims[1])
-                self.win.mvwin(self.dims[2], self.dims[3])
-                continue
-            # toggle .dot-files
-            elif ch == 0x08:    # Ctrl-H
-                toggle_dotfiles(None)
-                if self.pos != 0 and os.path.basename(self.path)[0] == '.':
-                    newdepth = self.tree[self.pos][1] - 1
-                    for i in xrange(self.pos-1, -1, -1):
-                        if self.tree[i][1] == newdepth:
-                            break
-                    newpos = i
-                else:
-                    newpos = self.pos
-            # quit
-            elif ch in (ord('q'), ord('Q'), curses.KEY_F10, 0x03):  # Ctrl-C
-                return -1
-            # else
-            else:
-                continue
-
-            # update
-            self.regenerate_tree(newpos)
-
-
-######################################################################
-
 # -*- coding: utf-8 -*-
 
 # Copyright (C) 2001-11  Iñigo Serna
-# Time-stamp: <2011-05-21 11:58:14 inigo>
+# Time-stamp: <2011-05-22 20:21:19 inigo>
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 ######################################################################
 ##### Global variables
 LOG_FILE = os.path.join(os.getcwd(), 'lfm.log')
+MAX_TABS = 4
 MAX_TAB_HISTORY = 15
 
 
                 else:
                     self.act_pane, self.noact_pane = self.lpane, self.rpane
             elif ret == RET_TAB_NEW:
-                tab = self.act_pane.act_tab
-                path = tab.path if tab.vfs=='' else os.path.dirname(tab.vbase)
-                idx = self.act_pane.tabs.index(tab)
-                newtab = TabVfs(self.act_pane)
-                newtab.init(path)
-                self.act_pane.tabs.insert(idx+1, newtab)
-                self.act_pane.act_tab = newtab
+                if len(self.act_pane.tabs) >= MAX_TABS:
+                    messages.error('Cannot create more tabs')
+                else:
+                    tab = self.act_pane.act_tab
+                    path = tab.path if tab.vfs=='' else os.path.dirname(tab.vbase)
+                    idx = self.act_pane.tabs.index(tab)
+                    newtab = TabVfs(self.act_pane)
+                    newtab.init(path)
+                    self.act_pane.tabs.insert(idx+1, newtab)
+                    self.act_pane.act_tab = newtab
             elif ret == RET_TAB_CLOSE:
-                tab = self.act_pane.act_tab
-                idx = self.act_pane.tabs.index(tab)
-                self.act_pane.act_tab = self.act_pane.tabs[idx-1]
-                self.act_pane.tabs.remove(tab)
-                del tab
+                if len(self.act_pane.tabs) == 1:
+                    messages.error('Cannot close last tab')
+                else:
+                    tab = self.act_pane.act_tab
+                    if tab.vfs:
+                        vfs.exit(tab)
+                    idx = self.act_pane.tabs.index(tab)
+                    self.act_pane.act_tab = self.act_pane.tabs[idx-1]
+                    self.act_pane.tabs.remove(tab)
+                    del tab
 
 
 ######################################################################
                 # except Exception as msg: # python v2.6+
                 except Exception, msg:
                     messages.error('Cannot execute PowerCLI command:\n  %s\n\n%s' % \
-                                       (cmd_orig, str(msg)))
+                                   (cmd_orig, str(msg)))
                     st = -1
                 else:
                     st = self.__run(cmd, tab.path, mode)
             # except Exception as msg: # python v2.6+
             except Exception, msg:
                 messages.error('Cannot execute PowerCLI command:\n  %s\n\n%s' % \
-                                   (cmd_orig, str(msg)))
+                               (cmd_orig, str(msg)))
             else:
                 st = self.__run(cmd, tab.path, mode)
 
         tabs = curses.newpad(1, self.dims[1]+1)
         tabs.bkgd(curses.color_pair(12))
         tabs.erase()
-        w = self.dims[1] / 4
+        w = self.dims[1] / MAX_TABS
         if w < 10:
             w = 5
         tabs.addstr(('[' + ' '*(w-2) + ']') * len(self.tabs))
         tabs.refresh(0, 0, 0, self.dims[3],  1, self.dims[3]+self.dims[1]-1)
 
 
-    def get_filetypecolorpair(self, f, typ):
-        if typ == files.FTYPE_DIR:
-            return curses.color_pair(22)
-        elif typ == files.FTYPE_EXE:
-            return curses.color_pair(23)  | curses.A_BOLD
-        ext = os.path.splitext(f)[1].lower()
-        files_ext = self.app.prefs.files_ext
-        if ext in files_ext['temp_files']:
-            return curses.color_pair(13)
-        elif ext in files_ext['document_files']:
-            return curses.color_pair(14)
-        elif ext in files_ext['media_files']:
-            return curses.color_pair(15)
-        elif ext in files_ext['archive_files']:
-            return curses.color_pair(16)
-        elif ext in files_ext['source_files']:
-            return curses.color_pair(17)
-        elif ext in files_ext['graphics_files']:
-            return curses.color_pair(18)
-        elif ext in files_ext['data_files']:
-            return curses.color_pair(19)
-        else:
-            return curses.color_pair(2)
-
-
     def display_files(self):
         tab = self.act_tab
         self.win.erase()
                 attr = curses.color_pair(10) | curses.A_BOLD
             else:
                 if self.app.prefs.options['color_files']:
-                    attr = self.get_filetypecolorpair(filename, tab.files[filename][files.FT_TYPE])
+                    attr = get_filetypecolorpair(filename,
+                                                 tab.files[filename][files.FT_TYPE],
+                                                 self.app.prefs.files_ext)
                 else:
                     attr = curses.color_pair(2)
             # show
     return (len(num) < 4) and num or (num2str(num[:-3])+","+num[-3:])
 
 
+def get_filetypecolorpair(f, ftype, files_ext):
+    if ftype == files.FTYPE_DIR:
+        return curses.color_pair(22)
+    elif ftype == files.FTYPE_EXE:
+        return curses.color_pair(23)  | curses.A_BOLD
+    ext = os.path.splitext(f)[1].lower()
+    if ext in files_ext['temp_files']:
+        return curses.color_pair(13)
+    elif ext in files_ext['document_files']:
+        return curses.color_pair(14)
+    elif ext in files_ext['media_files']:
+        return curses.color_pair(15)
+    elif ext in files_ext['archive_files']:
+        return curses.color_pair(16)
+    elif ext in files_ext['source_files']:
+        return curses.color_pair(17)
+    elif ext in files_ext['graphics_files']:
+        return curses.color_pair(18)
+    elif ext in files_ext['data_files']:
+        return curses.color_pair(19)
+    else:
+        return curses.color_pair(2)
+
+
 ######################################################################
 ##### Main
 def usage(msg=''):
 import os.path
 import curses
 import curses.panel
+
+from __init__ import *
 import files
 import utils
 
 
 
 ######################################################################
+##### Windows
 class BaseWindow(object):
     """Base class for CommonWindow and FixSizeWindow classes"""
 
 
 
 ######################################################################
+##### EntryLine
 class EntryLine(object):
     """An entry line to enter a dir. or file, a pattern, etc"""
 
 
 
 ######################################################################
+##### Entry
 class Entry(object):
     """An entry window to enter a dir. or file, a pattern, ..."""
 
 
 
 ######################################################################
+##### DoubleEntry
 class DoubleEntry(object):
     """An entry window to enter 2 dirs. or files, patterns, ..."""
 
 
 
 ######################################################################
+##### SelecItem
 class SelectItem(object):
     """A window to select an item"""
 
 
 
 ######################################################################
+##### FindfilesWin
 class FindfilesWin(object):
     """A window to select a file"""
 
 
 
 ######################################################################
+##### MenuWin
 class MenuWin(object):
     """A window to select a menu option"""
 
 
 
 ######################################################################
+##### ChangePerms
 class ChangePerms(object):
     """A window to change permissions, owner or group"""
 
 
 
 ######################################################################
+##### Tree
+class Tree(object):
+    """Tree class"""
+
+    def __init__(self, path=os.sep, panemode=0):
+        if not os.path.exists(path):
+            raise ValueError, 'path does not exist'
+        self.panemode = panemode
+        self.__init_ui()
+        if path[-1] == os.sep and path != os.sep:
+            path = path[:-1]
+        self.path = path
+        self.tree = self.get_tree()
+        self.pos = self.__get_curpos()
+
+
+    def __get_dirs(self, path):
+        """return a list of dirs in path"""
+
+        ds = []
+        try:
+            ds = [d for d in os.listdir(path) \
+                      if os.path.isdir(os.path.join(path, d))]
+        except OSError:
+            pass
+        if not app.prefs.options['show_dotfiles']:
+            ds = [d for d in ds if d[0] != '.']
+        ds.sort()
+        return ds
+
+
+    def __get_graph(self, path):
+        """return 2 dicts with tree structure"""
+
+        tree_n = {}
+        tree_dir = {}
+        expanded = None
+        while path:
+            if path == os.sep and tree_dir.has_key(os.sep):
+                break
+            tree_dir[path] = (self.__get_dirs(path), expanded)
+            expanded = os.path.basename(path)
+            path = os.path.dirname(path)
+        dir_keys = tree_dir.keys()
+        dir_keys.sort()
+        for n, d in enumerate(dir_keys):
+            tree_n[n] = d
+        return tree_n, tree_dir
+
+
+    def __get_node(self, i, tn, td, base):
+        """expand branch"""
+
+        lst2 = []
+        node = tn[i]
+        dirs, expanded_node = td[node]
+        if not expanded_node:
+            return []
+        for d in dirs:
+            if d == expanded_node:
+                lst2.append([d, i, os.path.join(base, d)])
+                lst3 = self.__get_node(i+1, tn, td, os.path.join(base, d))
+                if lst3 is not None:
+                    lst2.extend(lst3)
+            else:
+                lst2.append([d, i, os.path.join(base, d)])
+        return lst2
+
+
+    def get_tree(self):
+        """return list with tree structure"""
+
+        tn, td = self.__get_graph(self.path)
+        tree = [[os.sep, -1, os.sep]]
+        tree.extend(self.__get_node(0, tn, td, os.sep))
+        return tree
+
+
+    def __get_curpos(self):
+        """get position of current dir"""
+
+        for i in xrange(len(self.tree)):
+            if self.path == self.tree[i][2]:
+                return i
+        else:
+            return -1
+
+
+    def regenerate_tree(self, newpos):
+        """regenerate tree when changing to a new directory"""
+
+        self.path = self.tree[newpos][2]
+        self.tree = self.get_tree()
+        self.pos = self.__get_curpos()
+
+
+    def show_tree(self, a=0, z=-1):
+        """show an ascii representation of the tree. Not used in lfm"""
+
+        if z > len(self.tree) or z == -1:
+            z = len(self.tree)
+        for i in xrange(a, z):
+            name, depth, fullname = self.tree[i]
+            if fullname == self.path:
+                name += ' <====='
+            if name == os.sep:
+                print utils.encode(' ' + name)
+            else:
+                print utils.encode(' | ' * depth + ' +- ' + name)
+
+
+    # GUI functions
+    def __init_ui(self):
+        """initialize curses stuff"""
+
+        self.__calculate_dims()
+        try:
+            self.win = curses.newwin(*self.dims)
+        except curses.error:
+            print 'Can\'t create tree window'
+            sys.exit(-1)
+        self.win.keypad(1)
+        if curses.has_colors():
+            self.win.bkgd(curses.color_pair(2))
+
+
+    def __calculate_dims(self):
+        if self.panemode == PANE_MODE_LEFT:
+            self.dims = (app.maxh-2, int(app.maxw/2), 1, int(app.maxw/2))
+        elif self.panemode in (PANE_MODE_RIGHT, PANE_MODE_FULL):
+            self.dims = (app.maxh-2, int(app.maxw/2), 1, 0)
+        else: # PANE_MODE_HIDDEN:
+            self.dims = (app.maxh-2, 0, 0, 0)     # h, w, y, x
+
+
+    def display(self):
+        """show tree panel"""
+
+        self.win.erase()
+        h = app.maxh - 4
+        n = len(self.tree)
+        # box
+        self.win.attrset(curses.color_pair(5))
+        self.win.box()
+        self.win.addstr(0, 2, ' Tree ', curses.color_pair(6) | curses.A_BOLD)
+        # tree
+        self.win.attrset(curses.color_pair(2))
+        j = 0
+        a = int(self.pos/h) * h
+        z = (int(self.pos/h) + 1) * h
+        if z > n:
+            a = max(n-h, 0); z = n
+        for i in xrange(a, z):
+            j += 1
+            name, depth, fullname = self.tree[i]
+            if name == os.sep:
+                self.win.addstr(j, 1, ' ')
+            else:
+                self.win.move(j, 1)
+                for kk in xrange(depth):
+                    self.win.addstr(' ')
+                    self.win.addch(curses.ACS_VLINE)
+                    self.win.addstr(' ')
+                self.win.addstr(' ')
+                if i == n - 1:
+                    self.win.addch(curses.ACS_LLCORNER)
+                elif depth > self.tree[i+1][1]:
+                    self.win.addch(curses.ACS_LLCORNER)
+                else:
+                    self.win.addch(curses.ACS_LTEE)
+                self.win.addch(curses.ACS_HLINE)
+                self.win.addstr(' ')
+            w = int(app.maxw / 2) - 2
+            wd = 3 * depth + 4
+            if fullname == self.path:
+                self.win.addstr(utils.encode(name[:w-wd-3]), curses.color_pair(3))
+                child_dirs = self.__get_dirs(self.path)
+                if len(child_dirs) > 0:
+                    self.win.addstr(' ')
+                    self.win.addch(curses.ACS_HLINE)
+                    self.win.addch(curses.ACS_RARROW)
+            else:
+                self.win.addstr(utils.encode(name[:w-wd]))
+        # scrollbar
+        if n > h:
+            nn = max(int(h*h/n), 1)
+            y0 = min(max(int(int(self.pos/h)*h*h/n), 0), h-nn)
+        else:
+            y0 = nn = 0
+        self.win.attrset(curses.color_pair(5))
+        self.win.vline(y0 + 2, int(app.maxw/2) - 1, curses.ACS_CKBOARD, nn)
+        if a != 0:
+            self.win.vline(1, int(app.maxw/2) - 1, '^', 1)
+            if nn == 1 and (y0 + 2 == 2):
+                self.win.vline(3, int(app.maxw/2) - 1, curses.ACS_CKBOARD, nn)
+        if n - 1 > a + h - 1:
+            self.win.vline(h, int(app.maxw/2) - 1, 'v', 1)
+            if nn == 1 and (y0 + 2 == h + 1):
+                self.win.vline(h, int(app.maxw/2) - 1, curses.ACS_CKBOARD, nn)
+        # status
+        app.statusbar.win.erase()
+        wp = app.maxw - 8
+        if len(self.path) > wp:
+            path = self.path[:int(wp/2) -1] + '~' + self.path[-int(wp/2):]
+        else:
+            path = self.path
+        app.statusbar.win.addstr(' Path: %s' % utils.encode(path))
+        app.statusbar.win.refresh()
+
+
+    def run(self):
+        """manage keys"""
+
+        while True:
+            self.display()
+            chext = 0
+            ch = self.win.getch()
+
+            # to avoid extra chars input
+            if ch == 0x1B:
+                chext = 1
+                ch = self.win.getch()
+                ch = self.win.getch()
+
+            # cursor up
+            if ch in (ord('k'), ord('K'), curses.KEY_UP):
+                if self.pos == 0:
+                    continue
+                if self.tree[self.pos][1] != self.tree[self.pos-1][1]:
+                    continue
+                newpos = self.pos - 1
+            # cursor down
+            elif ch in (ord('j'), ord('j'), curses.KEY_DOWN):
+                if self.pos == len(self.tree) - 1:
+                    continue
+                if self.tree[self.pos][1] != self.tree[self.pos+1][1]:
+                    continue
+                newpos = self.pos + 1
+            # page previous
+            elif ch in (curses.KEY_PPAGE, curses.KEY_BACKSPACE, 0x02):
+                # BackSpace, Ctrl-B
+                depth = self.tree[self.pos][1]
+                if self.pos - (app.maxh-4) >= 0:
+                    if depth  == self.tree[self.pos - (app.maxh-4)][1]:
+                        newpos = self.pos - (app.maxh-4)
+                    else:
+                        newpos = self.pos
+                        while 1:
+                            if newpos - 1 < 0 or self.tree[newpos-1][1] != depth:
+                                break
+                            newpos -= 1
+                else:
+                    newpos = self.pos
+                    while True:
+                        if newpos - 1 < 0 or self.tree[newpos-1][1] != depth:
+                            break
+                        newpos -= 1
+            # page next
+            elif ch in (curses.KEY_NPAGE, ord(' '), 0x06):   # Ctrl-F
+                depth = self.tree[self.pos][1]
+                if self.pos + (app.maxh-4) <= len(self.tree) - 1:
+                    if depth  == self.tree[self.pos + (app.maxh-4)][1]:
+                        newpos = self.pos + (app.maxh-4)
+                    else:
+                        newpos = self.pos
+                        while True:
+                            if newpos + 1 == len(self.tree) or \
+                                    self.tree[newpos+1][1] != depth:
+                                break
+                            newpos += 1
+                else:
+                    newpos = self.pos
+                    while True:
+                        if newpos + 1 == len(self.tree) or \
+                                self.tree[newpos+1][1] != depth:
+                            break
+                        newpos += 1
+            # home
+            elif (ch in (curses.KEY_HOME, 0x01)) or \
+                 (chext == 1) and (ch == 72):  # home, Ctrl-A
+                newpos = 1
+            # end
+            elif (ch in (curses.KEY_END, 0x05)) or \
+                 (chext == 1) and (ch == 70):   # end, Ctrl-E
+                newpos = len(self.tree) - 1
+            # cursor left
+            elif ch == curses.KEY_LEFT:
+                if self.pos == 0:
+                    continue
+                newdepth = self.tree[self.pos][1] - 1
+                for i in xrange(self.pos-1, -1, -1):
+                    if self.tree[i][1] == newdepth:
+                        break
+                newpos = i
+            # cursor right
+            elif ch == curses.KEY_RIGHT:
+                child_dirs = self.__get_dirs(self.path)
+                if len(child_dirs) > 0:
+                    self.path = os.path.join(self.path, child_dirs[0])
+                    self.tree = self.get_tree()
+                    self.pos = self.__get_curpos()
+                continue
+            # enter
+            elif ch in (10, 13):
+                return self.path
+            # resize
+            elif ch == curses.KEY_RESIZE:
+                curses.doupdate()
+                app.resize()
+                self.__calculate_dims()
+                self.win.resize(self.dims[0], self.dims[1])
+                self.win.mvwin(self.dims[2], self.dims[3])
+                continue
+            # toggle .dot-files
+            elif ch == 0x08:    # Ctrl-H
+                app.prefs.options['show_dotfiles'] = 1 if app.prefs.options['show_dotfiles']==0 else 0
+                app.regenerate()
+                if self.pos != 0 and os.path.basename(self.path)[0] == '.':
+                    newdepth = self.tree[self.pos][1] - 1
+                    for i in xrange(self.pos-1, -1, -1):
+                        if self.tree[i][1] == newdepth:
+                            break
+                    newpos = i
+                else:
+                    newpos = self.pos
+            # quit
+            elif ch in (ord('q'), ord('Q'), curses.KEY_F10, 0x03):  # Ctrl-C
+                return -1
+            # else
+            else:
+                continue
+
+            # update
+            self.regenerate_tree(newpos)
+
+
+######################################################################
 ##### some utils
 def crop_line(line, w):
     if len(line) > w-1: