0025748: Parallel version of 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_ProgressScope.hxx>
21 #include <NCollection_List.hxx>
22 #include <Precision.hxx>
23 #include <OSD.hxx>
24 #include <OSD_Exception_CTRL_BREAK.hxx>
25 #include <OSD_Thread.hxx>
26
27 #include <stdio.h>
28 #include <time.h>
29 IMPLEMENT_STANDARD_RTTIEXT(Draw_ProgressIndicator,Message_ProgressIndicator)
30
31 //=======================================================================
32 //function : Draw_ProgressIndicator
33 //purpose  : 
34 //=======================================================================
35 Draw_ProgressIndicator::Draw_ProgressIndicator (const Draw_Interpretor &di, Standard_Real theUpdateThreshold)
36 : myTclMode ( DefaultTclMode() ),
37   myConsoleMode ( DefaultConsoleMode() ),
38   myGraphMode ( DefaultGraphMode() ),
39   myDraw ( (Draw_Interpretor*)&di ),
40   myShown ( Standard_False ),
41   myBreak ( Standard_False ),
42   myUpdateThreshold ( 0.01 * theUpdateThreshold ),
43   myLastPosition ( -1. ),
44   myStartTime ( 0 ),
45   myGuiThreadId (OSD_Thread::Current())
46 {
47 }
48
49 //=======================================================================
50 //function : ~Draw_ProgressIndicator
51 //purpose  : 
52 //=======================================================================
53
54 Draw_ProgressIndicator::~Draw_ProgressIndicator()
55 {
56   Reset();
57 }
58
59 //=======================================================================
60 //function : Reset
61 //purpose  : 
62 //=======================================================================
63
64 void Draw_ProgressIndicator::Reset()
65 {
66   Message_ProgressIndicator::Reset();
67   if ( myShown ) {
68     myDraw->Eval ( "destroy .xprogress" );
69     myShown = Standard_False;
70   }
71   myBreak = Standard_False;
72   myLastPosition = -1.;
73   myStartTime = 0;
74 }
75
76 //=======================================================================
77 //function : Show
78 //purpose  : 
79 //=======================================================================
80
81 void Draw_ProgressIndicator::Show (const Message_ProgressScope& theScope, const Standard_Boolean force)
82 {
83   if (!myGraphMode && !myTclMode && !myConsoleMode)
84     return;
85
86   // remember time of the first call to Show as process start time
87   if ( ! myStartTime )
88   {
89     if (!myStartTime)
90     {
91       time_t aTimeT;
92       time(&aTimeT);
93       myStartTime = (Standard_Size)aTimeT;
94     }
95   }
96
97   // unless show is forced, show updated state only if at least 1% progress has been reached since the last update
98   Standard_Real aPosition = GetPosition();
99   if ( ! force && aPosition < 1. && Abs (aPosition - myLastPosition) < myUpdateThreshold)
100     return; // return if update interval has not elapsed
101
102   myLastPosition = aPosition;
103   
104   // Prepare textual progress info
105   std::stringstream aText;
106   aText.setf (std::ios::fixed, std:: ios::floatfield);
107   aText.precision(0);
108   aText << "Progress: " << 100. * GetPosition() << "%";
109   NCollection_List<const Message_ProgressScope*> aScopes;
110   for (const Message_ProgressScope* aPS = &theScope; aPS; aPS = aPS->Parent())
111     aScopes.Prepend(aPS);
112   for (NCollection_List<const Message_ProgressScope*>::Iterator it(aScopes); it.More(); it.Next())
113   {
114     const Message_ProgressScope* aPS = it.Value();
115     if (!aPS->Name()) continue; // skip unnamed scopes
116     aText << " " << aPS->Name() << ": ";
117
118     // print progress info differently for finite and infinite scopes
119     Standard_Real aVal = aPS->Value();
120     if (aPS->IsInfinite())
121     {
122       if (Precision::IsInfinite(aVal))
123       {
124         aText << "finished";
125       }
126       else
127       {
128         aText << aVal;
129       }
130     }
131     else
132     {
133       aText << aVal << " / " << aPS->MaxValue();
134     }
135   }
136
137   // Show graphic progress bar.
138   // It will be updated only within GUI thread.
139   if (myGraphMode && myGuiThreadId == OSD_Thread::Current())
140   {
141     // In addition, write elapsed/estimated/remaining time
142     if ( GetPosition() > 0.01 ) { 
143       time_t aTimeT;
144       time ( &aTimeT );
145       Standard_Size aTime = (Standard_Size)aTimeT;
146       aText << "\nElapsed/estimated time: " << (long)(aTime - myStartTime) <<
147                "/" << ( aTime - myStartTime ) / GetPosition() << " sec";
148     }
149   
150     if ( ! myShown ) {
151       char command[1024];
152       Sprintf ( command, "toplevel .xprogress -height 100 -width 410;"
153                          "wm title .xprogress \"Progress\";"
154                          "set xprogress_stop 0;"
155                          "canvas .xprogress.bar -width 402 -height 22;"
156                          ".xprogress.bar create rectangle 2 2 2 21 -fill blue -tags progress;"
157                          ".xprogress.bar create rectangle 2 2 2 21 -outline black -tags progress_next;"
158                          "message .xprogress.text -width 400 -text \"Progress 0%%\";"
159                          "button .xprogress.stop -text \"Break\" -relief groove -width 9 -command {XProgress -stop %p};"
160                          "pack .xprogress.bar .xprogress.text .xprogress.stop -side top;", this );
161       myDraw->Eval ( command );
162       myShown = Standard_True;
163     }
164     std::stringstream aCommand;
165     aCommand.setf(std::ios::fixed, std::ios::floatfield);
166     aCommand.precision(0);
167     aCommand << ".xprogress.bar coords progress 2 2 " << (1 + 400 * GetPosition()) << " 21;";
168     aCommand << ".xprogress.bar coords progress_next 2 2 " << (1 + 400 * theScope.GetPortion()) << " 21;";
169     aCommand << ".xprogress.text configure -text \"" << aText.str() << "\";";
170     aCommand << "update";
171     myDraw->Eval (aCommand.str().c_str());
172   }
173
174   // Print textual progress info
175   if (myTclMode && myDraw)
176   {
177     *myDraw << aText.str().c_str() << "\n";
178   }
179   if (myConsoleMode)
180   {
181     std::cout << aText.str().c_str() << "\n";
182   }
183 }
184
185 //=======================================================================
186 //function : UserBreak
187 //purpose  : 
188 //=======================================================================
189
190 Standard_Boolean Draw_ProgressIndicator::UserBreak()
191 {
192   if ( StopIndicator() == this )
193   {
194 //    std::cout << "Progress Indicator - User Break: " << StopIndicator() << ", " << (void*)this << std::endl;
195     myBreak = Standard_True;
196     myDraw->Eval ( "XProgress -stop 0" );
197   }
198   else
199   {
200     // treatment of Ctrl-Break signal
201     try
202     {
203       OSD::ControlBreak();
204     }
205     catch (OSD_Exception_CTRL_BREAK)
206     {
207       myBreak = Standard_True;
208     }
209   }
210   return myBreak;
211 }
212        
213 //=======================================================================
214 //function : SetTclMode
215 //purpose  : Sets Tcl output mode (on/off)
216 //=======================================================================
217
218 void Draw_ProgressIndicator::SetTclMode(const Standard_Boolean theTclMode)
219 {
220   myTclMode = theTclMode;
221 }
222
223 //=======================================================================
224 //function : GetTclMode
225 //purpose  : Returns Tcl output mode (on/off)
226 //=======================================================================
227
228 Standard_Boolean Draw_ProgressIndicator::GetTclMode() const
229 {
230   return myTclMode;
231 }
232
233 //=======================================================================
234 //function : SetConsoleMode
235 //purpose  : Sets Console output mode (on/off)
236 //=======================================================================
237
238 void Draw_ProgressIndicator::SetConsoleMode(const Standard_Boolean theMode)
239 {
240   myConsoleMode = theMode;
241 }
242
243 //=======================================================================
244 //function : GetConsoleMode
245 //purpose  : Returns Console output mode (on/off)
246 //=======================================================================
247
248 Standard_Boolean Draw_ProgressIndicator::GetConsoleMode() const
249 {
250   return myConsoleMode;
251 }
252
253 //=======================================================================
254 //function : SetGraphMode
255 //purpose  : Sets graphical output mode (on/off)
256 //=======================================================================
257
258 void Draw_ProgressIndicator::SetGraphMode(const Standard_Boolean theGraphMode)
259 {
260   myGraphMode = theGraphMode;
261 }
262
263 //=======================================================================
264 //function : GetGraphMode
265 //purpose  : Returns graphical output mode (on/off)
266 //=======================================================================
267
268 Standard_Boolean Draw_ProgressIndicator::GetGraphMode() const
269 {
270   return myGraphMode;
271 }
272
273 //=======================================================================
274 //function : DefaultTclMode
275 //purpose  : 
276 //=======================================================================
277
278 Standard_Boolean &Draw_ProgressIndicator::DefaultTclMode()
279 {
280   static Standard_Boolean defTclMode = Standard_False;
281   return defTclMode;
282 }
283
284 //=======================================================================
285 //function : DefaultConsoleMode
286 //purpose  : 
287 //=======================================================================
288
289 Standard_Boolean &Draw_ProgressIndicator::DefaultConsoleMode()
290 {
291   static Standard_Boolean defConsoleMode = Standard_False;
292   return defConsoleMode;
293 }
294
295 //=======================================================================
296 //function : DefaultGraphMode
297 //purpose  : 
298 //=======================================================================
299
300 Standard_Boolean &Draw_ProgressIndicator::DefaultGraphMode()
301 {
302   static Standard_Boolean defGraphMode = Standard_False;
303   return defGraphMode;
304 }
305
306 //=======================================================================
307 //function : StopIndicator
308 //purpose  : 
309 //=======================================================================
310
311 Standard_Address &Draw_ProgressIndicator::StopIndicator()
312 {
313   static Standard_Address stopIndicator = 0;
314   return stopIndicator;
315 }
316
317