1 /*
2  *
3  *   Copyright (C) 2012-2018 by C.H. Huang
4  *   plushuang.tw@gmail.com
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2.1 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  *  ---
21  *
22  *  In addition, as a special exception, the copyright holders give
23  *  permission to link the code of portions of this program with the
24  *  OpenSSL library under certain conditions as described in each
25  *  individual source file, and distribute linked combinations
26  *  including the two.
27  *  You must obey the GNU Lesser General Public License in all respects
28  *  for all of the code used other than OpenSSL.  If you modify
29  *  file(s) with this exception, you may extend this exception to your
30  *  version of the file(s), but you are not obligated to do so.  If you
31  *  do not wish to do so, delete this exception statement from your
32  *  version.  If you delete this exception statement from all source
33  *  files in the program, then also delete it here.
34  *
35  */
36 
37 #include <UgUtil.h>
38 #include <UgStdio.h>
39 #include <UgString.h>
40 #include <UgFileUtil.h>
41 #include <UgHtmlFilter.h>
42 #include <UgetPluginCurl.h>
43 #include <UgetPluginAria2.h>
44 #include <UgetPluginMedia.h>
45 #include <UgetPluginMega.h>
46 #include <UgtkApp.h>
47 #include <UgtkUtil.h>
48 #include <UgtkNodeDialog.h>
49 #include <UgtkBatchDialog.h>
50 #include <UgtkConfirmDialog.h>
51 
52 #include <glib/gi18n.h>
53 
ugtk_app_init(UgtkApp * app,UgetRpc * rpc)54 void  ugtk_app_init (UgtkApp* app, UgetRpc* rpc)
55 {
56 	char*  dir;
57 
58 	app->rpc = rpc;
59 	uget_app_init ((UgetApp*) app);
60 	// set application config directory for each user
61 	dir = g_build_filename (ugtk_get_config_dir (), UGTK_APP_DIR, NULL);
62 	uget_app_set_config_dir ((UgetApp*) app, dir);
63 	g_free (dir);
64 
65 	app->rss_builtin = uget_rss_new ();
66 	ugtk_app_load (app);
67 	ugtk_app_init_ui (app);
68 	ugtk_app_init_callback (app);
69 	if (app->real.n_children == 0)
70 		ugtk_app_add_default_category (app);
71 	// clipboard
72 	ugtk_clipboard_init (&app->clipboard, app->setting.clipboard.pattern);
73 	// plug-in initialize
74 	uget_plugin_global_set(UgetPluginCurlInfo,  UGET_PLUGIN_GLOBAL_INIT, (void*) TRUE);
75 	uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_GLOBAL_INIT, (void*) TRUE);
76 	uget_plugin_global_set(UgetPluginMediaInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) TRUE);
77 	uget_plugin_global_set(UgetPluginMegaInfo,  UGET_PLUGIN_GLOBAL_INIT, (void*) TRUE);
78 	// apply UgtkSetting
79 	ugtk_app_set_plugin_setting (app, &app->setting);
80 	ugtk_app_set_window_setting (app, &app->setting);
81 	ugtk_app_set_column_setting (app, &app->setting);
82 	ugtk_app_set_other_setting (app, &app->setting);
83 	ugtk_app_set_ui_setting (app, &app->setting);
84 
85 	ugtk_tray_icon_set_info (&app->trayicon, 0, 0, 0);
86 	ugtk_statusbar_set_speed (&app->statusbar, 0, 0);
87 	ugtk_menubar_sync_category (&app->menubar, app, TRUE);
88 
89 	app->recent.category_index = 0;
90 	app->recent.data = ug_data_new(8, 0);
91 	// RSS
92 	uget_rss_add_builtin (app->rss_builtin, UGET_RSS_STABLE);
93 	uget_rss_add_builtin (app->rss_builtin, UGET_RSS_NEWS);
94 	uget_rss_add_builtin (app->rss_builtin, UGET_RSS_TUTORIALS);
95 	uget_rss_update (app->rss_builtin, FALSE);
96 	gtk_widget_hide (app->banner.self);
97 
98 	uget_app_use_uri_hash ((UgetApp*) app);
99 	ugtk_app_init_timeout (app);
100 
101 	if (app->setting.ui.start_in_tray)
102 		ugtk_tray_icon_set_visible (&app->trayicon, TRUE);
103 	else
104 		gtk_widget_show ((GtkWidget*) app->window.self);
105 	// offline
106 	if (app->setting.ui.start_in_offline_mode)
107 		g_signal_emit_by_name (app->menubar.file.offline_mode, "activate");
108 }
109 
ugtk_app_final(UgtkApp * app)110 void  ugtk_app_final (UgtkApp* app)
111 {
112 	int  shutdown_now;
113 
114 	uget_app_set_notification ((UgetApp*) app, NULL, NULL, NULL, NULL);
115 
116 	if (app->setting.plugin_order >= UGTK_PLUGIN_ORDER_ARIA2)
117 		shutdown_now = app->setting.aria2.shutdown;
118 	else
119 		shutdown_now = FALSE;
120 	ug_data_unref(app->recent.data);
121 	uget_rss_unref (app->rss_builtin);
122 	uget_app_final ((UgetApp*) app);
123 	// plug-in finalize
124 	uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_ARIA2_GLOBAL_SHUTDOWN_NOW,
125 			(void*)(intptr_t) shutdown_now);
126 	uget_plugin_global_set(UgetPluginCurlInfo,  UGET_PLUGIN_GLOBAL_INIT, (void*) FALSE);
127 	uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_GLOBAL_INIT, (void*) FALSE);
128 	uget_plugin_global_set(UgetPluginMediaInfo, UGET_PLUGIN_GLOBAL_INIT, (void*) FALSE);
129 	uget_plugin_global_set(UgetPluginMegaInfo,  UGET_PLUGIN_GLOBAL_INIT, (void*) FALSE);
130 }
131 
ugtk_app_save(UgtkApp * app)132 void  ugtk_app_save (UgtkApp* app)
133 {
134 	gchar*    file;
135 
136 	if (app->config_dir == NULL)
137 		return;
138 	ug_create_dir_all (app->config_dir, -1);
139 	file = g_build_filename (app->config_dir, "Setting.json", NULL);
140 	ugtk_setting_save (&app->setting, file);
141 	g_free (file);
142 
143 	// RSS
144 	file = g_build_filename (app->config_dir, "RSS-built-in.json", NULL);
145 	uget_rss_save_feeds (app->rss_builtin, file);
146 	g_free (file);
147 
148 //	uget_app_save_categories ((UgetApp*) app, ugtk_get_config_dir ());
149 	uget_app_save_categories ((UgetApp*) app, NULL);
150 }
151 
ugtk_app_load(UgtkApp * app)152 void  ugtk_app_load (UgtkApp* app)
153 {
154 	int       counts;
155 	gchar*    file;
156 
157 	// load setting
158 	ugtk_setting_init (&app->setting);
159 	file = g_build_filename (app->config_dir, "Setting.json", NULL);
160 	counts = ugtk_setting_load (&app->setting, file);
161 	g_free (file);
162 	if (counts == FALSE)
163 		ugtk_setting_reset (&app->setting);
164 	else if (app->setting.scheduler.state.length < 7*24) {
165 		ug_array_alloc (&app->setting.scheduler.state,
166 		                7*24 - app->setting.scheduler.state.length);
167 	}
168 
169 	// RSS
170 	file = g_build_filename (app->config_dir, "RSS-built-in.json", NULL);
171 	uget_rss_load_feeds (app->rss_builtin, file);
172 	g_free (file);
173 
174 //	uget_app_load_categories ((UgetApp*) app, ugtk_get_config_dir ());
175 	counts = uget_app_load_categories ((UgetApp*) app, NULL);
176 	if (counts == 0)
177 		ugtk_app_add_default_category (app);
178 }
179 
ugtk_app_quit(UgtkApp * app)180 void  ugtk_app_quit (UgtkApp* app)
181 {
182 	// stop all tasks
183 	uget_task_remove_all (&app->task);
184 	// sync setting and save data
185 	ugtk_app_get_window_setting (app, &app->setting);
186 	ugtk_app_get_column_setting (app, &app->setting);
187 	ugtk_app_save (app);
188 	// clear plug-in
189 	uget_app_clear_plugins ((UgetApp*) app);
190 	// hide icon in system tray before quit
191 	ugtk_tray_icon_set_visible (&app->trayicon, FALSE);
192 	// hide window
193 	gtk_widget_hide (GTK_WIDGET (app->window.self));
194 
195 	gtk_main_quit ();
196 }
197 
ugtk_app_get_window_setting(UgtkApp * app,UgtkSetting * setting)198 void  ugtk_app_get_window_setting (UgtkApp* app, UgtkSetting* setting)
199 {
200 	GdkWindowState  gdk_wstate;
201 	GdkWindow*      gdk_window;
202 	gint            x, y;
203 
204 	// get window position, size, and maximized state
205 	if (gtk_widget_get_visible (GTK_WIDGET (app->window.self)) == TRUE) {
206 		gdk_window = gtk_widget_get_window (GTK_WIDGET (app->window.self));
207 		gdk_wstate = gdk_window_get_state (gdk_window);
208 
209 		if (gdk_wstate & GDK_WINDOW_STATE_MAXIMIZED)
210 			setting->window.maximized = TRUE;
211 		else
212 			setting->window.maximized = FALSE;
213 		// get geometry
214 		if (setting->window.maximized == FALSE) {
215 			gtk_window_get_position (app->window.self, &x, &y);
216 			gtk_window_get_size (app->window.self,
217 					&setting->window.width, &setting->window.height);
218 			// gtk_window_get_position() may return: x == -32000, y == -32000
219 			if (x + app->setting.window.width > 0)
220 				setting->window.x = x;
221 			if (y + app->setting.window.height > 0)
222 				setting->window.y = y;
223 		}
224 	}
225 	// GtkPaned position
226 	if (app->setting.window.category)
227 		setting->window.paned_position_h = gtk_paned_get_position (app->window.hpaned);
228 	if (app->setting.window.summary)
229 		setting->window.paned_position_v = gtk_paned_get_position (app->window.vpaned);
230 
231 	// banner
232 	setting->window.banner = gtk_widget_get_visible (app->banner.self);
233 	// traveler
234 	setting->window.nth_category = app->traveler.category.cursor.pos;
235 	setting->window.nth_state    = app->traveler.state.cursor.pos;
236 }
237 
ugtk_app_set_window_setting(UgtkApp * app,UgtkSetting * setting)238 void  ugtk_app_set_window_setting (UgtkApp* app, UgtkSetting* setting)
239 {
240 	// set window position, size, and maximized state
241 	if (setting->window.width  > 0 &&
242 	    setting->window.height > 0 &&
243 	    setting->window.x < gdk_screen_width ()  &&
244 	    setting->window.y < gdk_screen_height () &&
245 	    setting->window.x + setting->window.width > 0  &&
246 	    setting->window.y + setting->window.height > 0)
247 	{
248 		gtk_window_move (app->window.self,
249 				setting->window.x, setting->window.y);
250 		gtk_window_resize (app->window.self,
251 				setting->window.width, setting->window.height);
252 	}
253 	if (setting->window.maximized)
254 		gtk_window_maximize (app->window.self);
255 	// GtkPaned position
256 	if (setting->window.paned_position_h > 0) {
257 		gtk_paned_set_position (app->window.hpaned,
258 		                        setting->window.paned_position_h);
259 	}
260 	if (setting->window.paned_position_v > 0) {
261 		if (setting->window.paned_position_v > 100) // for uGet < 2.0.4
262 		gtk_paned_set_position (app->window.vpaned,
263 		                        setting->window.paned_position_v);
264 	}
265 	// set visible widgets
266 	gtk_widget_set_visible (app->toolbar.self,
267 			setting->window.toolbar);
268 	gtk_widget_set_visible ((GtkWidget*) app->statusbar.self,
269 			setting->window.statusbar);
270 	gtk_widget_set_visible (gtk_paned_get_child1 (app->window.hpaned),
271 			setting->window.category);
272 	gtk_widget_set_visible (app->summary.self,
273 			setting->window.summary);
274 	gtk_widget_set_visible (app->banner.self,
275 			setting->window.banner);
276 	// Summary
277 	app->summary.visible.name     = setting->summary.name;
278 	app->summary.visible.folder   = setting->summary.folder;
279 	app->summary.visible.category = setting->summary.category;
280 	app->summary.visible.uri      = setting->summary.uri;
281 	app->summary.visible.message  = setting->summary.message;
282 
283 	// traveler
284 	if (setting->window.nth_category >= app->real.n_children)
285 		setting->window.nth_category = 0;
286 	if (setting->window.nth_state >= app->split.n_children)
287 		setting->window.nth_state = 0;
288 	ugtk_traveler_select_category (&app->traveler,
289 	                               setting->window.nth_category,
290 	                               setting->window.nth_state);
291 	// menu
292 	ugtk_app_set_menu_setting (app, setting);
293 }
294 
ugtk_app_get_column_setting(UgtkApp * app,UgtkSetting * setting)295 void  ugtk_app_get_column_setting (UgtkApp* app, UgtkSetting* setting)
296 {
297 	GtkTreeViewColumn* column;
298 	int                width;
299 
300 	// state
301 	column = gtk_tree_view_get_column (app->traveler.download.view,
302 			UGTK_NODE_COLUMN_STATE);
303 	width = gtk_tree_view_column_get_width (column);
304 	setting->download_column.width.state = width;
305 	// name
306 	column = gtk_tree_view_get_column (app->traveler.download.view,
307 			UGTK_NODE_COLUMN_NAME);
308 	width = gtk_tree_view_column_get_width (column);
309 	setting->download_column.width.name = width;
310 	// complete
311 	column = gtk_tree_view_get_column (app->traveler.download.view,
312 			UGTK_NODE_COLUMN_COMPLETE);
313 	width = gtk_tree_view_column_get_width (column);
314 	setting->download_column.width.complete = width;
315 	// total
316 	column = gtk_tree_view_get_column (app->traveler.download.view,
317 			UGTK_NODE_COLUMN_TOTAL);
318 	width = gtk_tree_view_column_get_width (column);
319 	setting->download_column.width.total = width;
320 	// percent
321 	column = gtk_tree_view_get_column (app->traveler.download.view,
322 			UGTK_NODE_COLUMN_PERCENT);
323 	width = gtk_tree_view_column_get_width (column);
324 	setting->download_column.width.percent = width;
325 	// elapsed
326 	column = gtk_tree_view_get_column (app->traveler.download.view,
327 			UGTK_NODE_COLUMN_ELAPSED);
328 	width = gtk_tree_view_column_get_width (column);
329 	setting->download_column.width.elapsed = width;
330 	// left
331 	column = gtk_tree_view_get_column (app->traveler.download.view,
332 			UGTK_NODE_COLUMN_LEFT);
333 	width = gtk_tree_view_column_get_width (column);
334 	setting->download_column.width.left = width;
335 	// speed
336 	column = gtk_tree_view_get_column (app->traveler.download.view,
337 			UGTK_NODE_COLUMN_SPEED);
338 	width = gtk_tree_view_column_get_width (column);
339 	setting->download_column.width.speed = width;
340 	// upload_speed
341 	column = gtk_tree_view_get_column (app->traveler.download.view,
342 			UGTK_NODE_COLUMN_UPLOAD_SPEED);
343 	width = gtk_tree_view_column_get_width (column);
344 	setting->download_column.width.upload_speed = width;
345 	// uploaded
346 	column = gtk_tree_view_get_column (app->traveler.download.view,
347 			UGTK_NODE_COLUMN_UPLOADED);
348 	width = gtk_tree_view_column_get_width (column);
349 	setting->download_column.width.uploaded = width;
350 	// ratio
351 	column = gtk_tree_view_get_column (app->traveler.download.view,
352 			UGTK_NODE_COLUMN_RATIO);
353 	width = gtk_tree_view_column_get_width (column);
354 	setting->download_column.width.ratio = width;
355 	// retry
356 	column = gtk_tree_view_get_column (app->traveler.download.view,
357 			UGTK_NODE_COLUMN_RETRY);
358 	width = gtk_tree_view_column_get_width (column);
359 	setting->download_column.width.retry = width;
360 	// category
361 	column = gtk_tree_view_get_column (app->traveler.download.view,
362 			UGTK_NODE_COLUMN_CATEGORY);
363 	width = gtk_tree_view_column_get_width (column);
364 	setting->download_column.width.category = width;
365 	// uri
366 	column = gtk_tree_view_get_column (app->traveler.download.view,
367 			UGTK_NODE_COLUMN_URI);
368 	width = gtk_tree_view_column_get_width (column);
369 	setting->download_column.width.uri = width;
370 	// added_on
371 	column = gtk_tree_view_get_column (app->traveler.download.view,
372 			UGTK_NODE_COLUMN_ADDED_ON);
373 	width = gtk_tree_view_column_get_width (column);
374 	setting->download_column.width.added_on = width;
375 	// completed_on
376 	column = gtk_tree_view_get_column (app->traveler.download.view,
377 			UGTK_NODE_COLUMN_COMPLETED_ON);
378 	width = gtk_tree_view_column_get_width (column);
379 	setting->download_column.width.completed_on = width;
380 }
381 
ugtk_app_set_column_setting(UgtkApp * app,UgtkSetting * setting)382 void  ugtk_app_set_column_setting (UgtkApp* app, UgtkSetting* setting)
383 {
384 	GtkTreeViewColumn* column;
385 	int                width;
386 
387 	// state
388 	column = gtk_tree_view_get_column (app->traveler.download.view,
389 			UGTK_NODE_COLUMN_STATE);
390 	width = setting->download_column.width.state;
391 	if (width > 0)
392 		gtk_tree_view_column_set_fixed_width (column, width);
393 	// name
394 	column = gtk_tree_view_get_column (app->traveler.download.view,
395 			UGTK_NODE_COLUMN_NAME);
396 	width = setting->download_column.width.name;
397 	if (width > 0)
398 		gtk_tree_view_column_set_fixed_width (column, width);
399 	// complete
400 	column = gtk_tree_view_get_column (app->traveler.download.view,
401 			UGTK_NODE_COLUMN_COMPLETE);
402 	width = setting->download_column.width.complete;
403 	if (width > 0)
404 		gtk_tree_view_column_set_fixed_width (column, width);
405 	// total
406 	column = gtk_tree_view_get_column (app->traveler.download.view,
407 			UGTK_NODE_COLUMN_TOTAL);
408 	width = setting->download_column.width.total;
409 	if (width > 0)
410 		gtk_tree_view_column_set_fixed_width (column, width);
411 	// percent
412 	column = gtk_tree_view_get_column (app->traveler.download.view,
413 			UGTK_NODE_COLUMN_PERCENT);
414 	width = setting->download_column.width.percent;
415 	if (width > 0)
416 		gtk_tree_view_column_set_fixed_width (column, width);
417 	// elapsed
418 	column = gtk_tree_view_get_column (app->traveler.download.view,
419 			UGTK_NODE_COLUMN_ELAPSED);
420 	width = setting->download_column.width.elapsed;
421 	if (width > 0)
422 		gtk_tree_view_column_set_fixed_width (column, width);
423 	// left
424 	column = gtk_tree_view_get_column (app->traveler.download.view,
425 			UGTK_NODE_COLUMN_LEFT);
426 	width = setting->download_column.width.left;
427 	if (width > 0)
428 		gtk_tree_view_column_set_fixed_width (column, width);
429 	// speed
430 	column = gtk_tree_view_get_column (app->traveler.download.view,
431 			UGTK_NODE_COLUMN_SPEED);
432 	width = setting->download_column.width.speed;
433 	if (width > 0)
434 		gtk_tree_view_column_set_fixed_width (column, width);
435 	// upload_speed
436 	column = gtk_tree_view_get_column (app->traveler.download.view,
437 			UGTK_NODE_COLUMN_UPLOAD_SPEED);
438 	width = setting->download_column.width.upload_speed;
439 	if (width > 0)
440 		gtk_tree_view_column_set_fixed_width (column, width);
441 	// uploaded
442 	column = gtk_tree_view_get_column (app->traveler.download.view,
443 			UGTK_NODE_COLUMN_UPLOADED);
444 	width = setting->download_column.width.uploaded;
445 	if (width > 0)
446 		gtk_tree_view_column_set_fixed_width (column, width);
447 	// ratio
448 	column = gtk_tree_view_get_column (app->traveler.download.view,
449 			UGTK_NODE_COLUMN_RATIO);
450 	width = setting->download_column.width.ratio;
451 	if (width > 0)
452 		gtk_tree_view_column_set_fixed_width (column, width);
453 	// retry
454 	column = gtk_tree_view_get_column (app->traveler.download.view,
455 			UGTK_NODE_COLUMN_RETRY);
456 	width = setting->download_column.width.retry;
457 	if (width > 0)
458 		gtk_tree_view_column_set_fixed_width (column, width);
459 	// category
460 	column = gtk_tree_view_get_column (app->traveler.download.view,
461 			UGTK_NODE_COLUMN_CATEGORY);
462 	width = setting->download_column.width.category;
463 	if (width > 0)
464 		gtk_tree_view_column_set_fixed_width (column, width);
465 	// uri
466 	column = gtk_tree_view_get_column (app->traveler.download.view,
467 			UGTK_NODE_COLUMN_URI);
468 	width = setting->download_column.width.uri;
469 	if (width > 0)
470 		gtk_tree_view_column_set_fixed_width (column, width);
471 	// added_on
472 	column = gtk_tree_view_get_column (app->traveler.download.view,
473 			UGTK_NODE_COLUMN_ADDED_ON);
474 	width = setting->download_column.width.added_on;
475 	if (width > 0)
476 		gtk_tree_view_column_set_fixed_width (column, width);
477 	// completed_on
478 	column = gtk_tree_view_get_column (app->traveler.download.view,
479 			UGTK_NODE_COLUMN_COMPLETED_ON);
480 	width = setting->download_column.width.completed_on;
481 	if (width > 0)
482 		gtk_tree_view_column_set_fixed_width (column, width);
483 }
484 
ugtk_app_set_plugin_setting(UgtkApp * app,UgtkSetting * setting)485 void  ugtk_app_set_plugin_setting (UgtkApp* app, UgtkSetting* setting)
486 {
487 	const UgetPluginInfo*  default_plugin;
488 	int  limit[2];
489 	int  sensitive = FALSE;
490 
491 	switch (setting->plugin_order) {
492 	default:
493 	case UGTK_PLUGIN_ORDER_CURL:
494 		uget_app_remove_plugin ((UgetApp*) app, UgetPluginAria2Info);
495 		default_plugin = UgetPluginCurlInfo;
496 		sensitive = FALSE;
497 		break;
498 
499 	case UGTK_PLUGIN_ORDER_ARIA2:
500 		uget_app_remove_plugin ((UgetApp*) app, UgetPluginCurlInfo);
501 		default_plugin = UgetPluginAria2Info;
502 		sensitive = TRUE;
503 		break;
504 
505 	case UGTK_PLUGIN_ORDER_CURL_ARIA2:
506 		uget_app_add_plugin ((UgetApp*) app, UgetPluginAria2Info);
507 		default_plugin = UgetPluginCurlInfo;
508 		sensitive = TRUE;
509 		break;
510 
511 	case UGTK_PLUGIN_ORDER_ARIA2_CURL:
512 		uget_app_add_plugin ((UgetApp*) app, UgetPluginCurlInfo);
513 		default_plugin = UgetPluginAria2Info;
514 		sensitive = TRUE;
515 		break;
516 	}
517 
518 	// set default plug-in
519 	uget_app_set_default_plugin ((UgetApp*) app, default_plugin);
520 	// set agent plug-in (used by media and MEGA plug-in)
521 	uget_plugin_agent_global_set(UGET_PLUGIN_AGENT_GLOBAL_PLUGIN,
522 	                 (void*) default_plugin);
523 	// set media plug-in
524 	uget_app_add_plugin ((UgetApp*) app, UgetPluginMediaInfo);
525 	uget_plugin_global_set(UgetPluginMediaInfo, UGET_PLUGIN_MEDIA_GLOBAL_MATCH_MODE,
526 	                 (void*)(intptr_t) setting->media.match_mode);
527 	uget_plugin_global_set(UgetPluginMediaInfo, UGET_PLUGIN_MEDIA_GLOBAL_QUALITY,
528 	                 (void*)(intptr_t) setting->media.quality);
529 	uget_plugin_global_set(UgetPluginMediaInfo, UGET_PLUGIN_MEDIA_GLOBAL_TYPE,
530 	                 (void*)(intptr_t) setting->media.type);
531 	// set MEGA plug-in
532 	uget_app_add_plugin ((UgetApp*) app, UgetPluginMegaInfo);
533 	// set aria2 plug-in
534 	if (setting->plugin_order >= UGTK_PLUGIN_ORDER_ARIA2) {
535 		uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_ARIA2_GLOBAL_URI,
536 		                 setting->aria2.uri);
537 		uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_ARIA2_GLOBAL_PATH,
538 		                 setting->aria2.path);
539 		uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_ARIA2_GLOBAL_ARGUMENT,
540 		                 setting->aria2.args);
541 		uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_ARIA2_GLOBAL_TOKEN,
542 		                 setting->aria2.token);
543 		uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_ARIA2_GLOBAL_LAUNCH,
544 		                 (void*)(intptr_t) setting->aria2.launch);
545 		uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_ARIA2_GLOBAL_SHUTDOWN,
546 		                 (void*)(intptr_t) setting->aria2.shutdown);
547 		limit[0] = setting->aria2.limit.download * 1024;
548 		limit[1] = setting->aria2.limit.upload * 1024;
549 		uget_plugin_global_set(UgetPluginAria2Info, UGET_PLUGIN_GLOBAL_SPEED_LIMIT, limit);
550 	}
551 
552 //	app->aria2.remote_updated = FALSE;
553 	gtk_widget_set_sensitive ((GtkWidget*) app->trayicon.menu.create_torrent, sensitive);
554 	gtk_widget_set_sensitive ((GtkWidget*) app->trayicon.menu.create_metalink, sensitive);
555 	gtk_widget_set_sensitive ((GtkWidget*) app->menubar.file.create_torrent, sensitive);
556 	gtk_widget_set_sensitive ((GtkWidget*) app->menubar.file.create_metalink, sensitive);
557 	gtk_widget_set_sensitive ((GtkWidget*) app->toolbar.create_torrent, sensitive);
558 	gtk_widget_set_sensitive ((GtkWidget*) app->toolbar.create_metalink, sensitive);
559 }
560 
ugtk_app_set_other_setting(UgtkApp * app,UgtkSetting * setting)561 void  ugtk_app_set_other_setting (UgtkApp* app, UgtkSetting* setting)
562 {
563 	// clipboard & commandline
564 	ugtk_clipboard_set_pattern (&app->clipboard, setting->clipboard.pattern);
565 	app->clipboard.website = app->setting.clipboard.website;
566 	// global speed limit
567 	uget_task_set_speed (&app->task,
568 			setting->bandwidth.normal.download * 1024,
569 			setting->bandwidth.normal.upload   * 1024);
570 }
571 
ugtk_app_set_menu_setting(UgtkApp * app,UgtkSetting * setting)572 void  ugtk_app_set_menu_setting (UgtkApp* app, UgtkSetting* setting)
573 {
574 	// ----------------------------------------------------
575 	// UgtkEditMenu
576 	gtk_check_menu_item_set_active (
577 			(GtkCheckMenuItem*) app->menubar.edit.clipboard_monitor,
578 			setting->clipboard.monitor);
579 	gtk_check_menu_item_set_active (
580 			(GtkCheckMenuItem*) app->menubar.edit.clipboard_quiet,
581 			setting->clipboard.quiet);
582 	gtk_check_menu_item_set_active (
583 			(GtkCheckMenuItem*) app->menubar.edit.commandline_quiet,
584 			setting->commandline.quiet);
585 	gtk_check_menu_item_set_active (
586 			(GtkCheckMenuItem*) app->menubar.edit.skip_existing,
587 			setting->ui.skip_existing);
588 	gtk_check_menu_item_set_active (
589 			(GtkCheckMenuItem*) app->menubar.edit.apply_recent,
590 			setting->ui.apply_recent);
591 
592 	switch (app->setting.completion.action) {
593 	default:
594 	case 0:
595 		gtk_check_menu_item_set_active (
596 				(GtkCheckMenuItem*)app->menubar.edit.completion.disable, TRUE);
597 		break;
598 
599 	case 1:
600 		gtk_check_menu_item_set_active (
601 				(GtkCheckMenuItem*)app->menubar.edit.completion.hibernate, TRUE);
602 		break;
603 
604 	case 2:
605 		gtk_check_menu_item_set_active (
606 				(GtkCheckMenuItem*)app->menubar.edit.completion.suspend, TRUE);
607 		break;
608 
609 	case 3:
610 		gtk_check_menu_item_set_active (
611 				(GtkCheckMenuItem*)app->menubar.edit.completion.shutdown, TRUE);
612 		break;
613 
614 	case 4:
615 		gtk_check_menu_item_set_active (
616 				(GtkCheckMenuItem*)app->menubar.edit.completion.reboot, TRUE);
617 		break;
618 
619 	case 5:
620 		gtk_check_menu_item_set_active (
621 				(GtkCheckMenuItem*)app->menubar.edit.completion.custom, TRUE);
622 		break;
623 	}
624 	gtk_check_menu_item_set_active (
625 			(GtkCheckMenuItem*) app->menubar.edit.completion.remember,
626 			setting->completion.remember);
627 	// ----------------------------------------------------
628 	// UgtkViewMenu
629 	gtk_check_menu_item_set_active (
630 			(GtkCheckMenuItem*) app->menubar.view.toolbar,
631 			setting->window.toolbar);
632 	gtk_check_menu_item_set_active (
633 			(GtkCheckMenuItem*) app->menubar.view.statusbar,
634 			setting->window.statusbar);
635 	gtk_check_menu_item_set_active (
636 			(GtkCheckMenuItem*) app->menubar.view.category,
637 			setting->window.category);
638 	gtk_check_menu_item_set_active (
639 			(GtkCheckMenuItem*) app->menubar.view.summary,
640 			setting->window.summary);
641 	// summary items
642 	gtk_check_menu_item_set_active (
643 			(GtkCheckMenuItem*) app->menubar.view.summary_items.name,
644 			setting->summary.name);
645 	gtk_check_menu_item_set_active (
646 			(GtkCheckMenuItem*) app->menubar.view.summary_items.folder,
647 			setting->summary.folder);
648 	gtk_check_menu_item_set_active (
649 			(GtkCheckMenuItem*) app->menubar.view.summary_items.category,
650 			setting->summary.category);
651 	gtk_check_menu_item_set_active (
652 			(GtkCheckMenuItem*) app->menubar.view.summary_items.uri,
653 			setting->summary.uri);
654 	gtk_check_menu_item_set_active (
655 			(GtkCheckMenuItem*) app->menubar.view.summary_items.message,
656 			setting->summary.message);
657 	// download column
658 	gtk_check_menu_item_set_active (
659 			(GtkCheckMenuItem*) app->menubar.view.columns.complete,
660 			setting->download_column.complete);
661 	gtk_check_menu_item_set_active (
662 			(GtkCheckMenuItem*) app->menubar.view.columns.total,
663 			setting->download_column.total);
664 	gtk_check_menu_item_set_active (
665 			(GtkCheckMenuItem*) app->menubar.view.columns.percent,
666 			setting->download_column.percent);
667 	gtk_check_menu_item_set_active (
668 			(GtkCheckMenuItem*) app->menubar.view.columns.elapsed,
669 			setting->download_column.elapsed);
670 	gtk_check_menu_item_set_active (
671 			(GtkCheckMenuItem*) app->menubar.view.columns.left,
672 			setting->download_column.left);
673 	gtk_check_menu_item_set_active (
674 			(GtkCheckMenuItem*) app->menubar.view.columns.speed,
675 			setting->download_column.speed);
676 	gtk_check_menu_item_set_active (
677 			(GtkCheckMenuItem*) app->menubar.view.columns.upload_speed,
678 			setting->download_column.upload_speed);
679 	gtk_check_menu_item_set_active (
680 			(GtkCheckMenuItem*) app->menubar.view.columns.uploaded,
681 			setting->download_column.uploaded);
682 	gtk_check_menu_item_set_active (
683 			(GtkCheckMenuItem*) app->menubar.view.columns.ratio,
684 			setting->download_column.ratio);
685 	gtk_check_menu_item_set_active (
686 			(GtkCheckMenuItem*) app->menubar.view.columns.retry,
687 			setting->download_column.retry);
688 	gtk_check_menu_item_set_active (
689 			(GtkCheckMenuItem*) app->menubar.view.columns.category,
690 			setting->download_column.category);
691 	gtk_check_menu_item_set_active (
692 			(GtkCheckMenuItem*) app->menubar.view.columns.uri,
693 			setting->download_column.uri);
694 	gtk_check_menu_item_set_active (
695 			(GtkCheckMenuItem*) app->menubar.view.columns.added_on,
696 			setting->download_column.added_on);
697 	gtk_check_menu_item_set_active (
698 			(GtkCheckMenuItem*) app->menubar.view.columns.completed_on,
699 			setting->download_column.completed_on);
700 }
701 
ugtk_app_set_ui_setting(UgtkApp * app,UgtkSetting * setting)702 void  ugtk_app_set_ui_setting (UgtkApp* app, UgtkSetting* setting)
703 {
704 	GtkIconSize   icon_size;
705 
706 #ifdef HAVE_APP_INDICATOR
707 	// AppIndicator
708 	ugtk_tray_icon_use_indicator (&app->trayicon, setting->ui.app_indicator);
709 #endif
710 
711 	ugtk_tray_icon_set_visible (&app->trayicon, setting->ui.show_trayicon);
712 
713 	// ----------------------------------------------------
714 	// large icon
715 	if (setting->ui.large_icon)
716 		icon_size = GTK_ICON_SIZE_LARGE_TOOLBAR;
717 	else
718 		icon_size = GTK_ICON_SIZE_SMALL_TOOLBAR;
719 	// toolbar
720 	gtk_toolbar_set_icon_size ((GtkToolbar*) app->toolbar.self, icon_size);
721 	// state list
722 	ugtk_node_view_use_large_icon (app->traveler.state.view,
723 	                               setting->ui.large_icon,
724 	                               setting->download_column.width.state);
725 	// category list
726 	ugtk_node_view_use_large_icon (app->traveler.category.view,
727 	                               setting->ui.large_icon,
728 	                               setting->download_column.width.state);
729 	// download list
730 	ugtk_node_view_use_large_icon (app->traveler.download.view,
731 	                               setting->ui.large_icon,
732 	                               setting->download_column.width.state);
733 	// summary
734 	ugtk_node_view_use_large_icon (app->summary.view,
735 	                               setting->ui.large_icon,
736 	                               setting->download_column.width.state);
737 }
738 
739 // decide sensitive for menu, toolbar
ugtk_app_decide_download_sensitive(UgtkApp * app)740 void  ugtk_app_decide_download_sensitive (UgtkApp* app)
741 {
742 	GtkTreeSelection*  selection;
743 	gboolean           sensitive;
744 	static gboolean    sensitive_last = TRUE;
745 	gint               n_selected;
746 
747 	selection = gtk_tree_view_get_selection (app->traveler.download.view);
748 	n_selected = gtk_tree_selection_count_selected_rows (selection);
749 	if (n_selected > 0)
750 		sensitive = TRUE;
751 	else
752 		sensitive = FALSE;
753 
754 	// change sensitive after select/unselect
755 	if (sensitive_last != sensitive) {
756 		sensitive_last  = sensitive;
757 		gtk_widget_set_sensitive (app->toolbar.runnable, sensitive);
758 		gtk_widget_set_sensitive (app->toolbar.pause, sensitive);
759 		gtk_widget_set_sensitive (app->toolbar.properties, sensitive);
760 		gtk_widget_set_sensitive (app->menubar.download.open, sensitive);
761 		gtk_widget_set_sensitive (app->menubar.download.open_folder, sensitive);
762 		gtk_widget_set_sensitive (app->menubar.download.delete, sensitive);
763 		gtk_widget_set_sensitive (app->menubar.download.delete_file, sensitive);
764 		gtk_widget_set_sensitive (app->menubar.download.force_start, sensitive);
765 		gtk_widget_set_sensitive (app->menubar.download.runnable, sensitive);
766 		gtk_widget_set_sensitive (app->menubar.download.pause, sensitive);
767 		gtk_widget_set_sensitive (app->menubar.download.move_to.item, sensitive);
768 		gtk_widget_set_sensitive (app->menubar.download.prioriy.item, sensitive);
769 	}
770 	// properties
771 	if (n_selected > 1) {
772 		gtk_widget_set_sensitive (app->toolbar.properties, FALSE);
773 		gtk_widget_set_sensitive (app->menubar.download.properties, FALSE);
774 	}
775 	else {
776 		gtk_widget_set_sensitive (app->toolbar.properties, sensitive);
777 		gtk_widget_set_sensitive (app->menubar.download.properties, sensitive);
778 	}
779 
780 	// Move Up/Down/Top/Bottom functions need reset sensitive when selection changed.
781 	// These need by  on_move_download_xxx()  series.
782 	if (n_selected > 0) {
783 		// Any Category/Status can't move download position if they were sorted.
784 		if (app->setting.download_column.sort.nth == UGTK_NODE_COLUMN_STATE)
785 			sensitive = TRUE;
786 		else
787 			sensitive = FALSE;
788 	}
789 	// move up/down/top/bottom
790 	gtk_widget_set_sensitive (app->toolbar.move_up, sensitive);
791 	gtk_widget_set_sensitive (app->toolbar.move_down, sensitive);
792 	gtk_widget_set_sensitive (app->toolbar.move_top, sensitive);
793 	gtk_widget_set_sensitive (app->toolbar.move_bottom, sensitive);
794 	gtk_widget_set_sensitive (app->menubar.download.move_up, sensitive);
795 	gtk_widget_set_sensitive (app->menubar.download.move_down, sensitive);
796 	gtk_widget_set_sensitive (app->menubar.download.move_top, sensitive);
797 	gtk_widget_set_sensitive (app->menubar.download.move_bottom, sensitive);
798 }
799 
800 // decide sensitive for menu, toolbar
ugtk_app_decide_category_sensitive(UgtkApp * app)801 void  ugtk_app_decide_category_sensitive (UgtkApp* app)
802 {
803 	static gboolean  sensitive_last = TRUE;
804 	gboolean         sensitive;
805 
806 	if (app->traveler.category.cursor.node)
807 		sensitive = TRUE;
808 	else
809 		sensitive = FALSE;
810 
811 	if (sensitive_last != sensitive) {
812 		sensitive_last  = sensitive;
813 		gtk_widget_set_sensitive (app->menubar.category.properties, sensitive);
814 		gtk_widget_set_sensitive (app->menubar.view.columns.self, sensitive);
815 	}
816 	// cursor at "All Category"
817 	if (app->traveler.category.cursor.pos == 0) {
818 		gtk_widget_set_sensitive (app->menubar.file.save_category, FALSE);
819 		gtk_widget_set_sensitive (app->menubar.category.delete, FALSE);
820 	}
821 	else {
822 		gtk_widget_set_sensitive (app->menubar.file.save_category, sensitive);
823 		gtk_widget_set_sensitive (app->menubar.category.delete, sensitive);
824 	}
825 	// Move Up
826 	if (app->traveler.category.cursor.pos <= 1)
827 		gtk_widget_set_sensitive (app->menubar.category.move_up, FALSE);
828 	else
829 		gtk_widget_set_sensitive (app->menubar.category.move_up, TRUE);
830 	// Move Down
831 	if (app->traveler.category.cursor.pos == 0 ||
832 	    app->traveler.category.cursor.node->next == NULL)
833 	{
834 		gtk_widget_set_sensitive (app->menubar.category.move_down, FALSE);
835 	}
836 	else
837 		gtk_widget_set_sensitive (app->menubar.category.move_down, TRUE);
838 
839 	ugtk_app_decide_download_sensitive (app);
840 }
841 
ugtk_app_decide_trayicon_visible(UgtkApp * app)842 void  ugtk_app_decide_trayicon_visible (UgtkApp* app)
843 {
844 	gboolean  visible;
845 
846 	if (app->setting.ui.show_trayicon)
847 		visible = TRUE;
848 	else {
849 		if (gtk_widget_get_visible ((GtkWidget*) app->window.self))
850 			visible = FALSE;
851 		else
852 			visible = TRUE;
853 	}
854 	ugtk_tray_icon_set_visible (&app->trayicon, visible);
855 }
856 
ugtk_app_decide_to_quit(UgtkApp * app)857 void  ugtk_app_decide_to_quit (UgtkApp* app)
858 {
859 	UgtkConfirmDialog*  cdialog;
860 
861 	if (app->setting.ui.exit_confirmation == FALSE)
862 		ugtk_app_quit (app);
863 	else if (app->dialogs.exit_confirmation)
864 		gtk_widget_show (app->dialogs.exit_confirmation);
865 	else {
866 		cdialog = ugtk_confirm_dialog_new (UGTK_CONFIRM_DIALOG_EXIT, app);
867 		ugtk_confirm_dialog_run (cdialog);
868 	}
869 }
870 
871 // ------------------------------------
872 // create node by UI
873 
ugtk_app_create_category(UgtkApp * app)874 void  ugtk_app_create_category (UgtkApp* app)
875 {
876 	UgtkNodeDialog*  ndialog;
877 	UgetCommon* common_src;
878 	UgetCommon* common;
879 	UgetNode*  cnode_src;
880 	UgetNode*  cnode;
881 	gchar*     title;
882 
883 	title = g_strconcat (UGTK_APP_NAME, " - ", _("New Category"), NULL);
884 	ndialog = ugtk_node_dialog_new (title, app, TRUE);
885 	g_free (title);
886 	ugtk_download_form_set_folders (&ndialog->download, &app->setting);
887 
888 	// category list
889 	cnode_src = app->traveler.category.cursor.node->base;
890 	if (cnode_src->parent != &app->real)
891 		cnode_src = app->real.children;
892 	common_src = ug_data_get(cnode_src->data, UgetCommonInfo);
893 	cnode = uget_node_new (NULL);
894 	common = ug_data_realloc(cnode->data, UgetCommonInfo);
895 	ug_data_assign (cnode->data, cnode_src->data, NULL);
896 	ug_free(common->name);
897 	common->name = ug_strdup_printf("%s%s", _("Copy - "),
898 						(common_src->name) ? common_src->name : NULL);
899 
900 	ugtk_node_dialog_set (ndialog, cnode->data);
901 	ugtk_node_dialog_run (ndialog, UGTK_NODE_DIALOG_NEW_CATEGORY, cnode);
902 }
903 
ugtk_app_create_download(UgtkApp * app,const char * sub_title,const char * uri)904 void  ugtk_app_create_download (UgtkApp* app, const char* sub_title, const char* uri)
905 {
906 	UgtkNodeDialog*  ndialog;
907 	UgUri      uuri;
908 	UgetNode*  cnode;
909 	GList*     list;
910 	union {
911 		gchar*     title;
912 		UgetNode*  cnode;
913 	} temp;
914 
915 	if (sub_title)
916 		temp.title = g_strconcat (UGTK_APP_NAME, " - ", sub_title, NULL);
917 	else
918 		temp.title = g_strconcat (UGTK_APP_NAME, " - ", _("New Download"), NULL);
919 	ndialog = ugtk_node_dialog_new (temp.title, app, FALSE);
920 	g_free (temp.title);
921 	ugtk_download_form_set_folders (&ndialog->download, &app->setting);
922 
923 	// category list
924 	cnode = app->traveler.category.cursor.node->base;
925 	if (cnode->parent != &app->real)
926 		cnode = app->real.children;
927 
928 	if (uri != NULL) {
929 		// set URI entry
930 		gtk_entry_set_text ((GtkEntry*) ndialog->download.uri_entry, uri);
931 		ndialog->download.changed.uri = TRUE;
932 		// match category by URI
933 		ug_uri_init (&uuri, uri);
934 		temp.cnode = uget_app_match_category ((UgetApp*) app, &uuri, NULL);
935 		if (temp.cnode)
936 			cnode = temp.cnode;
937 	}
938 	else if ( (list = ugtk_clipboard_get_uris (&app->clipboard)) != NULL ) {
939 		// use first URI from clipboard to set URI entry
940 		gtk_entry_set_text ((GtkEntry*) ndialog->download.uri_entry, list->data);
941 		ndialog->download.changed.uri = TRUE;
942 		// match category by URI from clipboard
943 		ug_uri_init (&uuri, list->data);
944 		temp.cnode = uget_app_match_category ((UgetApp*) app, &uuri, NULL);
945 		if (temp.cnode)
946 			cnode = temp.cnode;
947 		//
948 		g_list_free_full (list, g_free);
949 		ugtk_download_form_complete_entry (&ndialog->download);
950 	}
951 
952 	if (cnode)
953 		cnode = cnode->base;
954 	ugtk_node_dialog_set_category (ndialog, cnode);
955 	ugtk_node_dialog_run (ndialog, UGTK_NODE_DIALOG_NEW_DOWNLOAD, NULL);
956 }
957 
958 // ------------------------------------
959 // delete selected node
960 
ugtk_app_delete_category(UgtkApp * app)961 void  ugtk_app_delete_category (UgtkApp* app)
962 {
963 	UgetNode*    cnode;
964 	int          pos;
965 
966 	cnode = app->traveler.category.cursor.node->base;
967 	pos   = app->traveler.category.cursor.pos;
968 	// move cursor
969 	if (pos <= 0)
970 		return;
971 
972 	if (cnode->next)
973 		ugtk_traveler_select_category (&app->traveler, pos + 1, -1);
974 	else {
975 		if (app->real.n_children > 1)
976 			ugtk_traveler_select_category (&app->traveler, pos - 1, -1);
977 		else {
978 			// The last category will be deleted.
979 			ugtk_app_add_default_category (app);
980 			ugtk_traveler_select_category (&app->traveler, pos + 1, -1);
981 		}
982 	}
983 	// remove category
984 	uget_app_delete_category ((UgetApp*) app, cnode);
985 	// sync UgtkMenubar.download.move_to
986 	ugtk_menubar_sync_category (&app->menubar, app, TRUE);
987 }
988 
ugtk_app_delete_download(UgtkApp * app,gboolean delete_files)989 void  ugtk_app_delete_download (UgtkApp* app, gboolean delete_files)
990 {
991 	UgetNode* cursor;
992 	UgetNode* node;
993 	GList*    link;
994 	GList*    list = NULL;
995 	// check shift key status
996 	GdkWindow*       gdk_win;
997 	GdkDevice*       dev_pointer;
998 	GdkModifierType  mask;
999 
1000 	// check shift key status
1001 	gdk_win = gtk_widget_get_parent_window ((GtkWidget*) app->traveler.download.view);
1002 	dev_pointer = gdk_device_manager_get_client_pointer (
1003 			gdk_display_get_device_manager (gdk_window_get_display (gdk_win)));
1004 	gdk_window_get_device_position (gdk_win, dev_pointer, NULL, NULL, &mask);
1005 
1006 	cursor = app->traveler.download.cursor.node;
1007 	if (cursor)
1008 		cursor = cursor->base;
1009 	list = ugtk_traveler_get_selected (&app->traveler);
1010 	for (link = list;  link;  link = link->next) {
1011 		node = link->data;
1012 		node = node->base;
1013 		link->data = node;
1014 		if (delete_files || mask & GDK_SHIFT_MASK)
1015 			uget_app_delete_download ((UgetApp*) app, node, delete_files);
1016 		else {
1017 			if (uget_app_recycle_download ((UgetApp*) app, node))
1018 				continue;
1019 		}
1020 		// if current node has been deleted
1021 		if (cursor == node)
1022 			cursor = NULL;
1023 		link->data = NULL;
1024 	}
1025 	if (delete_files == FALSE && (mask & GDK_SHIFT_MASK) == 0) {
1026 		ugtk_traveler_set_cursor (&app->traveler, cursor);
1027 		ugtk_traveler_set_selected (&app->traveler, list);
1028 	}
1029 	g_list_free (list);
1030 	// refresh
1031 	gtk_widget_queue_draw ((GtkWidget*) app->traveler.category.view);
1032 	gtk_widget_queue_draw ((GtkWidget*) app->traveler.state.view);
1033 
1034 	app->user_action = TRUE;
1035 }
1036 
1037 // ------------------------------------
1038 // edit selected node
1039 
ugtk_app_edit_category(UgtkApp * app)1040 void  ugtk_app_edit_category (UgtkApp* app)
1041 {
1042 	UgtkNodeDialog* ndialog;
1043 	UgetNode*       node;
1044 	gchar*          title;
1045 
1046 	if (app->traveler.category.cursor.pos == 0)
1047 		node = app->real.children;
1048 	else
1049 		node = app->traveler.category.cursor.node;
1050 	if (node == NULL)
1051 		return;
1052 
1053 	title = g_strconcat (UGTK_APP_NAME " - ", _("Category Properties"), NULL);
1054 	ndialog = ugtk_node_dialog_new (title, app, TRUE);
1055 	g_free (title);
1056 	ugtk_download_form_set_folders (&ndialog->download, &app->setting);
1057 	ugtk_node_dialog_set (ndialog, node->base->data);
1058 	ugtk_node_dialog_run (ndialog, UGTK_NODE_DIALOG_EDIT_CATEGORY, node->base);
1059 }
1060 
ugtk_app_edit_download(UgtkApp * app)1061 void  ugtk_app_edit_download (UgtkApp* app)
1062 {
1063 	UgtkNodeDialog* ndialog;
1064 	UgetNode*       node;
1065 	gchar*          title;
1066 
1067 	title = g_strconcat (UGTK_APP_NAME " - ", _("Download Properties"), NULL);
1068 	ndialog = ugtk_node_dialog_new (title, app, FALSE);
1069 	g_free (title);
1070 	ugtk_download_form_set_folders (&ndialog->download, &app->setting);
1071 
1072 	node = app->traveler.download.cursor.node;
1073 	ugtk_node_dialog_set (ndialog, node->base->data);
1074 	ugtk_node_dialog_run (ndialog, UGTK_NODE_DIALOG_EDIT_DOWNLOAD, node->base);
1075 }
1076 
1077 // ------------------------------------
1078 // queue/pause
1079 
ugtk_app_queue_download(UgtkApp * app,gboolean keep_active)1080 void  ugtk_app_queue_download (UgtkApp* app, gboolean keep_active)
1081 {
1082 	UgetRelation* relation;
1083 	UgetNode*  node;
1084 	UgetNode*  cursor;
1085 	GList*     list;
1086 	GList*     link;
1087 
1088 	cursor = app->traveler.download.cursor.node;
1089 	if (cursor)
1090 		cursor = cursor->base;
1091 
1092 	list = ugtk_traveler_get_selected (&app->traveler);
1093 	for (link = list;  link;  link = link->next) {
1094 		node = link->data;
1095 		node = node->base;
1096 		link->data = node;
1097 		relation = ug_data_realloc(node->data, UgetRelationInfo);
1098 		if (keep_active && relation->group & UGET_GROUP_ACTIVE)
1099 			continue;
1100 		uget_app_queue_download ((UgetApp*) app, node);
1101 	}
1102 	if (app->traveler.state.cursor.pos == 0) {
1103 		ugtk_traveler_set_cursor (&app->traveler, cursor);
1104 		ugtk_traveler_set_selected (&app->traveler, list);
1105 	}
1106 	g_list_free (list);
1107 	// refresh other data & status
1108 	gtk_widget_queue_draw ((GtkWidget*) app->traveler.download.view);
1109 	gtk_widget_queue_draw ((GtkWidget*) app->traveler.category.view);
1110 	gtk_widget_queue_draw ((GtkWidget*) app->traveler.state.view);
1111 //	ugtk_summary_show (&app->summary, app->traveler.download.cursor.node);
1112 }
1113 
ugtk_app_pause_download(UgtkApp * app)1114 void  ugtk_app_pause_download (UgtkApp* app)
1115 {
1116 	UgetNode*  node;
1117 	UgetNode*  cursor;
1118 	GList*     list;
1119 	GList*     link;
1120 
1121 	cursor = app->traveler.download.cursor.node;
1122 	if (cursor)
1123 		cursor = cursor->base;
1124 
1125 	list = ugtk_traveler_get_selected (&app->traveler);
1126 	for (link = list;  link;  link = link->next) {
1127 		node = link->data;
1128 		node = node->base;
1129 		link->data = node;
1130 		uget_app_pause_download ((UgetApp*) app, node);
1131 	}
1132 	if (app->traveler.state.cursor.pos == 0) {
1133 		ugtk_traveler_set_cursor (&app->traveler, cursor);
1134 		ugtk_traveler_set_selected (&app->traveler, list);
1135 	}
1136 	g_list_free (list);
1137 	// refresh other data & status
1138 	gtk_widget_queue_draw ((GtkWidget*) app->traveler.download.view);
1139 	gtk_widget_queue_draw ((GtkWidget*) app->traveler.category.view);
1140 	gtk_widget_queue_draw ((GtkWidget*) app->traveler.state.view);
1141 //	ugtk_summary_show (&app->summary, app->traveler.download.cursor.node);
1142 
1143 	app->user_action = TRUE;
1144 }
1145 
ugtk_app_switch_download_state(UgtkApp * app)1146 void  ugtk_app_switch_download_state (UgtkApp* app)
1147 {
1148 	UgetRelation* relation;
1149 	UgetNode*  node;
1150 	UgetNode*  cursor;
1151 	GList*     list;
1152 	GList*     link;
1153 
1154 	cursor = app->traveler.download.cursor.node;
1155 	if (cursor)
1156 		cursor = cursor->base;
1157 
1158 	list = ugtk_traveler_get_selected (&app->traveler);
1159 	for (link = list;  link;  link = link->next) {
1160 		node = link->data;
1161 		node = node->base;
1162 		link->data = node;
1163 		relation = ug_data_realloc(node->data, UgetRelationInfo);
1164 		if (relation->group & UGET_GROUP_PAUSED)
1165 			uget_app_queue_download ((UgetApp*) app, node);
1166 		else if (relation->group & UGET_GROUP_ACTIVE)
1167 			uget_app_pause_download ((UgetApp*) app, node);
1168 	}
1169 	if (app->traveler.state.cursor.pos == 0) {
1170 		ugtk_traveler_set_cursor (&app->traveler, cursor);
1171 		ugtk_traveler_set_selected (&app->traveler, list);
1172 	}
1173 	g_list_free (list);
1174 	// refresh other data & status
1175 	gtk_widget_queue_draw ((GtkWidget*) app->traveler.download.view);
1176 	gtk_widget_queue_draw ((GtkWidget*) app->traveler.category.view);
1177 	gtk_widget_queue_draw ((GtkWidget*) app->traveler.state.view);
1178 //	ugtk_summary_show (&app->summary, app->traveler.download.cursor.node);
1179 
1180 	app->user_action = TRUE;
1181 }
1182 
1183 // ------------------------------------
1184 // move selected node
1185 
ugtk_app_move_download_up(UgtkApp * app)1186 void  ugtk_app_move_download_up (UgtkApp* app)
1187 {
1188 	if (ugtk_traveler_move_selected_up (&app->traveler) > 0) {
1189 		gtk_widget_set_sensitive (app->toolbar.move_down, TRUE);
1190 		gtk_widget_set_sensitive (app->toolbar.move_bottom, TRUE);
1191 		gtk_widget_set_sensitive (app->menubar.download.move_down, TRUE);
1192 		gtk_widget_set_sensitive (app->menubar.download.move_bottom, TRUE);
1193 	}
1194 	else {
1195 		gtk_widget_set_sensitive (app->toolbar.move_up, FALSE);
1196 		gtk_widget_set_sensitive (app->toolbar.move_top, FALSE);
1197 		gtk_widget_set_sensitive (app->menubar.download.move_up, FALSE);
1198 		gtk_widget_set_sensitive (app->menubar.download.move_top, FALSE);
1199 	}
1200 }
1201 
ugtk_app_move_download_down(UgtkApp * app)1202 void  ugtk_app_move_download_down (UgtkApp* app)
1203 {
1204 	if (ugtk_traveler_move_selected_down (&app->traveler) > 0) {
1205 		gtk_widget_set_sensitive (app->toolbar.move_up, TRUE);
1206 		gtk_widget_set_sensitive (app->toolbar.move_top, TRUE);
1207 		gtk_widget_set_sensitive (app->menubar.download.move_up, TRUE);
1208 		gtk_widget_set_sensitive (app->menubar.download.move_top, TRUE);
1209 	}
1210 	else {
1211 		gtk_widget_set_sensitive (app->toolbar.move_down, FALSE);
1212 		gtk_widget_set_sensitive (app->toolbar.move_bottom, FALSE);
1213 		gtk_widget_set_sensitive (app->menubar.download.move_down, FALSE);
1214 		gtk_widget_set_sensitive (app->menubar.download.move_bottom, FALSE);
1215 	}
1216 }
1217 
ugtk_app_move_download_top(UgtkApp * app)1218 void  ugtk_app_move_download_top (UgtkApp* app)
1219 {
1220 	if (ugtk_traveler_move_selected_top (&app->traveler) > 0) {
1221 		gtk_widget_set_sensitive (app->toolbar.move_down, TRUE);
1222 		gtk_widget_set_sensitive (app->toolbar.move_bottom, TRUE);
1223 		gtk_widget_set_sensitive (app->menubar.download.move_down, TRUE);
1224 		gtk_widget_set_sensitive (app->menubar.download.move_bottom, TRUE);
1225 	}
1226 	gtk_widget_set_sensitive (app->toolbar.move_up, FALSE);
1227 	gtk_widget_set_sensitive (app->toolbar.move_top, FALSE);
1228 	gtk_widget_set_sensitive (app->menubar.download.move_up, FALSE);
1229 	gtk_widget_set_sensitive (app->menubar.download.move_top, FALSE);
1230 }
1231 
ugtk_app_move_download_bottom(UgtkApp * app)1232 void  ugtk_app_move_download_bottom (UgtkApp* app)
1233 {
1234 	if (ugtk_traveler_move_selected_bottom (&app->traveler) > 0) {
1235 		gtk_widget_set_sensitive (app->toolbar.move_up, TRUE);
1236 		gtk_widget_set_sensitive (app->toolbar.move_top, TRUE);
1237 		gtk_widget_set_sensitive (app->menubar.download.move_up, TRUE);
1238 		gtk_widget_set_sensitive (app->menubar.download.move_top, TRUE);
1239 	}
1240 	gtk_widget_set_sensitive (app->toolbar.move_down, FALSE);
1241 	gtk_widget_set_sensitive (app->toolbar.move_bottom, FALSE);
1242 	gtk_widget_set_sensitive (app->menubar.download.move_down, FALSE);
1243 	gtk_widget_set_sensitive (app->menubar.download.move_bottom, FALSE);
1244 }
1245 
ugtk_app_move_download_to(UgtkApp * app,UgetNode * cnode)1246 void  ugtk_app_move_download_to (UgtkApp* app, UgetNode* cnode)
1247 {
1248 	UgetNode* node;
1249 	GList*    link;
1250 	GList*    list = NULL;
1251 
1252 	if (cnode == app->traveler.category.cursor.node->base)
1253 		return;
1254 
1255 	list = ugtk_traveler_get_selected (&app->traveler);
1256 	for (link = list;  link;  link = link->next) {
1257 		node = link->data;
1258 		node = node->base;
1259 		if (node->parent == cnode)
1260 			continue;
1261 		uget_node_remove (node->parent, node);
1262 		uget_node_clear_fake (node);
1263 		uget_node_append (cnode, node);
1264 	}
1265 	g_list_free (list);
1266 	// refresh
1267 	gtk_widget_queue_draw ((GtkWidget*) app->traveler.category.view);
1268 	gtk_widget_queue_draw ((GtkWidget*) app->traveler.state.view);
1269 }
1270 
1271 // ------------------------------------
1272 // torrent & metalink
1273 
create_file_chooser(GtkWindow * parent,GtkFileChooserAction action,const gchar * title,const gchar * filter_name,const gchar * mine_type)1274 static GtkWidget*  create_file_chooser (GtkWindow* parent,
1275                                         GtkFileChooserAction action,
1276                                         const gchar* title,
1277                                         const gchar* filter_name,
1278                                         const gchar* mine_type)
1279 {
1280 	GtkWidget*      dialog;
1281 	GtkFileFilter*  filter;
1282 
1283 	dialog = gtk_file_chooser_dialog_new (title,
1284 			parent,
1285 			action,
1286 			GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1287 			GTK_STOCK_OK,     GTK_RESPONSE_OK,
1288 			NULL);
1289 	gtk_window_set_destroy_with_parent ((GtkWindow*) dialog, TRUE);
1290 
1291 	if (filter_name) {
1292 		filter = gtk_file_filter_new ();
1293 		gtk_file_filter_set_name (filter, filter_name);
1294 		gtk_file_filter_add_mime_type (filter, mine_type);
1295 		gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1296 	}
1297 	return dialog;
1298 }
1299 
on_create_torrent_response(GtkWidget * dialog,gint response,UgtkApp * app)1300 static void  on_create_torrent_response (GtkWidget* dialog, gint response, UgtkApp* app)
1301 {
1302 	gchar*  file;
1303 
1304 	if (response != GTK_RESPONSE_OK ) {
1305 		gtk_widget_destroy (dialog);
1306 		return;
1307 	}
1308 	// get filename
1309 	file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1310 //	file = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
1311 	gtk_widget_destroy (dialog);
1312 	ugtk_app_create_download (app, _("New Torrent"), file);
1313 	g_free (file);
1314 }
1315 
on_create_metalink_response(GtkWidget * dialog,gint response,UgtkApp * app)1316 static void  on_create_metalink_response (GtkWidget* dialog, gint response, UgtkApp* app)
1317 {
1318 	gchar*  file;
1319 
1320 	if (response != GTK_RESPONSE_OK) {
1321 		gtk_widget_destroy (dialog);
1322 		return;
1323 	}
1324 	// get filename
1325 	file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1326 //	file = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
1327 	gtk_widget_destroy (dialog);
1328 	ugtk_app_create_download (app, _("New Metalink"), file);
1329 	g_free (file);
1330 }
1331 
ugtk_app_create_torrent(UgtkApp * app)1332 void  ugtk_app_create_torrent (UgtkApp* app)
1333 {
1334 	GtkWidget*  dialog;
1335 	gchar*      title;
1336 
1337 	title = g_strconcat (UGTK_APP_NAME " - ", _("Open Torrent file"), NULL);
1338 	dialog = create_file_chooser (app->window.self,
1339 			GTK_FILE_CHOOSER_ACTION_OPEN,
1340 			title, _("Torrent file (*.torrent)"), "application/x-bittorrent");
1341 	g_free (title);
1342 	g_signal_connect (dialog, "response",
1343 			G_CALLBACK (on_create_torrent_response), app);
1344 	gtk_widget_show (dialog);
1345 }
1346 
ugtk_app_create_metalink(UgtkApp * app)1347 void  ugtk_app_create_metalink (UgtkApp* app)
1348 {
1349 	GtkFileFilter*  filter;
1350 	GtkWidget*      dialog;
1351 	gchar*          title;
1352 
1353 	title = g_strconcat (UGTK_APP_NAME " - ", _("Open Metalink file"), NULL);
1354 	dialog = create_file_chooser (app->window.self,
1355 			GTK_FILE_CHOOSER_ACTION_OPEN,
1356 			title, NULL, NULL);
1357 	g_free (title);
1358 
1359 	filter = gtk_file_filter_new ();
1360 	gtk_file_filter_set_name (filter, "Metalink file (*.metalink, *.meta4)");
1361 	gtk_file_filter_add_pattern (filter, "*.metalink");
1362 	gtk_file_filter_add_pattern (filter, "*.meta4");
1363 //	gtk_file_filter_add_mime_type (filter, "application/metalink+xml");
1364 //	gtk_file_filter_add_mime_type (filter, "application/metalink4+xml");
1365 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
1366 	g_signal_connect (dialog, "response",
1367 			G_CALLBACK (on_create_metalink_response), app);
1368 	gtk_widget_show (dialog);
1369 }
1370 
1371 // ------------------------------------
1372 // import/export
1373 
on_save_category_response(GtkWidget * dialog,gint response,UgtkApp * app)1374 static void  on_save_category_response (GtkWidget* dialog, gint response, UgtkApp* app)
1375 {
1376 	UgetNode* cnode;
1377 	gchar*    file;
1378 
1379 	gtk_widget_set_sensitive ((GtkWidget*) app->window.self, TRUE);
1380 	if (response != GTK_RESPONSE_OK) {
1381 		gtk_widget_destroy (dialog);
1382 		return;
1383 	}
1384 	if (app->traveler.category.cursor.pos == 0)
1385 		return;
1386 
1387 	// get filename
1388 	file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1389 //	file = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
1390 	gtk_widget_destroy (dialog);
1391 	cnode = app->traveler.category.cursor.node;
1392 	if (uget_app_save_category ((UgetApp*) app, cnode->base, file, NULL) == FALSE)
1393 		ugtk_app_show_message (app, GTK_MESSAGE_ERROR, _("Failed to save category file."));
1394 	g_free (file);
1395 }
1396 
on_load_category_response(GtkWidget * dialog,gint response,UgtkApp * app)1397 static void  on_load_category_response (GtkWidget* dialog, gint response, UgtkApp* app)
1398 {
1399 	gchar*  file;
1400 
1401 	gtk_widget_set_sensitive ((GtkWidget*) app->window.self, TRUE);
1402 	if (response != GTK_RESPONSE_OK) {
1403 		gtk_widget_destroy (dialog);
1404 		return;
1405 	}
1406 	// get filename
1407 	file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1408 //	file = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
1409 	gtk_widget_destroy (dialog);
1410 	if (uget_app_load_category ((UgetApp*) app, file, NULL))
1411 		ugtk_menubar_sync_category (&app->menubar, app, TRUE);
1412 	else
1413 		ugtk_app_show_message (app, GTK_MESSAGE_ERROR, _("Failed to load category file."));
1414 	g_free (file);
1415 }
1416 
ugtk_app_save_category(UgtkApp * app)1417 void  ugtk_app_save_category (UgtkApp* app)
1418 {
1419 	GtkWidget*      dialog;
1420 	gchar*          title;
1421 
1422 	gtk_widget_set_sensitive ((GtkWidget*) app->window.self, FALSE);
1423 
1424 	title = g_strconcat (UGTK_APP_NAME " - ", _("Save Category file"), NULL);
1425 	dialog = create_file_chooser (app->window.self,
1426 			GTK_FILE_CHOOSER_ACTION_SAVE,
1427 			title, NULL, NULL);
1428 	g_free (title);
1429 
1430 	g_signal_connect (dialog, "response",
1431 			G_CALLBACK (on_save_category_response), app);
1432 	gtk_widget_show (dialog);
1433 }
1434 
ugtk_app_load_category(UgtkApp * app)1435 void  ugtk_app_load_category (UgtkApp* app)
1436 {
1437 	GtkWidget*      dialog;
1438 	gchar*          title;
1439 
1440 	gtk_widget_set_sensitive ((GtkWidget*) app->window.self, FALSE);
1441 
1442 	title = g_strconcat (UGTK_APP_NAME " - ", _("Open Category file"), NULL);
1443 	dialog = create_file_chooser (app->window.self,
1444 			GTK_FILE_CHOOSER_ACTION_OPEN,
1445 			title, _("JSON file (*.json)"), "application/json");
1446 	g_free (title);
1447 
1448 	g_signal_connect (dialog, "response",
1449 			G_CALLBACK (on_load_category_response), app);
1450 	gtk_widget_show (dialog);
1451 }
1452 
on_import_html_file_response(GtkWidget * dialog,gint response,UgtkApp * app)1453 static void  on_import_html_file_response (GtkWidget* dialog, gint response, UgtkApp* app)
1454 {
1455 	UgHtmlFilter*     filter;
1456 	UgHtmlFilterTag*  tag_a;
1457 	UgHtmlFilterTag*  tag_img;
1458 	UgtkBatchDialog*  bdialog;
1459 	UgtkSelectorPage* page;
1460 	UgetNode*  cnode;
1461 	gchar*  string;
1462 	gchar*  file;
1463 
1464 	if (response != GTK_RESPONSE_OK ) {
1465 		gtk_widget_destroy (dialog);
1466 		return;
1467 	}
1468 	// read URLs from html file
1469 	string = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1470 	gtk_widget_destroy (dialog);
1471 	file = g_filename_to_utf8 (string, -1, NULL, NULL, NULL);
1472 	g_free (string);
1473 	string = NULL;
1474 	// parse html
1475 	filter = ug_html_filter_new ();
1476 	tag_a = ug_html_filter_tag_new ("A", "HREF");		// <A HREF="Link">
1477 	ug_html_filter_add_tag (filter, tag_a);
1478 	tag_img = ug_html_filter_tag_new ("IMG", "SRC");		// <IMG SRC="Link">
1479 	ug_html_filter_add_tag (filter, tag_img);
1480 	ug_html_filter_parse_file (filter, file);
1481 	g_free (file);
1482 	if (filter->base_href)
1483 		string = g_strdup (filter->base_href);
1484 	ug_html_filter_free (filter);
1485 	// UgtkBatchDialog
1486 	bdialog = ugtk_batch_dialog_new (
1487 			gtk_window_get_title ((GtkWindow*) dialog), app);
1488 	ugtk_download_form_set_folders (&bdialog->download, &app->setting);
1489 	ugtk_batch_dialog_use_selector (bdialog);
1490 	// category
1491 	cnode = app->traveler.category.cursor.node->base;
1492 	if (cnode->parent != &app->real)
1493 		cnode = app->real.children;
1494 	ugtk_batch_dialog_set_category (bdialog, cnode);
1495 	// set <base href>
1496 	if (string) {
1497 		gtk_entry_set_text (bdialog->selector.href_entry, string);
1498 		g_free (string);
1499 	}
1500 	// add link
1501 	page = ugtk_selector_add_page (&bdialog->selector, _("Link <A>"));
1502 	ugtk_selector_page_add_uris (page, (GList*)tag_a->attr_values.head);
1503 	ug_list_clear (&tag_a->attr_values, TRUE);
1504 	ug_html_filter_tag_unref (tag_a);
1505 	// add image
1506 	page = ugtk_selector_add_page (&bdialog->selector, _("Image <IMG>"));
1507 	ugtk_selector_page_add_uris (page, (GList*)tag_img->attr_values.head);
1508 	ug_list_clear (&tag_img->attr_values, TRUE);
1509 	ug_html_filter_tag_unref (tag_img);
1510 
1511 	ugtk_batch_dialog_run (bdialog);
1512 }
1513 
on_import_text_file_response(GtkWidget * dialog,gint response,UgtkApp * app)1514 static void  on_import_text_file_response (GtkWidget* dialog, gint response, UgtkApp* app)
1515 {
1516 	UgtkBatchDialog*   bdialog;
1517 	UgtkSelectorPage*  page;
1518 	UgetNode* cnode;
1519 	gchar*    string;
1520 	gchar*    file;
1521 	GList*    list;
1522 	GError*   error = NULL;
1523 
1524 	if (response != GTK_RESPONSE_OK ) {
1525 		gtk_widget_destroy (dialog);
1526 		return;
1527 	}
1528 	// read URLs from text file
1529 	string = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1530 	gtk_widget_destroy (dialog);
1531 	file = g_filename_to_utf8 (string, -1, NULL, NULL, NULL);
1532 	g_free (string);
1533 	list = ugtk_text_file_get_uris (file, &error);
1534 	g_free (file);
1535 	if (error) {
1536 		ugtk_app_show_message (app, GTK_MESSAGE_ERROR, error->message);
1537 		g_error_free (error);
1538 		return;
1539 	}
1540 	// UgtkBatchDialog
1541 	bdialog = ugtk_batch_dialog_new (
1542 			gtk_window_get_title ((GtkWindow*) dialog), app);
1543 	ugtk_batch_dialog_use_selector (bdialog);
1544 	ugtk_download_form_set_folders (&bdialog->download, &app->setting);
1545 	// category
1546 	cnode = app->traveler.category.cursor.node->base;
1547 	if (cnode->parent != &app->real)
1548 		cnode = app->real.children;
1549 	ugtk_batch_dialog_set_category (bdialog, cnode);
1550 
1551 	page = ugtk_selector_add_page (&bdialog->selector, _("Text File"));
1552 	ugtk_selector_hide_href (&bdialog->selector);
1553 	ugtk_selector_page_add_uris (page, list);
1554 	g_list_free (list);
1555 
1556 	ugtk_batch_dialog_run (bdialog);
1557 }
1558 
on_export_text_file_response(GtkWidget * dialog,gint response,UgtkApp * app)1559 static void  on_export_text_file_response (GtkWidget* dialog, gint response, UgtkApp* app)
1560 {
1561 	GIOChannel*  channel;
1562 	UgetCommon*  common;
1563 	UgetNode*    node;
1564 	gchar*       fname;
1565 
1566 	if (response != GTK_RESPONSE_OK ) {
1567 		gtk_widget_destroy (dialog);
1568 		return;
1569 	}
1570 	// write all URLs to text file
1571 	fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1572 	gtk_widget_destroy (dialog);
1573 	channel = g_io_channel_new_file (fname, "w", NULL);
1574 	g_free (fname);
1575 
1576 	node = app->traveler.category.cursor.node->base;
1577 	for (node = node->children;  node;  node = node->next) {
1578 		common = ug_data_get (node->data, UgetCommonInfo);
1579 		if (common == NULL)
1580 			continue;
1581 		if (common->uri) {
1582 			g_io_channel_write_chars (channel, common->uri, -1, NULL, NULL);
1583 #ifdef _WIN32
1584 			g_io_channel_write_chars (channel, "\r\n", 2, NULL, NULL);
1585 #else
1586 			g_io_channel_write_chars (channel, "\n", 1, NULL, NULL);
1587 #endif
1588 		}
1589 	}
1590 	g_io_channel_unref (channel);
1591 }
1592 
ugtk_app_import_html_file(UgtkApp * app)1593 void  ugtk_app_import_html_file (UgtkApp* app)
1594 {
1595 	GtkWidget*  dialog;
1596 	gchar*      title;
1597 
1598 	title = g_strconcat (UGTK_APP_NAME " - ", _("Import URLs from HTML file"), NULL);
1599 	dialog = create_file_chooser (app->window.self,
1600 			GTK_FILE_CHOOSER_ACTION_OPEN,
1601 			title, _("HTML file (*.htm, *.html)"), "text/html");
1602 	g_free (title);
1603 	g_signal_connect (dialog, "response",
1604 			G_CALLBACK (on_import_html_file_response), app);
1605 	gtk_widget_show (dialog);
1606 }
1607 
ugtk_app_import_text_file(UgtkApp * app)1608 void  ugtk_app_import_text_file (UgtkApp* app)
1609 {
1610 	GtkWidget*  dialog;
1611 	gchar*      title;
1612 
1613 	title = g_strconcat (UGTK_APP_NAME " - ", _("Import URLs from text file"), NULL);
1614 	dialog = create_file_chooser (app->window.self,
1615 			GTK_FILE_CHOOSER_ACTION_OPEN,
1616 			title, _("Plain text file"), "text/plain");
1617 	g_free (title);
1618 	g_signal_connect (dialog, "response",
1619 			G_CALLBACK (on_import_text_file_response), app);
1620 	gtk_widget_show (dialog);
1621 }
1622 
ugtk_app_export_text_file(UgtkApp * app)1623 void  ugtk_app_export_text_file (UgtkApp* app)
1624 {
1625 	GtkWidget*  dialog;
1626 	gchar*      title;
1627 
1628 	title = g_strconcat (UGTK_APP_NAME " - ", _("Export URLs to text file"), NULL);
1629 	dialog = create_file_chooser (app->window.self,
1630 			GTK_FILE_CHOOSER_ACTION_SAVE,
1631 			title, NULL, NULL);
1632 	g_free (title);
1633 	g_signal_connect (dialog, "response",
1634 			G_CALLBACK (on_export_text_file_response), app);
1635 	gtk_widget_show (dialog);
1636 }
1637 
1638 // ------------------------------------
1639 // batch
1640 
ugtk_app_sequence_batch(UgtkApp * app)1641 void  ugtk_app_sequence_batch (UgtkApp* app)
1642 {
1643 	UgtkBatchDialog* bdialog;
1644 	UgetNode*  cnode;
1645 	gchar*     title;
1646 
1647 	title = g_strconcat (UGTK_APP_NAME " - ", _("URL Sequence batch"), NULL);
1648 	bdialog = ugtk_batch_dialog_new (title, app);
1649 	g_free (title);
1650 	ugtk_batch_dialog_use_sequencer (bdialog);
1651 	ugtk_download_form_set_folders (&bdialog->download, &app->setting);
1652 
1653 	// category list
1654 	cnode = app->traveler.category.cursor.node->base;
1655 	if (cnode->parent != &app->real)
1656 		cnode = app->real.children;
1657 	ugtk_batch_dialog_set_category (bdialog, cnode);
1658 
1659 	ugtk_batch_dialog_run (bdialog);
1660 }
1661 
ugtk_app_clipboard_batch(UgtkApp * app)1662 void  ugtk_app_clipboard_batch (UgtkApp* app)
1663 {
1664 	UgtkBatchDialog*  bdialog;
1665 	UgtkSelectorPage* page;
1666 	UgetNode*  cnode;
1667 	GList*     list;
1668 	gchar*     title;
1669 
1670 	list = ugtk_clipboard_get_uris (&app->clipboard);
1671 	if (list == NULL) {
1672 		ugtk_app_show_message (app, GTK_MESSAGE_ERROR,
1673 				_("No URLs found in clipboard."));
1674 		return;
1675 	}
1676 	// filter existing
1677 	if (app->setting.ui.skip_existing) {
1678 		if (ugtk_app_filter_existing (app, list) == 0) {
1679 //			g_list_foreach (list, (GFunc) g_free, NULL);
1680 			g_list_free (list);
1681 			ugtk_app_show_message (app, GTK_MESSAGE_INFO,
1682 					_("All URLs had existed."));
1683 			return;
1684 		}
1685 	}
1686 
1687 	title = g_strconcat (UGTK_APP_NAME " - ", _("Clipboard batch"), NULL);
1688 	bdialog = ugtk_batch_dialog_new (title, app);
1689 	g_free (title);
1690 	ugtk_download_form_set_folders (&bdialog->download, &app->setting);
1691 	ugtk_batch_dialog_use_selector (bdialog);
1692 	// selector
1693 	ugtk_selector_hide_href (&bdialog->selector);
1694 	page = ugtk_selector_add_page (&bdialog->selector, _("Clipboard"));
1695 	ugtk_selector_page_add_uris (page, list);
1696 	g_list_free (list);
1697 
1698 	// category list
1699 	cnode = app->traveler.category.cursor.node->base;
1700 	if (cnode->parent != &app->real)
1701 		cnode = app->real.children;
1702 	ugtk_batch_dialog_set_category (bdialog, cnode);
1703 
1704 	ugtk_batch_dialog_run (bdialog);
1705 }
1706 
ugtk_app_filter_existing(UgtkApp * app,GList * uris)1707 int   ugtk_app_filter_existing (UgtkApp* app, GList* uris)
1708 {
1709 	int  counts;
1710 
1711 	for (counts = 0;  uris;  uris = uris->next) {
1712 		if (uris->data == NULL)
1713 			continue;
1714 		if (uget_uri_hash_find (app->uri_hash, (char*) uris->data) == FALSE)
1715 			counts++;
1716 		else {
1717 			g_free (uris->data);
1718 			uris->data = NULL;
1719 		}
1720 	}
1721 	return counts;
1722 }
1723 
1724 // ------------------------------------
1725 // emit signal "row-changed" for UgtkNodeTree and UgtkNodeList
1726 
ugtk_app_download_changed(UgtkApp * app,UgetNode * dnode)1727 void  ugtk_app_download_changed (UgtkApp* app, UgetNode* dnode)
1728 {
1729 	GtkTreeModel* model;
1730 	GtkTreePath*  path;
1731 	GtkTreeIter   iter;
1732 
1733 	if (ugtk_traveler_get_iter (&app->traveler, &iter, dnode)) {
1734 		model = GTK_TREE_MODEL (app->traveler.download.model);
1735 		path = gtk_tree_model_get_path (model, &iter);
1736 		if (path) {
1737 			gtk_tree_model_row_changed (model, path, &iter);
1738 			gtk_tree_path_free (path);
1739 		}
1740 	}
1741 }
1742 
ugtk_app_category_changed(UgtkApp * app,UgetNode * cnode)1743 void  ugtk_app_category_changed (UgtkApp* app, UgetNode* cnode)
1744 {
1745 	GtkTreeIter   iter;
1746 	GtkTreePath*  path;
1747 	GtkTreeModel* model;
1748 
1749 	model = GTK_TREE_MODEL (app->traveler.category.model);
1750 	if (app->traveler.category.cursor.pos > 0) {
1751 		iter.stamp = app->traveler.category.model->stamp;
1752 		iter.user_data = cnode;
1753 		// update category
1754 		path = gtk_tree_model_get_path (model, &iter);
1755 		gtk_tree_model_row_changed (model, path, &iter);
1756 		gtk_tree_path_free (path);
1757 	}
1758 	// update "All Category"
1759 	path = gtk_tree_path_new_first ();
1760 	gtk_tree_model_get_iter_first (model, &iter);
1761 	gtk_tree_model_row_changed (model, path, &iter);
1762 	gtk_tree_path_free (path);
1763 
1764 	// refresh status list
1765 	gtk_widget_queue_draw ((GtkWidget*) app->traveler.state.view);
1766 }
1767 
ugtk_app_add_default_category(UgtkApp * app)1768 void  ugtk_app_add_default_category (UgtkApp* app)
1769 {
1770 	UgetNode*     cnode;
1771 	UgetCommon*   common;
1772 	UgetCategory* category;
1773 	static int    counts = 0;
1774 
1775 	cnode = uget_node_new (NULL);
1776 	common = ug_data_realloc (cnode->data, UgetCommonInfo);
1777 	common->name = ug_strdup_printf ("%s %d", _("New"), counts++);
1778 	common->folder = ug_strdup (g_get_home_dir ());
1779 	category = ug_data_realloc (cnode->data, UgetCategoryInfo);
1780 	*(char**)ug_array_alloc (&category->schemes, 1) = ug_strdup ("ftps");
1781 	*(char**)ug_array_alloc (&category->schemes, 1) = ug_strdup ("magnet");
1782 	*(char**)ug_array_alloc (&category->hosts, 1) = ug_strdup (".edu");
1783 	*(char**)ug_array_alloc (&category->hosts, 1) = ug_strdup (".idv");
1784 	*(char**)ug_array_alloc (&category->file_exts, 1) = ug_strdup ("torrent");
1785 	*(char**)ug_array_alloc (&category->file_exts, 1) = ug_strdup ("metalink");
1786 
1787 	uget_app_add_category ((UgetApp*) app, cnode, TRUE);
1788 }
1789 
1790 // ------------------------------------
1791 // others
1792 
on_message_response(GtkWidget * dialog,gint response,GtkWidget ** value)1793 static void  on_message_response (GtkWidget* dialog, gint response, GtkWidget** value)
1794 {
1795 	gtk_widget_destroy (dialog);
1796 	*value = NULL;
1797 }
1798 
ugtk_app_show_message(UgtkApp * app,GtkMessageType type,const gchar * message)1799 void  ugtk_app_show_message (UgtkApp* app, GtkMessageType type,
1800                              const gchar* message)
1801 {
1802 	GtkWidget*		dialog;
1803 	GtkWidget**		value;
1804 	gchar*			title;
1805 
1806 	dialog = gtk_message_dialog_new (app->window.self,
1807 			GTK_DIALOG_DESTROY_WITH_PARENT,
1808 			type, GTK_BUTTONS_OK,
1809 			"%s", message);
1810 	// set title
1811 	switch (type) {
1812 	case GTK_MESSAGE_ERROR:
1813 		if (app->dialogs.error)
1814 			gtk_widget_destroy (app->dialogs.error);
1815 		app->dialogs.error = dialog;
1816 		value = &app->dialogs.error;
1817 		title = g_strconcat (UGTK_APP_NAME " - ", _("Error"), NULL);
1818 		break;
1819 
1820 	default:
1821 		if (app->dialogs.message)
1822 			gtk_widget_destroy (app->dialogs.message);
1823 		app->dialogs.message = dialog;
1824 		value = &app->dialogs.message;
1825 		title = g_strconcat (UGTK_APP_NAME " - ", _("Message"), NULL);
1826 		break;
1827 	}
1828 	gtk_window_set_title ((GtkWindow*) dialog, title);
1829 	g_free (title);
1830 	// signal handler
1831 	g_signal_connect (dialog, "response",
1832 			G_CALLBACK (on_message_response), value);
1833 	gtk_widget_show (dialog);
1834 }
1835 
1836 // -------------------------------------------------------
1837 // UgtkClipboard
1838 
ugtk_clipboard_init(struct UgtkClipboard * clipboard,const gchar * pattern)1839 void  ugtk_clipboard_init (struct UgtkClipboard* clipboard, const gchar* pattern)
1840 {
1841 	clipboard->self  = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
1842 	clipboard->text  = NULL;
1843 	clipboard->regex = g_regex_new (pattern, G_REGEX_CASELESS, 0, NULL);
1844 	clipboard->website = TRUE;
1845 }
1846 
ugtk_clipboard_set_pattern(struct UgtkClipboard * clipboard,const gchar * pattern)1847 void  ugtk_clipboard_set_pattern (struct UgtkClipboard* clipboard, const gchar* pattern)
1848 {
1849 	if (clipboard->regex)
1850 		g_regex_unref (clipboard->regex);
1851 
1852 	if (pattern)
1853 		clipboard->regex = g_regex_new (pattern, G_REGEX_CASELESS, 0, NULL);
1854 	else
1855 		clipboard->regex = g_regex_new ("", G_REGEX_CASELESS, 0, NULL);
1856 }
1857 
ugtk_clipboard_set_text(struct UgtkClipboard * clipboard,gchar * text)1858 void  ugtk_clipboard_set_text (struct UgtkClipboard* clipboard, gchar* text)
1859 {
1860 	g_free (clipboard->text);
1861 	clipboard->text = text;
1862 	gtk_clipboard_set_text (clipboard->self, text, -1);
1863 }
1864 
ugtk_clipboard_get_uris(struct UgtkClipboard * clipboard)1865 GList* ugtk_clipboard_get_uris (struct UgtkClipboard* clipboard)
1866 {
1867 	GList*		list;
1868 	gchar*		text;
1869 
1870 	if (gtk_clipboard_wait_is_text_available (clipboard->self) == FALSE)
1871 		return NULL;
1872 	text = gtk_clipboard_wait_for_text (clipboard->self);
1873 	if (text == NULL)
1874 		return NULL;
1875 	// get URIs that scheme is not "file" from text
1876 	list = ugtk_text_get_uris (text);
1877 	list = ugtk_uri_list_remove_scheme (list, "file");
1878 	g_free (text);
1879 
1880 	return list;
1881 }
1882 
ugtk_clipboard_get_matched(struct UgtkClipboard * clipboard,const gchar * text)1883 GList* ugtk_clipboard_get_matched (struct UgtkClipboard* clipboard, const gchar* text)
1884 {
1885 	GList*		link;
1886 	GList*		list;
1887 	gchar*		temp;
1888 
1889 	if (text == NULL) {
1890 		g_free (clipboard->text);
1891 		clipboard->text = NULL;
1892 		return NULL;
1893 	}
1894 	// compare
1895 	temp = (clipboard->text) ? clipboard->text : "";
1896 	if (g_ascii_strcasecmp (text, temp) == 0)
1897 		return NULL;
1898 	// replace text
1899 	g_free (clipboard->text);
1900 	clipboard->text = g_strdup (text);
1901 	// get and filter list
1902 	list = ugtk_text_get_uris (text);
1903 	list = ugtk_uri_list_remove_scheme (list, "file");
1904 	// filter by filename extension
1905 	for (link = list;  link;  link = link->next) {
1906 		temp = ug_filename_from_uri (link->data);
1907 		// get filename extension
1908 		if (temp)
1909 			text = strrchr (temp, '.');
1910 		else
1911 			text = NULL;
1912 		// free URIs if not matched
1913 		if (text == NULL || g_regex_match (clipboard->regex, text+1, 0, NULL) == FALSE) {
1914 			// storage or media website
1915 			if (clipboard->website == FALSE ||
1916 			     uget_site_get_id (link->data) == UGET_SITE_UNKNOWN)
1917 			{
1918 				g_free (link->data);
1919 				link->data = NULL;
1920 			}
1921 		}
1922 		ug_free (temp);
1923 	}
1924 	list = g_list_remove_all (list, NULL);
1925 	return list;
1926 }
1927 
1928 // -------------------------------------------------------
1929 // UgtkStatusbar
1930 
ugtk_statusbar_set_info(struct UgtkStatusbar * statusbar,gint n_selected)1931 void  ugtk_statusbar_set_info (struct UgtkStatusbar* statusbar, gint n_selected)
1932 {
1933 	static guint	context_id = 0;
1934 	gchar*			string;
1935 
1936 	if (context_id == 0)
1937 		context_id = gtk_statusbar_get_context_id (statusbar->self, "selected");
1938 	gtk_statusbar_pop  (statusbar->self, context_id);
1939 
1940 	if (n_selected > 0) {
1941 		string = g_strdup_printf (_("Selected %d items"), n_selected);
1942 		gtk_statusbar_push (statusbar->self, context_id, string);
1943 		g_free (string);
1944 	}
1945 }
1946 
ugtk_statusbar_set_speed(struct UgtkStatusbar * statusbar,gint64 down_speed,gint64 up_speed)1947 void  ugtk_statusbar_set_speed (struct UgtkStatusbar* statusbar, gint64 down_speed, gint64 up_speed)
1948 {
1949 	char*		string;
1950 
1951 	string = ug_str_from_int_unit (down_speed, "/s");
1952 	gtk_label_set_text (statusbar->down_speed, string);
1953 	ug_free (string);
1954 
1955 	string = ug_str_from_int_unit (up_speed, "/s");
1956 	gtk_label_set_text (statusbar->up_speed, string);
1957 	ug_free (string);
1958 }
1959 
1960