backup_paradise 1.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +452 -0
  3. data/backup_paradise.gemspec +50 -0
  4. data/bin/backup_for_ingrid +10 -0
  5. data/bin/backup_paradise +7 -0
  6. data/bin/windows_backup_paradise +9 -0
  7. data/doc/README.gen +390 -0
  8. data/doc/TODO.md +130 -0
  9. data/img/BackupParadise_Logo.png +0 -0
  10. data/lib/backup_paradise/actions/README.md +2 -0
  11. data/lib/backup_paradise/actions/backup.rb +62 -0
  12. data/lib/backup_paradise/base/base.rb +529 -0
  13. data/lib/backup_paradise/base/colours.rb +137 -0
  14. data/lib/backup_paradise/base/namespace.rb +16 -0
  15. data/lib/backup_paradise/base/tab.rb +47 -0
  16. data/lib/backup_paradise/colours/colours.rb +88 -0
  17. data/lib/backup_paradise/constants/constants.rb +162 -0
  18. data/lib/backup_paradise/gui/glimmer/libui/backup_for_ingrid/backup_for_ingrid.rb +87 -0
  19. data/lib/backup_paradise/gui/gtk2/OLD_backup.rb +165 -0
  20. data/lib/backup_paradise/gui/libui/backup_for_ingrid/backup_for_ingrid.rb +99 -0
  21. data/lib/backup_paradise/gui/shared_code/simple_backup_widget/simple_backup_widget_module.rb +0 -0
  22. data/lib/backup_paradise/gui/tk/backup.rb +108 -0
  23. data/lib/backup_paradise/gui/universal_widgets/simple_backup_widget/simple_backup_widget.rb +921 -0
  24. data/lib/backup_paradise/images/BACKUP_IMAGE.png +0 -0
  25. data/lib/backup_paradise/images/right_arrow.png +0 -0
  26. data/lib/backup_paradise/project/project.rb +40 -0
  27. data/lib/backup_paradise/requires/require_the_backup_paradise_project.rb +18 -0
  28. data/lib/backup_paradise/requires/require_yaml.rb +7 -0
  29. data/lib/backup_paradise/tab/tab.rb +87 -0
  30. data/lib/backup_paradise/toplevel_methods/cliner.rb +16 -0
  31. data/lib/backup_paradise/toplevel_methods/config.rb +86 -0
  32. data/lib/backup_paradise/toplevel_methods/create_and_remove.rb +63 -0
  33. data/lib/backup_paradise/toplevel_methods/e.rb +16 -0
  34. data/lib/backup_paradise/toplevel_methods/esystem.rb +19 -0
  35. data/lib/backup_paradise/toplevel_methods/files_and_directories.rb +181 -0
  36. data/lib/backup_paradise/toplevel_methods/help.rb +93 -0
  37. data/lib/backup_paradise/toplevel_methods/misc.rb +153 -0
  38. data/lib/backup_paradise/toplevel_methods/mountpoint.rb +188 -0
  39. data/lib/backup_paradise/toplevel_methods/opnn.rb +27 -0
  40. data/lib/backup_paradise/utility_scripts/backup/backup.rb +1942 -0
  41. data/lib/backup_paradise/version/version.rb +19 -0
  42. data/lib/backup_paradise/windows/README.md +1 -0
  43. data/lib/backup_paradise/windows/windows.rb +101 -0
  44. data/lib/backup_paradise/www/backup.cgi +63 -0
  45. data/lib/backup_paradise/yaml/config.yml +82 -0
  46. data/lib/backup_paradise.rb +5 -0
  47. data/test/testing_toplevel_functionality.rb +11 -0
  48. metadata +192 -0
@@ -0,0 +1,921 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # === BackupParadise::GUI::UniversalWidgets::SimpleBackupWidget
6
+ #
7
+ # This is a simple gtk3-widget that can be used to quickly back up data
8
+ # to an external USB device (or a second harddisc).
9
+ #
10
+ # Usage example:
11
+ #
12
+ # BackupParadise::GUI::UniversalWidgets::SimpleBackupWidget.new(ARGV)
13
+ #
14
+ # =========================================================================== #
15
+ # require 'backup_paradise/gui/universal_widgets/simple_backup_widget/simple_backup_widget.rb'
16
+ # =========================================================================== #
17
+ require 'backup_paradise/base/base.rb'
18
+
19
+ module BackupParadise
20
+
21
+ module GUI
22
+
23
+ module UniversalWidgets
24
+
25
+ class SimpleBackupWidget < ::BackupParadise::Base # === BackupParadise::GUI::UniversalWidgets::SimpleBackupWidget
26
+
27
+ require 'universal_widgets/base_module/base_module.rb'
28
+ include ::UniversalWidgets::BaseModule
29
+
30
+ # ========================================================================= #
31
+ # The old ruby-gtk2 code had this:
32
+ # begin
33
+ # require 'gtk_paradise/classes/gtk2/information_about_the_harddisc.rb'
34
+ # rescue LoadError; end
35
+ # ========================================================================= #
36
+
37
+ begin
38
+ require 'open'
39
+ rescue LoadError; end
40
+
41
+ begin
42
+ require 'mountpoints'
43
+ rescue LoadError; end
44
+
45
+ # ========================================================================= #
46
+ # Add backup-paradise related .rb files next:
47
+ # ========================================================================= #
48
+ require 'backup_paradise/project/project.rb'
49
+ require 'backup_paradise/utility_scripts/backup/backup.rb'
50
+ require 'backup_paradise/actions/backup.rb'
51
+ require 'backup_paradise/windows/windows.rb'
52
+
53
+ # ========================================================================= #
54
+ # === ARRAY_PREDEFINED_DEVICES
55
+ # ========================================================================= #
56
+ ARRAY_PREDEFINED_DEVICES = [
57
+ ENV['USB1'],
58
+ ENV['USB2'],
59
+ ENV['USB3'],
60
+ ENV['USB4'],
61
+ ENV['USB5'],
62
+ ENV['FESTPLATTE1']
63
+ ]
64
+
65
+ # ========================================================================= #
66
+ # === USE_THESE_CSS_RULES
67
+ # ========================================================================= #
68
+ USE_THESE_CSS_RULES = '
69
+
70
+ .dotted_steelblue_border {
71
+ border: 2px dotted steelblue;
72
+ }
73
+
74
+ .the_backup_button {
75
+ border: 3px dotted royalblue;
76
+ padding: 8px;
77
+ margin: 4px;
78
+ color: darkgreen;
79
+ font-weight: bold;
80
+ }
81
+
82
+ .the_backup_button:hover {
83
+ color: forestgreen;
84
+ font-weight: bold;
85
+ }
86
+
87
+ .the_backup_button_for_ingrid {
88
+ border: 2px dotted royalblue;
89
+ padding: 5px;
90
+ margin: 2px;
91
+ color: royalblue;
92
+ font-weight: bold;
93
+ }
94
+
95
+ .the_backup_button_for_ingrid_button:hover {
96
+ color: steelblue;
97
+ font-weight: bold;
98
+ }
99
+
100
+ '
101
+
102
+ # ========================================================================= #
103
+ # === TITLE
104
+ # ========================================================================= #
105
+ TITLE = '💾 Simple Backup Widget 💾'
106
+
107
+ # ========================================================================= #
108
+ # === WIDTH
109
+ # ========================================================================= #
110
+ WIDTH = '82% or minimum 1280px'
111
+
112
+ # ========================================================================= #
113
+ # === HEIGHT
114
+ # ========================================================================= #
115
+ HEIGHT = '30% or minimum 400px'
116
+
117
+ # ========================================================================= #
118
+ # === USE_THIS_FONT
119
+ # ========================================================================= #
120
+ USE_THIS_FONT = :dejavu_condensed_19
121
+
122
+ # ========================================================================= #
123
+ # === LARGER_FONT
124
+ # ========================================================================= #
125
+ LARGER_FONT = :dejavu_condensed_21
126
+
127
+ # ========================================================================= #
128
+ # === SMALLER_FONT
129
+ # ========================================================================= #
130
+ SMALLER_FONT = :dejavu_condensed_18
131
+
132
+ # ========================================================================= #
133
+ # === USE_THIS_MONOSPACED_FONT
134
+ # ========================================================================= #
135
+ USE_THIS_MONOSPACED_FONT = :hack_16
136
+
137
+ # ========================================================================= #
138
+ # === initialize
139
+ # ========================================================================= #
140
+ def initialize(
141
+ commandline_arguments = ARGV,
142
+ run_already = true
143
+ )
144
+ super(:vertical) if use_gtk3?
145
+ determine_the_GUI_to_be_used(commandline_arguments) # This must come first, even before reset().
146
+ reset
147
+ set_commandline_arguments(
148
+ commandline_arguments
149
+ )
150
+ on_delete_event_quit_the_application
151
+ # self.label_widget.set_markup %Q(
152
+ # <span size="larger" weight="bold">💾 Backup Script</span>
153
+ # )
154
+ run if run_already
155
+ end
156
+
157
+ # ========================================================================= #
158
+ # === reset (reset tag)
159
+ # ========================================================================= #
160
+ def reset
161
+ super() if respond_to?(:super)
162
+ reset_the_shared_module # This can come early.
163
+ reset_the_base_module
164
+ reset_the_internal_variables
165
+ infer_the_namespace
166
+ # ======================================================================= #
167
+ # === @configuration
168
+ # ======================================================================= #
169
+ @configuration = [true, __dir__, namespace?]
170
+ # ======================================================================= #
171
+ # === Set the title, width, height and the font in use.
172
+ # ======================================================================= #
173
+ title_width_height_font(TITLE, WIDTH, HEIGHT, USE_THIS_FONT)
174
+ if use_gtk3?
175
+ handle_CSS_rules
176
+ end
177
+ infer_the_size_automatically
178
+ # ======================================================================= #
179
+ # === @object_rbackup
180
+ # ======================================================================= #
181
+ # @object_rbackup = BackupParadise::Backup.new(nil, :do_not_run_yet)
182
+ # ======================================================================= #
183
+ # === @object_hdd_info
184
+ # ======================================================================= #
185
+ # @object_hdd_info = ::Gtk::InformationAboutTheHarddisc.new
186
+ end
187
+
188
+ # ========================================================================= #
189
+ # === favicon?
190
+ # ========================================================================= #
191
+ def favicon?
192
+ :tabble
193
+ end
194
+
195
+ # ========================================================================= #
196
+ # === smaller_font?
197
+ # ========================================================================= #
198
+ def smaller_font?
199
+ SMALLER_FONT
200
+ end
201
+
202
+ # ========================================================================= #
203
+ # === update_fdisk
204
+ #
205
+ # Use this if you wanna get new fdisk information.
206
+ #
207
+ # Or use this:
208
+ #
209
+ # `fdisk -l`.gsub!(%r[^(!?/dev).*\n], '')
210
+ #
211
+ # ========================================================================= #
212
+ def update_fdisk
213
+ return `fdisk -l`.split("\n").delete_if { |line| line !~ /^\/dev/ }.join("\n")
214
+ end
215
+
216
+ # ========================================================================= #
217
+ # === handle_CSS_rules (CSS tag)
218
+ # ========================================================================= #
219
+ def handle_CSS_rules
220
+ use_gtk_paradise_project_css_file
221
+ append_project_css_file
222
+ more_CSS_then_apply_it(USE_THESE_CSS_RULES)
223
+ end
224
+
225
+ # ========================================================================= #
226
+ # === reset_the_shared_module
227
+ #
228
+ # This method can be used for ruby-gtk3 and ruby-libui, among other
229
+ # toolkits.
230
+ # ========================================================================= #
231
+ def reset_the_shared_module
232
+ # ======================================================================= #
233
+ # === @file_chooser_dialog
234
+ # ======================================================================= #
235
+ @file_chooser_dialog = nil
236
+ # ======================================================================= #
237
+ # === @dataset_from_the_config_file
238
+ # ======================================================================= #
239
+ @dataset_from_the_config_file = nil
240
+ if File.exist? BackupParadise.file_config?
241
+ @dataset_from_the_config_file = YAML.load_file(BackupParadise.file_config?)
242
+ end
243
+ end
244
+
245
+ # ========================================================================= #
246
+ # === padding?
247
+ # ========================================================================= #
248
+ def padding?
249
+ 0
250
+ end
251
+
252
+ # ========================================================================= #
253
+ # === border_size?
254
+ # ========================================================================= #
255
+ def border_size?
256
+ 0
257
+ end
258
+
259
+ # ========================================================================= #
260
+ # === create_the_backup_audio_button
261
+ # ========================================================================= #
262
+ def create_the_backup_audio_button
263
+ # ======================================================================= #
264
+ # === @button_backup_audio
265
+ # ======================================================================= #
266
+ @button_backup_audio = button('Backup Audio')
267
+ @button_backup_audio.hint = 'This button is ad-hoc code to quickly '\
268
+ 'copy all local songs on my home layout. You can modify this '\
269
+ 'by modifying the config.yml file and changing the entry called '\
270
+ '<b>local_audio_directory</b>.'
271
+ @button_backup_audio.on_clicked {
272
+ # ===================================================================== #
273
+ # First, if the config-dataset exists, sync the combo-box entry.
274
+ # ===================================================================== #
275
+ if @dataset_from_the_config_file
276
+ local_audio_directory = @dataset_from_the_config_file['local_audio_directory'].to_s
277
+ entry_left?.set_text(
278
+ local_audio_directory
279
+ )
280
+ end
281
+ do_backup_my_songs
282
+ }
283
+ end
284
+
285
+ # ========================================================================= #
286
+ # === create_the_backup_button
287
+ # ========================================================================= #
288
+ def create_the_backup_button
289
+ # ======================================================================= #
290
+ # === @button_backup
291
+ # ======================================================================= #
292
+ @button_backup = button('_Backup the data', self, :use_mnemonics) {
293
+ :do_backup_the_data
294
+ }
295
+ @button_backup.clear_background
296
+ @button_backup.on_hover(:lightblue)
297
+ @button_backup.pad8px
298
+ @button_backup.css_class('the_backup_button')
299
+ @button_backup.set_size_request(16, 25)
300
+ @button_backup.set_border_width(2)
301
+ @button_backup.hint =
302
+ "Click this button to <b>backup your data</b>. This works for both "\
303
+ "directories, as well as individual files and special instructions. "\
304
+ "Special instructions are indicated via a leading : character on "\
305
+ "the top-left hand side.\n\n"\
306
+ "Make sure that the USB device(s) are properly connected before "\
307
+ "clicking any button, though."
308
+ end
309
+
310
+ # ========================================================================= #
311
+ # === do_backup_the_data
312
+ # ========================================================================= #
313
+ def do_backup_the_data(
314
+ from = from?,
315
+ to = to?
316
+ )
317
+ @label_showing_results.set_text(
318
+ 'Command that will be run: '+"\n\n"+
319
+ ' <b>cp -rv '+from+' '+to+"</b>\n"
320
+ )
321
+ @label_showing_results.do_markify
322
+ Thread.new {
323
+ e 'Backing up the data next, from `'+
324
+ sfile(from)+'` to `'+sfile(to)+'`.'
325
+ copy_from_to(from, to)
326
+ }
327
+ end
328
+
329
+ # ========================================================================= #
330
+ # === backup_ingrid_directory
331
+ #
332
+ # This is a method for a custom-backup. Other users won't need to use
333
+ # this method.
334
+ # ========================================================================= #
335
+ def backup_ingrid_directory
336
+ BackupParadise::Windows.backup_ingrid_directory
337
+ end; alias do_backup_for_ingrid backup_ingrid_directory # === do_backup_for_ingrid
338
+
339
+ # ========================================================================= #
340
+ # === return_backup_complete_message
341
+ # ========================================================================= #
342
+ def return_backup_complete_message
343
+ 'Backup complete! Time finish at: '+time_now?
344
+ end
345
+
346
+ # ========================================================================= #
347
+ # === run_file_chooser_dialog
348
+ # ========================================================================= #
349
+ def run_file_chooser_dialog(
350
+ _ = @file_chooser_dialog
351
+ )
352
+ if _ and (_.run == ::Gtk::ResponseType::ACCEPT)
353
+ filename = _.filename
354
+ e "filename = #{filename}"
355
+ e "uri = #{_.uri}"
356
+ entry_left?.set_text(filename)
357
+ @file_chooser_dialog.destroy
358
+ end
359
+ end
360
+
361
+ # ========================================================================= #
362
+ # === create_file_chooser_dialog_widget
363
+ # ========================================================================= #
364
+ def create_file_chooser_dialog_widget
365
+ @file_chooser_dialog = ::Gtk::FileChooserDialog.new(
366
+ self: self,
367
+ title: 'Choose a file or directory',
368
+ action: ::Gtk::FileChooserAction::OPEN,
369
+ buttons: [[::Gtk::Stock::OPEN, ::Gtk::ResponseType::ACCEPT],
370
+ [::Gtk::Stock::CANCEL, ::Gtk::ResponseType::CANCEL]]
371
+ )
372
+ # ======================================================================= #
373
+ # === /home/Temp
374
+ # ======================================================================= #
375
+ if File.directory? '/home/Temp/'
376
+ @file_chooser_dialog.add_shortcut_folder('/home/Temp/')
377
+ end
378
+ # ======================================================================= #
379
+ # === /home/x/Temp
380
+ # ======================================================================= #
381
+ if File.directory? '/home/x/Temp/'
382
+ @file_chooser_dialog.add_shortcut_folder('/home/x/Temp/')
383
+ end
384
+ # ======================================================================= #
385
+ # === /home/x/data/
386
+ # ======================================================================= #
387
+ if File.directory? HOME_DIRECTORY_OF_THE_USER_X+'data/'
388
+ @file_chooser_dialog.add_shortcut_folder(HOME_DIRECTORY_OF_THE_USER_X+'data/')
389
+ end
390
+ # ======================================================================= #
391
+ # Add the audio-directory shortcut, defined in the yaml file.
392
+ # ======================================================================= #
393
+ if @dataset_from_the_config_file and
394
+ @dataset_from_the_config_file.has_key?('local_audio_directory')
395
+ @file_chooser_dialog.add_shortcut_folder(
396
+ @dataset_from_the_config_file['local_audio_directory'].to_s
397
+ )
398
+ end
399
+ @file_chooser_dialog.add_shortcut_folder('/Ingrid')
400
+ @file_chooser_dialog.current_folder = Dir.pwd
401
+ @file_chooser_dialog.do_show_hidden_files
402
+ # @file_chooser_dialog.destroy
403
+ end
404
+
405
+ # ========================================================================= #
406
+ # === copy_this_file
407
+ # ========================================================================= #
408
+ def copy_this_file(from, b)
409
+ ::BackupParadise.copy_this_file(from, b)
410
+ end
411
+
412
+ # ========================================================================= #
413
+ # === larger_font?
414
+ # ========================================================================= #
415
+ def larger_font?
416
+ LARGER_FONT
417
+ end
418
+
419
+ # ========================================================================= #
420
+ # === do_transfer_a_single_file
421
+ # ========================================================================= #
422
+ def do_transfer_a_single_file(
423
+ _ = entry_left?.text?.strip,
424
+ target = onto?
425
+ )
426
+ target = target.dup if target.frozen?
427
+ target << File.basename(_)
428
+
429
+ if _.empty?
430
+ e 'Please supply a file to transfer.'
431
+ else
432
+ e "Now trying to copy #{_} to #{target}."
433
+ Thread.new {
434
+ copy_this_file(_, target)
435
+ pop_up_this_text_over_that_widget(return_backup_complete_message, @button_backup)
436
+ }
437
+ end
438
+ end
439
+
440
+ # ========================================================================= #
441
+ # === main_target?
442
+ #
443
+ # This method will "return" our main target.
444
+ # ========================================================================= #
445
+ def main_target?
446
+ @backup_to_this_target.text?
447
+ end
448
+
449
+ # ========================================================================= #
450
+ # === do_backup_my_songs
451
+ # ========================================================================= #
452
+ def do_backup_my_songs(
453
+ to =
454
+ ("#{onto?}#{File.basename(entry_left?.text?)}/").squeeze('/')
455
+ )
456
+ to.squeeze!('/')
457
+ Thread.new {
458
+ BackupParadise.simple_backup(
459
+ entry_left?.text?, to
460
+ )
461
+ pop_up_this_text_over_that_widget(
462
+ return_backup_complete_message,
463
+ @button_backup_audio
464
+ )
465
+ }
466
+ end
467
+
468
+ # ========================================================================= #
469
+ # === time_now?
470
+ # ========================================================================= #
471
+ def time_now?
472
+ return ::Time.now.strftime('%d.%m.%Y, %H:%M:%S')
473
+ end
474
+
475
+ # ========================================================================= #
476
+ # === entry1?
477
+ # ========================================================================= #
478
+ def entry1?
479
+ @entry1_for_the_backup_from_value
480
+ end; alias entry_left? entry1? # === entry_left?
481
+
482
+ # ========================================================================= #
483
+ # === create_the_entries (entries tag)
484
+ # ========================================================================= #
485
+ def create_the_entries
486
+ # ======================================================================= #
487
+ # === @entry1_for_the_backup_from_value
488
+ # ======================================================================= #
489
+ @entry1_for_the_backup_from_value = entry
490
+ @entry1_for_the_backup_from_value.pad4px
491
+ @entry1_for_the_backup_from_value.bblack1
492
+ @entry1_for_the_backup_from_value.very_light_yellow_background
493
+ # ======================================================================= #
494
+ # === @entry2_for_the_backup_onto_value
495
+ # ======================================================================= #
496
+ @entry2_for_the_backup_onto_value = entry
497
+ @entry2_for_the_backup_onto_value.pad4px
498
+ @entry2_for_the_backup_onto_value.bblack1
499
+ @entry2_for_the_backup_onto_value.very_light_yellow_background
500
+ @entry2_for_the_backup_onto_value.width_height(250, 50)
501
+ end
502
+
503
+ # ========================================================================= #
504
+ # === from?
505
+ #
506
+ # This method has to keep in mind that Strings such as ":ingrid" are
507
+ # used. This indicates a symbol which has to be treated in a special
508
+ # manner.
509
+ #
510
+ # Furthermore, only directories will have a '/' appended; files must
511
+ # not have a '/' appended.
512
+ # ========================================================================= #
513
+ def from?(
514
+ i = @entry1_for_the_backup_from_value.text?
515
+ )
516
+ if i.is_a?(String) and i.start_with?(':')
517
+ case i.delete(':').to_sym
518
+ # ===================================================================== #
519
+ # === :ingrid
520
+ # ===================================================================== #
521
+ when :ingrid
522
+ i = 'C/ingrid/'
523
+ end
524
+ end
525
+ if i.is_a?(String) and i.frozen?
526
+ i = i.dup
527
+ end
528
+ i.squeeze!('/')
529
+ if File.directory?(i) and !i.end_with?('/')
530
+ i << '/'
531
+ end
532
+ return i
533
+ end
534
+
535
+ # ========================================================================= #
536
+ # === copy_from_to
537
+ #
538
+ # This is the method that can be used for backing up the data.
539
+ # ========================================================================= #
540
+ def copy_from_to(
541
+ from = from?,
542
+ to = onto?
543
+ )
544
+ unless File.directory? from
545
+ e "#{sfile(from)} should be a directory."
546
+ end
547
+ if from == 'C/ingrid/'
548
+ # ====================================================================== #
549
+ # The first entry is a special case, applying to only one particular
550
+ # situation on Windows. It is retained here on an ad-hoc basis,
551
+ # but it may be better to move this into another location.
552
+ # ====================================================================== #
553
+ BackupParadise::Windows.backup_ingrid_directory
554
+ elsif File.file?(from)
555
+ # ====================================================================== #
556
+ # Backup files here.
557
+ # ====================================================================== #
558
+ do_transfer_a_single_file
559
+ else
560
+ # ====================================================================== #
561
+ # Backup directories here.
562
+ # ====================================================================== #
563
+ if from.is_a?(String) and from.start_with?(':')
564
+ case from.delete(':').to_sym
565
+ # ===================================================================== #
566
+ # === :everything
567
+ #
568
+ # This will default to the registered action stored in the
569
+ # config.yml file.
570
+ # ===================================================================== #
571
+ when :everything
572
+ if @dataset_from_the_config_file
573
+ i = @dataset_from_the_config_file['backup_these_directories']
574
+ BackupParadise::Actions.backup {{
575
+ backup_these_directories: i,
576
+ where_to: to
577
+ }}
578
+ else
579
+ e 'No file called config.yml was found. Defaulting to the'
580
+ e 'current working directory thus.'
581
+ i = File.absolute_path("#{Dir.pwd}/")
582
+ end
583
+ end
584
+ else
585
+ begin
586
+ Thread.new {
587
+ @spinner.is_active # go_and_spin_now
588
+ FileUtils.cp_r(from, to)
589
+ pop_up_this_text_over_that_widget(
590
+ return_backup_complete_message, @button_backup
591
+ )
592
+ @spinner.stop_spinning
593
+ }
594
+ rescue Exception => error
595
+ pp error
596
+ end
597
+ end
598
+ end
599
+ end
600
+
601
+ # ========================================================================= #
602
+ # === backup_audio_button?
603
+ # ========================================================================= #
604
+ def backup_audio_button?
605
+ @button_backup_audio
606
+ end
607
+
608
+ # ========================================================================= #
609
+ # === backup_ingrid_button?
610
+ # ========================================================================= #
611
+ def backup_ingrid_button?
612
+ @button_ingrid
613
+ end
614
+
615
+ # ========================================================================= #
616
+ # === backup_button?
617
+ # ========================================================================= #
618
+ def backup_button?
619
+ @button_backup
620
+ end
621
+
622
+ # ========================================================================= #
623
+ # === create_the_file_chooser_button
624
+ # ========================================================================= #
625
+ def create_the_file_chooser_button
626
+ # ======================================================================= #
627
+ # === @button_choose_file
628
+ # ======================================================================= #
629
+ @button_choose_file = button('Choose file')
630
+ @button_choose_file.on_clicked {
631
+ create_file_chooser_dialog_widget
632
+ run_file_chooser_dialog
633
+ }
634
+ end
635
+
636
+ # ========================================================================= #
637
+ # === choose_file_button?
638
+ # ========================================================================= #
639
+ def choose_file_button?
640
+ @button_choose_file
641
+ end
642
+
643
+ # ========================================================================= #
644
+ # === create_the_label_showing_results
645
+ # ========================================================================= #
646
+ def create_the_label_showing_results
647
+ @label_showing_results = label
648
+ end
649
+
650
+ # ========================================================================= #
651
+ # === create_the_buttons (buttons tag, button tag)
652
+ # ========================================================================= #
653
+ def create_the_buttons
654
+ create_the_file_chooser_button
655
+ create_the_backup_button
656
+ create_the_backup_audio_button
657
+ create_the_ingrid_button if is_on_roebe?
658
+ end
659
+
660
+ # ========================================================================= #
661
+ # === onto
662
+ # ========================================================================= #
663
+ def onto?
664
+ return "#{@entry2_for_the_backup_onto_value.text?}/".squeeze('/')
665
+ end; alias to? onto? # === to?
666
+
667
+ # ========================================================================= #
668
+ # === create_the_grid (grid tag)
669
+ # ========================================================================= #
670
+ def create_the_grid
671
+ # ======================================================================= #
672
+ # === @grid
673
+ # ======================================================================= #
674
+ @grid = default_grid
675
+ @grid.pad10px
676
+ @grid.css_class('dotted_steelblue_border')
677
+ @grid.set_size_request(100, 50)
678
+ @grid.row_spacing = 5
679
+ @grid.line_spacing = 5
680
+ label_backup_from = text('Backup from:')
681
+ label_backup_from.make_bold
682
+ label_backup_from.hint = 'Input which directory '\
683
+ 'you wish to back up. Use the combo-box entry '\
684
+ 'below this widget, or the entry below '\
685
+ 'that combo-box.'
686
+ @grid.left(label_backup_from)
687
+
688
+ label_backup_onto = text('Backup onto:')
689
+ label_backup_onto.make_bold
690
+ label_backup_onto.hint = 'Input the target device onto which we will '\
691
+ 'copy the data onto.'
692
+ @grid.right(label_backup_onto)
693
+
694
+ # ======================================================================= #
695
+ # Next we will add the two main combo-boxes.
696
+ # ======================================================================= #
697
+ @grid.left(@combo_box_backup_from)
698
+ @grid.right(@combo_box_backup_onto)
699
+ @grid.left(@entry1_for_the_backup_from_value)
700
+ @grid.right(@entry2_for_the_backup_onto_value)
701
+ end
702
+
703
+ # ========================================================================= #
704
+ # === create_the_combo_boxes (combo tag)
705
+ # ========================================================================= #
706
+ def create_the_combo_boxes
707
+ # ======================================================================= #
708
+ # === @combo_box_backup_from
709
+ #
710
+ # This is the combo-box that keeps the core entries, such as
711
+ # "/home/x/songs" and so forth.
712
+ # ======================================================================= #
713
+ @combo_box_backup_from = combo_box
714
+ @combo_box_backup_from.bblack1
715
+ @combo_box_backup_from.set_border_width(2)
716
+ # ======================================================================= #
717
+ # Next we will populate the combo-box with proper entries:
718
+ # ======================================================================= #
719
+ _ = BackupParadise.backup_these_directories?.map {|entry| "#{entry}/".squeeze('/') }
720
+ _.prepend(':everything')
721
+ _.prepend(':ingrid') if is_on_roebe?
722
+ @combo_box_backup_from.populate(_)
723
+ @combo_box_backup_from.the_first_entry_is_active
724
+ @combo_box_backup_from.hint =
725
+ ':everything means to backup the default action, as-is. If you '\
726
+ 'need a more fine-tuned level of control then simply backup only '\
727
+ 'some directories, or use the entry to the right side of this '\
728
+ 'combo box to backup only individual directories or files.'
729
+ # ======================================================================= #
730
+ # === @combo_box_backup_onto
731
+ # ======================================================================= #
732
+ @combo_box_backup_onto = combo_box
733
+ @combo_box_backup_onto.bblack1
734
+ @combo_box_backup_onto.set_border_width(2)
735
+ scan_for_mountpoints_then_update_the_appropriate_combo_box
736
+ end
737
+
738
+ # ========================================================================= #
739
+ # === sync_the_combo_box_values_onto_the_entries_below
740
+ # ========================================================================= #
741
+ def sync_the_combo_box_values_onto_the_entries_below
742
+ _ = @combo_box_backup_from.text?.to_s
743
+ entry1?.set_text(_)
744
+ sync_the_second_entry
745
+ end
746
+
747
+ # ========================================================================= #
748
+ # === sync_the_second_entry
749
+ # ========================================================================= #
750
+ def sync_the_second_entry
751
+ entry2?.set_text(
752
+ @combo_box_backup_onto.text?.to_s
753
+ )
754
+ end
755
+
756
+ # ========================================================================= #
757
+ # === entry2?
758
+ # ========================================================================= #
759
+ def entry2?
760
+ @entry2_for_the_backup_onto_value
761
+ end
762
+
763
+ # ========================================================================= #
764
+ # === do_handle_the_proper_syncing_when_the_combo_box_entries_are_changed
765
+ # ========================================================================= #
766
+ def do_handle_the_proper_syncing_when_the_combo_box_entries_are_changed
767
+ # ======================================================================= #
768
+ # Sync any change made in the combo box onto the associated entry.
769
+ # ======================================================================= #
770
+ sync_connect(@combo_box_backup_from, entry1?)
771
+ sync_connect(@combo_box_backup_onto, entry2?)
772
+ end
773
+
774
+ # ========================================================================= #
775
+ # === scan_for_mountpoints_then_update_the_appropriate_combo_box
776
+ # ========================================================================= #
777
+ def scan_for_mountpoints_then_update_the_appropriate_combo_box
778
+ if Object.const_defined? :Mountpoints
779
+ @combo_box_backup_onto.clear_old_datapoints
780
+ @combo_box_backup_onto.populate(Mountpoints[])
781
+ @combo_box_backup_onto.the_first_entry_is_active
782
+ sync_the_second_entry
783
+ end
784
+ end
785
+
786
+ # ========================================================================= #
787
+ # === create_the_skeleton (create tag, skeleton tag)
788
+ # ========================================================================= #
789
+ def create_the_skeleton
790
+ create_the_label_showing_results
791
+ create_the_buttons
792
+ create_the_entries
793
+ create_the_combo_boxes
794
+ create_the_grid
795
+ end
796
+
797
+ # ========================================================================= #
798
+ # === run (run tag)
799
+ # ========================================================================= #
800
+ def run
801
+ run_super
802
+ end
803
+
804
+ # ========================================================================= #
805
+ # === BackupParadise::GUI::Gtk::SimpleBackupWidget.run
806
+ # ========================================================================= #
807
+ def self.run(
808
+ i = ARGV
809
+ )
810
+ require 'gtk_paradise/run'
811
+ _ = ::BackupParadise::GUI::Gtk::SimpleBackupWidget.new(i)
812
+ r = ::Gtk.run
813
+ r << _
814
+ _.set_parent_widget(r)
815
+ r.automatic_size_then_automatic_title
816
+ r.enable_quick_exit
817
+ r.set_background :white
818
+ r.is_resizable # <- This line was added due to a possible prior .maximize action.
819
+ r.top_left_then_run
820
+ end; self.instance_eval { alias start_gui_application run } # === BackupParadise::GUI::Gtk::SimpleBackupWidget.start_gui_application
821
+
822
+ # ========================================================================= #
823
+ # === BackupParadise::GUI::UniversalWidgets::SimpleBackupWidget[]
824
+ # ========================================================================= #
825
+ def self.[](i = ARGV)
826
+ new(i)
827
+ end
828
+
829
+ # ========================================================================= #
830
+ # === connect_the_skeleton (connect tag)
831
+ # ========================================================================= #
832
+ def connect_the_skeleton
833
+ abort_on_exception
834
+
835
+ outer_vbox = create_vbox # A new vbox.
836
+
837
+ header_bar = return_default_header_bar { :with_close_button_and_inferred_title }
838
+ header_bar.spacing = 10
839
+ header_bar.add_left(@button_choose_file)
840
+ header_bar.add_left(@button_backup_audio)
841
+ @spinner = default_spinner
842
+ @spinner.is_inactive
843
+ header_bar.add_right(@spinner)
844
+ button = icon_theme_image('daytime-sunset-symbolic.symbolic')
845
+ button.hint = 'Click this icon to show which devices are mounted and '\
846
+ 'update the combo-box showing all mounted devices.'
847
+ button.on_clicked {
848
+ scan_for_mountpoints_then_update_the_appropriate_combo_box
849
+ }
850
+ header_bar.add_left(button)
851
+ outer_vbox.minimal(header_bar, 1)
852
+ outer_vbox.minimal(horizontal_separator, 1)
853
+ outer_vbox.minimal(@grid, 1)
854
+ outer_vbox.minimal(horizontal_separator, 1)
855
+ hbox = create_hbox
856
+ _ = BackupParadise.project_base_directory?+'images/right_arrow.png'
857
+ if File.exist? _
858
+ hbox.minimal(image(_), 5)
859
+ end
860
+ hbox.maximal(@button_backup)
861
+ outer_vbox.minimal(hbox)
862
+ outer_vbox.minimal(horizontal_separator)
863
+ if is_on_roebe?
864
+ outer_vbox.minimal(@button_ingrid)
865
+ outer_vbox.minimal(horizontal_separator)
866
+ end
867
+ outer_vbox.minimal(@label_showing_results)
868
+ outer_vbox.minimal(horizontal_separator)
869
+
870
+ window = create_window_or_runner
871
+ window << outer_vbox
872
+
873
+ properly_prepare_this_window(window,
874
+ {
875
+ title: title?,
876
+ font: font?,
877
+ width: width?,
878
+ height: height?,
879
+ padding: padding?,
880
+ border_size: border_size?
881
+ }
882
+ )
883
+ window.show_all
884
+ window.top_left
885
+ do_all_startup_related_actions
886
+ run_main
887
+ end
888
+
889
+ # ========================================================================= #
890
+ # === do_all_startup_related_actions
891
+ # ========================================================================= #
892
+ def do_all_startup_related_actions
893
+ sync_the_combo_box_values_onto_the_entries_below
894
+ do_handle_the_proper_syncing_when_the_combo_box_entries_are_changed
895
+ end
896
+
897
+ # ========================================================================= #
898
+ # === create_the_ingrid_button
899
+ # ========================================================================= #
900
+ def create_the_ingrid_button
901
+ # ======================================================================= #
902
+ # === @button_ingrid
903
+ # ======================================================================= #
904
+ @button_ingrid = button('Backup _ingrid', self, :use_mnemonics) {
905
+ :do_backup_for_ingrid
906
+ }
907
+ @button_ingrid.clear_background
908
+ @button_ingrid.css_class('the_backup_button_for_ingrid')
909
+ @button_backup.on_hover(:lightblue)
910
+ @button_ingrid.pad8px
911
+ @button_ingrid.set_size_request(16, 25)
912
+ @button_ingrid.set_border_width(2)
913
+ @button_ingrid.hint = 'This will backup c:\ingrid to '\
914
+ 'the appropriate external USB device.'
915
+ end
916
+
917
+ end; end; end; end
918
+
919
+ if __FILE__ == $PROGRAM_NAME
920
+ BackupParadise::GUI::UniversalWidgets::SimpleBackupWidget.new(ARGV)
921
+ end # backupwidget