keditlistbox.cpp

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 <qstringlist.h>
00022 #include <qpushbutton.h>
00023 #include <qlayout.h>
00024 #include <qgroupbox.h>
00025 #include <qlistbox.h>
00026 #include <qwhatsthis.h>
00027 #include <qlabel.h>
00028 
00029 #include <kcombobox.h>
00030 #include <kdebug.h>
00031 #include <kdialog.h>
00032 #include <klineedit.h>
00033 #include <klocale.h>
00034 #include <kapplication.h>
00035 #include <knotifyclient.h>
00036 
00037 #include "keditlistbox.h"
00038 
00039 #include <assert.h>
00040 
00041 class KEditListBoxPrivate
00042 {
00043 public:
00044     bool m_checkAtEntering;
00045     uint buttons;
00046 };
00047 
00048 KEditListBox::KEditListBox(QWidget *parent, const char *name,
00049                bool checkAtEntering, int buttons )
00050     :QGroupBox(parent, name ), d(new KEditListBoxPrivate)
00051 {
00052     init( checkAtEntering, buttons );
00053 }
00054 
00055 KEditListBox::KEditListBox(const QString& title, QWidget *parent,
00056                const char *name, bool checkAtEntering, int buttons)
00057     :QGroupBox(title, parent, name ), d(new KEditListBoxPrivate)
00058 {
00059     init( checkAtEntering, buttons );
00060 }
00061 
00062 KEditListBox::KEditListBox(const QString& title, const CustomEditor& custom,
00063                            QWidget *parent, const char *name,
00064                            bool checkAtEntering, int buttons)
00065     :QGroupBox(title, parent, name ), d(new KEditListBoxPrivate)
00066 {
00067     m_lineEdit = custom.lineEdit();
00068     init( checkAtEntering, buttons, custom.representationWidget() );
00069 }
00070 
00071 KEditListBox::~KEditListBox()
00072 {
00073     delete d;
00074 }
00075 
00076 void KEditListBox::init( bool checkAtEntering, int buttons,
00077                          QWidget *representationWidget )
00078 {
00079     d->m_checkAtEntering = checkAtEntering;
00080 
00081     servNewButton = servRemoveButton = servUpButton = servDownButton = 0L;
00082     setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding,
00083                               QSizePolicy::MinimumExpanding));
00084 
00085     QGridLayout * grid = new QGridLayout(this, 7, 2,
00086                                          KDialog::marginHint(),
00087                                          KDialog::spacingHint());
00088     grid->addRowSpacing(0, fontMetrics().lineSpacing());
00089     grid->setRowStretch( 6, 1 );
00090 
00091     grid->setMargin(15);
00092 
00093     if ( representationWidget )
00094         representationWidget->reparent( this, QPoint(0,0) );
00095     else
00096         m_lineEdit=new KLineEdit(this);
00097 
00098     m_listBox = new QListBox(this);
00099 
00100     QWidget *editingWidget = representationWidget ?
00101                              representationWidget : m_lineEdit;
00102     grid->addMultiCellWidget(editingWidget,1,1,0,1);
00103     grid->addMultiCellWidget(m_listBox, 2, 6, 0, 0);
00104 
00105     setButtons( buttons );
00106 
00107     connect(m_lineEdit,SIGNAL(textChanged(const QString&)),this,SLOT(typedSomething(const QString&)));
00108     m_lineEdit->setTrapReturnKey(true);
00109     connect(m_lineEdit,SIGNAL(returnPressed()),this,SLOT(addItem()));
00110     connect(m_listBox, SIGNAL(highlighted(int)), SLOT(enableMoveButtons(int)));
00111 
00112     // maybe supplied lineedit has some text already
00113     typedSomething( m_lineEdit->text() );
00114 }
00115 
00116 void KEditListBox::setButtons( uint buttons )
00117 {
00118     if ( d->buttons == buttons )
00119         return;
00120 
00121     QGridLayout* grid = static_cast<QGridLayout *>( layout() );
00122     if ( ( buttons & Add ) && !servNewButton ) {
00123         servNewButton = new QPushButton(i18n("&Add"), this);
00124         servNewButton->setEnabled(false);
00125         servNewButton->show();
00126         connect(servNewButton, SIGNAL(clicked()), SLOT(addItem()));
00127 
00128         grid->addWidget(servNewButton, 2, 1);
00129     } else if ( ( buttons & Add ) == 0 && servNewButton ) {
00130         delete servNewButton;
00131         servNewButton = 0;
00132     }
00133 
00134     if ( ( buttons & Remove ) && !servRemoveButton ) {
00135         servRemoveButton = new QPushButton(i18n("&Remove"), this);
00136         servRemoveButton->setEnabled(false);
00137         servRemoveButton->show();
00138         connect(servRemoveButton, SIGNAL(clicked()), SLOT(removeItem()));
00139 
00140         grid->addWidget(servRemoveButton, 3, 1);
00141     } else if ( ( buttons & Remove ) == 0 && servRemoveButton ) {
00142         delete servRemoveButton;
00143         servRemoveButton = 0;
00144     }
00145 
00146     if ( ( buttons & UpDown ) && !servUpButton ) {
00147         servUpButton = new QPushButton(i18n("Move &Up"), this);
00148         servUpButton->setEnabled(false);
00149         servUpButton->show();
00150         connect(servUpButton, SIGNAL(clicked()), SLOT(moveItemUp()));
00151 
00152         servDownButton = new QPushButton(i18n("Move &Down"), this);
00153         servDownButton->setEnabled(false);
00154         servDownButton->show();
00155         connect(servDownButton, SIGNAL(clicked()), SLOT(moveItemDown()));
00156 
00157         grid->addWidget(servUpButton, 4, 1);
00158         grid->addWidget(servDownButton, 5, 1);
00159     } else if ( ( buttons & UpDown ) == 0 && servUpButton ) {
00160         delete servUpButton; servUpButton = 0;
00161         delete servDownButton; servDownButton = 0;
00162     }
00163 
00164     d->buttons = buttons;
00165 }
00166 
00167 void KEditListBox::typedSomething(const QString& text)
00168 {
00169     if(currentItem() >= 0) {
00170         if(currentText() != m_lineEdit->text())
00171         {
00172             // IMHO changeItem() shouldn't do anything with the value
00173             // of currentItem() ... like changing it or emitting signals ...
00174             // but TT disagree with me on this one (it's been that way since ages ... grrr)
00175             bool block = m_listBox->signalsBlocked();
00176             m_listBox->blockSignals( true );
00177             m_listBox->changeItem(text, currentItem());
00178             m_listBox->blockSignals( block );
00179             emit changed();
00180         }
00181     }
00182 
00183     if ( !servNewButton )
00184         return;
00185 
00186     if (!d->m_checkAtEntering)
00187         servNewButton->setEnabled(!text.isEmpty());
00188     else
00189     {
00190         if (text.isEmpty())
00191         {
00192             servNewButton->setEnabled(false);
00193         }
00194         else
00195         {
00196             StringComparisonMode mode = (StringComparisonMode) (ExactMatch | CaseSensitive );
00197             bool enable = (!m_listBox->findItem( text, mode ));
00198             servNewButton->setEnabled( enable );
00199         }
00200     }
00201 }
00202 
00203 void KEditListBox::moveItemUp()
00204 {
00205     if (!m_listBox->isEnabled())
00206     {
00207         KNotifyClient::beep();
00208         return;
00209     }
00210 
00211     const unsigned int selIndex = m_listBox->currentItem();
00212     if (selIndex == 0)
00213     {
00214         KNotifyClient::beep();
00215         return;
00216     }
00217 
00218     QListBoxItem *selItem = m_listBox->item(selIndex);
00219     m_listBox->takeItem(selItem);
00220     m_listBox->insertItem(selItem, selIndex-1);
00221     m_listBox->setCurrentItem(selIndex - 1);
00222 
00223     emit changed();
00224 }
00225 
00226 void KEditListBox::moveItemDown()
00227 {
00228     if (!m_listBox->isEnabled())
00229     {
00230         KNotifyClient::beep();
00231         return;
00232     }
00233 
00234     unsigned int selIndex = m_listBox->currentItem();
00235     if (selIndex == m_listBox->count() - 1)
00236     {
00237         KNotifyClient::beep();
00238         return;
00239     }
00240 
00241     QListBoxItem *selItem = m_listBox->item(selIndex);
00242     m_listBox->takeItem(selItem);
00243     m_listBox->insertItem(selItem, selIndex+1);
00244     m_listBox->setCurrentItem(selIndex + 1);
00245 
00246     emit changed();
00247 }
00248 
00249 void KEditListBox::addItem()
00250 {
00251     // when m_checkAtEntering is true, the add-button is disabled, but this
00252     // slot can still be called through Key_Return/Key_Enter. So we guard
00253     // against this.
00254     if ( !servNewButton || !servNewButton->isEnabled() )
00255         return;
00256 
00257     const QString& currentTextLE=m_lineEdit->text();
00258     bool alreadyInList(false);
00259     //if we didn't check for dupes at the inserting we have to do it now
00260     if (!d->m_checkAtEntering)
00261     {
00262         // first check current item instead of dumb iterating the entire list
00263         if ( m_listBox->currentText() == currentTextLE )
00264             alreadyInList = true;
00265         else
00266         {
00267             StringComparisonMode mode = (StringComparisonMode) (ExactMatch | CaseSensitive );
00268             alreadyInList =(m_listBox->findItem(currentTextLE, mode) );
00269         }
00270     }
00271 
00272     if ( servNewButton )
00273         servNewButton->setEnabled(false);
00274 
00275     bool block = m_lineEdit->signalsBlocked();
00276     m_lineEdit->blockSignals(true);
00277     m_lineEdit->clear();
00278     m_lineEdit->blockSignals(block);
00279 
00280     m_listBox->setSelected(currentItem(), false);
00281 
00282     if (!alreadyInList)
00283     {
00284         block = m_listBox->signalsBlocked();
00285         m_listBox->blockSignals( true );
00286         m_listBox->insertItem(currentTextLE);
00287         m_listBox->blockSignals( block );
00288         emit changed();
00289     emit added( currentTextLE );
00290     }
00291 }
00292 
00293 int KEditListBox::currentItem() const
00294 {
00295     int nr = m_listBox->currentItem();
00296     if(nr >= 0 && !m_listBox->item(nr)->isSelected()) return -1;
00297     return nr;
00298 }
00299 
00300 void KEditListBox::removeItem()
00301 {
00302     int selected = m_listBox->currentItem();
00303 
00304     if ( selected >= 0 )
00305     {
00306     QString removedText = m_listBox->currentText();
00307 
00308         m_listBox->removeItem( selected );
00309         if ( count() > 0 )
00310             m_listBox->setSelected( QMIN( selected, count() - 1 ), true );
00311 
00312         emit changed();
00313     emit removed( removedText );
00314     }
00315 
00316     if ( servRemoveButton && m_listBox->currentItem() == -1 )
00317         servRemoveButton->setEnabled(false);
00318 }
00319 
00320 void KEditListBox::enableMoveButtons(int index)
00321 {
00322     // Update the lineEdit when we select a different line.
00323     if(currentText() != m_lineEdit->text())
00324         m_lineEdit->setText(currentText());
00325 
00326     bool moveEnabled = servUpButton && servDownButton;
00327 
00328     if (moveEnabled )
00329     {
00330         if (m_listBox->count() <= 1)
00331         {
00332             servUpButton->setEnabled(false);
00333             servDownButton->setEnabled(false);
00334         }
00335         else if ((uint) index == (m_listBox->count() - 1))
00336         {
00337             servUpButton->setEnabled(true);
00338             servDownButton->setEnabled(false);
00339         }
00340         else if (index == 0)
00341         {
00342             servUpButton->setEnabled(false);
00343             servDownButton->setEnabled(true);
00344         }
00345         else
00346         {
00347             servUpButton->setEnabled(true);
00348             servDownButton->setEnabled(true);
00349         }
00350     }
00351 
00352     if ( servRemoveButton )
00353         servRemoveButton->setEnabled(true);
00354 }
00355 
00356 void KEditListBox::clear()
00357 {
00358     m_lineEdit->clear();
00359     m_listBox->clear();
00360     emit changed();
00361 }
00362 
00363 void KEditListBox::insertStringList(const QStringList& list, int index)
00364 {
00365     m_listBox->insertStringList(list,index);
00366 }
00367 
00368 void KEditListBox::insertStrList(const QStrList* list, int index)
00369 {
00370     m_listBox->insertStrList(list,index);
00371 }
00372 
00373 void KEditListBox::insertStrList(const QStrList& list, int index)
00374 {
00375     m_listBox->insertStrList(list,index);
00376 }
00377 
00378 void KEditListBox::insertStrList(const char ** list, int numStrings, int index)
00379 {
00380     m_listBox->insertStrList(list,numStrings,index);
00381 }
00382 
00383 QStringList KEditListBox::items() const
00384 {
00385     QStringList list;
00386     for (QListBoxItem const * i = m_listBox->firstItem(); i != 0; i = i->next() )
00387     list.append( i->text());
00388 
00389     return list;
00390 }
00391 
00392 void KEditListBox::setItems(const QStringList& items)
00393 {
00394   m_listBox->clear();
00395   m_listBox->insertStringList(items, 0);
00396 }
00397 
00398 int KEditListBox::buttons() const
00399 {
00400   return d->buttons;
00401 }
00402 
00403 void KEditListBox::virtual_hook( int, void* )
00404 { /*BASE::virtual_hook( id, data );*/ }
00405 
00406 
00409 
00410 KEditListBox::CustomEditor::CustomEditor( KComboBox *combo )
00411 {
00412     m_representationWidget = combo;
00413     m_lineEdit = dynamic_cast<KLineEdit*>( combo->lineEdit() );
00414     assert( m_lineEdit );
00415 }
00416 
00417 #include "keditlistbox.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys