progress.cpp

Go to the documentation of this file.
00001 // $Id: progress.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 //  The progress indicator, for slow operations (kernel implementation).
00100 
00101 
00102 #include "camtypes.h"
00103 
00104 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00105 #include "csrstack.h"
00106 //#include "jason.h"
00107 #include "keypress.h"
00108 //#include "mainfrm.h"
00109 //#include "monotime.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "oilprog.h"
00111 //#include "progbar.h"
00112 //#include "node.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 #include "statline.h"
00114 
00115 #include "progress.h"
00116 
00117 
00118 DECLARE_SOURCE("$Revision: 1282 $");
00119 
00120 CC_IMPLEMENT_MEMDUMP(Progress, CC_CLASS_MEMDUMP)
00121 
00122 #define new CAM_DEBUG_NEW
00123 
00124 
00125 BOOL Progress::AbortJob     = FALSE;        // TRUE if the we want to abort a job in ralph
00126 
00127 
00128 #if !defined(EXCLUDE_FROM_RALPH)
00129 
00130 // --- Thread activation - set to 1 to enable the delayed-show thread
00131 // (NOTE: The start-delay thread is currently non-operational, so turning it on
00132 // has no effect. See below for details)
00133 #define DELAY_THREAD 0
00134 
00135 // --- Debugging trace statements. Set to 1 to turn on debug output
00136 #define DEBUG_OUTPUT 0
00137 
00138 
00139 // --- Constants
00140 // IMMEDIATE REDRAW
00141 // const INT32 STARTDELAY = 3333;
00142 const INT32 STARTDELAY = 333;                       // Default delay before cursor appears (1/3rd sec)
00143 
00144 
00145 
00146 /********************************************************************************************
00147 
00148 >   BOOL BeginSlowJob(INT32 finalcount = -1, BOOL delay = TRUE, String_64 *Description = NULL)
00149     Purpose:    DEPRECATED - do not call this function!
00150     SeeAlso:    Progress::Start; Progress::Progress
00151 
00152 ********************************************************************************************/
00153 
00154 BOOL BeginSlowJob(INT32 finalcount /* =-1 */, BOOL delay /* = TRUE */,
00155                     String_64 *Description /* = NULL */)
00156 {
00157     Progress::Start(delay, Description, finalcount);
00158 
00159     return(TRUE);
00160 }
00161 
00162 
00163 
00164 /********************************************************************************************
00165 
00166 >   BOOL ContinueSlowJob(INT32 upto = 0) 
00167     Purpose:    DEPRECATED - do not call this function!
00168     SeeAlso:    Progress::Update
00169 
00170 ********************************************************************************************/
00171 
00172 BOOL ContinueSlowJob(INT32 upto)
00173 {
00174     return(Progress::Update(upto));
00175 }
00176 
00177 
00178 
00179 /********************************************************************************************
00180 
00181 >   void EndSlowJob(void)
00182     Purpose:    DEPRECATED - do not call this function!
00183     SeeAlso:    Progress::Stop
00184 
00185 ********************************************************************************************/
00186 
00187 void EndSlowJob(void)
00188 {
00189     Progress::Stop();
00190 }
00191 
00192 
00193 
00194 /********************************************************************************************
00195 
00196 >   void SmashSlowJob(void)
00197     Purpose:    DEPRECATED - do not call this function!
00198     SeeAlso:    Progress::Smash
00199 
00200 ********************************************************************************************/
00201 
00202 void SmashSlowJob(void)
00203 {
00204     Progress::Smash();
00205 }
00206 
00207 
00208 
00209 
00210 
00211 
00212 
00213 
00214 
00215 
00216 
00217 // -----------------------------------------------------------------------------------------
00218 // --- The new Progress class - firstly the static threading support
00219 
00220 #if DELAY_THREAD
00221 // Thread control
00222 volatile static BOOL ThreadAlive = FALSE;           // TRUE while the thread is alive - set to FALSE to kill it
00223 
00224 
00225 /********************************************************************************************
00226 
00227 >   static UINT32 ThreadProc(LPVOID Param)
00228 
00229     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00230     Date:       10/11/95
00231 
00232     Purpose:    This function is the progress system's delayed-show thread. It runs
00233                 alongside the main program, sleeping for 1/3rd of a second. After this
00234                 delay period, it calls Progress::ThreadCallback.
00235 
00236     Notes:      While this thread is running, ThreadAlive will be TRUE.
00237                 Set ThreadAlive to FALSE to kill the thread.
00238 
00239     Scope:      static/private in winoil\progress.cpp
00240 
00241     SeeAlso:    Progress::ThreadCallback
00242 
00243 ********************************************************************************************/
00244 
00245 static UINT32 ThreadProc(LPVOID Param)
00246 {
00247     // If there's already an active thread, then we'll exit immediately
00248     if (ThreadAlive)
00249         return(0);
00250 
00251     // Flag the fact that we are alive
00252     ThreadAlive = TRUE;
00253 
00254     // While we're alive, update the progress display periodically. 
00255     // The main program thread will set ThreadAlive=FALSE if they want us to stop
00256     while (ThreadAlive)
00257     {
00258         Sleep(STARTDELAY);
00259 
00260         if (ThreadAlive)    // Check again as the value may have changed while we slept
00261             Progress::ThreadCallback();
00262     }
00263 
00264     return(0);
00265 }
00266 #endif
00267 
00268 
00269 
00270 /********************************************************************************************
00271 
00272 >   static void Progress::ThreadCallback(void)
00273 
00274     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00275     Date:       10/11/95
00276 
00277     Purpose:    This method is called by our delay thread to show any delayed progress
00278                 displays that we wish to display. It should not be called from elsewhere.
00279 
00280     Notes:      There are 2 progress displays - the hourglass and progress bar. There is no
00281                 point in showing the bar until there is a percentage to display, so this
00282                 function only turns on the hourglass cursor.
00283 
00284                 NOTE also that if you change this method do anything more than this, you
00285                 must be very careful - generally the thread can introduce instability
00286                 that causes random access violations and stuff.
00287 
00288     Scope:      public, but don't let that fool you. It'd be private but for a technical hitch.
00289 
00290     SeeAlso:    ::ThreadProc
00291 
00292 ********************************************************************************************/
00293 
00294 void Progress::ThreadCallback(void)
00295 {
00296 #if DELAY_THREAD
00297     //-- This does not work. The SetCursor call is executed, but the cursor stubbornly
00298     //-- refuses to change shape - I suspect this is because the window under the cursor
00299     //-- belongs to the main process thread, not us...
00300 
00301     // Tell the thread that it can exit now
00302     ThreadAlive = FALSE;
00303 
00304     // And change the cursor shape to an hourglass
00305     // NOTE that I don't call BeginBusyCursor here, to avoid the cursor stack
00306     // doing anything - that way the busy pointer will happily go away as soon as anyone
00307     // tries to do anything with the Camelot cursor stack.
00308     HCURSOR Busy = ::LoadCursor(NULL, _R(IDC_WAIT));
00309     ::SetCursor(Busy);
00310 #endif
00311 }
00312 
00313 
00314 
00315 
00316 // -----------------------------------------------------------------------------------------
00317 // --- The new Progress class
00318 
00319 // --- Statics
00320 INT32 Progress::ActiveDisplays  = 0;            // A count of the number of active progress incarnations
00321 BOOL Progress::JobCancelled     = FALSE;        // TRUE if the job has been cancelled
00322 
00323 BOOL Progress::JobDelayed       = FALSE;        // TRUE if the job has a delayed-start
00324 
00325 INT32 Progress::FinalCount      = 0;            // The number we're currently counting up to
00326 INT32 Progress::CurrentPercent  = 0;            // The number we're currently counting up to
00327 
00328 BOOL Progress::HourglassShown   = FALSE;        // TRUE if we have already shown the hourglass
00329 
00330 String_64 Progress::JobDescription = TEXT("");  // A description of the current job
00331 BOOL Progress::HaveJobDescription = FALSE;      // TRUE if JobDescription is a proper (caller supplied) one
00332 
00333 MonotonicTime Progress::StartTime;              // Time the first call to Show() was made
00334 
00335 //CProgressBar *Progress::ProgBar = NULL;           // The progress bar object (if used)
00336 
00337 
00338 /********************************************************************************************
00339 
00340     Preference:     ProgressBar
00341     Section:        Displays
00342     Range:          TRUE or FALSE
00343     Purpose:        If TRUE, a progress bar will be displayed while Camelot is busy
00344                     processing.
00345     SeeAlso:        Hourglass
00346 
00347 ********************************************************************************************/
00348 
00349 INT32 Progress::DisplayBar = TRUE;              // Preference: Is progress bar shown?
00350 
00351 
00352 
00353 
00354 
00355 /********************************************************************************************
00356 
00357 >   Progress::Progress()
00358 
00359     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00360     Date:       10/11/95
00361 
00362     Purpose:    Constructs an instance of a Progress object.
00363                 This starts the hourglass running.
00364                 Destruct the object to stop the hourglass.
00365 
00366                 See Progress::Start() for more details on the progress system
00367 
00368     Notes:      IMPORTANT!
00369                 Only use this constructor for small, deep-down functions which you can't
00370                 supply a useful operation description for. Whenever we're busy we must
00371                 endeavour to show a useful description to the user.
00372 
00373     SeeAlso:    Progress::~Progress; Progress::Start
00374 
00375 ********************************************************************************************/
00376 
00377 Progress::Progress()
00378 {
00379     ProgressCount = 0;
00380 
00381     Progress::Start(TRUE, (StringBase *)NULL, -1);
00382 }
00383 
00384 
00385 
00386 /********************************************************************************************
00387 
00388 >   Progress::Progress(StringBase *Description, INT32 FinalCount,BOOL Delay=TRUE, BOOL bEnable = TRUE)
00389 >   Progress::Progress(UINT32 DescriptionID, INT32 FinalCount,BOOL Delay=TRUE, BOOL bEnable = TRUE)
00390 
00391     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00392     Date:       10/11/95
00393 
00394     Inputs:     Description - A pointer to a string describing what the program is busy doing
00395                 or DescriptionID - The string Resource ID of the string to use
00396 
00397                 FinalCount  - -1 if you want no progress bar (percentage) indication, else
00398                               the number you expect to count up to (e.g. number of lines
00399                               in the file you're reading, number of nodes you're changing, etc)
00400 
00401                 Delay       - TRUE if you want the hourglass to appear after a short delay
00402                               FALSE for it to appear immediately
00403 
00404     Purpose:    Constructs an instance of a Progress object.
00405                 This starts the hourglass (and optional progress bar) running.
00406                 Destruct the object to stop the hourglass.
00407 
00408                 See Progress::Start() for more details on the progress system
00409 
00410     SeeAlso:    Progress::~Progress; Progress::Start; Progress::Update
00411 
00412 ********************************************************************************************/
00413 
00414 Progress::Progress(StringBase *Description, INT32 FinalCount,BOOL Delay, BOOL bEnable)
00415 {
00416     if (bEnable)
00417     {
00418         ProgressCount = 0;
00419         ERROR3IF(Description == NULL, "Progress constructor - Illegal NULL parameter");
00420         Progress::Start(Delay, Description, FinalCount);
00421     }
00422 }
00423 
00424 
00425 Progress::Progress(UINT32 DescriptionID, INT32 FinalCount,BOOL Delay, BOOL bEnable)
00426 {
00427     if (bEnable)
00428     {
00429         ProgressCount = 0;
00430         ERROR3IF(!DescriptionID, "Progress constructor - Illegal NULL parameter");
00431         Progress::Start(Delay, DescriptionID, FinalCount);
00432     }
00433 }
00434 
00435 
00436 
00437 /********************************************************************************************
00438 
00439 >   Progress::~Progress()
00440 
00441     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00442     Date:       10/11/95
00443 
00444     Purpose:    Destructs an instance of a Progress object.
00445                 This stops the hourglass (and optional progress bar) which the constructor
00446                 started going.
00447 
00448     SeeAlso:    Progress::Progress; Progress::Stop
00449 
00450 ********************************************************************************************/
00451 
00452 Progress::~Progress()
00453 {
00454     Progress::Stop();
00455 }
00456 
00457 
00458 /********************************************************************************************
00459 
00460 >   BOOL Progress::SetDescription(const StringBase* const Description)
00461 
00462     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00463     Date:       18/12/96
00464 
00465     Inputs:     Description:    See Start() for a description of this parameter
00466 
00467     Purpose:    Gives the user some textual description of what's going on when the hourglass
00468                 is blocking the view.
00469 
00470 ********************************************************************************************/
00471 BOOL Progress::SetDescription(const StringBase* const Description)
00472 {
00473     Description->Left(&JobDescription, 63);
00474     HaveJobDescription = TRUE;
00475 
00476     return TRUE;
00477 }
00478 
00479 
00480 /********************************************************************************************
00481 
00482 >   void Progress::Start(BOOL Delay, StringBase *Description, INT32 FinalCount)
00483 >   void Progress::Start(BOOL Delay, UINT32 DescriptionID, INT32 FinalCount)
00484 
00485     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00486     Date:       10/11/95
00487 
00488     Inputs:     Delay       - TRUE to start the hourglass after a 1/3rd second delay
00489                               FALSE to show the hourglass immediately [see Notes]
00490 
00491                 Description - NULL ("Processing... please wait") or a pointer to a string
00492                               describing what the program is currently busy doing
00493                 or DescriptionID - NULL or the string Resource ID of the string to use
00494 
00495                 FinalCount  - -1 if you want no progress bar (percentage) indication, else
00496                               the number you expect to count up to (e.g. number of lines
00497                               in the file you're reading, number of nodes you're changing, etc)
00498 
00499     Purpose:    [NOTE that to show a progress display, the easiest system is to construct
00500                 a Progress object - this will automatically turn the hourglass off when the
00501                 object is destructed. Only use this call if you need lower level control
00502                 or it is a lot more convenient than a simple instance of the class]
00503 
00504                 Starts a progress (hourglass and optional progress bar) indication. Call this
00505                 when you start doing something that could take a significant amount of time
00506                 (more than half a second delay should show an hourglass under all circumstances)
00507 
00508     Notes:      The delay parameter specifies whether the hourglass should be shown immediately
00509                 or if its appearance should be put off for a short time in case you don't take
00510                 as long as you thought you might. NOTE however, that you *must* call 
00511                 Progress::Update at frequent intervals or the delayed hourglass may never appear!
00512                 Note that Progress::Update is very efficient, so may be called very often (it
00513                 only updates 6 times a second at the most).
00514 
00515                 IMPORTANT - The description should be filled in with an appropriate string.
00516                 We must avoid use of the default generic description whenever possible.
00517 
00518                 Multiple progress indications may be active at any time. In this case, the
00519                 calls to Start and Stop are "stacked" so the hourglass will only go away when
00520                 all Start calls have been countermanded by Stops. Preferably, the outermost
00521                 Start/Stop will provide a progress percentage, while the inner ones will
00522                 simply use Start() with the default parameters, merely to ensure that an
00523                 hourglass is shown while they are busy. Don't rely upon your caller to
00524                 show the hourglass for you! The start/stop/update calls have all been designed
00525                 to be called often without introducing noticable performance overheads.
00526 
00527     SeeAlso:    Progress::Start; Progress::Update; Progress::Stop; Progress::Smash;
00528                 Progress::Progress
00529 
00530 ********************************************************************************************/
00531 
00532 void Progress::Start(BOOL Delay, UINT32 DescriptionID, INT32 IntendedFinalCount)
00533 {
00534     if (!DescriptionID)
00535         Progress::Start(Delay, (StringBase *)NULL, IntendedFinalCount);
00536     else
00537     {
00538         String_256 Description(DescriptionID);
00539 
00540         Progress::Start(Delay, (StringBase *)&Description, IntendedFinalCount);
00541     }
00542 }
00543 
00544 
00545 
00546 void Progress::Start(BOOL Delay, StringBase *Description, INT32 IntendedFinalCount)
00547 {
00548 #if DEBUG_OUTPUT
00549 TRACE( _T("Progress::Start ActiveDisplays = %d IntendedFinalCount = %d\n"),ActiveDisplays,IntendedFinalCount);
00550 #endif
00551 
00552     // Ensure the ActiveDisplays value is valid
00553     if (ActiveDisplays < 0)
00554         ActiveDisplays = 0;
00555 
00556     ActiveDisplays++;
00557     if (ActiveDisplays <= 1)
00558     {
00559         // --- We're starting a brand new progress indication - set everything up
00560         JobDelayed      = Delay;
00561         JobCancelled    = FALSE;
00562         CurrentPercent  = 0;
00563         FinalCount      = IntendedFinalCount;
00564         HourglassShown  = FALSE;
00565 
00566         // Remember when we started and when we last updated the screen displays
00567         StartTime.Sample();
00568 
00569         if (Description != NULL)
00570         {
00571             SetDescription(Description);
00572         }
00573         else
00574         {
00575             JobDescription.MakeMsg(_R(IDS_BUSYMSG));
00576             HaveJobDescription = FALSE;
00577         }
00578 
00579         // Inform the Node subsystem that we're putting up an hourglass
00580         Node::StartHourglass();
00581 
00582         // Update the status line text
00583         GetApplication()->UpdateStatusBarText((String_256 *)&JobDescription, FALSE);
00584 
00585 #if DELAY_THREAD
00586         // Attempt to start a thread to show the hourglass after a delay
00587         if (JobDelayed)
00588             ::AfxBeginThread(ThreadProc, NULL);
00589 #endif
00590     }
00591     else
00592     {
00593         // --- We're starting a progress indication while another one is already active.
00594         // If they've got a better idea about what the final count should be, use their estimate
00595 
00596         // If an "inner" job wants the hourglass to _not_ be delayed, we override the
00597         // current JobDelayed state to make sure it definitely shows an hourglass
00598         if (!Delay)
00599             JobDelayed = FALSE;
00600 
00601         // Removed by Jason, 22/1/96. This causes ensures to go off and bad progress
00602         // displays when you have a case like the following:
00603         //      Start (-1)
00604         //          Start(100)
00605         //          End
00606         //          Start(200)
00607         //          End
00608         //      End
00609         // ...In the 2nd progress bar, the FinalCount remains at 100, so Update error3's
00610         // This occurs in saving/exporting and other multi-part busy processes
00611         // A proper fix for this problem requires proper nesting of hourglasses,
00612         // which is not feasible at this stage (a *lot* of conversion work on
00613         // existing code would be necessary).
00614         // This still won't work if progress bars are nested, but should work
00615         // reasonably well otherwise.
00616         //      if (FinalCount <= 0)
00617         //          FinalCount = IntendedFinalCount;
00618         // The replacement code for the above now occurs below, after we get the JobDescription
00619         
00620 
00621         // Similarly, if we have only a generic job desc and they've supplied one, then we'll
00622         // use the one that they supplied.
00623         if (!HaveJobDescription && Description != NULL)
00624         {
00625             SetDescription(Description);
00626         }
00627 
00628         // Check if we're starting a new progress-bar job, in which case it overrides
00629         // any previous settings for FinalCount and the description string
00630         if (IntendedFinalCount > 0)
00631         {
00632             FinalCount = IntendedFinalCount;
00633 
00634             // And reset the current percentage and job description fields
00635             CurrentPercent  = 0;
00636             if (Description != NULL)
00637             {
00638                 SetDescription(Description);
00639             }
00640 
00641             // And reset/redraw the progress bar display to make sure it starts from 0 again
00642             // and shows the new job description (if any).
00643             if (StatusLine::Get())
00644             {
00645                 StatusLine::Get()->SetPercent(0, TRUE, (HaveJobDescription) ? &JobDescription : NULL);
00646             }
00647         }
00648     }
00649 
00650     // And finally, update to show the current state. This will show the progress displays
00651     // if appropriate at this time, etc.
00652     Progress::Update(0);
00653 }
00654 
00655 
00656 
00657 /********************************************************************************************
00658 
00659 >   BOOL Progress::Update(INT32 CurrentCount = 0,BOOL FreqEscChecks = FALSE)
00660 
00661     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00662     Date:       10/11/95
00663 
00664     Inputs:     CurrentCount - 0 if you are not maintaining a percentage display, or if you
00665                 simply don't want to update the percentage on this particular call.
00666                 Otherwise, a value between 0 and the FinalCount value passed to Start().
00667                 This value is used to calculate a percentage value to display.
00668 
00669                 FreqEscChecks = if TRUE, the escape key is checked once, guaranteed
00670                                 if FALSE, the escape key will only be checked if the percentage displayed increases
00671 
00672     Returns:    TRUE if everything is OK
00673                 FALSE if the user has aborted the job by pressing 'escape'
00674 
00675     Purpose:    Updates progress indications. This serves 3 purposes:
00676                 a) To show the progress indications if a delayed-start was specified in
00677                    your call to Start(). This is the default action.
00678                 b) To check for the user pressing escape to abort the job
00679                 c) To change the displayed percentage on the progress bar and animated cursor
00680 
00681     Notes:      This function is very efficient so it is perfectly safe to call it often.
00682 
00683                 In fact, if it is not called often,
00684                 a) Delayed start won't work, and you may not get an hourglass at all!
00685                 b) The user won't be able to abort part way through a job
00686 
00687                 WHEN IN DOUBT, CALL THIS ROUTINE. IT IS BETTER TO CALL IT TOO OFTEN
00688                 THAN TO NOT CALL IT OFTEN ENOUGH.
00689 
00690                 It is safe to call this function at ANY time, even if no progress indication
00691                 is active, so if your function can take more than 1/3rd of a second to
00692                 execute, it really should call Update occasionally just to ensure smooth
00693                 operation.
00694 
00695                 You need not check the return value on every call. Once the user has pressed
00696                 escape, this function will always return FALSE until someone takes note.
00697                 Thus, routines which cannot cope with abortion can possibly leave abortion
00698                 to their callers.
00699 
00700                 The percentage is only updated if it has become greater than the currently
00701                 displayed percentage value.
00702 
00703                 The FreqEscChecks parameter (markn) - this param will control the frequency
00704                 with which the escape key is checked when this function is called.
00705                 If it is TRUE, it is checked once, guaranteed.
00706                 If it is FALSE, it is only checked if the percentage displayed increases.
00707 
00708                 You should only call with FreqEscChecks = FALSE if you can detect a performance hit due
00709                 to too many escape key checks.
00710                 
00711                 NOTE: If you call with FreqEscChecks = FALSE, and you never display a percentage, the user
00712                 will not be able to abort the op part way through.
00713 
00714 
00715 
00716     SeeAlso:    Progress::Start; Progress::Update; Progress::Stop; Progress::Smash
00717 
00718 ********************************************************************************************/
00719 
00720 BOOL Progress::Update(INT32 CurrentCount,BOOL FreqEscChecks)
00721 {
00722 #if DEBUG_OUTPUT
00723 TRACE( _T("Progress::Update ActiveDisplays = %d CurrentCount = %d FinalCount=%d\n"),ActiveDisplays,CurrentCount, FinalCount);
00724 #endif
00725 
00726     // --- If no active progress display is on, then return immediately
00727     if (ActiveDisplays <= 0)
00728     {
00729         ActiveDisplays = 0;
00730         return(TRUE);
00731     }
00732 
00733     // --- If the job has been cancelled, then return FALSE to indicate user intervention
00734     if (JobCancelled)
00735         return(FALSE);
00736 
00737     // If FreqEscChecks is TRUE, ensure we check the escape key, no matter what percentage is displayed 
00738     if (FreqEscChecks)
00739     {
00740         // Has the user cancelled the job via the Escape key?
00741         if (KeyPress::IsEscapePressed())
00742         {
00743             JobCancelled = TRUE;
00744             Beep();
00745             return(FALSE);
00746         }
00747     }
00748 
00749     // --- If the startup delay (if any) has not expired, we do nothing just yet
00750     if (JobDelayed && !StartTime.Elapsed(STARTDELAY))
00751         return(TRUE);
00752 
00753     // --- Check that the parameter passed in was vaguely sensible
00754     ERROR3IF(CurrentCount < 0, "Progress::Update called with out of range parameter");
00755 
00756     // --- If we haven't yet shown the hourglass cursor, do it now
00757     if (!HourglassShown)
00758     {
00759 #if DELAY_THREAD
00760         ThreadAlive = FALSE;        // Stop the delay thread (if any) because it's not needed now
00761 #endif
00762         BeginBusyCursor();
00763         HourglassShown = TRUE;
00764 
00765     }
00766 
00767     // --- Calculate the new percentage to display. This is limited to lie between
00768     // the last displayed percentage and 99 inclusive.
00769     INT32 NewPercent = CurrentPercent;
00770     if (FinalCount > 0)
00771     {
00772         NewPercent = (100 * CurrentCount) / FinalCount;
00773 
00774         if (NewPercent > 99)
00775             NewPercent = 99;
00776         
00777         if (NewPercent < CurrentPercent)
00778             NewPercent = CurrentPercent;
00779     }
00780 
00781     // --- Now, update the percentage display if it has changed, or if it is a while since
00782     // our last update. NOTE: Updates occur periodically for (a) checking the escape key state
00783     // occasionally, so we can be called often without a huge performance hit, and (b) to 
00784     // update frames of our animated hourglass pointer.
00785     if (NewPercent > CurrentPercent)
00786     {
00787         // If FreqEscChecks is FALSE, we only check the escape key when the percentage increases
00788         if (!FreqEscChecks)
00789         {
00790             // Has the user cancelled the job via the Escape key?
00791             if (KeyPress::IsEscapePressed())
00792             {
00793                 JobCancelled = TRUE;
00794                 Beep();
00795                 return(FALSE);
00796             }
00797         }
00798 
00799         // (Create if necessary) and update the progress bar, if it is needed
00800         if (DisplayBar && FinalCount > 0)
00801         {
00802             if (StatusLine::Get())
00803             {
00804                 StatusLine::Get()->ShowProgress(TRUE, &JobDescription);
00805                 StatusLine::Get()->SetPercent(NewPercent);
00806             }
00807         }
00808 
00809         // Remember the last displayed percentage
00810         CurrentPercent = NewPercent;
00811     }
00812 
00813     return(TRUE);
00814 }
00815 
00816 
00817 
00818 /********************************************************************************************
00819 
00820 >   void Progress::Stop(void)
00821 
00822     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00823     Date:       10/11/95
00824 
00825     Purpose:    Stops a progress indication started with a call to Start()
00826                 The hourglass and progress bar etc will only be removed once all calls
00827                 to Start() have been countermanded by calls to Stop().
00828 
00829     Notes:      Be careful to call Stop() exactly the same number of times as Start() through
00830                 each possible execution path!
00831 
00832                 It is recommended that you do not call Start() and Stop() directly, but 
00833                 instead construct a local instance of the Progress class in your function.
00834                 This will automatically start and stop the hourglass for you, and also
00835                 ensures that Start() and Stop() calls are correctly nested/balanced.
00836 
00837     SeeAlso:    Progress::Start; Progress::Update; Progress::Stop; Progress::Smash
00838 
00839 ********************************************************************************************/
00840 
00841 void Progress::Stop(void)
00842 {
00843 #if DEBUG_OUTPUT
00844 TRACE( _T("Progress::Stop ActiveDisplays = %d \n"),ActiveDisplays);
00845 #endif
00846 
00847     // Decrement the usage count. The progress display remains until the count returns to zero
00848     ActiveDisplays--;
00849 
00850     if (ActiveDisplays <0)
00851     {
00852         // This should never happen but does as Op::End() calls EndSlowJob despite
00853         // BeginSlowJob() not being called first. We return immediately because Progress::Smash() is
00854         // expensive and not a great thing to do on every Op.
00855         ActiveDisplays = 0;
00856         return;
00857     }
00858 
00859     // Return if there are active displays left
00860     if (ActiveDisplays > 0)
00861         return;
00862 
00863     // We have zero active displays, and before the call, had a positive number, so smash the
00864     // hourglass and delete the progress bar
00865 
00866     if (StatusLine::Get() && StatusLine::Get()->IsProgressShown() && CurrentPercent < 97)
00867     {
00868         // We are showing a progress bar, but have not shown "completion" of the job (99%)
00869         // Briefly jump to 99% on the progress bar so the user can't see how bad our estimate
00870         // of when we'd finish really was.
00871 
00872         StatusLine::Get()->SetPercent(99);
00873 
00874         ::wxMilliSleep(150); /* wait */ 
00875     }
00876 
00877     // Make sure everything is reset properly
00878     Progress::Smash(TRUE);
00879 }
00880 
00881 
00882 
00883 /********************************************************************************************
00884 
00885 >   void Progress::Smash(BOOL ForceSmash = FALSE)
00886 
00887     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00888     Date:       10/11/95
00889 
00890     Inputs:     ForceSmash - Pass in FALSE for this parameter - for internal use only
00891                 [Forces the hourglass to be smashed even if we believe it is not actually
00892                 running at present. Used by Progress::Stop to kill its displays when its
00893                 usage count is decremented to zero. Calling with TRUE is a lot less efficient
00894                 than with FALSE when no jobs are currently active]
00895 
00896     Purpose:    Smashes the hourglass and other progress displays. This kills all active
00897                 progress indications immediately, as if Progress::Stop() had been called enough
00898                 times to cancel all active displays.
00899 
00900     Notes:      Returns very quickly if no jobs are running, so can be called often
00901                 without significant loss of efficiency.
00902 
00903                 This is called on each idle event to ensure that spurious hourglasses
00904                 are removed.
00905 
00906     SeeAlso:    Progress::Start; Progress::Update; Progress::Stop; Progress::Smash
00907 
00908 ********************************************************************************************/
00909 
00910 void Progress::Smash(BOOL ForceSmash)
00911 {
00912     if (ActiveDisplays > 0 || ForceSmash)
00913     {
00914 #if DELAY_THREAD
00915         ThreadAlive = FALSE;        // Stop the delay thread (if any)
00916 #endif
00917 
00918         // --- Tell the node subsystem that we're turning off the hourglass
00919         Node::StopHourglass();
00920 
00921         // --- Blank the status line text
00922         String_256 Blank("");
00923         GetApplication()->UpdateStatusBarText(&Blank);
00924 
00925         // --- Remove any active progress bar
00926         if (StatusLine::Get())
00927         {
00928             StatusLine::Get()->ShowProgress(FALSE);
00929         }
00930 
00931         // --- And reset all variables to suitable defaults
00932         ActiveDisplays  = 0;
00933         JobCancelled    = FALSE;
00934 
00935         JobDelayed      = TRUE;
00936         FinalCount      = 0;
00937         CurrentPercent  = 0;
00938         HourglassShown  = FALSE;
00939 
00940         JobDescription.MakeMsg(_R(IDS_BUSYMSG));
00941     }
00942 
00943     // --- And ensure no busy cursors are left active
00944     SmashBusyCursor();
00945 }
00946 
00947 
00948 
00949 /********************************************************************************************
00950 
00951 >   static BOOL Progress::Init(void)
00952 
00953     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00954     Date:       10/11/95
00955 
00956     Returns:    TRUE for success, FALSE for failure
00957 
00958     Purpose:    Initialise the progress display system. Call once on startup
00959                 (see main3.cpp)
00960 
00961     SeeAlso:    Progress::DeInit
00962 
00963 ********************************************************************************************/
00964 
00965 BOOL Progress::Init(void)
00966 {
00967     Camelot.DeclareSection(TEXT("Displays"), 8);
00968     Camelot.DeclarePref(TEXT("Displays"), TEXT("ProgressBar"), &DisplayBar);
00969 
00970     return(TRUE);       // We successfully initialised
00971 }
00972 
00973 
00974 
00975 /********************************************************************************************
00976 
00977 >   static BOOL Progress::DeInit(void)
00978 
00979     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00980     Date:       10/11/95
00981 
00982     Returns:    TRUE for success, FALSE for failure
00983 
00984     Purpose:    De-initialise the progress display system. Call once on shutdown
00985                 (see main.cpp)
00986 
00987     SeeAlso:    Progress::Init
00988 
00989 ********************************************************************************************/
00990 
00991 BOOL Progress::Deinit(void)
00992 {
00993     return(TRUE);
00994 }
00995 
00996 /********************************************************************************************
00997 
00998 >   static void Progress::SetFinalCount(INT32 n);
00999 
01000     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01001     Date:       18/1/96
01002     Inputs:     n = the final count value
01003     Returns:    -
01004     Purpose:    Allows you to set this value after construction of a Progress object.
01005                 You should call this value before you make any calls to Update().
01006 
01007                 If there are already other Progress objects created, this call does nothing.
01008 
01009     SeeAlso:    Progress::Progress()
01010 
01011 ********************************************************************************************/
01012 
01013 void Progress::SetFinalCount(INT32 n)
01014 {
01015 //  if (ActiveDisplays <= 1)
01016 //  {
01017         // --- We're starting a brand new progress indication - so set it up
01018         FinalCount = n;
01019 //  }
01020 }
01021 
01022 /********************************************************************************************
01023 
01024 >   INT32 Progress::GetCount(INT32 n=0)
01025 
01026     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01027     Date:       18/1/96
01028     Inputs:     n = the increment value
01029     Returns:    Current count+n
01030     Purpose:    Gets the current progress count, and add 'n' to it.
01031                 'n' is added before the current count is returned
01032 
01033                 This function doubles up as an incrementing function for the progress count.
01034 
01035                 If the final count var (as supplied to the constructor or SetFinalCount()) is
01036                 less that 1, the counter is not incremented AND 0 is always returned.
01037 
01038     SeeAlso:    Progress::SetFinalCount(), Progress::ResetCount()
01039 
01040 ********************************************************************************************/
01041 
01042 INT32 Progress::GetCount(INT32 n)
01043 {
01044     if (FinalCount > 0)
01045     {
01046         ProgressCount += n;
01047         return ProgressCount;
01048     }
01049     else
01050         return 0;
01051 }
01052 
01053 /********************************************************************************************
01054 
01055 >   void Progress::ResetCount(INT32 n=0)
01056 
01057     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01058     Date:       18/1/96
01059     Inputs:     -
01060     Returns:    -
01061     Purpose:    Resets the progress count to n
01062 
01063     SeeAlso:    Progress::Progress(), Progress::GetCount()
01064 
01065 ********************************************************************************************/
01066 
01067 void Progress::ResetCount(INT32 n)
01068 {
01069     ProgressCount = n;
01070 }
01071 
01072 #else
01073 
01074 // Stubs for use in Ralph, who has no progress system...
01075 BOOL BeginSlowJob(INT32 finalcount, BOOL delay, String_64 *Description)
01076 {
01077     // Ralph
01078     return TRUE;
01079 }
01080 BOOL ContinueSlowJob(INT32 upto)
01081 {
01082     // test for abort
01083     return Progress::Update(0,0);
01084 }
01085 void EndSlowJob(void)
01086 {
01087     // Ralph
01088 }
01089 void SmashSlowJob(void)
01090 {
01091     // Ralph
01092     return;
01093 }
01094 void Progress::ThreadCallback(void)
01095 {
01096     // Ralph
01097 }
01098 Progress::Progress()
01099 {
01100     // Ralph
01101 }
01102 Progress::Progress(StringBase *Description, INT32 FinalCount,BOOL Delay, BOOL bEnable)
01103 {
01104     // Ralph
01105 }
01106 Progress::Progress(UINT32 DescriptionID, INT32 FinalCount,BOOL Delay, BOOL bEnable)
01107 {
01108     // Ralph
01109 }
01110 Progress::~Progress()
01111 {
01112     // Ralph
01113 }
01114 void Progress::Start(BOOL Delay, UINT32 DescriptionID, INT32 IntendedFinalCount)
01115 {
01116     // Ralph
01117 }
01118 void Progress::Start(BOOL Delay, StringBase *Description, INT32 IntendedFinalCount)
01119 {
01120     // Ralph
01121 }
01122 BOOL Progress::Update(INT32 CurrentCount,BOOL FreqEscChecks)
01123 {
01124     // test for a fake escape condition
01125     return !AbortJob;
01126 }
01127 void Progress::Stop(void)
01128 {
01129     // Ralph
01130 }
01131 void Progress::Smash(BOOL ForceSmash)
01132 {
01133     // Ralph
01134 }
01135 BOOL Progress::Init(void)
01136 {
01137     // Ralph
01138     return TRUE;
01139 }
01140 BOOL Progress::Deinit(void)
01141 {
01142     // Ralph
01143     return TRUE;
01144 }
01145 void Progress::SetFinalCount(INT32 n)
01146 {
01147     // Ralph
01148 }
01149 INT32 Progress::GetCount(INT32 n)
01150 {
01151     // Ralph
01152     return 0;
01153 }
01154 void Progress::ResetCount(INT32 n)
01155 {
01156     // Ralph
01157 }
01158 
01159 #endif

Generated on Sat Nov 10 03:48:48 2007 for Camelot by  doxygen 1.4.4