| |
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 <gio/gio.h> |
| |
24 |
| |
25 #include "purpleattachments.h" |
| |
26 |
| |
27 struct _PurpleAttachments { |
| |
28 GObject parent; |
| |
29 |
| |
30 GPtrArray *attachments; |
| |
31 }; |
| |
32 |
| |
33 enum { |
| |
34 PROP_0, |
| |
35 PROP_ITEM_TYPE, |
| |
36 PROP_N_ITEMS, |
| |
37 N_PROPERTIES, |
| |
38 }; |
| |
39 static GParamSpec *properties[N_PROPERTIES] = {NULL, }; |
| |
40 |
| |
41 /****************************************************************************** |
| |
42 * Helpers |
| |
43 *****************************************************************************/ |
| |
44 static gboolean |
| |
45 purple_attachments_equal(gconstpointer a, gconstpointer b) { |
| |
46 PurpleAttachment *attachment1 = (gpointer)a; |
| |
47 PurpleAttachment *attachment2 = (gpointer)b; |
| |
48 |
| |
49 return purple_attachment_equal(attachment1, attachment2); |
| |
50 } |
| |
51 |
| |
52 /****************************************************************************** |
| |
53 * GListModel Implementation |
| |
54 *****************************************************************************/ |
| |
55 static GType |
| |
56 purple_attachments_get_item_type(G_GNUC_UNUSED GListModel *model) { |
| |
57 return PURPLE_TYPE_ATTACHMENT; |
| |
58 } |
| |
59 |
| |
60 static guint |
| |
61 purple_attachments_get_n_items(GListModel *model) { |
| |
62 PurpleAttachments *attachments = PURPLE_ATTACHMENTS(model); |
| |
63 |
| |
64 return attachments->attachments->len; |
| |
65 } |
| |
66 |
| |
67 static gpointer |
| |
68 purple_attachments_get_item(GListModel *model, guint position) { |
| |
69 PurpleAttachments *attachments = PURPLE_ATTACHMENTS(model); |
| |
70 PurpleAttachment *attachment = NULL; |
| |
71 |
| |
72 if(position < attachments->attachments->len) { |
| |
73 attachment = g_ptr_array_index(attachments->attachments, position); |
| |
74 |
| |
75 if(PURPLE_IS_ATTACHMENT(attachment)) { |
| |
76 g_object_ref(attachment); |
| |
77 } |
| |
78 } |
| |
79 |
| |
80 return attachment; |
| |
81 } |
| |
82 |
| |
83 static void |
| |
84 purple_attachments_list_model_iface_init(GListModelInterface *iface) { |
| |
85 iface->get_item_type = purple_attachments_get_item_type; |
| |
86 iface->get_n_items = purple_attachments_get_n_items; |
| |
87 iface->get_item = purple_attachments_get_item; |
| |
88 } |
| |
89 |
| |
90 /****************************************************************************** |
| |
91 * GObject Implementation |
| |
92 *****************************************************************************/ |
| |
93 G_DEFINE_FINAL_TYPE_WITH_CODE(PurpleAttachments, |
| |
94 purple_attachments, |
| |
95 G_TYPE_OBJECT, |
| |
96 G_IMPLEMENT_INTERFACE(G_TYPE_LIST_MODEL, |
| |
97 purple_attachments_list_model_iface_init)) |
| |
98 |
| |
99 static void |
| |
100 purple_attachments_finalize(GObject *obj) { |
| |
101 PurpleAttachments *attachments = PURPLE_ATTACHMENTS(obj); |
| |
102 |
| |
103 g_clear_pointer(&attachments->attachments, g_ptr_array_unref); |
| |
104 |
| |
105 G_OBJECT_CLASS(purple_attachments_parent_class)->finalize(obj); |
| |
106 } |
| |
107 |
| |
108 static void |
| |
109 purple_attachments_get_property(GObject *obj, guint param_id, GValue *value, |
| |
110 GParamSpec *pspec) |
| |
111 { |
| |
112 GListModel *model = G_LIST_MODEL(obj); |
| |
113 |
| |
114 switch(param_id) { |
| |
115 case PROP_ITEM_TYPE: |
| |
116 g_value_set_gtype(value, g_list_model_get_item_type(model)); |
| |
117 break; |
| |
118 case PROP_N_ITEMS: |
| |
119 g_value_set_uint(value, g_list_model_get_n_items(model)); |
| |
120 break; |
| |
121 default: |
| |
122 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); |
| |
123 break; |
| |
124 } |
| |
125 } |
| |
126 |
| |
127 static void |
| |
128 purple_attachments_init(PurpleAttachments *attachments) { |
| |
129 attachments->attachments = g_ptr_array_new_full(0, g_object_unref); |
| |
130 } |
| |
131 |
| |
132 static void |
| |
133 purple_attachments_class_init(PurpleAttachmentsClass *klass) { |
| |
134 GObjectClass *obj_class = G_OBJECT_CLASS(klass); |
| |
135 |
| |
136 obj_class->finalize = purple_attachments_finalize; |
| |
137 obj_class->get_property = purple_attachments_get_property; |
| |
138 |
| |
139 /** |
| |
140 * PurpleAttachments:item-type: |
| |
141 * |
| |
142 * The type of items. See [vfunc@Gio.ListModel.get_item_type]. |
| |
143 * |
| |
144 * Since: 3.0 |
| |
145 */ |
| |
146 properties[PROP_ITEM_TYPE] = g_param_spec_gtype( |
| |
147 "item-type", NULL, NULL, |
| |
148 PURPLE_TYPE_ATTACHMENT, |
| |
149 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); |
| |
150 |
| |
151 /** |
| |
152 * PurpleAttachments:n-items: |
| |
153 * |
| |
154 * The number of items. See [vfunc@Gio.ListModel.get_n_items]. |
| |
155 * |
| |
156 * Since: 3.0 |
| |
157 */ |
| |
158 properties[PROP_N_ITEMS] = g_param_spec_uint( |
| |
159 "n-items", NULL, NULL, |
| |
160 0, G_MAXUINT, 0, |
| |
161 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); |
| |
162 |
| |
163 g_object_class_install_properties(obj_class, N_PROPERTIES, properties); |
| |
164 } |
| |
165 |
| |
166 /****************************************************************************** |
| |
167 * Public API |
| |
168 *****************************************************************************/ |
| |
169 gboolean |
| |
170 purple_attachments_add_attachment(PurpleAttachments *attachments, |
| |
171 PurpleAttachment *attachment) |
| |
172 { |
| |
173 GObject *obj = NULL; |
| |
174 gboolean found = FALSE; |
| |
175 guint len = 0; |
| |
176 |
| |
177 g_return_val_if_fail(PURPLE_IS_ATTACHMENTS(attachments), FALSE); |
| |
178 g_return_val_if_fail(PURPLE_IS_ATTACHMENT(attachment), FALSE); |
| |
179 |
| |
180 found = g_ptr_array_find_with_equal_func(attachments->attachments, |
| |
181 attachment, |
| |
182 purple_attachments_equal, |
| |
183 NULL); |
| |
184 |
| |
185 if(found) { |
| |
186 return FALSE; |
| |
187 } |
| |
188 |
| |
189 /* Store length before adding to make the math easier to understand. */ |
| |
190 len = attachments->attachments->len; |
| |
191 |
| |
192 g_ptr_array_add(attachments->attachments, g_object_ref(attachment)); |
| |
193 |
| |
194 obj = G_OBJECT(attachments); |
| |
195 g_object_freeze_notify(obj); |
| |
196 g_list_model_items_changed(G_LIST_MODEL(attachments), len, 0, 1); |
| |
197 g_object_notify_by_pspec(obj, properties[PROP_N_ITEMS]); |
| |
198 g_object_thaw_notify(obj); |
| |
199 |
| |
200 return TRUE; |
| |
201 } |
| |
202 |
| |
203 PurpleAttachment * |
| |
204 purple_attachments_find_with_id(PurpleAttachments *attachments, guint64 id) { |
| |
205 g_return_val_if_fail(PURPLE_IS_ATTACHMENTS(attachments), NULL); |
| |
206 |
| |
207 for(guint i = 0; i < attachments->attachments->len; i++) { |
| |
208 PurpleAttachment *attachment = NULL; |
| |
209 |
| |
210 attachment = g_ptr_array_index(attachments->attachments, i); |
| |
211 |
| |
212 if(purple_attachment_get_id(attachment) == id) { |
| |
213 return attachment; |
| |
214 } |
| |
215 } |
| |
216 |
| |
217 return NULL; |
| |
218 } |
| |
219 |
| |
220 PurpleAttachments * |
| |
221 purple_attachments_new(void) { |
| |
222 return g_object_new(PURPLE_TYPE_ATTACHMENTS, NULL); |
| |
223 } |
| |
224 |
| |
225 gboolean |
| |
226 purple_attachments_remove_attachment(PurpleAttachments *attachments, |
| |
227 PurpleAttachment *attachment) |
| |
228 { |
| |
229 GObject *obj = NULL; |
| |
230 gboolean found = FALSE; |
| |
231 guint index = 0; |
| |
232 |
| |
233 g_return_val_if_fail(PURPLE_IS_ATTACHMENTS(attachments), FALSE); |
| |
234 g_return_val_if_fail(PURPLE_IS_ATTACHMENT(attachment), FALSE); |
| |
235 |
| |
236 found = g_ptr_array_find_with_equal_func(attachments->attachments, |
| |
237 attachment, |
| |
238 purple_attachments_equal, |
| |
239 &index); |
| |
240 if(!found) { |
| |
241 return FALSE; |
| |
242 } |
| |
243 |
| |
244 g_ptr_array_remove_index(attachments->attachments, index); |
| |
245 |
| |
246 obj = G_OBJECT(attachments); |
| |
247 g_object_freeze_notify(obj); |
| |
248 g_list_model_items_changed(G_LIST_MODEL(attachments), index, 1, 0); |
| |
249 g_object_notify_by_pspec(obj, properties[PROP_N_ITEMS]); |
| |
250 g_object_thaw_notify(obj); |
| |
251 |
| |
252 return TRUE; |
| |
253 } |
| |
254 |
| |
255 void |
| |
256 purple_attachments_remove_all(PurpleAttachments *attachments) { |
| |
257 guint removed = 0; |
| |
258 |
| |
259 g_return_if_fail(PURPLE_IS_ATTACHMENTS(attachments)); |
| |
260 |
| |
261 removed = attachments->attachments->len; |
| |
262 g_ptr_array_remove_range(attachments->attachments, 0, removed); |
| |
263 |
| |
264 if(removed > 0) { |
| |
265 GObject *obj = G_OBJECT(attachments); |
| |
266 g_object_freeze_notify(obj); |
| |
267 g_list_model_items_changed(G_LIST_MODEL(attachments), 0, removed, 0); |
| |
268 g_object_notify_by_pspec(obj, properties[PROP_N_ITEMS]); |
| |
269 g_object_thaw_notify(obj); |
| |
270 } |
| |
271 } |