libpurple/purplecommandmanager.c

changeset 43053
f2f944ac775c
child 43057
2c801eae5449
equal deleted inserted replaced
43052:3978d8a6af7f 43053:f2f944ac775c
1 /*
2 * Purple - Internet Messaging Library
3 * Copyright (C) Pidgin Developers <devel@pidgin.im>
4 *
5 * Purple is the legal property of its developers, whose names are too numerous
6 * to list here. Please refer to the COPYRIGHT file distributed with this
7 * source distribution.
8 *
9 * This library is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
12 * any later version.
13 *
14 * This library is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this library; if not, see <https://www.gnu.org/licenses/>.
21 */
22
23 #include "purplecommandmanager.h"
24 #include "purplecommandmanagerprivate.h"
25
26 #include "util.h"
27
28 struct _PurpleCommandManager {
29 GObject parent;
30
31 GPtrArray *commands;
32 };
33
34 static PurpleCommandManager *default_manager = NULL;
35
36 /******************************************************************************
37 * GListModel Implementation
38 *****************************************************************************/
39 static GType
40 purple_command_manager_get_item_type(G_GNUC_UNUSED GListModel *list) {
41 return PURPLE_TYPE_COMMAND;
42 }
43
44 static guint
45 purple_command_manager_get_n_items(GListModel *list) {
46 PurpleCommandManager *manager = PURPLE_COMMAND_MANAGER(list);
47
48 return manager->commands->len;
49 }
50
51 static gpointer
52 purple_command_manager_get_item(GListModel *list, guint position) {
53 PurpleCommandManager *manager = PURPLE_COMMAND_MANAGER(list);
54 PurpleCommand *command = NULL;
55
56 if(position < manager->commands->len) {
57 command = g_ptr_array_index(manager->commands, position);
58 g_object_ref(command);
59 }
60
61 return command;
62 }
63
64 static void
65 purple_command_manager_list_model_init(GListModelInterface *iface) {
66 iface->get_item_type = purple_command_manager_get_item_type;
67 iface->get_n_items = purple_command_manager_get_n_items;
68 iface->get_item = purple_command_manager_get_item;
69 }
70
71 /******************************************************************************
72 * GObject Implementation
73 *****************************************************************************/
74 G_DEFINE_FINAL_TYPE_WITH_CODE(PurpleCommandManager, purple_command_manager,
75 G_TYPE_OBJECT,
76 G_IMPLEMENT_INTERFACE(G_TYPE_LIST_MODEL,
77 purple_command_manager_list_model_init))
78
79 static void
80 purple_command_manager_finalize(GObject *obj) {
81 PurpleCommandManager *manager = PURPLE_COMMAND_MANAGER(obj);
82
83 g_clear_pointer(&manager->commands, g_ptr_array_unref);
84
85 G_OBJECT_CLASS(purple_command_manager_parent_class)->finalize(obj);
86 }
87
88 static void
89 purple_command_manager_init(PurpleCommandManager *manager) {
90 manager->commands = g_ptr_array_new_full(10, g_object_unref);
91 }
92
93 static void
94 purple_command_manager_class_init(PurpleCommandManagerClass *klass) {
95 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
96
97 obj_class->finalize = purple_command_manager_finalize;
98 }
99
100 static gboolean
101 purple_command_manager_commands_equal(gconstpointer a, gconstpointer b) {
102 PurpleCommand *command1 = (gpointer)a;
103 PurpleCommand *command2 = (gpointer)b;
104 const char *name1 = NULL;
105 const char *name2 = NULL;
106
107 name1 = purple_command_get_name(command1);
108 name2 = purple_command_get_name(command2);
109
110 if(purple_strequal(name1, name2)) {
111 const char *source1 = NULL;
112 const char *source2 = NULL;
113
114 source1 = purple_command_get_source(command1);
115 source2 = purple_command_get_source(command2);
116
117 if(purple_strequal(source1, source2)) {
118 return TRUE;
119 }
120 }
121
122 return FALSE;
123 }
124
125 /******************************************************************************
126 * Private API
127 *****************************************************************************/
128 void
129 purple_command_manager_startup(void) {
130 if(default_manager == NULL) {
131 default_manager = purple_command_manager_new();
132 if(PURPLE_IS_COMMAND_MANAGER(default_manager)) {
133 g_object_add_weak_pointer(G_OBJECT(default_manager),
134 (gpointer *)&default_manager);
135 }
136 }
137 }
138
139 void
140 purple_command_manager_shutdown(void) {
141 g_clear_object(&default_manager);
142 }
143
144 /******************************************************************************
145 * Public API
146 *****************************************************************************/
147 void
148 purple_command_manager_add(PurpleCommandManager *manager,
149 PurpleCommand *command)
150 {
151 gboolean found = FALSE;
152
153 g_return_if_fail(PURPLE_IS_COMMAND_MANAGER(manager));
154 g_return_if_fail(PURPLE_IS_COMMAND(command));
155
156 /* If the manager already knows about the command, we do nothing. */
157 found = g_ptr_array_find_with_equal_func(manager->commands, command,
158 purple_command_manager_commands_equal,
159 NULL);
160 if(!found) {
161 g_ptr_array_add(manager->commands, command);
162
163 g_list_model_items_changed(G_LIST_MODEL(manager),
164 manager->commands->len - 1, 0, 1);
165 } else {
166 g_object_unref(command);
167 }
168 }
169
170 PurpleCommand *
171 purple_command_manager_find(PurpleCommandManager *manager,
172 PurpleConversation *conversation,
173 const char *name)
174 {
175 PurpleCommand *command = NULL;
176 PurpleTags *conversation_tags = NULL;
177 int current_priority = 0;
178
179 g_return_val_if_fail(PURPLE_IS_COMMAND_MANAGER(manager), NULL);
180 g_return_val_if_fail(!purple_strempty(name), NULL);
181
182 if(PURPLE_IS_CONVERSATION(conversation)) {
183 conversation_tags = purple_conversation_get_tags(conversation);
184 }
185
186 for(guint i = 0; i < manager->commands->len; i++) {
187 PurpleCommand *candidate = NULL;
188 const char *candidate_name = NULL;
189 int candidate_priority = 0;
190
191 candidate = g_ptr_array_index(manager->commands, i);
192 if(!PURPLE_IS_COMMAND(candidate)) {
193 continue;
194 }
195
196 candidate_name = purple_command_get_name(candidate);
197 if(!purple_strequal(candidate_name, name)) {
198 continue;
199 }
200
201 if(conversation_tags != NULL) {
202 PurpleTags *command_tags = purple_command_get_tags(candidate);
203
204 if(!purple_tags_contains(conversation_tags, command_tags)) {
205 continue;
206 }
207 }
208
209 candidate_priority = purple_command_get_priority(candidate);
210
211 if(command == NULL || candidate_priority > current_priority) {
212 command = candidate;
213 current_priority = candidate_priority;
214 }
215 }
216
217 return command;
218 }
219
220 GListModel *
221 purple_command_manager_find_all(PurpleCommandManager *manager,
222 PurpleConversation *conversation,
223 const char *name)
224 {
225 PurpleTags *conversation_tags = NULL;
226 GListStore *commands = NULL;
227
228 g_return_val_if_fail(PURPLE_IS_COMMAND_MANAGER(manager), NULL);
229 g_return_val_if_fail(!purple_strempty(name), NULL);
230
231 if(PURPLE_IS_CONVERSATION(conversation)) {
232 conversation_tags = purple_conversation_get_tags(conversation);
233 }
234
235 commands = g_list_store_new(PURPLE_TYPE_COMMAND);
236
237 for(guint i = 0; i < manager->commands->len; i++) {
238 PurpleCommand *command = NULL;
239 const char *command_name = NULL;
240
241 command = g_ptr_array_index(manager->commands, i);
242 if(!PURPLE_IS_COMMAND(command)) {
243 continue;
244 }
245
246 command_name = purple_command_get_name(command);
247 if(!purple_strequal(command_name, name)) {
248 continue;
249 }
250
251 if(conversation_tags != NULL) {
252 PurpleTags *command_tags = purple_command_get_tags(command);
253
254 if(!purple_tags_contains(conversation_tags, command_tags)) {
255 continue;
256 }
257 }
258
259 g_list_store_append(commands, command);
260 }
261
262 return G_LIST_MODEL(commands);
263 }
264
265 gboolean
266 purple_command_manager_find_and_execute(PurpleCommandManager *manager,
267 PurpleConversation *conversation,
268 const char *command_line)
269 {
270 PurpleCommand *command = NULL;
271 GStrv params = NULL;
272 char *command_name = NULL;
273 gboolean ret = FALSE;
274
275 g_return_val_if_fail(PURPLE_IS_COMMAND_MANAGER(manager), FALSE);
276 g_return_val_if_fail(PURPLE_IS_CONVERSATION(conversation), FALSE);
277 g_return_val_if_fail(!purple_strempty(command_line), FALSE);
278
279 params = g_strsplit(command_line, " ", -1);
280 command_name = params[0];
281
282 command = purple_command_manager_find(manager, conversation, command_name);
283 if(PURPLE_IS_COMMAND(command)) {
284 purple_command_executev(command, conversation, params + 1);
285
286 ret = TRUE;
287 }
288
289 g_strfreev(params);
290
291 return ret;
292 }
293
294 PurpleCommandManager *
295 purple_command_manager_get_default(void) {
296 return default_manager;
297 }
298
299 GListModel *
300 purple_command_manager_get_default_as_model(void) {
301 return G_LIST_MODEL(default_manager);
302 }
303
304 GListModel *
305 purple_command_manager_get_commands_for_conversation(PurpleCommandManager *manager,
306 PurpleConversation *conversation)
307 {
308 PurpleTags *conversation_tags = NULL;
309 GListStore *commands = NULL;
310
311 g_return_val_if_fail(PURPLE_IS_COMMAND_MANAGER(manager), NULL);
312 g_return_val_if_fail(PURPLE_IS_CONVERSATION(conversation), NULL);
313
314 commands = g_list_store_new(PURPLE_TYPE_COMMAND);
315 conversation_tags = purple_conversation_get_tags(conversation);
316
317 for(guint i = 0; i < manager->commands->len; i++) {
318 PurpleCommand *command = NULL;
319 PurpleTags *command_tags = NULL;
320
321 command = g_ptr_array_index(manager->commands, i);
322 command_tags = purple_command_get_tags(command);
323
324 if(purple_tags_contains(conversation_tags, command_tags)) {
325 g_list_store_append(commands, command);
326 }
327 }
328
329 return G_LIST_MODEL(commands);
330 }
331
332 PurpleCommandManager *
333 purple_command_manager_new(void) {
334 return g_object_new(PURPLE_TYPE_COMMAND_MANAGER, NULL);
335 }
336
337 gboolean
338 purple_command_manager_remove(PurpleCommandManager *manager, const char *name,
339 const char *source)
340 {
341 g_return_val_if_fail(PURPLE_IS_COMMAND_MANAGER(manager), FALSE);
342
343 for(guint i = 0; i < manager->commands->len; i++) {
344 PurpleCommand *command = NULL;
345 const char *command_name = NULL;
346 const char *command_source = NULL;
347
348 command = g_ptr_array_index(manager->commands, i);
349 if(!PURPLE_IS_COMMAND(command)) {
350 continue;
351 }
352
353 command_name = purple_command_get_name(command);
354 command_source = purple_command_get_source(command);
355 if(purple_strequal(command_name, name) &&
356 purple_strequal(command_source, source))
357 {
358 g_ptr_array_remove_index(manager->commands, i);
359
360 g_list_model_items_changed(G_LIST_MODEL(manager), i, 1, 0);
361
362 return TRUE;
363 }
364 }
365
366 return FALSE;
367 }
368
369 void
370 purple_command_manager_remove_all_with_source(PurpleCommandManager *manager,
371 const char *source)
372 {
373 g_return_if_fail(PURPLE_IS_COMMAND_MANAGER(manager));
374 g_return_if_fail(!purple_strempty(source));
375
376 /* Since GPtrArray shifts everything down on a remove, we only increment
377 * when we haven't removed a command.
378 */
379 for(guint i = 0; i < manager->commands->len;) {
380 PurpleCommand *command = NULL;
381 const char *command_source = NULL;
382
383 command = g_ptr_array_index(manager->commands, i);
384 if(!PURPLE_IS_COMMAND(command)) {
385 continue;
386 }
387
388 command_source = purple_command_get_source(command);
389 if(purple_strequal(command_source, source)) {
390 g_ptr_array_remove_index(manager->commands, i);
391
392 /* TODO: optimize this so we notify when a group of items is
393 * removed instead of notifying for every remove.
394 */
395 g_list_model_items_changed(G_LIST_MODEL(manager), i, 1, 0);
396 } else {
397 i++;
398 }
399 }
400 }

mercurial