#!/usr/bin/env python
#
# 2005-02-12    initial version    hp

import os
import pickle
from qt import *
from dirview import Directory, DirectoryView

bookmarks = [
    "22 14 8 1",
    "# c #000080",
    "a c #585858",
    "b c #000000",
    "c c #ffffff",
    "d c #ffffff",
    "e c #ffffff",
    "f c #000000",
    ". c None",
    "...bb.................",
    "..bacb....bbb.........",
    "..badcb.bbccbab.......",
    "..bacccbadccbab.......",
    "..baecdbcccdbab.......",
    "..bacccbacccbab.......",
    "..badcdbcecdfab.......",
    "..bacecbacccbab.......",
    "..baccdbcccdbab.......",
    "...badcbacdbbab.......",
    "....bacbcbbccab.......",
    ".....babbaaaaab.......",
    ".....bbabbbbbbb.......",
    "......bb.............."
]

home = [
    "16 15 4 1",
    "# c #000000",
    "a c #ffffff",
    "b c #c0c0c0",
    ". c None",
    ".......##.......",
    "..#...####......",
    "..#..#aabb#.....",
    "..#.#aaaabb#....",
    "..##aaaaaabb#...",
    "..#aaaaaaaabb#..",
    ".#aaaaaaaaabbb#.",
    "###aaaaaaaabb###",
    "..#aaaaaaaabb#..",
    "..#aaa###aabb#..",
    "..#aaa#.#aabb#..",
    "..#aaa#.#aabb#..",
    "..#aaa#.#aabb#..",
    "..#aaa#.#aabb#..",
    "..#####.######.."
]


class PixmapView(QScrollView):
    def __init__(self, parent):
        QScrollView.__init__(self, parent)
        self.pixmap = None
        self.viewport().setBackgroundMode(self.PaletteBase)

    def setPixmap(self, pix):
        self.pixmap = pix
        self.resizeContents(pix.size().width(), pix.size().height())
        self.viewport().repaint(False)

    def drawContents(self, p, cx, cy, cw, ch):
        p.fillRect(cx, cy, cw, ch, self.colorGroup().brush(QColorGroup.Base))
        p.drawPixmap(0, 0, self.pixmap)


class Preview(QWidgetStack):
    def __init__(self, parent):
        QWidgetStack.__init__(self, parent)
        self.normalText = QMultiLineEdit(self)
        self.normalText.setReadOnly(True)
        self.html = QTextView(self)
        self.pixmap = PixmapView(self)
        self.raiseWidget(self.normalText)

    def showPreview(self, url, size):
        if url.isLocalFile():
            path = url.path()
            fi = QFileInfo(path)
            if fi.isFile() and fi.size() > size * 1000:
                self.normalText.setText(
                    "The File\n%s\nis too large, so I don't show it!" % path)
                self.raiseWidget(self.normalText)
                return
            pix = QPixmap(path)
            if pix.isNull():
                if fi.isFile():
                    err = False
                    try:
                        text = open(path.latin1(), "r").read()
                    except IOError, msg:
                        text = QString(str(msg))
                        err = True
                    if not err and fi.extension().lower().contains("htm"):
                        url = self.html.mimeSourceFactory().makeAbsolute(
                                                path, self.html.context())
                        self.html.setText(text, url)
                        self.raiseWidget(self.html)
                        return
                    else:
                        self.normalText.setText(text)
                        self.raiseWidget(self.normalText)
                        return
                else:
                    self.normalText.setText("")
                    self.raiseWidget(self.normalText)
            else:
                self.pixmap.setPixmap(pix)
                self.raiseWidget(self.pixmap)
        else:
            self.normalText.setText("I only show local files!")
            self.raiseWidget(self.normalText)


# We can't instantiate QFilePreview directly because it is abstract.  Note that
# the previewUrl() abstract is patched in later to work around the fact that
# you can't multiply inherit from more than one wrapped class.
class FilePreview(QFilePreview):
    pass


class PreviewWidget(QVBox):
    def __init__(self, parent):
        QVBox.__init__(self, parent)
        self.setSpacing( 5 )
        self.setMargin( 5 )
        row = QHBox(self)
        row.setSpacing(5)
        QLabel("Only show files smaller than: ", row)
        self.sizeSpinBox = QSpinBox(1, 10000, 1, row)
        self.sizeSpinBox.setSuffix(" KB")
        self.sizeSpinBox.setValue(128)
        row.setFixedHeight(10 + self.sizeSpinBox.sizeHint().height())
        self.__preview = Preview(self)
        # workaround sip inability of multiple inheritance
        # create a local QFilePreview instance and redirect
        # the method, which is called on preview, to us
        self.preview = FilePreview()
        self.preview.previewUrl = self.previewUrl

    def previewUrl(self, url):
        self.__preview.showPreview(url, self.sizeSpinBox.value())


class CustomFileDialog(QFileDialog):
    def __init__(self, preview = False):
        QFileDialog.__init__(self, None, None, True)
        self.bookmarkFile = ".pybookmarks"
        self.bookmarkList = []
        if os.path.exists(self.bookmarkFile):
            try:
                self.bookmarkList = pickle.loads(open(self.bookmarkFile, "rb").read())
            except IOError, msg:
                print msg
        self.setDir("/")
        self.dirView = DirectoryView(self, None, True)
        self.dirView.addColumn("")
        self.dirView.header().hide()
        root = Directory(self.dirView, "/")
        root.setOpen(True)
        self.dirView.setFixedWidth(200)
        self.addLeftWidget(self.dirView)
        p = QPushButton(self)
        p.setPixmap(QPixmap(bookmarks))
        QToolTip.add(p, "Bookmarks")
        self.bookmarkMenu = QPopupMenu(self)
        self.connect(self.bookmarkMenu, SIGNAL("activated(int)"),
             self.bookmarkChosen)
        self.addId = self.bookmarkMenu.insertItem("Add bookmark")
        self.bookmarkMenu.insertSeparator()
        for l in self.bookmarkList:
            self.bookmarkMenu.insertItem(l)
        p.setPopup(self.bookmarkMenu)
        self.addToolButton(p, True)
        self.connect(self.dirView, PYSIGNAL("folderSelected(const QString &)"),
             self.setDir2)
        self.connect(self, SIGNAL("dirEntered(const QString &)"),
             self.dirView.setDir)
        b = QToolButton(self)
        QToolTip.add(b, "Go Home!")
        b.setPixmap(QPixmap(home))
        self.connect(b, SIGNAL("clicked()"), self.goHome)
        self.addToolButton(b)

        if preview:
            self.setContentsPreviewEnabled(True)
            pw = PreviewWidget(self)
            self.setContentsPreview(pw, pw.preview)
            self.setViewMode(QFileDialog.List)
            self.setPreviewMode(QFileDialog.Contents)

        w = self.width()
        h = self.height()
        if preview:
            self.resize(w + w / 2, h + h / 3)
        else:
            self.resize(w + w / 3, h + h / 4)

    def done(self, r):
        if self.bookmarkList:
            try:
                open(self.bookmarkFile, "wb").write(pickle.dumps(self.bookmarkList))
            except IOError, msg:
                print msg
        return QFileDialog.done(self, r)

    def showEvent(self, e):
        QFileDialog.showEvent(self, e)
        self.dirView.setDir(self.dirPath())

    def setDir2(self, path):
        self.blockSignals(True)
        self.setDir(path)
        self.blockSignals(False)

    def bookmarkChosen(self, i):
        if i == self.addId:
            # keep bookmarks pythonic
            dp = self.dirPath().latin1()
            if dp not in self.bookmarkList:
                self.bookmarkList.append(dp)
                self.bookmarkMenu.insertItem(dp)
        else:
            self.setDir(self.bookmarkMenu.text(i))

    def goHome(self):
        if os.getenv("HOME"):
            self.setDir(os.getenv("HOME"))
        else:
            self.setDir("/")


if __name__ == '__main__':
    import sys
    import getopt

    def usage(msg = None):
        if msg:
            print >> sys.stderr, msg
        print >> sys.stderr, """\
usage: qdir [--any | --dir | --custom] [--preview] [--default f] {--filter f} [caption ...]
     --any         Get any filename, need not exist.
     --dir         Return a directory rather than a file.
     --custom      Opens a customized QFileDialog with
                   dir browser, bookmark menu, etc.
     --preview     Show a preview widget.
     --default f   Start from directory/file f.
     --filter f    eg. '*.gif' '*.bmp'
     caption ...   Caption for dialog.
"""
        sys.exit(1)

    def main():
        options = ["help", "any", "dir", "custom", "preview", "default=", "filter="]
        mode = QFileDialog.ExistingFile
        preview = False
        custom = False
        start = None
        filter = QString.null
        app = QApplication(sys.argv)
    
        try:
            optlist, args = getopt.getopt(sys.argv[1:], "h", options)
        except getopt.error, msg:
            usage(msg)
    
        for opt, par in optlist:
            if opt in ("-h", "--help"):
                usage()
            elif opt == "--any":
                mode = QFileDialog.AnyFile
            elif opt == "--dir":
                mode = QFileDialog.Directory
            elif opt == "--default":
                start = par
            elif opt == "--filter":
                filter = par
            elif opt == "--preview":
                preview = True
            elif opt == "--custom":
                custom = True
        if args:
            caption = " ".join(args)
        elif mode == QFileDialog.Directory:
            caption = "Choose directory..."
        else:
            caption = "Choose file..."
        if not start:
            start = QDir.currentDirPath()
        if not custom:
            fd = QFileDialog(QString.null, filter, None, None, True)
            fd.setMode(mode)
            if preview:
                fd.setContentsPreviewEnabled(True)
                pw = PreviewWidget(fd)
                fd.setContentsPreview(pw, pw.preview)
                fd.setViewMode(QFileDialog.List)
                fd.setPreviewMode(QFileDialog.Contents)
                w = fd.width()
                h = fd.height()
                fd.resize(w + w / 3, h + h / 4)
            fd.setCaption(caption)
            fd.setSelection(start)
            if fd.exec_loop() == QDialog.Accepted:
                print "%s\n" % fd.selectedFile().latin1()
                return 0
            else:
                return 1
        else:
            fd = CustomFileDialog(preview)
            fd.exec_loop()
        return 1

    sys.exit(main())
