Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

table.hpp

00001 // table.hpp
00002 
00003 // Copyright (C) 2004 Steven Weiß (steven11@gmx.de)
00004 //
00005 // Permission to copy, use, sell and distribute this software is granted
00006 // provided this copyright notice appears in all copies.
00007 // Permission to modify the code and to distribute modified code is granted
00008 // provided this copyright notice appears in all copies, and a notice
00009 // that the code was modified is included with the copyright notice.
00010 //
00011 // This software is provided "as is" without express or implied warranty,
00012 // and with no claim as to its suitability for any purpose.
00013 
00014 
00015 #pragma once
00016 #include <background_wnd/detail/include.hpp>
00017 
00018 
00019 namespace win32 { namespace gui {
00020 namespace bg_wnd {
00021 
00022 template <class CellData> class table;                      // forward declarations
00023 
00024 namespace detail {
00025      template <class Table> class forward_proxy;
00026 }
00027 
00028 // ========================================================================================================= //
00029 
00033 class COORDS
00034 {    
00035      unsigned col_;
00036      unsigned row_;
00037 
00038 public:
00040      COORDS(unsigned col, unsigned row) : col_(col), row_(row)
00041      {}
00042 
00044      void row(unsigned r)
00045      {
00046           row_ = r;
00047      }
00048 
00050      unsigned row() const
00051      {
00052           return row_;
00053      }    
00054 
00056      void col(unsigned c)
00057      {
00058           col_ = c;
00059      }
00060 
00062      unsigned col() const
00063      {
00064           return col_;
00065      }    
00066 
00068      void move(int horz, int vert)
00069      {
00070           col_ += horz;
00071           row_ += vert;       
00072      }
00073 
00075      bool operator== (COORDS coords) const
00076      {
00077           return row_ == coords.row() && col_ == coords.col();
00078      }
00079 
00081      bool operator!= (COORDS coords) const
00082      {
00083           return ! operator== (coords);
00084      }
00085 
00087      void swap(COORDS& coords)
00088      {
00089           std::swap(row_, coords.row_);
00090           std::swap(col_, coords.col_);
00091      }
00092 };
00093 
00094 // ========================================================================================================== //
00095 
00099 class cell_range
00100 {         
00101      COORDS top_left_;
00102      COORDS bottom_right_;
00103 
00104      inline static bool between(unsigned val, unsigned start, unsigned end)
00105      {
00106           return (start <= val && val <= end);
00107      }
00108 
00109 public:        
00111      cell_range(COORDS topleft, COORDS bottomright) 
00112           : top_left_(topleft), bottom_right_(bottomright)
00113      {         
00114           _ASSERTE(top_left_.col() <= bottom_right_.col());      // coordinates must be correct     
00115           _ASSERTE(top_left_.row() <= bottom_right_.row());      
00116      }
00117 
00124      cell_range(COORDS topleft, unsigned horz_count, unsigned vert_count) 
00125           : top_left_( topleft ), 
00126             bottom_right_( topleft.col() + ((horz_count == 0) ? 0 : horz_count - 1), topleft.row() + ((vert_count == 0) ? 0 : vert_count - 1) )
00127      {}
00128      
00130      bool is_intersecting(const cell_range& range) const
00131      {              
00132           bool bHorz = between(range.top_left_.col(),      top_left_.col(),        bottom_right_.col()) ||
00133                           between(range.bottom_right_.col(), top_left_.col(),      bottom_right_.col()) ||
00134                           between(top_left_.col(),              range.top_left_.col(), range.bottom_right_.col()) ||
00135                           between(bottom_right_.col(),     range.top_left_.col(), range.bottom_right_.col()); 
00136 
00137           bool bVert = between(range.top_left_.row(),      top_left_.row(),        bottom_right_.row()) ||
00138                           between(range.bottom_right_.row(), top_left_.row(),      bottom_right_.row()) ||
00139                           between(top_left_.row(),              range.top_left_.row(), range.bottom_right_.row()) ||
00140                           between(bottom_right_.row(),     range.top_left_.row(), range.bottom_right_.row());           
00141           return bHorz && bVert;
00142      }
00143      
00145      cell_range operator+ (const cell_range& range) const
00146      {
00147           cell_range m_ret(*this);
00148           m_ret += range;
00149           return m_ret;
00150      }
00151 
00153      void operator+= (const cell_range& range)
00154      {
00155           top_left_.col( min(top_left_.col(), range.top_left_.col()) );
00156           top_left_.row( min(top_left_.row(), range.top_left_.row()) );
00157           bottom_right_.col( max(bottom_right_.col(), range.bottom_right_.col()) );
00158           bottom_right_.row( max(bottom_right_.row(), range.bottom_right_.row()) );       
00159      }         
00160 
00162      bool operator== (const cell_range& range) const
00163      {
00164           return top_left_     == range.top_left_ &&
00165                   bottom_right_ == range.bottom_right_;
00166      }
00167 
00169      bool operator!= (const cell_range& range) const
00170      {
00171           return ! operator==(range);
00172      }
00173 
00175      COORDS top_left() const
00176      {         
00177           return top_left_;
00178      }
00179 
00181      COORDS bottom_right() const
00182      {         
00183           return bottom_right_;
00184      }
00185 
00187      void move(int horz, int vert)
00188      {
00189           // ensure the coordinates won't be less than 0 (-> they are unsigned!)          
00190           int horz_amount = top_left_.col() + horz;
00191           int vert_amount = top_left_.row() + vert;
00192           if (horz_amount < 0)
00193                horz -= horz_amount;
00194           if (vert_amount < 0)
00195                vert -= vert_amount;
00196 
00197           top_left_.move(horz, vert);
00198           bottom_right_.move(horz, vert);         
00199      }    
00200 
00202      void horz_count(unsigned count)
00203      {
00204           _ASSERTE(count > 0);               // 0 is not possible
00205           bottom_right_.col( top_left_.col() + (count - 1) );
00206      }
00207 
00209      unsigned horz_count() const
00210      {
00211           return (bottom_right_.col() - top_left_.col()) + 1;
00212      }
00213 
00215      void vert_count(unsigned count)
00216      {
00217           _ASSERTE(count > 0);               // 0 is not possible          
00218           bottom_right_.row( top_left_.row() + (count - 1) );
00219      }
00220 
00222      unsigned vert_count() const
00223      {
00224           return (bottom_right_.row() - top_left_.row()) + 1;
00225      }
00226 };
00227 
00228 
00229 // ========================================================================================================== //
00230 
00231 namespace detail {
00232 
00233      // Base class of cell_proxy. this class is the implementation shared by both cell_proxy-specializations
00234      template <class CellData>
00235      class cell_proxy_base
00236      {         
00237      protected:
00238           typedef CellData cell_data;   
00239           typedef table<CellData> Table;
00240           typedef typename Table::factor      factor;
00241 
00242           COORDS coords_;                    // coordinates of the cell
00243 
00244           cell_proxy_base(COORDS coords) : coords_(coords)
00245           {}
00246 
00247           inline factor log_left(const Table& table) const
00248           {
00249                factor x = 0;
00250                unsigned begin_col = range(table).top_left().col();    
00251                for (unsigned c = 0; c < begin_col; ++c)
00252                     x += table.col_width(c);
00253                return x;
00254           }
00255 
00256           inline factor log_top(const Table& table) const
00257           {
00258                factor y = 0;
00259                unsigned begin_row = range(table).top_left().row();    
00260                for (unsigned r = 0; r < begin_row; ++r)
00261                     y += table.row_height(r);
00262                return y;
00263           }
00264 
00265           inline factor log_width(const Table& table) const
00266           {
00267                factor width = 0;
00268                unsigned begin_col = range(table).top_left().col();
00269                unsigned end_col   = range(table).bottom_right().col();          
00270                for (unsigned c = begin_col; c <= end_col; ++c)
00271                     width += table.col_width(c);       
00272                return width;
00273           }
00274 
00275           inline factor log_height(const Table& table) const
00276           {
00277                factor height = 0;
00278                unsigned begin_row = range(table).top_left().row();
00279                unsigned end_row   = range(table).bottom_right().row();                    
00280                for (unsigned r = begin_row; r <= end_row; ++r)
00281                     height += table.row_height(r);          
00282                return height;      
00283           }
00284 
00285           const cell_range range(const Table& table) const
00286           {    
00287                typename Table::MergeColl::iterator it_range = table.find_cell_range(coords_);       
00288                if (it_range != table.pMerges_->end())
00289                     return *it_range;
00290                else
00291                     return cell_range(coords_, coords_);         // cell isn't in a range so create one exclusively for this cell ;-)
00292           }
00293 
00294           inline const cell_data get_cell_data(const Table& table) const
00295           {
00296                return (*table.pMatrix_) [ table.cell_idx(coords_) ];
00297           }
00298      };
00299 }    // namespace detail
00300 
00301 // ========================================================================================================== //
00302 
00312 // there are two specializations:
00313 //        one for a non-const table: the user is allowed to change the cell's data
00314 //        one for a const table: the user has only read-access to the cell
00315 template <class Table> class cell_proxy;
00316 
00317 // specialization for a non-const table
00318 template <class CellData>
00319 class cell_proxy<table<CellData> > : private detail::cell_proxy_base<CellData>
00320 {    
00321      typedef detail::cell_proxy_base<CellData> Base;
00322 
00323      Table&     table_;
00324           
00325      // a cell_proxy based on a const Table should be constructible by this non-const cell_proxy.
00326      // it needs access to table_ so it's our friend ;-)
00327      friend class cell_proxy<const Table>;
00328 
00329      // only a forward_proxy is allowed to create an object of this class ;-)
00330      friend class detail::forward_proxy<Table>;   
00331      cell_proxy(Table& table, COORDS coords) : Base(coords), table_(table)
00332      {}   
00333      
00334 public:   
00335      typedef typename Base::cell_data cell_data;
00336 
00338      cell_proxy(const cell_proxy& cell) : Base(cell.coords_), table_(cell.table_)
00339      {}
00340 
00342      const cell_proxy& operator= (const cell_data& data)    
00343      { 
00344           (*table_.pMatrix_) [ table_.cell_idx(coords_) ] = data;                    
00345           return *this;
00346      }
00347      
00349      factor log_left() const       { return Base::log_left(table_); }
00350 
00352      factor log_top() const        { return Base::log_top(table_);    }
00353 
00355      factor log_width() const { return Base::log_width(table_); }
00356 
00358      factor log_height() const     { return Base::log_height(table_); }
00359 
00361      const cell_range range() const { return Base::range(table_); }
00362 
00363      // conversion to CellData
00364      operator const cell_data() const { return Base::get_cell_data(table_); }
00365 };
00366 
00367 // specialization for a const table
00368 template <class CellData>
00369 class cell_proxy<const table<CellData> > : private detail::cell_proxy_base<CellData>
00370 {    
00371      typedef detail::cell_proxy_base<CellData> Base;   
00372                
00373      const Table& table_;
00374      
00375      // only a forward_proxy is allowed to create an object of this class ;-)
00376      friend class detail::forward_proxy<const Table>;  
00377      cell_proxy(const Table& t, COORDS coords) : Base(coords), table_(t)
00378      {}   
00379      
00380 public:   
00381      typedef typename Base::cell_data cell_data;
00382 
00384      cell_proxy(const cell_proxy& cell) : Base(cell.coords_), table_(cell.table_)
00385      {}
00386 
00388      cell_proxy(const cell_proxy<Table>& cell) : Base(cell.coords_), table_(cell.table_)
00389      {}
00390 
00392      factor log_left() const       { return Base::log_left(table_); }
00393 
00395      factor log_top() const        { return Base::log_top(table_);    }
00396 
00398      factor log_width() const { return Base::log_width(table_); }
00399 
00401      factor log_height() const     { return Base::log_height(table_); }
00402 
00404      const cell_range range() const { return Base::range(table_); }
00405 
00406      // conversion to CellData
00407      operator const cell_data() const { return Base::get_cell_data(table_); }
00408 };
00409 
00410 // ========================================================================================================= //
00411 
00412 namespace detail {
00413      // proxy class which returns a cell_proxy-object for the cell [col_idx][row_idx]. this indirection is necessary because
00414      // operator[] has only one dimension -> operator[] of table returns a forward_proxy so this creates two dimensions ;-)
00415      template <class Table>
00416      class forward_proxy
00417      {              
00418           Table& matrix_;
00419           unsigned col_;
00420 
00421           // only a table is allowed to construct an object of this class ;-)
00422           typedef typename Table::cell_data cell_data;
00423           friend class table<cell_data>;
00424           forward_proxy(Table& table, unsigned col) : matrix_(table), col_(col)
00425           {}
00426 
00427      public:
00428           // forward to cell_proxy
00429           inline cell_proxy<Table> operator[] (unsigned row)
00430           {                   
00431                return cell_proxy<Table> (matrix_, COORDS(col_, row));
00432           }
00433 
00434           inline const cell_proxy<Table> operator[] (unsigned row) const
00435           {    
00436                return cell_proxy<Table> (matrix_, COORDS(col_, row));                
00437           }
00438      };
00439 }    // namespace detail
00440 
00441 // ========================================================================================================= //
00442 
00455 template <class CellData>
00456 class table
00457 {    
00458 public:
00459      // typedef's
00460      typedef double factor;             // factor which indicates the height, width and position of cells. they are
00461                                              // only logical -> you have to define a default value which will be multiplied with the factor                               
00462      typedef CellData cell_data;
00463      typedef table<CellData> self;
00464      
00465      typedef cell_proxy<self>                cell_type;          
00466      typedef const cell_proxy<const self>    const_cell_type;
00467 
00468      // cell_proxy_base is a friend (needs access to our matrix). cell_type is also a friend (needs to change a cell)
00469      friend class detail::cell_proxy_base<CellData>;
00470      friend class cell_type;
00471      
00472 
00477      table(const cell_data& def_cell_data) : pMatrix_(new Matrix()), pRowHeights_(new RowHeightColl()), pColWidths_(new ColWidthColl()), pMerges_(new MergeColl()), def_cell_data_(def_cell_data)
00478      {}
00479 
00486      table(const cell_data& def_cell_data, unsigned cols, unsigned rows) 
00487           : pMatrix_( new Matrix(cols * rows, def_cell_data) ),                 // init with default cell_data
00488             pColWidths_(new ColWidthColl(cols, 1)),
00489             pRowHeights_(new RowHeightColl(rows, 1)),
00490             pMerges_(new MergeColl()), def_cell_data_(def_cell_data)
00491      {}
00492 
00493      // copy c'tor
00494      table(const table& t) 
00495           : pMatrix_( new Matrix(*t.pMatrix_.get()) ),
00496             pColWidths_( new ColWidthColl(*t.pColWidths_.get()) ),
00497             pRowHeights_( new RowHeightColl(*t.pRowHeights_.get()) ),
00498             pMerges_( new MergeColl(*t.pMerges_.get()) ),
00499             def_cell_data_(t.def_cell_data_)
00500      {}
00501 
00502      virtual ~table()
00503      {}
00504 
00505      const table& operator= (const table& t)
00506      {
00507           if (this != &t) {
00508                table temp(t);
00509                swap(temp);              
00510           }
00511           return *this;
00512      }
00513 
00516      const cell_data default_cell_data() const
00517      {
00518           return def_cell_data_;
00519      }
00520 
00523      void dimensions(unsigned cols, unsigned rows)
00524      {
00525           if (rows == 0 || cols == 0) {
00526                pMatrix_->clear();       
00527                pRowHeights_->clear();
00528                pColWidths_->clear();    
00529                pMerges_->clear();            
00530           }
00531           // copy cells (exception safe)
00532           else if (rows != row_count() || cols != col_count()) {
00533                self temp(def_cell_data_, cols, rows);
00534 
00535                // set row heights and copy cell data
00536                for (unsigned row = 0; row < rows && row < row_count(); ++row) {
00537                     temp.row_height(row, row_height(row));
00538                     for (unsigned col = 0; col < cols && col < col_count(); ++col)                            
00539                          temp[col][row] = (*this) [col][row];                                            
00540                }
00541                // set column widths
00542                for (unsigned col = 0; col < cols && col < col_count(); ++col)
00543                     temp.col_width(col, col_width(col));
00544                
00545                // copy ranges           
00546                temp.pMerges_->reserve(pMerges_->size());
00547                for (MergeColl::iterator it = pMerges_->begin(); it != pMerges_->end(); ++it)
00548                {              
00549                     // if table shrinks some ranges can be deleted
00550                     cell_range range = *it;       
00551                     unsigned left   = range.top_left().col();
00552                     unsigned top    = range.top_left().row();
00553                     
00554                     if (cols <= left || rows <= top)
00555                          continue;                     
00556                     
00557                     range.horz_count( min(cols - left, range.horz_count()) );        // shrink if necessary
00558                     range.vert_count( min(rows - top, range.vert_count()) );
00559                          
00560                     temp.pMerges_->push_back( range );
00561                }              
00562 
00563                swap(temp);
00564           }
00565      }
00566 
00569      inline unsigned row_count() const
00570      {
00571           return static_cast<unsigned> (pRowHeights_->size());
00572      }
00573 
00576      inline unsigned col_count() const
00577      {
00578           return static_cast<unsigned> (pColWidths_->size());
00579      }
00580 
00583      inline detail::forward_proxy<self> operator[] (unsigned col)
00584      {
00585           return detail::forward_proxy<self> (*this, col);
00586      }
00587 
00590      inline const detail::forward_proxy<const self> operator[] (unsigned col) const
00591      {
00592           return detail::forward_proxy<const self> (*this, col);
00593      }
00594 
00599      void row_height(unsigned row, factor height_factor)
00600      {
00601           _ASSERTE(row < pRowHeights_->size());                  // must be in bounds
00602           (*pRowHeights_) [row] = height_factor;  
00603      }
00604 
00609      factor row_height(unsigned row) const
00610      {
00611           _ASSERTE(row < pRowHeights_->size());                  // must be in bounds
00612           return (*pRowHeights_) [row];           
00613      }
00614 
00619      void col_width(unsigned col, factor width_factor)
00620      {
00621           _ASSERTE(col < pColWidths_->size());                   // must be in bounds
00622           (*pColWidths_) [col] = width_factor;
00623      }
00624 
00629      factor col_width(unsigned col) const
00630      {
00631           _ASSERTE(col < pColWidths_->size());                   // must be in bounds
00632           return (*pColWidths_) [col];            
00633      }                   
00634 
00639      void insert_row(unsigned row)
00640      {
00641           row = min(row, row_count());
00642 
00643           // copy cells (exception safe)
00644           self temp(def_cell_data_, col_count(), row_count() + 1);
00645           for (unsigned c = 0; c < col_count(); ++c) {
00646                for (unsigned r = 0; r < row_count() + 1; ++r) {
00647                     if (r < row)
00648                          temp[c][r] = (*this) [c][r];
00649                     else if (r > row)
00650                          temp[c][r] = (*this) [c][r - 1];
00651                }
00652           }    
00653 
00654           // copy merges
00655           temp.pMerges_->reserve(pMerges_->size());
00656           for (MergeColl::iterator it = pMerges_->begin(); it != pMerges_->end(); ++it) {           
00657                // if a row is inserted the ranges are likely to be changed
00658                cell_range range = *it;  
00659                unsigned top    = range.top_left().row();
00660                unsigned bottom = range.bottom_right().row();
00661                if (row <= top)
00662                     range.move(0, 1);                  
00663                else if (top < row && row <= bottom)
00664                     range.vert_count(range.vert_count() + 1);
00665 
00666                temp.pMerges_->push_back( range );
00667           }
00668 
00669           // ensure exception safety ;-)
00670           swap(temp);
00671      }         
00672 
00677      void insert_col(unsigned col)
00678      {
00679           col = min(col, col_count());
00680 
00681           // copy cells
00682           self temp(def_cell_data_, col_count() + 1, row_count());
00683           for (unsigned r = 0; r < row_count(); ++r) {
00684                for (unsigned c = 0; c < col_count() + 1; ++c) {
00685                     if (c < col)
00686                          temp[c][r] = (*this) [c][r];
00687                     else if (c > col)
00688                          temp[c][r] = (*this) [c - 1][r];
00689                }                   
00690           }         
00691 
00692           // copy merges
00693           temp.pMerges_->reserve(pMerges_->size());
00694           for (MergeColl::iterator it = pMerges_->begin(); it != pMerges_->end(); ++it) {           
00695                // if a column is inserted the ranges are likely to be changed
00696                cell_range range = *it;       
00697                unsigned left  = range.top_left().col();
00698                unsigned right = range.bottom_right().col();
00699                if (col <= left)
00700                     range.move(1, 0);                  
00701                else if (left < col && col <= right)
00702                     range.horz_count(range.horz_count() + 1);
00703 
00704                temp.pMerges_->push_back( range );
00705           }
00706 
00707           // ensure exception safety ;-)
00708           swap(temp);
00709      }    
00710 
00713      void remove_col(unsigned col)
00714      {
00715           _ASSERTE(col < col_count());  
00716 
00717           // take care of the merged cells
00718           for (unsigned row = 0; row < row_count(); ++row) {
00719                MergeColl::iterator it_range = find_cell_range(COORDS(col, row));
00720                if (it_range != pMerges_->end()) {
00721                     cell_range& range = *it_range;
00722                     
00723                     if (range.horz_count() == 1)                 // if range is only in this column remove it
00724                          pMerges_->erase(it_range);                        
00725                     else {
00726                          unsigned left  = range.top_left().col();
00727                          unsigned right = range.bottom_right().col();
00728                                              
00729                          if (left <= col && col <= right) {                     
00730                               range.horz_count(range.horz_count() - 1);
00731                               row += range.vert_count() - 1;          // go to next row which isn't in this range
00732                          }
00733                          if (left == col)                             // if first column of range is removed move the range
00734                               range.move(-1, 0);
00735                     }
00736                }              
00737           }    
00738 
00739           // erase cells - but from last to first so that the index is always correct. 
00740           // note: because row is unsigned we have to be aware of the underflow when decreasing 0!!!
00741           for (unsigned row = row_count(); row > 0; --row)
00742                pMatrix_->erase( pMatrix_->begin() + cell_idx(COORDS(col, row - 1)) );
00743 
00744           // erase column          
00745           pColWidths_->erase(pColWidths_->begin() + col);        
00746      }
00747      
00750      void remove_row(unsigned row)
00751      {
00752           _ASSERTE(row < row_count());  
00753 
00754           // take care of the merged cells
00755           for (unsigned col = 0; col < col_count(); ++col) {
00756                MergeColl::iterator it_range = find_cell_range(COORDS(col, row));
00757                if (it_range != pMerges_->end()) {
00758                     cell_range& range = *it_range;
00759                     
00760                     if (range.vert_count() == 1)                 // if range is only in this row remove it
00761                          pMerges_->erase(it_range);                        
00762                     else {
00763                          unsigned top    = range.top_left().row();
00764                          unsigned bottom = range.bottom_right().row();
00765                                              
00766                          if (top <= row && row <= bottom) {                     
00767                               range.vert_count(range.vert_count() - 1);
00768                               col += range.horz_count() - 1;          // go to next column which isn't in this range
00769                          }
00770                          if (top == row)                                   // if first row of range is removed move the range
00771                               range.move(0, -1);
00772                     }
00773                }              
00774           }    
00775 
00776           // erase cells - but from last to first so that the index is always correct. 
00777           // note: because col is unsigned we have to be aware of the underflow when decreasing 0!!!
00778           for (unsigned col = col_count(); col > 0; --col)
00779                pMatrix_->erase( pMatrix_->begin() + cell_idx(COORDS(col - 1, row)) );
00780 
00781           // erase row
00782           pRowHeights_->erase(pRowHeights_->begin() + row);
00783      }
00784 
00787      void merge_cells(const cell_range& range)
00788      {
00789           cell_range r = apply_merge_recursive(range);
00790           pMerges_->push_back(r);
00791      }
00792 
00795      void unmerge_cells(const cell_range& range)
00796      {
00797           MergeColl::iterator it_range = std::find(pMerges_->begin(), pMerges_->end(), range);
00798           if (it_range != pMerges_->end())
00799                pMerges_->erase(it_range);         
00800      }
00801 
00804      void unmerge_cells(COORDS coords)
00805      {
00806           MergeColl::iterator it_range = find_cell_range(coords);
00807           if (it_range != pMerges_->end())
00808                pMerges_->erase(it_range);
00809      }
00810 
00813      void swap(self& t)
00814      {
00815           std::swap(pMatrix_, t.pMatrix_);
00816           std::swap(pRowHeights_,   t.pRowHeights_);
00817           std::swap(pColWidths_,    t.pColWidths_);
00818           std::swap(def_cell_data_, t.def_cell_data_);
00819           std::swap(pMerges_, t.pMerges_);
00820      }
00821 
00822 private:  
00823      // applies a merge-operation recursively
00824      cell_range apply_merge_recursive(const cell_range& range)
00825      {              
00826           for (unsigned i = 0; i < pMerges_->size(); ++i) {           
00827                cell_range& r2 = (*pMerges_) [i];
00828                if (range == r2)
00829                     continue;
00830 
00831                // if merges intersect add them and call this function recursive                          
00832                if (range.is_intersecting(r2)) {
00833                     cell_range temp = range + r2;      
00834                     if (temp != range) {                         
00835                          pMerges_->erase(pMerges_->begin() + i);      // erase from collection
00836                          --i;                
00837                          return apply_merge_recursive(temp);
00838                     }
00839                }
00840           }
00841 
00842           return range;
00843      }
00844 
00845      // returns the index of cell with the passed coordinates in the vector matrix_
00846      inline unsigned cell_idx(COORDS coords) const
00847      {              
00848           unsigned ret = coords.col() + coords.row() * col_count();
00849           _ASSERTE(ret < (row_count() * col_count())); // index must be in bounds
00850           return ret;
00851      }
00852 
00853 
00854 private:
00855      // members
00856      typedef std::vector<cell_data> Matrix;
00857      typedef std::auto_ptr<Matrix> MatrixPtr;
00858      MatrixPtr pMatrix_;                                    // the Matrix: saves the data
00859      cell_data def_cell_data_;                              // default data
00860 
00861      typedef std::vector<factor> RowHeightColl;
00862      typedef RowHeightColl         ColWidthColl;
00863      typedef std::auto_ptr<RowHeightColl> RowHeightCollPtr;
00864      typedef std::auto_ptr<ColWidthColl>  ColWidthCollPtr;
00865      RowHeightCollPtr pRowHeights_;                         // saves the height and width of the rows/columns
00866      ColWidthCollPtr  pColWidths_;                
00867 
00868      typedef std::vector<cell_range>   MergeColl;      
00869      typedef std::auto_ptr<MergeColl>  MergeCollPtr;
00870      MergeCollPtr pMerges_;                                 // collection of the merged cells
00871 
00872 
00873 private:
00874      // returns the cell range of the cell with the passed coordinates
00875      MergeColl::iterator find_cell_range(COORDS coords) const
00876      {
00877           cell_range this_cell(coords, coords);
00878           for (MergeColl::iterator it = pMerges_->begin(); it != pMerges_->end(); ++it) {
00879                if (this_cell.is_intersecting(*it))
00880                     return it;               
00881           }
00882 
00883           return pMerges_->end();
00884      }
00885 };
00886 
00887 
00888 }    // namespace bg_wnd
00889 } }  // namespace win32::gui



by Steven Weiss. You can contact me at steven11@gmx.de.