Salome HOME
updated copyright message
[modules/gui.git] / src / Qtx / QtxPathListEdit.cxx
1 // Copyright (C) 2007-2023  CEA, EDF, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File:      QtxPathListEdit.cxx
21 // Author:    Sergey TELKOV
22 //
23 #include "QtxPathListEdit.h"
24
25 #include "QtxPathEdit.h"
26
27 #include <QLayout>
28 #include <QPainter>
29 #include <QListView>
30 #include <QLineEdit>
31 #include <QKeyEvent>
32 #include <QDirModel>
33 #include <QCompleter>
34 #include <QToolButton>
35 #include <QMessageBox>
36 #include <QFileDialog>
37 #include <QItemDelegate>
38 #include <QStringListModel>
39
40 static const char* delete_icon[] = {
41 "16 16 3 1",
42 "` c #810000",
43 "  c none",
44 "# c #ffffff",
45 "                ",
46 "                ",
47 " ``#        ``# ",
48 " ````#     ``#  ",
49 "  ````#   ``#   ",
50 "    ```# `#     ",
51 "     `````#     ",
52 "      ```#      ",
53 "     `````#     ",
54 "    ```# ``#    ",
55 "   ```#   ``#   ",
56 "  ```#     `#   ",
57 "  ```#      `#  ",
58 "   `#        `# ",
59 "                ",
60 "                "
61 };
62
63 static const char* insert_icon[] = {
64 "16 16 5 1",
65 "` c #000000",
66 ". c #ffff00",
67 "# c #9d9da1",
68 "  c none",
69 "b c #ffffff",
70 "                ",
71 "                ",
72 " #  #b #.       ",
73 "  # #.#.` ` `   ",
74 "  .#.b####   `  ",
75 " ### ..         ",
76 "  . # .#     `  ",
77 " #` #.          ",
78 "    #        `  ",
79 "  `             ",
80 "             `  ",
81 "  `             ",
82 "             `  ",
83 "  ` ` ` ` ` `   ",
84 "                ",
85 "                "
86 };
87
88 static const char* movedown_icon[] = {
89 "16 16 2 1",
90 "` c #000000",
91 "  c none",
92 "                ",
93 "                ",
94 "         ```    ",
95 "        ```     ",
96 "       ```      ",
97 "       ```      ",
98 "       ```      ",
99 "       ```      ",
100 "   ```````````  ",
101 "    `````````   ",
102 "     ```````    ",
103 "      `````     ",
104 "       ```      ",
105 "        `       ",
106 "                ",
107 "                "
108 };
109
110 static const char* moveup_icon[] = {
111 "16 16 2 1",
112 "` c #000000",
113 "  c none",
114 "                ",
115 "                ",
116 "        `       ",
117 "       ```      ",
118 "      `````     ",
119 "     ```````    ",
120 "    `````````   ",
121 "   ```````````  ",
122 "       ```      ",
123 "       ```      ",
124 "       ```      ",
125 "       ```      ",
126 "      ```       ",
127 "     ```        ",
128 "                ",
129 "                "
130 };
131
132
133 /*!
134   \class QtxPathListEdit::Editor
135   \brief Path editor widget
136   \internal
137 */
138
139 class QtxPathListEdit::Editor : public QtxPathEdit
140 {
141 public:
142   /*!
143     \brief Constructor
144     \internal
145   */
146   Editor( QWidget* parent = 0 ) : QtxPathEdit( parent, true )
147   {
148     layout()->setSpacing( 0 );
149     lineEdit()->setFrame( false );
150   }
151
152   /*!
153     \brief Destructor
154     \internal
155   */
156   virtual ~Editor() {}
157 };
158
159 /*!
160   \class QtxPathListEdit::Delegate
161   \brief Custom item delegate for the paths list widget.
162   \internal
163 */
164
165 class QtxPathListEdit::Delegate : public QItemDelegate
166 {
167 public:
168   Delegate( QtxPathListEdit*, QObject* = 0 );
169   virtual ~Delegate();
170
171   virtual QWidget* createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const;
172   virtual void     setModelData( QWidget*, QAbstractItemModel*, const QModelIndex& ) const;
173   virtual void     setEditorData( QWidget*, const QModelIndex& ) const;
174   virtual void     paint( QPainter*, const QStyleOptionViewItem&, const QModelIndex& ) const;
175
176 protected:
177   virtual void     drawFocus( QPainter*, const QStyleOptionViewItem&, const QRect& ) const;
178
179 private:
180   QtxPathListEdit* myPathEdit;
181 };
182
183 /*!
184   \brief Constructor.
185   \internal
186   \param pe path list editor
187   \param parent parent widget
188 */
189 QtxPathListEdit::Delegate::Delegate( QtxPathListEdit* pe, QObject* parent )
190 : QItemDelegate( parent ),
191   myPathEdit( pe )
192 {
193 }
194
195 /*!
196   \brief Destructor.
197   \internal
198 */
199 QtxPathListEdit::Delegate::~Delegate()
200 {
201 }
202
203 /*!
204   \brief Create editor widget.
205   \internal
206   \param parent parent widget
207   \param option style option
208   \param index data model index
209 */
210 QWidget* QtxPathListEdit::Delegate::createEditor( QWidget* parent, const QStyleOptionViewItem& /*option*/,
211                                                   const QModelIndex& /*index*/ ) const
212 {
213   return myPathEdit->createEditor( parent );
214 }
215
216 /*!
217   \brief Set modified data back to the data model.
218   \internal
219   \param editor editor widget
220   \param model data model
221   \param index data model index
222 */
223 void QtxPathListEdit::Delegate::setModelData( QWidget* editor, QAbstractItemModel* /*model*/,
224                                               const QModelIndex& index ) const
225 {
226   myPathEdit->setModelData( editor, index );
227 }
228
229 /*!
230   \brief Set data from the data model to the editor.
231   \internal
232   \param editor editor widget
233   \param index data model index
234 */
235 void QtxPathListEdit::Delegate::setEditorData( QWidget* editor, const QModelIndex& index ) const
236 {
237   myPathEdit->setEditorData( editor, index );
238 }
239
240 /*!
241   \brief Customize paint operation.
242   \internal
243   \param painter painter
244   \param option style option
245   \param index data model index
246 */
247 void QtxPathListEdit::Delegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
248                                        const QModelIndex& index ) const
249 {
250   QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
251   if ( cg == QPalette::Normal && !( option.state & QStyle::State_Active ) )
252     cg = QPalette::Inactive;
253
254   if ( option.state & QStyle::State_Selected )
255   {
256     painter->fillRect( option.rect, option.palette.brush( cg, QPalette::Highlight ) );
257     painter->setPen( option.palette.color( cg, QPalette::HighlightedText ) );
258   }
259   else
260     painter->setPen( option.palette.color( cg, QPalette::Text ) );
261
262   QItemDelegate::paint( painter, option, index );
263 }
264
265 /*!
266   \brief Customize drawing selection focus operation.
267   \internal
268   \param painter painter
269   \param option style option
270   \param rect selection rectangle
271 */
272 void QtxPathListEdit::Delegate::drawFocus( QPainter* painter, const QStyleOptionViewItem& option,
273                                            const QRect& /*rect*/ ) const
274 {
275   QItemDelegate::drawFocus( painter, option, option.rect );
276 }
277
278 /*!
279   \class QtxPathListEdit
280   \brief The QtxPathListEdit class represents a widget for files or 
281   directories paths list preference items editing.
282
283   The path list preference item is represented as the list box widget.
284   It provides such operations like adding new file/directory path to the
285   list, removing selected paths and modifying of already entered ones.
286
287   The widget can be used in two modes: list of files or list of directories.
288   The mode defines the type of the standard browse dialog box which is
289   invoked on the browse button clicking.
290
291   Initial path list value can be set with setPathList() method. Chosen path
292   list can be retrieved with the pathList() method. The widget mode can be set 
293   with setPathType() and retrieved with pathType() method.
294
295   In addition, it is possible to add path items to the list with the insert()
296   method, remove items with the remove() methods, clear all the widget contents
297   with the clear() method. To get the number of entered paths can be retrieved
298   with the count() method. To check if any path already exists in the paths list,
299   use contains() method.
300 */
301
302 /*!
303   \brief Constructor.
304   \param type widget mode (Qtx::PathType)
305   \param parent parent widget
306   \sa pathType(), setPathType()
307 */
308 QtxPathListEdit::QtxPathListEdit( const Qtx::PathType type, QWidget* parent )
309 : QFrame( parent ),
310   myType( type ),
311   myCompleter( 0 ),
312   myDuplicate( false )
313 {
314   initialize();
315 }
316
317 /*!
318   \brief Constructor.
319
320   Qtx::PT_OpenFile mode is used by default.
321
322   \param parent parent widget
323   \sa pathType(), setPathType()
324 */
325 QtxPathListEdit::QtxPathListEdit( QWidget* parent )
326 : QFrame( parent ),
327   myType( Qtx::PT_OpenFile ),
328   myCompleter( 0 ),
329   myDuplicate( false )
330 {
331   initialize();
332 }
333
334 /*!
335   \brief Destructor.
336 */
337 QtxPathListEdit::~QtxPathListEdit()
338 {
339 }
340
341 /*!
342   \brief Get widget mode.
343   \return currently used widget mode (Qtx::PathType)
344   \sa setPathType()
345 */
346 Qtx::PathType QtxPathListEdit::pathType() const
347 {
348   return myType;
349 }
350
351 /*!
352   \brief Set widget mode.
353   \param t new widget mode (Qtx::PathType)
354   \sa pathType()
355 */
356 void QtxPathListEdit::setPathType( const Qtx::PathType t )
357 {
358   if ( myType == t )
359     return;
360
361   myType = t;
362
363   delete myCompleter;
364   myCompleter = 0;
365 }
366
367 /*!
368   \brief Get currently selected paths list.
369   \return files or directories paths list entered by the user
370   \sa setPathList()
371 */
372 QStringList QtxPathListEdit::pathList() const
373 {
374   return myModel->stringList();
375 }
376
377 /*!
378   \brief Set paths list.
379   \param lst files or directories paths list
380   \sa pathList()
381 */
382 void QtxPathListEdit::setPathList( const QStringList& lst )
383 {
384   myModel->setStringList( lst );
385 }
386
387 /*!
388   \brief Check if the duplication of paths is enabled.
389   \return \c true if the duplication is enabled
390 */
391 bool QtxPathListEdit::isDuplicateEnabled() const
392 {
393   return myDuplicate;
394 }
395
396 /*!
397   \brief Enable/disable paths duplication.
398   \param on new flag value
399 */
400 void QtxPathListEdit::setDuplicateEnabled( const bool on )
401 {
402   myDuplicate = on;
403 }
404
405 /*!
406   \brief Get number of currently entered paths.
407   \return current paths number
408 */
409 int QtxPathListEdit::count() const
410 {
411   return myModel->rowCount();
412 }
413
414 /*!
415   \brief Check if the specified \a path already exists in 
416   the paths list.
417   \param path path to be checked
418   \return \c true if the path is already selected by the user 
419   or \c false otherwise
420 */
421 bool QtxPathListEdit::contains( const QString& path ) const
422 {
423   return myModel->stringList().contains( path );
424 }
425
426 /*!
427   \brief Clear paths list.
428 */
429 void QtxPathListEdit::clear()
430 {
431   myModel->removeRows( 0, myModel->rowCount() );
432 }
433
434 /*!
435   \brief Remove path from the paths list.
436   \param idx path index in the list
437 */
438 void QtxPathListEdit::remove( const int idx )
439 {
440   if ( 0 <= idx && idx < myModel->rowCount() )
441     myModel->removeRow( idx );
442 }
443
444 /*!
445   \brief Remove path from the paths list.
446   \param path path to be removed
447 */
448 void QtxPathListEdit::remove( const QString& path )
449 {
450   QModelIndexList indexes = myModel->match( myModel->index( 0, 0 ), Qt::DisplayRole, path,
451                                             myModel->rowCount(), Qt::MatchExactly | Qt::MatchCaseSensitive );
452   while ( !indexes.isEmpty() )
453   {
454     myModel->removeRow( indexes.last().row() );
455     indexes.removeLast();
456   }
457 }
458
459 /*!
460   \brief Add path to the list of paths.
461
462   If the specified index is out of range, the path is added to 
463   the end of the list.
464
465   \param path path to be added
466   \param idx index in the list to which the path should be inserted.
467 */
468 void QtxPathListEdit::insert( const QString& path, const int idx )
469 {
470   int index = idx < 0 ? myModel->rowCount() : qMin( idx, myModel->rowCount() );
471   if ( myModel->insertRow( index ) )
472     myModel->setData( myModel->index( index, 0 ), path, Qt::EditRole );
473 }
474
475 /*
476 bool QtxPathListEdit::validate( const bool quietMode )
477 {
478   if ( myEdited )
479   {
480     QString dirPath = QFileInfo( myEdit->text().stripWhiteSpace() ).filePath();
481     QDir dir(dirPath);
482     QListBoxItem* found = 0;
483     for (unsigned i = 0; i < myList->count()-1; i++) {
484       QDir aDir(myList->text(i));
485       if ( aDir.canonicalPath().isNull() && myList->text(i) == dir.absPath() ||
486           !aDir.canonicalPath().isNull() && aDir.exists() && aDir.canonicalPath() == dir.canonicalPath()) {
487           found = myList->item(i);
488         break;
489       }
490     }
491     if (dirPath.isEmpty()) {
492       if (found) {
493         // it should be last (empty) item in the list - nothing to do
494         return true;
495       }
496       else {
497         // delete directory from the list
498         removeDir(myLastSelected);
499         return true;
500       }
501     }
502     else {
503       if (found) {
504         if (found != myLastSelected) {
505           // it is forbidden to add directory more then once
506           if ( !quietMode )
507             QMessageBox::critical(this, 
508                                   tr("Error"),
509                                   tr("Directory already specified."), 
510                                   tr("Ok"));
511           myEdit->setFocus();
512           return false;
513         }
514       }
515       else {
516         if (!dir.exists()) {
517           if ( !quietMode && QMessageBox::information(this, 
518                                                       tr("Warning"),
519                                                       tr("%1\n\nThe directory doesn't exist.\nAdd directory anyway?").arg(dir.absPath()),
520                                                       tr("Yes"), tr("No"), QString(), 1, 1) == 1) {
521             myEdit->setFocus();
522             return false;
523           }
524         }
525         // append
526         appendDir(myLastSelected, dir.absPath());
527       }
528     }
529   }
530   return true;
531 }
532 */
533
534 /*!
535   \brief Customize child widget events processing.
536   \param o event receiver object
537   \param e event
538   \return \c true if the further event processing should be stopped.
539 */
540 bool QtxPathListEdit::eventFilter( QObject* o, QEvent* e )
541 {
542   if ( e->type() == QEvent::KeyPress )
543   {
544     QKeyEvent* ke = (QKeyEvent*)e;
545     if ( ke->key() == Qt::Key_Delete )
546       onDelete();
547     else if ( ke->key() == Qt::Key_Insert )
548       onInsert();
549     else if ( ke->key() == Qt::Key_Up && ke->modifiers() == Qt::CTRL )
550     {
551       onUp();
552       return true;
553     }
554     else if ( ke->key() == Qt::Key_Down && ke->modifiers() == Qt::CTRL )
555     {
556       onDown();
557       return true;
558     }
559   }
560
561   return QFrame::eventFilter( o, e );
562 }
563
564 /*!
565   \brief Called when <Insert> button is clicked.
566
567   Inserts new empty line to the list and sets input focus to it.
568
569   \param on (not used)
570 */
571 void QtxPathListEdit::onInsert( bool /*on*/ )
572 {
573   int empty = -1;
574   QStringList lst = myModel->stringList();
575   for ( int r = 0; r < lst.count() && empty == -1; r++ )
576   {
577     if ( lst.at( r ).isEmpty() )
578       empty = r;
579   }
580
581   if ( empty == -1 )
582     myModel->insertRows( empty = myModel->rowCount(), 1 );
583
584   QModelIndex idx = myModel->index( empty, 0 );
585   myList->setCurrentIndex( idx );
586   myList->edit( idx );
587 }
588
589 /*!
590   \brief Called when <Delete> button is clicked.
591
592   Removes currently selected path item.
593   
594   \param on (not used)
595 */
596 void QtxPathListEdit::onDelete( bool )
597 {
598   QModelIndex idx = myList->currentIndex();
599   if ( !idx.isValid() )
600     return;
601
602   myModel->removeRow( idx.row() );
603 }
604
605 /*!
606   \brief Called when <Up> button is clicked.
607
608   Move currently selected path item up to one row in the paths list.
609
610   \param on (not used)
611 */
612 void QtxPathListEdit::onUp( bool )
613 {
614   QModelIndex idx = myList->currentIndex();
615   if ( !idx.isValid() || idx.row() < 1 )
616     return;
617
618   QModelIndex toIdx = myModel->index( idx.row() - 1, 0 );
619
620   QVariant val = myModel->data( toIdx, Qt::DisplayRole );
621   myModel->setData( toIdx, myModel->data( idx, Qt::DisplayRole ), Qt::DisplayRole );
622   myModel->setData( idx, val, Qt::DisplayRole );
623
624   myList->setCurrentIndex( toIdx );
625 }
626
627 /*!
628   \brief Called when <Down> button is clicked.
629
630   Move currently selected path item down to one row in the paths list.
631
632   \param on (not used)
633 */
634 void QtxPathListEdit::onDown( bool )
635 {
636   QModelIndex idx = myList->currentIndex();
637   if ( !idx.isValid() || idx.row() >= myModel->rowCount() - 1 )
638     return;
639
640   QModelIndex toIdx = myModel->index( idx.row() + 1, 0 );
641
642   QVariant val = myModel->data( toIdx, Qt::DisplayRole );
643   myModel->setData( toIdx, myModel->data( idx, Qt::DisplayRole ), Qt::DisplayRole );
644   myModel->setData( idx, val, Qt::DisplayRole );
645
646   myList->setCurrentIndex( toIdx );
647 }
648
649 /*!
650   \brief Perform internal widget initialization.
651 */
652 void QtxPathListEdit::initialize()
653 {
654   QVBoxLayout* base = new QVBoxLayout( this );
655   base->setMargin( 0 );
656   base->setSpacing( 5 );
657
658   QWidget* cBox = new QWidget( this );
659   base->addWidget( cBox );
660   
661   QHBoxLayout* cLayout = new QHBoxLayout( cBox );
662   cLayout->setMargin( 0 );
663   cLayout->setSpacing( 0 );
664
665   cLayout->addStretch( 1 );
666
667   QToolButton* insertBtn = new QToolButton( cBox );
668   insertBtn->setIcon( QPixmap( insert_icon ) );
669   cLayout->addWidget( insertBtn );
670
671   QToolButton* deleteBtn = new QToolButton( cBox );
672   deleteBtn->setIcon( QPixmap( delete_icon ) );
673   cLayout->addWidget( deleteBtn );
674
675   QToolButton* upBtn = new QToolButton( cBox );
676   upBtn->setIcon( QPixmap( moveup_icon ) );
677   cLayout->addWidget( upBtn );
678
679   QToolButton* downBtn = new QToolButton( cBox );
680   downBtn->setIcon( QPixmap( movedown_icon ) );
681   cLayout->addWidget( downBtn );
682
683
684   myList = new QListView( this );
685   myList->setAlternatingRowColors( true );
686   myList->setItemDelegate( new Delegate( this, myList ) );
687   myList->setModel( myModel = new QStringListModel( myList ) );
688   myList->setSelectionMode( QListView::SingleSelection );
689   myList->setSelectionBehavior( QListView::SelectRows );
690   myList->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
691   myList->setEditTriggers( QListView::DoubleClicked );
692   myList->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
693   myList->installEventFilter( this );
694
695   base->addWidget( myList );
696
697   connect( insertBtn, SIGNAL( clicked( bool ) ), this, SLOT( onInsert( bool ) ) );
698   connect( deleteBtn, SIGNAL( clicked( bool ) ), this, SLOT( onDelete( bool ) ) );
699   connect( upBtn,     SIGNAL( clicked( bool ) ), this, SLOT( onUp( bool ) ) );
700   connect( downBtn,   SIGNAL( clicked( bool ) ), this, SLOT( onDown( bool ) ) );
701 }
702
703 /*!
704   \brief Create editor widget.
705   \param parent parent widget for the editor
706   \return created editor widget
707 */
708 QWidget* QtxPathListEdit::createEditor( QWidget* parent )
709 {
710   QtxPathEdit* edit = new Editor( parent );
711   edit->setPathType( pathType() );
712   return edit;
713 }
714
715 /*!
716   \brief Set modified data from the editor to the list widget.
717   \param editor editor widget
718   \param index data model index
719 */
720 void QtxPathListEdit::setModelData( QWidget* editor, const QModelIndex& index )
721 {
722   QtxPathEdit* edit = ::qobject_cast<QtxPathEdit*>( editor );
723   if ( !edit )
724     return;
725
726   QString path = edit->path().trimmed();
727
728   if ( !isDuplicateEnabled() && !checkDuplicate( path, index.row() ) )
729     return;
730
731   if ( !checkExistance( path ) )
732     return;
733
734   myModel->setData( index, path, Qt::EditRole );
735 }
736
737 /*!
738   \brief Set data to the editor from the list widget when 
739   user starts path edition.
740   \param editor editor widget
741   \param index data model index
742 */
743 void QtxPathListEdit::setEditorData( QWidget* editor, const QModelIndex& index )
744 {
745   QtxPathEdit* edit = ::qobject_cast<QtxPathEdit*>( editor );
746   if ( !edit )
747     return;
748
749   QVariant v = myModel->data( index, Qt::EditRole );
750   edit->setPath( v.toString() );
751 }
752
753 /*!
754   \brief Check if path is correct (exists) and optionally 
755   show the question message box.
756   \param str path to be checked
757   \param msg if \c true and path does not exist, question message box is shown
758   \return \c true if the user confirms the path adding
759 */
760 bool QtxPathListEdit::checkExistance( const QString& str, const bool msg )
761 {
762   if ( pathType() == Qtx::PT_SaveFile )
763     return true;
764
765   QFileInfo aFI = QFileInfo( Qtx::makeEnvVarSubst( str ) );
766   bool ok = aFI.exists();
767   if ( !ok && msg )
768     ok = QMessageBox::question( this, tr( "Warning" ), tr( "Path \"%1\" doesn't exist. Add it to list anyway?" ).arg( str ),
769                                 QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes;
770
771   if ( ok && aFI.exists() )
772   {
773     switch ( pathType() )
774     {
775     case Qtx::PT_OpenFile:
776       ok = aFI.isFile();
777       if ( !ok && msg )
778         QMessageBox::warning( this, tr( "Error" ), tr( "Location \"%1\" doesn't point to file" ).arg( str ) );
779       break;
780     case Qtx::PT_Directory:
781       ok = aFI.isDir();
782       if ( !ok && msg )
783         QMessageBox::warning( this, tr( "Error" ), tr( "Location \"%1\" doesn't point to directory" ).arg( str ) );
784       break;
785     default:
786       break;
787     }
788   }
789
790   return ok;
791 }
792
793 /*!
794   \brief Check if path already exists in the list and optionally
795   show the warning message box.
796   \param str path to be checked
797   \param row row corresponding to the path checked
798   \param msg if \c true and path does not exist, warning message box is shown
799   \return \c true if the user confirms the path adding
800 */
801 bool QtxPathListEdit::checkDuplicate( const QString& str, const int row, const bool msg )
802 {
803   int cur = -1;
804   QStringList lst = myModel->stringList();
805   for ( int r = 0; r < lst.count() && cur == -1; r++ )
806   {
807     if ( r != row && lst.at( r ) == str )
808       cur = r;
809   }
810
811   if ( cur != -1 && msg )
812     QMessageBox::warning( this, tr( "Error" ), tr( "Path \"%1\" already exist in the list" ).arg( str ) );
813    
814   return cur == -1;
815 }