root/trunk/qt4-gui/src/widgets/historyview.cpp

Revision 6466, 12.9 kB (checked in by flynd, 4 months ago)

Use const pointer for owner objects that are fetched only for read access.

Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * This file is part of Licq, an instant messaging client for UNIX.
4 * Copyright (C) 2007 Licq developers
5 *
6 * Licq is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * Licq is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Licq; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 */
20
21#include "historyview.h"
22
23#include <QDateTime>
24#include <QRegExp>
25#include <QTextCodec>
26
27#include <licq_events.h>
28#include <licq_user.h>
29
30#include "config/chat.h"
31
32#include "helpers/eventdesc.h"
33#include "helpers/usercodec.h"
34
35using namespace LicqQtGui;
36/* TRANSLATOR LicqQtGui::HistoryView */
37
38QStringList HistoryView::getStyleNames(bool includeHistoryStyles)
39{
40  static const char* const styleNames[] = {
41    QT_TR_NOOP("Default"),
42    QT_TR_NOOP("Compact"),
43    QT_TR_NOOP("Tiny"),
44    QT_TR_NOOP("Table"),
45    QT_TR_NOOP("Long"),
46    QT_TR_NOOP("Wide")
47  };
48
49  int listLength = 6;
50
51  // Style 5 (Wide) is currently only supported in buffered mode which is not used for chat
52  if (!includeHistoryStyles)
53    listLength--;
54
55  QStringList styleList;
56  for (int i = 0; i < listLength; ++i)
57    styleList.append(tr(styleNames[i]));
58
59  return styleList;
60}
61
62HistoryView::HistoryView(bool historyMode, QString id, unsigned long ppid, QWidget* parent)
63  : MLView(parent),
64    myId(id),
65    myPpid(ppid)
66{
67  Config::Chat* chatConfig = Config::Chat::instance();
68  if (historyMode)
69  {
70    setHistoryConfig(chatConfig->histMsgStyle(), chatConfig->histDateFormat(),
71        chatConfig->histVertSpacing(), chatConfig->reverseHistory());
72  }
73  else
74  {
75    setChatConfig(chatConfig->chatMsgStyle(), chatConfig->chatDateFormat(),
76        chatConfig->chatVertSpacing(), chatConfig->chatAppendLineBreak(),
77        chatConfig->showNotices());
78  }
79
80  setColors();
81  connect(chatConfig, SIGNAL(chatColorsChanged()), SLOT(setColors()));
82
83  clear();
84}
85
86HistoryView::~HistoryView()
87{
88}
89
90QSize HistoryView::sizeHint() const
91{
92  // Set a size hint wide enough for history to be readable
93  return QSize(400, 150);
94}
95
96void HistoryView::setHistoryConfig(unsigned short msgStyle, QString dateFormat, bool extraSpacing, bool reverse)
97{
98  myUseBuffer = true;
99  myMsgStyle = msgStyle;
100  myDateFormat = dateFormat;
101  myExtraSpacing = extraSpacing;
102  myReverse = reverse;
103  myAppendLineBreak = false;
104  myShowNotices = false;
105}
106
107void HistoryView::setChatConfig(unsigned short msgStyle, QString dateFormat, bool extraSpacing, bool appendLineBreak, bool showNotices)
108{
109  myUseBuffer = false;
110  myMsgStyle = msgStyle;
111  myDateFormat = dateFormat;
112  myExtraSpacing = extraSpacing;
113  myReverse = false;
114  myAppendLineBreak = appendLineBreak;
115  myShowNotices = showNotices;
116}
117
118void HistoryView::setColors(QString back, QString rcv, QString snt,
119    QString rcvHist, QString sntHist, QString notice)
120{
121  myColorRcv = rcv;
122  myColorSnt = snt;
123  if (!rcvHist.isEmpty())
124    myColorRcvHistory = rcvHist;
125  if (!sntHist.isEmpty())
126    myColorSntHistory = sntHist;
127  if (!notice.isEmpty())
128    myColorNotice = notice;
129  if (!back.isEmpty())
130    setBackground(QColor(back));
131}
132
133void HistoryView::setColors()
134{
135  Config::Chat* chatConfig = Config::Chat::instance();
136
137  setColors(
138      chatConfig->chatBackColor(),
139      chatConfig->recvColor(),
140      chatConfig->sentColor(),
141      chatConfig->recvHistoryColor(),
142      chatConfig->sentHistoryColor(),
143      chatConfig->noticeColor()
144  );
145}
146
147void HistoryView::setReverse(bool reverse)
148{
149  myReverse = reverse;
150}
151
152void HistoryView::setOwner(QString id, unsigned long ppid)
153{
154  myId = id;
155  if (ppid != 0)
156    myPpid = ppid;
157}
158
159void HistoryView::clear()
160{
161  MLView::clear();
162
163  myBuffer = "";
164
165  switch (myMsgStyle)
166  {
167    case 5:
168      // table doesn't work when appending so must buffer when using this style
169      myUseBuffer = true;
170      break;
171  }
172}
173
174void HistoryView::updateContent()
175{
176  if (!myUseBuffer)
177    return;
178
179  switch (myMsgStyle)
180  {
181    case 5:
182      // When myReverse is set (so that we prepend() to the buffer),
183      // we cannot put the <table> tag in HistoryView::clear().
184      // That's why we are prepend()'ing it here, in updateContent().
185      // Then, if we combine incremenetal updateContent()'s with
186      // myMsgStyle == 5 (we don't so far), we'll obtain several
187      // <table>'s in the buffer -- this works, but stinks heavily.
188      myBuffer.prepend("<table border=\"0\">");
189      break;
190  }
191  // actually, we don't need it at all
192  // myBuffer.prepend("<html><body>");
193
194  setText(myBuffer);
195}
196
197void HistoryView::internalAddMsg(QString s)
198{
199  if (myExtraSpacing)
200  {
201    if (myMsgStyle != 5)
202    {
203      if (myUseBuffer)
204      {
205        s.prepend("<p>");
206        s.append("</p>");
207      }
208      else
209      {
210        s.append("<br>");
211      }
212    }
213    else
214    {
215      s.append("<tr><td colspan=\"3\"></td></tr>");
216    }
217  }
218
219  if (myUseBuffer)
220  {
221    if (!myExtraSpacing && myMsgStyle != 5)
222      s.append("<br>");
223
224    if (myAppendLineBreak)
225      s.append("<hr>");
226
227    if (myReverse)
228      myBuffer.prepend(s);
229    else
230      myBuffer.append(s);
231  }
232  else
233  {
234    if (myAppendLineBreak)
235      s.append("<hr>");
236
237    append(s);
238  }
239}
240
241void HistoryView::addMsg(const ICQEvent* event)
242{
243  if (event->Id() == myId && event->PPID() == myPpid && event->UserEvent() != NULL)
244    addMsg(event->UserEvent());
245}
246
247void HistoryView::addMsg(direction dir, bool fromHistory, QString eventDescription, QDateTime date,
248  bool isDirect, bool isMultiRec, bool isUrgent, bool isEncrypted,
249  QString contactName, QString messageText, QString anchor)
250{
251  QString s;
252  QString color;
253
254  if (fromHistory)
255  {
256    if (dir == D_RECEIVER)
257      color = myColorRcvHistory;
258    else
259      color = myColorSntHistory;
260  }
261  else
262  {
263    if (dir == D_RECEIVER)
264      color = myColorRcv;
265    else
266      color = myColorSnt;
267  }
268
269  // Remove trailing line breaks.
270  for (int i = messageText.length(); i > 0; --i)
271  {
272    if (messageText.at(i - 1) != '\n' && messageText.at(i - 1) != '\r')
273    {
274      messageText.truncate(i);
275      break;
276    }
277  }
278
279  // Extract everything inside <body>...</body>
280  // Leaving <html> and <body> messes with our message display
281  QRegExp body("<body[^>]*>(.*)</body>");
282  if (body.indexIn(messageText) != -1)
283    messageText = body.cap(1);
284
285  // Remove all font tags
286  messageText.replace(QRegExp("</?font[^>]*>"), "");
287
288  QString dateString = date.toString(myDateFormat);
289
290  if (!anchor.isEmpty())
291    anchor = "<a name=\"" + anchor + "\"/>";
292
293  QString flags = QString("%1%2%3%4")
294      .arg(isDirect ? 'D' : '-')
295      .arg(isMultiRec ? 'M' : '-')
296      .arg(isUrgent ? 'U' : '-')
297      .arg(isEncrypted ? 'E' : '-');
298
299  switch (myMsgStyle)
300  {
301    case 0:
302      s = QString("%1<font color=\"%2\"><b>%3%4 [%5] %6:</b></font><br>")
303          .arg(anchor)
304          .arg(color)
305          .arg(eventDescription)
306          .arg(dateString)
307          .arg(flags)
308          .arg(contactName);
309      s.append(QString("<font color=\"%1\">%2</font>")
310          .arg(color)
311          .arg(messageText));
312      break;
313    case 1:
314      s = QString("%1<font color=\"%2\"><b>(%3%4) [%5] %6: </b></font>")
315          .arg(anchor)
316          .arg(color)
317          .arg(eventDescription)
318          .arg(dateString)
319          .arg(flags)
320          .arg(contactName);
321      s.append(QString("<font color=\"%1\">%2</font>")
322          .arg(color)
323          .arg(messageText));
324      break;
325    case 2:
326      s = QString("%1<font color=\"%2\"><b>%3%4 - %5: </b></font>")
327          .arg(anchor)
328          .arg(color)
329          .arg(eventDescription)
330          .arg(dateString)
331          .arg(contactName);
332      s.append(QString("<font color=\"%1\">%2</font>")
333          .arg(color)
334          .arg(messageText));
335      break;
336    case 3:
337      s = QString("%1<table border=\"1\"><tr><td><b><font color=\"%2\">%3%4</font><b><td><b><font color=\"%5\">%6</font></b></font></td>")
338          .arg(anchor)
339          .arg(color)
340          .arg(eventDescription)
341          .arg(dateString)
342          .arg(color)
343          .arg(contactName);
344      s.append(QString("<td><font color=\"%1\">%2</font></td></tr></table>")
345          .arg(color)
346          .arg(messageText));
347      break;
348    case 4:
349      s = QString("%1<font color=\"%2\"><b>%3 %4 %5<br>%6 [%7]</b></font><br><br>")
350          .arg(anchor)
351          .arg(color)
352          .arg(eventDescription)
353          .arg(dir == D_RECEIVER ? tr("from") : tr("to"))
354          .arg(contactName)
355          .arg(dateString)
356          .arg(flags);
357
358      // We break the paragraph here, since the history text
359      // could be in a different BiDi directionality than the
360      // header and timestamp text.
361      s.append(QString("<font color=\"%1\">%2</font><br><br>")
362          .arg(color)
363          .arg(messageText));
364      break;
365    case 5:
366      // Mode 5 is a table so it cannot be displayed in paragraphs
367      s = QString("<tr><td>%1<nobr><b><font color=\"%2\">%3</font><b> </nobr></td>")
368          .arg(anchor)
369          .arg(color)
370          .arg(dateString);
371      s.append(QString("<td><b><font color=\"%1\">%2</font></b></font>&nbsp;</td>")
372          .arg(color)
373          .arg(contactName));
374      s.append(QString("<td><font color=\"%1\">%2</font></td></tr>")
375          .arg(color)
376          .arg(messageText));
377      break;
378  }
379
380  internalAddMsg(s);
381}
382
383void HistoryView::addMsg(const CUserEvent* event, QString id, unsigned long ppid)
384{
385  QDateTime date;
386  date.setTime_t(event->Time());
387  QString sd = date.time().toString(myDateFormat);
388  bool bUseHTML = false;
389
390  QString contactName;
391  QTextCodec* codec = NULL;
392
393  if (id.isNull())
394  {
395    id = myId;
396    ppid = myPpid;
397  }
398
399  const ICQUser* u = gUserManager.FetchUser(id.toLatin1(), ppid, LOCK_R);
400  if (u != NULL)
401  {
402    codec = UserCodec::codecForICQUser(u);
403    if (event->Direction() == D_RECEIVER)
404    {
405      contactName = QString::fromUtf8(u->GetAlias());
406      if (myPpid == LICQ_PPID)
407        for (int x = 0; x < myId.length(); ++x)
408          if (!myId.at(x).isDigit())
409          {
410            bUseHTML = true;
411            break;
412          }
413    }
414    gUserManager.DropUser(u);
415  }
416
417  if (event->Direction() != D_RECEIVER)
418  {
419    const ICQOwner* o = gUserManager.FetchOwner(myPpid, LOCK_R);
420    if (o != NULL)
421    {
422      contactName = QString::fromUtf8(o->GetAlias());
423      gUserManager.DropOwner(o);
424    }
425  }
426
427  // Fallback, in case we couldn't fetch User.
428  if (codec == NULL)
429    codec = QTextCodec::codecForName("UTF-8");
430
431  QString messageText;
432  if (event->SubCommand() == ICQ_CMDxSUB_SMS)
433    messageText = QString::fromUtf8(event->Text());
434  else
435    messageText = codec->toUnicode(event->Text());
436
437  addMsg(event->Direction(), false,
438         (event->SubCommand() == ICQ_CMDxSUB_MSG ? QString("") : (EventDescription(event) + " ")),
439         date,
440         event->IsDirect(),
441         event->IsMultiRec(),
442         event->IsUrgent(),
443         event->IsEncrypted(),
444         contactName,
445         MLView::toRichText(messageText, true, bUseHTML));
446  GotoEnd();
447
448  if (event->Direction() == D_RECEIVER &&
449      (event->SubCommand() == ICQ_CMDxSUB_MSG ||
450       event->SubCommand() == ICQ_CMDxSUB_URL))
451    emit messageAdded();
452}
453
454void HistoryView::addNotice(QDateTime dt, QString messageText)
455{
456  if (!myShowNotices)
457    return;
458
459  QString color = myColorNotice;
460  QString s = "";
461  const QString dateTime = dt.toString(myDateFormat);
462
463  // Remove trailing line breaks.
464  for (int i = messageText.length(); i >= 0; --i)
465  {
466    if (messageText.at(i - 1) != '\n' && messageText.at(i - 1) != '\r')
467    {
468      messageText.truncate(i);
469      break;
470    }
471  }
472
473  switch (myMsgStyle)
474  {
475    case 1:
476      s = QString("<font color=\"%1\"><b>[%2] %3</b></font>")
477          .arg(color)
478          .arg(dateTime)
479          .arg(messageText);
480      break;
481    case 2:
482      s = QString("<font color=\"%1\"><b>[%2] %3</b></font>")
483          .arg(color)
484          .arg(dateTime)
485          .arg(messageText);
486      break;
487    case 3:
488      s = QString("<table border=\"1\"><tr><td><b><font color=\"%1\">%2</font><b><td><b><font color=\"%3\">%4</font></b></font></td></tr></table>")
489          .arg(color)
490          .arg(dateTime)
491          .arg(color)
492          .arg(messageText);
493      break;
494
495    case 5:
496      s = QString("<tr><td><b><font color=\"%1\">%2</font><b></td><td colspan=\"2\"><b><font color=\"%3\">%4</font></b></font></td></tr>")
497          .arg(color)
498          .arg(dateTime)
499          .arg(color)
500          .arg(messageText);
501      break;
502
503    case 0:
504    default:
505      s = QString("<font color=\"%1\"><b>[%2] %3</b></font><br>")
506          .arg(color)
507          .arg(dateTime)
508          .arg(messageText);
509      break;
510  }
511
512  internalAddMsg(s);
513  GotoEnd();
514}
Note: See TracBrowser for help on using the browser.