mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-24 10:52:49 +00:00
666 lines
18 KiB
C++
666 lines
18 KiB
C++
/* This file is part of the KDE libraries
|
|
Copyright (C) 2000 David Faure <faure@kde.org>, Alexander Neundorf <neundorf@kde.org>
|
|
(C) 2000, 2002 Carsten Pfeiffer <pfeiffer@kde.org>
|
|
(C) 2010 Sebastian Trueg <trueg@kde.org>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "keditlistwidget.h"
|
|
|
|
#include <QtCore/QStringList>
|
|
#include <QtGui/qevent.h>
|
|
#include <QtGui/QLabel>
|
|
#include <QtGui/QLayout>
|
|
#include <QtGui/QListView>
|
|
|
|
#include <kcombobox.h>
|
|
#include <kdebug.h>
|
|
#include <kdialog.h>
|
|
#include <klineedit.h>
|
|
#include <klocale.h>
|
|
#include <knotification.h>
|
|
#include <kpushbutton.h>
|
|
|
|
#include <assert.h>
|
|
|
|
class KEditListWidgetPrivate
|
|
{
|
|
public:
|
|
KEditListWidgetPrivate( KEditListWidget* parent )
|
|
: lineEdit(0),
|
|
editingWidget(0),
|
|
q(parent) {
|
|
}
|
|
QListView *listView;
|
|
QPushButton *servUpButton, *servDownButton;
|
|
QPushButton *servNewButton, *servRemoveButton;
|
|
KLineEdit *lineEdit;
|
|
QWidget* editingWidget;
|
|
QVBoxLayout* mainLayout;
|
|
QVBoxLayout* btnsLayout;
|
|
QStringListModel *model;
|
|
|
|
bool checkAtEntering;
|
|
KEditListWidget::Buttons buttons;
|
|
|
|
void init( bool check = false, KEditListWidget::Buttons buttons = KEditListWidget::All,
|
|
QWidget *representationWidget = 0 );
|
|
void setEditor( KLineEdit* lineEdit, QWidget* representationWidget = 0 );
|
|
void updateButtonState();
|
|
QModelIndex selectedIndex();
|
|
|
|
private:
|
|
KEditListWidget* q;
|
|
};
|
|
|
|
|
|
void KEditListWidgetPrivate::init( bool check, KEditListWidget::Buttons newButtons,
|
|
QWidget *representationWidget )
|
|
{
|
|
checkAtEntering = check;
|
|
|
|
servNewButton = servRemoveButton = servUpButton = servDownButton = 0L;
|
|
q->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding,
|
|
QSizePolicy::Preferred));
|
|
|
|
mainLayout = new QVBoxLayout(q);
|
|
|
|
QHBoxLayout* subLayout = new QHBoxLayout;
|
|
btnsLayout = new QVBoxLayout;
|
|
btnsLayout->addStretch();
|
|
|
|
model = new QStringListModel();
|
|
listView = new QListView(q);
|
|
listView->setModel(model);
|
|
|
|
subLayout->addWidget(listView);
|
|
subLayout->addLayout(btnsLayout);
|
|
|
|
mainLayout->insertLayout(1, subLayout);
|
|
|
|
setEditor( lineEdit, representationWidget );
|
|
|
|
buttons = 0;
|
|
q->setButtons( newButtons );
|
|
|
|
q->connect(listView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
|
SLOT(slotSelectionChanged(QItemSelection,QItemSelection)));
|
|
}
|
|
|
|
|
|
void KEditListWidgetPrivate::setEditor( KLineEdit* newLineEdit, QWidget* representationWidget )
|
|
{
|
|
if (editingWidget != lineEdit &&
|
|
editingWidget != representationWidget) {
|
|
delete editingWidget;
|
|
}
|
|
if (lineEdit != newLineEdit) {
|
|
delete lineEdit;
|
|
}
|
|
lineEdit = newLineEdit ? newLineEdit : new KLineEdit(q);
|
|
editingWidget = representationWidget ?
|
|
representationWidget : lineEdit;
|
|
|
|
if ( representationWidget )
|
|
representationWidget->setParent(q);
|
|
|
|
mainLayout->insertWidget(0,editingWidget);
|
|
|
|
lineEdit->setTrapReturnKey(true);
|
|
lineEdit->installEventFilter(q);
|
|
|
|
q->connect(lineEdit,SIGNAL(textChanged(QString)),SLOT(typedSomething(QString)));
|
|
q->connect(lineEdit,SIGNAL(returnPressed()),SLOT(addItem()));
|
|
|
|
// maybe supplied lineedit has some text already
|
|
q->typedSomething( lineEdit->text() );
|
|
|
|
|
|
// fix tab ordering
|
|
q->setTabOrder(editingWidget, listView);
|
|
QWidget* w = listView;
|
|
if (servNewButton) {
|
|
q->setTabOrder(w,servNewButton);
|
|
w = servNewButton;
|
|
}
|
|
if (servRemoveButton) {
|
|
q->setTabOrder(w,servRemoveButton);
|
|
w = servRemoveButton;
|
|
}
|
|
if (servUpButton) {
|
|
q->setTabOrder(w,servUpButton);
|
|
w = servUpButton;
|
|
}
|
|
if (servDownButton) {
|
|
q->setTabOrder(w,servDownButton);
|
|
w = servDownButton;
|
|
}
|
|
}
|
|
|
|
|
|
void KEditListWidgetPrivate::updateButtonState()
|
|
{
|
|
QModelIndex index = selectedIndex();
|
|
if (servUpButton) {
|
|
servUpButton->setEnabled(index.isValid());
|
|
}
|
|
if (servDownButton) {
|
|
servDownButton->setEnabled(index.isValid());
|
|
}
|
|
if (servRemoveButton) {
|
|
servRemoveButton->setEnabled(index.isValid());
|
|
}
|
|
}
|
|
|
|
QModelIndex KEditListWidgetPrivate::selectedIndex()
|
|
{
|
|
QItemSelectionModel *selection = listView->selectionModel();
|
|
const QModelIndexList selectedIndexes = selection->selectedIndexes();
|
|
if ( !selectedIndexes.isEmpty() && selectedIndexes[0].isValid() )
|
|
return selectedIndexes[0];
|
|
else
|
|
return QModelIndex();
|
|
}
|
|
|
|
|
|
class KEditListWidget::CustomEditorPrivate
|
|
{
|
|
public:
|
|
CustomEditorPrivate(KEditListWidget::CustomEditor *q):
|
|
q(q),
|
|
representationWidget(0),
|
|
lineEdit(0) {}
|
|
|
|
KEditListWidget::CustomEditor *q;
|
|
QWidget *representationWidget;
|
|
KLineEdit *lineEdit;
|
|
};
|
|
|
|
KEditListWidget::CustomEditor::CustomEditor()
|
|
: d(new CustomEditorPrivate(this))
|
|
{
|
|
}
|
|
|
|
KEditListWidget::CustomEditor::CustomEditor( QWidget *repWidget, KLineEdit *edit )
|
|
: d(new CustomEditorPrivate(this))
|
|
{
|
|
d->representationWidget = repWidget;
|
|
d->lineEdit = edit;
|
|
}
|
|
|
|
KEditListWidget::CustomEditor::CustomEditor( KComboBox *combo )
|
|
: d(new CustomEditorPrivate(this))
|
|
{
|
|
d->representationWidget = combo;
|
|
d->lineEdit = qobject_cast<KLineEdit*>( combo->lineEdit() );
|
|
Q_ASSERT( d->lineEdit );
|
|
}
|
|
|
|
KEditListWidget::CustomEditor::~CustomEditor()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
void KEditListWidget::CustomEditor::setRepresentationWidget( QWidget *repWidget )
|
|
{
|
|
d->representationWidget = repWidget;
|
|
}
|
|
|
|
void KEditListWidget::CustomEditor::setLineEdit( KLineEdit *edit )
|
|
{
|
|
d->lineEdit = edit;
|
|
}
|
|
|
|
QWidget *KEditListWidget::CustomEditor::representationWidget() const
|
|
{
|
|
return d->representationWidget;
|
|
}
|
|
|
|
KLineEdit *KEditListWidget::CustomEditor::lineEdit() const
|
|
{
|
|
return d->lineEdit;
|
|
}
|
|
|
|
KEditListWidget::KEditListWidget(QWidget *parent)
|
|
: QWidget(parent), d(new KEditListWidgetPrivate(this))
|
|
{
|
|
d->init();
|
|
}
|
|
|
|
KEditListWidget::KEditListWidget(const CustomEditor& custom,
|
|
QWidget *parent,
|
|
bool checkAtEntering,
|
|
Buttons buttons)
|
|
:QWidget(parent), d(new KEditListWidgetPrivate(this))
|
|
{
|
|
d->lineEdit = custom.lineEdit();
|
|
d->init( checkAtEntering, buttons, custom.representationWidget() );
|
|
}
|
|
|
|
KEditListWidget::~KEditListWidget()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
void KEditListWidget::setCustomEditor( const CustomEditor& editor )
|
|
{
|
|
d->setEditor( editor.lineEdit(), editor.representationWidget() );
|
|
}
|
|
|
|
QListView *KEditListWidget::listView() const
|
|
{
|
|
return d->listView;
|
|
}
|
|
|
|
KLineEdit *KEditListWidget::lineEdit() const
|
|
{
|
|
return d->lineEdit;
|
|
}
|
|
|
|
QPushButton *KEditListWidget::addButton() const
|
|
{
|
|
return d->servNewButton;
|
|
}
|
|
|
|
QPushButton *KEditListWidget::removeButton() const
|
|
{
|
|
return d->servRemoveButton;
|
|
}
|
|
|
|
QPushButton *KEditListWidget::upButton() const
|
|
{
|
|
return d->servUpButton;
|
|
}
|
|
|
|
QPushButton *KEditListWidget::downButton() const
|
|
{
|
|
return d->servDownButton;
|
|
}
|
|
|
|
int KEditListWidget::count() const
|
|
{
|
|
return int(d->model->rowCount());
|
|
}
|
|
|
|
void KEditListWidget::setButtons( Buttons buttons )
|
|
{
|
|
if ( d->buttons == buttons )
|
|
return;
|
|
|
|
if ( ( buttons & Add ) && !d->servNewButton ) {
|
|
d->servNewButton = new KPushButton(KIcon("list-add"), i18n("&Add"), this);
|
|
d->servNewButton->setEnabled(false);
|
|
d->servNewButton->show();
|
|
connect(d->servNewButton, SIGNAL(clicked()), SLOT(addItem()));
|
|
|
|
d->btnsLayout->insertWidget(0, d->servNewButton);
|
|
} else if ( ( buttons & Add ) == 0 && d->servNewButton ) {
|
|
delete d->servNewButton;
|
|
d->servNewButton = 0;
|
|
}
|
|
|
|
if ( ( buttons & Remove ) && !d->servRemoveButton ) {
|
|
d->servRemoveButton = new KPushButton(KIcon("list-remove"), i18n("&Remove"), this);
|
|
d->servRemoveButton->setEnabled(false);
|
|
d->servRemoveButton->show();
|
|
connect(d->servRemoveButton, SIGNAL(clicked()), SLOT(removeItem()));
|
|
|
|
d->btnsLayout->insertWidget(1, d->servRemoveButton);
|
|
} else if ( ( buttons & Remove ) == 0 && d->servRemoveButton ) {
|
|
delete d->servRemoveButton;
|
|
d->servRemoveButton = 0;
|
|
}
|
|
|
|
if ( ( buttons & UpDown ) && !d->servUpButton ) {
|
|
d->servUpButton = new KPushButton(KIcon("arrow-up"), i18n("Move &Up"), this);
|
|
d->servUpButton->setEnabled(false);
|
|
d->servUpButton->show();
|
|
connect(d->servUpButton, SIGNAL(clicked()), SLOT(moveItemUp()));
|
|
|
|
d->servDownButton = new KPushButton(KIcon("arrow-down"), i18n("Move &Down"), this);
|
|
d->servDownButton->setEnabled(false);
|
|
d->servDownButton->show();
|
|
connect(d->servDownButton, SIGNAL(clicked()), SLOT(moveItemDown()));
|
|
|
|
d->btnsLayout->insertWidget(2, d->servUpButton);
|
|
d->btnsLayout->insertWidget(3, d->servDownButton);
|
|
} else if ( ( buttons & UpDown ) == 0 && d->servUpButton ) {
|
|
delete d->servUpButton; d->servUpButton = 0;
|
|
delete d->servDownButton; d->servDownButton = 0;
|
|
}
|
|
|
|
d->buttons = buttons;
|
|
}
|
|
|
|
void KEditListWidget::setCheckAtEntering(bool check)
|
|
{
|
|
d->checkAtEntering = check;
|
|
}
|
|
|
|
bool KEditListWidget::checkAtEntering()
|
|
{
|
|
return d->checkAtEntering;
|
|
}
|
|
|
|
void KEditListWidget::typedSomething(const QString& text)
|
|
{
|
|
if(currentItem() >= 0) {
|
|
if(currentText() != d->lineEdit->text())
|
|
{
|
|
// IMHO changeItem() shouldn't do anything with the value
|
|
// of currentItem() ... like changing it or emitting signals ...
|
|
// but TT disagree with me on this one (it's been that way since ages ... grrr)
|
|
bool block = d->listView->signalsBlocked();
|
|
d->listView->blockSignals( true );
|
|
QModelIndex currentIndex = d->selectedIndex();
|
|
if ( currentIndex.isValid() )
|
|
d->model->setData(currentIndex,text);
|
|
d->listView->blockSignals( block );
|
|
emit changed();
|
|
}
|
|
}
|
|
|
|
if ( !d->servNewButton )
|
|
return;
|
|
|
|
if ( !d->lineEdit->hasAcceptableInput() ) {
|
|
d->servNewButton->setEnabled(false);
|
|
return;
|
|
}
|
|
|
|
if (!d->checkAtEntering)
|
|
d->servNewButton->setEnabled(!text.isEmpty());
|
|
else
|
|
{
|
|
if (text.isEmpty())
|
|
{
|
|
d->servNewButton->setEnabled(false);
|
|
}
|
|
else
|
|
{
|
|
QStringList list = d->model->stringList();
|
|
bool enable = !list.contains( text, Qt::CaseSensitive );
|
|
d->servNewButton->setEnabled( enable );
|
|
}
|
|
}
|
|
}
|
|
|
|
void KEditListWidget::moveItemUp()
|
|
{
|
|
if (!d->listView->isEnabled())
|
|
{
|
|
KNotification::beep();
|
|
return;
|
|
}
|
|
|
|
QModelIndex index = d->selectedIndex();
|
|
if ( index.isValid() ) {
|
|
if (index.row() == 0) {
|
|
KNotification::beep();
|
|
return;
|
|
}
|
|
|
|
QModelIndex aboveIndex = d->model->index( index.row() - 1, index.column() );
|
|
|
|
QString tmp = d->model->data( aboveIndex, Qt::DisplayRole ).toString();
|
|
d->model->setData( aboveIndex, d->model->data( index, Qt::DisplayRole ) );
|
|
d->model->setData( index, tmp );
|
|
|
|
d->listView->selectionModel()->select(index, QItemSelectionModel::Deselect);
|
|
d->listView->selectionModel()->select(aboveIndex, QItemSelectionModel::Select);
|
|
}
|
|
|
|
emit changed();
|
|
}
|
|
|
|
void KEditListWidget::moveItemDown()
|
|
{
|
|
if (!d->listView->isEnabled())
|
|
{
|
|
KNotification::beep();
|
|
return;
|
|
}
|
|
|
|
QModelIndex index = d->selectedIndex();
|
|
if ( index.isValid() ) {
|
|
if (index.row() == d->model->rowCount() - 1) {
|
|
KNotification::beep();
|
|
return;
|
|
}
|
|
|
|
QModelIndex belowIndex = d->model->index( index.row() + 1, index.column() );
|
|
|
|
QString tmp = d->model->data( belowIndex, Qt::DisplayRole ).toString();
|
|
d->model->setData( belowIndex, d->model->data( index, Qt::DisplayRole ) );
|
|
d->model->setData( index, tmp );
|
|
|
|
d->listView->selectionModel()->select(index, QItemSelectionModel::Deselect);
|
|
d->listView->selectionModel()->select(belowIndex, QItemSelectionModel::Select);
|
|
}
|
|
|
|
emit changed();
|
|
}
|
|
|
|
void KEditListWidget::addItem()
|
|
{
|
|
// when checkAtEntering is true, the add-button is disabled, but this
|
|
// slot can still be called through Key_Return/Key_Enter. So we guard
|
|
// against this.
|
|
if ( !d->servNewButton || !d->servNewButton->isEnabled() )
|
|
return;
|
|
|
|
QModelIndex currentIndex = d->selectedIndex();
|
|
|
|
const QString& currentTextLE=d->lineEdit->text();
|
|
bool alreadyInList(false);
|
|
//if we didn't check for dupes at the inserting we have to do it now
|
|
if (!d->checkAtEntering)
|
|
{
|
|
// first check current item instead of dumb iterating the entire list
|
|
if ( currentIndex.isValid() ) {
|
|
if ( d->model->data( currentIndex, Qt::DisplayRole ).toString() == currentTextLE )
|
|
alreadyInList = true;
|
|
}
|
|
else
|
|
{
|
|
alreadyInList = d->model->stringList().contains( currentTextLE, Qt::CaseSensitive );
|
|
}
|
|
}
|
|
if ( d->servNewButton )
|
|
d->servNewButton->setEnabled(false);
|
|
|
|
bool block = d->lineEdit->signalsBlocked();
|
|
d->lineEdit->blockSignals(true);
|
|
d->lineEdit->clear();
|
|
d->lineEdit->blockSignals(block);
|
|
|
|
d->listView->selectionModel()->setCurrentIndex(currentIndex, QItemSelectionModel::Deselect);
|
|
|
|
if (!alreadyInList)
|
|
{
|
|
block = d->listView->signalsBlocked();
|
|
|
|
if ( currentIndex.isValid() ) {
|
|
d->model->setData(currentIndex, currentTextLE );
|
|
} else {
|
|
QStringList lst;
|
|
lst<<currentTextLE;
|
|
lst<<d->model->stringList();
|
|
d->model->setStringList(lst);
|
|
}
|
|
emit changed();
|
|
emit added( currentTextLE ); // TODO: pass the index too
|
|
}
|
|
|
|
d->updateButtonState();
|
|
}
|
|
|
|
int KEditListWidget::currentItem() const
|
|
{
|
|
QModelIndex selectedIndex = d->selectedIndex();
|
|
if ( selectedIndex.isValid() )
|
|
return selectedIndex.row();
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
void KEditListWidget::removeItem()
|
|
{
|
|
QModelIndex currentIndex = d->selectedIndex();
|
|
if ( !currentIndex.isValid() )
|
|
return;
|
|
|
|
if ( currentIndex.row() >= 0 )
|
|
{
|
|
QString removedText = d->model->data( currentIndex, Qt::DisplayRole ).toString();
|
|
|
|
d->model->removeRows( currentIndex.row(), 1 );
|
|
|
|
d->listView->selectionModel()->clear();
|
|
|
|
emit changed();
|
|
|
|
emit removed( removedText );
|
|
}
|
|
|
|
d->updateButtonState();
|
|
}
|
|
|
|
void KEditListWidget::enableMoveButtons(const QModelIndex &newIndex, const QModelIndex&)
|
|
{
|
|
int index = newIndex.row();
|
|
|
|
// Update the lineEdit when we select a different line.
|
|
if(currentText() != d->lineEdit->text())
|
|
d->lineEdit->setText(currentText());
|
|
|
|
bool moveEnabled = d->servUpButton && d->servDownButton;
|
|
|
|
if (moveEnabled )
|
|
{
|
|
if (d->model->rowCount() <= 1)
|
|
{
|
|
d->servUpButton->setEnabled(false);
|
|
d->servDownButton->setEnabled(false);
|
|
}
|
|
else if (index == (d->model->rowCount() - 1))
|
|
{
|
|
d->servUpButton->setEnabled(true);
|
|
d->servDownButton->setEnabled(false);
|
|
}
|
|
else if (index == 0)
|
|
{
|
|
d->servUpButton->setEnabled(false);
|
|
d->servDownButton->setEnabled(true);
|
|
}
|
|
else
|
|
{
|
|
d->servUpButton->setEnabled(true);
|
|
d->servDownButton->setEnabled(true);
|
|
}
|
|
}
|
|
|
|
if ( d->servRemoveButton )
|
|
d->servRemoveButton->setEnabled(true);
|
|
}
|
|
|
|
void KEditListWidget::clear()
|
|
{
|
|
d->lineEdit->clear();
|
|
d->model->setStringList( QStringList() );
|
|
emit changed();
|
|
}
|
|
|
|
void KEditListWidget::insertStringList(const QStringList& list, int index)
|
|
{
|
|
QStringList content = d->model->stringList();
|
|
if ( index < 0 )
|
|
content += list;
|
|
else
|
|
for ( int i = 0, j = index; i < list.count(); ++i, ++j )
|
|
content.insert( j, list[ i ] );
|
|
|
|
d->model->setStringList( content );
|
|
}
|
|
|
|
void KEditListWidget::insertItem(const QString& text, int index)
|
|
{
|
|
QStringList list = d->model->stringList();
|
|
|
|
if ( index < 0 )
|
|
list.append( text );
|
|
else
|
|
list.insert( index, text );
|
|
|
|
d->model->setStringList(list);
|
|
}
|
|
|
|
QString KEditListWidget::text(int index) const
|
|
{
|
|
const QStringList list = d->model->stringList();
|
|
|
|
return list[ index ];
|
|
}
|
|
|
|
QString KEditListWidget::currentText() const
|
|
{
|
|
QModelIndex index = d->selectedIndex();
|
|
if ( !index.isValid() )
|
|
return QString();
|
|
else
|
|
return text( index.row() );
|
|
}
|
|
|
|
QStringList KEditListWidget::items() const
|
|
{
|
|
return d->model->stringList();
|
|
}
|
|
|
|
void KEditListWidget::setItems(const QStringList& items)
|
|
{
|
|
d->model->setStringList(items);
|
|
}
|
|
|
|
KEditListWidget::Buttons KEditListWidget::buttons() const
|
|
{
|
|
return d->buttons;
|
|
}
|
|
|
|
void KEditListWidget::slotSelectionChanged( const QItemSelection&, const QItemSelection& )
|
|
{
|
|
d->updateButtonState();
|
|
QModelIndex index = d->selectedIndex();
|
|
enableMoveButtons(index, QModelIndex());
|
|
if (index.isValid()) {
|
|
d->lineEdit->setFocus( Qt::OtherFocusReason );
|
|
}
|
|
}
|
|
|
|
bool KEditListWidget::eventFilter( QObject* o, QEvent* e )
|
|
{
|
|
if (o == d->lineEdit && e->type() == QEvent::KeyPress ) {
|
|
QKeyEvent* keyEvent = (QKeyEvent*)e;
|
|
if (keyEvent->key() == Qt::Key_Down ||
|
|
keyEvent->key() == Qt::Key_Up) {
|
|
return ((QObject*)d->listView)->event(e);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#include "moc_keditlistwidget.cpp"
|