Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a class to ask questions with custom behavior
- Loading branch information
Showing
5 changed files
with
319 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
# encoding: utf-8 | ||
|
||
# Copyright (c) [2017] SUSE LLC | ||
# | ||
# All Rights Reserved. | ||
# | ||
# This program is free software; you can redistribute it and/or modify it | ||
# under the terms of version 2 of the GNU General Public License as published | ||
# by the Free Software Foundation. | ||
# | ||
# This program is distributed in the hope that it will be useful, but WITHOUT | ||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
# more details. | ||
# | ||
# You should have received a copy of the GNU General Public License along | ||
# with this program; if not, contact SUSE LLC. | ||
# | ||
# To contact SUSE LLC about this file by physical or electronic mail, you may | ||
# find current contact information at www.suse.com. | ||
|
||
require "ui/dialog" | ||
|
||
Yast.import "HTML" | ||
Yast.import "Label" | ||
Yast.import "UI" | ||
|
||
module Y2Autoinstallation | ||
module Dialogs | ||
# Generic dialog for AutoYaST questions supporting RichText. | ||
# | ||
# It can behave in two different ways: | ||
# | ||
# * Ask the user if she/he wants to continue or abort the installation. | ||
# * Display a message and only offer an 'Abort' button. | ||
# | ||
# In order to integrate nicely with AutoYaST, a timeout can be set. | ||
# Bear in mind that the timeout will not be respected when a showing only | ||
# the 'Abort' button. | ||
# | ||
# This dialog could be extended in the future in order to support other | ||
# AutoYaST interaction which are not covered in the {Yast::Report} module. | ||
class Question < UI::Dialog | ||
|
||
# @return [String] Dialog's content | ||
attr_reader :content | ||
|
||
# Constructor | ||
# | ||
# @param content [String] Dialog's content | ||
# @param timeout [Integer] Countdown (in seconds); 0 means no timeout. | ||
# @param buttons_set [Symbol] Buttons set (:abort, :question) | ||
def initialize(content, timeout: 10, buttons_set: :question) | ||
@content = content | ||
@remaining_time = timeout | ||
@timed = timeout > 0 | ||
@buttons_set = buttons_set | ||
end | ||
|
||
# Return YaST terms for dialog's content | ||
# | ||
# @return [Yast::Term] Dialog's content | ||
# @see UI::Dialog#dialog_content | ||
def dialog_content | ||
HBox( | ||
VSpacing(20), | ||
VBox( | ||
HSpacing(70), | ||
Left(Heading("Partitioning issues")), | ||
VSpacing(1), | ||
RichText(content), | ||
timed? ? ReplacePoint(Id(:counter_replace), counter) : Empty(), | ||
ButtonBox(*buttons) | ||
) | ||
) | ||
end | ||
|
||
# 'Continue' button handler | ||
# | ||
# When the 'Continue' button is pressed, the dialog will return the {:ok} value. | ||
def ok_handler | ||
finish_dialog(:ok) | ||
end | ||
|
||
# 'Abort' button handler | ||
# | ||
# When the 'Abort' button is pressed, the dialog will return the {:abort} value. | ||
def abort_handler | ||
finish_dialog(:abort) | ||
end | ||
|
||
# 'Stop' button handler | ||
# | ||
# When the 'Stop' button is pressed, the countdown will stop. | ||
def stop_handler | ||
@remaining_time = nil | ||
Yast::UI.ChangeWidget(Id(:stop), :Enabled, false) | ||
end | ||
|
||
def timeout_handler | ||
return finish_dialog(:ok) if @remaining_time.zero? | ||
@remaining_time -= 1 | ||
Yast::UI.ReplaceWidget(Id(:counter_replace), counter) | ||
end | ||
|
||
private | ||
# @return [Integer] Timeout | ||
attr_reader :timeout | ||
|
||
# @return [Symbol] Buttons set (:abort, :question) | ||
attr_reader :buttons_set | ||
|
||
# Determine whether it is a timed dialog or not | ||
# | ||
# @return [Boolean] True if the timeout is running; false otherwise | ||
def timed? | ||
@timed | ||
end | ||
|
||
# Return dialog buttons | ||
# | ||
# @see question_buttons | ||
# @see abort_buttons | ||
def buttons | ||
send("#{buttons_set}_buttons") | ||
end | ||
|
||
# Return buttons to show when the user should be asked about what to do | ||
# | ||
# @return [Array<Yast::Term>] | ||
def question_buttons | ||
set = [ | ||
PushButton(Id(:ok), Opt(:okButton, :key_F9, :default), Yast::Label.ContinueButton), | ||
abort_button | ||
] | ||
|
||
if timed? | ||
set.unshift( | ||
PushButton(Id(:stop), Opt(:customButton), Yast::Label.StopButton), | ||
) | ||
end | ||
|
||
set | ||
end | ||
|
||
# Return buttons to show when abort is the only option | ||
# | ||
# @return [Array<Yast::Term>] | ||
def abort_buttons | ||
[abort_button] | ||
end | ||
|
||
# Return an 'Abort' button | ||
# | ||
# @return Yast::Term | ||
def abort_button | ||
PushButton(Id(:abort), Opt(:cancel_button, :key_F10), Yast::Label.AbortButton) | ||
end | ||
|
||
# Timeout counter | ||
# | ||
# @return [Yast::Term] | ||
def counter | ||
Label(Id(:counter), @remaining_time.to_s) | ||
end | ||
|
||
# Handle user input | ||
# | ||
# @return [Symbol] User input (:ok, :stop, :abort or :timeout) | ||
def user_input | ||
if timed? && @remaining_time | ||
Yast::UI.TimeoutUserInput(1000) | ||
else | ||
Yast::UI.UserInput | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
#!/usr/bin/env rspec | ||
# encoding: utf-8 | ||
|
||
# Copyright (c) [2017] SUSE LLC | ||
# | ||
# All Rights Reserved. | ||
# | ||
# This program is free software; you can redistribute it and/or modify it | ||
# under the terms of version 2 of the GNU General Public License as published | ||
# by the Free Software Foundation. | ||
# | ||
# This program is distributed in the hope that it will be useful, but WITHOUT | ||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
# more details. | ||
# | ||
# You should have received a copy of the GNU General Public License along | ||
# with this program; if not, contact SUSE LLC. | ||
# | ||
# To contact SUSE LLC about this file by physical or electronic mail, you may | ||
# find current contact information at www.suse.com. | ||
|
||
require_relative "../../test_helper" | ||
require "autoinstall/dialogs/question" | ||
require "y2storage/autoinst_issues" | ||
|
||
describe Y2Autoinstallation::Dialogs::Question do | ||
subject(:dialog) { described_class.new(content, timeout: timeout, buttons_set: buttons_set) } | ||
|
||
let(:timeout) { 0 } | ||
let(:content) { "some content" } | ||
let(:buttons_set) { :abort } | ||
|
||
before do | ||
allow(Yast::UI).to receive(:OpenDialog).and_return(true) | ||
allow(Yast::UI).to receive(:CloseDialog).and_return(true) | ||
end | ||
|
||
describe "#dialog_content" do | ||
it "displays the given content" do | ||
expect(dialog.dialog_content.to_s).to include(content) | ||
end | ||
|
||
context "when buttons_set is set to :abort" do | ||
let(:buttons_set) { :abort } | ||
|
||
it "only shows the 'Abort' button" do | ||
expect(dialog).to receive(:PushButton).with(Yast::Term.new(:id, :abort), anything, anything) | ||
dialog.dialog_content | ||
end | ||
|
||
context "and a timeout was given" do | ||
it "ignores the timeout" do | ||
expect(dialog).to receive(:PushButton).with(Yast::Term.new(:id, :abort), anything, anything) | ||
expect(dialog).to_not receive(:Id).with(:counter) | ||
allow(dialog).to receive(:Id).and_call_original | ||
dialog.dialog_content | ||
end | ||
end | ||
end | ||
|
||
context "when buttons_set is set to :question" do | ||
let(:buttons_set) { :question } | ||
|
||
it "shows the 'Continue' and 'Abort' buttons" do | ||
expect(dialog).to receive(:PushButton).with(Yast::Term.new(:id, :abort), anything, anything) | ||
expect(dialog).to receive(:PushButton).with(Yast::Term.new(:id, :ok), anything, anything) | ||
dialog.dialog_content | ||
end | ||
|
||
context "and a timeout was given" do | ||
let(:timeout) { 10 } | ||
|
||
it "shows the 'Stop' button" do | ||
expect(dialog).to receive(:PushButton).with(Yast::Term.new(:id, :stop), anything, anything) | ||
allow(dialog).to receive(:PushButton).and_call_original | ||
dialog.dialog_content | ||
end | ||
end | ||
end | ||
end | ||
|
||
describe "#run" do | ||
let(:timeout) { 10 } | ||
|
||
context "when no timeout was given" do | ||
let(:timeout) { 0 } | ||
|
||
it "does not use a timeout when asking for user input" do | ||
expect(Yast::UI).to receive(:UserInput).and_return(:ok) | ||
dialog.run | ||
end | ||
end | ||
|
||
context "when user pushes 'Abort'" do | ||
let(:input) { :abort } | ||
|
||
it "returns :abort" do | ||
allow(Yast::UI).to receive(:TimeoutUserInput).and_return(:abort) | ||
expect(dialog.run).to eq(:abort) | ||
end | ||
end | ||
|
||
context "when user pushes 'Continue'" do | ||
it "returns :ok" do | ||
allow(Yast::UI).to receive(:TimeoutUserInput).and_return(:ok) | ||
expect(dialog.run).to eq(:ok) | ||
end | ||
end | ||
|
||
context "when user pushes 'Stop'" do | ||
it "stops the countdown" do | ||
allow(Yast::UI).to receive(:TimeoutUserInput).and_return(:stop) | ||
allow(Yast::UI).to receive(:UserInput).and_return(:ok) | ||
expect(Yast::UI).to receive(:ChangeWidget) | ||
.with(Id(:stop), :Enabled, false) | ||
dialog.run | ||
end | ||
end | ||
|
||
context "when user input times-out" do | ||
let(:timeout) { 1 } | ||
|
||
it "returns :ok" do | ||
allow(Yast::UI).to receive(:TimeoutUserInput).and_return(:timeout) | ||
expect(dialog.run).to eq(:ok) | ||
end | ||
end | ||
end | ||
end |