Hi,In this summer of code, i m working on the project, KDE-Conversation
logging framework.
A  part of the project is to Modify the history plugin of Kopete such that
it saves its chat in Akonadi.

In the process of modification, we decided that it is a good idea to replace
the QDomDocument with the History object, that represents a chatLog. While
trying to understand the code of the function given below,(as is uses
QDomNode, and Element everywhere), i though it would be a good idea, to get
mylogic clear, about the algorithm that is used in this function.

The function is as follows

QList<Kopete::Message> HistoryLogger::readMessages(int lines,

        const Kopete::Contact *c, Sens sens, bool reverseOrder, bool colorize)
{
        //QDate dd =  QDate::currentDate().addMonths(0-m_currentMonth);

        QList<Kopete::Message> messages;

        // A regexp useful for this function
        QRegExp rxTime("(\\d+) (\\d+):(\\d+)($|:)(\\d*)"); //(with a 0.7.x
compatibility)

        if(!m_metaContact)
        { //this may happen if the contact has been moved, and the MC deleted
                if(c && c->metaContact())
                        m_metaContact=c->metaContact();
                else
                        return messages;
        }

        if(c && 
!m_metaContact->contacts().contains(const_cast<Kopete::Contact*>(c)) )
                return messages;

        if(sens == Default )  //if no sens are selected, just continue in the
previous sens
                sens = m_oldSens ;
        if( m_oldSens != Default && sens != m_oldSens )
        { //we changed our sens! so retrieve the old position to fly in the 
other way
                m_currentElements= m_oldElements;
                m_currentMonth=m_oldMonth;
        }
        else
        {
                m_oldElements=m_currentElements;
                m_oldMonth=m_currentMonth;
        }
        m_oldSens=sens;

        //getting the color for messages:
        QColor fgColor = HistoryConfig::history_color();

        //Hello guest!

        //there are two algoritms:
        // - if a contact is given, or the metacontact contain only one
contact,  just read the history.
        // - else, merge the history

        //the merging algoritm is the following:
        // we see what contact we have to read first, and we look at the firt
date before another contact
        // has a message with a bigger date.

        QDateTime timeLimit;
        const Kopete::Contact *currentContact=c;
        if(!c && m_metaContact->contacts().count()==1)
                currentContact=m_metaContact->contacts().first();
        else if(!c && m_metaContact->contacts().count()== 0)
        {
                return messages;
        }


        while(messages.count() < lines)
        {
                timeLimit=QDateTime();
                QDomElement msgElem; //here is the message element
                QDateTime timestamp; //and the timestamp of this message

                if(!c && m_metaContact->contacts().count()>1)
                { //we have to merge the differents subcontact history
                        QList<Kopete::Contact*> ct=m_metaContact->contacts();

                        foreach(Kopete::Contact *contact, ct)
                        { //we loop over each contact. we are searching the 
contact with
the next message with the smallest date,
                          // it will becomes our current contact, and the 
contact with the
mext message with the second smallest
                          // date, this date will bocomes the limit.

                                QDomNode n;
                                if(m_currentElements.contains(contact))
                                        n=m_currentElements[contact];
                                else  //there is not yet "next message" 
register, so we will take
the first  (for the current month)
                                {
                                        QDomDocument 
doc=getDocument(contact,m_currentMonth);
                                        QDomElement docElem = 
doc.documentElement();
                                        n= 
(sens==Chronological)?docElem.firstChild() : docElem.lastChild();

                                        //i can't drop the root element
                                        workaround.append(docElem);
                                }
                                while(!n.isNull())
                                {
                                        QDomElement  msgElem2 = n.toElement();
                                        if( !msgElem2.isNull() && 
msgElem2.tagName()=="msg")
                                        {
                                                
rxTime.indexIn(msgElem2.attribute("time"));
                                                QDate 
d=QDate::currentDate().addMonths(0-m_currentMonth);
                                                QDateTime dt( QDate(d.year() , 
d.month() ,
rxTime.cap(1).toUInt()), QTime( rxTime.cap(2).toUInt() ,
rxTime.cap(3).toUInt(), rxTime.cap(5).toUInt()  ) );
                                                if(!timestamp.isValid() || 
((sens==Chronological )? dt <
timestamp : dt > timestamp) )
                                                {
                                                        timeLimit=timestamp;
                                                        timestamp=dt;
                                                        msgElem=msgElem2;
                                                        currentContact=contact;

                                                }
                                                else if(!timeLimit.isValid() || 
((sens==Chronological) ?
timeLimit > dt : timeLimit < dt) )
                                                {
                                                        timeLimit=dt;
                                                }
                                                break;
                                        }
                                        n=(sens==Chronological)? 
n.nextSibling() : n.previousSibling();
                                }
                        }
                }
                else  //we don't have to merge the history. just take the next 
item
in the contact
                {
                        if(m_currentElements.contains(currentContact))
                                msgElem=m_currentElements[currentContact];
                        else
                        {
                                QDomDocument 
doc=getDocument(currentContact,m_currentMonth);
                                QDomElement docElem = doc.documentElement();
                                QDomNode n= 
(sens==Chronological)?docElem.firstChild() :
docElem.lastChild();
                                msgElem=QDomElement();
                                while(!n.isNull()) //continue until we get a msg
                                {
                                        msgElem=n.toElement();
                                        if( !msgElem.isNull() && 
msgElem.tagName()=="msg")
                                        {
                                                
m_currentElements[currentContact]=msgElem;
                                                break;
                                        }
                                        n=(sens==Chronological)? 
n.nextSibling() : n.previousSibling();
                                }

                                //i can't drop the root element
                                workaround.append(docElem);
                        }
                }


                if(msgElem.isNull()) //we don't find ANY messages in any 
contact for
this month. so we change the month
                {
                        if(sens==Chronological)
                        {
                                if(m_currentMonth <= 0)
                                        break; //there are no other messages to 
show. break even if we
don't have nb messages
                                setCurrentMonth(m_currentMonth-1);
                        }
                        else
                        {
                                if(m_currentMonth >= getFirstMonth(c))
                                        break; //we don't have any other 
messages to show
                                setCurrentMonth(m_currentMonth+1);
                        }
                        continue; //begin the loop from the bottom, and find 
currentContact
and timeLimit again
                }

                while(
                        (messages.count() < lines) &&
                        !msgElem.isNull() &&
                        (!timestamp.isValid() || !timeLimit.isValid() ||
                                ((sens==Chronological) ? timestamp <= timeLimit 
: timestamp >= timeLimit)
                        ))
                {
                        // break this loop, if we have reached the correct 
number of messages,
                        // if there are no more messages for this contact, or 
if we reached
                        // the timeLimit msgElem is the next message, still not 
parsed, so
                        // we parse it now

                        Kopete::Message::MessageDirection dir = 
(msgElem.attribute("in") == "1") ?
                                Kopete::Message::Inbound : 
Kopete::Message::Outbound;

                        if(!m_hideOutgoing || dir != Kopete::Message::Outbound)
                        { //parse only if we don't hide it

                                if( m_filter.isNull() || ( m_filterRegExp?
msgElem.text().contains(QRegExp(m_filter,m_filterCaseSensitive)) :
msgElem.text().contains(m_filter,m_filterCaseSensitive) ))
                                {
                                        Q_ASSERT(currentContact);
                                        QString f=msgElem.attribute("from" );
                                        const Kopete::Contact *from=f.isNull() 
? 0L :
currentContact->account()->contacts().value(f);

                                        if( !from )
                                                from = (dir == 
Kopete::Message::Inbound) ? currentContact :
currentContact->account()->myself();

                                        Kopete::ContactPtrList to;
                                        to.append( 
dir==Kopete::Message::Inbound ?
currentContact->account()->myself() :
const_cast<Kopete::Contact*>(currentContact) );

                                        if(!timestamp.isValid())
                                        {
                                                //parse timestamp only if it 
was not already parsed
                                                
rxTime.indexIn(msgElem.attribute("time"));
                                                QDate 
d=QDate::currentDate().addMonths(0-m_currentMonth);
                                                timestamp=QDateTime( 
QDate(d.year() , d.month() ,
rxTime.cap(1).toUInt()), QTime( rxTime.cap(2).toUInt() ,
rxTime.cap(3).toUInt() , rxTime.cap(5).toUInt() ) );
                                        }

                                        Kopete::Message msg(from, to);
                                        msg.setTimestamp( timestamp );
                                        msg.setDirection( dir );
                                        msg.setPlainBody( msgElem.text() );
                                        if (colorize)
                                        {
                                                msg.setHtmlBody( 
QString::fromLatin1("<span style=\"color:%1\"
title=\"%2\">%3</span>")
                                                        .arg( fgColor.name(), 
timestamp.toString(Qt::LocalDate),
msg.escapedBody() ));
                                                msg.setForegroundColor( fgColor 
);
                                                msg.addClass( "history" );
                                        }
                                        else
                                        {
                                                msg.setHtmlBody( 
QString::fromLatin1("<span title=\"%1\">%2</span>")
                                                        .arg( 
timestamp.toString(Qt::LocalDate), msg.escapedBody() ));
                                        }

                                        if(reverseOrder)
                                                messages.prepend(msg);
                                        else
                                                messages.append(msg);
                                }
                        }

                        //here is the point of workaround. If i drop the root 
element, this crashes
                        //get the next message
                        QDomNode node = ( (sens==Chronological) ? 
msgElem.nextSibling() :
                                msgElem.previousSibling() );

                        msgElem = QDomElement(); //n.toElement();
                        while (!node.isNull() && msgElem.isNull())
                        {
                                msgElem = node.toElement();
                                if (!msgElem.isNull())
                                {
                                        if (msgElem.tagName() == "msg")
                                        {
                                                if (!c && 
(m_metaContact->contacts().count() > 1))
                                                {
                                                        // In case of 
hideoutgoing messages, it is faster to do
                                                        // this, so we don't 
parse the date if it is not needed
                                                        QRegExp rx("(\\d+) 
(\\d+):(\\d+):(\\d+)");
                                                        
rx.indexIn(msgElem.attribute("time"));

                                                        QDate d = 
QDate::currentDate().addMonths(0-m_currentMonth);
                                                        timestamp = QDateTime(
                                                                QDate(d.year(), 
d.month(), rx.cap(1).toUInt()),
                                                                QTime( 
rx.cap(2).toUInt(), rx.cap(3).toUInt() ) );
                                                }
                                                else
                                                        timestamp = 
QDateTime(); //invalid
                                        }
                                        else
                                                msgElem = QDomElement();
                                }

                                node = (sens == Chronological) ? 
node.nextSibling() :
                                        node.previousSibling();
                        }
                        m_currentElements[currentContact]=msgElem;  //this is 
the next message
                }
        }

        if(messages.count() < lines)
                m_currentElements.clear(); //current elements are null this 
can't be allowed

        return messages;
}

After spending a lot of time, in understanding this function,
The algorithm i have understood here is that,
The function has to return a number of lines of chat of a particular
contact.
IF the contact is given then just read the history and return it(easy part)
if the contact is not given, and the metacontact has more than one contact.
merge the history(confusing here),
How merging works is. if there are more than one contact, Find out the
Contact which has the chat with smallest/largest date (depends on the
chronological order). Note the date. Then find out another contact Which has
a message with date just below or above the first chosen contact.
Now return the list of chat messages that lie between these two dates..

Have i understood the logic correctly or have i missed something here ?


-- 
Please do make some comments on this, they are always helpful. :)
Greetings,
ro...@irc.freenode.net
roideuniverse.blogspot.com
_______________________________________________
kopete-devel mailing list
kopete-devel@kde.org
https://mail.kde.org/mailman/listinfo/kopete-devel

Reply via email to