#!/usr/bin/env python

"""**************************************************************************
** $Id: dirview.py,v 1.7 2005/11/14 17:21:26 phil Exp $
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
** Some corrections by M. Biermaier (http://www.office-m.at)
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
***************************************************************************"""

import sys
from qt import *

folder_closed_xpm = [
    "16 16 9 1",
    "g c #808080",
    "b c #c0c000",
    "e c #c0c0c0",
    "# c #000000",
    "c c #ffff00",
    ". c None",
    "a c #585858",
    "f c #a0a0a4",
    "d c #ffffff",
    "..###...........",
    ".#abc##.........",
    ".#daabc#####....",
    ".#ddeaabbccc#...",
    ".#dedeeabbbba...",
    ".#edeeeeaaaab#..",
    ".#deeeeeeefe#ba.",
    ".#eeeeeeefef#ba.",
    ".#eeeeeefeff#ba.",
    ".#eeeeefefff#ba.",
    ".##geefeffff#ba.",
    "...##gefffff#ba.",
    ".....##fffff#ba.",
    ".......##fff#b##",
    ".........##f#b##",
    "...........####."
]

folder_open_xpm = [
    "16 16 11 1",
    "# c #000000",
    "g c #c0c0c0",
    "e c #303030",
    "a c #ffa858",
    "b c #808080",
    "d c #a0a0a4",
    "f c #585858",
    "c c #ffdca8",
    "h c #dcdcdc",
    "i c #ffffff",
    ". c None",
    "....###.........",
    "....#ab##.......",
    "....#acab####...",
    "###.#acccccca#..",
    "#ddefaaaccccca#.",
    "#bdddbaaaacccab#",
    ".eddddbbaaaacab#",
    ".#bddggdbbaaaab#",
    "..edgdggggbbaab#",
    "..#bgggghghdaab#",
    "...ebhggghicfab#",
    "....#edhhiiidab#",
    "......#egiiicfb#",
    "........#egiibb#",
    "..........#egib#",
    "............#ee#"
]

folder_locked = [
    "16 16 10 1",
    "h c #808080",
    "b c #ffa858",
    "f c #c0c0c0",
    "e c #c05800",
    "# c #000000",
    "c c #ffdca8",
    ". c None",
    "a c #585858",
    "g c #a0a0a4",
    "d c #ffffff",
    "..#a#...........",
    ".#abc####.......",
    ".#daa#eee#......",
    ".#ddf#e##b#.....",
    ".#dfd#e#bcb##...",
    ".#fdccc#daaab#..",
    ".#dfbbbccgfg#ba.",
    ".#ffb#ebbfgg#ba.",
    ".#ffbbe#bggg#ba.",
    ".#fffbbebggg#ba.",
    ".##hf#ebbggg#ba.",
    "...###e#gggg#ba.",
    ".....#e#gggg#ba.",
    "......###ggg#b##",
    ".........##g#b##",
    "...........####."
]

pix_file = [
    "16 16 7 1",
    "# c #000000",
    "b c #ffffff",
    "e c #000000",
    "d c #404000",
    "c c #c0c000",
    "a c #ffffc0",
    ". c None",
    "................",
    ".........#......",
    "......#.#a##....",
    ".....#b#bbba##..",
    "....#b#bbbabbb#.",
    "...#b#bba##bb#..",
    "..#b#abb#bb##...",
    ".#a#aab#bbbab##.",
    "#a#aaa#bcbbbbbb#",
    "#ccdc#bcbbcbbb#.",
    ".##c#bcbbcabb#..",
    "...#acbacbbbe...",
    "..#aaaacaba#....",
    "...##aaaaa#.....",
    ".....##aa#......",
    ".......##......."
]

folderLocked = None
folderClosed = None
folderOpened = None
fileNormal   = None

class FileItem( QListViewItem ) :
    def __init__( self, parent=None, s1=QString.null, s2=QString.null ):
        QListViewItem.__init__( self, parent, s1, s2 )
        self.pix = None
    
    def setPixmap( self, p ) :
        self.pix = p
        self.setup()
        self.widthChanged( 0 )
        self.invalidateHeight()
        self.repaint()
    
    def pixmap( self, i ) :
        if i : return None
        else : return self.pix;

# Class Directory    
class Directory( QListViewItem ) :
    def __init__( self, parent=None, filename=QString.null, col2=QString.null ):
        QListViewItem.__init__( self, parent, filename, col2 )
        self.pix = None
        global folderLocked, folderClosed, folderOpened, fileNormal
        self.showDirsOnly = False
        if isinstance(parent, QListView):
            self.p = None
            self.showDirsOnly = parent.showDirsOnly()
            self.f = QFile( QString('/') )
        else:
            self.p = parent
            self.showDirsOnly = parent.showDirsOnly
            self.f = QFile( QString(filename) )

        self.readable = QDir( self.fullName() ).isReadable()
        if not self.readable : self.setPixmap( folderLocked )
        else : self.setPixmap( folderClosed )

    def setPixmap( self, px ) :
        self.pix = px
        self.setup()
        self.widthChanged( 0 )
        self.invalidateHeight()
        self.repaint()
    
    def pixmap( self, i ) :
        if i : return None
        else : return self.pix
    
    def setOpen( self, o ) :
        if o : self.setPixmap( folderOpened )
        else : self.setPixmap( folderClosed )

        if o and not self.childCount() :
            s = QString( self.fullName() )
            thisDir = QDir( s )
            if not thisDir.isReadable() :
                self.readable = False
                self.setExpandable( False )
                return
            
            self.listView().setUpdatesEnabled( False )
            files = thisDir.entryInfoList()
            if files :
                fi = QFileInfo()
                for it in files:
                    fi = it
                    if str(fi.fileName()) == "." or str(fi.fileName()) == ".." :
                        continue # nothing
                    elif fi.isSymLink() and not self.showDirsOnly :
                        item = FileItem( self, fi.fileName(), "Symbolic Link" )
                        item.setPixmap( fileNormal )
                    elif fi.isDir() :
                        Directory( self, fi.fileName() )
                    elif not self.showDirsOnly :
                        if fi.isFile() : item = FileItem( self, fi.fileName(), "File" )
                        else : item = FileItem( self, fi.fileName(), "Special" )
                        item.setPixmap( fileNormal )
                    
            self.listView().setUpdatesEnabled( True )
        QListViewItem.setOpen( self, o )

    def setup( self ):
        self.setExpandable( True )
        QListViewItem.setup( self )

    def fullName( self ):
        s = QString()
        if self.p :
            s = self.p.fullName()
            s.append( self.f.name() )
            s.append( "/" )
        else :
            s = self.f.name()
        return s

    def text( self, column ) :
        if column == 0 : return self.f.name()
        elif self.readable  : return "Directory"
        else : return "Unreadable Directory"
    
# Class DirectoryView

class DirectoryView( QListView ):
    def __init__( self, parent=None, name=None, sdo=False ):
        QListView.__init__( self, parent, name )
        self.dirsOnly = sdo
        self.oldCurrent = 0
        self.dropItem = 0
        self.presspos = QPoint(0,0)
        self.mousePressed = False
        global folderLocked, folderClosed, folderOpened, fileNormal #= QPixmap()
        self.autoopenTime = 750
      
        self.autoopen_timer = QTimer( self )
        if not folderLocked :
            folderLocked = QPixmap( folder_locked )
            folderClosed = QPixmap( folder_closed_xpm )
            folderOpened = QPixmap( folder_open_xpm )
            fileNormal   = QPixmap( pix_file )
        
        self.connect( self, SIGNAL("doubleClicked(QListViewItem *)"),
                      self.slotFolderSelected )
        self.connect( self, SIGNAL("returnPressed(QListViewItem *)"),
                      self.slotFolderSelected )

        self.setAcceptDrops( True )
        self.viewport().setAcceptDrops( True )

        self.connect( self.autoopen_timer, SIGNAL("timeout()"), self.openFolder )

    def showDirsOnly( self ):
        return self.dirsOnly
    
    def slotFolderSelected( self, i ):
        if not i or not self.showDirsOnly():
            return
        dir = i
        self.emit( PYSIGNAL("folderSelected(const QString &)"), (dir.fullName(), ) )
            
    def openFolder( self ):
        self.autoopen_timer.stop()
        if self.dropItem and not self.dropItem.isOpen():
            self.dropItem.setOpen( True )
            self.dropItem.repaint()
        
    def contentsDragEnterEvent( self, e ):
        if not QUriDrag.canDecode(e) :
            e.ignore()
            return
        self.oldCurrent = self.currentItem()
        i = self.itemAt( self.contentsToViewport(e.pos()) )
        if i :
            self.dropItem = i
            self.autoopen_timer.start( self.autoopenTime )

    def contentsDragMoveEvent( self, e ) :
        if not QUriDrag.canDecode(e) :
            e.ignore()
            return
        vp = self.contentsToViewport( e.pos() )
        i = self.itemAt( vp )
        if i :
            self.setSelected( i, True )
            e.accept()
            if i != self.dropItem :
                self.autoopen_timer.stop()
                self.dropItem = i
                self.autoopen_timer.start( self.autoopenTime )

            if e.action() == QDropEvent.Copy:
                pass
            elif e.action() == QDropEvent.Move:
                e.acceptAction()
            elif e.action() == QDropEvent.Link:
                e.acceptAction()
            else:
                pass
        else :
            e.ignore()
            self.autoopen_timer.stop()
            self.dropItem = 0

    def contentsDragLeaveEvent( self, QDragLeaveEvent ) :
        self.autoopen_timer.stop()
        self.dropItem = 0

        self.setCurrentItem( self.oldCurrent )
        self.setSelected( self.oldCurrent, True )
    
    def contentsDropEvent( self, e ):
        self.autoopen_timer.stop()
        if not QUriDrag.canDecode(e) :
            e.ignore()
            return
        item = self.itemAt( self.contentsToViewport(e.pos()) )
        if item :
            lst = QStringList()
            QUriDrag.decodeLocalFiles( e, lst )
            if e.action() == QDropEvent.Copy:
                s = QString("Copy")
            elif e.action() ==  QDropEvent.Move:
                s = QString("Move")
                e.acceptAction()
            elif e.action() == QDropEvent.Link:
                s = QString("Link")
                e.acceptAction()
            else:
                s = QString("Unknown")
          
            s += "\n\n"
            e.accept()

            for filename in lst:
                s += filename
                s += "\n"

            s += "\nTo\n\n   "
            s += self.fullPath(item)
            QMessageBox.information( self, "Drop target", s, "Not implemented" )
        else :
            e.ignore()
   
    def fullPath( self, item ):
        fullpath = QString( item.text(0) )
        item = item.parent()
        while item:
            newpath = item.text(0)

            if item.parent():
                newpath += "/"

            newpath += fullpath
            fullpath = newpath
            item = item.parent()

        return fullpath
    
    def contentsMousePressEvent( self, e ) :
        QListView.contentsMousePressEvent( self, e )
        p = QPoint( self.contentsToViewport( e.pos() ) )
        i = self.itemAt( p )
        if i :
            # if the user clicked into the root decoration of the item, don't try to start a drag!
            if self.rootIsDecorated(): isdecorated = 1
            else : isdecorated = 0
            if p.x() > self.header().sectionPos( self.header().mapToIndex( 0 )) + self.treeStepSize() * ( i.depth() + isdecorated + self.itemMargin() or
               p.x() < self.header().sectionPos( self.header().mapToIndex( 0 ) ) ) :
               self.presspos.setX(e.pos().x())
               self.presspos.setY(e.pos().y())
               self.mousePressed = True

    def contentsMouseMoveEvent( self, e ):
        offset = QPoint( self.presspos.x() - e.pos().x(),
                         self.presspos.y() - e.pos().y() )
        if self.mousePressed and (offset).manhattanLength() > QApplication.startDragDistance() :
            self.mousePressed = False
            item = self.itemAt( self.contentsToViewport(self.presspos) )
            if item :
                source = self.fullPath(item)
                if QFile.exists(source) :
                    ud = QUriDrag(self.viewport())
                    ud.setFileNames( QStringList (source) )
                    if ud.drag() :
                        QMessageBox.information( self, "Drag source",
                                                QString("Delete ")+source, "Not implemented" )

    def contentsMouseReleaseEvent( self, QMouseEvent ):
        self.mousePressed = False

    def setDir( self, s ):
        it = QListViewItem( self )
        it.setOpen(False)
        thisDir = QDir( s )
        it = QListViewItem( self )
        it.setOpen(False)
        lst = QStringList( QStringList.split( "/", s ) )
        listview2 = []
        listview2.extend( lst )
        
        item = self.firstChild()
        for it2 in listview2 :
            while item :
                if item.text( 0 ) == it2 :
                    item.setOpen( True )
                    break
                item = item.itemBelow()
        if item:
            self.setCurrentItem( item )

def main( args ):
    a = QApplication( args )
    
    mw = DirectoryView()
    mw.addColumn( "Name" )
    mw.addColumn( "Type" )
    mw.setTreeStepSize( 20 )
    
    roots = QDir.drives()
    if roots :
        for it in roots:
            fi = it
            root = Directory( mw, fi.filePath() )
            if roots.count(it) <= 1 :
                root.setOpen( True )  # be interesting
    
    mw.resize( 400, 400 )
    mw.setCaption( "Qt Example - Directory Browser" )
    mw.setAllColumnsShowFocus( True )
    a.setMainWidget( mw )
    mw.show()
    
    a.exec_loop()
    
if __name__=="__main__":
    main(sys.argv)
