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:
std::string rsid;
unsigned int chatflags;
uint32_t sendTime;
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)
{
i.rsid = c -> PeerId();
i.chatflags = 0 ;
i.msg = c -> message;
i.rsid = c->PeerId();
i.chatflags = 0;
i.sendTime =c->sendTime;
i.msg = c->message;
if (c -> chatFlags & RS_CHAT_FLAG_PRIVATE)
{

View File

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

View File

@ -24,7 +24,6 @@
#include <QShortcut>
#include <QWidgetAction>
#include <QScrollBar>
#include <QDesktopWidget>
#include <QColorDialog>
#include <QFontDialog>
#include <QDropEvent>
@ -32,7 +31,7 @@
#include "common/vmessagebox.h"
#include <gui/mainpagestack.h>
#include "rshare.h"
#include "retroshare/rsinit.h"
#include "PeersDialog.h"
#include <retroshare/rsiface.h>
#include <retroshare/rspeers.h>
@ -139,127 +138,134 @@ private:
/** Constructor */
PeersDialog::PeersDialog(QWidget *parent)
: RsAutoUpdatePage(1500,parent),
historyKeeper(Rshare::dataDirectory() + "/his1.xml"),
smWidget(0)
: RsAutoUpdatePage(1500,parent)
{
/* Invoke the Qt Designer generated object setup routine */
ui.setupUi(this);
/* Invoke the Qt Designer generated object setup routine */
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( itemDoubleClicked ( QTreeWidgetItem *, int)), this, SLOT(chatfriend(QTreeWidgetItem *)));
connect( ui.peertreeWidget, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( peertreeWidgetCostumPopupMenu( QPoint ) ) );
connect( ui.peertreeWidget, SIGNAL( itemDoubleClicked ( QTreeWidgetItem *, int)), this, SLOT(chatfriend(QTreeWidgetItem *)));
connect( ui.avatartoolButton, SIGNAL(clicked()), SLOT(getAvatar()));
connect( ui.mypersonalstatuslabel, SIGNAL(clicked()), SLOT(statusmessage()));
connect( ui.actionSet_your_Avatar, SIGNAL(triggered()), this, SLOT(getAvatar()));
connect( ui.actionSet_your_Personal_Message, SIGNAL(triggered()), this, SLOT(statusmessage()));
connect( ui.addfileButton, SIGNAL(clicked() ), this , SLOT(addExtraFile()));
connect( ui.msgText, SIGNAL(anchorClicked(const QUrl &)), SLOT(anchorClicked(const QUrl &)));
connect( ui.avatartoolButton, SIGNAL(clicked()), SLOT(getAvatar()));
connect( ui.mypersonalstatuslabel, SIGNAL(clicked()), SLOT(statusmessage()));
connect( ui.actionSet_your_Avatar, SIGNAL(triggered()), this, SLOT(getAvatar()));
connect( ui.actionSet_your_Personal_Message, SIGNAL(triggered()), this, SLOT(statusmessage()));
connect( ui.addfileButton, SIGNAL(clicked() ), this , SLOT(addExtraFile()));
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_Status_Column, SIGNAL(triggered()), this, SLOT(statusColumn()));
connect(ui.action_Hide_Offline_Friends, SIGNAL(triggered()), this, SLOT(insertPeers()));
connect(ui.action_Hide_Status_Column, SIGNAL(triggered()), this, SLOT(statusColumn()));
ui.peertabWidget->setTabPosition(QTabWidget::North);
ui.peertabWidget->addTab(new ProfileWidget(),QString(tr("Profile")));
ui.peertabWidget->addTab(new NewsFeed(),QString(tr("Friends Storm")));
ui.peertabWidget->setTabPosition(QTabWidget::North);
ui.peertabWidget->addTab(new ProfileWidget(),QString(tr("Profile")));
ui.peertabWidget->addTab(new NewsFeed(),QString(tr("Friends Storm")));
ui.peertreeWidget->setColumnCount(4);
ui.peertreeWidget->setColumnHidden ( 3, true);
ui.peertreeWidget->setColumnHidden ( 2, true);
ui.peertreeWidget->sortItems( 0, Qt::AscendingOrder );
ui.peertreeWidget->setColumnCount(4);
ui.peertreeWidget->setColumnHidden ( 3, true);
ui.peertreeWidget->setColumnHidden ( 2, true);
ui.peertreeWidget->sortItems( 0, Qt::AscendingOrder );
// set header text aligment
QTreeWidgetItem * headerItem = ui.peertreeWidget->headerItem();
headerItem->setTextAlignment(COLUMN_NAME, Qt::AlignHCenter | Qt::AlignVCenter);
headerItem->setTextAlignment(COLUMN_STATE, Qt::AlignLeft | Qt::AlignVCenter);
headerItem->setTextAlignment(COLUMN_INFO, Qt::AlignHCenter | Qt::AlignVCenter);
// set header text aligment
QTreeWidgetItem * headerItem = ui.peertreeWidget->headerItem();
headerItem->setTextAlignment(COLUMN_NAME, Qt::AlignHCenter | Qt::AlignVCenter);
headerItem->setTextAlignment(COLUMN_STATE, Qt::AlignLeft | Qt::AlignVCenter);
headerItem->setTextAlignment(COLUMN_INFO, Qt::AlignHCenter | Qt::AlignVCenter);
connect(ui.Sendbtn, SIGNAL(clicked()), this, SLOT(sendMsg()));
connect(ui.emoticonBtn, SIGNAL(clicked()), this, SLOT(smileyWidgetgroupchat()));
connect(ui.lineEdit, SIGNAL(textChanged ( ) ), this, SLOT(checkChat( ) ));
connect(ui.Sendbtn, SIGNAL(clicked()), this, SLOT(sendMsg()));
connect(ui.emoticonBtn, SIGNAL(clicked()), this, SLOT(smileyWidgetgroupchat()));
ui.lineEdit->setContextMenuPolicy(Qt::CustomContextMenu) ;
connect(ui.lineEdit,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(contextMenu(QPoint)));
ui.lineEdit->setContextMenuPolicy(Qt::CustomContextMenu) ;
connect(ui.lineEdit,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(contextMenu(QPoint)));
pasteLinkAct = new QAction(QIcon(":/images/pasterslink.png"), tr( "Paste retroshare Link" ), this );
connect( pasteLinkAct , SIGNAL( triggered() ), this, SLOT( pasteLink() ) );
pasteLinkAct = new QAction(QIcon(":/images/pasterslink.png"), tr( "Paste retroshare Link" ), this );
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.textunderlineChatButton, SIGNAL(clicked()), this, SLOT(setFont()));
connect(ui.textitalicChatButton, SIGNAL(clicked()), this, SLOT(setFont()));
connect(ui.fontsButton, SIGNAL(clicked()), this, SLOT(getFont()));
connect(ui.colorChatButton, SIGNAL(clicked()), this, SLOT(setColor()));
connect(ui.actionSave_History, SIGNAL(triggered()), this, SLOT(fileSaveAs()));
connect(ui.textboldChatButton, SIGNAL(clicked()), this, SLOT(setFont()));
connect(ui.textunderlineChatButton, SIGNAL(clicked()), this, SLOT(setFont()));
connect(ui.textitalicChatButton, SIGNAL(clicked()), this, SLOT(setFont()));
connect(ui.fontsButton, SIGNAL(clicked()), this, SLOT(getFont()));
connect(ui.colorChatButton, SIGNAL(clicked()), this, SLOT(setColor()));
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);
QPixmap pxm(16,16);
pxm.fill(_currentColor);
ui.colorChatButton->setIcon(pxm);
Settings->beginGroup(QString("Chat"));
mCurrentFont.fromString(Settings->value(QString::fromUtf8("ChatScreenFont")).toString());
ui.lineEdit->setFont(mCurrentFont);
mCurrentFont.fromString(Settings->valueFromGroup("Chat", QString::fromUtf8("ChatScreenFont")).toString());
ui.lineEdit->setFont(mCurrentFont);
setChatInfo(tr("Welcome to RetroShare's group chat."), QString::fromUtf8("blue"));
style.setStylePath(":/qss/chat/public");
style.loadEmoticons();
if (Settings->value(QString::fromUtf8("GroupChat_History"), true).toBool())
{
QStringList him;
historyKeeper.getMessages(him, "", "THIS", 8);
foreach(QString mess, him)
ui.msgText->append(mess);
}
Settings->endGroup();
setChatInfo(tr("Welcome to RetroShare's group chat."), QString::fromUtf8("blue"));
//setChatInfo(mess, "green");
if (Settings->valueFromGroup("Chat", QString::fromUtf8("GroupChat_History"), true).toBool()) {
historyKeeper.init(QString::fromStdString(RsInit::RsProfileConfigDirectory()) + "/chatPublic.xml");
QMenu * grpchatmenu = new QMenu();
grpchatmenu->addAction(ui.actionClearChat);
grpchatmenu->addAction(ui.actionSave_History);
grpchatmenu->addAction(ui.actionMessageHistory);
ui.menuButton->setMenu(grpchatmenu);
QList<IMHistoryItem> historyItems;
historyKeeper.getMessages(historyItems, 20);
foreach(IMHistoryItem item, historyItems) {
addChatMsg(item.incoming, true, item.name, item.sendTime, item.messageText);
}
}
_underline = false;
QMenu * grpchatmenu = new QMenu();
grpchatmenu->addAction(ui.actionClearChat);
grpchatmenu->addAction(ui.actionSave_History);
grpchatmenu->addAction(ui.actionMessageHistory);
ui.menuButton->setMenu(grpchatmenu);
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);
_underline = false;
ui.menupushButton->setMenu(menu);
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.msgText->setOpenExternalLinks ( false );
//ui.msgText->setOpenLinks ( false );
ui.menupushButton->setMenu(menu);
setAcceptDrops(true);
ui.lineEdit->setAcceptDrops(false);
//ui.msgText->setOpenExternalLinks ( false );
//ui.msgText->setOpenLinks ( false );
updateAvatar();
loadmypersonalstatus();
loadEmoticonsgroupchat();
displayMenu();
setAcceptDrops(true);
ui.lineEdit->setAcceptDrops(false);
// load settings
processSettings(true);
updateAvatar();
loadmypersonalstatus();
displayMenu();
// 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 ()));
// load settings
processSettings(true);
/* Hide platform specific features */
// 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
#endif
@ -269,8 +275,6 @@ PeersDialog::~PeersDialog ()
{
// save settings
processSettings(false);
delete smWidget;
}
void PeersDialog::processSettings(bool bLoad)
@ -314,6 +318,17 @@ void PeersDialog::processSettings(bool bLoad)
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()
{
ui.lineEdit->insertHtml(RSLinkClipboard::toHtml()) ;
@ -468,15 +483,7 @@ void PeersDialog::peertreeWidgetCostumPopupMenu( QPoint point )
void PeersDialog::updateDisplay()
{
// 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))) ;
}
insertPeers() ;
insertPeers() ;
}
/* 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()
{
std::list<ChatInfo> newchat;
@ -1100,19 +1135,11 @@ void PeersDialog::insertChat()
#ifdef PEERS_DEBUG
std::cerr << "got new chat." << std::endl;
#endif
QTextEdit *msgWidget = ui.msgText;
std::list<ChatInfo>::iterator it;
/* add in lines at the bottom */
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? */
if (it->chatflags & RS_CHAT_PRIVATE)
{
@ -1120,95 +1147,79 @@ void PeersDialog::insertChat()
continue;
}
std::ostringstream out;
QString extraTxt;
QDateTime sendTime = QDateTime::fromTime_t(it->sendTime);
QString name = QString::fromStdString(rsPeers->getPeerName(it->rsid));
QString msg = QString::fromStdWString(it->msg);
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
QString name = QString::fromStdString(peer_name);
QString line = "<span style=\"color:#C00000\">" + timestamp + "</span>" +
"<span style=\"color:#2D84C9\"><strong>" + " " + name + "</strong></span>";
QString msgContents = QString::fromStdWString(it->msg);
#ifdef PEERS_DEBUG
std::cerr << "PeersDialog::insertChat(): " << msg << std::endl;
#endif
//std::cerr << "PeersDialog::insertChat(): 1.11\n";
historyKeeper.addMessage(name, "THIS", msgContents);
//std::cerr << "PeersDialog::insertChat(): 1.12\n";
extraTxt += line;
bool incoming = false;
// notify with a systray icon msg
if(it->rsid != rsPeers->getOwnId())
{
incoming = true;
// This is a trick to translate HTML into text.
QTextEdit editor ;
editor.setHtml(QString::fromStdWString(it->msg));
QString notifyMsg(name+": "+editor.toPlainText()) ;
QTextEdit editor;
editor.setHtml(msg);
QString notifyMsg = name + ": " + editor.toPlainText();
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
emit notifyGroupChat(QString("New group chat"), notifyMsg);
}
// create a DOM tree object from the message and embed contents with HTML tags
QDomDocument doc;
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();
}
historyKeeper.addMessage(incoming, it->rsid, name, sendTime, msg);
addChatMsg(incoming, false, name, sendTime, msg);
}
}
void PeersDialog::checkChat()
bool PeersDialog::eventFilter(QObject *obj, QEvent *event)
{
/* if <return> at the end of the text -> we can send it! */
QTextEdit *chatWidget = ui.lineEdit;
std::string txt = chatWidget->toPlainText().toStdString();
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() ;
if (obj == ui.lineEdit) {
if (event->type() == QEvent::KeyPress) {
updateStatusTyping() ;
//std::cerr << "No <return> found in :" << txt << ":";
//std::cerr << std::endl;
}
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
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()
{
QTextEdit *lineWidget = ui.lineEdit;
//ci.msg = lineWidget->Text().toStdWString();
std::wstring message = lineWidget->toHtml().toStdWString();
if (lineWidget->toPlainText().isEmpty()) {
// nothing to send
return;
}
//historyKeeper.addMessage("THIS", "ALL", lineWidget->toHtml() );
std::wstring message = lineWidget->toHtml().toStdWString();
#ifdef PEERS_DEBUG
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()
{
ui.msgText->clear();
ui.msgText->clear();
historyKeeper.clear();
}
void PeersDialog::displayInfoChatMenu(const QPoint& pos)
@ -1385,143 +1397,14 @@ void PeersDialog::displayInfoChatMenu(const QPoint& pos)
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()
{
qDebug("MainWindow::smileyWidget()");
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();
style.showSmileyWidget(this, ui.emoticonBtn, SLOT(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 */
@ -1873,6 +1756,6 @@ void PeersDialog::statusColumn()
void PeersDialog::on_actionMessageHistory_triggered()
{
ImHistoryBrowser imBrowser(this);
ImHistoryBrowser imBrowser(historyKeeper, this);
imBrowser.exec();
}

View File

@ -22,7 +22,7 @@
#ifndef _PEERSDIALOG_H
#define _PEERSDIALOG_H
#include "chat/HandleRichText.h"
#include "chat/ChatStyle.h"
#include "RsAutoUpdatePage.h"
#include "mainpage.h"
@ -60,7 +60,6 @@ public:
/** Default Destructor */
~PeersDialog ();
void loadEmoticonsgroupchat();
// void setChatDialog(ChatDialog *cd);
virtual void updateDisplay() ; // overloaded from RsAutoUpdatePage
@ -96,6 +95,8 @@ public slots:
protected:
virtual void dragEnterEvent(QDragEnterEvent *event);
virtual void dropEvent(QDropEvent *event);
bool eventFilter(QObject *obj, QEvent *ev);
void showEvent (QShowEvent *event);
private slots:
void pasteLink() ;
@ -129,7 +130,6 @@ private slots:
void setColor();
void insertSendList();
void checkChat();
void sendMsg();
void statusmessage();
@ -166,6 +166,7 @@ signals:
private:
void processSettings(bool bLoad);
void addChatMsg(bool incoming, bool history, QString &name, QDateTime &sendTime, QString &message);
class QLabel *iconLabel, *textLabel;
class QWidget *widget;
@ -177,10 +178,6 @@ private:
QString fileName;
/** store default information for embedding HTML */
RsChat::EmbedInHtmlAhref defEmbedAhref;
RsChat::EmbedInHtmlImg defEmbedImg;
/* Worker Functions */
/* (1) Update Display */
@ -190,17 +187,13 @@ private:
/** Defines the actions for the context menu */
QAction* pasteLinkAct;
//QTreeWidget *peertreeWidget;
IMHistoryKeeper historyKeeper;
ChatStyle style;
QColor _currentColor;
bool _underline;
time_t last_status_send_time ;
QHash<QString, QString> smileys;
QWidget *smWidget;
QFont mCurrentFont; /* how the text will come out */
/** 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 <QFontDialog>
#include <QDir>
#include <QDesktopWidget>
#include <QFileDialog>
#include <QBuffer>
#include <QTextCodec>
@ -58,8 +57,6 @@
/* Define the format used for displaying the date and time */
#define DATETIME_FMT "MMM dd hh:mm:ss"
#include <sstream>
/*****
* #define CHAT_DEBUG 1
*****/
@ -101,10 +98,9 @@ PopupChatDialog::PopupChatDialog(std::string id, std::string name,
m_bInsertOnVisible = true;
loadEmoticons();
last_status_send_time = 0 ;
styleHtm = ":/qss/chat/default.htm";
style.setStylePath(":/qss/chat/private");
style.loadEmoticons();
/* Hide or show the frames */
showAvatarFrame(true);
@ -115,8 +111,6 @@ PopupChatDialog::PopupChatDialog(std::string id, std::string name,
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.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(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;
ui.chattextEdit->setContextMenuPolicy(Qt::CustomContextMenu) ;
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
QString customStateString = QString::fromStdString(rsMsgs->getCustomStateString(dialogId));
updatePeersCustomStateString(QString::fromStdString(dialogId), customStateString);
ui.chattextEdit->installEventFilter(this);
}
/** Destructor. */
@ -527,88 +526,87 @@ void PopupChatDialog::insertChatMsgs()
continue;
}
addChatMsg(it->rsid, it->msg);
addChatMsg(it->rsid, it->sendTime, it->msg);
}
playsound();
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 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
std::cout << "PopupChatDialog:addChatMsg message : " << message.toStdString() << std::endl;
#endif
if (Settings->valueFromGroup(QString("Chat"), QString::fromUtf8("Emoteicons_PrivatChat"), true).toBool())
{
QHashIterator<QString, QString> i(smileys);
while(i.hasNext())
{
i.next();
foreach(QString code, i.key().split("|"))
message.replace(code, "<img src=\"" + i.value() + "\" />");
}
unsigned int formatFlag = CHAT_FORMATMSG_EMBED_LINKS;
// embed smileys ?
if (Settings->valueFromGroup(QString("Chat"), QString::fromUtf8("Emoteicons_PrivatChat"), true).toBool()) {
formatFlag |= CHAT_FORMATMSG_EMBED_SMILEYS;
}
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)
.replace(color)
.replace(font)
.replace(fontSize)*/
.replace("%timestamp%", timestamp)
.replace("%name%", name)
.replace("%message%", message);
QString formatMsg = style.formatMessage(type, name, timestamp, message, formatFlag);
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() ;
}
void PopupChatDialog::checkChat()
bool PopupChatDialog::eventFilter(QObject *obj, QEvent *event)
{
/* if <return> at the end of the text -> we can send it! */
QTextEdit *chatWidget = ui.chattextEdit;
std::string txt = chatWidget->toPlainText().toStdString();
if ('\n' == txt[txt.length()-1] && txt.length()-1 == txt.find('\n')) /* only if on first line! */
sendChat();
else
updateStatusTyping() ;
if (obj == ui.chattextEdit) {
if (event->type() == QEvent::KeyPress) {
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()
{
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;
{
@ -620,13 +618,11 @@ void PopupChatDialog::sendChat()
rsiface->unlockData(); /* Unlock Interface */
}
std::wstring msg = chatWidget->toHtml().toStdWString();
#ifdef CHAT_DEBUG
std::cout << "PopupChatDialog:sendChat " << styleHtm.toStdString() << std::endl;
#endif
addChatMsg(ownId, msg);
addChatMsg(ownId, time(NULL), msg);
rsMsgs->sendPrivateChat(dialogId, msg);
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()
{
qDebug("MainWindow::smileyWidget()");
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();
style.showSmileyWidget(this, ui.emoteiconButton, SLOT(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()
{
ui.textBrowser->clear();
@ -903,27 +719,27 @@ void PopupChatDialog::on_actionClear_Chat_triggered()
void PopupChatDialog::changeStyle()
{
QString newStyle = QFileDialog::getOpenFileName(this, tr("Open Style"),
appDir + "/style/chat/",
tr("Styles (*.htm)"));
if(!newStyle.isEmpty())
{
QString wholeChat;
styleHtm = newStyle;
for(int i = 0; i < history.size(); i+=4)
{
QString formatMsg = loadEmptyStyle();
wholeChat += formatMsg.replace("%timestamp%", history.at(i+1))
.replace("%name%", history.at(i+2))
.replace("%message%", history.at(i+3)) + "\n";
}
ui.textBrowser->setHtml(wholeChat);
}
QTextCursor cursor = ui.textBrowser->textCursor();
cursor.movePosition(QTextCursor::End);
ui.textBrowser->setTextCursor(cursor);
// QString newStyle = QFileDialog::getOpenFileName(this, tr("Open Style"),
// appDir + "/style/chat/",
// tr("Styles (*.htm)"));
// if(!newStyle.isEmpty())
// {
// QString wholeChat;
// styleHtm = newStyle;
//
//
// for(int i = 0; i < history.size(); i+=4)
// {
// QString formatMsg = loadEmptyStyle();
// wholeChat += formatMsg.replace("%timestamp%", history.at(i+1))
// .replace("%name%", history.at(i+2))
// .replace("%message%", history.at(i+3)) + "\n";
// }
// ui.textBrowser->setHtml(wholeChat);
// }
// QTextCursor cursor = ui.textBrowser->textCursor();
// cursor.movePosition(QTextCursor::End);
// ui.textBrowser->setTextCursor(cursor);
}
void PopupChatDialog::updatePeerAvatar(const std::string& peer_id)
@ -1121,7 +937,7 @@ void PopupChatDialog::fileHashingFinished(AttachFileItem* file)
std::wstring msg = message.toStdWString();
addChatMsg(ownId, msg);
addChatMsg(ownId, time(NULL), msg);
rsMsgs->sendPrivateChat(dialogId, msg);
}

View File

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

View File

@ -26,6 +26,8 @@
#include "FeedHolder.h"
#include "../RsAutoUpdatePage.h"
#include "gui/msgs/MessageComposer.h"
#include "gui/chat/ChatStyle.h"
#include "gui/settings/rsharesettings.h"
#include "gui/notifyqt.h"
@ -137,7 +139,20 @@ void ChatMsgItem::insertChat(std::string &message)
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
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()

View File

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

View File

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

View File

@ -23,6 +23,7 @@
#include <QFile>
#include <QIODevice>
#include <QTimer>
#include <QtAlgorithms> //for qSort
@ -31,148 +32,137 @@
#include "IMHistoryReader.h"
#include "IMHistoryWriter.h"
//#include <iostream>
//=============================================================================
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()
{
//=== we have to save all messages
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);
saveHistory();
}
//=============================================================================
void
IMHistoryKeeper::addMessage(const QString fromID, const QString toID,
const QString messageText)
void IMHistoryKeeper::init(QString historyFileName)
{
IMHistoryItem item(fromID, toID, messageText,
QDateTime::currentDateTime());
hfName = historyFileName;
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 "
// << messageText.toStdString() << "\n";
//std::cerr << "IMHistoryKeeper::addMessage count is" << hitems.count();
}
//=============================================================================
int
IMHistoryKeeper::loadHistoryFile(QString fileName)
bool IMHistoryKeeper::loadHistoryFile()
{
qDebug() << " IMHistoryKeeper::loadHistoryFile is here";
QFile fl(fileName);
if ( !fl.exists() )
{
lastErrorMessage = QString("history file not found (%1)").arg(fileName) ;
return 1;
if (hfName.isEmpty()) {
lastErrorMessage = "history file not set";
return false;
}
QFile fl(hfName);
if (!fl.exists()) {
lastErrorMessage = QString("history file not found (%1)").arg(hfName) ;
return false;
}
IMHistoryReader hreader;
if( !hreader.read( hitems, fileName ) )
{
if (!hreader.read(hitems, hfName)) {
lastErrorMessage = hreader.errorMessage();
return 1;
return false;
}
qSort( hitems.begin(), hitems.end() ) ;
qSort(hitems.begin(), hitems.end());
qDebug() << " IMHistoryKeeper::loadHistoryFile finished";
return 0;
historyChanged = false;
return true;
}
//=============================================================================
QString
IMHistoryKeeper::errorMessage()
QString IMHistoryKeeper::errorMessage()
{
return lastErrorMessage;
lastErrorMessage = "No error" ;
QString errorMessage = lastErrorMessage;
lastErrorMessage.clear();
return errorMessage;
}
//=============================================================================
int
IMHistoryKeeper::getMessages(QStringList& messagesList,
const QString fromID, const QString toID,
const int messagesCount )
bool IMHistoryKeeper::getMessages(QList<IMHistoryItem> &historyItems, const int messagesCount)
{
int messFound = 0;
QList<IMHistoryItem> ril;//result item list
historyItems.clear();
QListIterator<IMHistoryItem> hii(hitems);
hii.toBack();
while (hii.hasPrevious() && (messFound<messagesCount))
{
while (hii.hasPrevious()) {
IMHistoryItem hitem = hii.previous();
if ( ( (fromID.isEmpty())&&( hitem.receiver()==toID) ) ||
( (hitem.sender()==fromID)&&( hitem.receiver()==toID) ) ||
( (hitem.receiver()== fromID)&&(hitem.sender()==toID) ) )
{
ril << hitem ;
messFound++;
if (messFound>=messagesCount)
break;
historyItems.insert(historyItems.begin(), hitem);
messFound++;
if (messagesCount && messFound >= messagesCount) {
break;
}
}
formStringList(ril, messagesList) ;
return 0; // successful end
return true; // successful end
}
//=============================================================================
void
IMHistoryKeeper::formStringList(QList<IMHistoryItem>& itemList,
QStringList& strList)
void IMHistoryKeeper::clear()
{
strList.clear();
hitems.clear();
historyChanged = true;
QListIterator<IMHistoryItem> hii(itemList);
hii.toBack();
while (hii.hasPrevious() )
{
IMHistoryItem hitem = hii.previous();
emit historyClear();
}
QString tline;
//=============================================================================
tline = QString("<strong><u>%1</u> %2 : </strong>"
"<span style=\"color:#008800\">%3</span>")
.arg(hitem.time().toString( Qt::TextDate ) )
.arg(hitem.sender())
.arg(hitem.text()) ;
void IMHistoryKeeper::saveHistory()
{
if (historyChanged && hfName.isEmpty() == false) {
//=== we have to save all messages
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 <QDebug>
#include <QString>
#include <QStringList>
#include "IMHistoryItem.h"
class QTimer;
//! 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
//! <?xml version="1.0" encoding="UTF-8"?>
//! <!DOCTYPE history_file>
//! <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
//! ...
@ -45,14 +46,14 @@
//! 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
//! 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:
IMHistoryKeeper();
IMHistoryKeeper(QString historyFileName);
//! A destructor
//! Warning: history messages will be saved to the file here. This means,
@ -62,32 +63,38 @@ public:
//! last error description
QString errorMessage();
//! initialize history keeper
void init(QString historyFileName);
//! Select messages from history
//! Fills given list with html-decorated messages (see formStringList(..))
//! Takes no more then messageText messages from history, where messages
//! 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);
//! Fills given list with items
bool getMessages(QList<IMHistoryItem> &historyItems, const int messagesCount);
//! Adds new message to the history
//! Adds new message to the history, but the message will be saved to
//! file only after destroing the object
void addMessage(const QString fromID, const QString toID,
const QString messageText);
void addMessage(bool incoming, std::string &id, const QString &name, const QDateTime &sendTime, const QString &messageText);
protected:
int loadHistoryFile(QString fileName);
void formStringList(QList<IMHistoryItem>& itemList, QStringList& strList);
//! Clear the history
void clear();
private:
bool loadHistoryFile();
QList<IMHistoryItem> hitems;
QString hfName ; //! history file name
bool historyChanged;
QString lastErrorMessage;
QTimer *saveTimer;
private slots:
void saveHistory();
signals:
void historyAdd(IMHistoryItem item) const;
void historyClear() const;
};
#endif // _HISTORY_KEEPER_H_

View File

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

View File

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

View File

@ -24,22 +24,63 @@
#include <QDateTime>
#include <QMenu>
#include <QClipboard>
//#include <QDomDocument>
#include "rshare.h"
//#include "gui/chat/HandleRichText.h"
/** Default constructor */
ImHistoryBrowser::ImHistoryBrowser(QWidget *parent, Qt::WFlags flags)
: QDialog(parent, flags), historyKeeper(Rshare::dataDirectory() + "/his1.xml")
ImHistoryBrowser::ImHistoryBrowser(IMHistoryKeeper &histKeeper, QWidget *parent, Qt::WFlags flags)
: QDialog(parent, flags), historyKeeper(histKeeper)
{
/* Invoke Qt Designer generated QObject setup routine */
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:
/** Default constructor */
ImHistoryBrowser(QWidget *parent = 0, Qt::WFlags flags = 0);
ImHistoryBrowser(IMHistoryKeeper &histKeeper, QWidget *parent = 0, Qt::WFlags flags = 0);
/** Default destructor */
private slots:
void historyAdd(IMHistoryItem item);
void historyClear();
private:
void addItem(IMHistoryItem &item);
IMHistoryKeeper historyKeeper;
IMHistoryKeeper &historyKeeper;
/** Qt Designer generated object */
Ui::ImHistoryBrowser ui;
};
#endif

View File

@ -449,11 +449,16 @@
<file>images/window_fullscreen.png</file>
<file>images/window_nofullscreen.png</file>
<file>layouts/default.ui</file>
<file>qss/chat/default.htm</file>
<file>qss/chat/default.css</file>
<file>qss/chat/second.htm</file>
<file>qss/chat/second.css</file>
<file>qss/chat/second.css</file>
<file>qss/chat/private/incoming.htm</file>
<file>qss/chat/private/outgoing.htm</file>
<file>qss/chat/private/hincoming.htm</file>
<file>qss/chat/private/houtgoing.htm</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/beer.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%'>
<tr>
<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>
</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
ChatPage::save(QString &errmsg)
{
Settings->beginGroup(QString("Chat"));
Settings->beginGroup(QString("Chat"));
Settings->setValue(QString::fromUtf8("Emoteicons_PrivatChat"), emotePrivatChat());
Settings->setValue(QString::fromUtf8("Emoteicons_GroupChat"), emoteGroupChat());
Settings->setValue(QString::fromUtf8("GroupChat_History"), groupchatHistory());
Settings->setValue(QString::fromUtf8("ChatScreenFont"), fontTempChat.toString());
Settings->setValue(QString::fromUtf8("Emoteicons_PrivatChat"), emotePrivatChat());
Settings->setValue(QString::fromUtf8("Emoteicons_GroupChat"), emoteGroupChat());
Settings->setValue(QString::fromUtf8("GroupChat_History"), groupchatHistory());
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 */
void
ChatPage::load()
{
Settings->beginGroup(QString("Chat"));
Settings->beginGroup(QString("Chat"));
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_groupchathistory->setChecked(Settings->value(QString::fromUtf8("GroupChat_History"), 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_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.labelChatFontPreview->setFont(fontTempChat);
ui.sendMessageWithCtrlReturn->setChecked(Settings->getChatSendMessageWithCtrlReturn());
ui.labelChatFontPreview->setText(fontTempChat.rawName());
ui.labelChatFontPreview->setFont(fontTempChat);
}
bool ChatPage::emotePrivatChat() const {

View File

@ -516,7 +516,7 @@
</property>
</widget>
</item>
<item row="0" column="1" rowspan="4">
<item row="0" column="1" rowspan="5">
<widget class="QGroupBox" name="groupBoxIRCColors">
<property name="maximumSize">
<size>
@ -609,7 +609,7 @@
</property>
</widget>
</item>
<item row="3" column="0">
<item row="4" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -622,6 +622,13 @@
</property>
</spacer>
</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>
</widget>
</item>

View File

@ -289,6 +289,16 @@ void RshareSettings::setAddFeedsAtEnd(bool 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. */
bool
RshareSettings::runRetroshareOnBoot()

View File

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