From 8213a2aa7790e290f84de2f35c256fba545bda52 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Sat, 4 Sep 2010 14:23:30 +0000 Subject: [PATCH] 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 --- libretroshare/src/retroshare/rsmsgs.h | 1 + libretroshare/src/services/p3chatservice.cc | 7 +- retroshare-gui/src/RetroShare.pro | 2 + retroshare-gui/src/gui/PeersDialog.cpp | 513 +++++++----------- retroshare-gui/src/gui/PeersDialog.h | 17 +- retroshare-gui/src/gui/chat/ChatStyle.cpp | 333 ++++++++++++ retroshare-gui/src/gui/chat/ChatStyle.h | 75 +++ .../src/gui/chat/PopupChatDialog.cpp | 354 +++--------- retroshare-gui/src/gui/chat/PopupChatDialog.h | 18 +- retroshare-gui/src/gui/feeds/ChatMsgItem.cpp | 17 +- .../src/gui/im_history/IMHistoryItem.cpp | 82 +-- .../src/gui/im_history/IMHistoryItem.h | 29 +- .../src/gui/im_history/IMHistoryKeeper.cpp | 154 +++--- .../src/gui/im_history/IMHistoryKeeper.h | 51 +- .../src/gui/im_history/IMHistoryReader.cpp | 201 ++++--- .../src/gui/im_history/IMHistoryReader.h | 5 +- .../src/gui/im_history/IMHistoryWriter.cpp | 32 +- .../src/gui/im_history/ImHistoryBrowser.cpp | 55 +- .../src/gui/im_history/ImHistoryBrowser.h | 14 +- retroshare-gui/src/gui/images.qrc | 15 +- retroshare-gui/src/gui/qss/chat/default.css | 28 - .../{default.htm => private/incoming.htm} | 2 +- .../src/gui/qss/chat/private/main.css | 51 ++ .../src/gui/qss/chat/private/outgoing.htm | 16 + .../src/gui/qss/chat/public/incoming.htm | 7 + .../src/gui/qss/chat/public/main.css | 31 ++ .../src/gui/qss/chat/public/outgoing.htm | 7 + retroshare-gui/src/gui/qss/chat/second.css | 25 - retroshare-gui/src/gui/qss/chat/second.htm | 28 - retroshare-gui/src/gui/settings/ChatPage.cpp | 34 +- retroshare-gui/src/gui/settings/ChatPage.ui | 11 +- .../src/gui/settings/rsharesettings.cpp | 10 + .../src/gui/settings/rsharesettings.h | 3 + 33 files changed, 1167 insertions(+), 1061 deletions(-) create mode 100644 retroshare-gui/src/gui/chat/ChatStyle.cpp create mode 100644 retroshare-gui/src/gui/chat/ChatStyle.h delete mode 100644 retroshare-gui/src/gui/qss/chat/default.css rename retroshare-gui/src/gui/qss/chat/{default.htm => private/incoming.htm} (68%) create mode 100644 retroshare-gui/src/gui/qss/chat/private/main.css create mode 100644 retroshare-gui/src/gui/qss/chat/private/outgoing.htm create mode 100644 retroshare-gui/src/gui/qss/chat/public/incoming.htm create mode 100644 retroshare-gui/src/gui/qss/chat/public/main.css create mode 100644 retroshare-gui/src/gui/qss/chat/public/outgoing.htm delete mode 100644 retroshare-gui/src/gui/qss/chat/second.css delete mode 100644 retroshare-gui/src/gui/qss/chat/second.htm diff --git a/libretroshare/src/retroshare/rsmsgs.h b/libretroshare/src/retroshare/rsmsgs.h index baf22490f..275a13ccc 100644 --- a/libretroshare/src/retroshare/rsmsgs.h +++ b/libretroshare/src/retroshare/rsmsgs.h @@ -127,6 +127,7 @@ class ChatInfo public: std::string rsid; unsigned int chatflags; + uint32_t sendTime; std::wstring msg; }; diff --git a/libretroshare/src/services/p3chatservice.cc b/libretroshare/src/services/p3chatservice.cc index 36d7fa586..04b11ad1c 100644 --- a/libretroshare/src/services/p3chatservice.cc +++ b/libretroshare/src/services/p3chatservice.cc @@ -529,9 +529,10 @@ bool p3ChatService::getPrivateChatQueue(std::string id, std::list &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) { diff --git a/retroshare-gui/src/RetroShare.pro b/retroshare-gui/src/RetroShare.pro index ba07d10af..ba009fbac 100644 --- a/retroshare-gui/src/RetroShare.pro +++ b/retroshare-gui/src/RetroShare.pro @@ -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 \ diff --git a/retroshare-gui/src/gui/PeersDialog.cpp b/retroshare-gui/src/gui/PeersDialog.cpp index b7dd62818..6bd959a1a 100644 --- a/retroshare-gui/src/gui/PeersDialog.cpp +++ b/retroshare-gui/src/gui/PeersDialog.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -32,7 +31,7 @@ #include "common/vmessagebox.h" #include -#include "rshare.h" +#include "retroshare/rsinit.h" #include "PeersDialog.h" #include #include @@ -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); - - last_status_send_time = 0 ; + /* Invoke the Qt Designer generated object setup routine */ + ui.setupUi(this); + 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.lineEdit, SIGNAL(textChanged ( ) ), this, SLOT(checkChat( ) )); - connect(ui.Sendbtn, SIGNAL(clicked()), this, SLOT(sendMsg())); - connect(ui.emoticonBtn, SIGNAL(clicked()), this, SLOT(smileyWidgetgroupchat())); + 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; - QPixmap pxm(16,16); - pxm.fill(_currentColor); - ui.colorChatButton->setIcon(pxm); + _currentColor = Qt::black; - Settings->beginGroup(QString("Chat")); - mCurrentFont.fromString(Settings->value(QString::fromUtf8("ChatScreenFont")).toString()); - ui.lineEdit->setFont(mCurrentFont); - - setChatInfo(tr("Welcome to RetroShare's group chat."), QString::fromUtf8("blue")); + QPixmap pxm(16,16); + pxm.fill(_currentColor); + ui.colorChatButton->setIcon(pxm); - 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(); + mCurrentFont.fromString(Settings->valueFromGroup("Chat", QString::fromUtf8("ChatScreenFont")).toString()); + ui.lineEdit->setFont(mCurrentFont); - //setChatInfo(mess, "green"); + style.setStylePath(":/qss/chat/public"); + style.loadEmoticons(); - QMenu * grpchatmenu = new QMenu(); - grpchatmenu->addAction(ui.actionClearChat); - grpchatmenu->addAction(ui.actionSave_History); - grpchatmenu->addAction(ui.actionMessageHistory); - ui.menuButton->setMenu(grpchatmenu); + setChatInfo(tr("Welcome to RetroShare's group chat."), QString::fromUtf8("blue")); - _underline = false; + if (Settings->valueFromGroup("Chat", QString::fromUtf8("GroupChat_History"), true).toBool()) { + historyKeeper.init(QString::fromStdString(RsInit::RsProfileConfigDirectory()) + "/chatPublic.xml"); - 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(); - loadEmoticonsgroupchat(); - displayMenu(); + QList historyItems; + historyKeeper.getMessages(historyItems, 20); + foreach(IMHistoryItem item, historyItems) { + addChatMsg(item.incoming, true, item.name, item.sendTime, item.messageText); + } + } - // load settings - processSettings(true); + QMenu * grpchatmenu = new QMenu(); + 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 - // 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 ())); + _underline = false; - /* 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("%1"); + 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("%1"); - 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 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::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 = "" + timestamp + "" + - "" + " " + name + ""; - 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 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 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 found in :" << txt << ":"; - //std::cerr << std::endl; - } + QKeyEvent *keyEvent = static_cast(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 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� widgetu do kt�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� w zale�no�ci od tego czy po lewej stronie - // jest wi�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� y - centrujemy w pionie - int y = w_pos.y() + w->height()/2 - e_size.height()/2; - // je�li wychodzi poza doln� kraw�d� to r�wnamy do niej - if (y + e_size.height() > s_size.height()) - y = s_size.height() - e_size.height(); - // je�li wychodzi poza g�rn� kraw�d� to r�wnamy do niej - if (y < 0) - y = 0; - // ustawiamy selektor na wyliczonej pozycji - smWidget->move(x, y); - - x = 0; - y = 0; - - QHashIterator 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(sender())->toolTip().split("|").first()); + ui.lineEdit->textCursor().insertText(qobject_cast(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(); } diff --git a/retroshare-gui/src/gui/PeersDialog.h b/retroshare-gui/src/gui/PeersDialog.h index 77c8c4fb4..a2ac7b297 100644 --- a/retroshare-gui/src/gui/PeersDialog.h +++ b/retroshare-gui/src/gui/PeersDialog.h @@ -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 smileys; - QWidget *smWidget; - QFont mCurrentFont; /* how the text will come out */ /** Qt Designer generated object */ diff --git a/retroshare-gui/src/gui/chat/ChatStyle.cpp b/retroshare-gui/src/gui/chat/ChatStyle.cpp new file mode 100644 index 000000000..cb02d6062 --- /dev/null +++ b/retroshare-gui/src/gui/chat/ChatStyle.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +#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 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� widgetu do kt�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� w zale�no�ci od tego czy po lewej stronie + // jest wi�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� y - centrujemy w pionie + int y = pos.y() + button->height()/2 - e_size.height()/2; + // je�li wychodzi poza doln� kraw�d� to r�wnamy do niej + if (y + e_size.height() > s_size.height()) + y = s_size.height() - e_size.height(); + // je�li wychodzi poza g�rn� kraw�d� to r�wnamy do niej + if (y < 0) + y = 0; + // ustawiamy selektor na wyliczonej pozycji + smWidget->move(x, y); + + x = 0; + y = 0; + + QHashIterator 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 ×tamp, 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 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) + "" + rx.cap(count) + "" + message.mid(pos + rx.matchedLength(), -1); +// message = tempMessg; +// } +// pos += rx.matchedLength() + 15; +// count ++; +// } + +// { +// QHashIterator i(smileys); +// while(i.hasNext()) +// { +// i.next(); +// foreach(QString code, i.key().split("|")) +// message.replace(code, ""); +// } +// } + + QString formatMsg = style.replace("%name%", name) + .replace("%timestamp%", timestamp.toString("hh:mm:ss")) + .replace("%message%", msg); + + return formatMsg; +} diff --git a/retroshare-gui/src/gui/chat/ChatStyle.h b/retroshare-gui/src/gui/chat/ChatStyle.h new file mode 100644 index 000000000..492180d8e --- /dev/null +++ b/retroshare-gui/src/gui/chat/ChatStyle.h @@ -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 +#include +#include + +#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 smileys; + +public: + /* Default constructor */ + ChatStyle(); + /* Default destructor */ + ~ChatStyle(); + + void setStylePath(QString path); + void loadEmoticons(); + + QString formatMessage(enumFormatMessage type, QString &name, QDateTime ×tamp, 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 diff --git a/retroshare-gui/src/gui/chat/PopupChatDialog.cpp b/retroshare-gui/src/gui/chat/PopupChatDialog.cpp index d57b1d4bc..c807145f7 100644 --- a/retroshare-gui/src/gui/chat/PopupChatDialog.cpp +++ b/retroshare-gui/src/gui/chat/PopupChatDialog.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -58,8 +57,6 @@ /* Define the format used for displaying the date and time */ #define DATETIME_FMT "MMM dd hh:mm:ss" -#include - /***** * #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 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); 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.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 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) + "" + rx.cap(count) + "" + 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 i(smileys); - while(i.hasNext()) - { - i.next(); - foreach(QString code, i.key().split("|")) - message.replace(code, ""); - } + 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 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(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� widgetu do kt�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� w zale�no�ci od tego czy po lewej stronie - // jest wi�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� y - centrujemy w pionie - int y = w_pos.y() + w->height()/2 - e_size.height()/2; - // je�li wychodzi poza doln� kraw�d� to r�wnamy do niej - if (y + e_size.height() > s_size.height()) - y = s_size.height() - e_size.height(); - // je�li wychodzi poza g�rn� kraw�d� to r�wnamy do niej - if (y < 0) - y = 0; - // ustawiamy selektor na wyliczonej pozycji - smWidget->move(x, y); - - - x = 0; - y = 0; - - QHashIterator 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(sender())->toolTip().split("|").first()); + ui.chattextEdit->textCursor().insertText(qobject_cast(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); } diff --git a/retroshare-gui/src/gui/chat/PopupChatDialog.h b/retroshare-gui/src/gui/chat/PopupChatDialog.h index aa399cef7..d80964ad4 100644 --- a/retroshare-gui/src/gui/chat/PopupChatDialog.h +++ b/retroshare-gui/src/gui/chat/PopupChatDialog.h @@ -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 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; diff --git a/retroshare-gui/src/gui/feeds/ChatMsgItem.cpp b/retroshare-gui/src/gui/feeds/ChatMsgItem.cpp index 2aed7db0e..d22d0f9c6 100644 --- a/retroshare-gui/src/gui/feeds/ChatMsgItem.cpp +++ b/retroshare-gui/src/gui/feeds/ChatMsgItem.cpp @@ -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() diff --git a/retroshare-gui/src/gui/im_history/IMHistoryItem.cpp b/retroshare-gui/src/gui/im_history/IMHistoryItem.cpp index 648803f00..c38d4ebf0 100644 --- a/retroshare-gui/src/gui/im_history/IMHistoryItem.cpp +++ b/retroshare-gui/src/gui/im_history/IMHistoryItem.cpp @@ -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()) ; -} \ No newline at end of file + return (sendTime < item.sendTime) ; +} diff --git a/retroshare-gui/src/gui/im_history/IMHistoryItem.h b/retroshare-gui/src/gui/im_history/IMHistoryItem.h index 6b4a2d0d7..ff16fda03 100644 --- a/retroshare-gui/src/gui/im_history/IMHistoryItem.h +++ b/retroshare-gui/src/gui/im_history/IMHistoryItem.h @@ -25,37 +25,20 @@ #include #include - - 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 diff --git a/retroshare-gui/src/gui/im_history/IMHistoryKeeper.cpp b/retroshare-gui/src/gui/im_history/IMHistoryKeeper.cpp index fb4516fb5..9277ecb9d 100644 --- a/retroshare-gui/src/gui/im_history/IMHistoryKeeper.cpp +++ b/retroshare-gui/src/gui/im_history/IMHistoryKeeper.cpp @@ -23,6 +23,7 @@ #include #include +#include #include //for qSort @@ -31,148 +32,137 @@ #include "IMHistoryReader.h" #include "IMHistoryWriter.h" -//#include - //============================================================================= 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 &historyItems, const int messagesCount) { int messFound = 0; - QList ril;//result item list + + historyItems.clear(); QListIterator hii(hitems); hii.toBack(); - while (hii.hasPrevious() && (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& itemList, - QStringList& strList) +void IMHistoryKeeper::clear() { - strList.clear(); + hitems.clear(); + historyChanged = true; - QListIterator hii(itemList); - hii.toBack(); - while (hii.hasPrevious() ) - { - IMHistoryItem hitem = hii.previous(); + emit historyClear(); +} - QString tline; +//============================================================================= - tline = QString("%1 %2 : " - "%3") - .arg(hitem.time().toString( Qt::TextDate ) ) - .arg(hitem.sender()) - .arg(hitem.text()) ; - - strList.append( tline ); +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 + + IMHistoryWriter wri; + wri.write(hitems, hfName); } } - -//============================================================================= - diff --git a/retroshare-gui/src/gui/im_history/IMHistoryKeeper.h b/retroshare-gui/src/gui/im_history/IMHistoryKeeper.h index 9c8974c02..cb2ccd4bf 100644 --- a/retroshare-gui/src/gui/im_history/IMHistoryKeeper.h +++ b/retroshare-gui/src/gui/im_history/IMHistoryKeeper.h @@ -25,18 +25,19 @@ #include #include #include -#include #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 //! //! //! -//! manual message +//! manual message //! ... //! other messages in ... tags //! ... @@ -45,49 +46,55 @@ //! 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, //! a IMHistoryKeeper object must be deleted properly. virtual ~IMHistoryKeeper(); - + //! 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 &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); - -protected: - int loadHistoryFile(QString fileName); - void formStringList(QList& itemList, QStringList& strList); + void addMessage(bool incoming, std::string &id, const QString &name, const QDateTime &sendTime, const QString &messageText); + + //! Clear the history + void clear(); + +private: + bool loadHistoryFile(); QList 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_ diff --git a/retroshare-gui/src/gui/im_history/IMHistoryReader.cpp b/retroshare-gui/src/gui/im_history/IMHistoryReader.cpp index 26cfc084a..a2885ab51 100644 --- a/retroshare-gui/src/gui/im_history/IMHistoryReader.cpp +++ b/retroshare-gui/src/gui/im_history/IMHistoryReader.cpp @@ -30,13 +30,12 @@ IMHistoryReader::IMHistoryReader() :errMess("No error") { - // nothing to do here + // nothing to do here } //============================================================================= -bool -IMHistoryReader::read(QList& resultList, +bool IMHistoryReader::read(QList& resultList, const QString fileName) { errMess = "No error"; @@ -45,154 +44,140 @@ IMHistoryReader::read(QList& 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(); - - QList::const_iterator hii;//history items iterator - for (hii = result.constBegin(); hii != result.constEnd(); ++hii) - resultList << *hii ; + } else { + resultList.clear(); + + QList::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 -IMHistoryReader::readHistory() +void IMHistoryReader::readUnknownElement() { Q_ASSERT(isStartElement()); - - // qDebug()<< " " << "node with message " << name() ; - QList rez; - - while (!atEnd()) - { - readNext(); - if (isEndElement()) - break; - - if (isStartElement()) - { - if ( name() == "message" ) - { - IMHistoryItem item = readMessage(); - rez.append(item); - } - else - readUnknownElement(); + qDebug()<< " " << "unknown node " << name().toString(); + + while (!atEnd()) { + readNext(); + if (isEndElement()) { + break; + } + + if (isStartElement()) { + readUnknownElement(); } } - - return rez; } //============================================================================= -//#include -IMHistoryItem -IMHistoryReader::readMessage() + +void IMHistoryReader::readHistory(QList &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); - } - - rez.setText( tstr ); + int ti = attributes().value("sendTime").toString().toInt(); + historyItem.sendTime = QDateTime::fromTime_t(ti); - //qDebug() << QString(" readMessage: %1, %2, %3, %4" ) - // .arg(rez.text()).arg(rez.sender()) - // .arg(rez.receiver()).arg(ti) ; - } + //=== after processing attributes, read the message text + QString tstr = readElementText(); - 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) ; + } } //============================================================================= diff --git a/retroshare-gui/src/gui/im_history/IMHistoryReader.h b/retroshare-gui/src/gui/im_history/IMHistoryReader.h index f3eb5efcc..80e809520 100644 --- a/retroshare-gui/src/gui/im_history/IMHistoryReader.h +++ b/retroshare-gui/src/gui/im_history/IMHistoryReader.h @@ -41,12 +41,11 @@ public: private: void readUnknownElement(); - QList readHistory(); - IMHistoryItem readMessage(); + void readHistory(QList &historyItems); + void readMessage(IMHistoryItem &historyItem); QString errMess; } ; - #endif diff --git a/retroshare-gui/src/gui/im_history/IMHistoryWriter.cpp b/retroshare-gui/src/gui/im_history/IMHistoryWriter.cpp index b28554e71..59be07fb4 100644 --- a/retroshare-gui/src/gui/im_history/IMHistoryWriter.cpp +++ b/retroshare-gui/src/gui/im_history/IMHistoryWriter.cpp @@ -22,9 +22,7 @@ #include "IMHistoryWriter.h" #include - #include - #include //============================================================================= @@ -32,27 +30,23 @@ IMHistoryWriter::IMHistoryWriter() :errMess("No error") { - // nothing to do here + // nothing to do here } //============================================================================= -bool -IMHistoryWriter::write(QList& itemList, - const QString fileName ) +bool IMHistoryWriter::write(QList& 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& 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(); } @@ -80,4 +74,4 @@ IMHistoryWriter::write(QList& itemList, qDebug() << " IMHistoryWriter::write done" ; return true; -} \ No newline at end of file +} diff --git a/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp b/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp index 351093f75..f4a41725e 100644 --- a/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp +++ b/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp @@ -24,22 +24,63 @@ #include #include #include +//#include #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 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 = "" + timestamp + "" + + "" + " " + item.name + ""; + + // 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); +} diff --git a/retroshare-gui/src/gui/im_history/ImHistoryBrowser.h b/retroshare-gui/src/gui/im_history/ImHistoryBrowser.h index 18069a44b..fea6e8f23 100644 --- a/retroshare-gui/src/gui/im_history/ImHistoryBrowser.h +++ b/retroshare-gui/src/gui/im_history/ImHistoryBrowser.h @@ -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 diff --git a/retroshare-gui/src/gui/images.qrc b/retroshare-gui/src/gui/images.qrc index 50d85f32a..b5777f25e 100644 --- a/retroshare-gui/src/gui/images.qrc +++ b/retroshare-gui/src/gui/images.qrc @@ -449,11 +449,16 @@ images/window_fullscreen.png images/window_nofullscreen.png layouts/default.ui - qss/chat/default.htm - qss/chat/default.css - qss/chat/second.htm - qss/chat/second.css - qss/chat/second.css + qss/chat/private/incoming.htm + qss/chat/private/outgoing.htm + qss/chat/private/hincoming.htm + qss/chat/private/houtgoing.htm + qss/chat/private/main.css + qss/chat/public/incoming.htm + qss/chat/public/outgoing.htm + qss/chat/public/hincoming.htm + qss/chat/public/houtgoing.htm + qss/chat/public/main.css smileys/angry.png smileys/beer.png smileys/cake.png diff --git a/retroshare-gui/src/gui/qss/chat/default.css b/retroshare-gui/src/gui/qss/chat/default.css deleted file mode 100644 index 931ca702a..000000000 --- a/retroshare-gui/src/gui/qss/chat/default.css +++ /dev/null @@ -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; - } - diff --git a/retroshare-gui/src/gui/qss/chat/default.htm b/retroshare-gui/src/gui/qss/chat/private/incoming.htm similarity index 68% rename from retroshare-gui/src/gui/qss/chat/default.htm rename to retroshare-gui/src/gui/qss/chat/private/incoming.htm index 3241ce01c..017935438 100644 --- a/retroshare-gui/src/gui/qss/chat/default.htm +++ b/retroshare-gui/src/gui/qss/chat/private/incoming.htm @@ -4,7 +4,7 @@ - +
%name%%timestamp% [%timestamp%]
diff --git a/retroshare-gui/src/gui/qss/chat/private/main.css b/retroshare-gui/src/gui/qss/chat/private/main.css new file mode 100644 index 000000000..f7e30f25e --- /dev/null +++ b/retroshare-gui/src/gui/qss/chat/private/main.css @@ -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; +} + diff --git a/retroshare-gui/src/gui/qss/chat/private/outgoing.htm b/retroshare-gui/src/gui/qss/chat/private/outgoing.htm new file mode 100644 index 000000000..45630b08b --- /dev/null +++ b/retroshare-gui/src/gui/qss/chat/private/outgoing.htm @@ -0,0 +1,16 @@ + + + + + + + +
%name%[%timestamp%]
+ + + + +
%message%
+ \ No newline at end of file diff --git a/retroshare-gui/src/gui/qss/chat/public/incoming.htm b/retroshare-gui/src/gui/qss/chat/public/incoming.htm new file mode 100644 index 000000000..ef2ae9ee7 --- /dev/null +++ b/retroshare-gui/src/gui/qss/chat/public/incoming.htm @@ -0,0 +1,7 @@ + + +%timestamp% +%name% +%message% diff --git a/retroshare-gui/src/gui/qss/chat/public/main.css b/retroshare-gui/src/gui/qss/chat/public/main.css new file mode 100644 index 000000000..3f18504d7 --- /dev/null +++ b/retroshare-gui/src/gui/qss/chat/public/main.css @@ -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; +} diff --git a/retroshare-gui/src/gui/qss/chat/public/outgoing.htm b/retroshare-gui/src/gui/qss/chat/public/outgoing.htm new file mode 100644 index 000000000..09c86bfee --- /dev/null +++ b/retroshare-gui/src/gui/qss/chat/public/outgoing.htm @@ -0,0 +1,7 @@ + + +%timestamp% +%name% +%message% diff --git a/retroshare-gui/src/gui/qss/chat/second.css b/retroshare-gui/src/gui/qss/chat/second.css deleted file mode 100644 index 213ed4cb1..000000000 --- a/retroshare-gui/src/gui/qss/chat/second.css +++ /dev/null @@ -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; - } diff --git a/retroshare-gui/src/gui/qss/chat/second.htm b/retroshare-gui/src/gui/qss/chat/second.htm deleted file mode 100644 index 4a871e583..000000000 --- a/retroshare-gui/src/gui/qss/chat/second.htm +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - -
-
- -
-
- %name% -
- - - - - -
%message%%timestamp%
-
- \ No newline at end of file diff --git a/retroshare-gui/src/gui/settings/ChatPage.cpp b/retroshare-gui/src/gui/settings/ChatPage.cpp index c45f9dd64..d75284816 100644 --- a/retroshare-gui/src/gui/settings/ChatPage.cpp +++ b/retroshare-gui/src/gui/settings/ChatPage.cpp @@ -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 { diff --git a/retroshare-gui/src/gui/settings/ChatPage.ui b/retroshare-gui/src/gui/settings/ChatPage.ui index 4754ca283..c2b2bf7b8 100644 --- a/retroshare-gui/src/gui/settings/ChatPage.ui +++ b/retroshare-gui/src/gui/settings/ChatPage.ui @@ -516,7 +516,7 @@ - + @@ -609,7 +609,7 @@ - + Qt::Vertical @@ -622,6 +622,13 @@ + + + + Send message with Ctrl+Return + + + diff --git a/retroshare-gui/src/gui/settings/rsharesettings.cpp b/retroshare-gui/src/gui/settings/rsharesettings.cpp index 5c6fab44a..994b665ab 100644 --- a/retroshare-gui/src/gui/settings/rsharesettings.cpp +++ b/retroshare-gui/src/gui/settings/rsharesettings.cpp @@ -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() diff --git a/retroshare-gui/src/gui/settings/rsharesettings.h b/retroshare-gui/src/gui/settings/rsharesettings.h index 0e145590f..029846a83 100644 --- a/retroshare-gui/src/gui/settings/rsharesettings.h +++ b/retroshare-gui/src/gui/settings/rsharesettings.h @@ -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);