RetroShare/retroshare-gui/src/gui/notifyqt.cpp
2016-08-09 01:22:14 +02:00

1272 lines
33 KiB
C++

/****************************************************************
* This file is distributed under the following license:
*
* Copyright (c) 2010 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 <retroshare/rsgxsifacehelper.h>
#include <QInputDialog>
#include <QMessageBox>
#include <QTimer>
//#include <QMutexLocker>
#include <QDesktopWidget>
#include "notifyqt.h"
#include <retroshare/rsnotify.h>
#include <retroshare/rspeers.h>
#include <retroshare/rsidentity.h>
#include <util/rsdir.h>
#include "RsAutoUpdatePage.h"
#include "MainWindow.h"
#include "toaster/OnlineToaster.h"
#include "toaster/MessageToaster.h"
#include "toaster/DownloadToaster.h"
#include "toaster/ChatToaster.h"
#include "toaster/GroupChatToaster.h"
#include "toaster/ChatLobbyToaster.h"
#include "toaster/FriendRequestToaster.h"
#include "toaster/ToasterItem.h"
#include "common/ToasterNotify.h"
#include "chat/ChatDialog.h"
#include "chat/ChatLobbyDialog.h"
#include "chat/ChatWidget.h"
#include "FriendsDialog.h"
#include "gui/settings/rsharesettings.h"
#include "SoundManager.h"
#include "retroshare/rsplugin.h"
/*****
* #define NOTIFY_DEBUG
****/
/*static*/ NotifyQt *NotifyQt::_instance = NULL;
/*static*/ bool NotifyQt::_disableAllToaster = false;
/*static*/ NotifyQt *NotifyQt::Create ()
{
if (_instance == NULL) {
_instance = new NotifyQt ();
}
return _instance;
}
/*static*/ NotifyQt *NotifyQt::getInstance ()
{
return _instance;
}
/*static*/ bool NotifyQt::isAllDisable ()
{
return _disableAllToaster;
}
void NotifyQt::SetDisableAll(bool bValue)
{
if (bValue!=_disableAllToaster)
{
_disableAllToaster=bValue;
emit disableAllChanged(bValue);
}
}
NotifyQt::NotifyQt() : cDialog(NULL)
{
runningToasterTimer = new QTimer(this);
connect(runningToasterTimer, SIGNAL(timeout()), this, SLOT(runningTick()));
runningToasterTimer->setInterval(10); // tick 100 times a second
runningToasterTimer->setSingleShot(true);
{
QMutexLocker m(&_mutex) ;
_enabled = false ;
}
// register to allow sending over Qt::QueuedConnection
qRegisterMetaType<ChatId>("ChatId");
qRegisterMetaType<ChatMessage>("ChatMessage");
qRegisterMetaType<RsGxsChanges>("RsGxsChanges");
qRegisterMetaType<RsGxsId>("RsGxsId");
}
void NotifyQt::notifyErrorMsg(int list, int type, std::string msg)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
emit errorOccurred(list,type,QString::fromUtf8(msg.c_str())) ;
}
void NotifyQt::notifyChatMessage(const ChatMessage &msg)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "notifyQt: Received chat message " << std::endl ;
#endif
emit chatMessageReceived(msg);
}
void NotifyQt::notifyOwnAvatarChanged()
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "Notifyqt:: notified that own avatar changed" << std::endl ;
#endif
emit ownAvatarChanged() ;
}
class SignatureEventData
{
public:
SignatureEventData(const void *_data,int32_t _len,unsigned int _signlen, std::string _reason)
{
// We need a new memory chnk because there's no guarranty _sign nor _signlen are not in the stack
sign = (unsigned char *)rs_malloc(_signlen) ;
if(!sign)
{
signlen = NULL ;
signature_result = SELF_SIGNATURE_RESULT_FAILED ;
return ;
}
signlen = new unsigned int ;
*signlen = _signlen ;
signature_result = SELF_SIGNATURE_RESULT_PENDING ;
data = rs_malloc(_len) ;
if(!data)
{
len = 0 ;
return ;
}
len = _len ;
memcpy(data,_data,len) ;
reason = _reason ;
}
~SignatureEventData()
{
free(sign) ;
delete signlen ;
free(data) ;
}
void performSignature()
{
if(rsPeers->gpgSignData(data,len,sign,signlen,reason))
signature_result = SELF_SIGNATURE_RESULT_SUCCESS ;
else
signature_result = SELF_SIGNATURE_RESULT_FAILED ;
}
void *data ;
uint32_t len ;
unsigned char *sign ;
unsigned int *signlen ;
int signature_result ; // 0=pending, 1=done, 2=failed/cancelled.
std::string reason ;
};
bool NotifyQt::askForDeferredSelfSignature(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen,int& signature_result, std::string reason /*=""*/)
{
{
QMutexLocker m(&_mutex) ;
std::cerr << "NotifyQt:: deferred signature event requeted. " << std::endl;
// Look into the queue
Sha1CheckSum chksum = RsDirUtil::sha1sum((uint8_t*)data,len) ;
std::map<std::string,SignatureEventData*>::iterator it = _deferred_signature_queue.find(chksum.toStdString()) ;
signature_result = SELF_SIGNATURE_RESULT_PENDING ;
if(it != _deferred_signature_queue.end())
{
signature_result = it->second->signature_result ;
if(it->second->signature_result != SELF_SIGNATURE_RESULT_PENDING) // found it. Copy the result, and remove from the queue.
{
// We should check for the exact data match, for the sake of being totally secure.
//
std::cerr << "Found into queue: returning it" << std::endl;
memcpy(sign,it->second->sign,*it->second->signlen) ;
*signlen = *(it->second->signlen) ;
delete it->second ;
_deferred_signature_queue.erase(it) ;
}
return true ; // already registered, but not done yet.
}
// Not found. Store in the queue and emit a signal.
//
std::cerr << "NotifyQt:: deferred signature event requeted. Pushing into queue" << std::endl;
SignatureEventData *edta = new SignatureEventData(data,len,*signlen, reason) ;
_deferred_signature_queue[chksum.toStdString()] = edta ;
}
emit deferredSignatureHandlingRequested() ;
return true;
}
void NotifyQt::handleSignatureEvent()
{
std::cerr << "NotifyQt:: performing a deferred signature in the main GUI thread." << std::endl;
static bool working = false ;
if(!working)
{
working = true ;
for(std::map<std::string,SignatureEventData*>::const_iterator it(_deferred_signature_queue.begin());it!=_deferred_signature_queue.end();++it)
it->second->performSignature() ;
working = false ;
}
}
bool NotifyQt::askForPassword(const std::string& title, const std::string& key_details, bool prev_is_bad, std::string& password,bool& cancelled)
{
RsAutoUpdatePage::lockAllEvents() ;
QInputDialog dialog;
if (title == "") {
dialog.setWindowTitle(tr("PGP key passphrase"));
} else if (title == "AuthSSLimpl::SignX509ReqWithGPG()") {
dialog.setWindowTitle(tr("You need to sign your node's certificate."));
} else if (title == "p3IdService::service_CreateGroup()") {
dialog.setWindowTitle(tr("You need to sign your forum/chatrooms identity."));
} else {
dialog.setWindowTitle(QString::fromStdString(title));
}
dialog.setLabelText((prev_is_bad ? QString("%1\n\n").arg(tr("Wrong password !")) : QString()) + QString("%1:\n %2").arg(tr("Please enter your PGP password for key"), QString::fromUtf8(key_details.c_str())));
dialog.setTextEchoMode(QLineEdit::Password);
dialog.setModal(true);
int ret = dialog.exec();
cancelled = false ;
RsAutoUpdatePage::unlockAllEvents() ;
if (ret == QDialog::Rejected) {
password.clear() ;
cancelled = true ;
return true ;
}
if (ret == QDialog::Accepted) {
password = dialog.textValue().toUtf8().constData();
return true;
}
return false;
}
bool NotifyQt::askForPluginConfirmation(const std::string& plugin_file_name, const std::string& plugin_file_hash)
{
RsAutoUpdatePage::lockAllEvents() ;
QMessageBox dialog;
dialog.setWindowTitle(tr("Unregistered plugin/executable"));
QString text ;
text += tr( "RetroShare has detected an unregistered plugin. This happens in two cases:<UL><LI>Your RetroShare executable has changed.</LI><LI>The plugin has changed</LI></UL>Click on Yes to authorize this plugin, or No to deny it. You can change your mind later in Options -> Plugins, then restart." ) ;
text += "<UL>" ;
text += "<LI>Hash:\t" + QString::fromStdString(plugin_file_hash) + "</LI>" ;
text += "<LI>File:\t" + QString::fromStdString(plugin_file_name) + "</LI>";
text += "</UL>" ;
dialog.setText(text) ;
dialog.setWindowIcon(QIcon(":/icons/logo_128.png"));
dialog.setStandardButtons(QMessageBox::Yes | QMessageBox::No) ;
int ret = dialog.exec();
RsAutoUpdatePage::unlockAllEvents() ;
if (ret == QMessageBox::Yes)
return true ;
else
return false;
}
void NotifyQt::notifyDiscInfoChanged()
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "Notifyqt:: notified that discoveryInfo changed" << std::endl ;
#endif
emit discInfoChanged() ;
}
void NotifyQt::notifyDownloadComplete(const std::string& fileHash)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "Notifyqt::notifyDownloadComplete notified that a download is completed" << std::endl;
#endif
emit downloadComplete(QString::fromStdString(fileHash));
}
void NotifyQt::notifyDownloadCompleteCount(uint32_t count)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
std::cerr << "Notifyqt::notifyDownloadCompleteCount " << count << std::endl;
emit downloadCompleteCountChanged(count);
}
void NotifyQt::notifyDiskFull(uint32_t loc,uint32_t size_in_mb)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
std::cerr << "Notifyqt:: notified that disk is full" << std::endl ;
emit diskFull(loc,size_in_mb) ;
}
/* peer has changed the state */
void NotifyQt::notifyPeerStatusChanged(const std::string& peer_id, uint32_t state)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "Notifyqt:: notified that peer " << peer_id << " has changed the state to " << state << std::endl;
#endif
emit peerStatusChanged(QString::fromStdString(peer_id), state);
}
/* one or more peers has changed the states */
void NotifyQt::notifyPeerStatusChangedSummary()
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "Notifyqt:: notified that one peer has changed the state" << std::endl;
#endif
emit peerStatusChangedSummary();
}
void NotifyQt::notifyGxsChange(const RsGxsChanges& changes)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "Notifyqt:: notified that gxs has changes" << std::endl;
#endif
emit gxsChange(changes);
}
void NotifyQt::notifyOwnStatusMessageChanged()
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "Notifyqt:: notified that own avatar changed" << std::endl ;
#endif
emit ownStatusMessageChanged() ;
}
void NotifyQt::notifyPeerHasNewAvatar(std::string peer_id)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "notifyQt: notification of new avatar." << std::endl ;
#endif
emit peerHasNewAvatar(QString::fromStdString(peer_id)) ;
}
void NotifyQt::notifyCustomState(const std::string& peer_id, const std::string& status_string)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "notifyQt: Received custom status string notification" << std::endl ;
#endif
emit peerHasNewCustomStateString(QString::fromStdString(peer_id), QString::fromUtf8(status_string.c_str())) ;
}
void NotifyQt::notifyChatLobbyTimeShift(int shift)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "notifyQt: Received chat lobby time shift message: shift = " << shift << std::endl;
#endif
emit chatLobbyTimeShift(shift) ;
}
void NotifyQt::handleChatLobbyTimeShift(int /*shift*/)
{
return ; // we say nothing. The help dialog of lobbies explains this already.
static bool already = false ;
if(!already)
{
already = true ;
QString string = tr("For the chat lobbies to work properly, the time of your computer needs to be correct. Please check that this is the case (A possible time shift of several minutes was detected with your friends).") ;
QMessageBox::warning(NULL,tr("Please check your system clock."),string) ;
}
}
void NotifyQt::notifyChatLobbyEvent(uint64_t lobby_id,uint32_t event_type,const RsGxsId& nickname,const std::string& str)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "notifyQt: Received chat lobby event message: lobby #" << std::hex << lobby_id << std::dec << ", event=" << event_type << ", str=\"" << str << "\"" << std::endl ;
#endif
emit chatLobbyEvent(lobby_id,event_type,nickname,QString::fromUtf8(str.c_str())) ;
}
void NotifyQt::notifyChatStatus(const ChatId& chat_id,const std::string& status_string)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "notifyQt: Received chat status string: " << status_string << std::endl ;
#endif
emit chatStatusChanged(chat_id, QString::fromUtf8(status_string.c_str()));
}
void NotifyQt::notifyChatCleared(const ChatId& chat_id)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "notifyQt: Received chat cleared." << std::endl ;
#endif
emit chatCleared(chat_id);
}
void NotifyQt::notifyTurtleSearchResult(uint32_t search_id,const std::list<TurtleFileInfo>& files)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "in notify search result..." << std::endl ;
#endif
for(std::list<TurtleFileInfo>::const_iterator it(files.begin());it!=files.end();++it)
{
FileDetail det ;
det.rank = 0 ;
det.age = 0 ;
det.name = (*it).name ;
det.hash = (*it).hash ;
det.size = (*it).size ;
det.id.clear() ;
emit gotTurtleSearchResult(search_id,det) ;
}
}
void NotifyQt::notifyHashingInfo(uint32_t type, const std::string& fileinfo)
{
QString info;
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
switch (type) {
case NOTIFY_HASHTYPE_EXAMINING_FILES:
info = tr("Examining shared files...");
break;
case NOTIFY_HASHTYPE_FINISH:
break;
case NOTIFY_HASHTYPE_HASH_FILE:
info = tr("Hashing file") + " " + QString::fromUtf8(fileinfo.c_str());
break;
case NOTIFY_HASHTYPE_SAVE_FILE_INDEX:
info = tr("Saving file index...");
break;
}
emit hashingInfoChanged(info);
}
void NotifyQt::notifyHistoryChanged(uint32_t msgId, int type)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
emit historyChanged(msgId, type);
}
void NotifyQt::notifyListChange(int list, int type)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "NotifyQt::notifyListChange()" << std::endl;
#endif
switch(list)
{
case NOTIFY_LIST_NEIGHBOURS:
#ifdef NOTIFY_DEBUG
std::cerr << "received neighbours changed" << std::endl ;
#endif
emit neighboursChanged();
break;
case NOTIFY_LIST_FRIENDS:
#ifdef NOTIFY_DEBUG
std::cerr << "received friends changed" << std::endl ;
#endif
emit friendsChanged() ;
break;
case NOTIFY_LIST_DIRLIST_LOCAL:
#ifdef NOTIFY_DEBUG
std::cerr << "received files changed" << std::endl ;
#endif
emit filesPostModChanged(true) ; /* Local */
break;
case NOTIFY_LIST_CHAT_LOBBY_INVITATION:
#ifdef NOTIFY_DEBUG
std::cerr << "received files changed" << std::endl ;
#endif
emit chatLobbyInviteReceived() ; /* Local */
break;
case NOTIFY_LIST_DIRLIST_FRIENDS:
#ifdef NOTIFY_DEBUG
std::cerr << "received files changed" << std::endl ;
#endif
emit filesPostModChanged(false) ; /* Local */
break;
case NOTIFY_LIST_SEARCHLIST:
break;
case NOTIFY_LIST_MESSAGELIST:
#ifdef NOTIFY_DEBUG
std::cerr << "received msg changed" << std::endl ;
#endif
emit messagesChanged() ;
break;
case NOTIFY_LIST_MESSAGE_TAGS:
#ifdef NOTIFY_DEBUG
std::cerr << "received msg tags changed" << std::endl ;
#endif
emit messagesTagsChanged();
break;
case NOTIFY_LIST_CHANNELLIST:
break;
case NOTIFY_LIST_TRANSFERLIST:
#ifdef NOTIFY_DEBUG
std::cerr << "received transfer changed" << std::endl ;
#endif
emit transfersChanged() ;
break;
case NOTIFY_LIST_CONFIG:
#ifdef NOTIFY_DEBUG
std::cerr << "received config changed" << std::endl ;
#endif
emit configChanged() ;
break ;
#ifdef REMOVE
case NOTIFY_LIST_FORUMLIST_LOCKED:
#ifdef NOTIFY_DEBUG
std::cerr << "received forum msg changed" << std::endl ;
#endif
emit forumsChanged(); // use connect with Qt::QueuedConnection
break;
case NOTIFY_LIST_CHANNELLIST_LOCKED:
#ifdef NOTIFY_DEBUG
std::cerr << "received channel msg changed" << std::endl ;
#endif
emit channelsChanged(type); // use connect with Qt::QueuedConnection
break;
case NOTIFY_LIST_PUBLIC_CHAT:
#ifdef NOTIFY_DEBUG
std::cerr << "received public chat changed" << std::endl ;
#endif
emit publicChatChanged(type);
break;
case NOTIFY_LIST_PRIVATE_INCOMING_CHAT:
case NOTIFY_LIST_PRIVATE_OUTGOING_CHAT:
#ifdef NOTIFY_DEBUG
std::cerr << "received private chat changed" << std::endl ;
#endif
emit privateChatChanged(list, type);
break;
#endif
case NOTIFY_LIST_CHAT_LOBBY_LIST:
#ifdef NOTIFY_DEBUG
std::cerr << "received notify chat lobby list" << std::endl;
#endif
emit lobbyListChanged();
break;
case NOTIFY_LIST_GROUPLIST:
#ifdef NOTIFY_DEBUG
std::cerr << "received groups changed" << std::endl ;
#endif
emit groupsChanged(type);
break;
default:
break;
}
return;
}
void NotifyQt::notifyListPreChange(int list, int /*type*/)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "NotifyQt::notifyListPreChange()" << std::endl;
#endif
switch(list)
{
case NOTIFY_LIST_NEIGHBOURS:
break;
case NOTIFY_LIST_FRIENDS:
emit friendsChanged() ;
break;
case NOTIFY_LIST_DIRLIST_FRIENDS:
emit filesPreModChanged(false) ; /* remote */
break ;
case NOTIFY_LIST_DIRLIST_LOCAL:
emit filesPreModChanged(true) ; /* local */
break;
case NOTIFY_LIST_SEARCHLIST:
break;
case NOTIFY_LIST_MESSAGELIST:
break;
case NOTIFY_LIST_CHANNELLIST:
break;
case NOTIFY_LIST_TRANSFERLIST:
break;
default:
break;
}
return;
}
/* New Timer Based Update scheme ...
* means correct thread seperation
*
* uses Flags, to detect changes
*/
void NotifyQt::enable()
{
QMutexLocker m(&_mutex) ;
std::cerr << "Enabling notification system" << std::endl;
_enabled = true ;
}
void NotifyQt::UpdateGUI()
{
if(RsAutoUpdatePage::eventsLocked())
return ;
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
static bool already_updated = false ; // these only update once at start because they may already have been set before
// the gui is running, then they get updated by callbacks.
if(!already_updated)
{
emit messagesChanged() ;
emit neighboursChanged();
emit configChanged();
already_updated = true ;
}
/* Finally Check for PopupMessages / System Error Messages */
if (rsNotify)
{
uint32_t sysid;
uint32_t type;
std::string title, id, msg;
/* You can set timeToShow, timeToLive and timeToHide or can leave the standard */
ToasterItem *toaster = NULL;
if (rsNotify->NotifyPopupMessage(type, id, title, msg))
{
uint popupflags = Settings->getNotifyFlags();
switch(type)
{
case RS_POPUP_ENCRYPTED_MSG:
SoundManager::play(SOUND_MESSAGE_ARRIVED);
if ((popupflags & RS_POPUP_MSG) && !_disableAllToaster)
{
toaster = new ToasterItem(new MessageToaster("", tr("Encrypted message"), QString("[%1]").arg(tr("Encrypted message"))));
}
break;
case RS_POPUP_MSG:
SoundManager::play(SOUND_MESSAGE_ARRIVED);
if ((popupflags & RS_POPUP_MSG) && !_disableAllToaster)
{
toaster = new ToasterItem(new MessageToaster(id, QString::fromUtf8(title.c_str()), QString::fromUtf8(msg.c_str())));
}
break;
case RS_POPUP_CONNECT:
SoundManager::play(SOUND_USER_ONLINE);
if ((popupflags & RS_POPUP_CONNECT) && !_disableAllToaster)
{
toaster = new ToasterItem(new OnlineToaster(RsPeerId(id)));
}
break;
case RS_POPUP_DOWNLOAD:
SoundManager::play(SOUND_DOWNLOAD_COMPLETE);
if ((popupflags & RS_POPUP_DOWNLOAD) && !_disableAllToaster)
{
/* id = file hash */
toaster = new ToasterItem(new DownloadToaster(RsFileHash(id), QString::fromUtf8(title.c_str())));
}
break;
case RS_POPUP_CHAT:
if ((popupflags & RS_POPUP_CHAT) && !_disableAllToaster)
{
// TODO: fix for distant chat, look up if dstant chat uses RS_POPUP_CHAT
ChatDialog *chatDialog = ChatDialog::getChat(ChatId(RsPeerId(id)));
ChatWidget *chatWidget;
if (chatDialog && (chatWidget = chatDialog->getChatWidget()) && chatWidget->isActive()) {
// do not show when active
break;
}
toaster = new ToasterItem(new ChatToaster(RsPeerId(id), QString::fromUtf8(msg.c_str())));
}
break;
case RS_POPUP_GROUPCHAT:
if ((popupflags & RS_POPUP_GROUPCHAT) && !_disableAllToaster)
{
MainWindow *mainWindow = MainWindow::getInstance();
if (mainWindow && mainWindow->isActiveWindow() && !mainWindow->isMinimized()) {
if (MainWindow::getActivatePage() == MainWindow::Friends) {
if (FriendsDialog::isGroupChatActive()) {
// do not show when active
break;
}
}
}
toaster = new ToasterItem(new GroupChatToaster(RsPeerId(id), QString::fromUtf8(msg.c_str())));
}
break;
case RS_POPUP_CHATLOBBY:
if ((popupflags & RS_POPUP_CHATLOBBY) && !_disableAllToaster)
{
ChatId chat_id(id);
ChatDialog *chatDialog = ChatDialog::getChat(chat_id);
ChatWidget *chatWidget;
if (chatDialog && (chatWidget = chatDialog->getChatWidget()) && chatWidget->isActive()) {
// do not show when active
break;
}
ChatLobbyDialog *chatLobbyDialog = dynamic_cast<ChatLobbyDialog*>(chatDialog);
RsGxsId sender(title);
if (!chatLobbyDialog || chatLobbyDialog->isParticipantMuted(sender))
break; // participant is muted
toaster = new ToasterItem(new ChatLobbyToaster(chat_id.toLobbyId(), sender, QString::fromUtf8(msg.c_str())));
}
break;
case RS_POPUP_CONNECT_ATTEMPT:
if ((popupflags & RS_POPUP_CONNECT_ATTEMPT) && !_disableAllToaster)
{
// id = gpgid
// title = ssl name
// msg = peer id
toaster = new ToasterItem(new FriendRequestToaster(RsPgpId(id), QString::fromUtf8(title.c_str()), RsPeerId(msg)));
}
break;
}
}
/*Now check Plugins*/
if (!toaster) {
int pluginCount = rsPlugins->nbPlugins();
for (int i = 0; i < pluginCount; ++i) {
RsPlugin *rsPlugin = rsPlugins->plugin(i);
if (rsPlugin) {
ToasterNotify *toasterNotify = rsPlugin->qt_toasterNotify();
if (toasterNotify) {
toaster = toasterNotify->toasterItem();
continue;
}
}
}
}
if (toaster) {
/* init attributes */
toaster->widget->setWindowFlags(Qt::ToolTip | Qt::WindowStaysOnTopHint);
/* add toaster to waiting list */
//QMutexLocker lock(&waitingToasterMutex);
waitingToasterList.push_back(toaster);
}
if (rsNotify->NotifySysMessage(sysid, type, title, msg))
{
/* make a warning message */
switch(type)
{
case RS_SYS_ERROR:
QMessageBox::critical(MainWindow::getInstance(),
QString::fromUtf8(title.c_str()),
QString::fromUtf8(msg.c_str()));
break;
case RS_SYS_WARNING:
QMessageBox::warning(MainWindow::getInstance(),
QString::fromUtf8(title.c_str()),
QString::fromUtf8(msg.c_str()));
break;
default:
case RS_SYS_INFO:
QMessageBox::information(MainWindow::getInstance(),
QString::fromUtf8(title.c_str()),
QString::fromUtf8(msg.c_str()));
break;
}
}
if (rsNotify->NotifyLogMessage(sysid, type, title, msg))
{
/* make a log message */
std::string logMesString = title + " " + msg;
switch(type)
{
case RS_SYS_ERROR:
case RS_SYS_WARNING:
case RS_SYS_INFO:
emit logInfoChanged(QString::fromUtf8(logMesString.c_str()));
}
}
}
/* Now start the waiting toasters */
startWaitingToasters();
}
void NotifyQt::testToasters(uint notifyFlags, /*RshareSettings::enumToasterPosition*/ int position, QPoint margin)
{
QString title = tr("Test");
QString message = tr("This is a test.");
RsPeerId id = rsPeers->getOwnId();
RsPgpId pgpid = rsPeers->getGPGOwnId();
uint pos = 0;
while (notifyFlags) {
uint type = notifyFlags & (1 << pos);
notifyFlags &= ~(1 << pos);
++pos;
ToasterItem *toaster = NULL;
switch(type)
{
case RS_POPUP_ENCRYPTED_MSG:
toaster = new ToasterItem(new MessageToaster(std::string(), tr("Unknown title"), QString("[%1]").arg(tr("Encrypted message"))));
break;
case RS_POPUP_MSG:
toaster = new ToasterItem(new MessageToaster(id.toStdString(), title, message));
break;
case RS_POPUP_CONNECT:
toaster = new ToasterItem(new OnlineToaster(id));
break;
case RS_POPUP_DOWNLOAD:
toaster = new ToasterItem(new DownloadToaster(RsFileHash::random(), title));
break;
case RS_POPUP_CHAT:
toaster = new ToasterItem(new ChatToaster(id, message));
break;
case RS_POPUP_GROUPCHAT:
toaster = new ToasterItem(new GroupChatToaster(id, message));
break;
case RS_POPUP_CHATLOBBY:
{
std::list<RsGxsId> gxsid;
if(rsIdentity->getOwnIds(gxsid) && (gxsid.size() > 0)){
toaster = new ToasterItem(new ChatLobbyToaster(0, gxsid.front(), message));
}
break;
}
case RS_POPUP_CONNECT_ATTEMPT:
toaster = new ToasterItem(new FriendRequestToaster(pgpid, title, id));
break;
}
if (toaster) {
/* init attributes */
toaster->widget->setWindowFlags(Qt::ToolTip | Qt::WindowStaysOnTopHint);
toaster->position = (RshareSettings::enumToasterPosition) position;
toaster->margin = margin;
/* add toaster to waiting list */
//QMutexLocker lock(&waitingToasterMutex);
waitingToasterList.push_back(toaster);
}
}
}
void NotifyQt::testToaster(ToasterNotify *toasterNotify, /*RshareSettings::enumToasterPosition*/ int position, QPoint margin)
{
if (!toasterNotify) {
return;
}
ToasterItem *toaster = toasterNotify->testToasterItem();
if (toaster) {
/* init attributes */
toaster->widget->setWindowFlags(Qt::ToolTip | Qt::WindowStaysOnTopHint);
toaster->position = (RshareSettings::enumToasterPosition) position;
toaster->margin = margin;
/* add toaster to waiting list */
//QMutexLocker lock(&waitingToasterMutex);
waitingToasterList.push_back(toaster);
}
}
void NotifyQt::testToaster(QString tag, ToasterNotify *toasterNotify, /*RshareSettings::enumToasterPosition*/ int position, QPoint margin)
{
if (!toasterNotify) {
return;
}
ToasterItem *toaster = toasterNotify->testToasterItem(tag);
if (toaster) {
/* init attributes */
toaster->widget->setWindowFlags(Qt::ToolTip | Qt::WindowStaysOnTopHint);
toaster->position = (RshareSettings::enumToasterPosition) position;
toaster->margin = margin;
/* add toaster to waiting list */
//QMutexLocker lock(&waitingToasterMutex);
waitingToasterList.push_back(toaster);
}
}
void NotifyQt::notifyChatFontChanged()
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
emit chatFontChanged();
}
void NotifyQt::notifyChatStyleChanged(int /*ChatStyle::enumStyleType*/ styleType)
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
emit chatStyleChanged(styleType);
}
void NotifyQt::notifySettingsChanged()
{
emit settingsChanged();
}
void NotifyQt::startWaitingToasters()
{
{
//QMutexLocker lock(&waitingToasterMutex);
if (waitingToasterList.empty()) {
/* No toasters are waiting */
return;
}
}
{
//QMutexLocker lock(&runningToasterMutex);
if (runningToasterList.size() >= 3) {
/* Don't show more than 3 toasters at once */
return;
}
}
ToasterItem *toaster = NULL;
{
//QMutexLocker lock(&waitingToasterMutex);
if (waitingToasterList.size()) {
/* Take one toaster of the waiting list */
toaster = waitingToasterList.front();
waitingToasterList.pop_front();
}
}
if (toaster) {
//QMutexLocker lock(&runningToasterMutex);
/* Calculate positions */
QSize size = toaster->widget->size();
QDesktopWidget *desktop = QApplication::desktop();
QRect desktopGeometry = desktop->availableGeometry(desktop->primaryScreen());
switch (toaster->position) {
case RshareSettings::TOASTERPOS_TOPLEFT:
toaster->startPos = QPoint(desktopGeometry.left() + toaster->margin.x(), desktopGeometry.top() - size.height());
toaster->endPos = QPoint(toaster->startPos.x(), desktopGeometry.top() + toaster->margin.y());
break;
case RshareSettings::TOASTERPOS_TOPRIGHT:
toaster->startPos = QPoint(desktopGeometry.right() - size.width() - toaster->margin.x(), desktopGeometry.top() - size.height());
toaster->endPos = QPoint(toaster->startPos.x(), desktopGeometry.top() + toaster->margin.y());
break;
case RshareSettings::TOASTERPOS_BOTTOMLEFT:
toaster->startPos = QPoint(desktopGeometry.left() + toaster->margin.x(), desktopGeometry.bottom());
toaster->endPos = QPoint(toaster->startPos.x(), desktopGeometry.bottom() - size.height() - toaster->margin.y());
break;
case RshareSettings::TOASTERPOS_BOTTOMRIGHT: // default
default:
toaster->startPos = QPoint(desktopGeometry.right() - size.width() - toaster->margin.x(), desktopGeometry.bottom());
toaster->endPos = QPoint(toaster->startPos.x(), desktopGeometry.bottom() - size.height() - toaster->margin.y());
break;
}
/* Initialize widget */
toaster->widget->move(toaster->startPos);
/* Initialize toaster */
toaster->elapsedTimeToShow = 0;
toaster->elapsedTimeToLive = 0;
toaster->elapsedTimeToHide = 0;
/* Add toaster to the running list */
runningToasterList.push_front(toaster);
if (runningToasterTimer->isActive() == false) {
/* Start the toaster timer */
runningToasterTimer->start();
}
}
}
void NotifyQt::runningTick()
{
//QMutexLocker lock(&runningToasterMutex);
int interval = runningToasterTimer->interval();
QPoint diff;
QList<ToasterItem*>::iterator it = runningToasterList.begin();
while (it != runningToasterList.end()) {
ToasterItem *toaster = *it;
bool visible = true;
if (toaster->elapsedTimeToShow) {
/* Toaster is started, check for visible */
visible = toaster->widget->isVisible();
}
QPoint newPos;
enum { NOTHING, SHOW, HIDE } operation = NOTHING;
if (visible && toaster->elapsedTimeToShow <= toaster->timeToShow) {
/* Toaster is showing */
if (toaster->elapsedTimeToShow == 0) {
/* Toaster is not visible, show it now */
operation = SHOW;
}
toaster->elapsedTimeToShow += interval;
newPos = QPoint(toaster->startPos.x() - (toaster->startPos.x() - toaster->endPos.x()) * toaster->elapsedTimeToShow / toaster->timeToShow,
toaster->startPos.y() - (toaster->startPos.y() - toaster->endPos.y()) * toaster->elapsedTimeToShow / toaster->timeToShow);
} else if (visible && toaster->elapsedTimeToLive <= toaster->timeToLive) {
/* Toaster is living */
toaster->elapsedTimeToLive += interval;
newPos = toaster->endPos;
} else if (visible && toaster->elapsedTimeToHide <= toaster->timeToHide) {
/* Toaster is hiding */
toaster->elapsedTimeToHide += interval;
if (toaster->elapsedTimeToHide == toaster->timeToHide) {
/* Toaster is back at the start position, hide it */
operation = HIDE;
}
newPos = QPoint(toaster->startPos.x() - (toaster->startPos.x() - toaster->endPos.x()) * (toaster->timeToHide - toaster->elapsedTimeToHide) / toaster->timeToHide,
toaster->startPos.y() - (toaster->startPos.y() - toaster->endPos.y()) * (toaster->timeToHide - toaster->elapsedTimeToHide) / toaster->timeToHide);
} else {
/* Toaster is hidden, delete it */
it = runningToasterList.erase(it);
//delete(toaster->widget);
delete(toaster);
continue;
}
toaster->widget->move(newPos + diff);
diff += newPos - toaster->startPos;
QRect mask = QRect(0, 0, toaster->widget->width(), qAbs(toaster->startPos.y() - newPos.y()));
if (newPos.y() > toaster->startPos.y()) {
/* Toaster is moving from top */
mask.moveTop(toaster->widget->height() - (newPos.y() - toaster->startPos.y()));
}
toaster->widget->setMask(QRegion(mask));
switch (operation) {
case NOTHING:
break;
case SHOW:
toaster->widget->show();
break;
case HIDE:
toaster->widget->hide();
break;
}
++it;
}
if (runningToasterList.size()) {
/* There are more running toasters, start the timer again */
runningToasterTimer->start();
}
}