1 /* vi:set et ai sw=2 sts=2 ts=2: */
2 /*-
3 * Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the Free
17 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #ifdef HAVE_MEMORY_H
26 #include <memory.h>
27 #endif
28 #ifdef HAVE_STRING_H
29 #include <string.h>
30 #endif
31
32 #include <exo/exo.h>
33
34 #include <thunar/thunar-enum-types.h>
35 #include <thunar/thunar-job.h>
36 #include <thunar/thunar-marshal.h>
37 #include <thunar/thunar-private.h>
38
39
40
41 /* Signal identifiers */
42 enum
43 {
44 ASK,
45 ASK_REPLACE,
46 ASK_JOBS,
47 FILES_READY,
48 NEW_FILES,
49 FROZEN,
50 UNFROZEN,
51 LAST_SIGNAL,
52 };
53
54
55
56 static void thunar_job_finalize (GObject *object);
57 static ThunarJobResponse thunar_job_real_ask (ThunarJob *job,
58 const gchar *message,
59 ThunarJobResponse choices);
60 static ThunarJobResponse thunar_job_real_ask_replace (ThunarJob *job,
61 ThunarFile *source_file,
62 ThunarFile *target_file);
63
64
65
66 struct _ThunarJobPrivate
67 {
68 ThunarJobResponse earlier_ask_create_response;
69 ThunarJobResponse earlier_ask_overwrite_response;
70 ThunarJobResponse earlier_ask_delete_response;
71 ThunarJobResponse earlier_ask_skip_response;
72 GList *total_files;
73 guint n_total_files;
74 gboolean pausable;
75 gboolean paused; /* the job has been manually paused using the UI */
76 gboolean frozen; /* the job has been automaticaly paused regarding some parallel copy behavior */
77 };
78
79
80
81 static guint job_signals[LAST_SIGNAL];
82
83
84
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(ThunarJob,thunar_job,EXO_TYPE_JOB)85 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ThunarJob, thunar_job, EXO_TYPE_JOB)
86
87
88
89 static gboolean
90 _thunar_job_ask_accumulator (GSignalInvocationHint *ihint,
91 GValue *return_accu,
92 const GValue *handler_return,
93 gpointer data)
94 {
95 g_value_copy (handler_return, return_accu);
96 return FALSE;
97 }
98
99
100
101 static void
thunar_job_class_init(ThunarJobClass * klass)102 thunar_job_class_init (ThunarJobClass *klass)
103 {
104 GObjectClass *gobject_class;
105
106 gobject_class = G_OBJECT_CLASS (klass);
107 gobject_class->finalize = thunar_job_finalize;
108
109 klass->ask = thunar_job_real_ask;
110 klass->ask_replace = thunar_job_real_ask_replace;
111
112 /**
113 * ThunarJob::ask:
114 * @job : a #ThunarJob.
115 * @message : question to display to the user.
116 * @choices : a combination of #ThunarJobResponse<!---->s.
117 *
118 * The @message is garantied to contain valid UTF-8.
119 *
120 * Return value: the selected choice.
121 **/
122 job_signals[ASK] =
123 g_signal_new (I_("ask"),
124 G_TYPE_FROM_CLASS (klass),
125 G_SIGNAL_NO_HOOKS | G_SIGNAL_RUN_LAST,
126 G_STRUCT_OFFSET (ThunarJobClass, ask),
127 _thunar_job_ask_accumulator, NULL,
128 _thunar_marshal_FLAGS__STRING_FLAGS,
129 THUNAR_TYPE_JOB_RESPONSE,
130 2, G_TYPE_STRING,
131 THUNAR_TYPE_JOB_RESPONSE);
132
133 /**
134 * ThunarJob::ask-replace:
135 * @job : a #ThunarJob.
136 * @src_file : the #ThunarFile of the source file.
137 * @dst_file : the #ThunarFile of the destination file, that
138 * may be replaced with the source file.
139 *
140 * Emitted to ask the user whether the destination file should
141 * be replaced by the source file.
142 *
143 * Return value: the selected choice.
144 **/
145 job_signals[ASK_REPLACE] =
146 g_signal_new (I_("ask-replace"),
147 G_TYPE_FROM_CLASS (klass),
148 G_SIGNAL_NO_HOOKS | G_SIGNAL_RUN_LAST,
149 G_STRUCT_OFFSET (ThunarJobClass, ask_replace),
150 _thunar_job_ask_accumulator, NULL,
151 _thunar_marshal_FLAGS__OBJECT_OBJECT,
152 THUNAR_TYPE_JOB_RESPONSE,
153 2, THUNAR_TYPE_FILE, THUNAR_TYPE_FILE);
154
155 /**
156 * ThunarJob::files-ready:
157 * @job : a #ThunarJob.
158 * @file_list : a list of #ThunarFile<!---->s.
159 *
160 * This signal is used by #ThunarJob<!---->s returned by
161 * the thunar_io_jobs_list_directory() function whenever
162 * there's a bunch of #ThunarFile<!---->s ready. This signal
163 * is garantied to be never emitted with an @file_list
164 * parameter of %NULL.
165 *
166 * To allow some further optimizations on the handler-side,
167 * the handler is allowed to take over ownership of the
168 * @file_list, i.e. it can reuse the @infos list and just replace
169 * the data elements with it's own objects based on the
170 * #ThunarFile<!---->s contained within the @file_list (and
171 * of course properly unreffing the previously contained infos).
172 * If a handler takes over ownership of @file_list it must return
173 * %TRUE here, and no further handlers will be run. Else, if
174 * the handler doesn't want to take over ownership of @infos,
175 * it must return %FALSE, and other handlers will be run. Use
176 * this feature with care, and only if you can be sure that
177 * you are the only handler connected to this signal for a
178 * given job!
179 *
180 * Return value: %TRUE if the handler took over ownership of
181 * @file_list, else %FALSE.
182 **/
183 job_signals[FILES_READY] =
184 g_signal_new (I_("files-ready"),
185 G_TYPE_FROM_CLASS (klass), G_SIGNAL_NO_HOOKS,
186 0, g_signal_accumulator_true_handled, NULL,
187 _thunar_marshal_BOOLEAN__POINTER,
188 G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);
189
190 /**
191 * ThunarJob::new-files:
192 * @job : a #ThunarJob.
193 * @file_list : a list of #GFile<!---->s that were created by @job.
194 *
195 * This signal is emitted by the @job right before the @job is terminated
196 * and informs the application about the list of created files in @file_list.
197 * @file_list contains only the toplevel file items, that were specified by
198 * the application on creation of the @job.
199 **/
200 job_signals[NEW_FILES] =
201 g_signal_new (I_("new-files"),
202 G_TYPE_FROM_CLASS (klass),
203 G_SIGNAL_NO_HOOKS, 0, NULL, NULL,
204 g_cclosure_marshal_VOID__POINTER,
205 G_TYPE_NONE, 1, G_TYPE_POINTER);
206
207 /**
208 * ThunarJob::ask-jobs:
209 * @job : a #ThunarJob.
210 *
211 * Emitted to ask the running job list.
212 *
213 * Return value: GList* of running jobs.
214 **/
215 job_signals[ASK_JOBS] =
216 g_signal_new (I_("ask-jobs"),
217 G_TYPE_FROM_CLASS (klass),
218 G_SIGNAL_NO_HOOKS, 0,
219 NULL, NULL,
220 g_cclosure_marshal_generic,
221 G_TYPE_POINTER, 0);
222
223 /**
224 * ThunarJob::frozen:
225 * @job : a #ThunarJob.
226 *
227 * This signal is emitted by the @job right after the @job is being frozen.
228 **/
229 job_signals[FROZEN] =
230 g_signal_new (I_("frozen"),
231 G_TYPE_FROM_CLASS (klass),
232 G_SIGNAL_NO_HOOKS, 0,
233 NULL, NULL,
234 g_cclosure_marshal_generic,
235 G_TYPE_NONE, 0);
236
237 /**
238 * ThunarJob::unfrozen:
239 * @job : a #ThunarJob.
240 *
241 * This signal is emitted by the @job right after the @job is being unfrozen.
242 **/
243 job_signals[UNFROZEN] =
244 g_signal_new (I_("unfrozen"),
245 G_TYPE_FROM_CLASS (klass),
246 G_SIGNAL_NO_HOOKS, 0,
247 NULL, NULL,
248 g_cclosure_marshal_generic,
249 G_TYPE_NONE, 0);
250 }
251
252
253
254 static void
thunar_job_init(ThunarJob * job)255 thunar_job_init (ThunarJob *job)
256 {
257 job->priv = thunar_job_get_instance_private (job);
258 job->priv->earlier_ask_create_response = 0;
259 job->priv->earlier_ask_overwrite_response = 0;
260 job->priv->earlier_ask_delete_response = 0;
261 job->priv->earlier_ask_skip_response = 0;
262 job->priv->n_total_files = 0;
263 job->priv->pausable = FALSE;
264 job->priv->paused = FALSE;
265 job->priv->frozen = FALSE;
266 }
267
268
269
270 static void
thunar_job_finalize(GObject * object)271 thunar_job_finalize (GObject *object)
272 {
273 (*G_OBJECT_CLASS (thunar_job_parent_class)->finalize) (object);
274 }
275
276
277
278 static ThunarJobResponse
thunar_job_real_ask(ThunarJob * job,const gchar * message,ThunarJobResponse choices)279 thunar_job_real_ask (ThunarJob *job,
280 const gchar *message,
281 ThunarJobResponse choices)
282 {
283 ThunarJobResponse response;
284
285 _thunar_return_val_if_fail (THUNAR_IS_JOB (job), THUNAR_JOB_RESPONSE_CANCEL);
286 g_signal_emit (job, job_signals[ASK], 0, message, choices, &response);
287 return response;
288 }
289
290
291
292 static ThunarJobResponse
thunar_job_real_ask_replace(ThunarJob * job,ThunarFile * source_file,ThunarFile * target_file)293 thunar_job_real_ask_replace (ThunarJob *job,
294 ThunarFile *source_file,
295 ThunarFile *target_file)
296 {
297 ThunarJobResponse response;
298 gchar *message;
299
300 _thunar_return_val_if_fail (THUNAR_IS_JOB (job), THUNAR_JOB_RESPONSE_CANCEL);
301 _thunar_return_val_if_fail (THUNAR_IS_FILE (source_file), THUNAR_JOB_RESPONSE_CANCEL);
302 _thunar_return_val_if_fail (THUNAR_IS_FILE (target_file), THUNAR_JOB_RESPONSE_CANCEL);
303
304 message = g_strdup_printf (_("The file \"%s\" already exists. Would you like to replace it?\n\n"
305 "If you replace an existing file, its contents will be overwritten."),
306 thunar_file_get_display_name (source_file));
307
308 g_signal_emit (job, job_signals[ASK], 0, message,
309 THUNAR_JOB_RESPONSE_REPLACE
310 | THUNAR_JOB_RESPONSE_REPLACE_ALL
311 | THUNAR_JOB_RESPONSE_RENAME
312 | THUNAR_JOB_RESPONSE_RENAME_ALL
313 | THUNAR_JOB_RESPONSE_SKIP
314 | THUNAR_JOB_RESPONSE_SKIP_ALL
315 | THUNAR_JOB_RESPONSE_CANCEL,
316 &response);
317
318 /* clean up */
319 g_free (message);
320
321 return response;
322 }
323
324
325
326 static ThunarJobResponse
_thunar_job_ask_valist(ThunarJob * job,const gchar * format,va_list var_args,const gchar * question,ThunarJobResponse choices)327 _thunar_job_ask_valist (ThunarJob *job,
328 const gchar *format,
329 va_list var_args,
330 const gchar *question,
331 ThunarJobResponse choices)
332 {
333 ThunarJobResponse response;
334 gchar *text;
335 gchar *message;
336
337 _thunar_return_val_if_fail (THUNAR_IS_JOB (job), THUNAR_JOB_RESPONSE_CANCEL);
338 _thunar_return_val_if_fail (g_utf8_validate (format, -1, NULL), THUNAR_JOB_RESPONSE_CANCEL);
339
340 /* generate the dialog message */
341 text = g_strdup_vprintf (format, var_args);
342 message = (question != NULL)
343 ? g_strconcat (text, ".\n\n", question, NULL)
344 : g_strconcat (text, ".", NULL);
345 g_free (text);
346
347 /* send the question and wait for the answer */
348 exo_job_emit (EXO_JOB (job), job_signals[ASK], 0, message, choices, &response);
349 g_free (message);
350
351 /* cancel the job as per users request */
352 if (G_UNLIKELY (response == THUNAR_JOB_RESPONSE_CANCEL))
353 exo_job_cancel (EXO_JOB (job));
354
355 return response;
356 }
357
358
359
360 ThunarJobResponse
thunar_job_ask_overwrite(ThunarJob * job,const gchar * format,...)361 thunar_job_ask_overwrite (ThunarJob *job,
362 const gchar *format,
363 ...)
364 {
365 ThunarJobResponse response;
366 va_list var_args;
367
368 _thunar_return_val_if_fail (THUNAR_IS_JOB (job), THUNAR_JOB_RESPONSE_CANCEL);
369 _thunar_return_val_if_fail (format != NULL, THUNAR_JOB_RESPONSE_CANCEL);
370
371 /* check if the user already cancelled the job */
372 if (G_UNLIKELY (exo_job_is_cancelled (EXO_JOB (job))))
373 return THUNAR_JOB_RESPONSE_CANCEL;
374
375 /* check if the user said "Overwrite All" earlier */
376 if (G_UNLIKELY (job->priv->earlier_ask_overwrite_response == THUNAR_JOB_RESPONSE_REPLACE_ALL))
377 return THUNAR_JOB_RESPONSE_REPLACE;
378
379 /* check if the user said "Overwrite None" earlier */
380 if (G_UNLIKELY (job->priv->earlier_ask_overwrite_response == THUNAR_JOB_RESPONSE_SKIP_ALL))
381 return THUNAR_JOB_RESPONSE_SKIP;
382
383 /* ask the user what he wants to do */
384 va_start (var_args, format);
385 response = _thunar_job_ask_valist (job, format, var_args,
386 _("Do you want to overwrite it?"),
387 THUNAR_JOB_RESPONSE_REPLACE
388 | THUNAR_JOB_RESPONSE_REPLACE_ALL
389 | THUNAR_JOB_RESPONSE_SKIP
390 | THUNAR_JOB_RESPONSE_SKIP_ALL
391 | THUNAR_JOB_RESPONSE_CANCEL);
392 va_end (var_args);
393
394 /* remember response for later */
395 job->priv->earlier_ask_overwrite_response = response;
396
397 /* translate response */
398 switch (response)
399 {
400 case THUNAR_JOB_RESPONSE_REPLACE_ALL:
401 response = THUNAR_JOB_RESPONSE_REPLACE;
402 break;
403
404 case THUNAR_JOB_RESPONSE_SKIP_ALL:
405 response = THUNAR_JOB_RESPONSE_SKIP;
406 break;
407
408 default:
409 break;
410 }
411
412 return response;
413 }
414
415
416
417 ThunarJobResponse
thunar_job_ask_delete(ThunarJob * job,const gchar * format,...)418 thunar_job_ask_delete (ThunarJob *job,
419 const gchar *format,
420 ...)
421 {
422 ThunarJobResponse response;
423 va_list var_args;
424
425 _thunar_return_val_if_fail (THUNAR_IS_JOB (job), THUNAR_JOB_RESPONSE_CANCEL);
426 _thunar_return_val_if_fail (format != NULL, THUNAR_JOB_RESPONSE_CANCEL);
427
428 /* check if the user already cancelled the job */
429 if (G_UNLIKELY (exo_job_is_cancelled (EXO_JOB (job))))
430 return THUNAR_JOB_RESPONSE_CANCEL;
431
432 /* check if the user said "Delete All" earlier */
433 if (G_UNLIKELY (job->priv->earlier_ask_delete_response == THUNAR_JOB_RESPONSE_YES_ALL))
434 return THUNAR_JOB_RESPONSE_YES;
435
436 /* check if the user said "Delete None" earlier */
437 if (G_UNLIKELY (job->priv->earlier_ask_delete_response == THUNAR_JOB_RESPONSE_NO_ALL))
438 return THUNAR_JOB_RESPONSE_NO;
439
440 /* ask the user what he wants to do */
441 va_start (var_args, format);
442 response = _thunar_job_ask_valist (job, format, var_args,
443 _("Do you want to permanently delete it?"),
444 THUNAR_JOB_RESPONSE_YES
445 | THUNAR_JOB_RESPONSE_YES_ALL
446 | THUNAR_JOB_RESPONSE_NO
447 | THUNAR_JOB_RESPONSE_NO_ALL
448 | THUNAR_JOB_RESPONSE_CANCEL);
449 va_end (var_args);
450
451 /* remember response for later */
452 job->priv->earlier_ask_delete_response = response;
453
454 /* translate response */
455 switch (response)
456 {
457 case THUNAR_JOB_RESPONSE_YES_ALL:
458 response = THUNAR_JOB_RESPONSE_YES;
459 break;
460
461 case THUNAR_JOB_RESPONSE_NO_ALL:
462 response = THUNAR_JOB_RESPONSE_NO;
463 break;
464
465 default:
466 break;
467 }
468
469 return response;
470 }
471
472
473
474 ThunarJobResponse
thunar_job_ask_create(ThunarJob * job,const gchar * format,...)475 thunar_job_ask_create (ThunarJob *job,
476 const gchar *format,
477 ...)
478 {
479 ThunarJobResponse response;
480 va_list var_args;
481
482 _thunar_return_val_if_fail (THUNAR_IS_JOB (job), THUNAR_JOB_RESPONSE_CANCEL);
483
484 if (G_UNLIKELY (exo_job_is_cancelled (EXO_JOB (job))))
485 return THUNAR_JOB_RESPONSE_CANCEL;
486
487 /* check if the user said "Create All" earlier */
488 if (G_UNLIKELY (job->priv->earlier_ask_create_response == THUNAR_JOB_RESPONSE_YES_ALL))
489 return THUNAR_JOB_RESPONSE_YES;
490
491 /* check if the user said "Create None" earlier */
492 if (G_UNLIKELY (job->priv->earlier_ask_create_response == THUNAR_JOB_RESPONSE_NO_ALL))
493 return THUNAR_JOB_RESPONSE_NO;
494
495 va_start (var_args, format);
496 response = _thunar_job_ask_valist (job, format, var_args,
497 _("Do you want to create it?"),
498 THUNAR_JOB_RESPONSE_YES
499 | THUNAR_JOB_RESPONSE_CANCEL);
500 va_end (var_args);
501
502 job->priv->earlier_ask_create_response = response;
503
504 /* translate the response */
505 if (response == THUNAR_JOB_RESPONSE_YES_ALL)
506 response = THUNAR_JOB_RESPONSE_YES;
507 else if (response == THUNAR_JOB_RESPONSE_NO_ALL)
508 response = THUNAR_JOB_RESPONSE_NO;
509 else if (response == THUNAR_JOB_RESPONSE_CANCEL)
510 exo_job_cancel (EXO_JOB (job));
511
512 return response;
513 }
514
515
516
517 ThunarJobResponse
thunar_job_ask_replace(ThunarJob * job,GFile * source_path,GFile * target_path,GError ** error)518 thunar_job_ask_replace (ThunarJob *job,
519 GFile *source_path,
520 GFile *target_path,
521 GError **error)
522 {
523 ThunarJobResponse response;
524 ThunarFile *source_file;
525 ThunarFile *target_file;
526
527 _thunar_return_val_if_fail (THUNAR_IS_JOB (job), THUNAR_JOB_RESPONSE_CANCEL);
528 _thunar_return_val_if_fail (G_IS_FILE (source_path), THUNAR_JOB_RESPONSE_CANCEL);
529 _thunar_return_val_if_fail (G_IS_FILE (target_path), THUNAR_JOB_RESPONSE_CANCEL);
530
531 if (G_UNLIKELY (exo_job_set_error_if_cancelled (EXO_JOB (job), error)))
532 return THUNAR_JOB_RESPONSE_CANCEL;
533
534 /* check if the user said "Overwrite All" earlier */
535 if (G_UNLIKELY (job->priv->earlier_ask_overwrite_response == THUNAR_JOB_RESPONSE_REPLACE_ALL))
536 return THUNAR_JOB_RESPONSE_REPLACE;
537
538 /* check if the user said "Rename All" earlier */
539 if (G_UNLIKELY (job->priv->earlier_ask_overwrite_response == THUNAR_JOB_RESPONSE_RENAME_ALL))
540 return THUNAR_JOB_RESPONSE_RENAME;
541
542 /* check if the user said "Overwrite None" earlier */
543 if (G_UNLIKELY (job->priv->earlier_ask_overwrite_response == THUNAR_JOB_RESPONSE_SKIP_ALL))
544 return THUNAR_JOB_RESPONSE_SKIP;
545
546 source_file = thunar_file_get (source_path, error);
547
548 if (G_UNLIKELY (source_file == NULL))
549 return THUNAR_JOB_RESPONSE_SKIP;
550
551 target_file = thunar_file_get (target_path, error);
552
553 if (G_UNLIKELY (target_file == NULL))
554 {
555 g_object_unref (source_file);
556 return THUNAR_JOB_RESPONSE_SKIP;
557 }
558
559 exo_job_emit (EXO_JOB (job), job_signals[ASK_REPLACE], 0,
560 source_file, target_file, &response);
561
562 g_object_unref (source_file);
563 g_object_unref (target_file);
564
565 /* remember the response for later */
566 job->priv->earlier_ask_overwrite_response = response;
567
568 /* translate the response */
569 if (response == THUNAR_JOB_RESPONSE_REPLACE_ALL)
570 response = THUNAR_JOB_RESPONSE_REPLACE;
571 else if (response == THUNAR_JOB_RESPONSE_RENAME_ALL)
572 response = THUNAR_JOB_RESPONSE_RENAME;
573 else if (response == THUNAR_JOB_RESPONSE_SKIP_ALL)
574 response = THUNAR_JOB_RESPONSE_SKIP;
575 else if (response == THUNAR_JOB_RESPONSE_CANCEL)
576 exo_job_cancel (EXO_JOB (job));
577
578 return response;
579 }
580
581
582
583 ThunarJobResponse
thunar_job_ask_skip(ThunarJob * job,const gchar * format,...)584 thunar_job_ask_skip (ThunarJob *job,
585 const gchar *format,
586 ...)
587 {
588 ThunarJobResponse response;
589 va_list var_args;
590
591 _thunar_return_val_if_fail (THUNAR_IS_JOB (job), THUNAR_JOB_RESPONSE_CANCEL);
592 _thunar_return_val_if_fail (format != NULL, THUNAR_JOB_RESPONSE_CANCEL);
593
594 /* check if the user already cancelled the job */
595 if (G_UNLIKELY (exo_job_is_cancelled (EXO_JOB (job))))
596 return THUNAR_JOB_RESPONSE_CANCEL;
597
598 /* check if the user said "Skip All" earlier */
599 if (G_UNLIKELY (job->priv->earlier_ask_skip_response == THUNAR_JOB_RESPONSE_SKIP_ALL))
600 return THUNAR_JOB_RESPONSE_SKIP;
601
602 /* ask the user what he wants to do */
603 va_start (var_args, format);
604 response = _thunar_job_ask_valist (job, format, var_args,
605 _("Do you want to skip it?"),
606 THUNAR_JOB_RESPONSE_SKIP
607 | THUNAR_JOB_RESPONSE_SKIP_ALL
608 | THUNAR_JOB_RESPONSE_CANCEL
609 | THUNAR_JOB_RESPONSE_RETRY);
610 va_end (var_args);
611
612 /* remember the response */
613 job->priv->earlier_ask_skip_response = response;
614
615 /* translate the response */
616 switch (response)
617 {
618 case THUNAR_JOB_RESPONSE_SKIP_ALL:
619 response = THUNAR_JOB_RESPONSE_SKIP;
620 break;
621
622 case THUNAR_JOB_RESPONSE_SKIP:
623 case THUNAR_JOB_RESPONSE_CANCEL:
624 case THUNAR_JOB_RESPONSE_RETRY:
625 break;
626
627 default:
628 _thunar_assert_not_reached ();
629 }
630
631 return response;
632 }
633
634
635
636 gboolean
thunar_job_ask_no_size(ThunarJob * job,const gchar * format,...)637 thunar_job_ask_no_size (ThunarJob *job,
638 const gchar *format,
639 ...)
640 {
641 ThunarJobResponse response;
642 va_list var_args;
643
644 _thunar_return_val_if_fail (THUNAR_IS_JOB (job), THUNAR_JOB_RESPONSE_CANCEL);
645 _thunar_return_val_if_fail (format != NULL, THUNAR_JOB_RESPONSE_CANCEL);
646
647 /* check if the user already cancelled the job */
648 if (G_UNLIKELY (exo_job_is_cancelled (EXO_JOB (job))))
649 return THUNAR_JOB_RESPONSE_CANCEL;
650
651 /* ask the user what he wants to do */
652 va_start (var_args, format);
653 response = _thunar_job_ask_valist (job, format, var_args,
654 _("There is not enough space on the destination. Try to remove files to make space."),
655 THUNAR_JOB_RESPONSE_FORCE
656 | THUNAR_JOB_RESPONSE_CANCEL);
657 va_end (var_args);
658
659 return (response == THUNAR_JOB_RESPONSE_FORCE);
660 }
661
662
663
664 gboolean
thunar_job_files_ready(ThunarJob * job,GList * file_list)665 thunar_job_files_ready (ThunarJob *job,
666 GList *file_list)
667 {
668 gboolean handled = FALSE;
669
670 _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
671
672 exo_job_emit (EXO_JOB (job), job_signals[FILES_READY], 0, file_list, &handled);
673 return handled;
674 }
675
676
677
678 void
thunar_job_new_files(ThunarJob * job,const GList * file_list)679 thunar_job_new_files (ThunarJob *job,
680 const GList *file_list)
681 {
682 ThunarFile *file;
683 const GList *lp;
684
685 _thunar_return_if_fail (THUNAR_IS_JOB (job));
686
687 /* check if we have any files */
688 if (G_LIKELY (file_list != NULL))
689 {
690 /* schedule a reload of cached files when idle */
691 for (lp = file_list; lp != NULL; lp = lp->next)
692 {
693 file = thunar_file_cache_lookup (lp->data);
694 if (file != NULL)
695 {
696 thunar_file_reload_idle_unref (file);
697 }
698 }
699
700 /* emit the "new-files" signal */
701 exo_job_emit (EXO_JOB (job), job_signals[NEW_FILES], 0, file_list);
702 }
703 }
704
705
706
707 GList *
thunar_job_ask_jobs(ThunarJob * job)708 thunar_job_ask_jobs (ThunarJob *job)
709 {
710 GList* jobs = NULL;
711
712 _thunar_return_val_if_fail (THUNAR_IS_JOB (job), NULL);
713
714 g_signal_emit (EXO_JOB (job), job_signals[ASK_JOBS], 0, &jobs);
715 return jobs;
716 }
717
718
719
720 void
thunar_job_set_total_files(ThunarJob * job,GList * total_files)721 thunar_job_set_total_files (ThunarJob *job,
722 GList *total_files)
723 {
724 _thunar_return_if_fail (THUNAR_IS_JOB (job));
725 _thunar_return_if_fail (job->priv->total_files == NULL);
726 _thunar_return_if_fail (total_files != NULL);
727
728 job->priv->total_files = total_files;
729 job->priv->n_total_files = g_list_length (total_files);
730 }
731
732
733
734 void
thunar_job_set_pausable(ThunarJob * job,gboolean pausable)735 thunar_job_set_pausable (ThunarJob *job,
736 gboolean pausable)
737 {
738 _thunar_return_if_fail (THUNAR_IS_JOB (job));
739 job->priv->pausable = pausable;
740 }
741
742
743
744 gboolean
thunar_job_is_pausable(ThunarJob * job)745 thunar_job_is_pausable (ThunarJob *job)
746 {
747 _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
748 return job->priv->pausable;
749 }
750
751
752
753 void
thunar_job_pause(ThunarJob * job)754 thunar_job_pause (ThunarJob *job)
755 {
756 _thunar_return_if_fail (THUNAR_IS_JOB (job));
757 job->priv->paused = TRUE;
758 }
759
760
761
762 void
thunar_job_resume(ThunarJob * job)763 thunar_job_resume (ThunarJob *job)
764 {
765 _thunar_return_if_fail (THUNAR_IS_JOB (job));
766 job->priv->paused = FALSE;
767 }
768
769
770
771 void
thunar_job_freeze(ThunarJob * job)772 thunar_job_freeze (ThunarJob *job)
773 {
774 _thunar_return_if_fail (THUNAR_IS_JOB (job));
775 job->priv->frozen = TRUE;
776 g_signal_emit (EXO_JOB (job), job_signals[FROZEN], 0);
777 }
778
779
780
781 void
thunar_job_unfreeze(ThunarJob * job)782 thunar_job_unfreeze (ThunarJob *job)
783 {
784 _thunar_return_if_fail (THUNAR_IS_JOB (job));
785 job->priv->frozen = FALSE;
786 g_signal_emit (EXO_JOB (job), job_signals[UNFROZEN], 0);
787 }
788
789
790
791 gboolean
thunar_job_is_paused(ThunarJob * job)792 thunar_job_is_paused (ThunarJob *job)
793 {
794 _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
795 return job->priv->paused;
796 }
797
798
799
800 gboolean
thunar_job_is_frozen(ThunarJob * job)801 thunar_job_is_frozen (ThunarJob *job)
802 {
803 _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
804 return job->priv->frozen;
805 }
806
807
808
809 void
thunar_job_processing_file(ThunarJob * job,GList * current_file,guint n_processed)810 thunar_job_processing_file (ThunarJob *job,
811 GList *current_file,
812 guint n_processed)
813 {
814 gchar *base_name;
815 gchar *display_name;
816
817 _thunar_return_if_fail (THUNAR_IS_JOB (job));
818 _thunar_return_if_fail (current_file != NULL);
819
820 /* emit only if n_processed is a multiple of 8 */
821 if ((n_processed % 8) != 0)
822 return;
823
824 base_name = g_file_get_basename (current_file->data);
825 display_name = g_filename_display_name (base_name);
826 g_free (base_name);
827
828 exo_job_info_message (EXO_JOB (job), "%s", display_name);
829 g_free (display_name);
830
831 /* verify that we have total files set */
832 if (G_LIKELY (job->priv->n_total_files > 0))
833 exo_job_percent (EXO_JOB (job), (n_processed * 100.0) / job->priv->n_total_files);
834 }
835