HTML capable QListViewItem

Some time ago I was in the need of a HTML displaying QListViewItem, so I tried to implement one, and with the help of the QSimpleRichText class, it was fairly simple to get it running.

First of all I thought that the derived class needs to render all the extended QListViewItem capabilities like highlighting, focus border and so on, but then I used a little trick to make Qt doing this for me. I simply let Qt think, that there is a list-view item with no text in it and then call the paintCell() function to render the background. There was a little trouble getting the automatic relayout right (need to override the setup() function).

Some minor problems are in the source below, but nevertheless it is a good start:

  • Highlighted entries are not readable (the text color needs to be changed to white).
  • I don’t like the concept of calling setHeight() in drawCell() (but it worked fine with no locks).
  • I detected some pixel-rendering-errors on MacOS X, probably the background is not completely covered by paintCell(), I suspect that this is a problem of Qt.

And here is the excerpt:

class RListViewItem : public QListViewItem
{
    typedef QListViewItem Super;
 
public:
    RListViewItem(QListView* lv, QListViewItem* parent,
        const QString& str, unsigned int indent)
    : Super(lv, parent, "")
    , rText(str)
    , indent(indent)
    {}
 
    void setRichText(const QString& rt)
    {
        rText = rt;
        setup();
        repaint();
    }
 
protected:
 
    virtual void setup()
    {
        assert(listView());
 
        widthChanged();
 
        doc.reset(0);
        makeDocAvailable();
 
        QListView* lv = listView();
 
        doc->setWidth(std::max(1, int(lv->columnWidth(0) – indent)));
        setHeight(doc->height());
    }
 
 
    virtual void paintCell(QPainter* p, const QColorGroup& cg,
        int column, int width, int align)
    {
        assert(doc.get() && p);
 
        // paint background (empty text or other columns)
 
        if (column)
        {
            Super::paintCell(p, cg, column, width, align);
            return; // we support only column 0
        }
 
        // check width
 
        int widthPrepared = indent + doc->width();
 
        if (width != widthPrepared)
            doc->setWidth(p, std::max(1, int(width – indent)));
 
        // check height
 
        if (height() != doc->height())
        {
            // invalid height, don't draw
 
            setHeight(doc->height());
            return;
        }
 
        // draw appropriate background
 
        Super::paintCell(p, cg, column, width, align);
 
        // draw it
 
        doc->draw(p, indent, 0, QRect(0,0, width, height()), cg);
    }
 
private:
 
    void makeDocAvailable()
    {
        if (doc.get())
            return;
 
        assert(listView());
        doc.reset(new QSimpleRichText(rText, listView()->font()));
    }
 
    QString rText;
    unsigned int indent;
    std::auto_ptr<QSimpleRichText> doc;
};