Changeset 13731
- Timestamp:
- Jan 1, 2013, 6:43:41 PM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/gtk/filter.c
r13722 r13731 38 38 enum 39 39 { 40 41 42 43 44 45 46 47 48 49 40 CAT_FILTER_TYPE_ALL, 41 CAT_FILTER_TYPE_PRIVATE, 42 CAT_FILTER_TYPE_PUBLIC, 43 CAT_FILTER_TYPE_HOST, 44 CAT_FILTER_TYPE_PARENT, 45 CAT_FILTER_TYPE_PRI_HIGH, 46 CAT_FILTER_TYPE_PRI_NORMAL, 47 CAT_FILTER_TYPE_PRI_LOW, 48 CAT_FILTER_TYPE_TAG, 49 CAT_FILTER_TYPE_SEPARATOR, 50 50 }; 51 51 52 52 enum 53 53 { 54 55 56 57 58 59 54 CAT_FILTER_COL_NAME, /* human-readable name; ie, Legaltorrents */ 55 CAT_FILTER_COL_COUNT, /* how many matches there are */ 56 CAT_FILTER_COL_TYPE, 57 CAT_FILTER_COL_HOST, /* pattern-matching text; ie, legaltorrents.com */ 58 CAT_FILTER_COL_PIXBUF, 59 CAT_FILTER_N_COLS 60 60 }; 61 61 … … 63 63 pstrcmp (const void * a, const void * b) 64 64 { 65 65 return strcmp (* (const char**)a, * (const char**)b); 66 66 } 67 67 … … 70 70 get_name_from_host (const char * host) 71 71 { 72 73 74 75 76 77 78 79 80 81 82 83 84 72 char * name; 73 const char * dot = strrchr (host, '.'); 74 75 if (tr_addressIsIP (host)) 76 name = g_strdup (host); 77 else if (dot) 78 name = g_strndup (host, dot - host); 79 else 80 name = g_strdup (host); 81 82 *name = g_ascii_toupper (*name); 83 84 return name; 85 85 } 86 86 … … 88 88 category_model_update_count (GtkTreeStore * store, GtkTreeIter * iter, int n) 89 89 { 90 91 92 93 94 90 int count; 91 GtkTreeModel * model = GTK_TREE_MODEL (store); 92 gtk_tree_model_get (model, iter, CAT_FILTER_COL_COUNT, &count, -1); 93 if (n != count) 94 gtk_tree_store_set (store, iter, CAT_FILTER_COL_COUNT, n, -1); 95 95 } 96 96 … … 98 98 favicon_ready_cb (gpointer pixbuf, gpointer vreference) 99 99 { 100 101 102 103 104 { 105 106 107 108 109 110 111 112 113 114 115 116 } 117 118 100 GtkTreeIter iter; 101 GtkTreeRowReference * reference = vreference; 102 103 if (pixbuf != NULL) 104 { 105 GtkTreePath * path = gtk_tree_row_reference_get_path (reference); 106 GtkTreeModel * model = gtk_tree_row_reference_get_model (reference); 107 108 if (gtk_tree_model_get_iter (model, &iter, path)) 109 gtk_tree_store_set (GTK_TREE_STORE (model), &iter, 110 CAT_FILTER_COL_PIXBUF, pixbuf, 111 -1); 112 113 gtk_tree_path_free (path); 114 115 g_object_unref (pixbuf); 116 } 117 118 gtk_tree_row_reference_free (reference); 119 119 } 120 120 … … 122 122 category_filter_model_update (GtkTreeStore * store) 123 123 { 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 { 148 149 150 151 152 153 154 155 156 157 158 159 { 160 161 162 163 164 165 166 167 168 169 124 int i, n; 125 int low = 0; 126 int all = 0; 127 int high = 0; 128 int public = 0; 129 int normal = 0; 130 int private = 0; 131 int store_pos; 132 GtkTreeIter top; 133 GtkTreeIter iter; 134 GtkTreeModel * model = GTK_TREE_MODEL (store); 135 GPtrArray * hosts = g_ptr_array_new (); 136 GStringChunk * strings = g_string_chunk_new (4096); 137 GHashTable * hosts_hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); 138 GObject * o = G_OBJECT (store); 139 GtkTreeModel * tmodel = GTK_TREE_MODEL (g_object_get_qdata (o, TORRENT_MODEL_KEY)); 140 141 g_object_steal_qdata (o, DIRTY_KEY); 142 143 /* Walk through all the torrents, tallying how many matches there are 144 * for the various categories. Also make a sorted list of all tracker 145 * hosts s.t. we can merge it with the existing list */ 146 if (gtk_tree_model_iter_nth_child (tmodel, &iter, NULL, 0)) do 147 { 148 tr_torrent * tor; 149 const tr_info * inf; 150 int keyCount; 151 char ** keys; 152 153 gtk_tree_model_get (tmodel, &iter, MC_TORRENT, &tor, -1); 154 inf = tr_torrentInfo (tor); 155 keyCount = 0; 156 keys = g_new (char*, inf->trackerCount); 157 158 for (i=0, n=inf->trackerCount; i<n; ++i) 159 { 160 int k; 161 int * count; 162 char buf[1024]; 163 char * key; 164 165 gtr_get_host_from_url (buf, sizeof (buf), inf->trackers[i].announce); 166 key = g_string_chunk_insert_const (strings, buf); 167 168 count = g_hash_table_lookup (hosts_hash, key); 169 if (count == NULL) 170 170 { 171 172 173 171 count = tr_new0 (int, 1); 172 g_hash_table_insert (hosts_hash, key, count); 173 g_ptr_array_add (hosts, key); 174 174 } 175 175 176 for (k=0; k<keyCount; ++k) 177 if (!strcmp (keys[k], key)) 178 break; 179 if (k==keyCount) 180 keys[keyCount++] = key; 181 } 182 183 for (i=0; i<keyCount; ++i) 184 { 185 int * incrementme = g_hash_table_lookup (hosts_hash, keys[i]); 186 ++*incrementme; 187 } 188 g_free (keys); 189 190 ++all; 191 192 if (inf->isPrivate) 193 ++private; 194 else 195 ++public; 196 197 switch (tr_torrentGetPriority (tor)) 198 { 199 case TR_PRI_HIGH: ++high; break; 200 case TR_PRI_LOW: ++low; break; 201 default: ++normal; break; 202 } 203 } 204 while (gtk_tree_model_iter_next (tmodel, &iter)); 205 qsort (hosts->pdata, hosts->len, sizeof (char*), pstrcmp); 206 207 /* update the "all" count */ 208 gtk_tree_model_iter_children (model, &top, NULL); 209 category_model_update_count (store, &top, all); 210 211 /* skip separator */ 212 gtk_tree_model_iter_next (model, &top); 213 214 /* update the "hosts" subtree */ 215 gtk_tree_model_iter_next (model, &top); 216 for (i=store_pos=0, n=hosts->len ; ;) 217 { 218 const gboolean new_hosts_done = i >= n; 219 const gboolean old_hosts_done = !gtk_tree_model_iter_nth_child (model, &iter, &top, store_pos); 220 gboolean remove_row = FALSE; 221 gboolean insert_row = FALSE; 222 223 /* are we done yet? */ 224 if (new_hosts_done && old_hosts_done) 225 break; 226 227 /* decide what to do */ 228 if (new_hosts_done) 176 for (k=0; k<keyCount; ++k) 177 if (!strcmp (keys[k], key)) 178 break; 179 180 if (k==keyCount) 181 keys[keyCount++] = key; 182 } 183 184 for (i=0; i<keyCount; ++i) 185 { 186 int * incrementme = g_hash_table_lookup (hosts_hash, keys[i]); 187 ++*incrementme; 188 } 189 190 g_free (keys); 191 192 ++all; 193 194 if (inf->isPrivate) 195 ++private; 196 else 197 ++public; 198 199 switch (tr_torrentGetPriority (tor)) 200 { 201 case TR_PRI_HIGH: ++high; break; 202 case TR_PRI_LOW: ++low; break; 203 default: ++normal; break; 204 } 205 } 206 while (gtk_tree_model_iter_next (tmodel, &iter)); 207 208 qsort (hosts->pdata, hosts->len, sizeof (char*), pstrcmp); 209 210 /* update the "all" count */ 211 gtk_tree_model_iter_children (model, &top, NULL); 212 category_model_update_count (store, &top, all); 213 214 /* skip separator */ 215 gtk_tree_model_iter_next (model, &top); 216 217 /* update the "hosts" subtree */ 218 gtk_tree_model_iter_next (model, &top); 219 for (i=store_pos=0, n=hosts->len ; ;) 220 { 221 const gboolean new_hosts_done = i >= n; 222 const gboolean old_hosts_done = !gtk_tree_model_iter_nth_child (model, &iter, &top, store_pos); 223 gboolean remove_row = FALSE; 224 gboolean insert_row = FALSE; 225 226 /* are we done yet? */ 227 if (new_hosts_done && old_hosts_done) 228 break; 229 230 /* decide what to do */ 231 if (new_hosts_done) 232 { 233 remove_row = TRUE; 234 } 235 else if (old_hosts_done) 236 { 237 insert_row = TRUE; 238 } 239 else 240 { 241 int cmp; 242 char * host; 243 gtk_tree_model_get (model, &iter, CAT_FILTER_COL_HOST, &host, -1); 244 cmp = strcmp (host, hosts->pdata[i]); 245 246 if (cmp < 0) 229 247 remove_row = TRUE; 230 else if (old_hosts_done)248 else if (cmp > 0) 231 249 insert_row = TRUE; 232 else { 233 int cmp; 234 char * host; 235 gtk_tree_model_get (model, &iter, CAT_FILTER_COL_HOST, &host, -1); 236 cmp = strcmp (host, hosts->pdata[i]); 237 if (cmp < 0) 238 remove_row = TRUE; 239 else if (cmp > 0) 240 insert_row = TRUE; 241 g_free (host); 242 } 243 244 /* do something */ 245 if (remove_row) { 246 /* g_message ("removing row and incrementing i"); */ 247 gtk_tree_store_remove (store, &iter); 248 } else if (insert_row) { 249 GtkTreeIter add; 250 GtkTreePath * path; 251 GtkTreeRowReference * reference; 252 tr_session * session = g_object_get_qdata (G_OBJECT (store), SESSION_KEY); 253 const char * host = hosts->pdata[i]; 254 char * name = get_name_from_host (host); 255 const int count = * (int*)g_hash_table_lookup (hosts_hash, host); 256 gtk_tree_store_insert_with_values (store, &add, &top, store_pos, 257 CAT_FILTER_COL_HOST, host, 258 CAT_FILTER_COL_NAME, name, 259 CAT_FILTER_COL_COUNT, count, 260 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_HOST, 261 -1); 262 path = gtk_tree_model_get_path (model, &add); 263 reference = gtk_tree_row_reference_new (model, path); 264 gtr_get_favicon (session, host, favicon_ready_cb, reference); 265 gtk_tree_path_free (path); 266 g_free (name); 267 ++store_pos; 268 ++i; 269 } else { /* update row */ 270 const char * host = hosts->pdata[i]; 271 const int count = * (int*)g_hash_table_lookup (hosts_hash, host); 272 category_model_update_count (store, &iter, count); 273 ++store_pos; 274 ++i; 275 } 276 } 277 278 /* update the "public" subtree */ 279 gtk_tree_model_iter_next (model, &top); 280 gtk_tree_model_iter_children (model, &iter, &top); 281 category_model_update_count (store, &iter, public); 282 gtk_tree_model_iter_next (model, &iter); 283 category_model_update_count (store, &iter, private); 284 285 /* update the "priority" subtree */ 286 gtk_tree_model_iter_next (model, &top); 287 gtk_tree_model_iter_children (model, &iter, &top); 288 category_model_update_count (store, &iter, high); 289 gtk_tree_model_iter_next (model, &iter); 290 category_model_update_count (store, &iter, normal); 291 gtk_tree_model_iter_next (model, &iter); 292 category_model_update_count (store, &iter, low); 293 294 /* cleanup */ 295 g_ptr_array_free (hosts, TRUE); 296 g_hash_table_unref (hosts_hash); 297 g_string_chunk_free (strings); 298 return FALSE; 250 251 g_free (host); 252 } 253 254 /* do something */ 255 if (remove_row) 256 { 257 /* g_message ("removing row and incrementing i"); */ 258 gtk_tree_store_remove (store, &iter); 259 } 260 else if (insert_row) 261 { 262 GtkTreeIter add; 263 GtkTreePath * path; 264 GtkTreeRowReference * reference; 265 tr_session * session = g_object_get_qdata (G_OBJECT (store), SESSION_KEY); 266 const char * host = hosts->pdata[i]; 267 char * name = get_name_from_host (host); 268 const int count = * (int*)g_hash_table_lookup (hosts_hash, host); 269 gtk_tree_store_insert_with_values (store, &add, &top, store_pos, 270 CAT_FILTER_COL_HOST, host, 271 CAT_FILTER_COL_NAME, name, 272 CAT_FILTER_COL_COUNT, count, 273 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_HOST, 274 -1); 275 path = gtk_tree_model_get_path (model, &add); 276 reference = gtk_tree_row_reference_new (model, path); 277 gtr_get_favicon (session, host, favicon_ready_cb, reference); 278 gtk_tree_path_free (path); 279 g_free (name); 280 ++store_pos; 281 ++i; 282 } 283 else /* update row */ 284 { 285 const char * host = hosts->pdata[i]; 286 const int count = * (int*)g_hash_table_lookup (hosts_hash, host); 287 category_model_update_count (store, &iter, count); 288 ++store_pos; 289 ++i; 290 } 291 } 292 293 /* update the "public" subtree */ 294 gtk_tree_model_iter_next (model, &top); 295 gtk_tree_model_iter_children (model, &iter, &top); 296 category_model_update_count (store, &iter, public); 297 gtk_tree_model_iter_next (model, &iter); 298 category_model_update_count (store, &iter, private); 299 300 /* update the "priority" subtree */ 301 gtk_tree_model_iter_next (model, &top); 302 gtk_tree_model_iter_children (model, &iter, &top); 303 category_model_update_count (store, &iter, high); 304 gtk_tree_model_iter_next (model, &iter); 305 category_model_update_count (store, &iter, normal); 306 gtk_tree_model_iter_next (model, &iter); 307 category_model_update_count (store, &iter, low); 308 309 /* cleanup */ 310 g_ptr_array_free (hosts, TRUE); 311 g_hash_table_unref (hosts_hash); 312 g_string_chunk_free (strings); 313 return FALSE; 299 314 } 300 315 … … 302 317 category_filter_model_new (GtkTreeModel * tmodel) 303 318 { 304 305 306 307 308 309 310 311 312 313 314 CAT_FILTER_COL_NAME, _("All"),315 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_ALL,316 -1);317 318 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_SEPARATOR,319 -1);320 321 322 CAT_FILTER_COL_NAME, _("Trackers"),323 CAT_FILTER_COL_COUNT, invisible_number,324 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_PARENT,325 -1);326 327 328 CAT_FILTER_COL_NAME, _("Privacy"),329 CAT_FILTER_COL_COUNT, invisible_number,330 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_PARENT,331 -1);332 333 CAT_FILTER_COL_NAME, _("Public"),334 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_PUBLIC,335 -1);336 337 CAT_FILTER_COL_NAME, _("Private"),338 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_PRIVATE,339 -1);340 341 342 CAT_FILTER_COL_NAME, _("Priority"),343 CAT_FILTER_COL_COUNT, invisible_number,344 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_PARENT,345 -1);346 347 CAT_FILTER_COL_NAME, _("High"),348 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_PRI_HIGH,349 -1);350 351 CAT_FILTER_COL_NAME, _("Normal"),352 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_PRI_NORMAL,353 -1);354 355 CAT_FILTER_COL_NAME, _("Low"),356 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_PRI_LOW,357 -1);358 359 360 361 319 GtkTreeIter iter; 320 const int invisible_number = -1; /* doesn't get rendered */ 321 GtkTreeStore * store = gtk_tree_store_new (CAT_FILTER_N_COLS, 322 G_TYPE_STRING, 323 G_TYPE_INT, 324 G_TYPE_INT, 325 G_TYPE_STRING, 326 GDK_TYPE_PIXBUF); 327 328 gtk_tree_store_insert_with_values (store, NULL, NULL, -1, 329 CAT_FILTER_COL_NAME, _("All"), 330 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_ALL, 331 -1); 332 gtk_tree_store_insert_with_values (store, NULL, NULL, -1, 333 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_SEPARATOR, 334 -1); 335 336 gtk_tree_store_insert_with_values (store, &iter, NULL, -1, 337 CAT_FILTER_COL_NAME, _("Trackers"), 338 CAT_FILTER_COL_COUNT, invisible_number, 339 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_PARENT, 340 -1); 341 342 gtk_tree_store_insert_with_values (store, &iter, NULL, -1, 343 CAT_FILTER_COL_NAME, _("Privacy"), 344 CAT_FILTER_COL_COUNT, invisible_number, 345 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_PARENT, 346 -1); 347 gtk_tree_store_insert_with_values (store, NULL, &iter, -1, 348 CAT_FILTER_COL_NAME, _("Public"), 349 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_PUBLIC, 350 -1); 351 gtk_tree_store_insert_with_values (store, NULL, &iter, -1, 352 CAT_FILTER_COL_NAME, _("Private"), 353 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_PRIVATE, 354 -1); 355 356 gtk_tree_store_insert_with_values (store, &iter, NULL, -1, 357 CAT_FILTER_COL_NAME, _("Priority"), 358 CAT_FILTER_COL_COUNT, invisible_number, 359 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_PARENT, 360 -1); 361 gtk_tree_store_insert_with_values (store, NULL, &iter, -1, 362 CAT_FILTER_COL_NAME, _("High"), 363 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_PRI_HIGH, 364 -1); 365 gtk_tree_store_insert_with_values (store, NULL, &iter, -1, 366 CAT_FILTER_COL_NAME, _("Normal"), 367 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_PRI_NORMAL, 368 -1); 369 gtk_tree_store_insert_with_values (store, NULL, &iter, -1, 370 CAT_FILTER_COL_NAME, _("Low"), 371 CAT_FILTER_COL_TYPE, CAT_FILTER_TYPE_PRI_LOW, 372 -1); 373 374 g_object_set_qdata (G_OBJECT (store), TORRENT_MODEL_KEY, tmodel); 375 category_filter_model_update (store); 376 return GTK_TREE_MODEL (store); 362 377 } 363 378 … … 365 380 is_it_a_separator (GtkTreeModel * m, GtkTreeIter * iter, gpointer data UNUSED) 366 381 { 367 368 369 382 int type; 383 gtk_tree_model_get (m, iter, CAT_FILTER_COL_TYPE, &type, -1); 384 return type == CAT_FILTER_TYPE_SEPARATOR; 370 385 } 371 386 … … 373 388 category_model_update_idle (gpointer category_model) 374 389 { 375 376 377 378 { 379 380 381 390 GObject * o = G_OBJECT (category_model); 391 const gboolean pending = g_object_get_qdata (o, DIRTY_KEY) != NULL; 392 if (!pending) 393 { 394 GSourceFunc func = (GSourceFunc) category_filter_model_update; 395 g_object_set_qdata (o, DIRTY_KEY, GINT_TO_POINTER (1)); 396 gdk_threads_add_idle (func, category_model); 382 397 } 383 398 } … … 389 404 gpointer category_model) 390 405 { 391 406 category_model_update_idle (category_model); 392 407 } 393 408 … … 397 412 gpointer category_model) 398 413 { 399 414 category_model_update_idle (category_model); 400 415 } 401 416 … … 407 422 gpointer data UNUSED) 408 423 { 409 410 411 412 413 414 415 416 417 418 419 424 int type; 425 int width = 0; 426 const gboolean leaf = !gtk_tree_model_iter_has_child (tree_model, iter); 427 428 gtk_tree_model_get (tree_model, iter, CAT_FILTER_COL_TYPE, &type, -1); 429 if (type == CAT_FILTER_TYPE_HOST) 430 width = 20; 431 432 g_object_set (cell_renderer, "width", width, 433 "sensitive", leaf, 434 NULL); 420 435 } 421 436 … … 427 442 gpointer data UNUSED) 428 443 { 429 430 431 432 444 const gboolean leaf = !gtk_tree_model_iter_has_child (tree_model, iter); 445 446 g_object_set (cell_renderer, "sensitive", leaf, 447 NULL); 433 448 } 434 449 … … 440 455 gpointer data UNUSED) 441 456 { 442 443 444 445 446 447 448 449 450 451 452 453 454 455 457 int count; 458 char buf[32]; 459 const gboolean leaf = !gtk_tree_model_iter_has_child (tree_model, iter); 460 461 gtk_tree_model_get (tree_model, iter, CAT_FILTER_COL_COUNT, &count, -1); 462 463 if (count >= 0) 464 g_snprintf (buf, sizeof (buf), "%'d", count); 465 else 466 *buf = '\0'; 467 468 g_object_set (cell_renderer, "text", buf, 469 "sensitive", leaf, 470 NULL); 456 471 } 457 472 … … 459 474 number_renderer_new (void) 460 475 { 461 462 463 464 465 466 467 468 469 476 GtkCellRenderer * r = gtk_cell_renderer_text_new (); 477 478 g_object_set (G_OBJECT (r), "alignment", PANGO_ALIGN_RIGHT, 479 "weight", PANGO_WEIGHT_ULTRALIGHT, 480 "xalign", 1.0, 481 "xpad", GUI_PAD, 482 NULL); 483 484 return r; 470 485 } 471 486 … … 473 488 disconnect_cat_model_callbacks (gpointer tmodel, GObject * cat_model) 474 489 { 475 476 490 g_signal_handlers_disconnect_by_func (tmodel, torrent_model_row_changed, cat_model); 491 g_signal_handlers_disconnect_by_func (tmodel, torrent_model_row_deleted_cb, cat_model); 477 492 } 478 493 … … 480 495 category_combo_box_new (GtkTreeModel * tmodel) 481 496 { 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 497 GtkWidget * c; 498 GtkCellRenderer * r; 499 GtkTreeModel * cat_model; 500 GtkCellLayout * c_cell_layout; 501 GtkComboBox * c_combo_box; 502 503 /* create the category combobox */ 504 cat_model = category_filter_model_new (tmodel); 505 c = gtk_combo_box_new_with_model (cat_model); 506 c_combo_box = GTK_COMBO_BOX (c); 507 c_cell_layout = GTK_CELL_LAYOUT (c); 508 g_object_unref (cat_model); 509 gtk_combo_box_set_row_separator_func (c_combo_box, 510 is_it_a_separator, NULL, NULL); 511 gtk_combo_box_set_active (c_combo_box, 0); 512 513 r = gtk_cell_renderer_pixbuf_new (); 514 gtk_cell_layout_pack_start (c_cell_layout, r, FALSE); 515 gtk_cell_layout_set_cell_data_func (c_cell_layout, r, 516 render_pixbuf_func, NULL, NULL); 517 gtk_cell_layout_set_attributes (c_cell_layout, r, 518 "pixbuf", CAT_FILTER_COL_PIXBUF, 519 NULL); 520 521 r = gtk_cell_renderer_text_new (); 522 gtk_cell_layout_pack_start (c_cell_layout, r, FALSE); 523 gtk_cell_layout_set_attributes (c_cell_layout, r, 524 "text", CAT_FILTER_COL_NAME, 525 NULL); 526 gtk_cell_layout_set_cell_data_func (c_cell_layout, r, 527 is_capital_sensitive, 528 NULL, NULL); 529 530 531 r = number_renderer_new (); 532 gtk_cell_layout_pack_end (c_cell_layout, r, TRUE); 533 gtk_cell_layout_set_cell_data_func (c_cell_layout, r, 534 render_number_func, NULL, NULL); 535 536 g_object_weak_ref (G_OBJECT (cat_model), disconnect_cat_model_callbacks, tmodel); 537 g_signal_connect (tmodel, "row-changed", G_CALLBACK (torrent_model_row_changed), cat_model); 538 g_signal_connect (tmodel, "row-inserted", G_CALLBACK (torrent_model_row_changed), cat_model); 539 g_signal_connect (tmodel, "row-deleted", G_CALLBACK (torrent_model_row_deleted_cb), cat_model); 540 541 return c; 527 542 } 528 543 … … 530 545 test_category (tr_torrent * tor, int active_category_type, const char * host) 531 546 { 532 const tr_info * const inf = tr_torrentInfo (tor); 533 534 switch (active_category_type) 535 { 536 case CAT_FILTER_TYPE_ALL: 537 return TRUE; 538 539 case CAT_FILTER_TYPE_PRIVATE: 540 return inf->isPrivate; 541 542 case CAT_FILTER_TYPE_PUBLIC: 543 return !inf->isPrivate; 544 545 case CAT_FILTER_TYPE_PRI_HIGH: 546 return tr_torrentGetPriority (tor) == TR_PRI_HIGH; 547 548 case CAT_FILTER_TYPE_PRI_NORMAL: 549 return tr_torrentGetPriority (tor) == TR_PRI_NORMAL; 550 551 case CAT_FILTER_TYPE_PRI_LOW: 552 return tr_torrentGetPriority (tor) == TR_PRI_LOW; 553 554 case CAT_FILTER_TYPE_HOST: { 555 unsigned int i; 556 char tmp[1024]; 557 for (i=0; i<inf->trackerCount; ++i) { 558 gtr_get_host_from_url (tmp, sizeof (tmp), inf->trackers[i].announce); 559 if (!strcmp (tmp, host)) 560 break; 547 const tr_info * const inf = tr_torrentInfo (tor); 548 549 switch (active_category_type) 550 { 551 case CAT_FILTER_TYPE_ALL: 552 return TRUE; 553 554 case CAT_FILTER_TYPE_PRIVATE: 555 return inf->isPrivate; 556 557 case CAT_FILTER_TYPE_PUBLIC: 558 return !inf->isPrivate; 559 560 case CAT_FILTER_TYPE_PRI_HIGH: 561 return tr_torrentGetPriority (tor) == TR_PRI_HIGH; 562 563 case CAT_FILTER_TYPE_PRI_NORMAL: 564 return tr_torrentGetPriority (tor) == TR_PRI_NORMAL; 565 566 case CAT_FILTER_TYPE_PRI_LOW: 567 return tr_torrentGetPriority (tor) == TR_PRI_LOW; 568 569 case CAT_FILTER_TYPE_HOST: 570 { 571 unsigned int i; 572 char tmp[1024]; 573 for (i=0; i<inf->trackerCount; ++i) 574 { 575 gtr_get_host_from_url (tmp, sizeof (tmp), inf->trackers[i].announce); 576 if (!strcmp (tmp, host)) 577 break; 561 578 } 562 563 } 564 565 566 567 568 569 570 579 return i < inf->trackerCount; 580 } 581 582 case CAT_FILTER_TYPE_TAG: 583 /* FIXME */ 584 return TRUE; 585 586 default: 587 return TRUE; 571 588 } 572 589 } … … 580 597 enum 581 598 { 582 583 584 585 586 587 588 589 590 599 ACTIVITY_FILTER_ALL, 600 ACTIVITY_FILTER_DOWNLOADING, 601 ACTIVITY_FILTER_SEEDING, 602 ACTIVITY_FILTER_ACTIVE, 603 ACTIVITY_FILTER_PAUSED, 604 ACTIVITY_FILTER_FINISHED, 605 ACTIVITY_FILTER_VERIFYING, 606 ACTIVITY_FILTER_ERROR, 607 ACTIVITY_FILTER_SEPARATOR 591 608 }; 592 609 593 610 enum 594 611 { 595 596 597 598 599 612 ACTIVITY_FILTER_COL_NAME, 613 ACTIVITY_FILTER_COL_COUNT, 614 ACTIVITY_FILTER_COL_TYPE, 615 ACTIVITY_FILTER_COL_STOCK_ID, 616 ACTIVITY_FILTER_N_COLS 600 617 }; 601 618 … … 603 620 activity_is_it_a_separator (GtkTreeModel * m, GtkTreeIter * i, gpointer d UNUSED) 604 621 { 605 606 607 622 int type; 623 gtk_tree_model_get (m, i, ACTIVITY_FILTER_COL_TYPE, &type, -1); 624 return type == ACTIVITY_FILTER_SEPARATOR; 608 625 } 609 626 … … 611 628 test_torrent_activity (tr_torrent * tor, int type) 612 629 { 613 614 615 616 { 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 630 const tr_stat * st = tr_torrentStatCached (tor); 631 632 switch (type) 633 { 634 case ACTIVITY_FILTER_DOWNLOADING: 635 return (st->activity == TR_STATUS_DOWNLOAD) 636 || (st->activity == TR_STATUS_DOWNLOAD_WAIT); 637 638 case ACTIVITY_FILTER_SEEDING: 639 return (st->activity == TR_STATUS_SEED) 640 || (st->activity == TR_STATUS_SEED_WAIT); 641 642 case ACTIVITY_FILTER_ACTIVE: 643 return (st->peersSendingToUs > 0) 644 || (st->peersGettingFromUs > 0) 645 || (st->webseedsSendingToUs > 0) 646 || (st->activity == TR_STATUS_CHECK); 647 648 case ACTIVITY_FILTER_PAUSED: 649 return st->activity == TR_STATUS_STOPPED; 650 651 case ACTIVITY_FILTER_FINISHED: 652 return st->finished == TRUE; 653 654 case ACTIVITY_FILTER_VERIFYING: 655 return (st->activity == TR_STATUS_CHECK) 656 || (st->activity == TR_STATUS_CHECK_WAIT); 657 658 case ACTIVITY_FILTER_ERROR: 659 return st->error != 0; 660 661 default: /* ACTIVITY_FILTER_ALL */ 662 return TRUE; 646 663 } 647 664 } … … 650 667 status_model_update_count (GtkListStore * store, GtkTreeIter * iter, int n) 651 668 { 652 653 654 655 656 669 int count; 670 GtkTreeModel * model = GTK_TREE_MODEL (store); 671 gtk_tree_model_get (model, iter, ACTIVITY_FILTER_COL_COUNT, &count, -1); 672 if (n != count) 673 gtk_list_store_set (store, iter, ACTIVITY_FILTER_COL_COUNT, n, -1); 657 674 } 658 675 … … 660 677 activity_filter_model_update (GtkListStore * store) 661 678 { 662 GtkTreeIter iter; 663 GtkTreeModel * model = GTK_TREE_MODEL (store); 664 GObject * o = G_OBJECT (store); 665 GtkTreeModel * tmodel = GTK_TREE_MODEL (g_object_get_qdata (o, TORRENT_MODEL_KEY)); 666 667 g_object_steal_qdata (o, DIRTY_KEY); 668 669 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, 0)) do 670 { 671 int hits; 672 int type; 673 GtkTreeIter torrent_iter; 674 675 gtk_tree_model_get (model, &iter, ACTIVITY_FILTER_COL_TYPE, &type, -1); 676 677 hits = 0; 678 if (gtk_tree_model_iter_nth_child (tmodel, &torrent_iter, NULL, 0)) do { 679 tr_torrent * tor; 680 gtk_tree_model_get (tmodel, &torrent_iter, MC_TORRENT, &tor, -1); 681 if (test_torrent_activity (tor, type)) 682 ++hits; 683 } while (gtk_tree_model_iter_next (tmodel, &torrent_iter)); 684 685 status_model_update_count (store, &iter, hits); 686 687 } while (gtk_tree_model_iter_next (model, &iter)); 679 GtkTreeIter iter; 680 GtkTreeModel * model = GTK_TREE_MODEL (store); 681 GObject * o = G_OBJECT (store); 682 GtkTreeModel * tmodel = GTK_TREE_MODEL (g_object_get_qdata (o, TORRENT_MODEL_KEY)); 683 684 g_object_steal_qdata (o, DIRTY_KEY); 685 686 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, 0)) do 687 { 688 int hits; 689 int type; 690 GtkTreeIter torrent_iter; 691 692 gtk_tree_model_get (model, &iter, ACTIVITY_FILTER_COL_TYPE, &type, -1); 693 694 hits = 0; 695 if (gtk_tree_model_iter_nth_child (tmodel, &torrent_iter, NULL, 0)) do 696 { 697 tr_torrent * tor; 698 gtk_tree_model_get (tmodel, &torrent_iter, MC_TORRENT, &tor, -1); 699 if (test_torrent_activity (tor, type)) 700 ++hits; 701 } 702 while (gtk_tree_model_iter_next (tmodel, &torrent_iter)); 703 704 status_model_update_count (store, &iter, hits); 705 706 } 707 while (gtk_tree_model_iter_next (model, &iter)); 688 708 } 689 709 … … 691 711 activity_filter_model_new (GtkTreeModel * tmodel) 692 712 { 693 int i, n; 694 struct { 695 int type; 696 const char * context; 697 const char * name; 698 const char * stock_id; 699 } types[] = { 700 { ACTIVITY_FILTER_ALL, NULL, N_("All"), NULL }, 701 { ACTIVITY_FILTER_SEPARATOR, NULL, NULL, NULL }, 702 { ACTIVITY_FILTER_ACTIVE, NULL, N_("Active"), GTK_STOCK_EXECUTE }, 703 { ACTIVITY_FILTER_DOWNLOADING, "Verb", NC_("Verb", "Downloading"), GTK_STOCK_GO_DOWN }, 704 { ACTIVITY_FILTER_SEEDING, "Verb", NC_("Verb", "Seeding"), GTK_STOCK_GO_UP }, 705 { ACTIVITY_FILTER_PAUSED, NULL, N_("Paused"), GTK_STOCK_MEDIA_PAUSE }, 706 { ACTIVITY_FILTER_FINISHED, NULL, N_("Finished"), NULL }, 707 { ACTIVITY_FILTER_VERIFYING, "Verb", NC_("Verb", "Verifying"), GTK_STOCK_REFRESH }, 708 { ACTIVITY_FILTER_ERROR, NULL, N_("Error"), GTK_STOCK_DIALOG_ERROR } 709 }; 710 GtkListStore * store = gtk_list_store_new (ACTIVITY_FILTER_N_COLS, 711 G_TYPE_STRING, 712 G_TYPE_INT, 713 G_TYPE_INT, 714 G_TYPE_STRING); 715 for (i=0, n=G_N_ELEMENTS (types); i<n; ++i) { 716 const char * name = types[i].context ? g_dpgettext2 (NULL, types[i].context, types[i].name) 717 : _ (types[i].name); 718 gtk_list_store_insert_with_values (store, NULL, -1, 719 ACTIVITY_FILTER_COL_NAME, name, 720 ACTIVITY_FILTER_COL_TYPE, types[i].type, 721 ACTIVITY_FILTER_COL_STOCK_ID, types[i].stock_id, 722 -1); 723 } 724 725 g_object_set_qdata (G_OBJECT (store), TORRENT_MODEL_KEY, tmodel); 726 activity_filter_model_update (store); 727 return GTK_TREE_MODEL (store); 713 int i, n; 714 struct { 715 int type; 716 const char * context; 717 const char * name; 718 const char * stock_id; 719 } types[] = { 720 { ACTIVITY_FILTER_ALL, NULL, N_("All"), NULL }, 721 { ACTIVITY_FILTER_SEPARATOR, NULL, NULL, NULL }, 722 { ACTIVITY_FILTER_ACTIVE, NULL, N_("Active"), GTK_STOCK_EXECUTE }, 723 { ACTIVITY_FILTER_DOWNLOADING, "Verb", NC_("Verb", "Downloading"), GTK_STOCK_GO_DOWN }, 724 { ACTIVITY_FILTER_SEEDING, "Verb", NC_("Verb", "Seeding"), GTK_STOCK_GO_UP }, 725 { ACTIVITY_FILTER_PAUSED, NULL, N_("Paused"), GTK_STOCK_MEDIA_PAUSE }, 726 { ACTIVITY_FILTER_FINISHED, NULL, N_("Finished"), NULL }, 727 { ACTIVITY_FILTER_VERIFYING, "Verb", NC_("Verb", "Verifying"), GTK_STOCK_REFRESH }, 728 { ACTIVITY_FILTER_ERROR, NULL, N_("Error"), GTK_STOCK_DIALOG_ERROR } 729 }; 730 731 GtkListStore * store = gtk_list_store_new (ACTIVITY_FILTER_N_COLS, 732 G_TYPE_STRING, 733 G_TYPE_INT, 734 G_TYPE_INT, 735 G_TYPE_STRING); 736 for (i=0, n=G_N_ELEMENTS (types); i<n; ++i) 737 { 738 const char * name = types[i].context ? g_dpgettext2 (NULL, types[i].context, types[i].name) 739 : _ (types[i].name); 740 gtk_list_store_insert_with_values (store, NULL, -1, 741 ACTIVITY_FILTER_COL_NAME, name, 742 ACTIVITY_FILTER_COL_TYPE, types[i].type, 743 ACTIVITY_FILTER_COL_STOCK_ID, types[i].stock_id, 744 -1); 745 } 746 747 g_object_set_qdata (G_OBJECT (store), TORRENT_MODEL_KEY, tmodel); 748 activity_filter_model_update (store); 749 return GTK_TREE_MODEL (store); 728 750 } 729 751 … … 735 757 gpointer data UNUSED) 736 758 { 737 738 739 740 741 742 743 744 745 746 747 748 749 759 int type; 760 int width; 761 int ypad; 762 const gboolean leaf = !gtk_tree_model_iter_has_child (tree_model, iter); 763 764 gtk_tree_model_get (tree_model, iter, ACTIVITY_FILTER_COL_TYPE, &type, -1); 765 width = type == ACTIVITY_FILTER_ALL ? 0 : 20; 766 ypad = type == ACTIVITY_FILTER_ALL ? 0 : 2; 767 768 g_object_set (cell_renderer, "width", width, 769 "sensitive", leaf, 770 "ypad", ypad, 771 NULL); 750 772 } 751 773 … … 753 775 activity_model_update_idle (gpointer activity_model) 754 776 { 755 756 757 758 { 759 760 761 777 GObject * o = G_OBJECT (activity_model); 778 const gboolean pending = g_object_get_qdata (o, DIRTY_KEY) != NULL; 779 if (!pending) 780 { 781 GSourceFunc func = (GSourceFunc) activity_filter_model_update; 782 g_object_set_qdata (o, DIRTY_KEY, GINT_TO_POINTER (1)); 783 gdk_threads_add_idle (func, activity_model); 762 784 } 763 785 } … … 769 791 gpointer activity_model) 770 792 { 771 793 activity_model_update_idle (activity_model); 772 794 } 773 795 … … 777 799 gpointer activity_model) 778 800 { 779 801 activity_model_update_idle (activity_model); 780 802 } 781 803 … … 783 805 disconnect_activity_model_callbacks (gpointer tmodel, GObject * cat_model) 784 806 { 785 786 807 g_signal_handlers_disconnect_by_func (tmodel, activity_torrent_model_row_changed, cat_model); 808 g_signal_handlers_disconnect_by_func (tmodel, activity_torrent_model_row_deleted_cb, cat_model); 787 809 } 788 810 … … 790 812 activity_combo_box_new (GtkTreeModel * tmodel) 791 813 { 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 814 GtkWidget * c; 815 GtkCellRenderer * r; 816 GtkTreeModel * activity_model; 817 GtkComboBox * c_combo_box; 818 GtkCellLayout * c_cell_layout; 819 820 activity_model = activity_filter_model_new (tmodel); 821 c = gtk_combo_box_new_with_model (activity_model); 822 c_combo_box = GTK_COMBO_BOX (c); 823 c_cell_layout = GTK_CELL_LAYOUT (c); 824 g_object_unref (activity_model); 825 gtk_combo_box_set_row_separator_func (c_combo_box, 826 activity_is_it_a_separator, NULL, NULL); 827 gtk_combo_box_set_active (c_combo_box, 0); 828 829 r = gtk_cell_renderer_pixbuf_new (); 830 gtk_cell_layout_pack_start (c_cell_layout, r, FALSE); 831 gtk_cell_layout_set_attributes (c_cell_layout, r, 832 "stock-id", ACTIVITY_FILTER_COL_STOCK_ID, 833 NULL); 834 gtk_cell_layout_set_cell_data_func (c_cell_layout, r, 835 render_activity_pixbuf_func, NULL, NULL); 836 837 r = gtk_cell_renderer_text_new (); 838 gtk_cell_layout_pack_start (c_cell_layout, r, TRUE); 839 gtk_cell_layout_set_attributes (c_cell_layout, r, 840 "text", ACTIVITY_FILTER_COL_NAME, 841 NULL); 842 843 r = number_renderer_new (); 844 gtk_cell_layout_pack_end (c_cell_layout, r, TRUE); 845 gtk_cell_layout_set_cell_data_func (c_cell_layout, r, 846 render_number_func, NULL, NULL); 847 848 g_object_weak_ref (G_OBJECT (activity_model), disconnect_activity_model_callbacks, tmodel); 849 g_signal_connect (tmodel, "row-changed", G_CALLBACK (activity_torrent_model_row_changed), activity_model); 850 g_signal_connect (tmodel, "row-inserted", G_CALLBACK (activity_torrent_model_row_changed), activity_model); 851 g_signal_connect (tmodel, "row-deleted", G_CALLBACK (activity_torrent_model_row_deleted_cb), activity_model); 852 853 return c; 832 854 } 833 855 … … 841 863 testText (const tr_torrent * tor, const char * key) 842 864 { 843 844 845 846 { 847 848 } 849 850 { 851 852 853 854 855 856 857 858 859 860 861 862 863 { 864 865 866 867 } 868 } 869 870 865 gboolean ret = FALSE; 866 867 if (!key || !*key) 868 { 869 ret = TRUE; 870 } 871 else 872 { 873 tr_file_index_t i; 874 const tr_info * inf = tr_torrentInfo (tor); 875 876 /* test the torrent name... */ 877 { 878 char * pch = g_utf8_casefold (tr_torrentName (tor), -1); 879 ret = !key || strstr (pch, key) != NULL; 880 g_free (pch); 881 } 882 883 /* test the files... */ 884 for (i=0; i<inf->fileCount && !ret; ++i) 885 { 886 char * pch = g_utf8_casefold (inf->files[i].name, -1); 887 ret = !key || strstr (pch, key) != NULL; 888 g_free (pch); 889 } 890 } 891 892 return ret; 871 893 } 872 894 … … 874 896 entry_clear (GtkEntry * e) 875 897 { 876 898 gtk_entry_set_text (e, ""); 877 899 } 878 900 … … 880 902 filter_entry_changed (GtkEditable * e, gpointer filter_model) 881 903 { 882 883 884 885 886 887 888 889 890 891 904 char * pch; 905 char * folded; 906 907 pch = gtk_editable_get_chars (e, 0, -1); 908 folded = g_utf8_casefold (pch, -1); 909 g_strstrip (folded); 910 g_object_set_qdata_full (filter_model, TEXT_KEY, folded, g_free); 911 g_free (pch); 912 913 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model)); 892 914 } 893 915 … … 900 922 struct filter_data 901 923 { 902 903 904 905 906 907 908 924 GtkWidget * activity; 925 GtkWidget * category; 926 GtkWidget * entry; 927 GtkTreeModel * filter_model; 928 int active_activity_type; 929 int active_category_type; 930 char * active_category_host; 909 931 }; 910 932 … … 912 934 is_row_visible (GtkTreeModel * model, GtkTreeIter * iter, gpointer vdata) 913 935 { 914 915 916 917 918 919 920 921 922 923 924 925 936 const char * text; 937 tr_torrent * tor; 938 struct filter_data * data = vdata; 939 GObject * o = G_OBJECT (data->filter_model); 940 941 gtk_tree_model_get (model, iter, MC_TORRENT, &tor, -1); 942 943 text = (const char*) g_object_get_qdata (o, TEXT_KEY); 944 945 return (tor != NULL) && test_category (tor, data->active_category_type, data->active_category_host) 946 && test_torrent_activity (tor, data->active_activity_type) 947 && testText (tor, text); 926 948 } 927 949 … … 929 951 selection_changed_cb (GtkComboBox * combo, gpointer vdata) 930 952 { 931 int type; 932 char * host; 933 GtkTreeIter iter; 934 GtkTreeModel * model; 935 struct filter_data * data = vdata; 936 937 /* set data->active_activity_type from the activity combobox */ 938 combo = GTK_COMBO_BOX (data->activity); 939 model = gtk_combo_box_get_model (combo); 940 if (gtk_combo_box_get_active_iter (combo, &iter)) 941 gtk_tree_model_get (model, &iter, ACTIVITY_FILTER_COL_TYPE, &type, -1); 942 else 943 type = ACTIVITY_FILTER_ALL; 944 data->active_activity_type = type; 945 946 /* set the active category type & host from the category combobox */ 947 combo = GTK_COMBO_BOX (data->category); 948 model = gtk_combo_box_get_model (combo); 949 if (gtk_combo_box_get_active_iter (combo, &iter)) { 950 gtk_tree_model_get (model, &iter, CAT_FILTER_COL_TYPE, &type, 951 CAT_FILTER_COL_HOST, &host, 952 -1); 953 } else { 954 type = CAT_FILTER_TYPE_ALL; 955 host = NULL; 956 } 957 g_free (data->active_category_host); 958 data->active_category_host = host; 959 data->active_category_type = type; 960 961 /* refilter */ 962 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (data->filter_model)); 953 int type; 954 char * host; 955 GtkTreeIter iter; 956 GtkTreeModel * model; 957 struct filter_data * data = vdata; 958 959 /* set data->active_activity_type from the activity combobox */ 960 combo = GTK_COMBO_BOX (data->activity); 961 model = gtk_combo_box_get_model (combo); 962 if (gtk_combo_box_get_active_iter (combo, &iter)) 963 gtk_tree_model_get (model, &iter, ACTIVITY_FILTER_COL_TYPE, &type, -1); 964 else 965 type = ACTIVITY_FILTER_ALL; 966 data->active_activity_type = type; 967 968 /* set the active category type & host from the category combobox */ 969 combo = GTK_COMBO_BOX (data->category); 970 model = gtk_combo_box_get_model (combo); 971 if (gtk_combo_box_get_active_iter (combo, &iter)) 972 { 973 gtk_tree_model_get (model, &iter, CAT_FILTER_COL_TYPE, &type, 974 CAT_FILTER_COL_HOST, &host, 975 -1); 976 } 977 else 978 { 979 type = CAT_FILTER_TYPE_ALL; 980 host = NULL; 981 } 982 g_free (data->active_category_host); 983 data->active_category_host = host; 984 data->active_category_type = type; 985 986 /* refilter */ 987 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (data->filter_model)); 963 988 } 964 989 … … 966 991 gtr_filter_bar_new (tr_session * session, GtkTreeModel * tmodel, GtkTreeModel ** filter_model) 967 992 { 968 GtkWidget * l; 969 GtkWidget * w; 970 GtkWidget * h; 971 GtkWidget * s; 972 GtkWidget * activity; 973 GtkWidget * category; 974 GtkBox * h_box; 975 const char * str; 976 struct filter_data * data; 977 978 g_assert (DIRTY_KEY == 0); 979 TEXT_KEY = g_quark_from_static_string ("tr-filter-text-key"); 980 DIRTY_KEY = g_quark_from_static_string ("tr-filter-dirty-key"); 981 SESSION_KEY = g_quark_from_static_string ("tr-session-key"); 982 TORRENT_MODEL_KEY = g_quark_from_static_string ("tr-filter-torrent-model-key"); 983 984 data = g_new0 (struct filter_data, 1); 985 data->activity = activity = activity_combo_box_new (tmodel); 986 data->category = category = category_combo_box_new (tmodel); 987 data->filter_model = gtk_tree_model_filter_new (tmodel, NULL); 988 989 g_object_set (G_OBJECT (data->category), "width-request", 170, NULL); 990 g_object_set_qdata (G_OBJECT (gtk_combo_box_get_model (GTK_COMBO_BOX (data->category))), SESSION_KEY, session); 991 992 gtk_tree_model_filter_set_visible_func ( 993 GTK_TREE_MODEL_FILTER (data->filter_model), 994 is_row_visible, data, g_free); 995 996 g_signal_connect (data->category, "changed", G_CALLBACK (selection_changed_cb), data); 997 g_signal_connect (data->activity, "changed", G_CALLBACK (selection_changed_cb), data); 998 999 1000 h = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, GUI_PAD_SMALL); 1001 h_box = GTK_BOX (h); 1002 1003 /* add the activity combobox */ 1004 str = _("_Show:"); 1005 w = activity; 1006 l = gtk_label_new (NULL); 1007 gtk_label_set_markup_with_mnemonic (GTK_LABEL (l), str); 1008 gtk_label_set_mnemonic_widget (GTK_LABEL (l), w); 1009 gtk_box_pack_start (h_box, l, FALSE, FALSE, 0); 1010 gtk_box_pack_start (h_box, w, TRUE, TRUE, 0); 1011 1012 /* add a spacer */ 1013 w = gtk_alignment_new (0.0f, 0.0f, 0.0f, 0.0f); 1014 gtk_widget_set_size_request (w, 0u, GUI_PAD_BIG); 1015 gtk_box_pack_start (h_box, w, FALSE, FALSE, 0); 1016 1017 /* add the category combobox */ 1018 w = category; 1019 gtk_box_pack_start (h_box, w, TRUE, TRUE, 0); 1020 1021 /* add a spacer */ 1022 w = gtk_alignment_new (0.0f, 0.0f, 0.0f, 0.0f); 1023 gtk_widget_set_size_request (w, 0u, GUI_PAD_BIG); 1024 gtk_box_pack_start (h_box, w, FALSE, FALSE, 0); 1025 1026 /* add the entry field */ 1027 s = gtk_entry_new (); 1028 gtk_entry_set_icon_from_stock (GTK_ENTRY (s), GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR); 1029 g_signal_connect (s, "icon-release", G_CALLBACK (entry_clear), NULL); 1030 gtk_box_pack_start (h_box, s, TRUE, TRUE, 0); 1031 1032 g_signal_connect (s, "changed", G_CALLBACK (filter_entry_changed), data->filter_model); 1033 selection_changed_cb (NULL, data); 1034 1035 *filter_model = data->filter_model; 1036 return h; 1037 } 993 GtkWidget * l; 994 GtkWidget * w; 995 GtkWidget * h; 996 GtkWidget * s; 997 GtkWidget * activity; 998 GtkWidget * category; 999 GtkBox * h_box; 1000 const char * str; 1001 struct filter_data * data; 1002 1003 g_assert (DIRTY_KEY == 0); 1004 TEXT_KEY = g_quark_from_static_string ("tr-filter-text-key"); 1005 DIRTY_KEY = g_quark_from_static_string ("tr-filter-dirty-key"); 1006 SESSION_KEY = g_quark_from_static_string ("tr-session-key"); 1007 TORRENT_MODEL_KEY = g_quark_from_static_string ("tr-filter-torrent-model-key"); 1008 1009 data = g_new0 (struct filter_data, 1); 1010 data->activity = activity = activity_combo_box_new (tmodel); 1011 data->category = category = category_combo_box_new (tmodel); 1012 data->filter_model = gtk_tree_model_filter_new (tmodel, NULL); 1013 1014 g_object_set (G_OBJECT (data->category), "width-request", 170, NULL); 1015 g_object_set_qdata (G_OBJECT (gtk_combo_box_get_model (GTK_COMBO_BOX (data->category))), SESSION_KEY, session); 1016 1017 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (data->filter_model), 1018 is_row_visible, data, g_free); 1019 1020 g_signal_connect (data->category, "changed", G_CALLBACK (selection_changed_cb), data); 1021 g_signal_connect (data->activity, "changed", G_CALLBACK (selection_changed_cb), data); 1022 1023 1024 h = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, GUI_PAD_SMALL); 1025 h_box = GTK_BOX (h); 1026 1027 /* add the activity combobox */ 1028 str = _("_Show:"); 1029 w = activity; 1030 l = gtk_label_new (NULL); 1031 gtk_label_set_markup_with_mnemonic (GTK_LABEL (l), str); 1032 gtk_label_set_mnemonic_widget (GTK_LABEL (l), w); 1033 gtk_box_pack_start (h_box, l, FALSE, FALSE, 0); 1034 gtk_box_pack_start (h_box, w, TRUE, TRUE, 0); 1035 1036 /* add a spacer */ 1037 w = gtk_alignment_new (0.0f, 0.0f, 0.0f, 0.0f); 1038 gtk_widget_set_size_request (w, 0u, GUI_PAD_BIG); 1039 gtk_box_pack_start (h_box, w, FALSE, FALSE, 0); 1040 1041 /* add the category combobox */ 1042 w = category; 1043 gtk_box_pack_start (h_box, w, TRUE, TRUE, 0); 1044 1045 /* add a spacer */ 1046 w = gtk_alignment_new (0.0f, 0.0f, 0.0f, 0.0f); 1047 gtk_widget_set_size_request (w, 0u, GUI_PAD_BIG); 1048 gtk_box_pack_start (h_box, w, FALSE, FALSE, 0); 1049 1050 /* add the entry field */ 1051 s = gtk_entry_new (); 1052 gtk_entry_set_icon_from_stock (GTK_ENTRY (s), GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR); 1053 g_signal_connect (s, "icon-release", G_CALLBACK (entry_clear), NULL); 1054 gtk_box_pack_start (h_box, s, TRUE, TRUE, 0); 1055 1056 g_signal_connect (s, "changed", G_CALLBACK (filter_entry_changed), data->filter_model); 1057 selection_changed_cb (NULL, data); 1058 1059 *filter_model = data->filter_model; 1060 return h; 1061 }
Note: See TracChangeset
for help on using the changeset viewer.