Use pkg-config to find ncursesw
[centerim5.git] / src / ConversationRoomList.cpp
bloba35bd2c467e98ced5d202b991d946826c977c438
1 // Copyright (C) 2015 Wade Berrier <wberrier@gmail.com>
2 //
3 // This file is part of CenterIM.
4 //
5 // CenterIM is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // CenterIM is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with CenterIM. If not, see <http://www.gnu.org/licenses/>.
18 #include "ConversationRoomList.h"
20 // Move the widget to a position according to sorting function.
21 void ConversationRoomList::moveToSortedPosition(Buddy *new_buddy)
23 Buddy *buddy = nullptr;
24 CppConsUI::Widgets::iterator iter;
26 g_assert(new_buddy != nullptr);
28 for (iter = children_.begin(); iter != children_.end(); ++iter) {
29 buddy = dynamic_cast<Buddy *>(*iter);
30 g_assert(buddy != nullptr);
32 // If buddy is in the list already, skip it.
33 if (*buddy == *new_buddy)
34 continue;
36 // Break once insertion point is found.
37 if (!Buddy::less_than_op_away_name(*buddy, *new_buddy))
38 break;
41 // Do not change anything if wanting to put into the same position (also
42 // returns on single node case).
43 if (*buddy == *new_buddy)
44 return;
46 // Insert after if at end.
47 if (iter == children_.end())
48 moveWidgetAfter(*new_buddy, *buddy);
49 else
50 moveWidgetBefore(*new_buddy, *buddy);
53 void ConversationRoomList::add_users(GList *cbuddies, gboolean /*new_arrivals*/)
55 for (GList *l = cbuddies; l != nullptr; l = l->next) {
56 PurpleConvChatBuddy *pbuddy = static_cast<PurpleConvChatBuddy *>(l->data);
58 auto buddy = new Buddy(pbuddy);
59 buddy->setButtonText();
60 buddies_[pbuddy->name] = buddy;
62 appendWidget(*buddy);
64 moveToSortedPosition(buddy);
68 void ConversationRoomList::rename_user(
69 const char *old_name, const char *new_name, const char * /*new_alias*/)
71 // The old PurpleConvChatBuddy is still valid while
72 // this function is executing
73 // PurpleConvChatBuddy * old_pbuddy = purple_conv_chat_cb_find(
74 // conv_->u.chat, old_name);
76 PurpleConvChat *conv = PURPLE_CONV_CHAT(conv_);
77 g_assert(conv != nullptr);
79 PurpleConvChatBuddy *new_pbuddy = purple_conv_chat_cb_find(conv, new_name);
80 // g_assert(old_pbuddy != nullptr);
81 g_assert(new_pbuddy != nullptr);
83 // NOTE: PurpleConvChatBuddy::ui_data is pidgin 2.9!!
84 // Buddy * buddy = static_cast<Buddy *>(old_pbuddy->ui_data);
85 Buddy *buddy = buddies_[old_name];
86 g_assert(buddy != nullptr);
88 // Update buddy.
89 buddy->setPurpleBuddy(new_pbuddy);
91 // Update buddy map.
92 buddies_.erase(old_name);
93 buddies_[new_name] = buddy;
95 // Move and then update.
96 moveToSortedPosition(buddy);
97 buddy->setButtonText();
100 void ConversationRoomList::remove_users(GList *users)
102 for (GList *l = users; l != nullptr; l = l->next) {
103 const char *name = static_cast<const char *>(l->data);
105 // NOTE: can't remove purple_conv_chat_cb_find, because the user
106 // and PurpleConvChatBuddy has already been removed
108 Buddies::iterator iter = buddies_.find(name);
110 if (buddies_.end() != iter) {
111 buddies_.erase(iter);
112 // NOTE: this deletes the buddy object.
113 removeWidget(*iter->second);
118 void ConversationRoomList::update_user(const char *user)
120 PurpleConvChat *conv = PURPLE_CONV_CHAT(conv_);
121 g_assert(conv != nullptr);
123 PurpleConvChatBuddy *pbuddy = purple_conv_chat_cb_find(conv, user);
124 g_assert(pbuddy != nullptr);
126 // NOTE: PurpleConvChatBuddy::ui_data is pidgin 2.9!!
127 // Buddy * buddy = static_cast<Buddy *>(pbuddy->ui_data);
128 Buddy *buddy = buddies_[user];
129 g_assert(buddy != nullptr);
131 // Move and then update.
132 moveToSortedPosition(buddy);
133 buddy->setButtonText();
136 ConversationRoomList::Buddy::Buddy(PurpleConvChatBuddy *pbuddy)
137 : CppConsUI::Button(AUTOSIZE, 1, ""), pbuddy_(pbuddy)
139 // Set ui data.
140 // NOTE: PurpleConvChatBuddy::ui_data is pidgin 2.9!!
141 // pbuddy_->ui_data = static_cast<void*>(this);
144 ConversationRoomList::Buddy::~Buddy()
148 void ConversationRoomList::Buddy::readFlags(
149 bool &is_op, bool &is_typing, bool &is_away) const
151 g_assert(pbuddy_ != nullptr);
153 PurpleConvChatBuddyFlags flags = pbuddy_->flags;
155 // TODO: how about founder? Does that matter?
157 is_op = (((flags & PURPLE_CBFLAGS_OP) != 0));
158 is_typing = (((flags & PURPLE_CBFLAGS_TYPING) != 0));
159 #if PURPLE_VERSION_CHECK(2, 8, 0)
160 is_away = (((flags & PURPLE_CBFLAGS_AWAY) != 0));
161 #else
162 is_away = false;
163 #endif
166 void ConversationRoomList::Buddy::setButtonText()
168 char *text = displayText();
169 setText(text);
170 g_free(text);
173 char *ConversationRoomList::Buddy::displayText() const
175 char *ret;
177 bool is_op = false;
178 bool is_typing = false;
179 bool is_away = false;
181 readFlags(is_op, is_typing, is_away);
183 ret = g_strdup_printf("[%s] %s%s%s", (is_away ? "a" : "o"),
184 (is_op ? "@" : ""), displayName(), (is_typing ? "*" : ""));
186 // TODO: elide long names?
188 return ret;
191 const char *ConversationRoomList::Buddy::displayName() const
193 g_assert(pbuddy_ != nullptr);
195 // Prefer alias.
196 // NOTE: pbuddy_->alias_key isn't used yet... (according to docs)
197 if (pbuddy_->alias != nullptr)
198 return pbuddy_->alias;
199 else
200 return pbuddy_->name;
203 bool ConversationRoomList::Buddy::operator==(const Buddy &rhs)
205 return pbuddy_ == rhs.pbuddy_;
208 void ConversationRoomList::Buddy::setPurpleBuddy(PurpleConvChatBuddy *pbuddy)
210 pbuddy_ = pbuddy;
211 // NOTE: PurpleConvChatBuddy::ui_data is pidgin 2.9!!
212 // pbuddy_->ui_data = static_cast<void*>(this);
215 bool ConversationRoomList::Buddy::less_than_op_away_name(
216 const Buddy &lhs, const Buddy &rhs)
218 // Sort order:
220 // 1. ops first
221 // 2. online (vs away)
222 // 3. name/alias
224 bool lhs_is_op, lhs_is_typing, lhs_is_away;
225 bool rhs_is_op, rhs_is_typing, rhs_is_away;
227 lhs.readFlags(lhs_is_op, lhs_is_typing, lhs_is_away);
228 rhs.readFlags(rhs_is_op, rhs_is_typing, rhs_is_away);
230 // Probably a more elegant way to do this.
231 if (lhs_is_op && !rhs_is_op)
232 return true;
233 else if (!lhs_is_op && rhs_is_op)
234 return false;
235 // Equal op or non-op status.
236 else {
237 if (lhs_is_away && !rhs_is_away)
238 return false;
239 else if (!lhs_is_away && rhs_is_away)
240 return true;
241 // On equal online/away status.
242 else
243 return g_utf8_collate(lhs.displayName(), rhs.displayName()) < 0;
247 // vim: set tabstop=2 shiftwidth=2 textwidth=80 expandtab: