libtdepim

kimportdialog.cpp
1 /*
2  This file is part of libtdepim.
3 
4  Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>
5  Copyright (c) 2002 Tobias Koenig <tokoe@kde.org>
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Library General Public
9  License as published by the Free Software Foundation; either
10  version 2 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Library General Public License for more details.
16 
17  You should have received a copy of the GNU Library General Public License
18  along with this library; see the file COPYING.LIB. If not, write to
19  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  Boston, MA 02110-1301, USA.
21 */
22 
23 // Generic CSV import. Please do not add application specific code to this
24 // class. Application specific code should go to a subclass provided by the
25 // application using this dialog.
26 
27 #include <tqbuttongroup.h>
28 #include <tqfile.h>
29 #include <tqlabel.h>
30 #include <tqlayout.h>
31 #include <tqlineedit.h>
32 #include <tqlistview.h>
33 #include <tqradiobutton.h>
34 #include <tqregexp.h>
35 #include <tqtable.h>
36 #include <tqtextstream.h>
37 #include <tqvbox.h>
38 
39 #include <tdeapplication.h>
40 #include <kdebug.h>
41 #include <kcombobox.h>
42 #include <kinputdialog.h>
43 #include <klineedit.h>
44 #include <tdelocale.h>
45 #include <kprogress.h>
46 #include <ksimpleconfig.h>
47 #include <kstandarddirs.h>
48 #include <kurlrequester.h>
49 #include <tdefiledialog.h>
50 
51 #include "kimportdialog.h"
52 #include "kimportdialog.moc"
53 
54 KImportColumn::KImportColumn(KImportDialog *dlg,const TQString &header, int count)
55  : m_maxCount(count),
56  m_refCount(0),
57  m_header(header),
58  mDialog(dlg)
59 {
60  mFormats.append(FormatPlain);
61  mFormats.append(FormatUnquoted);
62 // mFormats.append(FormatBracketed);
63 
64  mDefaultFormat = FormatUnquoted;
65 
66  mDialog->addColumn(this);
67 }
68 
69 TQValueList<int> KImportColumn::formats()
70 {
71  return mFormats;
72 }
73 
74 TQString KImportColumn::formatName(int format)
75 {
76  switch (format) {
77  case FormatPlain:
78  return i18n("Plain");
79  case FormatUnquoted:
80  return i18n("Unquoted");
81  case FormatBracketed:
82  return i18n("Bracketed");
83  default:
84  return i18n("Undefined");
85  }
86 }
87 
88 int KImportColumn::defaultFormat()
89 {
90  return mDefaultFormat;
91 }
92 
93 TQString KImportColumn::preview(const TQString &value, int format)
94 {
95  if (format == FormatBracketed) {
96  return "(" + value + ")";
97  } else if (format == FormatUnquoted) {
98  if (value.left(1) == "\"" && value.right(1) == "\"") {
99  return value.mid(1,value.length()-2);
100  } else {
101  return value;
102  }
103  } else {
104  return value;
105  }
106 }
107 
108 void KImportColumn::addColId(int id)
109 {
110  mColIds.append(id);
111 }
112 
113 void KImportColumn::removeColId(int id)
114 {
115  mColIds.remove(id);
116 }
117 
118 TQValueList<int> KImportColumn::colIdList()
119 {
120  return mColIds;
121 }
122 
123 TQString KImportColumn::convert()
124 {
125  TQValueList<int>::ConstIterator it = mColIds.begin();
126  if (it == mColIds.end()) return "";
127  else return mDialog->cell(*it);
128 }
129 
130 
131 class ColumnItem : public TQListViewItem {
132  public:
133  ColumnItem(KImportColumn *col,TQListView *parent) : TQListViewItem(parent), mColumn(col)
134  {
135  setText(0,mColumn->header());
136  }
137 
138  KImportColumn *column() { return mColumn; }
139 
140  private:
141  KImportColumn *mColumn;
142 };
143 
151 KImportDialog::KImportDialog(TQWidget* parent)
152  : KDialogBase(parent,"importdialog",true,i18n("Import Text File"),Ok|Cancel),
153  mSeparator(","),
154  mCurrentRow(0)
155 {
156  mData.setAutoDelete( true );
157 
158  TQVBox *topBox = new TQVBox(this);
159  setMainWidget(topBox);
160  topBox->setSpacing(spacingHint());
161 
162  TQHBox *fileBox = new TQHBox(topBox);
163  fileBox->setSpacing(spacingHint());
164  new TQLabel(i18n("File to import:"),fileBox);
165  KURLRequester *urlRequester = new KURLRequester(fileBox);
166  urlRequester->setFilter( "*.csv" );
167  connect(urlRequester,TQ_SIGNAL(returnPressed(const TQString &)),
168  TQ_SLOT(setFile(const TQString &)));
169  connect(urlRequester,TQ_SIGNAL(urlSelected(const TQString &)),
170  TQ_SLOT(setFile(const TQString &)));
171  connect(urlRequester->lineEdit(),TQ_SIGNAL(textChanged ( const TQString & )),
172  TQ_SLOT(slotUrlChanged(const TQString & )));
173  mTable = new TQTable(5,5,topBox);
174  mTable->setMinimumHeight( 150 );
175  connect(mTable,TQ_SIGNAL(selectionChanged()),TQ_SLOT(tableSelected()));
176 
177  TQHBox *separatorBox = new TQHBox( topBox );
178  separatorBox->setSpacing( spacingHint() );
179 
180  new TQLabel( i18n( "Separator:" ), separatorBox );
181 
182  mSeparatorCombo = new KComboBox( separatorBox );
183  mSeparatorCombo->insertItem( "," );
184  mSeparatorCombo->insertItem( i18n( "Tab" ) );
185  mSeparatorCombo->insertItem( i18n( "Space" ) );
186  mSeparatorCombo->insertItem( "=" );
187  mSeparatorCombo->insertItem( ";" );
188  connect(mSeparatorCombo, TQ_SIGNAL( activated(int) ),
189  this, TQ_SLOT( separatorClicked(int) ) );
190  mSeparatorCombo->setCurrentItem( 0 );
191 
192  TQHBox *rowsBox = new TQHBox( topBox );
193  rowsBox->setSpacing( spacingHint() );
194 
195  new TQLabel( i18n( "Import starts at row:" ), rowsBox );
196  mStartRow = new TQSpinBox( rowsBox );
197  mStartRow->setMinValue( 1 );
198 /*
199  new TQLabel( i18n( "And ends at row:" ), rowsBox );
200  mEndRow = new TQSpinBox( rowsBox );
201  mEndRow->setMinValue( 1 );
202 */
203  TQVBox *assignBox = new TQVBox(topBox);
204  assignBox->setSpacing(spacingHint());
205 
206  TQHBox *listsBox = new TQHBox(assignBox);
207  listsBox->setSpacing(spacingHint());
208 
209  mHeaderList = new TQListView(listsBox);
210  mHeaderList->addColumn(i18n("Header"));
211  connect(mHeaderList, TQ_SIGNAL(selectionChanged(TQListViewItem*)),
212  this, TQ_SLOT(headerSelected(TQListViewItem*)));
213  connect(mHeaderList,TQ_SIGNAL(doubleClicked(TQListViewItem*)),
214  TQ_SLOT(assignColumn(TQListViewItem *)));
215 
216  mFormatCombo = new KComboBox( listsBox );
217  mFormatCombo->setDuplicatesEnabled( false );
218 
219  TQPushButton *assignButton = new TQPushButton(i18n("Assign to Selected Column"),
220  assignBox);
221  connect(assignButton,TQ_SIGNAL(clicked()),TQ_SLOT(assignColumn()));
222 
223  TQPushButton *removeButton = new TQPushButton(i18n("Remove Assignment From Selected Column"),
224  assignBox);
225  connect(removeButton,TQ_SIGNAL(clicked()),TQ_SLOT(removeColumn()));
226 
227  TQPushButton *assignTemplateButton = new TQPushButton(i18n("Assign with Template..."),
228  assignBox);
229  connect(assignTemplateButton,TQ_SIGNAL(clicked()),TQ_SLOT(assignTemplate()));
230 
231  TQPushButton *saveTemplateButton = new TQPushButton(i18n("Save Current Template"),
232  assignBox);
233  connect(saveTemplateButton,TQ_SIGNAL(clicked()),TQ_SLOT(saveTemplate()));
234 
235  resize(500,300);
236 
237  connect(this,TQ_SIGNAL(okClicked()),TQ_SLOT(applyConverter()));
238  connect(this,TQ_SIGNAL(applyClicked()),TQ_SLOT(applyConverter()));
239  enableButtonOK(!urlRequester->lineEdit()->text().isEmpty());
240 }
241 
242 void KImportDialog::slotUrlChanged(const TQString & text)
243 {
244  enableButtonOK(!text.isEmpty());
245 }
246 
247 bool KImportDialog::setFile(const TQString& file)
248 {
249  enableButtonOK(!file.isEmpty());
250  kdDebug(5300) << "KImportDialog::setFile(): " << file << endl;
251 
252  TQFile f(file);
253 
254  if (f.open(IO_ReadOnly)) {
255  mFile = "";
256  TQTextStream t(&f);
257  mFile = t.read();
258 // while (!t.eof()) mFile.append(t.readLine());
259  f.close();
260 
261  readFile();
262 
263 // mEndRow->setValue( mData.count() );
264 
265  return true;
266  } else {
267  kdDebug(5300) << " Open failed" << endl;
268  return false;
269  }
270 }
271 
272 void KImportDialog::registerColumns()
273 {
274  TQPtrListIterator<KImportColumn> colIt(mColumns);
275  for (; colIt.current(); ++colIt) {
276  new ColumnItem(*colIt,mHeaderList);
277  }
278  mHeaderList->setSelected(mHeaderList->firstChild(),true);
279 }
280 
281 void KImportDialog::fillTable()
282 {
283 // kdDebug(5300) << "KImportDialog::fillTable()" << endl;
284 
285  int row, column;
286 
287  for (row = 0; row < mTable->numRows(); ++row)
288  for (column = 0; column < mTable->numCols(); ++column)
289  mTable->clearCell(row, column);
290 
291  for ( row = 0; row < int(mData.count()); ++row ) {
292  TQValueVector<TQString> *rowVector = mData[ row ];
293  for( column = 0; column < int(rowVector->size()); ++column ) {
294  setCellText( row, column, rowVector->at( column ) );
295  }
296  }
297 }
298 
299 void KImportDialog::readFile( int rows )
300 {
301  kdDebug(5300) << "KImportDialog::readFile(): " << rows << endl;
302 
303  mData.clear();
304 
305  int row, column;
306  enum { S_START, S_QUOTED_FIELD, S_MAYBE_END_OF_QUOTED_FIELD, S_END_OF_QUOTED_FIELD,
307  S_MAYBE_NORMAL_FIELD, S_NORMAL_FIELD } state = S_START;
308 
309  TQChar m_textquote = '"';
310  int m_startline = 0;
311 
312  TQChar x;
313  TQString field = "";
314 
315  row = column = 0;
316  TQTextStream inputStream(mFile, IO_ReadOnly);
317  inputStream.setEncoding(TQTextStream::Locale);
318 
319  KProgressDialog pDialog(this, 0, i18n("Loading Progress"),
320  i18n("Please wait while the file is loaded."), true);
321  pDialog.setAllowCancel(true);
322  pDialog.showCancelButton(true);
323  pDialog.setAutoClose(true);
324 
325  KProgress *progress = pDialog.progressBar();
326  progress->setTotalSteps( mFile.contains(mSeparator, false) );
327  progress->setValue(0);
328  int progressValue = 0;
329 
330  if (progress->totalSteps() > 0) // We have data
331  pDialog.show();
332 
333  while (!inputStream.atEnd() && !pDialog.wasCancelled()) {
334  inputStream >> x; // read one char
335 
336  // update the dialog if needed
337  if (x == mSeparator)
338  {
339  progress->setValue(progressValue++);
340  if (progressValue % 15 == 0) // try not to constantly repaint
341  kapp->processEvents();
342  }
343 
344  if (x == '\r') inputStream >> x; // eat '\r', to handle DOS/LOSEDOWS files correctly
345 
346  switch (state) {
347  case S_START :
348  if (x == m_textquote) {
349  field += x;
350  state = S_QUOTED_FIELD;
351  } else if (x == mSeparator) {
352  ++column;
353  } else if (x == '\n') {
354  ++row;
355  column = 0;
356  } else {
357  field += x;
358  state = S_MAYBE_NORMAL_FIELD;
359  }
360  break;
361  case S_QUOTED_FIELD :
362  if (x == m_textquote) {
363  field += x;
364  state = S_MAYBE_END_OF_QUOTED_FIELD;
365  } else if (x == '\n') {
366  setData(row - m_startline, column, field);
367  field = "";
368  if (x == '\n') {
369  ++row;
370  column = 0;
371  } else {
372  ++column;
373  }
374  state = S_START;
375  } else {
376  field += x;
377  }
378  break;
379  case S_MAYBE_END_OF_QUOTED_FIELD :
380  if (x == m_textquote) {
381  field += x;
382  state = S_QUOTED_FIELD;
383  } else if (x == mSeparator || x == '\n') {
384  setData(row - m_startline, column, field);
385  field = "";
386  if (x == '\n') {
387  ++row;
388  column = 0;
389  } else {
390  ++column;
391  }
392  state = S_START;
393  } else {
394  state = S_END_OF_QUOTED_FIELD;
395  }
396  break;
397  case S_END_OF_QUOTED_FIELD :
398  if (x == mSeparator || x == '\n') {
399  setData(row - m_startline, column, field);
400  field = "";
401  if (x == '\n') {
402  ++row;
403  column = 0;
404  } else {
405  ++column;
406  }
407  state = S_START;
408  } else {
409  state = S_END_OF_QUOTED_FIELD;
410  }
411  break;
412  case S_MAYBE_NORMAL_FIELD :
413  if (x == m_textquote) {
414  field = "";
415  state = S_QUOTED_FIELD;
416  }
417  case S_NORMAL_FIELD :
418  if (x == mSeparator || x == '\n') {
419  setData(row - m_startline, column, field);
420  field = "";
421  if (x == '\n') {
422  ++row;
423  column = 0;
424  } else {
425  ++column;
426  }
427  state = S_START;
428  } else {
429  field += x;
430  }
431  }
432 
433  if ( rows > 0 && row > rows ) break;
434  }
435 
436  fillTable();
437 }
438 
439 void KImportDialog::setCellText(int row, int col, const TQString& text)
440 {
441  if (row < 0) return;
442 
443  if ((mTable->numRows() - 1) < row) mTable->setNumRows(row + 1);
444  if ((mTable->numCols() - 1) < col) mTable->setNumCols(col + 1);
445 
446  KImportColumn *c = mColumnDict.find(col);
447  TQString formattedText;
448  if (c) formattedText = c->preview(text,findFormat(col));
449  else formattedText = text;
450  mTable->setText(row, col, formattedText);
451 }
452 
453 void KImportDialog::formatSelected(TQListViewItem*)
454 {
455 // kdDebug(5300) << "KImportDialog::formatSelected()" << endl;
456 }
457 
458 void KImportDialog::headerSelected(TQListViewItem* item)
459 {
460  KImportColumn *col = ((ColumnItem *)item)->column();
461 
462  if (!col) return;
463 
464  mFormatCombo->clear();
465 
466  TQValueList<int> formats = col->formats();
467 
468  TQValueList<int>::ConstIterator it = formats.begin();
469  TQValueList<int>::ConstIterator end = formats.end();
470  while(it != end) {
471  mFormatCombo->insertItem( col->formatName(*it), *it - 1 );
472  ++it;
473  }
474 
475  TQTableSelection selection = mTable->selection(mTable->currentSelection());
476 
477  updateFormatSelection(selection.leftCol());
478 }
479 
480 void KImportDialog::updateFormatSelection(int column)
481 {
482  int format = findFormat(column);
483 
484  if ( format == KImportColumn::FormatUndefined )
485  mFormatCombo->setCurrentItem( 0 );
486  else
487  mFormatCombo->setCurrentItem( format - 1 );
488 }
489 
490 void KImportDialog::tableSelected()
491 {
492  TQTableSelection selection = mTable->selection(mTable->currentSelection());
493 
494  TQListViewItem *item = mHeaderList->firstChild();
495  KImportColumn *col = mColumnDict.find(selection.leftCol());
496  if (col) {
497  while(item) {
498  if (item->text(0) == col->header()) {
499  break;
500  }
501  item = item->nextSibling();
502  }
503  }
504  if (item) {
505  mHeaderList->setSelected(item,true);
506  }
507 
508  updateFormatSelection(selection.leftCol());
509 }
510 
511 void KImportDialog::separatorClicked(int id)
512 {
513  switch(id) {
514  case 0:
515  mSeparator = ',';
516  break;
517  case 1:
518  mSeparator = '\t';
519  break;
520  case 2:
521  mSeparator = ' ';
522  break;
523  case 3:
524  mSeparator = '=';
525  break;
526  case 4:
527  mSeparator = ';';
528  break;
529  default:
530  mSeparator = ',';
531  break;
532  }
533 
534  readFile();
535 }
536 
537 void KImportDialog::assignColumn(TQListViewItem *item)
538 {
539  if (!item) return;
540 
541 // kdDebug(5300) << "KImportDialog::assignColumn(): current Col: " << mTable->currentColumn()
542 // << endl;
543 
544  ColumnItem *colItem = (ColumnItem *)item;
545 
546  TQTableSelection selection = mTable->selection(mTable->currentSelection());
547 
548 // kdDebug(5300) << " l: " << selection.leftCol() << " r: " << selection.rightCol() << endl;
549 
550  for(int i=selection.leftCol();i<=selection.rightCol();++i) {
551  if (i >= 0) {
552  mTable->horizontalHeader()->setLabel(i,colItem->text(0));
553  mColumnDict.replace(i,colItem->column());
554  int format = mFormatCombo->currentItem() + 1;
555  mFormats.replace(i,format);
556  colItem->column()->addColId(i);
557  }
558  }
559 
560  readFile();
561 }
562 
563 void KImportDialog::assignColumn()
564 {
565  assignColumn(mHeaderList->currentItem());
566 }
567 
568 void KImportDialog::assignTemplate()
569 {
570  TQMap<uint,int> columnMap;
571  TQMap<TQString, TQString> fileMap;
572  TQStringList templates;
573 
574  // load all template files
575  TQStringList list = TDEGlobal::dirs()->findAllResources( "data" , TQString( kapp->name() ) +
576  "/csv-templates/*.desktop", true, true );
577 
578  for ( TQStringList::iterator it = list.begin(); it != list.end(); ++it )
579  {
580  KSimpleConfig config( *it, true );
581 
582  if ( !config.hasGroup( "csv column map" ) )
583  continue;
584 
585  config.setGroup( "Misc" );
586  templates.append( config.readEntry( "Name" ) );
587  fileMap.insert( config.readEntry( "Name" ), *it );
588  }
589 
590  // let the user chose, what to take
591  bool ok = false;
592  TQString tmp;
593  tmp = KInputDialog::getItem( i18n( "Template Selection" ),
594  i18n( "Please select a template, that matches the CSV file:" ),
595  templates, 0, false, &ok, this );
596 
597  if ( !ok )
598  return;
599 
600  KSimpleConfig config( fileMap[ tmp ], true );
601  config.setGroup( "General" );
602  uint numColumns = config.readUnsignedNumEntry( "Columns" );
603  int format = config.readNumEntry( "Format" );
604 
605  // create the column map
606  config.setGroup( "csv column map" );
607  for ( uint i = 0; i < numColumns; ++i ) {
608  int col = config.readNumEntry( TQString::number( i ) );
609  columnMap.insert( i, col );
610  }
611 
612  // apply the column map
613  for ( uint i = 0; i < columnMap.count(); ++i ) {
614  int tableColumn = columnMap[i];
615  if ( tableColumn == -1 )
616  continue;
617  KImportColumn *col = mColumns.at(i);
618  mTable->horizontalHeader()->setLabel( tableColumn, col->header() );
619  mColumnDict.replace( tableColumn, col );
620  mFormats.replace( tableColumn, format );
621  col->addColId( tableColumn );
622  }
623 
624  readFile();
625 }
626 
627 void KImportDialog::removeColumn()
628 {
629  TQTableSelection selection = mTable->selection(mTable->currentSelection());
630 
631 // kdDebug(5300) << " l: " << selection.leftCol() << " r: " << selection.rightCol() << endl;
632 
633  for(int i=selection.leftCol();i<=selection.rightCol();++i) {
634  if (i >= 0) {
635  mTable->horizontalHeader()->setLabel(i,TQString::number(i+1));
636  KImportColumn *col = mColumnDict.find(i);
637  if (col) {
638  mColumnDict.remove(i);
639  mFormats.remove(i);
640  col->removeColId(i);
641  }
642  }
643  }
644 
645  readFile();
646 }
647 
648 void KImportDialog::applyConverter()
649 {
650  kdDebug(5300) << "KImportDialog::applyConverter" << endl;
651 
652  KProgressDialog pDialog(this, 0, i18n("Importing Progress"),
653  i18n("Please wait while the data is imported."), true);
654  pDialog.setAllowCancel(true);
655  pDialog.showCancelButton(true);
656  pDialog.setAutoClose(true);
657 
658  KProgress *progress = pDialog.progressBar();
659  progress->setTotalSteps( mTable->numRows()-1 );
660  progress->setValue(0);
661 
662  readFile( 0 );
663 
664  pDialog.show();
665  for( uint i = mStartRow->value() - 1; i < mData.count() && !pDialog.wasCancelled(); ++i ) {
666  mCurrentRow = i;
667  progress->setValue(i);
668  if (i % 5 == 0) // try to avoid constantly processing events
669  kapp->processEvents();
670 
671  convertRow();
672  }
673 }
674 
675 int KImportDialog::findFormat(int column)
676 {
677  TQMap<int,int>::ConstIterator formatIt = mFormats.find(column);
678  int format;
679  if (formatIt == mFormats.end()) format = KImportColumn::FormatUndefined;
680  else format = *formatIt;
681 
682 // kdDebug(5300) << "KImportDialog::findformat(): " << column << ": " << format << endl;
683 
684  return format;
685 }
686 
687 TQString KImportDialog::cell(uint col)
688 {
689  if ( col >= mData[ mCurrentRow ]->size() ) return "";
690  else return data( mCurrentRow, col );
691 }
692 
693 void KImportDialog::addColumn(KImportColumn *col)
694 {
695  mColumns.append(col);
696 }
697 
698 void KImportDialog::setData( uint row, uint col, const TQString &value )
699 {
700  TQString val = value;
701  val.replace( "\\n", "\n" );
702 
703  if ( row >= mData.count() ) {
704  mData.resize( row + 1 );
705  }
706 
707  TQValueVector<TQString> *rowVector = mData[ row ];
708  if ( !rowVector ) {
709  rowVector = new TQValueVector<TQString>;
710  mData.insert( row, rowVector );
711  }
712  if ( col >= rowVector->size() ) {
713  rowVector->resize( col + 1 );
714  }
715 
716  KImportColumn *c = mColumnDict.find( col );
717  if ( c )
718  rowVector->at( col ) = c->preview( val, findFormat(col) );
719  else
720  rowVector->at( col ) = val;
721 }
722 
723 TQString KImportDialog::data( uint row, uint col )
724 {
725  return mData[ row ]->at( col );
726 }
727 
728 void KImportDialog::saveTemplate()
729 {
730  TQString fileName = KFileDialog::getSaveFileName(
731  locateLocal( "data", TQString( kapp->name() ) + "/csv-templates/" ),
732  "*.desktop", this );
733 
734  if ( fileName.isEmpty() )
735  return;
736 
737  if ( !fileName.contains( ".desktop" ) )
738  fileName += ".desktop";
739 
740  TQString name = KInputDialog::getText( i18n( "Template Name" ), i18n( "Please enter a name for the template:" ) );
741 
742  if ( name.isEmpty() )
743  return;
744 
745  TDEConfig config( fileName );
746  config.setGroup( "General" );
747  config.writeEntry( "Columns", mColumns.count() );
748  config.writeEntry( "Format", mFormatCombo->currentItem() + 1 );
749 
750  config.setGroup( "Misc" );
751  config.writeEntry( "Name", name );
752 
753  config.setGroup( "csv column map" );
754 
755  KImportColumn *column;
756  uint counter = 0;
757  for ( column = mColumns.first(); column; column = mColumns.next() ) {
758  TQValueList<int> list = column->colIdList();
759  if ( list.count() > 0 )
760  config.writeEntry( TQString::number( counter ), list[ 0 ] );
761  else
762  config.writeEntry( TQString::number( counter ), -1 );
763  counter++;
764  }
765 
766  config.sync();
767 }