Class: Yast::DelayedProgressPopup

Inherits:
Object
  • Object
show all
Includes:
Logger, UIShortcuts
Defined in:
library/general/src/lib/ui/delayed_progress_popup.rb

Overview

Progress popup dialog that only opens after a certain delay, so it never opens for very short operations (< 4 seconds by default), only when an operation takes long enough to actually give feedback to the user.

This is less disruptive than a progress dialog that always opens, and in most cases, flashes by so fast that the user can't recognize what it says.

The tradeoff is that it takes a few seconds until there is any visual feedback (until the delay is expired).

Notice that this does not use an active timer; the calling application has to trigger the check for the timeout by calling progress() in regular intervals.

You can change the delay by changing the delay_seconds member variable, you can force the dialog to open with open!, and you can stop and (re-) start the timer.

In any case, when done with this progress reporting, call close(). You don't need to check if it ever opened; close() does that automatically.

see examples/delayed_progress_1.rb for a usage example.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(delay: nil, auto_start: true, heading: nil) ⇒ DelayedProgressPopup

Constructor.

If auto_start is true (default), this also starts the timer with a default (4 seconds) timeout.

The close method must be explicitly called at the end when the progress is finished.

Parameters:

  • delay (Integer, nil) (defaults to: nil)

    optional delay in seconds

  • auto_start (Boolean) (defaults to: true)

    start the timer immediately

  • heading (String, nil) (defaults to: nil)

    optional popup heading



70
71
72
73
74
75
76
77
78
79
80
81
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 70

def initialize(delay: nil, auto_start: true, heading: nil)
  Yast.import "UI"
  Yast.import "Label"

  @delay_seconds = delay || 4
  @heading = heading
  @use_cancel_button = true
  @almost_done_percent = 80
  @is_open = false
  start_timer if auto_start
  log.info "Created delayed progress popup"
end

Instance Attribute Details

#almost_done_percentInteger

so the dialog is not opened anymore if it isn't already. Default: 80 Set this to 100 to disable that.

Returns:

  • (Integer)

    Percent (0..100) that are considered "almost done"



54
55
56
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 54

def almost_done_percent
  @almost_done_percent
end

#delay_secondsInteger

Returns Delay (timeout) in seconds.

Returns:

  • (Integer)

    Delay (timeout) in seconds.



49
50
51
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 49

def delay_seconds
  @delay_seconds
end

#headingString

Returns Text for the dialog heading. Default: nil.

Returns:

  • (String)

    Text for the dialog heading. Default: nil.



46
47
48
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 46

def heading
  @heading
end

#use_cancel_buttonBoolean

Returns Add a "Cancel" button to the dialog. Default: true.

Returns:

  • (Boolean)

    Add a "Cancel" button to the dialog. Default: true.



57
58
59
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 57

def use_cancel_button
  @use_cancel_button
end

Class Method Details

.run(delay: nil, auto_start: true, heading: nil, &block) ⇒ Object

A static variant with block, it automatically closes the popup at the end.

Examples:

Yast::DelayedProgressPopup.run(delay: 5, heading: "Working...") do |popup|
  10.times do |sec|
    popup.progress(10 * sec, "Working #{sec}")
    sleep(1)
  end
end

Parameters:

  • delay (Integer, nil) (defaults to: nil)

    optional delay in seconds

  • heading (String, nil) (defaults to: nil)

    optional popup heading



94
95
96
97
98
99
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 94

def self.run(delay: nil, auto_start: true, heading: nil, &block)
  popup = new(delay: delay, auto_start: auto_start, heading: heading)
  block.call(popup)
ensure
  popup&.close
end

Instance Method Details

#closeObject

Close the dialog if it is open. Only stop the timer if it is not (because the timer didn't expire).

Do not call this if another dialog was opened on top of this one in the meantime: Just like a normal UI.CloseDialog call, this closes the topmost dialog; which in that case might not be the right one.



146
147
148
149
150
151
152
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 146

def close
  stop_timer
  return unless open?

  UI.CloseDialog
  @is_open = false
end

#dialog_buttonsObject (protected)

Return a widget term for the dialog buttons. Reimplement this in inherited classes for different buttons.

Notice that the buttons only do anything if the calling application handles them, e.g. with UI.PollInput().

Don't forget that in the Qt UI, every window has a WM_CLOSE button (the [x] icon in the window title bar that is meant for closing the window) that returns :cancel in UI.UserInput() / UI.PollInput().



226
227
228
229
230
231
232
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 226

def dialog_buttons
  return Empty() unless @use_cancel_button

  ButtonBox(
    PushButton(Id(:cancel), Opt(:cancelButton), Yast::Label.CancelButton)
  )
end

#dialog_headingObject (protected)

Return a widget term for the dialog heading.



210
211
212
213
214
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 210

def dialog_heading
  return Empty() if @heading.nil?

  Left(Heading(@heading))
end

#dialog_widgetsObject (protected)

Return a widget term for the dialog widgets. Reimplement this in inherited classes for a different dialog content.



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 187

def dialog_widgets
  placeholder_label = " " # at least one blank
  heading_spacing = @heading.nil? ? 0 : 0.4
  MinWidth(
    40,
    VBox(
      MarginBox(
        1, 0.4,
        VBox(
          dialog_heading,
          VSpacing(heading_spacing),
          VCenter(
            ProgressBar(Id(:progress_bar), placeholder_label, 100, 0)
          )
        )
      ),
      VSpacing(0.4),
      dialog_buttons
    )
  )
end

#open!Object

Open the dialog unconditionally.



132
133
134
135
136
137
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 132

def open!
  log.info "Opening the delayed progress popup"
  UI.OpenDialog(dialog_widgets)
  @is_open = true
  stop_timer
end

#open?Boolean

Check if the dialog is open.

Returns:

  • (Boolean)


165
166
167
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 165

def open?
  @is_open
end

#open_if_neededObject

Open the dialog if needed, i.e. if it's not already open and if the timer expired.

Notice that progress() does this automatically.



125
126
127
128
129
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 125

def open_if_needed
  return if open?

  open! if timer_expired?
end

#progress(progress_percent, progress_text = nil) ⇒ Object

Update the progress.

If the dialog is not open yet, this opens it if the timeout is expired; unless the whole process is almost done anyway, i.e. at the time when the dialog would be opened, progress_percent is already at the almost immediately again.

Parameters:

  • progress_percent (Integer)

    numeric progress bar value

  • progress_text (nil|String) (defaults to: nil)

    optional progress bar label text



112
113
114
115
116
117
118
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 112

def progress(progress_percent, progress_text = nil)
  log.info "progress_percent: #{progress_percent}"
  open_if_needed unless progress_percent >= @almost_done_percent
  return unless open?

  update_progress(progress_percent, progress_text)
end

#start_timerObject

Start or restart the timer.



155
156
157
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 155

def start_timer
  @start_time = Yast2::SystemTime.uptime
end

#stop_timerObject

Stop the timer.



160
161
162
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 160

def stop_timer
  @start_time = nil
end

#timer_expired?Boolean

Check if the timer expired.

Returns:

  • (Boolean)


170
171
172
173
174
175
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 170

def timer_expired?
  return false unless timer_running?

  now = Yast2::SystemTime.uptime
  now > @start_time + delay_seconds
end

#timer_running?Boolean

Check if the timer is running.

Returns:

  • (Boolean)


178
179
180
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 178

def timer_running?
  !@start_time.nil?
end

#update_progress(progress_percent, progress_text = nil) ⇒ Object (protected)

Update the progress bar.



235
236
237
238
239
240
# File 'library/general/src/lib/ui/delayed_progress_popup.rb', line 235

def update_progress(progress_percent, progress_text = nil)
  return unless UI.WidgetExists(:progress_bar)

  UI.ChangeWidget(Id(:progress_bar), :Value, progress_percent)
  UI.ChangeWidget(Id(:progress_bar), :Label, progress_text) unless progress_text.nil?
end