RetroShare/retroshare-gui/src/gui/GxsForumsDialog.cpp

731 lines
21 KiB
C++
Raw Normal View History

/****************************************************************
* RetroShare is distributed under the following license:
*
* Copyright (C) 2008 Robert Fernie
*
* 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 <QMenu>
#include <QMessageBox>
#include "GxsForumsDialog.h"
#include "gxs/GxsForumGroupDialog.h"
#include "gxsforums/GxsForumThreadWidget.h"
#include "settings/rsharesettings.h"
#include "RetroShareLink.h"
#include "channels/ShareKey.h"
#include "notifyqt.h"
// These should be in retroshare/ folder.
#include "gxs/rsgxsflags.h"
//#define DEBUG_FORUMS
/* Images for TreeWidget */
#define IMAGE_FOLDER ":/images/folder16.png"
#define IMAGE_FOLDERGREEN ":/images/folder_green.png"
#define IMAGE_FOLDERRED ":/images/folder_red.png"
#define IMAGE_FOLDERYELLOW ":/images/folder_yellow.png"
#define IMAGE_FORUM ":/images/konversation.png"
#define IMAGE_SUBSCRIBE ":/images/edit_add24.png"
#define IMAGE_UNSUBSCRIBE ":/images/cancel.png"
#define IMAGE_INFO ":/images/info16.png"
#define IMAGE_NEWFORUM ":/images/new_forum16.png"
#define IMAGE_FORUMAUTHD ":/images/konv_message2.png"
#define IMAGE_COPYLINK ":/images/copyrslink.png"
/*
* Transformation Notes:
* there are still a couple of things that the new forums differ from Old version.
* these will need to be addressed in the future.
* -> Missing Messages are not handled yet.
* -> Child TS (for sorting) is not handled by GXS, this will probably have to be done in the GUI.
* -> Need to handle IDs properly.
* -> Popularity not handled in GXS yet.
* -> Much more to do.
*/
/** Constructor */
GxsForumsDialog::GxsForumsDialog(QWidget *parent)
: RsAutoUpdatePage(1000,parent)
{
/* Invoke the Qt Designer generated object setup routine */
ui.setupUi(this);
/* Setup Queue */
mForumQueue = new TokenQueue(rsGxsForums->getTokenService(), this);
mTokenGroupSummary = 0;
mRequestGroupSummary = false;
connect(ui.forumTreeWidget, SIGNAL(treeCustomContextMenuRequested(QPoint)), this, SLOT(forumListCustomPopupMenu(QPoint)));
connect(ui.newForumButton, SIGNAL(clicked()), this, SLOT(newforum()));
connect(ui.forumTreeWidget, SIGNAL(treeItemClicked(QString)), this, SLOT(changedForum(QString)));
connect(ui.threadTabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(threadTabCloseRequested(int)));
connect(NotifyQt::getInstance(), SIGNAL(forumMsgReadSatusChanged(QString,QString,int)), this, SLOT(forumMsgReadSatusChanged(QString,QString,int)));
// HACK - TEMPORARY HIJACKING THIS BUTTON FOR REFRESH.
connect(ui.refreshButton, SIGNAL(clicked()), this, SLOT(forceUpdateDisplay()));
/* Set initial size the splitter */
QList<int> sizes;
sizes << 300 << width(); // Qt calculates the right sizes
ui.splitter->setSizes(sizes);
/* create forum tree */
yourForums = ui.forumTreeWidget->addCategoryItem(tr("Your Forums"), QIcon(IMAGE_FOLDER), true);
subscribedForums = ui.forumTreeWidget->addCategoryItem(tr("Subscribed Forums"), QIcon(IMAGE_FOLDERRED), true);
popularForums = ui.forumTreeWidget->addCategoryItem(tr("Popular Forums"), QIcon(IMAGE_FOLDERGREEN), false);
otherForums = ui.forumTreeWidget->addCategoryItem(tr("Other Forums"), QIcon(IMAGE_FOLDERYELLOW), false);
// load settings
processSettings(true);
/* Hide platform specific features */
#ifdef Q_WS_WIN
#endif
}
GxsForumsDialog::~GxsForumsDialog()
{
// save settings
processSettings(false);
delete(mForumQueue);
}
//#AFTER MERGE UserNotify *GxsForumsDialog::getUserNotify(QObject *parent)
//{
// return new GxsForumUserNotify(parent);
//}
void GxsForumsDialog::processSettings(bool bLoad)
{
Settings->beginGroup(QString("GxsForumsDialog"));
if (bLoad) {
// load settings
// state of splitter
ui.splitter->restoreState(Settings->value("Splitter").toByteArray());
} else {
// save settings
// state of splitter
Settings->setValue("Splitter", ui.splitter->saveState());
}
ui.forumTreeWidget->processSettings(Settings, bLoad);
Settings->endGroup();
}
void GxsForumsDialog::forumListCustomPopupMenu(QPoint /*point*/)
{
int subscribeFlags = ui.forumTreeWidget->subscribeFlags(QString::fromStdString(mForumId));
QMenu contextMnu(this);
QAction *action = contextMnu.addAction(QIcon(IMAGE_SUBSCRIBE), tr("Subscribe to Forum"), this, SLOT(subscribeToForum()));
action->setDisabled (mForumId.empty() || IS_GROUP_SUBSCRIBED(subscribeFlags));
action = contextMnu.addAction(QIcon(IMAGE_UNSUBSCRIBE), tr("Unsubscribe to Forum"), this, SLOT(unsubscribeToForum()));
action->setEnabled (!mForumId.empty() && IS_GROUP_SUBSCRIBED(subscribeFlags));
contextMnu.addSeparator();
contextMnu.addAction(QIcon(IMAGE_NEWFORUM), tr("New Forum"), this, SLOT(newforum()));
action = contextMnu.addAction(QIcon(IMAGE_INFO), tr("Show Forum Details"), this, SLOT(showForumDetails()));
action->setEnabled (!mForumId.empty ());
action = contextMnu.addAction(QIcon(":/images/settings16.png"), tr("Edit Forum Details"), this, SLOT(editForumDetails()));
action->setEnabled (!mForumId.empty () && IS_GROUP_ADMIN(subscribeFlags));
QAction *shareKeyAct = new QAction(QIcon(":/images/gpgp_key_generate.png"), tr("Share Forum"), &contextMnu);
connect( shareKeyAct, SIGNAL( triggered() ), this, SLOT( shareKey() ) );
shareKeyAct->setEnabled(!mForumId.empty() && IS_GROUP_ADMIN(subscribeFlags));
contextMnu.addAction( shareKeyAct);
QAction *restoreKeysAct = new QAction(QIcon(":/images/settings16.png"), tr("Restore Publish Rights for Forum" ), &contextMnu);
connect( restoreKeysAct , SIGNAL( triggered() ), this, SLOT( restoreForumKeys() ) );
restoreKeysAct->setEnabled(!mForumId.empty() && !IS_GROUP_ADMIN(subscribeFlags));
contextMnu.addAction( restoreKeysAct);
action = contextMnu.addAction(QIcon(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyForumLink()));
action->setEnabled(!mForumId.empty());
contextMnu.addSeparator();
action = contextMnu.addAction(QIcon(":/images/message-mail-read.png"), tr("Mark all as read"), this, SLOT(markMsgAsReadAll()));
action->setEnabled (!mForumId.empty () && IS_GROUP_SUBSCRIBED(subscribeFlags));
action = contextMnu.addAction(QIcon(":/images/message-mail.png"), tr("Mark all as unread"), this, SLOT(markMsgAsUnreadAll()));
action->setEnabled (!mForumId.empty () && IS_GROUP_SUBSCRIBED(subscribeFlags));
#ifdef DEBUG_FORUMS
contextMnu.addSeparator();
action = contextMnu.addAction("Generate mass data", this, SLOT(generateMassData()));
action->setEnabled (!mCurrForumId.empty() && IS_GROUP_SUBSCRIBED(mSubscribeFlags));
#endif
contextMnu.exec(QCursor::pos());
}
void GxsForumsDialog::restoreForumKeys(void)
{
QMessageBox::warning(this, "RetroShare", "ToDo");
#ifdef TOGXS
rsGxsForums->groupRestoreKeys(mCurrForumId);
#endif
}
void GxsForumsDialog::updateDisplay()
{
std::list<std::string> forumIds;
std::list<std::string>::iterator it;
if (!rsGxsForums)
return;
#if 0
// TODO groupsChanged... HACK XXX.
if ((rsGxsForums->groupsChanged(forumIds)) || (rsGxsForums->updated()))
{
/* update Forums List */
insertForums();
it = std::find(forumIds.begin(), forumIds.end(), mCurrForumId);
if (it != forumIds.end())
{
/* update threads as well */
insertThreads();
}
}
#endif
/* The proper version (above) can be done with a data request -> TODO */
if (rsGxsForums->updated())
{
/* update Forums List */
insertForums();
}
}
// HACK until update works.
void GxsForumsDialog::forceUpdateDisplay()
{
std::cerr << "GxsForumsDialog::forceUpdateDisplay()";
std::cerr << std::endl;
/* update Forums List */
insertForums();
}
void GxsForumsDialog::forumInfoToGroupItemInfo(const RsGroupMetaData &forumInfo, GroupItemInfo &groupItemInfo)
{
groupItemInfo.id = QString::fromStdString(forumInfo.mGroupId);
groupItemInfo.name = QString::fromUtf8(forumInfo.mGroupName.c_str());
//groupItemInfo.description = QString::fromUtf8(forumInfo.forumDesc);
groupItemInfo.popularity = forumInfo.mPop;
groupItemInfo.lastpost = QDateTime::fromTime_t(forumInfo.mLastPost);
groupItemInfo.subscribeFlags = forumInfo.mSubscribeFlags;
#if TOGXS
if (forumInfo.mGroupFlags & RS_DISTRIB_AUTHEN_REQ) {
groupItemInfo.name += " (" + tr("AUTHD") + ")";
groupItemInfo.icon = QIcon(IMAGE_FORUMAUTHD);
}
else
#endif
{
groupItemInfo.icon = QIcon(IMAGE_FORUM);
}
}
/***** INSERT FORUM LISTS *****/
void GxsForumsDialog::insertForumsData(const std::list<RsGroupMetaData> &forumList)
{
std::list<RsGroupMetaData>::const_iterator it;
QList<GroupItemInfo> adminList;
QList<GroupItemInfo> subList;
QList<GroupItemInfo> popList;
QList<GroupItemInfo> otherList;
std::multimap<uint32_t, GroupItemInfo> popMap;
for (it = forumList.begin(); it != forumList.end(); it++) {
/* sort it into Publish (Own), Subscribed, Popular and Other */
uint32_t flags = it->mSubscribeFlags;
GroupItemInfo groupItemInfo;
forumInfoToGroupItemInfo(*it, groupItemInfo);
if (IS_GROUP_ADMIN(flags)) {
adminList.push_back(groupItemInfo);
} else if (IS_GROUP_SUBSCRIBED(flags)) {
/* subscribed forum */
subList.push_back(groupItemInfo);
} else {
/* rate the others by popularity */
popMap.insert(std::make_pair(it->mPop, groupItemInfo));
}
}
/* iterate backwards through popMap - take the top 5 or 10% of list */
uint32_t popCount = 5;
if (popCount < popMap.size() / 10)
{
popCount = popMap.size() / 10;
}
uint32_t i = 0;
uint32_t popLimit = 0;
std::multimap<uint32_t, GroupItemInfo>::reverse_iterator rit;
for(rit = popMap.rbegin(); ((rit != popMap.rend()) && (i < popCount)); rit++, i++) ;
if (rit != popMap.rend()) {
popLimit = rit->first;
}
for (rit = popMap.rbegin(); rit != popMap.rend(); rit++) {
if (rit->second.popularity < (int) popLimit) {
otherList.append(rit->second);
} else {
popList.append(rit->second);
}
}
/* now we can add them in as a tree! */
ui.forumTreeWidget->fillGroupItems(yourForums, adminList);
ui.forumTreeWidget->fillGroupItems(subscribedForums, subList);
ui.forumTreeWidget->fillGroupItems(popularForums, popList);
ui.forumTreeWidget->fillGroupItems(otherForums, otherList);
updateMessageSummaryList("");
}
void GxsForumsDialog::changedForum(const QString &id)
{
mForumId = id.toStdString();
if (mForumId.empty()) {
return;
}
// requestGroupSummary_CurrentForum(mForumId);
/* search exisiting tab */
GxsForumThreadWidget *threadWidget = NULL;
int tabCount = ui.threadTabWidget->count();
for (int index = 0; index < tabCount; ++index) {
GxsForumThreadWidget *childWidget = dynamic_cast<GxsForumThreadWidget*>(ui.threadTabWidget->widget(index));
if (childWidget && childWidget->forumId() == id.toStdString()) {
threadWidget = childWidget;
break;
}
}
if (!threadWidget) {
/* create a thread widget */
threadWidget = new GxsForumThreadWidget(id.toStdString());
int index = ui.threadTabWidget->addTab(threadWidget, threadWidget->forumName());
ui.threadTabWidget->setTabIcon(index, threadWidget->forumIcon());
connect(threadWidget, SIGNAL(forumChanged(QWidget*)), this, SLOT(threadTabChanged(QWidget*)));
}
ui.threadTabWidget->setCurrentWidget(threadWidget);
}
void GxsForumsDialog::threadTabCloseRequested(int index)
{
GxsForumThreadWidget *threadWidget = dynamic_cast<GxsForumThreadWidget*>(ui.threadTabWidget->widget(index));
if (threadWidget) {
delete(threadWidget);
}
}
void GxsForumsDialog::threadTabChanged(QWidget *widget)
{
int index = ui.threadTabWidget->indexOf(widget);
if (index < 0) {
return;
}
GxsForumThreadWidget *threadWidget = dynamic_cast<GxsForumThreadWidget*>(ui.threadTabWidget->widget(index));
if (!threadWidget) {
return;
}
ui.threadTabWidget->setTabText(index, threadWidget->forumName());
ui.threadTabWidget->setTabIcon(index, threadWidget->forumIcon());
}
QString GxsForumsDialog::titleFromInfo(const RsMsgMetaData &meta)
{
// NOTE - NOTE SURE HOW THIS WILL WORK!
#ifdef TOGXS
if (meta.mMsgStatus & RS_DISTRIB_MISSING_MSG) {
return QApplication::translate("GxsForumsDialog", "[ ... Missing Message ... ]");
}
#endif
return QString::fromUtf8(meta.mMsgName.c_str());
}
QString GxsForumsDialog::messageFromInfo(const RsGxsForumMsg &msg)
{
#ifdef TOGXS
if (msg.mMeta.mMsgStatus & RS_DISTRIB_MISSING_MSG) {
return QApplication::translate("GxsForumsDialog", "Placeholder for missing Message");
}
#endif
return QString::fromUtf8(msg.mMsg.c_str());
}
void GxsForumsDialog::copyForumLink()
{
if (mForumId.empty()) {
return;
}
// THIS CODE CALLS getForumInfo() to verify that the Ids are valid.
// As we are switching to Request/Response this is now harder to do...
// So not bothering any more - shouldn't be necessary.
// IF we get errors - fix them, rather than patching here.
#if 0
ForumInfo fi;
if (rsGxsForums->getForumInfo(mCurrForumId, fi)) {
RetroShareLink link;
if (link.createForum(fi.forumId, "")) {
QList<RetroShareLink> urls;
urls.push_back(link);
RSLinkClipboard::copyLinks(urls);
}
}
#endif
QMessageBox::warning(this, "RetroShare", "ToDo");
}
void GxsForumsDialog::newforum()
{
GxsForumGroupDialog cf(mForumQueue, this);
cf.exec ();
}
void GxsForumsDialog::subscribeToForum()
{
forumSubscribe(true);
}
void GxsForumsDialog::unsubscribeToForum()
{
forumSubscribe(false);
}
void GxsForumsDialog::forumSubscribe(bool subscribe)
{
if (mForumId.empty()) {
return;
}
uint32_t token;
rsGxsForums->subscribeToGroup(token, mForumId, subscribe);
}
void GxsForumsDialog::showForumDetails()
{
if (mForumId.empty()) {
return;
}
RsGxsForumGroup grp;
grp.mMeta.mGroupId = mForumId;
GxsForumGroupDialog cf(grp, GxsGroupDialog::MODE_SHOW, this);
cf.exec ();
}
void GxsForumsDialog::editForumDetails()
{
if (mForumId.empty()) {
return;
}
RsGxsForumGroup grp;
grp.mMeta.mGroupId = mForumId;
GxsForumGroupDialog cf(grp, GxsGroupDialog::MODE_EDIT, this);
cf.exec ();
}
void GxsForumsDialog::shareKey()
{
ShareKey shareUi(this, 0, mForumId, FORUM_KEY_SHARE);
shareUi.exec();
}
void GxsForumsDialog::updateMessageSummaryList(std::string forumId)
{
QTreeWidgetItem *items[2] = { yourForums, subscribedForums };
for (int item = 0; item < 2; item++) {
int child;
int childCount = items[item]->childCount();
for (child = 0; child < childCount; child++) {
QTreeWidgetItem *childItem = items[item]->child(child);
std::string childId = ui.forumTreeWidget->itemId(childItem).toStdString();
if (childId.empty()) {
continue;
}
if (forumId.empty() || childId == forumId) {
/* calculate unread messages */
unsigned int newMessageCount = 0;
unsigned int unreadMessageCount = 0;
//#TODO rsGxsForums->getMessageCount(childId, newMessageCount, unreadMessageCount);
std::cerr << "IMPLEMENT rsGxsForums->getMessageCount()";
std::cerr << std::endl;
ui.forumTreeWidget->setUnreadCount(childItem, unreadMessageCount);
if (forumId.empty() == false) {
/* Calculate only this forum */
break;
}
}
}
}
}
bool GxsForumsDialog::navigate(const std::string& forumId, const std::string& msgId)
{
if (forumId.empty()) {
return false;
}
if (ui.forumTreeWidget->activateId(QString::fromStdString(forumId), msgId.empty()) == NULL) {
return false;
}
/* Threads are filled in changedForum */
if (mForumId != forumId) {
return false;
}
if (msgId.empty()) {
return true;
}
//#TODO
// if (mThreadLoading) {
// mThreadLoad.FocusMsgId = msgId;
// return true;
// }
/* Search exisiting item */
// QTreeWidgetItemIterator itemIterator(ui.threadTreeWidget);
// QTreeWidgetItem *item = NULL;
// while ((item = *itemIterator) != NULL) {
// itemIterator++;
// if (item->data(COLUMN_THREAD_DATA, ROLE_THREAD_MSGID).toString().toStdString() == msgId) {
// ui.threadTreeWidget->setCurrentItem(item);
// ui.threadTreeWidget->setFocus();
// return true;
// }
// }
return false;
}
void GxsForumsDialog::generateMassData()
{
#ifdef DEBUG_FORUMS
if (mCurrForumId.empty ()) {
return;
}
if (QMessageBox::question(this, "Generate mass data", "Do you really want to generate mass data ?", QMessageBox::Yes|QMessageBox::No, QMessageBox::No) == QMessageBox::No) {
return;
}
for (int thread = 1; thread < 1000; thread++) {
ForumMsgInfo threadInfo;
threadInfo.forumId = mCurrForumId;
threadInfo.title = QString("Test %1").arg(thread, 3, 10, QChar('0')).toStdWString();
threadInfo.msg = QString("That is only a test").toStdWString();
if (rsGxsForums->ForumMessageSend(threadInfo) == false) {
return;
}
for (int msg = 1; msg < 3; msg++) {
ForumMsgInfo msgInfo;
msgInfo.forumId = mCurrForumId;
msgInfo.threadId = threadInfo.msgId;
msgInfo.parentId = threadInfo.msgId;
msgInfo.title = threadInfo.title;
msgInfo.msg = threadInfo.msg;
if (rsGxsForums->ForumMessageSend(msgInfo) == false) {
return;
}
}
}
#endif
}
/*********************** **** **** **** ***********************/
/** Request / Response of Data ********************************/
/*********************** **** **** **** ***********************/
#define FORUMSV2DIALOG_LISTING 1
//#define FORUMSV2DIALOG_CURRENTFORUM 2
void GxsForumsDialog::insertForums()
{
requestGroupSummary();
}
void GxsForumsDialog::requestGroupSummary()
{
std::cerr << "GxsForumsDialog::requestGroupSummary()";
std::cerr << std::endl;
if (mRequestGroupSummary) {
std::cerr << "GxsForumsDialog::requestGroupSummary() Canceling Request: " << mTokenGroupSummary;
std::cerr << std::endl;
mForumQueue->cancelRequest(mTokenGroupSummary);
mTokenGroupSummary = 0;
mRequestGroupSummary = false;
}
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_GROUP_META;
mForumQueue->requestGroupInfo(mTokenGroupSummary, RS_TOKREQ_ANSTYPE_SUMMARY, opts, FORUMSV2DIALOG_LISTING);
mRequestGroupSummary = true;
}
void GxsForumsDialog::loadGroupSummary(const uint32_t &token)
{
std::cerr << "GxsForumsDialog::loadGroupSummary()";
std::cerr << std::endl;
if (!mRequestGroupSummary) {
std::cerr << "GxsForumsDialog::loadGroupSummary()) No waiting request got token: " << token;
std::cerr << std::endl;
return;
}
if (token != mTokenGroupSummary) {
std::cerr << "GxsForumsDialog::loadGroupSummary()) Wrong token - want: " << mTokenGroupSummary << " got: " << token;
std::cerr << std::endl;
return;
}
std::list<RsGroupMetaData> groupInfo;
rsGxsForums->getGroupSummary(token, groupInfo);
if (groupInfo.size() > 0)
{
insertForumsData(groupInfo);
}
else
{
std::cerr << "GxsForumsDialog::loadGroupSummary() ERROR No Groups...";
std::cerr << std::endl;
}
mTokenGroupSummary = 0;
mRequestGroupSummary = false;
}
/*********************** **** **** **** ***********************/
/*********************** **** **** **** ***********************/
//void GxsForumsDialog::requestGroupSummary_CurrentForum(const std::string &forumId)
//{
// RsTokReqOptions opts;
// opts.mReqType = GXS_REQUEST_TYPE_GROUP_META;
// std::list<std::string> grpIds;
// grpIds.push_back(forumId);
// std::cerr << "GxsForumsDialog::requestGroupSummary_CurrentForum(" << forumId << ")";
// std::cerr << std::endl;
// uint32_t token;
// mForumQueue->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_SUMMARY, opts, grpIds, FORUMSV2DIALOG_CURRENTFORUM);
//}
//void GxsForumsDialog::loadGroupSummary_CurrentForum(const uint32_t &token)
//{
// std::cerr << "GxsForumsDialog::loadGroupSummary_CurrentForum()";
// std::cerr << std::endl;
// std::list<RsGroupMetaData> groupInfo;
// rsGxsForums->getGroupSummary(token, groupInfo);
// if (groupInfo.size() == 1)
// {
// RsGroupMetaData fi = groupInfo.front();
// mSubscribeFlags = fi.mSubscribeFlags;
// }
// else
// {
// resetData();
// std::cerr << "GxsForumsDialog::loadGroupSummary_CurrentForum() ERROR Invalid Number of Groups...";
// std::cerr << std::endl;
// }
// setValid(true);
//}
/*********************** **** **** **** ***********************/
/*********************** **** **** **** ***********************/
void GxsForumsDialog::loadRequest(const TokenQueue *queue, const TokenRequest &req)
{
std::cerr << "GxsForumsDialog::loadRequest() UserType: " << req.mUserType;
std::cerr << std::endl;
if (queue == mForumQueue)
{
/* now switch on req */
switch(req.mUserType)
{
case FORUMSV2DIALOG_LISTING:
loadGroupSummary(req.mToken);
break;
// case FORUMSV2DIALOG_CURRENTFORUM:
// loadGroupSummary_CurrentForum(req.mToken);
// break;
default:
std::cerr << "GxsForumsDialog::loadRequest() ERROR: INVALID TYPE";
std::cerr << std::endl;
break;
}
}
}