backup_paradise 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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