mrdialog 1.0.1

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.
@@ -0,0 +1,1245 @@
1
+
2
+ # vim:ts=4:sw=4:
3
+ # = rdialog - A dialog gem for Ruby
4
+ #
5
+ # Homepage:: http://built-it.net/ruby/rdialog/
6
+ # Author:: Aleks Clark (http://built-it.net)
7
+ # Copyright:: (cc) 2004 Aleks Clark
8
+ # License:: BSD
9
+ #
10
+ # class RDialog::Dialog.new( array, str, array)
11
+ #
12
+
13
+ #=================================================
14
+ # I did the following:
15
+ # - renamed the class to MRDialog
16
+ # - removed tabs
17
+ # - added support for the follwoing:
18
+ # - form
19
+ # -
20
+ #
21
+ # muquit@muquit.com, Apr-05-2014
22
+ #=================================================
23
+
24
+ require 'logger'
25
+ require 'tempfile'
26
+ require 'date'
27
+ require 'time'
28
+ require 'shellwords'
29
+ class MRDialog
30
+ DIALOG_OK = 0
31
+ DIALOG_CANCEL = 1
32
+ DIALOG_HELP = 2
33
+ DIALOG_EXTRA = 3
34
+ DIALOG_ITEM_HELP = 4
35
+ DIALOG_ESC = 255
36
+ #MRDialog - Interface to ncurses dialog program
37
+
38
+ #
39
+ # All accessors are boolean unless otherwise noted.
40
+ #
41
+
42
+ #
43
+ # This gives you some control over the box dimensions when
44
+ # using auto sizing (specifying 0 for height and width).
45
+ # It represents width / height. The default is 9,
46
+ # which means 9 characters wide to every 1 line high.
47
+ #
48
+ attr_accessor :aspect
49
+
50
+ #
51
+ # Specifies a backtitle string to be displayed on the backdrop,
52
+ # at the top of the screen.
53
+ #
54
+ attr_accessor :backtitle
55
+
56
+ #
57
+ # Sound the audible alarm each time the screen is refreshed.
58
+ #
59
+ attr_accessor :beep
60
+
61
+ #
62
+ # Specify the position of the upper left corner of a dialog box
63
+ # on the screen, as an array containing two integers.
64
+ #
65
+ attr_accessor :begin
66
+
67
+ #
68
+ # Interpret embedded newlines in the dialog text as a newline
69
+ # on the screen. Otherwise, dialog will only wrap lines where
70
+ # needed to fit inside the text box. Even though you can control
71
+ # line breaks with this, dialog will still wrap any lines that are
72
+ # too long for the width of the box. Without cr-wrap, the layout
73
+ # of your text may be formatted to look nice in the source code of
74
+ # your script without affecting the way it will look in the dialog.
75
+ #
76
+ attr_accessor :crwrap
77
+
78
+ #
79
+ # Interpret the tags data for checklist, radiolist and menuboxes
80
+ # adding a column which is displayed in the bottom line of the
81
+ # screen, for the currently selected item.
82
+ #
83
+ attr_accessor :itemhelp
84
+
85
+ #
86
+ # Suppress the "Cancel" button in checklist, inputbox and menubox
87
+ # modes. A script can still test if the user pressed the ESC key to
88
+ # cancel to quit.
89
+ #
90
+ attr_accessor :nocancel
91
+
92
+ #
93
+ # Draw a shadow to the right and bottom of each dialog box.
94
+ #
95
+ attr_accessor :shadow
96
+
97
+ #
98
+ # Sleep (delay) for the given integer of seconds after processing
99
+ # a dialog box.
100
+ #
101
+ attr_accessor :sleep
102
+
103
+ #
104
+ # Convert each tab character to one or more spaces.
105
+ # Otherwise, tabs are rendered according to the curses library's
106
+ # interpretation.
107
+ #
108
+ attr_accessor :tabcorrect
109
+
110
+ #
111
+ # Specify the number(int) of spaces that a tab character occupies
112
+ # if the tabcorrect option is set true. The default is 8.
113
+ #
114
+ attr_accessor :tablen
115
+
116
+ #
117
+ # Title string to be displayed at the top of the dialog box.
118
+ #
119
+ attr_accessor :title
120
+
121
+ #
122
+ # Alternate path to dialog. If this is not set, environment path
123
+ # is used.
124
+ attr_accessor :path_to_dialog
125
+
126
+ # -- muquit@muquit.com mod starts---
127
+
128
+ # exit codes
129
+ attr_accessor :dialog_ok
130
+ attr_accessor :dialog_cancel
131
+ attr_accessor :dialog_help
132
+ attr_accessor :dialog_extra
133
+ attr_accessor :dialog_item_help
134
+ attr_accessor :dialog_esc
135
+
136
+ #
137
+ # ruby logger
138
+ attr_accessor :logger
139
+
140
+ # Override the label used for "OK" buttons
141
+ attr_accessor :ok_label
142
+
143
+ # clear screen
144
+ attr_accessor :clear
145
+
146
+ # make the password widget friendlier but less secure, by echoing
147
+ # asterisks for each character.
148
+ attr_accessor :insecure
149
+
150
+ # rather than draw graphics lines around boxes, draw ASCII + and -
151
+ attr_accessor :ascii_lines
152
+
153
+ attr_accessor :separator
154
+
155
+ # set it to true for passwordform.
156
+ attr_accessor :password_form
157
+
158
+ # For widgets holding a scrollable set of data, draw a scrollbar
159
+ # on its right-margin. This does not respond to the mouse.
160
+ attr_accessor :scrollbar
161
+ # -- muquit@muquit.com mod ends---
162
+
163
+ # Returns a new RDialog Object
164
+
165
+ def initialize
166
+ # muquit@muquit.com mod starts--
167
+ $stdout.sync = true
168
+ $stderr.sync = true
169
+ @dialog_ok = DIALOG_OK
170
+ @dialog_cancel = DIALOG_CANCEL
171
+ @dialog_help = DIALOG_HELP
172
+ @dialog_extra = DIALOG_EXTRA
173
+ @dialog_item_help = DIALOG_ITEM_HELP
174
+ @dialog_esc = DIALOG_ESC
175
+ @exit_code = 0
176
+ # muquit@muquit.com mod ends--
177
+ end
178
+
179
+ ##---- muquit@muquit.com mod starts---
180
+
181
+ ##---------------------------------------------------
182
+ # if @logger is set, log
183
+ ##---------------------------------------------------
184
+ def log_debug(msg)
185
+ if @logger
186
+ @logger.debug("#{msg}")
187
+ end
188
+ end
189
+
190
+ # return the exit code of the dialog
191
+ def exit_code
192
+ return @exit_code
193
+ end
194
+
195
+ ##---------------------------------------------------
196
+ # return the path of the executable which exists
197
+ # in the PATH env variable
198
+ # return nil otherwise
199
+ # arg is the name of the program without extensin
200
+ # muquit@muquit.com
201
+ ##---------------------------------------------------
202
+ def which(prog)
203
+ path_ext = ENV['PATHEXT']
204
+ exts = ['']
205
+ if path_ext # WINDOW$
206
+ exts = path_ext.split(';')
207
+ end
208
+ path = ENV['PATH']
209
+ path.split(File::PATH_SEPARATOR).each do |dir|
210
+ exts.each do |ext|
211
+ candidate = File.join(dir, "#{prog}#{ext}")
212
+ return candidate if File.executable?(candidate)
213
+ end
214
+ end
215
+ return nil
216
+ end
217
+
218
+
219
+ # A gauge box displays a meter along the bottom of the box. The
220
+ # meter indicates the percentage. New percentages are read from
221
+ # standard input, one integer per line. The meter is updated to
222
+ # reflect each new percentage. If the standard input reads the
223
+ # string "XXX", then the first line following is taken as an
224
+ # integer percentage, then subsequent lines up to another "XXX" are
225
+ # used for a new prompt. The gauge exits when EOF is reached on
226
+ # the standard input.
227
+ #
228
+ # The percent value denotes the initial percentage shown in the
229
+ # meter. If not speciied, it is zero.
230
+ #
231
+ # On exit, no text is written to dialog's output. The widget
232
+ # accepts no input, so the exit status is always OK.
233
+ #
234
+ # The caller will write the text markers to stdout
235
+ # as described above inside a block and will pass the block to the
236
+ # method. Look at samples/gauge for
237
+ # an example on how the method is called. Thanks to Mike Morgan
238
+ # for the idea to use a block.
239
+ #
240
+ # Author:: muquit@muquit.com Apr-02-2014
241
+ ##---------------------------------------------------
242
+ def gauge(text, height=0, width=0, percent=0)
243
+ cmd = ""
244
+ cmd << option_string()
245
+ cmd << " "
246
+ cmd << "--gauge"
247
+ cmd << " "
248
+ cmd << '"'
249
+ cmd << text
250
+ cmd << '"'
251
+ cmd << " "
252
+ cmd << height.to_s
253
+ cmd << " "
254
+ cmd << width.to_s
255
+ cmd << " "
256
+ cmd << percent.to_s
257
+
258
+ log_debug "Command:\n#{cmd}"
259
+ IO.popen(cmd, "w") {|fh| yield fh}
260
+ end
261
+
262
+
263
+ # Progressbox is used to display the piped output of a command.
264
+ # After the command completes, the user can press the ENTER key so
265
+ # that dialog will exit and the calling shell script can continue its operation.
266
+ # If three parameters are given, it displays the text under the title,
267
+ # delineated from the scrolling file's contents. If only two
268
+ # parameters are given, this text is omitted.
269
+ #
270
+ # The caller will write the progress string on stdout in a block
271
+ # and will pass the block to the method. Please look at samples/
272
+ # progress.rb for an example.
273
+ # Author: muquit@muquit.com Apr-02-2014
274
+ def progressbox(description='', height=0, width=0)
275
+ cmd = ""
276
+ cmd << option_string()
277
+ cmd << " "
278
+ cmd << "--progressbox"
279
+ cmd << " "
280
+ if description.length > 0
281
+ cmd << '"'
282
+ cmd << description
283
+ cmd << '"'
284
+ end
285
+ cmd << " "
286
+ cmd << height.to_s
287
+ cmd << " "
288
+ cmd << width.to_s
289
+
290
+ log_debug("Command\n#{cmd}")
291
+ IO.popen(cmd, "w") {|fh| yield fh}
292
+ end
293
+
294
+ # same as progressbox but displays OK button at the end
295
+ def programbox(description='', height=0, width=0)
296
+ cmd = ""
297
+ cmd << option_string()
298
+ cmd << " "
299
+ cmd << "--programbox"
300
+ cmd << " "
301
+ if description.length > 0
302
+ cmd << '"'
303
+ cmd << description
304
+ cmd << '"'
305
+ end
306
+ cmd << " "
307
+ cmd << height.to_s
308
+ cmd << " "
309
+ cmd << width.to_s
310
+
311
+ log_debug("Command\n#{cmd}")
312
+ IO.popen(cmd, "w") {|fh| yield fh}
313
+ end
314
+
315
+ #
316
+ # A prgbox is very similar to a programbox.
317
+ #
318
+ # This dialog box is used to display the output of a command that
319
+ # is specified as an argument to prgbox.
320
+ #
321
+ # After the command completes, the user can press the ENTER key so
322
+ # that dialog will exit and the calling shell script can continue
323
+ # its operation.
324
+ #
325
+ # If three parameters are given, it displays the text under the
326
+ # title, delineated from the scrolling file's contents. If only
327
+ # two parameters are given, this text is omitted.
328
+ #
329
+ def prgbox(command, height=0, width=0, text='')
330
+ cmd = ""
331
+ cmd << option_string()
332
+ cmd << " "
333
+ cmd << "--prgbox"
334
+ cmd << " "
335
+ if text.length > 0
336
+ cmd << '"'
337
+ cmd << text
338
+ cmd << '"'
339
+ end
340
+ cmd << " "
341
+ cmd << '"'
342
+ cmd << command
343
+ cmd << '"'
344
+ cmd << " "
345
+ cmd << height.to_s
346
+ cmd << " "
347
+ cmd << width.to_s
348
+ system(cmd)
349
+ @exit_code = $?.exitstatus
350
+ end
351
+
352
+ #
353
+ # Display data organized as a tree. Each group of data contains a
354
+ # tag, the text to display for the item, its status ("on" or
355
+ # "off") and the depth of the item in the tree.
356
+ #
357
+ # Only one item can be selected (like the radiolist). The tag is
358
+ # not displayed.
359
+ #
360
+ # On exit, the tag of the selected item is written to dialog's
361
+ # output.
362
+ def treeview(text="Text Goes Here", items=nil, height=0, width=0, listheight=0)
363
+ tmp = Tempfile.new('dialog')
364
+ itemlist = ''
365
+ items.each do |item|
366
+ itemlist << '"'
367
+ itemlist << item[0].to_s
368
+ itemlist << '"'
369
+ itemlist << " "
370
+ itemlist << '"'
371
+ itemlist << item[1].to_s
372
+ itemlist << '"'
373
+ itemlist << " "
374
+ itemlist << '"'
375
+ if item[2]
376
+ item[2] = "on"
377
+ else
378
+ item[2] = "off"
379
+ end
380
+ itemlist << item[2]
381
+ itemlist << '"'
382
+ itemlist << " "
383
+ itemlist << item[3].to_s
384
+ itemlist << " "
385
+ end
386
+ itemlist << "2>"
387
+ itemlist << tmp.path
388
+
389
+ cmd = ""
390
+ cmd << option_string()
391
+ cmd << " "
392
+ cmd << "--treeview"
393
+ cmd << " "
394
+ cmd << '"'
395
+ cmd << " "
396
+ cmd << text
397
+ cmd << '"'
398
+ cmd << " "
399
+ cmd << height.to_s
400
+ cmd << " "
401
+ cmd << width.to_s
402
+ cmd << " "
403
+ cmd << listheight.to_s
404
+ cmd << " "
405
+ cmd << itemlist
406
+
407
+ log_debug "Number of items: #{items.size}"
408
+ log_debug "Command:\n#{cmd}"
409
+
410
+ system(cmd)
411
+ @exit_code = $?.exitstatus
412
+ log_debug "Exit code: #{exit_code}"
413
+ tag = ''
414
+ if @exit_code == 0
415
+ tag = tmp.read
416
+ end
417
+ tmp.close!
418
+ return tag
419
+ end
420
+
421
+ #
422
+ # A buildlist dialog displays two lists, side-by-side. The list
423
+ # on the left shows unselected items. The list on the right shows
424
+ # selected items. As items are selected or unselected, they move
425
+ # between the lists. Use SPACE bar to select/unselect an item.
426
+ #
427
+ # Use a carriage return or the "OK" button to accept the current
428
+ # value in the selected-window and exit. The results are written
429
+ # using the order displayed in the selected-window.
430
+ #
431
+ # The caller is responsile to create the items properly. Please
432
+ # look at samples/buildlist.rb for an example.
433
+ #
434
+ # return an array of selected tags
435
+ # Author:: muquit@muquit.com
436
+ def buildlist(text="Text Goes Here", items = nil, height=0, width=0, listheight=0)
437
+ tmp = Tempfile.new('dialog')
438
+ selected_tags = []
439
+ itemlist = ''
440
+
441
+ items.each do |item|
442
+ itemlist << '"'
443
+ itemlist << item[0].to_s
444
+ itemlist << '"'
445
+ itemlist << " "
446
+ itemlist << '"'
447
+ itemlist << item[1].to_s
448
+ itemlist << '"'
449
+ itemlist << " "
450
+ itemlist << '"'
451
+ if item[2]
452
+ item[2] = "on"
453
+ else
454
+ item[2] = "off"
455
+ end
456
+ itemlist << item[2]
457
+ itemlist << '"'
458
+ itemlist << " "
459
+ end
460
+ itemlist << "2>"
461
+ itemlist << tmp.path
462
+
463
+ cmd = ""
464
+
465
+ cmd << option_string()
466
+ if !@separator
467
+ @separator = "|"
468
+ cmd << " "
469
+ cmd << "--separator"
470
+ cmd << " "
471
+ cmd << '"'
472
+ cmd << @separator
473
+ cmd << '"'
474
+ end
475
+ cmd << " "
476
+ cmd << "--buildlist"
477
+ cmd << " "
478
+ cmd << '"'
479
+ cmd << " "
480
+ cmd << text
481
+ cmd << '"'
482
+ cmd << " "
483
+ cmd << height.to_s
484
+ cmd << " "
485
+ cmd << width.to_s
486
+ cmd << " "
487
+ cmd << listheight.to_s
488
+ cmd << " "
489
+ cmd << itemlist
490
+
491
+ log_debug "Number of items: #{items.size}"
492
+ log_debug "Command:\n#{cmd}"
493
+
494
+ system(cmd)
495
+ @exit_code = $?.exitstatus
496
+ log_debug "Exit code: #{exit_code}"
497
+ if @exit_code == 0
498
+ lines = tmp.read
499
+ log_debug "lines: #{lines} #{lines.class}"
500
+ sep = Shellwords.escape(@separator)
501
+ a = lines.split(/#{sep}/)
502
+ a.each do |tag|
503
+ log_debug "tag: '#{tag}'"
504
+ selected_tags << tag if tag.to_s.length > 0
505
+ end
506
+ end
507
+ tmp.close!
508
+ return selected_tags
509
+ end
510
+
511
+ # A pause box displays a meter along the bottom of the box. The
512
+ # meter indicates how many seconds remain until the end of the
513
+ # pause. The pause exits when timeout is reached or the user
514
+ # presses the OK button (status OK) or the user presses the CANCEL
515
+ # button or Esc key.
516
+ def pause(text="Text Goes Here", height=0, width=0, secs=10)
517
+ cmd = ""
518
+ cmd << option_string()
519
+ cmd << " "
520
+ cmd << "--pause"
521
+ cmd << " "
522
+ cmd << '"'
523
+ cmd << text
524
+ cmd << '"'
525
+ cmd << " "
526
+ cmd << height.to_s
527
+ cmd << " "
528
+ cmd << width.to_s
529
+ cmd << " "
530
+ cmd << secs.to_s
531
+ log_debug "Command:\n#{cmd}"
532
+
533
+ system(cmd)
534
+ result = ''
535
+ @exit_code = $?.exitstatus
536
+ log_debug "Exit code: #{exit_code}"
537
+ end
538
+
539
+ # The edit-box dialog displays a copy of the file. You may edit
540
+ # it using the backspace, delete and cursor keys to correct typing
541
+ # errors. It also recognizes pageup/pagedown. Unlike the --in-
542
+ # putbox, you must tab to the "OK" or "Cancel" buttons to close
543
+ # the dialog. Pressing the "Enter" key within the box will split
544
+ # the corresponding line.
545
+ #
546
+ # On exit, the contents of the edit window are written to dialog's
547
+ # output.
548
+ def editbox(filepath, height=0, width=0)
549
+ tmp = Tempfile.new('dialog')
550
+
551
+ cmd = ""
552
+ cmd << option_string()
553
+ cmd << " "
554
+ cmd << "--editbox"
555
+ cmd << " "
556
+ cmd << '"'
557
+ cmd << filepath
558
+ cmd << '"'
559
+ cmd << " "
560
+ cmd << height.to_s
561
+ cmd << " "
562
+ cmd << width.to_s
563
+ cmd << " "
564
+ cmd << "2>"
565
+ cmd << tmp.path
566
+
567
+ log_debug "Command:\n#{cmd}"
568
+
569
+ system(cmd)
570
+ result = ''
571
+ @exit_code = $?.exitstatus
572
+ log_debug "Exit code: #{exit_code}"
573
+ if @exit_code == 0
574
+ result = tmp.read
575
+ end
576
+ tmp.close!
577
+ return result
578
+ end
579
+
580
+ #
581
+ # form/mixedform dialog
582
+ # A form dialog displays a form consisting of labels and fields,
583
+ # which are positioned on a scrollable window by coordinates given in
584
+ # the script. The field length flen and input-length ilen tell how
585
+ # long the field can be. The former defines the length shown for a
586
+ # selected field, while the latter defines the permissible length of
587
+ # the data entered in the field.
588
+ # The caller is responsile to create the items properly. Please
589
+ # look at samples/form.rb for an example
590
+ #
591
+ # return a hash. keys are the labels
592
+ # Author:: muquit@muquit.com
593
+ def form(text, items, height=0, width=0, formheight=0)
594
+ res_hash = {}
595
+ tmp = Tempfile.new('dialog')
596
+ itemlist = ''
597
+ mixed_form = false
598
+ item_size = items[0].size
599
+ log_debug "Item size:#{item_size}"
600
+ # if there are 9 elements, it's a mixedform
601
+ if item_size == 9
602
+ mixed_form = true
603
+ end
604
+ items.each do |item|
605
+ itemlist << '"'
606
+ itemlist << item[0].to_s
607
+ itemlist << '"'
608
+ itemlist << " "
609
+ itemlist << item[1].to_s
610
+ itemlist << " "
611
+ itemlist << item[2].to_s
612
+ itemlist << " "
613
+ itemlist << '"'
614
+ itemlist << item[3].to_s
615
+ itemlist << '"'
616
+ itemlist << " "
617
+ itemlist << item[4].to_s
618
+ itemlist << " "
619
+ itemlist << item[5].to_s
620
+ itemlist << " "
621
+ itemlist << item[6].to_s
622
+ itemlist << " "
623
+ itemlist << item[7].to_s
624
+ itemlist << " "
625
+ if mixed_form
626
+ itemlist << item[8].to_s
627
+ itemlist << " "
628
+ end
629
+ end
630
+ itemlist << " "
631
+ itemlist << "2>"
632
+ itemlist << tmp.path
633
+
634
+ cmd = ""
635
+ cmd << option_string()
636
+ cmd << " "
637
+ if mixed_form
638
+ cmd << "--mixedform"
639
+ else
640
+ if @password_form
641
+ cmd << "--passwordform"
642
+ else
643
+ cmd << "--form"
644
+ end
645
+ end
646
+ cmd << " "
647
+ cmd << '"'
648
+ cmd << text
649
+ cmd << '"'
650
+ cmd << " "
651
+ cmd << height.to_s
652
+ cmd << " "
653
+ cmd << width.to_s
654
+ cmd << " "
655
+ cmd << formheight.to_s
656
+ cmd << " "
657
+ cmd << itemlist
658
+
659
+ log_debug("Number of items: #{items.size}")
660
+ log_debug("Command:\n#{cmd}")
661
+ system(cmd)
662
+ @exit_code = $?.exitstatus
663
+ log_debug "Exit code: #{exit_code}"
664
+
665
+ if @exit_code == 0
666
+ lines = tmp.readlines
667
+ lines.each_with_index do |val, idx|
668
+ key = items[idx][0]
669
+ res_hash[key] = val.chomp
670
+ end
671
+ end
672
+
673
+ tmp.close!
674
+ return res_hash
675
+ end
676
+
677
+ #
678
+ # A mixedform dialog displays a form consisting of labels and fields,
679
+ # much like the --form dialog. It differs by adding a field-type
680
+ # parameter to each field's description. Each bit in the type denotes
681
+ # an attribute of the field:
682
+ # * 1 hidden, e.g., a password field.
683
+ # * 2 readonly, e.g., a label.#
684
+ # Author:: muquit@muquit.com
685
+ def mixedform(text, items, height=0, width=0, formheight=0)
686
+ item_size = items[0].size
687
+ log_debug "Item size:#{item_size}"
688
+ if item_size == 9
689
+ return form(text, items, height, width, formheight)
690
+ end
691
+ return nil
692
+ end
693
+
694
+ #
695
+ # This is identical to --form except that all text fields are
696
+ # treated as password widgets rather than inputbox widgets.
697
+ def passwordform(text, items, height=0, width=0, formheight=0)
698
+ @password_form = true
699
+ return form(text, items, height, width, formheight)
700
+ end
701
+
702
+ ##---- muquit@muquit.com mod ends---
703
+
704
+
705
+ # A calendar box displays month, day and year in separately
706
+ # adjustable windows. If the values for day, month or year are
707
+ # missing or negative, the current date's corresponding values
708
+ # are used. You can increment or decrement any of those using
709
+ # the left-, up-, right- and down-arrows. Use vi-style h, j, k
710
+ # and l for moving around the array of days in a month. Use tab
711
+ # or backtab to move between windows. If the year is given as
712
+ # zero, the current date is used as an initial value.
713
+ #
714
+ # Returns a Date object with the selected date
715
+
716
+ def calendar(text="Select a Date", height=0, width=0, day=Date.today.mday(), month=Date.today.mon(), year=Date.today.year())
717
+
718
+ tmp = Tempfile.new('tmp')
719
+
720
+ command = option_string() + "--calendar \"" + text.to_s +
721
+ "\" " + height.to_i.to_s + " " + width.to_i.to_s + " " +
722
+ day.to_i.to_s + " " + month.to_i.to_s + " " + year.to_i.to_s +
723
+ " 2> " + tmp.path
724
+ success = system(command)
725
+ if success
726
+ date = Date::civil(*tmp.readline.split('/').collect {|i| i.to_i}.reverse)
727
+ tmp.close!
728
+ return date
729
+ else
730
+ tmp.close!
731
+ return success
732
+ end
733
+
734
+ end
735
+
736
+ # A checklist box is similar to a menu box; there are multiple
737
+ # entries presented in the form of a menu. Instead of choosing
738
+ # one entry among the entries, each entry can be turned on or off
739
+ # by the user. The initial on/off state of each entry is speci-
740
+ # fied by status.
741
+ # return an array of selected items
742
+ def checklist(text, items, height=0, width=0, listheight=0)
743
+
744
+ tmp = Tempfile.new('tmp')
745
+
746
+ itemlist = String.new
747
+
748
+ for item in items
749
+ if item[2]
750
+ item[2] = "on"
751
+ else
752
+ item[2] = "off"
753
+ end
754
+ itemlist += "\"" + item[0].to_s + "\" \"" + item[1].to_s +
755
+ "\" " + item[2] + " "
756
+
757
+ if @itemhelp
758
+ itemlist += "\"" + item[3].to_s + "\" "
759
+ end
760
+ end
761
+
762
+ sep = "|"
763
+ command = option_string() + "--checklist \"" + text.to_s +
764
+ "\" " + height.to_i.to_s + " " + width.to_i.to_s +
765
+ " " + listheight.to_i.to_s + " " + itemlist + "2> " +
766
+ tmp.path
767
+ log_debug "Command:\n#{command}"
768
+ success = system(command)
769
+ selected_array = []
770
+ if success
771
+ selected_string = tmp.readline
772
+ tmp.close!
773
+ log_debug "Separator: #{@separator}"
774
+
775
+ sep = Shellwords.escape(@separator)
776
+ a = selected_string.split(/#{sep}/)
777
+ a.each do |item|
778
+ log_debug ">> #{item}"
779
+ selected_array << item if item && item.to_s.length > 0
780
+ end
781
+ return selected_array
782
+ else
783
+ tmp.close!
784
+ return success
785
+ end
786
+
787
+ end
788
+
789
+ # The file-selection dialog displays a text-entry window in which
790
+ # you can type a filename (or directory), and above that two win-
791
+ # dows with directory names and filenames.
792
+
793
+ # Here filepath can be a filepath in which case the file and
794
+ # directory windows will display the contents of the path and the
795
+ # text-entry window will contain the preselected filename.
796
+ #
797
+ # Use tab or arrow keys to move between the windows. Within the
798
+ # directory or filename windows, use the up/down arrow keys to
799
+ # scroll the current selection. Use the space-bar to copy the
800
+ # current selection into the text-entry window.
801
+ #
802
+ # Typing any printable characters switches focus to the text-
803
+ # entry window, entering that character as well as scrolling the
804
+ # directory and filename windows to the closest match.
805
+ #
806
+ # Use a carriage return or the "OK" button to accept the current
807
+ # value in the text-entry window and exit.
808
+
809
+ def fselect(path, height=0, width=0)
810
+ tmp = Tempfile.new('tmp')
811
+
812
+ command = option_string() + "--fselect \"" + path.to_s +
813
+ "\" " + height.to_i.to_s + " " + width.to_i.to_s + " "
814
+
815
+ command += "2> " + tmp.path
816
+
817
+ success = system(command)
818
+
819
+ if success
820
+ begin
821
+ selected_string = tmp.readline
822
+ rescue EOFError
823
+ selected_string = ""
824
+ end
825
+ tmp.close!
826
+ return selected_string
827
+ else
828
+ tmp.close!
829
+ return success
830
+ end
831
+ end
832
+
833
+
834
+ #
835
+ # An info box is basically a message box. However, in this case,
836
+ # dialog will exit immediately after displaying the message to
837
+ # the user. The screen is not cleared when dialog exits, so that
838
+ # the message will remain on the screen until the calling shell
839
+ # script clears it later. This is useful when you want to inform
840
+ # the user that some operations are carrying on that may require
841
+ # some time to finish.
842
+ #
843
+ # Returns false if esc was pushed
844
+ def infobox(text, height=0, width=0)
845
+ command = option_string() + "--infobox \"" + text.to_s +
846
+ "\" " + height.to_i.to_s + " " + width.to_i.to_s + " "
847
+ success = system(command)
848
+ return success
849
+ end
850
+
851
+ # A radiolist box is similar to a menu box. The only difference
852
+ # is that you can indicate which entry is currently selected, by
853
+ # setting its status to true.
854
+
855
+ def radiolist(text, items, height=0, width=0, listheight=0)
856
+
857
+ tmp = Tempfile.new('tmp')
858
+
859
+ itemlist = String.new
860
+
861
+ for item in items
862
+ if item[2]
863
+ item[2] = "on"
864
+ else
865
+ item[2] = "off"
866
+ end
867
+ itemlist += "\"" + item[0].to_s + "\" \"" + item[1].to_s +
868
+ "\" " + item[2] + " "
869
+
870
+ if @itemhelp
871
+ itemlist += "\"" + item[3].to_s + "\" "
872
+ end
873
+ end
874
+
875
+ command = option_string() + "--radiolist \"" + text.to_s +
876
+ "\" " + height.to_i.to_s + " " + width.to_i.to_s +
877
+ " " + listheight.to_i.to_s + " " + itemlist + "2> " +
878
+ tmp.path
879
+ log_debug("Command:\n#{command}")
880
+ success = system(command)
881
+
882
+ if success
883
+ selected_string = tmp.readline
884
+ tmp.close!
885
+ return selected_string
886
+ else
887
+ tmp.close!
888
+ return success
889
+ end
890
+
891
+ end
892
+
893
+ # As its name suggests, a menu box is a dialog box that can be
894
+ # used to present a list of choices in the form of a menu for the
895
+ # user to choose. Choices are displayed in the order given.
896
+ # Each menu entry consists of a tag string and an item string.
897
+ # The tag gives the entry a name to distinguish it from the other
898
+ # entries in the menu. The item is a short description of the
899
+ # option that the entry represents. The user can move between
900
+ # the menu entries by pressing the cursor keys, the first letter
901
+ # of the tag as a hot-key, or the number keys 1-9. There are
902
+ # menu-height entries displayed in the menu at one time, but the
903
+ # menu will be scrolled if there are more entries than that.
904
+ #
905
+ # Returns a string containing the tag of the chosen menu entry.
906
+
907
+ def menu(text="Text Goes Here", items=nil, height=0, width=0, listheight=0)
908
+ tmp = Tempfile.new('tmp')
909
+
910
+ itemlist = String.new
911
+
912
+ for item in items
913
+ itemlist += "\"" + item[0].to_s + "\" \"" + item[1].to_s + "\" "
914
+
915
+ if @itemhelp
916
+ itemlist += "\"" + item[2].to_s + "\" "
917
+ end
918
+ end
919
+
920
+ command = option_string() + "--menu \"" + text.to_s +
921
+ "\" " + height.to_i.to_s + " " + width.to_i.to_s +
922
+ " " + listheight.to_i.to_s + " " + itemlist + "2> " +
923
+ tmp.path
924
+
925
+ log_debug("Command:\n#{command}")
926
+ success = system(command)
927
+
928
+ if success
929
+ selected_string = tmp.readline
930
+ tmp.close!
931
+ return selected_string
932
+ else
933
+ tmp.close!
934
+ return success
935
+ end
936
+
937
+ end
938
+
939
+ # A message box is very similar to a yes/no box. The only dif-
940
+ # ference between a message box and a yes/no box is that a mes-
941
+ # sage box has only a single OK button. You can use this dialog
942
+ # box to display any message you like. After reading the mes-
943
+ # sage, the user can press the ENTER key so that dialog will exit
944
+ # and the calling shell script can continue its operation.
945
+
946
+ def msgbox(text="Text Goes Here", height=0, width=0)
947
+ command = option_string() + "--msgbox \"" + text.to_s +
948
+ "\" " + height.to_i.to_s + " " + width.to_i.to_s + " "
949
+
950
+ log_debug "Command\n#{command}"
951
+ success = system(command)
952
+ return success
953
+ end
954
+
955
+ # A password box is similar to an input box, except that the text
956
+ # the user enters is not displayed. This is useful when prompt-
957
+ # ing for passwords or other sensitive information. Be aware
958
+ # that if anything is passed in "init", it will be visible in the
959
+ # system's process table to casual snoopers. Also, it is very
960
+ # confusing to the user to provide them with a default password
961
+ # they cannot see. For these reasons, using "init" is highly
962
+ # discouraged.
963
+
964
+ def passwordbox(text="Please enter some text", height=0, width=0, init="")
965
+ tmp = Tempfile.new('tmp')
966
+ command = option_string() + "--passwordbox \"" + text.to_s +
967
+ "\" " + height.to_i.to_s + " " + width.to_i.to_s + " "
968
+
969
+ unless init.empty?
970
+ command += init.to_s + " "
971
+ end
972
+
973
+ command += "2> " + tmp.path
974
+ log_debug(command)
975
+ success = system(command)
976
+
977
+ if success
978
+ begin
979
+ selected_string = tmp.readline
980
+ rescue EOFError
981
+ selected_string = ""
982
+ end
983
+ tmp.close!
984
+ return selected_string
985
+ else
986
+ tmp.close!
987
+ return success
988
+ end
989
+ end
990
+
991
+ # The textbox method handles three similar dialog functions, textbox,
992
+ # tailbox, and tailboxbg. They are activated by setting type to
993
+ # "text", "tail", and "bg" respectively
994
+ #
995
+ # Textbox mode:
996
+ # A text box lets you display the contents of a text file in a
997
+ # dialog box. It is like a simple text file viewer. The user
998
+ # can move through the file by using the cursor, PGUP/PGDN and
999
+ # HOME/END keys available on most keyboards. If the lines are
1000
+ # too long to be displayed in the box, the LEFT/RIGHT keys can be
1001
+ # used to scroll the text region horizontally. You may also use
1002
+ # vi-style keys h, j, k, l in place of the cursor keys, and B or
1003
+ # N in place of the pageup/pagedown keys. Scroll up/down using
1004
+ # vi-style 'k' and 'j', or arrow-keys. Scroll left/right using
1005
+ # vi-style 'h' and 'l', or arrow-keys. A '0' resets the
1006
+ # left/right scrolling. For more convenience, vi-style forward
1007
+ # and backward searching functions are also provided.
1008
+ #
1009
+ # Tailbox mode:
1010
+ # Display text from a file in a dialog box, as in a "tail -f"
1011
+ # command. Scroll left/right using vi-style 'h' and 'l', or
1012
+ # arrow-keys. A '0' resets the scrolling.
1013
+ #
1014
+ # Tailboxbg mode:
1015
+ # Display text from a file in a dialog box as a background task,
1016
+ # as in a "tail -f &" command. Scroll left/right using vi-style
1017
+ # 'h' and 'l', or arrow-keys. A '0' resets the scrolling.
1018
+
1019
+ def textbox(file, type="text", height=0, width=0)
1020
+ case type
1021
+ when "text"
1022
+ opt = "--textbox"
1023
+ when "tail"
1024
+ opt = "--tailbox"
1025
+ when "bg"
1026
+ opt = "--textboxbg"
1027
+ end
1028
+
1029
+ command = option_string() + opt +" \"" + file.to_s +
1030
+ "\" " + height.to_i.to_s + " " + width.to_i.to_s + " "
1031
+
1032
+ success = system(command)
1033
+
1034
+ return success
1035
+ end
1036
+
1037
+ # A dialog is displayed which allows you to select hour, minute
1038
+ # and second. If the values for hour, minute or second are miss-
1039
+ # ing or negative, the current date's corresponding values are
1040
+ # used. You can increment or decrement any of those using the
1041
+ # left-, up-, right- and down-arrows. Use tab or backtab to move
1042
+ # between windows.
1043
+ #
1044
+ # On exit, a Time object is returned.
1045
+
1046
+ ##- def timebox(file, type="text", height=0, width=0, time=Time.now)
1047
+ def timebox(text, height=0, width=0, time=Time.now)
1048
+ tmp = Tempfile.new('tmp')
1049
+
1050
+ command = option_string() + "--timebox \"" + text.to_s +
1051
+ "\" " + height.to_i.to_s + " " + width.to_i.to_s + " " +
1052
+ time.hour.to_s + " " + time.min.to_s + " " +
1053
+ time.sec.to_s + " 2> " + tmp.path
1054
+ log_debug("Command:\n#{command}")
1055
+ success = system(command)
1056
+ if success
1057
+ time = Time.parse(tmp.readline)
1058
+ tmp.close!
1059
+ return time
1060
+ else
1061
+ tmp.close!
1062
+ return success
1063
+ end
1064
+
1065
+ end
1066
+
1067
+ # An input box is useful when you want to ask questions that
1068
+ # require the user to input a string as the answer. If init is
1069
+ # supplied it is used to initialize the input string. When
1070
+ # entering the string, the backspace, delete and cursor keys can
1071
+ # be used to correct typing errors. If the input string is
1072
+ # longer than can fit in the dialog box, the input field will be
1073
+ # scrolled.
1074
+ #
1075
+ # On exit, the input string will be returned.
1076
+ def inputbox(text="Please enter some text", height=0, width=0, init="")
1077
+ tmp = Tempfile.new('tmp')
1078
+
1079
+ command = option_string() + "--inputbox \"" + text.to_s +
1080
+ "\" " + height.to_i.to_s + " " + width.to_i.to_s + " "
1081
+
1082
+ unless init.empty?
1083
+ command += init.to_s + " "
1084
+ end
1085
+
1086
+ command += "2> " + tmp.path
1087
+
1088
+ log_debug(command)
1089
+ success = system(command)
1090
+
1091
+ if success
1092
+ begin
1093
+ selected_string = tmp.readline
1094
+ rescue EOFError
1095
+ selected_string = ""
1096
+ end
1097
+ tmp.close!
1098
+ return selected_string
1099
+ else
1100
+ tmp.close!
1101
+ return success
1102
+ end
1103
+ end
1104
+
1105
+ # A yes/no dialog box of size height rows by width columns will
1106
+ # be displayed. The string specified by text is displayed inside
1107
+ # the dialog box. If this string is too long to fit in one line,
1108
+ # it will be automatically divided into multiple lines at appro-
1109
+ # priate places. The text string can also contain the sub-string
1110
+ # "\n" or newline characters '\n' to control line breaking
1111
+ # explicitly. This dialog box is useful for asking questions
1112
+ # that require the user to answer either yes or no. The dialog
1113
+ # box has a Yes button and a No button, in which the user can
1114
+ # switch between by pressing the TAB key.
1115
+
1116
+ # changing --inputbox to --yesno
1117
+ # muquit@muquit.com Apr-01-2014
1118
+ def yesno(text="Please enter some text", height=0, width=0)
1119
+ # command = option_string() + "--inputbox \"" + text.to_s +
1120
+ # "\" " + height.to_i.to_s + " " + width.to_i.to_s
1121
+
1122
+ command = ""
1123
+ command << option_string();
1124
+ command << " "
1125
+ command << '"'
1126
+ command << "--yesno"
1127
+ command << '"'
1128
+ command << " "
1129
+ command << '"'
1130
+ command << text
1131
+ command << '"'
1132
+ command << " "
1133
+ command << height.to_s
1134
+ command << " "
1135
+ command << width.to_s
1136
+
1137
+
1138
+ log_debug("Command:\n#{command}")
1139
+ success = system(command)
1140
+ return success
1141
+ end
1142
+
1143
+ private
1144
+
1145
+ def option_string
1146
+ # make sure 'dialog' is installed
1147
+ # muquit@muquit.com
1148
+ exe_loc = ''
1149
+ unless @path_to_dialog
1150
+ exe_loc = which("dialog")
1151
+ ostring = exe_loc
1152
+ else
1153
+ exe_loc = @path_to_dialog
1154
+ if !File.exists?(exe_loc)
1155
+ raise "Specified path of dialog '#{exe_loc}' does not exist"
1156
+ end
1157
+ if !File.executable?(exe_loc)
1158
+ raise "The program #{exe_loc} is not executable"
1159
+ end
1160
+ end
1161
+ raise "'dialog' executable not found in path" unless exe_loc
1162
+ ostring = exe_loc + " "
1163
+
1164
+ if @aspect
1165
+ ostring += "--aspect " + aspect + " "
1166
+ end
1167
+
1168
+ if @beep
1169
+ ostring += "--beep "
1170
+ end
1171
+
1172
+ if @boxbegin
1173
+ ostring += "--begin " + @boxbegin[0] + @boxbegin[1] + " "
1174
+ end
1175
+
1176
+ if @backtitle
1177
+ ostring += "--backtitle \"" + @backtitle + "\" "
1178
+ end
1179
+
1180
+ if @itemhelp
1181
+ ostring += "--item-help "
1182
+ end
1183
+
1184
+ unless @shadow == nil
1185
+ if @shadow == true
1186
+ ostring += "--shadow "
1187
+ else
1188
+ ostring += "--no-shadow "
1189
+ end
1190
+ end
1191
+
1192
+ if @sleep
1193
+ ostring += "--sleep " + @sleep.to_s + " "
1194
+ end
1195
+
1196
+ if @tabcorrect
1197
+ ostring += "--tab-correct "
1198
+ end
1199
+
1200
+ if @tablen
1201
+ ostring += "--tab-len " + @tablen.to_s + " "
1202
+ end
1203
+
1204
+ if @title
1205
+ # ostring += "--title " + "\"" + @title.to_s "\"" + " "
1206
+ # muquit@muquit.com Apr-01-2014
1207
+ ostring += "--title \"" + @title.to_s + "\" "
1208
+ end
1209
+
1210
+ # muquit@muquit.com mod starts--
1211
+ if @clear
1212
+ ostring += "--clear "
1213
+ end
1214
+
1215
+ if @insecure
1216
+ ostring += "--insecure "
1217
+ end
1218
+
1219
+ if @ascii_lines
1220
+ ostring += "--ascii-lines "
1221
+ end
1222
+
1223
+ if @ok_label
1224
+ ostring += "--ok-label #{@ok_label} "
1225
+ end
1226
+
1227
+ if @separator
1228
+ ostring += "--separator \"#{@separator}\" "
1229
+ end
1230
+ if @scrollbar
1231
+ ostring += "--scrollbar "
1232
+ end
1233
+ # muquit@muquit.com mod ends--
1234
+
1235
+ if @nocancel
1236
+ ostring += "--nocancel "
1237
+ end
1238
+
1239
+ return ostring
1240
+ end
1241
+ end
1242
+
1243
+
1244
+
1245
+ #Dir[File.join(File.dirname(__FILE__), 'rdialog/**/*.rb')].sort.each { |lib| require lib }