KDEUI
keditlistwidget.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2000 David Faure <faure@kde.org>, Alexander Neundorf <neundorf@kde.org> 00003 (C) 2000, 2002 Carsten Pfeiffer <pfeiffer@kde.org> 00004 (C) 2010 Sebastian Trueg <trueg@kde.org> 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License as published by the Free Software Foundation; either 00009 version 2 of the License, or (at your option) any later version. 00010 00011 This library is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 Library General Public License for more details. 00015 00016 You should have received a copy of the GNU Library General Public License 00017 along with this library; see the file COPYING.LIB. If not, write to 00018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 Boston, MA 02110-1301, USA. 00020 */ 00021 00022 #include "keditlistwidget.h" 00023 00024 #include <QtCore/QStringList> 00025 #include <QtGui/QKeyEvent> 00026 #include <QtGui/QLabel> 00027 #include <QtGui/QLayout> 00028 #include <QtGui/QListView> 00029 00030 #include <kcombobox.h> 00031 #include <kdebug.h> 00032 #include <kdialog.h> 00033 #include <klineedit.h> 00034 #include <klocale.h> 00035 #include <knotification.h> 00036 #include <kpushbutton.h> 00037 00038 #include <assert.h> 00039 00040 class KEditListWidgetPrivate 00041 { 00042 public: 00043 KEditListWidgetPrivate( KEditListWidget* parent ) 00044 : lineEdit(0), 00045 editingWidget(0), 00046 q(parent) { 00047 } 00048 QListView *listView; 00049 QPushButton *servUpButton, *servDownButton; 00050 QPushButton *servNewButton, *servRemoveButton; 00051 KLineEdit *lineEdit; 00052 QWidget* editingWidget; 00053 QVBoxLayout* mainLayout; 00054 QVBoxLayout* btnsLayout; 00055 QStringListModel *model; 00056 00057 bool checkAtEntering; 00058 KEditListWidget::Buttons buttons; 00059 00060 void init( bool check = false, KEditListWidget::Buttons buttons = KEditListWidget::All, 00061 QWidget *representationWidget = 0 ); 00062 void setEditor( KLineEdit* lineEdit, QWidget* representationWidget = 0 ); 00063 void updateButtonState(); 00064 QModelIndex selectedIndex(); 00065 00066 private: 00067 KEditListWidget* q; 00068 }; 00069 00070 00071 void KEditListWidgetPrivate::init( bool check, KEditListWidget::Buttons newButtons, 00072 QWidget *representationWidget ) 00073 { 00074 checkAtEntering = check; 00075 00076 servNewButton = servRemoveButton = servUpButton = servDownButton = 0L; 00077 q->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, 00078 QSizePolicy::Preferred)); 00079 00080 mainLayout = new QVBoxLayout(q); 00081 00082 QHBoxLayout* subLayout = new QHBoxLayout; 00083 btnsLayout = new QVBoxLayout; 00084 btnsLayout->addStretch(); 00085 00086 model = new QStringListModel(); 00087 listView = new QListView(q); 00088 listView->setModel(model); 00089 00090 subLayout->addWidget(listView); 00091 subLayout->addLayout(btnsLayout); 00092 00093 mainLayout->insertLayout(1, subLayout); 00094 00095 setEditor( lineEdit, representationWidget ); 00096 00097 buttons = 0; 00098 q->setButtons( newButtons ); 00099 00100 q->connect(listView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), 00101 SLOT(slotSelectionChanged(const QItemSelection&, const QItemSelection&))); 00102 } 00103 00104 00105 void KEditListWidgetPrivate::setEditor( KLineEdit* newLineEdit, QWidget* representationWidget ) 00106 { 00107 if (editingWidget != lineEdit && 00108 editingWidget != representationWidget) { 00109 delete editingWidget; 00110 } 00111 if (lineEdit != newLineEdit) { 00112 delete lineEdit; 00113 } 00114 lineEdit = newLineEdit ? newLineEdit : new KLineEdit(q); 00115 editingWidget = representationWidget ? 00116 representationWidget : lineEdit; 00117 00118 if ( representationWidget ) 00119 representationWidget->setParent(q); 00120 00121 mainLayout->insertWidget(0,editingWidget); 00122 00123 lineEdit->setTrapReturnKey(true); 00124 lineEdit->installEventFilter(q); 00125 00126 q->connect(lineEdit,SIGNAL(textChanged(const QString&)),SLOT(typedSomething(const QString&))); 00127 q->connect(lineEdit,SIGNAL(returnPressed()),SLOT(addItem())); 00128 00129 // maybe supplied lineedit has some text already 00130 q->typedSomething( lineEdit->text() ); 00131 00132 00133 // fix tab ordering 00134 q->setTabOrder(editingWidget, listView); 00135 QWidget* w = listView; 00136 if (servNewButton) { 00137 q->setTabOrder(w,servNewButton); 00138 w = servNewButton; 00139 } 00140 if (servRemoveButton) { 00141 q->setTabOrder(w,servRemoveButton); 00142 w = servRemoveButton; 00143 } 00144 if (servUpButton) { 00145 q->setTabOrder(w,servUpButton); 00146 w = servUpButton; 00147 } 00148 if (servDownButton) { 00149 q->setTabOrder(w,servDownButton); 00150 w = servDownButton; 00151 } 00152 } 00153 00154 00155 void KEditListWidgetPrivate::updateButtonState() 00156 { 00157 QModelIndex index = selectedIndex(); 00158 if (servUpButton) { 00159 servUpButton->setEnabled(index.isValid()); 00160 } 00161 if (servDownButton) { 00162 servDownButton->setEnabled(index.isValid()); 00163 } 00164 if (servRemoveButton) { 00165 servRemoveButton->setEnabled(index.isValid()); 00166 } 00167 } 00168 00169 QModelIndex KEditListWidgetPrivate::selectedIndex() 00170 { 00171 QItemSelectionModel *selection = listView->selectionModel(); 00172 const QModelIndexList selectedIndexes = selection->selectedIndexes(); 00173 if ( !selectedIndexes.isEmpty() && selectedIndexes[0].isValid() ) 00174 return selectedIndexes[0]; 00175 else 00176 return QModelIndex(); 00177 } 00178 00179 00180 class KEditListWidget::CustomEditorPrivate 00181 { 00182 public: 00183 CustomEditorPrivate(KEditListWidget::CustomEditor *q): 00184 q(q), 00185 representationWidget(0), 00186 lineEdit(0) {} 00187 00188 KEditListWidget::CustomEditor *q; 00189 QWidget *representationWidget; 00190 KLineEdit *lineEdit; 00191 }; 00192 00193 KEditListWidget::CustomEditor::CustomEditor() 00194 : d(new CustomEditorPrivate(this)) 00195 { 00196 } 00197 00198 KEditListWidget::CustomEditor::CustomEditor( QWidget *repWidget, KLineEdit *edit ) 00199 : d(new CustomEditorPrivate(this)) 00200 { 00201 d->representationWidget = repWidget; 00202 d->lineEdit = edit; 00203 } 00204 00205 KEditListWidget::CustomEditor::CustomEditor( KComboBox *combo ) 00206 : d(new CustomEditorPrivate(this)) 00207 { 00208 d->representationWidget = combo; 00209 d->lineEdit = qobject_cast<KLineEdit*>( combo->lineEdit() ); 00210 Q_ASSERT( d->lineEdit ); 00211 } 00212 00213 KEditListWidget::CustomEditor::~CustomEditor() 00214 { 00215 delete d; 00216 } 00217 00218 void KEditListWidget::CustomEditor::setRepresentationWidget( QWidget *repWidget ) 00219 { 00220 d->representationWidget = repWidget; 00221 } 00222 00223 void KEditListWidget::CustomEditor::setLineEdit( KLineEdit *edit ) 00224 { 00225 d->lineEdit = edit; 00226 } 00227 00228 QWidget *KEditListWidget::CustomEditor::representationWidget() const 00229 { 00230 return d->representationWidget; 00231 } 00232 00233 KLineEdit *KEditListWidget::CustomEditor::lineEdit() const 00234 { 00235 return d->lineEdit; 00236 } 00237 00238 KEditListWidget::KEditListWidget(QWidget *parent) 00239 : QWidget(parent), d(new KEditListWidgetPrivate(this)) 00240 { 00241 d->init(); 00242 } 00243 00244 KEditListWidget::KEditListWidget(const CustomEditor& custom, 00245 QWidget *parent, 00246 bool checkAtEntering, 00247 Buttons buttons) 00248 :QWidget(parent), d(new KEditListWidgetPrivate(this)) 00249 { 00250 d->lineEdit = custom.lineEdit(); 00251 d->init( checkAtEntering, buttons, custom.representationWidget() ); 00252 } 00253 00254 KEditListWidget::~KEditListWidget() 00255 { 00256 delete d; 00257 } 00258 00259 void KEditListWidget::setCustomEditor( const CustomEditor& editor ) 00260 { 00261 d->setEditor( editor.lineEdit(), editor.representationWidget() ); 00262 } 00263 00264 QListView *KEditListWidget::listView() const 00265 { 00266 return d->listView; 00267 } 00268 00269 KLineEdit *KEditListWidget::lineEdit() const 00270 { 00271 return d->lineEdit; 00272 } 00273 00274 QPushButton *KEditListWidget::addButton() const 00275 { 00276 return d->servNewButton; 00277 } 00278 00279 QPushButton *KEditListWidget::removeButton() const 00280 { 00281 return d->servRemoveButton; 00282 } 00283 00284 QPushButton *KEditListWidget::upButton() const 00285 { 00286 return d->servUpButton; 00287 } 00288 00289 QPushButton *KEditListWidget::downButton() const 00290 { 00291 return d->servDownButton; 00292 } 00293 00294 int KEditListWidget::count() const 00295 { 00296 return int(d->model->rowCount()); 00297 } 00298 00299 void KEditListWidget::setButtons( Buttons buttons ) 00300 { 00301 if ( d->buttons == buttons ) 00302 return; 00303 00304 if ( ( buttons & Add ) && !d->servNewButton ) { 00305 d->servNewButton = new KPushButton(KIcon("list-add"), i18n("&Add"), this); 00306 d->servNewButton->setEnabled(false); 00307 d->servNewButton->show(); 00308 connect(d->servNewButton, SIGNAL(clicked()), SLOT(addItem())); 00309 00310 d->btnsLayout->insertWidget(0, d->servNewButton); 00311 } else if ( ( buttons & Add ) == 0 && d->servNewButton ) { 00312 delete d->servNewButton; 00313 d->servNewButton = 0; 00314 } 00315 00316 if ( ( buttons & Remove ) && !d->servRemoveButton ) { 00317 d->servRemoveButton = new KPushButton(KIcon("list-remove"), i18n("&Remove"), this); 00318 d->servRemoveButton->setEnabled(false); 00319 d->servRemoveButton->show(); 00320 connect(d->servRemoveButton, SIGNAL(clicked()), SLOT(removeItem())); 00321 00322 d->btnsLayout->insertWidget(1, d->servRemoveButton); 00323 } else if ( ( buttons & Remove ) == 0 && d->servRemoveButton ) { 00324 delete d->servRemoveButton; 00325 d->servRemoveButton = 0; 00326 } 00327 00328 if ( ( buttons & UpDown ) && !d->servUpButton ) { 00329 d->servUpButton = new KPushButton(KIcon("arrow-up"), i18n("Move &Up"), this); 00330 d->servUpButton->setEnabled(false); 00331 d->servUpButton->show(); 00332 connect(d->servUpButton, SIGNAL(clicked()), SLOT(moveItemUp())); 00333 00334 d->servDownButton = new KPushButton(KIcon("arrow-down"), i18n("Move &Down"), this); 00335 d->servDownButton->setEnabled(false); 00336 d->servDownButton->show(); 00337 connect(d->servDownButton, SIGNAL(clicked()), SLOT(moveItemDown())); 00338 00339 d->btnsLayout->insertWidget(2, d->servUpButton); 00340 d->btnsLayout->insertWidget(3, d->servDownButton); 00341 } else if ( ( buttons & UpDown ) == 0 && d->servUpButton ) { 00342 delete d->servUpButton; d->servUpButton = 0; 00343 delete d->servDownButton; d->servDownButton = 0; 00344 } 00345 00346 d->buttons = buttons; 00347 } 00348 00349 void KEditListWidget::setCheckAtEntering(bool check) 00350 { 00351 d->checkAtEntering = check; 00352 } 00353 00354 bool KEditListWidget::checkAtEntering() 00355 { 00356 return d->checkAtEntering; 00357 } 00358 00359 void KEditListWidget::typedSomething(const QString& text) 00360 { 00361 if(currentItem() >= 0) { 00362 if(currentText() != d->lineEdit->text()) 00363 { 00364 // IMHO changeItem() shouldn't do anything with the value 00365 // of currentItem() ... like changing it or emitting signals ... 00366 // but TT disagree with me on this one (it's been that way since ages ... grrr) 00367 bool block = d->listView->signalsBlocked(); 00368 d->listView->blockSignals( true ); 00369 QModelIndex currentIndex = d->selectedIndex(); 00370 if ( currentIndex.isValid() ) 00371 d->model->setData(currentIndex,text); 00372 d->listView->blockSignals( block ); 00373 emit changed(); 00374 } 00375 } 00376 00377 if ( !d->servNewButton ) 00378 return; 00379 00380 if ( !d->lineEdit->hasAcceptableInput() ) { 00381 d->servNewButton->setEnabled(false); 00382 return; 00383 } 00384 00385 if (!d->checkAtEntering) 00386 d->servNewButton->setEnabled(!text.isEmpty()); 00387 else 00388 { 00389 if (text.isEmpty()) 00390 { 00391 d->servNewButton->setEnabled(false); 00392 } 00393 else 00394 { 00395 QStringList list = d->model->stringList(); 00396 bool enable = !list.contains( text, Qt::CaseSensitive ); 00397 d->servNewButton->setEnabled( enable ); 00398 } 00399 } 00400 } 00401 00402 void KEditListWidget::moveItemUp() 00403 { 00404 if (!d->listView->isEnabled()) 00405 { 00406 KNotification::beep(); 00407 return; 00408 } 00409 00410 QModelIndex index = d->selectedIndex(); 00411 if ( index.isValid() ) { 00412 if (index.row() == 0) { 00413 KNotification::beep(); 00414 return; 00415 } 00416 00417 QModelIndex aboveIndex = d->model->index( index.row() - 1, index.column() ); 00418 00419 QString tmp = d->model->data( aboveIndex, Qt::DisplayRole ).toString(); 00420 d->model->setData( aboveIndex, d->model->data( index, Qt::DisplayRole ) ); 00421 d->model->setData( index, tmp ); 00422 00423 d->listView->selectionModel()->select(index, QItemSelectionModel::Deselect); 00424 d->listView->selectionModel()->select(aboveIndex, QItemSelectionModel::Select); 00425 } 00426 00427 emit changed(); 00428 } 00429 00430 void KEditListWidget::moveItemDown() 00431 { 00432 if (!d->listView->isEnabled()) 00433 { 00434 KNotification::beep(); 00435 return; 00436 } 00437 00438 QModelIndex index = d->selectedIndex(); 00439 if ( index.isValid() ) { 00440 if (index.row() == d->model->rowCount() - 1) { 00441 KNotification::beep(); 00442 return; 00443 } 00444 00445 QModelIndex belowIndex = d->model->index( index.row() + 1, index.column() ); 00446 00447 QString tmp = d->model->data( belowIndex, Qt::DisplayRole ).toString(); 00448 d->model->setData( belowIndex, d->model->data( index, Qt::DisplayRole ) ); 00449 d->model->setData( index, tmp ); 00450 00451 d->listView->selectionModel()->select(index, QItemSelectionModel::Deselect); 00452 d->listView->selectionModel()->select(belowIndex, QItemSelectionModel::Select); 00453 } 00454 00455 emit changed(); 00456 } 00457 00458 void KEditListWidget::addItem() 00459 { 00460 // when checkAtEntering is true, the add-button is disabled, but this 00461 // slot can still be called through Key_Return/Key_Enter. So we guard 00462 // against this. 00463 if ( !d->servNewButton || !d->servNewButton->isEnabled() ) 00464 return; 00465 00466 QModelIndex currentIndex = d->selectedIndex(); 00467 00468 const QString& currentTextLE=d->lineEdit->text(); 00469 bool alreadyInList(false); 00470 //if we didn't check for dupes at the inserting we have to do it now 00471 if (!d->checkAtEntering) 00472 { 00473 // first check current item instead of dumb iterating the entire list 00474 if ( currentIndex.isValid() ) { 00475 if ( d->model->data( currentIndex, Qt::DisplayRole ).toString() == currentTextLE ) 00476 alreadyInList = true; 00477 } 00478 else 00479 { 00480 alreadyInList = d->model->stringList().contains( currentTextLE, Qt::CaseSensitive ); 00481 } 00482 } 00483 if ( d->servNewButton ) 00484 d->servNewButton->setEnabled(false); 00485 00486 bool block = d->lineEdit->signalsBlocked(); 00487 d->lineEdit->blockSignals(true); 00488 d->lineEdit->clear(); 00489 d->lineEdit->blockSignals(block); 00490 00491 d->listView->selectionModel()->setCurrentIndex(currentIndex, QItemSelectionModel::Deselect); 00492 00493 if (!alreadyInList) 00494 { 00495 block = d->listView->signalsBlocked(); 00496 00497 if ( currentIndex.isValid() ) { 00498 d->model->setData(currentIndex, currentTextLE ); 00499 } else { 00500 QStringList lst; 00501 lst<<currentTextLE; 00502 lst<<d->model->stringList(); 00503 d->model->setStringList(lst); 00504 } 00505 emit changed(); 00506 emit added( currentTextLE ); // TODO: pass the index too 00507 } 00508 00509 d->updateButtonState(); 00510 } 00511 00512 int KEditListWidget::currentItem() const 00513 { 00514 QModelIndex selectedIndex = d->selectedIndex(); 00515 if ( selectedIndex.isValid() ) 00516 return selectedIndex.row(); 00517 else 00518 return -1; 00519 } 00520 00521 void KEditListWidget::removeItem() 00522 { 00523 QModelIndex currentIndex = d->selectedIndex(); 00524 if ( !currentIndex.isValid() ) 00525 return; 00526 00527 if ( currentIndex.row() >= 0 ) 00528 { 00529 QString removedText = d->model->data( currentIndex, Qt::DisplayRole ).toString(); 00530 00531 d->model->removeRows( currentIndex.row(), 1 ); 00532 00533 d->listView->selectionModel()->clear(); 00534 00535 emit changed(); 00536 00537 emit removed( removedText ); 00538 } 00539 00540 d->updateButtonState(); 00541 } 00542 00543 void KEditListWidget::enableMoveButtons(const QModelIndex &newIndex, const QModelIndex&) 00544 { 00545 int index = newIndex.row(); 00546 00547 // Update the lineEdit when we select a different line. 00548 if(currentText() != d->lineEdit->text()) 00549 d->lineEdit->setText(currentText()); 00550 00551 bool moveEnabled = d->servUpButton && d->servDownButton; 00552 00553 if (moveEnabled ) 00554 { 00555 if (d->model->rowCount() <= 1) 00556 { 00557 d->servUpButton->setEnabled(false); 00558 d->servDownButton->setEnabled(false); 00559 } 00560 else if (index == (d->model->rowCount() - 1)) 00561 { 00562 d->servUpButton->setEnabled(true); 00563 d->servDownButton->setEnabled(false); 00564 } 00565 else if (index == 0) 00566 { 00567 d->servUpButton->setEnabled(false); 00568 d->servDownButton->setEnabled(true); 00569 } 00570 else 00571 { 00572 d->servUpButton->setEnabled(true); 00573 d->servDownButton->setEnabled(true); 00574 } 00575 } 00576 00577 if ( d->servRemoveButton ) 00578 d->servRemoveButton->setEnabled(true); 00579 } 00580 00581 void KEditListWidget::clear() 00582 { 00583 d->lineEdit->clear(); 00584 d->model->setStringList( QStringList() ); 00585 emit changed(); 00586 } 00587 00588 void KEditListWidget::insertStringList(const QStringList& list, int index) 00589 { 00590 QStringList content = d->model->stringList(); 00591 if ( index < 0 ) 00592 content += list; 00593 else 00594 for ( int i = 0, j = index; i < list.count(); ++i, ++j ) 00595 content.insert( j, list[ i ] ); 00596 00597 d->model->setStringList( content ); 00598 } 00599 00600 void KEditListWidget::insertItem(const QString& text, int index) 00601 { 00602 QStringList list = d->model->stringList(); 00603 00604 if ( index < 0 ) 00605 list.append( text ); 00606 else 00607 list.insert( index, text ); 00608 00609 d->model->setStringList(list); 00610 } 00611 00612 QString KEditListWidget::text(int index) const 00613 { 00614 const QStringList list = d->model->stringList(); 00615 00616 return list[ index ]; 00617 } 00618 00619 QString KEditListWidget::currentText() const 00620 { 00621 QModelIndex index = d->selectedIndex(); 00622 if ( !index.isValid() ) 00623 return QString(); 00624 else 00625 return text( index.row() ); 00626 } 00627 00628 QStringList KEditListWidget::items() const 00629 { 00630 return d->model->stringList(); 00631 } 00632 00633 void KEditListWidget::setItems(const QStringList& items) 00634 { 00635 d->model->setStringList(items); 00636 } 00637 00638 KEditListWidget::Buttons KEditListWidget::buttons() const 00639 { 00640 return d->buttons; 00641 } 00642 00643 void KEditListWidget::slotSelectionChanged( const QItemSelection&, const QItemSelection& ) 00644 { 00645 d->updateButtonState(); 00646 QModelIndex index = d->selectedIndex(); 00647 enableMoveButtons(index, QModelIndex()); 00648 if (index.isValid()) { 00649 d->lineEdit->setFocus( Qt::OtherFocusReason ); 00650 } 00651 } 00652 00653 bool KEditListWidget::eventFilter( QObject* o, QEvent* e ) 00654 { 00655 if (o == d->lineEdit && e->type() == QEvent::KeyPress ) { 00656 QKeyEvent* keyEvent = (QKeyEvent*)e; 00657 if (keyEvent->key() == Qt::Key_Down || 00658 keyEvent->key() == Qt::Key_Up) { 00659 return ((QObject*)d->listView)->event(e); 00660 } 00661 } 00662 00663 return false; 00664 } 00665 00666 #include "keditlistwidget.moc"
KDE 4.6 API Reference