Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members

dlgProgress.cpp

Go to the documentation of this file.
00001 /* 00002 * wxChecksums 00003 * Copyright (C) 2003-2004 Julien Couot 00004 * 00005 * Based on the wxProgressDialog class provided in wxWidgets written by 00006 * Karsten Ballüder. 00007 * 00008 * This program is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU General Public License 00010 * as published by the Free Software Foundation; either version 2 00011 * of the License, or (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00021 */ 00022 00023 /** 00024 * \file dlgProgress.cpp 00025 * Progress dialog. 00026 */ 00027 00028 00029 //--------------------------------------------------------------------------- 00030 // For compilers that support precompilation, includes "wx.h". 00031 #include <wx/wxprec.h> 00032 00033 #ifdef __BORLANDC__ 00034 #pragma hdrstop 00035 #endif 00036 00037 #ifndef WX_PRECOMP 00038 // Include your minimal set of headers here, or wx.h 00039 #include <wx/wx.h> 00040 #endif 00041 00042 #include "dlgProgress.hpp" 00043 #include "comdefs.hpp" 00044 00045 #include "compat.hpp" 00046 //--------------------------------------------------------------------------- 00047 00048 00049 /// The C++ standard namespace. 00050 using namespace std; 00051 00052 00053 IMPLEMENT_DYNAMIC_CLASS(dlgProgress, wxDialog) 00054 00055 00056 /** 00057 * Creates and displays dialog, disables event handling for other frames or 00058 * parent frame to avoid recursion problems. 00059 * 00060 * @param title Title for window. 00061 * @param message Message to display in window. 00062 * @param maximum Value for status bar, if <CODE><= 0</CODE>, no bar is shown. 00063 * @param parent Window or <CODE>NULL</CODE>. 00064 * @param style Is the bit mask of <CODE>wxPD_XXX</CODE> constants from <CODE>wx/defs.h</CODE>. 00065 */ 00066 dlgProgress::dlgProgress(const wxString& title, const wxString& message, 00067 int maximum, wxWindow* parent, int style) 00068 : wxDialog(parent, -1, title) 00069 { 00070 // we may disappear at any moment, let the others know about it 00071 SetExtraStyle(GetExtraStyle() | wxWS_EX_TRANSIENT); 00072 00073 m_windowStyle |= style; 00074 00075 bool hasAbortButton = (style & wxPD_CAN_ABORT) != 0; 00076 00077 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) 00078 // we have to remove the "Close" button from the title bar then as it is 00079 // confusing to have it - it doesn't work anyhow 00080 // 00081 // FIXME: should probably have a (extended?) window style for this 00082 if (!hasAbortButton) 00083 EnableCloseButton(FALSE); 00084 #endif // wxMSW 00085 00086 state = hasAbortButton ? Continue : Uncancelable; 00087 this->maximum = maximum; 00088 00089 #if defined(__WXMSW__) || defined(__WXPM__) 00090 // We can't have values > 65,536 in the progress control under Windows, so 00091 // scale everything down 00092 factor = this->maximum / SHRT_MAX + 1; 00093 this->maximum /= factor; 00094 #endif // __WXMSW__ 00095 00096 // Get the top parent window 00097 ctrParentTop = parent; 00098 while (ctrParentTop && ctrParentTop->GetParent()) 00099 ctrParentTop = ctrParentTop->GetParent(); 00100 00101 // Create the dialog's controls. 00102 createControls(); 00103 00104 this->Centre(wxBOTH); 00105 00106 if (style & wxPD_APP_MODAL) 00107 winDisabler = new wxWindowDisabler(this); 00108 else 00109 if (ctrParentTop) 00110 { 00111 ctrParentTop->Enable(FALSE); 00112 winDisabler = (wxWindowDisabler*)NULL; 00113 } 00114 00115 this->Show(true); 00116 this->Enable(true); 00117 00118 // Set the current time 00119 timeStart = ::wxGetCurrentTime(); 00120 00121 // This one can be initialized even if the others are unknown for now. 00122 if (lblElapsed) 00123 SetTimeLabel(0, lblElapsed); 00124 00125 // Update the display (especially on X, GTK) 00126 wxYield(); 00127 00128 #ifdef __WXMAC__ 00129 MacUpdateImmediately(); 00130 #endif 00131 } 00132 //--------------------------------------------------------------------------- 00133 00134 00135 /** 00136 * Creates and initializes the controls of the dialog. 00137 */ 00138 void dlgProgress::createControls(const wxString& message) 00139 { 00140 // Message label 00141 wxClientDC dc(this); 00142 wxSize size = wxDefaultSize; 00143 size.SetHeight(GetCharHeight() * 2); 00144 lblMessage = new wxStaticText(this, -1, message, wxDefaultPosition, size); 00145 00146 if (maximum > 0) 00147 // Note that we can't use wxGA_SMOOTH because it happens to also mean 00148 // wxDIALOG_MODAL and will cause the dialog to be modal. Have an extra 00149 // style argument to wxProgressDialog, perhaps. 00150 gauProgress = new wxGauge(this, -1, maximum, wxDefaultPosition, 00151 wxDefaultSize, wxGA_HORIZONTAL); 00152 else 00153 gauProgress = (wxGauge*)NULL; 00154 00155 // Count how many labels we really have for time 00156 size_t nTimeLabels = 0; 00157 00158 // Elapsed time 00159 wxStaticText* lblElapsedTxt; 00160 if (GetWindowStyle() & wxPD_ELAPSED_TIME) 00161 { 00162 lblElapsedTxt = new wxStaticText(this, -1, _("Elapsed time:")); 00163 lblElapsed = new wxStaticText(this, -1, _("unknown")); 00164 nTimeLabels++; 00165 } 00166 else 00167 { 00168 lblElapsedTxt = (wxStaticText*)NULL; 00169 lblElapsed = (wxStaticText*)NULL; 00170 } 00171 00172 // Estimated time 00173 wxStaticText* lblEstimatedTxt; 00174 if (GetWindowStyle() & wxPD_ESTIMATED_TIME) 00175 { 00176 lblEstimatedTxt = new wxStaticText(this, -1, _("Estimated time:")); 00177 lblEstimated = new wxStaticText(this, -1, _("unknown")); 00178 nTimeLabels++; 00179 } 00180 else 00181 { 00182 lblEstimatedTxt = (wxStaticText*)NULL; 00183 lblEstimated = (wxStaticText*)NULL; 00184 } 00185 00186 // Remaining time 00187 wxStaticText* lblRemainingTxt; 00188 if (GetWindowStyle() & wxPD_REMAINING_TIME) 00189 { 00190 lblRemainingTxt = new wxStaticText(this, -1, _("Remaining time:")); 00191 lblRemaining = new wxStaticText(this, -1, _("unknown")); 00192 nTimeLabels++; 00193 } 00194 else 00195 { 00196 lblRemainingTxt = (wxStaticText*)NULL; 00197 lblRemaining = (wxStaticText*)NULL; 00198 } 00199 00200 // Buttons 00201 btnPause = new wxButton(this, BTN_PAUSE, _("&Pause")); 00202 btnPause->SetDefault(); 00203 bool hasAbortButton = (GetWindowStyle() & wxPD_CAN_ABORT) != 0; 00204 btnCancel = new wxButton(this, wxID_CANCEL, _("&Cancel")); 00205 if (!hasAbortButton) 00206 btnCancel->Enable(false); 00207 00208 //------------------------------------------------------------------------- 00209 // Creates the dialog sizer 00210 int clientHeight = 0; // Client height of the dialog 00211 00212 // Dialog sizer 00213 wxBoxSizer* dlgProgressSizer2 = new wxBoxSizer(wxVERTICAL); 00214 this->SetSizer(dlgProgressSizer2); 00215 wxBoxSizer* dlgProgressSizer = new wxBoxSizer(wxVERTICAL); 00216 dlgProgressSizer2->Add(dlgProgressSizer, 1, wxALL | wxGROW, CONTROL_SPACE); 00217 clientHeight += CONTROL_SPACE * 2; 00218 00219 // Message 00220 dlgProgressSizer->Add(lblMessage, 0, wxGROW | wxALIGN_LEFT); 00221 clientHeight += lblMessage->GetSize().GetHeight(); 00222 00223 // Progress gauge 00224 if (maximum > 0) 00225 { 00226 dlgProgressSizer->Add(gauProgress, 0, wxGROW | wxTOP | wxALIGN_LEFT, CONTROL_SPACE / 2); 00227 clientHeight += gauProgress->GetSize().GetHeight() + CONTROL_SPACE / 2; 00228 } 00229 00230 // Progress section 00231 if (nTimeLabels > 0) 00232 { 00233 clientHeight += CONTROL_SPACE; 00234 wxBoxSizer* timeSizerRight = new wxBoxSizer(wxHORIZONTAL); 00235 dlgProgressSizer->Add(timeSizerRight, 0, wxTOP | wxALIGN_CENTER_HORIZONTAL, CONTROL_SPACE); 00236 wxFlexGridSizer* timeSizer = new wxFlexGridSizer(2, CONTROL_SPACE / 2, CONTROL_SPACE); 00237 timeSizerRight->Add(timeSizer, 0, wxALIGN_RIGHT); 00238 timeSizer->AddGrowableCol(1); 00239 if (lblElapsed) 00240 { 00241 timeSizer->Add(lblElapsedTxt, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT); 00242 timeSizer->Add(lblElapsed, 1, wxALIGN_CENTER_VERTICAL | wxGROW); 00243 clientHeight += lblElapsed->GetSize().GetHeight() + CONTROL_SPACE / 2; 00244 } 00245 if (lblEstimated) 00246 { 00247 timeSizer->Add(lblEstimatedTxt, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT); 00248 timeSizer->Add(lblEstimated, 1, wxALIGN_CENTER_VERTICAL | wxGROW); 00249 clientHeight += lblEstimated->GetSize().GetHeight() + CONTROL_SPACE / 2; 00250 } 00251 if (lblRemaining) 00252 { 00253 timeSizer->Add(lblRemainingTxt, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT); 00254 timeSizer->Add(lblRemaining, 1, wxALIGN_CENTER_VERTICAL | wxGROW); 00255 clientHeight += lblRemaining->GetSize().GetHeight() + CONTROL_SPACE / 2; 00256 } 00257 } 00258 00259 // Validation buttons sizer 00260 wxGridSizer* buttonsSizer = new wxGridSizer(2, 0, 2 * CONTROL_SPACE); 00261 buttonsSizer->Add(btnPause); 00262 buttonsSizer->Add(btnCancel); 00263 dlgProgressSizer->Add(buttonsSizer, 0, wxTOP | wxALIGN_RIGHT, CONTROL_SPACE); 00264 clientHeight += CONTROL_SPACE + wxMax(btnPause->GetSize().GetHeight(), btnCancel->GetSize().GetHeight()); 00265 00266 // Set on the auto-layout feature 00267 this->SetAutoLayout(true); 00268 this->Layout(); 00269 00270 // Set the dialog client size 00271 size.SetHeight(clientHeight); 00272 size.SetWidth((16 * size.GetHeight()) / 7); 00273 SetClientSize(size); 00274 } 00275 //--------------------------------------------------------------------------- 00276 00277 00278 /** 00279 * The class descructor. 00280 */ 00281 dlgProgress::~dlgProgress() 00282 { 00283 // Normally this should have been already done, but just in case. 00284 ReenableOtherWindows(); 00285 } 00286 //--------------------------------------------------------------------------- 00287 00288 00289 /** 00290 * Reenables the other windows temporarily disabled while the dialog was shown. 00291 * 00292 * Must be called to reenable the other windows temporarily disabled while 00293 * the dialog was shown. 00294 */ 00295 void dlgProgress::ReenableOtherWindows() 00296 { 00297 if (GetWindowStyle() & wxPD_APP_MODAL) 00298 { 00299 delete winDisabler; 00300 winDisabler = (wxWindowDisabler*)NULL; 00301 } 00302 else 00303 if (ctrParentTop) 00304 ctrParentTop->Enable(true); 00305 } 00306 //--------------------------------------------------------------------------- 00307 00308 00309 /** 00310 * Update the status bar to the new value. 00311 * 00312 * @param value New value. 00313 * @param newmsg If used, new message to display. 00314 * @return <CODE>true</CODE> if <I>Cancel</I> button has not been pressed. 00315 */ 00316 bool dlgProgress::Update(int value, const wxString& newmsg) 00317 { 00318 wxASSERT_MSG(state != paused, wxT("paused state isn't handled correctly")); 00319 wxASSERT_MSG(value == -1 || gauProgress, wxT("cannot update non existent dialog")); 00320 00321 #ifdef __WXMSW__ 00322 value /= factor; 00323 #endif // __WXMSW__ 00324 00325 wxASSERT_MSG(value <= maximum, wxT("invalid progress value")); 00326 00327 if (gauProgress && value < maximum) 00328 gauProgress->SetValue(value + 1); 00329 00330 if (!newmsg.IsEmpty()) 00331 { 00332 lblMessage->SetLabel(newmsg); 00333 wxYield(); 00334 } 00335 00336 if ((lblElapsed || lblRemaining || lblEstimated) && (value != 0)) 00337 { 00338 unsigned long elapsed = wxGetCurrentTime() - timeStart; 00339 unsigned long estimated = (unsigned long)(((double)elapsed * maximum) / ((double)value)); 00340 unsigned long remaining = estimated - elapsed; 00341 00342 SetTimeLabel(elapsed, lblElapsed); 00343 SetTimeLabel(estimated, lblEstimated); 00344 SetTimeLabel(remaining, lblRemaining); 00345 } 00346 00347 if (value == maximum) 00348 { 00349 // So that we return TRUE below and that out [Cancel] handler knew what 00350 // to do 00351 state = Finished; 00352 if (!(GetWindowStyle() & wxPD_AUTO_HIDE)) 00353 { 00354 // Update the gauge 00355 if (gauProgress != NULL) 00356 gauProgress->SetValue(maximum); 00357 00358 // Disable the pause button 00359 btnPause->Disable(); 00360 00361 // Tell the user what he should do... 00362 btnCancel->SetLabel(_("&Close")); 00363 btnCancel->Enable(true); 00364 btnCancel->SetFocus(); 00365 00366 bool hasAbortButton = (GetWindowStyle() & wxPD_CAN_ABORT) != 0; 00367 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) 00368 if (!hasAbortButton) 00369 { 00370 // Enable the button to give the user a way to close the dlg 00371 EnableCloseButton(TRUE); 00372 } 00373 #endif // __WXMSW__ 00374 00375 if (!newmsg) 00376 // Also provide the finishing message if the application didn't 00377 lblMessage->SetLabel(_("Done.")); 00378 00379 wxYield(); 00380 (void)ShowModal(); 00381 } 00382 else // Auto hide 00383 { 00384 // Reenable other windows before hiding this one because otherwise 00385 // Windows wouldn't give the focus back to the window which had 00386 // been previously focused because it would still be disabled. 00387 ReenableOtherWindows(); 00388 00389 Hide(); 00390 } 00391 } 00392 else 00393 { 00394 // Update the display 00395 wxYield(); 00396 } 00397 00398 #ifdef __WXMAC__ 00399 MacUpdateImmediately(); 00400 #endif 00401 00402 return state != Canceled; 00403 } 00404 //--------------------------------------------------------------------------- 00405 00406 00407 /** 00408 * Can be called to continue after the <I>Cancel</I> button has been pressed. 00409 */ 00410 void dlgProgress::Resume() 00411 { 00412 if (state == Canceled) 00413 { 00414 state = Continue; 00415 00416 // It may have been disabled by OnCancel(), so enable it back to let the 00417 // user interrupt us again if needed. 00418 if ((GetWindowStyle() & wxPD_CAN_ABORT) != 0) 00419 btnCancel->Enable(); 00420 btnPause->Enable(); 00421 } 00422 } 00423 //--------------------------------------------------------------------------- 00424 00425 00426 /** 00427 * Shows the dialog. 00428 * 00429 * @param show If <CODE>true</CODE> displays the window. Otherwise, hides it. 00430 * @return <CODE>true</CODE> if the window has been shown or hidden or 00431 * <CODE>false</CODE> if nothing was done because it already was in the 00432 * requested state. 00433 */ 00434 bool dlgProgress::Show(bool show) 00435 { 00436 // Reenable other windows before hiding this one because otherwise Windows 00437 // wouldn't give the focus back to the window which had been previously 00438 // focused because it would still be disabled. 00439 if (!show) 00440 ReenableOtherWindows(); 00441 00442 return wxDialog::Show(show); 00443 } 00444 //--------------------------------------------------------------------------- 00445 00446 00447 /** 00448 * Processes button Cancel. 00449 * 00450 * @param event The event's parameters 00451 */ 00452 void dlgProgress::btnCancelClick(wxCommandEvent& event) 00453 { 00454 if (state == Finished) 00455 { 00456 // This means that the count down is already finished and we're being 00457 // shown as a modal dialog - so just let the default handler do the job 00458 event.Skip(); 00459 } 00460 else 00461 { 00462 // Request to cancel was received, the next time Update() is called we 00463 // will handle it. 00464 state = Canceled; 00465 00466 // Update the button state immediately so that the user knows that the 00467 // request has been noticed. 00468 btnCancel->Disable(); 00469 btnPause->Disable(); 00470 } 00471 } 00472 //--------------------------------------------------------------------------- 00473 00474 00475 /** 00476 * Processes button Pause. 00477 * 00478 * @param event The event's parameters 00479 */ 00480 void dlgProgress::btnPauseClick(wxCommandEvent& event) 00481 { 00482 switch (state) 00483 { 00484 case Continue : 00485 case Uncancelable : 00486 btnPause->SetLabel(_("C&ontinue")); 00487 state = Paused; 00488 break; 00489 case Paused : 00490 btnPause->SetLabel(_("&Pause")); 00491 if ((GetWindowStyle() & wxPD_CAN_ABORT) != 0) 00492 state = Continue; 00493 else 00494 state = Uncancelable; 00495 break; 00496 } 00497 wxYield(); 00498 #ifdef __WXMAC__ 00499 MacUpdateImmediately(); 00500 #endif 00501 } 00502 //--------------------------------------------------------------------------- 00503 00504 00505 /** 00506 * Event handler to respond to system close events. 00507 * 00508 * @param event event parameters. 00509 */ 00510 void dlgProgress::FrameClose(wxCloseEvent& event) 00511 { 00512 if (state == Uncancelable) 00513 { 00514 // Can't close this dialog 00515 event.Veto(true); 00516 } 00517 else if (state == Finished) 00518 { 00519 // Let the default handler close the window as we already terminated 00520 event.Skip(); 00521 } 00522 else 00523 { 00524 // Check the paused state in Uncancelable mode 00525 if ((GetWindowStyle() & wxPD_CAN_ABORT) != 0) 00526 // Next Update() will notice it 00527 state = Canceled; 00528 } 00529 } 00530 //--------------------------------------------------------------------------- 00531 00532 00533 /** 00534 * Is the user has clicked on Pause ? 00535 * 00536 * @return <CODE>true</CODE> if the dialog has been paused, <CODE>false</CODE> 00537 * otherwise. 00538 */ 00539 bool dlgProgress::isPaused() const 00540 { 00541 return state == Paused; 00542 } 00543 //--------------------------------------------------------------------------- 00544 00545 00546 /** 00547 * Updates the label to show the given time (in seconds). 00548 * 00549 * @param val Time value. 00550 * @param label Label to change (can be <CODE>NULL</CODE>). 00551 */ 00552 void dlgProgress::SetTimeLabel(unsigned long val, wxStaticText* label) 00553 { 00554 if (label != NULL) 00555 { 00556 wxString s; 00557 unsigned long hours = val / 3600; 00558 unsigned long minutes = (val % 3600) / 60; 00559 unsigned long seconds = val % 60; 00560 s.Printf(wxT("%lu:%02lu:%02lu"), hours, minutes, seconds); 00561 00562 if (s != label->GetLabel()) 00563 label->SetLabel(s); 00564 } 00565 } 00566 //--------------------------------------------------------------------------- 00567 00568 00569 00570 BEGIN_EVENT_TABLE(dlgProgress, wxDialog) 00571 EVT_BUTTON(wxID_CANCEL, dlgProgress::btnCancelClick) 00572 EVT_BUTTON(BTN_PAUSE, dlgProgress::btnPauseClick) 00573 EVT_CLOSE(dlgProgress::FrameClose) 00574 END_EVENT_TABLE() 00575 //---------------------------------------------------------------------------

Generated on Sun May 30 13:37:44 2004 for wxChecksums by doxygen 1.3.7