views:

988

answers:

4

I'm rendering some HTML in a QT QLabel. The HTML looks like this:

<pre>foo\tbar</pre>

(note that I've put "\t" where there is a tab chracter in the code).

This renders fine, but the tab character appears to be rendered as eight spaces, whereas I want it to be redered as 4. How can I change this without having to change the source HTML?

+3  A: 

According to W3 (HTML4):

The horizontal tab character (decimal 9 in [ISO10646] and [ISO88591]) is usually interpreted by visual user agents as the smallest non-zero number of spaces necessary to line characters up along tab stops that are every 8 characters. We strongly discourage using horizontal tabs in preformatted text since it is common practice, when editing, to set the tab-spacing to other values, leading to misaligned documents.

It's implementation-defined, essencially. Most, if not all, browsers/renderers use eight spaces for tabs. This cannot be configured in Qt.

It is, however somewhat trivial to go through your HTML and replace tabs with however many spaces you wish. Write a simple parser for that. Pseudocode:

for each <pre> block {
    for each line in block {
        position_in_line = 0

        for each character in line {
            if character is a tab {
                remove tab character

                do {
                    add a space character

                    ++position_in_line
                } while position_in_line % 8 != 0
            } else {
                ++position_in_line
            }
        }
    }
}

In case you're curious, HTML3 specifies the use of eight-character tabs:

Within <PRE>, the tab should be interpreted to shift the horizontal column position to the next position which is a multiple of 8 on the same line; that is, col := (col+8) mod 8.

strager
Yes, I realize that I could edit the source and replace tab characters with space characters, but I explicitly mentioned in the question that I really don't want to start editing the source HTML.Besides, your parser pseudocode could be written a lot easier in python:code.replace('\t', ' ')
Thomi
He explained that it is your only solution dumbarse.
Max Howell
+1  A: 

Try this:

<pre style="tab-interval:0.5in">foo\tbar</pre>

Could work

xgoan
A: 

White space is not the answer really because then the rows wont be aligned as in:

This is some text. This is some text. This is some text. 
This              This is some text. This is some text. 
This is some text. This is some text. This is some text. 
This is some text. This is some text. This is some text.
Dimitrije
+1  A: 

While QLabel uses a QTextDocument internally when rendering rich text, it does not allow access to it in it's API. However, since QTextDocument is a QObject, you can try to use

QTextDocument * tl = label->findChild<QTextDocument>();

to get access to it (will work if the QLabel creates the QTextDocument as a (direct or indirect) child of itself).

Once you have a pointer to the text document, you can use the QTextDocument API, e.g. QTextOption::setTabsStop(), to change the tab stops.

The last step is to somehow make the QLabel repaint itself. Probably a call to QWidget::update() suffices, but caching (or worse, recreating the text document) might thward that. In this case, you can register an event listener on the label to adjust the text document just prior to a paintEvent(), but note that the sizeHint() might also change when the tab stops change, so it might be more complicated still.

That said, it's how I'd approach the problem.