From b62f94ff4834ab607a888826ec7bf4404837f400 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Thu, 15 Mar 2007 17:25:15 +0000
Subject: [PATCH] added wxGridUpdateLocker helper class wrapping
 Begin/EndBatch() calls in a more convenient and safe way

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@44833 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/changes.txt           |  1 +
 docs/latex/wx/classes.tex  |  1 +
 docs/latex/wx/grid.tex     |  8 ++++
 docs/latex/wx/gupdlock.tex | 81 ++++++++++++++++++++++++++++++++++++++
 include/wx/generic/grid.h  | 41 +++++++++++++++++++
 samples/grid/griddemo.cpp  |  6 +--
 src/common/dbgrid.cpp      |  4 +-
 src/generic/grid.cpp       | 20 ++++------
 8 files changed, 143 insertions(+), 19 deletions(-)
 create mode 100644 docs/latex/wx/gupdlock.tex

diff --git a/docs/changes.txt b/docs/changes.txt
index 0dc9025a39..0ea04eb93f 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -39,6 +39,7 @@ All:
 - Fixed crashes in helpview when opening a file.
 - Added wxMutex::LockTimeout() (Aleksandr Napylov)
 - Set locale to the default in all ports, not just wxGTK
+- Added wxGridUpdateLocker helper class (Evgeniy Tarassov)
 
 wxGTK:
 
diff --git a/docs/latex/wx/classes.tex b/docs/latex/wx/classes.tex
index 50f5926823..5046e4ceaa 100644
--- a/docs/latex/wx/classes.tex
+++ b/docs/latex/wx/classes.tex
@@ -188,6 +188,7 @@
 \input gridrend.tex
 \input gridtbl.tex
 \input gridsizr.tex
+\input gupdlock.tex
 \input hashmap.tex
 \input hashset.tex
 \input hash.tex
diff --git a/docs/latex/wx/grid.tex b/docs/latex/wx/grid.tex
index 0231c365d0..62b640cda8 100644
--- a/docs/latex/wx/grid.tex
+++ b/docs/latex/wx/grid.tex
@@ -253,6 +253,10 @@ the grid is suppressed. Each call to BeginBatch must be matched by a later call
 modification can be enclosed between BeginBatch and EndBatch calls to avoid
 screen flicker. The final EndBatch will cause the grid to be repainted.
 
+\wxheading{See also}
+
+\helpref{wxGridUpdateLocker}{wxgridupdatelocker}
+
 
 
 \membersection{wxGrid::BlockToDeviceRect}\label{wxgridblocktodevicerect}
@@ -514,6 +518,10 @@ EndBatch. Code that does a lot of grid modification can be enclosed between
 BeginBatch and EndBatch calls to avoid screen flicker. The final EndBatch will
 cause the grid to be repainted.
 
+\wxheading{See also}
+
+\helpref{wxGridUpdateLocker}{wxgridupdatelocker}
+
 
 
 \membersection{wxGrid::Fit}\label{wxgridfit}
diff --git a/docs/latex/wx/gupdlock.tex b/docs/latex/wx/gupdlock.tex
new file mode 100644
index 0000000000..f0c6a3ce2e
--- /dev/null
+++ b/docs/latex/wx/gupdlock.tex
@@ -0,0 +1,81 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Name:        gupdlock.tex
+%% Purpose:     wxGridUpdateLocker documentation
+%% Author:      Evgeniy Tarassov
+%% Created:     2007-03-15
+%% RCS-ID:      $Id$
+%% Copyright:   (c) 2007 TT-Solutions SARL
+%% License:     wxWindows license
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{\class{wxGridUpdateLocker}}\label{wxgridupdatelocker}
+
+This small class can be used to prevent \helpref{wxGrid}{wxgrid} from redrawing
+during its lifetime by calling \helpref{wxGrid::BeginBatch}{wxgridbeginbatch}
+in its constructor and \helpref{wxGrid::EndBatch}{wxgridendbatch} in its
+destructor. It is typically used in a function performing several operations
+with a grid which would otherwise result in flicker. For example:
+
+{\small
+\begin{verbatim}
+    void MyFrame::Foo()
+    {
+        m_grid = new wxGrid(this, ...);
+
+        wxGridUpdateLocker noUpdates(m_grid);
+        m_grid->AppendColumn();
+        ... many other operations with m_grid...
+        m_grid->AppendRow();
+
+        // destructor called, grid refreshed
+    }
+\end{verbatim}
+}
+
+Using this class is easier and safer than calling 
+\helpref{BeginBatch}{wxgridbeginbatch} and \helpref{EndBatch}{wxgridendbatch}
+because you don't risk not to call the latter (due to an exception for example).
+
+\wxheading{Derived from}
+
+None.
+
+\wxheading{Include files}
+
+<wx/grid.h>
+
+
+\latexignore{\rtfignore{\wxheading{Members}}}
+
+
+\membersection{wxGridUpdateLocker::wxGridUpdateLocker}\label{wxgridupdatelockerctor}
+
+\func{}{wxGridUpdateLocker}{\param{wxGrid *}{grid = \NULL}}
+
+Creates an object preventing the updates of the specified \arg{grid}. The
+parameter could be \NULL in which case nothing is done. If \arg{grid} is
+non-\NULL then the grid must exist for longer than wxGridUpdateLocker object
+itself.
+
+The default constructor could be followed by a call to 
+\helpref{wxGridUpdateLocker::Create}{wxgridupdatelockercreate} to set the
+grid object later.
+
+
+
+\membersection{wxGridUpdateLocker::\destruct{wxGridUpdateLocker}}\label{wxgridupdatelockerdtor}
+
+\func{}{\destruct{wxGridUpdateLocker}}{\void}
+
+Destructor reenables updates for the grid this object is associated with.
+
+
+
+\membersection{wxGridUpdateLocker::Create}\label{wxgridupdatelockercreate}
+
+\func{void}{Create}{\param{wxGrid* }{grid}}
+
+This method can be called if the object had been constructed using the default
+constructor. It must not be called more than once.
+
+
diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h
index 4229751aa1..2d04e59b6c 100644
--- a/include/wx/generic/grid.h
+++ b/include/wx/generic/grid.h
@@ -2007,6 +2007,47 @@ protected:
 };
 
 
+// ----------------------------------------------------------------------------
+// wxGridUpdateLocker prevents updates to a grid during its lifetime
+// ----------------------------------------------------------------------------
+
+class WXDLLIMPEXP_ADV wxGridUpdateLocker
+{
+public:
+    // if the pointer is NULL, Create() can be called later
+    wxGridUpdateLocker(wxGrid *grid = NULL)
+    {
+        Init(grid);
+    }
+
+    // can be called if ctor was used with a NULL pointer, must not be called
+    // more than once
+    void Create(wxGrid *grid)
+    {
+        wxASSERT_MSG( !m_grid, _T("shouldn't be called more than once") );
+
+        Init(grid);
+    }
+
+    ~wxGridUpdateLocker()
+    {
+        if ( m_grid )
+            m_grid->EndBatch();
+    }
+
+private:
+    void Init(wxGrid *grid)
+    {
+        m_grid = grid;
+        if ( m_grid )
+            m_grid->BeginBatch();
+    }
+
+    wxGrid *m_grid;
+
+    DECLARE_NO_COPY_CLASS(wxGridUpdateLocker)
+};
+
 // ----------------------------------------------------------------------------
 // Grid event class and event types
 // ----------------------------------------------------------------------------
diff --git a/samples/grid/griddemo.cpp b/samples/grid/griddemo.cpp
index 387fb57614..85867844af 100644
--- a/samples/grid/griddemo.cpp
+++ b/samples/grid/griddemo.cpp
@@ -668,7 +668,7 @@ void GridFrame::DeleteSelectedRows( wxCommandEvent& WXUNUSED(ev) )
 {
     if ( grid->IsSelection() )
     {
-        grid->BeginBatch();
+        wxGridUpdateLocker locker(grid);
         for ( int n = 0; n < grid->GetNumberRows(); )
         {
             if ( grid->IsInSelection( n , 0 ) )
@@ -676,7 +676,6 @@ void GridFrame::DeleteSelectedRows( wxCommandEvent& WXUNUSED(ev) )
             else
                 n++;
         }
-        grid->EndBatch();
     }
 }
 
@@ -685,7 +684,7 @@ void GridFrame::DeleteSelectedCols( wxCommandEvent& WXUNUSED(ev) )
 {
     if ( grid->IsSelection() )
     {
-        grid->BeginBatch();
+        wxGridUpdateLocker locker(grid);
         for ( int n = 0; n < grid->GetNumberCols(); )
         {
             if ( grid->IsInSelection( 0 , n ) )
@@ -693,7 +692,6 @@ void GridFrame::DeleteSelectedCols( wxCommandEvent& WXUNUSED(ev) )
             else
                 n++;
         }
-        grid->EndBatch();
     }
 }
 
diff --git a/src/common/dbgrid.cpp b/src/common/dbgrid.cpp
index d8b13172a3..634be020d8 100644
--- a/src/common/dbgrid.cpp
+++ b/src/common/dbgrid.cpp
@@ -203,11 +203,12 @@ bool wxDbGridTableBase::AssignDbTable(wxDbTable *tab, int count, bool takeOwners
 {
     wxDbGridCellAttrProvider *provider;
 
+    wxGridUpdateLocker locker(GetView());
+
     //Remove Information from grid about old data
     if (GetView())
     {
         wxGrid *grid = GetView();
-        grid->BeginBatch();
         grid->ClearSelection();
         if (grid->IsCellEditControlEnabled())
         {
@@ -250,7 +251,6 @@ bool wxDbGridTableBase::AssignDbTable(wxDbTable *tab, int count, bool takeOwners
         wxGrid * grid = GetView();
         wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rowtotal);
         grid->ProcessTableMessage(msg);
-        grid->EndBatch();
     }
     m_dbowner = takeOwnership;
     m_rowmodified = false;
diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp
index 20121718e0..e8ef3ce6dd 100644
--- a/src/generic/grid.cpp
+++ b/src/generic/grid.cpp
@@ -10595,8 +10595,9 @@ int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin)
 {
     int width = m_rowLabelWidth;
 
-    if ( !calcOnly )
-        BeginBatch();
+    wxGridUpdateLocker locker;
+    if(!calcOnly)
+        locker.Create(this);
 
     for ( int col = 0; col < m_numCols; col++ )
     {
@@ -10606,9 +10607,6 @@ int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin)
         width += GetColWidth(col);
     }
 
-    if ( !calcOnly )
-        EndBatch();
-
     return width;
 }
 
@@ -10616,8 +10614,9 @@ int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin)
 {
     int height = m_colLabelHeight;
 
-    if ( !calcOnly )
-        BeginBatch();
+    wxGridUpdateLocker locker;
+    if(!calcOnly)
+        locker.Create(this);
 
     for ( int row = 0; row < m_numRows; row++ )
     {
@@ -10627,15 +10626,12 @@ int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin)
         height += GetRowHeight(row);
     }
 
-    if ( !calcOnly )
-        EndBatch();
-
     return height;
 }
 
 void wxGrid::AutoSize()
 {
-    BeginBatch();
+    wxGridUpdateLocker locker(this);
 
     // we need to round up the size of the scrollable area to a multiple of
     // scroll step to ensure that we don't get the scrollbars when we're sized
@@ -10701,8 +10697,6 @@ void wxGrid::AutoSize()
     // client size but also leave space for (not needed any more) scrollbars
     SetScrollbars(0, 0, 0, 0, 0, 0, true);
     SetClientSize(sizeFit.x + m_rowLabelWidth, sizeFit.y + m_colLabelHeight);
-
-    EndBatch();
 }
 
 void wxGrid::AutoSizeRowLabelSize( int row )
-- 
2.50.0

