PDA

View Full Version : QTextDocument and insertImage



bunjee
21st January 2008, 16:34
Hey there,

I'm using a QTextDocument and QTextCursor::insertImage.
The goal is to remplace : - ) keywords by a :) in the text document.



ZePictureWidget * test = new ZePictureWidget("zeData/zeSmileys/Crying.png");
document()->addResource(QTextDocument::ImageResource, QUrl("test"), test->getPixmap());


//================================================== ===========================
//================================================== ===========================

void ZeSmileyController::scanSmiley(QTextDocument & textDocument,
const QString & smiley,
const QString & path)
{
QTextCursor textCursor;
textCursor = textDocument.find(smiley);
while (textCursor.isNull() == false)
{
textCursor.deleteChar();
textCursor.insertImage("test");

textCursor = textDocument.find(smiley);
}
}

Unfortunately when replacing 100 smileys it's very slow, it's like the Cursor is reloading the smileys over and over again.

Any idea?

wysota
21st January 2008, 18:47
Take a look at QTextDocument::addResource.

bunjee
21st January 2008, 22:31
1.
ZePictureWidget * test = new ZePictureWidget("zeData/zeSmileys/Crying.png");
2.
document()->addResource(QTextDocument::ImageResource, QUrl("test"), test->getPixmap());

I've already used that, did I miss something?

wysota
21st January 2008, 22:51
Oh, no... sorry, I read your post too fast and missed the first chunk of code. Did you try profiling the code to find the bottleneck?

bunjee
21st January 2008, 23:33
//================================================== ===========================
//================================================== ===========================

void ZeSmileyController::InsertSmiley(QTextDocument & textDocument)
{
ZeLog::get()->AddLine("ZeSmileyController - insertSmiley\n");

QMapIterator<QString, QString> i(mSmileyMap);

while (i.hasNext())
{
i.next();
scanSmiley(textDocument, i.key(), i.value());
}
}

//================================================== ===========================
//================================================== ===========================

void ZeSmileyController::scanSmiley(QTextDocument & textDocument,
const QString & smiley,
const QString & path)
{
QTextCursor textCursor;
textCursor = textDocument.find(smiley);
while (textCursor.isNull() == false)
{
textCursor.insertImage(path); // <<< THIS IS SLOW

textCursor = textDocument.find(smiley);
}
}

Yes : textCursor.insertImage(path); is the line slowing down everything.

wysota
22nd January 2008, 00:58
How about profiling deeper - going into Qt code too?

jpn
22nd January 2008, 07:59
Do you replace several smileys at time? Perhaps you should break the QTextDocument-QTextEdit relation meanwhile? I guess QTextEdit ends up doing a lot of unnecessary updates upon every change to the document.

bunjee
22nd January 2008, 16:38
Yes I'm doing a lot of smiley replacement at a time, since I'm progressively refreshing a text bubble as if somebody was typing on the keyboard.

how would you break the QTextDocument-QTextEdit relation meanwhile?

Thanks.

jpn
22nd January 2008, 17:31
Whatever it takes to make QTextEdit ignorant of those updates. Block signals, remove and set the document back or modify a copy of the document. Also, make sure you have things like undo-redo-stack disabled.

wysota
22nd January 2008, 20:12
It might be wise to replace the smileys as the user is typing the text - this way you replace only one at the time and only check the current paragraph instead of the whole text that gets bigger and bigger as one types. If you work on a document which already exists, be sure to replace the smileys before you associate the text with a widget as J-P suggests - this way the text will not have to be relaid again and again.

bunjee
22nd January 2008, 21:28
Thanks jpn and wysota,

This implementation is working way faster :


//================================================== ===========================
//================================================== ===========================

void ZeParagraphWidget::setHtml(const QString & text, bool smiley)
{
//QTextEdit::setHtml(text);

QTextDocument * temp = document()->clone();

temp->setHtml(text);
if (smiley)
{
ZeSmileyController::get()->InsertSmiley(*temp);
setDocument(temp);
}
emit paragraphUpdate();
}

I don't seem to have to delete my old document after doing a setDocument, do you confirm on that ?

jpn
22nd January 2008, 21:41
I don't seem to have to delete my old document after doing a setDocument, do you confirm on that ?
As a practice, you could open src/gui/widgets/qtextedit.cpp and confirm it yourself. It's wonderful to have sources, isn't it?

PS. src/gui/text/qtextcontrol.cpp ;)

wysota
22nd January 2008, 22:52
A general rule is that a widget or other component will delete the object it doesn't use anymore if it is its child in terms of QObject hierarchy.

bunjee
23rd January 2008, 21:03
And Qt doc confirms this :


void QTextEdit::setDocument ( QTextDocument * document )
Makes document the new document of the text editor.
The parent QObject of the provided document remains the owner of the object. If the current document is a child of the text editor, then it is deleted.
See also document().