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