/* Copyright © 2014-2015 by The qTox Project This file is part of qTox, a Qt-based graphical interface for Tox. qTox is libre 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 3 of the License, or (at your option) any later version. qTox 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 qTox. If not, see . */ #include "friendlistwidget.h" #include "friendlistlayout.h" #include "src/friend.h" #include "src/friendlist.h" #include "src/misc/settings.h" #include "friendwidget.h" #include "groupwidget.h" #include "circlewidget.h" #include #include #include #include #include #include #include "widget.h" FriendListWidget::FriendListWidget(Widget* parent, bool groupsOnTop) : QWidget(parent) , groupsOnTop(groupsOnTop) { listLayout = new FriendListLayout(); setLayout(listLayout); setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); circleLayout.getLayout()->setSpacing(0); circleLayout.getLayout()->setMargin(0); groupLayout.getLayout()->setSpacing(0); groupLayout.getLayout()->setMargin(0); listLayout->addLayout(circleLayout.getLayout()); onGroupchatPositionChanged(groupsOnTop); setAcceptDrops(true); } void FriendListWidget::addGroupWidget(GroupWidget* widget) { groupLayout.addSortedWidget(widget); connect(widget, &GroupWidget::renameRequested, this, &FriendListWidget::renameGroupWidget); // Only rename group if groups are visible. if (Widget::getInstance()->groupsVisible()) widget->rename(); } void FriendListWidget::addFriendWidget(FriendWidget* w, Status s, int circleIndex) { CircleWidget* circleWidget = CircleWidget::getFromID(circleIndex); if (circleWidget == nullptr) moveWidget(w, s, true); else circleWidget->addFriendWidget(w, s); } void FriendListWidget::addCircleWidget(int id) { createCircleWidget(id); } void FriendListWidget::addCircleWidget(FriendWidget* friendWidget) { CircleWidget* circleWidget = createCircleWidget(); if (friendWidget != nullptr) { CircleWidget* circleOriginal = CircleWidget::getFromID(Settings::getInstance().getFriendCircleID(FriendList::findFriend(friendWidget->friendId)->getToxId())); circleWidget->addFriendWidget(friendWidget, FriendList::findFriend(friendWidget->friendId)->getStatus()); circleWidget->setExpanded(true); Widget::getInstance()->searchCircle(circleWidget); if (circleOriginal != nullptr) Widget::getInstance()->searchCircle(circleOriginal); } } void FriendListWidget::removeCircleWidget(CircleWidget* widget) { circleLayout.removeSortedWidget(widget); widget->deleteLater(); } void FriendListWidget::searchChatrooms(const QString &searchString, bool hideOnline, bool hideOffline, bool hideGroups) { groupLayout.search(searchString, hideGroups); listLayout->searchChatrooms(searchString, hideOnline, hideOffline); for (int i = 0; i != circleLayout.getLayout()->count(); ++i) { CircleWidget* circleWidget = static_cast(circleLayout.getLayout()->itemAt(i)->widget()); circleWidget->search(searchString, true, hideOnline, hideOffline); } } void FriendListWidget::renameGroupWidget(const QString &newName) { assert(sender() != nullptr); GroupWidget* groupWidget = dynamic_cast(sender()); assert(groupWidget != nullptr); groupLayout.removeSortedWidget(groupWidget); groupWidget->setName(newName); groupLayout.addSortedWidget(groupWidget); reDraw(); // Prevent artifacts. } void FriendListWidget::renameCircleWidget(const QString &newName) { assert(sender() != nullptr); CircleWidget* circleWidget = dynamic_cast(sender()); assert(circleWidget != nullptr); // Rename before removing so you can find it successfully. circleLayout.removeSortedWidget(circleWidget); circleWidget->setName(newName); circleLayout.addSortedWidget(circleWidget); } void FriendListWidget::onGroupchatPositionChanged(bool top) { groupsOnTop = top; listLayout->removeItem(groupLayout.getLayout()); if (top) { listLayout->insertLayout(0, groupLayout.getLayout()); } else { listLayout->insertLayout(1, groupLayout.getLayout()); } } void FriendListWidget::cycleContacts(GenericChatroomWidget* activeChatroomWidget, bool forward) { if (activeChatroomWidget == nullptr) return; int index = -1; QLayout* currentLayout = nullptr; CircleWidget* circleWidget = nullptr; FriendWidget* friendWidget = dynamic_cast(activeChatroomWidget); if (friendWidget != nullptr) { circleWidget = CircleWidget::getFromID(Settings::getInstance().getFriendCircleID(FriendList::findFriend(friendWidget->friendId)->getToxId())); if (circleWidget != nullptr) { if (circleWidget->cycleContacts(friendWidget, forward)) return; index = circleLayout.indexOfSortedWidget(circleWidget); currentLayout = circleLayout.getLayout(); } else { currentLayout = listLayout->getLayoutOnline(); index = listLayout->indexOfFriendWidget(friendWidget, true); if (index == -1) { currentLayout = listLayout->getLayoutOffline(); index = listLayout->indexOfFriendWidget(friendWidget, false); } } } else { GroupWidget* groupWidget = dynamic_cast(activeChatroomWidget); if (groupWidget != nullptr) { currentLayout = groupLayout.getLayout(); index = groupLayout.indexOfSortedWidget(groupWidget); } else { return; }; } index += forward ? 1 : -1; for (;;) { // Bounds checking. if (index < 0) { currentLayout = nextLayout(currentLayout, forward); index = currentLayout->count() - 1; continue; } else if (index >= currentLayout->count()) { currentLayout = nextLayout(currentLayout, forward); index = 0; continue; } // Go to the actual next index. if (currentLayout == listLayout->getLayoutOnline() || currentLayout == listLayout->getLayoutOffline() || currentLayout == groupLayout.getLayout()) { GenericChatroomWidget* chatWidget = dynamic_cast(currentLayout->itemAt(index)->widget()); if (chatWidget != nullptr) emit chatWidget->chatroomWidgetClicked(chatWidget); return; } else if (currentLayout == circleLayout.getLayout()) { circleWidget = dynamic_cast(currentLayout->itemAt(index)->widget()); if (circleWidget != nullptr) { if (!circleWidget->cycleContacts(forward)) { // Skip empty or finished circles. index += forward ? 1 : -1; continue; } } return; } else { return; } } } QVector FriendListWidget::getAllCircles() { QVector vec; vec.reserve(circleLayout.getLayout()->count()); for (int i = 0; i < circleLayout.getLayout()->count(); ++i) { vec.push_back(dynamic_cast(circleLayout.getLayout()->itemAt(i)->widget())); } return vec; } void FriendListWidget::dragEnterEvent(QDragEnterEvent* event) { if (event->mimeData()->hasFormat("friend")) event->acceptProposedAction(); } void FriendListWidget::dropEvent(QDropEvent* event) { if (event->mimeData()->hasFormat("friend")) { int friendId = event->mimeData()->data("friend").toInt(); Friend* f = FriendList::findFriend(friendId); assert(f != nullptr); FriendWidget* widget = f->getFriendWidget(); assert(widget != nullptr); // Update old circle after moved. CircleWidget* circleWidget = CircleWidget::getFromID(Settings::getInstance().getFriendCircleID(f->getToxId())); listLayout->addFriendWidget(widget, f->getStatus()); if (circleWidget != nullptr) { // In case the status was changed while moving, update both. circleWidget->updateStatus(); } } } void FriendListWidget::moveWidget(FriendWidget* w, Status s, bool add) { int circleId = Settings::getInstance().getFriendCircleID(FriendList::findFriend(w->friendId)->getToxId()); CircleWidget* circleWidget = CircleWidget::getFromID(circleId); if (circleWidget == nullptr || add) { if (circleId != -1) Settings::getInstance().setFriendCircleID(FriendList::findFriend(w->friendId)->getToxId(), -1); listLayout->addFriendWidget(w, s); return; } circleWidget->addFriendWidget(w, s); } // update widget after add/delete/hide/show void FriendListWidget::reDraw() { hide(); show(); resize(QSize()); //lifehack } CircleWidget* FriendListWidget::createCircleWidget(int id) { CircleWidget* circleWidget = new CircleWidget(this, id); circleLayout.addSortedWidget(circleWidget); connect(this, &FriendListWidget::onCompactChanged, circleWidget, &CircleWidget::onCompactChanged); connect(circleWidget, &CircleWidget::renameRequested, this, &FriendListWidget::renameCircleWidget); circleWidget->show(); // Avoid flickering. return circleWidget; } QLayout* FriendListWidget::nextLayout(QLayout* layout, bool forward) const { if (layout == groupLayout.getLayout()) { if (forward) { if (groupsOnTop) return listLayout->getLayoutOnline(); return listLayout->getLayoutOffline(); } else { if (groupsOnTop) return circleLayout.getLayout(); return listLayout->getLayoutOnline(); } } else if (layout == listLayout->getLayoutOnline()) { if (forward) { if (groupsOnTop) return listLayout->getLayoutOffline(); return groupLayout.getLayout(); } else { if (groupsOnTop) return groupLayout.getLayout(); return circleLayout.getLayout(); } } else if (layout == listLayout->getLayoutOffline()) { if (forward) return circleLayout.getLayout(); else if (groupsOnTop) return listLayout->getLayoutOnline(); return groupLayout.getLayout(); } else if (layout == circleLayout.getLayout()) { if (forward) { if (groupsOnTop) return groupLayout.getLayout(); return listLayout->getLayoutOnline(); } else return listLayout->getLayoutOffline(); } return nullptr; }