/**************************************************************** * 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 #include #include #include #include #include "retroshare/rspeers.h" #include "retroshare/rsstatus.h" #include "GroupDefs.h" #include "gui/chat/PopupChatDialog.h" #include "gui/common/AvatarDefs.h" #include "gui/connect/ConfCertDialog.h" #include "gui/connect/ConnectFriendWizard.h" #include "gui/groups/CreateGroup.h" #include "gui/msgs/MessageComposer.h" #include "gui/notifyqt.h" #include "gui/RetroShareLink.h" #include "gui/RsAutoUpdatePage.h" #ifdef UNFINISHED #include "gui/unfinished/profile/ProfileView.h" #endif #include "RSTreeWidgetItem.h" #include "StatusDefs.h" #include "util/misc.h" #include "vmessagebox.h" #include "FriendList.h" #include "ui_FriendList.h" /* Images for context menu icons */ #define IMAGE_DENYFRIEND ":/images/denied16.png" #define IMAGE_REMOVEFRIEND ":/images/removefriend16.png" #define IMAGE_EXPORTFRIEND ":/images/exportpeers_16x16.png" #define IMAGE_ADDFRIEND ":/images/user/add_user16.png" #define IMAGE_FRIENDINFO ":/images/peerdetails_16x16.png" #define IMAGE_CHAT ":/images/chat.png" #define IMAGE_MSG ":/images/mail_new.png" #define IMAGE_CONNECT ":/images/connect_friend.png" #define IMAGE_COPYLINK ":/images/copyrslink.png" #define IMAGE_GROUP16 ":/images/user/group16.png" #define IMAGE_EDIT ":/images/edit_16.png" #define IMAGE_REMOVE ":/images/delete.png" #define IMAGE_EXPAND ":/images/edit_add24.png" #define IMAGE_COLLAPSE ":/images/edit_remove24.png" /* Images for Status icons */ #define IMAGE_AVAILABLE ":/images/user/identityavaiblecyan24.png" #define IMAGE_CONNECT2 ":/images/reload24.png" #define IMAGE_PASTELINK ":/images/pasterslink.png" #define IMAGE_GROUP24 ":/images/user/group24.png" #define COLUMN_COUNT 4 #define COLUMN_NAME 0 #define COLUMN_STATE 1 #define COLUMN_LAST_CONTACT 2 #define COLUMN_AVATAR 3 #define COLUMN_DATA 0 // column for storing the userdata id #define COLUMN_AVATAR_WIDTH 42 #define ROLE_SORT Qt::UserRole #define ROLE_ID Qt::UserRole + 1 #define ROLE_STANDARD Qt::UserRole + 2 #define TYPE_GPG 0 #define TYPE_SSL 1 #define TYPE_GROUP 2 // states for sorting (equal values are possible) // used in BuildSortString - state + name #define PEER_STATE_ONLINE 1 #define PEER_STATE_BUSY 2 #define PEER_STATE_AWAY 3 #define PEER_STATE_AVAILABLE 4 #define PEER_STATE_INACTIVE 5 #define PEER_STATE_OFFLINE 6 #define BuildStateSortString(bEnabled,sName,nState) bEnabled ? (QString ("%1").arg(nState) + " " + sName) : sName /****** * #define FRIENDS_DEBUG 1 *****/ FriendList::FriendList(QWidget *parent) : RsAutoUpdatePage(1500, parent), ui(new Ui::FriendList), m_compareRole(new RSTreeWidgetItemCompareRole), mBigName(false), mShowGroups(true), mHideState(false), mHideUnconnected(false), groupsHasChanged(false), openGroups(NULL), openPeers(NULL) { ui->setupUi(this); m_compareRole->setRole(COLUMN_NAME, ROLE_SORT); m_compareRole->setRole(COLUMN_STATE, ROLE_SORT); m_compareRole->setRole(COLUMN_LAST_CONTACT, ROLE_SORT); m_compareRole->setRole(COLUMN_AVATAR, ROLE_STANDARD); connect(ui->peerTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(peerTreeWidgetCostumPopupMenu())); connect(ui->peerTreeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(chatfriend(QTreeWidgetItem *))); connect(NotifyQt::getInstance(), SIGNAL(groupsChanged(int)), this, SLOT(groupsChanged())); connect(NotifyQt::getInstance(), SIGNAL(friendsChanged()), this, SLOT(insertPeers())); connect(NotifyQt::getInstance(), SIGNAL(peerHasNewAvatar(const QString&)), this, SLOT(updateAvatar(const QString&))); connect(ui->actionHideOfflineFriends, SIGNAL(triggered(bool)), this, SLOT(setHideUnconnected(bool))); connect(ui->actionShowStatusColumn, SIGNAL(triggered(bool)), this, SLOT(setShowStatusColumn(bool))); connect(ui->actionShowAvatarColumn, SIGNAL(triggered(bool)), this, SLOT(setShowAvatarColumn(bool))); connect(ui->actionShowLastContactColumn, SIGNAL(triggered(bool)), this, SLOT(setShowLastContactColumn(bool))); connect(ui->actionHideState, SIGNAL(triggered(bool)), this, SLOT(setHideState(bool))); connect(ui->actionRootIsDecorated, SIGNAL(triggered(bool)), this, SLOT(setRootIsDecorated(bool))); connect(ui->actionShowGroups, SIGNAL(triggered(bool)), this, SLOT(setShowGroups(bool))); connect(ui->actionSortByName, SIGNAL(triggered()), this, SLOT(setSortByName())); connect(ui->actionSortByState, SIGNAL(triggered()), this, SLOT(setSortByState())); connect(ui->actionSortByLastContact, SIGNAL(triggered()), this, SLOT(setSortByLastContact())); connect(ui->actionSortPeersAscendingOrder, SIGNAL(triggered()), this, SLOT(sortPeersAscendingOrder())); connect(ui->actionSortPeersDescendingOrder, SIGNAL(triggered()), this, SLOT(sortPeersDescendingOrder())); initializeHeader(false); ui->peerTreeWidget->sortItems(COLUMN_NAME, 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_AVATAR, Qt::AlignLeft | Qt::AlignVCenter); // 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())); } FriendList::~FriendList() { delete ui; delete(m_compareRole); } void FriendList::processSettings(bool bLoad) { int peerTreeVersion = 2; // version number for the settings to solve problems when modifying the column count if (bLoad) { // load settings // state of peer tree if (Settings->value("peerTreeVersion").toInt() == peerTreeVersion) { ui->peerTreeWidget->header()->restoreState(Settings->value("peerTree").toByteArray()); } // ui->peerTreeWidget->header()->doItemsLayout(); // is needed because I added a third column // restoreState would corrupt the internal sectionCount // state of the columns setShowStatusColumn(Settings->value("showStatusColumn", !ui->peerTreeWidget->isColumnHidden(COLUMN_STATE)).toBool()); setShowLastContactColumn(Settings->value("showLastContactColumn", !ui->peerTreeWidget->isColumnHidden(COLUMN_LAST_CONTACT)).toBool()); setShowAvatarColumn(Settings->value("showAvatarColumn", !ui->peerTreeWidget->isColumnHidden(COLUMN_AVATAR)).toBool()); // states setHideUnconnected(Settings->value("hideUnconnected", mHideUnconnected).toBool()); setHideState(Settings->value("hideState", mHideState).toBool()); setRootIsDecorated(Settings->value("rootIsDecorated", ui->peerTreeWidget->rootIsDecorated()).toBool()); setShowGroups(Settings->value("showGroups", mShowGroups).toBool()); // open groups int arrayIndex = Settings->beginReadArray("Groups"); for (int index = 0; index < arrayIndex; index++) { Settings->setArrayIndex(index); addGroupToExpand(Settings->value("open").toString().toStdString()); } Settings->endArray(); initializeHeader(true); updateHeader(); } else { // save settings // state of peer tree Settings->setValue("peerTree", ui->peerTreeWidget->header()->saveState()); Settings->setValue("peerTreeVersion", peerTreeVersion); // state of the columns Settings->setValue("showStatusColumn", !ui->peerTreeWidget->isColumnHidden(COLUMN_STATE)); Settings->setValue("showLastContactColumn", !ui->peerTreeWidget->isColumnHidden(COLUMN_LAST_CONTACT)); Settings->setValue("showAvatarColumn", !ui->peerTreeWidget->isColumnHidden(COLUMN_AVATAR)); // states Settings->setValue("hideUnconnected", mHideUnconnected); Settings->setValue("hideState", mHideState); Settings->setValue("rootIsDecorated", ui->peerTreeWidget->rootIsDecorated()); Settings->setValue("showGroups", mShowGroups); // open groups Settings->beginWriteArray("Groups"); int arrayIndex = 0; std::set expandedPeers; getExpandedGroups(expandedPeers); foreach (std::string groupId, expandedPeers) { Settings->setArrayIndex(arrayIndex++); Settings->setValue("open", QString::fromStdString(groupId)); } Settings->endArray(); } } void FriendList::initializeHeader(bool afterLoadSettings) { // set column size QHeaderView *header = ui->peerTreeWidget->header(); header->setMovable(false); header->setResizeMode(COLUMN_NAME, QHeaderView::Stretch); header->setResizeMode(COLUMN_STATE, QHeaderView::Interactive); header->setResizeMode(COLUMN_LAST_CONTACT, QHeaderView::Interactive); header->setResizeMode(COLUMN_AVATAR, QHeaderView::Fixed); if (!afterLoadSettings) { header->resizeSection(COLUMN_NAME, 150); header->resizeSection(COLUMN_LAST_CONTACT, 120); } header->resizeSection(COLUMN_AVATAR, COLUMN_AVATAR_WIDTH); } /* Utility Fns */ inline std::string getRsId(QTreeWidgetItem *item) { return item->data(COLUMN_DATA, ROLE_ID).toString().toStdString(); } /** * Creates the context popup menu and its submenus, * then shows it at the current cursor position. */ void FriendList::peerTreeWidgetCostumPopupMenu() { QTreeWidgetItem *c = getCurrentPeer(); QMenu contextMnu(this); QWidget *widget = new QWidget(&contextMnu); widget->setStyleSheet( ".QWidget{background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,stop:0 #FEFEFE, stop:1 #E8E8E8); border: 1px solid #CCCCCC;}"); // create menu header QHBoxLayout *hbox = new QHBoxLayout(widget); hbox->setMargin(0); hbox->setSpacing(6); QLabel *iconLabel = new QLabel(widget); iconLabel->setPixmap(QPixmap(":/images/user/friends24.png")); iconLabel->setMaximumSize(iconLabel->frameSize().height() + 24, 24); hbox->addWidget(iconLabel); QLabel *textLabel = new QLabel("RetroShare", widget); hbox->addWidget(textLabel); QSpacerItem *spacerItem = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); hbox->addItem(spacerItem); widget->setLayout(hbox); QWidgetAction *widgetAction = new QWidgetAction(this); widgetAction->setDefaultWidget(widget); contextMnu.addAction(widgetAction); // create menu entries if (c) { // if a peer is selected int type = c->type(); // define header switch (type) { case TYPE_GROUP: //this is a GPG key textLabel->setText("" + tr("Group") + ""); break; case TYPE_GPG: //this is a GPG key textLabel->setText("" + tr("Friend") + ""); break; case TYPE_SSL: //this is a SSL key textLabel->setText("" + tr("Location") + ""); break; } switch (type) { case TYPE_GROUP: { bool standard = c->data(COLUMN_DATA, ROLE_STANDARD).toBool(); contextMnu.addAction(QIcon(IMAGE_MSG), tr("Message Group"), this, SLOT(msgfriend())); contextMnu.addAction(QIcon(IMAGE_ADDFRIEND), tr("Add Friend"), this, SLOT(addFriend())); contextMnu.addSeparator(); QAction *action = contextMnu.addAction(QIcon(IMAGE_EDIT), tr("Edit Group"), this, SLOT(editGroup())); action->setDisabled(standard); action = contextMnu.addAction(QIcon(IMAGE_REMOVE), tr("Remove Group"), this, SLOT(removeGroup())); action->setDisabled(standard); contextMnu.addAction(QIcon(IMAGE_CHAT), tr("Create chat lobby"), this, SLOT(createchatlobby())); } break; case TYPE_GPG: case TYPE_SSL: { contextMnu.addAction(QIcon(IMAGE_CHAT), tr("Chat"), this, SLOT(chatfriendproxy())); QMenu *mnu = contextMnu.addMenu(QIcon(IMAGE_CHAT), tr("Invite to chat lobby")) ; std::list cl_infos ; rsMsgs->getChatLobbyList(cl_infos) ; for(std::list::const_iterator it(cl_infos.begin());it!=cl_infos.end();++it) { QAction* inviteToLobbyAction = new QAction(QString::fromUtf8((*it).nick_name.c_str()), mnu); inviteToLobbyAction->setData(QString::number((*it).lobby_id,16)); connect(inviteToLobbyAction, SIGNAL(triggered()), this, SLOT(inviteToLobby())); mnu->addAction(inviteToLobbyAction); } mnu->addAction(QIcon(IMAGE_CHAT),tr("create new"),this,SLOT(createchatlobby())) ; contextMnu.addAction(QIcon(IMAGE_MSG), tr("Message Friend"), this, SLOT(msgfriend())); contextMnu.addSeparator(); contextMnu.addAction(QIcon(IMAGE_FRIENDINFO), tr("Friend Details"), this, SLOT(configurefriend())); // contextMnu.addAction(QIcon(IMAGE_PEERINFO), tr("Profile View"), this, SLOT(viewprofile())); // action = contextMnu.addAction(QIcon(IMAGE_EXPORTFRIEND), tr("Export Friend"), this, SLOT(exportfriend())); if (type == TYPE_GPG) { contextMnu.addAction(QIcon(IMAGE_EXPORTFRIEND), tr("Recommend this Friend to..."), this, SLOT(recommendfriend())); } contextMnu.addAction(QIcon(IMAGE_CONNECT), tr("Connect To Friend"), this, SLOT(connectfriend())); if (type == TYPE_GPG) { contextMnu.addAction(QIcon(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyLink())); } QAction *action = contextMnu.addAction(QIcon(IMAGE_PASTELINK), tr("Paste Friend Link"), this, SLOT(pastePerson())); if (RSLinkClipboard::empty(RetroShareLink::TYPE_PERSON)) { action->setDisabled(true); } if (type == TYPE_GPG) { contextMnu.addAction(QIcon(IMAGE_DENYFRIEND), tr("Deny Friend"), this, SLOT(removefriend())); } else { //this is a SSL key contextMnu.addAction(QIcon(IMAGE_REMOVEFRIEND), tr("Remove Friend Location"), this, SLOT(removefriend())); } if (mShowGroups && type == TYPE_GPG) { QMenu* addToGroupMenu = NULL; QMenu* moveToGroupMenu = NULL; std::list groupInfoList; rsPeers->getGroupInfoList(groupInfoList); GroupDefs::sortByName(groupInfoList); std::string gpgId = getRsId(c); QTreeWidgetItem *parent = c->parent(); bool foundGroup = false; // add action for all groups, except the own group for (std::list::iterator groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); groupIt++) { if (std::find(groupIt->peerIds.begin(), groupIt->peerIds.end(), gpgId) == groupIt->peerIds.end()) { if (parent) { if (addToGroupMenu == NULL) { addToGroupMenu = new QMenu(tr("Add to group"), &contextMnu); } QAction* addToGroupAction = new QAction(GroupDefs::name(*groupIt), addToGroupMenu); addToGroupAction->setData(QString::fromStdString(groupIt->id)); connect(addToGroupAction, SIGNAL(triggered()), this, SLOT(addToGroup())); addToGroupMenu->addAction(addToGroupAction); } if (moveToGroupMenu == NULL) { moveToGroupMenu = new QMenu(tr("Move to group"), &contextMnu); } QAction* moveToGroupAction = new QAction(GroupDefs::name(*groupIt), moveToGroupMenu); moveToGroupAction->setData(QString::fromStdString(groupIt->id)); connect(moveToGroupAction, SIGNAL(triggered()), this, SLOT(moveToGroup())); moveToGroupMenu->addAction(moveToGroupAction); } else { foundGroup = true; } } if (addToGroupMenu || moveToGroupMenu || foundGroup) { QMenu *groupsMenu = contextMnu.addMenu(QIcon(IMAGE_GROUP16), tr("Groups")); if (addToGroupMenu) { groupsMenu->addMenu(addToGroupMenu); } if (moveToGroupMenu) { groupsMenu->addMenu(moveToGroupMenu); } if (foundGroup) { // add remove from group if (parent && parent->type() == TYPE_GROUP) { QAction *removeFromGroup = groupsMenu->addAction(tr("Remove from group")); removeFromGroup->setData(parent->data(COLUMN_DATA, ROLE_ID)); connect(removeFromGroup, SIGNAL(triggered()), this, SLOT(removeFromGroup())); } QAction *removeFromAllGroups = groupsMenu->addAction(tr("Remove from all groups")); removeFromAllGroups->setData(""); connect(removeFromAllGroups, SIGNAL(triggered()), this, SLOT(removeFromGroup())); } } } } } } else { QAction *action = contextMnu.addAction(QIcon(IMAGE_PASTELINK), tr("Paste Friend Link"), this, SLOT(pastePerson())); if (RSLinkClipboard::empty(RetroShareLink::TYPE_PERSON)) { action->setDisabled(true); } } contextMnu.addSeparator(); contextMnu.addAction(QIcon(IMAGE_EXPAND), tr("Expand all"), ui->peerTreeWidget, SLOT(expandAll())); contextMnu.addAction(QIcon(IMAGE_COLLAPSE), tr("Collapse all"), ui->peerTreeWidget, SLOT(collapseAll())); contextMnu.exec(QCursor::pos()); } void FriendList::updateDisplay() { insertPeers(); } void FriendList::groupsChanged() { groupsHasChanged = true; insertPeers(); } void FriendList::updateAvatar(const QString& id) { if (ui->peerTreeWidget->isColumnHidden(COLUMN_AVATAR)) return; QTreeWidgetItemIterator it(ui->peerTreeWidget); while (*it) { if ((*it)->type() == TYPE_SSL && id == (*it)->data(COLUMN_DATA, ROLE_ID).toString()) { if ((*it)->parent() != NULL && (*it)->parent()->type() == TYPE_GPG) { QPixmap avatar; AvatarDefs::getAvatarFromSslId(id.toStdString(), avatar); QIcon avatar_icon(avatar); (*it)->parent()->setIcon(COLUMN_AVATAR, avatar_icon); } } ++it; } } /** * Get the list of peers from the RsIface. * Adds all friend gpg ids, with their locations as children to the peerTreeWidget. * If enabled, peers are sorted in their associated groups. * Groups are only updated, when groupsHasChanged is true. */ void FriendList::insertPeers() { if (RsAutoUpdatePage::eventsLocked()) return; #ifdef FRIENDS_DEBUG std::cerr << "FriendList::insertPeers() called." << std::endl; #endif bool isStatusColumnHidden = ui->peerTreeWidget->isColumnHidden(COLUMN_STATE); bool isAvatarColumnHidden = ui->peerTreeWidget->isColumnHidden(COLUMN_AVATAR); std::list statusInfo; rsStatus->getStatusList(statusInfo); if (!rsPeers) { /* not ready yet! */ std::cerr << "FriendList::insertPeers() not ready yet : rsPeers unintialized." << std::endl; return; } // get ids of existing private chat messages std::list privateChatIds; rsMsgs->getPrivateChatQueueIds(true, privateChatIds); // get existing groups std::list groupInfoList; std::list::iterator groupIt; rsPeers->getGroupInfoList(groupInfoList); std::list gpgFriends; std::list::iterator gpgIt; rsPeers->getGPGAcceptedList(gpgFriends); //add own gpg id, if we have more than on location (ssl client) std::list ownSslContacts; std::string ownId = rsPeers->getGPGOwnId(); rsPeers->getAssociatedSSLIds(ownId, ownSslContacts); if (ownSslContacts.size() > 0) { gpgFriends.push_back(ownId); } /* get a link to the table */ QTreeWidget *peerTreeWidget = ui->peerTreeWidget; // remove items don't exist anymore QTreeWidgetItemIterator itemIterator(peerTreeWidget); QTreeWidgetItem *item; while ((item = *itemIterator) != NULL) { itemIterator++; switch (item->type()) { case TYPE_GPG: { QTreeWidgetItem *parent = item->parent(); std::string gpg_widget_id = getRsId(item); // remove items that are not friends anymore if (std::find(gpgFriends.begin(), gpgFriends.end(), gpg_widget_id) == gpgFriends.end()) { if (parent) { delete(parent->takeChild(parent->indexOfChild(item))); } else { delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); } break; } if (mShowGroups && groupsHasChanged) { if (parent) { if (parent->type() == TYPE_GROUP) { std::string groupId = getRsId(parent); // the parent is a group, check if the gpg id is assigned to the group for (groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); groupIt++) { if (groupIt->id == groupId) { if (std::find(groupIt->peerIds.begin(), groupIt->peerIds.end(), gpg_widget_id) == groupIt->peerIds.end()) { delete(parent->takeChild(parent->indexOfChild(item))); } break; } } } } else { // gpg item without group, check if the gpg id is assigned to a group for (groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); groupIt++) { if (std::find(groupIt->peerIds.begin(), groupIt->peerIds.end(), gpg_widget_id) != groupIt->peerIds.end()) { delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); break; } } } } } break; case TYPE_GROUP: { if (!mShowGroups) { if (item->parent()) { delete(item->parent()->takeChild(item->parent()->indexOfChild(item))); } else { delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); } } else if (groupsHasChanged) { // remove deleted groups std::string groupId = getRsId(item); for (groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); groupIt++) { if (groupIt->id == groupId) { break; } } if (groupIt == groupInfoList.end() || groupIt->peerIds.size() == 0) { if (item->parent()) { delete(item->parent()->takeChild(item->parent()->indexOfChild(item))); } else { delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); } } } } break; } } std::list fillGpgIds; // start with groups groupIt = groupInfoList.begin(); while (true) { QTreeWidgetItem *groupItem = NULL; RsGroupInfo *groupInfo = NULL; int onlineCount = 0; int availableCount = 0; if (mShowGroups && groupIt != groupInfoList.end()) { groupInfo = &(*groupIt); if ((groupInfo->flag & RS_GROUP_FLAG_STANDARD) && groupInfo->peerIds.size() == 0) { // don't show empty standard groups groupIt++; continue; } // search existing group item int itemCount = peerTreeWidget->topLevelItemCount(); for (int index = 0; index < itemCount; index++) { QTreeWidgetItem *groupItemLoop = peerTreeWidget->topLevelItem(index); if (groupItemLoop->type() == TYPE_GROUP && getRsId(groupItemLoop) == groupInfo->id) { groupItem = groupItemLoop; break; } } if (groupItem == NULL) { // add group item groupItem = new RSTreeWidgetItem(m_compareRole, TYPE_GROUP); /* Add item to the list. Add here, because for setHidden the item must be added */ peerTreeWidget->addTopLevelItem(groupItem); groupItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless); groupItem->setSizeHint(COLUMN_NAME, QSize(26, 26)); groupItem->setTextAlignment(COLUMN_NAME, Qt::AlignLeft | Qt::AlignVCenter); groupItem->setIcon(COLUMN_NAME, QIcon(IMAGE_GROUP24)); groupItem->setForeground(COLUMN_NAME, QBrush(QColor(123, 123, 123))); /* used to find back the item */ groupItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(groupInfo->id)); groupItem->setData(COLUMN_DATA, ROLE_STANDARD, (groupInfo->flag & RS_GROUP_FLAG_STANDARD) ? true : false); } else { // remove all gpg items that are not more assigned int childCount = groupItem->childCount(); int childIndex = 0; while (childIndex < childCount) { QTreeWidgetItem *gpgItemLoop = groupItem->child(childIndex); if (gpgItemLoop->type() == TYPE_GPG) { if (std::find(groupInfo->peerIds.begin(), groupInfo->peerIds.end(), getRsId(gpgItemLoop)) == groupInfo->peerIds.end()) { delete(groupItem->takeChild(groupItem->indexOfChild(gpgItemLoop))); childCount = groupItem->childCount(); continue; } } childIndex++; } } if (openGroups != NULL && openGroups->find(groupInfo->id) != openGroups->end()) { groupItem->setExpanded(true); } // name is set after calculation of online/offline items } // iterate through gpg friends for (gpgIt = gpgFriends.begin(); gpgIt != gpgFriends.end(); gpgIt++) { std::string gpgId = *gpgIt; if (mShowGroups) { if (groupInfo) { // we fill a group, check if gpg id is assigned if (std::find(groupInfo->peerIds.begin(), groupInfo->peerIds.end(), gpgId) == groupInfo->peerIds.end()) { continue; } } else { // we fill the not assigned gpg ids if (std::find(fillGpgIds.begin(), fillGpgIds.end(), gpgId) != fillGpgIds.end()) { continue; } } // add equal too, its no problem fillGpgIds.push_back(gpgId); } //add the gpg friends #ifdef FRIENDS_DEBUG std::cerr << "FriendList::insertPeers() inserting gpg_id : " << gpgId << std::endl; #endif /* make a widget per friend */ QTreeWidgetItem *gpgItem = NULL; QTreeWidgetItem *gpgItemLoop = NULL; // search existing gpg item int itemCount = groupItem ? groupItem->childCount() : peerTreeWidget->topLevelItemCount(); for (int index = 0; index < itemCount; index++) { gpgItemLoop = groupItem ? groupItem->child(index) : peerTreeWidget->topLevelItem(index); if (gpgItemLoop->type() == TYPE_GPG && getRsId(gpgItemLoop) == gpgId) { gpgItem = gpgItemLoop; break; } } RsPeerDetails detail; if ((!rsPeers->getPeerDetails(gpgId, detail) || !detail.accept_connection) && detail.gpg_id != ownId) { // don't accept anymore connection, remove from the view if (gpgItem) { if (groupItem) { delete(groupItem->takeChild(groupItem->indexOfChild(gpgItem))); } else { delete (peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(gpgItem))); } } continue; } if (gpgItem == NULL) { // create gpg item and add it to tree gpgItem = new RSTreeWidgetItem(m_compareRole, TYPE_GPG); //set type to 0 for custom popup menu /* Add gpg item to the list. Add here, because for setHidden the item must be added */ if (groupItem) { groupItem->addChild(gpgItem); } else { peerTreeWidget->addTopLevelItem(gpgItem); } gpgItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless); gpgItem->setTextAlignment(COLUMN_NAME, Qt::AlignLeft | Qt::AlignVCenter); /* not displayed, used to find back the item */ gpgItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(detail.id)); } if (mBigName && !mHideState && isStatusColumnHidden) { gpgItem->setSizeHint(COLUMN_NAME, QSize(40, 40)); } else { gpgItem->setSizeHint(COLUMN_NAME, QSize(26, 26)); } availableCount++; QString gpgItemText = QString::fromUtf8(detail.name.c_str()); // remove items that are not friends anymore int childCount = gpgItem->childCount(); int childIndex = 0; while (childIndex < childCount) { std::string ssl_id = getRsId(gpgItem->child(childIndex)); if (!rsPeers->isFriend(ssl_id)) { delete (gpgItem->takeChild(childIndex)); // count again childCount = gpgItem->childCount(); } else { childIndex++; } } // update the childs (ssl certs) bool gpg_connected = false; bool gpg_online = false; bool gpg_hasPrivateChat = false; int bestPeerState = 0; // for gpg item unsigned int bestRSState = 0; // for gpg item std::string bestSslId; // for gpg item QString bestCustomStateString;// for gpg item std::list sslContacts; QDateTime lastContact; rsPeers->getAssociatedSSLIds(detail.gpg_id, sslContacts); for (std::list::iterator sslIt = sslContacts.begin(); sslIt != sslContacts.end(); sslIt++) { QTreeWidgetItem *sslItem = NULL; std::string sslId = *sslIt; //find the corresponding sslItem child item of the gpg item bool newChild = true; childCount = gpgItem->childCount(); for (int childIndex = 0; childIndex < childCount; childIndex++) { // we assume, that only ssl items are child of the gpg item, so we don't need to test the type if (getRsId(gpgItem->child(childIndex)) == sslId) { sslItem = gpgItem->child(childIndex); newChild = false; break; } } RsPeerDetails sslDetail; if (!rsPeers->getPeerDetails(sslId, sslDetail) || !rsPeers->isFriend(sslId)) { #ifdef FRIENDS_DEBUG std::cerr << "Removing widget from the view : id : " << sslId << std::endl; #endif //child has disappeared, remove it from the gpg_item if (sslItem) { gpgItem->removeChild(sslItem); } continue; } if (newChild) { sslItem = new RSTreeWidgetItem(m_compareRole, TYPE_SSL); //set type to 1 for custom popup menu #ifdef FRIENDS_DEBUG std::cerr << "FriendList::insertPeers() inserting sslItem." << std::endl; #endif /* Add ssl child to the list. Add here, because for setHidden the item must be added */ gpgItem->addChild(sslItem); } /* not displayed, used to find back the item */ sslItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(sslDetail.id)); QString sText; QString customStateString; if (sslDetail.state & RS_PEER_STATE_CONNECTED) { customStateString = QString::fromUtf8(rsMsgs->getCustomStateString(sslDetail.id).c_str()); } sText = QString::fromUtf8(sslDetail.location.c_str()); if (customStateString.isEmpty() == false) { sText += " - " + customStateString; } QString connectStateString = StatusDefs::connectStateString(sslDetail); if (!isStatusColumnHidden) { sslItem->setText(COLUMN_STATE, connectStateString); } else if (!mHideState && connectStateString.isEmpty() == false) { sText += " [" + StatusDefs::connectStateString(sslDetail) + "]"; } sslItem->setText( COLUMN_NAME, sText); if (isStatusColumnHidden == true && mHideState == true) { /* Show the state as tooltip */ sslItem->setToolTip(COLUMN_NAME, connectStateString); } else { sslItem->setToolTip(COLUMN_NAME, ""); } // sort location sslItem->setData(COLUMN_STATE, ROLE_SORT, sText); /* last contact */ QDateTime sslLastContact = QDateTime::fromTime_t(sslDetail.lastConnect); sslItem->setData(COLUMN_LAST_CONTACT, Qt::DisplayRole, QVariant(sslLastContact)); sslItem->setData(COLUMN_LAST_CONTACT, ROLE_SORT, sslLastContact); if (sslLastContact > lastContact) { lastContact = sslLastContact; } /* change color and icon */ QIcon sslIcon; QFont sslFont; QColor sslColor; if (sslDetail.state & RS_PEER_STATE_CONNECTED) { // get the status info for this ssl id int peerState = 0; int rsState = 0; std::list::iterator it; for(it = statusInfo.begin(); it != statusInfo.end(); it++) { if(it->id == sslId){ rsState = it->status; switch (rsState) { case RS_STATUS_INACTIVE: peerState = PEER_STATE_INACTIVE; break; case RS_STATUS_ONLINE: peerState = PEER_STATE_ONLINE; break; case RS_STATUS_AWAY: peerState = PEER_STATE_AWAY; break; case RS_STATUS_BUSY: peerState = PEER_STATE_BUSY; break; } /* find the best ssl contact for the gpg item */ if (bestPeerState == 0 || peerState < bestPeerState) { /* first ssl contact or higher state */ bestPeerState = peerState; bestSslId = sslId; bestRSState = rsState; bestCustomStateString = customStateString; } else if (peerState == bestPeerState) { /* equal state */ if (mBigName && bestCustomStateString.isEmpty() && !customStateString.isEmpty()) { /* when customStateString is shown in name item, use sslId with customStateString. second with a custom state string ... use second */ bestPeerState = peerState; bestSslId = sslId; bestRSState = rsState; bestCustomStateString = customStateString; } } break; } } sslItem->setHidden(false); gpg_connected = true; sslIcon = QIcon(":/images/connect_established.png"); if (rsState == 0) { sslFont.setBold(true); sslColor = Qt::darkBlue; } else { sslFont = StatusDefs::font(rsState); sslColor = StatusDefs::textColor(rsState); } } else if (sslDetail.state & RS_PEER_STATE_ONLINE) { sslItem->setHidden(mHideUnconnected); gpg_online = true; if (sslDetail.connectState) { sslIcon = QIcon(":/images/connect_creating.png"); } else { sslIcon = QIcon(":/images/connect_no.png"); } sslFont.setBold(true); sslColor = Qt::black; } else { sslItem->setHidden(mHideUnconnected); if (sslDetail.connectState) { sslIcon = QIcon(":/images/connect_creating.png"); } else { sslIcon = QIcon(":/images/connect_no.png"); } sslFont.setBold(false); sslColor = Qt::black; } if (std::find(privateChatIds.begin(), privateChatIds.end(), sslDetail.id) != privateChatIds.end()) { // private chat is available sslIcon = QIcon(":/images/chat.png"); gpg_hasPrivateChat = true; } sslItem -> setIcon(COLUMN_NAME, sslIcon); for (int i = 0; i < COLUMN_COUNT; i++) { sslItem -> setTextColor(i, sslColor); sslItem -> setFont(i, sslFont); } } QIcon gpgIcon; if (gpg_connected) { gpgItem->setHidden(false); onlineCount++; if (bestPeerState == 0) { // show as online bestPeerState = PEER_STATE_ONLINE; bestRSState = RS_STATUS_ONLINE; } QColor textColor = StatusDefs::textColor(bestRSState); QFont font = StatusDefs::font(bestRSState); for(int i = 0; i < COLUMN_COUNT; i++) { gpgItem->setTextColor(i, textColor); gpgItem->setFont(i, font); } gpgIcon = QIcon(StatusDefs::imageUser(bestRSState)); if (!isStatusColumnHidden) { gpgItem->setText(COLUMN_STATE, StatusDefs::name(bestRSState)); } if (isStatusColumnHidden && mBigName && !mHideState) { if (bestCustomStateString.isEmpty()) { gpgItemText += "\n" + StatusDefs::name(bestRSState); } else { gpgItemText += "\n" + bestCustomStateString; } } else if (isStatusColumnHidden && !mHideState){ gpgItemText += " [" + StatusDefs::name(bestRSState) + "]"; } } else if (gpg_online) { if (!isStatusColumnHidden) { gpgItem->setText(COLUMN_STATE, tr("Available")); } else if (!mHideState && !mBigName) { gpgItemText += " [" + tr("Available") + "]"; } bestPeerState = PEER_STATE_AVAILABLE; onlineCount++; gpgItem->setHidden(mHideUnconnected); gpgIcon = QIcon(IMAGE_AVAILABLE); QFont font; font.setBold(true); for(int i = 0; i < COLUMN_COUNT; i++) { gpgItem->setTextColor(i,(Qt::black)); gpgItem->setFont(i,font); } } else { if (!isStatusColumnHidden) { gpgItem->setText(COLUMN_STATE, StatusDefs::name(RS_STATUS_OFFLINE)); } else if (!mHideState && !mBigName) { gpgItemText += " [" + StatusDefs::name(RS_STATUS_OFFLINE) + "]"; } bestPeerState = PEER_STATE_OFFLINE; gpgItem->setHidden(mHideUnconnected); gpgIcon = QIcon(StatusDefs::imageUser(RS_STATUS_OFFLINE)); QColor textColor = StatusDefs::textColor(RS_STATUS_OFFLINE); QFont font = StatusDefs::font(RS_STATUS_OFFLINE); for(int i = 0; i < COLUMN_COUNT; i++) { gpgItem->setTextColor(i, textColor); gpgItem->setFont(i, font); } } if (gpg_hasPrivateChat) { gpgIcon = QIcon(":/images/chat.png"); } if (!isAvatarColumnHidden && gpgItem->icon(COLUMN_AVATAR).isNull()) { // only set the avatar image the first time, or when it changed // otherwise getAvatarFromSslId sends request packages to peers. QPixmap avatar; AvatarDefs::getAvatarFromSslId(bestSslId, avatar); QIcon avatar_icon(avatar); gpgItem->setIcon(COLUMN_AVATAR, avatar_icon); } gpgItem->setText(COLUMN_NAME, gpgItemText); gpgItem->setData(COLUMN_NAME, ROLE_SORT, "2 " + gpgItemText); gpgItem->setData(COLUMN_STATE, ROLE_SORT, "2 " + BuildStateSortString(true, gpgItemText, bestPeerState)); gpgItem->setIcon(COLUMN_NAME, gpgIcon); gpgItem->setData(COLUMN_LAST_CONTACT, Qt::DisplayRole, QVariant(lastContact)); gpgItem->setData(COLUMN_LAST_CONTACT, ROLE_SORT, "2 " + lastContact.toString("yyyyMMdd_hhmmss")); if (openPeers != NULL && openPeers->find(gpgId) != openPeers->end()) { gpgItem->setExpanded(true); } } if (groupInfo && groupItem) { if ((groupInfo->flag & RS_GROUP_FLAG_STANDARD) && groupItem->childCount() == 0) { // there are some dead id's assigned groupItem->setHidden(true); } else { groupItem->setHidden(false); QString groupName = GroupDefs::name(*groupInfo); groupItem->setText(COLUMN_NAME, QString("%1 (%2/%3)").arg(groupName).arg(onlineCount).arg(availableCount)); // show first the standard groups, than the user groups groupItem->setData(COLUMN_NAME, ROLE_SORT, ((groupInfo->flag & RS_GROUP_FLAG_STANDARD) ? "0 " : "1 ") + groupName); } } if (mShowGroups && groupIt != groupInfoList.end()) { groupIt++; } else { // all done break; } } if (filterText.isEmpty() == false) { filterItems(filterText); } QTreeWidgetItem *c = getCurrentPeer(); if (c && c->isHidden()) { // active item is hidden, deselect it ui->peerTreeWidget->setCurrentItem(NULL); } groupsHasChanged = false; if (openGroups != NULL) { delete(openGroups); openGroups = NULL; } if (openPeers != NULL) { delete(openPeers); openPeers = NULL; } } /** * Returns a list with all groupIds that are expanded */ bool FriendList::getExpandedGroups(std::set &groups) const { int itemCount = ui->peerTreeWidget->topLevelItemCount(); for (int index = 0; index < itemCount; index++) { QTreeWidgetItem *item = ui->peerTreeWidget->topLevelItem(index); if (item->type() == TYPE_GROUP && item->isExpanded()) { groups.insert(item->data(COLUMN_DATA, ROLE_ID).toString().toStdString()); } } return true; } /** * Returns a list with all gpg ids that are expanded */ bool FriendList::getExpandedPeers(std::set &peers) const { peers.clear(); QTreeWidgetItemIterator it(ui->peerTreeWidget); while (*it) { QTreeWidgetItem *item = *it; if (item->type() == TYPE_GPG && item->isExpanded()) { peers.insert(peers.end(), getRsId(item)); } ++it; } return true; } ///** Open a QFileDialog to browse for export a file. */ //void FriendList::exportfriend() //{ // QTreeWidgetItem *c = getCurrentPeer(); //#ifdef FRIENDS_DEBUG // std::cerr << "FriendList::exportfriend()" << std::endl; //#endif // if (!c) // { //#ifdef FRIENDS_DEBUG // std::cerr << "FriendList::exportfriend() None Selected -- sorry" << std::endl; //#endif // return; // } // std::string id = getPeerRsCertId(c); // if (misc::getSaveFileName(this, RshareSettings::LASTDIR_CERT, tr("Save Certificate"), tr("Certificates (*.pqi)"), fileName)) // { //#ifdef FRIENDS_DEBUG // std::cerr << "FriendList::exportfriend() Saving to: " << fileName.toStdString() << std::endl; //#endif // if (rsPeers) // { // rsPeers->saveCertificateToFile(id, fileName.toUtf8().constData()); // } // } //} void FriendList::chatfriendproxy() { chatfriend(getCurrentPeer()); } /** * Start a chat with a friend * * @param pPeer the gpg or ssl QTreeWidgetItem to chat with */ void FriendList::chatfriend(QTreeWidgetItem *pPeer) { if (pPeer == NULL) { return; } std::string id = getRsId(pPeer); PopupChatDialog::chatFriend(id); } void FriendList::addFriend() { std::string groupId = getSelectedGroupId(); ConnectFriendWizard connwiz (this); if (groupId.empty() == false) { connwiz.setGroup(groupId); } connwiz.exec (); } void FriendList::msgfriend() { QTreeWidgetItem *peer = getCurrentPeer(); if (!peer) return; std::string id = getRsId(peer); MessageComposer::msgFriend(id, (peer->type() == TYPE_GROUP)); } void FriendList::recommendfriend() { QTreeWidgetItem *peer = getCurrentPeer(); if (!peer) return; std::list ids; ids.push_back(getRsId(peer)); MessageComposer::recommendFriend(ids); } void FriendList::pastePerson() { RSLinkClipboard::process(RetroShareLink::TYPE_PERSON); } void FriendList::copyLink() { QTreeWidgetItem *c = getCurrentPeer(); if (c == NULL) { return; } QList urls; RetroShareLink link; if (link.createPerson(getRsId(c))) { urls.push_back(link); } RSLinkClipboard::copyLinks(urls); } /** * Find out which group is selected * * @return If a group item is selected, its groupId otherwise an empty string */ std::string FriendList::getSelectedGroupId() const { QTreeWidgetItem *c = getCurrentPeer(); if (c && c->type() == TYPE_GROUP) { return getRsId(c); } return std::string(); } QTreeWidgetItem *FriendList::getCurrentPeer() const { /* get the current, and extract the Id */ QTreeWidgetItem *item = ui->peerTreeWidget->currentItem(); #ifdef FRIENDS_DEBUG if (!item) { std::cerr << "Invalid Current Item" << std::endl; return NULL; } /* Display the columns of this item. */ std::ostringstream out; out << "CurrentPeerItem: " << std::endl; for(int i = 1; i < COLUMN_COUNT; i++) { QString txt = item -> text(i); out << "\t" << i << ":" << txt.toStdString() << std::endl; } std::cerr << out.str(); #endif return item; } #ifdef UNFINISHED /* GUI stuff -> don't do anything directly with Control */ void FriendsDialog::viewprofile() { /* display Dialog */ QTreeWidgetItem *c = getCurrentPeer(); // static ProfileView *profileview = new ProfileView(); if (!c) return; /* set the Id */ std::string id = getRsId(c); profileview -> setPeerId(id); profileview -> show(); } #endif /* So from the Peers Dialog we can call the following control Functions: * (1) Remove Current. FriendRemove(id) * (2) Allow/DisAllow. FriendStatus(id, accept) * (2) Connect. FriendConnectAttempt(id, accept) * (3) Set Address. FriendSetAddress(id, str, port) * (4) Set Trust. FriendTrustSignature(id, bool) * (5) Configure (GUI Only) -> 3/4 * * All of these rely on the finding of the current Id. */ void FriendList::removefriend() { QTreeWidgetItem *c = getCurrentPeer(); #ifdef FRIENDS_DEBUG std::cerr << "FriendList::removefriend()" << std::endl; #endif if (!c) { #ifdef FRIENDS_DEBUG std::cerr << "FriendList::removefriend() None Selected -- sorry" << std::endl; #endif return; } if (rsPeers) { if ((QMessageBox::question(this, "RetroShare", tr("Do you want to remove this Friend?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes)) == QMessageBox::Yes) { rsPeers->removeFriend(getRsId(c)); } } } void FriendList::connectfriend() { QTreeWidgetItem *c = getCurrentPeer(); #ifdef FRIENDS_DEBUG std::cerr << "FriendList::connectfriend()" << std::endl; #endif if (!c) { #ifdef FRIENDS_DEBUG std::cerr << "FriendList::connectfriend() None Selected -- sorry" << std::endl; #endif return; } if (rsPeers) { if (c->type() == TYPE_GPG) { int childCount = c->childCount(); for (int childIndex = 0; childIndex < childCount; childIndex++) { QTreeWidgetItem *item = c->child(childIndex); if (item->type() == TYPE_SSL) { rsPeers->connectAttempt(getRsId(item)); item->setIcon(COLUMN_NAME,(QIcon(IMAGE_CONNECT2))); } } } else { //this is a SSL key rsPeers->connectAttempt(getRsId(c)); c->setIcon(COLUMN_NAME,(QIcon(IMAGE_CONNECT2))); } } } /* GUI stuff -> don't do anything directly with Control */ void FriendList::configurefriend() { ConfCertDialog::showIt(getRsId(getCurrentPeer()), ConfCertDialog::PageDetails); } void FriendList::inviteToLobby() { QTreeWidgetItem *c = getCurrentPeer(); if (c == NULL) { return; } if (c->type() != TYPE_SSL) { // wrong type return; } std::string lobby_id = qobject_cast(sender())->data().toString().toStdString(); if(lobby_id.empty()) return; std::string peer_id = getRsId(c) ; // add to group rsMsgs->invitePeerToLobby(ChatLobbyId(QString::fromStdString(lobby_id).toULongLong()), peer_id); } void FriendList::createchatlobby() { QTreeWidgetItem *c = getCurrentPeer(); if (c == NULL) return; std::list friend_list ; std::string peer_id = getRsId(c) ; friend_list.push_back(peer_id) ; std::string lobby_name = "New lobby (Plz add the code to select this name at creation time)" ; // add to group ChatLobbyId id = rsMsgs->createChatLobby(lobby_name, friend_list); std::cerr << "gui: Created chat lobby " << std::hex << id << std::endl ; } void FriendList::addToGroup() { QTreeWidgetItem *c = getCurrentPeer(); if (c == NULL) { return; } if (c->type() != TYPE_GPG) { // wrong type return; } std::string groupId = qobject_cast(sender())->data().toString().toStdString(); std::string gpgId = getRsId(c); if (gpgId.empty() || groupId.empty()) { return; } // automatically expand the group, the peer is added to addGroupToExpand(groupId); // add to group rsPeers->assignPeerToGroup(groupId, gpgId, true); } void FriendList::moveToGroup() { QTreeWidgetItem *c = getCurrentPeer(); if (c == NULL) { return; } if (c->type() != TYPE_GPG) { // wrong type return; } std::string groupId = qobject_cast(sender())->data().toString().toStdString(); std::string gpgId = getRsId(c); if (gpgId.empty() || groupId.empty()) { return; } // remove from all groups rsPeers->assignPeerToGroup("", gpgId, false); // automatically expand the group, the peer is added to addGroupToExpand(groupId); // add to group rsPeers->assignPeerToGroup(groupId, gpgId, true); } void FriendList::removeFromGroup() { QTreeWidgetItem *c = getCurrentPeer(); if (c == NULL) { return; } if (c->type() != TYPE_GPG) { // wrong type return; } std::string groupId = qobject_cast(sender())->data().toString().toStdString(); std::string gpgId = getRsId(c); if (gpgId.empty()) { return; } // remove from (all) group(s) rsPeers->assignPeerToGroup(groupId, gpgId, false); } void FriendList::editGroup() { QTreeWidgetItem *c = getCurrentPeer(); if (c == NULL) { return; } if (c->type() != TYPE_GROUP) { // wrong type return; } std::string groupId = getRsId(c); if (groupId.empty()) { return; } CreateGroup editGrpDialog(groupId, this); editGrpDialog.exec(); } void FriendList::removeGroup() { QTreeWidgetItem *c = getCurrentPeer(); if (c == NULL) { return; } if (c->type() != TYPE_GROUP) { // wrong type return; } std::string groupId = getRsId(c); if (groupId.empty()) { return; } rsPeers->removeGroup(groupId); } void FriendList::setHideUnconnected(bool hidden) { if (mHideUnconnected != hidden) { mHideUnconnected = hidden; insertPeers(); } } void FriendList::setShowStatusColumn(bool show) { ui->actionHideState->setEnabled(!show); bool isColumnVisible = !ui->peerTreeWidget->isColumnHidden(COLUMN_STATE); if (isColumnVisible != show) { ui->peerTreeWidget->setColumnHidden(COLUMN_STATE, !show); updateHeader(); insertPeers(); } } void FriendList::setShowLastContactColumn(bool show) { bool isColumnVisible = !ui->peerTreeWidget->isColumnHidden(COLUMN_LAST_CONTACT); if (isColumnVisible != show) { ui->peerTreeWidget->setColumnHidden(COLUMN_LAST_CONTACT, !show); updateHeader(); insertPeers(); } } void FriendList::setShowAvatarColumn(bool show) { bool isColumnVisible = !ui->peerTreeWidget->isColumnHidden(COLUMN_AVATAR); if (isColumnVisible == show) return; ui->peerTreeWidget->setColumnHidden(COLUMN_AVATAR, !show); updateHeader(); insertPeers(); } void FriendList::setHideState(bool hidden) { if (mHideState != hidden) { mHideState = hidden; insertPeers(); } } /** * Set the header visible. */ void FriendList::updateHeader() { if (ui->peerTreeWidget->isColumnHidden(COLUMN_STATE) && ui->peerTreeWidget->isColumnHidden(COLUMN_LAST_CONTACT)) { ui->peerTreeWidget->setHeaderHidden(true); } else { ui->peerTreeWidget->setHeaderHidden(false); } } void FriendList::setSortByName() { ui->peerTreeWidget->sortByColumn(COLUMN_NAME); sortPeersAscendingOrder(); } void FriendList::setSortByState() { ui->peerTreeWidget->sortByColumn(COLUMN_STATE); sortPeersAscendingOrder(); } void FriendList::setSortByLastContact() { ui->peerTreeWidget->sortByColumn(COLUMN_LAST_CONTACT); sortPeersDescendingOrder(); } void FriendList::sortPeersAscendingOrder() { ui->peerTreeWidget->sortByColumn(ui->peerTreeWidget->sortColumn(), Qt::AscendingOrder); } void FriendList::sortPeersDescendingOrder() { ui->peerTreeWidget->sortByColumn(ui->peerTreeWidget->sortColumn(), Qt::DescendingOrder); } void FriendList::setRootIsDecorated(bool show) { ui->peerTreeWidget->setRootIsDecorated(show); } void FriendList::setShowGroups(bool show) { if (mShowGroups != show) { mShowGroups = show; if (mShowGroups) { // remove all not assigned gpg ids int childCount = ui->peerTreeWidget->topLevelItemCount(); int childIndex = 0; while (childIndex < childCount) { QTreeWidgetItem *item = ui->peerTreeWidget->topLevelItem(childIndex); if (item->type() == TYPE_GPG) { delete(ui->peerTreeWidget->takeTopLevelItem(childIndex)); childCount = ui->peerTreeWidget->topLevelItemCount(); continue; } childIndex++; } } insertPeers(); } } /** * If set to true, the customStateString will be shwon in all gpg peer items, * not only in the ssl ids (used in MessengerWindow). * These items will then be doublespaced. */ void FriendList::setBigName(bool bigName) { if (mBigName != bigName) { mBigName = bigName; // Change the size of the already existing items QSize newSize; if (mBigName) { newSize.setHeight(40); newSize.setWidth(40); } else { newSize.setHeight(26); newSize.setWidth(26); } QTreeWidgetItemIterator it(ui->peerTreeWidget); while (*it) { if ((*it)->type() == TYPE_GPG) { (*it)->setSizeHint(COLUMN_NAME, newSize); } it++; } } } /** * Hides all items that don't contain sPattern in the name column. */ void FriendList::filterItems(const QString &sPattern) { filterText = sPattern; int nCount = ui->peerTreeWidget->topLevelItemCount(); for (int nIndex = 0; nIndex < nCount; nIndex++) { FriendList::filterItem(ui->peerTreeWidget->topLevelItem(nIndex), sPattern); } QTreeWidgetItem *c = getCurrentPeer(); if (c && c->isHidden()) { // active item is hidden, deselect it ui->peerTreeWidget->setCurrentItem(NULL); } } bool FriendList::filterItem(QTreeWidgetItem *pItem, const QString &sPattern) { bool bVisible = true; if (sPattern.isEmpty() == false) { if (pItem->text(0).contains(sPattern, Qt::CaseInsensitive) == false) { bVisible = false; } } int nVisibleChildCount = 0; int nCount = pItem->childCount(); for (int nIndex = 0; nIndex < nCount; nIndex++) { if (FriendList::filterItem(pItem->child(nIndex), sPattern)) { nVisibleChildCount++; } } if (bVisible || nVisibleChildCount) { pItem->setHidden(false); } else { pItem->setHidden(true); } return (bVisible || nVisibleChildCount); } /** * Add a groupId to the openGroups list. These groups * will be expanded, when they're added to the QTreeWidget */ void FriendList::addGroupToExpand(const std::string &groupId) { if (openGroups == NULL) { openGroups = new std::set; } openGroups->insert(groupId); } /** * Add a gpgId to the openPeers list. These peers * will be expanded, when they're added to the QTreeWidget */ void FriendList::addPeerToExpand(const std::string &gpgId) { if (openPeers == NULL) { openPeers = new std::set; } openPeers->insert(gpgId); } QMenu *FriendList::createDisplayMenu() { QMenu *displayMenu = new QMenu(this); connect(displayMenu, SIGNAL(aboutToShow()), this, SLOT(updateMenu())); displayMenu->addAction(ui->actionSortPeersDescendingOrder); displayMenu->addAction(ui->actionSortPeersAscendingOrder); QMenu *menu = displayMenu->addMenu(tr("Columns")); menu->addAction(ui->actionShowAvatarColumn); menu->addAction(ui->actionShowLastContactColumn); menu->addAction(ui->actionShowStatusColumn); menu = displayMenu->addMenu(tr("Sort by")); menu->addAction(ui->actionSortByName); menu->addAction(ui->actionSortByState); menu->addAction(ui->actionSortByLastContact); displayMenu->addAction(ui->actionHideOfflineFriends); displayMenu->addAction(ui->actionHideState); displayMenu->addAction(ui->actionRootIsDecorated); displayMenu->addAction(ui->actionShowGroups); QActionGroup *group = new QActionGroup(this); group->addAction(ui->actionSortByName); group->addAction(ui->actionSortByState); group->addAction(ui->actionSortByLastContact); return displayMenu; } void FriendList::updateMenu() { switch (ui->peerTreeWidget->sortColumn()) { case COLUMN_NAME: ui->actionSortByName->setChecked(true); break; case COLUMN_STATE: ui->actionSortByState->setChecked(true); break; case COLUMN_LAST_CONTACT: ui->actionSortByLastContact->setChecked(true); break; case COLUMN_AVATAR: break; } ui->actionShowStatusColumn->setChecked(!ui->peerTreeWidget->isColumnHidden(COLUMN_STATE)); ui->actionShowLastContactColumn->setChecked(!ui->peerTreeWidget->isColumnHidden(COLUMN_LAST_CONTACT)); ui->actionShowAvatarColumn->setChecked(!ui->peerTreeWidget->isColumnHidden(COLUMN_AVATAR)); ui->actionHideOfflineFriends->setChecked(mHideUnconnected); ui->actionHideState->setChecked(mHideState); ui->actionRootIsDecorated->setChecked(ui->peerTreeWidget->rootIsDecorated()); ui->actionShowGroups->setChecked(mShowGroups); }