# Copyright (c) 2000 Phil Thompson <phil@river-bank.demon.co.uk>


import sys
from qt import SIGNAL, PYSIGNAL, QListView, QListViewItem, QDir, QFileInfo
from qt import QSize, QWhatsThis

from Icons import *


class ExplorerNode(QListViewItem):
    """ExplorerNode(self,parent,text,after)

    This class is a thin wrapper around QListViewItem that makes sure it is
    positioned after the previous sibling.  parent is the parent Explorer or
    ExplorerNode.  text is the text of the node.  after is the sibling this
    node is position after, and it is None if this is the first child.

    """
    def __init__(self,parent,text,after):
        if after is None:
            QListViewItem.__init__(self,parent,text)
        else:
            QListViewItem.__init__(self,parent,after,text)


class ExplorerDirectory(ExplorerNode):
    """ExplorerDirectory(self,parent,dinfo,after,full=1)

    This class is an ExplorerNode that represents a directory.  parent is the
    parent Explorer or ExplorerNode.  dinfo is the QFileInfo of the directory.
    after is the sibling this node is position after, and it is None if this is
    the first child.  full is non-zero if the full pathname of the directory
    should be displayed.

    """
    def __init__(self,parent,dinfo,after,full=1):
        self.dirName = dinfo.absFilePath()

        if full:
            dn = self.dirName
        else:
            dn = dinfo.fileName()

        ExplorerNode.__init__(self,parent,dn,after)

        self.setExpandable(1)
        self.setPixmap(0,IconDirClosed)

        self.doneOpen = 0
        self.children = []

    def setOpen(self,o):
        if o:
            if not self.doneOpen:
                self.dir = QDir(self.dirName)
                last = None

                for f in self.dir.entryInfoList():
                    if str(f.fileName()) in ('.', '..'):
                        continue

                    if f.isDir():
                        node = ExplorerDirectory(self,f,last,0)
                    else:
                        node = ExplorerFile(self,f,last)

                    last = node
                    self.children.append(node)

                self.doneOpen = 1

            self.setPixmap(0,IconDirOpen)
        else:
            self.setPixmap(0,IconDirClosed)

        QListViewItem.setOpen(self,o)


class ExplorerSysPath(ExplorerNode):
    """ExplorerSysPath(self,parent,after)

    This class is an ExplorerNode that represents the Python sys.path.  parent
    is the parent Explorer or ExplorerNode.  dinfo is the QFileInfo of the
    directory.  after is the sibling this node is position after, and it is
    None if this is the first child.  full is non-zero if the full pathname of
    the directory should be displayed.

    """
    def __init__(self,parent,after):
        ExplorerNode.__init__(self,parent,'sys.path',after)

        self.setExpandable(1)
        self.setPixmap(0,IconFilePython)

        self.doneOpen = 0
        self.children = []

    def setOpen(self,o):
        if o and not self.doneOpen:
            last = None

            for p in sys.path:
                if p == '':
                    p = QDir.currentDirPath()

                node = ExplorerDirectory(self,QFileInfo(p),last)
                last = node
                self.children.append(node)

            self.doneOpen = 1

        QListViewItem.setOpen(self,o)


class ExplorerFile(ExplorerNode):
    """ExplorerDirectory(self,parent,finfo,after)

    This class is an ExplorerNode that represents a file.  parent is the parent
    Explorer or ExplorerNode.  finfo is the QFileInfo of the file.  after is
    the sibling this node is position after, and it is None if this is the
    first child.

    """
    def __init__(self,parent,finfo,after):
        ExplorerNode.__init__(self,parent,finfo.fileName(),after)

        if str(finfo.extension()) == 'py':
            self.setPixmap(0,IconFilePython)
            self.pyFileName = finfo.absFilePath()
        else:
            self.setPixmap(0,IconFileMisc)
            self.pyFileName = None

    def pythonFileName(self):
        return self.pyFileName


class Explorer(QListView):
    """Explorer(self,parent=None)

    A class used to display a Python source file that is broken down into
    separate, colour coded, tokens.  The Python signal pythonFile is emitted
    when the user double-clicks on a Python source file, the file name is the
    signal argument.

    """
    def __init__(self,parent=None):
        QListView.__init__(self,parent)

        self.setCaption('Explorer')
        self.setRootIsDecorated(1)
        self.setSorting(-1)
        self.addColumn('Name')

        self.progDir = None
        self.children = []
        last = None

        node = ExplorerSysPath(self,last)
        last = node
        self.children.append(node)

        for d in QDir.drives():
            node = ExplorerDirectory(self,d,last)
            last = node
            self.children.append(node)

        self.connect(self,SIGNAL('doubleClicked(QListViewItem *)'),
                     self.handleDoubleClick)

        req = QSize(250,350)

        if parent is not None:
            req = req.boundedTo(parent.size())

        self.resize(req)

        QWhatsThis.add(self,
"""<b>The Explorer Window</b>"""
"""<p>This allows you to easily navigate the hierachy of directories and"""
""" files on your system, identify the Python programs and open them up in"""
""" a Source Viewer window. The window displays several separate"""
""" hierachies.</p>"""
"""<p>The first hierachy is only shown if you have opened a program for"""
""" debugging and it's root is the directory containing that program."""
""" Usually all of the separate files that make up a Python application are"""
""" held in the same directory, so this hierachy gives you easy access to"""
""" most of what you will need.</p>"""
"""<p>The next hierachy is used to easily navigate the directories that are"""
""" specified in the Python <tt>sys.path</tt> variable.</p>"""
"""<p>The remaining hierachies allow you navigate your system as a whole."""
""" On a UNIX system there will be a single hierachy with <tt>/</tt> at its"""
""" root. On a Windows system there will be a hierachy for each drive on the"""
""" system.</p>"""
"""<p>Python programs (i.e. those with a <tt>.py</tt> file name suffix)"""
""" are identified in the hierachies with a Python icon. Double-clicking"""
""" on one of these file names will open a Source Viewer window containing"""
""" that file.</p>"""
                      )

    def handleDoubleClick(self,itm):
        try:
            pyfn = itm.pythonFileName()
        except:
            pyfn = None

        if pyfn is not None:
            self.emit(PYSIGNAL('pythonFile'),(pyfn,))

    def handleProgramChange(self,finfo):
        # Delete the old program directory if there was one.
        if self.progDir is not None:
            self.takeItem(self.progDir)

        self.progDir = ExplorerDirectory(self,QFileInfo(finfo.dirPath()),None)
