[yast-commit] r50558 - in /trunk/packager: package/ src/clients/ src/modules/
Author: visnov Date: Tue Sep 2 11:23:10 2008 New Revision: 50558 URL: http://svn.opensuse.org/viewcvs/yast?rev=50558&view=rev Log: Unified progress during installation Added: trunk/packager/src/modules/PackageSlideShow.ycp trunk/packager/src/modules/Slides.ycp Modified: trunk/packager/package/yast2-packager.changes trunk/packager/src/clients/inst_rpmcopy.ycp trunk/packager/src/clients/sw_single.ycp trunk/packager/src/modules/PackageInstallation.ycp trunk/packager/src/modules/Packages.ycp trunk/packager/src/modules/SlideShow.ycp trunk/packager/src/modules/SlideShowCallbacks.ycp Modified: trunk/packager/package/yast2-packager.changes URL: http://svn.opensuse.org/viewcvs/yast/trunk/packager/package/yast2-packager.changes?rev=50558&r1=50557&r2=50558&view=diff ============================================================================== --- trunk/packager/package/yast2-packager.changes (original) +++ trunk/packager/package/yast2-packager.changes Tue Sep 2 11:23:10 2008 @@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Tue Sep 2 11:11:56 CEST 2008 - visnov@suse.cz + +- Use unified progress bar during installation (FATE #303860) + +------------------------------------------------------------------- Wed Aug 27 13:28:07 CEST 2008 - locilka@suse.cz - Initializing installation URL got from install.inf (RepoURL) Modified: trunk/packager/src/clients/inst_rpmcopy.ycp URL: http://svn.opensuse.org/viewcvs/yast/trunk/packager/src/clients/inst_rpmcopy.ycp?rev=50558&r1=50557&r2=50558&view=diff ============================================================================== --- trunk/packager/src/clients/inst_rpmcopy.ycp (original) +++ trunk/packager/src/clients/inst_rpmcopy.ycp Tue Sep 2 11:23:10 2008 @@ -27,6 +27,7 @@ import "PackageInstallation"; import "Packages"; import "SlideShow"; + import "PackageSlideShow"; import "SlideShowCallbacks"; import "Popup"; import "Report"; @@ -661,7 +662,7 @@ } list<string> failed = []; - list<string> patterns = AutoinstData::post_patterns; + list<string> patterns = []; // WORKAROUND, REMOVE!!! AutoinstData::post_patterns; /* set SoftLock to avoid the installation of recommended patterns (#159466) */ foreach( map<string,any> p, Pkg::ResolvableProperties ("", `pattern, ""), ``{ Pkg::ResolvableSetSoftLock( p["name"]:"", `pattern ); @@ -871,9 +872,10 @@ // initialize the package agent in continue mode Packages::Init( true ); RestoreDiskCacheSettings (); - } - SlideShow::OpenSlideShowDialog (); + // in 1st stage, this is opened already + SlideShow::OpenDialog (); + } Pkg::TargetLogfile (Installation::destdir + Directory::logdir + "/y2logRPM"); @@ -899,6 +901,13 @@ integer maxnumbercds = cdnumbers["maxnumbercds"]:10; integer current_cd_no = cdnumbers["current_cd_no"]:1; + // re-initialize package information + PackageSlideShow::InitPkgData(true); + // we want the table + SlideShow::ShowTable(); + // move the progress to the packages stage + SlideShow::MoveToStage("packages"); + // install packages from CD current_cd_no to CD maxnumbercds symbol result = InstallPackagesFromMedia (current_cd_no, maxnumbercds); @@ -909,7 +918,7 @@ Pkg::PkgCommit (9999); } - SlideShow::CloseSlideShowDialog(); + SlideShow::CloseDialog(); if (result != `abort) { Modified: trunk/packager/src/clients/sw_single.ycp URL: http://svn.opensuse.org/viewcvs/yast/trunk/packager/src/clients/sw_single.ycp?rev=50558&r1=50557&r2=50558&view=diff ============================================================================== --- trunk/packager/src/clients/sw_single.ycp (original) +++ trunk/packager/src/clients/sw_single.ycp Tue Sep 2 11:23:10 2008 @@ -528,6 +528,19 @@ SlideShow::InitPkgData(true); // force reinitialization SlideShow::OpenSlideShowDialog(); + list< map<string,any> > stages = [ + $[ + "name" : "packages", + "description": _("Installing Packages..."), + "value" : SlideShow::total_size_to_install / 1024 , // kilobytes + "units" : `kb, + ], + ]; + + SlideShow::Setup( stages ); + + SlideShow::MoveToStage( "packages" ); + import "PackageInstallation"; Pkg::TargetLogfile (Installation::destdir + Directory::logdir + "/y2logRPM"); integer oldvmlinuzsize = (integer) SCR::Read(.target.size, "/boot/vmlinuz"); Modified: trunk/packager/src/modules/PackageInstallation.ycp URL: http://svn.opensuse.org/viewcvs/yast/trunk/packager/src/modules/PackageInstallation.ycp?rev=50558&r1=50557&r2=50558&view=diff ============================================================================== --- trunk/packager/src/modules/PackageInstallation.ycp (original) +++ trunk/packager/src/modules/PackageInstallation.ycp Tue Sep 2 11:23:10 2008 @@ -16,6 +16,7 @@ import "Directory"; import "Packages"; import "SlideShow"; + import "PackageSlideShow"; import "Label"; @@ -100,7 +101,7 @@ list <integer> sources = Pkg::SourceGetCurrent (false); integer source_id = sources[0]:0; - SlideShow::InitPkgData(false); + PackageSlideShow::InitPkgData(false); // structure: [ ["source_name", id] ] list< list > src_list = Pkg::PkgMediaNames(); @@ -112,13 +113,13 @@ if (media_number == 0) { - SlideShow::SetCurrentCdNo (first_source, 1); + PackageSlideShow::SetCurrentCdNo (first_source, 1); } else { - SlideShow::SetCurrentCdNo (first_source, media_number); + PackageSlideShow::SetCurrentCdNo (first_source, media_number); } - SlideShow::UpdateAllCdProgress (false); + PackageSlideShow::UpdateAllCdProgress (false); SlideShow::StartTimer(); boolean do_commit = true; Added: trunk/packager/src/modules/PackageSlideShow.ycp URL: http://svn.opensuse.org/viewcvs/yast/trunk/packager/src/modules/PackageSlideShow.ycp?rev=50558&view=auto ============================================================================== --- trunk/packager/src/modules/PackageSlideShow.ycp (added) +++ trunk/packager/src/modules/PackageSlideShow.ycp Tue Sep 2 11:23:10 2008 @@ -0,0 +1,1113 @@ +/** + * Module: PackageSlideShow.ycp + * + * Purpose: Module to access slides from installation repository + * + * Author: Stefan Hundhammer <sh@suse.de> + * Stanislav Visnovsky <visnov@suse.cz> + * + */ +{ + module "PackageSlideShow"; + + textdomain "packager"; + + import "Slides"; + import "SlideShow"; + import "String"; + + global list<list<integer> > total_sizes_per_cd_per_src = []; // total sizes per inst-src: [ [42, 43, 44], [12, 13, 14] ] + global list<list<integer> > remaining_sizes_per_cd_per_src = []; // remaining sizes + global list<list<integer> > remaining_times_per_cd_per_src = []; // remaining times + global list<string> inst_src_names = []; // a list of strings identifying each repository + global list<list<integer> > total_pkg_count_per_cd_per_src = []; // number of pkgs per inst-src: [ [7, 5, 3], [2, 3, 4] ] + global list<list<integer> > remaining_pkg_count_per_cd_per_src = []; // remaining number of pkgs + global map<integer,integer> srcid_to_current_src_no = $[]; + // the string is follwed by a media number, e.g. "Medium 1" + global string media_type = _("Medium"); + global integer total_size_installed = 0; + global integer total_size_to_install = 0; + global integer min_time_per_cd = 10; // const - minimum time displayed per CD if there is something to install + global integer max_time_per_cd = 7200; // const - seconds to cut off predicted time (it's bogus anyway) + global integer size_column = 1; // const - column number for remaining size per CD + global integer pkg_count_column = 2; // const - column number for remaining number of packages per CD + global integer time_column = 3; // const - column number for remaining time per CD + global integer current_src_no = -1; // 1..n + global integer current_cd_no = -1; // 1..n + global integer next_src_no = -1; + global integer next_cd_no = -1; + global boolean last_cd = false; + global integer total_cd_count = 0; + global boolean unit_is_seconds = false; // begin with package sizes + global integer bytes_per_second = 1; + global boolean init_pkg_data_complete = false; + + boolean debug = false; // more debugging info + string provide_name = ""; // currently downlaoded package name + string provide_size = ""; // currently downlaoded package size + + +/*****************************************************************************/ +/*************** Formatting functions and helpers ***************************/ +/*****************************************************************************/ + + /** + * Get version info for a package (without build no.) + * + * @param pkg_name name of the package without path and ".rpm" extension + * @return version string + **/ + global string StripReleaseNo( string pkg_name ) + { + integer build_no_pos = findlastof (pkg_name, "-" ); // find trailing build no. + + if ( build_no_pos != nil && build_no_pos > 0 ) + { + // cut off trailing build no. + pkg_name = substring( pkg_name , 0, build_no_pos ); + } + + return pkg_name; + } + + /** + * Get package file name from path + * + * @param pkg_name location of the package + * @return string package file name + **/ + global string StripPath(string pkg_name) + { + if (pkg_name == nil) + { + return nil; + } + + integer file_pos = findlastof(pkg_name, "/"); + + if (file_pos != nil && file_pos > 0 ) + { + // return just the file name + pkg_name = substring(pkg_name, file_pos + 1); + } + + return pkg_name; + } + + + /** + * set media type "CD" or "DVD" + */ + global void SetMediaType (string new_media_type) + { + media_type = new_media_type; + } + + /** + * Sum up all list items + **/ + integer ListSum( list<integer> sizes ) + { + integer sum = 0; + + foreach( integer item, sizes, ``{ + if ( item != -1 ) + sum = sum + item; + }); + + return sum; + } + + + /** + * Sum up all positive list items, but cut off individual items at a maximum value. + * Negative return values indicate overflow of any individual item at "max_cutoff". + * In this case, the real sum is the absolute value of the return value. + **/ + integer ListSumCutOff( list<integer> sizes, integer max_cutoff ) + { + boolean overflow = false; + integer sum = 0; + + foreach( integer item, sizes, ``{ + if ( item > 0 ) + { + if ( item > max_cutoff ) + { + overflow = true; + sum = sum + max_cutoff; + } + else + sum = sum + item; + } + }); + + if ( overflow ) + sum = -sum; + + return sum; + } + + + integer TotalRemainingSize() + { + return ListSum( flatten( remaining_sizes_per_cd_per_src ) ); + } + + + integer TotalRemainingTime() + { + return ListSumCutOff( flatten( remaining_times_per_cd_per_src ), + max_time_per_cd ); + } + + + integer TotalRemainingPkgCount() + { + return ListSum( flatten( remaining_pkg_count_per_cd_per_src ) ); + } + + + integer TotalInstalledSize() + { + return total_size_to_install - TotalRemainingSize(); + } + + + /** + * Format an integer number as (at least) two digits; use leading zeroes if + * necessary. + * @return number as two-digit string + **/ + string FormatTwoDigits( integer x ) + { + return x < 10 && x >= 0 ? + sformat( "0%1", x ) : + sformat( "%1", x ); + } + + + /** + * Format an integer seconds value with min:sec or hours:min:sec + **/ + string FormatTime( integer seconds ) + { + if ( seconds < 0 ) + return ""; + + if ( seconds < 3600 ) // Less than one hour + { + return sformat( "%1:%2", FormatTwoDigits( seconds / 60 ), FormatTwoDigits( seconds % 60 ) ); + } + else // More than one hour - we don't hope this will ever happen, but who knows? + { + integer hours = seconds / 3600; + seconds = seconds % 3600; + return sformat( "%1:%2:%3", hours, FormatTwoDigits( seconds / 60 ), FormatTwoDigits( seconds % 60 ) ); + } + } + + + /** + * Format an integer seconds value with min:sec or hours:min:sec + * + * Negative values are interpreted as overflow - ">" is prepended and the + * absolute value is used. + **/ + string FormatTimeShowOverflow( integer seconds ) + { + string text = ""; + + if ( seconds < 0 ) // Overflow (indicated by negative value) + { + // When data throughput goes downhill (stalled network connection etc.), + // cut off the predicted time at a reasonable maximum. + // "%1" is a predefined maximum time. + + text = sformat( _(">%1"), FormatTime( -seconds ) ); + } + else + { + text = FormatTime( seconds ); + } + + return text; + } + + + /** + * Format number of remaining bytes to be installed as string. + * @param remaining bytes remaining, -1 for 'done' + * @return string human readable remaining time or byte / kB/ MB size + **/ + string FormatRemainingSize( integer remaining ) + { + if ( remaining < 0 ) + { + // Nothing more to install from this CD (very concise - little space!!) + return _("Done."); + } + if ( remaining == 0 ) + { + return ""; + } + + return String::FormatSize( remaining ); + } + + + /** + * Format number of remaining packages to be installed as string. + * @param remaining bytes remaining, -1 for 'done' + * @return string human readable remaining time or byte / kB/ MB size + **/ + string FormatRemainingCount( integer remaining ) + { + if ( remaining < 0 ) + { + // Nothing more to install from this CD (very concise - little space!!) + return _("Done."); + } + if ( remaining == 0 ) + { + return ""; + } + + return sformat( "%1", remaining ); + } + + + string FormatNextMedia() + { + string text = ""; + + if ( next_src_no >= 0 && next_cd_no >= 0 ) + { + string next_media_name = sformat( "%1 %2 %3", + inst_src_names[ next_src_no ]:"", + media_type, next_cd_no+1 ); + + if ( unit_is_seconds ) + { + // Status line informing about the next CD that will be used + // %1: Media type ("CD" / "DVD", ???) + // %2: Media name ("SuSE Linux Professional CD 2" ) + // %3: Time remaining until this media will be needed + text = sformat( _("Next %1: %2 -- %3"), media_type, next_media_name, + FormatTime( remaining_times_per_cd_per_src[ current_src_no-1, current_cd_no-1 ]: 1) ); + } + else + { + // Status line informing about the next CD that will be used + // %1: Media type ("CD" / "DVD", ???) + // %2: Media name ("SuSE Linux Professional CD 2" ) + text = sformat( _("Next %1: %2"), media_type, next_media_name ); + } + } + + return text; + } + +/*****************************************************************************/ +/*********************** Computing Helpers **********************************/ +/*****************************************************************************/ + + + /** + * Perform sanity check for correct initialzation etc. + * @param silent don't complain in log file + * @return true if OK, false if any error + **/ + boolean SanityCheck( boolean silent ) + { + return true; // FIXME! + if ( ! init_pkg_data_complete ) + { + if ( ! silent ) + { + y2error( "SlideShow::SanityCheck(): Slide show not correctly initialized: " + + "SlideShow::InitPkgData() never called!" ); + } + return false; + } + + if ( current_src_no < 1 || current_cd_no < 1 ) + { + // nothing to install but something is going to be deleted, so it's OK + if (Pkg::IsAnyResolvable(`package, `to_remove)) + { + return true; + } + else if (!silent) + { + y2error(-1, "SlideShow::SanityCheck(): Illegal values for current_src (%1) or current_cd (%2)", + current_src_no, current_cd_no ); + y2milestone( "total sizes: %1", total_sizes_per_cd_per_src ); + } + return false; + } + + return true; + } + + /** + * Update internal bookkeeping: subtract size of one package from the + * global list of remaining sizes per CD + **/ + void SubtractPackageSize( integer pkg_size ) + { + integer remaining = remaining_sizes_per_cd_per_src [ current_src_no-1, current_cd_no-1 ]: 1; + remaining = remaining - pkg_size; + total_size_installed = total_size_installed + pkg_size; + + if ( remaining <= 0 ) + { + // -1 is the indicator for "done with this CD" - not to be + // confused with 0 for "nothing to install from this CD". + remaining = -1; + } + + remaining_sizes_per_cd_per_src [ current_src_no-1, current_cd_no-1 ] = remaining; + remaining_pkg_count_per_cd_per_src [ current_src_no-1, current_cd_no-1 ] = + remaining_pkg_count_per_cd_per_src [ current_src_no-1, current_cd_no-1 ]:0 -1; + + if ( unit_is_seconds ) + { + integer seconds = 0; + + if ( remaining > 0 && bytes_per_second > 0 ) + seconds = remaining / bytes_per_second; + + remaining_times_per_cd_per_src [ current_src_no-1, current_cd_no-1 ] = seconds; + } + + if ( debug ) + y2milestone( "SubtractPackageSize( %1 ) -> %2", pkg_size, remaining_sizes_per_cd_per_src); + } + + + /** + * Initialize internal pacakge data, such as remaining package sizes and + * times. This may not be called before the pkginfo server is up and + * running, so this cannot be reliably done from the constructor in all + * cases. + * @param force true to force reinitialization + **/ + global void InitPkgData(boolean force) + { + if ( init_pkg_data_complete && ! force) + return; + + // Reinititalize some globals (in case this is a second run) + total_size_installed = 0; + //total_time_elapsed = 0; + //start_time = -1; + current_src_no = -1; // 1..n + current_cd_no = -1; // 1..n + next_src_no = -1; + next_cd_no = -1; + last_cd = false; + unit_is_seconds = false; // begin with package sizes + bytes_per_second = 1; + + list< list > src_list = Pkg::PkgMediaNames(); + inst_src_names = maplist( list src, src_list, ``(src[0]:"CD") ); + + y2milestone ("Media names: %1", inst_src_names); + + integer index = 0; + + srcid_to_current_src_no = listmap( list src, src_list, { + index = index + 1; + return $[src[1]:-1 : index]; + }); + + y2milestone ("Repository mapping information: %1", srcid_to_current_src_no ); + + total_sizes_per_cd_per_src = Pkg::PkgMediaSizes(); + total_pkg_count_per_cd_per_src = Pkg::PkgMediaCount(); + + + total_size_to_install = ListSum( flatten( total_sizes_per_cd_per_src ) ); + y2milestone("total_size_to_install: %1", total_size_to_install); + remaining_sizes_per_cd_per_src = (list<list <integer> >) eval (total_sizes_per_cd_per_src); + remaining_pkg_count_per_cd_per_src = (list<list <integer> >) eval (total_pkg_count_per_cd_per_src); + total_cd_count = size( flatten( total_sizes_per_cd_per_src ) ); + init_pkg_data_complete = true; + + y2milestone( "SlideShow::InitPkgData() done; total_sizes_per_cd_per_src: %1", total_sizes_per_cd_per_src ); + y2milestone( "SlideShow::InitPkgData(): pkg: %1", total_pkg_count_per_cd_per_src ); + + // RebuildDialog(true); + } + + /** + * Try to figure out what media will be needed next + * and set next_src_no and next_cd_no accordingly. + **/ + void FindNextMedia() + { + // Normally we would have to use current_cd_no+1, + // but since this uses 1..n and we need 0..n-1 + // for array subscripts anyway, use it as it is. + next_cd_no = current_cd_no; + next_src_no = current_src_no-1; + last_cd = false; + + while ( next_src_no < size( remaining_sizes_per_cd_per_src ) ) + { + list<integer> remaining_sizes = remaining_sizes_per_cd_per_src[ next_src_no ]: []; + + while ( next_cd_no < size( remaining_sizes ) ) + { + if ( remaining_sizes[ next_cd_no ]:0 > 0 ) + { + if ( debug ) + y2milestone( "Next media: src: %1 CD: %2", next_src_no, next_cd_no ); + return; + } + else + { + next_cd_no = next_cd_no + 1; + } + } + + next_src_no = next_src_no + 1; + } + + if ( debug ) + y2milestone( "No next media - all done" ); + + next_src_no = -1; + next_cd_no = -1; + last_cd = true; + } + + + /** + * Set the current repository and CD number. Must be called for each CD change. + * src_no: 1...n + * cd_no: 1...n + **/ + global void SetCurrentCdNo( integer src_no, integer cd_no ) + { + if (cd_no == 0) + { + y2milestone("medium number 0, using medium number 1"); + cd_no = 1; + } + + y2milestone("SetCurrentCdNo() - src: %1 , CD: %2", src_no, cd_no); + current_src_no = srcid_to_current_src_no[src_no]:-1; + current_cd_no = cd_no; + + SlideShow::CheckForSlides(); + FindNextMedia(); + + if ( Slides::HaveSlides() && Slides::HaveSlideSupport() ) + { + if ( ! SlideShow::HaveSlideWidget() ) + { + SlideShow::RebuildDialog(); + + if ( SlideShow::user_switched_to_details ) + SlideShow::SwitchToDetailsView(); + } + + if ( ! SlideShow::user_switched_to_details ) // Don't override explicit user request! + { + SlideShow::SwitchToSlideView(); + } + } + else + { + if ( ! SlideShow::ShowingDetails() ) + SlideShow::RebuildDialog(); + } + } + + + + /** + * Recalculate remaining times per CD based on package sizes remaining + * and data rate so far. Recalculation is only done each 'recalc_interval' + * seconds unless 'force_recalc' is set to 'true'. + * + * @param force_recalc force recalculation even if timeout not reached yet + * @return true if recalculated, false if not + **/ + boolean RecalcRemainingTimes( boolean force_recalc ) + { + if ( ! force_recalc + && time() < SlideShow::next_recalc_time ) + { + // Nothing to do (yet) - simply return + return false; + } + + + // Actually do recalculation + + integer elapsed = SlideShow::total_time_elapsed; + + if ( SlideShow::start_time >= 0 ) + { + elapsed = elapsed + time() - SlideShow::start_time; + } + + if ( elapsed == 0 ) + { + // Called too early - no calculation possible yet. + // This happens regularly during initialization, so an error + // message wouldn't be a good idea here. + + return false; + } + + // This is the real thing. + + integer real_bytes_per_second = total_size_installed / elapsed; + + // But this turns out to be way to optimistic - RPM gets slower and + // slower while installing. So let's add some safety margin to make + // sure initial estimates are on the pessimistic side - the + // installation being faster than initially estimated will be a + // pleasant surprise to the user. Most users don't like it the other + // way round. + // + // The "pessimistic factor" progressively decreases as the installation + // proceeds. It begins with about 1.7, i.e. the data transfer rate is + // halved to what it looks like initially. It decreases to 1.0 towards + // the end. + + float pessimistic_factor = 1.0; + + if ( total_size_to_install > 0 ) + pessimistic_factor = 1.7 - tofloat( total_size_installed ) / tofloat( total_size_to_install ); + bytes_per_second = tointeger( tofloat( real_bytes_per_second ) / pessimistic_factor + 0.5 ); + + if ( bytes_per_second < 1 ) + bytes_per_second = 1; + + remaining_times_per_cd_per_src = []; + + // Recalculate remaining times for the individual CDs + + foreach ( list<integer> remaining_sizes_list, remaining_sizes_per_cd_per_src, + ``{ + list<integer> remaining_times_list = []; + integer remaining_time = -1; + + foreach ( integer remaining_size, remaining_sizes_list, + ``{ + remaining_time = remaining_size; + + if ( remaining_size > 0 ) + { + remaining_time = remaining_size / bytes_per_second; + + if ( remaining_time < min_time_per_cd ) + { + // It takes at least this long for the CD drive to spin up and + // for RPM to do _anything_. Times below this values are + // ridiculously unrealistic. + remaining_time = min_time_per_cd; + } + else if ( remaining_time > max_time_per_cd ) // clip off at 2 hours + { + // When data throughput goes downhill (stalled network connection etc.), + // cut off the predicted time at a reasonable maximum. + remaining_time = max_time_per_cd; + } + } + remaining_times_list = add( remaining_times_list, remaining_time ); + }); + + remaining_times_per_cd_per_src = add( remaining_times_per_cd_per_src, remaining_times_list ); + }); + + + // Recalculate slide interval + + if ( Slides::HaveSlides() ) + { + integer slides_remaining = size( Slides::slides ) - SlideShow::current_slide_no - 1; + + if ( slides_remaining > 0 ) + { + // The remaining time for the rest of the slides depends on the + // remaining time for the current CD only: This is where the + // slide images and texts reside. Normally, only CD1 has slides + // at all, i.e. the slide show must be finished when CD1 is + // done. + // + // In addition to that, take elapsed time for current slide + // into account so all slides get about the same time. + + integer time_remaining = remaining_times_per_cd_per_src[current_src_no-1, current_cd_no-1]:1 + time() - SlideShow::slide_start_time; + SlideShow::slide_interval = time_remaining / slides_remaining; + y2debug( "New slide interval: %1 - slides remaining: %2 - remaining time: %3", + SlideShow::slide_interval, slides_remaining, time_remaining ); + + if ( SlideShow::slide_interval < SlideShow::slide_min_interval ) + { + SlideShow::slide_interval = SlideShow::slide_min_interval; + y2debug( "Resetting slide interval to min slide interval: %1", SlideShow::slide_interval ); + } + + if ( SlideShow::slide_interval > SlideShow::slide_max_interval ) + { + SlideShow::slide_interval = SlideShow::slide_max_interval; + y2debug( "Resetting slide interval to max slide interval: %1", SlideShow::slide_interval ); + } + } + } + + SlideShow::next_recalc_time = time() + SlideShow::recalc_interval; + + return true; + } + + /** + * Switch unit to seconds if necessary and recalc everything accordingly. + * @return true if just switched from sizes to seconds, false otherwise + **/ + boolean SwitchToSecondsIfNecessary() + { + if ( unit_is_seconds + || time() < SlideShow::start_time + SlideShow::initial_recalc_delay ) + { + return false; // no need to switch + } + + RecalcRemainingTimes( true ); // force recalculation + unit_is_seconds = true; + + return true; // just switched + } + + + +/*****************************************************************************/ +/****************** Callbacks and progress bars *****************************/ +/*****************************************************************************/ + + + + /** + * Update progress widgets for the current CD: Label and ProgressBar. + * Use global statistics variables for that. + **/ + global void UpdateCurrentCdProgress(boolean silent_check) + { + if ( ! SanityCheck( silent_check ) ) return; + if ( ! UI::WidgetExists(`cdStatisticsTable) ) return; + + + // + // Update table entries for current CD + // + + integer remaining = remaining_sizes_per_cd_per_src [ current_src_no-1, current_cd_no-1 ]:0; + UI::ChangeWidget(`id(`cdStatisticsTable ), + `Item( sformat( "cd(%1,%2)", current_src_no-1, current_cd_no-1), size_column ), + FormatRemainingSize( remaining ) ); + + UI::ChangeWidget(`id(`cdStatisticsTable ), + `Item( sformat( "cd(%1,%2)", current_src_no-1, current_cd_no-1), pkg_count_column ), + FormatRemainingCount( remaining_pkg_count_per_cd_per_src [ current_src_no-1, current_cd_no-1 ]:0 ) ); + + if ( unit_is_seconds ) + { + // Convert 'remaining' from size (bytes) to time (seconds) + + remaining = remaining / bytes_per_second; + + if ( remaining <= 0 ) + remaining = 0; + + if ( remaining > max_time_per_cd ) // clip off at 2 hours + { + // When data throughput goes downhill (stalled network connection etc.), + // cut off the predicted time at a reasonable maximum. + remaining = -max_time_per_cd; + } + + UI::ChangeWidget(`id(`cdStatisticsTable ), + `Item( sformat( "cd(%1,%2)", current_src_no-1, current_cd_no-1), time_column ), + FormatTimeShowOverflow( remaining ) ); + } + + + // + // Update "total" table entries + // + + UI::ChangeWidget(`id( `cdStatisticsTable ), + `Item( "total", size_column ), + FormatRemainingSize( TotalRemainingSize() ) ); + + UI::ChangeWidget(`id( `cdStatisticsTable ), + `Item( "total", pkg_count_column ), + FormatRemainingCount( TotalRemainingPkgCount() ) ); + + if ( unit_is_seconds ) + { + UI::ChangeWidget(`id( `cdStatisticsTable ), `Item( "total", time_column ), + FormatTimeShowOverflow( TotalRemainingTime() ) ); + + } + } + + /** + * Update progress widgets + **/ + void UpdateTotalProgress(boolean silent_check) + { + SlideShow::StageProgress( ( TotalInstalledSize() >> 10 ) * 100 / ( total_size_to_install >> 10 ), nil /*, SlideShow::GetProgressLabel()*/ ); + + UpdateCurrentCdProgress(silent_check); + + if ( UI::WidgetExists(`nextMedia ) ) + { + string nextMedia = FormatNextMedia(); + + if ( nextMedia != "" || last_cd ) + { + UI::ChangeWidget(`nextMedia, `Value, nextMedia ); + UI::RecalcLayout(); + last_cd = false; + } + } + } + + + /** + * Returns a table widget item list for CD statistics + **/ + list<term> CdStatisticsTableItems() + { + list<term> itemList = []; + + // + // Add "Total" item - at the top so it is visible by default even if there are many items + // + + { + // List column header for total remaining MB and time to install + string caption = _("Total"); + integer remaining = TotalRemainingSize(); + string rem_size = FormatRemainingSize( remaining ); + string rem_count = FormatRemainingCount( TotalRemainingPkgCount() ); + string rem_time = ""; + + if ( unit_is_seconds && bytes_per_second > 0 ) + { + rem_time = FormatTimeShowOverflow( TotalRemainingTime() ); + } + + itemList = add( itemList, SlideShow::TableItem( "total", caption, " " + rem_size, " " + rem_count, " " + rem_time ) ); + } + + + // + // Now go through all repositories + // + + integer src_no = 0; + + foreach ( list<integer> inst_src, remaining_sizes_per_cd_per_src, ``{ + y2milestone( "src #%1: %2", src_no, inst_src ); + + if (ListSum(inst_src) > 0) // Ignore repositories from where there is nothing is to install + { + // Add heading for this repository + itemList = add( itemList, SlideShow::TableItem( sformat( "src(%1)", src_no ), + inst_src_names[ src_no ]:"", "", "", "" ) ); + + integer cd_no = 0; + + foreach ( integer remaining, inst_src, ``{ + if ( remaining > 0 + || ( src_no+1 == current_src_no && cd_no+1 == current_cd_no ) ) // suppress current CD + { + string caption = sformat( "%1 %2", media_type, cd_no+1 ); // "CD 1" - column #0 + string rem_size = FormatRemainingSize( remaining ); // column #1 + string rem_count = FormatRemainingCount( remaining_pkg_count_per_cd_per_src[ src_no, cd_no ]:0 ); + string rem_time = ""; + + if ( unit_is_seconds && bytes_per_second > 0 ) + { + remaining = remaining / bytes_per_second; + rem_time = FormatTime( remaining ); // column #2 + + if ( remaining > max_time_per_cd ) // clip off at 2 hours + { + // When data throughput goes downhill (stalled network connection etc.), + // cut off the predicted time at a reasonable maximum. + // "%1" is a predefined maximum time. + rem_time = FormatTimeShowOverflow( -max_time_per_cd ); + } + } + + itemList = add( itemList, + SlideShow::TableItem( sformat("cd(%1,%2)", src_no, cd_no ), // ID + caption, " " + rem_size, " " + rem_count, " " + rem_time ) ); + } + + cd_no = cd_no + 1; + }); + } + + src_no = src_no + 1; + }); + + if ( debug ) + { + y2milestone( "Remaining: %1", remaining_sizes_per_cd_per_src ); + y2milestone( "CD table item list:\n%1", itemList ); + } + + return itemList; + } + + + + /** + * Progress display update + * This is called via the packager's progress callbacks. + * + * @param pkg_percent package percentage + **/ + global void UpdateCurrentPackageProgress(integer pkg_percent) + { + SlideShow::SubProgress( pkg_percent, nil ); + } + + // update the download rate + global void UpdateCurrentPackageRateProgress(integer pkg_percent, integer bps_avg, integer bps_current) + { + if( ! SlideShow::ShowingDetails() ) return; + + string new_text = nil; // no update of the label + if (bps_current > 0) + { + // do not show the average download rate if the space is limited + if (SlideShow::textmode && SlideShow::display_width < 100) + { + bps_avg = -1; + } + new_text = String::FormatRateMessage(provide_name + " - %1", bps_avg, bps_current); + new_text = sformat(_("Downloading %1 (download size %2)"), new_text, provide_size); + } + + SlideShow::SubProgress( pkg_percent, new_text ); + } + + + /** + * Update progress widgets for all CDs. + * Uses global statistics variables. + **/ + global void UpdateAllCdProgress(boolean silent_check) + { + if ( ! SanityCheck( silent_check ) ) return; + + if ( unit_is_seconds ) + RecalcRemainingTimes( true ); // force + + SlideShow::UpdateTable( CdStatisticsTableItems() ); + } + + + /** + * Return a CD's progress bar ID + * @param src_no number of the repository (from 0 on) + * @param cd_no number of the CD within that repository (from 0 on) + **/ + string CdProgressId( integer src_no, integer cd_no ) + { + return sformat( "Src %1 CD %2", src_no, cd_no ); + } + + + /** + * package start display update + * - this is called at the end of a new package + * + * @param pkg_name package name + * @param deleting Flag: deleting (true) or installing (false) package? + **/ + global void SlideDisplayDone ( string pkg_name, + integer pkg_size, + boolean deleting ) + { + if ( ! deleting ) + { + SubtractPackageSize( pkg_size ); + + if (SwitchToSecondsIfNecessary() + || RecalcRemainingTimes( false ) ) // no forced recalculation + { + y2debug( "Updating progress for all CDs" ); + UpdateAllCdProgress(false); + } + else + { + UpdateCurrentCdProgress(false); + } + + UpdateTotalProgress(false); + + } // ! deleting + + } + + + + /** + * package start display update + * - this is called at the beginning of a new package + * + * @param pkg_name package name + * @param pkg_summary package summary (short description) + * @param deleting Flag: deleting (true) or installing (false) package? + **/ + global void SlideDisplayStart( string pkg_name, + string pkg_summary, + integer pkg_size, + boolean deleting ) + { + if ( ! SanityCheck( false ) ) return; + + // remove path + pkg_name = StripPath(pkg_name); + + // remove release and .rpm suffix + // pkg_name = StripReleaseNo( pkg_name ); // bug #154872 + + if ( deleting ) + { + pkg_size = -1; + + // This is a kind of misuse of insider knowledge: If there are packages to delete, this + // deletion comes first, and only then packages are installed. This, however, greatly + // distorts the estimated times based on data throughput so far: While packages are + // deleted, throughput is zero, and estimated times rise to infinity (they are cut off + // at max_time_per_cd to hide this). So we make sure the time spent deleting packages is + // not counted for estimating remaining times - reset the timer. + // + // Note: This will begin to fail when some day packages are deleted in the middle of the + // installaton process. + + SlideShow::ResetTimer(); + } + + if ( pkg_summary == nil ) + pkg_summary = ""; + + string msg = ""; + + if ( deleting ) + { + // Heading for the progress bar for the current package + // while it is deleted. "%1" is the package name. + msg = sformat( _("Deleting %1"), pkg_name ); + } + else + { + // package installation - summary text + // %1 is RPM name, %2 is installed (unpacked) size (e.g. 6.20MB) + msg = sformat( _("%1 (installed size %2)"), pkg_name, String::FormatSize( pkg_size ) ); + } + + + // + // Update package progress bar + // + SlideShow::SubProgress( 0, msg ); + + // Update global progress bar + string rem_string = ""; + integer tot_rem_t = TotalRemainingTime(); + + rem_string = ( unit_is_seconds && bytes_per_second > 0 && tot_rem_t > 0) ? + sformat("%1 / %2", FormatRemainingSize(TotalRemainingSize()), FormatTimeShowOverflow(tot_rem_t)) + : FormatRemainingSize(TotalRemainingSize()); + SlideShow::SetGlobalProgressLabel( SlideShow::CurrentStageDescription() + sformat(_(" (Remaining: %1)"), rem_string)); + + // + // Update (user visible) installation log + // + SlideShow::AppendMessageToInstLog( sformat( _("Installing %1"), msg) ); + + // + // Update the current slide if applicable + // + if ( SlideShow::ShowingSlide() ) + { + SlideShow::ChangeSlideIfNecessary(); + } + } + + + global void SlideGenericProvideStart (string pkg_name, integer sz, + string pattern, boolean remote) + { + if ( ! SanityCheck( false ) ) return; + if ( ! SlideShow::ShowingDetails() ) return; + + string provide_msg = ""; + + if (remote) + { + provide_name = pkg_name; + provide_size = String::FormatSize(sz); + + provide_msg = sformat(_("Downloading %1 (download size %2)"), provide_name, provide_size); + } + else + { + provide_msg = pkg_name; + } + + SlideShow::SubProgress( 0, provide_msg ); + + // + // Update (user visible) installation log + // for remote download only + // + + if( ! remote ) return; + + y2milestone( "Package '%1' is remote", pkg_name ); + + // message in the installatino log, %1 is package name, + // %2 is package size + SlideShow::AppendMessageToInstLog( sformat (pattern, pkg_name, String::FormatSize (sz)) ); + } + + global void SlideDeltaApplyStart (string pkg_name) { + if ( ! SanityCheck( false ) ) return; + if ( ! SlideShow::ShowingDetails() ) return; + + SlideShow::SubProgress( 0, pkg_name ); + + SlideShow::AppendMessageToInstLog( sformat (_("Applying delta RPM: %1"), pkg_name) ); + } + + + /** + * Package providal start + */ + global void SlideProvideStart (string pkg_name, integer sz, boolean remote) + { + // message in the installatino log, %1 is package name, + // %2 is package size + SlideGenericProvideStart (pkg_name, sz, _("Downloading %1 (download size %2)"), + remote); + } + + + +} Modified: trunk/packager/src/modules/Packages.ycp URL: http://svn.opensuse.org/viewcvs/yast/trunk/packager/src/modules/Packages.ycp?rev=50558&r1=50557&r2=50558&view=diff ============================================================================== --- trunk/packager/src/modules/Packages.ycp (original) +++ trunk/packager/src/modules/Packages.ycp Tue Sep 2 11:23:10 2008 @@ -25,6 +25,7 @@ import "ProductFeatures"; import "ProductControl"; import "Report"; +import "Slides"; import "SlideShow"; import "SpaceCalculation"; import "String"; @@ -1070,7 +1071,7 @@ // try to download only slides that are needed (by selected language) // no images are cached string search_for_dir = sformat ("/%1/setup/slide/", datadir); - FindAndCopySlideDirWithoutCallbacks(our_slidedir, source, search_for_dir, lang_long, lang_short, SlideShow::fallback_lang); + FindAndCopySlideDirWithoutCallbacks(our_slidedir, source, search_for_dir, lang_long, lang_short, Slides::fallback_lang); // fallback solution disabled /* @@ -1090,7 +1091,7 @@ */ y2milestone ("Setting up the slide directory local copy: %1", our_slidedir); - SlideShow::SetSlideDir (our_slidedir); + Slides::SetSlideDir (our_slidedir); if (load_release_notes (source)) { Modified: trunk/packager/src/modules/SlideShow.ycp URL: http://svn.opensuse.org/viewcvs/yast/trunk/packager/src/modules/SlideShow.ycp?rev=50558&r1=50557&r2=50558&view=diff ============================================================================== --- trunk/packager/src/modules/SlideShow.ycp (original) +++ trunk/packager/src/modules/SlideShow.ycp Tue Sep 2 11:23:10 2008 @@ -1,9 +1,10 @@ /** * Module: SlideShow.ycp * - * Purpose: Slide show during package installation + * Purpose: Slide show during installation * * Author: Stefan Hundhammer <sh@suse.de> + * Stanislav Visnovsky <visnov@suse.cz> * * $Id$ * @@ -20,104 +21,60 @@ import "String"; import "Wizard"; import "FileUtils"; + import "Mode"; + import "Popup"; + import "Slides"; - global list<list<integer> > total_sizes_per_cd_per_src = []; // total sizes per inst-src: [ [42, 43, 44], [12, 13, 14] ] - global list<list<integer> > remaining_sizes_per_cd_per_src = []; // remaining sizes - global list<list<integer> > remaining_times_per_cd_per_src = []; // remaining times - global list<string> inst_src_names = []; // a list of strings identifying each repository - global list<list<integer> > total_pkg_count_per_cd_per_src = []; // number of pkgs per inst-src: [ [7, 5, 3], [2, 3, 4] ] - global list<list<integer> > remaining_pkg_count_per_cd_per_src = []; // remaining number of pkgs - global map<integer,integer> srcid_to_current_src_no = $[]; - // the string is follwed by a media number, e.g. "Medium 1" - global string media_type = _("Medium"); - global integer total_size_installed = 0; - global integer total_size_to_install = 0; global integer total_time_elapsed = 0; global integer start_time = -1; global integer initial_recalc_delay = 60; // const - seconds before initially calculating remaining times global integer recalc_interval = 30; // const - seconds between "remaining time" recalculations - global integer min_time_per_cd = 10; // const - minimum time displayed per CD if there is something to install - global integer max_time_per_cd = 7200; // const - seconds to cut off predicted time (it's bogus anyway) - global integer size_column = 1; // const - column number for remaining size per CD - global integer pkg_count_column = 2; // const - column number for remaining number of packages per CD - global integer time_column = 3; // const - column number for remaining time per CD - global integer next_recalc_time = -1; - global integer current_src_no = -1; // 1..n - global integer current_cd_no = -1; // 1..n - global integer next_src_no = -1; - global integer next_cd_no = -1; - global boolean last_cd = false; - global integer total_cd_count = 0; - global boolean unit_is_seconds = false; // begin with package sizes - global integer bytes_per_second = 1; + global integer next_recalc_time = time(); global integer current_slide_no = 0; global integer slide_start_time = 0; global integer slide_min_interval = 30; // const - minimum seconds between slide changes global integer slide_max_interval = 3*60; // const - maximum seconds between slide changes - global string slide_base_path = Installation::sourcedir + "/suse/setup/slide"; - - global string slide_txt_path = ""; - global string slide_pic_path = ""; - global string fallback_lang = "en"; global integer slide_interval = slide_min_interval; - global list<string> slides = []; global string language = Language::language; - global boolean init_pkg_data_complete = false; global boolean widgets_created = false; global boolean user_switched_to_details = false; global boolean opened_own_wizard = false; global string inst_log = ""; global boolean debug = false; - boolean user_abort = false; + boolean user_abort = false; + + // we need to remember the values for tab switching + string total_progress_label = _("Installing..."); + string sub_progress_label = _("Installing..."); + integer total_progress_value = 0; + integer sub_progress_value =0; + list<term> table_items = []; + + boolean _show_table = false; // properties of the current UI - boolean textmode = nil; - integer display_width = nil; + global boolean textmode = UI::GetDisplayInfo()["TextMode"]:false; + global integer display_width = UI::GetDisplayInfo()["Width"]:0; global string relnotes = nil; + + global void ChangeSlideIfNecessary(); // forward declaration /** - * return the value of text_mode (true for ncurses) - */ - global boolean GetTextMode () { - - if (textmode == nil) - { - map display_info = UI::GetDisplayInfo (); - textmode = display_info["TextMode"]:false; - } - return textmode; - } - - /** - * return the value of screen width + * Set the flag that user requested abort of the installation + * @param abort new state of the abort requested flag (true = abort requested) */ - global integer GetDisplayWidth () { - - if (display_width == nil) - { - map display_info = UI::GetDisplayInfo (); - display_width = display_info["Width"]:0; - } - return display_width; - } - - /** - * Constructor - **/ - global void SlideShow() - { - y2milestone( "SlideShow constructor" ); - next_recalc_time = time(); - } - global void SetUserAbort(boolean abort) { user_abort = abort; } + /** + * Get the status of the flag that user requested abort of the installation + * @return boolean state of the abort requested flag (true = abort requested) + */ global boolean GetUserAbort() { return user_abort; @@ -161,12 +118,11 @@ total_time_elapsed % 60 ); // sec } - /** * Check if currently the "Details" page is shown * @return true if showing details, false otherwise **/ - boolean ShowingDetails() + global boolean ShowingDetails() { return widgets_created && UI::WidgetExists(`detailsPage ); } @@ -176,653 +132,164 @@ * Check if currently the "Slide Show" page is shown * @return true if showing details, false otherwise **/ - boolean ShowingSlide() + global boolean ShowingSlide() { - return widgets_created && UI::WidgetExists(`slidesPage ); + return widgets_created && UI::WidgetExists(`slideShowPage ); } /** * Check if currently the "Release Notes" page is shown * @return true if showing details, false otherwise **/ - boolean ShowingRelNotes() + global boolean ShowingRelNotes() { return widgets_created && UI::WidgetExists(`relNotesPage); } - - /** - * Sum up all list items - **/ - integer ListSum( list<integer> sizes ) - { - integer sum = 0; - - foreach( integer item, sizes, ``{ - if ( item != -1 ) - sum = sum + item; - }); - - return sum; - } - - - /** - * Sum up all positive list items, but cut off individual items at a maximum value. - * Negative return values indicate overflow of any individual item at "max_cutoff". - * In this case, the real sum is the absolute value of the return value. - **/ - integer ListSumCutOff( list<integer> sizes, integer max_cutoff ) - { - boolean overflow = false; - integer sum = 0; - - foreach( integer item, sizes, ``{ - if ( item > 0 ) - { - if ( item > max_cutoff ) - { - overflow = true; - sum = sum + max_cutoff; - } - else - sum = sum + item; - } - }); - - if ( overflow ) - sum = -sum; - - return sum; - } - - - integer TotalRemainingSize() - { - return ListSum( flatten( remaining_sizes_per_cd_per_src ) ); - } - - - integer TotalRemainingTime() - { - return ListSumCutOff( flatten( remaining_times_per_cd_per_src ), - max_time_per_cd ); - } - - - integer TotalRemainingPkgCount() - { - return ListSum( flatten( remaining_pkg_count_per_cd_per_src ) ); - } - - - integer TotalInstalledSize() - { - return total_size_to_install - TotalRemainingSize(); - } - - - /** - * Format an integer number as (at least) two digits; use leading zeroes if - * necessary. - * @return number as two-digit string - **/ - string FormatTwoDigits( integer x ) - { - return x < 10 && x >= 0 ? - sformat( "0%1", x ) : - sformat( "%1", x ); - } - - - /** - * Format an integer seconds value with min:sec or hours:min:sec - **/ - string FormatTime( integer seconds ) - { - if ( seconds < 0 ) - return ""; - - if ( seconds < 3600 ) // Less than one hour - { - return sformat( "%1:%2", FormatTwoDigits( seconds / 60 ), FormatTwoDigits( seconds % 60 ) ); - } - else // More than one hour - we don't hope this will ever happen, but who knows? - { - integer hours = seconds / 3600; - seconds = seconds % 3600; - return sformat( "%1:%2:%3", hours, FormatTwoDigits( seconds / 60 ), FormatTwoDigits( seconds % 60 ) ); - } - } - - - /** - * Format an integer seconds value with min:sec or hours:min:sec - * - * Negative values are interpreted as overflow - ">" is prepended and the - * absolute value is used. - **/ - string FormatTimeShowOverflow( integer seconds ) - { - string text = ""; - - if ( seconds < 0 ) // Overflow (indicated by negative value) - { - // When data throughput goes downhill (stalled network connection etc.), - // cut off the predicted time at a reasonable maximum. - // "%1" is a predefined maximum time. - - text = sformat( _(">%1"), FormatTime( -seconds ) ); - } - else - { - text = FormatTime( seconds ); - } - - return text; - } - - - /** - * Format number of remaining bytes to be installed as string. - * @param remaining bytes remaining, -1 for 'done' - * @return string human readable remaining time or byte / kB/ MB size - **/ - string FormatRemainingSize( integer remaining ) - { - if ( remaining < 0 ) - { - // Nothing more to install from this CD (very concise - little space!!) - return _("Done."); - } - if ( remaining == 0 ) - { - return ""; - } - - return String::FormatSize( remaining ); - } - - - /** - * Format number of remaining packages to be installed as string. - * @param remaining bytes remaining, -1 for 'done' - * @return string human readable remaining time or byte / kB/ MB size - **/ - string FormatRemainingCount( integer remaining ) - { - if ( remaining < 0 ) - { - // Nothing more to install from this CD (very concise - little space!!) - return _("Done."); - } - if ( remaining == 0 ) - { - return ""; - } - - return sformat( "%1", remaining ); - } - - - string FormatTotalRemaining() - { - // (Short!) headline for the total remaining time or MBs to install - return sformat( _("Remaining:\n%1"), - unit_is_seconds ? - FormatTimeShowOverflow( TotalRemainingTime() ) : - FormatRemainingSize( TotalRemainingSize() ) ); - } - - - string FormatNextMedia() - { - string text = ""; - - if ( next_src_no >= 0 && next_cd_no >= 0 ) - { - string next_media_name = sformat( "%1 %2 %3", - inst_src_names[ next_src_no ]:"", - media_type, next_cd_no+1 ); - - if ( unit_is_seconds ) - { - // Status line informing about the next CD that will be used - // %1: Media type ("CD" / "DVD", ???) - // %2: Media name ("SuSE Linux Professional CD 2" ) - // %3: Time remaining until this media will be needed - text = sformat( _("Next %1: %2 -- %3"), media_type, next_media_name, - FormatTime( remaining_times_per_cd_per_src[ current_src_no-1, current_cd_no-1 ]: 1) ); - } - else - { - // Status line informing about the next CD that will be used - // %1: Media type ("CD" / "DVD", ???) - // %2: Media name ("SuSE Linux Professional CD 2" ) - text = sformat( _("Next %1: %2"), media_type, next_media_name ); - } - } - - return text; - } - - - /** - * Normalize a CD size list like [ [ 111, 0, 333 ], [ 211, 222, 0 ] ] - * to a flat single list that doesn't contain any 0 items (but -1 if there are any) - * If the resulting list would be completely empty, use a simple fallback: [ 1 ] - **/ - list<integer> FlattenNoZeroes( list< list<integer> > sizesPerSourceList ) - { - list <integer> normalizedList = - filter( integer item, flatten( sizesPerSourceList ), - ``{ return item != 0; }); - - if ( size( normalizedList ) < 1 ) - normalizedList = [ 1 ]; - - return normalizedList; - } - - /** - * Get a list of available slides (images) for the slide show. - * @return list slides - **/ - list<string> GetSlideList( string lang ) - { - list<string> slide_list = nil; - - string txt_path = sformat( "%1/txt/%2", slide_base_path, lang ); - if (FileUtils::Exists (txt_path)) { - slide_list = (list<string>) SCR::Read (.target.dir, txt_path ); - } - - if ( slide_list == nil ) - { - y2debug( "Directory %1 does not exist", txt_path ); - if ( size( lang ) > 2 ) - { - lang = substring( lang, 0, 2 ); - txt_path = sformat( "%1/txt/%2", slide_base_path, lang ); - - if (FileUtils::Exists (txt_path)) { - slide_list = (list<string>) SCR::Read (.target.dir, txt_path ); - } - } - } - - if ( slide_list == nil ) - { - y2milestone( "Slideshow directory %1 does not exist", txt_path ); - } - else - { - y2milestone ("Using slides from '%1' (%2 slides)", txt_path, size (slide_list)); - - slide_list = sort( filter( string filename, slide_list, ``{ - // Check for valid extensions - ignore editor save files and other leftover stuff - return regexpmatch( filename, ".*\.(rtf|RTF|html|HTML|htm|HTM)$" ); - } ) ); - - y2debug( "GetSlideList(): Slides at %1: %2", txt_path, slide_list ); - } - - if ( slide_list != nil && size( slide_list ) > 0 ) // Slide texts found - { - slide_txt_path = txt_path; - slide_pic_path = slide_base_path + "/pic"; - - y2milestone ("Using TXT: %1, PIC: %2", slide_txt_path, slide_pic_path); - } - else // No slide texts found - { - y2debug( "No slides found at %1", txt_path ); - - // function calls itself! - if ( lang != fallback_lang ) - { - y2debug( "Trying to load slides from fallback: %1", fallback_lang ); - slide_list = GetSlideList( fallback_lang ); - } - } - - return slide_list; - } - - - /** - * Check if showing slides is supported. - * - * Not to be confused with HaveSlides() which checks if there are slides available. - **/ - boolean HaveSlideSupport() + * Restart the subprogress of the slideshow. This means the + * label will be set to \param text, value to 0. + * @param text new label for the subprogress + */ + global void SubProgressStart(string text) { - map disp = UI::GetDisplayInfo(); - - if (disp != nil // This shouldn't happen, but who knows? - && disp["HasImageSupport"]:false - && disp["DefaultWidth"]:-1 >= 800 - && disp["DefaultHeight"]:-1 >= 600 - && disp["Depth"]:-1 >= 8 ) - { - return true; - } - else + if ( UI::WidgetExists(`progressCurrentPackage ) ) { - return false; + UI::ChangeWidget(`progressCurrentPackage, `Value, 0); + UI::ChangeWidget(`progressCurrentPackage, `Label, text); } + + sub_progress_label = text; } - - - /** - * Check if slides are available. - * - * Not to be confused with HaveSlideSupport() which checks - * if slides could be displayed if there are any. - **/ - boolean HaveSlides() - { - return size( slides ) > 0; - } - - - /** - * Check if the dialog is currently set up so the user could switch to the slide page. - **/ - boolean HaveSlideWidget() - { - return UI::WidgetExists(`dumbTab); - } - - + /** - * Check if the slide show is available. This must be called before trying - * to access any slides; some late initialization is done here. - **/ - global void CheckForSlides() + * Update status of subprogress of the slideshow. The new value will be set + * to \param value, if the \text is not nil, the label will be updated + * to this text as well. Otherwise label will not change. + * @param value new value for the subprogress + * @param text new label for the subprogress + */ + global void SubProgress(integer value, string text) { - slides = []; - - map tmp = (map) WFM::Read(.local.stat, slide_base_path); - if (! tmp["isdir"]:false) + if( UI::WidgetExists( `progressCurrentPackage ) ) { - slide_base_path = "/var/adm/YaST/InstSrcManager/tmp/CurrentMedia/suse/setup/slide"; + UI::ChangeWidget(`progressCurrentPackage, `Value, value ); + if( text != nil ) + UI::ChangeWidget(`progressCurrentPackage, `Label, text ); } - - if ( debug && false ) - { - y2milestone( "Debug mode - using faster time recalc values" ); - initial_recalc_delay = 7; - recalc_interval = 5; - slide_min_interval = 5; - } - - - if ( Stage::initial () || Stage::cont () ) - { - if ( HaveSlideSupport() ) - { - y2milestone( "Display OK for slide show" ); - - slides = GetSlideList( language ); - } - else - { - y2warning( "Disabling slide show - insufficient display capabilities" ); - } - } - } - - - /** - * Set the slide show text. - * @param text - **/ - void SetSlideText( string text ) + + sub_progress_value = value; + if (text != nil) + sub_progress_label = text; + } + + /** + * Restart the global progress of the slideshow. This means the + * label will be set to \param text, value to 0. + * @param text new label for the global progress + */ + global void GlobalProgressStart(string text) { - if ( UI::WidgetExists(`slideText ) ) + total_progress_label = text; + if ( UI::WidgetExists(`progressTotal ) ) { - // - // Fix <img src> tags: Replace image path with current slide_pic_path - // - - while (true) - { - string replaced = regexpsub( text, "(.*)&imagedir;(.*)", - sformat("\\1%1\\2", slide_pic_path ) ); - if ( replaced == nil ) break; - text = replaced; - } - - UI::ChangeWidget(`slideText, `Value, text ); + UI::ChangeWidget(`progressTotal, `Value, 0); + UI::ChangeWidget(`progressTotal, `Label, text ); } + + total_progress_label = text; + total_progress_value = 0; } - - + /** - * Load one slide from files complete with image and textual description. - * @param text_file_name file name + path of the text file (rich text / HTML) - * @return true if OK, false if error - **/ - boolean LoadSlideFile( string text_file_name ) + * Update status of global progress of the slideshow. The new value will be set + * to \param value, if the \text is not nil, the label will be updated + * to this text as well. Otherwise label will not change. + * @param value new value for the global progress + * @param text new label for the global progress + */ + void UpdateGlobalProgress(integer value, string new_text) { - string text = (string) SCR::Read( .target.string, [text_file_name, ""] ); + if( new_text != nil) + total_progress_label = new_text; + total_progress_value = value; - if ( text == "" ) + if ( UI::WidgetExists(`progressTotal ) ) { - return false; + UI::ChangeWidget(`progressTotal, `Value, value); + if( new_text != nil ) + UI::ChangeWidget(`progressTotal, `Label, new_text ); } else + y2milestone( "progressTotal widget missing" ); + + // update slide + if( ShowingSlide() ) { - y2debug( "Loading slide show text from %1", text_file_name); - SetSlideText( text ); - return true; - } - } - - - /** - * Get version info for a package (without build no.) - * - * @param pkg_name name of the package without path and ".rpm" extension - * @return version string - **/ - global string StripReleaseNo( string pkg_name ) - { - integer build_no_pos = findlastof (pkg_name, "-" ); // find trailing build no. - - if ( build_no_pos != nil && build_no_pos > 0 ) - { - // cut off trailing build no. - pkg_name = substring( pkg_name , 0, build_no_pos ); - } - - return pkg_name; - } - - /** - * Get package file name from path - * - * @param pkg_name location of the package - * @return string package file name - **/ - global string StripPath(string pkg_name) - { - if (pkg_name == nil) - { - return nil; - } - - integer file_pos = findlastof(pkg_name, "/"); - - if (file_pos != nil && file_pos > 0 ) - { - // return just the file name - pkg_name = substring(pkg_name, file_pos + 1); + ChangeSlideIfNecessary(); } - - return pkg_name; } + map<string, map<string,any> > _stages = $[]; // list of the configured stages + map<string, any> _current_stage = nil; // current stage /** - * set media type "CD" or "DVD" + * Return the description for the current stage. + * @return string localized string description */ - global void SetMediaType (string new_media_type) + global string CurrentStageDescription() { - media_type = new_media_type; + return _current_stage["description"]:_("Installing..."); } - - + /** - * Set the slide show directory + * Move the global progress to the beginning of the given stage. + * @param stage_name id of the stage to move to */ - global void SetSlideDir( string dir ) - { - slide_base_path = dir; - - map tmp = (map) WFM::Read (.local.stat, slide_base_path); - - if ( ! tmp["isdir"]:false ) - slide_base_path = "/var/adm/YaST/InstSrcManager/tmp/CurrentMedia/suse/setup/slide"; - - y2milestone( "SetSlideDir: %1", slide_base_path ); - } - - - /** - * Perform sanity check for correct initialzation etc. - * @param silent don't complain in log file - * @return true if OK, false if any error - **/ - boolean SanityCheck( boolean silent ) + global void MoveToStage( string stage_name ) { - if ( ! init_pkg_data_complete ) + if( ! haskey( _stages, stage_name ) ) { - if ( ! silent ) - { - y2error( "SlideShow::SanityCheck(): Slide show not correctly initialized: " + - "SlideShow::InitPkgData() never called!" ); - } - return false; - } - - if ( current_src_no < 1 || current_cd_no < 1 ) - { - // nothing to install but something is going to be deleted, so it's OK - if (Pkg::IsAnyResolvable(`package, `to_remove)) - { - return true; - } - else if (!silent) - { - y2error(-1, "SlideShow::SanityCheck(): Illegal values for current_src (%1) or current_cd (%2)", - current_src_no, current_cd_no ); - y2milestone( "total sizes: %1", total_sizes_per_cd_per_src ); - } - return false; - } - - return true; - } - - string provide_name = ""; - string provide_size = ""; - - global void SlideGenericProvideStart (string pkg_name, integer sz, - string pattern, boolean remote) - { - if ( ! SanityCheck( false ) ) return; - if ( ! ShowingDetails() ) return; - - if ( UI::WidgetExists(`progressCurrentPackage) ) - { - string provide_msg = ""; - - if (remote) - { - provide_name = pkg_name; - provide_size = String::FormatSize(sz); - - provide_msg = sformat(_("Downloading %1 (download size %2)"), provide_name, provide_size); - } - else - { - provide_msg = pkg_name; - } - - UI::ChangeWidget(`progressCurrentPackage, `Label, provide_msg); - UI::ChangeWidget(`progressCurrentPackage, `Value, 0); + y2error( "Unknown progress stage \"%1\"", stage_name ); + return; } - // - // Update (user visible) installation log - // for remote download only - // - if( ! remote ) return; - - y2milestone( "Package '%1' is remote", pkg_name ); + _current_stage = _stages[stage_name]:nil; - string strsize = String::FormatSize (sz); - // message in the installatino log, %1 is package name, - // %2 is package size - string msg = sformat (pattern, pkg_name, strsize); - string log_line = "\n" + msg; - inst_log = inst_log + log_line; - - if ( ShowingDetails() ) - { - if ( UI::WidgetExists( `instLog ) ) - UI::ChangeWidget(`instLog, `LastLine, log_line ); - } - - } - - global void SlideDeltaApplyStart (string pkg_name) { - if ( ! SanityCheck( false ) ) return; - if ( ! ShowingDetails() ) return; - - if ( UI::WidgetExists(`progressCurrentPackage) ) - { - UI::ChangeWidget(`progressCurrentPackage, `Label, pkg_name); - UI::ChangeWidget(`progressCurrentPackage, `Value, 0); - } - - string msg = sformat (_("Applying delta RPM: %1"), pkg_name); - string log_line = "\n" + msg; - inst_log = inst_log + log_line; - - if ( ShowingDetails() ) - { - if ( UI::WidgetExists( `instLog ) ) - UI::ChangeWidget(`instLog, `LastLine, log_line ); - } + y2milestone( "Moving to stage %1 (%2)", stage_name, _stages[stage_name, "start"]:0 ); + // translators: default global progress bar label + UpdateGlobalProgress( _stages[stage_name, "start"]:0, _current_stage["description"]:_("Installing...") ); } - /** - * Package providal start - */ - global void SlideProvideStart (string pkg_name, integer sz, boolean remote) + * Update the global progress according to the progress in the current stage. + * The new value will be set to the per cent of the current stage according to \param value, + * if the \text is not nil, the label will be updated + * to this text as well. Otherwise label will not change. + * @param value new value for the stage progress + * @param text new label for the global progress + */ + global void StageProgress( integer value, string text ) { - // message in the installatino log, %1 is package name, - // %2 is package size - SlideGenericProvideStart (pkg_name, sz, _("Downloading %1 (download size %2)"), - remote); + UpdateGlobalProgress( _current_stage["start"]:0 + (value * _current_stage["size"]:1 / 100), text ); } - /** - * Set the curent language. Must be called once during initialization. - **/ - global void SetLanguage( string new_language ) + * Return the current global progress label. + * @return string current label + */ + global void SetGlobalProgressLabel( string text ) { - language = new_language; + total_progress_label = text; + if ( UI::WidgetExists(`progressTotal ) ) + { + UI::ChangeWidget(`progressTotal, `Label, text); + } } /** - * Append message to the installation log + * Append message to the installation log. + * @param msg message to be added, without trailing eoln */ global void AppendMessageToInstLog (string msg) { @@ -836,480 +303,68 @@ } } - /** - * Update internal bookkeeping: subtract size of one package from the - * global list of remaining sizes per CD - **/ - void SubtractPackageSize( integer pkg_size ) - { - integer remaining = remaining_sizes_per_cd_per_src [ current_src_no-1, current_cd_no-1 ]: 1; - remaining = remaining - pkg_size; - total_size_installed = total_size_installed + pkg_size; - - if ( remaining <= 0 ) - { - // -1 is the indicator for "done with this CD" - not to be - // confused with 0 for "nothing to install from this CD". - remaining = -1; - } - - remaining_sizes_per_cd_per_src [ current_src_no-1, current_cd_no-1 ] = remaining; - remaining_pkg_count_per_cd_per_src [ current_src_no-1, current_cd_no-1 ] = - remaining_pkg_count_per_cd_per_src [ current_src_no-1, current_cd_no-1 ]:0 -1; - - if ( unit_is_seconds ) - { - integer seconds = 0; - - if ( remaining > 0 && bytes_per_second > 0 ) - seconds = remaining / bytes_per_second; - - remaining_times_per_cd_per_src [ current_src_no-1, current_cd_no-1 ] = seconds; - } - - if ( debug ) - y2milestone( "SubtractPackageSize( %1 ) -> %2", pkg_size, remaining_sizes_per_cd_per_src); - } - - - /** - * Return a CD's progress bar ID - * @param src_no number of the repository (from 0 on) - * @param cd_no number of the CD within that repository (from 0 on) - **/ - string CdProgressId( integer src_no, integer cd_no ) - { - return sformat( "Src %1 CD %2", src_no, cd_no ); - } /** - * Recalculate remaining times per CD based on package sizes remaining - * and data rate so far. Recalculation is only done each 'recalc_interval' - * seconds unless 'force_recalc' is set to 'true'. - * - * @param force_recalc force recalculation even if timeout not reached yet - * @return true if recalculated, false if not - **/ - boolean RecalcRemainingTimes( boolean force_recalc ) - { - if ( ! force_recalc - && time() < next_recalc_time ) - { - // Nothing to do (yet) - simply return - return false; - } - - - // Actually do recalculation - - integer elapsed = total_time_elapsed; - - if ( start_time >= 0 ) - { - elapsed = elapsed + time() - start_time; - } - - if ( elapsed == 0 ) - { - // Called too early - no calculation possible yet. - // This happens regularly during initialization, so an error - // message wouldn't be a good idea here. - - return false; - } - - - // This is the real thing. - - integer real_bytes_per_second = total_size_installed / elapsed; - - // But this turns out to be way to optimistic - RPM gets slower and - // slower while installing. So let's add some safety margin to make - // sure initial estimates are on the pessimistic side - the - // installation being faster than initially estimated will be a - // pleasant surprise to the user. Most users don't like it the other - // way round. - // - // The "pessimistic factor" progressively decreases as the installation - // proceeds. It begins with about 1.7, i.e. the data transfer rate is - // halved to what it looks like initially. It decreases to 1.0 towards - // the end. - - float pessimistic_factor = 1.0; - - if ( total_size_to_install > 0 ) - pessimistic_factor = 1.7 - tofloat( total_size_installed ) / tofloat( total_size_to_install ); - bytes_per_second = tointeger( tofloat( real_bytes_per_second ) / pessimistic_factor + 0.5 ); - - if ( bytes_per_second < 1 ) - bytes_per_second = 1; - - remaining_times_per_cd_per_src = []; - - // Recalculate remaining times for the individual CDs - - foreach ( list<integer> remaining_sizes_list, remaining_sizes_per_cd_per_src, - ``{ - list<integer> remaining_times_list = []; - integer remaining_time = -1; - - foreach ( integer remaining_size, remaining_sizes_list, - ``{ - remaining_time = remaining_size; - - if ( remaining_size > 0 ) - { - remaining_time = remaining_size / bytes_per_second; - - if ( remaining_time < min_time_per_cd ) - { - // It takes at least this long for the CD drive to spin up and - // for RPM to do _anything_. Times below this values are - // ridiculously unrealistic. - remaining_time = min_time_per_cd; - } - else if ( remaining_time > max_time_per_cd ) // clip off at 2 hours - { - // When data throughput goes downhill (stalled network connection etc.), - // cut off the predicted time at a reasonable maximum. - remaining_time = max_time_per_cd; - } - } - remaining_times_list = add( remaining_times_list, remaining_time ); - }); - - remaining_times_per_cd_per_src = add( remaining_times_per_cd_per_src, remaining_times_list ); - }); - - - // Recalculate slide interval - - if ( size( slides ) > 0 ) - { - integer slides_remaining = size( slides ) - current_slide_no - 1; - - if ( slides_remaining > 0 ) - { - // The remaining time for the rest of the slides depends on the - // remaining time for the current CD only: This is where the - // slide images and texts reside. Normally, only CD1 has slides - // at all, i.e. the slide show must be finished when CD1 is - // done. - // - // In addition to that, take elapsed time for current slide - // into account so all slides get about the same time. - - integer time_remaining = remaining_times_per_cd_per_src[current_src_no-1, current_cd_no-1]:1 + time() - slide_start_time; - slide_interval = time_remaining / slides_remaining; - y2debug( "New slide interval: %1 - slides remaining: %2 - remaining time: %3", - slide_interval, slides_remaining, time_remaining ); - - if ( slide_interval < slide_min_interval ) - { - slide_interval = slide_min_interval; - y2debug( "Resetting slide interval to min slide interval: %1", slide_interval ); - } - - if ( slide_interval > slide_max_interval ) - { - slide_interval = slide_max_interval; - y2debug( "Resetting slide interval to max slide interval: %1", slide_interval ); - } - } - } - - next_recalc_time = time() + recalc_interval; - - return true; - } - - - /** - * Create one single item for the CD statistics table - **/ - term TableItem( string id, string col1, string col2, string col3, string col4 ) - { - return `item(`id( id ), col1, col2, col3, col4 ); - } - - - /** - * Returns a table widget item list for CD statistics + * Check if the dialog is currently set up so the user could switch to the slide page. **/ - list<term> CdStatisticsTableItems() + global boolean HaveSlideWidget() { - list<term> itemList = []; - - // - // Add "Total" item - at the top so it is visible by default even if there are many items - // - - { - // List column header for total remaining MB and time to install - string caption = _("Total"); - integer remaining = TotalRemainingSize(); - string rem_size = FormatRemainingSize( remaining ); - string rem_count = FormatRemainingCount( TotalRemainingPkgCount() ); - string rem_time = ""; - - if ( unit_is_seconds && bytes_per_second > 0 ) - { - rem_time = FormatTimeShowOverflow( TotalRemainingTime() ); - } - - itemList = add( itemList, TableItem( "total", caption, " " + rem_size, " " + rem_count, " " + rem_time ) ); - } - - - // - // Now go through all repositories - // - - integer src_no = 0; - - foreach ( list<integer> inst_src, remaining_sizes_per_cd_per_src, ``{ - y2milestone( "src #%1: %2", src_no, inst_src ); - - if (ListSum(inst_src) > 0) // Ignore repositories from where there is nothing is to install - { - // Add heading for this repository - itemList = add( itemList, TableItem( sformat( "src(%1)", src_no ), - inst_src_names[ src_no ]:"", "", "", "" ) ); - - integer cd_no = 0; - - foreach ( integer remaining, inst_src, ``{ - if ( remaining > 0 - || ( src_no+1 == current_src_no && cd_no+1 == current_cd_no ) ) // suppress current CD - { - string caption = sformat( "%1 %2", media_type, cd_no+1 ); // "CD 1" - column #0 - string rem_size = FormatRemainingSize( remaining ); // column #1 - string rem_count = FormatRemainingCount( remaining_pkg_count_per_cd_per_src[ src_no, cd_no ]:0 ); - string rem_time = ""; - - if ( unit_is_seconds && bytes_per_second > 0 ) - { - remaining = remaining / bytes_per_second; - rem_time = FormatTime( remaining ); // column #2 - - if ( remaining > max_time_per_cd ) // clip off at 2 hours - { - // When data throughput goes downhill (stalled network connection etc.), - // cut off the predicted time at a reasonable maximum. - // "%1" is a predefined maximum time. - rem_time = FormatTimeShowOverflow( -max_time_per_cd ); - } - } - - itemList = add( itemList, - TableItem( sformat("cd(%1,%2)", src_no, cd_no ), // ID - caption, " " + rem_size, " " + rem_count, " " + rem_time ) ); - } - - cd_no = cd_no + 1; - }); - } - - src_no = src_no + 1; - }); - - if ( debug ) - { - y2milestone( "Remaining: %1", remaining_sizes_per_cd_per_src ); - y2milestone( "CD table item list:\n%1", itemList ); - } - - return itemList; + return UI::WidgetExists(`dumbTab); } - /** - * Progress display update - * This is called via the packager's progress callbacks. - * - * @param pkg_percent package percentage + * Check if the slide show is available. This must be called before trying + * to access any slides; some late initialization is done here. **/ - global void UpdateCurrentPackageProgress(integer pkg_percent) + global void CheckForSlides() { - if ( UI::WidgetExists(`progressCurrentPackage ) ) - { - UI::ChangeWidget(`progressCurrentPackage, `Value, pkg_percent); - } - } + Slides::CheckBasePath(); - global void UpdateCurrentPackageRateProgress(integer pkg_percent, integer bps_avg, integer bps_current) - { - // update the download rate - if ( UI::WidgetExists(`progressCurrentPackage ) ) + if ( Stage::initial () || Stage::cont () ) { - UI::ChangeWidget(`progressCurrentPackage, `Value, pkg_percent); - - if (bps_current > 0) + if ( Slides::HaveSlideSupport() ) { - // do not show the average download rate if the space is limited - if (GetTextMode () && GetDisplayWidth () < 100) - { - bps_avg = -1; - } - - string msg_rate = String::FormatRateMessage(provide_name + " - %1", bps_avg, bps_current); - msg_rate = sformat(_("Downloading %1 (download size %2)"), msg_rate, provide_size); - - UI::ChangeWidget(`progressCurrentPackage, `Label, msg_rate); + y2milestone( "Display OK for slide show, loading" ); + Slides::LoadSlides( language ); } - } - } - - - /** - * Update progress widgets for all CDs. - * Uses global statistics variables. - **/ - global void UpdateAllCdProgress(boolean silent_check) - { - if ( ! SanityCheck( silent_check ) ) return; - if ( ! widgets_created ) return; - - if ( unit_is_seconds ) - RecalcRemainingTimes( true ); // force - - if ( UI::WidgetExists(`cdStatisticsTable) ) - UI::ChangeWidget(`cdStatisticsTable, `Items, CdStatisticsTableItems() ); - } - - - /** - * Update progress widgets for the current CD: Label and ProgressBar. - * Use global statistics variables for that. - **/ - global void UpdateCurrentCdProgress(boolean silent_check) - { - if ( ! SanityCheck( silent_check ) ) return; - if ( ! UI::WidgetExists(`cdStatisticsTable) ) return; - - - // - // Update table entries for current CD - // - - integer remaining = remaining_sizes_per_cd_per_src [ current_src_no-1, current_cd_no-1 ]:0; - UI::ChangeWidget(`id(`cdStatisticsTable ), - `Item( sformat( "cd(%1,%2)", current_src_no-1, current_cd_no-1), size_column ), - FormatRemainingSize( remaining ) ); - - UI::ChangeWidget(`id(`cdStatisticsTable ), - `Item( sformat( "cd(%1,%2)", current_src_no-1, current_cd_no-1), pkg_count_column ), - FormatRemainingCount( remaining_pkg_count_per_cd_per_src [ current_src_no-1, current_cd_no-1 ]:0 ) ); - - if ( unit_is_seconds ) - { - // Convert 'remaining' from size (bytes) to time (seconds) - - remaining = remaining / bytes_per_second; - - if ( remaining <= 0 ) - remaining = 0; - - if ( remaining > max_time_per_cd ) // clip off at 2 hours + else { - // When data throughput goes downhill (stalled network connection etc.), - // cut off the predicted time at a reasonable maximum. - remaining = -max_time_per_cd; + y2warning( "Disabling slide show - insufficient display capabilities" ); } - - UI::ChangeWidget(`id(`cdStatisticsTable ), - `Item( sformat( "cd(%1,%2)", current_src_no-1, current_cd_no-1), time_column ), - FormatTimeShowOverflow( remaining ) ); - } - - - // - // Update "total" table entries - // - - UI::ChangeWidget(`id( `cdStatisticsTable ), - `Item( "total", size_column ), - FormatRemainingSize( TotalRemainingSize() ) ); - - UI::ChangeWidget(`id( `cdStatisticsTable ), - `Item( "total", pkg_count_column ), - FormatRemainingCount( TotalRemainingPkgCount() ) ); - - if ( unit_is_seconds ) - { - UI::ChangeWidget(`id( `cdStatisticsTable ), `Item( "total", time_column ), - FormatTimeShowOverflow( TotalRemainingTime() ) ); - } } - string GetProgressLabel() - { - string rem_string = ""; - integer tot_rem_t = TotalRemainingTime(); - - rem_string = ( unit_is_seconds && bytes_per_second > 0 && tot_rem_t > 0) ? - sformat("%1 / %2", FormatRemainingSize(TotalRemainingSize()), FormatTimeShowOverflow(tot_rem_t)) - : FormatRemainingSize(TotalRemainingSize()); - - return sformat(_("Remaining: %1"), rem_string); - } /** - * Update progress widgets + * Set the slide show text. + * @param text **/ - void UpdateTotalProgress(boolean silent_check) + void SetSlideText( string text ) { - if ( UI::WidgetExists(`multiProgressMeter ) ) - UI::ChangeWidget(`multiProgressMeter, `Values, FlattenNoZeroes( remaining_sizes_per_cd_per_src ) ); - - if ( UI::WidgetExists(`progressTotal ) ) - { - // progress is in kB - UI::ChangeWidget(`progressTotal, `Value, TotalInstalledSize() >> 10); - UI::ChangeWidget(`progressTotal, `Label, GetProgressLabel() ); - } - - UpdateCurrentCdProgress(silent_check); - - if ( UI::WidgetExists(`nextMedia ) ) + if ( UI::WidgetExists(`slideText ) ) { - string nextMedia = FormatNextMedia(); - - if ( nextMedia != "" || last_cd ) - { - UI::ChangeWidget(`nextMedia, `Value, nextMedia ); - UI::RecalcLayout(); - last_cd = false; - } + UI::ChangeWidget(`slideText, `Value, text ); } - - if ( UI::WidgetExists(`totalRemainingLabel ) ) - UI::ChangeWidget(`totalRemainingLabel, `Value, FormatTotalRemaining() ); - - if ( UI::WidgetExists(`multiProgressMeter ) ) // Avoid that in NCurses - too much flicker - UI::RecalcLayout(); } /** - * Switch unit to seconds if necessary and recalc everything accordingly. - * @return true if just switched from sizes to seconds, false otherwise + * Set the curent language. Must be called once during initialization. **/ - boolean SwitchToSecondsIfNecessary() + global void SetLanguage( string new_language ) { - if ( unit_is_seconds - || time() < start_time + initial_recalc_delay ) - { - return false; // no need to switch - } + language = new_language; + } - RecalcRemainingTimes( true ); // force recalculation - unit_is_seconds = true; - return true; // just switched + /** + * Create one single item for the CD statistics table + **/ + global term TableItem( string id, string col1, string col2, string col3, string col4 ) + { + return `item(`id( id ), col1, col2, col3, col4 ); } @@ -1319,18 +374,17 @@ **/ void LoadSlide( integer slide_no ) { - if ( slide_no > size( slides ) ) + if ( slide_no > size( Slides::slides ) ) { slide_no = 0; } current_slide_no = slide_no; - string slide_name = slides[slide_no]:""; + string slide_name = Slides::slides[slide_no]:""; slide_start_time = time(); - if ( LoadSlideFile( sformat ("%1/%2", slide_txt_path, slide_name ) ) ) return; - SetSlideText (""); + SetSlideText( Slides::LoadSlideFile( slide_name ) ); } @@ -1338,9 +392,9 @@ * Check if the current slide needs to be changed and do that if * necessary. **/ - void ChangeSlideIfNecessary() + global void ChangeSlideIfNecessary() { - if ( current_slide_no + 1 < size( slides ) + if ( current_slide_no + 1 < size( Slides::slides ) && time() > slide_start_time + slide_interval ) { y2debug( "Loading slide #%1", current_slide_no + 2 ); @@ -1348,151 +402,6 @@ } } - - /** - * package start display update - * - this is called at the beginning of a new package - * - * @param pkg_name package name - * @param pkg_summary package summary (short description) - * @param deleting Flag: deleting (true) or installing (false) package? - **/ - global void SlideDisplayStart( string pkg_name, - string pkg_summary, - integer pkg_size, - boolean deleting ) - { - if ( ! SanityCheck( false ) ) return; - - // remove path - pkg_name = StripPath(pkg_name); - - // remove release and .rpm suffix - // pkg_name = StripReleaseNo( pkg_name ); // bug #154872 - - if ( deleting ) - { - pkg_size = -1; - - // This is a kind of misuse of insider knowledge: If there are packages to delete, this - // deletion comes first, and only then packages are installed. This, however, greatly - // distorts the estimated times based on data throughput so far: While packages are - // deleted, throughput is zero, and estimated times rise to infinity (they are cut off - // at max_time_per_cd to hide this). So we make sure the time spent deleting packages is - // not counted for estimating remaining times - reset the timer. - // - // Note: This will begin to fail when some day packages are deleted in the middle of the - // installaton process. - - ResetTimer(); - } - - if ( pkg_summary == nil ) - pkg_summary = ""; - - string msg = ""; - - if ( deleting ) - { - // Heading for the progress bar for the current package - // while it is deleted. "%1" is the package name. - msg = sformat( _("Deleting %1"), pkg_name ); - } - else - { - // package installation - summary text - // %1 is RPM name, %2 is installed (unpacked) size (e.g. 6.20MB) - msg = sformat( _("%1 (installed size %2)"), pkg_name, String::FormatSize( pkg_size ) ); - } - - - // - // Update package progress bar - // - - if ( UI::WidgetExists(`progressCurrentPackage) ) - { - UI::ChangeWidget(`progressCurrentPackage, `Label, msg ); - UI::ChangeWidget(`progressCurrentPackage, `Value, 0); - } - - - // - // Update (user visible) installation log - // - - string log_line = "\n" + msg; - - if ( pkg_summary != "" ) - log_line = log_line + " -- " + pkg_summary; - - inst_log = inst_log + log_line; - - if ( ShowingDetails() ) - { - if ( UI::WidgetExists( `instLog ) ) - UI::ChangeWidget(`instLog, `LastLine, log_line ); - } - else - { - ChangeSlideIfNecessary(); - } - - - if ( ! deleting ) - { - // the actions are performed when package installation finishes -// SubtractPackageSize( pkg_size ); - y2milestone( "Installing %1 -- %2", pkg_name, pkg_summary ); - -// if (SwitchToSecondsIfNecessary() -// || RecalcRemainingTimes( false ) ) // no forced recalculation -// { -// y2debug( "Updating progress for all CDs" ); -// UpdateAllCdProgress(); -// } -// else -// { -// UpdateCurrentCdProgress(); -// } - -// UpdateTotalProgress(false); - - } // ! deleting - } - - /** - * package start display update - * - this is called at the end of a new package - * - * @param pkg_name package name - * @param deleting Flag: deleting (true) or installing (false) package? - **/ - global void SlideDisplayDone ( string pkg_name, - integer pkg_size, - boolean deleting ) - { - if ( ! deleting ) - { - SubtractPackageSize( pkg_size ); - - if (SwitchToSecondsIfNecessary() - || RecalcRemainingTimes( false ) ) // no forced recalculation - { - y2debug( "Updating progress for all CDs" ); - UpdateAllCdProgress(false); - } - else - { - UpdateCurrentCdProgress(false); - } - - UpdateTotalProgress(false); - - } // ! deleting - - } - /** * Add widgets for progress bar etc. around a slide show page * @param page_id ID to use for this page (for checking with UI::WidgetExists() ) @@ -1501,14 +410,6 @@ **/ term AddProgressWidgets( symbol page_id, term page_contents ) { - integer progress_max_kB = total_size_to_install >> 10; - - // max value cannot be 0, it means "tick" progress - if (progress_max_kB <= 0) - { - progress_max_kB = 1; - } - term widgets = `HBox(`id( page_id ), `HSpacing( 1 ), @@ -1516,17 +417,13 @@ `VWeight( 1, // lower layout priority page_contents ), // Progress bar for overall progress of software package installation - `ProgressBar(`id(`progressTotal ), GetProgressLabel(), - // progress is in kB due to 32 bit UI limit - progress_max_kB, TotalInstalledSize() >> 10) + `ProgressBar(`id(`progressTotal ), total_progress_label, 100, total_progress_value) // intentionally omitting `Label(`nextMedia) - // too much flicker upon update (UI::RecalcLayout() ) on NCurses ), `HSpacing( 0.5 ) ); - y2milestone("total_size_to_install: %1", total_size_to_install); - y2debug( "widget term: \n%1", widgets ); return widgets; } @@ -1548,18 +445,9 @@ return widgets; } - - /** - * Construct widgets for the "details" page - * - * @return A term describing the widgets - **/ - term DetailsPageWidgets() + term DetailsTableWidget() { - term widgets = - AddProgressWidgets( `detailsPage, - `VBox( - `VWeight( 1, + return `VWeight( 1, `Table( `id(`cdStatisticsTable), `opt(`keepSorting), `header( // Table headings for CD statistics during installation @@ -1571,13 +459,25 @@ // Table headings for CD statistics during installation `Right( _("Time") ) ), - CdStatisticsTableItems() + table_items ) - ), + ); + } + + /** + * Construct widgets for the "details" page + * + * @return A term describing the widgets + **/ + term DetailsPageWidgets() + { + term widgets = + AddProgressWidgets( `detailsPage, + `VBox( _show_table ? DetailsTableWidget() : `Empty(), `VWeight( 1, - `LogView(`id(`instLog ), "", 6, 0 ) + `LogView(`id(`instLog ), _("Actions performed:"), 6, 0 ) ), - `ProgressBar(`id(`progressCurrentPackage), " ", 100, 0 ) + `ProgressBar(`id(`progressCurrentPackage), sub_progress_label, 100, sub_progress_value ) ) ); @@ -1585,6 +485,11 @@ return widgets; } + /** + * Construct widgets for the "release notes" page + * + * @return A term describing the widgets + **/ term RelNotesPageWidgets() { term widgets = AddProgressWidgets (`relNotesPage, `RichText (relnotes) @@ -1606,30 +511,37 @@ { UI::ChangeWidget(`dumbTab, `CurrentItem, `showSlide ); UI::ReplaceWidget(`tabContents, SlidePageWidgets() ); - UpdateTotalProgress(false); + // UpdateTotalProgress(false); // FIXME: this breaks other stages! } } - /** - * Switch from the 'slide show' view to the 'details' view. - **/ - global void SwitchToDetailsView(boolean silent_check) + * Rebuild the details page. + */ + void RebuildDetailsView() { - if ( ShowingDetails() ) - return; - if ( UI::WidgetExists(`tabContents ) ) { UI::ChangeWidget(`dumbTab, `CurrentItem, `showDetails ); UI::ReplaceWidget(`tabContents, DetailsPageWidgets() ); + y2milestone( "Contents set to details" ); } - UpdateTotalProgress(silent_check); - UpdateAllCdProgress(silent_check); - if ( UI::WidgetExists( `instLog ) && inst_log != "" ) UI::ChangeWidget(`instLog, `Value, inst_log ); + } + + /** + * Switch from the 'slide show' view to the 'details' view. + **/ + global void SwitchToDetailsView() + { + if ( ShowingDetails() ) + { + y2milestone( "Already showing details" ); + return; + } + RebuildDetailsView(); } /** @@ -1644,11 +556,14 @@ { UI::ChangeWidget(`dumbTab, `CurrentItem, `showRelNotes ); UI::ReplaceWidget(`tabContents, RelNotesPageWidgets() ); - UpdateTotalProgress(false); + // UpdateTotalProgress(false); } } + /** + * Help text for the dialog + */ string HelpText() { // Help text while software packages are being installed (displayed only in rare cases) @@ -1658,14 +573,15 @@ } - void RebuildDialog(boolean silent_check) + /** + * Rebuild the dialog. Useful if slides become available post-creating the dialog. + */ + global void RebuildDialog() { - if (!SanityCheck(silent_check)) return; - term contents = `Empty(); - if ( UI::HasSpecialWidget(`DumbTab) && HaveSlideSupport() - && HaveSlides() ) + if ( UI::HasSpecialWidget(`DumbTab) && Slides::HaveSlideSupport() + && Slides::HaveSlides() ) { list tabs = [ // tab @@ -1698,17 +614,19 @@ contents = DetailsPageWidgets(); } + y2milestone( "SlideShow contents: %1", contents); + Wizard::SetContents( // Dialog heading while software packages are being installed - _("Package Installation"), + _("Perform Installation"), contents, HelpText(), false, false ); // has_back, has_next widgets_created = true; - if ( ! HaveSlides() && ShowingSlide() ) - SwitchToDetailsView(false); + if ( ! Slides::HaveSlides() && ShowingSlide() ) + SwitchToDetailsView(); } @@ -1738,7 +656,7 @@ HelpText(), false, false ); // has_back, has_next - RebuildDialog(true); + RebuildDialog(); Wizard::SetTitleIcon("yast-sw_single"); // reset abort status @@ -1747,153 +665,17 @@ /** - * Initialize internal pacakge data, such as remaining package sizes and - * times. This may not be called before the pkginfo server is up and - * running, so this cannot be reliably done from the constructor in all - * cases. - * @param force true to force reinitialization - **/ - global void InitPkgData(boolean force) + * Initialize generic data to default values + */ + global void Reset() { - if ( init_pkg_data_complete && ! force) - return; - - // Reinititalize some globals (in case this is a second run) - total_size_installed = 0; - total_time_elapsed = 0; - start_time = -1; - next_recalc_time = -1; - current_src_no = -1; // 1..n - current_cd_no = -1; // 1..n - next_src_no = -1; - next_cd_no = -1; - last_cd = false; - unit_is_seconds = false; // begin with package sizes - bytes_per_second = 1; current_slide_no = 0; slide_start_time = 0; - - list< list > src_list = Pkg::PkgMediaNames(); - inst_src_names = maplist( list src, src_list, ``(src[0]:"CD") ); - - y2milestone ("Media names: %1", inst_src_names); - - integer index = 0; - - srcid_to_current_src_no = listmap( list src, src_list, { - index = index + 1; - return $[src[1]:-1 : index]; - }); - - y2milestone ("Repository mapping information: %1", srcid_to_current_src_no ); - - total_sizes_per_cd_per_src = Pkg::PkgMediaSizes(); - total_pkg_count_per_cd_per_src = Pkg::PkgMediaCount(); - - - total_size_to_install = ListSum( flatten( total_sizes_per_cd_per_src ) ); - y2milestone("total_size_to_install: %1", total_size_to_install); - remaining_sizes_per_cd_per_src = (list<list <integer> >) eval (total_sizes_per_cd_per_src); - remaining_pkg_count_per_cd_per_src = (list<list <integer> >) eval (total_pkg_count_per_cd_per_src); - total_cd_count = size( flatten( total_sizes_per_cd_per_src ) ); - init_pkg_data_complete = true; - - y2milestone( "SlideShow::InitPkgData() done; total_sizes_per_cd_per_src: %1", total_sizes_per_cd_per_src ); - y2milestone( "SlideShow::InitPkgData(): pkg: %1", total_pkg_count_per_cd_per_src ); - RebuildDialog(true); - } - - - - /** - * Try to figure out what media will be needed next - * and set next_src_no and next_cd_no accordingly. - **/ - void FindNextMedia() - { - // Normally we would have to use current_cd_no+1, - // but since this uses 1..n and we need 0..n-1 - // for array subscripts anyway, use it as it is. - next_cd_no = current_cd_no; - next_src_no = current_src_no-1; - last_cd = false; - - while ( next_src_no < size( remaining_sizes_per_cd_per_src ) ) - { - list<integer> remaining_sizes = remaining_sizes_per_cd_per_src[ next_src_no ]: []; - - while ( next_cd_no < size( remaining_sizes ) ) - { - if ( remaining_sizes[ next_cd_no ]:0 > 0 ) - { - if ( debug ) - y2milestone( "Next media: src: %1 CD: %2", next_src_no, next_cd_no ); - return; - } - else - { - next_cd_no = next_cd_no + 1; - } - } - - next_src_no = next_src_no + 1; - } - - if ( debug ) - y2milestone( "No next media - all done" ); - - next_src_no = -1; - next_cd_no = -1; - last_cd = true; - } - - - /** - * Set the current repository and CD number. Must be called for each CD change. - * src_no: 1...n - * cd_no: 1...n - **/ - global void SetCurrentCdNo( integer src_no, integer cd_no ) - { - if (cd_no == 0) - { - y2milestone("medium number 0, using medium number 1"); - cd_no = 1; - } - - y2milestone("SetCurrentCdNo() - src: %1 , CD: %2", src_no, cd_no); - current_src_no = srcid_to_current_src_no[src_no]:-1; - current_cd_no = cd_no; - - CheckForSlides(); - FindNextMedia(); - - if ( HaveSlides() && HaveSlideSupport() ) - { - if ( ! HaveSlideWidget() ) - { - RebuildDialog(false); - - if ( user_switched_to_details ) - SwitchToDetailsView(false); - } - - if ( ! user_switched_to_details ) // Don't override explicit user request! - { - SwitchToSlideView(); - LoadSlide(0); - } - } - else - { - if ( ! ShowingDetails() ) - RebuildDialog(false); - else - UpdateTotalProgress(false); - - current_slide_no = 0; - } + total_time_elapsed = 0; + start_time = -1; + next_recalc_time = -1; } + /** @@ -1903,12 +685,13 @@ { if ( button == `showDetails && ! ShowingDetails() ) { + y2milestone( "User asks to switch to details" ); user_switched_to_details = true ; - SwitchToDetailsView(false); + SwitchToDetailsView(); } else if ( button == `showSlide && ! ShowingSlide() ) { - if ( HaveSlides() ) + if ( Slides::HaveSlides() ) { user_switched_to_details = false; SwitchToSlideView(); @@ -1934,29 +717,70 @@ /** + * Check for user button presses and handle them. Generic handling to be used in the + * progress handlers. + **/ + global void GenericHandleInput() + { + // any button = SlideShow::debug ? UI::PollInput() : UI::TimeoutUserInput( 10 ); + any button = UI::PollInput(); + + // in case of cancel ask user if he really wants to quit installation + if ( button == `abort || button == `cancel ) + { + if ( Mode::normal () ) + { + SlideShow::SetUserAbort(Popup::AnyQuestion( Popup::NoHeadline(), + // popup yes-no + _("Do you really want\nto quit the installation?"), + Label::YesButton(), + Label::NoButton(), + `focus_no )); + } + else if ( Stage::initial () ) + { + SlideShow::SetUserAbort(Popup::ConfirmAbort( `unusable )); + } + else // Mode::update (), Stage::cont () + { + SlideShow::SetUserAbort(Popup::ConfirmAbort( `incomplete )); + } + + if (SlideShow::GetUserAbort()) + { + SlideShow::AppendMessageToInstLog (_("Aborted")); + } + } + else + { + SlideShow::HandleInput( button ); + } + } + + /** * Open the slide show dialog. **/ - global void OpenSlideShowDialog() + global void OpenDialog() { // call SlideShowCallbacks::InstallSlideShowCallbacks() WFM::call("wrapper_slideshow_callbacks", ["InstallSlideShowCallbacks"]); - OpenSlideShowBaseDialog(); + // check for slides first, otherwise dialogs will be built without them CheckForSlides(); - if ( HaveSlides() ) + OpenSlideShowBaseDialog(); + + if ( Slides::HaveSlides() ) LoadSlide(0); else - SwitchToDetailsView(true); - - UpdateAllCdProgress(true); + SwitchToDetailsView(); } /** * Close the slide show dialog. **/ - global void CloseSlideShowDialog() + global void CloseDialog() { if ( opened_own_wizard ) Wizard::CloseDialog(); @@ -1965,4 +789,110 @@ WFM::call("wrapper_slideshow_callbacks", ["RemoveSlideShowCallbacks"]); } + global void ShowTable() + { + if ( ShowingDetails() && ! _show_table ) + { + _show_table = true; + RebuildDetailsView(); + } + _show_table = true; + } + + global void HideTable() + { + if ( ShowingDetails() && _show_table ) + { + _show_table = false; + RebuildDetailsView(); + } + _show_table = false; + } + + global void UpdateTable( list<term> items ) + { + table_items = items; + if( ShowingDetails() && _show_table ) + { + UI::ChangeWidget( `id(`cdStatisticsTable), `Items, items ); + } + } + + /** + * Prepare the stages for the global progressbar. Will compute the total estimate of time and + * partition the global 100% to given stages based on their estimates. Can compute out of + * time and size to download. + * + * The stages description list example: + * [ + * $[ + * "name" : "disk", + * "description" : "Prepare disk...", + * "value" : 85, // disk speed can be guessed by the storage, thus passing time + * "units" : `sec + * ], + * $[ + * "name" : "images"; + * "description" : "Deploying images...", + * "value" : 204800, // amount of kb to be downloaded/installed + * "units" : `kb + * ], + * ] + */ + global void Setup( list< map<string,any> > stages ) + { + // initiliaze the generic counters + Reset(); + + // gather total amount of time need + integer total_time = 0; + + foreach( map<string,any> stage, stages, { + if( stage["units"]:`sec == `sec ) + { + total_time = total_time + stage["value"]:0; + } + else // assume kilobytes + { + // assume 15 minutes for installation of openSUSE 11.0, giving 3495 as the constant for kb/s + total_time = total_time + (stage["value"]:0 / 3495); + } + }); + + y2milestone( "Total estimated time: %1", total_time ); + + integer start = 0; // value where the current stage starts + + _stages = $[]; // prepare a new stages description + + // distribute the total time to stages as per cents + foreach( map<string,any> stage, stages, { + if( stage["units"]:`sec == `sec ) + { + stage["size"] = stage["value"]:0 * 100 / total_time; + stage["start"] = start; + + start = start + stage["size"]:0; + } + else // assume kilobytes + { + // assume 15 minutes for installation of openSUSE 11.0, giving 3495 as the constant + stage["size"] = ( stage["value"]:0 * 100 ) / 3495 / total_time; + stage["start"] = start; + if( stage["size"]:0 + start > 100 ) + stage["size"] = 100 - start; + + start = start + stage["size"]:0; + } + + _stages[ stage["name"]:"" ] = stage; + + // setup first stage + if( _current_stage == nil ) + _current_stage = stage; + }); + + y2milestone( "Global progress bar: %1", _stages ); + } + } Modified: trunk/packager/src/modules/SlideShowCallbacks.ycp URL: http://svn.opensuse.org/viewcvs/yast/trunk/packager/src/modules/SlideShowCallbacks.ycp?rev=50558&r1=50557&r2=50558&view=diff ============================================================================== --- trunk/packager/src/modules/SlideShowCallbacks.ycp (original) +++ trunk/packager/src/modules/SlideShowCallbacks.ycp Tue Sep 2 11:23:10 2008 @@ -22,6 +22,7 @@ import "PackageCallbacks"; import "Popup"; import "SlideShow"; + import "PackageSlideShow"; import "Message"; import "Directory"; import "URL"; @@ -82,7 +83,7 @@ if ( remote ) { - SlideShow::SlideProvideStart (name , archivesize, remote); + PackageSlideShow::SlideProvideStart (name , archivesize, remote); _remote_provide = true; } } @@ -95,7 +96,7 @@ { if (_remote_provide) { - SlideShow::UpdateCurrentPackageProgress( percent ); + PackageSlideShow::UpdateCurrentPackageProgress( percent ); } HandleInput(); return ! SlideShow::GetUserAbort(); @@ -103,7 +104,7 @@ global boolean ProgressDownload(integer percent, integer bps_avg, integer bps_current) { - SlideShow::UpdateCurrentPackageRateProgress(percent, bps_avg, bps_current); + PackageSlideShow::UpdateCurrentPackageRateProgress(percent, bps_avg, bps_current); HandleInput(); return ! SlideShow::GetUserAbort(); @@ -117,7 +118,7 @@ { if ( _remote_provide ) { - SlideShow::UpdateCurrentPackageProgress( 100 ); + PackageSlideShow::UpdateCurrentPackageProgress( 100 ); _remote_provide = false; } if (SlideShow::GetUserAbort()) @@ -291,7 +292,7 @@ **/ global void DisplayStartInstall(string pkg_name, string pkg_description, integer pkg_size, boolean deleting ) { - SlideShow::SlideDisplayStart( pkg_name, pkg_description, pkg_size, deleting ); + PackageSlideShow::SlideDisplayStart( pkg_name, pkg_description, pkg_size, deleting ); HandleInput(); // warn user about exhausted diskspace during installation (not if deleting packages) @@ -395,7 +396,7 @@ if (!SlideShow::GetUserAbort()) { - SlideShow::UpdateCurrentPackageProgress ( pkg_percent ); + PackageSlideShow::UpdateCurrentPackageProgress ( pkg_percent ); } if (SlideShow::GetUserAbort()) @@ -414,7 +415,7 @@ { if (SlideShow::GetUserAbort()) return "I"; - SlideShow::UpdateCurrentPackageProgress (100); + PackageSlideShow::UpdateCurrentPackageProgress (100); string ret = ""; if (error != 0) @@ -423,7 +424,7 @@ } if (size (ret) == 0 || tolower (substring (ret, 0, 1)) != "r") { - SlideShow::SlideDisplayDone( + PackageSlideShow::SlideDisplayDone( PackageCallbacks::_package_name, PackageCallbacks::_package_size, PackageCallbacks::_deleting_package); @@ -437,7 +438,7 @@ */ global void StartDeltaProvide( string name, integer archivesize ) { - SlideShow::SlideGenericProvideStart (name , archivesize, _("Downloading delta RPM %1 (download size %2)"), true /*remote*/); + PackageSlideShow::SlideGenericProvideStart (name , archivesize, _("Downloading delta RPM %1 (download size %2)"), true /*remote*/); _remote_provide = true; } @@ -446,7 +447,7 @@ */ global void StartDeltaApply( string name ) { - SlideShow::SlideDeltaApplyStart (name); + PackageSlideShow::SlideDeltaApplyStart (name); _remote_provide = true; } /** @@ -454,7 +455,7 @@ */ global void StartPatchProvide( string name, integer archivesize ) { - SlideShow::SlideGenericProvideStart (name , archivesize, _("Downloading patch RPM %1 (download size %2)"), true /*remote*/); + PackageSlideShow::SlideGenericProvideStart (name , archivesize, _("Downloading patch RPM %1 (download size %2)"), true /*remote*/); _remote_provide = true; } @@ -463,7 +464,7 @@ */ global void ProgressDeltaApply( integer percent ) { - SlideShow::UpdateCurrentPackageProgress ( percent ); + PackageSlideShow::UpdateCurrentPackageProgress ( percent ); } /** @@ -500,9 +501,9 @@ global void CallbackSourceChange( integer source, integer media) { PackageCallbacks::SourceChange( source, media ); // inform PackageCallbacks about the change - SlideShow::SetCurrentCdNo( source, media ); - SlideShow::UpdateCurrentPackageProgress(0); - SlideShow::UpdateAllCdProgress(false); + PackageSlideShow::SetCurrentCdNo( source, media ); + PackageSlideShow::UpdateCurrentPackageProgress(0); + PackageSlideShow::UpdateAllCdProgress(false); }; global string MediaChange (string error_code, string error, string url, string product, @@ -525,7 +526,7 @@ // moved from PackageCallbacks if (ret == "" || URL::Check(ret)) { - SlideShow::SetCurrentCdNo (PackageCallbacks::_current_source, wanted); + PackageSlideShow::SetCurrentCdNo (PackageCallbacks::_current_source, wanted); } } Added: trunk/packager/src/modules/Slides.ycp URL: http://svn.opensuse.org/viewcvs/yast/trunk/packager/src/modules/Slides.ycp?rev=50558&view=auto ============================================================================== --- trunk/packager/src/modules/Slides.ycp (added) +++ trunk/packager/src/modules/Slides.ycp Tue Sep 2 11:23:10 2008 @@ -0,0 +1,205 @@ +/** + * Module: Slides.ycp + * + * Purpose: Module to access slides from installation repository + * + * Author: Stefan Hundhammer <sh@suse.de> + * Stanislav Visnovsky <visnov@suse.cz> + * + */ +{ + module "Slides"; + + textdomain "packager"; + + import "FileUtils"; + import "Installation"; + + // list of currently known slides, in the order they should be shown + global list<string> slides = []; + // base path to look for slides + global string slide_base_path = Installation::sourcedir + "/suse/setup/slide"; + // path to look for texts of slides + global string slide_txt_path = ""; + // path to look for images of slides + global string slide_pic_path = ""; + // if no other language is configured, use this fallback + global string fallback_lang = "en"; + + + + /** + * Get a list of available slides (images) for the slide show. + * @param lang language of slides to load + * @return list slides + **/ + list<string> GetSlideList( string lang ) + { + list<string> slide_list = nil; + + string txt_path = sformat( "%1/txt/%2", slide_base_path, lang ); + if (FileUtils::Exists (txt_path)) { + slide_list = (list<string>) SCR::Read (.target.dir, txt_path ); + } + + if ( slide_list == nil ) + { + y2error( "Directory %1 does not exist", txt_path ); + if ( size( lang ) > 2 ) + { + lang = substring( lang, 0, 2 ); + txt_path = sformat( "%1/txt/%2", slide_base_path, lang ); + + if (FileUtils::Exists (txt_path)) { + slide_list = (list<string>) SCR::Read (.target.dir, txt_path ); + } + } + } + + if ( slide_list == nil ) + { + y2milestone( "Slideshow directory %1 does not exist", txt_path ); + } + else + { + y2milestone ("Using slides from '%1' (%2 slides)", txt_path, size (slide_list)); + + slide_list = sort( filter( string filename, slide_list, ``{ + // Check for valid extensions - ignore editor save files and other leftover stuff + return regexpmatch( filename, ".*\.(rtf|RTF|html|HTML|htm|HTM)$" ); + } ) ); + + y2debug( "GetSlideList(): Slides at %1: %2", txt_path, slide_list ); + } + + if ( slide_list != nil && size( slide_list ) > 0 ) // Slide texts found + { + slide_txt_path = txt_path; + slide_pic_path = slide_base_path + "/pic"; + + y2milestone ("Using TXT: %1, PIC: %2", slide_txt_path, slide_pic_path); + } + else // No slide texts found + { + y2debug( "No slides found at %1", txt_path ); + + // function calls itself! + if ( lang != fallback_lang ) + { + y2debug( "Trying to load slides from fallback: %1", fallback_lang ); + slide_list = GetSlideList( fallback_lang ); + } + } + + return slide_list; + } + + + /** + * Check if showing slides is supported. + * + * Not to be confused with HaveSlides() which checks if there are slides available. + * @return boolean if the current UI is capable of showing slides + **/ + global boolean HaveSlideSupport() + { + map disp = UI::GetDisplayInfo(); + + if (disp != nil // This shouldn't happen, but who knows? + && disp["HasImageSupport"]:false + && disp["DefaultWidth"]:-1 >= 800 + && disp["DefaultHeight"]:-1 >= 600 + && disp["Depth"]:-1 >= 8 ) + { + return true; + } + else + { + return false; + } + } + + + /** + * Check if slides are available. + * + * Not to be confused with HaveSlideSupport() which checks + * if slides could be displayed if there are any. + * @return boolean if the loaded list of slides contains any slides + **/ + global boolean HaveSlides() + { + return size( slides ) > 0; + } + + /** + * Load one slide from files complete with image and textual description. + * Also adapt img links + * @param slide_name name of the slide + * @return true if OK, false if error + **/ + global string LoadSlideFile( string slide_name ) + { + string text_file_name = sformat ("%1/%2", slide_txt_path, slide_name ); + // returns empty string if not found + string text = (string) SCR::Read( .target.string, [text_file_name, ""] ); + + // + // Fix <img src> tags: Replace image path with current slide_pic_path + // + while (true) + { + string replaced = regexpsub( text, "(.*)&imagedir;(.*)", + sformat("\\1%1\\2", slide_pic_path ) ); + if ( replaced == nil ) break; + text = replaced; + } + + return text; + } + + + /** + * Set the slide show directory + */ + global void SetSlideDir( string dir ) + { + slide_base_path = dir; + + map tmp = (map) WFM::Read (.local.stat, slide_base_path); + + if ( ! tmp["isdir"]:false ) + { + y2error( "Using default path instead of %1", tmp ); + slide_base_path = "/var/adm/YaST/InstSrcManager/tmp/CurrentMedia/suse/setup/slide"; + } + + y2milestone( "SetSlideDir: %1", slide_base_path ); + } + + /** + * Load slides for the given language and store them in the internal variables. + * @param language requested language of the slides + */ + global void LoadSlides( string language ) + { + slides = GetSlideList( language ); + } + + /** + * Check, if the base path set up for slides is valid (it exists and contains slides) + * @return boolean true, if it is possible to load the slides + */ + global boolean CheckBasePath() + { + map tmp = (map) WFM::Read(.local.stat, slide_base_path); + if (! tmp["isdir"]:false) + { + y2error( "Using default path instead of %1", slide_base_path ); + slide_base_path = "/var/adm/YaST/InstSrcManager/tmp/CurrentMedia/suse/setup/slide"; + + return false; + } + return true; + } +} -- To unsubscribe, e-mail: yast-commit+unsubscribe@opensuse.org For additional commands, e-mail: yast-commit+help@opensuse.org
participants (1)
-
visnov@svn.opensuse.org