Salome HOME
CMake: replacing CMAKE_* variables by PROJECT_* variables
[modules/kernel.git] / src / SALOMEDSImpl / SALOMEDSImpl_AttributeTableOfString.cxx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
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.
10 //
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.
15 //
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
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  File   : SALOMEDSImpl_AttributeTableOfString.cxx
24 //  Author : Sergey Ruin
25 //  Module : SALOME
26 //
27 #include "SALOMEDSImpl_AttributeTableOfString.hxx"
28
29 #include <sstream>
30 #include <algorithm>
31
32 #define SEPARATOR '\1'
33 typedef std::map<int, std::string>::const_iterator MI;
34
35 static std::string getUnit(std::string theString)
36 {
37   std::string aString(theString);
38   int aPos = aString.find(SEPARATOR);
39   if(aPos <= 0 || aPos == aString.size() ) return std::string();
40   return aString.substr(aPos+1, aString.size());
41 }
42
43 static std::string getTitle(std::string theString)
44 {
45   std::string aString(theString);
46   int aPos = aString.find(SEPARATOR);
47   if(aPos < 1) return aString;
48   if(aPos == 0) return std::string();
49   return aString.substr(0, aPos);
50 }
51
52 const std::string& SALOMEDSImpl_AttributeTableOfString::GetID() 
53 {
54   static std::string SALOMEDSImpl_AttributeTableOfStringID ("128371A4-8F52-11d6-A8A3-0001021E8C7F");
55   return SALOMEDSImpl_AttributeTableOfStringID;
56 }
57
58 SALOMEDSImpl_AttributeTableOfString* SALOMEDSImpl_AttributeTableOfString::Set(const DF_Label& label) 
59 {
60   SALOMEDSImpl_AttributeTableOfString* A = NULL;
61   if (!(A=(SALOMEDSImpl_AttributeTableOfString*)label.FindAttribute(SALOMEDSImpl_AttributeTableOfString::GetID()))) {
62     A = new SALOMEDSImpl_AttributeTableOfString();
63     label.AddAttribute(A);
64   }
65   return A;
66 }
67
68 SALOMEDSImpl_AttributeTableOfString::SALOMEDSImpl_AttributeTableOfString() 
69 :SALOMEDSImpl_GenericAttribute("AttributeTableOfString")
70 {
71   myNbRows = 0;
72   myNbColumns = 0;
73 }
74
75 void SALOMEDSImpl_AttributeTableOfString::SetNbColumns(const int theNbColumns)
76 {
77   CheckLocked();  
78   Backup();
79   
80   std::map<int, std::string> aMap;
81   aMap = myTable;
82   myTable.clear();
83
84   for(MI p = aMap.begin(); p!=aMap.end(); p++) {
85     int aRow = (int)(p->first/myNbColumns) + 1;
86     int aCol = (int)(p->first - myNbColumns*(aRow-1));
87     if(aCol == 0) { aCol = myNbColumns; aRow--; }
88     if(aCol > theNbColumns) continue;
89     int aKey = (aRow-1)*theNbColumns+aCol;
90     myTable[aKey] = p->second;
91   }
92
93   myNbColumns = theNbColumns;
94
95   while (myCols.size() < myNbColumns) { // append empty columns titles
96     myCols.push_back(std::string(""));
97   }
98
99   SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved 
100 }
101
102 void SALOMEDSImpl_AttributeTableOfString::SetRowTitle(const int theRow,
103                                                       const std::string& theTitle) 
104 {
105   CheckLocked();  
106   Backup();
107   std::string aTitle(theTitle), aUnit = GetRowUnit(theRow);
108   if(aUnit.size()>0) {
109     aTitle += SEPARATOR;
110     aTitle += aUnit;
111   }
112   myRows[theRow-1] = aTitle;
113   
114   SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved 
115 }
116
117 void SALOMEDSImpl_AttributeTableOfString::SetRowUnit(const int theRow,
118                                                      const std::string& theUnit) 
119 {
120   CheckLocked();  
121   Backup();
122   std::string aTitle = GetRowTitle(theRow);
123   aTitle += SEPARATOR;
124   aTitle += theUnit;
125
126   myRows[theRow-1] = aTitle;
127   
128   SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved 
129 }
130
131 void SALOMEDSImpl_AttributeTableOfString::SetRowUnits(const std::vector<std::string>& theUnits)
132 {
133   if (theUnits.size() != GetNbRows()) throw DFexception("Invalid number of rows");
134   int aLength = theUnits.size(), i;
135   for(i = 1; i <= aLength; i++) SetRowUnit(i, theUnits[i-1]);
136 }
137
138 std::vector<std::string> SALOMEDSImpl_AttributeTableOfString::GetRowUnits()
139 {
140   std::vector<std::string> aSeq;
141   int aLength = myRows.size(), i;
142   for(i=0; i<aLength; i++) aSeq.push_back(getUnit(myRows[i]));
143   return aSeq;
144 }
145
146 void SALOMEDSImpl_AttributeTableOfString::SetRowTitles(const std::vector<std::string>& theTitles)
147 {
148   if (theTitles.size() != GetNbRows()) throw DFexception("Invalid number of rows");
149   int aLength = theTitles.size(), i;
150   for(i = 1; i <= aLength; i++) SetRowTitle(i, theTitles[i-1]);
151   
152   SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved 
153 }
154
155 std::vector<std::string> SALOMEDSImpl_AttributeTableOfString::GetRowTitles()
156 {
157   std::vector<std::string> aSeq;
158   int aLength = myRows.size(), i;
159   for(i=0; i<aLength; i++) aSeq.push_back(getTitle(myRows[i]));
160   return aSeq;
161 }
162
163 std::string SALOMEDSImpl_AttributeTableOfString::GetRowTitle(const int theRow) const 
164 {
165   return getTitle(myRows[theRow-1]);
166 }
167
168 std::string SALOMEDSImpl_AttributeTableOfString::GetRowUnit(const int theRow) const 
169 {
170   return getUnit(myRows[theRow-1]);
171 }
172
173 void SALOMEDSImpl_AttributeTableOfString::SetRowData(const int theRow,
174                                                      const std::vector<std::string>& theData) 
175 {
176   CheckLocked();  
177   if(theData.size() > myNbColumns) SetNbColumns(theData.size());
178
179   Backup();
180
181   while (myRows.size() < theRow) { // append new row titles
182     myRows.push_back(std::string(""));
183   }
184
185   int i, aShift = (theRow-1)*myNbColumns, aLength = theData.size();
186   for(i = 1; i <= aLength; i++) {
187     myTable[aShift + i] = theData[i-1];
188   }
189
190   if(theRow > myNbRows) myNbRows = theRow;
191   
192   SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved 
193 }
194
195 void SALOMEDSImpl_AttributeTableOfString::SetTitle(const std::string& theTitle) 
196 {
197   CheckLocked();  
198   Backup();
199   myTitle = theTitle;
200   
201   SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved 
202 }
203
204 std::string SALOMEDSImpl_AttributeTableOfString::GetTitle() const 
205 {
206   return myTitle;
207 }
208
209 std::vector<std::string> SALOMEDSImpl_AttributeTableOfString::GetRowData(const int theRow)
210 {
211   std::vector<std::string> aSeq;
212   int i, aShift = (theRow-1)*myNbColumns;
213   for(i = 1; i <= myNbColumns; i++) {
214      if(myTable.find(aShift+i) != myTable.end()) 
215        aSeq.push_back(myTable[aShift+i]);
216      else
217        aSeq.push_back("");
218   }
219   
220   return aSeq;
221 }
222
223 void SALOMEDSImpl_AttributeTableOfString::SetColumnData(const int theColumn,
224                                                         const std::vector<std::string>& theData) 
225 {
226   CheckLocked();  
227   if(theColumn > myNbColumns) SetNbColumns(theColumn);
228
229   Backup();
230
231   int i, aLength = theData.size();
232   for(i = 1; i <= aLength; i++) {
233     myTable[myNbColumns*(i-1)+theColumn] = theData[i-1];
234   }
235
236   if(aLength > myNbRows) {
237     myNbRows = aLength;
238     while (myRows.size() < myNbRows) { // append empty row titles
239       myRows.push_back(std::string(""));
240     }
241   }
242   
243   SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved 
244 }
245
246 std::vector<std::string> SALOMEDSImpl_AttributeTableOfString::GetColumnData(const int theColumn)
247 {
248   std::vector<std::string> aSeq;
249   
250   int i, anIndex;
251   for(i = 1; i <= myNbRows; i++) {
252     anIndex = myNbColumns*(i-1) + theColumn;
253     if(myTable.find(anIndex) != myTable.end()) 
254       aSeq.push_back(myTable[anIndex]);
255     else
256       aSeq.push_back("");
257   }
258   
259   return aSeq;
260 }
261
262 void SALOMEDSImpl_AttributeTableOfString::SetColumnTitle(const int theColumn,
263                                                          const std::string& theTitle) 
264 {
265   CheckLocked();  
266   Backup();
267   while(myCols.size() < theColumn) myCols.push_back(std::string(""));
268   myCols[theColumn-1] = theTitle;
269   
270   SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved 
271 }
272
273 std::string SALOMEDSImpl_AttributeTableOfString::GetColumnTitle(const int theColumn) const 
274 {
275   if(myCols.empty()) return "";
276   if(myCols.size() < theColumn) return "";
277   return myCols[theColumn-1];
278 }
279
280 void SALOMEDSImpl_AttributeTableOfString::SetColumnTitles(const std::vector<std::string>& theTitles)
281 {
282   if (theTitles.size() != myNbColumns) throw DFexception("Invalid number of columns");
283   int aLength = theTitles.size(), i;
284   for(i = 0; i < aLength; i++)  myCols[i] =  theTitles[i];
285   
286   SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved 
287 }
288
289 std::vector<std::string> SALOMEDSImpl_AttributeTableOfString::GetColumnTitles()
290 {
291   std::vector<std::string> aSeq;
292   int aLength = myCols.size(), i;
293   for(i=0; i<aLength; i++) aSeq.push_back(myCols[i]);
294   return aSeq;
295 }
296
297 int SALOMEDSImpl_AttributeTableOfString::GetNbRows() const
298 {
299   return myNbRows;
300 }
301
302 int SALOMEDSImpl_AttributeTableOfString::GetNbColumns() const
303 {
304   return myNbColumns;
305 }
306
307 void SALOMEDSImpl_AttributeTableOfString::PutValue(const std::string& theValue,
308                                                    const int theRow,
309                                                    const int theColumn) 
310 {
311   CheckLocked();  
312   //Backup();
313   if(theColumn > myNbColumns) SetNbColumns(theColumn);
314
315   int anIndex = (theRow-1)*myNbColumns + theColumn;
316   myTable[anIndex] = theValue;
317
318   if(theRow > myNbRows) {
319     while (myRows.size() < theRow) { // append empty row titles
320       myRows.push_back(std::string(""));
321     }
322     myNbRows = theRow;
323   }
324   
325   SetModifyFlag(); //SRN: Mark the study as being modified, so it could be saved 
326 }
327
328 bool SALOMEDSImpl_AttributeTableOfString::HasValue(const int theRow,
329                                                    const int theColumn) 
330 {
331   if(theRow > myNbRows || theRow < 1) return false;
332   if(theColumn > myNbColumns || theColumn < 1) return false;
333
334   int anIndex = (theRow-1)*myNbColumns + theColumn;
335   return (myTable.find(anIndex) !=  myTable.end()); 
336 }
337
338 std::string SALOMEDSImpl_AttributeTableOfString::GetValue(const int theRow,
339                                                           const int theColumn) 
340 {
341   if(theRow > myNbRows || theRow < 1) throw DFexception("Invalid cell index");
342   if(theColumn > myNbColumns || theColumn < 1) throw DFexception("Invalid cell index");
343
344   int anIndex = (theRow-1)*myNbColumns + theColumn;
345   if(myTable.find(anIndex) != myTable.end()) return myTable[anIndex];
346   
347   throw DFexception("Invalid cell index");
348   return "";
349 }
350
351 void SALOMEDSImpl_AttributeTableOfString::RemoveValue(const int theRow, const int theColumn)
352 {
353   CheckLocked();  
354   if(theRow > myNbRows || theRow < 1) throw DFexception("Invalid cell index");
355   if(theColumn > myNbColumns || theColumn < 1) throw DFexception("Invalid cell index");
356
357   int anIndex = (theRow-1)*myNbColumns + theColumn;
358   if (myTable.find(anIndex) != myTable.end()) {
359     //Backup();
360     myTable.erase(anIndex);
361     SetModifyFlag(); // table is modified
362   }
363 }
364
365 const std::string& SALOMEDSImpl_AttributeTableOfString::ID() const
366 {
367   return GetID();
368 }
369
370 void SALOMEDSImpl_AttributeTableOfString::Restore(DF_Attribute* with) 
371 {
372   int anIndex;
373   SALOMEDSImpl_AttributeTableOfString* aTable = dynamic_cast<SALOMEDSImpl_AttributeTableOfString*>(with);
374
375   myTable.clear();
376   myCols.clear();
377   myRows.clear();
378
379   myTable = aTable->myTable;
380   myNbRows = aTable->myNbRows;
381   myNbColumns = aTable->myNbColumns;
382   myTitle = aTable->myTitle;
383   
384   for(anIndex = 1; anIndex <= aTable->GetNbRows();anIndex++)
385     myRows.push_back(aTable->GetRowTitle(anIndex));
386
387   for(anIndex = 1; anIndex <= aTable->GetNbColumns(); anIndex++) 
388     myCols.push_back(aTable->GetColumnTitle(anIndex));
389 }
390
391 DF_Attribute* SALOMEDSImpl_AttributeTableOfString::NewEmpty() const
392 {
393   return new SALOMEDSImpl_AttributeTableOfString();
394 }
395
396 void SALOMEDSImpl_AttributeTableOfString::Paste(DF_Attribute* into)
397 {
398   int anIndex;
399   SALOMEDSImpl_AttributeTableOfString* aTable = dynamic_cast<SALOMEDSImpl_AttributeTableOfString*>(into);
400
401   aTable->myTable.clear();
402   aTable->myCols.clear();
403   aTable->myRows.clear();
404
405   aTable->myTable = myTable;
406   aTable->myTitle = myTitle;
407   aTable->myNbRows = myNbRows;
408   aTable->myNbColumns = myNbColumns;
409
410   for(anIndex = 1; anIndex <= GetNbRows();anIndex++)
411     aTable->myRows.push_back(GetRowTitle(anIndex));
412   for(anIndex = 1; anIndex <= GetNbColumns(); anIndex++) 
413     aTable->myCols.push_back(GetColumnTitle(anIndex));
414 }
415
416 std::vector<int> SALOMEDSImpl_AttributeTableOfString::GetSetRowIndices(const int theRow)
417 {
418   std::vector<int> aSeq;
419
420   int i, aShift = myNbColumns*(theRow-1);
421   for(i = 1; i <= myNbColumns; i++) {
422     if(myTable.find(aShift + i) != myTable.end()) aSeq.push_back(i);
423   }
424   
425   return aSeq;
426 }
427
428 std::vector<int> SALOMEDSImpl_AttributeTableOfString::GetSetColumnIndices(const int theColumn)
429 {
430   std::vector<int> aSeq;
431
432   int i, anIndex;
433   for(i = 1; i <= myNbRows; i++) {
434     anIndex = myNbColumns*(i-1)+theColumn;
435     if(myTable.find(anIndex) != myTable.end()) aSeq.push_back(i);
436   }
437   
438   return aSeq;
439 }
440
441 std::string SALOMEDSImpl_AttributeTableOfString::Save() 
442 {
443   std::string aString;
444   char* buffer = new char[1024];
445   int i, j, l;
446
447   //Title
448   l = myTitle.size();
449   sprintf(buffer, "%d\n", l);
450   aString+=buffer;
451   for(i=0; i<l; i++) {
452     aString += myTitle[i];
453     aString +='\n';
454   }
455   
456   //Nb rows
457   sprintf(buffer, "%d\n", myNbRows);
458   aString+=buffer;
459
460   //Row titles
461   for(i=0; i<myNbRows; i++) {
462     l = myRows[i].size();
463     sprintf(buffer, "%d\n", l);
464     aString+=buffer;
465     for(j=0; j<l; j++) {
466       aString += myRows[i][j];
467       aString += '\n';
468     }
469   }  
470
471   //Nb columns
472   sprintf(buffer, "%d\n", myNbColumns);
473   aString+=buffer;
474
475   //Columns titles
476   for(i=0; i<myNbColumns; i++) {
477     l = myCols[i].size();
478     sprintf(buffer, "%d\n", l);
479     aString+=buffer;
480     for(j=0; j<l; j++) {
481       aString += myCols[i][j];
482       aString += '\n';
483     }
484   }
485
486   //Store the table values
487   l = myTable.size();
488   sprintf(buffer, "%d\n", l);
489   aString+=buffer;
490   for(MI p = myTable.begin(); p!=myTable.end(); p++) {
491     if (p->second.size()) { // check empty string in the value table
492       sprintf(buffer, "%d\n", p->first);
493       aString += buffer;
494       unsigned long aValueSize = p->second.size();
495       sprintf(buffer, "%ld\n", aValueSize);
496       aString +=buffer;
497       aString += p->second;
498       aString += '\n';
499     } else { // write index only of kind: "0key"; "05", for an example
500       sprintf(buffer, "0%d\n", p->first);
501       aString+=buffer;
502     }
503   }
504
505   delete []buffer;
506   return aString;
507 }
508
509 void SALOMEDSImpl_AttributeTableOfString::Load(const std::string& value) 
510 {
511   std::vector<std::string> v;
512   int i,  j, l, pos, aSize = (int)value.size(); 
513   for(i = 0, pos = 0; i<aSize; i++) {
514     if(value[i] == '\n') {
515        v.push_back(value.substr(pos, i-pos));
516        pos = i+1;
517     }
518   }
519
520   Backup();
521
522   pos = 0;
523   std::string aStr;
524
525   //Title
526   l = strtol(v[pos++].c_str(), NULL, 10);
527
528   myTitle = std::string(l, 0);
529   for(i=0; i<l; i++) {
530     myTitle[i] = v[pos++][0];
531   }
532
533   //Nb rows
534   myNbRows = strtol(v[pos++].c_str(), NULL, 10);
535
536   //Rows titles
537   myRows.clear();  
538   for(i=1; i<=myNbRows; i++) { 
539     l = strtol(v[pos++].c_str(), NULL, 10);
540     aStr = std::string(l,0);
541     for(j=0; j<l; j++) {
542       aStr[j] = v[pos++][0];
543     }
544     myRows.push_back(aStr);
545   }
546
547   //Nb columns
548   myNbColumns = strtol(v[pos++].c_str(), NULL, 10);
549
550   //Columns titles
551   myCols.clear();
552   for(i=1; i<=myNbColumns; i++) {
553     l = strtol(v[pos++].c_str(), NULL, 10);
554     aStr = std::string(l,0);
555     for(j=0; j<l; j++) {
556       aStr[j] = v[pos++][0];
557     }
558     myCols.push_back(aStr);
559   }
560
561   //Restore the table values
562   l = strtol(v[pos++].c_str(), NULL, 10);
563   myTable.clear();
564   for(i=1; i<=l; i++) {
565     aStr = v[pos++]; //Ket as a string 
566     int aKey = strtol(aStr.c_str(), NULL, 10);
567     std::string aValue;
568     if(aStr[0] == '0') //If the first character of the key is 0, then empty value
569       aValue = "";
570     else {
571       strtol(v[pos++].c_str(), NULL, 10);
572       aValue = v[pos++];
573     }
574     myTable[aKey] = aValue;
575   }
576 }
577
578 std::vector<int> SALOMEDSImpl_AttributeTableOfString::SortRow(const int theRow, SortOrder sortOrder, SortPolicy sortPolicy )
579 {
580   CheckLocked();  
581   std::vector<int> result;
582   if ( theRow > 0 && theRow <= myNbRows ) {
583     std::vector<int> indices( myNbColumns );
584     int cnt = 0;
585     for ( int i = 0; i < myNbColumns; i++ ) {
586       if ( sortPolicy != EmptyIgnore || HasValue(theRow, i+1) ) {
587         indices[cnt++] = i+1;
588       }
589     }
590     indices.resize(cnt);
591     
592     TableSorter<SALOMEDSImpl_AttributeTableOfString> sorter( this, sortOrder, sortPolicy, theRow, true );
593     std::stable_sort( indices.begin(), indices.end(), sorter );
594     
595     if ( sortPolicy == EmptyIgnore ) {
596       std::vector<int> other( myNbColumns );
597       cnt = 0;
598       for( int i = 0; i < myNbColumns; i++ )
599         other[i] = HasValue(theRow, i+1) ? indices[cnt++] : i+1;
600       indices = other;
601     }
602     result = indices;
603
604     for ( int col = 0; col < indices.size(); col++ ) {
605       int idx = indices[col];
606       if ( col+1 == idx ) continue;
607       SwapCells(theRow, col+1, theRow, idx);
608       int idx1 = 0;
609       for ( int i = col+1; i < indices.size() && idx1 == 0; i++)
610         if ( indices[i] == col+1 ) idx1 = i;
611       indices[idx1] = idx;
612     }
613     // no need for SetModifyFlag(), since it is done by SwapCells()
614   }
615   return result;
616 }
617
618 std::vector<int> SALOMEDSImpl_AttributeTableOfString::SortColumn(const int theColumn, SortOrder sortOrder, SortPolicy sortPolicy )
619 {
620   CheckLocked();  
621   std::vector<int> result;
622   if ( theColumn > 0 && theColumn <= myNbColumns ) {
623     std::vector<int> indices( myNbRows );
624     int cnt = 0;
625     for ( int i = 0; i < myNbRows; i++ ) {
626       if ( sortPolicy != EmptyIgnore || HasValue(i+1, theColumn) ) {
627         indices[cnt++] = i+1;
628       }
629     }
630     indices.resize(cnt);
631     
632     TableSorter<SALOMEDSImpl_AttributeTableOfString> sorter( this, sortOrder, sortPolicy, theColumn, false );
633     std::stable_sort( indices.begin(), indices.end(), sorter );
634     
635     if ( sortPolicy == EmptyIgnore ) {
636       std::vector<int> other( myNbRows );
637       cnt = 0;
638       for( int i = 0; i < myNbRows; i++ )
639         other[i] = HasValue(i+1, theColumn) ? indices[cnt++] : i+1;
640       indices = other;
641     }
642     result = indices;
643
644     for ( int row = 0; row < indices.size(); row++ ) {
645       int idx = indices[row];
646       if ( row+1 == idx ) continue;
647       SwapCells(row+1, theColumn, idx, theColumn);
648       int idx1 = 0;
649       for ( int i = row+1; i < indices.size() && idx1 == 0; i++)
650         if ( indices[i] == row+1 ) idx1 = i;
651       indices[idx1] = idx;
652     }
653     // no need for SetModifyFlag(), since it is done by SwapCells()
654   }
655   return result;
656 }
657
658 std::vector<int> SALOMEDSImpl_AttributeTableOfString::SortByRow(const int theRow, SortOrder sortOrder, SortPolicy sortPolicy )
659 {
660   CheckLocked();  
661   std::vector<int> result;
662   if ( theRow > 0 && theRow <= myNbRows ) {
663     std::vector<int> indices( myNbColumns );
664     int cnt = 0;
665     for ( int i = 0; i < myNbColumns; i++ ) {
666       if ( sortPolicy != EmptyIgnore || HasValue(theRow, i+1) ) {
667         indices[cnt++] = i+1;
668       }
669     }
670     indices.resize(cnt);
671     
672     TableSorter<SALOMEDSImpl_AttributeTableOfString> sorter( this, sortOrder, sortPolicy, theRow, true );
673     std::stable_sort( indices.begin(), indices.end(), sorter );
674     
675     if ( sortPolicy == EmptyIgnore ) {
676       std::vector<int> other( myNbColumns );
677       cnt = 0;
678       for( int i = 0; i < myNbColumns; i++ )
679         other[i] = HasValue(theRow, i+1) ? indices[cnt++] : i+1;
680       indices = other;
681     }
682     result = indices;
683
684     for ( int col = 0; col < indices.size(); col++ ) {
685       int idx = indices[col];
686       if ( col+1 == idx ) continue;
687       SwapColumns(col+1, idx);
688       int idx1 = 0;
689       for ( int i = col+1; i < indices.size() && idx1 == 0; i++)
690         if ( indices[i] == col+1 ) idx1 = i;
691       indices[idx1] = idx;
692     }
693     // no need for SetModifyFlag(), since it is done by SwapColumns()
694   }
695   return result;
696 }
697
698 std::vector<int> SALOMEDSImpl_AttributeTableOfString::SortByColumn(const int theColumn, SortOrder sortOrder, SortPolicy sortPolicy )
699 {
700   CheckLocked();  
701   std::vector<int> result;
702   if ( theColumn > 0 && theColumn <= myNbColumns ) {
703     std::vector<int> indices( myNbRows );
704     int cnt = 0;
705     for ( int i = 0; i < myNbRows; i++ ) {
706       if ( sortPolicy != EmptyIgnore || HasValue(i+1, theColumn) ) {
707         indices[cnt++] = i+1;
708       }
709     }
710     indices.resize(cnt);
711     
712     TableSorter<SALOMEDSImpl_AttributeTableOfString> sorter( this, sortOrder, sortPolicy, theColumn, false );
713     std::stable_sort( indices.begin(), indices.end(), sorter );
714     
715     if ( sortPolicy == EmptyIgnore ) {
716       std::vector<int> other( myNbRows );
717       cnt = 0;
718       for( int i = 0; i < myNbRows; i++ )
719         other[i] = HasValue(i+1, theColumn) ? indices[cnt++] : i+1;
720       indices = other;
721     }
722     result = indices;
723
724     for ( int row = 0; row < indices.size(); row++ ) {
725       int idx = indices[row];
726       if ( row+1 == idx ) continue;
727       SwapRows(row+1, idx);
728       int idx1 = 0;
729       for ( int i = row+1; i < indices.size() && idx1 == 0; i++)
730         if ( indices[i] == row+1 ) idx1 = i;
731       indices[idx1] = idx;
732     }
733     // no need for SetModifyFlag(), since it is done by SwapRows()
734   }
735   return result;
736 }
737
738 void SALOMEDSImpl_AttributeTableOfString::SwapCells(const int theRow1, const int theColumn1, 
739                                                     const int theRow2, const int theColumn2)
740 {
741   CheckLocked();  
742   if (theRow1    > myNbRows    || theRow1 < 1)    throw DFexception("Invalid cell index");
743   if (theRow2    > myNbRows    || theRow2 < 1)    throw DFexception("Invalid cell index");
744   if (theColumn1 > myNbColumns || theColumn1 < 1) throw DFexception("Invalid cell index");
745   if (theColumn2 > myNbColumns || theColumn2 < 1) throw DFexception("Invalid cell index");
746
747   int anIndex1 = (theRow1-1)*myNbColumns + theColumn1;
748   int anIndex2 = (theRow2-1)*myNbColumns + theColumn2;
749
750   bool hasValue1 = myTable.find(anIndex1) != myTable.end();
751   bool hasValue2 = myTable.find(anIndex2) != myTable.end();
752
753   if (!hasValue1 && !hasValue2) return;                   // nothing changed
754
755   std::string value1 = hasValue1 ? myTable[anIndex1] : 0;
756   std::string value2 = hasValue2 ? myTable[anIndex2] : 0;
757
758   if (hasValue1 && hasValue2 && value1 == value2) return; // nothing changed
759
760   if (hasValue1) myTable[anIndex2] = value1;
761   else           myTable.erase(anIndex2);
762   if (hasValue2) myTable[anIndex1] = value2;
763   else           myTable.erase(anIndex1);
764
765   SetModifyFlag(); // table is modified
766 }
767
768 void SALOMEDSImpl_AttributeTableOfString::SwapRows(const int theRow1, const int theRow2)
769 {
770   CheckLocked();  
771   for (int i = 1; i <= myNbColumns; i++)
772     SwapCells(theRow1, i, theRow2, i);
773   // swap row titles
774   std::string tmp = myRows[theRow1-1];
775   myRows[theRow1-1] = myRows[theRow2-1];
776   myRows[theRow2-1] = tmp;
777   // no need for SetModifyFlag(), since it is done by SwapCells()
778 }
779
780 void SALOMEDSImpl_AttributeTableOfString::SwapColumns(const int theColumn1, const int theColumn2)
781 {
782   CheckLocked();  
783   for (int i = 1; i <= myNbRows; i++)
784     SwapCells(i, theColumn1, i, theColumn2);
785   // swap column titles
786   std::string tmp = myCols[theColumn1-1];
787   myCols[theColumn1-1] = myCols[theColumn2-1];
788   myCols[theColumn2-1] = tmp;
789   // no need for SetModifyFlag(), since it is done by SwapCells()
790 }