コード例 #1
0
ファイル: test_containers.py プロジェクト: rongmu/tarman
class TestFileSystem(unittest.TestCase):
    def setUp(self):
        self.fs = FileSystem()
        self.testcwd = os.getcwd()
        self.testfilepath = tarman.tests.test_containers.__file__
        self.testdirectory = os.path.dirname(self.testfilepath)
        self.testdatadir = os.path.join(self.testdirectory, 'testdata')

    def test_container(self):
        self.assertTrue(isinstance(self.fs, Container))

    def test_listdir(self):
        self.assertEqual(self.fs.listdir(self.testdirectory),
                         os.listdir(self.testdirectory))

    def test_isenterable(self):
        self.assertTrue(self.fs.isenterable(self.testdirectory))

    def test_abspath(self):
        self.assertEqual(self.fs.abspath('.'), self.testcwd)

    def test_dirname(self):
        self.assertEqual(self.fs.dirname(self.testfilepath),
                         self.testdirectory)

    def test_basename(self):
        self.assertEqual(self.fs.basename(self.testfilepath),
                         os.path.basename(self.testfilepath))

    def test_join(self):
        self.assertEqual(self.fs.join('/home', 'someone', 'bin', 'python'),
                         '/home/someone/bin/python')

    def test_split(self):
        self.assertEqual(self.fs.split('/home/someone/bin/python'),
                         ('/home/someone/bin', 'python'))

    def test_samefile(self):
        self.assertTrue(self.fs.samefile(self.testfilepath, self.testfilepath))
        self.assertFalse(
            self.fs.samefile(self.testfilepath,
                             tarman.tests.test_tree.__file__))

    def test_count_items(self):
        self.assertEqual(self.fs.count_items(self.testdatadir), 17)
        self.assertEqual(self.fs.count_items(self.testdatadir, stop_at=9), 9)
コード例 #2
0
ファイル: test_tree.py プロジェクト: rongmu/tarman
class TestDirectoryTree(unittest.TestCase):

    def setUp(self):
        self.testfilepath = tarman.tests.test_containers.__file__
        self.testdirectory = os.path.dirname(self.testfilepath)
        self.testdatapath = os.path.join(
            self.testdirectory, 'testdata', 'testdata'
        )
        self.fs = FileSystem()

    def test_init(self):
        self.assertIsNotNone(
            DirectoryTree(self.testdatapath, self.fs)
        )

    def test_add_file(self):
        tree = DirectoryTree(self.testdatapath, self.fs)
        path1 = self.fs.join(self.testdatapath, 'a', 'aa', 'aaa')
        path2 = self.fs.join(self.testdatapath, 'a', 'aa')
        tree.add(path1)
        self.assertIn(path1, tree)
        self.assertIn(path2, tree)  # not-added one-level-up directory

    def test_add_dir(self):
        tree = DirectoryTree(self.testdatapath, self.fs)
        dir1 = self.fs.join(self.testdatapath, 'a', 'ab')
        tree.add(dir1)
        self.assertIn(dir1, tree)

    def test_out_of_range(self):
        tree = DirectoryTree(self.testdatapath, self.fs)

        # one level up directory
        dir1 = self.fs.abspath(self.fs.join(self.testdatapath, '..'))
        with self.assertRaises(OutOfRange):
            tree.add(dir1)

        # completely different directory
        with tempfile.NamedTemporaryFile() as f:
            with self.assertRaises(OutOfRange):
                tree.add(f.name)
コード例 #3
0
ファイル: __init__.py プロジェクト: pombredanne/tarman
class Main(object):

    @utf8_args(3)
    def __init__(self, mainscr, stdscr, directory, encoding):
        self.encoding = encoding
        self.header_lns = HEADER_LNS
        self.mainscr = mainscr
        self.stdscr = stdscr
        self.color = curses.has_colors()
        if self.color:
            # set file type attributes (color and bold)
            curses.init_pair(1, curses.COLOR_BLUE, -1)
            self.attr_folder = curses.color_pair(1) | curses.A_BOLD
            curses.init_pair(2, 7, -1)
            self.attr_norm = curses.color_pair(2)

            # set wright / wrong attributes (color and bold)
            curses.init_pair(3, curses.COLOR_GREEN, -1)
            self.attr_wright = curses.color_pair(3) | curses.A_BOLD

            curses.init_pair(4, curses.COLOR_RED, -1)
            self.attr_wrong = curses.color_pair(4) | curses.A_BOLD

        self.kill = False
        self.ch = -1
        self.visited = {}
        self.area = None
        self.container = FileSystem()
        self.directory = self.container.abspath(directory)
        self.checked = DirectoryTree(self.directory, self.container)
        self.chdir(self.directory)

    @utf8_args(1, 2)
    def header(self, prefix, path):
        #self.mainscr.clear()
        h, w = self.mainscr.getmaxyx()
        sep = "  "
        length = len(prefix) + len(path) + len(sep)
        empty = 0
        if length > w:
            path = "..." + path[length - w + 3:]
        else:
            empty = w - length
        self.mainscr.addstr(
            0, 0,
            u"{0}{1}{2}{3}".format(
                prefix, sep, path, empty * ' '
            ).encode(self.encoding)
        )
        self.mainscr.refresh()

    def identify_container_and_checked(self, path):
        if self.container.isenterable(path):  # is folder
            return self.container, self.checked

        # force one-level archive browsing
        if not isinstance(self.container, FileSystem):
            return None, None

        aclass = get_archive_class(path)

        if not aclass:
            return None, None

        workwin = WorkWin(self)
        workwin.show("Working ...")

        newcontainer = aclass(path)
        newchecked = DirectoryTree(path, newcontainer)

        workwin.close()

        return newcontainer, newchecked

    def chdir(self, newpath):
        if newpath is None:
            return False

        if not newpath.startswith(self.directory):
            return False

        try:
            if self.area is None:
                oldsel = 0
                oldpath = self.directory
            else:
                oldsel = self.area.selected
                oldpath = self.area.abspath

            oldcontainer = self.container
            oldchecked = self.checked

            if newpath in self.visited:
                newsel, newcontainer, newchecked = self.visited[newpath]
            else:
                newcontainer, newchecked = \
                    self.identify_container_and_checked(newpath)
                if newcontainer is None:
                    return False
                newsel = 0

            self.visited[oldpath] = [oldsel, oldcontainer, oldchecked]
            logging.info(u"OLD - {0} - {1} - {2}".format(
                oldpath, oldsel, oldcontainer.__class__.__name__
            ))
            logging.info(u"NEW - {0} - {1} - {2}".format(
                newpath, newsel, newcontainer.__class__.__name__
            ))

            h, w = self.stdscr.getmaxyx()
            self.container = newcontainer
            self.checked = newchecked

            def show_unreadable_error(path, name):
                if isinstance(name, unicode):
                    error_str = name.encode('utf8', errors='replace')
                else:
                    error_str = name
                logging.info("Unreadable file name: {0} (in '{1}')".format(
                    error_str, path
                ))
                errorwin = TextWin(self)
                errorwin.show("Unreadable file name:\n{0}\n\nPress ESC to close.".format(error_str))

            self.area = ViewArea(
                newpath, h, newcontainer, show_unreadable_error
            )
            self.header(
                "{0}".format(
                    self.container.__class__.__name__
                ),
                self.area.abspath
            )
            self.area.set_params(h, offset=newsel)
            self.refresh_scr()

            return True
        except OutOfRange:
            logging.error("OutOfRange .. {0}".format(newpath))
            curses.flash()

    def insert_line(self, y, item):
        i, name, abspath = item
        self.stdscr.addstr(
            y, 0,
            "[{0}]".format(
                '*' if abspath in self.checked else ' '
            ).encode(self.encoding)
        )
        if self.color:
            if self.container.isenterable(abspath):
                attr = self.attr_folder
                name = u"{0}/".format(name)
            else:
                attr = self.attr_norm

            self.stdscr.addstr(y, 5, name.encode(self.encoding), attr)
        else:
            if self.container.isenterable(abspath):
                name = u"{0}/".format(name)
            self.stdscr.addstr(y, 5, name.encode(self.encoding))

    def refresh_scr(self):
        self.stdscr.clear()

        if not getattr(self, 'area', None):
            return

        if len(self.area) == 0:
            self.stdscr.addstr(1, 5, "Directory is empty!")
            return

        iitem = 0
        for item in self.area:
            self.insert_line(iitem, item)
            iitem += 1

        y = self.area.selected_local

        h, w = self.stdscr.getmaxyx()
        self.stdscr.chgat(y, 0, w, curses.A_REVERSE)
        self.stdscr.move(y, 1)

    def loop(self):
        while not self.kill:
            self.ch = self.stdscr.getch()
            h, w = self.stdscr.getmaxyx()

            if self.ch in [ord('q'), ]:
                self.kill = True

            elif self.ch == curses.KEY_UP:
                self.area.set_params(h, offset=-1)

            elif self.ch == curses.KEY_DOWN:
                self.area.set_params(h, offset=1)

            elif self.ch == curses.KEY_PPAGE:
                self.area.set_params(h, offset=-5)

            elif self.ch == curses.KEY_NPAGE:
                self.area.set_params(h, offset=5)

            elif self.ch == 32:
                index = self.area.selected
                if index == -1:
                    curses.flash()
                    continue
                abspath = self.area.get_abspath(index)
                if abspath in self.checked:
                    del self.checked[abspath]
                else:
                    countitems = self.container.count_items(
                        abspath,
                        stop_at=ITEMS_WARNING
                    )
                    if countitems >= ITEMS_WARNING and \
                            self.show_items_warning() != 0:
                        continue
                    self.checked.add(abspath, sub=True)

            elif self.ch in [curses.KEY_RIGHT, 10, 13]:
                index = self.area.selected
                if index == -1:
                    curses.flash()
                    continue
                abspath = self.area.get_abspath(index)

                result = self.chdir(abspath)
                if not result:
                    curses.flash()

            elif self.ch in [curses.KEY_LEFT,
                             127, curses.ascii.BS, curses.KEY_BACKSPACE]:
                if not self.chdir(
                    self.container.dirname(self.area.abspath)
                ):
                    curses.flash()

            elif self.ch in [ord('c'), ord('C')]:
                if isinstance(self.container, FileSystem):
                    aclass = self.container.__class__
                    checked = self.checked
                    container = self.container

                    pathwin = PathWin(self)
                    exitstatus, archivepath = pathwin.show(
                        "Create archive with format/compression based on file"
                        " extension (ENTER to confirm or ESC to cancel):",
                        os.path.join(os.getcwd(), "NewArchive.tar.gz")
                    )
                    pathwin.close()
                    logging.info("window exitstatus: {0}, '{1}'".format(
                        exitstatus, archivepath
                    ))
                    if exitstatus != 0:
                        continue

                    archivepath = os.path.abspath(archivepath)
                    aclass = get_archive_class(archivepath)
                    if aclass is None:
                        curses.flash()
                        continue

                    created = aclass.create(container, archivepath, checked)

                    if created:
                        TextWin(self).show(
                            "Successfully created archive:\n{0}".format(
                                archivepath
                            )
                        )
                    else:
                        curses.flash()

            elif self.ch in [ord('e'), ord('E')]:
                if isinstance(self.container, Archive):
                    aclass = self.container.__class__
                    archive = self.container.archive
                    checked = self.checked
                    container = self.container
                else:
                    index = self.area.selected
                    if index == -1:
                        curses.flash()
                        continue
                    abspath = self.area.get_abspath(index)
                    if not abspath:
                        curses.flash()
                        continue
                    aclass = get_archive_class(abspath)
                    if aclass is None:
                        curses.flash()
                        continue
                    archive = aclass.open(abspath)
                    checked = None
                    container = None

                pathwin = PathWin(self)
                exitstatus, s = pathwin.show(
                    "Extract to "
                    "(press ENTER for confirmation or ESC to cancel):"
                )
                pathwin.close()
                logging.info("window exitstatus: {0}, '{1}'".format(
                    exitstatus, s
                ))
                if exitstatus != 0:
                    continue

                workwin = WorkWin(self)
                workwin.show("Extracting ...")
                aclass.extract(container, archive, s, checked=checked)
                workwin.close()

                TextWin(self).show("Extracted to:\n{0}".format(s))

            elif self.ch in [ord('?'), curses.KEY_F1, ord('h')]:
                textwin = TextWin(self)
                textwin.show(HELP_STRING)

            if self.ch != -1:
                self.refresh_scr()

            if self.kill:
                break

    def show_items_warning(self):
        questionwin = QuestionWin(self)
        return questionwin.show(
            "There are more than {0} items in this folder,"
            "\ndo you really want to select it?".format(
                ITEMS_WARNING
            )
        )

    def cancel(self):
        self.kill = True
コード例 #4
0
ファイル: test_containers.py プロジェクト: matejc/tarman
class TestFileSystem(unittest.TestCase):

    def setUp(self):
        self.fs = FileSystem()
        self.testcwd = os.getcwd()
        self.testfilepath = tarman.tests.test_containers.__file__
        self.testdirectory = os.path.dirname(self.testfilepath)
        self.testdatadir = os.path.join(self.testdirectory, 'testdata')

    def test_container(self):
        self.assertTrue(isinstance(self.fs, Container))

    def test_listdir(self):
        self.assertEqual(
            self.fs.listdir(self.testdirectory),
            os.listdir(self.testdirectory)
        )

    def test_isenterable(self):
        self.assertTrue(self.fs.isenterable(self.testdirectory))

    def test_abspath(self):
        self.assertEqual(self.fs.abspath('.'), self.testcwd)

    def test_dirname(self):
        self.assertEqual(
            self.fs.dirname(self.testfilepath), self.testdirectory
        )

    def test_basename(self):
        self.assertEqual(
            self.fs.basename(self.testfilepath),
            os.path.basename(self.testfilepath)
        )

    def test_join(self):
        self.assertEqual(
            self.fs.join('/home', 'someone', 'bin', 'python'),
            '/home/someone/bin/python'
        )

    def test_split(self):
        self.assertEqual(
            self.fs.split('/home/someone/bin/python'),
            ('/home/someone/bin', 'python')
        )

    def test_samefile(self):
        self.assertTrue(
            self.fs.samefile(self.testfilepath, self.testfilepath)
        )
        self.assertFalse(
            self.fs.samefile(
                self.testfilepath,
                tarman.tests.test_tree.__file__
            )
        )

    def test_count_items(self):
        self.assertEqual(
            self.fs.count_items(self.testdatadir),
            17
        )
        self.assertEqual(
            self.fs.count_items(self.testdatadir, stop_at=9),
            9
        )
コード例 #5
0
ファイル: __init__.py プロジェクト: brodul/tarman
class Main(object):

    def __init__(self, mainscr, stdscr, directory):
        logging.basicConfig(filename='tarman.log', filemode='w', level=logging.DEBUG)
        self.header_lns = 1
        self.mainscr = mainscr
        self.stdscr = stdscr
        self.color = curses.has_colors()
        if self.color:
            curses.init_pair(1, curses.COLOR_BLUE, -1)
            self.attr_folder = curses.color_pair(1) | curses.A_BOLD
            curses.init_pair(2, 7, -1)
            self.attr_norm = curses.color_pair(2)
        self.kill = False
        self.ch = -1
        self.visited = {}     # TODO
        self.area = None
        self.container = FileSystem()
        self.directory = self.container.abspath(directory)
        self.checked = DirectoryTree(self.directory, self.container)
        self.chdir(self.directory)

    def header(self, text, line=0):
        self.mainscr.clear()
        self.mainscr.addstr(line, 0, text)
        self.mainscr.refresh()

    def identify_container(self, path):
        if self.container.isenterable(path):  # is folder
            return self.container

        # force one-level archive browsing
        if not isinstance(self.container, FileSystem):
            return None

        return container(path)

    def chdir(self, newpath):
        if newpath is None:
            return False

        if not newpath.startswith(self.directory):
            return False

        try:
            if self.area is None:
                oldsel = 0
                oldpath = self.directory
            else:
                oldsel = self.area.selected
                oldpath = self.area.abspath

            oldcontainer = self.container
            oldchecked = self.checked

            if newpath in self.visited:
                newsel, newcontainer, newchecked = self.visited[newpath]
            else:
                newcontainer = self.identify_container(newpath)
                if newcontainer is None:
                    return False
                newchecked = DirectoryTree(newpath, newcontainer)
                newsel = 0

            self.visited[oldpath] = [oldsel, oldcontainer, oldchecked]
            logging.info("OLD - {0} - {1} - {2}".format(oldpath, oldsel, oldcontainer.__class__.__name__))
            logging.info("NEW - {0} - {1} - {2}".format(newpath, newsel, newcontainer.__class__.__name__))

            h, w = self.stdscr.getmaxyx()
            self.container = newcontainer
            self.checked = newchecked
            self.area = ViewArea(newpath, h, newcontainer)
            self.header("({0})  {1}".format(
                self.container.__class__.__name__, self.area.abspath
            ))
            self.area.set_params(h, offset=newsel)
            self.refresh_scr()

            return True
        except OutOfRange:
            curses.flash()

    def insert_line(self, y, item):
        i, name, abspath = item
        self.stdscr.addstr(
            y, 0, "[{0}]".format('*' if abspath in self.checked else ' ')
        )
        if self.color:
            if self.container.isenterable(abspath):
                attr = self.attr_folder
                name = "{0}/".format(name)
            else:
                attr = self.attr_norm

            self.stdscr.addstr(y, 5, name, attr)
        else:
            if self.container.isenterable(abspath):
                name = "{0}/".format(name)
            self.stdscr.addstr(y, 5, name)

    def refresh_scr(self):
        self.stdscr.clear()

        if len(self.area) == 0:
            self.stdscr.addstr(1, 5, "Directory is empty!")
            return

        iitem = 0
        for item in self.area:
            self.insert_line(iitem, item)
            iitem += 1

        y = self.area.selected_local

        h, w = self.stdscr.getmaxyx()
        self.stdscr.chgat(y, 0, w, curses.A_REVERSE)
        self.stdscr.move(y, 1)

    def loop(self):
        while not self.kill:
            self.ch = self.stdscr.getch()
            h, w = self.stdscr.getmaxyx()

            if self.ch in [ord('q'), 27]:
                self.kill = True

            elif self.ch == curses.KEY_UP:
                self.area.set_params(h, offset=-1)

            elif self.ch == curses.KEY_DOWN:
                self.area.set_params(h, offset=1)

            elif self.ch == curses.KEY_PPAGE:
                self.area.set_params(h, offset=-5)

            elif self.ch == curses.KEY_NPAGE:
                self.area.set_params(h, offset=5)

            elif self.ch == 32:
                index = self.area.selected
                if index == -1:
                    curses.flash()
                    continue
                abspath = self.area.get_abspath(index)
                if abspath in self.checked:
                    del self.checked[abspath]
                else:
                    self.checked.add(abspath, sub=True)

            elif self.ch == curses.KEY_RIGHT:
                index = self.area.selected
                if index == -1:
                    curses.flash()
                    continue
                abspath = self.area.get_abspath(index)
                if not self.chdir(abspath):
                    curses.flash()

            elif self.ch == curses.KEY_LEFT:
                if not self.chdir(
                    self.container.dirname(self.area.abspath)
                ):
                    curses.flash()

            elif self.ch in [ord('e'), ord('E')]:

                if isinstance(self.container, Archive):
                    aclass = self.container.__class__
                    archive = self.container.archive
                    checked = self.checked
                else:
                    index = self.area.selected
                    if index == -1:
                        curses.flash()
                        continue
                    abspath = self.area.get_abspath(index)
                    if not abspath:
                        curses.flash()
                        continue
                    aclass = get_archive_class(abspath)
                    archive = aclass.open(abspath)
                    checked = None
                aclass.extract(archive, '.', checked=checked)

            if self.ch != -1:
                self.refresh_scr()

            if self.kill:
                break

        self.stdscr.clear()

    def cancel(self):
        self.kill = True
コード例 #6
0
ファイル: __init__.py プロジェクト: rongmu/tarman
class Main(object):

    @utf8_args(3)
    def __init__(self, mainscr, stdscr, directory, encoding, show_hiddens):
        self.encoding = encoding
        self.header_lns = HEADER_LNS
        self.mainscr = mainscr
        self.stdscr = stdscr
        self.color = curses.has_colors()
        if self.color:
            # set file type attributes (color and bold)
            curses.init_pair(1, curses.COLOR_BLUE, -1)
            self.attr_folder = curses.color_pair(1) | curses.A_BOLD
            curses.init_pair(2, 7, -1)
            self.attr_norm = curses.color_pair(2)

            # set wright / wrong attributes (color and bold)
            curses.init_pair(3, curses.COLOR_GREEN, -1)
            self.attr_wright = curses.color_pair(3) | curses.A_BOLD

            curses.init_pair(4, curses.COLOR_RED, -1)
            self.attr_wrong = curses.color_pair(4) | curses.A_BOLD

        self.kill = False
        self.ch = -1
        self.visited = {}
        self.area = None
        self.container = FileSystem()
        self.directory = self.container.abspath(directory)
        self.checked = DirectoryTree(self.directory, self.container)
        self.show_hiddens = show_hiddens
        self.chdir(self.directory)

    @utf8_args(1, 2)
    def header(self, prefix, path):
        #self.mainscr.clear()
        h, w = self.mainscr.getmaxyx()
        sep = "  "
        length = len(prefix) + len(path) + len(sep)
        empty = 0
        if length > w:
            path = "..." + path[length - w + 3:]
        else:
            empty = w - length
        self.mainscr.addstr(
            0, 0,
            u"{0}{1}{2}{3}".format(
                prefix, sep, path, empty * ' '
            ).encode(self.encoding)
        )
        self.mainscr.refresh()

    def identify_container_and_checked(self, path):
        if self.container.isenterable(path):  # is folder
            return self.container, self.checked

        # force one-level archive browsing
        if not isinstance(self.container, FileSystem):
            return None, None

        aclass = get_archive_class(path)

        if not aclass:
            return None, None

        workwin = WorkWin(self)
        workwin.show("Working ...")

        newcontainer = aclass(path)
        newchecked = DirectoryTree(path, newcontainer)

        workwin.close()

        return newcontainer, newchecked

    def chdir(self, newpath):
        if newpath is None:
            return False

        if not newpath.startswith(self.directory):
            return False

        try:
            if self.area is None:
                oldsel = 0
                oldpath = self.directory
            else:
                oldsel = self.area.selected
                oldpath = self.area.abspath

            oldcontainer = self.container
            oldchecked = self.checked

            if newpath in self.visited:
                newsel, newcontainer, newchecked = self.visited[newpath]
            else:
                newcontainer, newchecked = \
                    self.identify_container_and_checked(newpath)
                if newcontainer is None:
                    return False
                newsel = 0

            self.visited[oldpath] = [oldsel, oldcontainer, oldchecked]
            logging.info(u"OLD - {0} - {1} - {2}".format(
                oldpath, oldsel, oldcontainer.__class__.__name__
            ))
            logging.info(u"NEW - {0} - {1} - {2}".format(
                newpath, newsel, newcontainer.__class__.__name__
            ))

            h, w = self.stdscr.getmaxyx()
            self.container = newcontainer
            self.checked = newchecked

            def show_unreadable_error(path, name):
                if isinstance(name, unicode):
                    error_str = name.encode('utf8', errors='replace')
                else:
                    error_str = name
                logging.info("Unreadable file name: {0} (in '{1}')".format(
                    error_str, path
                ))
                errorwin = TextWin(self)
                errorwin.show("Unreadable file name:\n{0}\n\nPress ESC to close.".format(error_str))

            self.area = ViewArea(
                newpath, h, newcontainer, show_unreadable_error, self.show_hiddens
            )
            self.header(
                "{0}".format(
                    self.container.__class__.__name__
                ),
                self.area.abspath
            )
            self.area.set_params(h, offset=newsel)
            self.refresh_scr()

            return True
        except OutOfRange:
            logging.error("OutOfRange .. {0}".format(newpath))
            curses.flash()

    def insert_line(self, y, item):
        i, name, abspath = item
        self.stdscr.addstr(
            y, 0,
            "[{0}]".format(
                '*' if abspath in self.checked else ' '
            ).encode(self.encoding)
        )
        if self.color:
            if self.container.isenterable(abspath):
                attr = self.attr_folder
                name = u"{0}/".format(name)
            else:
                attr = self.attr_norm

            self.stdscr.addstr(y, 5, name.encode(self.encoding), attr)
        else:
            if self.container.isenterable(abspath):
                name = u"{0}/".format(name)
            self.stdscr.addstr(y, 5, name.encode(self.encoding))

    def refresh_scr(self):
        self.stdscr.clear()

        if not getattr(self, 'area', None):
            return

        if len(self.area) == 0:
            self.stdscr.addstr(1, 5, "Directory is empty!")
            return

        iitem = 0
        for item in self.area:
            self.insert_line(iitem, item)
            iitem += 1

        y = self.area.selected_local

        h, w = self.stdscr.getmaxyx()
        self.stdscr.chgat(y, 0, w, curses.A_REVERSE)
        self.stdscr.move(y, 1)

    def loop(self):
        while not self.kill:
            self.ch = self.stdscr.getch()
            h, w = self.stdscr.getmaxyx()

            if self.ch in [ord('q'), ]:
                self.kill = True

            elif self.ch == curses.KEY_UP:
                self.area.set_params(h, offset=-1)

            elif self.ch == curses.KEY_DOWN:
                self.area.set_params(h, offset=1)

            elif self.ch == curses.KEY_PPAGE:
                self.area.set_params(h, offset=-5)

            elif self.ch == curses.KEY_NPAGE:
                self.area.set_params(h, offset=5)

            elif self.ch == 32:
                index = self.area.selected
                if index == -1:
                    curses.flash()
                    continue
                abspath = self.area.get_abspath(index)
                if abspath in self.checked:
                    del self.checked[abspath]
                else:
                    countitems = self.container.count_items(
                        abspath,
                        stop_at=ITEMS_WARNING
                    )
                    if countitems >= ITEMS_WARNING and \
                            self.show_items_warning() != 0:
                        continue
                    self.checked.add(abspath, sub=True)

            elif self.ch in [curses.KEY_RIGHT, 10, 13]:
                index = self.area.selected
                if index == -1:
                    curses.flash()
                    continue
                abspath = self.area.get_abspath(index)

                result = self.chdir(abspath)
                if not result:
                    curses.flash()

            elif self.ch in [curses.KEY_LEFT,
                             127, curses.ascii.BS, curses.KEY_BACKSPACE]:
                if not self.chdir(
                    self.container.dirname(self.area.abspath)
                ):
                    curses.flash()

            elif self.ch in [ord('c'), ord('C')]:
                if isinstance(self.container, FileSystem):
                    aclass = self.container.__class__
                    checked = self.checked
                    container = self.container

                    pathwin = PathWin(self)
                    exitstatus, archivepath = pathwin.show(
                        "Create archive with format/compression based on file"
                        " extension (ENTER to confirm or ESC to cancel):",
                        os.path.join(os.getcwd(), "NewArchive.tar.gz")
                    )
                    pathwin.close()
                    logging.info("window exitstatus: {0}, '{1}'".format(
                        exitstatus, archivepath
                    ))
                    if exitstatus != 0:
                        continue

                    archivepath = os.path.abspath(archivepath)
                    aclass = get_archive_class(archivepath)
                    if aclass is None:
                        curses.flash()
                        continue

                    created = aclass.create(container, archivepath, checked)

                    if created:
                        TextWin(self).show(
                            "Successfully created archive:\n{0}".format(
                                archivepath
                            )
                        )
                    else:
                        curses.flash()

            elif self.ch in [ord('e'), ord('E')]:
                if isinstance(self.container, Archive):
                    aclass = self.container.__class__
                    archive = self.container.archive
                    checked = self.checked
                    container = self.container
                else:
                    index = self.area.selected
                    if index == -1:
                        curses.flash()
                        continue
                    abspath = self.area.get_abspath(index)
                    if not abspath:
                        curses.flash()
                        continue
                    aclass = get_archive_class(abspath)
                    if aclass is None:
                        curses.flash()
                        continue
                    archive = aclass.open(abspath)
                    checked = None
                    container = None

                pathwin = PathWin(self)
                exitstatus, s = pathwin.show(
                    "Extract to "
                    "(press ENTER for confirmation or ESC to cancel):"
                )
                pathwin.close()
                logging.info("window exitstatus: {0}, '{1}'".format(
                    exitstatus, s
                ))
                if exitstatus != 0:
                    continue

                workwin = WorkWin(self)
                workwin.show("Extracting ...")
                aclass.extract(container, archive, s, checked=checked)
                workwin.close()

                TextWin(self).show("Extracted to:\n{0}".format(s))

            elif self.ch in [ord('?'), curses.KEY_F1]:
                curses.curs_set(0)
                textwin = TextWin(self)
                textwin.show(HELP_STRING)

            if self.ch == ord('h'):
                if self.show_hiddens == True:
                    self.show_hiddens = False
                else:
                    self.show_hiddens = True
                self.chdir(self.area.abspath)

            if self.ch != -1:
                self.refresh_scr()

            if self.kill:
                break

    def show_items_warning(self):
        questionwin = QuestionWin(self)
        return questionwin.show(
            "There are more than {0} items in this folder,"
            "\ndo you really want to select it?".format(
                ITEMS_WARNING
            )
        )

    def cancel(self):
        self.kill = True