RetroShare/retroshare-gui/src/gui/chat/ChatDialog.cpp
2018-02-04 17:51:26 +01:00

403 lines
10 KiB
C++

/****************************************************************
*
* RetroShare is distributed under the following license:
*
* Copyright (C) 2011, RetroShare Team
*
* 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 <QMessageBox>
#include <QCloseEvent>
#include <QMenu>
#include <QWidgetAction>
#include "ChatDialog.h"
#include "gui/common/PeerDefs.h"
#include "PopupChatDialog.h"
#include "PopupDistantChatDialog.h"
#include "ChatLobbyDialog.h"
#include "PopupChatWindow.h"
#include "gui/settings/rsharesettings.h"
#include "gui/SoundManager.h"
#include <retroshare/rsiface.h>
#include <retroshare/rsnotify.h>
#include <retroshare/rspeers.h>
static std::map<ChatId, ChatDialog*> chatDialogsList;
ChatDialog::ChatDialog(QWidget *parent, Qt::WindowFlags flags) :
QWidget(parent, flags)
{
setAttribute(Qt::WA_DeleteOnClose, true);
}
ChatDialog::~ChatDialog()
{
std::map<ChatId, ChatDialog *>::iterator it;
if (chatDialogsList.end() != (it = chatDialogsList.find(mChatId))) {
chatDialogsList.erase(it);
}
}
void ChatDialog::closeEvent(QCloseEvent *event)
{
if (!canClose()) {
event->ignore();
return;
}
emit dialogClose(this);
}
void ChatDialog::init(const ChatId &id, const QString &title)
{
mChatId = id;
ChatWidget *cw = getChatWidget();
if (cw) {
cw->init(id, title);
connect(cw, SIGNAL(infoChanged(ChatWidget*)), this, SLOT(chatInfoChanged(ChatWidget*)));
connect(cw, SIGNAL(newMessage(ChatWidget*)), this, SLOT(chatNewMessage(ChatWidget*)));
}
}
/*static*/ ChatDialog* ChatDialog::getExistingChat(ChatId id)
{
std::map<ChatId, ChatDialog*>::iterator it;
if (chatDialogsList.end() != (it = chatDialogsList.find(id))) {
/* exists already */
return it->second;
}
return NULL;
}
/*static*/ ChatDialog* ChatDialog::getChat(ChatId id, uint chatflags)
{
if(id.isBroadcast() || id.isNotSet())
return NULL; // broadcast is not handled by a chat dialog
/* see if it already exists */
ChatDialog *cd = getExistingChat(id);
if (cd == NULL) {
if(id.isDistantChatId())
chatflags = RS_CHAT_OPEN | RS_CHAT_FOCUS; // force open for distant chat
if (chatflags & RS_CHAT_OPEN) {
if (id.isLobbyId()) {
ChatLobbyDialog* cld = new ChatLobbyDialog(id.toLobbyId());
cld->init(ChatId(), "");
cd = cld;
}
else if(id.isDistantChatId())
{
PopupDistantChatDialog* pdcd = new PopupDistantChatDialog(id.toDistantChatId());
pdcd->init(id, "");
cd = pdcd;
}
else
{
RsPeerDetails sslDetails;
if (rsPeers->getPeerDetails(id.toPeerId(), sslDetails)) {
PopupChatDialog* pcd = new PopupChatDialog();
pcd->init(id, PeerDefs::nameWithLocation(sslDetails));
cd = pcd;
}
}
if(cd)
chatDialogsList[id] = cd;
}
}
if (cd == NULL) {
return NULL;
}
cd->showDialog(chatflags);
return cd;
}
/*static*/ void ChatDialog::cleanupChat()
{
PopupChatWindow::cleanup();
/* ChatDialog destuctor removes the entry from the map */
std::list<ChatDialog*> list;
std::map<ChatId, ChatDialog*>::iterator it;
for (it = chatDialogsList.begin(); it != chatDialogsList.end(); ++it) {
if (it->second) {
list.push_back(it->second);
}
}
chatDialogsList.clear();
std::list<ChatDialog*>::iterator it1;
for (it1 = list.begin(); it1 != list.end(); ++it1) {
delete (*it1);
}
}
/*static*/ void ChatDialog::closeChat(const ChatId &chat_id)
{
ChatDialog *chatDialog = getExistingChat(chat_id);
if (chatDialog) {
//delete chatDialog; // ChatDialog removes itself from the map
chatDialog->deleteLater();
}
}
/*static*/ void ChatDialog::chatMessageReceived(ChatMessage msg)
{
if(msg.chat_id.isBroadcast())
return; // broadcast is not handled by a chat dialog
if(msg.incoming && (msg.chat_id.isPeerId() || msg.chat_id.isDistantChatId()))
// play sound when recv a message
SoundManager::play(SOUND_NEW_CHAT_MESSAGE);
ChatDialog *cd = getChat(msg.chat_id, Settings->getChatFlags());
if(cd)
cd->addChatMsg(msg);
else
std::cerr << "ChatDialog::chatMessageReceived(): no ChatDialog for this message. Ignoring Message: " << msg.msg << std::endl;
}
/*static*/ void ChatDialog::chatFriend(const ChatId &peerId, const bool forceFocus)
{
getChat(peerId, forceFocus ? RS_CHAT_OPEN | RS_CHAT_FOCUS : RS_CHAT_OPEN);
// below is the old code witch does lots of error checking.
// because there are many different chat types, there are also different ways to check if the id is valid
// i think the chatservice should offer a method bool isChatAvailable(ChatId)
/*
if (peerId.isNull()){
return;
}
uint32_t distant_peer_status ;
if(rsMsgs->getDistantChatStatus(RsGxsId(peerId),distant_peer_status))
{
getChat(peerId, forceFocus ? RS_CHAT_OPEN | RS_CHAT_FOCUS : RS_CHAT_OPEN ); // use own flags
return ;
}
ChatLobbyId lid;
if (rsMsgs->isLobbyId(peerId, lid)) {
getChat(peerId, (forceFocus ? (RS_CHAT_OPEN | RS_CHAT_FOCUS) : RS_CHAT_OPEN));
}
RsPeerDetails detail;
if (!rsPeers->getPeerDetails(peerId, detail))
return;
if (detail.isOnlyGPGdetail) {
// Should not happen
//chatFriend(detail.gpg_id, forceFocus);
return;
}
getChat(peerId, forceFocus ? RS_CHAT_OPEN | RS_CHAT_FOCUS : RS_CHAT_OPEN);
*/
}
/*static*/ void ChatDialog::chatFriend(const RsPgpId &gpgId, const bool forceFocus)
{
if (gpgId.isNull()){
return;
}
RsPeerDetails detail;
if (!rsPeers->getGPGDetails(gpgId, detail))
return;
if (!detail.isOnlyGPGdetail) {
return;
}
//let's get the ssl child details
std::list<RsPeerId> sslIds;
rsPeers->getAssociatedSSLIds(detail.gpg_id, sslIds);
if (sslIds.size() == 1) {
// chat with the one ssl id (online or offline)
chatFriend(ChatId(sslIds.front()), forceFocus);
return;
}
// more than one ssl ids available, check for online
std::list<RsPeerId> onlineIds;
for (std::list<RsPeerId>::iterator it = sslIds.begin(); it != sslIds.end(); ++it) {
if (rsPeers->isOnline(*it)) {
onlineIds.push_back(*it);
}
}
if (onlineIds.size() == 1) {
// chat with the online ssl id
chatFriend(ChatId(onlineIds.front()), forceFocus);
return;
}
// show menu with online locations
QMenu menu;
QLabel* label = new QLabel("<strong>Select one of your friends locations to chat with</strong>");
QWidgetAction *widgetAction = new QWidgetAction(&menu);
widgetAction->setDefaultWidget(label);
menu.addAction(widgetAction);
QObject cleanupchildren;
for(std::list<RsPeerId>::iterator it = onlineIds.begin(); it != onlineIds.end(); ++it)
{
RsPeerDetails detail;
rsPeers->getPeerDetails(*it, detail);
menu.addAction(QString::fromUtf8(detail.location.c_str()), new ChatFriendMethod(&cleanupchildren, *it), SLOT(chatFriend()));
}
menu.exec(QCursor::pos());
}
void ChatDialog::addToParent(QWidget *newParent)
{
ChatWidget *cw = getChatWidget();
if (cw) {
cw->addToParent(newParent);
}
}
void ChatDialog::removeFromParent(QWidget *oldParent)
{
ChatWidget *cw = getChatWidget();
if (cw) {
cw->removeFromParent(oldParent);
}
}
bool ChatDialog::isTyping()
{
ChatWidget *cw = getChatWidget();
if (cw) {
return cw->isTyping();
}
return false;
}
bool ChatDialog::hasNewMessages()
{
ChatWidget *cw = getChatWidget();
if (cw) {
return cw->hasNewMessages();
}
return false;
}
QString ChatDialog::getPeerName(const ChatId& id) const
{
if(id.isPeerId())
return QString::fromUtf8(rsPeers->getPeerName(id.toPeerId()).c_str()) ;
else
return "ChatDialog::getPeerName(): invalid id type passed (RsPeerId is required). This is a bug.";
}
QString ChatDialog::getOwnName() const
{
if(mChatId.isPeerId())
return QString::fromUtf8(rsPeers->getPeerName(rsPeers->getOwnId()).c_str());
else
return "ChatDialog::getOwnName(): invalid id type passed (RsPeerId is required). This is a bug.";
}
void ChatDialog::setPeerStatus(uint32_t status)
{
ChatWidget *cw = getChatWidget();
if (cw)
{
// convert to virtual peer id
// this is only required for private and distant chat,
// because lobby and broadcast does not have a status
RsPeerId vpid;
if(mChatId.isPeerId())
vpid = mChatId.toPeerId();
if(mChatId.isDistantChatId())
vpid = RsPeerId(mChatId.toDistantChatId());
cw->updateStatus(QString::fromStdString(vpid.toStdString()), status);
}
}
int ChatDialog::getPeerStatus()
{
ChatWidget *cw = getChatWidget();
if (cw) {
return cw->getPeerStatus();
}
return 0;
}
QString ChatDialog::getTitle()
{
ChatWidget *cw = getChatWidget();
if (cw) {
return cw->getTitle();
}
return "";
}
void ChatDialog::focusDialog()
{
ChatWidget *cw = getChatWidget();
if (cw) {
cw->focusDialog();
}
}
bool ChatDialog::setStyle()
{
ChatWidget *cw = getChatWidget();
if (cw) {
return cw->setStyle();
}
return false;
}
const RSStyle *ChatDialog::getStyle()
{
ChatWidget *cw = getChatWidget();
if (cw) {
return cw->getStyle();
}
return NULL;
}
void ChatDialog::chatInfoChanged(ChatWidget*)
{
emit infoChanged(this);
}
void ChatDialog::chatNewMessage(ChatWidget*)
{
emit newMessage(this);
}