1 /*
2 Copyright © 2014-2019 by The qTox Project Contributors
3
4 This file is part of qTox, a Qt-based graphical interface for Tox.
5
6 qTox is libre software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 qTox is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with qTox. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "friendlistwidget.h"
21 #include "circlewidget.h"
22 #include "friendlistlayout.h"
23 #include "friendwidget.h"
24 #include "groupwidget.h"
25 #include "widget.h"
26 #include "src/friendlist.h"
27 #include "src/model/friend.h"
28 #include "src/model/group.h"
29 #include "src/model/status.h"
30 #include "src/persistence/settings.h"
31 #include "src/widget/categorywidget.h"
32
33 #include <QDragEnterEvent>
34 #include <QDragLeaveEvent>
35 #include <QGridLayout>
36 #include <QMimeData>
37 #include <QTimer>
38 #include <cassert>
39
40 enum class Time
41 {
42 Today,
43 Yesterday,
44 ThisWeek,
45 ThisMonth,
46 Month1Ago,
47 Month2Ago,
48 Month3Ago,
49 Month4Ago,
50 Month5Ago,
51 LongAgo,
52 Never
53 };
54
55 static const int LAST_TIME = static_cast<int>(Time::Never);
56
getTimeBucket(const QDateTime & date)57 Time getTimeBucket(const QDateTime& date)
58 {
59 if (date == QDateTime()) {
60 return Time::Never;
61 }
62
63 QDate today = QDate::currentDate();
64 // clang-format off
65 const QMap<Time, QDate> dates {
66 { Time::Today, today.addDays(0) },
67 { Time::Yesterday, today.addDays(-1) },
68 { Time::ThisWeek, today.addDays(-6) },
69 { Time::ThisMonth, today.addMonths(-1) },
70 { Time::Month1Ago, today.addMonths(-2) },
71 { Time::Month2Ago, today.addMonths(-3) },
72 { Time::Month3Ago, today.addMonths(-4) },
73 { Time::Month4Ago, today.addMonths(-5) },
74 { Time::Month5Ago, today.addMonths(-6) },
75 };
76 // clang-format on
77
78 for (Time time : dates.keys()) {
79 if (dates[time] <= date.date()) {
80 return time;
81 }
82 }
83
84 return Time::LongAgo;
85 }
86
getActiveTimeFriend(const Friend * contact)87 QDateTime getActiveTimeFriend(const Friend* contact)
88 {
89 return Settings::getInstance().getFriendActivity(contact->getPublicKey());
90 }
91
timeUntilTomorrow()92 qint64 timeUntilTomorrow()
93 {
94 QDateTime now = QDateTime::currentDateTime();
95 QDateTime tomorrow = now.addDays(1); // Tomorrow.
96 tomorrow.setTime(QTime()); // Midnight.
97 return now.msecsTo(tomorrow);
98 }
99
FriendListWidget(Widget * parent,bool groupsOnTop)100 FriendListWidget::FriendListWidget(Widget* parent, bool groupsOnTop)
101 : QWidget(parent)
102 , groupsOnTop(groupsOnTop)
103 {
104 listLayout = new FriendListLayout();
105 setLayout(listLayout);
106 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
107
108 groupLayout.getLayout()->setSpacing(0);
109 groupLayout.getLayout()->setMargin(0);
110
111 // Prevent QLayout's add child warning before setting the mode.
112 listLayout->removeItem(listLayout->getLayoutOnline());
113 listLayout->removeItem(listLayout->getLayoutOffline());
114
115 mode = Settings::getInstance().getFriendSortingMode();
116 sortByMode(mode);
117
118 onGroupchatPositionChanged(groupsOnTop);
119 dayTimer = new QTimer(this);
120 dayTimer->setTimerType(Qt::VeryCoarseTimer);
121 connect(dayTimer, &QTimer::timeout, this, &FriendListWidget::dayTimeout);
122 dayTimer->start(timeUntilTomorrow());
123
124 setAcceptDrops(true);
125 }
126
~FriendListWidget()127 FriendListWidget::~FriendListWidget()
128 {
129 if (activityLayout != nullptr) {
130 QLayoutItem* item;
131 while ((item = activityLayout->takeAt(0)) != nullptr) {
132 delete item->widget();
133 delete item;
134 }
135 delete activityLayout;
136 }
137
138 if (circleLayout != nullptr) {
139 QLayoutItem* item;
140 while ((item = circleLayout->getLayout()->takeAt(0)) != nullptr) {
141 delete item->widget();
142 delete item;
143 }
144 delete circleLayout;
145 }
146 }
147
setMode(SortingMode mode)148 void FriendListWidget::setMode(SortingMode mode)
149 {
150 if (this->mode == mode)
151 return;
152
153 this->mode = mode;
154 Settings::getInstance().setFriendSortingMode(mode);
155
156 sortByMode(mode);
157 }
158
sortByMode(SortingMode mode)159 void FriendListWidget::sortByMode(SortingMode mode)
160 {
161 if (mode == SortingMode::Name) {
162 circleLayout = new GenericChatItemLayout;
163 circleLayout->getLayout()->setSpacing(0);
164 circleLayout->getLayout()->setMargin(0);
165
166 for (int i = 0; i < Settings::getInstance().getCircleCount(); ++i) {
167 addCircleWidget(i);
168 CircleWidget::getFromID(i)->setVisible(false);
169 }
170
171 // Only display circles once all created to avoid artifacts.
172 for (int i = 0; i < Settings::getInstance().getCircleCount(); ++i)
173 CircleWidget::getFromID(i)->setVisible(true);
174
175 int count = activityLayout ? activityLayout->count() : 0;
176 for (int i = 0; i < count; i++) {
177 QWidget* widget = activityLayout->itemAt(i)->widget();
178 CategoryWidget* categoryWidget = qobject_cast<CategoryWidget*>(widget);
179 if (categoryWidget) {
180 categoryWidget->moveFriendWidgets(this);
181 } else {
182 qWarning() << "Unexpected widget";
183 }
184 }
185
186 listLayout->addLayout(listLayout->getLayoutOnline());
187 listLayout->addLayout(listLayout->getLayoutOffline());
188 listLayout->addLayout(circleLayout->getLayout());
189 onGroupchatPositionChanged(groupsOnTop);
190
191 if (activityLayout != nullptr) {
192 QLayoutItem* item;
193 while ((item = activityLayout->takeAt(0)) != nullptr) {
194 delete item->widget();
195 delete item;
196 }
197 delete activityLayout;
198 activityLayout = nullptr;
199 }
200
201 reDraw();
202 } else if (mode == SortingMode::Activity) {
203 QLocale ql(Settings::getInstance().getTranslation());
204 QDate today = QDate::currentDate();
205 #define COMMENT "Category for sorting friends by activity"
206 // clang-format off
207 const QMap<Time, QString> names {
208 { Time::Today, tr("Today", COMMENT) },
209 { Time::Yesterday, tr("Yesterday", COMMENT) },
210 { Time::ThisWeek, tr("Last 7 days", COMMENT) },
211 { Time::ThisMonth, tr("This month", COMMENT) },
212 { Time::LongAgo, tr("Older than 6 Months", COMMENT) },
213 { Time::Never, tr("Never", COMMENT) },
214 { Time::Month1Ago, ql.monthName(today.addMonths(-1).month()) },
215 { Time::Month2Ago, ql.monthName(today.addMonths(-2).month()) },
216 { Time::Month3Ago, ql.monthName(today.addMonths(-3).month()) },
217 { Time::Month4Ago, ql.monthName(today.addMonths(-4).month()) },
218 { Time::Month5Ago, ql.monthName(today.addMonths(-5).month()) },
219 };
220 // clang-format on
221 #undef COMMENT
222
223 activityLayout = new QVBoxLayout();
224 bool compact = Settings::getInstance().getCompactLayout();
225 for (Time t : names.keys()) {
226 CategoryWidget* category = new CategoryWidget(compact, this);
227 category->setName(names[t]);
228 activityLayout->addWidget(category);
229 }
230
231 moveFriends(listLayout->getLayoutOffline());
232 moveFriends(listLayout->getLayoutOnline());
233 if (circleLayout != nullptr) {
234 moveFriends(circleLayout->getLayout());
235 }
236
237 for (int i = 0; i < activityLayout->count(); ++i) {
238 QWidget* widget = activityLayout->itemAt(i)->widget();
239 CategoryWidget* categoryWidget = qobject_cast<CategoryWidget*>(widget);
240 categoryWidget->setVisible(categoryWidget->hasChatrooms());
241 }
242
243 listLayout->removeItem(listLayout->getLayoutOnline());
244 listLayout->removeItem(listLayout->getLayoutOffline());
245
246 if (circleLayout != nullptr) {
247 listLayout->removeItem(circleLayout->getLayout());
248
249 QLayoutItem* item;
250 while ((item = circleLayout->getLayout()->takeAt(0)) != nullptr) {
251 delete item->widget();
252 delete item;
253 }
254 delete circleLayout;
255 circleLayout = nullptr;
256 }
257
258 listLayout->insertLayout(1, activityLayout);
259
260 reDraw();
261 }
262 }
263
moveFriends(QLayout * layout)264 void FriendListWidget::moveFriends(QLayout* layout)
265 {
266 while (!layout->isEmpty()) {
267 QWidget* widget = layout->itemAt(0)->widget();
268 FriendWidget* friendWidget = qobject_cast<FriendWidget*>(widget);
269 CircleWidget* circleWidget = qobject_cast<CircleWidget*>(widget);
270 if (circleWidget) {
271 circleWidget->moveFriendWidgets(this);
272 } else if (friendWidget) {
273 const Friend* contact = friendWidget->getFriend();
274 auto* categoryWidget = getTimeCategoryWidget(contact);
275 categoryWidget->addFriendWidget(friendWidget, contact->getStatus());
276 }
277 }
278 }
279
getTimeCategoryWidget(const Friend * frd) const280 CategoryWidget* FriendListWidget::getTimeCategoryWidget(const Friend* frd) const
281 {
282 const auto activityTime = getActiveTimeFriend(frd);
283 int timeIndex = static_cast<int>(getTimeBucket(activityTime));
284 QWidget* widget = activityLayout->itemAt(timeIndex)->widget();
285 return qobject_cast<CategoryWidget*>(widget);
286 }
287
getMode() const288 FriendListWidget::SortingMode FriendListWidget::getMode() const
289 {
290 return mode;
291 }
292
addGroupWidget(GroupWidget * widget)293 void FriendListWidget::addGroupWidget(GroupWidget* widget)
294 {
295 groupLayout.addSortedWidget(widget);
296 Group* g = widget->getGroup();
297 connect(g, &Group::titleChanged, [=](const QString& author, const QString& name) {
298 Q_UNUSED(author);
299 renameGroupWidget(widget, name);
300 });
301 }
302
addFriendWidget(FriendWidget * w,Status::Status s,int circleIndex)303 void FriendListWidget::addFriendWidget(FriendWidget* w, Status::Status s, int circleIndex)
304 {
305 CircleWidget* circleWidget = CircleWidget::getFromID(circleIndex);
306 if (circleWidget == nullptr)
307 moveWidget(w, s, true);
308 else
309 circleWidget->addFriendWidget(w, s);
310 connect(w, &FriendWidget::friendWidgetRenamed, this, &FriendListWidget::onFriendWidgetRenamed);
311 }
312
removeGroupWidget(GroupWidget * w)313 void FriendListWidget::removeGroupWidget(GroupWidget* w)
314 {
315 groupLayout.removeSortedWidget(w);
316 w->deleteLater();
317 }
318
removeFriendWidget(FriendWidget * w)319 void FriendListWidget::removeFriendWidget(FriendWidget* w)
320 {
321 const Friend* contact = w->getFriend();
322
323 if (mode == SortingMode::Activity) {
324 auto* categoryWidget = getTimeCategoryWidget(contact);
325 categoryWidget->removeFriendWidget(w, contact->getStatus());
326 categoryWidget->setVisible(categoryWidget->hasChatrooms());
327 } else {
328 int id = Settings::getInstance().getFriendCircleID(contact->getPublicKey());
329 CircleWidget* circleWidget = CircleWidget::getFromID(id);
330 if (circleWidget != nullptr) {
331 circleWidget->removeFriendWidget(w, contact->getStatus());
332 emit searchCircle(*circleWidget);
333 }
334 }
335 }
336
addCircleWidget(int id)337 void FriendListWidget::addCircleWidget(int id)
338 {
339 createCircleWidget(id);
340 }
341
addCircleWidget(FriendWidget * friendWidget)342 void FriendListWidget::addCircleWidget(FriendWidget* friendWidget)
343 {
344 CircleWidget* circleWidget = createCircleWidget();
345 if (circleWidget != nullptr) {
346 if (friendWidget != nullptr) {
347 const Friend* f = friendWidget->getFriend();
348 ToxPk toxPk = f->getPublicKey();
349 int circleId = Settings::getInstance().getFriendCircleID(toxPk);
350 CircleWidget* circleOriginal = CircleWidget::getFromID(circleId);
351
352 circleWidget->addFriendWidget(friendWidget, f->getStatus());
353 circleWidget->setExpanded(true);
354
355 if (circleOriginal != nullptr)
356 emit searchCircle(*circleOriginal);
357 }
358
359 emit searchCircle(*circleWidget);
360
361 if (window()->isActiveWindow())
362 circleWidget->editName();
363 }
364 reDraw();
365 }
366
removeCircleWidget(CircleWidget * widget)367 void FriendListWidget::removeCircleWidget(CircleWidget* widget)
368 {
369 circleLayout->removeSortedWidget(widget);
370 widget->deleteLater();
371 }
372
searchChatrooms(const QString & searchString,bool hideOnline,bool hideOffline,bool hideGroups)373 void FriendListWidget::searchChatrooms(const QString& searchString, bool hideOnline,
374 bool hideOffline, bool hideGroups)
375 {
376 groupLayout.search(searchString, hideGroups);
377 listLayout->searchChatrooms(searchString, hideOnline, hideOffline);
378
379 if (circleLayout != nullptr) {
380 for (int i = 0; i != circleLayout->getLayout()->count(); ++i) {
381 CircleWidget* circleWidget =
382 static_cast<CircleWidget*>(circleLayout->getLayout()->itemAt(i)->widget());
383 circleWidget->search(searchString, true, hideOnline, hideOffline);
384 }
385 } else if (activityLayout != nullptr) {
386 for (int i = 0; i != activityLayout->count(); ++i) {
387 CategoryWidget* categoryWidget =
388 static_cast<CategoryWidget*>(activityLayout->itemAt(i)->widget());
389 categoryWidget->search(searchString, true, hideOnline, hideOffline);
390 categoryWidget->setVisible(categoryWidget->hasChatrooms());
391 }
392 }
393 }
394
renameGroupWidget(GroupWidget * groupWidget,const QString & newName)395 void FriendListWidget::renameGroupWidget(GroupWidget* groupWidget, const QString& newName)
396 {
397 groupLayout.removeSortedWidget(groupWidget);
398 groupLayout.addSortedWidget(groupWidget);
399 }
400
renameCircleWidget(CircleWidget * circleWidget,const QString & newName)401 void FriendListWidget::renameCircleWidget(CircleWidget* circleWidget, const QString& newName)
402 {
403 circleLayout->removeSortedWidget(circleWidget);
404 circleWidget->setName(newName);
405 circleLayout->addSortedWidget(circleWidget);
406 }
407
onFriendWidgetRenamed(FriendWidget * friendWidget)408 void FriendListWidget::onFriendWidgetRenamed(FriendWidget* friendWidget)
409 {
410 const Friend* contact = friendWidget->getFriend();
411 auto status = contact->getStatus();
412 if (mode == SortingMode::Activity) {
413 auto* categoryWidget = getTimeCategoryWidget(contact);
414 categoryWidget->removeFriendWidget(friendWidget, status);
415 categoryWidget->addFriendWidget(friendWidget, status);
416 } else {
417 int id = Settings::getInstance().getFriendCircleID(contact->getPublicKey());
418 CircleWidget* circleWidget = CircleWidget::getFromID(id);
419 if (circleWidget != nullptr) {
420 circleWidget->removeFriendWidget(friendWidget, status);
421 circleWidget->addFriendWidget(friendWidget, status);
422 emit searchCircle(*circleWidget);
423 } else {
424 listLayout->removeFriendWidget(friendWidget, status);
425 listLayout->addFriendWidget(friendWidget, status);
426 }
427 }
428 }
429
onGroupchatPositionChanged(bool top)430 void FriendListWidget::onGroupchatPositionChanged(bool top)
431 {
432 groupsOnTop = top;
433
434 if (mode != SortingMode::Name)
435 return;
436
437 listLayout->removeItem(groupLayout.getLayout());
438
439 if (top)
440 listLayout->insertLayout(0, groupLayout.getLayout());
441 else
442 listLayout->insertLayout(1, groupLayout.getLayout());
443
444 reDraw();
445 }
446
cycleContacts(GenericChatroomWidget * activeChatroomWidget,bool forward)447 void FriendListWidget::cycleContacts(GenericChatroomWidget* activeChatroomWidget, bool forward)
448 {
449 if (!activeChatroomWidget) {
450 return;
451 }
452
453 int index = -1;
454 FriendWidget* friendWidget = qobject_cast<FriendWidget*>(activeChatroomWidget);
455
456 if (mode == SortingMode::Activity) {
457 if (!friendWidget) {
458 return;
459 }
460
461 const auto activityTime = getActiveTimeFriend(friendWidget->getFriend());
462 index = static_cast<int>(getTimeBucket(activityTime));
463 QWidget* widget = activityLayout->itemAt(index)->widget();
464 CategoryWidget* categoryWidget = qobject_cast<CategoryWidget*>(widget);
465
466 if (categoryWidget == nullptr || categoryWidget->cycleContacts(friendWidget, forward)) {
467 return;
468 }
469
470 index += forward ? 1 : -1;
471
472 for (;;) {
473 // Bounds checking.
474 if (index < 0) {
475 index = LAST_TIME;
476 continue;
477 } else if (index > LAST_TIME) {
478 index = 0;
479 continue;
480 }
481
482 auto* widget = activityLayout->itemAt(index)->widget();
483 categoryWidget = qobject_cast<CategoryWidget*>(widget);
484
485 if (categoryWidget != nullptr) {
486 if (!categoryWidget->cycleContacts(forward)) {
487 // Skip empty or finished categories.
488 index += forward ? 1 : -1;
489 continue;
490 }
491 }
492
493 break;
494 }
495
496 return;
497 }
498
499 QLayout* currentLayout = nullptr;
500 CircleWidget* circleWidget = nullptr;
501
502 if (friendWidget != nullptr) {
503 const ToxPk& pk = friendWidget->getFriend()->getPublicKey();
504 uint32_t circleId = Settings::getInstance().getFriendCircleID(pk);
505 circleWidget = CircleWidget::getFromID(circleId);
506 if (circleWidget != nullptr) {
507 if (circleWidget->cycleContacts(friendWidget, forward)) {
508 return;
509 }
510
511 index = circleLayout->indexOfSortedWidget(circleWidget);
512 currentLayout = circleLayout->getLayout();
513 } else {
514 currentLayout = listLayout->getLayoutOnline();
515 index = listLayout->indexOfFriendWidget(friendWidget, true);
516 if (index == -1) {
517 currentLayout = listLayout->getLayoutOffline();
518 index = listLayout->indexOfFriendWidget(friendWidget, false);
519 }
520 }
521 } else {
522 GroupWidget* groupWidget = qobject_cast<GroupWidget*>(activeChatroomWidget);
523 if (groupWidget != nullptr) {
524 currentLayout = groupLayout.getLayout();
525 index = groupLayout.indexOfSortedWidget(groupWidget);
526 } else {
527 return;
528 };
529 }
530
531 index += forward ? 1 : -1;
532
533 for (;;) {
534 // Bounds checking.
535 if (index < 0) {
536 currentLayout = nextLayout(currentLayout, forward);
537 index = currentLayout->count() - 1;
538 continue;
539 } else if (index >= currentLayout->count()) {
540 currentLayout = nextLayout(currentLayout, forward);
541 index = 0;
542 continue;
543 }
544
545 // Go to the actual next index.
546 if (currentLayout == listLayout->getLayoutOnline()
547 || currentLayout == listLayout->getLayoutOffline()
548 || currentLayout == groupLayout.getLayout()) {
549 GenericChatroomWidget* chatWidget =
550 qobject_cast<GenericChatroomWidget*>(currentLayout->itemAt(index)->widget());
551
552 if (chatWidget != nullptr)
553 emit chatWidget->chatroomWidgetClicked(chatWidget);
554
555 return;
556 } else if (currentLayout == circleLayout->getLayout()) {
557 circleWidget = qobject_cast<CircleWidget*>(currentLayout->itemAt(index)->widget());
558 if (circleWidget != nullptr) {
559 if (!circleWidget->cycleContacts(forward)) {
560 // Skip empty or finished circles.
561 index += forward ? 1 : -1;
562 continue;
563 }
564 }
565 return;
566 } else {
567 return;
568 }
569 }
570 }
571
dragEnterEvent(QDragEnterEvent * event)572 void FriendListWidget::dragEnterEvent(QDragEnterEvent* event)
573 {
574 if (!event->mimeData()->hasFormat("toxPk")) {
575 return;
576 }
577 ToxPk toxPk(event->mimeData()->data("toxPk"));
578 Friend* frnd = FriendList::findFriend(toxPk);
579 if (frnd)
580 event->acceptProposedAction();
581 }
582
dropEvent(QDropEvent * event)583 void FriendListWidget::dropEvent(QDropEvent* event)
584 {
585 // Check, that the element is dropped from qTox
586 QObject* o = event->source();
587 FriendWidget* widget = qobject_cast<FriendWidget*>(o);
588 if (!widget)
589 return;
590
591 // Check, that the user has a friend with the same ToxPk
592 assert(event->mimeData()->hasFormat("toxPk"));
593 const ToxPk toxPk{event->mimeData()->data("toxPk")};
594 Friend* f = FriendList::findFriend(toxPk);
595 if (!f)
596 return;
597
598 // Save CircleWidget before changing the Id
599 int circleId = Settings::getInstance().getFriendCircleID(f->getPublicKey());
600 CircleWidget* circleWidget = CircleWidget::getFromID(circleId);
601
602 moveWidget(widget, f->getStatus(), true);
603
604 if (circleWidget)
605 circleWidget->updateStatus();
606 }
607
dayTimeout()608 void FriendListWidget::dayTimeout()
609 {
610 if (mode == SortingMode::Activity) {
611 setMode(SortingMode::Name);
612 setMode(SortingMode::Activity); // Refresh all.
613 }
614
615 dayTimer->start(timeUntilTomorrow());
616 }
617
moveWidget(FriendWidget * widget,Status::Status s,bool add)618 void FriendListWidget::moveWidget(FriendWidget* widget, Status::Status s, bool add)
619 {
620 if (mode == SortingMode::Name) {
621 const Friend* f = widget->getFriend();
622 int circleId = Settings::getInstance().getFriendCircleID(f->getPublicKey());
623 CircleWidget* circleWidget = CircleWidget::getFromID(circleId);
624
625 if (circleWidget == nullptr || add) {
626 if (circleId != -1)
627 Settings::getInstance().setFriendCircleID(f->getPublicKey(), -1);
628
629 listLayout->addFriendWidget(widget, s);
630 return;
631 }
632
633 circleWidget->addFriendWidget(widget, s);
634 } else {
635 const Friend* contact = widget->getFriend();
636 auto* categoryWidget = getTimeCategoryWidget(contact);
637 categoryWidget->addFriendWidget(widget, contact->getStatus());
638 categoryWidget->show();
639 }
640 }
641
updateActivityTime(const QDateTime & time)642 void FriendListWidget::updateActivityTime(const QDateTime& time)
643 {
644 if (mode != SortingMode::Activity)
645 return;
646
647 int timeIndex = static_cast<int>(getTimeBucket(time));
648 QWidget* widget = activityLayout->itemAt(timeIndex)->widget();
649 CategoryWidget* categoryWidget = static_cast<CategoryWidget*>(widget);
650 categoryWidget->updateStatus();
651
652 categoryWidget->setVisible(categoryWidget->hasChatrooms());
653 }
654
655 // update widget after add/delete/hide/show
reDraw()656 void FriendListWidget::reDraw()
657 {
658 hide();
659 show();
660 resize(QSize()); // lifehack
661 }
662
createCircleWidget(int id)663 CircleWidget* FriendListWidget::createCircleWidget(int id)
664 {
665 if (id == -1)
666 id = Settings::getInstance().addCircle();
667
668 // Stop, after it has been created. Code after this is for displaying.
669 if (mode == SortingMode::Activity)
670 return nullptr;
671
672 assert(circleLayout != nullptr);
673
674 CircleWidget* circleWidget = new CircleWidget(this, id);
675 emit connectCircleWidget(*circleWidget);
676 circleLayout->addSortedWidget(circleWidget);
677 connect(this, &FriendListWidget::onCompactChanged, circleWidget, &CircleWidget::onCompactChanged);
678 connect(circleWidget, &CircleWidget::renameRequested, this, &FriendListWidget::renameCircleWidget);
679 circleWidget->show(); // Avoid flickering.
680
681 return circleWidget;
682 }
683
nextLayout(QLayout * layout,bool forward) const684 QLayout* FriendListWidget::nextLayout(QLayout* layout, bool forward) const
685 {
686 if (layout == groupLayout.getLayout()) {
687 if (forward) {
688 if (groupsOnTop)
689 return listLayout->getLayoutOnline();
690
691 return listLayout->getLayoutOffline();
692 } else {
693 if (groupsOnTop)
694 return circleLayout->getLayout();
695
696 return listLayout->getLayoutOnline();
697 }
698 } else if (layout == listLayout->getLayoutOnline()) {
699 if (forward) {
700 if (groupsOnTop)
701 return listLayout->getLayoutOffline();
702
703 return groupLayout.getLayout();
704 } else {
705 if (groupsOnTop)
706 return groupLayout.getLayout();
707
708 return circleLayout->getLayout();
709 }
710 } else if (layout == listLayout->getLayoutOffline()) {
711 if (forward)
712 return circleLayout->getLayout();
713 else if (groupsOnTop)
714 return listLayout->getLayoutOnline();
715
716 return groupLayout.getLayout();
717 } else if (layout == circleLayout->getLayout()) {
718 if (forward) {
719 if (groupsOnTop)
720 return groupLayout.getLayout();
721
722 return listLayout->getLayoutOnline();
723 } else
724 return listLayout->getLayoutOffline();
725 }
726 return nullptr;
727 }
728