kchatbase.cpp

00001 /*
00002     This file is part of the KDE games library
00003     Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de)
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License version 2 as published by the Free Software Foundation.
00008 
00009     This library is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012     Library General Public License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to
00016     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017     Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "kchatbase.h"
00021 
00022 #include <klineedit.h>
00023 #include <klocale.h>
00024 #include <kstandarddirs.h>
00025 #include <kconfig.h>
00026 #include <kapplication.h>
00027 #include <kdebug.h>
00028 
00029 #include <qlayout.h>
00030 #include <qcombobox.h>
00031 #include <qpainter.h>
00032 
00033 class KChatBaseTextPrivate
00034 {
00035 public:
00036     KChatBaseTextPrivate()
00037     {
00038         mNameFont = 0;
00039         mMessageFont = 0;
00040     }
00041 
00042     QString mName;
00043     QString mMessage;
00044 
00045     const QFont* mNameFont;
00046     const QFont* mMessageFont;
00047 };
00048 
00049 
00050 KChatBaseText::KChatBaseText(const QString& name, const QString& message) : QListBoxText()
00051 {
00052  init();
00053  setName(name);
00054  setMessage(message);
00055 }
00056 
00057 KChatBaseText::KChatBaseText(const QString& message) : QListBoxText()
00058 {
00059  init();
00060  setMessage(message);
00061 }
00062 
00063 KChatBaseText::~KChatBaseText()
00064 { 
00065  delete d;
00066 }
00067 
00068 void KChatBaseText::init()
00069 {
00070  d = new KChatBaseTextPrivate;
00071 }
00072 
00073 void KChatBaseText::setName(const QString& n)
00074 {
00075 // d->mName = n;
00076  d->mName = QString("%1: ").arg(n);
00077  setText(QString("%1: %2").arg(name()).arg(message())); // esp. for sorting
00078 }
00079 
00080 void KChatBaseText::setMessage(const QString& m)
00081 {
00082  d->mMessage = m;
00083  setText(QString("%1: %2").arg(name()).arg(message())); // esp. for sorting
00084 }
00085 
00086 const QString& KChatBaseText::name() const
00087 { return d->mName; }
00088 
00089 const QString& KChatBaseText::message() const
00090 { return d->mMessage; }
00091 
00092 QFont KChatBaseText::nameFont() const
00093 {
00094  if (d->mNameFont) {
00095     return *d->mNameFont; 
00096  } else if (listBox()) {
00097     return listBox()->font();
00098  } else {
00099     return QFont();
00100  }
00101 }
00102 
00103 QFont KChatBaseText::messageFont() const
00104 {
00105  if (d->mMessageFont) {
00106     return *d->mMessageFont; 
00107  } else if (listBox()) {
00108     return listBox()->font();
00109  } else {
00110     return QFont();
00111  }
00112 }
00113 
00114 void KChatBaseText::setNameFont(const QFont* f)
00115 { d->mNameFont = f; }
00116 
00117 void KChatBaseText::setMessageFont(const QFont* f)
00118 { d->mMessageFont = f; }
00119 
00120 void KChatBaseText::paint(QPainter* painter)
00121 {
00122  QFontMetrics fm = painter->fontMetrics();
00123  painter->setFont(nameFont());
00124  painter->drawText(3, fm.ascent() + fm.leading()/2, name());
00125  painter->setFont(messageFont());
00126  painter->drawText(3 + QFontMetrics(nameFont()).width(name()), fm.ascent() + fm.leading()/2, message());
00127 }
00128 
00129 int KChatBaseText::width(QListBox* lb) const
00130 {
00131  int w = 0;
00132  if (lb) {
00133     w += 6;
00134     w += QFontMetrics(nameFont()).width(name());
00135     w += QFontMetrics(messageFont()).width(message());
00136  }
00137 // int w = lb ? lb->fontMetrics().width( text() ) + 6 : 0; // QT orig
00138  return QMAX(w, QApplication::globalStrut().width());
00139 }
00140 
00141 int KChatBaseText::height(QListBox* lb) const
00142 {
00143  int h = 0;
00144  if (lb) {
00145     h += 2;
00146     // AB: is lineSpacing still correct?
00147     if (QFontMetrics(nameFont()).lineSpacing() > QFontMetrics(messageFont()).lineSpacing()) { 
00148         h += QFontMetrics(nameFont()).lineSpacing();
00149     } else {
00150         h += QFontMetrics(messageFont()).lineSpacing();
00151     }
00152  }
00153 // int h = lb ? lb->fontMetrics().lineSpacing() + 2 : 0; // QT orig
00154  return QMAX(h, QApplication::globalStrut().height());
00155 }
00156 
00157 
00158 
00159 class KChatBasePrivate
00160 {
00161 public:
00162     KChatBasePrivate() 
00163     { 
00164         mBox = 0;
00165         mEdit = 0;
00166         mCombo = 0;
00167 
00168         mAcceptMessage = true;
00169         mMaxItems = -1;
00170     }
00171     QListBox* mBox;
00172     KLineEdit* mEdit;
00173     QComboBox* mCombo;
00174     bool mAcceptMessage;
00175     int mMaxItems;
00176 
00177     QValueList<int> mIndex2Id;
00178 
00179     QFont mNameFont;
00180     QFont mMessageFont;
00181     QFont mSystemNameFont;
00182     QFont mSystemMessageFont;
00183 };
00184 
00185 KChatBase::KChatBase(QWidget* parent, bool noComboBox) : QFrame(parent)
00186 {
00187  init(noComboBox); 
00188 }
00189 
00190 KChatBase::~KChatBase()
00191 {
00192 // kdDebug(11000) << "KChatBase: DESTRUCT (" << this << ")" << endl;
00193  saveConfig();
00194  delete d;
00195 }
00196 
00197 void KChatBase::init(bool noComboBox)
00198 {
00199 // kdDebug(11000) << "KChatBase: INIT (" << this << ")" << endl;
00200 
00201  d = new KChatBasePrivate;
00202 
00203  setMinimumWidth(100);
00204  setMinimumHeight(150);
00205  
00206  QVBoxLayout* l = new QVBoxLayout(this);
00207 
00208  d->mBox = new QListBox(this);
00209  connect(d->mBox, SIGNAL(rightButtonClicked(QListBoxItem*, const QPoint&)), 
00210         this, SIGNAL(rightButtonClicked(QListBoxItem*, const QPoint&)));
00211  l->addWidget(d->mBox);
00212  d->mBox->setVScrollBarMode(QScrollView::AlwaysOn);
00213  d->mBox->setHScrollBarMode(QScrollView::AlwaysOff);
00214  d->mBox->setFocusPolicy(QWidget::NoFocus);
00215 // d->mBox->setSelectionMode(QListBox::NoSelection);
00216  d->mBox->setSelectionMode(QListBox::Single);
00217 
00218  l->addSpacing(5);
00219 
00220  QHBoxLayout* h = new QHBoxLayout(l);
00221  d->mEdit = new KLineEdit(this);
00222  d->mEdit->setHandleSignals(false);
00223  d->mEdit->setTrapReturnKey(true);
00224  d->mEdit->completionObject(); // add the completion object
00225  d->mEdit->setCompletionMode(KGlobalSettings::CompletionNone);
00226  connect(d->mEdit, SIGNAL(returnPressed(const QString&)), this, SLOT(slotReturnPressed(const QString&)));
00227  h->addWidget(d->mEdit);
00228 
00229  if (!noComboBox) {
00230     d->mCombo = new QComboBox(this);
00231     h->addWidget(d->mCombo);
00232     addSendingEntry(i18n("Send to All Players"), SendToAll);//FIXME: where to put the id?
00233  }
00234 
00235  d->mAcceptMessage = true; // by default
00236  setMaxItems(-1); // unlimited
00237 
00238  if (kapp) {
00239     // kapp might be NULL as well - in case we are in Qt designer.
00240     readConfig();
00241  }
00242 }
00243 
00244 bool KChatBase::acceptMessage() const
00245 { return d->mAcceptMessage; }
00246 
00247 void KChatBase::setAcceptMessage(bool a)
00248 { d->mAcceptMessage = a; }
00249 
00250 bool KChatBase::addSendingEntry(const QString& text, int id)
00251 {
00252 //FIXME: is ID used correctly? 
00253 // do we need ID at all? 
00254 // what the hell should be here?
00255 // d->mCombo->insertItem(i18n("Send to All Players"), SendToAll);
00256  return insertSendingEntry(text, id);
00257 }
00258 
00259 bool KChatBase::insertSendingEntry(const QString& text, int id, int index)
00260 {
00261  if (!d->mCombo) {
00262     kdWarning(11000) << "KChatBase: Cannot add an entry to the combo box" << endl;
00263     return false;
00264  }
00265  if (d->mIndex2Id.findIndex(id) != -1) {
00266     kdError(11000) << "KChatBase: Cannot add more than one entry with the same ID! " << endl;
00267     kdError(11000) << "KChatBase: Text="<<text<<endl;
00268     return false;
00269  }
00270  d->mCombo->insertItem(text, index);
00271  if (index < 0) {
00272     d->mIndex2Id.append(id);
00273  } else {
00274     d->mIndex2Id.insert(d->mIndex2Id.at(index), id);
00275  }
00276  if (d->mIndex2Id.count() != (uint)d->mCombo->count()) {
00277     kdError(11000) << "KChatBase: internal ERROR - local IDs do not match combo box entries!" << endl;
00278  }
00279  return true;
00280 }
00281 
00282 int KChatBase::sendingEntry() const
00283 {
00284  if (!d->mCombo) {
00285     kdWarning(11001) << "Cannot retrieve index from NULL combo box" << endl;
00286     return -1;
00287  }
00288  int index = d->mCombo->currentItem();
00289  if (d->mIndex2Id.at(index) == d->mIndex2Id.end()) {
00290     kdWarning(11000) << "could not find the selected sending entry!" << endl;
00291     return -1;
00292  }
00293  return d->mIndex2Id[index];
00294 }
00295 
00296 void KChatBase::removeSendingEntry(int id)
00297 {
00298  if (!d->mCombo) {
00299     kdWarning(11000) << "KChatBase: Cannot remove an entry from the combo box" << endl;
00300     return;
00301  }
00302  d->mCombo->removeItem(findIndex(id));
00303  d->mIndex2Id.remove(id);
00304 }
00305 
00306 void KChatBase::changeSendingEntry(const QString& text, int id)
00307 {
00308  if (!d->mCombo) {
00309     kdWarning(11000) << "KChatBase: Cannot change an entry in the combo box" << endl;
00310     return;
00311  }
00312  int index = findIndex(id);
00313  d->mCombo->changeItem(text, index);
00314 }
00315 
00316 void KChatBase::setSendingEntry(int id)
00317 {
00318  if (!d->mCombo) {
00319     kdWarning(11000) << "KChatBase: Cannot set an entry in the combo box" << endl;
00320     return;
00321  }
00322  d->mCombo->setCurrentItem(findIndex(id));
00323 }
00324  
00325 int KChatBase::findIndex(int id) const
00326 {
00327  return d->mIndex2Id.findIndex(id);
00328 }
00329 
00330 int KChatBase::nextId() const
00331 {
00332  int i = SendToAll + 1;
00333  while (d->mIndex2Id.findIndex(i) != -1) {
00334     i++;
00335  }
00336  return i;
00337 }
00338 
00339 void KChatBase::addItem(const QListBoxItem* text)
00340 {
00341  d->mBox->insertItem(text); 
00342  int index = d->mBox->count() -1;
00343  d->mBox->setBottomItem(index);//FIXME: don't scroll to bottom if user scrolled down manually
00344  if (maxItems() >= 0 && d->mBox->count() > (unsigned int)maxItems()) {
00345     d->mBox->removeItem(0);
00346  }
00347 }
00348 
00349 void KChatBase::addMessage(const QString& fromName, const QString& text)
00350 {
00351 //maybe "%1 says: %2" or so
00352  addItem(layoutMessage(fromName, text));
00353 }
00354 
00355 void KChatBase::addSystemMessage(const QString& fromName, const QString& text)
00356 {
00357  addItem(layoutSystemMessage(fromName, text));
00358 }
00359 
00360 QListBoxItem* KChatBase::layoutMessage(const QString& fromName, const QString& text)
00361 {
00362  //TODO: KChatBaseConfigure? - e.g. color
00363  QListBoxItem* message;
00364  if (text.startsWith("/me ")) {
00365     // replace "/me" by a nice star. leave one space after the star
00366     QPixmap pix;
00367     pix.load(locate("data", QString::fromLatin1("kdegames/pics/star.png")));
00368     
00369     //TODO KChatBasePixmap? Should change the font here!
00370     
00371     message = (QListBoxItem*)new QListBoxPixmap(pix, i18n("%1 %2").arg(fromName).arg(text.mid(3)));
00372  } else {
00373     // the text is not edited in any way. just return an item
00374     KChatBaseText* m = new KChatBaseText(fromName, text);
00375     m->setNameFont(&d->mNameFont);
00376     m->setMessageFont(&d->mMessageFont);
00377     message = (QListBoxItem*)m;
00378  }
00379  return message;
00380 }
00381 
00382 QListBoxItem* KChatBase::layoutSystemMessage(const QString& fromName, const QString& text)
00383 {
00384  //TODO: KChatBaseConfigure? - e.g. color
00385 
00386  // no need to check for /me etc.
00387  KChatBaseText* m = new KChatBaseText(i18n("--- %1").arg(fromName), text);
00388  m->setNameFont(&d->mSystemNameFont);
00389  m->setMessageFont(&d->mSystemMessageFont);
00390  return (QListBoxItem*)m;
00391 }
00392 
00393 void KChatBase::slotReturnPressed(const QString& text)
00394 {
00395  if (text.length() <= 0) {
00396     // no text entered - probably hit return by accident
00397     return;
00398  } else if (!acceptMessage()) {
00399     return;
00400  }
00401  d->mEdit->completionObject()->addItem(text);
00402 // connect(d->mEdit, SIGNAL(returnPressed(const QString&)), comp, SLOT(addItem(const QString&)));
00403  d->mEdit->clear();
00404  returnPressed(text);
00405 }
00406 
00407 QString KChatBase::comboBoxItem(const QString& name) const
00408 { // TODO: such a function for "send to all" and "send to my group"
00409  return i18n("Send to %1").arg(name);
00410 }
00411 
00412 void KChatBase::slotClear()
00413 {
00414  d->mBox->clear();
00415 }
00416 
00417 void KChatBase::setCompletionMode(KGlobalSettings::Completion mode)
00418 { d->mEdit->setCompletionMode(mode); }
00419 
00420 void KChatBase::setNameFont(const QFont& font)
00421 {
00422  d->mNameFont = font; 
00423  d->mBox->triggerUpdate(false);
00424 }
00425 
00426 void KChatBase::setMessageFont(const QFont& font)
00427 {
00428  d->mMessageFont = font; 
00429  d->mBox->triggerUpdate(false);
00430 }
00431 
00432 void KChatBase::setBothFont(const QFont& font)
00433 {
00434  setNameFont(font);
00435  setMessageFont(font);
00436 }
00437 
00438 const QFont& KChatBase::nameFont() const
00439 { return d->mNameFont; }
00440 
00441 const QFont& KChatBase::messageFont() const
00442 { return d->mMessageFont; }
00443 
00444 void KChatBase::setSystemNameFont(const QFont& font)
00445 {
00446  d->mSystemNameFont = font; 
00447  d->mBox->triggerUpdate(false);
00448 }
00449 
00450 void KChatBase::setSystemMessageFont(const QFont& font)
00451 {
00452  d->mSystemMessageFont = font; 
00453  d->mBox->triggerUpdate(false);
00454 }
00455 
00456 void KChatBase::setSystemBothFont(const QFont& font)
00457 {
00458  setSystemNameFont(font);
00459  setSystemMessageFont(font);
00460 }
00461 
00462 const QFont& KChatBase::systemNameFont() const
00463 { return d->mSystemNameFont; }
00464 
00465 const QFont& KChatBase::systemMessageFont() const
00466 { return d->mSystemMessageFont; }
00467 
00468 void KChatBase::saveConfig(KConfig* conf)
00469 {
00470  QString oldGroup;
00471  if (!conf) {
00472     conf = kapp->config();
00473     oldGroup = conf->group();
00474     conf->setGroup("KChatBase");
00475  }
00476 
00477  conf->writeEntry("NameFont", nameFont());
00478  conf->writeEntry("MessageFont", messageFont());
00479  conf->writeEntry("SystemNameFont", systemNameFont());
00480  conf->writeEntry("SystemMessageFont", systemMessageFont());
00481  conf->writeEntry("MaxMessages", maxItems());
00482 
00483  if (!oldGroup.isNull()) {
00484     conf->setGroup(oldGroup);
00485  }
00486 }
00487 
00488 void KChatBase::readConfig(KConfig* conf)
00489 {
00490  QString oldGroup;
00491  if (!conf) {
00492     conf = kapp->config();
00493     oldGroup = conf->group();
00494     conf->setGroup("KChatBase");
00495  }
00496 
00497  setNameFont(conf->readFontEntry("NameFont"));
00498  setMessageFont(conf->readFontEntry("MessageFont"));
00499  setSystemNameFont(conf->readFontEntry("SystemNameFont"));
00500  setSystemMessageFont(conf->readFontEntry("SystemMessageFont"));
00501  setMaxItems(conf->readNumEntry("MaxMessages", -1));
00502 
00503  if (!oldGroup.isNull()) {
00504     conf->setGroup(oldGroup);
00505  }
00506 }
00507 
00508 void KChatBase::clear()
00509 {
00510  d->mBox->clear();
00511 }
00512 
00513 void KChatBase::setMaxItems(int maxItems)
00514 {
00515  d->mMaxItems = maxItems;
00516  //TODO cut too many messages
00517  if (maxItems == 0) {
00518     clear();
00519  } else if (maxItems > 0) {
00520     while (d->mBox->count() > (unsigned int)maxItems) {
00521         d->mBox->removeItem(0);
00522     }
00523  }
00524 }
00525 
00526 int KChatBase::maxItems() const
00527 { return d->mMaxItems; }
00528 
00529 
00530 #include "kchatbase.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys