You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegames/libtdegames/kchatbase.cpp

531 lines
13 KiB

/*
This file is part of the KDE games library
Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kchatbase.h"
#include <klineedit.h>
#include <klocale.h>
#include <kstandarddirs.h>
#include <kconfig.h>
#include <kapplication.h>
#include <kdebug.h>
#include <layout.h>
#include <tqcombobox.h>
#include <tqpainter.h>
class KChatBaseTextPrivate
{
public:
KChatBaseTextPrivate()
{
mNameFont = 0;
mMessageFont = 0;
}
TQString mName;
TQString mMessage;
const TQFont* mNameFont;
const TQFont* mMessageFont;
};
KChatBaseText::KChatBaseText(const TQString& name, const TQString& message) : TQListBoxText()
{
init();
setName(name);
setMessage(message);
}
KChatBaseText::KChatBaseText(const TQString& message) : TQListBoxText()
{
init();
setMessage(message);
}
KChatBaseText::~KChatBaseText()
{
delete d;
}
void KChatBaseText::init()
{
d = new KChatBaseTextPrivate;
}
void KChatBaseText::setName(const TQString& n)
{
// d->mName = n;
d->mName = TQString("%1: ").arg(n);
setText(TQString("%1: %2").arg(name()).arg(message())); // esp. for sorting
}
void KChatBaseText::setMessage(const TQString& m)
{
d->mMessage = m;
setText(TQString("%1: %2").arg(name()).arg(message())); // esp. for sorting
}
const TQString& KChatBaseText::name() const
{ return d->mName; }
const TQString& KChatBaseText::message() const
{ return d->mMessage; }
TQFont KChatBaseText::nameFont() const
{
if (d->mNameFont) {
return *d->mNameFont;
} else if (listBox()) {
return listBox()->font();
} else {
return TQFont();
}
}
TQFont KChatBaseText::messageFont() const
{
if (d->mMessageFont) {
return *d->mMessageFont;
} else if (listBox()) {
return listBox()->font();
} else {
return TQFont();
}
}
void KChatBaseText::setNameFont(const TQFont* f)
{ d->mNameFont = f; }
void KChatBaseText::setMessageFont(const TQFont* f)
{ d->mMessageFont = f; }
void KChatBaseText::paint(TQPainter* painter)
{
TQFontMetrics fm = painter->fontMetrics();
painter->setFont(nameFont());
painter->drawText(3, fm.ascent() + fm.leading()/2, name());
painter->setFont(messageFont());
painter->drawText(3 + TQFontMetrics(nameFont()).width(name()), fm.ascent() + fm.leading()/2, message());
}
int KChatBaseText::width(TQListBox* lb) const
{
int w = 0;
if (lb) {
w += 6;
w += TQFontMetrics(nameFont()).width(name());
w += TQFontMetrics(messageFont()).width(message());
}
// int w = lb ? lb->fontMetrics().width( text() ) + 6 : 0; // QT orig
return TQMAX(w, TQApplication::globalStrut().width());
}
int KChatBaseText::height(TQListBox* lb) const
{
int h = 0;
if (lb) {
h += 2;
// AB: is lineSpacing still correct?
if (TQFontMetrics(nameFont()).lineSpacing() > TQFontMetrics(messageFont()).lineSpacing()) {
h += TQFontMetrics(nameFont()).lineSpacing();
} else {
h += TQFontMetrics(messageFont()).lineSpacing();
}
}
// int h = lb ? lb->fontMetrics().lineSpacing() + 2 : 0; // QT orig
return TQMAX(h, TQApplication::globalStrut().height());
}
class KChatBasePrivate
{
public:
KChatBasePrivate()
{
mBox = 0;
mEdit = 0;
mCombo = 0;
mAcceptMessage = true;
mMaxItems = -1;
}
TQListBox* mBox;
KLineEdit* mEdit;
TQComboBox* mCombo;
bool mAcceptMessage;
int mMaxItems;
TQValueList<int> mIndex2Id;
TQFont mNameFont;
TQFont mMessageFont;
TQFont mSystemNameFont;
TQFont mSystemMessageFont;
};
KChatBase::KChatBase(TQWidget* parent, bool noComboBox) : TQFrame(parent)
{
init(noComboBox);
}
KChatBase::~KChatBase()
{
// kdDebug(11000) << "KChatBase: DESTRUCT (" << this << ")" << endl;
saveConfig();
delete d;
}
void KChatBase::init(bool noComboBox)
{
// kdDebug(11000) << "KChatBase: INIT (" << this << ")" << endl;
d = new KChatBasePrivate;
setMinimumWidth(100);
setMinimumHeight(150);
TQVBoxLayout* l = new TQVBoxLayout(this);
d->mBox = new TQListBox(this);
connect(d->mBox, TQT_SIGNAL(rightButtonClicked(TQListBoxItem*, const TQPoint&)),
this, TQT_SIGNAL(rightButtonClicked(TQListBoxItem*, const TQPoint&)));
l->addWidget(d->mBox);
d->mBox->setVScrollBarMode(TQScrollView::AlwaysOn);
d->mBox->setHScrollBarMode(TQScrollView::AlwaysOff);
d->mBox->setFocusPolicy(TQ_NoFocus);
// d->mBox->setSelectionMode(TQListBox::NoSelection);
d->mBox->setSelectionMode(TQListBox::Single);
l->addSpacing(5);
TQHBoxLayout* h = new TQHBoxLayout(l);
d->mEdit = new KLineEdit(this);
d->mEdit->setHandleSignals(false);
d->mEdit->setTrapReturnKey(true);
d->mEdit->completionObject(); // add the completion object
d->mEdit->setCompletionMode(KGlobalSettings::CompletionNone);
connect(d->mEdit, TQT_SIGNAL(returnPressed(const TQString&)), this, TQT_SLOT(slotReturnPressed(const TQString&)));
h->addWidget(d->mEdit);
if (!noComboBox) {
d->mCombo = new TQComboBox(this);
h->addWidget(d->mCombo);
addSendingEntry(i18n("Send to All Players"), SendToAll);//FIXME: where to put the id?
}
d->mAcceptMessage = true; // by default
setMaxItems(-1); // unlimited
if (kapp) {
// kapp might be NULL as well - in case we are in TQt designer.
readConfig();
}
}
bool KChatBase::acceptMessage() const
{ return d->mAcceptMessage; }
void KChatBase::setAcceptMessage(bool a)
{ d->mAcceptMessage = a; }
bool KChatBase::addSendingEntry(const TQString& text, int id)
{
//FIXME: is ID used correctly?
// do we need ID at all?
// what the hell should be here?
// d->mCombo->insertItem(i18n("Send to All Players"), SendToAll);
return insertSendingEntry(text, id);
}
bool KChatBase::insertSendingEntry(const TQString& text, int id, int index)
{
if (!d->mCombo) {
kdWarning(11000) << "KChatBase: Cannot add an entry to the combo box" << endl;
return false;
}
if (d->mIndex2Id.findIndex(id) != -1) {
kdError(11000) << "KChatBase: Cannot add more than one entry with the same ID! " << endl;
kdError(11000) << "KChatBase: Text="<<text<<endl;
return false;
}
d->mCombo->insertItem(text, index);
if (index < 0) {
d->mIndex2Id.append(id);
} else {
d->mIndex2Id.insert(d->mIndex2Id.at(index), id);
}
if (d->mIndex2Id.count() != (uint)d->mCombo->count()) {
kdError(11000) << "KChatBase: internal ERROR - local IDs do not match combo box entries!" << endl;
}
return true;
}
int KChatBase::sendingEntry() const
{
if (!d->mCombo) {
kdWarning(11001) << "Cannot retrieve index from NULL combo box" << endl;
return -1;
}
int index = d->mCombo->currentItem();
if (d->mIndex2Id.at(index) == d->mIndex2Id.end()) {
kdWarning(11000) << "could not find the selected sending entry!" << endl;
return -1;
}
return d->mIndex2Id[index];
}
void KChatBase::removeSendingEntry(int id)
{
if (!d->mCombo) {
kdWarning(11000) << "KChatBase: Cannot remove an entry from the combo box" << endl;
return;
}
d->mCombo->removeItem(findIndex(id));
d->mIndex2Id.remove(id);
}
void KChatBase::changeSendingEntry(const TQString& text, int id)
{
if (!d->mCombo) {
kdWarning(11000) << "KChatBase: Cannot change an entry in the combo box" << endl;
return;
}
int index = findIndex(id);
d->mCombo->changeItem(text, index);
}
void KChatBase::setSendingEntry(int id)
{
if (!d->mCombo) {
kdWarning(11000) << "KChatBase: Cannot set an entry in the combo box" << endl;
return;
}
d->mCombo->setCurrentItem(findIndex(id));
}
int KChatBase::findIndex(int id) const
{
return d->mIndex2Id.findIndex(id);
}
int KChatBase::nextId() const
{
int i = SendToAll + 1;
while (d->mIndex2Id.findIndex(i) != -1) {
i++;
}
return i;
}
void KChatBase::addItem(const TQListBoxItem* text)
{
d->mBox->insertItem(text);
int index = d->mBox->count() -1;
d->mBox->setBottomItem(index);//FIXME: don't scroll to bottom if user scrolled down manually
if (maxItems() >= 0 && d->mBox->count() > (unsigned int)maxItems()) {
d->mBox->removeItem(0);
}
}
void KChatBase::addMessage(const TQString& fromName, const TQString& text)
{
//maybe "%1 says: %2" or so
addItem(layoutMessage(fromName, text));
}
void KChatBase::addSystemMessage(const TQString& fromName, const TQString& text)
{
addItem(layoutSystemMessage(fromName, text));
}
TQListBoxItem* KChatBase::layoutMessage(const TQString& fromName, const TQString& text)
{
//TODO: KChatBaseConfigure? - e.g. color
TQListBoxItem* message;
if (text.startsWith("/me ")) {
// replace "/me" by a nice star. leave one space after the star
TQPixmap pix;
pix.load(locate("data", TQString::fromLatin1("tdegames/pics/star.png")));
//TODO KChatBasePixmap? Should change the font here!
message = (TQListBoxItem*)new TQListBoxPixmap(pix, i18n("%1 %2").arg(fromName).arg(text.mid(3)));
} else {
// the text is not edited in any way. just return an item
KChatBaseText* m = new KChatBaseText(fromName, text);
m->setNameFont(&d->mNameFont);
m->setMessageFont(&d->mMessageFont);
message = (TQListBoxItem*)m;
}
return message;
}
TQListBoxItem* KChatBase::layoutSystemMessage(const TQString& fromName, const TQString& text)
{
//TODO: KChatBaseConfigure? - e.g. color
// no need to check for /me etc.
KChatBaseText* m = new KChatBaseText(i18n("--- %1").arg(fromName), text);
m->setNameFont(&d->mSystemNameFont);
m->setMessageFont(&d->mSystemMessageFont);
return (TQListBoxItem*)m;
}
void KChatBase::slotReturnPressed(const TQString& text)
{
if (text.length() <= 0) {
// no text entered - probably hit return by accident
return;
} else if (!acceptMessage()) {
return;
}
d->mEdit->completionObject()->addItem(text);
// connect(d->mEdit, TQT_SIGNAL(returnPressed(const TQString&)), comp, TQT_SLOT(addItem(const TQString&)));
d->mEdit->clear();
returnPressed(text);
}
TQString KChatBase::comboBoxItem(const TQString& name) const
{ // TODO: such a function for "send to all" and "send to my group"
return i18n("Send to %1").arg(name);
}
void KChatBase::slotClear()
{
d->mBox->clear();
}
void KChatBase::setCompletionMode(KGlobalSettings::Completion mode)
{ d->mEdit->setCompletionMode(mode); }
void KChatBase::setNameFont(const TQFont& font)
{
d->mNameFont = font;
d->mBox->triggerUpdate(false);
}
void KChatBase::setMessageFont(const TQFont& font)
{
d->mMessageFont = font;
d->mBox->triggerUpdate(false);
}
void KChatBase::setBothFont(const TQFont& font)
{
setNameFont(font);
setMessageFont(font);
}
const TQFont& KChatBase::nameFont() const
{ return d->mNameFont; }
const TQFont& KChatBase::messageFont() const
{ return d->mMessageFont; }
void KChatBase::setSystemNameFont(const TQFont& font)
{
d->mSystemNameFont = font;
d->mBox->triggerUpdate(false);
}
void KChatBase::setSystemMessageFont(const TQFont& font)
{
d->mSystemMessageFont = font;
d->mBox->triggerUpdate(false);
}
void KChatBase::setSystemBothFont(const TQFont& font)
{
setSystemNameFont(font);
setSystemMessageFont(font);
}
const TQFont& KChatBase::systemNameFont() const
{ return d->mSystemNameFont; }
const TQFont& KChatBase::systemMessageFont() const
{ return d->mSystemMessageFont; }
void KChatBase::saveConfig(KConfig* conf)
{
TQString oldGroup;
if (!conf) {
conf = kapp->config();
oldGroup = conf->group();
conf->setGroup("KChatBase");
}
conf->writeEntry("NameFont", nameFont());
conf->writeEntry("MessageFont", messageFont());
conf->writeEntry("SystemNameFont", systemNameFont());
conf->writeEntry("SystemMessageFont", systemMessageFont());
conf->writeEntry("MaxMessages", maxItems());
if (!oldGroup.isNull()) {
conf->setGroup(oldGroup);
}
}
void KChatBase::readConfig(KConfig* conf)
{
TQString oldGroup;
if (!conf) {
conf = kapp->config();
oldGroup = conf->group();
conf->setGroup("KChatBase");
}
setNameFont(conf->readFontEntry("NameFont"));
setMessageFont(conf->readFontEntry("MessageFont"));
setSystemNameFont(conf->readFontEntry("SystemNameFont"));
setSystemMessageFont(conf->readFontEntry("SystemMessageFont"));
setMaxItems(conf->readNumEntry("MaxMessages", -1));
if (!oldGroup.isNull()) {
conf->setGroup(oldGroup);
}
}
void KChatBase::clear()
{
d->mBox->clear();
}
void KChatBase::setMaxItems(int maxItems)
{
d->mMaxItems = maxItems;
//TODO cut too many messages
if (maxItems == 0) {
clear();
} else if (maxItems > 0) {
while (d->mBox->count() > (unsigned int)maxItems) {
d->mBox->removeItem(0);
}
}
}
int KChatBase::maxItems() const
{ return d->mMaxItems; }
#include "kchatbase.moc"