1 /*
2 	category.c
3 
4 
5 
6 	2003  Plus Huang
7  */
8 
9 #include <stdlib.h>
10 #include "category.h"
11 #include "category_store.h"
12 #include "download_thread.h"
13 
category_new()14 Category* category_new ()
15 {
16 	Category* cate = g_malloc (sizeof (Category));
17 
18 	// initial base class category_setting
19 	category_setting_init (&cate->setting);
20 
21 	g_static_rec_mutex_init (&cate->mutex);
22 
23 	download_store_init (&cate->waiting_store);
24 	download_store_init (&cate->completed_store);
25 	download_store_init (&cate->recycled_store);
26 
27 	download_store_set_historical (&cate->completed_store, TRUE);
28 	download_store_set_historical (&cate->recycled_store, TRUE);
29 
30 	download_list_view_init (&cate->waiting_view, &cate->waiting_store);
31 	download_list_view_init (&cate->completed_view, &cate->completed_store);
32 	download_list_view_init (&cate->recycled_view, &cate->recycled_store);
33 	download_list_view_hide_runtime_state (&cate->completed_view);
34 	download_list_view_hide_runtime_state (&cate->recycled_view);
35 
36 	cate->valid = FALSE;
37 	cate->reference_count = 1;
38 	cate->thread_list     = NULL;
39 	cate->n_thread        = 0;
40 
41 	category_apply_setting (cate);
42 
43 	return cate;
44 }
45 
category_new_from_setting(CategorySetting * cd)46 Category* category_new_from_setting (CategorySetting* cd)
47 {
48 	Category* cate = category_new ();
49 
50 	category_setting_assign (&cate->setting, cd);
51 	category_apply_setting (cate);
52 
53 	return cate;
54 }
55 
category_ref(Category * ca)56 void category_ref (Category* ca)
57 {
58 	category_lock (ca);
59 	ca->reference_count++;
60 	category_unlock (ca);
61 }
62 
category_unref(Category * ca)63 void category_unref (Category* ca)
64 {
65 	int  count;
66 
67 	category_lock (ca);
68 	count = --ca->reference_count;
69 	category_unlock (ca);
70 
71 	if (count > 0)
72 		return;
73 
74 	g_static_rec_mutex_free (&ca->mutex);
75 
76 	category_setting_clear (&ca->setting);
77 
78 	download_list_view_clear (&ca->waiting_view);
79 	download_list_view_clear (&ca->completed_view);
80 	download_list_view_clear (&ca->recycled_view);
81 
82 	download_store_clear (&ca->waiting_store);
83 	download_store_clear (&ca->completed_store);
84 	download_store_clear (&ca->recycled_store);
85 
86 	g_free (ca);
87 }
88 
category_apply_setting(Category * ca)89 void category_apply_setting (Category* ca)
90 {
91 	CategorySetting*  setting = CATEGORY_SETTING (ca);
92 	DownloadListView* dlv = &ca->waiting_view;
93 
94 	gtk_tree_view_column_set_visible (dlv->col_completed,
95 	                                  setting->col_completed);
96 	gtk_tree_view_column_set_visible (dlv->col_total,
97 	                                  setting->col_total);
98 	gtk_tree_view_column_set_visible (dlv->col_speed,
99 	                                  setting->col_speed);
100 	gtk_tree_view_column_set_visible (dlv->col_retry,
101 	                                  setting->col_retry);
102 	gtk_tree_view_column_set_visible (dlv->col_url,
103 	                                  setting->col_url);
104 
105 	gtk_tree_view_column_set_visible (ca->completed_view.col_url,
106 	                                  setting->col_url);
107 	gtk_tree_view_column_set_visible (ca->recycled_view.col_url,
108 	                                  setting->col_url);
109 
110 	ca->completed_store.capacity_limit = setting->completed_capacity;
111 	ca->recycled_store.capacity_limit = setting->recycled_capacity;
112 }
113 
category_changed_with_children(Category * ca,gint flag_child)114 void category_changed_with_children (Category* ca, gint flag_child)
115 {
116 	GtkTreePath* path;
117 	GtkTreeIter  iter;
118 	CategoryStore* category_store = (CategoryStore*)ca->category_store;
119 
120 	if (ca->valid==FALSE)
121 		return;
122 
123 	// list store
124 	path = gtk_tree_model_get_path ((GtkTreeModel*)category_store->list_store,
125 	                                &ca->iter_list_store);
126 	gtk_tree_model_row_changed ((GtkTreeModel*)category_store->list_store,
127 	                            path, &ca->iter_list_store);
128 	gtk_tree_path_free (path);
129 
130 	// tree store
131 	path = gtk_tree_model_get_path ((GtkTreeModel*)category_store->tree_store,
132 	                                &ca->iter_tree_store);
133 	gtk_tree_model_row_changed ((GtkTreeModel*)category_store->tree_store,
134 	                            path, &ca->iter_tree_store);
135 	gtk_tree_path_free (path);
136 
137 	if (flag_child) {
138 		gtk_tree_model_iter_children ((GtkTreeModel*)category_store->tree_store,
139 		                              &iter, &ca->iter_tree_store);
140 		if (flag_child & CATEGORY_COMPLETED) {
141 			path = gtk_tree_model_get_path ((GtkTreeModel*)category_store->tree_store,
142 			                                &iter);
143 			gtk_tree_model_row_changed ((GtkTreeModel*)category_store->tree_store,
144 			                            path, &iter);
145 			gtk_tree_path_free (path);
146 		}
147 		if (flag_child & CATEGORY_RECYCLED) {
148 			gtk_tree_model_iter_next ((GtkTreeModel*)category_store->tree_store,
149 			                          &iter);
150 			path = gtk_tree_model_get_path ((GtkTreeModel*)category_store->tree_store,
151 			                                &iter);
152 			gtk_tree_model_row_changed ((GtkTreeModel*)category_store->tree_store,
153 			                            path, &iter);
154 			gtk_tree_path_free (path);
155 		}
156 	}
157 }
158 
category_thread_count_request(Category * ca)159 gint category_thread_count_request (Category* ca)
160 {
161 	return CATEGORY_SETTING(ca)->n_active_download - ca->n_thread;
162 }
163 
category_thread_destroy(Category * ca)164 void category_thread_destroy (Category* ca)
165 {
166 	DownloadThread* dt;
167 
168 	category_lock (ca);
169 
170 	for (dt=ca->thread_list; dt; dt=dt->next)
171 		download_thread_destroy (dt);
172 
173 	category_unlock (ca);
174 }
175 
category_thread_activate(Category * ca)176 gboolean category_thread_activate (Category* ca)
177 {
178 	GtkTreeIter     iter;
179 	DownloadThread* thread;
180 	gboolean        found;
181 	gboolean        activated = FALSE;
182 
183 	do {
184 		if (category_thread_count_request (ca) <= 0 )
185 			break;
186 
187 		download_store_lock (&ca->waiting_store);
188 
189 		if (found=download_store_find_waiting (&ca->waiting_store, &iter)) {
190 			thread = download_thread_new (ca, &iter);
191 			download_store_unlock (&ca->waiting_store);
192 			download_thread_activate (thread);
193 		}
194 		else
195 			download_store_unlock (&ca->waiting_store);
196 		activated = TRUE;
197 	} while (found);
198 
199 	return activated;
200 }
201 
category_thread_stop(Category * ca)202 void category_thread_stop (Category* ca)
203 {
204 	DownloadThread* dt;
205 
206 	category_lock (ca);
207 
208 	for (dt=ca->thread_list; dt; dt=dt->next)
209 		download_thread_stop (dt);
210 
211 	category_unlock (ca);
212 }
213 
category_thread_remove(Category * category,gpointer th)214 void category_thread_remove (Category* category,
215                              gpointer  th)
216 {
217 	DownloadThread* thread = th;
218 	gboolean        activated = TRUE;
219 
220 	category_lock (category);
221 
222 	if (category->thread_list == thread) {
223 		category->thread_list = thread->next;
224 	}
225 	if (thread->next)
226 		thread->next->prev = thread->prev;
227 	if (thread->prev)
228 		thread->prev->next = thread->next;
229 
230 	category->n_thread--;
231 	if (category->n_thread==0) {
232 		CATEGORY_SETTING (category)->state = CATEGORY_STATE_WAITING;
233 		category_changed (category);
234 		activated = FALSE;
235 	}
236 
237 	category_unlock (category);
238 
239 	// avoid dead lock
240 	if (activated == FALSE) {
241 		category_store_thread_unref ((CategoryStore*)category->category_store);
242 		category_store_thread_activate_next ((CategoryStore*)category->category_store,
243 		                                     category);
244 	}
245 }
246 
category_thread_add(Category * category,gpointer thread)247 void category_thread_add (Category* category,
248                           gpointer  thread)
249 {
250 	gboolean activated = FALSE;
251 
252 	category_lock (category);
253 
254 	if (category->n_thread==0) {
255 		CATEGORY_SETTING (category)->state = CATEGORY_STATE_EXECUTING;
256 		category_changed (category);
257 		activated = TRUE;
258 	}
259 	category->n_thread++;
260 
261 	if (category->thread_list) {
262 		((DownloadThread*)category->thread_list)->prev = thread;
263 		((DownloadThread*)thread)->next = category->thread_list;
264 	}
265 	category->thread_list = thread;
266 
267 	category_unlock (category);
268 
269 	// avoid dead lock
270 	if (activated)
271 		category_store_thread_ref ((CategoryStore*)category->category_store);
272 }
273 
274