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