1 #include <stdio.h>
2 #include <gdk/gdkkeysyms.h>
3 #include "urlgfe.h"
4 #include "utility.h"
5 #include "main_app.h"
6 #include "download_dialog.h"
7 #include "category_dialog.h"
8 #include "batch_dialog.h"
9 #include "download_thread.h"
10 #include "global_dialog.h"
11 #include "category_selection_dialog.h"
12 
13 #ifdef G_OS_WIN32
14 #include <windows.h>
15 #define main_app_thread_sleep()    Sleep (500);
16 #else
17 #define main_app_thread_sleep()    sleep (1);
18 #endif
19 
20 // utility functions ------------------------------------------------
21 
add_batch_download(Category * cate,Download * download_data,const gchar * pattern,guint n_min,guint n_max,guint n_width)22 static void add_batch_download (Category* cate,
23                                 Download* download_data,
24                                 const gchar* pattern,
25                                 guint n_min,
26                                 guint n_max,
27                                 guint n_width)
28 {
29 	DownloadSetting* setting = DOWNLOAD_SETTING (download_data);
30 	const gchar* p_star;
31 	GString *str_url;
32 	gssize   truncate_len;
33 	guint    n_serial;
34 	UrlPart  up;
35 
36 	for (p_star=pattern; *p_star; ++p_star) {
37 		if (*p_star=='*')
38 			break;
39 	}
40 	if (*p_star == 0)
41 		return;
42 
43 
44 	str_url = g_string_new_len (pattern, p_star-pattern);
45 	truncate_len = str_url->len;
46 	g_free (setting->filename);
47 	g_free (setting->url);
48 
49 	for (n_serial=n_min; n_serial<=n_max; ++n_serial) {
50 		if (n_width) {
51 			g_string_append_printf (str_url,
52 			                        "%.*u%s",
53 			                        n_width,
54 			                        n_serial,
55 			                        p_star+1);
56 		}
57 		else {  // character mode
58 			g_string_append_printf (str_url,
59 			                        "%c%s",
60 			                        (unsigned char)n_serial,
61 			                        p_star+1);
62 		}
63 		setting->url = str_url->str;
64 		// get filename
65 		url_part (&up, setting->url);
66 		setting->filename = up.name_beg;
67 
68 		download_store_add (&cate->waiting_store, download_data);
69 		g_string_truncate (str_url, truncate_len);
70 	}
71 	g_string_free (str_url, TRUE);
72 
73 	setting->filename = NULL;
74 	setting->url      = NULL;
75 }
76 
77 // utility function for GtkTreeSelection
78 // malloc and return Selected GtkTreeIter
79 // return value : number of Selected GtkTreeIter
tree_selection_get_selected_iters(GtkTreeSelection * selection,GtkTreeIter ** iter_array)80 guint tree_selection_get_selected_iters (GtkTreeSelection* selection,
81                                          GtkTreeIter** iter_array)
82 {
83 	GtkTreeModel*     model;
84 	GtkTreeIter*      p_iter;
85 	GList*            path_list;
86 	GList*            node_prev;
87 	guint             n_iter;
88 
89 	if (n_iter = gtk_tree_selection_count_selected_rows (selection)) {
90 		// allocate array of iter
91 		*iter_array = g_malloc (sizeof (GtkTreeIter) * n_iter);
92 		// get GList contain GtkTreePath
93 		path_list = gtk_tree_selection_get_selected_rows (selection, &model);
94 		// convert GtkTreePath to GtkTreeIter
95 		p_iter = *iter_array;
96 		while (path_list) {
97 			gtk_tree_model_get_iter (model, p_iter, path_list->data);
98             p_iter++;
99 			node_prev = path_list;
100 			path_list = path_list->next;
101 			gtk_tree_path_free (node_prev->data);
102 			g_list_free_1 (node_prev);
103 		}
104 		return n_iter;
105 	}
106 	return 0;
107 }
108 
show_about_dialog(GtkWindow * parent)109 static void show_about_dialog (GtkWindow* parent)
110 {
111 	GtkWidget* vbox;
112 //	GtkWidget* image;
113 	GtkWidget* label;
114 	GtkWidget* dialog;
115 
116 	dialog = gtk_dialog_new_with_buttons (_("About UrlGfe"),
117 	                                      parent,
118 	         (GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT),
119 	                                      GTK_STOCK_OK,
120 	                                      GTK_RESPONSE_OK,
121 	                                      NULL);
122 	gtk_window_set_default_size (GTK_WINDOW (dialog), 150, 150);
123 	vbox = GTK_DIALOG (dialog)->vbox;
124 	// icon
125 //	image = gtk_image_new_from_file (PACKAGE_PIXMAPS_DIR G_DIR_SEPARATOR_S"urlget_icon.png");
126 //	gtk_box_pack_start (GTK_BOX(vbox), image, FALSE, FALSE, 0);
127 	label = gtk_label_new ("UrlGfe 0.7 stable");
128 	gtk_box_pack_start (GTK_BOX(vbox), label, TRUE, TRUE, 0);
129 	label = gtk_label_new (_("Copyright(C) 2002-2004 Plus Huang"));
130 	gtk_box_pack_start (GTK_BOX(vbox), label, TRUE, TRUE, 0);
131 	label = gtk_label_new ("http://urlget.sourceforge.net/");
132 	gtk_box_pack_start (GTK_BOX(vbox), label, TRUE, TRUE, 0);
133 	gtk_widget_show_all (vbox);
134 
135 	gtk_dialog_run (GTK_DIALOG (dialog));
136 	gtk_widget_destroy (dialog);
137 }
138 
139 // End of utility functions =========================================
140 
141 
142 // download signal handler ------------------------------------------
on_download_start(MainApp * app)143 static void on_download_start (MainApp* app)
144 {
145 	GtkTreeSelection* selection;
146 	DownloadListView* download_view;
147 	DownloadStore*    download_store;
148 	Category*         category;
149 
150 	DownloadSetting*  setting;
151 	DownloadThread*   thread;
152 
153 	GtkTreeIter*      iter_array;
154 	guint             n_iter;
155 	guint             index;
156 
157 	gboolean          need_active = FALSE;
158 
159 	if (category_tree_view_get_selected (app->window.category_view,
160                                          &category,
161                                          &download_view,
162                                          &download_store)==FALSE )
163 	{
164 		return;
165 	}
166 
167 	selection = gtk_tree_view_get_selection (download_view->self);
168 
169 	download_store_lock (download_store);
170 
171 	if ( n_iter=tree_selection_get_selected_iters (selection, &iter_array) )
172 	{
173 		for (index=0; index<n_iter; index++) {
174 			gtk_tree_model_get ((GtkTreeModel*)download_store->list_store,
175 	                            iter_array + index,
176 			                    DOWNLOAD_COL_DATA,   &setting,
177 			                    DOWNLOAD_COL_THREAD, &thread,
178 			                    -1);
179 			if (thread==NULL) {
180 				setting->state = DOWNLOAD_STATE_WAITING;
181 				download_store_row_changed (download_store, iter_array+index);
182 			}
183 		}
184 		g_free (iter_array);
185 		need_active = TRUE;
186 	}
187 
188 	download_store_unlock (download_store);
189 
190 	if (need_active)
191 		category_store_thread_activate_1 (&app->category_store, category);
192 }
193 
on_download_stop(MainApp * app)194 static void on_download_stop (MainApp* app)
195 {
196 	GtkTreeSelection* selection;
197 	DownloadListView* download_view;
198 	DownloadStore*    download_store;
199 	Category*         category;
200 
201 	DownloadSetting*  setting;
202 	DownloadThread*   thread;
203 
204 	GtkTreeIter*      iter_array;
205 	guint             n_iter;
206 	guint             index;
207 
208 	if (category_tree_view_get_selected (app->window.category_view,
209                                          &category,
210                                          &download_view,
211                                          &download_store) == FALSE )
212 	{
213 		return;
214 	}
215 
216 	selection = gtk_tree_view_get_selection (download_view->self);
217 
218 	download_store_lock (download_store);
219 
220 	if ( n_iter=tree_selection_get_selected_iters (selection, &iter_array) )
221 	{
222 		for (index=0; index<n_iter; index++) {
223 			gtk_tree_model_get ((GtkTreeModel*)download_store->list_store,
224 	                            iter_array + index,
225 			                    DOWNLOAD_COL_DATA,   &setting,
226 			                    DOWNLOAD_COL_THREAD, &thread,
227 			                    -1);
228 			if (thread)
229 				download_thread_skip (thread);
230 			else {
231 				setting->state = DOWNLOAD_STATE_PAUSE;
232 				download_store_row_changed (download_store, iter_array+index);
233 			}
234 		}
235 		g_free (iter_array);
236 	}
237 
238 	download_store_unlock (download_store);
239 }
240 
on_download_new(MainApp * app)241 static void on_download_new (MainApp* app)
242 {
243 	gchar*         clip_text = NULL;
244 
245 	Category* selected_category = NULL;
246 	UrlPart   urlp;
247 
248 	// check Clipboard
249 	if ( gtk_clipboard_wait_is_text_available (app->clipboard) ) {
250 		clip_text = gtk_clipboard_wait_for_text (app->clipboard);
251 
252 		url_part (&urlp, clip_text);
253 		if ( urlp.protocol_beg == NULL ) {
254 			g_free (clip_text);
255 			clip_text = NULL;
256 		}
257 	}
258 
259 	main_app_add_download_from_url (app, clip_text);
260 
261 	g_free (clip_text);
262 }
263 
on_download_batch(MainApp * app)264 static void on_download_batch (MainApp* app)
265 {
266 	BatchDialog bat_dialog;
267 	gint        batch_mode;
268 	gint        max, min, width;
269 	gchar*      pattern;
270 
271 	Download*   download_data;
272 	gboolean    had_selected;
273 	Category*   selected_category;
274 
275 	// batch dialog
276 	batch_dialog_init (&bat_dialog, app->window.self);
277 
278 	if ( (batch_mode=batch_dialog_run (&bat_dialog))==BATCH_MODE_NONE ) {
279 		batch_dialog_clear (&bat_dialog);
280 		return;
281 	}
282 	if (batch_mode == BATCH_MODE_CHAR) {
283 		max = batch_dialog_get_char_max (&bat_dialog);
284 		min = batch_dialog_get_char_min (&bat_dialog);
285 		width = 0;
286 	}
287 	else {
288 		max = batch_dialog_get_int_max (&bat_dialog);
289 		min = batch_dialog_get_int_min (&bat_dialog);
290 		width = batch_dialog_get_int_width (&bat_dialog);
291 	}
292 	pattern  = g_strdup (batch_dialog_get_pattern (&bat_dialog) );
293 
294 	batch_dialog_clear (&bat_dialog);
295 
296 	// download import dialog
297 	// initial
298 	download_data = download_new ();
299 	had_selected = main_app_get_download_from_user (app,
300 	                                                DOWNLOAD_SETTING (download_data),
301 	                                                &selected_category,
302 	                                                TRUE);
303 	if (had_selected) {
304 		add_batch_download (selected_category,
305 		                    download_data,
306 		                    pattern,
307 		                    min,
308 		                    max,
309 		                    width);
310 		// try to start-up thread.
311 		category_store_thread_activate_1 (&app->category_store,
312 		                                  selected_category);
313 	}
314 
315 	download_unref (download_data);
316 	g_free (pattern);
317 }
318 
319 // bugs here
on_download_erase(MainApp * app)320 static void on_download_erase (MainApp* app)
321 {
322 	GdkWindow*        gdk_win;
323 	GdkModifierType   mask;
324 
325 	GtkTreeSelection* selection;
326 	DownloadListView* download_view;
327 	DownloadStore*    download_store;
328 	Category*         category;
329 
330 	Download*         dl_data;
331 	DownloadThread*   thread;
332 
333 	GtkTreeIter*      iter_array;
334 	guint             n_iter;
335 	guint             index;
336 
337 	if (category_tree_view_get_selected (app->window.category_view,
338                                          &category,
339                                          &download_view,
340                                          &download_store)==FALSE )
341 	{
342 		return;
343 	}
344 
345 	selection = gtk_tree_view_get_selection (download_view->self);
346 
347 	download_store_lock (download_store);
348 
349 	if ( n_iter=tree_selection_get_selected_iters (selection, &iter_array) )
350 	{
351 		gdk_win = gtk_widget_get_parent_window ((GtkWidget*)download_view->self);
352 		gdk_window_get_pointer (gdk_win, NULL, NULL, &mask);
353 
354 		for (index=0; index<n_iter; index++) {
355 			gtk_tree_model_get ((GtkTreeModel*)download_store->list_store,
356 	                            iter_array + index,
357 			                    DOWNLOAD_COL_DATA, &dl_data,
358 			                    DOWNLOAD_COL_THREAD, &thread,
359 			                    -1);
360 			if (thread)
361 				download_thread_job_erased (thread);
362 			if ( &category->recycled_store == download_store || mask & GDK_SHIFT_MASK)
363 				download_store_erase (download_store, iter_array+index);
364 			else {
365 				download_store_move_to_store (download_store,
366 				                              &category->recycled_store,
367 				                              iter_array + index);
368 			}
369 		}
370 		g_free (iter_array);
371 
372 		category_changed (category);
373 	}
374 
375 	download_store_unlock (download_store);
376 }
377 
on_download_property(MainApp * app)378 static void on_download_property (MainApp* app)
379 {
380 	DownloadListView* download_view;
381 	DownloadStore*    download_store;
382 	Download*         dl_data;
383 	GList*            dl_list;
384 	GList*            node;
385 	gint              n_iter;
386 
387 	if (category_tree_view_get_selected (app->window.category_view,
388                                          NULL,
389                                          &download_view,
390                                          &download_store)==FALSE )
391 	{
392 		return;
393 	}
394 
395 	dl_list = download_list_view_selected_list_copy (download_view, &n_iter);
396 
397 	if (n_iter) {
398 		dl_data = download_new ();
399 		download_assign (dl_data, dl_list->data);
400 		if (n_iter>1)
401 			DOWNLOAD_SETTING (dl_data)->multiple = TRUE;
402 		if ( main_app_get_download_from_user (app, DOWNLOAD_SETTING (dl_data),
403 		                                      NULL, (n_iter>1) ? TRUE : FALSE) )
404 		{
405 			for (node=dl_list; node; node=node->next)
406 				download_assign (node->data, dl_data);
407 		}
408 		download_unref (dl_data);
409 	}
410 
411 	download_list_view_selected_list_free (dl_list);
412 
413 	main_window_update_download_view (&app->window);
414 	main_window_text_view_update (&app->window);
415 }
416 
on_download_move_to(MainApp * app)417 static void on_download_move_to (MainApp* app)
418 {
419 	CategorySelectionDialog* csd;
420 	DownloadListView* dlv_src;
421 	DownloadListView* dlv_dest;
422 	gboolean  had_selected;
423 
424 	had_selected = category_tree_view_get_selected (app->window.category_view,
425 		                                            NULL,
426 	                                                &dlv_src,
427 		                                            NULL );
428 
429 	csd = category_selection_dialog_new (_("Move selected download to..."),
430 	                                     &app->category_store,
431 	                                     app->window.self);
432 
433 	if (gtk_dialog_run (csd->self)==GTK_RESPONSE_OK) {
434 		had_selected = category_tree_view_get_selected (csd->category_view,
435 		                                                NULL,
436 		                                                &dlv_dest,
437 		                                                NULL);
438 		if (had_selected && dlv_src!=dlv_dest) {
439 			main_app_move_selected_download (app, dlv_src, dlv_dest);
440 			main_window_text_view_update (&app->window);
441 		}
442 	}
443 
444 	category_selection_dialog_destroy (csd);
445 
446 	category_store_thread_activate (&app->category_store);
447 }
448 
on_download_move_top(MainApp * app)449 static void on_download_move_top (MainApp* app)
450 {
451 	GtkTreeSelection* selection;
452 	DownloadListView* download_view;
453 	DownloadStore*    download_store;
454 	GtkTreeIter*      iter_array;
455 	guint             n_iter;
456 
457 	if (category_tree_view_get_selected (app->window.category_view,
458                                          NULL,
459                                          &download_view,
460                                          &download_store)==FALSE )
461 	{
462 		return;
463 	}
464 
465 	selection = gtk_tree_view_get_selection (download_view->self);
466 
467 	download_store_lock (download_store);
468 
469 	if ( n_iter=tree_selection_get_selected_iters (selection, &iter_array) )
470 	{
471 		while (n_iter--) {
472 			gtk_list_store_move_after (download_store->list_store,
473 			                           iter_array + n_iter, NULL);
474 		}
475 		g_free (iter_array);
476 	}
477 
478 	download_store_unlock (download_store);
479 }
480 
on_download_move_bottom(MainApp * app)481 static void on_download_move_bottom (MainApp* app)
482 {
483 	GtkTreeSelection* selection;
484 	DownloadListView* download_view;
485 	DownloadStore*    download_store;
486 	GtkTreeIter*      iter_array;
487 	guint             n_iter;
488 	guint             index;
489 
490 	if (category_tree_view_get_selected (app->window.category_view,
491                                          NULL,
492                                          &download_view,
493                                          &download_store)==FALSE )
494 	{
495 		return;
496 	}
497 
498 	selection = gtk_tree_view_get_selection (download_view->self);
499 
500 	download_store_lock (download_store);
501 
502 	if ( n_iter=tree_selection_get_selected_iters (selection, &iter_array) )
503 	{
504 		for (index=0; index<n_iter; index++) {
505 			gtk_list_store_move_before (download_store->list_store,
506 			                            iter_array + index, NULL);
507 		}
508 		g_free (iter_array);
509 	}
510 
511 	download_store_unlock (download_store);
512 }
513 
514 // End of download signal handler ===================================
515 
516 
517 // category signal handler ------------------------------------------
518 
on_category_new(MainApp * app)519 static void on_category_new (MainApp* app)
520 {
521 	CategoryDialog* dialog;
522 	CategorySetting setting;
523 	Category* category;
524 
525 	dialog = category_dialog_new (app->window.self);
526 	category_setting_init (&setting);
527 	category_setting_assign (&setting, CATEGORY_SETTING (app->setting));
528 	download_setting_view_set_history (DOWNLOAD_SETTING_VIEW (&dialog->setting_view),
529 	                                   app->setting->directory_list);
530 
531 	category_setting_view_set (&dialog->setting_view, &setting);
532 
533 	if (gtk_dialog_run (GTK_DIALOG (dialog->self))==GTK_RESPONSE_OK) {
534 		category_setting_view_get (&dialog->setting_view, &setting);
535 		category = category_new_from_setting (&setting);
536 		category_store_append (&app->category_store, category);
537 		main_app_connect_category_signal (app, category);
538 	}
539 
540 	category_setting_clear (&setting);
541 	category_dialog_destroy (dialog);
542 }
543 
on_category_erase(MainApp * app)544 static void on_category_erase (MainApp* app)
545 {
546 	Category*   category;
547 	GtkWidget*  dialog;
548 	gint        response;
549 
550 	if ( category_tree_view_get_selected (app->window.category_view,
551 	                                      &category, NULL, NULL)==FALSE )
552 	{
553 		return;
554 	}
555 
556 	dialog = gtk_message_dialog_new (app->window.self,
557 	                                 GTK_DIALOG_DESTROY_WITH_PARENT,
558 	                                 GTK_MESSAGE_WARNING,
559 	                                 GTK_BUTTONS_YES_NO,
560 	   _("This will erase category and it's download. Are you sure to erase?"));
561 	response = gtk_dialog_run (GTK_DIALOG(dialog));
562 	gtk_widget_destroy(dialog);
563 
564 	if (response == GTK_RESPONSE_YES) {
565 		main_window_on_category_erasing (&app->window, category);
566 	//	category_thread_destroy (category);
567 		category_store_erase (&app->category_store, category);
568 
569 		// check selection when erase category
570 		main_window_selection_changed (&app->window);
571 	}
572 }
573 
on_category_property(MainApp * app)574 static void on_category_property (MainApp* app)
575 {
576 	CategoryDialog* dialog;
577 	Category*       category;
578 
579 	if ( category_tree_view_get_selected (app->window.category_view,
580 	                                      &category, NULL, NULL)==FALSE )
581 	{
582 		return;
583 	}
584 
585 	dialog = category_dialog_new (app->window.self);
586 	download_setting_view_set_history (DOWNLOAD_SETTING_VIEW (&dialog->setting_view),
587 	                                   app->setting->directory_list);
588 
589 	category_setting_view_set (&dialog->setting_view,
590 	                           CATEGORY_SETTING(category));
591 
592 	if (gtk_dialog_run (GTK_DIALOG (dialog->self))==GTK_RESPONSE_OK) {
593 		category_setting_view_get (&dialog->setting_view,
594 		                           CATEGORY_SETTING(category));
595 		category_apply_setting (category);
596 		category_changed (category);
597 	}
598 
599 	category_dialog_destroy (dialog);
600 	category_store_thread_activate_1 (&app->category_store, category);
601 }
602 
603 // End of category signal handler ===================================
604 
605 
606 // global signal handler --------------------------------------------
607 
on_set_category_default(MainApp * app)608 static void on_set_category_default (MainApp* app)
609 {
610 	CategoryDialog* dialog;
611 
612 	dialog = category_dialog_new (app->window.self);
613 	download_setting_view_set_history (DOWNLOAD_SETTING_VIEW (&dialog->setting_view),
614 	                                   app->setting->directory_list);
615 
616 	category_setting_view_set (&dialog->setting_view,
617 	                           CATEGORY_SETTING(app->setting));
618     category_setting_view_set_multiple (&dialog->setting_view, TRUE);
619 
620 	if (gtk_dialog_run (GTK_DIALOG (dialog->self))==GTK_RESPONSE_OK) {
621 		category_setting_view_get (&dialog->setting_view,
622 		                           CATEGORY_SETTING(app->setting));
623 	}
624 
625 	category_dialog_destroy (dialog);
626 }
627 
on_set_global_setting(MainApp * app)628 static void on_set_global_setting (MainApp* app)
629 {
630 	GlobalDialog* gd;
631 
632 	gd = global_dialog_new (app->window.self);
633 
634 	global_dialog_set (gd, app->setting);
635 
636 	if (gtk_dialog_run (gd->self)==GTK_RESPONSE_OK)
637 		global_dialog_get (gd, app->setting);
638 
639 	global_dialog_destroy (gd);
640 
641 	main_app_apply_setting (app);
642 	category_store_thread_activate (&app->category_store);
643 }
644 // End of global signal handler =====================================
645 
646 // keyboard
on_key_press_event(MainApp * app,GdkEventKey * event,GtkWidget * widget)647 gboolean on_key_press_event(MainApp* app,
648                             GdkEventKey *event,
649                             GtkWidget *widget)
650 {
651 	if (event->keyval==GDK_Delete) {
652 		if (widget == (GtkWidget*)app->window.category_view)
653 			on_category_erase (app);
654 		else
655 			on_download_erase (app);
656 	}
657 	return FALSE;
658 }
659 
660 // MainApp
main_app_init(MainApp * app)661 void main_app_init (MainApp* app)
662 {
663 	const gchar* home_dir = g_get_home_dir ();
664 
665 	category_store_init (&app->category_store);
666 	main_window_init (&app->window, &app->category_store);
667 
668 	// clipboard data
669 	app->clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
670 	app->clipboard_text = NULL;
671 	app->clipboard_timer_tag = 0;
672 	app->clipboard_monitoring = FALSE;
673 	app->clipboard_waiting = FALSE;
674 
675 	// read setting file
676 	if (main_app_read_setting_file (app, urlgfe_get_conf_filename ())==FALSE) {
677 		app->setting = global_setting_new ();
678 	}
679 
680 	// read data file
681 	if (main_app_read_data_file (app, urlgfe_get_data_filename ())==FALSE) {
682 		Category* category = category_new();
683 
684 		category_setting_set_name (CATEGORY_SETTING (category), "Home");
685 		download_setting_set_directory (DOWNLOAD_SETTING (category), home_dir);
686 
687 		category_store_append (&app->category_store, category);
688 		gtk_tree_view_expand_all (app->window.category_view);
689 	}
690 
691 	// window
692 	g_signal_connect (app->window.self, "destroy",
693 	                  G_CALLBACK(gtk_main_quit), NULL);
694 	g_signal_connect_swapped (app->window.self, "delete-event",
695 	                          G_CALLBACK(main_app_on_delete_event), app);
696 	g_signal_connect_swapped (app->window.category_view, "key-press-event",
697                               G_CALLBACK (on_key_press_event), app);
698 
699 
700 	// file menu
701 	g_signal_connect_swapped (app->window.file_menu.load, "activate",
702 	                          G_CALLBACK(main_app_on_load), app);
703 	g_signal_connect_swapped (app->window.file_menu.save, "activate",
704 	                          G_CALLBACK(main_app_on_save), app);
705 	g_signal_connect_swapped (app->window.file_menu.save_as, "activate",
706 	                          G_CALLBACK(main_app_on_save_as), app);
707 	g_signal_connect_swapped (app->window.file_menu.import_html, "activate",
708 	                          G_CALLBACK(main_app_on_import_html), app);
709 	g_signal_connect_swapped (app->window.file_menu.export, "activate",
710 	                          G_CALLBACK(main_app_on_export_url), app);
711 
712 	// download
713 	g_signal_connect_swapped (app->window.button_start, "clicked",
714 	                          G_CALLBACK(on_download_start), app);
715 	g_signal_connect_swapped (app->window.button_stop, "clicked",
716 	                          G_CALLBACK(on_download_stop), app);
717 	g_signal_connect_swapped (app->window.button_new, "clicked",
718 	                          G_CALLBACK(on_download_new), app);
719 	g_signal_connect_swapped (app->window.button_batch, "clicked",
720 	                          G_CALLBACK(on_download_batch), app);
721 	g_signal_connect_swapped (app->window.button_erase, "clicked",
722 	                          G_CALLBACK(on_download_erase), app);
723 	g_signal_connect_swapped (app->window.button_property, "clicked",
724 	                          G_CALLBACK(on_download_property), app);
725 	g_signal_connect_swapped (app->window.button_move_top, "clicked",
726 	                          G_CALLBACK(on_download_move_top), app);
727 	g_signal_connect_swapped (app->window.button_move_bottom, "clicked",
728 	                          G_CALLBACK(on_download_move_bottom), app);
729 	// CategoryMenu
730 	g_signal_connect_swapped (app->window.category_menu.new_category, "activate",
731 	                          G_CALLBACK(on_category_new), app);
732 	g_signal_connect_swapped (app->window.category_menu.erase_category, "activate",
733 	                          G_CALLBACK(on_category_erase), app);
734 	g_signal_connect_swapped (app->window.category_menu.properties, "activate",
735 	                          G_CALLBACK(on_category_property), app);
736 	// DownloadMenu
737 	g_signal_connect_swapped (app->window.download_menu.start, "activate",
738 	                          G_CALLBACK(on_download_start), app);
739 	g_signal_connect_swapped (app->window.download_menu.stop, "activate",
740 	                          G_CALLBACK(on_download_stop), app);
741 	g_signal_connect_swapped (app->window.download_menu.new_download, "activate",
742 	                          G_CALLBACK(on_download_new), app);
743 	g_signal_connect_swapped (app->window.download_menu.add_batch, "activate",
744 	                          G_CALLBACK(on_download_batch), app);
745 	g_signal_connect_swapped (app->window.download_menu.erase, "activate",
746 	                          G_CALLBACK(on_download_erase), app);
747 	g_signal_connect_swapped (app->window.download_menu.properties, "activate",
748 	                          G_CALLBACK(on_download_property), app);
749 	g_signal_connect_swapped (app->window.download_menu.move_to, "activate",
750 	                          G_CALLBACK(on_download_move_to), app);
751 	g_signal_connect_swapped (app->window.download_menu.move_top, "activate",
752 	                          G_CALLBACK(on_download_move_top), app);
753 	g_signal_connect_swapped (app->window.download_menu.move_bottom, "activate",
754 	                          G_CALLBACK(on_download_move_bottom), app);
755 	// Global Menu
756 	g_signal_connect_swapped (app->window.global_menu.start_job, "activate",
757 	                          G_CALLBACK(category_store_thread_activate),
758 	                          &app->category_store);
759 	g_signal_connect_swapped (app->window.global_menu.stop_all, "activate",
760 	                          G_CALLBACK(category_store_thread_stop),
761 	                          &app->category_store);
762 	g_signal_connect_swapped (app->window.global_menu.category_default, "activate",
763 	                          G_CALLBACK(on_set_category_default), app);
764 	g_signal_connect_swapped (app->window.global_menu.setting, "activate",
765 	                          G_CALLBACK(on_set_global_setting), app);
766 
767 	// Help Menu
768 	g_signal_connect_swapped (app->window.help_menu.about_urlgfe, "activate",
769 	                          G_CALLBACK(show_about_dialog), app->window.self);
770 
771 	main_window_selection_changed (&app->window);
772 
773 	// init Drag and Drop
774 	main_app_dnd_init (app);
775 
776 	main_app_apply_setting (app);
777 }
778 
main_app_run(MainApp * app)779 void main_app_run (MainApp* app)
780 {
781 	gtk_widget_show (GTK_WIDGET (app->window.self));
782 }
783 
main_app_on_delete_event(MainApp * app)784 gboolean main_app_on_delete_event (MainApp* app)
785 {
786 	GtkWidget* dialog;
787 	gint       response;
788 
789 	if (category_store_thread_is_active (&app->category_store)) {
790 		dialog = gtk_message_dialog_new (app->window.self,
791 		                                 GTK_DIALOG_DESTROY_WITH_PARENT,
792 		                                 GTK_MESSAGE_WARNING,
793 		                                 GTK_BUTTONS_YES_NO,
794 		             _("There are still downloading. Are you sure to quit?"));
795 		response = gtk_dialog_run (GTK_DIALOG(dialog));
796 		gtk_widget_destroy (dialog);
797 
798 		if (response==GTK_RESPONSE_NO)
799 			return TRUE;
800 	}
801 	category_store_thread_destroy (&app->category_store);
802 	main_app_on_save (app);
803 
804 	return FALSE;
805 }
806 
main_app_apply_setting(MainApp * app)807 void main_app_apply_setting (MainApp* app)
808 {
809 	app->category_store.n_thread_limit = app->setting->n_active_category;
810 	gtk_tree_view_set_headers_visible (app->window.category_view,
811 	                                   app->setting->header_category_visible);
812 
813 	if (app->clipboard_monitoring != app->setting->monitoring_clipboard) {
814 		if (app->clipboard_monitoring == TRUE) {
815 			g_source_remove (app->clipboard_timer_tag);
816 			app->clipboard_timer_tag = 0;
817 		}
818 		else if (app->clipboard_timer_tag==0) {
819 			app->clipboard_timer_tag = g_timeout_add (500,
820 			                           (GSourceFunc)main_app_on_timer, app);
821 		}
822 		app->clipboard_monitoring = app->setting->monitoring_clipboard;
823 	}
824 }
825 
main_app_add_download_from_url(MainApp * app,const gchar * url_text)826 void main_app_add_download_from_url (MainApp* app, const gchar* url_text)
827 {
828 	Category* selected_category = NULL;
829 	Download* download_data;
830 	gboolean  had_selected;
831 
832 	download_data = download_new ();
833 	download_setting_set_url (DOWNLOAD_SETTING (download_data), url_text);
834 
835 	had_selected = main_app_get_download_from_user (app,
836 	                                                DOWNLOAD_SETTING (download_data),
837 	                                                &selected_category,
838 	                                                FALSE);
839 	if (had_selected) {
840 		download_store_add_allocated (&selected_category->waiting_store,
841 		                              download_data);
842 		category_store_thread_activate_1 (&app->category_store,
843 		                                  selected_category);
844 	}
845 	else
846 		download_unref (download_data);
847 }
848 
main_app_get_download_from_user(MainApp * app,DownloadSetting * setting,Category ** selected_category,gboolean multiple)849 gboolean main_app_get_download_from_user (MainApp* app,
850                                           DownloadSetting* setting,
851                                           Category** selected_category,
852                                           gboolean multiple)
853 {
854 	DownloadDialog* dd = download_dialog_new (app->window.self);
855 	Category*  category;
856 	gboolean   had_input = FALSE;
857 
858 
859 	if (selected_category) {
860 		category_tree_view_get_selected (app->window.category_view,
861 		                                 &category, NULL, NULL);
862 		download_dialog_set_category (dd,
863 		                              &app->category_store,
864 		                              category);
865 	}
866 
867 	download_setting_view_set_history (&dd->setting_view,
868 	                                   app->setting->directory_list);
869 	download_dialog_import_setting (dd, setting);
870 	download_dialog_set_multiple (dd, multiple);
871 
872 	if (download_dialog_run (dd)==GTK_RESPONSE_OK) {
873 		download_dialog_export_setting (dd, setting);
874 		global_setting_add_directory (app->setting, setting->directory);
875 		had_input = TRUE;
876 
877 		if (selected_category)
878 			*selected_category = dd->selected_category;
879 	}
880 
881 	download_dialog_destroy (dd);
882 
883 	return had_input;
884 }
885 
main_app_move_selected_download(MainApp * app,DownloadListView * dlv_src,DownloadListView * dlv_dest)886 void main_app_move_selected_download (MainApp* app,
887                                       DownloadListView* dlv_src,
888                                       DownloadListView* dlv_dest)
889 {
890 	guint n_iter, index;
891 	GtkTreeIter* iter_array;
892 	GtkTreeSelection* selection;
893 	DownloadStore* ds_src  = dlv_src->store;
894 	DownloadStore* ds_dest = dlv_dest->store;
895 
896 	selection = gtk_tree_view_get_selection (dlv_src->self);
897 
898 	download_store_lock (ds_src);
899 
900 	n_iter = tree_selection_get_selected_iters (selection, &iter_array);
901 
902 	for (index=0; index < n_iter; index++) {
903 		download_store_move_to_store (ds_src,
904 		                              ds_dest,
905 		                              iter_array+index);
906 	}
907 	g_free (iter_array);
908 
909 	download_store_unlock (ds_src);
910 
911 	// update CategoryTree
912 	gtk_widget_queue_draw (GTK_WIDGET (app->window.category_view));
913 
914 	category_store_thread_activate (&app->category_store);
915 }
916 
main_app_connect_category_signal(MainApp * app,Category * category)917 void main_app_connect_category_signal (MainApp* app,
918                                        Category* category)
919 {
920 	main_window_connect_download_view (&app->window,
921 	                                   &category->waiting_view);
922 	main_window_connect_download_view (&app->window,
923 	                                   &category->completed_view);
924 	main_window_connect_download_view (&app->window,
925 	                                   &category->recycled_view);
926 	g_signal_connect_swapped (category->waiting_view.self, "key-press-event",
927 	                          G_CALLBACK (on_key_press_event), app);
928 	g_signal_connect_swapped (category->completed_view.self, "key-press-event",
929 	                          G_CALLBACK (on_key_press_event), app);
930 	g_signal_connect_swapped (category->recycled_view.self, "key-press-event",
931 	                          G_CALLBACK (on_key_press_event), app);
932 }
933 
934 
935