ACC SHELL

Path : /usr/share/YaST2/clients/
File Upload :
Current File : //usr/share/YaST2/clients/inst_language_add-on.ycp

/**
 * File:	clients/inst_language_add-on.ycp
 * Authors:	Lukas Ocilka <locilka@suse.cz>
 * Summary:	Template client for language Add-On products
 *
 * This is a template for Language Add-Ons. It can be either called
 * from the installation.xml in the root ("/") of the product or
 * called from command-line for testing purposes:
 * `yast2 inst_language_add-on.ycp "$[]" url_to_add_on_source`.
 *
 * $Id$
 */
{
    import "Language";
    import "Wizard";
    import "Label";
    import "Popup";
    
    textdomain "add-on";

    /**
     * Returns the list of available languages. It is based on the
     * "LINGUAS" entry in the /content file. Returns nil if something
     * is wrong.
     *
     * @return list <string> supported languages
     *   (e.g., ["af", "ar", "be_BY", "bg", "ca", "cs", "cy", "da", "el", "et", "fi"])
     */
    list <string> GetListOfSupportedLanguages (integer source) {
	string content_file = Pkg::SourceProvideSignedFile (source, 1, "/content", false);
	if (content_file == nil || content_file == "") {
	    y2error ("There is no content file!");
	    return nil;
	}

	SCR::RegisterAgent (.media.content, `ag_ini(
	    `IniAgent( content_file,
	    $[
		"options" : [ "read_only", "global_values", "flat" ],
		"comments" : [ "^#.*", "^[ \t]*$", ],
		"params" : [
		    $[ "match" : [ "^[ \t]*([a-zA-Z0-9_\.]+)[ \t]*(.*)[ \t]*$", "%s %s" ] ]
		]
	    ]
	)));
	string supported_languages = tostring (SCR::Read (.media.content.LINGUAS));
	if (supported_languages == nil || supported_languages == "") {
	    y2error ("No languages [LINGUAS] defined!");
	    return nil;
	}

	y2milestone("Languages found: %1", supported_languages);
	SCR::UnregisterAgent (.media.content);

	return splitstring (supported_languages, " ");
    }

    /**
     * Solves dependencies and installs packages
     */
    boolean Install (list <string> languages_to_install) {
	y2milestone ("Installing packages for languages: %1", languages_to_install);
	Pkg::SetAdditionalLocales (languages_to_install);

	y2milestone("Solving dependencies");
	if (Pkg::PkgSolve(true) != true) {
	    y2error("Cannot solve dependencies");
	    return false;
	}

	y2milestone("Installing packages");
	WFM::call("inst_rpmcopy");
	WFM::call("inst_suseconfig");
	
	Popup::Message (
	    // TRANSLATORS: popup message
	    _("Installation of the Language Extension has been finished.")
	);

	return true;
    }

    /**
     * Only when WFM::Args[1] contains an URL to be added
     */
    void InitFunction () {
	list args = WFM::Args();
	y2milestone ("Args: %1", args);
	string add_on_url = tostring (args[1]:"");

	if (add_on_url == "") {
	    y2milestone("No URL given as an argument, not initializing source.");
	    return;
	}
	
	y2milestone ("Using URL: '%1'", add_on_url);

	import "PackageCallbacksInit";
	import "SourceManager";

	PackageCallbacksInit::InitPackageCallbacks();
    
	Pkg::TargetInit ("/", true);
	Pkg::SourceStartManager (true);
    
        SourceManager::createSource (add_on_url);
    }

    // Dialog definitions -->
    
    void Dialog_Init () {
	Wizard::SetContentsButtons(
	    // TRANSLATORS: dialog caption
	    _("Add-On Product Installation"),
	    // TRANSLATORS: dialog content - a very simple label
	    `Label(_("Initializing...")),
	    // TRANSLATORS: help text
	    _("<p>Initializing add-on products...</p>"),
	    Label::BackButton(),
	    Label::NextButton()
	);
	Wizard::SetTitleIcon("yast-language");
	Wizard::DisableBackButton();
	Wizard::DisableAbortButton();
	Wizard::DisableNextButton();
    }

    list <string> Dialog_SelectLanguagesUI (
	map <string, string> & known_languages,
	list <string> & already_installed_languages
    ) {
	list <term> items = [];
	list <string> pre_selected_languages = [];
	boolean pre_selected = nil;

	// for each language supported on the medium
	foreach (string short, string long, known_languages, {
	    // installed is 'de' or 'cs' or 'zh'
	    if (contains (already_installed_languages, short)) {
		pre_selected = true;
	    // installed is 'de_XY' or 'cs_AB' or 'zh_CD'
	    // but not on the medium, find similar
	    } else if (size (short) > 2) {
		string language_substring = substring (short, 0, 2);
		if (contains (already_installed_languages, language_substring)) {
		    pre_selected = true;
		} else {
		    pre_selected = false;
		}
	    } else {
		pre_selected = false;
	    }
	    if (pre_selected) pre_selected_languages = add (pre_selected_languages,
		sformat ("%1 (%2)", short, long)
	    );
	    items = add (items, `item (`id (short), long, pre_selected));
	});
	y2milestone ("Preselected languages: %1", pre_selected_languages);
	
	items = sort (term x, term y, items, ``(x[1]:"" < y[1]:""));
	Wizard::SetContentsButtons(
	    // TRANSLATORS: dialog caption
	    _("Add-On Product Installation"),
	    `VBox (
		`HBox (
		    `HStretch (),
		    `MultiSelectionBox (
			`id ("languages"),
			// TRANSLATORS:: multi-selection box
			_("&Select Language Extensions to be Installed"),
			items
		    ),
		    `HStretch ()
		)
	    ),
	    // TRANSLATORS: help text
	    _("<p>Select the language extensions to be installed and then click the <b>OK</b> button.</p>"),
	    Label::BackButton(),
	    Label::OKButton()
	);
	Wizard::SetTitleIcon("yast-language");
	Wizard::DisableBackButton();
	Wizard::EnableAbortButton();
	Wizard::EnableNextButton();
	
	list <string> selected_languages = nil;
	any ret = nil;
	while (true) {
	    ret = UI::UserInput();
	    
	    if (ret == `cancel || ret == `abort) {
		if (Popup::YesNo(
		    // TRANSLATORS: popup question
		    _("Are you sure you want to abort the add-on product installation?")
		)) {
		    selected_languages = [];
		    break;
		}
	    } else if (ret == `next) {
		selected_languages = (list <string>) UI::QueryWidget(`id ("languages"), `SelectedItems);
		if (size (selected_languages) == 0) {
		    if (! Popup::YesNo (
			_("There are no selected languages to be installed.
Are you sure you want to abort the installation?")
		    )) {
			continue;
		    } else {
			y2warning ("User decided not to install any language support.");
		    }
		}
		
		break;
	    }
	}
	
	return selected_languages;
    }
    
    list <string> Dialog_SelectLanguages (
	list <string> available_languages,
	list <string> & already_installed_languages
    ) {
	if (available_languages == nil || available_languages == []) {
	    y2error ("No availabel languages");
	    return nil;
	} else if (size (available_languages) == 1) {
	    y2milestone ("Only one language available, using %1", available_languages);
	    return available_languages;
	} else {
	    map <string, list> known_languages = Language::GetLanguagesMap(false);
	    
	    map <string, string> short_to_lang = $[];
	    foreach (string one_lang, available_languages, {
		// full xx_YY
		if (known_languages[one_lang]:nil != nil) {
		    short_to_lang[one_lang] = known_languages[one_lang,4]:"";
		// xx only without _YY
		} else {
		    boolean found = false;
		    foreach (string lang_short, list lang_params, known_languages, {
			if (regexpmatch(lang_short, sformat("%1_.*", one_lang))) {
			    short_to_lang[one_lang] = tostring(lang_params[4]:"");
			    found = true;
			    break;
			}
		    });
		    if (! found) {
			y2warning ("Couldn't find language for '%1'", one_lang);
			// TRANSLATORS: multiselection box item, %1 stands for 'ar', 'mk', 'zh_TW'
			// it used only as a fallback
			short_to_lang[one_lang] = sformat (_("Language %1"), one_lang);
		    }
		}
	    });

	    y2milestone("%1", short_to_lang);
	    list <string> selected_languages = Dialog_SelectLanguagesUI (short_to_lang, already_installed_languages);
	    
	    return selected_languages;
	}
    }
    
    // Dialog definitions <--
    
    integer MainFunction () {
	Dialog_Init ();

	// This call can be removed
	InitFunction ();

	// Finding out the source, can be also used AddOnProduct::src_id
	// but this is better for testing
	list <integer> all_sources = Pkg::SourceGetCurrent (true);
	all_sources = sort (integer x, integer y, all_sources, ``(x < y));
	integer source = all_sources[size(all_sources) - 1]:-1;
	Pkg::SourceSetEnabled (source, true);
    
	// one language   -> preselect it and install
	// more languages -> let user decides
	list <string> available_languages = GetListOfSupportedLanguages (source);
	if (available_languages == nil || available_languages == []) {
	    y2error ("No languages available!");
	    return 10;
	}
	
	// bugzilla #217052
	// some languages should be pre-selected (already installed, at least partly)
	list <map <string, any> > installed_languages = Pkg::ResolvableProperties("", `language, "");
	list <string> already_installed_languages = [];
	foreach (map <string, any> language, installed_languages, {
	    if (language["status"]:nil == `installed) {
		if (language["name"]:nil != nil) {
		    already_installed_languages = add (already_installed_languages, language["name"]:"");
		} else {
		    y2error ("Language %1 has no 'name'", language);
		}
	    }
	});

	y2milestone ("Already installed languages: %1", already_installed_languages);
	list <string> selected_languages = Dialog_SelectLanguages (available_languages, already_installed_languages);
	if (selected_languages == nil || selected_languages == []) {
	    y2warning("User did not select any language, finishing...");
	    return 15;
	}

	if (Install (selected_languages) != true) {
	    y2error("Error occured during installation");
	    return 20;
	}
	
	return 0;
    }
    
    Wizard::CreateDialog();
    y2milestone("====================[ Language Add-On Script ]====================");
    integer ret = MainFunction ();
    y2milestone("====================[ Language Add-On Script ]====================");
    Wizard::CloseDialog();

    if (ret == 0) {
	return `next;
    } else {
	return `abort;
    }
}

ACC SHELL 2018