home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / generic / progdlgg.cpp < prev    next >
C/C++ Source or Header  |  2002-12-16  |  15KB  |  507 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        progdlgg.h
  3. // Purpose:     wxProgressDialog class
  4. // Author:      Karsten Ballⁿder
  5. // Modified by:
  6. // Created:     09.05.1999
  7. // RCS-ID:      $Id: progdlgg.cpp,v 1.62.2.2 2002/12/16 10:57:48 JS Exp $
  8. // Copyright:   (c) Karsten Ballⁿder
  9. // Licence:     wxWindows license
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. // ============================================================================
  13. // declarations
  14. // ============================================================================
  15.  
  16. // ----------------------------------------------------------------------------
  17. // headers
  18. // ----------------------------------------------------------------------------
  19.  
  20. #ifdef __GNUG__
  21.     #pragma implementation "progdlgg.h"
  22. #endif
  23.  
  24. // For compilers that support precompilation, includes "wx.h".
  25. #include "wx/wxprec.h"
  26.  
  27. #ifdef __BORLANDC__
  28.     #pragma hdrstop
  29. #endif
  30.  
  31. #if wxUSE_PROGRESSDLG
  32.  
  33. #ifndef WX_PRECOMP
  34.     #include "wx/utils.h"
  35.     #include "wx/frame.h"
  36.     #include "wx/button.h"
  37.     #include "wx/stattext.h"
  38.     #include "wx/layout.h"
  39.     #include "wx/event.h"
  40.     #include "wx/gauge.h"
  41.     #include "wx/intl.h"
  42.     #include "wx/settings.h"
  43.     #include "wx/dcclient.h"
  44.     #include "wx/timer.h"
  45. #endif
  46.  
  47. #include "wx/generic/progdlgg.h"
  48.  
  49. // ----------------------------------------------------------------------------
  50. // constants
  51. // ----------------------------------------------------------------------------
  52.  
  53. #define LAYOUT_X_MARGIN 8
  54. #define LAYOUT_Y_MARGIN 8
  55.  
  56. // ----------------------------------------------------------------------------
  57. // private functions
  58. // ----------------------------------------------------------------------------
  59.  
  60. // update the label to show the given time (in seconds)
  61. static void SetTimeLabel(unsigned long val, wxStaticText *label);
  62.  
  63. // ----------------------------------------------------------------------------
  64. // event tables
  65. // ----------------------------------------------------------------------------
  66.  
  67. BEGIN_EVENT_TABLE(wxProgressDialog, wxDialog)
  68.     EVT_BUTTON(wxID_CANCEL, wxProgressDialog::OnCancel)
  69.  
  70.     EVT_CLOSE(wxProgressDialog::OnClose)
  71. END_EVENT_TABLE()
  72.  
  73. IMPLEMENT_CLASS(wxProgressDialog, wxDialog)
  74.  
  75. // ============================================================================
  76. // wxProgressDialog implementation
  77. // ============================================================================
  78.  
  79. // ----------------------------------------------------------------------------
  80. // wxProgressDialog creation
  81. // ----------------------------------------------------------------------------
  82.  
  83. wxProgressDialog::wxProgressDialog(wxString const &title,
  84.                                    wxString const &message,
  85.                                    int maximum,
  86.                                    wxWindow *parent,
  87.                                    int style)
  88.                 : wxDialog(parent, -1, title)
  89. {
  90.     // we may disappear at any moment, let the others know about it
  91.     SetExtraStyle(GetExtraStyle() | wxWS_EX_TRANSIENT);
  92.  
  93.     m_windowStyle |= style;
  94.  
  95.     bool hasAbortButton = (style & wxPD_CAN_ABORT) != 0;
  96.  
  97. #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
  98.     // we have to remove the "Close" button from the title bar then as it is
  99.     // confusing to have it - it doesn't work anyhow
  100.     //
  101.     // FIXME: should probably have a (extended?) window style for this
  102.     if ( !hasAbortButton )
  103.     {
  104.         EnableCloseButton(FALSE);
  105.     }
  106. #endif // wxMSW
  107.  
  108.     m_state = hasAbortButton ? Continue : Uncancelable;
  109.     m_maximum = maximum;
  110.  
  111. #if defined(__WXMSW__) || defined(__WXPM__)
  112.     // we can't have values > 65,536 in the progress control under Windows, so
  113.     // scale everything down
  114.     m_factor = m_maximum / 65536 + 1;
  115.     m_maximum /= m_factor;
  116. #endif // __WXMSW__
  117.  
  118.     m_parentTop = parent;
  119.     while ( m_parentTop && m_parentTop->GetParent() )
  120.     {
  121.         m_parentTop = m_parentTop->GetParent();
  122.     }
  123.  
  124.     wxLayoutConstraints *c;
  125.  
  126.     wxClientDC dc(this);
  127.     dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
  128.     long widthText;
  129.     dc.GetTextExtent(message, &widthText, NULL, NULL, NULL, NULL);
  130.  
  131.     m_msg = new wxStaticText(this, -1, message);
  132.     c = new wxLayoutConstraints;
  133.     c->left.SameAs(this, wxLeft, 2*LAYOUT_X_MARGIN);
  134.     c->top.SameAs(this, wxTop, 2*LAYOUT_Y_MARGIN);
  135.     c->width.AsIs();
  136.     c->height.AsIs();
  137.     m_msg->SetConstraints(c);
  138.  
  139.     wxSize sizeDlg,
  140.            sizeLabel = m_msg->GetSize();
  141.     sizeDlg.y = 2*LAYOUT_Y_MARGIN + sizeLabel.y;
  142.  
  143.     wxWindow *lastWindow = m_msg;
  144.  
  145.     if ( maximum > 0 )
  146.     {
  147.         // note that we can't use wxGA_SMOOTH because it happens to also mean
  148.         // wxDIALOG_MODAL and will cause the dialog to be modal. Have an extra
  149.         // style argument to wxProgressDialog, perhaps.
  150.         m_gauge = new wxGauge(this, -1, m_maximum,
  151.                               wxDefaultPosition, wxDefaultSize,
  152.                               wxGA_HORIZONTAL);
  153.  
  154.         c = new wxLayoutConstraints;
  155.         c->left.SameAs(this, wxLeft, 2*LAYOUT_X_MARGIN);
  156.         c->top.Below(m_msg, 2*LAYOUT_Y_MARGIN);
  157.         c->right.SameAs(this, wxRight, 2*LAYOUT_X_MARGIN);
  158.         c->height.AsIs();
  159.         m_gauge->SetConstraints(c);
  160.         m_gauge->SetValue(0);
  161.         lastWindow = m_gauge;
  162.  
  163.         wxSize sizeGauge = m_gauge->GetSize();
  164.         sizeDlg.y += 2*LAYOUT_Y_MARGIN + sizeGauge.y;
  165.     }
  166.     else
  167.         m_gauge = (wxGauge *)NULL;
  168.  
  169.     // create the estimated/remaining/total time zones if requested
  170.     m_elapsed = m_estimated = m_remaining = (wxStaticText*)NULL;
  171.  
  172.     // if we are going to have at least one label, remmeber it in this var
  173.     wxStaticText *label = NULL;
  174.  
  175.     // also count how many labels we really have
  176.     size_t nTimeLabels = 0;
  177.  
  178.     if ( style & wxPD_ELAPSED_TIME )
  179.     {
  180.         nTimeLabels++;
  181.  
  182.         label =
  183.         m_elapsed = CreateLabel(_("Elapsed time : "), &lastWindow);
  184.     }
  185.  
  186.     if ( style & wxPD_ESTIMATED_TIME )
  187.     {
  188.         nTimeLabels++;
  189.  
  190.         label =
  191.         m_estimated = CreateLabel(_("Estimated time : "), &lastWindow);
  192.     }
  193.  
  194.     if ( style & wxPD_REMAINING_TIME )
  195.     {
  196.         nTimeLabels++;
  197.  
  198.         label =
  199.         m_remaining = CreateLabel(_("Remaining time : "), &lastWindow);
  200.     }
  201.  
  202.     if ( nTimeLabels > 0 )
  203.     {
  204.         // set it to the current time
  205.         m_timeStart = wxGetCurrentTime();
  206.         sizeDlg.y += nTimeLabels * (label->GetSize().y + LAYOUT_Y_MARGIN);
  207.     }
  208.  
  209.     if ( hasAbortButton )
  210.     {
  211.         m_btnAbort = new wxButton(this, wxID_CANCEL, _("Cancel"));
  212.         c = new wxLayoutConstraints;
  213.  
  214.         // Windows dialogs usually have buttons in the lower right corner
  215. #if defined(__WXMSW__) || defined(__WXPM__)
  216.         c->right.SameAs(this, wxRight, 2*LAYOUT_X_MARGIN);
  217. #else // !MSW
  218.         c->centreX.SameAs(this, wxCentreX);
  219. #endif // MSW/!MSW
  220.         c->bottom.SameAs(this, wxBottom, 2*LAYOUT_Y_MARGIN);
  221.  
  222.         c->width.AsIs();
  223.         c->height.AsIs();
  224.  
  225.         m_btnAbort->SetConstraints(c);
  226.  
  227.         sizeDlg.y += 2*LAYOUT_Y_MARGIN + wxButton::GetDefaultSize().y;
  228.     }
  229.     else // no "Cancel" button
  230.     {
  231.         m_btnAbort = (wxButton *)NULL;
  232.     }
  233.  
  234.     SetAutoLayout(TRUE);
  235.     Layout();
  236.  
  237.     sizeDlg.y += 2*LAYOUT_Y_MARGIN;
  238.  
  239.     // try to make the dialog not square but rectangular of reasonabel width
  240.     sizeDlg.x = (wxCoord)wxMax(widthText, 4*sizeDlg.y/3);
  241.     sizeDlg.x *= 3;
  242.     sizeDlg.x /= 2;
  243.     SetClientSize(sizeDlg);
  244.  
  245.     Centre(wxCENTER_FRAME | wxBOTH);
  246.  
  247.     if ( style & wxPD_APP_MODAL )
  248.     {
  249.         m_winDisabler = new wxWindowDisabler(this);
  250.     }
  251.     else
  252.     {
  253.         if ( m_parentTop )
  254.             m_parentTop->Enable(FALSE);
  255.         m_winDisabler = NULL;
  256.     }
  257.  
  258.     Show(TRUE);
  259.     Enable(TRUE); // enable this window
  260.  
  261.     // this one can be initialized even if the others are unknown for now
  262.     //
  263.     // NB: do it after calling Layout() to keep the labels correctly aligned
  264.     if ( m_elapsed )
  265.     {
  266.         SetTimeLabel(0, m_elapsed);
  267.     }
  268.  
  269.     // Update the display (especially on X, GTK)
  270.     wxYield();
  271.  
  272. #ifdef __WXMAC__
  273.     MacUpdateImmediately();
  274. #endif
  275. }
  276.  
  277. wxStaticText *wxProgressDialog::CreateLabel(const wxString& text,
  278.                                             wxWindow **lastWindow)
  279. {
  280.     wxLayoutConstraints *c;
  281.  
  282.     wxStaticText *label = new wxStaticText(this, -1, _("unknown"));
  283.     c = new wxLayoutConstraints;
  284.  
  285.     // VZ: I like the labels be centered - if the others don't mind, you may
  286.     //     remove "#ifdef __WXMSW__" and use it for all ports
  287. #if defined(__WXMSW__) || defined(__WXPM__)
  288.     c->left.SameAs(this, wxCentreX, LAYOUT_X_MARGIN);
  289. #else // !MSW
  290.     c->right.SameAs(this, wxRight, 2*LAYOUT_X_MARGIN);
  291. #endif // MSW/!MSW
  292.     c->top.Below(*lastWindow, LAYOUT_Y_MARGIN);
  293.     c->width.AsIs();
  294.     c->height.AsIs();
  295.     label->SetConstraints(c);
  296.  
  297.     wxStaticText *dummy = new wxStaticText(this, -1, text);
  298.     c = new wxLayoutConstraints;
  299.     c->right.LeftOf(label);
  300.     c->top.SameAs(label, wxTop, 0);
  301.     c->width.AsIs();
  302.     c->height.AsIs();
  303.     dummy->SetConstraints(c);
  304.  
  305.     *lastWindow = label;
  306.  
  307.     return label;
  308. }
  309.  
  310. // ----------------------------------------------------------------------------
  311. // wxProgressDialog operations
  312. // ----------------------------------------------------------------------------
  313.  
  314. bool
  315. wxProgressDialog::Update(int value, const wxString& newmsg)
  316. {
  317.     wxASSERT_MSG( value == -1 || m_gauge, wxT("cannot update non existent dialog") );
  318.  
  319. #ifdef __WXMSW__
  320.     value /= m_factor;
  321. #endif // __WXMSW__
  322.  
  323.     wxASSERT_MSG( value <= m_maximum, wxT("invalid progress value") );
  324.  
  325.     if ( m_gauge && value < m_maximum )
  326.     {
  327.         m_gauge->SetValue(value + 1);
  328.     }
  329.  
  330.     if ( !newmsg.IsEmpty() )
  331.     {
  332.         m_msg->SetLabel(newmsg);
  333.  
  334.         wxYield();
  335.     }
  336.  
  337.     if ( (m_elapsed || m_remaining || m_estimated) && (value != 0) )
  338.     {
  339.         unsigned long elapsed = wxGetCurrentTime() - m_timeStart;
  340.         unsigned long estimated = elapsed * m_maximum / value;
  341.         unsigned long remaining = estimated - elapsed;
  342.  
  343.         SetTimeLabel(elapsed, m_elapsed);
  344.         SetTimeLabel(estimated, m_estimated);
  345.         SetTimeLabel(remaining, m_remaining);
  346.     }
  347.  
  348.     if ( value == m_maximum )
  349.     {
  350.         // so that we return TRUE below and that out [Cancel] handler knew what
  351.         // to do
  352.         m_state = Finished;
  353.         if( !(GetWindowStyle() & wxPD_AUTO_HIDE) )
  354.         {
  355.             if ( m_btnAbort )
  356.             {
  357.                 // tell the user what he should do...
  358.                 m_btnAbort->SetLabel(_("Close"));
  359.             }
  360. #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
  361.             else // enable the button to give the user a way to close the dlg
  362.             {
  363.                 EnableCloseButton(TRUE);
  364.             }
  365. #endif // __WXMSW__
  366.  
  367.             if ( !newmsg )
  368.             {
  369.                 // also provide the finishing message if the application didn't
  370.                 m_msg->SetLabel(_("Done."));
  371.             }
  372.  
  373.             wxYield();
  374.  
  375.             (void)ShowModal();
  376.         }
  377.         else // auto hide
  378.         {
  379.             // reenable other windows before hiding this one because otherwise
  380.             // Windows wouldn't give the focus back to the window which had
  381.             // been previously focused because it would still be disabled
  382.             ReenableOtherWindows();
  383.  
  384.             Hide();
  385.         }
  386.     }
  387.     else
  388.     {
  389.         // update the display
  390.         wxYield();
  391.     }
  392.  
  393. #ifdef __WXMAC__
  394.     MacUpdateImmediately();
  395. #endif
  396.  
  397.     return m_state != Canceled;
  398. }
  399.  
  400. void wxProgressDialog::Resume()
  401. {
  402.     m_state = Continue;
  403.  
  404.     // it may have been disabled by OnCancel(), so enable it back to let the
  405.     // user interrupt us again if needed
  406.     m_btnAbort->Enable();
  407. }
  408.  
  409. bool wxProgressDialog::Show( bool show )
  410. {
  411.     // reenable other windows before hiding this one because otherwise
  412.     // Windows wouldn't give the focus back to the window which had
  413.     // been previously focused because it would still be disabled
  414.     if(!show)
  415.         ReenableOtherWindows();
  416.  
  417.     return wxDialog::Show(show);
  418. }
  419.  
  420. // ----------------------------------------------------------------------------
  421. // event handlers
  422. // ----------------------------------------------------------------------------
  423.  
  424. void wxProgressDialog::OnCancel(wxCommandEvent& event)
  425. {
  426.     if ( m_state == Finished )
  427.     {
  428.         // this means that the count down is already finished and we're being
  429.         // shown as a modal dialog - so just let the default handler do the job
  430.         event.Skip();
  431.     }
  432.     else
  433.     {
  434.         // request to cancel was received, the next time Update() is called we
  435.         // will handle it
  436.         m_state = Canceled;
  437.  
  438.         // update the button state immediately so that the user knows that the
  439.         // request has been noticed
  440.         m_btnAbort->Disable();
  441.     }
  442. }
  443.  
  444. void wxProgressDialog::OnClose(wxCloseEvent& event)
  445. {
  446.     if ( m_state == Uncancelable )
  447.     {
  448.         // can't close this dialog
  449.         event.Veto(TRUE);
  450.     }
  451.     else if ( m_state == Finished )
  452.     {
  453.         // let the default handler close the window as we already terminated
  454.         event.Skip();
  455.     }
  456.     else
  457.     {
  458.         // next Update() will notice it
  459.         m_state = Canceled;
  460.     }
  461. }
  462.  
  463. // ----------------------------------------------------------------------------
  464. // destruction
  465. // ----------------------------------------------------------------------------
  466.  
  467. wxProgressDialog::~wxProgressDialog()
  468. {
  469.     // normally this should have been already done, but just in case
  470.     ReenableOtherWindows();
  471. }
  472.  
  473. void wxProgressDialog::ReenableOtherWindows()
  474. {
  475.     if ( GetWindowStyle() & wxPD_APP_MODAL )
  476.     {
  477.         delete m_winDisabler;
  478.         m_winDisabler = (wxWindowDisabler *)NULL;
  479.     }
  480.     else
  481.     {
  482.         if ( m_parentTop )
  483.             m_parentTop->Enable(TRUE);
  484.     }
  485. }
  486.  
  487. // ----------------------------------------------------------------------------
  488. // private functions
  489. // ----------------------------------------------------------------------------
  490.  
  491. static void SetTimeLabel(unsigned long val, wxStaticText *label)
  492. {
  493.     if ( label )
  494.     {
  495.         wxString s;
  496.         unsigned long hours = val / 3600;
  497.         unsigned long minutes = (val % 3600) / 60;
  498.         unsigned long seconds = val % 60;
  499.         s.Printf(wxT("%lu:%02lu:%02lu"), hours, minutes, seconds);
  500.  
  501.         if ( s != label->GetLabel() )
  502.             label->SetLabel(s);
  503.     }
  504. }
  505.  
  506. #endif // wxUSE_PROGRESSDLG
  507.