Chat service:

- Added send time to ChatInfo.

Chat:
- Reworked IMHistoryKeeper to save only needed data as raw data (not formatted from PeersDialog).
- Renamed the public chat history file from "his1.xml" to "chatPublic.xml" and moved it from data dir to config dir. The current history is lost. Please delete the file "his1.xml" manually.
- Optimized save of the history. Save only when changed, also during the runtime.
- Clear the history in PeersDialog clears the IMHistoryKeeper too.
- New setting to send chat message with Ctrl+Return. Changed the check for Enter in PeersDialog and PopupChatDialog from textChanged to eventFilter.
- Smileys are inserted at the current cursor position, not added at the end.
- Don't send emty messages.

New class ChatStyle:
- Created a new class for the work with chat styles and smileys.
- Currently only two internal styles are available - private and public. Later more external styles planned.
- Moved functions for loading and showing the emoticons from PeersDialog and PopupChatDialog to the new class.

Private chat:
- Split private chat style into incoming.htm and outgoing.htm.
- Removed style change.

Public chat:
- New chat style incoming.htm, outgoing.htm, hincoming.htm and houtgoing.htm.

Chat feed:
- Show links and emoticons if they are enabled for public chat.

PeersDialog:
- Show the own name and location only once at start and not with QTimer every 1.5 second.

git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@3441 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
thunder2 2010-09-04 14:23:30 +00:00
parent 73f3fa3223
commit 8213a2aa77
33 changed files with 1167 additions and 1061 deletions

View file

@ -127,6 +127,7 @@ class ChatInfo
public: public:
std::string rsid; std::string rsid;
unsigned int chatflags; unsigned int chatflags;
uint32_t sendTime;
std::wstring msg; std::wstring msg;
}; };

View file

@ -529,9 +529,10 @@ bool p3ChatService::getPrivateChatQueue(std::string id, std::list<ChatInfo> &cha
void p3ChatService::initRsChatInfo(RsChatMsgItem *c, ChatInfo &i) void p3ChatService::initRsChatInfo(RsChatMsgItem *c, ChatInfo &i)
{ {
i.rsid = c -> PeerId(); i.rsid = c->PeerId();
i.chatflags = 0 ; i.chatflags = 0;
i.msg = c -> message; i.sendTime =c->sendTime;
i.msg = c->message;
if (c -> chatFlags & RS_CHAT_FLAG_PRIVATE) if (c -> chatFlags & RS_CHAT_FLAG_PRIVATE)
{ {

View file

@ -235,6 +235,7 @@ HEADERS += rshare.h \
gui/profile/StatusMessage.h \ gui/profile/StatusMessage.h \
gui/chat/PopupChatDialog.h \ gui/chat/PopupChatDialog.h \
gui/chat/HandleRichText.h \ gui/chat/HandleRichText.h \
gui/chat/ChatStyle.h \
gui/channels/CreateChannel.h \ gui/channels/CreateChannel.h \
gui/channels/ChannelDetails.h \ gui/channels/ChannelDetails.h \
gui/channels/CreateChannelMsg.h \ gui/channels/CreateChannelMsg.h \
@ -453,6 +454,7 @@ SOURCES += main.cpp \
gui/channels/ShareKey.cpp \ gui/channels/ShareKey.cpp \
gui/chat/PopupChatDialog.cpp \ gui/chat/PopupChatDialog.cpp \
gui/chat/HandleRichText.cpp \ gui/chat/HandleRichText.cpp \
gui/chat/ChatStyle.cpp \
gui/connect/ConfCertDialog.cpp \ gui/connect/ConfCertDialog.cpp \
gui/msgs/MessageComposer.cpp \ gui/msgs/MessageComposer.cpp \
gui/common/vmessagebox.cpp \ gui/common/vmessagebox.cpp \

View file

@ -24,7 +24,6 @@
#include <QShortcut> #include <QShortcut>
#include <QWidgetAction> #include <QWidgetAction>
#include <QScrollBar> #include <QScrollBar>
#include <QDesktopWidget>
#include <QColorDialog> #include <QColorDialog>
#include <QFontDialog> #include <QFontDialog>
#include <QDropEvent> #include <QDropEvent>
@ -32,7 +31,7 @@
#include "common/vmessagebox.h" #include "common/vmessagebox.h"
#include <gui/mainpagestack.h> #include <gui/mainpagestack.h>
#include "rshare.h" #include "retroshare/rsinit.h"
#include "PeersDialog.h" #include "PeersDialog.h"
#include <retroshare/rsiface.h> #include <retroshare/rsiface.h>
#include <retroshare/rspeers.h> #include <retroshare/rspeers.h>
@ -139,127 +138,134 @@ private:
/** Constructor */ /** Constructor */
PeersDialog::PeersDialog(QWidget *parent) PeersDialog::PeersDialog(QWidget *parent)
: RsAutoUpdatePage(1500,parent), : RsAutoUpdatePage(1500,parent)
historyKeeper(Rshare::dataDirectory() + "/his1.xml"),
smWidget(0)
{ {
/* Invoke the Qt Designer generated object setup routine */ /* Invoke the Qt Designer generated object setup routine */
ui.setupUi(this); ui.setupUi(this);
last_status_send_time = 0 ;
last_status_send_time = 0 ;
connect( ui.peertreeWidget, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( peertreeWidgetCostumPopupMenu( QPoint ) ) ); connect( ui.peertreeWidget, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( peertreeWidgetCostumPopupMenu( QPoint ) ) );
connect( ui.peertreeWidget, SIGNAL( itemDoubleClicked ( QTreeWidgetItem *, int)), this, SLOT(chatfriend(QTreeWidgetItem *))); connect( ui.peertreeWidget, SIGNAL( itemDoubleClicked ( QTreeWidgetItem *, int)), this, SLOT(chatfriend(QTreeWidgetItem *)));
connect( ui.avatartoolButton, SIGNAL(clicked()), SLOT(getAvatar())); connect( ui.avatartoolButton, SIGNAL(clicked()), SLOT(getAvatar()));
connect( ui.mypersonalstatuslabel, SIGNAL(clicked()), SLOT(statusmessage())); connect( ui.mypersonalstatuslabel, SIGNAL(clicked()), SLOT(statusmessage()));
connect( ui.actionSet_your_Avatar, SIGNAL(triggered()), this, SLOT(getAvatar())); connect( ui.actionSet_your_Avatar, SIGNAL(triggered()), this, SLOT(getAvatar()));
connect( ui.actionSet_your_Personal_Message, SIGNAL(triggered()), this, SLOT(statusmessage())); connect( ui.actionSet_your_Personal_Message, SIGNAL(triggered()), this, SLOT(statusmessage()));
connect( ui.addfileButton, SIGNAL(clicked() ), this , SLOT(addExtraFile())); connect( ui.addfileButton, SIGNAL(clicked() ), this , SLOT(addExtraFile()));
connect( ui.msgText, SIGNAL(anchorClicked(const QUrl &)), SLOT(anchorClicked(const QUrl &))); connect( ui.msgText, SIGNAL(anchorClicked(const QUrl &)), SLOT(anchorClicked(const QUrl &)));
connect(ui.action_Hide_Offline_Friends, SIGNAL(triggered()), this, SLOT(insertPeers())); connect(ui.action_Hide_Offline_Friends, SIGNAL(triggered()), this, SLOT(insertPeers()));
connect(ui.action_Hide_Status_Column, SIGNAL(triggered()), this, SLOT(statusColumn())); connect(ui.action_Hide_Status_Column, SIGNAL(triggered()), this, SLOT(statusColumn()));
ui.peertabWidget->setTabPosition(QTabWidget::North); ui.peertabWidget->setTabPosition(QTabWidget::North);
ui.peertabWidget->addTab(new ProfileWidget(),QString(tr("Profile"))); ui.peertabWidget->addTab(new ProfileWidget(),QString(tr("Profile")));
ui.peertabWidget->addTab(new NewsFeed(),QString(tr("Friends Storm"))); ui.peertabWidget->addTab(new NewsFeed(),QString(tr("Friends Storm")));
ui.peertreeWidget->setColumnCount(4); ui.peertreeWidget->setColumnCount(4);
ui.peertreeWidget->setColumnHidden ( 3, true); ui.peertreeWidget->setColumnHidden ( 3, true);
ui.peertreeWidget->setColumnHidden ( 2, true); ui.peertreeWidget->setColumnHidden ( 2, true);
ui.peertreeWidget->sortItems( 0, Qt::AscendingOrder ); ui.peertreeWidget->sortItems( 0, Qt::AscendingOrder );
// set header text aligment // set header text aligment
QTreeWidgetItem * headerItem = ui.peertreeWidget->headerItem(); QTreeWidgetItem * headerItem = ui.peertreeWidget->headerItem();
headerItem->setTextAlignment(COLUMN_NAME, Qt::AlignHCenter | Qt::AlignVCenter); headerItem->setTextAlignment(COLUMN_NAME, Qt::AlignHCenter | Qt::AlignVCenter);
headerItem->setTextAlignment(COLUMN_STATE, Qt::AlignLeft | Qt::AlignVCenter); headerItem->setTextAlignment(COLUMN_STATE, Qt::AlignLeft | Qt::AlignVCenter);
headerItem->setTextAlignment(COLUMN_INFO, Qt::AlignHCenter | Qt::AlignVCenter); headerItem->setTextAlignment(COLUMN_INFO, Qt::AlignHCenter | Qt::AlignVCenter);
connect(ui.lineEdit, SIGNAL(textChanged ( ) ), this, SLOT(checkChat( ) )); connect(ui.Sendbtn, SIGNAL(clicked()), this, SLOT(sendMsg()));
connect(ui.Sendbtn, SIGNAL(clicked()), this, SLOT(sendMsg())); connect(ui.emoticonBtn, SIGNAL(clicked()), this, SLOT(smileyWidgetgroupchat()));
connect(ui.emoticonBtn, SIGNAL(clicked()), this, SLOT(smileyWidgetgroupchat()));
ui.lineEdit->setContextMenuPolicy(Qt::CustomContextMenu) ; ui.lineEdit->setContextMenuPolicy(Qt::CustomContextMenu) ;
connect(ui.lineEdit,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(contextMenu(QPoint))); connect(ui.lineEdit,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(contextMenu(QPoint)));
pasteLinkAct = new QAction(QIcon(":/images/pasterslink.png"), tr( "Paste retroshare Link" ), this ); pasteLinkAct = new QAction(QIcon(":/images/pasterslink.png"), tr( "Paste retroshare Link" ), this );
connect( pasteLinkAct , SIGNAL( triggered() ), this, SLOT( pasteLink() ) ); connect( pasteLinkAct , SIGNAL( triggered() ), this, SLOT( pasteLink() ) );
connect( ui.msgText, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayInfoChatMenu(const QPoint&))); connect( ui.msgText, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayInfoChatMenu(const QPoint&)));
connect(ui.textboldChatButton, SIGNAL(clicked()), this, SLOT(setFont())); connect(ui.textboldChatButton, SIGNAL(clicked()), this, SLOT(setFont()));
connect(ui.textunderlineChatButton, SIGNAL(clicked()), this, SLOT(setFont())); connect(ui.textunderlineChatButton, SIGNAL(clicked()), this, SLOT(setFont()));
connect(ui.textitalicChatButton, SIGNAL(clicked()), this, SLOT(setFont())); connect(ui.textitalicChatButton, SIGNAL(clicked()), this, SLOT(setFont()));
connect(ui.fontsButton, SIGNAL(clicked()), this, SLOT(getFont())); connect(ui.fontsButton, SIGNAL(clicked()), this, SLOT(getFont()));
connect(ui.colorChatButton, SIGNAL(clicked()), this, SLOT(setColor())); connect(ui.colorChatButton, SIGNAL(clicked()), this, SLOT(setColor()));
connect(ui.actionSave_History, SIGNAL(triggered()), this, SLOT(fileSaveAs())); connect(ui.actionSave_History, SIGNAL(triggered()), this, SLOT(fileSaveAs()));
ui.fontsButton->setIcon(QIcon(QString(":/images/fonts.png"))); ui.fontsButton->setIcon(QIcon(QString(":/images/fonts.png")));
_currentColor = Qt::black; _currentColor = Qt::black;
QPixmap pxm(16,16);
pxm.fill(_currentColor);
ui.colorChatButton->setIcon(pxm);
Settings->beginGroup(QString("Chat")); QPixmap pxm(16,16);
mCurrentFont.fromString(Settings->value(QString::fromUtf8("ChatScreenFont")).toString()); pxm.fill(_currentColor);
ui.lineEdit->setFont(mCurrentFont); ui.colorChatButton->setIcon(pxm);
setChatInfo(tr("Welcome to RetroShare's group chat."), QString::fromUtf8("blue"));
if (Settings->value(QString::fromUtf8("GroupChat_History"), true).toBool()) mCurrentFont.fromString(Settings->valueFromGroup("Chat", QString::fromUtf8("ChatScreenFont")).toString());
{ ui.lineEdit->setFont(mCurrentFont);
QStringList him;
historyKeeper.getMessages(him, "", "THIS", 8);
foreach(QString mess, him)
ui.msgText->append(mess);
}
Settings->endGroup();
//setChatInfo(mess, "green"); style.setStylePath(":/qss/chat/public");
style.loadEmoticons();
QMenu * grpchatmenu = new QMenu(); setChatInfo(tr("Welcome to RetroShare's group chat."), QString::fromUtf8("blue"));
grpchatmenu->addAction(ui.actionClearChat);
grpchatmenu->addAction(ui.actionSave_History);
grpchatmenu->addAction(ui.actionMessageHistory);
ui.menuButton->setMenu(grpchatmenu);
_underline = false; if (Settings->valueFromGroup("Chat", QString::fromUtf8("GroupChat_History"), true).toBool()) {
historyKeeper.init(QString::fromStdString(RsInit::RsProfileConfigDirectory()) + "/chatPublic.xml");
QMenu *menu = new QMenu(); QList<IMHistoryItem> historyItems;
menu->addAction(ui.actionAdd_Friend); historyKeeper.getMessages(historyItems, 20);
menu->addSeparator(); foreach(IMHistoryItem item, historyItems) {
menu->addAction(ui.actionCreate_New_Forum); addChatMsg(item.incoming, true, item.name, item.sendTime, item.messageText);
#ifndef RS_RELEASE_VERSION }
menu->addAction(ui.actionCreate_New_Channel); }
#endif
menu->addAction(ui.actionSet_your_Avatar);
menu->addAction(ui.actionSet_your_Personal_Message);
ui.menupushButton->setMenu(menu);
//ui.msgText->setOpenExternalLinks ( false );
//ui.msgText->setOpenLinks ( false );
setAcceptDrops(true);
ui.lineEdit->setAcceptDrops(false);
updateAvatar();
loadmypersonalstatus();
loadEmoticonsgroupchat();
displayMenu();
// load settings QMenu * grpchatmenu = new QMenu();
processSettings(true); grpchatmenu->addAction(ui.actionClearChat);
grpchatmenu->addAction(ui.actionSave_History);
grpchatmenu->addAction(ui.actionMessageHistory);
ui.menuButton->setMenu(grpchatmenu);
// workaround for Qt bug, should be solved in next Qt release 4.7.0 _underline = false;
// http://bugreports.qt.nokia.com/browse/QTBUG-8270
QShortcut *Shortcut = new QShortcut(QKeySequence (Qt::Key_Delete), ui.peertreeWidget, 0, 0, Qt::WidgetShortcut);
connect(Shortcut, SIGNAL(activated()), this, SLOT( removefriend ()));
/* Hide platform specific features */ QMenu *menu = new QMenu();
menu->addAction(ui.actionAdd_Friend);
menu->addSeparator();
menu->addAction(ui.actionCreate_New_Forum);
#ifndef RS_RELEASE_VERSION
menu->addAction(ui.actionCreate_New_Channel);
#endif
menu->addAction(ui.actionSet_your_Avatar);
menu->addAction(ui.actionSet_your_Personal_Message);
ui.menupushButton->setMenu(menu);
//ui.msgText->setOpenExternalLinks ( false );
//ui.msgText->setOpenLinks ( false );
setAcceptDrops(true);
ui.lineEdit->setAcceptDrops(false);
updateAvatar();
loadmypersonalstatus();
displayMenu();
// load settings
processSettings(true);
// workaround for Qt bug, should be solved in next Qt release 4.7.0
// http://bugreports.qt.nokia.com/browse/QTBUG-8270
QShortcut *Shortcut = new QShortcut(QKeySequence (Qt::Key_Delete), ui.peertreeWidget, 0, 0, Qt::WidgetShortcut);
connect(Shortcut, SIGNAL(activated()), this, SLOT( removefriend ()));
ui.lineEdit->installEventFilter(this);
// add self nick and Avatar to Friends.
RsPeerDetails pd ;
if (rsPeers->getPeerDetails(rsPeers->getOwnId(),pd)) {
QString titleStr("<span style=\"font-size:16pt; font-weight:500;"
"color:#32cd32;\">%1</span>");
ui.nicklabel->setText(titleStr.arg(QString::fromStdString(pd.name) + tr(" (me)") + QString::fromStdString(pd.location)));
}
/* Hide platform specific features */
#ifdef Q_WS_WIN #ifdef Q_WS_WIN
#endif #endif
@ -269,8 +275,6 @@ PeersDialog::~PeersDialog ()
{ {
// save settings // save settings
processSettings(false); processSettings(false);
delete smWidget;
} }
void PeersDialog::processSettings(bool bLoad) void PeersDialog::processSettings(bool bLoad)
@ -314,6 +318,17 @@ void PeersDialog::processSettings(bool bLoad)
Settings->endGroup(); Settings->endGroup();
} }
void PeersDialog::showEvent(QShowEvent *event)
{
static bool first = true;
if (first) {
// Workaround: now the scroll position is correct calculated
first = false;
QScrollBar *scrollbar = ui.msgText->verticalScrollBar();
scrollbar->setValue(scrollbar->maximum());
}
}
void PeersDialog::pasteLink() void PeersDialog::pasteLink()
{ {
ui.lineEdit->insertHtml(RSLinkClipboard::toHtml()) ; ui.lineEdit->insertHtml(RSLinkClipboard::toHtml()) ;
@ -468,15 +483,7 @@ void PeersDialog::peertreeWidgetCostumPopupMenu( QPoint point )
void PeersDialog::updateDisplay() void PeersDialog::updateDisplay()
{ {
// add self nick and Avatar to Friends. insertPeers() ;
RsPeerDetails pd ;
if (rsPeers->getPeerDetails(rsPeers->getOwnId(),pd)) {
QString titleStr("<span style=\"font-size:16pt; font-weight:500;"
"color:#32cd32;\">%1</span>");
ui.nicklabel->setText(titleStr.arg(QString::fromStdString(pd.name) + tr(" (me)") + QString::fromStdString(pd.location))) ;
}
insertPeers() ;
} }
/* get the list of peers from the RsIface. */ /* get the list of peers from the RsIface. */
@ -1087,6 +1094,34 @@ void PeersDialog::publicChatChanged(int type)
} }
} }
void PeersDialog::addChatMsg(bool incoming, bool history, QString &name, QDateTime &sendTime, QString &message)
{
unsigned int formatFlag = CHAT_FORMATMSG_EMBED_LINKS;
// embed smileys ?
if (Settings->valueFromGroup(QString("Chat"), QString::fromUtf8("Emoteicons_GroupChat"), true).toBool()) {
formatFlag |= CHAT_FORMATMSG_EMBED_SMILEYS;
}
ChatStyle::enumFormatMessage type;
if (incoming) {
if (history) {
type = ChatStyle::FORMATMSG_HINCOMING;
} else {
type = ChatStyle::FORMATMSG_INCOMING;
}
} else {
if (history) {
type = ChatStyle::FORMATMSG_HOUTGOING;
} else {
type = ChatStyle::FORMATMSG_OUTGOING;
}
}
QString formatMsg = style.formatMessage(type, name, sendTime, message, formatFlag);
ui.msgText->append(formatMsg);
}
void PeersDialog::insertChat() void PeersDialog::insertChat()
{ {
std::list<ChatInfo> newchat; std::list<ChatInfo> newchat;
@ -1100,19 +1135,11 @@ void PeersDialog::insertChat()
#ifdef PEERS_DEBUG #ifdef PEERS_DEBUG
std::cerr << "got new chat." << std::endl; std::cerr << "got new chat." << std::endl;
#endif #endif
QTextEdit *msgWidget = ui.msgText;
std::list<ChatInfo>::iterator it; std::list<ChatInfo>::iterator it;
/* add in lines at the bottom */ /* add in lines at the bottom */
for(it = newchat.begin(); it != newchat.end(); it++) for(it = newchat.begin(); it != newchat.end(); it++)
{ {
std::string msg(it->msg.begin(), it->msg.end());
#ifdef PEERS_DEBUG
std::cerr << "PeersDialog::insertChat(): " << msg << std::endl;
#endif
std::string peer_name = rsPeers->getPeerName(it->rsid);
/* are they private? */ /* are they private? */
if (it->chatflags & RS_CHAT_PRIVATE) if (it->chatflags & RS_CHAT_PRIVATE)
{ {
@ -1120,95 +1147,79 @@ void PeersDialog::insertChat()
continue; continue;
} }
std::ostringstream out; QDateTime sendTime = QDateTime::fromTime_t(it->sendTime);
QString extraTxt; QString name = QString::fromStdString(rsPeers->getPeerName(it->rsid));
QString msg = QString::fromStdWString(it->msg);
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss"); #ifdef PEERS_DEBUG
QString name = QString::fromStdString(peer_name); std::cerr << "PeersDialog::insertChat(): " << msg << std::endl;
QString line = "<span style=\"color:#C00000\">" + timestamp + "</span>" + #endif
"<span style=\"color:#2D84C9\"><strong>" + " " + name + "</strong></span>";
QString msgContents = QString::fromStdWString(it->msg);
//std::cerr << "PeersDialog::insertChat(): 1.11\n"; bool incoming = false;
historyKeeper.addMessage(name, "THIS", msgContents);
//std::cerr << "PeersDialog::insertChat(): 1.12\n";
extraTxt += line;
// notify with a systray icon msg // notify with a systray icon msg
if(it->rsid != rsPeers->getOwnId()) if(it->rsid != rsPeers->getOwnId())
{ {
incoming = true;
// This is a trick to translate HTML into text. // This is a trick to translate HTML into text.
QTextEdit editor ; QTextEdit editor;
editor.setHtml(QString::fromStdWString(it->msg)); editor.setHtml(msg);
QString notifyMsg(name+": "+editor.toPlainText()) ; QString notifyMsg = name + ": " + editor.toPlainText();
if(notifyMsg.length() > 30) if(notifyMsg.length() > 30)
emit notifyGroupChat(QString("New group chat"), notifyMsg.left(30)+QString("...")); emit notifyGroupChat(QString("New group chat"), notifyMsg.left(30) + QString("..."));
else else
emit notifyGroupChat(QString("New group chat"), notifyMsg); emit notifyGroupChat(QString("New group chat"), notifyMsg);
} }
// create a DOM tree object from the message and embed contents with HTML tags historyKeeper.addMessage(incoming, it->rsid, name, sendTime, msg);
QDomDocument doc; addChatMsg(incoming, false, name, sendTime, msg);
doc.setContent(msgContents);
// embed links
QDomElement body = doc.documentElement();
RsChat::embedHtml(doc, body, defEmbedAhref);
// embed smileys
Settings->beginGroup("Chat");
if (Settings->value(QString::fromUtf8("Emoteicons_GroupChat"), true).toBool())
RsChat::embedHtml(doc, body, defEmbedImg);
Settings->endGroup();
msgContents = doc.toString(-1); // -1 removes any annoying carriage return misinterpreted by QTextEdit
extraTxt += msgContents;
if ((msgWidget->verticalScrollBar()->maximum() - 30) < msgWidget->verticalScrollBar()->value() ) {
msgWidget->append(extraTxt);
} else {
//the vertical scroll is not at the bottom, so just update the text, the scroll will stay at the current position
int scroll = msgWidget->verticalScrollBar()->value();
msgWidget->setHtml(msgWidget->toHtml() + extraTxt);
msgWidget->verticalScrollBar()->setValue(scroll);
msgWidget->update();
}
} }
} }
void PeersDialog::checkChat() bool PeersDialog::eventFilter(QObject *obj, QEvent *event)
{ {
/* if <return> at the end of the text -> we can send it! */ if (obj == ui.lineEdit) {
QTextEdit *chatWidget = ui.lineEdit; if (event->type() == QEvent::KeyPress) {
std::string txt = chatWidget->toPlainText().toStdString(); updateStatusTyping() ;
if ('\n' == txt[txt.length()-1])
{
//std::cerr << "Found <return> found at end of :" << txt << ": should send!";
//std::cerr << std::endl;
if (txt.length()-1 == txt.find('\n')) /* only if on first line! */
{
/* should remove last char ... */
sendMsg();
}
}
else
{
updateStatusTyping() ;
//std::cerr << "No <return> found in :" << txt << ":"; QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
//std::cerr << std::endl; if (keyEvent && (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return)) {
} // Enter pressed
if (Settings->getChatSendMessageWithCtrlReturn()) {
if (keyEvent->modifiers() & Qt::ControlModifier) {
// send message with Ctrl+Enter
sendMsg();
return true; // eat event
}
} else {
if (keyEvent->modifiers() & Qt::ControlModifier) {
// insert return
ui.lineEdit->textCursor().insertText("\n");
} else {
// send message with Enter
sendMsg();
}
return true; // eat event
}
}
}
}
// pass the event on to the parent class
return RsAutoUpdatePage::eventFilter(obj, event);
} }
void PeersDialog::sendMsg() void PeersDialog::sendMsg()
{ {
QTextEdit *lineWidget = ui.lineEdit; QTextEdit *lineWidget = ui.lineEdit;
//ci.msg = lineWidget->Text().toStdWString(); if (lineWidget->toPlainText().isEmpty()) {
std::wstring message = lineWidget->toHtml().toStdWString(); // nothing to send
return;
}
//historyKeeper.addMessage("THIS", "ALL", lineWidget->toHtml() ); std::wstring message = lineWidget->toHtml().toStdWString();
#ifdef PEERS_DEBUG #ifdef PEERS_DEBUG
std::string msg(ci.msg.begin(), ci.msg.end()); std::string msg(ci.msg.begin(), ci.msg.end());
@ -1373,7 +1384,8 @@ void PeersDialog::setChatInfo(QString info, QColor color)
void PeersDialog::on_actionClearChat_triggered() void PeersDialog::on_actionClearChat_triggered()
{ {
ui.msgText->clear(); ui.msgText->clear();
historyKeeper.clear();
} }
void PeersDialog::displayInfoChatMenu(const QPoint& pos) void PeersDialog::displayInfoChatMenu(const QPoint& pos)
@ -1385,143 +1397,14 @@ void PeersDialog::displayInfoChatMenu(const QPoint& pos)
myChatMenu.exec(mapToGlobal(pos)+QPoint(0,80)); myChatMenu.exec(mapToGlobal(pos)+QPoint(0,80));
} }
void PeersDialog::loadEmoticonsgroupchat()
{
QString sm_codes;
#if defined(Q_OS_WIN32)
QFile sm_file(QApplication::applicationDirPath() + "/emoticons/emotes.acs");
#else
QFile sm_file(QString(":/smileys/emotes.acs"));
#endif
if(!sm_file.open(QIODevice::ReadOnly))
{
std::cerr << "Could not open resouce file :/emoticons/emotes.acs" << std::endl ;
return ;
}
sm_codes = sm_file.readAll();
sm_file.close();
sm_codes.remove("\n");
sm_codes.remove("\r");
int i = 0;
QString smcode;
QString smfile;
while(sm_codes[i] != '{')
{
i++;
}
while (i < sm_codes.length()-2)
{
smcode = "";
smfile = "";
while(sm_codes[i] != '\"')
{
i++;
}
i++;
while (sm_codes[i] != '\"')
{
smcode += sm_codes[i];
i++;
}
i++;
while(sm_codes[i] != '\"')
{
i++;
}
i++;
while(sm_codes[i] != '\"' && sm_codes[i+1] != ';')
{
smfile += sm_codes[i];
i++;
}
i++;
if(!smcode.isEmpty() && !smfile.isEmpty())
#if defined(Q_OS_WIN32)
smileys.insert(smcode, smfile);
#else
smileys.insert(smcode, ":/"+smfile);
#endif
}
// init <img> embedder
defEmbedImg.InitFromAwkwardHash(smileys);
}
void PeersDialog::smileyWidgetgroupchat() void PeersDialog::smileyWidgetgroupchat()
{ {
qDebug("MainWindow::smileyWidget()"); style.showSmileyWidget(this, ui.emoticonBtn, SLOT(addSmileys()));
if(smWidget == 0) {
smWidget = new QWidget(this , Qt::Popup );
smWidget->setWindowTitle("Emoticons");
smWidget->setWindowIcon(QIcon(QString(":/images/rstray3.png")));
//smWidget->setFixedSize(256,256);
smWidget->setBaseSize( 4*24, (smileys.size()/4)*24 );
//Warning: this part of code was taken from kadu instant messenger;
// It was EmoticonSelector::alignTo(QWidget* w) function there
// comments are Polish, I dont' know how does it work...
// oblicz pozycj<63> widgetu do kt<6B>rego r<>wnamy
QWidget* w = ui.emoticonBtn;
QPoint w_pos = w->mapToGlobal(QPoint(0,0));
// oblicz rozmiar selektora
QSize e_size = smWidget->sizeHint();
// oblicz rozmiar pulpitu
QSize s_size = QApplication::desktop()->size();
// oblicz dystanse od widgetu do lewego brzegu i do prawego
int l_dist = w_pos.x();
int r_dist = s_size.width() - (w_pos.x() + w->width());
// oblicz pozycj<63> w zale<6C>no<6E>ci od tego czy po lewej stronie
// jest wi<77>cej miejsca czy po prawej
int x;
if (l_dist >= r_dist)
x = w_pos.x() - e_size.width();
else
x = w_pos.x() + w->width();
// oblicz pozycj<63> y - centrujemy w pionie
int y = w_pos.y() + w->height()/2 - e_size.height()/2;
// je<6A>li wychodzi poza doln<6C> kraw<61>d<EFBFBD> to r<>wnamy do niej
if (y + e_size.height() > s_size.height())
y = s_size.height() - e_size.height();
// je<6A>li wychodzi poza g<>rn<72> kraw<61>d<EFBFBD> to r<>wnamy do niej
if (y < 0)
y = 0;
// ustawiamy selektor na wyliczonej pozycji
smWidget->move(x, y);
x = 0;
y = 0;
QHashIterator<QString, QString> i(smileys);
while(i.hasNext())
{
i.next();
QPushButton *smButton = new QPushButton("", smWidget);
smButton->setGeometry(x*24, y*24, 24,24);
smButton->setIconSize(QSize(24,24));
smButton->setIcon(QPixmap(i.value()));
smButton->setToolTip(i.key());
//smButton->setFixedSize(24,24);
++x;
if(x > 4)
{
x = 0;
y++;
}
connect(smButton, SIGNAL(clicked()), this, SLOT(addSmileys()));
connect(smButton, SIGNAL(clicked()), smWidget, SLOT(close()));
}
}
smWidget->show();
} }
void PeersDialog::addSmileys() void PeersDialog::addSmileys()
{ {
ui.lineEdit->setText(ui.lineEdit->toHtml() + qobject_cast<QPushButton*>(sender())->toolTip().split("|").first()); ui.lineEdit->textCursor().insertText(qobject_cast<QPushButton*>(sender())->toolTip().split("|").first());
} }
/* GUI stuff -> don't do anything directly with Control */ /* GUI stuff -> don't do anything directly with Control */
@ -1873,6 +1756,6 @@ void PeersDialog::statusColumn()
void PeersDialog::on_actionMessageHistory_triggered() void PeersDialog::on_actionMessageHistory_triggered()
{ {
ImHistoryBrowser imBrowser(this); ImHistoryBrowser imBrowser(historyKeeper, this);
imBrowser.exec(); imBrowser.exec();
} }

View file

@ -22,7 +22,7 @@
#ifndef _PEERSDIALOG_H #ifndef _PEERSDIALOG_H
#define _PEERSDIALOG_H #define _PEERSDIALOG_H
#include "chat/HandleRichText.h" #include "chat/ChatStyle.h"
#include "RsAutoUpdatePage.h" #include "RsAutoUpdatePage.h"
#include "mainpage.h" #include "mainpage.h"
@ -60,7 +60,6 @@ public:
/** Default Destructor */ /** Default Destructor */
~PeersDialog (); ~PeersDialog ();
void loadEmoticonsgroupchat();
// void setChatDialog(ChatDialog *cd); // void setChatDialog(ChatDialog *cd);
virtual void updateDisplay() ; // overloaded from RsAutoUpdatePage virtual void updateDisplay() ; // overloaded from RsAutoUpdatePage
@ -96,6 +95,8 @@ public slots:
protected: protected:
virtual void dragEnterEvent(QDragEnterEvent *event); virtual void dragEnterEvent(QDragEnterEvent *event);
virtual void dropEvent(QDropEvent *event); virtual void dropEvent(QDropEvent *event);
bool eventFilter(QObject *obj, QEvent *ev);
void showEvent (QShowEvent *event);
private slots: private slots:
void pasteLink() ; void pasteLink() ;
@ -129,7 +130,6 @@ private slots:
void setColor(); void setColor();
void insertSendList(); void insertSendList();
void checkChat();
void sendMsg(); void sendMsg();
void statusmessage(); void statusmessage();
@ -166,6 +166,7 @@ signals:
private: private:
void processSettings(bool bLoad); void processSettings(bool bLoad);
void addChatMsg(bool incoming, bool history, QString &name, QDateTime &sendTime, QString &message);
class QLabel *iconLabel, *textLabel; class QLabel *iconLabel, *textLabel;
class QWidget *widget; class QWidget *widget;
@ -177,10 +178,6 @@ private:
QString fileName; QString fileName;
/** store default information for embedding HTML */
RsChat::EmbedInHtmlAhref defEmbedAhref;
RsChat::EmbedInHtmlImg defEmbedImg;
/* Worker Functions */ /* Worker Functions */
/* (1) Update Display */ /* (1) Update Display */
@ -190,17 +187,13 @@ private:
/** Defines the actions for the context menu */ /** Defines the actions for the context menu */
QAction* pasteLinkAct; QAction* pasteLinkAct;
//QTreeWidget *peertreeWidget;
IMHistoryKeeper historyKeeper; IMHistoryKeeper historyKeeper;
ChatStyle style;
QColor _currentColor; QColor _currentColor;
bool _underline; bool _underline;
time_t last_status_send_time ; time_t last_status_send_time ;
QHash<QString, QString> smileys;
QWidget *smWidget;
QFont mCurrentFont; /* how the text will come out */ QFont mCurrentFont; /* how the text will come out */
/** Qt Designer generated object */ /** Qt Designer generated object */

View file

@ -0,0 +1,333 @@
/****************************************************************
*
* RetroShare is distributed under the following license:
*
* Copyright (C) 2006, Thunder
*
* 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) any later version.
*
* 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., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
****************************************************************/
#include <QApplication>
#include <QDesktopWidget>
#include <QWidget>
#include <QFile>
#include <QIcon>
#include <QPushButton>
#include <iostream>
#include "ChatStyle.h"
enum enumGetStyle
{
GETSTYLE_INCOMING,
GETSTYLE_OUTGOING,
GETSTYLE_HINCOMING,
GETSTYLE_HOUTGOING
};
/* Default constructor */
ChatStyle::ChatStyle()
{
}
/* Destructor. */
ChatStyle::~ChatStyle()
{
}
void ChatStyle::setStylePath(QString path)
{
stylePath = path;
if (stylePath.right(1) != "/" && stylePath.right(1) != "\\") {
stylePath += "/";
}
}
void ChatStyle::loadEmoticons()
{
QString sm_codes;
bool internalEmoticons = true;
#if defined(Q_OS_WIN32)
// first try external emoticons
QFile sm_file(QApplication::applicationDirPath() + "/emoticons/emotes.acs");
if(sm_file.open(QIODevice::ReadOnly))
{
internalEmoticons = false;
} else {
// then embedded emotions
sm_file.setFileName(":/smileys/emotes.acs");
if(!sm_file.open(QIODevice::ReadOnly))
{
std::cout << "error opening ressource file" << std::endl ;
return ;
}
}
#else
QFile sm_file(QString(":/smileys/emotes.acs"));
if(!sm_file.open(QIODevice::ReadOnly))
{
std::cout << "error opening ressource file" << std::endl ;
return ;
}
#endif
sm_codes = sm_file.readAll();
sm_file.close();
sm_codes.remove("\n");
sm_codes.remove("\r");
int i = 0;
QString smcode;
QString smfile;
while(sm_codes[i] != '{')
{
i++;
}
while (i < sm_codes.length()-2)
{
smcode = "";
smfile = "";
while(sm_codes[i] != '\"')
{
i++;
}
i++;
while (sm_codes[i] != '\"')
{
smcode += sm_codes[i];
i++;
}
i++;
while(sm_codes[i] != '\"')
{
i++;
}
i++;
while(sm_codes[i] != '\"' && sm_codes[i+1] != ';')
{
smfile += sm_codes[i];
i++;
}
i++;
if(!smcode.isEmpty() && !smfile.isEmpty()) {
if (internalEmoticons) {
smileys.insert(smcode, ":/"+smfile);
} else {
smileys.insert(smcode, smfile);
}
}
}
// init <img> embedder
defEmbedImg.InitFromAwkwardHash(smileys);
}
void ChatStyle::showSmileyWidget(QWidget *parent, QWidget *button, const char *slotAddMethod)
{
QWidget *smWidget = new QWidget(parent, Qt::Popup);
smWidget->setAttribute( Qt::WA_DeleteOnClose);
smWidget->setWindowTitle("Emoticons");
smWidget->setWindowIcon(QIcon(QString(":/images/rstray3.png")));
smWidget->setBaseSize(4*24, (smileys.size()/4)*24);
//Warning: this part of code was taken from kadu instant messenger;
// It was EmoticonSelector::alignTo(QWidget* w) function there
// comments are Polish, I dont' know how does it work...
// oblicz pozycj<63> widgetu do kt<6B>rego r<>wnamy
// oblicz rozmiar selektora
QPoint pos = button->mapToGlobal(QPoint(0,0));
QSize e_size = smWidget->sizeHint();
// oblicz rozmiar pulpitu
QSize s_size = QApplication::desktop()->size();
// oblicz dystanse od widgetu do lewego brzegu i do prawego
int l_dist = pos.x();
int r_dist = s_size.width() - (pos.x() + button->width());
// oblicz pozycj<63> w zale<6C>no<6E>ci od tego czy po lewej stronie
// jest wi<77>cej miejsca czy po prawej
int x;
if (l_dist >= r_dist)
x = pos.x() - e_size.width();
else
x = pos.x() + button->width();
// oblicz pozycj<63> y - centrujemy w pionie
int y = pos.y() + button->height()/2 - e_size.height()/2;
// je<6A>li wychodzi poza doln<6C> kraw<61>d<EFBFBD> to r<>wnamy do niej
if (y + e_size.height() > s_size.height())
y = s_size.height() - e_size.height();
// je<6A>li wychodzi poza g<>rn<72> kraw<61>d<EFBFBD> to r<>wnamy do niej
if (y < 0)
y = 0;
// ustawiamy selektor na wyliczonej pozycji
smWidget->move(x, y);
x = 0;
y = 0;
QHashIterator<QString, QString> i(smileys);
while(i.hasNext())
{
i.next();
QPushButton *smButton = new QPushButton("", smWidget);
smButton->setGeometry(x*24, y*24, 24,24);
smButton->setIconSize(QSize(24,24));
smButton->setIcon(QPixmap(i.value()));
smButton->setToolTip(i.key());
++x;
if(x > 4)
{
x = 0;
y++;
}
QObject::connect(smButton, SIGNAL(clicked()), parent, slotAddMethod);
QObject::connect(smButton, SIGNAL(clicked()), smWidget, SLOT(close()));
}
smWidget->show();
}
static QString getStyle(QString &stylePath, enumGetStyle type)
{
QString style;
if (stylePath.isEmpty()) {
return "";
}
QFile fileHtml;
switch (type) {
case GETSTYLE_INCOMING:
fileHtml.setFileName(stylePath + "incoming.htm");
break;
case GETSTYLE_OUTGOING:
fileHtml.setFileName(stylePath + "outgoing.htm");
break;
case GETSTYLE_HINCOMING:
fileHtml.setFileName(stylePath + "hincoming.htm");
break;
case GETSTYLE_HOUTGOING:
fileHtml.setFileName(stylePath + "houtgoing.htm");
break;
default:
return "";
}
if (fileHtml.open(QIODevice::ReadOnly)) {
style = fileHtml.readAll();
fileHtml.close();
QFile fileCss(stylePath + "main.css");
QString css;
if (fileCss.open(QIODevice::ReadOnly)) {
css = fileCss.readAll();
fileCss.close();
}
style.replace("%css-style%", css);
}
return style;
}
QString ChatStyle::formatText(QString &message, unsigned int flag)
{
if (flag == 0) {
// nothing to do
return message;
}
QDomDocument doc;
doc.setContent(message);
QDomElement body = doc.documentElement();
if (flag & CHAT_FORMATTEXT_EMBED_LINKS) {
RsChat::embedHtml(doc, body, defEmbedAhref);
}
if (flag & CHAT_FORMATTEXT_EMBED_SMILEYS) {
RsChat::embedHtml(doc, body, defEmbedImg);
}
return doc.toString(-1); // -1 removes any annoying carriage return misinterpreted by QTextEdit
}
QString ChatStyle::formatMessage(enumFormatMessage type, QString &name, QDateTime &timestamp, QString &message, unsigned int flag)
{
QString style;
switch (type) {
case FORMATMSG_INCOMING:
style = getStyle(stylePath, GETSTYLE_INCOMING);
break;
case FORMATMSG_OUTGOING:
style = getStyle(stylePath, GETSTYLE_OUTGOING);
break;
case FORMATMSG_HINCOMING:
style = getStyle(stylePath, GETSTYLE_HINCOMING);
break;
case FORMATMSG_HOUTGOING:
style = getStyle(stylePath, GETSTYLE_HOUTGOING);
break;
}
if (style.isEmpty()) {
// default style
style = "%timestamp% %name% \n %message% ";
}
unsigned int formatFlag = 0;
if (flag & CHAT_FORMATMSG_EMBED_SMILEYS) {
formatFlag |= CHAT_FORMATTEXT_EMBED_SMILEYS;
}
if (flag & CHAT_FORMATMSG_EMBED_LINKS) {
formatFlag |= CHAT_FORMATTEXT_EMBED_LINKS;
}
QString msg = formatText(message, formatFlag);
// //replace http://, https:// and www. with <a href> links
// QRegExp rx("(retroshare://[^ <>]*)|(https?://[^ <>]*)|(www\\.[^ <>]*)");
// int count = 0;
// int pos = 100; //ignore the first 100 char because of the standard DTD ref
// while ( (pos = rx.indexIn(message, pos)) != -1 ) {
// //we need to look ahead to see if it's already a well formed link
// if (message.mid(pos - 6, 6) != "href=\"" && message.mid(pos - 6, 6) != "href='" && message.mid(pos - 6, 6) != "ttp://" ) {
// QString tempMessg = message.left(pos) + "<a href=\"" + rx.cap(count) + "\">" + rx.cap(count) + "</a>" + message.mid(pos + rx.matchedLength(), -1);
// message = tempMessg;
// }
// pos += rx.matchedLength() + 15;
// count ++;
// }
// {
// QHashIterator<QString, QString> i(smileys);
// while(i.hasNext())
// {
// i.next();
// foreach(QString code, i.key().split("|"))
// message.replace(code, "<img src=\"" + i.value() + "\" />");
// }
// }
QString formatMsg = style.replace("%name%", name)
.replace("%timestamp%", timestamp.toString("hh:mm:ss"))
.replace("%message%", msg);
return formatMsg;
}

View file

@ -0,0 +1,75 @@
/****************************************************************
* RetroShare is distributed under the following license:
*
* Copyright (C) 2006, Thunder
*
* 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) any later version.
*
* 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., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
****************************************************************/
#ifndef _CHATSTYLE_H
#define _CHATSTYLE_H
#include <QString>
#include <QDateTime>
#include <QHash>
#include "HandleRichText.h"
/* Flags for ChatStyle::formatMessage */
#define CHAT_FORMATMSG_EMBED_SMILEYS 1
#define CHAT_FORMATMSG_EMBED_LINKS 2
/* Flags for ChatStyle::formatText */
#define CHAT_FORMATTEXT_EMBED_SMILEYS 1
#define CHAT_FORMATTEXT_EMBED_LINKS 2
class ChatStyle
{
public:
enum enumFormatMessage
{
FORMATMSG_INCOMING,
FORMATMSG_OUTGOING,
FORMATMSG_HINCOMING,
FORMATMSG_HOUTGOING
};
QHash<QString, QString> smileys;
public:
/* Default constructor */
ChatStyle();
/* Default destructor */
~ChatStyle();
void setStylePath(QString path);
void loadEmoticons();
QString formatMessage(enumFormatMessage type, QString &name, QDateTime &timestamp, QString &message, unsigned int flag);
QString formatText(QString &message, unsigned int flag);
void showSmileyWidget(QWidget *parent, QWidget *button, const char *slotAddMethod);
private:
QString stylePath;
/** store default information for embedding HTML */
RsChat::EmbedInHtmlAhref defEmbedAhref;
RsChat::EmbedInHtmlImg defEmbedImg;
};
#endif // _CHATSTYLE_H

View file

@ -28,7 +28,6 @@
#include <QDateTime> #include <QDateTime>
#include <QFontDialog> #include <QFontDialog>
#include <QDir> #include <QDir>
#include <QDesktopWidget>
#include <QFileDialog> #include <QFileDialog>
#include <QBuffer> #include <QBuffer>
#include <QTextCodec> #include <QTextCodec>
@ -58,8 +57,6 @@
/* Define the format used for displaying the date and time */ /* Define the format used for displaying the date and time */
#define DATETIME_FMT "MMM dd hh:mm:ss" #define DATETIME_FMT "MMM dd hh:mm:ss"
#include <sstream>
/***** /*****
* #define CHAT_DEBUG 1 * #define CHAT_DEBUG 1
*****/ *****/
@ -100,12 +97,11 @@ PopupChatDialog::PopupChatDialog(std::string id, std::string name,
this->move(qrand()%100, qrand()%100); //avoid to stack multiple popup chat windows on the same position this->move(qrand()%100, qrand()%100); //avoid to stack multiple popup chat windows on the same position
m_bInsertOnVisible = true; m_bInsertOnVisible = true;
loadEmoticons();
last_status_send_time = 0 ; last_status_send_time = 0 ;
styleHtm = ":/qss/chat/default.htm"; style.setStylePath(":/qss/chat/private");
style.loadEmoticons();
/* Hide or show the frames */ /* Hide or show the frames */
showAvatarFrame(true); showAvatarFrame(true);
ui.infoframe->setVisible(false); ui.infoframe->setVisible(false);
@ -115,8 +111,6 @@ PopupChatDialog::PopupChatDialog(std::string id, std::string name,
connect(ui.actionAvatar, SIGNAL(triggered()),this, SLOT(getAvatar())); connect(ui.actionAvatar, SIGNAL(triggered()),this, SLOT(getAvatar()));
connect(ui.chattextEdit, SIGNAL(textChanged ( ) ), this, SLOT(checkChat( ) ));
connect(ui.sendButton, SIGNAL(clicked( ) ), this, SLOT(sendChat( ) )); connect(ui.sendButton, SIGNAL(clicked( ) ), this, SLOT(sendChat( ) ));
connect(ui.addFileButton, SIGNAL(clicked() ), this , SLOT(addExtraFile())); connect(ui.addFileButton, SIGNAL(clicked() ), this , SLOT(addExtraFile()));
@ -135,6 +129,9 @@ PopupChatDialog::PopupChatDialog(std::string id, std::string name,
connect(NotifyQt::getInstance(), SIGNAL(peerStatusChanged(const QString&, int)), this, SLOT(updateStatus(const QString&, int))); connect(NotifyQt::getInstance(), SIGNAL(peerStatusChanged(const QString&, int)), this, SLOT(updateStatus(const QString&, int)));
connect(NotifyQt::getInstance(), SIGNAL(peerHasNewCustomStateString(const QString&, const QString&)), this, SLOT(updatePeersCustomStateString(const QString&, const QString&))); connect(NotifyQt::getInstance(), SIGNAL(peerHasNewCustomStateString(const QString&, const QString&)), this, SLOT(updatePeersCustomStateString(const QString&, const QString&)));
// hide until it works
ui.styleButton->setVisible(false);
std::cerr << "Connecting custom context menu" << std::endl; std::cerr << "Connecting custom context menu" << std::endl;
ui.chattextEdit->setContextMenuPolicy(Qt::CustomContextMenu) ; ui.chattextEdit->setContextMenuPolicy(Qt::CustomContextMenu) ;
connect(ui.chattextEdit,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(contextMenu(QPoint))); connect(ui.chattextEdit,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(contextMenu(QPoint)));
@ -202,6 +199,8 @@ PopupChatDialog::PopupChatDialog(std::string id, std::string name,
// initialize first custom state string // initialize first custom state string
QString customStateString = QString::fromStdString(rsMsgs->getCustomStateString(dialogId)); QString customStateString = QString::fromStdString(rsMsgs->getCustomStateString(dialogId));
updatePeersCustomStateString(QString::fromStdString(dialogId), customStateString); updatePeersCustomStateString(QString::fromStdString(dialogId), customStateString);
ui.chattextEdit->installEventFilter(this);
} }
/** Destructor. */ /** Destructor. */
@ -527,88 +526,87 @@ void PopupChatDialog::insertChatMsgs()
continue; continue;
} }
addChatMsg(it->rsid, it->msg); addChatMsg(it->rsid, it->sendTime, it->msg);
} }
playsound(); playsound();
QApplication::alert(this); QApplication::alert(this);
} }
void PopupChatDialog::addChatMsg(std::string &id, std::wstring &msg) void PopupChatDialog::addChatMsg(std::string &id, uint sendTime, std::wstring &msg)
{ {
QString timestamp = "[" + QDateTime::currentDateTime().toString("hh:mm:ss") + "]"; QDateTime timestamp = QDateTime::fromTime_t(sendTime);
QString name = QString::fromStdString(rsPeers->getPeerName(id)); QString name = QString::fromStdString(rsPeers->getPeerName(id));
QString message = QString::fromStdWString(msg); QString message = QString::fromStdWString(msg);
//replace http://, https:// and www. with <a href> links
QRegExp rx("(retroshare://[^ <>]*)|(https?://[^ <>]*)|(www\\.[^ <>]*)");
int count = 0;
int pos = 100; //ignore the first 100 char because of the standard DTD ref
while ( (pos = rx.indexIn(message, pos)) != -1 ) {
//we need to look ahead to see if it's already a well formed link
if (message.mid(pos - 6, 6) != "href=\"" && message.mid(pos - 6, 6) != "href='" && message.mid(pos - 6, 6) != "ttp://" ) {
QString tempMessg = message.left(pos) + "<a href=\"" + rx.cap(count) + "\">" + rx.cap(count) + "</a>" + message.mid(pos + rx.matchedLength(), -1);
message = tempMessg;
}
pos += rx.matchedLength() + 15;
count ++;
}
#ifdef CHAT_DEBUG #ifdef CHAT_DEBUG
std::cout << "PopupChatDialog:addChatMsg message : " << message.toStdString() << std::endl; std::cout << "PopupChatDialog:addChatMsg message : " << message.toStdString() << std::endl;
#endif #endif
if (Settings->valueFromGroup(QString("Chat"), QString::fromUtf8("Emoteicons_PrivatChat"), true).toBool()) unsigned int formatFlag = CHAT_FORMATMSG_EMBED_LINKS;
{
QHashIterator<QString, QString> i(smileys); // embed smileys ?
while(i.hasNext()) if (Settings->valueFromGroup(QString("Chat"), QString::fromUtf8("Emoteicons_PrivatChat"), true).toBool()) {
{ formatFlag |= CHAT_FORMATMSG_EMBED_SMILEYS;
i.next();
foreach(QString code, i.key().split("|"))
message.replace(code, "<img src=\"" + i.value() + "\" />");
}
} }
history /*<< nickColor << color << font << fontSize*/ << timestamp << name << message;
ChatStyle::enumFormatMessage type = (id == rsPeers->getOwnId()) ? ChatStyle::FORMATMSG_INCOMING : ChatStyle::FORMATMSG_OUTGOING;
QString formatMsg = loadEmptyStyle()/*.replace(nickColor) QString formatMsg = style.formatMessage(type, name, timestamp, message, formatFlag);
.replace(color)
.replace(font)
.replace(fontSize)*/
.replace("%timestamp%", timestamp)
.replace("%name%", name)
.replace("%message%", message);
ui.textBrowser->append(formatMsg);
if ((ui.textBrowser->verticalScrollBar()->maximum() - 30) < ui.textBrowser->verticalScrollBar()->value() ) {
ui.textBrowser->append(formatMsg + "\n");
} else {
//the vertical scroll is not at the bottom, so just update the text, the scroll will stay at the current position
int scroll = ui.textBrowser->verticalScrollBar()->value();
ui.textBrowser->setHtml(ui.textBrowser->toHtml() + formatMsg + "\n");
ui.textBrowser->verticalScrollBar()->setValue(scroll);
ui.textBrowser->update();
}
resetStatusBar() ; resetStatusBar() ;
} }
void PopupChatDialog::checkChat() bool PopupChatDialog::eventFilter(QObject *obj, QEvent *event)
{ {
/* if <return> at the end of the text -> we can send it! */ if (obj == ui.chattextEdit) {
QTextEdit *chatWidget = ui.chattextEdit; if (event->type() == QEvent::KeyPress) {
std::string txt = chatWidget->toPlainText().toStdString(); updateStatusTyping() ;
if ('\n' == txt[txt.length()-1] && txt.length()-1 == txt.find('\n')) /* only if on first line! */
sendChat();
else
updateStatusTyping() ;
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent && (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return)) {
// Enter pressed
if (Settings->getChatSendMessageWithCtrlReturn()) {
if (keyEvent->modifiers() & Qt::ControlModifier) {
// send message with Ctrl+Enter
sendChat();
return true; // eat event
}
} else {
if (keyEvent->modifiers() & Qt::ControlModifier) {
// insert return
ui.chattextEdit->textCursor().insertText("\n");
} else {
// send message with Enter
sendChat();
}
return true; // eat event
}
}
}
}
// pass the event on to the parent class
return QMainWindow::eventFilter(obj, event);
} }
void PopupChatDialog::sendChat() void PopupChatDialog::sendChat()
{ {
QTextEdit *chatWidget = ui.chattextEdit; QTextEdit *chatWidget = ui.chattextEdit;
if (chatWidget->toPlainText().isEmpty()) {
// nothing to send
return;
}
std::wstring msg = chatWidget->toHtml().toStdWString();
if (msg.empty()) {
// nothing to send
return;
}
std::string ownId; std::string ownId;
{ {
@ -620,13 +618,11 @@ void PopupChatDialog::sendChat()
rsiface->unlockData(); /* Unlock Interface */ rsiface->unlockData(); /* Unlock Interface */
} }
std::wstring msg = chatWidget->toHtml().toStdWString();
#ifdef CHAT_DEBUG #ifdef CHAT_DEBUG
std::cout << "PopupChatDialog:sendChat " << styleHtm.toStdString() << std::endl; std::cout << "PopupChatDialog:sendChat " << styleHtm.toStdString() << std::endl;
#endif #endif
addChatMsg(ownId, msg); addChatMsg(ownId, time(NULL), msg);
rsMsgs->sendPrivateChat(dialogId, msg); rsMsgs->sendPrivateChat(dialogId, msg);
chatWidget->clear(); chatWidget->clear();
@ -700,202 +696,22 @@ void PopupChatDialog::setFont()
} }
void PopupChatDialog::loadEmoticons2()
{
QDir smdir(QApplication::applicationDirPath() + "/emoticons/kopete");
//QDir smdir(":/gui/images/emoticons/kopete");
QFileInfoList sminfo = smdir.entryInfoList(QStringList() << "*.gif" << "*.png", QDir::Files, QDir::Name);
foreach(QFileInfo info, sminfo)
{
QString smcode = info.fileName().replace(".gif", "");
QString smstring;
for(int i = 0; i < 9; i+=3)
{
smstring += QString((char)smcode.mid(i,3).toInt());
}
//qDebug(smstring.toAscii());
smileys.insert(smstring, info.absoluteFilePath());
}
}
void PopupChatDialog::loadEmoticons()
{
QString sm_codes;
#if defined(Q_OS_WIN32)
QFile sm_file(QApplication::applicationDirPath() + "/emoticons/emotes.acs");
#else
QFile sm_file(QString(":/smileys/emotes.acs"));
#endif
if(!sm_file.open(QIODevice::ReadOnly))
{
std::cout << "error opening ressource file" << std::endl ;
return ;
}
sm_codes = sm_file.readAll();
sm_file.close();
sm_codes.remove("\n");
sm_codes.remove("\r");
int i = 0;
QString smcode;
QString smfile;
while(sm_codes[i] != '{')
{
i++;
}
while (i < sm_codes.length()-2)
{
smcode = "";
smfile = "";
while(sm_codes[i] != '\"')
{
i++;
}
i++;
while (sm_codes[i] != '\"')
{
smcode += sm_codes[i];
i++;
}
i++;
while(sm_codes[i] != '\"')
{
i++;
}
i++;
while(sm_codes[i] != '\"' && sm_codes[i+1] != ';')
{
smfile += sm_codes[i];
i++;
}
i++;
if(!smcode.isEmpty() && !smfile.isEmpty())
#if defined(Q_OS_WIN32)
smileys.insert(smcode, smfile);
#else
smileys.insert(smcode, ":/"+smfile);
#endif
}
}
//============================================================================ //============================================================================
void PopupChatDialog::smileyWidget() void PopupChatDialog::smileyWidget()
{ {
qDebug("MainWindow::smileyWidget()"); style.showSmileyWidget(this, ui.emoteiconButton, SLOT(addSmiley()));
QWidget *smWidget = new QWidget(this , Qt::Popup);
smWidget->setAttribute( Qt::WA_DeleteOnClose);
smWidget->setWindowTitle("Emoticons");
smWidget->setWindowIcon(QIcon(QString(":/images/rstray3.png")));
smWidget->setBaseSize( 4*24, (smileys.size()/4)*24 );
//Warning: this part of code was taken from kadu instant messenger;
// It was EmoticonSelector::alignTo(QWidget* w) function there
// comments are Polish, I dont' know how does it work...
// oblicz pozycj<63> widgetu do kt<6B>rego r<>wnamy
QWidget* w = ui.emoteiconButton;
QPoint w_pos = w->mapToGlobal(QPoint(0,0));
// oblicz rozmiar selektora
QSize e_size = smWidget->sizeHint();
// oblicz rozmiar pulpitu
QSize s_size = QApplication::desktop()->size();
// oblicz dystanse od widgetu do lewego brzegu i do prawego
int l_dist = w_pos.x();
int r_dist = s_size.width() - (w_pos.x() + w->width());
// oblicz pozycj<63> w zale<6C>no<6E>ci od tego czy po lewej stronie
// jest wi<77>cej miejsca czy po prawej
int x;
if (l_dist >= r_dist)
x = w_pos.x() - e_size.width();
else
x = w_pos.x() + w->width();
// oblicz pozycj<63> y - centrujemy w pionie
int y = w_pos.y() + w->height()/2 - e_size.height()/2;
// je<6A>li wychodzi poza doln<6C> kraw<61>d<EFBFBD> to r<>wnamy do niej
if (y + e_size.height() > s_size.height())
y = s_size.height() - e_size.height();
// je<6A>li wychodzi poza g<>rn<72> kraw<61>d<EFBFBD> to r<>wnamy do niej
if (y < 0)
y = 0;
// ustawiamy selektor na wyliczonej pozycji
smWidget->move(x, y);
x = 0;
y = 0;
QHashIterator<QString, QString> i(smileys);
while(i.hasNext())
{
i.next();
QPushButton *smButton = new QPushButton("", smWidget);
smButton->setGeometry(x*24, y*24, 24,24);
smButton->setIconSize(QSize(24,24));
smButton->setIcon(QPixmap(i.value()));
smButton->setToolTip(i.key());
++x;
if(x > 4)
{
x = 0;
y++;
}
connect(smButton, SIGNAL(clicked()), this, SLOT(addSmiley()));
connect(smButton, SIGNAL(clicked()), smWidget, SLOT(close()));
}
smWidget->show();
} }
//============================================================================ //============================================================================
void PopupChatDialog::addSmiley() void PopupChatDialog::addSmiley()
{ {
ui.chattextEdit->setText(ui.chattextEdit->toHtml() + qobject_cast<QPushButton*>(sender())->toolTip().split("|").first()); ui.chattextEdit->textCursor().insertText(qobject_cast<QPushButton*>(sender())->toolTip().split("|").first());
} }
//============================================================================ //============================================================================
QString PopupChatDialog::loadEmptyStyle()
{
#ifdef CHAT_DEBUG
std::cout << "PopupChatDialog:loadEmptyStyle " << styleHtm.toStdString() << std::endl;
#endif
QString ret;
QFile file(styleHtm);
//file.open(QIODevice::ReadOnly);
if (file.open(QIODevice::ReadOnly)) {
ret = file.readAll();
file.close();
QString styleTmp = styleHtm;
QString styleCss = styleTmp.remove(styleHtm.lastIndexOf("."), styleHtm.length()-styleHtm.lastIndexOf(".")) + ".css";
qDebug() << styleCss.toAscii();
QFile css(styleCss);
QString tmp;
if (css.open(QIODevice::ReadOnly)) {
tmp = css.readAll();
css.close();
}
else {
#ifdef CHAT_DEBUG
std::cerr << "PopupChatDialog:loadEmptyStyle " << "Missing file of default css " << std::endl;
#endif
tmp = "";
}
ret.replace("%css-style%", tmp);
return ret;
}
else {
#ifdef CHAT_DEBUG
std::cerr << "PopupChatDialog:loadEmptyStyle " << "Missing file of default style " << std::endl;
#endif
ret="%timestamp% %name% \n %message% ";
return ret;
}
}
void PopupChatDialog::on_actionClear_Chat_triggered() void PopupChatDialog::on_actionClear_Chat_triggered()
{ {
ui.textBrowser->clear(); ui.textBrowser->clear();
@ -903,27 +719,27 @@ void PopupChatDialog::on_actionClear_Chat_triggered()
void PopupChatDialog::changeStyle() void PopupChatDialog::changeStyle()
{ {
QString newStyle = QFileDialog::getOpenFileName(this, tr("Open Style"), // QString newStyle = QFileDialog::getOpenFileName(this, tr("Open Style"),
appDir + "/style/chat/", // appDir + "/style/chat/",
tr("Styles (*.htm)")); // tr("Styles (*.htm)"));
if(!newStyle.isEmpty()) // if(!newStyle.isEmpty())
{ // {
QString wholeChat; // QString wholeChat;
styleHtm = newStyle; // styleHtm = newStyle;
//
//
for(int i = 0; i < history.size(); i+=4) // for(int i = 0; i < history.size(); i+=4)
{ // {
QString formatMsg = loadEmptyStyle(); // QString formatMsg = loadEmptyStyle();
wholeChat += formatMsg.replace("%timestamp%", history.at(i+1)) // wholeChat += formatMsg.replace("%timestamp%", history.at(i+1))
.replace("%name%", history.at(i+2)) // .replace("%name%", history.at(i+2))
.replace("%message%", history.at(i+3)) + "\n"; // .replace("%message%", history.at(i+3)) + "\n";
} // }
ui.textBrowser->setHtml(wholeChat); // ui.textBrowser->setHtml(wholeChat);
} // }
QTextCursor cursor = ui.textBrowser->textCursor(); // QTextCursor cursor = ui.textBrowser->textCursor();
cursor.movePosition(QTextCursor::End); // cursor.movePosition(QTextCursor::End);
ui.textBrowser->setTextCursor(cursor); // ui.textBrowser->setTextCursor(cursor);
} }
void PopupChatDialog::updatePeerAvatar(const std::string& peer_id) void PopupChatDialog::updatePeerAvatar(const std::string& peer_id)
@ -1121,7 +937,7 @@ void PopupChatDialog::fileHashingFinished(AttachFileItem* file)
std::wstring msg = message.toStdWString(); std::wstring msg = message.toStdWString();
addChatMsg(ownId, msg); addChatMsg(ownId, time(NULL), msg);
rsMsgs->sendPrivateChat(dialogId, msg); rsMsgs->sendPrivateChat(dialogId, msg);
} }

View file

@ -31,6 +31,8 @@ class QTextCharFormat;
class AttachFileItem; class AttachFileItem;
class ChatInfo; class ChatInfo;
#include "ChatStyle.h"
class PopupChatDialog : public QMainWindow class PopupChatDialog : public QMainWindow
{ {
Q_OBJECT Q_OBJECT
@ -79,16 +81,13 @@ protected:
virtual void dragEnterEvent(QDragEnterEvent *event); virtual void dragEnterEvent(QDragEnterEvent *event);
virtual void dropEvent(QDropEvent *event); virtual void dropEvent(QDropEvent *event);
void insertChatMsgs(); bool eventFilter(QObject *obj, QEvent *ev);
void addChatMsg(std::string &id, std::wstring &msg);
void loadEmoticons(); void insertChatMsgs();
void loadEmoticons2(); void addChatMsg(std::string &id, uint sendTime, std::wstring &msg);
void updateAvatar(); void updateAvatar();
QString loadEmptyStyle();
QPixmap picture; QPixmap picture;
private slots: private slots:
@ -101,7 +100,6 @@ private slots:
void getFont(); void getFont();
void setFont(); void setFont();
void checkChat();
void sendChat(); void sendChat();
void updatePeersCustomStateString(const QString& peer_id, const QString& status_string) ; void updatePeersCustomStateString(const QString& peer_id, const QString& status_string) ;
@ -130,17 +128,15 @@ private:
std::string lastChatName; std::string lastChatName;
time_t last_status_send_time ; time_t last_status_send_time ;
QHash<QString, QString> smileys;
QColor mCurrentColor; QColor mCurrentColor;
QFont mCurrentFont; QFont mCurrentFont;
QString styleHtm; // QStringList history;
QString emptyStyle;
QStringList history;
QString wholeChat; QString wholeChat;
QString fileName; QString fileName;
bool m_bInsertOnVisible; bool m_bInsertOnVisible;
ChatStyle style;
/** Qt Designer generated object */ /** Qt Designer generated object */
Ui::PopupChatDialog ui; Ui::PopupChatDialog ui;

View file

@ -26,6 +26,8 @@
#include "FeedHolder.h" #include "FeedHolder.h"
#include "../RsAutoUpdatePage.h" #include "../RsAutoUpdatePage.h"
#include "gui/msgs/MessageComposer.h" #include "gui/msgs/MessageComposer.h"
#include "gui/chat/ChatStyle.h"
#include "gui/settings/rsharesettings.h"
#include "gui/notifyqt.h" #include "gui/notifyqt.h"
@ -137,7 +139,20 @@ void ChatMsgItem::insertChat(std::string &message)
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss"); QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
timestampLabel->setText(timestamp); timestampLabel->setText(timestamp);
chatTextlabel->setText(QString::fromStdString(message)); QString formatMsg = QString::fromStdString(message);
ChatStyle style;
unsigned int formatFlag = CHAT_FORMATTEXT_EMBED_LINKS;
// embed smileys ?
if (Settings->valueFromGroup(QString("Chat"), QString::fromUtf8("Emoteicons_GroupChat"), true).toBool()) {
style.loadEmoticons();
formatFlag |= CHAT_FORMATTEXT_EMBED_SMILEYS;
}
formatMsg = style.formatText(formatMsg, formatFlag);
chatTextlabel->setText(formatMsg);
} }
void ChatMsgItem::removeItem() void ChatMsgItem::removeItem()

View file

@ -29,79 +29,13 @@ IMHistoryItem::IMHistoryItem()
//============================================================================ //============================================================================
IMHistoryItem::IMHistoryItem(const QString senderID, IMHistoryItem::IMHistoryItem(bool incomingIn, std::string &idIn, const QString &nameIn, const QDateTime &sendTimeIn, const QString &messageTextIn)
const QString receiverID,
const QString text,
const QDateTime time)
{ {
setTime(time); incoming = incomingIn;
setReceiver(receiverID); id = idIn;
setText(text); name = nameIn;
setSender(senderID); sendTime = sendTimeIn;
} messageText = messageTextIn;
//============================================================================
QDateTime
IMHistoryItem::time() const
{
return vTime;
}
//============================================================================
QString
IMHistoryItem::sender()
{
return vSender;
}
//============================================================================
QString
IMHistoryItem::receiver()
{
return vReceiver ;
}
//============================================================================
QString
IMHistoryItem::text() const
{
return vText;
}
//============================================================================
void
IMHistoryItem::setTime(QDateTime time)
{
vTime = time;
}
//============================================================================
void
IMHistoryItem::setSender(QString sender)
{
vSender = sender ;
}
//============================================================================
void
IMHistoryItem::setReceiver(QString receiver)
{
vReceiver = receiver;
}
//============================================================================
void
IMHistoryItem::setText(QString text)
{
vText = text ;
} }
//============================================================================ //============================================================================
@ -110,5 +44,5 @@ IMHistoryItem::setText(QString text)
bool bool
IMHistoryItem::operator<(const IMHistoryItem& item) const IMHistoryItem::operator<(const IMHistoryItem& item) const
{ {
return (vTime< item.time()) ; return (sendTime < item.sendTime) ;
} }

View file

@ -25,37 +25,20 @@
#include <QDateTime> #include <QDateTime>
#include <QString> #include <QString>
class IMHistoryItem class IMHistoryItem
{ {
public: public:
IMHistoryItem(); IMHistoryItem();
IMHistoryItem(const QString senderID, IMHistoryItem(bool incoming, std::string &id, const QString &name, const QDateTime &sendTime, const QString &messageText);
const QString receiverID,
const QString text,
const QDateTime time);
QDateTime time() const; bool incoming;
QString sender(); std::string id;
QString receiver(); QString name;
QString text() const; QDateTime sendTime;
QString messageText;
void setTime(QDateTime time);
void setTime(QString time);
void setSender(QString sender);
void setReceiver(QString receiver);
void setText(QString text);
bool operator<(const IMHistoryItem& item) const; bool operator<(const IMHistoryItem& item) const;
protected:
QDateTime vTime;
QString vSender;
QString vReceiver;
QString vText;
} ; } ;
#endif #endif

View file

@ -23,6 +23,7 @@
#include <QFile> #include <QFile>
#include <QIODevice> #include <QIODevice>
#include <QTimer>
#include <QtAlgorithms> //for qSort #include <QtAlgorithms> //for qSort
@ -31,148 +32,137 @@
#include "IMHistoryReader.h" #include "IMHistoryReader.h"
#include "IMHistoryWriter.h" #include "IMHistoryWriter.h"
//#include <iostream>
//============================================================================= //=============================================================================
IMHistoryKeeper::IMHistoryKeeper() IMHistoryKeeper::IMHistoryKeeper()
{ {
hfName = ""; historyChanged = false;
// save histroy every 10 seconds (when changed)
saveTimer = new QTimer(this);
saveTimer->connect(saveTimer, SIGNAL(timeout()), this, SLOT(saveHistory()));
saveTimer->setInterval(10000);
saveTimer->start();
}; };
//============================================================================= //=============================================================================
IMHistoryKeeper::IMHistoryKeeper(QString historyFileName)
{
hfName = historyFileName ;
loadHistoryFile( historyFileName );
//setHistoryFileName( historyFileName );
//IMHistoryWriter wri;
//wri.write(hitems, hfName);
}
//=============================================================================
IMHistoryKeeper::~IMHistoryKeeper() IMHistoryKeeper::~IMHistoryKeeper()
{ {
//=== we have to save all messages saveHistory();
qSort( hitems.begin(), hitems.end() ) ; // not nesessary, but just in case...
// it will not take a long time over
//ordered array
IMHistoryWriter wri;
wri.write(hitems, hfName);
} }
//============================================================================= //=============================================================================
void void IMHistoryKeeper::init(QString historyFileName)
IMHistoryKeeper::addMessage(const QString fromID, const QString toID,
const QString messageText)
{ {
IMHistoryItem item(fromID, toID, messageText, hfName = historyFileName;
QDateTime::currentDateTime()); loadHistoryFile();
}
hitems.append( item ); //=============================================================================
void IMHistoryKeeper::addMessage(bool incoming, std::string &id, const QString &name, const QDateTime &sendTime, const QString &messageText)
{
IMHistoryItem item(incoming, id, name, sendTime, messageText);
hitems.append(item);
historyChanged = true;
emit historyAdd(item);
//std::cerr << "IMHistoryKeeper::addMessage " //std::cerr << "IMHistoryKeeper::addMessage "
// << messageText.toStdString() << "\n"; // << messageText.toStdString() << "\n";
//std::cerr << "IMHistoryKeeper::addMessage count is" << hitems.count(); //std::cerr << "IMHistoryKeeper::addMessage count is" << hitems.count();
} }
//============================================================================= //=============================================================================
int bool IMHistoryKeeper::loadHistoryFile()
IMHistoryKeeper::loadHistoryFile(QString fileName)
{ {
qDebug() << " IMHistoryKeeper::loadHistoryFile is here"; qDebug() << " IMHistoryKeeper::loadHistoryFile is here";
QFile fl(fileName); if (hfName.isEmpty()) {
if ( !fl.exists() ) lastErrorMessage = "history file not set";
{ return false;
lastErrorMessage = QString("history file not found (%1)").arg(fileName) ; }
return 1;
QFile fl(hfName);
if (!fl.exists()) {
lastErrorMessage = QString("history file not found (%1)").arg(hfName) ;
return false;
} }
IMHistoryReader hreader; IMHistoryReader hreader;
if( !hreader.read( hitems, fileName ) ) if (!hreader.read(hitems, hfName)) {
{
lastErrorMessage = hreader.errorMessage(); lastErrorMessage = hreader.errorMessage();
return 1; return false;
} }
qSort( hitems.begin(), hitems.end() ) ; qSort(hitems.begin(), hitems.end());
qDebug() << " IMHistoryKeeper::loadHistoryFile finished"; qDebug() << " IMHistoryKeeper::loadHistoryFile finished";
return 0;
historyChanged = false;
return true;
} }
//============================================================================= //=============================================================================
QString QString IMHistoryKeeper::errorMessage()
IMHistoryKeeper::errorMessage()
{ {
return lastErrorMessage; QString errorMessage = lastErrorMessage;
lastErrorMessage = "No error" ; lastErrorMessage.clear();
return errorMessage;
} }
//============================================================================= //=============================================================================
int bool IMHistoryKeeper::getMessages(QList<IMHistoryItem> &historyItems, const int messagesCount)
IMHistoryKeeper::getMessages(QStringList& messagesList,
const QString fromID, const QString toID,
const int messagesCount )
{ {
int messFound = 0; int messFound = 0;
QList<IMHistoryItem> ril;//result item list
historyItems.clear();
QListIterator<IMHistoryItem> hii(hitems); QListIterator<IMHistoryItem> hii(hitems);
hii.toBack(); hii.toBack();
while (hii.hasPrevious() && (messFound<messagesCount)) while (hii.hasPrevious()) {
{
IMHistoryItem hitem = hii.previous(); IMHistoryItem hitem = hii.previous();
if ( ( (fromID.isEmpty())&&( hitem.receiver()==toID) ) ||
( (hitem.sender()==fromID)&&( hitem.receiver()==toID) ) || historyItems.insert(historyItems.begin(), hitem);
( (hitem.receiver()== fromID)&&(hitem.sender()==toID) ) ) messFound++;
{ if (messagesCount && messFound >= messagesCount) {
ril << hitem ; break;
messFound++;
if (messFound>=messagesCount)
break;
} }
} }
formStringList(ril, messagesList) ; return true; // successful end
return 0; // successful end
} }
//============================================================================= //=============================================================================
void void IMHistoryKeeper::clear()
IMHistoryKeeper::formStringList(QList<IMHistoryItem>& itemList,
QStringList& strList)
{ {
strList.clear(); hitems.clear();
historyChanged = true;
QListIterator<IMHistoryItem> hii(itemList); emit historyClear();
hii.toBack(); }
while (hii.hasPrevious() )
{
IMHistoryItem hitem = hii.previous();
QString tline; //=============================================================================
tline = QString("<strong><u>%1</u> %2 : </strong>" void IMHistoryKeeper::saveHistory()
"<span style=\"color:#008800\">%3</span>") {
.arg(hitem.time().toString( Qt::TextDate ) ) if (historyChanged && hfName.isEmpty() == false) {
.arg(hitem.sender()) //=== we have to save all messages
.arg(hitem.text()) ; qSort( hitems.begin(), hitems.end() ) ; // not nesessary, but just in case...
// it will not take a long time over ordered array
strList.append( tline );
IMHistoryWriter wri;
wri.write(hitems, hfName);
} }
} }
//=============================================================================

View file

@ -25,18 +25,19 @@
#include <QObject> #include <QObject>
#include <QDebug> #include <QDebug>
#include <QString> #include <QString>
#include <QStringList>
#include "IMHistoryItem.h" #include "IMHistoryItem.h"
class QTimer;
//! An engine for instant messaging history management //! An engine for instant messaging history management
//! This class holds history for instant messages. It stores all messages //! This class holds history for instant messages. It stores all messages
//! in xml file. Something like //! in xml file. Something like
//! <?xml version="1.0" encoding="UTF-8"?> //! <?xml version="1.0" encoding="UTF-8"?>
//! <!DOCTYPE history_file> //! <!DOCTYPE history_file>
//! <history_file format_version="1.0"> //! <history_file format_version="1.0">
//! <message dt="10000" sender="ALL" receiver="THIS">manual message</message> //! <message sendTime="10000" id="id" name="Name">manual message</message>
//! ... //! ...
//! other messages in <message..> ... </message> tags //! other messages in <message..> ... </message> tags
//! ... //! ...
@ -45,49 +46,55 @@
//! The class loads all messages from the file after creation, and saves them //! The class loads all messages from the file after creation, and saves them
//! at destruction. This means, the more history user has, the more memory //! at destruction. This means, the more history user has, the more memory
//! will be used. Maybe it's not good, but it isn't so large, I think //! will be used. Maybe it's not good, but it isn't so large, I think
class IMHistoryKeeper//: public QObject
class IMHistoryKeeper : public QObject
{ {
// Q_OBJECT Q_OBJECT
public: public:
IMHistoryKeeper(); IMHistoryKeeper();
IMHistoryKeeper(QString historyFileName);
//! A destructor //! A destructor
//! Warning: history messages will be saved to the file here. This means, //! Warning: history messages will be saved to the file here. This means,
//! a IMHistoryKeeper object must be deleted properly. //! a IMHistoryKeeper object must be deleted properly.
virtual ~IMHistoryKeeper(); virtual ~IMHistoryKeeper();
//! last error description //! last error description
QString errorMessage(); QString errorMessage();
//! initialize history keeper
void init(QString historyFileName);
//! Select messages from history //! Select messages from history
//! Fills given list with html-decorated messages (see formStringList(..)) //! Fills given list with items
//! Takes no more then messageText messages from history, where messages bool getMessages(QList<IMHistoryItem> &historyItems, const int messagesCount);
//! were sent from fromID to toID, or from toID to fromID. Also, if
//! fromID id ""(empty string), all messages, sent to toID, will be
//! extracted
int getMessages(QStringList& messagesList,
const QString fromID, const QString toID,
const int messagesCount = 5);
//! Adds new message to the history //! Adds new message to the history
//! Adds new message to the history, but the message will be saved to //! Adds new message to the history, but the message will be saved to
//! file only after destroing the object //! file only after destroing the object
void addMessage(const QString fromID, const QString toID, void addMessage(bool incoming, std::string &id, const QString &name, const QDateTime &sendTime, const QString &messageText);
const QString messageText);
//! Clear the history
protected: void clear();
int loadHistoryFile(QString fileName);
void formStringList(QList<IMHistoryItem>& itemList, QStringList& strList); private:
bool loadHistoryFile();
QList<IMHistoryItem> hitems; QList<IMHistoryItem> hitems;
QString hfName ; //! history file name QString hfName ; //! history file name
bool historyChanged;
QString lastErrorMessage; QString lastErrorMessage;
QTimer *saveTimer;
private slots:
void saveHistory();
signals:
void historyAdd(IMHistoryItem item) const;
void historyClear() const;
}; };
#endif // _HISTORY_KEEPER_H_ #endif // _HISTORY_KEEPER_H_

View file

@ -30,13 +30,12 @@
IMHistoryReader::IMHistoryReader() IMHistoryReader::IMHistoryReader()
:errMess("No error") :errMess("No error")
{ {
// nothing to do here // nothing to do here
} }
//============================================================================= //=============================================================================
bool bool IMHistoryReader::read(QList<IMHistoryItem>& resultList,
IMHistoryReader::read(QList<IMHistoryItem>& resultList,
const QString fileName) const QString fileName)
{ {
errMess = "No error"; errMess = "No error";
@ -45,154 +44,140 @@ IMHistoryReader::read(QList<IMHistoryItem>& resultList,
//==== check for file and open it //==== check for file and open it
QFile fl(fileName); QFile fl(fileName);
if (fl.exists()) if (fl.exists()) {
fl.open(QIODevice::ReadOnly); fl.open(QIODevice::ReadOnly);
else } else {
{
errMess = QString("file not found (%1)").arg(fileName); errMess = QString("file not found (%1)").arg(fileName);
return false ; return false ;
} }
//==== set the file, and check it once more //==== set the file, and check it once more
setDevice(&fl); setDevice(&fl);
if ( atEnd() ) if (atEnd()) {
{ errMess = "end of document reached before anything happened";
errMess = "end of document reache before anything happened";
return false; return false;
} }
//==== now, read the first element (it should be document element) //==== now, read the first element (it should be document element)
while (!atEnd()) while (!atEnd()) {
{
readNext(); readNext();
if ( isStartElement() ) if (isStartElement()) {
{ if (name() == "history_file" && attributes().value("format_version") == "1.0") {
if (name() == "history_file" && readHistory(result);
attributes().value("format_version") == "1.0")
{
result = readHistory();
break; break;
} } else {
else errMess = "The file is not a history file with format version 1.0";
{ return false ;
errMess="The file is not a history file with format version 1.0";
return false ;
} }
} }
} }
if ( error() ) if (error()) {
errMess = errorString(); errMess = errorString();
else } else {
{ resultList.clear();
resultList.clear();
QList<IMHistoryItem>::const_iterator hii;//history items iterator
QList<IMHistoryItem>::const_iterator hii;//history items iterator for (hii = result.constBegin(); hii != result.constEnd(); ++hii) {
for (hii = result.constBegin(); hii != result.constEnd(); ++hii) resultList << *hii;
resultList << *hii ; }
} }
return !error(); return !error();
} }
//============================================================================= //=============================================================================
QString QString IMHistoryReader::errorMessage()
IMHistoryReader::errorMessage()
{ {
QString result = errMess; QString result = errMess;
errMess = "No error" ; errMess = "No error" ;
return result; return result;
} }
//============================================================================= //=============================================================================
void void IMHistoryReader::readUnknownElement()
IMHistoryReader::readUnknownElement()
{
Q_ASSERT(isStartElement());
qDebug()<< " " << "unknown node " << name().toString();
while (!atEnd())
{
readNext();
if (isEndElement())
break;
if (isStartElement())
readUnknownElement();
}
}
//=============================================================================
QList<IMHistoryItem>
IMHistoryReader::readHistory()
{ {
Q_ASSERT(isStartElement()); Q_ASSERT(isStartElement());
// qDebug()<< " " << "node with message " << name() ;
QList<IMHistoryItem> rez; qDebug()<< " " << "unknown node " << name().toString();
while (!atEnd()) while (!atEnd()) {
{ readNext();
readNext(); if (isEndElement()) {
if (isEndElement()) break;
break; }
if (isStartElement()) if (isStartElement()) {
{ readUnknownElement();
if ( name() == "message" )
{
IMHistoryItem item = readMessage();
rez.append(item);
}
else
readUnknownElement();
} }
} }
return rez;
} }
//============================================================================= //=============================================================================
//#include <QXmlAttributes>
IMHistoryItem void IMHistoryReader::readHistory(QList<IMHistoryItem> &historyItems)
IMHistoryReader::readMessage() {
Q_ASSERT(isStartElement());
// qDebug()<< " " << "node with message " << name() ;
historyItems.clear();
while (!atEnd()) {
readNext();
if (isEndElement()) {
break;
}
if (isStartElement()) {
if ( name() == "message") {
IMHistoryItem item;
readMessage(item);
historyItems.append(item);
}
else {
readUnknownElement();
}
}
}
}
//=============================================================================
void IMHistoryReader::readMessage(IMHistoryItem &historyItem)
{ {
// Q_ASSERT(isStartElement() ); // Q_ASSERT(isStartElement() );
IMHistoryItem rez;// = new IMHistoryItem(); if (isStartElement() && (name() == "message")) {
//=== process attributes
if ( isStartElement() && (name() == "message")) historyItem.incoming = (attributes().value("incoming").toString().toInt() == 1);
{ historyItem.id = attributes().value("id").toString().toStdString();
//=== process attributes historyItem.name = attributes().value("name").toString();
int ti = attributes().value("dt").toString().toInt() ;
rez.setTime( QDateTime::fromTime_t( ti ) );
rez.setSender( attributes().value("sender").toString() ) ;
rez.setReceiver( attributes().value("receiver").toString() );
//=== after processing attributes, read the message text
QString tstr = readElementText();
//=== remove '\0' chars from the string. Is it a QXmlStuff bug, int ti = attributes().value("sendTime").toString().toInt();
// if they appear? historyItem.sendTime = QDateTime::fromTime_t(ti);
for(int i =0; i< tstr.length(); i++)
{
if (tstr.at(i) == '\n')
tstr.remove(i,1);
}
rez.setText( tstr );
//qDebug() << QString(" readMessage: %1, %2, %3, %4" ) //=== after processing attributes, read the message text
// .arg(rez.text()).arg(rez.sender()) QString tstr = readElementText();
// .arg(rez.receiver()).arg(ti) ;
}
return rez; //=== remove '\0' chars from the string. Is it a QXmlStuff bug,
// if they appear?
for (int i = 0; i< tstr.length(); i++) {
if (tstr.at(i) == '\n') {
tstr.remove(i, 1);
}
}
historyItem.messageText = tstr;
//qDebug() << QString(" readMessage: %1, %2, %3, %4" )
// .arg(rez.text()).arg(rez.sender())
// .arg(rez.receiver()).arg(ti) ;
}
} }
//============================================================================= //=============================================================================

View file

@ -41,12 +41,11 @@ public:
private: private:
void readUnknownElement(); void readUnknownElement();
QList<IMHistoryItem> readHistory(); void readHistory(QList<IMHistoryItem> &historyItems);
IMHistoryItem readMessage(); void readMessage(IMHistoryItem &historyItem);
QString errMess; QString errMess;
} ; } ;
#endif #endif

View file

@ -22,9 +22,7 @@
#include "IMHistoryWriter.h" #include "IMHistoryWriter.h"
#include <QFile> #include <QFile>
#include <QDebug> #include <QDebug>
#include <QDateTime> #include <QDateTime>
//============================================================================= //=============================================================================
@ -32,27 +30,23 @@
IMHistoryWriter::IMHistoryWriter() IMHistoryWriter::IMHistoryWriter()
:errMess("No error") :errMess("No error")
{ {
// nothing to do here // nothing to do here
} }
//============================================================================= //=============================================================================
bool bool IMHistoryWriter::write(QList<IMHistoryItem>& itemList, const QString fileName)
IMHistoryWriter::write(QList<IMHistoryItem>& itemList,
const QString fileName )
{ {
qDebug() << " IMHistoryWriter::write is here" ; qDebug() << " IMHistoryWriter::write is here" ;
errMess = "No error"; errMess = "No error";
//==== check for file and open it //==== check for file and open it
QFile fl(fileName); QFile fl(fileName);
if (fl.open(QIODevice::WriteOnly | QIODevice::Truncate)); if (fl.open(QIODevice::WriteOnly | QIODevice::Truncate) == false) {
else
{
errMess = QString("error opening file %1 (code %2)") errMess = QString("error opening file %1 (code %2)")
.arg(fileName).arg( fl.error() ); .arg(fileName).arg( fl.error() );
return false ; return false;
} }
//==== set the file, and check it once more //==== set the file, and check it once more
@ -63,13 +57,13 @@ IMHistoryWriter::write(QList<IMHistoryItem>& itemList,
writeStartElement("history_file"); writeStartElement("history_file");
writeAttribute("format_version", "1.0"); writeAttribute("format_version", "1.0");
foreach(IMHistoryItem item, itemList) foreach(IMHistoryItem item, itemList) {
{
writeStartElement("message"); writeStartElement("message");
writeAttribute( "dt", QString::number(item.time().toTime_t()) ) ; writeAttribute("incoming", QString::number(item.incoming ? 1 : 0));
writeAttribute( "sender", item.sender() ); writeAttribute("id", QString::fromStdString(item.id));
writeAttribute( "receiver", item.receiver() ) ; writeAttribute("name", item.name);
writeCharacters( item.text()); writeAttribute("sendTime", QString::number(item.sendTime.toTime_t()));
writeCharacters(item.messageText);
writeEndElement(); writeEndElement();
} }
@ -80,4 +74,4 @@ IMHistoryWriter::write(QList<IMHistoryItem>& itemList,
qDebug() << " IMHistoryWriter::write done" ; qDebug() << " IMHistoryWriter::write done" ;
return true; return true;
} }

View file

@ -24,22 +24,63 @@
#include <QDateTime> #include <QDateTime>
#include <QMenu> #include <QMenu>
#include <QClipboard> #include <QClipboard>
//#include <QDomDocument>
#include "rshare.h" #include "rshare.h"
//#include "gui/chat/HandleRichText.h"
/** Default constructor */ /** Default constructor */
ImHistoryBrowser::ImHistoryBrowser(QWidget *parent, Qt::WFlags flags) ImHistoryBrowser::ImHistoryBrowser(IMHistoryKeeper &histKeeper, QWidget *parent, Qt::WFlags flags)
: QDialog(parent, flags), historyKeeper(Rshare::dataDirectory() + "/his1.xml") : QDialog(parent, flags), historyKeeper(histKeeper)
{ {
/* Invoke Qt Designer generated QObject setup routine */ /* Invoke Qt Designer generated QObject setup routine */
ui.setupUi(this); ui.setupUi(this);
QStringList him;
historyKeeper.getMessages(him, "", "THIS", 8);
foreach(QString mess, him)
ui.textBrowser->append(mess);
connect(&historyKeeper, SIGNAL(historyAdd(IMHistoryItem)), this, SLOT(historyAdd(IMHistoryItem)));
connect(&historyKeeper, SIGNAL(historyClear()), this, SLOT(historyClear()));
QList<IMHistoryItem> historyItems;
historyKeeper.getMessages(historyItems, 0);
foreach(IMHistoryItem item, historyItems) {
addItem(item);
}
} }
void ImHistoryBrowser::historyAdd(IMHistoryItem item)
{
addItem(item);
}
void ImHistoryBrowser::historyClear()
{
ui.textBrowser->clear();
}
void ImHistoryBrowser::addItem(IMHistoryItem &item)
{
QString timestamp = item.sendTime.toString("hh:mm:ss");
QString text = "<span style=\"color:#C00000\">" + timestamp + "</span>" +
"<span style=\"color:#2D84C9\"><strong>" + " " + item.name + "</strong></span>";
// create a DOM tree object from the message and embed contents with HTML tags
// QDomDocument doc;
// doc.setContent(item.messageText);
//
// // embed links
// QDomElement body = doc.documentElement();
// RsChat::embedHtml(doc, body, defEmbedAhref);
//
// // embed smileys
// Settings->beginGroup("Chat");
// if (Settings->value(QString::fromUtf8("Emoteicons_GroupChat"), true).toBool()) {
// RsChat::embedHtml(doc, body, defEmbedImg);
// }
// Settings->endGroup();
//
// text += doc.toString(-1); // -1 removes any annoying carriage return misinterpreted by QTextEdit
text += item.messageText;
ui.textBrowser->append(text);
}

View file

@ -35,22 +35,20 @@ class ImHistoryBrowser : public QDialog
public: public:
/** Default constructor */ /** Default constructor */
ImHistoryBrowser(QWidget *parent = 0, Qt::WFlags flags = 0); ImHistoryBrowser(IMHistoryKeeper &histKeeper, QWidget *parent = 0, Qt::WFlags flags = 0);
/** Default destructor */ /** Default destructor */
private slots: private slots:
void historyAdd(IMHistoryItem item);
void historyClear();
private: private:
void addItem(IMHistoryItem &item);
IMHistoryKeeper &historyKeeper;
IMHistoryKeeper historyKeeper;
/** Qt Designer generated object */ /** Qt Designer generated object */
Ui::ImHistoryBrowser ui; Ui::ImHistoryBrowser ui;
}; };
#endif #endif

View file

@ -449,11 +449,16 @@
<file>images/window_fullscreen.png</file> <file>images/window_fullscreen.png</file>
<file>images/window_nofullscreen.png</file> <file>images/window_nofullscreen.png</file>
<file>layouts/default.ui</file> <file>layouts/default.ui</file>
<file>qss/chat/default.htm</file> <file>qss/chat/private/incoming.htm</file>
<file>qss/chat/default.css</file> <file>qss/chat/private/outgoing.htm</file>
<file>qss/chat/second.htm</file> <file>qss/chat/private/hincoming.htm</file>
<file>qss/chat/second.css</file> <file>qss/chat/private/houtgoing.htm</file>
<file>qss/chat/second.css</file> <file>qss/chat/private/main.css</file>
<file>qss/chat/public/incoming.htm</file>
<file>qss/chat/public/outgoing.htm</file>
<file>qss/chat/public/hincoming.htm</file>
<file>qss/chat/public/houtgoing.htm</file>
<file>qss/chat/public/main.css</file>
<file>smileys/angry.png</file> <file>smileys/angry.png</file>
<file>smileys/beer.png</file> <file>smileys/beer.png</file>
<file>smileys/cake.png</file> <file>smileys/cake.png</file>

View file

@ -1,28 +0,0 @@
.header {
font-weight: bold;
}
.time {
}
.incomingHeader {
background-color:#dfedff;
border-color:#fafafa #d1dfef #d1dfef #fafafa;
color: #295b07;
}
.incomingTime {
background-color:#dfedff;
color: #295b07;
}
.outgoingHeader {
background-color:#f5f5f5;
border-color:#fafafa #e3e3e3 #e3e3e3 #fafafa;
color: #244578;
}
.outgoingTime {
color: #244578;
}

View file

@ -4,7 +4,7 @@
<table width='100%'> <table width='100%'>
<tr> <tr>
<td class='header incomingHeader'>%name%</td> <td class='header incomingHeader'>%name%</td>
<td width='10%' align='left' class='time incomingTime'>%timestamp% </td> <td width='10%' align='left' class='time incomingTime'>[%timestamp%] </td>
</tr> </tr>
</table> </table>

View file

@ -0,0 +1,51 @@
.header {
font-weight: bold;
}
.time {
}
.incomingHeader {
background-color:#dfedff;
border-color:#fafafa #d1dfef #d1dfef #fafafa;
color: #295b07;
}
.incomingTime {
background-color:#dfedff;
color: #295b07;
}
.outgoingHeader {
background-color:#f5f5f5;
border-color:#fafafa #e3e3e3 #e3e3e3 #fafafa;
color: #244578;
}
.outgoingTime {
background-color:#f5f5f5;
color: #244578;
}
.hincomingHeader {
background-color:#dfedff;
border-color:#fafafa #d1dfef #d1dfef #fafafa;
color: #295b07;
}
.hincomingTime {
background-color:#dfedff;
color: #295b07;
}
.houtgoingHeader {
background-color:#f5f5f5;
border-color:#fafafa #e3e3e3 #e3e3e3 #fafafa;
color: #244578;
}
.houtgoingTime {
background-color:#f5f5f5;
color: #244578;
}

View file

@ -0,0 +1,16 @@
<style type="text/css">
%css-style%
</style>
<table width='100%'>
<tr>
<td class='header outgoingHeader'>%name%</td>
<td width='10%' align='left' class='time outgoingTime'>[%timestamp%] </td>
</tr>
</table>
<table width="100%">
<tr>
<td>%message%</td>
</tr>
</table>

View file

@ -0,0 +1,7 @@
<style type="text/css">
%css-style%
</style>
<span class='incomingTime'>%timestamp%</span>
<span class='incomingName'><strong>%name%</strong></span>
%message%

View file

@ -0,0 +1,31 @@
.incomingTime {
color:#C00000;
}
.incomingName{
color:#2D84C9;
}
.outgoingTime {
color:#C00000;
}
.outgoingName{
color:#2D84C9;
}
.hincomingTime {
color:#800000;
}
.hincomingName{
color:#1E5684;
}
.houtgoingTime {
color:#800000;
}
.houtgoingName{
color:#1E5684;
}

View file

@ -0,0 +1,7 @@
<style type="text/css">
%css-style%
</style>
<span class='outgoingTime'>%timestamp%</span>
<span class='outgoingName'><strong>%name%</strong></span>
%message%

View file

@ -1,25 +0,0 @@
.header {
font-weight: bold;
}
.time {
}
.incomingHeader {
background-color: #B2B2B2;
color: #000033;
}
.incomingTime {
color: #CCD9D9;
}
.outgoingHeader {
background-color: #c2d9fa;
color: #244578;
}
.outgoingTime {
color: #707070;
}

View file

@ -1,28 +0,0 @@
<style type="text/css">
%css-style%
</style>
<table width='100%' cellpadding='0' cellspacing='0'>
<tr>
<td align='right' width='32' bgcolor='white' rowspan='2'>
<div>
<img src='%avatar%'>
</div>
</td>
<td class='header incomingHeader'>
%name%
</td>
</tr>
<tr>
<td>
<table width='100%' cellpadding='0' cellspacing='0'>
<tr>
<td>%message%</td>
<td width='50' align='left' class='time incomingTime'>%timestamp%</td>
</tr>
</table>
</td>
</tr>
</table>

View file

@ -48,34 +48,38 @@ ChatPage::closeEvent (QCloseEvent * event)
bool bool
ChatPage::save(QString &errmsg) ChatPage::save(QString &errmsg)
{ {
Settings->beginGroup(QString("Chat")); Settings->beginGroup(QString("Chat"));
Settings->setValue(QString::fromUtf8("Emoteicons_PrivatChat"), emotePrivatChat()); Settings->setValue(QString::fromUtf8("Emoteicons_PrivatChat"), emotePrivatChat());
Settings->setValue(QString::fromUtf8("Emoteicons_GroupChat"), emoteGroupChat()); Settings->setValue(QString::fromUtf8("Emoteicons_GroupChat"), emoteGroupChat());
Settings->setValue(QString::fromUtf8("GroupChat_History"), groupchatHistory()); Settings->setValue(QString::fromUtf8("GroupChat_History"), groupchatHistory());
Settings->setValue(QString::fromUtf8("ChatScreenFont"), fontTempChat.toString()); Settings->setValue(QString::fromUtf8("ChatScreenFont"), fontTempChat.toString());
Settings->endGroup(); Settings->endGroup();
return true; Settings->setChatSendMessageWithCtrlReturn(ui.sendMessageWithCtrlReturn->isChecked());
return true;
} }
/** Loads the settings for this page */ /** Loads the settings for this page */
void void
ChatPage::load() ChatPage::load()
{ {
Settings->beginGroup(QString("Chat")); Settings->beginGroup(QString("Chat"));
ui.checkBox_emoteprivchat->setChecked(Settings->value(QString::fromUtf8("Emoteicons_PrivatChat"), true).toBool()); ui.checkBox_emoteprivchat->setChecked(Settings->value(QString::fromUtf8("Emoteicons_PrivatChat"), true).toBool());
ui.checkBox_emotegroupchat->setChecked(Settings->value(QString::fromUtf8("Emoteicons_GroupChat"), true).toBool()); ui.checkBox_emotegroupchat->setChecked(Settings->value(QString::fromUtf8("Emoteicons_GroupChat"), true).toBool());
ui.checkBox_groupchathistory->setChecked(Settings->value(QString::fromUtf8("GroupChat_History"), true).toBool()); ui.checkBox_groupchathistory->setChecked(Settings->value(QString::fromUtf8("GroupChat_History"), true).toBool());
fontTempChat.fromString(Settings->value(QString::fromUtf8("ChatScreenFont")).toString()); fontTempChat.fromString(Settings->value(QString::fromUtf8("ChatScreenFont")).toString());
Settings->endGroup(); Settings->endGroup();
ui.labelChatFontPreview->setText(fontTempChat.rawName()); ui.sendMessageWithCtrlReturn->setChecked(Settings->getChatSendMessageWithCtrlReturn());
ui.labelChatFontPreview->setFont(fontTempChat);
ui.labelChatFontPreview->setText(fontTempChat.rawName());
ui.labelChatFontPreview->setFont(fontTempChat);
} }
bool ChatPage::emotePrivatChat() const { bool ChatPage::emotePrivatChat() const {

View file

@ -516,7 +516,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" rowspan="4"> <item row="0" column="1" rowspan="5">
<widget class="QGroupBox" name="groupBoxIRCColors"> <widget class="QGroupBox" name="groupBoxIRCColors">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
@ -609,7 +609,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="4" column="0">
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
@ -622,6 +622,13 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="3" column="0">
<widget class="QCheckBox" name="sendMessageWithCtrlReturn">
<property name="text">
<string>Send message with Ctrl+Return</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View file

@ -289,6 +289,16 @@ void RshareSettings::setAddFeedsAtEnd(bool bValue)
setValue("AddFeedsAtEnd", bValue); setValue("AddFeedsAtEnd", bValue);
} }
bool RshareSettings::getChatSendMessageWithCtrlReturn()
{
return valueFromGroup("Chat", "SendMessageWithCtrlReturn", false).toBool();
}
void RshareSettings::setChatSendMessageWithCtrlReturn(bool bValue)
{
setValueToGroup("Chat", "SendMessageWithCtrlReturn", bValue);
}
/** Returns true if RetroShare is set to run on system boot. */ /** Returns true if RetroShare is set to run on system boot. */
bool bool
RshareSettings::runRetroshareOnBoot() RshareSettings::runRetroshareOnBoot()

View file

@ -120,6 +120,9 @@ public:
bool getAddFeedsAtEnd(); bool getAddFeedsAtEnd();
void setAddFeedsAtEnd(bool bValue); void setAddFeedsAtEnd(bool bValue);
bool getChatSendMessageWithCtrlReturn();
void setChatSendMessageWithCtrlReturn(bool bValue);
//! Save placement, state and size information of a window. //! Save placement, state and size information of a window.
void saveWidgetInformation(QWidget *widget); void saveWidgetInformation(QWidget *widget);