--- category: '' date: 2004/02/02 18:09 description: '' link: '' priority: '' slug: '17' tags: kde, programming, python title: 'PyBrowser: a nicer QTextBrowser' type: text updated: 2004/02/02 18:09 url_type: '' --- .. raw:: html

Working on some of my personal projects (specifically KRsN and Notty), I have needed to make QTextBrowser act a little more like a mensch in a few ways:

To achieve these goals, I had to dig into QMimeSourceFactory and QDragObject, and it ain't all that pretty :-)

Click here for the python file (it's in the public domain, do as you wish with it).

Current problems:

If anyone who has better python kungfu can help me, I'm a happy guy.

The result, in 143 lines of python, counting blanks and little demo proggie is this:

Source code for pybrowser.py
from qt import *
    import urlparse
    import traceback
    from urllib import urlopen
    import time
    
    
    class MimeFactory(QMimeSourceFactory):
    
            current=None
    
            def __init__(self,browser):
                    QMimeSourceFactory.__init__(self)
                    self.browser=browser
    
            def data(self,name,context=None):
                    if context:
                            return self.data(self.makeAbsolute(name,context))
                    res=None
                    (local,type,subtype)=self.fetchURL(str(name))
                    if type=="image":
                            i=QImage()
                            #If image loading fails, return empty image
                            if not i.loadFromData(local,None):
                                    i.create(10,10,8)
                            res=QImageDrag(i)
                    else: #Assume it's text
                            res=QTextDrag(local)
                            if subtype=="html":
                                    res.setSubtype("html")
                            else:
                                    res.setSubtype("plain")
                    self.current=res
                    return self.current
    
            def makeAbsolute(self,name,context):
                    return urlparse.urljoin(str(context),str(name))
    
            def fetchURL(self,url):
                    local=""
                    type="text"
                    subtype="plain"
                    try:
                            remote=urlopen(url)
                            info=remote.info()
                            (type,subtype)=info.gettype().split("/")
                            local=remote.read()
                            l=info.getheader('content-length')
                            if not l:
                                    l=0
                            else:
                                    l=int(l)
                            print 'size',l
    
                            p=0
                            c=0
                            bsize=1024
                            while True:
                                    self.browser.emit(PYSIGNAL('status'),("Downloading: "\
+url+"(%sKB)"%str(p/1024),)) self.browser.emit(PYSIGNAL('size'),(p,)) if l: self.browser.emit(PYSIGNAL('percent'),((p*100)/l,)) qApp.processEvents() #Lame attempt at making this report about once a second stamp=time.time() c=c+1 buf=remote.read(int(bsize)) delta=time.time()-stamp if delta <.5: #Data coming quickly, get more on each loop bsize=min(bsize*1.25,10000) elif delta >.75: #Data coming slowly, get less on each loop bsize=max(bsize*.75,100) #End of file if buf=='': self.browser.emit(PYSIGNAL('percent'),(100,)) break p=p+len(buf) local=local+buf except: traceback.print_exc() return (local,type,subtype) def printPage(self): printer=QPrinter(QPrinter.HighResolution) printer.setFullPage(True) if printer.setup(self): p=QPainter(printer) if not p.isActive(): # starting printing failed return; metrics=QPaintDeviceMetrics(p.device()) dpiy = metrics.logicalDpiY() margin = int(((2/2.54)*dpiy)) # 2 cm margins body=QRect(margin, margin, metrics.width() - 2*margin, metrics.height()-2*margin) richText=QSimpleRichText( self.viewer.text(), QFont(), self.viewer.context(), self.viewer.styleSheet(), self.viewer.mimeSourceFactory(), body.height() ) richText.setWidth( p, body.width() ) view=QRect(body) page = 1 while True: richText.draw(p,body.left(),body.top(),view,self.colorGroup()) view.moveBy(0,body.height()) p.translate(0,-body.height()) p.drawText(view.right()-p.fontMetrics().width(str(page)), view.bottom()+p.fontMetrics().ascent()+5, str(page)); if view.top() >= richText.height(): break printer.newPage() page+=1 p.end() class QBrowser(QTextBrowser): def __init__(self,parent=None): QTextBrowser.__init__(self,parent) self.mf=MimeFactory(self) self.setMimeSourceFactory(self.mf) def printit(arg): print str(arg) if __name__=="__main__": from sys import argv app=QApplication(argv) w=QBrowser() w.connect(w,PYSIGNAL('percent'),printit) w.connect(w,PYSIGNAL('size'),printit) w.connect(w,PYSIGNAL('status'),printit) w.show() w.setSource(argv[1]) app.connect(app, SIGNAL("lastWindowClosed()") , app, SLOT("quit()")) app.exec_loop()