ACC SHELL
/**
* File:
* include/restore/ui.ycp
*
* Package:
* Restore module
*
* Summary:
* User interface functions.
*
* Authors:
* Ladislav Slezak <lslezak@suse.cz>
*
* $Id: ui.ycp 60090 2009-12-14 10:16:38Z locilka $
*
* All user interface functions.
*
*/
{
textdomain "restore";
import "Wizard";
import "Wizard_hw";
import "Progress";
import "Restore";
import "Mode";
import "URL";
import "Popup";
import "Report";
import "Label";
import "Package";
import "PackageSystem";
import "Sequencer";
include "restore/helps.ycp";
include "restore/summary_dialog.ycp";
import "Label";
import "NetworkPopup";
string restorepackagename = nil;
list archivecontentscache = nil;
list<string> restoredfiles = [];
list<string> failedfiles = [];
integer restoredpackages = 0;
boolean bloaderstatus = nil;
boolean susestatus = nil;
map<string, any> packagestoinstall = $[];
map<string, any> packagestouninstall = $[];
// mounted directory
string mountdir = "";
// map with detected removable devices
map<string,map> removabledevices = nil;
// last user input, used for dialog skipping
symbol lastret = nil;
/**
* Try to detect all removable devices present in the system
* @return map Removable devices info
*/
define map<string, map> DetectRemovable() ``{
map<string, map> ret = $[];
// detect floppy devices
list<map> devices = (Mode::test () == false) ? (list<map>) SCR::Read(.probe.floppy) : [$["bus":"Floppy", "class_id":262, "dev_name":"/dev/fd0", "notready":true, "old_unique_key":"xjDN.oZ89vuho4Y3", "resource":$["size":[$["unit":"cinch", "x":350, "y":0], $["unit":"sectors", "x":2880, "y":512]]], "sub_class_id":3, "unique_key":"sPPV.oZ89vuho4Y3"]];
integer num = 0;
foreach(map dev, devices, ``{
string dev_name = dev["dev_name"]:"";
string device = dev["device"]:"";
if (device == "")
{
if (dev["bus"]:"" == "Floppy")
{
// floppy disk drive - combo box item
device = _("Floppy");
}
}
if (dev_name != "")
{
ret = add(ret, dev_name, $[ "device" : device, "type" : "fd" + num + "://" ]);
}
num = num + 1;
}
);
// detect cdrom devices
devices = (Mode::test () == false) ? (list<map>) SCR::Read(.probe.cdrom) : [$["bus":"IDE", "cdtype":"cdrom", "class_id":262, "dev_name":"/dev/hdc", "device":"CD-540E", "driver":"ide-cdrom", "notready":true, "old_unique_key":"3JYE.3LYJ0fijWD1", "resource":$["size":[$["unit":"sectors", "x":0, "y":512]]], "rev":"1.0A", "sub_class_id":2, "unique_key":"hY5p.ZxKxy3YdB66"]];
num = 0;
foreach(map dev, devices, ``{
string dev_name = dev["dev_name"]:"";
string device = dev["device"]:"";
if (dev_name != "")
{
ret = add(ret, dev_name, $[ "device" : device, "type" : "cd" + num + "://" ]);
}
num = num + 1;
}
);
return ret;
}
/**
* Propose next file name of volume from file name
* @param volume Previuos volume name
* @return string Proposed next volume name
*/
define string ProposeNextVolume(string volume) ``{
// increase number in file name
integer pos = findlastof(volume, "/");
string volumedir = (pos != nil) ? substring(volume, 0, pos + 1) : "";
string volumefile = (pos != nil) ? substring(volume, pos + 1) : volume;
// ignore leading zeroes, 0xxx means octal number in tointeger() builtin
integer volumenum = tointeger(regexpsub(volumefile, "0*([0-9]+)([^0-9]*)", "\\1"));
string volumebase = regexpsub(volumefile, "([0-9]+)([^0-9]*)", "\\2");
string newvolume = "";
if (volumenum != nil)
{
volumenum = volumenum + 1;
newvolume = sformat("%1", volumenum);
if (size(newvolume) == 1)
{
newvolume = "0" + newvolume;
}
return volumedir + newvolume + volumebase;
}
else
{
return "";
}
}
/**
* Create list of removable devices for combo box widget.
* @param dev Map with devices
* @param sel Preselected device
* @return list Combo box content
*/
define list CreateDeviceList(map<string,map> dev, string sel) ``{
list ret = [];
// add selected device list if it's missing in map
if (sel != nil && sel != "" && !haskey(dev, sel))
{
ret = [ `item(`id(sel), sel) ];
}
foreach(string d, map info, dev, ``{
ret = add(ret, `item(`id(info["device"]:"" + " (" + d + ")"), info["device"]:"" + " (" + d + ")", sel == d));
}
);
return ret;
}
/**
* Enable/disable widget in file selction dialog according to
* selected input type
* @param type Symbol of widget which will be enabled (possible values are `file, `nfs, `removable)
*/
define void ShadowButtons(symbol type) ``{
UI::ChangeWidget(`id(`filename), `Enabled, type == `file);
UI::ChangeWidget(`id(`selectfile), `Enabled, type == `file);
UI::ChangeWidget(`id(`nfsserver), `Enabled, type == `nfs);
UI::ChangeWidget(`id(`nfsfilename), `Enabled, type == `nfs);
UI::ChangeWidget(`id(`selecthost), `Enabled, type == `nfs);
UI::ChangeWidget(`id(`device), `Enabled, type == `removable);
UI::ChangeWidget(`id(`remfilename), `Enabled, type == `removable);
UI::ChangeWidget(`id(`remfile), `Enabled, type == `removable);
}
/**
* Convert selected device name in combobox to URL-like equivalent
* @param selected Selected string in combo box
* @param dev Devices info
* @return string Device name in URL-like syntax
*/
define string ComboToDevice(string selected, map<string,map> dev) ``{
string ret = "";
foreach(string d, map info, dev, ``{
if (selected == info["device"]:"" + " (" + d + ")")
{
ret = info["type"]:"cd://";
}
}
);
if (ret == "")
{
ret = "dev://" + selected + ":";
}
return ret;
}
/**
* Backup archive is selected in this dialog.
* @param multivolume True = first archive file is entered, otherwise volume parts are entered
* @param askformore False: ask only for one volume part, true: ask until all volumes are entered
* @return symbol UI::UserInput() result
*/
define symbol ArchiveSelectionDialog(boolean multivolume, boolean askformore, string input) ``{
y2debug("input: %1", input);
// cache removable devices
if (removabledevices == nil)
{
removabledevices = DetectRemovable();
y2milestone("Detected removable devices: %1", removabledevices);
}
if (multivolume == false && Mode::config () == false)
{
// clear previous selection
Restore::ResetArchiveSelection();
}
string file_name = "";
string nfs_server = "";
string nfs_file = "";
string cd_file = "";
symbol type = `file;
string dev = "";
string urlinput = (input != nil && input != "") ? input : Restore::inputname;
string proposal = "";
if (urlinput != nil)
{
y2debug("urlinput: %1", urlinput);
map parsed_url = URL::Parse(urlinput);
string scheme = parsed_url["scheme"]:"file";
if (scheme == "nfs")
{
type = `nfs;
nfs_server = parsed_url["host"]:"";
nfs_file = parsed_url["path"]:"";
proposal = nfs_file;
}
else if (regexpmatch(scheme, "^cd[0-9]*") || regexpmatch(scheme, "^fd[0-9]*"))
{
type = `removable;
string devindex = regexpsub(scheme, "[cf]d0*([0-9]*)", "\\1");
if (devindex == nil || devindex == "")
{
devindex = "0";
}
if (Mode::test () == false)
{
path devpath = regexpmatch(scheme, "^cd[0-9]*") ? .probe.cdrom : .probe.floppy;
list <map> devicemaps = (list<map>) SCR::Read(devpath);
map devicemap = devicemaps[tointeger(devindex)]:$[];
dev = (string) devicemap["dev_name"]:"";
// dev = lookup(select((list<map>) SCR::Read(devpath), tointeger(devindex), $[]), "dev_name", "");
}
cd_file = parsed_url["path"]:"";
proposal = cd_file;
}
else if (scheme == "dev")
{
type = `removable;
dev = "/dev/" + parsed_url["host"]:"";
file_name = parsed_url["path"]:"";
proposal = file_name;
}
else
{
type = `file;
file_name = parsed_url["path"]:"";
proposal = file_name;
}
if (urlinput == input && multivolume == true)
{
proposal = ProposeNextVolume(proposal);
if (proposal != "")
{
if (type == `removable)
{
cd_file = proposal;
}
else if (type == `nfs)
{
nfs_file = proposal;
}
else
{
file_name = proposal;
}
}
}
}
// unmount previous file system
Restore::Umount();
term contents = `VBox(
// frame label
`Frame((multivolume == false ? _("Backup Archive") : _("Multivolume Archive")),
`HBox(
`RadioButtonGroup(`id(`source), `opt(`notify),
`VBox(
`VSpacing(0.5),
// radio button label
`Left(`RadioButton(`id(`file), `opt(`notify), _("&Local File"), type == `file)),
`VSquash(`HBox(
`HSpacing(2),
// text entry label
`Bottom(`TextEntry(`id(`filename), _("Archive Filena&me"), file_name)),
`HSpacing(1),
// push button label
`Bottom(`PushButton(`id(`selectfile), _("&Select...")))
)),
`VSpacing(1),
// radio button label
`Left(`RadioButton(`id(`nfs), `opt(`notify), _("Network (N&FS)"), type == `nfs)),
`VSquash(`HBox(
`HSpacing(2),
// text entry label
`Bottom(`TextEntry(`id(`nfsserver), _("I&P Address or Name of NFS Server"), nfs_server)),
`HSpacing(1),
// push button label
`Bottom(`PushButton(`id(`selecthost), _("Select &Host...")))
)),
`HBox(
`HSpacing(2),
// text entry label
`TextEntry(`id(`nfsfilename), _("&Archive Filename"), nfs_file)
),
`VSpacing(1),
// radio button label
`Left(`RadioButton(`id(`removable), `opt(`notify), _("Rem&ovable Device"), type == `removable)),
`HBox(
`HSpacing(2),
// combo box label
`Left(`ComboBox(`id(`device), `opt(`editable), _("&Device"), CreateDeviceList(removabledevices, dev)))
),
`VSquash(`HBox(
`HSpacing(2),
// text entry label
`Bottom(`TextEntry(`id(`remfilename), _("Archi&ve Filename"), cd_file)),
`HSpacing(1),
// push button label
`Bottom(`PushButton(`id(`remfile), _("S&elect...")))
)),
`VSpacing(1)
)
),
`HSpacing(1)
)
),
`VSpacing(1)
);
// dialog header
string title = (multivolume == false) ? _("Archive Selection") : _("Multivolume Archive Selection");
Wizard::SetContents(title, contents, (multivolume == true ? ArchiveMultiSelectionHelp() : ArchiveSelectionHelp()), true, true);
ShadowButtons(type);
any ret = nil;
do
{
ret = UI::UserInput();
if (ret == `selectfile)
{
string file = UI::AskForExistingFile("/", "*.tar", _("Select Archive File"));
if (file != nil && file != "")
{
UI::ChangeWidget(`id(`filename), `Value, file);
}
}
if (ret == `selecthost)
{
string selectedhost = NetworkPopup::NFSServer((string) UI::QueryWidget(`id(`nfsserver), `Value));
if (selectedhost != "" && selectedhost != nil)
{
UI::ChangeWidget(`id(`nfsserver), `Value, selectedhost);
}
}
else if (ret == `nfs || ret == `removable || ret == `file)
{
ShadowButtons((symbol) UI::QueryWidget(`id(`source), `CurrentButton));
}
else if (ret == `remfile)
{
string selected = (string) UI::QueryWidget(`id(`device), `Value);
string device = ComboToDevice(selected, removabledevices);
string fname = (string) UI::QueryWidget(`id(`remfilename), `Value);
// file selection from removable device - mount device
map mount = Restore::MountInput(device + fname);
if (mount["success"]:false == true)
{
string mountpnt = mount["mpoint"]:"/";
string file = UI::AskForExistingFile(mountpnt + "/", "*.tar", _("Select Archive File"));
if (file != nil && file != "")
{
// check if file is under mountpoint directory
if (substring(file, 0, size(mountpnt)) != mountpnt)
{
// error message - selected file is out of mounted file system
Popup::Error(_("The selected file is not on the mounted device."));
}
else
{
// set file name
UI::ChangeWidget(`id(`remfilename), `Value, substring(file, size(mountpnt)));
}
}
// umount file system
SCR::Execute(.target.umount, mountpnt);
}
else
{
// error message
Popup::Error(_("Cannot mount file system."));
}
}
else if (ret == `next)
{
symbol type = (symbol) UI::QueryWidget(`id(`source), `CurrentButton);
if (Mode::test () == true)
{
input = "file:///tmp/archive.tar";
}
else if (type == `file)
{
string fname = (string) UI::QueryWidget(`id(`filename), `Value);
if (fname == "")
{
// error message - file name is missing
Popup::Error(_("Enter a valid filename."));
input = "";
}
else
{
input = "file://" + fname;
}
}
else if (type == `nfs)
{
string server = (string) UI::QueryWidget(`id(`nfsserver), `Value);
string file = (string) UI::QueryWidget(`id(`nfsfilename), `Value);
if (server == "" || file == "")
{
// error message - file or server name is missing
Popup::Error(_("Enter a valid server and filename."));
input = "";
}
else
{
input = "nfs://" + server + ":" + file;
}
}
else if (type == `removable)
{
string selected = (string) UI::QueryWidget(`id(`device), `Value);
string device = ComboToDevice(selected, removabledevices);
string fname = (string) UI::QueryWidget(`id(`remfilename), `Value);
y2milestone("Selected removable device: %1", device);
if (device == "" || fname == "")
{
// error message - file or device name is missing
Popup::Error(_("Enter a valid device and filename."));
input = "";
}
else
{
input = device + fname;
}
}
else
{
y2error("Unknown source type %1", type);
}
if (input != "")
{
boolean configure = true;
if (Mode::config ())
{
// popup question
boolean answer = Popup::YesNo(_("Detailed configuration requires reading the archive.
If an archive is not read, full restoration will be configured.
Read the selected archive?
"));
configure = answer;
Restore::completerestoration = !answer;
y2debug("completerestoration: %1", Restore::completerestoration);
if (!configure)
{
Restore::runbootloader = true;
Restore::runSuSEconfig = true;
Restore::restoreRPMdb = true;
Restore::inputname = input;
}
}
if (configure)
{
boolean readresult = false;
boolean lastvolume = false;
// progress message
UI::OpenDialog(`Label(_("Reading archive contents...")));
y2debug("Restore::IsMultiVolume(): %1", Restore::IsMultiVolume());
if (Restore::IsMultiVolume() == false)
{
readresult = Restore::Read(input);
}
else
{
// read next volume
map nextresult = Restore::ReadNextVolume(input);
readresult = nextresult["success"]:false;
lastvolume = nextresult["lastvolume"]:false;
}
UI::CloseDialog();
if (readresult == false)
{
// error message - %1 is archive file name
Popup::Error(sformat(_("Cannot read backup archive file %1."), input));
Restore::Umount();
ret = `dummy;
}
else
{
restoredfiles = [];
failedfiles = [];
if (Restore::IsMultiVolume() == true && askformore == true)
{
// umount source and ask for next volume
Restore::Umount();
if (lastvolume == false)
{
if (multivolume == true)
{
symbol widget = nil;
if (type == `file)
{
widget = `filename;
}
else if (type == `removable)
{
widget = `remfilename;
}
else if (type == `nfs)
{
widget = `nfsfilename;
}
else
{
y2warning("Unknown source type: %1", type);
}
string fn = (string) UI::QueryWidget(`id(widget), `Value);
string prop = ProposeNextVolume(fn);
if (prop != "")
{
UI::ChangeWidget(`id(widget), `Value, prop);
}
ret = `dummy;
}
}
else
{
// last volume - test all volumes together
boolean testall = Restore::TestAllVolumes();
y2debug("TestAllVolumes(): %1", testall);
if (testall == false)
{
y2error("Test Restore::TestAllVolumes() failed");
// error message - multi volume archive consistency check failed
Popup::Error(_("Test of all volumes failed.
An archive file is probably corrupted.
"));
ret = `back;
}
}
}
}
}
else
{
ret = `noconfig;
}
}
else
{
ret = `dummy;
}
}
else if (ret == `cancel)
{
ret = `abort;
}
}
while (ret != `next && ret != `abort && ret != `back && ret != `multi && ret != `noconfig);
return (symbol) ret;
}
/**
* Display archive property - date of backup, user comment...
* @return symbol UI::UserInput() result
*/
define symbol ArchivePropertyDialog() ``{
if (Mode::config () == false)
{
y2milestone("missing packages %1: ", Restore::GetMissingPackages());
y2milestone("extra packages %1: ", Restore::GetExtraPackages());
y2milestone("mismatched packages %1: ", Restore::GetMismatchedPackages());
}
string date = Restore::GetArchiveDate();
string hostname = Restore::GetArchiveHostname();
string comment = Restore::GetArchiveComment();
string archname = Restore::GetInputName();
string multivolume = (Restore::IsMultiVolume() == true) ? _("Yes") : _("No");
term contents = `HBox(
`HSpacing(2),
`VBox(
`VSpacing(1),
// label text
`Left(`HBox(`Label(`id(`flabel), _("Archive Filename:")), `HSpacing(2), `Label(`id(`flabel2), archname))),
`VSpacing(0.5),
// label text
`Left(`HBox(`Label(`id(`dlabel), _("Date of Backup:")), `HSpacing(2), `Label(`id(`dlabel2), date))),
`VSpacing(0.5),
// label text
`Left(`HBox(`Label(`id(`hlabel), _("Backup Hostname:")), `HSpacing(2), `Label(`id(`hlabel2), hostname))),
`VSpacing(0.5),
// label text
`Left(`HBox(`Label(`id(`mlabel), _("Multivolume Archive:")), `HSpacing(2), `Label(`id(`mlabel2), multivolume))),
`VSpacing(1.0),
// multi line widget label
`Left(`Label(_("Archive &Description:"))),
`RichText(`id(`description), `opt(`plainMode), comment),
`VSpacing(1.0),
// push button label
`PushButton(`id(`details), `opt(`key_F2), _("&Archive Content...")),
`VSpacing(1),
// push button label
`PushButton(`id(`options), `opt(`key_F7), _("E&xpert Options...")),
`VSpacing(1.5)
),
`HSpacing(2)
);
// dialog header
Wizard::SetContents(_("Archive Properties"),
contents, ArchivePropertyHelp(), true, true);
any ret = nil;
do
{
ret = UI::UserInput();
if (ret == `cancel)
{
ret = `abort;
}
}
while (ret != `next && ret != `abort && ret != `back && ret != `details && ret != `options);
if (Restore::IsMultiVolume() == true && Restore::TestAllVolumes() == false && ret == `next)
{
// ask for next volumes
ret = `multi;
}
lastret = (symbol) ret;
return (symbol) ret;
}
/**
* Return content for table widget - list of backup files
* @param packagesinfo Map $[ "packagename" : $[ "files" : ["files in the archive"] ] ]
* @return list Table content
*/
define list<term> CreateArchiveContentTree(map<string, map<string, any> > packagesinfo) ``{
list<term> ret = [];
integer num = 0;
if (packagesinfo != nil)
{
foreach(string p, map<string, any> info, packagesinfo, ``{
list<string> files = info["files"]:[];
list<term> itemfiles = [];
string version = info["vers"]:"";
itemfiles = maplist(string s, files, ``{return `item(s);});
if (p == "")
{
// package name for files not owned by any package
p = _("--No package--");
}
ret = add(ret, `item(`id(num), p + "-" + version, itemfiles));
num = num + 1;
}
);
}
return ret;
}
/**
* Display content of backup archive in the table.
* @return symbol UI::UserInput() result
*/
define symbol ArchiveContentsDialog() ``{
Wizard::ClearContents();
if (archivecontentscache == nil)
{
archivecontentscache = CreateArchiveContentTree(Restore::GetArchiveInfo());
}
term contents = `HBox(
`HSpacing(2),
`VBox(
`VSpacing(1),
// tree label
`Tree(`id(`tree), _("Archive &Contents"), CreateArchiveContentTree(Restore::GetArchiveInfo())),
`VSpacing(1.5)
),
`HSpacing(2)
);
Wizard::SetNextButton(`next, Label::OKButton() );
// dialog header
Wizard::SetContents(_("Archive Contents"), contents, ArchiveContentHelp(), true, true);
any ret = nil;
do
{
ret = UI::UserInput();
if (ret == `cancel)
{
ret = `abort;
}
}
while (ret != `next && ret != `abort && ret != `back);
Wizard::RestoreNextButton();
return (symbol) ret;
}
/**
* Dialog with options.
* @return UI::UserInput() result
*/
define symbol RestoreOptionsDialog() ``{
term contents = `HBox(
`HSpacing(2),
`VBox(
`VSpacing(1),
// check box label - restore option
`Left(`CheckBox(`id(`lilo), _("Activate &Boot Loader Configuration after Restoration"), Restore::runbootloader)),
`VSpacing(0.2),
// check box label - restore option
`Left(`CheckBox(`id(`susecfg), _("Run &SuSEconfig after Restoration"), Restore::runSuSEconfig)),
`VSpacing(1),
// check box label - restore option
`Left(`TextEntry(`id(`target), _("Target Directory"), Restore::targetDirectory)),
`VSpacing(1.5)
),
`HSpacing(2)
);
Wizard::SetNextButton(`next, Label::OKButton() );
// dialog header
Wizard::SetContents(_("Restore Options"), contents, RestoreOptionsHelp(), true, true);
any ret = nil;
string target_dir = "/";
do
{
ret = UI::UserInput();
target_dir = (string)UI::QueryWidget(`id(`target), `Value);
if (size(target_dir) == 0 || substring(target_dir, 0, 1) != "/")
{
// error message - entered directory is empty or doesn't start with / character
Popup::Error(_("The target directory is invalid or the path is not absolute."));
ret = nil;
}
}
while(ret != `next && ret != `abort && ret != `back);
if (ret == `cancel)
{
ret = `abort;
}
else
{
Restore::runbootloader = (boolean) UI::QueryWidget(`id(`lilo), `Value);
Restore::runSuSEconfig = (boolean) UI::QueryWidget(`id(`susecfg), `Value);
Restore::targetDirectory = (string)UI::QueryWidget(`id(`target), `Value);
}
Wizard::RestoreNextButton();
return (symbol) ret;
}
/**
* Create content for table widget - columns: selection mark, package name, backup version, installed version, description
* @param contents Map $[ "packagename" : $[ "ver" : "version", "descr" : "short description" ] ]
* @param defaultval if true "X" is in the first column, else " "
* @param selected Selected packages (only for autoinstallation, otherwise should be nil)
* @return list Contents for Table widget
*/
define list CreateTableContentsWithMismatched(map<string, map<string, string> > contents, map selected, boolean defaultval) ``{
list ret = [];
integer num = 0;
string defval = (defaultval == true) ? "X" : " ";
if (contents != nil)
{
foreach(string p, map<string, string> m, contents, ``{
string ver = m["ver"]:"";
string descr = m["descr"]:"";
string installed = m["inst"]:"";
if (selected != nil)
{
defval = haskey(selected, p) ? "X" : " ";
}
ret = add(ret, `item(`id(num), defval, p, ver, installed, descr));
num = num + 1;
}
);
}
return ret;
}
/**
* Dialog for package selection - packages to install
* @return symbol UI::UserInput() result
*/
define symbol SelectionInstallDialog() ``{
map<string, map<string, string> > missingpackages = Restore::GetMissingPackages();
// add mismatched packages
foreach(string p, map<string, string> info, Restore::GetMismatchedPackages(), ``{
missingpackages = add(missingpackages, p, info);
}
);
// if all packages are installed return `next (or `back)
if (size(missingpackages) == 0)
{
return lastret;
}
list missing = CreateTableContentsWithMismatched(missingpackages, packagestoinstall, true);
// table header
term header = `header(" ", _("Package"), _("Version"), _("Installed Version"), _("Description"));
term contents = `HBox(
`HSpacing(2),
`VBox(
`VSpacing(1),
`Table(`id(`pkg), `opt(`notify), header, missing),
`VSpacing(1),
`HBox(
// push button label
`PushButton(`id(`all), _("&Select All")),
// push button label
`PushButton(`id(`none), _("&Deselect All"))
),
`VSpacing(1.5)
),
`HSpacing(2)
);
// dialog header
Wizard::SetContents(_("Package Restoration: Installation"), contents, InstallPackageHelp(), true, true);
any ret = nil;
do
{
ret = UI::UserInput();
if (ret == `all)
{
UI::ChangeWidget(`id(`pkg), `Items, CreateTableContentsWithMismatched(missingpackages, nil, true));
}
else if (ret == `none)
{
UI::ChangeWidget(`id(`pkg), `Items, CreateTableContentsWithMismatched(missingpackages, nil, false));
}
else if (ret == `pkg)
{
integer current = (integer) UI::QueryWidget(`id(`pkg), `CurrentItem);
term current_item = (term) UI::QueryWidget(`id(`pkg), `Item(current));
string current_value = (string) current_item[1]:" ";
// string current_value = (string) select((term) UI::QueryWidget(`id(`pkg), `Item(current)), 1, " ");
if (current_value == " ")
{
current_value = "X";
}
else
{
current_value = " ";
}
UI::ChangeWidget(`id(`pkg), `Item(current, 0), current_value);
}
else if (ret == `cancel)
{
ret = `abort;
}
}
while (ret != `next && ret != `abort && ret != `back);
if (ret != `abort)
{
integer num = size(missingpackages);
integer i = 0;
packagestoinstall = $[];
while (i < num)
{
term current_item = (term) UI::QueryWidget(`id(`pkg), `Item(i));
string s = (string) current_item[1]:" ";
string p = (string) current_item[2]:" ";
// string s = (string) select((term) UI::QueryWidget(`id(`pkg), `Item(i)), 1, " ");
// string p = (string) select((term) UI::QueryWidget(`id(`pkg), `Item(i)), 2, " ");
if (s == "X")
{
map i = missingpackages[p]:$[];
string v = i["ver"]:"";
packagestoinstall = add(packagestoinstall, p, $[ "ver" : v ]);
// change default restore status to 'restore' for packages which will be installed
if (haskey(Restore::GetArchiveInfo(), p))
{
Restore::SetRestoreSelection(p, $[ "sel_type" : "X" ] );
}
}
else
{
// change default restore status to 'do not restore' for packages which will not be installed
if (haskey(Restore::GetArchiveInfo(), p))
{
Restore::SetRestoreSelection(p, $[ "sel_type" : " " ] );
}
if (haskey(packagestoinstall, p))
{
packagestoinstall = remove(packagestoinstall, p);
}
}
i = i + 1;
}
y2milestone("Selected packages to install: %1", packagestoinstall);
}
// TODO: warn if some packages are not available on CDs and display path selection dialog to packages
// LATER: allow to select package from backup archive (YOU stores packages to /var/... and they can be used)
lastret = (symbol) ret;
return (symbol) ret;
}
/**
* Create content for table widget - columns: selection mark, package name, version, description
* @param contents Map $[ "packagename" : $[ "ver" : "version", "descr" : "short description" ] ]
* @param defaultval if true "X" is in the first column, else " "
* @param selected Selected packages (only for autoinstallation, otherwise should be nil)
* @return list Contents for Table widget
*/
define list CreateTableContents(map<string, map<string, string> > contents, map selected, boolean defaultval) ``{
list ret = [];
integer num = 0;
string defval = (defaultval == true) ? "X" : " ";
if (contents != nil)
{
foreach(string p, map<string, string> m, contents, ``{
string ver = m["ver"]:"";
string descr = m["descr"]:"";
if (selected != nil)
{
defval = haskey(selected, p) ? "X" : " ";
}
ret = add(ret, `item(`id(num), defval, p, ver, descr));
num = num + 1;
}
);
}
return ret;
}
/**
* Dialog for package selection - packages to uninstall
* @return symbol UI::UserInput() result
*/
define symbol SelectionUninstallDialog() ``{
map<string, map<string, string> > extrapackages = Restore::GetExtraPackages();
// if none extra package is installed return `next (or `back)
if (size(extrapackages) == 0)
{
return lastret;
}
list extra = CreateTableContents(extrapackages, packagestouninstall, true);
// table header
term header = `header(" ", _("Package"), _("Version"), _("Description"));
term contents = `HBox(
`HSpacing(2),
`VBox(
`VSpacing(1),
`Table(`id(`pkg), `opt(`notify), header, extra),
`VSpacing(1),
`HBox(
// push button label
`PushButton(`id(`all), _("&Select All")),
// push button label
`PushButton(`id(`none), _("&Deselect All"))
),
`VSpacing(1.5)
),
`HSpacing(2)
);
// dialog header
Wizard::SetContents(_("Package Restoration: Uninstallation"), contents, UninstallPackageHelp(), true, true);
any ret = nil;
do
{
ret = UI::UserInput();
if (ret == `all)
{
UI::ChangeWidget(`id(`pkg), `Items, CreateTableContents(extrapackages, nil, true));
}
else if (ret == `none)
{
UI::ChangeWidget(`id(`pkg), `Items, CreateTableContents(extrapackages, nil, false));
}
else if (ret == `pkg)
{
integer current = (integer) UI::QueryWidget(`id(`pkg), `CurrentItem);
term current_item = (term) UI::QueryWidget(`id(`pkg), `Item(current));
string current_value = (string) current_item[1]:" ";
// string current_value = (string) select((term) UI::QueryWidget(`id(`pkg), `Item(current)), 1, " ");
if (current_value == " ")
{
current_value = "X";
}
else
{
current_value = " ";
}
UI::ChangeWidget(`id(`pkg), `Item(current, 0), current_value);
}
else if (ret == `cancel)
{
ret = `abort;
}
}
while (ret != `next && ret != `abort && ret != `back);
if (ret != `abort)
{
integer num = size(extrapackages);
integer i = 0;
packagestouninstall = $[];
while (i < num)
{
term current_item = (term) UI::QueryWidget(`id(`pkg), `Item(i));
string s = (string) current_item[1]:" ";
string p = (string) current_item[2]:" ";
// string s = (string) select((term) UI::QueryWidget(`id(`pkg), `Item(i)), 1, " ");
// string p = (string) select((term) UI::QueryWidget(`id(`pkg), `Item(i)), 2, " ");
if (s == "X")
{
map i = extrapackages[p]:$[];
string v = i["ver"]:"";
packagestouninstall = add(packagestouninstall, p, $[ "ver" : v ]);
}
else if (p != nil && haskey(packagestouninstall, p))
{
packagestouninstall = remove(packagestouninstall, p);
}
i = i + 1;
}
y2milestone("Selected packages to uninstall: %1", packagestouninstall);
}
lastret = (symbol) ret;
return (symbol) ret;
}
/**
* Start Yast2 package manager
* @return symbol UI::UserInput() result
*/
define symbol SWsingleDialog() ``{
list<string> install = [];
list<string> uninstall = [];
if (lastret == `back)
{
return `back;
}
if (size(packagestoinstall) > 0)
{
foreach(string k, any v, packagestoinstall, ``{install = add(install, k);});
}
if (size(packagestouninstall) > 0)
{
foreach(string k, any v, packagestouninstall, ``{uninstall = add(uninstall, k);});
}
y2milestone("install: %1", install);
y2milestone("uninstall: %1", uninstall);
list <string> unavailable_packages = [];
// Initialize the package manager (the same way it is used later)
// before checking for packages availability
PackageSystem::EnsureSourceInit();
// BNC #553400: Checking for all packages to install whether they are available
foreach (string one_package, install, {
// Package is not available - cannot be installed
if (Pkg::IsAvailable (one_package) != true) {
if (Popup::AnyQuestion (
// Headline
_("Error"),
// Error message
sformat(_("Package %1 is not available on any of the subscribed repositories.
Would you like to got back and unselect the package or skip it?"), one_package),
_("Yes, Go &Back"),
_("&Skip"),
`focus_yes
)) {
y2milestone ("User has decided to go back an unselect the package (%1)", one_package);
lastret = `back;
break;
} else {
unavailable_packages = add (unavailable_packages, one_package);
y2warning ("User decided to skip missing package (%1)", one_package);
}
}
});
// Remove all unavailable packages from list of packages to install
foreach (string do_not_install_package, unavailable_packages, {
install = filter (string one_package, install, {
return (one_package != do_not_install_package);
});
});
if (lastret == `back)
{
return `back;
}
if (size(install) > 0 || size(uninstall) > 0)
{
if (Package::DoInstallAndRemove(install, uninstall) != true) {
Report::Error (_("Installation or removal of some packages has failed."));
}
Restore::ReadActualInstalledPackages();
}
return lastret;
}
/**
* Return table widget contens - files and packages selected for restoration
* @param restoreselection Restore settings
* @return list Table content
*/
define list<term> CreateTableContentsRestoreSelection(map<string, map<string, any> > restoreselection) ``{
list<term> ret = [];
// id of item in the table
integer num = 0;
if (restoreselection != nil)
{
foreach(string p, map<string, any> m, restoreselection, ``{
string ver = m["vers"]:"";
string descr = m["descr"]:"";
string seltype = m["sel_type"]:" ";
string numfiles = "";
if (seltype == "X")
{
// all files selected for restoration
numfiles = _("All");
}
else if (seltype == " ")
{
numfiles = "";
}
else if (seltype == "P")
{
integer total = size(m["files"]:[]);
integer sel = size(m["sel_file"]:[]);
// selected %1 (number of files) of %2 (number of files)
numfiles = sformat(_("%1 of %2"), sel, total);
}
else
{
y2error("Unknown selection type: %1", seltype);
}
if (p == "")
{
// name for "no package" - files not owned by any package
p = _("--No package--");
}
ret = add(ret, `item(`id(num), seltype, numfiles, p, ver, descr));
num = num + 1;
}
);
}
return ret;
}
/**
* Ask wheter missing package should be installed and restored
* @param package Package name
* @param version Package version
* @return boolean True if package should be installed
*/
define boolean InstallQuestion(string package, string version) ``{
boolean ret = false;
if (Mode::config () == true)
{
// do not ask in autoinstall config mode
return true;
}
if (package != "" && !haskey(Restore::GetActualInstalledPackages(), package) && !haskey(packagestoinstall, package))
{
// popup question - %1 is package name
ret = Popup::AnyQuestion("", sformat(_("Package %1 is not installed in your system.
Install it?
"), package + "-" + version), Label::YesButton(), Label::NoButton(), `focus_yes);
if (ret == true)
{
// add package to the map of installed packages
packagestoinstall = add(packagestoinstall, package, $[ "ver" : version ]);
}
}
return ret;
}
/**
* Packages (and files) for restoration can be selected in this archive.
* @return symbol UI::UserInput() result
*/
define symbol PackageSelectionRestoreDialog() ``{
term button = `PushButton(`id(`files), `opt(`key_F7), _("S&elect Files"));
list<term> tablecontents = CreateTableContentsRestoreSelection(Restore::GetArchiveInfo());
integer position = 0;
// refresh previous selection
if (restorepackagename != nil)
{
foreach(term t, tablecontents, ``{
// if (restorepackagename == select(t, 3, ""))
if (restorepackagename == t[3]:"")
{
position = t[0,0]:0;
}
}
);
}
map<string, any> proposedRPMrestoration = Restore::ProposeRPMdbRestoration();
y2milestone("Proposed RPM restoration: %1", proposedRPMrestoration);
boolean RPMoption = Restore::restoreRPMdb;
y2warning("RPMoption: %1", RPMoption);
if (RPMoption == nil)
{
// BNC #553400, Comment #19: Use the proposed 'Restore RPM DB' only if proposal is valid
if (haskey(proposedRPMrestoration, "proposed") && proposedRPMrestoration["proposed"]:false != nil)
RPMoption = (boolean) (proposedRPMrestoration["proposed"]:false);
else
RPMoption = false;
}
y2warning("RPMoption: %1", RPMoption);
if (RPMoption == nil)
{
RPMoption = false;
}
term contents = `HBox(
`HSpacing(2),
`VBox(
`VSpacing(1),
// table header
`Table(`id(`pkgtable),`opt(`notify), `header(" ", _("Files"), _("Package"), _("Version"), _("Description")), tablecontents),
`VSpacing(0.2),
// push button label
`HBox(`PushButton(`id(`select), _("&Select All")), `PushButton(`id(`deselect), _("&Deselect All")), button),
`VSpacing(1.0),
// check box label - restore option
`CheckBox(`id(`rpmdb), `opt(`notify), _("Restore RPM &Database (if present in archive)"), RPMoption),
`VSpacing(1.5)
),
`HSpacing(2)
);
// description of symbols in the table 1/2
string helptext = _("X: Restore all files from backup, P: Partial restore of manually selected files");
// description of symbols in the table 2/2
helptext = helptext + _("<P>To select files to restore from the archive, press <B>Select Files</B>.</P>");
// dialog header
Wizard::SetContents(_("Packages to Restore"), contents, RestoreSelectionHelp(false), true, true);
if (Mode::config () == true)
{
Wizard::SetNextButton(`next, Label::FinishButton() );
}
else
{
Wizard::SetNextButton(`next, Label::OKButton() );
}
if (Restore::RPMrestorable() == false)
{
// RPM DB cannot be restored (it is not contained in the archive)
Restore::restoreRPMdb = false;
UI::ChangeWidget(`id(`rpmdb), `Enabled, false);
y2warning("RPM DB is not present in the archive - cannot be restored");
}
// set currnet item in the table
if (size(tablecontents) > 0)
{
UI::ChangeWidget(`id(`pkgtable), `CurrentItem, position);
}
any ret = nil;
do
{
ret = UI::UserInput();
integer current = 0;
string current_value = "";
string current_pkgname = "";
string current_version = "";
if (size(tablecontents) > 0)
{
current = (integer) UI::QueryWidget(`id(`pkgtable), `CurrentItem);
term current_item = (term) UI::QueryWidget(`id(`pkgtable), `Item(current));
current_value = (string) current_item[1]:" ";
current_pkgname = (string) current_item[3]:"";
current_version = (string) current_item[4]:"";
// current_value = (string) select((term) UI::QueryWidget(`id(`pkgtable), `Item(current)), 1, " ");
// current_pkgname = (string) select((term) UI::QueryWidget(`id(`pkgtable), `Item(current)), 3, "");
// current_version = (string) select((term) UI::QueryWidget(`id(`pkgtable), `Item(current)), 4, "");
}
restorepackagename = current_pkgname;
// package name "none" - files not owned by any package
if (current_pkgname == _("--No package--"))
{
current_pkgname = "";
}
if (ret == `pkgtable)
{
// toggle restore selection: "X" -> " ", " " -> "X", "P" -> " "
if (current_value == " ")
{
// check if package is installed
// TODO check versions
if (current_pkgname != "" && !haskey(Restore::GetActualInstalledPackages(), current_pkgname) && !haskey(packagestoinstall, current_pkgname))
{
current_value = InstallQuestion(current_pkgname, current_version) ? "X" : " ";
}
else
{
current_value = "X";
}
}
else
{
current_value = " ";
}
// files are selected to restore - all
string selectionstring = (current_value == "X") ? _("All") : "";
UI::ChangeWidget(`id(`pkgtable), `Item(current, 0), current_value);
UI::ChangeWidget(`id(`pkgtable), `Item(current, 1), selectionstring);
Restore::SetRestoreSelection(current_pkgname, $["sel_type" : current_value]);
}
else if (ret == `files)
{
// check if package is installed
// TODO check versions
if (current_value == " " && current_pkgname != "" && !haskey(Restore::GetActualInstalledPackages(), current_pkgname) && !haskey(packagestoinstall, current_pkgname))
{
if (InstallQuestion(current_pkgname, current_version) == false)
{
ret = `dummy;
}
}
restorepackagename = current_pkgname;
}
else if ((ret == `select || ret == `deselect) && size(tablecontents) > 0)
{
// set selection type
string sel_type = (ret == `select) ? "X" : " ";
if (sel_type == "X")
{
// check whether some packages are missing, ask if they should be selected too
map missing = Restore::GetMissingPackages();
boolean selmissing = Mode::config (); // select all packages in autoinstall config mode
if (missing != $[] && Mode::config () == false)
{
// user selected to restore all packages,
// but some packages are not installed
// ask to restore them
string question = _("Some packages are not installed.
Select them for restoration?
");
selmissing = Popup::AnyQuestion("", question, Label::YesButton(), Label::NoButton(), `focus_no);
}
// ask about mismatched packages
map mismatched = Restore::GetMismatchedPackages();
boolean selmismatch = Mode::config (); // select all packages in autoinstall config mode
if (mismatched != $[] && Mode::config () == false)
{
// user selected to restore all packages,
// but some installed packages have different version than at backup
// ask to restore them
string question = _("Some installed packages have a different
version than in the backup archive.
Select them for restoration?
");
selmismatch = Popup::AnyQuestion("", question, Label::YesButton(), Label::NoButton(), `focus_no);
}
// set selection type for packages
foreach(string p, map info, Restore::GetArchiveInfo(), ``{
string sel = sel_type;
if (selmissing == false && haskey(missing, p) == true)
{
sel = " ";
}
else if (selmismatch == false && haskey(mismatched, p) == true)
{
sel = " ";
}
Restore::SetRestoreSelection(p, $["sel_type" : sel, "sel_file" : []]);
}
);
}
else
{
// set selection type for all packages
foreach(string p, map info, Restore::GetArchiveInfo(), ``{
Restore::SetRestoreSelection(p, $["sel_type" : sel_type, "sel_file" : []]);
}
);
}
// change table contents
UI::ChangeWidget(`id(`pkgtable), `Items, CreateTableContentsRestoreSelection(Restore::GetArchiveInfo()));
// set previous selection
if (current != nil)
{
UI::ChangeWidget(`id(`pkgtable), `CurrentItem, current);
}
}
else if (ret == `rpmdb)
{
// check current RPM rezstoration status with proposed
boolean selectedRPM = (boolean) UI::QueryWidget(`id(`rpmdb), `Value);
proposedRPMrestoration = Restore::ProposeRPMdbRestoration();
RPMoption = (boolean) (proposedRPMrestoration["proposed"]:nil);
if (selectedRPM != RPMoption)
{
// display warning
if (RPMoption == true)
{
Popup::Warning(_("Restoring the RPM database is recommended."));
}
else if (RPMoption == false)
{
Popup::Warning(_("Not restoring the RPM database is recommended."));
}
else
{
// RPMoption is nil
Popup::Warning(_("There is a conflict between selected
packages and the RPM database restoration option.
Try changing the selection or the RPM database restoration status."));
}
Restore::restoreRPMdb = selectedRPM;
}
}
else if (ret == `cancel)
{
ret = `abort;
}
}
while (ret != `next && ret != `abort && ret != `back && ret != `files);
if (ret == `next)
{
map<string, map<string, any> >final = Restore::GetArchiveInfo();
final = filter(string p, map<string, any> i, final, ``{
return (i["sel_type"]:" " != " ");
}
);
Restore::restoreRPMdb = (boolean) UI::QueryWidget(`id(`rpmdb), `Value);
y2debug("Final restore selection: %1", final);
}
if (Mode::config () == true)
{
Wizard::RestoreNextButton();
}
lastret = (symbol) ret;
return (symbol) ret;
}
/**
* Display all files in backup archive which belong to package. User can select which files will be resored.
* @param packagename Name of package
* @return symbol UI::UserInput() result
*/
define symbol FileSelectionDialog(string packagename) ``{
// create multiselection widget contents
map restore_info = Restore::GetArchiveInfo();
map pkginfo = restore_info[packagename]:$[];
// map pkginfo = lookup(Restore::GetArchiveInfo(), packagename, $[]);
string sel_type = pkginfo["sel_type"]:" ";
list<string> files = pkginfo["files"]:[];
list sel_file = pkginfo["sel_file"]:[];
list cont = [];
foreach(string f, files, ``{
boolean selected = false;
if (sel_type == "X")
{
selected = true;
}
else if (sel_type == " ")
{
selected = false;
}
else if (sel_type == "P")
{
selected = contains(sel_file, f);
}
else
{
y2error("Unknown selection type %1 in package %2", sel_type, packagename);
}
cont = add(cont, `item(`id(f), f, selected));
}
);
// multi selection box label
string mlabel = _("&Files to Restore");
term contents = `HBox(
`HSpacing(2),
`VBox(
`VSpacing(1),
`ReplacePoint(`id(`rp), `MultiSelectionBox(`id(`mbox), mlabel, cont)),
`VSpacing(1),
`HBox(
// push button label
`PushButton(`id(`all), _("&Select All")),
// push button label
`PushButton(`id(`none), _("&Deselect All"))
),
`VSpacing(1.5)
),
`HSpacing(2)
);
Wizard::SetNextButton(`next, Label::OKButton() );
// dialog header - %1 is name of package (e.g. "aaa_base")
Wizard::SetContents(sformat(_("File Selection: Package %1"), packagename), contents, FileSelectionHelp(), true, true);
any ret = nil;
do
{
ret = UI::UserInput();
if (ret == `all || ret == `none)
{
cont = [];
boolean selected = (ret == `all);
foreach(string f, files, ``{
cont = add(cont, `item(`id(f), f, selected));
}
);
UI::ReplaceWidget(`id(`rp), `MultiSelectionBox(`id(`mbox), mlabel, cont));
}
else if (ret == `cancel)
{
ret = `abort;
}
}
while(ret != `next && ret != `abort && ret != `back);
if (ret == `next)
{
string sel_type_new = "";
list sel = (list) UI::QueryWidget(`id(`mbox), `SelectedItems);
if (size(sel) == 0)
{
sel_type_new = " ";
}
else if (size(sel) == size(files))
{
sel_type_new = "X";
// clear list of selected files to save memory, "X" as sel_type is enough
sel = [];
}
else
{
sel_type_new = "P";
}
Restore::SetRestoreSelection(packagename, $["sel_type" : sel_type_new, "sel_file" : sel]);
}
Wizard::RestoreNextButton();
return (symbol) ret;
}
/**
* Restore packages from backup archive - display progress of restoring process
* @return symbol UI::UserInput() result
*/
define symbol RestoreProgressDialog() ``{
symbol ret = nil;
symbol progressbar = `progress;
integer bootloaderstep = (Restore::runbootloader == true) ? 1 : 0;
term contents = `HBox(
`HSpacing(2),
`VBox(
`VSpacing(1),
`ProgressBar(`id(progressbar), " ", Restore::TotalPackagesToRestore() + bootloaderstep, 0),
`VSpacing(1.5)
),
`HSpacing(2)
);
// callback function for abort
block<boolean> callback = ``{
import "Label";
any ret = UI::PollInput();
boolean abort = false;
if (ret == `abort || ret == `cancel)
{
// abort popup question
abort = Popup::AnyQuestion(_("Abort Confirmation"), _("Really abort restore?"), Label::YesButton(), Label::NoButton(), `focus_no);
}
return abort;
};
// dialog header
Wizard::SetContents(_("Restoring Files"), contents, RestoreProgressHelp(), false, false);
// start restoration
map result = Restore::Write(callback, progressbar, Restore::targetDirectory);
// set values from restoration
ret = (result["aborted"]:false) ? `abort : `next;
// get lilo status
bloaderstatus = result["bootloader"]:false;
if (ret == `next)
{
restoredfiles = result["restored"]:[];
failedfiles = result["failed"]:[];
restoredpackages = result["packages"]:0;
}
lastret = ret;
return ret;
}
/**
* Start SuSEconfig
* @return symbol UI::UserInput() result
*/
define symbol SuSEconfigDialog() ``{
if (Restore::runSuSEconfig == true && Mode::test () == false)
{
WFM::CallFunction("inst_suseconfig", []);
// SuSE config was started
susestatus = true;
}
return `next;
}
/**
* This function should be called only once before end of client. This function
* cleans up the system - unmounts mounted files systems.
* @return symbol Returns symbol `next for wizard sequencer
*/
define symbol AtExit() ``{
// unmount file system
Restore::Umount();
return `next;
}
/**
* Convert programm status to string
* @param status Status: true = OK, false = Failed, nil = "Not started"
* @return string Status
*/
define string StatusToString(boolean status) ``{
// program return status - program was not started
string ret = "<I>" + _("Not started") + "</I>";
if (status == true)
{
// program return status - success
ret = _("OK");
}
else if (status == false)
{
// program return status - failed
ret = "<B>" + _("Failed") + "</B>";
}
return ret;
}
/**
* Display summary of restoration
* @return symbol UI::UserInput() result
*/
define symbol SummaryDialog() ``{
// summary information texts
string basicinfo = "<P>" + _("Number of Installed Packages: ") + size(packagestoinstall) + "<BR>" + _("Number of Uninstalled Packages: ") + size(packagestouninstall) + "</P><P>" + _("Total Restored Packages: ") + restoredpackages + "<BR>" + _("Total Restored Files: ") + ((restoredfiles != nil) ? size(restoredfiles) : 0) + "</P>";
// display failed files if any
if (size(failedfiles) > 0)
{
// summary information text - header
basicinfo = basicinfo + "<P><B>" + _("Failed Files") + "</B><BR>" + mergestring(failedfiles, "<BR>") + "</P>";
}
// set lilo result string
string lilostr = StatusToString(bloaderstatus);
// set SuSEconfig result string
string SuSEinfo = StatusToString(susestatus);
string filelist = "";
if (restoredfiles != nil && size(restoredfiles) > 0)
{
string prefix = Restore::targetDirectory;
if (substring(prefix, size(prefix) - 1, 1) != "/")
{
prefix = prefix + "/";
}
filelist = prefix + mergestring(restoredfiles, "<BR>" + prefix);
}
// summary information texts - details
string extendedinfo = "<P><BR><B>" + _("Details:") + "</B></P><P>" + _("Boot Loader Configuration: ") + lilostr + "<BR>" + _("SuSEconfig Status: ") + SuSEinfo + " </P><P><B>" + _("Restored Files:") + "</B><BR>" + filelist + "</P>";
// dialog header
return DisplaySummaryDialog(basicinfo, basicinfo + extendedinfo, SummaryHelp(), _("Summary of Restoration"), `finish);
}
/**
* Whole restoration
* @return any Returned value from Sequencer::Run() call
*/
define symbol RestoreSequence () ``{
map aliases =
$[
"archive" : ``( ArchiveSelectionDialog(false, false, "") ),
"property" : ``( ArchivePropertyDialog() ),
"marchive" : [ ``( ArchiveSelectionDialog(true, true, "") ), true ],
"contents" : [ ``( ArchiveContentsDialog() ), true ],
"options" : [ ``( RestoreOptionsDialog() ), true ],
"install" : ``( SelectionInstallDialog() ),
"uninstall" : ``( SelectionUninstallDialog() ),
"sw_single" : ``( SWsingleDialog() ),
"select" : ``( PackageSelectionRestoreDialog() ),
"selectfile": [ ``( FileSelectionDialog(restorepackagename) ), true ],
"restore" : [ ``( RestoreProgressDialog() ), true ],
"SuSEconfig": [ ``( SuSEconfigDialog() ), true ],
"atexit" : ``( AtExit() ),
"summary" : ``( SummaryDialog() ),
];
map sequence = $[
"ws_start" : "archive",
"archive" :
$[
`next : "property",
`noconfig : "atexit",
`abort : "atexit"
],
"marchive" :
$[
`next : "install",
`abort : "atexit"
],
"property" :
$[
`details : "contents",
`options : "options",
`multi : "marchive",
`next : "install",
`abort : "atexit"
],
"contents" :
$[
`next : "property",
`abort : "atexit"
],
"options" :
$[
`next : "property",
`abort : "atexit"
],
"install" :
$[
`next : "uninstall",
`abort : "atexit"
],
"uninstall" :
$[
`next : "sw_single",
`abort : "atexit"
],
"sw_single" :
$[
`next : "select",
`abort : "atexit"
],
"select" :
$[
`files : "selectfile",
`abort : "atexit",
`next : "restore"
],
"restore" :
$[
`next : "SuSEconfig",
`abort : "atexit"
],
"SuSEconfig" :
$[
`next : "summary",
`abort : "atexit"
],
"selectfile" :
$[
`next : "select",
`abort : "atexit"
],
"summary" :
$[
`abort : "atexit",
`next : "atexit"
],
"atexit" :
$[
`next : `next
]
];
Wizard::CreateDialog ();
Wizard::SetDesktopIcon("restore");
symbol ret = Sequencer::Run(aliases, sequence);
UI::CloseDialog ();
return ret;
}
/**
* Restoration without reading and writing.
* For use with autoinstallation.
* @return any Returned value from Sequencer::Run() call
*/
define any RestoreAutoSequence() ``{
map aliases =
$[
"archive" : ``( ArchiveSelectionDialog(false, false, "") ),
"property" : ``( ArchivePropertyDialog() ),
"marchive" : [ ``( ArchiveSelectionDialog(true, true, "") ), true ],
"contents" : [ ``( ArchiveContentsDialog() ), true ],
"options" : [ ``( RestoreOptionsDialog() ), true ],
"select" : ``( PackageSelectionRestoreDialog() ),
"atexit" : ``( AtExit() ),
"selectfile": [ ``( FileSelectionDialog(restorepackagename) ), true ],
];
map sequence = $[
"ws_start" : "archive",
"archive" :
$[
`next : "property",
`noconfig : "atexit",
`abort : `abort
],
"marchive" :
$[
`next : "select",
`abort : `abort
],
"property" :
$[
`details : "contents",
`options : "options",
`multi : "marchive",
`next : "select",
`abort : `abort
],
"contents" :
$[
`next : "property",
`abort : `abort
],
"options" :
$[
`next : "property",
`abort : `abort
],
"select" :
$[
`files : "selectfile",
`abort : `abort,
`next : `next
],
"selectfile" :
$[
`next : "select",
`abort : `abort
],
"atexit" :
$[
`next : `next
]
];
Wizard::CreateDialog ();
Wizard::SetDesktopIcon("restore");
any ret = Sequencer::Run(aliases, sequence);
UI::CloseDialog ();
return ret;
}
/**
* Return content for table widget - list of backup files
* @param packagesinfo Map $[ "packagename" : $[ "files" : ["files in the archive"] ] ]
* @return list Table content
*/
define list CreateArchiveContentTable(map<string, map<string, any> > packagesinfo) ``{
list ret = [];
integer num = 0;
if (packagesinfo != nil)
{
foreach(string p, map<string, any> info, packagesinfo, ``{
list<string> files = info["files"]:[];
string version = info["vers"]:"";
foreach(string file, files, ``{
ret = add(ret, `item(`id(num), p, version, file));
num = num + 1;
}
);
}
);
}
return ret;
}
/**
* Select item from list
* @param label Label in dialog
* @param inputlist List of values
* @param selected Default selected value
* @return string Selected value or empty string ("") if dialog was closed
*/
define string SelectFromList(string label, list inputlist, string selected) ``{
UI::OpenDialog(
`HBox(
`VSpacing(10),
`VBox(
`HSpacing(40),
`SelectionBox(`id(`selbox), label, inputlist),
`HBox(
`PushButton(`id(`ok), `opt(`default, `key_F10), Label::OKButton()),
`PushButton(`id(`cancel), `opt(`key_F9), Label::CancelButton())
)
)
)
);
if (contains(inputlist, selected))
{
UI::ChangeWidget(`id(`selbox), `CurrentItem, selected);
}
UI::SetFocus(`id(`ok));
any uinput = nil;
do
{
uinput = UI::UserInput();
}
while (uinput != `ok && uinput != `cancel);
string ret = (uinput == `cancel) ? "" : (string) UI::QueryWidget(`id(`selbox), `CurrentItem);
UI::CloseDialog();
return ret;
}
}
ACC SHELL 2018