Back to index

salome-gui  6.5.0
QtxPathListEdit.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // This library is free software; you can redistribute it and/or
00004 // modify it under the terms of the GNU Lesser General Public
00005 // License as published by the Free Software Foundation; either
00006 // version 2.1 of the License.
00007 //
00008 // This library is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011 // Lesser General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU Lesser General Public
00014 // License along with this library; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00016 //
00017 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00018 //
00019 
00020 // File:      QtxPathListEdit.cxx
00021 // Author:    Sergey TELKOV
00022 //
00023 #include "QtxPathListEdit.h"
00024 
00025 #include "QtxPathEdit.h"
00026 
00027 #include <QLayout>
00028 #include <QPainter>
00029 #include <QListView>
00030 #include <QLineEdit>
00031 #include <QKeyEvent>
00032 #include <QDirModel>
00033 #include <QCompleter>
00034 #include <QToolButton>
00035 #include <QMessageBox>
00036 #include <QFileDialog>
00037 #include <QItemDelegate>
00038 #include <QStringListModel>
00039 
00040 static const char* delete_icon[] = {
00041 "16 16 3 1",
00042 "` c #810000",
00043 "  c none",
00044 "# c #ffffff",
00045 "                ",
00046 "                ",
00047 " ``#        ``# ",
00048 " ````#     ``#  ",
00049 "  ````#   ``#   ",
00050 "    ```# `#     ",
00051 "     `````#     ",
00052 "      ```#      ",
00053 "     `````#     ",
00054 "    ```# ``#    ",
00055 "   ```#   ``#   ",
00056 "  ```#     `#   ",
00057 "  ```#      `#  ",
00058 "   `#        `# ",
00059 "                ",
00060 "                "
00061 };
00062 
00063 static const char* insert_icon[] = {
00064 "16 16 5 1",
00065 "` c #000000",
00066 ". c #ffff00",
00067 "# c #9d9da1",
00068 "  c none",
00069 "b c #ffffff",
00070 "                ",
00071 "                ",
00072 " #  #b #.       ",
00073 "  # #.#.` ` `   ",
00074 "  .#.b####   `  ",
00075 " ### ..         ",
00076 "  . # .#     `  ",
00077 " #` #.          ",
00078 "    #        `  ",
00079 "  `             ",
00080 "             `  ",
00081 "  `             ",
00082 "             `  ",
00083 "  ` ` ` ` ` `   ",
00084 "                ",
00085 "                "
00086 };
00087 
00088 static const char* movedown_icon[] = {
00089 "16 16 2 1",
00090 "` c #000000",
00091 "  c none",
00092 "                ",
00093 "                ",
00094 "         ```    ",
00095 "        ```     ",
00096 "       ```      ",
00097 "       ```      ",
00098 "       ```      ",
00099 "       ```      ",
00100 "   ```````````  ",
00101 "    `````````   ",
00102 "     ```````    ",
00103 "      `````     ",
00104 "       ```      ",
00105 "        `       ",
00106 "                ",
00107 "                "
00108 };
00109 
00110 static const char* moveup_icon[] = {
00111 "16 16 2 1",
00112 "` c #000000",
00113 "  c none",
00114 "                ",
00115 "                ",
00116 "        `       ",
00117 "       ```      ",
00118 "      `````     ",
00119 "     ```````    ",
00120 "    `````````   ",
00121 "   ```````````  ",
00122 "       ```      ",
00123 "       ```      ",
00124 "       ```      ",
00125 "       ```      ",
00126 "      ```       ",
00127 "     ```        ",
00128 "                ",
00129 "                "
00130 };
00131 
00132 
00139 class QtxPathListEdit::Editor : public QtxPathEdit
00140 {
00141 public:
00146   Editor( QWidget* parent = 0 ) : QtxPathEdit( parent )
00147   {
00148     layout()->setSpacing( 0 );
00149     lineEdit()->setFrame( false );
00150   }
00151 
00156   virtual ~Editor() {}
00157 };
00158 
00165 class QtxPathListEdit::Delegate : public QItemDelegate
00166 {
00167 public:
00168   Delegate( QtxPathListEdit*, QObject* = 0 );
00169   virtual ~Delegate();
00170 
00171   virtual QWidget* createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const;
00172   virtual void     setModelData( QWidget*, QAbstractItemModel*, const QModelIndex& ) const;
00173   virtual void     setEditorData( QWidget*, const QModelIndex& ) const;
00174   virtual void     paint( QPainter*, const QStyleOptionViewItem&, const QModelIndex& ) const;
00175 
00176 protected:
00177   virtual void     drawFocus( QPainter*, const QStyleOptionViewItem&, const QRect& ) const;
00178 
00179 private:
00180   QtxPathListEdit* myPathEdit;
00181 };
00182 
00189 QtxPathListEdit::Delegate::Delegate( QtxPathListEdit* pe, QObject* parent )
00190 : QItemDelegate( parent ),
00191   myPathEdit( pe )
00192 {
00193 }
00194 
00199 QtxPathListEdit::Delegate::~Delegate()
00200 {
00201 }
00202 
00210 QWidget* QtxPathListEdit::Delegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option,
00211                                                   const QModelIndex& index ) const
00212 {
00213   return myPathEdit->createEditor( parent );
00214 }
00215 
00223 void QtxPathListEdit::Delegate::setModelData( QWidget* editor, QAbstractItemModel* model,
00224                                               const QModelIndex& index ) const
00225 {
00226   myPathEdit->setModelData( editor, index );
00227 }
00228 
00235 void QtxPathListEdit::Delegate::setEditorData( QWidget* editor, const QModelIndex& index ) const
00236 {
00237   myPathEdit->setEditorData( editor, index );
00238 }
00239 
00247 void QtxPathListEdit::Delegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
00248                                        const QModelIndex& index ) const
00249 {
00250   QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
00251   if ( cg == QPalette::Normal && !( option.state & QStyle::State_Active ) )
00252     cg = QPalette::Inactive;
00253 
00254   if ( option.state & QStyle::State_Selected )
00255   {
00256     painter->fillRect( option.rect, option.palette.brush( cg, QPalette::Highlight ) );
00257     painter->setPen( option.palette.color( cg, QPalette::HighlightedText ) );
00258   }
00259   else
00260     painter->setPen( option.palette.color( cg, QPalette::Text ) );
00261 
00262   QItemDelegate::paint( painter, option, index );
00263 }
00264 
00272 void QtxPathListEdit::Delegate::drawFocus( QPainter* painter, const QStyleOptionViewItem& option,
00273                                            const QRect& rect ) const
00274 {
00275   QItemDelegate::drawFocus( painter, option, option.rect );
00276 }
00277 
00308 QtxPathListEdit::QtxPathListEdit( const Qtx::PathType type, QWidget* parent )
00309 : QFrame( parent ),
00310   myCompleter( 0 ),
00311   myType( type ),
00312   myDuplicate( false )
00313 {
00314   initialize();
00315 }
00316 
00325 QtxPathListEdit::QtxPathListEdit( QWidget* parent )
00326 : QFrame( parent ),
00327   myCompleter( 0 ),
00328   myType( Qtx::PT_OpenFile ),
00329   myDuplicate( false )
00330 {
00331   initialize();
00332 }
00333 
00337 QtxPathListEdit::~QtxPathListEdit()
00338 {
00339 }
00340 
00346 Qtx::PathType QtxPathListEdit::pathType() const
00347 {
00348   return myType;
00349 }
00350 
00356 void QtxPathListEdit::setPathType( const Qtx::PathType t )
00357 {
00358   if ( myType == t )
00359     return;
00360 
00361   myType = t;
00362 
00363   delete myCompleter;
00364   myCompleter = 0;
00365 }
00366 
00372 QStringList QtxPathListEdit::pathList() const
00373 {
00374   return myModel->stringList();
00375 }
00376 
00382 void QtxPathListEdit::setPathList( const QStringList& lst )
00383 {
00384   myModel->setStringList( lst );
00385 }
00386 
00391 bool QtxPathListEdit::isDuplicateEnabled() const
00392 {
00393   return myDuplicate;
00394 }
00395 
00400 void QtxPathListEdit::setDuplicateEnabled( const bool on )
00401 {
00402   myDuplicate = on;
00403 }
00404 
00409 int QtxPathListEdit::count() const
00410 {
00411   return myModel->rowCount();
00412 }
00413 
00421 bool QtxPathListEdit::contains( const QString& path ) const
00422 {
00423   return myModel->stringList().contains( path );
00424 }
00425 
00429 void QtxPathListEdit::clear()
00430 {
00431   myModel->removeRows( 0, myModel->rowCount() );
00432 }
00433 
00438 void QtxPathListEdit::remove( const int idx )
00439 {
00440   if ( 0 <= idx && idx < myModel->rowCount() )
00441     myModel->removeRow( idx );
00442 }
00443 
00448 void QtxPathListEdit::remove( const QString& path )
00449 {
00450   QModelIndexList indexes = myModel->match( myModel->index( 0, 0 ), Qt::DisplayRole, path,
00451                                             myModel->rowCount(), Qt::MatchExactly | Qt::MatchCaseSensitive );
00452   while ( !indexes.isEmpty() )
00453   {
00454     myModel->removeRow( indexes.last().row() );
00455     indexes.removeLast();
00456   }
00457 }
00458 
00468 void QtxPathListEdit::insert( const QString& path, const int idx )
00469 {
00470   int index = idx < 0 ? myModel->rowCount() : qMin( idx, myModel->rowCount() );
00471   if ( myModel->insertRow( index ) )
00472     myModel->setData( myModel->index( index, 0 ), path, Qt::EditRole );
00473 }
00474 
00475 /*
00476 bool QtxPathListEdit::validate( const bool quietMode )
00477 {
00478   if ( myEdited )
00479   {
00480     QString dirPath = QFileInfo( myEdit->text().stripWhiteSpace() ).filePath();
00481     QDir dir(dirPath);
00482     QListBoxItem* found = 0;
00483     for (unsigned i = 0; i < myList->count()-1; i++) {
00484       QDir aDir(myList->text(i));
00485       if ( aDir.canonicalPath().isNull() && myList->text(i) == dir.absPath() ||
00486           !aDir.canonicalPath().isNull() && aDir.exists() && aDir.canonicalPath() == dir.canonicalPath()) {
00487           found = myList->item(i);
00488         break;
00489       }
00490     }
00491     if (dirPath.isEmpty()) {
00492       if (found) {
00493         // it should be last (empty) item in the list - nothing to do
00494         return true;
00495       }
00496       else {
00497         // delete directory from the list
00498         removeDir(myLastSelected);
00499         return true;
00500       }
00501     }
00502     else {
00503       if (found) {
00504         if (found != myLastSelected) {
00505           // it is forbidden to add directory more then once
00506           if ( !quietMode )
00507             QMessageBox::critical(this, 
00508                                   tr("Error"),
00509                                   tr("Directory already specified."), 
00510                                   tr("Ok"));
00511           myEdit->setFocus();
00512           return false;
00513         }
00514       }
00515       else {
00516         if (!dir.exists()) {
00517           if ( !quietMode && QMessageBox::information(this, 
00518                                                       tr("Warning"),
00519                                                       tr("%1\n\nThe directory doesn't exist.\nAdd directory anyway?").arg(dir.absPath()),
00520                                                       tr("Yes"), tr("No"), QString(), 1, 1) == 1) {
00521             myEdit->setFocus();
00522             return false;
00523           }
00524         }
00525         // append
00526         appendDir(myLastSelected, dir.absPath());
00527       }
00528     }
00529   }
00530   return true;
00531 }
00532 */
00533 
00540 bool QtxPathListEdit::eventFilter( QObject* o, QEvent* e )
00541 {
00542   if ( e->type() == QEvent::KeyPress )
00543   {
00544     QKeyEvent* ke = (QKeyEvent*)e;
00545     if ( ke->key() == Qt::Key_Delete )
00546       onDelete();
00547     else if ( ke->key() == Qt::Key_Insert )
00548       onInsert();
00549     else if ( ke->key() == Qt::Key_Up && ke->modifiers() == Qt::CTRL )
00550     {
00551       onUp();
00552       return true;
00553     }
00554     else if ( ke->key() == Qt::Key_Down && ke->modifiers() == Qt::CTRL )
00555     {
00556       onDown();
00557       return true;
00558     }
00559   }
00560 
00561   return QFrame::eventFilter( o, e );
00562 }
00563 
00571 void QtxPathListEdit::onInsert( bool /*on*/ )
00572 {
00573   int empty = -1;
00574   QStringList lst = myModel->stringList();
00575   for ( int r = 0; r < lst.count() && empty == -1; r++ )
00576   {
00577     if ( lst.at( r ).isEmpty() )
00578       empty = r;
00579   }
00580 
00581   if ( empty == -1 )
00582     myModel->insertRows( empty = myModel->rowCount(), 1 );
00583 
00584   QModelIndex idx = myModel->index( empty, 0 );
00585   myList->setCurrentIndex( idx );
00586   myList->edit( idx );
00587 }
00588 
00596 void QtxPathListEdit::onDelete( bool )
00597 {
00598   QModelIndex idx = myList->currentIndex();
00599   if ( !idx.isValid() )
00600     return;
00601 
00602   myModel->removeRow( idx.row() );
00603 }
00604 
00612 void QtxPathListEdit::onUp( bool )
00613 {
00614   QModelIndex idx = myList->currentIndex();
00615   if ( !idx.isValid() || idx.row() < 1 )
00616     return;
00617 
00618   QModelIndex toIdx = myModel->index( idx.row() - 1, 0 );
00619 
00620   QVariant val = myModel->data( toIdx, Qt::DisplayRole );
00621   myModel->setData( toIdx, myModel->data( idx, Qt::DisplayRole ), Qt::DisplayRole );
00622   myModel->setData( idx, val, Qt::DisplayRole );
00623 
00624   myList->setCurrentIndex( toIdx );
00625 }
00626 
00634 void QtxPathListEdit::onDown( bool )
00635 {
00636   QModelIndex idx = myList->currentIndex();
00637   if ( !idx.isValid() || idx.row() >= myModel->rowCount() - 1 )
00638     return;
00639 
00640   QModelIndex toIdx = myModel->index( idx.row() + 1, 0 );
00641 
00642   QVariant val = myModel->data( toIdx, Qt::DisplayRole );
00643   myModel->setData( toIdx, myModel->data( idx, Qt::DisplayRole ), Qt::DisplayRole );
00644   myModel->setData( idx, val, Qt::DisplayRole );
00645 
00646   myList->setCurrentIndex( toIdx );
00647 }
00648 
00652 void QtxPathListEdit::initialize()
00653 {
00654   QVBoxLayout* base = new QVBoxLayout( this );
00655   base->setMargin( 0 );
00656   base->setSpacing( 5 );
00657 
00658   QWidget* cBox = new QWidget( this );
00659   base->addWidget( cBox );
00660   
00661   QHBoxLayout* cLayout = new QHBoxLayout( cBox );
00662   cLayout->setMargin( 0 );
00663   cLayout->setSpacing( 0 );
00664 
00665   cLayout->addStretch( 1 );
00666 
00667   QToolButton* insertBtn = new QToolButton( cBox );
00668   insertBtn->setIcon( QPixmap( insert_icon ) );
00669   cLayout->addWidget( insertBtn );
00670 
00671   QToolButton* deleteBtn = new QToolButton( cBox );
00672   deleteBtn->setIcon( QPixmap( delete_icon ) );
00673   cLayout->addWidget( deleteBtn );
00674 
00675   QToolButton* upBtn = new QToolButton( cBox );
00676   upBtn->setIcon( QPixmap( moveup_icon ) );
00677   cLayout->addWidget( upBtn );
00678 
00679   QToolButton* downBtn = new QToolButton( cBox );
00680   downBtn->setIcon( QPixmap( movedown_icon ) );
00681   cLayout->addWidget( downBtn );
00682 
00683 
00684   myList = new QListView( this );
00685   myList->setAlternatingRowColors( true );
00686   myList->setItemDelegate( new Delegate( this, myList ) );
00687   myList->setModel( myModel = new QStringListModel( myList ) );
00688   myList->setSelectionMode( QListView::SingleSelection );
00689   myList->setSelectionBehavior( QListView::SelectRows );
00690   myList->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
00691   myList->setEditTriggers( QListView::DoubleClicked );
00692   myList->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
00693   myList->installEventFilter( this );
00694 
00695   base->addWidget( myList );
00696 
00697   connect( insertBtn, SIGNAL( clicked( bool ) ), this, SLOT( onInsert( bool ) ) );
00698   connect( deleteBtn, SIGNAL( clicked( bool ) ), this, SLOT( onDelete( bool ) ) );
00699   connect( upBtn,     SIGNAL( clicked( bool ) ), this, SLOT( onUp( bool ) ) );
00700   connect( downBtn,   SIGNAL( clicked( bool ) ), this, SLOT( onDown( bool ) ) );
00701 }
00702 
00708 QWidget* QtxPathListEdit::createEditor( QWidget* parent )
00709 {
00710   QtxPathEdit* edit = new Editor( parent );
00711   edit->setPathType( pathType() );
00712   return edit;
00713 }
00714 
00720 void QtxPathListEdit::setModelData( QWidget* editor, const QModelIndex& index )
00721 {
00722   QtxPathEdit* edit = ::qobject_cast<QtxPathEdit*>( editor );
00723   if ( !edit )
00724     return;
00725 
00726   QString path = edit->path().trimmed();
00727 
00728   if ( !isDuplicateEnabled() && !checkDuplicate( path, index.row() ) )
00729     return;
00730 
00731   if ( !checkExistance( path ) )
00732     return;
00733 
00734   myModel->setData( index, path, Qt::EditRole );
00735 }
00736 
00743 void QtxPathListEdit::setEditorData( QWidget* editor, const QModelIndex& index )
00744 {
00745   QtxPathEdit* edit = ::qobject_cast<QtxPathEdit*>( editor );
00746   if ( !edit )
00747     return;
00748 
00749   QVariant v = myModel->data( index, Qt::EditRole );
00750   edit->setPath( v.toString() );
00751 }
00752 
00760 bool QtxPathListEdit::checkExistance( const QString& str, const bool msg )
00761 {
00762   if ( pathType() == Qtx::PT_SaveFile )
00763     return true;
00764 
00765   QFileInfo aFI = QFileInfo( Qtx::makeEnvVarSubst( str ) );
00766   bool ok = aFI.exists();
00767   if ( !ok && msg )
00768     ok = QMessageBox::question( this, tr( "Warning" ), tr( "Path \"%1\" doesn't exist. Add it to list anyway?" ).arg( str ),
00769                                 QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes;
00770 
00771   if ( ok && aFI.exists() )
00772   {
00773     switch ( pathType() )
00774     {
00775     case Qtx::PT_OpenFile:
00776       ok = aFI.isFile();
00777       if ( !ok && msg )
00778         QMessageBox::warning( this, tr( "Error" ), tr( "Location \"%1\" doesn't point to file" ).arg( str ) );
00779       break;
00780     case Qtx::PT_Directory:
00781       ok = aFI.isDir();
00782       if ( !ok && msg )
00783         QMessageBox::warning( this, tr( "Error" ), tr( "Location \"%1\" doesn't point to directory" ).arg( str ) );
00784       break;
00785     }
00786   }
00787 
00788   return ok;
00789 }
00790 
00799 bool QtxPathListEdit::checkDuplicate( const QString& str, const int row, const bool msg )
00800 {
00801   int cur = -1;
00802   QStringList lst = myModel->stringList();
00803   for ( int r = 0; r < lst.count() && cur == -1; r++ )
00804   {
00805     if ( r != row && lst.at( r ) == str )
00806       cur = r;
00807   }
00808 
00809   if ( cur != -1 && msg )
00810     QMessageBox::warning( this, tr( "Error" ), tr( "Path \"%1\" already exist in the list" ).arg( str ) );
00811    
00812   return cur == -1;
00813 }