1 // Copyright (C) 2007-2021 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // File : SALOMEDSImpl_AttributeTableOfString.cxx
24 // Author : Sergey Ruin
27 #include "SALOMEDSImpl_AttributeTableOfString.hxx"
32 #define SEPARATOR '\1'
33 typedef std::map<int, std::string>::const_iterator MI;
35 static std::string getUnit(std::string theString)
37 std::string aString(theString);
38 size_t aPos = aString.find(SEPARATOR);
39 return aPos >= aString.size()-1 ? std::string() : aString.substr(aPos+1);
42 static std::string getTitle(std::string theString)
44 std::string aString(theString);
45 size_t aPos = aString.find(SEPARATOR);
46 return aPos == std::string::npos ? aString : aString.substr(0, aPos);
49 const std::string& SALOMEDSImpl_AttributeTableOfString::GetID()
51 static std::string SALOMEDSImpl_AttributeTableOfStringID ("128371A4-8F52-11d6-A8A3-0001021E8C7F");
52 return SALOMEDSImpl_AttributeTableOfStringID;
55 SALOMEDSImpl_AttributeTableOfString* SALOMEDSImpl_AttributeTableOfString::Set(const DF_Label& label)
57 SALOMEDSImpl_AttributeTableOfString* A = NULL;
58 if (!(A=(SALOMEDSImpl_AttributeTableOfString*)label.FindAttribute(SALOMEDSImpl_AttributeTableOfString::GetID()))) {
59 A = new SALOMEDSImpl_AttributeTableOfString();
60 label.AddAttribute(A);
65 SALOMEDSImpl_AttributeTableOfString::SALOMEDSImpl_AttributeTableOfString()
66 :SALOMEDSImpl_GenericAttribute("AttributeTableOfString")
72 void SALOMEDSImpl_AttributeTableOfString::SetNbColumns(const int theNbColumns)
77 std::map<int, std::string> aMap;
81 for(MI p = aMap.begin(); p!=aMap.end(); p++) {
82 int aRow = (int)(p->first/myNbColumns) + 1;
83 int aCol = (int)(p->first - myNbColumns*(aRow-1));
84 if(aCol == 0) { aCol = myNbColumns; aRow--; }
85 if(aCol > theNbColumns) continue;
86 int aKey = (aRow-1)*theNbColumns+aCol;
87 myTable[aKey] = p->second;
90 myNbColumns = theNbColumns;
92 while ((int)myCols.size() < myNbColumns) { // append empty columns titles
93 myCols.push_back(std::string(""));
96 SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved
99 void SALOMEDSImpl_AttributeTableOfString::SetRowTitle(const int theRow,
100 const std::string& theTitle)
104 std::string aTitle(theTitle), aUnit = GetRowUnit(theRow);
109 myRows[theRow-1] = aTitle;
111 SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved
114 void SALOMEDSImpl_AttributeTableOfString::SetRowUnit(const int theRow,
115 const std::string& theUnit)
119 std::string aTitle = GetRowTitle(theRow);
123 myRows[theRow-1] = aTitle;
125 SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved
128 void SALOMEDSImpl_AttributeTableOfString::SetRowUnits(const std::vector<std::string>& theUnits)
130 if ((int)theUnits.size() != GetNbRows()) throw DFexception("Invalid number of rows");
131 size_t aLength = theUnits.size(), i;
132 for(i = 1; i <= aLength; i++) SetRowUnit((int)i, theUnits[i-1]); //!< TODO: conversion from size_t to int
135 std::vector<std::string> SALOMEDSImpl_AttributeTableOfString::GetRowUnits()
137 std::vector<std::string> aSeq;
138 size_t aLength = myRows.size(), i;
139 for(i=0; i<aLength; i++) aSeq.push_back(getUnit(myRows[i]));
143 void SALOMEDSImpl_AttributeTableOfString::SetRowTitles(const std::vector<std::string>& theTitles)
145 if ((int)theTitles.size() != GetNbRows()) throw DFexception("Invalid number of rows");
146 size_t aLength = theTitles.size(), i;
147 for(i = 1; i <= aLength; i++) SetRowTitle((int)i, theTitles[i-1]); //!< TODO: conversion from size_t to int
149 SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved
152 std::vector<std::string> SALOMEDSImpl_AttributeTableOfString::GetRowTitles()
154 std::vector<std::string> aSeq;
155 size_t aLength = myRows.size(), i;
156 for(i=0; i<aLength; i++) aSeq.push_back(getTitle(myRows[i]));
160 std::string SALOMEDSImpl_AttributeTableOfString::GetRowTitle(const int theRow) const
162 return getTitle(myRows[theRow-1]);
165 std::string SALOMEDSImpl_AttributeTableOfString::GetRowUnit(const int theRow) const
167 return getUnit(myRows[theRow-1]);
170 void SALOMEDSImpl_AttributeTableOfString::SetRowData(const int theRow,
171 const std::vector<std::string>& theData)
174 if((int)theData.size() > myNbColumns) SetNbColumns((int)theData.size()); //!< TODO: conversion from size_t to const int, possible loss of data
178 while ((int)myRows.size() < theRow) { // append new row titles
179 myRows.push_back(std::string(""));
182 size_t i, aShift = (theRow-1)*myNbColumns, aLength = theData.size();
183 for(i = 1; i <= aLength; i++) {
184 myTable[int(aShift + i)] = theData[i-1]; //!< TODO: conversion from size_t to int
187 if(theRow > myNbRows) myNbRows = theRow;
189 SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved
192 void SALOMEDSImpl_AttributeTableOfString::SetTitle(const std::string& theTitle)
198 SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved
201 std::string SALOMEDSImpl_AttributeTableOfString::GetTitle() const
206 std::vector<std::string> SALOMEDSImpl_AttributeTableOfString::GetRowData(const int theRow)
208 std::vector<std::string> aSeq;
209 int i, aShift = (theRow-1)*myNbColumns;
210 for(i = 1; i <= myNbColumns; i++) {
211 if(myTable.find(aShift+i) != myTable.end())
212 aSeq.push_back(myTable[aShift+i]);
220 void SALOMEDSImpl_AttributeTableOfString::SetColumnData(const int theColumn,
221 const std::vector<std::string>& theData)
224 if(theColumn > myNbColumns) SetNbColumns(theColumn);
228 size_t i, aLength = theData.size();
229 for(i = 1; i <= aLength; i++) {
230 myTable[myNbColumns*((int)i-1)+theColumn] = theData[i-1]; //!< TODO: conversion from size_t to int
233 if((int)aLength > myNbRows) {
234 myNbRows = (int)aLength; //!< TODO: conversion from size_t to int
235 while ((int)myRows.size() < myNbRows) { // append empty row titles
236 myRows.push_back(std::string(""));
240 SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved
243 std::vector<std::string> SALOMEDSImpl_AttributeTableOfString::GetColumnData(const int theColumn)
245 std::vector<std::string> aSeq;
248 for(i = 1; i <= myNbRows; i++) {
249 anIndex = myNbColumns*(i-1) + theColumn;
250 if(myTable.find(anIndex) != myTable.end())
251 aSeq.push_back(myTable[anIndex]);
259 void SALOMEDSImpl_AttributeTableOfString::SetColumnTitle(const int theColumn,
260 const std::string& theTitle)
264 while((int)myCols.size() < theColumn) myCols.push_back(std::string(""));
265 myCols[theColumn-1] = theTitle;
267 SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved
270 std::string SALOMEDSImpl_AttributeTableOfString::GetColumnTitle(const int theColumn) const
272 if(myCols.empty()) return "";
273 if((int)myCols.size() < theColumn) return "";
274 return myCols[theColumn-1];
277 void SALOMEDSImpl_AttributeTableOfString::SetColumnTitles(const std::vector<std::string>& theTitles)
279 if ((int)theTitles.size() != myNbColumns) throw DFexception("Invalid number of columns");
280 size_t aLength = theTitles.size(), i;
281 for(i = 0; i < aLength; i++) myCols[i] = theTitles[i];
283 SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved
286 std::vector<std::string> SALOMEDSImpl_AttributeTableOfString::GetColumnTitles()
288 std::vector<std::string> aSeq;
289 size_t aLength = myCols.size(), i;
290 for(i=0; i<aLength; i++) aSeq.push_back(myCols[i]);
294 int SALOMEDSImpl_AttributeTableOfString::GetNbRows() const
299 int SALOMEDSImpl_AttributeTableOfString::GetNbColumns() const
304 void SALOMEDSImpl_AttributeTableOfString::PutValue(const std::string& theValue,
310 if(theColumn > myNbColumns) SetNbColumns(theColumn);
312 int anIndex = (theRow-1)*myNbColumns + theColumn;
313 myTable[anIndex] = theValue;
315 if(theRow > myNbRows) {
316 while ((int)myRows.size() < theRow) { // append empty row titles
317 myRows.push_back(std::string(""));
322 SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved
325 bool SALOMEDSImpl_AttributeTableOfString::HasValue(const int theRow,
328 if(theRow > myNbRows || theRow < 1) return false;
329 if(theColumn > myNbColumns || theColumn < 1) return false;
331 int anIndex = (theRow-1)*myNbColumns + theColumn;
332 return (myTable.find(anIndex) != myTable.end());
335 std::string SALOMEDSImpl_AttributeTableOfString::GetValue(const int theRow,
338 if(theRow > myNbRows || theRow < 1) throw DFexception("Invalid cell index");
339 if(theColumn > myNbColumns || theColumn < 1) throw DFexception("Invalid cell index");
341 int anIndex = (theRow-1)*myNbColumns + theColumn;
342 if(myTable.find(anIndex) != myTable.end()) return myTable[anIndex];
344 throw DFexception("Invalid cell index");
348 void SALOMEDSImpl_AttributeTableOfString::RemoveValue(const int theRow, const int theColumn)
351 if(theRow > myNbRows || theRow < 1) throw DFexception("Invalid cell index");
352 if(theColumn > myNbColumns || theColumn < 1) throw DFexception("Invalid cell index");
354 int anIndex = (theRow-1)*myNbColumns + theColumn;
355 if (myTable.find(anIndex) != myTable.end()) {
357 myTable.erase(anIndex);
358 SetModifyFlag(); // table is modified
362 const std::string& SALOMEDSImpl_AttributeTableOfString::ID() const
367 void SALOMEDSImpl_AttributeTableOfString::Restore(DF_Attribute* with)
370 SALOMEDSImpl_AttributeTableOfString* aTable = dynamic_cast<SALOMEDSImpl_AttributeTableOfString*>(with);
376 myTable = aTable->myTable;
377 myNbRows = aTable->myNbRows;
378 myNbColumns = aTable->myNbColumns;
379 myTitle = aTable->myTitle;
381 for(anIndex = 1; anIndex <= aTable->GetNbRows();anIndex++)
382 myRows.push_back(aTable->GetRowTitle(anIndex));
384 for(anIndex = 1; anIndex <= aTable->GetNbColumns(); anIndex++)
385 myCols.push_back(aTable->GetColumnTitle(anIndex));
388 DF_Attribute* SALOMEDSImpl_AttributeTableOfString::NewEmpty() const
390 return new SALOMEDSImpl_AttributeTableOfString();
393 void SALOMEDSImpl_AttributeTableOfString::Paste(DF_Attribute* into)
396 SALOMEDSImpl_AttributeTableOfString* aTable = dynamic_cast<SALOMEDSImpl_AttributeTableOfString*>(into);
398 aTable->myTable.clear();
399 aTable->myCols.clear();
400 aTable->myRows.clear();
402 aTable->myTable = myTable;
403 aTable->myTitle = myTitle;
404 aTable->myNbRows = myNbRows;
405 aTable->myNbColumns = myNbColumns;
407 for(anIndex = 1; anIndex <= GetNbRows();anIndex++)
408 aTable->myRows.push_back(GetRowTitle(anIndex));
409 for(anIndex = 1; anIndex <= GetNbColumns(); anIndex++)
410 aTable->myCols.push_back(GetColumnTitle(anIndex));
413 std::vector<int> SALOMEDSImpl_AttributeTableOfString::GetSetRowIndices(const int theRow)
415 std::vector<int> aSeq;
417 int i, aShift = myNbColumns*(theRow-1);
418 for(i = 1; i <= myNbColumns; i++) {
419 if(myTable.find(aShift + i) != myTable.end()) aSeq.push_back(i);
425 std::vector<int> SALOMEDSImpl_AttributeTableOfString::GetSetColumnIndices(const int theColumn)
427 std::vector<int> aSeq;
430 for(i = 1; i <= myNbRows; i++) {
431 anIndex = myNbColumns*(i-1)+theColumn;
432 if(myTable.find(anIndex) != myTable.end()) aSeq.push_back(i);
438 std::string SALOMEDSImpl_AttributeTableOfString::Save()
441 char* buffer = new char[1024];
445 l = (int)myTitle.size();
446 sprintf(buffer, "%d\n", l);
449 aString += myTitle[i];
454 sprintf(buffer, "%d\n", myNbRows);
458 for(i=0; i<myNbRows; i++) {
459 l = (int)myRows[i].size();
460 sprintf(buffer, "%d\n", l);
463 aString += myRows[i][j];
469 sprintf(buffer, "%d\n", myNbColumns);
473 for(i=0; i<myNbColumns; i++) {
474 l = (int)myCols[i].size();
475 sprintf(buffer, "%d\n", l);
478 aString += myCols[i][j];
483 //Store the table values
484 l = (int)myTable.size();
485 sprintf(buffer, "%d\n", l);
487 for(MI p = myTable.begin(); p!=myTable.end(); p++) {
488 if (p->second.size()) { // check empty string in the value table
489 sprintf(buffer, "%d\n", p->first);
491 unsigned long aValueSize = (unsigned long)p->second.size(); //!< TODO conversion from size_t to unsigned long, possible loss of data
492 sprintf(buffer, "%ld\n", aValueSize);
494 aString += p->second;
496 } else { // write index only of kind: "0key"; "05", for an example
497 sprintf(buffer, "0%d\n", p->first);
506 void SALOMEDSImpl_AttributeTableOfString::Load(const std::string& value)
508 std::vector<std::string> v;
509 int i, j, l, pos, aSize = (int)value.size();
510 for(i = 0, pos = 0; i<aSize; i++) {
511 if(value[i] == '\n') {
512 v.push_back(value.substr(pos, i-pos));
523 l = strtol(v[pos++].c_str(), NULL, 10);
525 myTitle = std::string(l, 0);
527 myTitle[i] = v[pos++][0];
531 myNbRows = strtol(v[pos++].c_str(), NULL, 10);
535 for(i=1; i<=myNbRows; i++) {
536 l = strtol(v[pos++].c_str(), NULL, 10);
537 aStr = std::string(l,0);
539 aStr[j] = v[pos++][0];
541 myRows.push_back(aStr);
545 myNbColumns = strtol(v[pos++].c_str(), NULL, 10);
549 for(i=1; i<=myNbColumns; i++) {
550 l = strtol(v[pos++].c_str(), NULL, 10);
551 aStr = std::string(l,0);
553 aStr[j] = v[pos++][0];
555 myCols.push_back(aStr);
558 //Restore the table values
559 l = strtol(v[pos++].c_str(), NULL, 10);
561 for(i=1; i<=l; i++) {
562 aStr = v[pos++]; //Ket as a string
563 int aKey = strtol(aStr.c_str(), NULL, 10);
565 if(aStr[0] == '0') //If the first character of the key is 0, then empty value
568 strtol(v[pos++].c_str(), NULL, 10);
571 myTable[aKey] = aValue;
575 std::vector<int> SALOMEDSImpl_AttributeTableOfString::SortRow(const int theRow, SortOrder sortOrder, SortPolicy sortPolicy )
578 std::vector<int> result;
579 if ( theRow > 0 && theRow <= myNbRows ) {
580 std::vector<int> indices( myNbColumns );
582 for ( int i = 0; i < myNbColumns; i++ ) {
583 if ( sortPolicy != EmptyIgnore || HasValue(theRow, i+1) ) {
584 indices[cnt++] = i+1;
589 TableSorter<SALOMEDSImpl_AttributeTableOfString> sorter( this, sortOrder, sortPolicy, theRow, true );
590 std::stable_sort( indices.begin(), indices.end(), sorter );
592 if ( sortPolicy == EmptyIgnore ) {
593 std::vector<int> other( myNbColumns );
595 for( int i = 0; i < myNbColumns; i++ )
596 other[i] = HasValue(theRow, i+1) ? indices[cnt++] : i+1;
601 for ( int col = 0; col < (int)indices.size(); col++ ) { //TODO: mismatch signed/unsigned
602 int idx = indices[col];
603 if ( col+1 == idx ) continue;
604 SwapCells(theRow, col+1, theRow, idx);
606 for ( int i = col+1; i < (int)indices.size() && idx1 == 0; i++) //TODO: mismatch signed/unsigned
607 if ( indices[i] == col+1 ) idx1 = i;
610 // no need for SetModifyFlag(), since it is done by SwapCells()
615 std::vector<int> SALOMEDSImpl_AttributeTableOfString::SortColumn(const int theColumn, SortOrder sortOrder, SortPolicy sortPolicy )
618 std::vector<int> result;
619 if ( theColumn > 0 && theColumn <= myNbColumns ) {
620 std::vector<int> indices( myNbRows );
622 for ( int i = 0; i < myNbRows; i++ ) {
623 if ( sortPolicy != EmptyIgnore || HasValue(i+1, theColumn) ) {
624 indices[cnt++] = i+1;
629 TableSorter<SALOMEDSImpl_AttributeTableOfString> sorter( this, sortOrder, sortPolicy, theColumn, false );
630 std::stable_sort( indices.begin(), indices.end(), sorter );
632 if ( sortPolicy == EmptyIgnore ) {
633 std::vector<int> other( myNbRows );
635 for( int i = 0; i < myNbRows; i++ )
636 other[i] = HasValue(i+1, theColumn) ? indices[cnt++] : i+1;
641 for ( int row = 0; row < (int)indices.size(); row++ ) { //TODO: mismatch signed/unsigned
642 int idx = indices[row];
643 if ( row+1 == idx ) continue;
644 SwapCells(row+1, theColumn, idx, theColumn);
646 for ( int i = row+1; i < (int)indices.size() && idx1 == 0; i++) //TODO: mismathc signed/unsigned
647 if ( indices[i] == row+1 ) idx1 = i;
650 // no need for SetModifyFlag(), since it is done by SwapCells()
655 std::vector<int> SALOMEDSImpl_AttributeTableOfString::SortByRow(const int theRow, SortOrder sortOrder, SortPolicy sortPolicy )
658 std::vector<int> result;
659 if ( theRow > 0 && theRow <= myNbRows ) {
660 std::vector<int> indices( myNbColumns );
662 for ( int i = 0; i < myNbColumns; i++ ) {
663 if ( sortPolicy != EmptyIgnore || HasValue(theRow, i+1) ) {
664 indices[cnt++] = i+1;
669 TableSorter<SALOMEDSImpl_AttributeTableOfString> sorter( this, sortOrder, sortPolicy, theRow, true );
670 std::stable_sort( indices.begin(), indices.end(), sorter );
672 if ( sortPolicy == EmptyIgnore ) {
673 std::vector<int> other( myNbColumns );
675 for( int i = 0; i < myNbColumns; i++ )
676 other[i] = HasValue(theRow, i+1) ? indices[cnt++] : i+1;
681 for ( int col = 0; col < (int)indices.size(); col++ ) { //TODO: mismatch signed/unsigned
682 int idx = indices[col];
683 if ( col+1 == idx ) continue;
684 SwapColumns(col+1, idx);
686 for ( int i = col+1; i < (int)indices.size() && idx1 == 0; i++) //TODO: mismatch signed/unsigned
687 if ( indices[i] == col+1 ) idx1 = i;
690 // no need for SetModifyFlag(), since it is done by SwapColumns()
695 std::vector<int> SALOMEDSImpl_AttributeTableOfString::SortByColumn(const int theColumn, SortOrder sortOrder, SortPolicy sortPolicy )
698 std::vector<int> result;
699 if ( theColumn > 0 && theColumn <= myNbColumns ) {
700 std::vector<int> indices( myNbRows );
702 for ( int i = 0; i < myNbRows; i++ ) {
703 if ( sortPolicy != EmptyIgnore || HasValue(i+1, theColumn) ) {
704 indices[cnt++] = i+1;
709 TableSorter<SALOMEDSImpl_AttributeTableOfString> sorter( this, sortOrder, sortPolicy, theColumn, false );
710 std::stable_sort( indices.begin(), indices.end(), sorter );
712 if ( sortPolicy == EmptyIgnore ) {
713 std::vector<int> other( myNbRows );
715 for( int i = 0; i < myNbRows; i++ )
716 other[i] = HasValue(i+1, theColumn) ? indices[cnt++] : i+1;
721 for ( int row = 0; row < (int)indices.size(); row++ ) { //TODO: mismatch signed/unsigned
722 int idx = indices[row];
723 if ( row+1 == idx ) continue;
724 SwapRows(row+1, idx);
726 for ( int i = row+1; i < (int)indices.size() && idx1 == 0; i++) //TODO: mismatch signed/unsigned
727 if ( indices[i] == row+1 ) idx1 = i;
730 // no need for SetModifyFlag(), since it is done by SwapRows()
735 void SALOMEDSImpl_AttributeTableOfString::SwapCells(const int theRow1, const int theColumn1,
736 const int theRow2, const int theColumn2)
739 if (theRow1 > myNbRows || theRow1 < 1) throw DFexception("Invalid cell index");
740 if (theRow2 > myNbRows || theRow2 < 1) throw DFexception("Invalid cell index");
741 if (theColumn1 > myNbColumns || theColumn1 < 1) throw DFexception("Invalid cell index");
742 if (theColumn2 > myNbColumns || theColumn2 < 1) throw DFexception("Invalid cell index");
744 int anIndex1 = (theRow1-1)*myNbColumns + theColumn1;
745 int anIndex2 = (theRow2-1)*myNbColumns + theColumn2;
747 bool hasValue1 = myTable.find(anIndex1) != myTable.end();
748 bool hasValue2 = myTable.find(anIndex2) != myTable.end();
750 if (!hasValue1 && !hasValue2) return; // nothing changed
752 std::string value1 = hasValue1 ? myTable[anIndex1] : 0;
753 std::string value2 = hasValue2 ? myTable[anIndex2] : 0;
755 if (hasValue1 && hasValue2 && value1 == value2) return; // nothing changed
757 if (hasValue1) myTable[anIndex2] = value1;
758 else myTable.erase(anIndex2);
759 if (hasValue2) myTable[anIndex1] = value2;
760 else myTable.erase(anIndex1);
762 SetModifyFlag(); // table is modified
765 void SALOMEDSImpl_AttributeTableOfString::SwapRows(const int theRow1, const int theRow2)
768 for (int i = 1; i <= myNbColumns; i++)
769 SwapCells(theRow1, i, theRow2, i);
771 std::string tmp = myRows[theRow1-1];
772 myRows[theRow1-1] = myRows[theRow2-1];
773 myRows[theRow2-1] = tmp;
774 // no need for SetModifyFlag(), since it is done by SwapCells()
777 void SALOMEDSImpl_AttributeTableOfString::SwapColumns(const int theColumn1, const int theColumn2)
780 for (int i = 1; i <= myNbRows; i++)
781 SwapCells(i, theColumn1, i, theColumn2);
782 // swap column titles
783 std::string tmp = myCols[theColumn1-1];
784 myCols[theColumn1-1] = myCols[theColumn2-1];
785 myCols[theColumn2-1] = tmp;
786 // no need for SetModifyFlag(), since it is done by SwapCells()