• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yast / yast-yast2 / 13440235285

20 Feb 2025 04:40PM UTC coverage: 41.869% (-0.02%) from 41.889%
13440235285

push

github

web-flow
Merge pull request #1316 from yast/agama_kernel_conf

Respect Agama kernel parameters

2 of 4 new or added lines in 1 file covered. (50.0%)

265 existing lines in 40 files now uncovered.

12605 of 30106 relevant lines covered (41.87%)

10.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

52.46
/library/wizard/src/modules/Progress.rb
1
# ***************************************************************************
2
#
3
# Copyright (c) 2002 - 2012 Novell, Inc.
4
# All Rights Reserved.
5
#
6
# This program is free software; you can redistribute it and/or
7
# modify it under the terms of version 2 of the GNU General Public License as
8
# published by the Free Software Foundation.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, contact Novell, Inc.
17
#
18
# To contact Novell about this file by physical or electronic mail,
19
# you may find current contact information at www.novell.com
20
#
21
# ***************************************************************************
22
# File:  modules/Progress.ycp
23
#
24
# Functions for progress bar.<br>
25
# <pre>
26
# Dialog Title
27
#
28
# [x] Stage 1
29
# [x] Stage 2
30
#  => Stage 3
31
#  -  Stage 4
32
#  -  Stage 5
33
#
34
# Progress Title
35
# [============================90%=======================------]
36
#
37
# </pre>
38
# Example of progress bar usage (don't forget the translation marks in your code):
39
# Progress bar supposes main wizard dialog is created.<pre>
40
# Progress::Simple ("Some progress bar", "Progress runs here...", 3, "");
41
# Progress::NextStep (); // the 1st one does nothing!
42
# Progress::NextStep ();
43
# Progress::NextStep ();
44
# Progress::NextStep ();</pre>
45
#
46
# Another example:<pre>
47
# Progress::New ("Complex progress bar", " ", 100, [
48
#      "Stage1", "Stage2", "Stage3",
49
#      ], [
50
#      "Stage 1 ...", "Stage 2 ...", "Stage 3 ...", "Finished",
51
#      ], "Help text");
52
# Progress::NextStage ();
53
# Progress::NextStageStep (20);
54
# Progress::Stage (0, "I am back", 2);
55
# Progress::Title ("Still in stage 0");
56
# Progress::NextStageStep (90);
57
# Progress::Finish ();</pre>
58
#
59
# It is possible to add a detailed subprogress above the main progress bar:
60
#
61
# <pre>
62
# // create a standard progress
63
# Progress::New(...);
64
#
65
# // add a subprogress with 42 steps
66
# Progress::SubprogressType(`progress, 42);
67
# Progress::SubprogressTitle("Subprogress label");
68
#
69
# // set the subprogress value
70
# Progress::SubprogressValue(12);
71
# Progress::SubprogressValue(24);
72
#
73
# // remove the subprogress (it's only for the current task/stage)
74
# Progress::SubprogressType(`none, nil);
75
#
76
# // next stage
77
# Progress::NextStage();
78
# </pre>
79
#
80
# See also hand made documentation.
81
# <a href="../Progress.html">Progress.html</a>
82
require "yast"
1✔
83

84
module Yast
1✔
85
  class ProgressClass < Module
1✔
86
    include Yast::Logger
1✔
87

88
    def main
1✔
89
      Yast.import "UI"
1✔
90

91
      textdomain "base"
1✔
92

93
      Yast.import "CommandLine"
1✔
94
      Yast.import "Wizard"
1✔
95
      Yast.import "Mode"
1✔
96
      Yast.import "Directory"
1✔
97
      Yast.import "FileUtils"
1✔
98

99
      # *******************************************************************
100
      # // !!! IMPORTANT !!!
101
      # // If you add here a new variable which is valid only for the current
102
      # // progress do not forget to add it to PushState() and PopState()
103
      # // functions which are are used for nested progresses!
104
      # *******************************************************************
105

106
      # Number of stages.
107
      @stages = 0
1✔
108
      # Number of steps
109
      @steps = 0
1✔
110
      # Current stage
111
      @current_stage = 0
1✔
112
      # Current step
113
      @current_step = 0
1✔
114
      # list of stage-titles
115
      @titles = []
1✔
116

117
      # is progress bar used?
118
      @visible = true
1✔
119

120
      # superior progress (stages) bar
121
      @super_steps = 0
1✔
122
      @super_step = 0
1✔
123
      @super_stages = []
1✔
124

125
      # remember the last max. value of the subprogress bar
126
      @last_subprogress_max = 0
1✔
127

128
      @progress_running = 0
1✔
129

130
      # remember cumulated number of steps for nested progresses
131
      @progress_max = 0
1✔
132
      @progress_val = 0
1✔
133

134
      # stack with the running progresses
135
      # the top of the stack is the end of the list
136
      @progress_stack = []
1✔
137
    end
138

139
    def IsRunning
1✔
140
      # Check if any progress bar exists. If it does not, we're not running
141
      # (querying progress counter is not enough, a module ran previously
142
      # might have failed to reset the counter properly)
143
      @progress_running > 0 && UI.WidgetExists(:progress_replace_point)
8✔
144
    end
145

146
    # push the current progress into the stack
147
    def PushState
1✔
148
      current_subprogress = CurrentSubprogressType()
×
149
      state = {
150
        # global variable
151
        "stages"               => @stages,
×
152
        "steps"                => @steps,
153
        "current_step"         => @current_step,
154
        "current_stage"        => @current_stage,
155
        "titles"               => @titles,
156
        "last_subprogress_max" => @last_subprogress_max,
157
        "visible"              => @visible,
158
        # state of the widgets
159
        "subprogress_type"     => current_subprogress,
160
        "progress_label"       => Convert.to_string(
161
          UI.QueryWidget(Id(:pb), :Label)
162
        ),
163
        "progress_value"       => Convert.to_integer(
164
          UI.QueryWidget(Id(:pb), :Value)
165
        ),
166
        "progress_max"         => @progress_max,
167
        "progress_val"         => @progress_val
168
      }
169

170
      case current_subprogress
×
171
      when :progress
172
        Ops.set(
×
173
          state,
174
          "subprogress_label",
175
          Convert.to_string(UI.QueryWidget(Id(:subprogress_progress), :Label))
176
        )
177
        Ops.set(
×
178
          state,
179
          "subprogress_value",
180
          Convert.to_integer(UI.QueryWidget(Id(:subprogress_progress), :Value))
181
        )
182
      when :tick
183
        Ops.set(
×
184
          state,
185
          "subprogress_label",
186
          Convert.to_string(UI.QueryWidget(Id(:subprogress_tick), :Label))
187
        )
188
      end
189

190
      Builtins.y2milestone("Current state: %1", state)
×
191

192
      @progress_stack = Builtins.add(@progress_stack, state)
×
193

UNCOV
194
      nil
×
195
    end
196

197
    # pop the progress state from the stack and set it
198
    def PopState
1✔
199
      # pop the config
200
      state = Ops.get(
×
201
        @progress_stack,
202
        Ops.subtract(Builtins.size(@progress_stack), 1),
203
        {}
204
      )
205
      @progress_stack = Builtins.remove(
×
206
        @progress_stack,
207
        Ops.subtract(Builtins.size(@progress_stack), 1)
208
      )
209

210
      Builtins.y2milestone("setting up the previous state: %1", state)
×
211

212
      # refresh the variables
213
      @stages = Ops.get_integer(state, "stages", 0)
×
214
      @steps = Ops.get_integer(state, "steps", 0)
×
215
      @current_step = Ops.get_integer(state, "current_step", 0)
×
216
      @current_stage = Ops.get_integer(state, "current_stage", 0)
×
217
      @titles = Ops.get_list(state, "titles", [])
×
218
      @last_subprogress_max = Ops.get_integer(state, "last_subprogress_max", 0)
×
219
      @progress_max = Ops.get_integer(state, "progress_max", 0)
×
220
      @progress_val = Ops.get_integer(state, "progress_val", 0)
×
221

222
      pb_value = Ops.get_integer(state, "progress_value", 0)
×
223
      pb_value = Ops.add(pb_value.nil? ? 0 : pb_value, 1)
×
224

225
      # refresh the progress widget, add one step for the embedded progress
226
      try_replace_widget(
×
227
        Id(:progress_replace_point),
228
        ProgressBar(
229
          Id(:pb),
230
          Ops.get_string(state, "progress_label", ""),
231
          @steps,
232
          pb_value
233
        )
234
      )
235

236
      type = Ops.get_symbol(state, "subprogress_type", :none)
×
237
      SubprogressType(type, @last_subprogress_max)
×
238

239
      if [:progress, :tick].include?(type)
×
240
        SubprogressTitle(Ops.get_string(state, "subprogress_label", ""))
×
241
        SubprogressValue(Ops.get_integer(state, "subprogress_value", 0))
×
242
      end
243

UNCOV
244
      nil
×
245
    end
246

247
    # return size of the progress stack
248
    def StackSize
1✔
249
      Builtins.size(@progress_stack)
22✔
250
    end
251

252
    # return the value on the top of the stack
253
    # the stack is not changed
254
    def TopState
1✔
255
      Ops.get(
×
256
        @progress_stack,
257
        Ops.subtract(Builtins.size(@progress_stack), 1),
258
        {}
259
      )
260
    end
261

262
    # Sets progress bar state:
263
    # on = normal operation, off = All Progress:: calls return immediatelly.
264
    # @param [Boolean] state on or off
265
    # @return previous state
266
    def set(state)
1✔
267
      prev = @visible
×
268
      @visible = state
×
269
      prev
×
270
    end
271

272
    # Returns currently selected visibility status of all UI-modifying Progress:: functions.
273
    #
274
    # @return [Boolean] whether the progress bar is used
275
    # @see #Progress::set
276
    # @see #Progress::off
277
    # @see #Progress::on
278
    def status
1✔
279
      @visible
4✔
280
    end
281

282
    # Turns progress bar off. All Progress:: calls return immediatelly.
283
    # @deprecated set
284
    def off
1✔
285
      # no "deprecated" warning
286
      # because it is ok to use this function in testsuites
287
      @visible = false
×
288

UNCOV
289
      nil
×
290
    end
291

292
    # Turns progress bar on after calling Progress::off.
293
    # @deprecated set
294
    def on
1✔
295
      Builtins.y2warning(-1, "Deprecated function. Use Progress::set instead")
×
296
      @visible = true
×
297

UNCOV
298
      nil
×
299
    end
300

301
    # @param [Symbol] kind `todo, `current or `done
302
    # @return UI mark for stages
303
    def Mark(kind)
1✔
304
      return "-" if kind == :todo
22✔
305
      return UI.Glyph(:BulletArrowRight) if kind == :current
20✔
306
      return UI.Glyph(:CheckMark) if kind == :done
10✔
307

308
      "?@%!"
×
309
    end
310

311
    # @param [Fixnum] stage stage number
312
    # @return widget `id(...) for the marker
313
    def MarkId(stage)
1✔
314
      Id(Builtins.sformat("mark_stage_%1", stage))
30✔
315
    end
316

317
    # New complex progress bar with stages.
318
    # @param [String] window_title title of the window
319
    # @param [String] progress_title title of the progress bar. Pass at least " "
320
    #                       (one space) if you want some progress bar title.
321
    # @param [Fixnum] length number of steps. If 0, no progress bar is created,
322
    #               there are only stages and bottom title. THIS IS NOT
323
    #               NUMBER OF STAGES!
324
    # @param [Array<String>] stg list of strings - stage names. If it is nil, then there
325
    #            are no stages.
326
    # @param [Array] tits Titles corresponding to stages. When stage changes,
327
    #             progress bar title changes to one of these titles. May
328
    #             be nil/empty.
329
    # @param [String] help_text help text
330
    def New(window_title, progress_title, length, stg, tits, help_text)
1✔
331
      stg = deep_copy(stg)
2✔
332
      tits = deep_copy(tits)
2✔
333
      return if !@visible
2✔
334

335
      return if Mode.commandline
2✔
336

337
      # a progress is already running, remember the current status
338
      PushState() if IsRunning()
2✔
339

340
      Builtins.y2milestone(
2✔
341
        "Progress::New(%1, %2, %3)",
342
        window_title,
343
        length,
344
        stg
345
      )
346

347
      orig_current_step = @current_step
2✔
348

349
      @steps = length
2✔
350
      @stages = Builtins.size(stg)
2✔
351
      @titles = deep_copy(tits)
2✔
352
      @current_step = -1
2✔
353
      @current_stage = -1
2✔
354

355
      if Ops.less_than(length, Builtins.size(stg))
2✔
356
        Builtins.y2warning(
×
357
          "Number of stages (%1) is greater than number of steps (%2)",
358
          Builtins.size(stg),
359
          length
360
        )
361
      end
362

363
      if progress_title == ""
2✔
364
        # Reserve space for future progress bar labels. The ProgressBar
365
        # widget will suppress the label above the progress bar if the
366
        # initial label string is empty.
367
        progress_title = " "
2✔
368
      end
369

370
      # do not replace the UI, there is a progress already running
371
      if IsRunning()
2✔
372
        @progress_max = Ops.multiply(@progress_max, @steps)
×
373

374
        if StackSize() == 1
×
375
          @progress_val = Ops.multiply(orig_current_step, @steps)
×
376
        else
377
          prev_state = TopState()
×
378
          prev_progress_val = Ops.get_integer(prev_state, "progress_val", 0)
×
379

380
          @progress_val = Ops.multiply(prev_progress_val, @steps)
×
381
        end
382

383
        # set the maximum value of the progress bar
384
        try_replace_widget(
×
385
          Id(:progress_replace_point),
386
          ProgressBar(Id(:pb), progress_title, @progress_max, @progress_val)
387
        )
388
        Builtins.y2debug("New progress: %1/%2", @progress_val, @progress_max)
×
389

390
        @progress_running += 1
×
391
        return
×
392
      else
393
        @progress_max = @steps
2✔
394
      end
395

396
      bar = VBox(ProgressBar(Id(:pb), progress_title, length, 0)) # progressbar only
2✔
397
      if 0 != @stages
2✔
398
        bar = VBox(VSpacing(1))
2✔
399
        i = 0
2✔
400
        label_heading = Mark(:todo)
2✔
401

402
        items = VBox()
2✔
403
        Builtins.foreach(stg) do |item|
2✔
404
          items = Builtins.add(
10✔
405
            items,
406
            HBox(
407
              HSpacing(1),
408
              # check_ycp wants this text to be translatable. I do not know why.
409
              # HSquash + MinWidth(4) reserves a defined space for 'mark' plus 'emtpy space'
410
              # see bnc #395752
411
              HSquash(MinWidth(4, Heading(MarkId(i), label_heading))),
412
              Label(item),
413
              HStretch()
414
            )
415
          )
416
          i = Ops.add(i, 1)
10✔
417
        end
418
        bar = Builtins.add(bar, Left(HBox(HSquash(items))))
2✔
419

420
        bar = if 0 == @steps
2✔
421
          Builtins.add(
×
422
            bar,
423
            VBox(
424
              VStretch(),
425
              ReplacePoint(Id(:subprogress_replace_point), Empty()),
426
              ReplacePoint(
427
                Id(:progress_replace_point),
428
                Label(Id(:pb), Opt(:hstretch), progress_title)
429
              ),
430
              VSpacing(2)
431
            )
432
          )
433
        else
434
          Builtins.add(
2✔
435
            bar,
436
            VBox(
437
              VStretch(),
438
              ReplacePoint(Id(:subprogress_replace_point), Empty()),
439
              ReplacePoint(
440
                Id(:progress_replace_point),
441
                ProgressBar(Id(:pb), progress_title, length, 0)
442
              ),
443
              VSpacing(2)
444
            )
445
          )
446
        end
447
      end
448

449
      # patch from Michal Srb https://bugzilla.novell.com/show_bug.cgi?id=406890#c7
450
      try_replace_widget(Id(:contents), bar) unless Mode.test
2✔
451

452
      if !UI.WizardCommand(term(:SetDialogHeading, window_title))
2✔
453
        UI.ChangeWidget(Id(:title), :Value, window_title)
2✔
454
        UI.RecalcLayout
2✔
455
      end
456
      Wizard.SetHelpText(help_text) if "" != help_text && nil != help_text
2✔
457
      Wizard.DisableBackButton
2✔
458
      Wizard.DisableNextButton
2✔
459

460
      @progress_running += 1
2✔
461

462
      nil
2✔
463
    end
464

465
    # Get current subprogress type
466
    # @return [Symbol] Current type of the subprogress widget - can be `progress, `tick or `none
467
    def CurrentSubprogressType
1✔
468
      ret = :none
×
469

470
      return ret if !@visible || Mode.commandline
×
471

472
      # is there the subprogress progress widget?
473
      if UI.WidgetExists(:subprogress_progress) == true
×
474
        ret = :progress
×
475
      # or is there the tick subprogress widget?
476
      elsif UI.WidgetExists(:subprogress_tick) == true
×
477
        ret = :tick
×
478
      end
479

480
      ret
×
481
    end
482

483
    # Set value of the subprogress
484
    # @param [Fixnum] value Current value of the subprogress, if a tick subprogress is running the value is ignored and the next tick is displayed
485
    def SubprogressValue(value)
1✔
486
      return if !@visible || Mode.commandline
×
487

488
      current_type = CurrentSubprogressType()
×
489

490
      # normal progress
491
      case current_type
×
492
      when :progress
493
        UI.ChangeWidget(Id(:subprogress_progress), :Value, value)
×
494
      # tick progress
495
      when :tick
496
        UI.ChangeWidget(Id(:subprogress_tick), :Alive, true)
×
497
      else
498
        Builtins.y2warning("No subprogress is defined, cannot set the value!")
×
499
      end
500

UNCOV
501
      nil
×
502
    end
503

504
    # Create (or remove) a new subprogress above the progress bar, can be use for detailed progress of the current task
505
    # @param [Symbol] type type of the subprogress widget, can be `progress (standard progress),
506
    # `tick (tick progress) or `none (no subprogress, intended for removing the progress bar from the dialog)
507
    # @param [Fixnum] max_value maximum value for `progress type, for the other types it is not relevant (use any integer value or nil)
508
    def SubprogressType(type, max_value)
1✔
509
      return if !@visible || Mode.commandline
×
510

511
      Builtins.y2debug(
×
512
        "SubprogressType: type: %1, max_value: %2",
513
        type,
514
        max_value
515
      )
516

517
      if type == CurrentSubprogressType()
×
518
        case type
×
519
        when :progress
520
          # just reset the current value of the progress bar if the requested progress is the same
521
          if max_value == @last_subprogress_max
×
522
            Builtins.y2milestone("Resetting the subprogressbar...")
×
523
            SubprogressValue(0)
×
524
            return
×
525
          end
526
        when :tick
527
          # just restart the animation
528
          UI.ChangeWidget(Id(:subprogress_tick), :Alive, true)
×
529
        else
530
          Builtins.y2milestone("Subprogress initialization skipped")
×
531
          return
×
532
        end
533
      end
534

535
      widget = Empty()
×
536

537
      case type
×
538
      when :progress
539
        widget = ProgressBar(Id(:subprogress_progress), " ", max_value, 0)
×
540
      when :tick
541
        widget = BusyIndicator(Id(:subprogress_tick), " ", 3000)
×
542
      when :none
543
        widget = Empty()
×
544
      else
545
        Builtins.y2error("Unknown subprogress type: %1", type)
×
546
      end
547

548
      Builtins.y2debug("widget: %1", widget)
×
549
      try_replace_widget(Id(:subprogress_replace_point), widget)
×
550

551
      # remember the max. value
552
      @last_subprogress_max = max_value
×
553

UNCOV
554
      nil
×
555
    end
556

557
    # Set the label of the subprogress
558
    # @param [String] title New label for the subprogress
559
    def SubprogressTitle(title)
1✔
560
      return if !@visible || Mode.commandline
×
561

562
      current_type = CurrentSubprogressType()
×
563

564
      case current_type
×
565
      when :progress
566
        UI.ChangeWidget(Id(:subprogress_progress), :Label, title)
×
567
      when :tick
568
        UI.ChangeWidget(Id(:subprogress_tick), :Label, title)
×
569
      else
570
        Builtins.y2warning("No subprogress is defined, cannot set the label!")
×
571
      end
572

UNCOV
573
      nil
×
574
    end
575

576
    # @deprecated Use {#New} instead.
577
    # Obsolete function adding icon-support to progress dialog.
578
    # We don't use icons in popups any more.
579
    # @param [String] window_title
580
    # @param [String] progress_title
581
    # @param [Fixnum] length
582
    # @param [Array<String>] stg
583
    # @param [Array] tits
584
    # @param [String] help_textmap
585
    # @param [Array<Array<String>>] icons_definition
586
    # @see Function Progress::New()
587
    def NewProgressIcons(window_title, progress_title, length, stg, tits, help_textmap, _icons_definition)
1✔
588
      Builtins.y2warning(-1, "#{__method__} is deprecated. Use Progress::New instead!")
×
589
      New(window_title, progress_title, length, stg, tits, help_textmap)
×
590
    end
591

592
    # Create simple progress bar with no stages, only with progress bar.
593
    # @param [String] window_title Title of the window.
594
    # @param [String] progress_title Title of the progress bar.
595
    # @param [Fixnum] length Number of steps.
596
    # @param [String] help_text Help text.
597
    def Simple(window_title, progress_title, length, help_text)
1✔
598
      New(window_title, progress_title, length, [], [], help_text)
×
599

UNCOV
600
      nil
×
601
    end
602

603
    # Uses current_step
604
    def UpdateProgressBar
1✔
605
      if Ops.greater_than(@current_step, @steps)
8✔
606
        Builtins.y2error(
×
607
          -2,
608
          "Progress bar has only %1 steps, not %2.",
609
          @steps,
610
          @current_step
611
        )
612
        return
×
613
      end
614

615
      progress_value = @current_step
8✔
616

617
      if StackSize() != 0
8✔
618
        # recalculate the progress bar value according to the parent progress
619
        prev_state = TopState()
×
620
        prev_step = Ops.get_integer(prev_state, "current_step", 0)
×
621

622
        progress_value = Ops.add(
×
623
          Ops.multiply(prev_step, @steps),
624
          Ops.greater_than(@current_step, 0) ? @current_step : 0
×
625
        )
626
      end
627

628
      Builtins.y2debug(
8✔
629
        "New progress value: %1, current_step: %2/%3 (%4%%)",
630
        progress_value,
631
        @current_step,
632
        @steps,
633
        Ops.divide(
634
          Ops.multiply(
635
            100.0,
636
            Convert.convert(progress_value, from: "integer", to: "float")
637
          ),
638
          Convert.convert(@progress_max, from: "integer", to: "float")
639
        )
640
      )
641

642
      UI.ChangeWidget(Id(:pb), :Value, progress_value)
8✔
643

644
      nil
8✔
645
    end
646

647
    # the bar is either `ProgressBar or `Label
648
    # @param [String] title
649
    def SetProgressBarTitle(title)
1✔
650
      UI.ChangeWidget(Id(:pb), (0 == @steps) ? :Value : :Label, title)
4✔
651

652
      nil
4✔
653
    end
654

655
    # Some people say it is the best operating system ever. But now to the
656
    # function. Advances progress bar value by 1.
657
    def NextStep
1✔
658
      return if !@visible || Mode.commandline || 0 == @steps
2✔
659

660
      @current_step = Ops.add(@current_step, 1)
2✔
661
      UpdateProgressBar()
2✔
662

663
      nil
2✔
664
    end
665

666
    # Advance stage, advance step by 1 and set progress bar caption to
667
    # that defined in New.
668
    def NextStage
1✔
669
      return if !@visible
2✔
670

671
      NextStep()
2✔
672

673
      if 0 == @stages || Ops.greater_than(@current_stage, @stages)
2✔
674
        Builtins.y2error("Non-existing stage requested.")
×
675
        return
×
676
      end
677

678
      @current_stage = Ops.add(@current_stage, 1)
2✔
679

680
      # do not update the UI in a nested progress
681
      return if Ops.greater_than(StackSize(), 0)
2✔
682

683
      if Mode.commandline
2✔
684
        if Ops.less_than(@current_stage, @stages) &&
×
685
            Ops.less_than(@current_stage, Builtins.size(@titles))
686
          CommandLine.PrintVerbose(Ops.get_string(@titles, @current_stage, ""))
×
687
        end
688
        return
×
689
      end
690

691
      if Ops.greater_than(@current_stage, 0)
2✔
692
        UI.ChangeWidget(
2✔
693
          MarkId(Ops.subtract(@current_stage, 1)),
694
          :Value,
695
          Mark(:done)
696
        )
697
      end
698
      # we may be past the last stage
699
      if Ops.less_than(@current_stage, @stages)
2✔
700
        SetProgressBarTitle(Ops.get_string(@titles, @current_stage, "")) if Ops.less_than(@current_stage, Builtins.size(@titles))
×
701
        UI.ChangeWidget(MarkId(@current_stage), :Value, Mark(:current))
×
702
      end
703

704
      nil
2✔
705
    end
706

707
    # Changes progress bar value to st.
708
    # @param [Fixnum] stet new value
709
    def Step(step)
1✔
710
      return if !@visible || Mode.commandline || 0 == @steps
4✔
711

712
      return if Ops.less_than(step, 0) || Ops.greater_than(step, @steps)
4✔
713

714
      @current_step = step
4✔
715

716
      UpdateProgressBar()
4✔
717

718
      nil
4✔
719
    end
720

721
    # Go to stage st, change progress bar title to title and set progress
722
    # bar step to step.
723
    # @param [Fixnum] stage New stage.
724
    # @param [String] title New title for progress bar. If nil, title specified in
725
    #              New is used.
726
    # @param [Fixnum] step New step or -1 if step should not change.
727
    def Stage(stage, title, step)
1✔
728
      return if !@visible
10✔
729

730
      Step(step) if -1 != step
10✔
731

732
      # another progress is running
733
      # do not change the current stage, calculate the target step
734
      if Ops.greater_than(StackSize(), 0)
10✔
735
        UpdateProgressBar()
×
736
        return
×
737
      end
738

739
      if !Mode.commandline && Ops.greater_or_equal(@current_stage, 0)
10✔
740
        UI.ChangeWidget(
8✔
741
          MarkId(@current_stage),
742
          :Value,
743
          Mark(Ops.greater_than(stage, @current_stage) ? :done : :todo)
8✔
744
        )
745
      end
746

747
      @current_stage = stage
10✔
748
      s = ""
10✔
749
      s = Ops.get_string(@titles, @current_stage, "") if Ops.less_than(@current_stage, Builtins.size(@titles))
10✔
750
      s = title if nil != title
10✔
751
      if Ops.less_than(@current_stage, Builtins.size(@titles))
10✔
752
        if Mode.commandline
×
753
          CommandLine.PrintVerbose(s)
×
754
          return
×
755
        else
756
          SetProgressBarTitle(s)
×
757
        end
758
      end
759
      UI.ChangeWidget(MarkId(@current_stage), :Value, Mark(:current)) if Ops.less_than(@current_stage, @stages)
10✔
760

761
      nil
10✔
762
    end
763

764
    # Jumps to the next stage and sets step to st.
765
    # @param [Fixnum] step new progress bar value
766
    def NextStageStep(step)
1✔
767
      return if !@visible || Mode.commandline
×
768

769
      NextStage()
×
770
      Step(step)
×
771

UNCOV
772
      nil
×
773
    end
774

775
    # Change progress bar title.
776
    # @param [String] title. Use ""(empty string) if you want an empty progress bar.
777
    def Title(title)
1✔
778
      SetProgressBarTitle(title) if @visible && !Mode.commandline
2✔
779

780
      nil
2✔
781
    end
782

783
    # Moves progress bar to the end and marks all stages as completed.
784
    def Finish
1✔
785
      return if !@visible || Mode.commandline
2✔
786

787
      # decrease the reference counter
788
      @progress_running -= 1
2✔
789

790
      # set the previous state
791
      if Ops.greater_than(StackSize(), 0)
2✔
792
        PopState()
×
793
        return
×
794
      end
795

796
      if 0 != @stages
2✔
797
        # unwind remaining stages
798
        NextStage() while Ops.less_than(@current_stage, @stages)
2✔
799
      end
800
      if 0 != @steps
2✔
801
        @current_step = @steps
2✔
802
        UpdateProgressBar()
2✔
803
      end
804

805
      SetProgressBarTitle(" ")
2✔
806

807
      nil
2✔
808
    end
809

810
    # Creates a higher-level progress bar made of stages. Currently it is
811
    # placed instead of help text.
812
    # @param [String] title title of the progress...
813
    # @param [Array<String>] stages list of stage descriptions
814
    def OpenSuperior(title, stages)
1✔
815
      stages = deep_copy(stages)
×
816
      if UI.HasSpecialWidget(:Wizard)
×
817
        Wizard.OpenAcceptAbortStepsDialog
×
818
        UI.WizardCommand(term(:AddStepHeading, title))
×
819

820
        idx = 0
×
821
        @super_steps = Builtins.size(stages)
×
822
        @super_step = -1
×
823
        Builtins.foreach(stages) do |s|
×
824
          id = Builtins.sformat("super_progress_%1", idx)
×
825
          UI.WizardCommand(term(:AddStep, s, id))
×
826
        end
827
        UI.WizardCommand(term(:UpdateSteps)) # old behaviour
×
828
      else
829
        left = VBox(VStretch())
×
830
        right = VBox(VStretch())
×
831
        idx = 0
×
832
        @super_steps = Builtins.size(stages)
×
833
        @super_step = -1
×
834
        Builtins.foreach(stages) do |i|
×
835
          id = Builtins.sformat("super_progress_%1", idx)
×
836
          left = Builtins.add(left, Heading(Id(id), "-  "))
×
837
          right = Builtins.add(right, Label(Opt(:hstretch), i))
×
838
          left = Builtins.add(left, VStretch())
×
839
          right = Builtins.add(right, VStretch())
×
840
          idx = Ops.add(idx, 1)
×
841
        end
842
        left = Builtins.add(left, HSpacing(4))
×
843
        right = Builtins.add(right, HStretch())
×
844
        Wizard.ReplaceHelp(
×
845
          VBox(
846
            HBox(HSpacing(1), Frame(title, HBox(HSpacing(1), left, right))),
847
            VSpacing(0.5)
848
          )
849
        )
850
      end
851

UNCOV
852
      nil
×
853
    end
854

855
    # Replaces stages of superior progress by an empty help text.
856
    def CloseSuperior
1✔
857
      if UI.HasSpecialWidget(:Wizard)
×
858
        UI.CloseDialog
×
859
      else
860
        Wizard.RestoreHelp("")
×
861
      end
862
      @super_steps = 0
×
863
      @super_step = 0
×
864

UNCOV
865
      nil
×
866
    end
867

868
    # Make one step in a superior progress bar.
869
    def StepSuperior
1✔
870
      if Ops.greater_or_equal(@super_step, 0) &&
×
871
          Ops.less_than(@super_step, @super_steps) && !UI.HasSpecialWidget(:Wizard)
872
        UI.ChangeWidget(
×
873
          Id(Builtins.sformat("super_progress_%1", @super_step)),
874
          :Value,
875
          UI.Glyph(:CheckMark)
876
        )
877
      end
878
      @super_step = Ops.add(@super_step, 1)
×
879
      return if Ops.greater_or_equal(@super_step, @super_steps)
×
880

881
      if UI.HasSpecialWidget(:Wizard)
×
882
        UI.WizardCommand(
×
883
          term(
884
            :SetCurrentStep,
885
            Builtins.sformat("super_progress_%1", @super_step)
886
          )
887
        )
888
      else
889
        UI.ChangeWidget(
×
890
          Id(Builtins.sformat("super_progress_%1", @super_step)),
891
          :Value,
892
          UI.Glyph(:BulletArrowRight)
893
        )
894
      end
895

UNCOV
896
      nil
×
897
    end
898

899
    # Try replacing a ReplacePoint widget's content with new content, but only
900
    # if the ReplacePoint actually exists: It might be hidden by another dialog
901
    # that was opened on top of the current one (bsc#1187676).
902
    def try_replace_widget(widget_id, new_content)
1✔
903
      if UI.WidgetExists(widget_id)
2✔
904
        UI.ReplaceWidget(widget_id, new_content)
×
905
      else
906
        log.warn("No widget with ID #{widget_id} in the current dialog")
2✔
907
        UI.DumpWidgetTree
2✔
908
      end
909
    end
910

911
    publish function: :IsRunning, type: "boolean ()"
1✔
912
    publish function: :CurrentSubprogressType, type: "symbol ()"
1✔
913
    publish function: :SubprogressTitle, type: "void (string)"
1✔
914
    publish function: :SubprogressValue, type: "void (integer)"
1✔
915
    publish function: :SubprogressType, type: "void (symbol, integer)"
1✔
916
    publish function: :set, type: "boolean (boolean)"
1✔
917
    publish function: :status, type: "boolean ()"
1✔
918
    publish function: :off, type: "void ()"
1✔
919
    publish function: :on, type: "void ()"
1✔
920
    publish function: :New, type: "void (string, string, integer, list <string>, list, string)"
1✔
921
    publish function: :NewProgressIcons, type: "void (string, string, integer, list <string>, list, string, list <list <string>>)"
1✔
922
    publish function: :Simple, type: "void (string, string, integer, string)"
1✔
923
    publish function: :NextStep, type: "void ()"
1✔
924
    publish function: :NextStage, type: "void ()"
1✔
925
    publish function: :Step, type: "void (integer)"
1✔
926
    publish function: :Stage, type: "void (integer, string, integer)"
1✔
927
    publish function: :NextStageStep, type: "void (integer)"
1✔
928
    publish function: :Title, type: "void (string)"
1✔
929
    publish function: :Finish, type: "void ()"
1✔
930
    publish function: :OpenSuperior, type: "void (string, list <string>)"
1✔
931
    publish function: :CloseSuperior, type: "void ()"
1✔
932
    publish function: :StepSuperior, type: "void ()"
1✔
933
  end
934

935
  Progress = ProgressClass.new
1✔
936
  Progress.main
1✔
937
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc