From: Manuel Nickschas Date: Fri, 9 May 2008 15:48:46 +0000 (+0000) Subject: Moving branches/0.3 to trunk X-Git-Tag: 0.3.0~425 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=cc7f376eb105f7bf931fb7f96c9601a7b3f69511;hp=de1743fd47b4509eb6662ff08be339dc98ae5d29 Moving branches/0.3 to trunk --- diff --git a/build/buildconf.pri b/build/buildconf.pri index b85f1538..a5aa5558 100644 --- a/build/buildconf.pri +++ b/build/buildconf.pri @@ -23,3 +23,7 @@ mac:Tiger { QMAKE_MAC_SDK=/Developer/SDKs/MacOSX10.4u.sdk CONFIG += x86 ppc } + +sputdev { + DEFINES *= SPUTDEV +} diff --git a/src/client/client.cpp b/src/client/client.cpp index 536f2f79..6a7faa9c 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -21,21 +21,24 @@ #include "client.h" #include "bufferinfo.h" +#include "buffermodel.h" +#include "buffersettings.h" #include "buffersyncer.h" -#include "clientbacklogmanager.h" #include "bufferviewmanager.h" +#include "clientbacklogmanager.h" #include "global.h" #include "identity.h" #include "ircchannel.h" #include "ircuser.h" #include "message.h" +#ifdef SPUTDEV +# include "messagemodel.h" +#endif #include "network.h" #include "networkmodel.h" -#include "buffermodel.h" #include "quasselui.h" #include "signalproxy.h" #include "util.h" -#include "buffersettings.h" QPointer Client::instanceptr = 0; AccountId Client::_currentCoreAccount = 0; @@ -68,6 +71,7 @@ Client::Client(QObject *parent) _bufferSyncer(0), _backlogManager(new ClientBacklogManager(this)), _bufferViewManager(0), + _messageModel(0), _connectedToCore(false), _syncedToCore(false) { @@ -90,7 +94,9 @@ void Client::init() { _networkModel, SLOT(networkRemoved(NetworkId))); _bufferModel = new BufferModel(_networkModel); - +#ifdef SPUTDEV + _messageModel = mainUi->createMessageModel(this); +#endif SignalProxy *p = signalProxy(); p->attachSlot(SIGNAL(displayMsg(const Message &)), this, SLOT(recvMessage(const Message &))); @@ -429,6 +435,7 @@ void Client::networkDestroyed() { } } +#ifndef SPUTDEV void Client::recvMessage(const Message &message) { Message msg = message; Buffer *b; @@ -437,6 +444,8 @@ void Client::recvMessage(const Message &message) { // FIXME clean up code! (dup) + // TODO: make redirected messages show up in the correct buffer! + if(msg.flags() & Message::Redirected) { BufferSettings bufferSettings; bool inStatus = bufferSettings.value("UserMessagesInStatusBuffer", QVariant(true)).toBool(); @@ -480,7 +489,6 @@ void Client::recvMessage(const Message &message) { b = buffer(msg.bufferInfo()); b->appendMsg(msg); } - //bufferModel()->updateBufferActivity(msg); if(msg.type() == Message::Plain || msg.type() == Message::Notice || msg.type() == Message::Action) { @@ -489,17 +497,34 @@ void Client::recvMessage(const Message &message) { ? net->networkName() + ":" : QString(); QString sender = networkName + msg.bufferInfo().bufferName() + ":" + msg.sender(); - Message mmsg = Message(msg.timestamp(), msg.bufferInfo(), msg.type(), msg.text(), sender, msg.flags()); + Message mmsg = Message(msg.timestamp(), msg.bufferInfo(), msg.type(), msg.contents(), sender, msg.flags()); monitorBuffer()->appendMsg(mmsg); } - emit messageReceived(msg); } +#else + +void Client::recvMessage(const Message &msg) { + //checkForHighlight(msg); + _messageModel->insertMessage(msg); +} + +#endif /* SPUTDEV */ void Client::recvStatusMsg(QString /*net*/, QString /*msg*/) { //recvMessage(net, Message::server("", QString("[STATUS] %1").arg(msg))); } +#ifdef SPUTDEV +void Client::receiveBacklog(BufferId bufferId, const QVariantList &msgs) { + //checkForHighlight(msg); + foreach(QVariant v, msgs) { + _messageModel->insertMessage(v.value()); + } +} + +#else + void Client::receiveBacklog(BufferId bufferId, const QVariantList &msgs) { Buffer *buffer_ = buffer(bufferId); if(!buffer_) { @@ -527,6 +552,7 @@ void Client::receiveBacklog(BufferId bufferId, const QVariantList &msgs) { layoutTimer->start(); } } +#endif /* SPUTDEV */ void Client::layoutMsg() { if(layoutQueue.isEmpty()) { @@ -562,7 +588,7 @@ void Client::checkForHighlight(Message &msg) { QRegExp nickRegExp("^(.*\\W)?" + QRegExp::escape(nickname) + "(\\W.*)?$"); if((msg.type() & (Message::Plain | Message::Notice | Message::Action)) && !(msg.flags() & Message::Self) - && nickRegExp.exactMatch(msg.text())) { + && nickRegExp.exactMatch(msg.contents())) { msg.setFlags(msg.flags() | Message::Highlight); return; } @@ -582,7 +608,7 @@ void Client::checkForHighlight(Message &msg) { } if((msg.type() & (Message::Plain | Message::Notice | Message::Action)) && !(msg.flags() & Message::Self) - && userRegExp.exactMatch(msg.text())) { + && userRegExp.exactMatch(msg.contents())) { msg.setFlags(msg.flags() | Message::Highlight); return; } diff --git a/src/client/client.h b/src/client/client.h index bd31c322..4e7eb0e2 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -30,11 +30,11 @@ class BufferInfo; class Message; +class MessageModel; class Identity; class Network; - class AbstractUi; class AbstractUiMsg; class NetworkModel; @@ -49,7 +49,6 @@ struct NetworkInfo; class QTimer; - class Client : public QObject { Q_OBJECT @@ -94,6 +93,7 @@ public: static inline NetworkModel *networkModel() { return instance()->_networkModel; } static inline BufferModel *bufferModel() { return instance()->_bufferModel; } + static inline MessageModel *messageModel() { return instance()->_messageModel; } static inline SignalProxy *signalProxy() { return instance()->_signalProxy; } static inline ClientBacklogManager *backlogManager() { return instance()->_backlogManager; } @@ -216,6 +216,8 @@ private: ClientBacklogManager *_backlogManager; BufferViewManager *_bufferViewManager; + MessageModel *_messageModel; + ClientMode clientMode; bool _connectedToCore, _syncedToCore; diff --git a/src/client/client.pri b/src/client/client.pri index d16cec37..0945919b 100644 --- a/src/client/client.pri +++ b/src/client/client.pri @@ -1,7 +1,13 @@ DEPMOD = common QT_MOD = core network gui -SRCS += buffer.cpp buffersettings.cpp clientbacklogmanager.cpp treemodel.cpp networkmodel.cpp buffermodel.cpp client.cpp clientsettings.cpp clientsyncer.cpp \ - mappedselectionmodel.cpp selectionmodelsynchronizer.cpp -HDRS += buffer.h buffersettings.h clientbacklogmanager.h treemodel.h networkmodel.h buffermodel.h client.h clientsettings.h clientsyncer.h quasselui.h \ - mappedselectionmodel.h selectionmodelsynchronizer.h +SRCS += buffer.cpp buffersettings.cpp clientbacklogmanager.cpp treemodel.cpp networkmodel.cpp buffermodel.cpp \ + client.cpp clientsettings.cpp clientsyncer.cpp mappedselectionmodel.cpp selectionmodelsynchronizer.cpp +HDRS += buffer.h buffersettings.h clientbacklogmanager.h treemodel.h networkmodel.h buffermodel.h \ + client.h clientsettings.h clientsyncer.h quasselui.h mappedselectionmodel.h selectionmodelsynchronizer.h + +sputdev { + SRCS += messagemodel.cpp + HDRS += messagemodel.h +} + diff --git a/src/client/messagemodel.cpp b/src/client/messagemodel.cpp new file mode 100644 index 00000000..17e90495 --- /dev/null +++ b/src/client/messagemodel.cpp @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel IRC Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "messagemodel.h" + +#include "message.h" + +MessageModel::MessageModel(QObject *parent) : QAbstractItemModel(parent) { + + + +} + +MessageModel::~MessageModel() { + + +} + +QVariant MessageModel::data(const QModelIndex &index, int role) const { + int row = index.row(); + if(row < 0 || row >= _messageList.count()) return QVariant(); + return _messageList[row]->data(index.column(), role); +} + +bool MessageModel::setData(const QModelIndex &index, const QVariant &value, int role) { + int row = index.row(); + if(row < 0 || row >= _messageList.count()) return false; + if(_messageList[row]->setData(index.column(), value, role)) { + emit dataChanged(index, index); + return true; + } + return false; +} + +void MessageModel::insertMessage(const Message &msg) { + MsgId id = msg.msgId(); + int idx = indexForId(id); + MessageModelItem *item = createMessageModelItem(msg); + beginInsertRows(QModelIndex(), idx, idx); + _messageList.insert(idx, item); + endInsertRows(); +} + +void MessageModel::insertMessages(const QList &msglist) { + if(msglist.isEmpty()) return; + // FIXME make this more efficient by grouping msgs + foreach(Message msg, msglist) insertMessage(msg); + +} + +// returns index of msg with given Id or of the next message after that (i.e., the index where we'd insert this msg) +int MessageModel::indexForId(MsgId id) { + if(_messageList.isEmpty() || id <= _messageList[0]->data(0, MsgIdRole).value()) return 0; + if(id > _messageList.last()->data(0, MsgIdRole).value()) return _messageList.count(); + // binary search + int start = 0; int end = _messageList.count()-1; + while(1) { + if(end - start == 1) return end; + int pivot = (end + start) / 2; + if(id <= _messageList[pivot]->data(0, MsgIdRole).value()) end = pivot; + else start = pivot; + } +} + +/**********************************************************************************/ + +MessageModelItem::MessageModelItem(const Message &msg) { + _timestamp = msg.timestamp(); + _msgId = msg.msgId(); + _bufferId = msg.bufferInfo().bufferId(); + _type = msg.type(); + _flags = msg.flags(); + +} + +MessageModelItem::~MessageModelItem() { + +} + +QVariant MessageModelItem::data(int column, int role) const { + if(column < MessageModel::TimestampColumn || column > MessageModel::TextColumn) return QVariant(); + switch(role) { + case MessageModel::MsgIdRole: return QVariant::fromValue(_msgId); + case MessageModel::BufferIdRole: return QVariant::fromValue(_bufferId); + case MessageModel::TypeRole: return _type; + case MessageModel::FlagsRole: return (int)_flags; + case MessageModel::TimestampRole: return _timestamp; + default: return QVariant(); + } +} + diff --git a/src/client/messagemodel.h b/src/client/messagemodel.h new file mode 100644 index 00000000..d37100cd --- /dev/null +++ b/src/client/messagemodel.h @@ -0,0 +1,101 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel IRC Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef MESSAGEMODEL_H_ +#define MESSAGEMODEL_H_ + +#include +#include + +#include "message.h" +#include "types.h" + +class MessageModelItem; +class MsgId; + +class MessageModel : public QAbstractItemModel { + Q_OBJECT + + public: + enum MessageRole { + MsgIdRole = Qt::UserRole, + BufferIdRole, + TypeRole, + FlagsRole, + TimestampRole, + DisplayRole, + FormatRole, + UserRole + }; + + enum ColumnType { + TimestampColumn, SenderColumn, TextColumn, UserColumnType + }; + + MessageModel(QObject *parent); + virtual ~MessageModel(); + + inline QModelIndex index(int row, int column, const QModelIndex &/*parent*/ = QModelIndex()) const { return createIndex(row, column); } + inline QModelIndex parent(const QModelIndex &) const { return QModelIndex(); } + inline int rowCount(const QModelIndex &/*parent*/ = QModelIndex()) const { return _messageList.count(); } + inline int columnCount(const QModelIndex &/*parent*/ = QModelIndex()) const { return 3; } + + virtual QVariant data(const QModelIndex &index, int role) const; + virtual bool setData(const QModelIndex &index, const QVariant &value, int role); + + //virtual Qt::ItemFlags flags(const QModelIndex &index) const; + + void insertMessage(const Message &); + void insertMessages(const QList &); + + protected: + virtual MessageModelItem *createMessageModelItem(const Message &) = 0; + + private: + QList _messageList; + + int indexForId(MsgId); + +}; + +class MessageModelItem { + + public: + + //! Creates a MessageModelItem from a Message object. + /** This baseclass implementation takes care of all Message data *except* the stylable strings. + * Subclasses need to provide Qt::DisplayRole at least, which should describe the plaintext + * strings without formattings (e.g. for searching purposes). + */ + MessageModelItem(const Message &); + virtual ~MessageModelItem(); + + virtual QVariant data(int column, int role) const; + virtual bool setData(int column, const QVariant &value, int role) = 0; + + private: + QDateTime _timestamp; + MsgId _msgId; + BufferId _bufferId; + Message::Type _type; + Message::Flags _flags; +}; + +#endif diff --git a/src/client/quasselui.h b/src/client/quasselui.h index 747d8b81..bcb512be 100644 --- a/src/client/quasselui.h +++ b/src/client/quasselui.h @@ -24,6 +24,8 @@ #include #include "message.h" +class MessageModel; + class AbstractUiMsg { public: @@ -42,6 +44,7 @@ class AbstractUi : public QObject { public: virtual void init() {}; // called after the client is initialized + virtual MessageModel *createMessageModel(QObject *parent = 0) = 0; virtual AbstractUiMsg *layoutMsg(const Message &) = 0; protected slots: diff --git a/src/common/global.cpp b/src/common/global.cpp index 9f0e224d..59afde13 100644 --- a/src/common/global.cpp +++ b/src/common/global.cpp @@ -96,7 +96,6 @@ void Global::registerMetaTypes() { qRegisterMetaTypeStreamOperators("UserId"); qRegisterMetaTypeStreamOperators("AccountId"); qRegisterMetaTypeStreamOperators("MsgId"); - } // Static variables diff --git a/src/common/main.cpp b/src/common/main.cpp index 5fb3029a..3c36a280 100644 --- a/src/common/main.cpp +++ b/src/common/main.cpp @@ -103,7 +103,7 @@ int main(int argc, char **argv) { // Check if a non-standard core port is requested QStringList args = QCoreApplication::arguments(); // TODO Build a CLI parser - Global::DEBUG = args.contains("--debug"); // This enables (maybe) various debug features. + Global::DEBUG = args.contains("--debug"); // This enables various debug features. Global::defaultPort = 4242; int idx; diff --git a/src/common/message.cpp b/src/common/message.cpp index 8c0ebb31..2ce40f81 100644 --- a/src/common/message.cpp +++ b/src/common/message.cpp @@ -24,30 +24,31 @@ #include -Message::Message(BufferInfo bufferInfo, Type type, QString text, QString sender, quint8 flags) +Message::Message(const BufferInfo &bufferInfo, Type type, const QString &contents, const QString &sender, Flags flags) : _timestamp(QDateTime::currentDateTime().toUTC()), _bufferInfo(bufferInfo), - _text(text), + _contents(contents), _sender(sender), _type(type), _flags(flags) { } -Message::Message(QDateTime ts,BufferInfo bufferInfo, Type type, QString text, QString sender, quint8 flags) +Message::Message(const QDateTime &ts, const BufferInfo &bufferInfo, Type type, const QString &contents, const QString &sender, Flags flags) : _timestamp(ts), _bufferInfo(bufferInfo), - _text(text), + _contents(contents), _sender(sender), _type(type), _flags(flags) { } -void Message::setFlags(quint8 flags) { +void Message::setFlags(Flags flags) { _flags = flags; } +#ifndef SPUTDEV QString Message::mircToInternal(QString mirc) { mirc.replace('%', "%%"); // escape % just to be sure mirc.replace('\x02', "%B"); @@ -98,7 +99,7 @@ void Message::format() { QString user = userFromMask(sender()); QString host = hostFromMask(sender()); QString nick = nickFromMask(sender()); - QString txt = mircToInternal(text()); + QString txt = mircToInternal(contents()); QString bufferName = bufferInfo().bufferName(); _formattedTimestamp = tr("%DT[%1]").arg(timestamp().toLocalTime().toString("hh:mm:ss")); @@ -134,12 +135,12 @@ void Message::format() { break; case Message::Nick: s = tr("%Dr<->"); - if(nick == text()) t = tr("%DrYou are now known as %DN%1%DN").arg(txt); + if(nick == contents()) t = tr("%DrYou are now known as %DN%1%DN").arg(txt); else t = tr("%Dr%DN%1%DN is now known as %DN%2%DN").arg(nick, txt); break; case Message::Mode: s = tr("%Dm***"); - if(nick.isEmpty()) t = tr("%DmUser mode: %DM%1%DM").arg(text()); + if(nick.isEmpty()) t = tr("%DmUser mode: %DM%1%DM").arg(contents()); else t = tr("%DmMode %DM%1%DM by %DN%2%DN").arg(txt, nick); break; case Message::Action: @@ -168,18 +169,11 @@ QString Message::formattedText() { format(); return _formattedText; } - -/* -QString Message::formattedToHtml(const QString &f) { - - - return f; -} -*/ +#endif /* SPUTDEV */ QDataStream &operator<<(QDataStream &out, const Message &msg) { out << msg.msgId() << (quint32)msg.timestamp().toTime_t() << (quint32)msg.type() << (quint8)msg.flags() - << msg.bufferInfo() << msg.sender().toUtf8() << msg.text().toUtf8(); + << msg.bufferInfo() << msg.sender().toUtf8() << msg.contents().toUtf8(); return out; } @@ -191,11 +185,11 @@ QDataStream &operator>>(QDataStream &in, Message &msg) { BufferInfo buf; in >> msg._msgId >> ts >> t >> f >> buf >> s >> m; msg._type = (Message::Type)t; - msg._flags = (quint8)f; + msg._flags = (Message::Flags)f; msg._bufferInfo = buf; msg._timestamp = QDateTime::fromTime_t(ts); msg._sender = QString::fromUtf8(s); - msg._text = QString::fromUtf8(m); + msg._contents = QString::fromUtf8(m); return in; } diff --git a/src/common/message.h b/src/common/message.h index 08c70c6f..797e28b7 100644 --- a/src/common/message.h +++ b/src/common/message.h @@ -48,31 +48,32 @@ public: Error = 0x1000 }; - enum Flags { + enum Flag { None = 0, Self = 1, Highlight = 2, Redirected = 4 }; - Q_DECLARE_FLAGS(MessageFlags, Flags) + Q_DECLARE_FLAGS(Flags, Flag) - Message(BufferInfo bufferInfo = BufferInfo(), Type type = Plain, QString text = "", QString sender = "", quint8 flags = None); - - Message(QDateTime ts, BufferInfo buffer = BufferInfo(), Type type = Plain, QString text = "", QString sender = "", quint8 flags = None); + Message(const BufferInfo &bufferInfo = BufferInfo(), Type type = Plain, const QString &contents = "", const QString &sender = "", Flags flags = None); + Message(const QDateTime &ts, const BufferInfo &buffer = BufferInfo(), Type type = Plain, + const QString &contents = "", const QString &sender = "", Flags flags = None); inline MsgId msgId() const { return _msgId; } inline void setMsgId(MsgId id) { _msgId = id; } inline BufferInfo bufferInfo() const { return _bufferInfo; } - inline QString text() const { return _text; } + inline QString contents() const { return _contents; } inline QString sender() const { return _sender; } inline Type type() const { return _type; } - inline quint8 flags() const { return _flags; } + inline Flags flags() const { return _flags; } inline QDateTime timestamp() const { return _timestamp; } - void setFlags(quint8 flags); + void setFlags(Flags flags); +#ifndef SPUTDEV QString formattedTimestamp(); QString formattedSender(); QString formattedText(); @@ -83,15 +84,16 @@ public: static QString mircToInternal(QString); void format(); +#endif private: QDateTime _timestamp; MsgId _msgId; BufferInfo _bufferInfo; - QString _text; + QString _contents; QString _sender; Type _type; - quint8 _flags; + Flags _flags; QString _formattedTimestamp, _formattedSender, _formattedText; // cache @@ -103,6 +105,6 @@ QDataStream &operator<<(QDataStream &out, const Message &msg); QDataStream &operator>>(QDataStream &in, Message &msg); Q_DECLARE_METATYPE(Message); -Q_DECLARE_OPERATORS_FOR_FLAGS(Message::MessageFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(Message::Flags) #endif diff --git a/src/common/types.h b/src/common/types.h index 381c5d6b..0154247e 100644 --- a/src/common/types.h +++ b/src/common/types.h @@ -37,6 +37,7 @@ class SignedId { inline bool operator==(const SignedId &other) const { return id == other.id; } inline bool operator!=(const SignedId &other) const { return id != other.id; } inline bool operator<(const SignedId &other) const { return id < other.id; } + inline bool operator<=(const SignedId &other) const { return id <= other.id; } inline bool operator>(const SignedId &other) const { return id > other.id; } inline bool operator>=(const SignedId &other) const { return id >= other.id; } inline bool operator==(int i) const { return id == i; } diff --git a/src/core/basichandler.cpp b/src/core/basichandler.cpp index 02483d25..a00966d2 100644 --- a/src/core/basichandler.cpp +++ b/src/core/basichandler.cpp @@ -30,8 +30,8 @@ BasicHandler::BasicHandler(NetworkConnection *parent) _networkConnection(parent), initDone(false) { - connect(this, SIGNAL(displayMsg(Message::Type, BufferInfo::Type, QString, QString, QString, quint8)), - networkConnection(), SIGNAL(displayMsg(Message::Type, BufferInfo::Type, QString, QString, QString, quint8))); + connect(this, SIGNAL(displayMsg(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags)), + networkConnection(), SIGNAL(displayMsg(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags))); connect(this, SIGNAL(putCmd(QString, const QVariantList &, const QByteArray &)), networkConnection(), SLOT(putCmd(QString, const QVariantList &, const QByteArray &))); @@ -189,7 +189,7 @@ void BasicHandler::putCmd(const QString &cmd, const QList ¶ms, c emit putCmd(cmd, list, prefix); } -void BasicHandler::displayMsg(Message::Type msgType, QString target, QString text, QString sender, quint8 flags) { +void BasicHandler::displayMsg(Message::Type msgType, QString target, QString text, QString sender, Message::Flags flags) { IrcChannel *channel = network()->ircChannel(target); if(!channel && (target.startsWith('$') || target.startsWith('#'))) target = nickFromMask(sender); diff --git a/src/core/basichandler.h b/src/core/basichandler.h index 757af6e8..f641a30b 100644 --- a/src/core/basichandler.h +++ b/src/core/basichandler.h @@ -55,12 +55,12 @@ public: QList userEncode(const QString &userNick, const QStringList &stringlist); signals: - void displayMsg(Message::Type, BufferInfo::Type, QString target, QString text, QString sender = "", quint8 flags = Message::None); + void displayMsg(Message::Type, BufferInfo::Type, QString target, QString text, QString sender = "", Message::Flags flags = Message::None); void putCmd(const QString &cmd, const QVariantList ¶ms, const QByteArray &prefix); void putRawLine(const QByteArray &msg); protected: - void displayMsg(Message::Type, QString target, QString text, QString sender = "", quint8 flags = Message::None); + void displayMsg(Message::Type, QString target, QString text, QString sender = "", Message::Flags flags = Message::None); void putCmd(const QString &cmd, const QByteArray ¶m, const QByteArray &prefix = QByteArray()); void putCmd(const QString &cmd, const QList ¶ms, const QByteArray &prefix = QByteArray()); diff --git a/src/core/coresession.cpp b/src/core/coresession.cpp index b5768542..68f31271 100644 --- a/src/core/coresession.cpp +++ b/src/core/coresession.cpp @@ -192,8 +192,8 @@ void CoreSession::attachNetworkConnection(NetworkConnection *conn) { //signalProxy()->attachSignal(conn, SIGNAL(connected(NetworkId)), SIGNAL(networkConnected(NetworkId))); //signalProxy()->attachSignal(conn, SIGNAL(disconnected(NetworkId)), SIGNAL(networkDisconnected(NetworkId))); - connect(conn, SIGNAL(displayMsg(Message::Type, BufferInfo::Type, QString, QString, QString, quint8)), - this, SLOT(recvMessageFromServer(Message::Type, BufferInfo::Type, QString, QString, QString, quint8))); + connect(conn, SIGNAL(displayMsg(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags)), + this, SLOT(recvMessageFromServer(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags))); connect(conn, SIGNAL(displayStatusMsg(QString)), this, SLOT(recvStatusMsgFromServer(QString))); connect(conn, SIGNAL(nickChanged(const NetworkId &, const QString &, const QString &)), @@ -282,10 +282,11 @@ void CoreSession::msgFromClient(BufferInfo bufinfo, QString msg) { // ALL messages coming pass through these functions before going to the GUI. // So this is the perfect place for storing the backlog and log stuff. -void CoreSession::recvMessageFromServer(Message::Type type, BufferInfo::Type bufferType, QString target, QString text, QString sender, quint8 flags) { +void CoreSession::recvMessageFromServer(Message::Type type, BufferInfo::Type bufferType, + QString target, QString text, QString sender, Message::Flags flags) { NetworkConnection *netCon = qobject_cast(this->sender()); Q_ASSERT(netCon); - + BufferInfo bufferInfo = Core::bufferInfo(user(), netCon->networkId(), bufferType, target); Message msg(bufferInfo, type, text, sender, flags); msg.setMsgId(Core::storeMessage(msg)); diff --git a/src/core/coresession.h b/src/core/coresession.h index 482fa76a..1403c744 100644 --- a/src/core/coresession.h +++ b/src/core/coresession.h @@ -153,7 +153,7 @@ private slots: void removeClient(QIODevice *dev); void recvStatusMsgFromServer(QString msg); - void recvMessageFromServer(Message::Type, BufferInfo::Type, QString target, QString text, QString sender = "", quint8 flags = Message::None); + void recvMessageFromServer(Message::Type, BufferInfo::Type, QString target, QString text, QString sender = "", Message::Flags flags = Message::None); void networkConnected(NetworkId networkid); void networkDisconnected(NetworkId networkid); diff --git a/src/core/ctcphandler.cpp b/src/core/ctcphandler.cpp index 95fe173c..ba489648 100644 --- a/src/core/ctcphandler.cpp +++ b/src/core/ctcphandler.cpp @@ -94,7 +94,7 @@ void CtcpHandler::parse(Message::Type messageType, const QString &prefix, const ? CtcpReply : CtcpQuery; - quint8 flags = (messageType == Message::Notice && !network()->isChannelName(target)) + Message::Flags flags = (messageType == Message::Notice && !network()->isChannelName(target)) ? Message::Redirected : Message::None; diff --git a/src/core/networkconnection.h b/src/core/networkconnection.h index 1002cd6f..9b4126d0 100644 --- a/src/core/networkconnection.h +++ b/src/core/networkconnection.h @@ -109,7 +109,7 @@ signals: void recvRawServerMsg(QString); void displayStatusMsg(QString); //void displayMsg(Message msg); - void displayMsg(Message::Type, BufferInfo::Type, QString target, QString text, QString sender = "", quint8 flags = Message::None); + void displayMsg(Message::Type, BufferInfo::Type, QString target, QString text, QString sender = "", Message::Flags flags = Message::None); void connected(NetworkId networkId); ///< Emitted after receipt of 001 to indicate that we can now send data to the IRC server void disconnected(NetworkId networkId); void connectionStateChanged(Network::ConnectionState); diff --git a/src/core/sqlitestorage.cpp b/src/core/sqlitestorage.cpp index 8cd4d5b0..5dab67e5 100644 --- a/src/core/sqlitestorage.cpp +++ b/src/core/sqlitestorage.cpp @@ -629,9 +629,9 @@ MsgId SqliteStorage::logMessage(Message msg) { logMessageQuery->bindValue(":time", msg.timestamp().toTime_t()); logMessageQuery->bindValue(":bufferid", msg.bufferInfo().bufferId().toInt()); logMessageQuery->bindValue(":type", msg.type()); - logMessageQuery->bindValue(":flags", msg.flags()); + logMessageQuery->bindValue(":flags", (int)msg.flags()); logMessageQuery->bindValue(":sender", msg.sender()); - logMessageQuery->bindValue(":message", msg.text()); + logMessageQuery->bindValue(":message", msg.contents()); logMessageQuery->exec(); if(logMessageQuery->lastError().isValid()) { @@ -688,7 +688,7 @@ QList SqliteStorage::requestMsgs(UserId user, BufferId bufferId, int la (Message::Type)msgQuery->value(2).toUInt(), msgQuery->value(5).toString(), msgQuery->value(4).toString(), - msgQuery->value(3).toUInt()); + (Message::Flags)msgQuery->value(3).toUInt()); msg.setMsgId(msgQuery->value(0).toInt()); messagelist << msg; } @@ -726,7 +726,7 @@ QList SqliteStorage::requestMsgs(UserId user, BufferId bufferId, QDateT (Message::Type)msgQuery->value(2).toUInt(), msgQuery->value(5).toString(), msgQuery->value(4).toString(), - msgQuery->value(3).toUInt()); + (Message::Flags)msgQuery->value(3).toUInt()); msg.setMsgId(msgQuery->value(0).toInt()); messagelist << msg; } @@ -756,7 +756,7 @@ QList SqliteStorage::requestMsgRange(UserId user, BufferId bufferId, in (Message::Type)rangeQuery->value(2).toUInt(), rangeQuery->value(5).toString(), rangeQuery->value(4).toString(), - rangeQuery->value(3).toUInt()); + (Message::Flags)rangeQuery->value(3).toUInt()); msg.setMsgId(rangeQuery->value(0).toInt()); messagelist << msg; } diff --git a/src/core/userinputhandler.cpp b/src/core/userinputhandler.cpp index 0ef5aba0..9c7e03ba 100644 --- a/src/core/userinputhandler.cpp +++ b/src/core/userinputhandler.cpp @@ -168,6 +168,7 @@ void UserInputHandler::handleKick(const BufferInfo &bufferInfo, const QString &m } void UserInputHandler::handleKill(const BufferInfo &bufferInfo, const QString &msg) { + Q_UNUSED(bufferInfo) QString nick = msg.section(' ', 0, 0, QString::SectionSkipEmpty); QString pass = msg.section(' ', 1, -1, QString::SectionSkipEmpty); QList params; @@ -222,6 +223,7 @@ void UserInputHandler::handleOp(const BufferInfo &bufferInfo, const QString &msg } void UserInputHandler::handleOper(const BufferInfo &bufferInfo, const QString &msg) { + Q_UNUSED(bufferInfo) emit putRawLine(serverEncode(QString("OPER %1").arg(msg))); } diff --git a/src/qtopia/chatline.cpp b/src/qtopia/chatline.cpp index a380314a..0a709c03 100644 --- a/src/qtopia/chatline.cpp +++ b/src/qtopia/chatline.cpp @@ -26,7 +26,7 @@ ChatLine::ChatLine(Message msg) { _styledSender = QtopiaUi::style()->styleString(msg.formattedSender()); - _styledText = QtopiaUi::style()->styleString(msg.formattedText()); + _styledContents = QtopiaUi::style()->styleString(msg.formattedText()); _timestamp = msg.timestamp(); _msgId = msg.msgId(); _bufferInfo = msg.bufferInfo(); @@ -58,8 +58,8 @@ UiStyle::StyledText ChatLine::styledSender() const { return _styledSender; } -UiStyle::StyledText ChatLine::styledText() const { - return _styledText; +UiStyle::StyledText ChatLine::styledContents() const { + return _styledContents; } diff --git a/src/qtopia/chatline.h b/src/qtopia/chatline.h index 0d3f5e8b..bdaf7d41 100644 --- a/src/qtopia/chatline.h +++ b/src/qtopia/chatline.h @@ -35,11 +35,11 @@ class ChatLine : public AbstractUiMsg { QDateTime timestamp() const; UiStyle::StyledText styledSender() const; - UiStyle::StyledText styledText() const; + UiStyle::StyledText styledContents() const; private: QString _sender, _text, _htmlSender, _htmlText, _htmlTimestamp; - UiStyle::StyledText _styledSender, _styledText; + UiStyle::StyledText _styledSender, _styledContents; MsgId _msgId; BufferInfo _bufferInfo; QDateTime _timestamp; diff --git a/src/qtopia/chatwidget.cpp b/src/qtopia/chatwidget.cpp index 9f8eabb5..b6950c64 100644 --- a/src/qtopia/chatwidget.cpp +++ b/src/qtopia/chatwidget.cpp @@ -53,7 +53,7 @@ void ChatWidget::appendChatLine(ChatLine *line) { if(!document()->isEmpty()) insertPlainText("\n"); insertStyledText(line->styledSender()); insertPlainText(" "); - insertStyledText(line->styledText()); + insertStyledText(line->styledContents()); setTextCursor(cursor); } @@ -69,7 +69,7 @@ void ChatWidget::prependChatLine(ChatLine *line) { bool flg = document()->isEmpty(); insertStyledText(line->styledSender()); insertPlainText(" "); - insertStyledText(line->styledText()); + insertStyledText(line->styledContents()); if(!flg) insertPlainText("\n"); setTextCursor(cursor); } @@ -84,14 +84,14 @@ void ChatWidget::insertChatLine(ChatLine *line) { if(!document()->isEmpty()) insertPlainText("\n"); insertStyledText(line->styledSender()); insertPlainText(" "); - insertStyledText(line->styledText()); + insertStyledText(line->styledContents()); } void ChatWidget::insertStyledText(const QtopiaUiStyle::StyledText &stext) { QTextCursor cursor = textCursor(); - foreach(QTextLayout::FormatRange format, stext.formats) { + foreach(QTextLayout::FormatRange format, stext.formatList) { cursor.setCharFormat(format.format); setTextCursor(cursor); - insertPlainText(stext.text.mid(format.start, format.length)); + insertPlainText(stext.plainText.mid(format.start, format.length)); } } diff --git a/src/qtopia/qtopiamainwin.cpp b/src/qtopia/qtopiamainwin.cpp index 69b054ac..b927e72f 100644 --- a/src/qtopia/qtopiamainwin.cpp +++ b/src/qtopia/qtopiamainwin.cpp @@ -47,6 +47,7 @@ QtopiaMainWin::QtopiaMainWin(QWidget *parent, Qt::WFlags flags) : QMainWindow(pa Global::runMode = Global::ClientOnly; Global::defaultPort = 4242; + Global::DEBUG = true; Network::setDefaultCodecForServer("ISO-8859-1"); Network::setDefaultCodecForEncoding("UTF-8"); diff --git a/src/qtui/bufferwidget.cpp b/src/qtui/bufferwidget.cpp index d534b3dc..bc10ca54 100644 --- a/src/qtui/bufferwidget.cpp +++ b/src/qtui/bufferwidget.cpp @@ -19,7 +19,7 @@ ***************************************************************************/ #include "bufferwidget.h" -#include "chatline-old.h" +#include "chatview.h" #include "chatwidget.h" #include "settings.h" #include "client.h" @@ -35,7 +35,12 @@ BufferWidget::~BufferWidget() { } AbstractChatView *BufferWidget::createChatView(BufferId id) { - QWidget *chatView = new ChatWidget(id, this); + QWidget *chatView; +#ifdef SPUTDEV + chatView = new ChatView(Client::buffer(id), this); +#else + chatView = new ChatWidget(id, this); +#endif _chatViews[id] = chatView; ui.stackedWidget->addWidget(chatView); chatView->setFocusProxy(this); diff --git a/src/qtui/chatitem.cpp b/src/qtui/chatitem.cpp new file mode 100644 index 00000000..a677e105 --- /dev/null +++ b/src/qtui/chatitem.cpp @@ -0,0 +1,142 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include +#include +#include +#include + +#include + +#include "chatitem.h" + +ChatItem::ChatItem(const QPersistentModelIndex &index_, QGraphicsItem *parent) : QGraphicsItem(parent), _index(index_) { + //if(_wrapMode == WordWrap) { + // setFlags(QGraphicsItem::ItemClipsToShape, true); + //} +} + +ChatItem::~ChatItem() { + +} + +QVariant ChatItem::data(int role) const { + if(!_index.isValid()) { + qWarning() << "ChatItem::data(): Model index is invalid!"; + return QVariant(); + } + return _index.data(role); +} + +QRectF ChatItem::boundingRect() const { + return QRectF(0, 0, 500,20); +} + +void ChatItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { + Q_UNUSED(option); Q_UNUSED(widget); + + painter->drawRect(boundingRect()); + painter->drawText(boundingRect(), data(MessageModel::DisplayRole).toString()); +} + + +/* +void ChatItem::setWidth(int w) { + _width = w; + layout(); +} + +void ChatItem::setTextOption(const QTextOption &option) { + _textOption = option; + layout(); +} + +QTextOption ChatItem::textOption() const { + return _textOption; +} + +QString ChatItem::text() const { + return _layout.text(); +} + +void ChatItem::setText(const UiStyle::StyledText &text) { + _layout.setText(text.text); + _layout.setAdditionalFormats(text.formatList); + layout(); +} + +void ChatItem::layout() { + if(!_layout.additionalFormats().count()) return; // no text set + if(_width <= 0) return; + prepareGeometryChange(); + QFontMetrics metrics(_layout.additionalFormats()[0].format.font()); + int leading = metrics.leading(); + int height = 0; + _layout.setTextOption(textOption()); + _layout.beginLayout(); + while(1) { + QTextLine line = _layout.createLine(); + if(!line.isValid()) break; + line.setLineWidth(_width); + if(textOption().wrapMode() != QTextOption::NoWrap && line.naturalTextWidth() > _width) { + // word did not fit, we need to wrap it in the middle + // this is a workaround for Qt failing to handle WrapAtWordBoundaryOrAnywhere correctly + QTextOption::WrapMode mode = textOption().wrapMode(); + textOption().setWrapMode(QTextOption::WrapAnywhere); + _layout.setTextOption(textOption()); + line.setLineWidth(_width); + textOption().setWrapMode(mode); + _layout.setTextOption(textOption()); + } + height += leading; + line.setPosition(QPoint(0, height)); + height += line.height(); + } + _layout.endLayout(); + update(); +} QDateTime _timestamp; + MsgId _msgId; + + +QRectF ChatItem::boundingRect() const { + return _layout.boundingRect(); +} + +void ChatItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { + Q_UNUSED(option); Q_UNUSED(widget); + _layout.draw(painter, QPointF(0, 0)); + +} +*/ + +/* +void ChatItem::mouseMoveEvent ( QGraphicsSceneMouseEvent * event ) { + qDebug() << (void*)this << "moving" << event->pos(); + if(event->pos().y() < 0) { + QTextCursor cursor(document()); + //cursor.insertText("foo"); + //cursor.select(QTextCursor::Document); + event->ignore(); + } else QGraphicsTextItem::mouseMoveEvent(event); +} +*/ + + + diff --git a/src/qtui/chatitem.h b/src/qtui/chatitem.h new file mode 100644 index 00000000..2b7ac8a3 --- /dev/null +++ b/src/qtui/chatitem.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _CHATITEM_H_ +#define _CHATITEM_H_ + +#include +#include +#include +#include + +#include "messagemodel.h" +#include "uistyle.h" + +class QGraphicsSceneMouseEvent; + +class ChatItem : public QGraphicsItem { + + public: + ChatItem(const QPersistentModelIndex &index, QGraphicsItem *parent = 0); + virtual ~ChatItem(); + + virtual QRectF boundingRect() const; + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + + inline QPersistentModelIndex persistentIndex() const { return _index; } + inline const MessageModel *model() const { return _index.isValid() ? qobject_cast(_index.model()) : 0; } + inline int row() const { return _index.isValid() ? _index.row() : 0; } + virtual QVariant data(int role) const; + //QString text() const; + //void setText(const UiStyle::StyledText &text); + + //QTextOption textOption() const; + //void setTextOption(const QTextOption &option); + + //void setWidth(int width); + //virtual void layout(); + + protected: + //void mouseMoveEvent ( QGraphicsSceneMouseEvent * event ); + + private: + //int _width; + //QTextLayout _layout; + //QTextOption _textOption; + QPersistentModelIndex _index; +}; + +#endif diff --git a/src/qtui/chatline-old.cpp b/src/qtui/chatline-old.cpp index 497017da..3b0dae5c 100644 --- a/src/qtui/chatline-old.cpp +++ b/src/qtui/chatline-old.cpp @@ -51,7 +51,7 @@ void ChatLineOld::formatMsg(Message msg) { QTextOption tsOption, senderOption, textOption; styledTimeStamp = QtUi::style()->styleString(msg.formattedTimestamp()); styledSender = QtUi::style()->styleString(msg.formattedSender()); - styledText = QtUi::style()->styleString(msg.formattedText()); + styledContents = QtUi::style()->styleString(msg.formattedText()); precomputeLine(); } @@ -69,28 +69,28 @@ QList ChatLineOld::calcFormatRanges(const UiStyle::Sty QList ranges; if(additional.length > 0) { - for(int i = 0; i < fs.formats.count(); i++) { - int oldend = fs.formats[i].start + fs.formats[i].length - 1; + for(int i = 0; i < fs.formatList.count(); i++) { + int oldend = fs.formatList[i].start + fs.formatList[i].length - 1; int addend = additional.start + additional.length - 1; if(oldend < additional.start) continue; - fs.formats[i].length = additional.start - fs.formats[i].start; - QTextLayout::FormatRange addfmtrng = fs.formats[i]; + fs.formatList[i].length = additional.start - fs.formatList[i].start; + QTextLayout::FormatRange addfmtrng = fs.formatList[i]; addfmtrng.format.merge(additional.format); addfmtrng.start = additional.start; addfmtrng.length = qMin(oldend, addend) - additional.start + 1; - fs.formats.insert(++i, addfmtrng); + fs.formatList.insert(++i, addfmtrng); if(addend == oldend) break; if(addend < oldend) { - QTextLayout::FormatRange restfmtrng = fs.formats[i-1]; + QTextLayout::FormatRange restfmtrng = fs.formatList[i-1]; restfmtrng.start = addend + 1; restfmtrng.length = oldend - addend; - fs.formats.insert(++i, restfmtrng); + fs.formatList.insert(++i, restfmtrng); break; } } } - foreach(QTextLayout::FormatRange f, fs.formats) { + foreach(QTextLayout::FormatRange f, fs.formatList) { if(f.length <= 0) continue; FormatRange range; range.start = f.start; @@ -112,7 +112,7 @@ void ChatLineOld::setSelection(SelectionMode mode, int start, int end) { case None: tsFormat = calcFormatRanges(styledTimeStamp); senderFormat = calcFormatRanges(styledSender); - textFormat = calcFormatRanges(styledText); + textFormat = calcFormatRanges(styledContents); break; case Partial: selectionStart = qMin(start, end); selectionEnd = qMax(start, end); @@ -120,21 +120,21 @@ void ChatLineOld::setSelection(SelectionMode mode, int start, int end) { textSel.format.setBackground(pal.brush(QPalette::Highlight)); textSel.start = selectionStart; textSel.length = selectionEnd - selectionStart; - textFormat = calcFormatRanges(styledText, textSel); + textFormat = calcFormatRanges(styledContents, textSel); break; case Full: tsSel.format.setForeground(pal.brush(QPalette::HighlightedText)); tsSel.format.setBackground(pal.brush(QPalette::Highlight)); - tsSel.start = 0; tsSel.length = styledTimeStamp.text.length(); + tsSel.start = 0; tsSel.length = styledTimeStamp.plainText.length(); tsFormat = calcFormatRanges(styledTimeStamp, tsSel); senderSel.format.setForeground(pal.brush(QPalette::HighlightedText)); senderSel.format.setBackground(pal.brush(QPalette::Highlight)); - senderSel.start = 0; senderSel.length = styledSender.text.length(); + senderSel.start = 0; senderSel.length = styledSender.plainText.length(); senderFormat = calcFormatRanges(styledSender, senderSel); textSel.format.setForeground(pal.brush(QPalette::HighlightedText)); textSel.format.setBackground(pal.brush(QPalette::Highlight)); - textSel.start = 0; textSel.length = styledText.text.length(); - textFormat = calcFormatRanges(styledText, textSel); + textSel.start = 0; textSel.length = styledContents.plainText.length(); + textFormat = calcFormatRanges(styledContents, textSel); break; } } @@ -152,11 +152,11 @@ QDateTime ChatLineOld::timestamp() const { } QString ChatLineOld::sender() const { - return styledSender.text; + return styledSender.plainText; } QString ChatLineOld::text() const { - return styledText.text; + return styledContents.plainText; } bool ChatLineOld::isUrl(int c) const { @@ -167,7 +167,7 @@ bool ChatLineOld::isUrl(int c) const { QUrl ChatLineOld::getUrl(int c) const { if(c < 0 || c >= charUrlIdx.count()) return QUrl(); int i = charUrlIdx[c]; - if(i >= 0) return styledText.urls[i].url; + if(i >= 0) return styledContents.urls[i].url; else return QUrl(); } @@ -197,18 +197,18 @@ int ChatLineOld::posToCursor(QPointF pos) { void ChatLineOld::precomputeLine() { tsFormat = calcFormatRanges(styledTimeStamp); senderFormat = calcFormatRanges(styledSender); - textFormat = calcFormatRanges(styledText); + textFormat = calcFormatRanges(styledContents); minHeight = 0; foreach(FormatRange fr, tsFormat) minHeight = qMax(minHeight, fr.height); foreach(FormatRange fr, senderFormat) minHeight = qMax(minHeight, fr.height); words.clear(); - charPos.resize(styledText.text.length() + 1); - charHeights.resize(styledText.text.length()); - charUrlIdx.fill(-1, styledText.text.length()); - for(int i = 0; i < styledText.urls.count(); i++) { - QtUiStyle::UrlInfo url = styledText.urls[i]; + charPos.resize(styledContents.plainText.length() + 1); + charHeights.resize(styledContents.plainText.length()); + charUrlIdx.fill(-1, styledContents.plainText.length()); + for(int i = 0; i < styledContents.urls.count(); i++) { + QtUiStyle::UrlInfo url = styledContents.urls[i]; for(int j = url.start; j < url.end; j++) charUrlIdx[j] = i; } if(!textFormat.count()) return; @@ -216,10 +216,10 @@ void ChatLineOld::precomputeLine() { QFontMetrics metrics(textFormat[0].format.font()); Word wr; wr.start = -1; wr.trailing = -1; - for(int i = 0; i < styledText.text.length(); ) { + for(int i = 0; i < styledContents.plainText.length(); ) { charPos[i] = w; charHeights[i] = textFormat[idx].height; - w += metrics.charWidth(styledText.text, i); - if(!styledText.text[i].isSpace()) { + w += metrics.charWidth(styledContents.plainText, i); + if(!styledContents.plainText[i].isSpace()) { if(wr.trailing >= 0) { // new word after space words.append(wr); @@ -237,13 +237,13 @@ void ChatLineOld::precomputeLine() { wr.trailing++; } } - if(++i < styledText.text.length() && ++cnt >= textFormat[idx].length) { + if(++i < styledContents.plainText.length() && ++cnt >= textFormat[idx].length) { cnt = 0; idx++; Q_ASSERT(idx < textFormat.count()); metrics = QFontMetrics(textFormat[idx].format.font()); } } - charPos[styledText.text.length()] = w; + charPos[styledContents.plainText.length()] = w; if(wr.start >= 0) words.append(wr); } @@ -346,14 +346,14 @@ void ChatLineOld::draw(QPainter *p, const QPointF &pos) { foreach(FormatRange fr, tsFormat) { p->setFont(fr.format.font()); p->setPen(QPen(fr.format.foreground(), 0)); p->setBackground(fr.format.background()); - p->drawText(rect, Qt::AlignLeft|Qt::TextSingleLine, styledTimeStamp.text.mid(fr.start, fr.length), &brect); + p->drawText(rect, Qt::AlignLeft|Qt::TextSingleLine, styledTimeStamp.plainText.mid(fr.start, fr.length), &brect); rect.setLeft(brect.right()); } rect = QRectF(pos + QPointF(tsWidth + QtUi::style()->sepTsSender(), 0), QSizeF(senderWidth, minHeight)); for(int i = senderFormat.count() - 1; i >= 0; i--) { FormatRange fr = senderFormat[i]; p->setFont(fr.format.font()); p->setPen(QPen(fr.format.foreground(), 0)); p->setBackground(fr.format.background()); - p->drawText(rect, Qt::AlignRight|Qt::TextSingleLine, styledSender.text.mid(fr.start, fr.length), &brect); + p->drawText(rect, Qt::AlignRight|Qt::TextSingleLine, styledSender.plainText.mid(fr.start, fr.length), &brect); rect.setRight(brect.left()); } QPointF tpos = pos + QPointF(tsWidth + QtUi::style()->sepTsSender() + senderWidth + QtUi::style()->sepSenderText(), 0); @@ -371,7 +371,7 @@ void ChatLineOld::draw(QPainter *p, const QPointF &pos) { llend = lineLayouts[l].start + lineLayouts[l].length; start = qMax(fr.start, lineLayouts[l].start); end = qMin(frend, llend); rect.setLeft(tpos.x() + charPos[start] - offset); - p->drawText(rect, Qt::AlignLeft|Qt::TextSingleLine, styledText.text.mid(start, end - start), &brect); + p->drawText(rect, Qt::AlignLeft|Qt::TextSingleLine, styledContents.plainText.mid(start, end - start), &brect); if(llend <= end) { h += lineLayouts[l].height; l++; diff --git a/src/qtui/chatline-old.h b/src/qtui/chatline-old.h index 5ce5fc3f..b2b9445a 100644 --- a/src/qtui/chatline-old.h +++ b/src/qtui/chatline-old.h @@ -70,7 +70,7 @@ class ChatLineOld : public QObject, public AbstractUiMsg { qreal hght; Message msg; qreal tsWidth, senderWidth, textWidth; - UiStyle::StyledText styledTimeStamp, styledSender, styledText; + UiStyle::StyledText styledTimeStamp, styledSender, styledContents; struct FormatRange { int start; diff --git a/src/qtui/chatlinemodel.cpp b/src/qtui/chatlinemodel.cpp new file mode 100644 index 00000000..9ca1ff8b --- /dev/null +++ b/src/qtui/chatlinemodel.cpp @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel IRC Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "chatlinemodel.h" + +#include "chatlinemodelitem.h" + +ChatlineModel::ChatlineModel(QObject *parent) : MessageModel(parent) { + + +} + +ChatlineModel::~ChatlineModel() { + +} + + +MessageModelItem *ChatlineModel::createMessageModelItem(const Message &msg) { + return new ChatlineModelItem(msg); + +} diff --git a/src/qtui/chatlinemodel.h b/src/qtui/chatlinemodel.h new file mode 100644 index 00000000..11c9a076 --- /dev/null +++ b/src/qtui/chatlinemodel.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel IRC Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef CHATLINEMODEL_H_ +#define CHATLINEMODEL_H_ + +#include "messagemodel.h" + +class ChatlineModel : public MessageModel { + Q_OBJECT + + public: + enum ChatlineRole { + FormatRole = MessageModel::UserRole + }; + + ChatlineModel(QObject *parent = 0); + virtual ~ChatlineModel(); + + protected: + virtual MessageModelItem *createMessageModelItem(const Message &); + +}; + +#endif + diff --git a/src/qtui/chatlinemodelitem.cpp b/src/qtui/chatlinemodelitem.cpp new file mode 100644 index 00000000..009d535a --- /dev/null +++ b/src/qtui/chatlinemodelitem.cpp @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "chatlinemodelitem.h" +#include "chatlinemodel.h" +#include "qtui.h" +#include "uistyle.h" + +ChatlineModelItem::ChatlineModelItem(const Message &msg) : MessageModelItem(msg) { + QtUiStyle::StyledMessage m = QtUi::style()->styleMessage(msg); + + _timestamp.plainText = m.timestamp.plainText; + _sender.plainText = m.sender.plainText; + _contents.plainText = m.contents.plainText; + + _timestamp.formatList = m.timestamp.formatList; + _sender.formatList = m.sender.formatList; + _contents.formatList = m.contents.formatList; + +} + + +QVariant ChatlineModelItem::data(int column, int role) const { + const ChatlinePart *part; + + switch(column) { + case ChatlineModel::TimestampColumn: part = &_timestamp; break; + case ChatlineModel::SenderColumn: part = &_sender; break; + case ChatlineModel::TextColumn: part = &_contents; break; + default: return MessageModelItem::data(column, role); + } + + switch(role) { + case ChatlineModel::DisplayRole: return part->plainText; + case ChatlineModel::FormatRole: return QVariant::fromValue(part->formatList); + } + + return MessageModelItem::data(column, role); +} + +bool ChatlineModelItem::setData(int column, const QVariant &value, int role) { + return false; +} diff --git a/src/qtui/chatlinemodelitem.h b/src/qtui/chatlinemodelitem.h new file mode 100644 index 00000000..4d5469e5 --- /dev/null +++ b/src/qtui/chatlinemodelitem.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef CHATLINEMODELITEM_H_ +#define CHATLINEMODELITEM_H_ + +#include "messagemodel.h" +#include "uistyle.h" + +class ChatlineModelItem : public MessageModelItem { + + public: + ChatlineModelItem(const Message &); + //virtual ~ChatlineModelItem() {}; + + virtual QVariant data(int column, int role) const; + virtual bool setData(int column, const QVariant &value, int role); + + private: + struct ChatlinePart { + QString plainText; + UiStyle::FormatList formatList; + + }; + + ChatlinePart _timestamp, _sender, _contents; +}; + +#endif diff --git a/src/qtui/chatscene.cpp b/src/qtui/chatscene.cpp new file mode 100644 index 00000000..a78c2ba8 --- /dev/null +++ b/src/qtui/chatscene.cpp @@ -0,0 +1,57 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include +#include + +#include "buffer.h" +#include "chatitem.h" +#include "chatlinemodelitem.h" +#include "chatscene.h" +#include "quasselui.h" + +ChatScene::ChatScene(MessageModel *model, QObject *parent) : QGraphicsScene(parent), _model(model) { + connect(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(rowsInserted(const QModelIndex &, int, int))); + for(int i = 0; i < model->rowCount(); i++) { + ChatItem *item = new ChatItem(QPersistentModelIndex(model->index(i, 2))); + addItem(item); + item->setPos(30, i*item->boundingRect().height()); + } + + +} + +ChatScene::~ChatScene() { + + +} + + +void ChatScene::mousePressEvent ( QGraphicsSceneMouseEvent * mouseEvent ) { + /* + qDebug() << "recv" << mouseEvent->scenePos(); + ChatLine *line = static_cast(itemAt(mouseEvent->scenePos())); + ChatItem *item = static_cast(itemAt(mouseEvent->scenePos())); + qDebug() << (void*)line << (void*)item; + if(line) { + line->myMousePressEvent(mouseEvent); + } else QGraphicsScene::mousePressEvent(mouseEvent); + */ +} diff --git a/src/qtui/chatscene.h b/src/qtui/chatscene.h new file mode 100644 index 00000000..1ce9304d --- /dev/null +++ b/src/qtui/chatscene.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _CHATSCENE_H_ +#define _CHATSCENE_H_ + +#include + +#include "messagemodel.h" + +class AbstractUiMsg; +class Buffer; +class ChatItem; +class ChatLine; +class QGraphicsSceneMouseEvent; + +class ChatScene : public QGraphicsScene { + Q_OBJECT + + public: + ChatScene(MessageModel *model, QObject *parent); + virtual ~ChatScene(); + + Buffer *buffer() const; + inline MessageModel *model() const { return _model; } + + public slots: + + protected slots: + + void mousePressEvent ( QGraphicsSceneMouseEvent * mouseEvent ); + + private: + //Buffer *_buffer; + //QList _lines; + MessageModel *_model; + QList _items; + +}; + +#endif diff --git a/src/qtui/chatview.cpp b/src/qtui/chatview.cpp new file mode 100644 index 00000000..f76cf2ae --- /dev/null +++ b/src/qtui/chatview.cpp @@ -0,0 +1,88 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include + +#include "buffer.h" +#include "chatlinemodelitem.h" +#include "chatscene.h" +#include "chatview.h" +#include "client.h" +#include "quasselui.h" + +ChatView::ChatView(Buffer *buf, QWidget *parent) : QGraphicsView(parent), AbstractChatView() { + _scene = new ChatScene(Client::messageModel(), this); + setScene(_scene); + + //QGraphicsTextItem *item = scene()->addText(buf->bufferInfo().bufferName()); + +} + + +ChatView::~ChatView() { + +} + + +ChatScene *ChatView::scene() const { + return _scene; +} + + +void ChatView::clear() +{ +} + +void ChatView::prependMsg(AbstractUiMsg *msg) { + //ChatLine *line = dynamic_cast(msg); + //Q_ASSERT(line); + //prependChatLine(line); +} + +void ChatView::prependChatLine(ChatLine *line) { + //qDebug() << "prepending"; +} + +void ChatView::prependChatLines(QList clist) { + +} + +void ChatView::appendMsg(AbstractUiMsg *msg) { + //ChatLine *line = dynamic_cast(msg); + //Q_ASSERT(line); + //appendChatLine(line); +} + +void ChatView::appendChatLine(ChatLine *line) { + //qDebug() << "appending"; +} + + +void ChatView::appendChatLines(QList list) { + //foreach(ChatLine *line, list) { + + //} +} + +void ChatView::setContents(const QList &list) { + //qDebug() << "setting" << list.count(); + //appendChatLines(list); +} + diff --git a/src/qtui/chatview.h b/src/qtui/chatview.h new file mode 100644 index 00000000..7ae7c8dc --- /dev/null +++ b/src/qtui/chatview.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef CHATVIEW_H_ +#define CHATVIEW_H_ + +#include + +#include "abstractbuffercontainer.h" + +class AbstractUiMsg; +class Buffer; +class ChatLine; +class ChatScene; + +class ChatView : public QGraphicsView, public AbstractChatView { + Q_OBJECT + + public: + ChatView(Buffer *, QWidget *parent = 0); + ~ChatView(); + + ChatScene *scene() const; + + public slots: + + void clear(); + + void prependMsg(AbstractUiMsg *); + void appendMsg(AbstractUiMsg *); + + void prependChatLine(ChatLine *); + void appendChatLine(ChatLine *); + void prependChatLines(QList); + void appendChatLines(QList); + + void setContents(const QList &); + + private: + ChatScene *_scene; +}; + +#endif diff --git a/src/qtui/mainwin.cpp b/src/qtui/mainwin.cpp index ebd83f6c..64d4fd7c 100644 --- a/src/qtui/mainwin.cpp +++ b/src/qtui/mainwin.cpp @@ -25,7 +25,6 @@ #include "bufferviewconfig.h" #include "bufferviewfilter.h" #include "bufferviewmanager.h" -#include "chatline-old.h" #include "client.h" #include "clientbacklogmanager.h" #include "coreconnectdlg.h" @@ -275,6 +274,7 @@ void MainWin::setupNickWidget() { } void MainWin::setupChatMonitor() { +#ifndef SPUTDEV VerticalDock *dock = new VerticalDock(tr("Chat Monitor"), this); dock->setObjectName("ChatMonitorDock"); @@ -293,6 +293,7 @@ void MainWin::setupChatMonitor() { addDockWidget(Qt::TopDockWidgetArea, dock, Qt::Vertical); ui.menuViews->addAction(dock->toggleViewAction()); +#endif /* SPUTDEV */ } void MainWin::setupInputWidget() { @@ -483,10 +484,6 @@ void MainWin::setDisconnectedState() { sslLabel->setPixmap(QPixmap()); } -AbstractUiMsg *MainWin::layoutMsg(const Message &msg) { - return new ChatLineOld(msg); -} - void MainWin::showCoreConnectionDlg(bool autoConnect) { coreConnectDlg = new CoreConnectDlg(this, autoConnect); connect(coreConnectDlg, SIGNAL(finished(int)), this, SLOT(coreConnectionDlgFinished(int))); @@ -570,12 +567,13 @@ void MainWin::receiveMessage(const Message &msg) { UiSettings uiSettings; +#ifndef SPUTDEV if(uiSettings.value("DisplayPopupMessages", QVariant(true)).toBool()) { // FIXME don't invoke style engine for this! - QString text = QtUi::style()->styleString(Message::mircToInternal(msg.text())).text; + QString text = QtUi::style()->styleString(Message::mircToInternal(msg.contents())).plainText; displayTrayIconMessage(title, text); } - +#endif if(uiSettings.value("AnimateTrayIcon", QVariant(true)).toBool()) { QApplication::alert(this); setTrayIconActivity(true); diff --git a/src/qtui/mainwin.h b/src/qtui/mainwin.h index 96e0c715..e2e703f0 100644 --- a/src/qtui/mainwin.h +++ b/src/qtui/mainwin.h @@ -52,7 +52,6 @@ class MainWin : public QMainWindow { void init(); void addBufferView(BufferViewConfig *config = 0); - AbstractUiMsg *layoutMsg(const Message &); void displayTrayIconMessage(const QString &title, const QString &message); virtual bool event(QEvent *event); diff --git a/src/qtui/qtui.cpp b/src/qtui/qtui.cpp index b3539217..a65a4794 100644 --- a/src/qtui/qtui.cpp +++ b/src/qtui/qtui.cpp @@ -20,8 +20,12 @@ #include "qtui.h" +#ifdef SPUTDEV +# include "chatlinemodel.h" +#else +# include "chatline-old.h" +#endif #include "mainwin.h" -#include "chatline-old.h" QtUiStyle *QtUi::_style; @@ -48,8 +52,21 @@ QtUiStyle *QtUi::style() { return _style; } +MessageModel *QtUi::createMessageModel(QObject *parent) { +#ifndef SPUTDEV + Q_UNUSED(parent) + return 0; +#else + return new ChatlineModel(parent); +#endif +} + AbstractUiMsg *QtUi::layoutMsg(const Message &msg) { +#ifndef SPUTDEV return new ChatLineOld(msg); +#else + return 0; +#endif } void QtUi::connectedToCore() { diff --git a/src/qtui/qtui.h b/src/qtui/qtui.h index f6f1db5b..bbe31f7d 100644 --- a/src/qtui/qtui.h +++ b/src/qtui/qtui.h @@ -25,6 +25,7 @@ #include "quasselui.h" class MainWin; +class MessageModel; //! This class encapsulates Quassel's Qt-based GUI. /** This is basically a wrapper around MainWin, which is necessary because we cannot derive MainWin @@ -37,6 +38,7 @@ class QtUi : public AbstractUi { QtUi(); ~QtUi(); //void init(); + MessageModel *createMessageModel(QObject *parent = 0); AbstractUiMsg *layoutMsg(const Message &); static QtUiStyle *style(); diff --git a/src/qtui/qtui.pri b/src/qtui/qtui.pri index ab2774f4..5688c06a 100644 --- a/src/qtui/qtui.pri +++ b/src/qtui/qtui.pri @@ -11,6 +11,14 @@ HDRS += aboutdlg.h bufferwidget.h chatline-old.h chatwidget.h \ coreconnectdlg.h mainwin.h nicklistwidget.h qtui.h qtuisettings.h qtuistyle.h settingsdlg.h settingspagedlg.h \ titlesetter.h topicbutton.h topicwidget.h verticaldock.h jumpkeyhandler.h +# new chatline model stuff +sputdev { + SRCS += chatitem.cpp chatlinemodelitem.cpp chatlinemodel.cpp chatscene.cpp chatview.cpp + HDRS += chatitem.h chatlinemodelitem.h chatlinemodel.h chatscene.h chatview.h + SRCS -= chatline-old.cpp chatwidget.cpp + HDRS -= chatline-old.h chatwidget.h +} + FORMNAMES = aboutdlg.ui mainwin.ui coreaccounteditdlg.ui coreconnectdlg.ui bufferviewwidget.ui bufferwidget.ui nicklistwidget.ui settingsdlg.ui \ settingspagedlg.ui topicwidget.ui debugconsole.ui inputwidget.ui \ coreconfigwizardintropage.ui coreconfigwizardadminuserpage.ui coreconfigwizardstorageselectionpage.ui coreconfigwizardsyncpage.ui diff --git a/src/qtui/qtuistyle.cpp b/src/qtui/qtuistyle.cpp index cb4436d0..78255dca 100644 --- a/src/qtui/qtuistyle.cpp +++ b/src/qtui/qtuistyle.cpp @@ -20,7 +20,11 @@ #include "qtuistyle.h" +#ifndef SPUTDEV QtUiStyle::QtUiStyle() : UiStyle("QtUiStyle") { +#else +QtUiStyle::QtUiStyle() : UiStyle("QtUiStyleNew") { +#endif // We need to just set our internal formats; everything else is done by the base class... // Internal message formats diff --git a/src/qtui/settingspages/networkssettingspage.ui b/src/qtui/settingspages/networkssettingspage.ui index a180f3e3..aae2401c 100644 --- a/src/qtui/settingspages/networkssettingspage.ui +++ b/src/qtui/settingspages/networkssettingspage.ui @@ -161,7 +161,7 @@ Unless you *really* know what you do, leave this as ISO-8859-1! - 0 + 1 @@ -171,8 +171,8 @@ Unless you *really* know what you do, leave this as ISO-8859-1! 0 0 - 244 - 332 + 301 + 326 @@ -337,8 +337,8 @@ Unless you *really* know what you do, leave this as ISO-8859-1! 0 0 - 244 - 332 + 301 + 326 @@ -377,6 +377,13 @@ Unless you *really* know what you do, leave this as ISO-8859-1! true + + + + Service: + + + @@ -387,30 +394,23 @@ Unless you *really* know what you do, leave this as ISO-8859-1! - - + + true - - QLineEdit::Password - - - - - - Service: + Password: - - + + true - - Password: + + QLineEdit::Password @@ -428,8 +428,8 @@ Unless you *really* know what you do, leave this as ISO-8859-1! 0 0 - 244 - 332 + 301 + 326 diff --git a/src/qtui/topicbutton.cpp b/src/qtui/topicbutton.cpp index 4c26bfc3..f2f60af1 100644 --- a/src/qtui/topicbutton.cpp +++ b/src/qtui/topicbutton.cpp @@ -45,17 +45,20 @@ void TopicButton::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setBackgroundMode(Qt::OpaqueMode); + // FIXME re-enable topic painting +#ifndef SPUTDEV QRect drawRect = rect(); QRect brect; QString textPart; - foreach(QTextLayout::FormatRange fr, styledText.formats) { - textPart = styledText.text.mid(fr.start, fr.length); + foreach(QTextLayout::FormatRange fr, styledContents.formatList) { + textPart = styledContents.plainText.mid(fr.start, fr.length); painter.setFont(fr.format.font()); painter.setPen(QPen(fr.format.foreground(), 0)); painter.setBackground(fr.format.background()); painter.drawText(drawRect, Qt::AlignLeft|Qt::TextSingleLine, textPart, &brect); drawRect.setLeft(brect.right()); } +#endif } void TopicButton::setAndStyleText(const QString &text) { @@ -64,9 +67,10 @@ void TopicButton::setAndStyleText(const QString &text) { setText(text); // this triggers a repaint event - styledText = QtUi::style()->styleString(Message::mircToInternal(text)); +#ifndef SPUTDEV + styledContents = QtUi::style()->styleString(Message::mircToInternal(text)); int height = 1; - foreach(QTextLayout::FormatRange fr, styledText.formats) { + foreach(QTextLayout::FormatRange fr, styledContents.formatList) { height = qMax(height, QFontMetrics(fr.format.font()).height()); } @@ -75,7 +79,7 @@ void TopicButton::setAndStyleText(const QString &text) { height = QFontMetrics(qApp->font()).height(); setFixedHeight(height); - +#endif // show topic in tooltip setToolTip(tr("%1\n\nClick to edit!").arg(QAbstractButton::text())); } diff --git a/src/qtui/topicbutton.h b/src/qtui/topicbutton.h index e0b21885..71e9cd89 100644 --- a/src/qtui/topicbutton.h +++ b/src/qtui/topicbutton.h @@ -38,7 +38,9 @@ protected: virtual void paintEvent(QPaintEvent *event); private: - UiStyle::StyledText styledText; +#ifndef SPUTDEV + UiStyle::StyledText styledContents; +#endif QSize _sizeHint; }; diff --git a/src/uisupport/bufferview.cpp b/src/uisupport/bufferview.cpp index c0e85ad0..8e90fc6b 100644 --- a/src/uisupport/bufferview.cpp +++ b/src/uisupport/bufferview.cpp @@ -263,7 +263,11 @@ void BufferView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bott continue; bool isActive = networkIdx.data(NetworkModel::ItemActiveRole).toBool(); +#ifdef SPUTDEV + if(isExpanded(networkIdx) != isActive) setExpanded(networkIdx, true); +#else if(isExpanded(networkIdx) != isActive) setExpanded(networkIdx, isActive); +#endif } } diff --git a/src/uisupport/bufferviewfilter.cpp b/src/uisupport/bufferviewfilter.cpp index 59dd184f..e02549c6 100644 --- a/src/uisupport/bufferviewfilter.cpp +++ b/src/uisupport/bufferviewfilter.cpp @@ -266,7 +266,7 @@ QVariant BufferViewFilter::foreground(const QModelIndex &index) const { } void BufferViewFilter::source_rowsInserted(const QModelIndex &parent, int start, int end) { - if(parent.data(NetworkModel::ItemTypeRole) != NetworkModel::NetworkItemType) + if(parent.data(NetworkModel::ItemTypeRole) != NetworkModel::BufferItemType) return; if(!config() || !config()->addNewBuffersAutomatically()) diff --git a/src/uisupport/old-uistyle.cpp b/src/uisupport/old-uistyle.cpp new file mode 100644 index 00000000..83024aa4 --- /dev/null +++ b/src/uisupport/old-uistyle.cpp @@ -0,0 +1,242 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include + +#include "uistyle.h" +#include "uistylesettings.h" + +UiStyle::UiStyle(const QString &settingsKey) : _settingsKey(settingsKey) { + // Default format + QTextCharFormat def; + def.setForeground(QBrush("#000000")); + def.setFont(QFont("Monospace", QApplication::font().pointSize())); + def.font().setFixedPitch(true); + def.font().setStyleHint(QFont::TypeWriter); + _defaultFormats = QVector(NumFormatTypes, def); + _customFormats = QVector(NumFormatTypes, QTextFormat().toCharFormat()); + + // Load saved custom formats + UiStyleSettings s(_settingsKey); + foreach(FormatType type, s.availableFormats()) { + _customFormats[type] = s.customFormat(type); + } + + // Initialize color codes according to mIRC "standard" + QStringList colors; + //colors << "white" << "black" << "navy" << "green" << "red" << "maroon" << "purple" << "orange"; + //colors << "yellow" << "lime" << "teal" << "aqua" << "royalblue" << "fuchsia" << "grey" << "silver"; + colors << "#ffffff" << "#000000" << "#000080" << "#008000" << "#ff0000" << "#800000" << "#800080" << "#ffa500"; + colors << "#ffff00" << "#00ff00" << "#008080" << "#00ffff" << "#4169E1" << "#ff00ff" << "#808080" << "#c0c0c0"; + + // Now initialize the mapping between FormatCodes and FormatTypes... + _formatCodes["%O"] = None; + _formatCodes["%B"] = Bold; + _formatCodes["%S"] = Italic; + _formatCodes["%U"] = Underline; + _formatCodes["%R"] = Reverse; + + _formatCodes["%D0"] = PlainMsg; + _formatCodes["%Dn"] = NoticeMsg; + _formatCodes["%Ds"] = ServerMsg; + _formatCodes["%De"] = ErrorMsg; + _formatCodes["%Dj"] = JoinMsg; + _formatCodes["%Dp"] = PartMsg; + _formatCodes["%Dq"] = QuitMsg; + _formatCodes["%Dk"] = KickMsg; + _formatCodes["%Dr"] = RenameMsg; + _formatCodes["%Dm"] = ModeMsg; + _formatCodes["%Da"] = ActionMsg; + + _formatCodes["%DT"] = Timestamp; + _formatCodes["%DS"] = Sender; + _formatCodes["%DN"] = Nick; + _formatCodes["%DH"] = Hostmask; + _formatCodes["%DC"] = ChannelName; + _formatCodes["%DM"] = ModeFlags; + _formatCodes["%DU"] = Url; + + // Set color formats + for(int i = 0; i < 16; i++) { + QString idx = QString("%1").arg(i, (int)2, (int)10, (QChar)'0'); + _formatCodes[QString("%Dcf%1").arg(idx)] = (FormatType)(FgCol00 + i); + _formatCodes[QString("%Dcb%1").arg(idx)] = (FormatType)(BgCol00 + i); + QTextCharFormat fgf, bgf; + fgf.setForeground(QBrush(QColor(colors[i]))); setFormat((FormatType)(FgCol00 + i), fgf, Settings::Default); + bgf.setBackground(QBrush(QColor(colors[i]))); setFormat((FormatType)(BgCol00 + i), bgf, Settings::Default); + //FIXME fix the havoc caused by ColorSettingsPage + setFormat((FormatType)(FgCol00 + i), fgf, Settings::Custom); + setFormat((FormatType)(BgCol00 + i), bgf, Settings::Custom); + } + + // Set a few more standard formats + QTextCharFormat bold; bold.setFontWeight(QFont::Bold); + setFormat(Bold, bold, Settings::Default); + + QTextCharFormat italic; italic.setFontItalic(true); + setFormat(Italic, italic, Settings::Default); + + QTextCharFormat underline; underline.setFontUnderline(true); + setFormat(Underline, underline, Settings::Default); + + // All other formats should be defined in derived classes. +} + +UiStyle::~ UiStyle() { + +} + +void UiStyle::setFormat(FormatType ftype, QTextCharFormat fmt, Settings::Mode mode) { + if(mode == Settings::Default) { + _defaultFormats[ftype] = fmt; + } else { + UiStyleSettings s(_settingsKey); + if(fmt != _defaultFormats[ftype]) { + _customFormats[ftype] = fmt; + s.setCustomFormat(ftype, fmt); + } else { + _customFormats[ftype] = QTextFormat().toCharFormat(); + s.removeCustomFormat(ftype); + } + } +} + +QTextCharFormat UiStyle::format(FormatType ftype, Settings::Mode mode) const { + if(mode == Settings::Custom && _customFormats[ftype].isValid()) return _customFormats[ftype]; + else return _defaultFormats[ftype]; +} + +UiStyle::FormatType UiStyle::formatType(const QString & code) const { + if(_formatCodes.contains(code)) return _formatCodes.value(code); + return Invalid; +} + +QString UiStyle::formatCode(FormatType ftype) const { + return _formatCodes.key(ftype); +} + +UiStyle::StyledText UiStyle::styleString(const QString &_s) { + QString s = _s; + StyledText result; + QList fmtList; + fmtList.append(None); + QTextLayout::FormatRange curFmtRng; + curFmtRng.format = format(None); + curFmtRng.start = 0; + result.formatList.append(curFmtRng); + int pos = 0; int length = 0; + int fgCol = -1, bgCol = -1; // marks current mIRC color + for(;;) { + pos = s.indexOf('%', pos); + if(pos < 0) break; + if(s[pos+1] == '%') { // escaped %, just remove one and continue + s.remove(pos, 1); + pos++; + continue; + } else if(s[pos+1] == 'D' && s[pos+2] == 'c') { // color code + if(s[pos+3] == '-') { // color off + if(fgCol >= 0) { + fmtList.removeAll((FormatType)(FgCol00 + fgCol)); + fgCol = -1; + } + if(bgCol >= 0) { + fmtList.removeAll((FormatType)(BgCol00 + bgCol)); + bgCol = -1; + } + curFmtRng.format = mergedFormat(fmtList); + length = 4; + } else { + int color = 10 * s[pos+4].digitValue() + s[pos+5].digitValue(); + //TODO: use 99 as transparent color (re mirc color "standard") + color &= 0x0f; + int *colptr; FormatType coltype; + if(s[pos+3] == 'f') { // foreground + colptr = &fgCol; coltype = FgCol00; + } else { // background + Q_ASSERT(s[pos+3] == 'b'); + colptr = &bgCol; coltype = BgCol00; + } + if(*colptr >= 0) { + // color already set, remove format code and add new one + Q_ASSERT(fmtList.contains((FormatType)(coltype + *colptr))); + fmtList.removeAll((FormatType)(coltype + *colptr)); + fmtList.append((FormatType)(coltype + color)); + curFmtRng.format = mergedFormat(fmtList); + } else { + fmtList.append((FormatType)(coltype + color)); + curFmtRng.format.merge(format(fmtList.last())); + } + *colptr = color; + length = 6; + } + } else if(s[pos+1] == 'O') { // reset formatting + fmtList.clear(); fmtList.append(None); + curFmtRng.format = format(None); + fgCol = bgCol = -1; + length = 2; + } else if(s[pos+1] == 'R') { // reverse + // TODO: implement reverse formatting + + length = 2; + } else { // all others are toggles + QString code = QString("%") + s[pos+1]; + if(s[pos+1] == 'D') code += s[pos+2]; + FormatType ftype = formatType(code); + if(ftype == Invalid) { + qWarning(qPrintable(QString("Invalid format code in string: %1").arg(s))); + continue; + } + //Q_ASSERT(ftype != Invalid); + length = code.length(); + if(!fmtList.contains(ftype)) { + // toggle it on + fmtList.append(ftype); + curFmtRng.format.merge(format(ftype)); + } else { + // toggle it off + fmtList.removeAll(ftype); + curFmtRng.format = mergedFormat(fmtList); + } + } + s.remove(pos, length); // remove format code from string + // now see if something changed and else insert the format + if(curFmtRng.format == result.formatList.last().format) continue; // no change, so we just ignore + curFmtRng.start = pos; + if(pos == result.formatList.last().start) { + // same starting point -> we just overwrite the old format + result.formatList.last() = curFmtRng; + } else { + // fix length of last format + result.formatList.last().length = pos - result.formatList.last().start; + result.formatList.append(curFmtRng); + } + } + result.formatList.last().length = s.length() - result.formatList.last().start; + if(result.formatList.last().length == 0) result.formatList.removeLast(); + result.plainText = s; + return result; +} + +QTextCharFormat UiStyle::mergedFormat(QList formatList) { + QTextCharFormat fmt; + foreach(FormatType ftype, formatList) { + fmt.merge(format(ftype)); + } + return fmt; +} diff --git a/src/uisupport/old-uistyle.h b/src/uisupport/old-uistyle.h new file mode 100644 index 00000000..7b58c12f --- /dev/null +++ b/src/uisupport/old-uistyle.h @@ -0,0 +1,83 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _OLD_UISTYLE_H_ +#define _OLD_UISTYLE_H_ + +#include +#include +#include + +#include "message.h" +#include "settings.h" + +class UiStyle { + + public: + UiStyle(const QString &settingsKey); + virtual ~UiStyle(); + + /** This enumerates the possible formats a text element may have. */ + enum FormatType { + None, Bold, Italic, Underline, Reverse, // Standard formats + PlainMsg, NoticeMsg, ServerMsg, ErrorMsg, JoinMsg, PartMsg, QuitMsg, KickMsg, // Internal message formats + RenameMsg, ModeMsg, ActionMsg, // ...cnt'd + Timestamp, Sender, Nick, Hostmask, ChannelName, ModeFlags, Url, // individual elements + FgCol00, FgCol01, FgCol02, FgCol03, FgCol04, FgCol05, FgCol06, FgCol07, // Color codes + FgCol08, FgCol09, FgCol10, FgCol11, FgCol12, FgCol13, FgCol14, FgCol15, + BgCol00, BgCol01, BgCol02, BgCol03, BgCol04, BgCol05, BgCol06, BgCol07, + BgCol08, BgCol09, BgCol10, BgCol11, BgCol12, BgCol13, BgCol14, BgCol15, + NumFormatTypes, Invalid // Do not add anything after this + }; + + struct UrlInfo { + int start, end; + QUrl url; + }; + + struct StyledText { + QString plainText; + QList formatList; + QList urls; + }; + + StyledText styleString(const QString &); + + void setFormat(FormatType, QTextCharFormat, Settings::Mode mode/* = Settings::Custom*/); + QTextCharFormat format(FormatType, Settings::Mode mode = Settings::Custom) const; + + FormatType formatType(const QString &code) const; + QString formatCode(FormatType) const; + + protected: + + + private: + QTextCharFormat mergedFormat(QList); + + QVector _defaultFormats; + QVector _customFormats; + QHash _formatCodes; + + QString _settingsKey; + +}; + +#endif diff --git a/src/uisupport/uistyle.cpp b/src/uisupport/uistyle.cpp index 94c9742b..10b25e7d 100644 --- a/src/uisupport/uistyle.cpp +++ b/src/uisupport/uistyle.cpp @@ -21,17 +21,24 @@ #include "uistyle.h" #include "uistylesettings.h" +#include "util.h" UiStyle::UiStyle(const QString &settingsKey) : _settingsKey(settingsKey) { - // Default format - QTextCharFormat def; - def.setForeground(QBrush("#000000")); - def.setFont(QFont("Monospace", QApplication::font().pointSize())); - def.font().setFixedPitch(true); - def.font().setStyleHint(QFont::TypeWriter); - _defaultFormats = QVector(NumFormatTypes, def); - _customFormats = QVector(NumFormatTypes, QTextFormat().toCharFormat()); + // register FormatList if that hasn't happened yet + // FIXME I don't think this actually avoids double registration... then again... does it hurt? + if(QVariant::nameToType("UiStyle::FormatList") == QVariant::Invalid) { + qRegisterMetaType("UiStyle::FormatList"); + qRegisterMetaTypeStreamOperators("UiStyle::FormatList"); + Q_ASSERT(QVariant::nameToType("UiStyle::FormatList") != QVariant::Invalid); + } + // Default format + _defaultPlainFormat.setForeground(QBrush("#000000")); + _defaultPlainFormat.setFont(QFont("Monospace", QApplication::font().pointSize())); + _defaultPlainFormat.font().setFixedPitch(true); + _defaultPlainFormat.font().setStyleHint(QFont::TypeWriter); + setFormat(None, _defaultPlainFormat, Settings::Default); + // Load saved custom formats UiStyleSettings s(_settingsKey); foreach(FormatType type, s.availableFormats()) { @@ -80,9 +87,6 @@ UiStyle::UiStyle(const QString &settingsKey) : _settingsKey(settingsKey) { QTextCharFormat fgf, bgf; fgf.setForeground(QBrush(QColor(colors[i]))); setFormat((FormatType)(FgCol00 + i), fgf, Settings::Default); bgf.setBackground(QBrush(QColor(colors[i]))); setFormat((FormatType)(BgCol00 + i), bgf, Settings::Default); - //FIXME fix the havoc caused by ColorSettingsPage - setFormat((FormatType)(FgCol00 + i), fgf, Settings::Custom); - setFormat((FormatType)(BgCol00 + i), bgf, Settings::Custom); } // Set a few more standard formats @@ -115,11 +119,35 @@ void UiStyle::setFormat(FormatType ftype, QTextCharFormat fmt, Settings::Mode mo s.removeCustomFormat(ftype); } } + // TODO: invalidate only affected cached formats... if that's possible with less overhead than just rebuilding them + _cachedFormats.clear(); } QTextCharFormat UiStyle::format(FormatType ftype, Settings::Mode mode) const { - if(mode == Settings::Custom && _customFormats[ftype].isValid()) return _customFormats[ftype]; - else return _defaultFormats[ftype]; + if(mode == Settings::Custom && _customFormats.contains(ftype)) return _customFormats.value(ftype); + else return _defaultFormats.value(ftype, QTextCharFormat()); +} + +// NOTE: This function is intimately tied to the values in FormatType. Don't change this +// until you _really_ know what you do! +QTextCharFormat UiStyle::mergedFormat(quint32 ftype) { + if(_cachedFormats.contains(ftype)) return _cachedFormats[ftype]; + if(ftype == Invalid) return QTextCharFormat(); + // Now we construct the merged format, starting with the default + QTextCharFormat fmt = format(None); + // First: general message format + fmt.merge(format((FormatType)(ftype & 0x0f))); + // now more specific ones + for(quint32 mask = 0x0010; mask <= 0x2000; mask <<= 1) { + if(ftype & mask) fmt.merge(format((FormatType)mask)); + } + // color codes! + if(ftype & 0x00400000) fmt.merge(format((FormatType)(ftype & 0x0f400000))); // foreground + if(ftype & 0x00800000) fmt.merge(format((FormatType)(ftype & 0xf0800000))); // background + // URL + if(ftype & Url) fmt.merge(format(Url)); + _cachedFormats[ftype] = fmt; + return fmt; } UiStyle::FormatType UiStyle::formatType(const QString & code) const { @@ -131,64 +159,38 @@ QString UiStyle::formatCode(FormatType ftype) const { return _formatCodes.key(ftype); } -UiStyle::StyledText UiStyle::styleString(const QString &_s) { - QString s = _s; - StyledText result; - QList fmtList; - fmtList.append(None); - QTextLayout::FormatRange curFmtRng; - curFmtRng.format = format(None); - curFmtRng.start = 0; - result.formats.append(curFmtRng); +// This method expects a well-formatted string, there is no error checking! +// Since we create those ourselves, we should be pretty safe that nobody does something crappy here. +UiStyle::StyledString UiStyle::styleString(const QString &s_) { + QString s = s_; + StyledString result; + result.formatList.append(qMakePair(0, (quint32)None)); + quint32 curfmt = (quint32)None; int pos = 0; int length = 0; - int fgCol = -1, bgCol = -1; // marks current mIRC color for(;;) { pos = s.indexOf('%', pos); if(pos < 0) break; - if(s[pos+1] == '%') { // escaped %, just remove one and continue + if(s[pos+1] == '%') { // escaped %, we just remove one and continue s.remove(pos, 1); pos++; continue; - } else if(s[pos+1] == 'D' && s[pos+2] == 'c') { // color code - if(s[pos+3] == '-') { // color off - if(fgCol >= 0) { - fmtList.removeAll((FormatType)(FgCol00 + fgCol)); - fgCol = -1; - } - if(bgCol >= 0) { - fmtList.removeAll((FormatType)(BgCol00 + bgCol)); - bgCol = -1; - } - curFmtRng.format = mergedFormat(fmtList); + } + if(s[pos+1] == 'D' && s[pos+2] == 'c') { // color code + if(s[pos+3] == '-') { // color off + curfmt &= 0x003fffff; length = 4; } else { int color = 10 * s[pos+4].digitValue() + s[pos+5].digitValue(); //TODO: use 99 as transparent color (re mirc color "standard") color &= 0x0f; - int *colptr; FormatType coltype; - if(s[pos+3] == 'f') { // foreground - colptr = &fgCol; coltype = FgCol00; - } else { // background - Q_ASSERT(s[pos+3] == 'b'); - colptr = &bgCol; coltype = BgCol00; - } - if(*colptr >= 0) { - // color already set, remove format code and add new one - Q_ASSERT(fmtList.contains((FormatType)(coltype + *colptr))); - fmtList.removeAll((FormatType)(coltype + *colptr)); - fmtList.append((FormatType)(coltype + color)); - curFmtRng.format = mergedFormat(fmtList); - } else { - fmtList.append((FormatType)(coltype + color)); - curFmtRng.format.merge(format(fmtList.last())); - } - *colptr = color; + if(pos+3 == 'f') + curfmt |= (color << 24) | 0x00400000; + else + curfmt |= (color << 28) | 0x00800000; length = 6; } } else if(s[pos+1] == 'O') { // reset formatting - fmtList.clear(); fmtList.append(None); - curFmtRng.format = format(None); - fgCol = bgCol = -1; + curfmt &= 0x0000000f; // we keep message type-specific formatting length = 2; } else if(s[pos+1] == 'R') { // reverse // TODO: implement reverse formatting @@ -202,41 +204,143 @@ UiStyle::StyledText UiStyle::styleString(const QString &_s) { qWarning(qPrintable(QString("Invalid format code in string: %1").arg(s))); continue; } - //Q_ASSERT(ftype != Invalid); + curfmt ^= ftype; length = code.length(); - if(!fmtList.contains(ftype)) { - // toggle it on - fmtList.append(ftype); - curFmtRng.format.merge(format(ftype)); - } else { - // toggle it off - fmtList.removeAll(ftype); - curFmtRng.format = mergedFormat(fmtList); - } } - s.remove(pos, length); // remove format code from string - // now see if something changed and else insert the format - if(curFmtRng.format == result.formats.last().format) continue; // no change, so we just ignore - curFmtRng.start = pos; - if(pos == result.formats.last().start) { - // same starting point -> we just overwrite the old format - result.formats.last() = curFmtRng; + s.remove(pos, length); + if(pos == result.formatList.last().first) + result.formatList.last().second = curfmt; + else + result.formatList.append(qMakePair(pos, curfmt)); + } + result.plainText = s; + return result; +} + +QString UiStyle::mircToInternal(const QString &mirc_) { + QString mirc = mirc_; + mirc.replace('%', "%%"); // escape % just to be sure + mirc.replace('\x02', "%B"); + mirc.replace('\x0f', "%O"); + mirc.replace('\x12', "%R"); + mirc.replace('\x16', "%R"); + mirc.replace('\x1d', "%S"); + mirc.replace('\x1f', "%U"); + + // Now we bring the color codes (\x03) in a sane format that can be parsed more easily later. + // %Dcfxx is foreground, %Dcbxx is background color, where xx is a 2 digit dec number denoting the color code. + // %Dc- turns color off. + // Note: We use the "mirc standard" as described in . + // This means that we don't accept something like \x03,5 (even though others, like WeeChat, do). + int pos = 0; + for(;;) { + pos = mirc.indexOf('\x03', pos); + if(pos < 0) break; // no more mirc color codes + QString ins, num; + int l = mirc.length(); + int i = pos + 1; + // check for fg color + if(i < l && mirc[i].isDigit()) { + num = mirc[i++]; + if(i < l && mirc[i].isDigit()) num.append(mirc[i++]); + else num.prepend('0'); + ins = QString("%Dcf%1").arg(num); + + if(i+1 < l && mirc[i] == ',' && mirc[i+1].isDigit()) { + i++; + num = mirc[i++]; + if(i < l && mirc[i].isDigit()) num.append(mirc[i++]); + else num.prepend('0'); + ins += QString("%Dcb%1").arg(num); + } } else { - // fix length of last format - result.formats.last().length = pos - result.formats.last().start; - result.formats.append(curFmtRng); + ins = "%Dc-"; } + mirc.replace(pos, i-pos, ins); } - result.formats.last().length = s.length() - result.formats.last().start; - if(result.formats.last().length == 0) result.formats.removeLast(); - result.text = s; + return mirc; +} + +UiStyle::StyledMessage UiStyle::styleMessage(const Message &msg) { + QString user = userFromMask(msg.sender()); + QString host = hostFromMask(msg.sender()); + QString nick = nickFromMask(msg.sender()); + QString txt = mircToInternal(msg.contents()); + QString bufferName = msg.bufferInfo().bufferName(); + + StyledMessage result; + + result.timestamp = styleString(tr("%DT[%1]").arg(msg.timestamp().toLocalTime().toString("hh:mm:ss"))); + + QString s, t; + switch(msg.type()) { + case Message::Plain: + s = tr("%DS<%1>").arg(nick); t = tr("%D0%1").arg(txt); break; + case Message::Notice: + s = tr("%Dn[%1]").arg(nick); t = tr("%Dn%1").arg(txt); break; + case Message::Server: + s = tr("%Ds*"); t = tr("%Ds%1").arg(txt); break; + case Message::Error: + s = tr("%De*"); t = tr("%De%1").arg(txt); break; + case Message::Join: + s = tr("%Dj-->"); t = tr("%Dj%DN%1%DN %DH(%2@%3)%DH has joined %DC%4%DC").arg(nick, user, host, bufferName); break; + case Message::Part: + s = tr("%Dp<--"); t = tr("%Dp%DN%1%DN %DH(%2@%3)%DH has left %DC%4%DC").arg(nick, user, host, bufferName); + if(!txt.isEmpty()) t = QString("%1 (%2)").arg(t).arg(txt); + break; + case Message::Quit: + s = tr("%Dq<--"); t = tr("%Dq%DN%DU%1%DU%DN %DH(%2@%3)%DH has quit").arg(nick, user, host); + if(!txt.isEmpty()) t = QString("%1 (%2)").arg(t).arg(txt); + break; + case Message::Kick: + { s = tr("%Dk<-*"); + QString victim = txt.section(" ", 0, 0); + //if(victim == ui.ownNick->currentText()) victim = tr("you"); + QString kickmsg = txt.section(" ", 1); + t = tr("%Dk%DN%1%DN has kicked %DN%2%DN from %DC%3%DC").arg(nick).arg(victim).arg(bufferName); + if(!kickmsg.isEmpty()) t = QString("%1 (%2)").arg(t).arg(kickmsg); + } + break; + case Message::Nick: + s = tr("%Dr<->"); + if(nick == msg.contents()) t = tr("%DrYou are now known as %DN%1%DN").arg(txt); + else t = tr("%Dr%DN%1%DN is now known as %DN%2%DN").arg(nick, txt); + break; + case Message::Mode: + s = tr("%Dm***"); + if(nick.isEmpty()) t = tr("%DmUser mode: %DM%1%DM").arg(txt); + else t = tr("%DmMode %DM%1%DM by %DN%2%DN").arg(txt, nick); + break; + case Message::Action: + s = tr("%Da-*-"); + t = tr("%Da%DN%1%DN %2").arg(nick).arg(txt); + break; + default: + s = tr("%De%1").arg(msg.sender()); + t = tr("%De[%1]").arg(txt); + } + result.sender = styleString(s); + result.contents = styleString(t); return result; } -QTextCharFormat UiStyle::mergedFormat(QList formatList) { - QTextCharFormat fmt; - foreach(FormatType ftype, formatList) { - fmt.merge(format(ftype)); +QDataStream &operator<<(QDataStream &out, const UiStyle::FormatList &formatList) { + out << formatList.count(); + UiStyle::FormatList::const_iterator it = formatList.begin(); + while(it != formatList.end()) { + out << (*it).first << (*it).second; + ++it; } - return fmt; + return out; +} + +QDataStream &operator>>(QDataStream &in, UiStyle::FormatList &formatList) { + int cnt; + in >> cnt; + for(int i = 0; i < cnt; i++) { + int pos; quint32 ftype; + in >> pos >> ftype; + formatList.append(qMakePair(pos, ftype)); + } + return in; } diff --git a/src/uisupport/uistyle.h b/src/uisupport/uistyle.h index c722be82..426b398e 100644 --- a/src/uisupport/uistyle.h +++ b/src/uisupport/uistyle.h @@ -21,6 +21,11 @@ #ifndef _UISTYLE_H_ #define _UISTYLE_H_ +#ifndef SPUTDEV +# include "old-uistyle.h" +#else + +#include #include #include #include @@ -29,22 +34,85 @@ #include "settings.h" class UiStyle { + Q_DECLARE_TR_FUNCTIONS (UiStyle); public: UiStyle(const QString &settingsKey); virtual ~UiStyle(); - /** This enumerates the possible formats a text element may have. */ + typedef QList > FormatList; + + //! This enumerates the possible formats a text element may have. */ + /** These formats are ordered on increasing importance, in cases where a given property is specified + * by multiple active formats. + * \NOTE: Do not change/add values here without also adapting the relevant + * methods in this class (in particular mergedFormat())! + * Also, we _do_ rely on certain properties of these values in styleString() and friends! + */ enum FormatType { - None, Bold, Italic, Underline, Reverse, // Standard formats - PlainMsg, NoticeMsg, ServerMsg, ErrorMsg, JoinMsg, PartMsg, QuitMsg, KickMsg, // Internal message formats - RenameMsg, ModeMsg, ActionMsg, // ...cnt'd - Timestamp, Sender, Nick, Hostmask, ChannelName, ModeFlags, Url, // individual elements - FgCol00, FgCol01, FgCol02, FgCol03, FgCol04, FgCol05, FgCol06, FgCol07, // Color codes - FgCol08, FgCol09, FgCol10, FgCol11, FgCol12, FgCol13, FgCol14, FgCol15, - BgCol00, BgCol01, BgCol02, BgCol03, BgCol04, BgCol05, BgCol06, BgCol07, - BgCol08, BgCol09, BgCol10, BgCol11, BgCol12, BgCol13, BgCol14, BgCol15, - NumFormatTypes, Invalid // Do not add anything after this + None = 0x00000000, + Invalid = 0x11111111, + // Message Formats (mutually exclusive!) + PlainMsg = 0x00000001, + NoticeMsg = 0x00000002, + ServerMsg = 0x00000003, + ErrorMsg = 0x00000004, + JoinMsg = 0x00000005, + PartMsg = 0x00000006, + QuitMsg = 0x00000007, + KickMsg = 0x00000008, + RenameMsg = 0x00000009, + ModeMsg = 0x0000000a, + ActionMsg = 0x0000000b, + // Standard Formats + Bold = 0x00000010, + Italic = 0x00000020, + Underline = 0x00000040, + Reverse = 0x00000080, + // Individual parts of a message + Timestamp = 0x00000100, + Sender = 0x00000200, + Nick = 0x00000400, + Hostmask = 0x00000800, + ChannelName = 0x00001000, + ModeFlags = 0x00002000, + // URL is special, we want that to take precedence over the rest... + Url = 0x00100000, + // Colors + FgCol00 = 0x00400000, + FgCol01 = 0x01400000, + FgCol02 = 0x02400000, + FgCol03 = 0x03400000, + FgCol04 = 0x04400000, + FgCol05 = 0x05400000, + FgCol06 = 0x06400000, + FgCol07 = 0x07400000, + FgCol08 = 0x08400000, + FgCol09 = 0x09400000, + FgCol10 = 0x0a400000, + FgCol11 = 0x0b400000, + FgCol12 = 0x0c400000, + FgCol13 = 0x0d400000, + FgCol14 = 0x0e400000, + FgCol15 = 0x0f400000, + + BgCol00 = 0x00800000, + BgCol01 = 0x10800000, + BgCol02 = 0x20800000, + BgCol03 = 0x30800000, + BgCol04 = 0x40800000, + BgCol05 = 0x50800000, + BgCol06 = 0x60800000, + BgCol07 = 0x70800000, + BgCol08 = 0x80800000, + BgCol09 = 0x90800000, + BgCol10 = 0xa0800000, + BgCol11 = 0xb0800000, + BgCol12 = 0xc0800000, + BgCol13 = 0xd0800000, + BgCol14 = 0xe0800000, + BgCol15 = 0xf0800000 + }; struct UrlInfo { @@ -52,16 +120,23 @@ class UiStyle { QUrl url; }; - struct StyledText { - QString text; - QList formats; - QList urls; + struct StyledString { + QString plainText; + FormatList formatList; // starting pos, ftypes + }; + + struct StyledMessage { + StyledString timestamp; + StyledString sender; + StyledString contents; }; - StyledText styleString(const QString &); + StyledString styleString(const QString &); + StyledMessage styleMessage(const Message &); void setFormat(FormatType, QTextCharFormat, Settings::Mode mode/* = Settings::Custom*/); QTextCharFormat format(FormatType, Settings::Mode mode = Settings::Custom) const; + QTextCharFormat mergedFormat(quint32 formatType); FormatType formatType(const QString &code) const; QString formatCode(FormatType) const; @@ -70,14 +145,21 @@ class UiStyle { private: - QTextCharFormat mergedFormat(QList); + QString mircToInternal(const QString &); - QVector _defaultFormats; - QVector _customFormats; + QTextCharFormat _defaultPlainFormat; + QHash _defaultFormats; + QHash _customFormats; + QHash _cachedFormats; QHash _formatCodes; QString _settingsKey; - }; +QDataStream &operator<<(QDataStream &out, const UiStyle::FormatList &formatList); +QDataStream &operator>>(QDataStream &in, UiStyle::FormatList &formatList); + +Q_DECLARE_METATYPE(UiStyle::FormatList); + +#endif // SPUTDEV #endif diff --git a/src/uisupport/uisupport.pri b/src/uisupport/uisupport.pri index 1f5de7f0..d23c4082 100644 --- a/src/uisupport/uisupport.pri +++ b/src/uisupport/uisupport.pri @@ -6,6 +6,13 @@ SRCS += abstractbuffercontainer.cpp abstractitemview.cpp bufferview.cpp buffervi HDRS += abstractbuffercontainer.h abstractitemview.h bufferview.h bufferviewfilter.h clearablelineedit.h colorbutton.h \ nickviewfilter.h inputline.h nickview.h settingspage.h tabcompleter.h uisettings.h uistyle.h uistylesettings.h +!sputdev { + SRCS += old-uistyle.cpp + SRCS -= uistyle.cpp + HDRS += old-uistyle.h + HDRS -= uistyle.h +} + FORMNAMES = for(ui, FORMNAMES) { diff --git a/version.inc b/version.inc index 44d28ebf..8a4fbd8a 100644 --- a/version.inc +++ b/version.inc @@ -3,7 +3,7 @@ { using namespace Global; - quasselVersion = "0.2.0-beta2-pre"; + quasselVersion = "0.3.0-pre"; quasselDate = "2008-05-09"; quasselBuild = 827;