0031092: Foundation Classes - incorrect last output value for Infinite progress indicator
[occt.git] / src / Draw / Draw_ProgressIndicator.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14
15 #include <Draw.hxx>
16 #include <Draw_Interpretor.hxx>
17 #include <Draw_ProgressIndicator.hxx>
18 #include <Message.hxx>
19 #include <Message_Messenger.hxx>
20 #include <Message_ProgressScale.hxx>
21 #include <Precision.hxx>
22
23 #include <stdio.h>
24 #include <time.h>
25 IMPLEMENT_STANDARD_RTTIEXT(Draw_ProgressIndicator,Message_ProgressIndicator)
26
27 //=======================================================================
28 //function : Draw_ProgressIndicator
29 //purpose  : 
30 //=======================================================================
31 Draw_ProgressIndicator::Draw_ProgressIndicator (const Draw_Interpretor &di, Standard_Real theUpdateThreshold)
32 : myTextMode ( DefaultTextMode() ),
33   myGraphMode ( DefaultGraphMode() ),
34   myDraw ( (Standard_Address)&di ),
35   myShown ( Standard_False ),
36   myBreak ( Standard_False ),
37   myUpdateThreshold ( 0.01 * theUpdateThreshold ),
38   myLastPosition ( -1. ),
39   myStartTime ( 0 )
40 {
41 }
42
43 //=======================================================================
44 //function : ~Draw_ProgressIndicator
45 //purpose  : 
46 //=======================================================================
47
48 Draw_ProgressIndicator::~Draw_ProgressIndicator()
49 {
50   Reset();
51 }
52
53 //=======================================================================
54 //function : Reset
55 //purpose  : 
56 //=======================================================================
57
58 void Draw_ProgressIndicator::Reset()
59 {
60   Message_ProgressIndicator::Reset();
61   if ( myShown ) {
62     ((Draw_Interpretor*)myDraw)->Eval ( "destroy .xprogress" );
63     myShown = Standard_False;
64   }
65   myBreak = Standard_False;
66   myLastPosition = -1.;
67   myStartTime = 0;
68 }
69
70 //=======================================================================
71 //function : Show
72 //purpose  : 
73 //=======================================================================
74
75 Standard_Boolean Draw_ProgressIndicator::Show(const Standard_Boolean force)
76 {
77   if ( ! myGraphMode && ! myTextMode )
78     return Standard_False;
79
80   // remember time of the first call to Show as process start time
81   if ( ! myStartTime )
82   {
83     time_t aTimeT;
84     time ( &aTimeT );
85     myStartTime = (Standard_Size)aTimeT;
86   }
87
88   // unless show is forced, show updated state only if at least 1% progress has been reached since the last update
89   Standard_Real aPosition = GetPosition();
90   if ( ! force && aPosition < 1. && Abs (aPosition - myLastPosition) < myUpdateThreshold)
91     return Standard_False; // return if update interval has not elapsed
92   myLastPosition = aPosition;
93   
94   // Prepare textual progress info
95   std::stringstream aText;
96   aText.setf (std::ios::fixed, std:: ios::floatfield);
97   aText.precision(0);
98   aText << "Progress: " << 100. * GetPosition() << "%";
99   for ( Standard_Integer i=GetNbScopes(); i >=1; i-- ) {
100     const Message_ProgressScale &scale = GetScope ( i );
101     if ( scale.GetName().IsNull() ) continue; // skip unnamed scopes
102     aText << " " << scale.GetName()->ToCString() << ": ";
103
104     // if scope has subscopes, print end of subscope as its current position
105     Standard_Real locPos = ( i >1 ? GetScope ( i-1 ).GetLast() : GetPosition() );
106     // print progress info differently for finite and infinite scopes
107     if ( scale.GetInfinite() )
108     {
109       Standard_Real aVal = scale.BaseToLocal(locPos);
110       if (Precision::IsInfinite(aVal))
111       {
112         aText << "finished";
113       }
114       else
115       {
116         aText << aVal;
117       }
118     }
119     else
120     {
121       aText << scale.BaseToLocal ( locPos ) << " / " << scale.GetMax();
122     }
123   }
124
125   // Show graphic progress bar
126   if ( myGraphMode ) {
127
128     // In addition, write elapsed/estimated/remaining time
129     if ( GetPosition() > 0.01 ) { 
130       time_t aTimeT;
131       time ( &aTimeT );
132       Standard_Size aTime = (Standard_Size)aTimeT;
133       aText << "\nElapsed/estimated time: " << (long)(aTime - myStartTime) <<
134                "/" << ( aTime - myStartTime ) / GetPosition() << " sec";
135     }
136   
137     if ( ! myShown ) {
138       char command[1024];
139       Sprintf ( command, "toplevel .xprogress -height 100 -width 410;"
140                          "wm title .xprogress \"Progress\";"
141                          "set xprogress_stop 0;"
142                          "canvas .xprogress.bar -width 402 -height 22;"
143                          ".xprogress.bar create rectangle 2 2 2 21 -fill blue -tags progress;"
144                          ".xprogress.bar create rectangle 2 2 2 21 -outline black -tags progress_next;"
145                          "message .xprogress.text -width 400 -text \"Progress 0%%\";"
146                          "button .xprogress.stop -text \"Break\" -relief groove -width 9 -command {XProgress -stop %p};"
147                          "pack .xprogress.bar .xprogress.text .xprogress.stop -side top;", this );
148       ((Draw_Interpretor*)myDraw)->Eval ( command );
149       myShown = Standard_True;
150     }
151     std::stringstream aCommand;
152     aCommand.setf(std::ios::fixed, std::ios::floatfield);
153     aCommand.precision(0);
154     aCommand << ".xprogress.bar coords progress 2 2 " << (1 + 400 * GetPosition()) << " 21;";
155     aCommand << ".xprogress.bar coords progress_next 2 2 " << (1 + 400 * GetScope(1).GetLast()) << " 21;";
156     aCommand << ".xprogress.text configure -text \"" << aText.str() << "\";";
157     aCommand << "update";
158     ((Draw_Interpretor*)myDraw)->Eval (aCommand.str().c_str());
159   }
160
161   // Print textual progress info
162   if ( myTextMode )
163     Message::DefaultMessenger()->Send (aText.str().c_str(), Message_Info);
164   
165   return Standard_True;
166 }
167        
168 //=======================================================================
169 //function : UserBreak
170 //purpose  : 
171 //=======================================================================
172
173 Standard_Boolean Draw_ProgressIndicator::UserBreak()
174 {
175   if ( StopIndicator() == this ) {
176 //    std::cout << "Progress Indicator - User Break: " << StopIndicator() << ", " << (void*)this << std::endl;
177     myBreak = Standard_True;
178     ((Draw_Interpretor*)myDraw)->Eval ( "XProgress -stop 0" );
179   }
180   return myBreak;
181 }
182        
183 //=======================================================================
184 //function : SetTextMode
185 //purpose  : Sets text output mode (on/off)
186 //=======================================================================
187
188 void Draw_ProgressIndicator::SetTextMode(const Standard_Boolean theTextMode)
189 {
190   myTextMode = theTextMode;
191 }
192
193 //=======================================================================
194 //function : GetTextMode
195 //purpose  : Returns text output mode (on/off)
196 //=======================================================================
197
198 Standard_Boolean Draw_ProgressIndicator::GetTextMode() const
199 {
200   return myTextMode;
201 }
202
203 //=======================================================================
204 //function : SetGraphMode
205 //purpose  : Sets graphical output mode (on/off)
206 //=======================================================================
207
208 void Draw_ProgressIndicator::SetGraphMode(const Standard_Boolean theGraphMode)
209 {
210   myGraphMode = theGraphMode;
211 }
212
213 //=======================================================================
214 //function : GetGraphMode
215 //purpose  : Returns graphical output mode (on/off)
216 //=======================================================================
217
218 Standard_Boolean Draw_ProgressIndicator::GetGraphMode() const
219 {
220   return myGraphMode;
221 }
222
223 //=======================================================================
224 //function : DefaultTextMode
225 //purpose  : 
226 //=======================================================================
227
228 Standard_Boolean &Draw_ProgressIndicator::DefaultTextMode () 
229 {
230   static Standard_Boolean defTextMode = Standard_False;
231   return defTextMode;
232 }
233     
234 //=======================================================================
235 //function : DefaultGraphMode
236 //purpose  : 
237 //=======================================================================
238
239 Standard_Boolean &Draw_ProgressIndicator::DefaultGraphMode () 
240 {
241   static Standard_Boolean defGraphMode = Standard_False;
242   return defGraphMode;
243 }
244     
245 //=======================================================================
246 //function : StopIndicator
247 //purpose  : 
248 //=======================================================================
249
250 Standard_Address &Draw_ProgressIndicator::StopIndicator ()
251 {
252   static Standard_Address stopIndicator = 0;
253   return stopIndicator;
254 }
255
256