/****************************************************************************** * * Copyright 2008 Szymon Tomasz Stefanek * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *******************************************************************************/ #include "utils/configureaggregationsdialog.h" #include "utils/configureaggregationsdialog_p.h" #include "utils/aggregationeditor.h" #include "core/aggregation.h" #include "core/manager.h" #include #include #include #include #include #include #include #include namespace MessageList { namespace Utils { class AggregationListWidgetItem : public QListWidgetItem { private: Core::Aggregation * mAggregation; public: AggregationListWidgetItem( QListWidget * par, const Core::Aggregation &set ) : QListWidgetItem( set.name(), par ) { mAggregation = new Core::Aggregation( set ); } ~AggregationListWidgetItem() { delete mAggregation; } public: Core::Aggregation * aggregation() const { return mAggregation; } void forgetAggregation() { mAggregation = 0; } }; /** * The widget that lists the available Aggregations. * * At the moment of writing, derived from QListWidget only to override sizeHint(). */ class AggregationListWidget : public QListWidget { public: AggregationListWidget( QWidget * parent ) : QListWidget( parent ) { } public: // need a larger but shorter QListWidget QSize sizeHint() const { return QSize( 450, 128 ); } }; } // namespace Utils } // namespace MessageList using namespace MessageList::Core; using namespace MessageList::Utils; ConfigureAggregationsDialog::ConfigureAggregationsDialog( QWidget *parent ) : KDialog( parent ), d( new Private( this ) ) { setAttribute( Qt::WA_DeleteOnClose ); setWindowModality( Qt::ApplicationModal ); // FIXME: Sure ? setButtons( Ok | Cancel ); setWindowTitle( i18n( "Customize Message Aggregation Modes" ) ); QWidget * base = new QWidget( this ); setMainWidget( base ); QGridLayout * g = new QGridLayout( base ); d->mAggregationList = new AggregationListWidget( base ); d->mAggregationList->setSelectionMode(QAbstractItemView::ExtendedSelection); d->mAggregationList->setSortingEnabled( true ); g->addWidget( d->mAggregationList, 0, 0, 7, 1 ); connect( d->mAggregationList, SIGNAL(itemClicked(QListWidgetItem*)), SLOT(aggregationListItemClicked(QListWidgetItem*))); d->mNewAggregationButton = new QPushButton( i18n( "New Aggregation" ), base ); d->mNewAggregationButton->setIcon( KIcon( QLatin1String( "document-new" ) ) ); d->mNewAggregationButton->setIconSize( QSize( KIconLoader::SizeSmall, KIconLoader::SizeSmall ) ); g->addWidget( d->mNewAggregationButton, 0, 1 ); connect( d->mNewAggregationButton, SIGNAL(clicked()), SLOT(newAggregationButtonClicked()) ); d->mCloneAggregationButton = new QPushButton( i18n( "Clone Aggregation" ), base ); d->mCloneAggregationButton->setIcon( KIcon( QLatin1String( "edit-copy" ) ) ); d->mCloneAggregationButton->setIconSize( QSize( KIconLoader::SizeSmall, KIconLoader::SizeSmall ) ); g->addWidget( d->mCloneAggregationButton, 1, 1 ); connect( d->mCloneAggregationButton, SIGNAL(clicked()), SLOT(cloneAggregationButtonClicked()) ); QFrame * f = new QFrame( base ); f->setFrameStyle( QFrame::Sunken | QFrame::HLine ); f->setMinimumHeight( 24 ); g->addWidget( f, 2, 1, Qt::AlignVCenter ); d->mExportAggregationButton = new QPushButton( i18n( "Export Aggregation..." ), base ); g->addWidget( d->mExportAggregationButton, 3, 1 ); connect( d->mExportAggregationButton, SIGNAL(clicked()), SLOT(exportAggregationButtonClicked()) ); d->mImportAggregationButton = new QPushButton( i18n( "Import Aggregation..." ), base ); g->addWidget( d->mImportAggregationButton, 4, 1 ); connect( d->mImportAggregationButton, SIGNAL(clicked()), SLOT(importAggregationButtonClicked()) ); f = new QFrame( base ); f->setFrameStyle( QFrame::Sunken | QFrame::HLine ); f->setMinimumHeight( 24 ); g->addWidget( f, 5, 1, Qt::AlignVCenter ); d->mDeleteAggregationButton = new QPushButton( i18n( "Delete Aggregation" ), base ); d->mDeleteAggregationButton->setIcon( KIcon( QLatin1String( "edit-delete" ) ) ); d->mDeleteAggregationButton->setIconSize( QSize( KIconLoader::SizeSmall, KIconLoader::SizeSmall ) ); g->addWidget( d->mDeleteAggregationButton, 6, 1 ); connect( d->mDeleteAggregationButton, SIGNAL(clicked()), SLOT(deleteAggregationButtonClicked()) ); d->mEditor = new AggregationEditor( base ); g->addWidget( d->mEditor, 8, 0, 1, 2 ); connect( d->mEditor, SIGNAL(aggregationNameChanged()), SLOT(editedAggregationNameChanged()) ); g->setColumnStretch( 0, 1 ); g->setRowStretch( 7, 1 ); connect( this, SIGNAL(okClicked()), SLOT(okButtonClicked()) ); d->fillAggregationList(); } ConfigureAggregationsDialog::~ConfigureAggregationsDialog() { delete d; } void ConfigureAggregationsDialog::selectAggregation( const QString &aggregationId ) { AggregationListWidgetItem *item = d->findAggregationItemById( aggregationId ); if ( item ) { d->mAggregationList->setCurrentItem( item ); d->aggregationListItemClicked(item); } } void ConfigureAggregationsDialog::Private::okButtonClicked() { if (Manager::instance()) { commitEditor(); Manager::instance()->removeAllAggregations(); const int c = mAggregationList->count(); int i = 0; while ( i < c ) { AggregationListWidgetItem * item = dynamic_cast< AggregationListWidgetItem * >( mAggregationList->item( i ) ); if ( item ) { Manager::instance()->addAggregation( item->aggregation() ); item->forgetAggregation(); } ++i; } Manager::instance()->aggregationsConfigurationCompleted(); } q->close(); // this will delete too } void ConfigureAggregationsDialog::Private::commitEditor() { Aggregation * editedAggregation = mEditor->editedAggregation(); if ( !editedAggregation ) return; mEditor->commit(); AggregationListWidgetItem * editedItem = findAggregationItemByAggregation( editedAggregation ); if ( !editedItem ) return; const QString goodName = uniqueNameForAggregation( editedAggregation->name(), editedAggregation ); editedAggregation->setName( goodName ); editedItem->setText( goodName ); } void ConfigureAggregationsDialog::Private::editedAggregationNameChanged() { Aggregation * set = mEditor->editedAggregation(); if ( !set ) return; AggregationListWidgetItem * it = findAggregationItemByAggregation( set ); if ( !it ) return; const QString goodName = uniqueNameForAggregation( set->name(), set ); it->setText( goodName ); } void ConfigureAggregationsDialog::Private::fillAggregationList() { if (!Manager::instance()) return; const QHash< QString, Aggregation * > & sets = Manager::instance()->aggregations(); QHash< QString, Aggregation * >::ConstIterator end( sets.constEnd() ); for( QHash< QString, Aggregation * >::ConstIterator it = sets.constBegin(); it != end; ++it ) (void)new AggregationListWidgetItem( mAggregationList, *( *it ) ); } void ConfigureAggregationsDialog::Private::aggregationListItemClicked(QListWidgetItem* cur) { commitEditor(); updateButton(cur); } void ConfigureAggregationsDialog::Private::updateButton(QListWidgetItem* cur) { const int numberOfSelectedItem(mAggregationList->selectedItems().count()); AggregationListWidgetItem * item = cur ? dynamic_cast< AggregationListWidgetItem * >( cur ) : 0; mDeleteAggregationButton->setEnabled( item && !item->aggregation()->readOnly() && ( mAggregationList->count() > 1 ) ); mCloneAggregationButton->setEnabled( numberOfSelectedItem == 1 ); mExportAggregationButton->setEnabled( numberOfSelectedItem > 0 ); mEditor->editAggregation( item ? item->aggregation() : 0 ); if ( item && !item->isSelected() ) item->setSelected( true ); // make sure it's true } AggregationListWidgetItem * ConfigureAggregationsDialog::Private::findAggregationItemByName( const QString &name, Aggregation * skipAggregation ) { const int c = mAggregationList->count(); int i = 0; while ( i < c ) { AggregationListWidgetItem * item = dynamic_cast< AggregationListWidgetItem * >( mAggregationList->item( i ) ); if ( item ) { if ( item->aggregation() != skipAggregation ) { if ( item->aggregation()->name() == name ) return item; } } ++i; } return 0; } AggregationListWidgetItem * ConfigureAggregationsDialog::Private::findAggregationItemById( const QString &aggregationId ) { const int c = mAggregationList->count(); int i = 0; while ( i < c ) { AggregationListWidgetItem * item = dynamic_cast< AggregationListWidgetItem * >( mAggregationList->item( i ) ); if ( item ) { if ( item->aggregation()->id() == aggregationId ) return item; } ++i; } return 0; } AggregationListWidgetItem * ConfigureAggregationsDialog::Private::findAggregationItemByAggregation( Aggregation * set ) { const int c = mAggregationList->count(); int i = 0; while ( i < c ) { AggregationListWidgetItem * item = dynamic_cast< AggregationListWidgetItem * >( mAggregationList->item( i ) ); if ( item ) { if ( item->aggregation() == set ) return item; } ++i; } return 0; } QString ConfigureAggregationsDialog::Private::uniqueNameForAggregation( const QString& baseName, Aggregation * skipAggregation ) { QString ret = baseName; if( ret.isEmpty() ) ret = i18n( "Unnamed Aggregation" ); int idx = 1; AggregationListWidgetItem * item = findAggregationItemByName( ret, skipAggregation ); while ( item ) { idx++; ret = QString::fromLatin1( "%1 %2" ).arg( baseName ).arg( idx ); item = findAggregationItemByName( ret, skipAggregation ); } return ret; } void ConfigureAggregationsDialog::Private::newAggregationButtonClicked() { Aggregation emptyAggregation; emptyAggregation.setName( uniqueNameForAggregation( i18n( "New Aggregation" ) ) ); AggregationListWidgetItem * item = new AggregationListWidgetItem( mAggregationList, emptyAggregation ); mAggregationList->setCurrentItem( item ); mDeleteAggregationButton->setEnabled( item && !item->aggregation()->readOnly() ); } void ConfigureAggregationsDialog::Private::cloneAggregationButtonClicked() { AggregationListWidgetItem * item = dynamic_cast< AggregationListWidgetItem * >( mAggregationList->currentItem() ); if ( !item ) return; commitEditor(); item->setSelected(false); Aggregation copyAggregation( *( item->aggregation() ) ); copyAggregation.setReadOnly( false ); copyAggregation.generateUniqueId(); // regenerate id so it becomes different copyAggregation.setName( uniqueNameForAggregation( item->aggregation()->name() ) ); item = new AggregationListWidgetItem( mAggregationList, copyAggregation ); mAggregationList->setCurrentItem( item ); aggregationListItemClicked( item ); } void ConfigureAggregationsDialog::Private::deleteAggregationButtonClicked() { QList list = mAggregationList->selectedItems(); if(list.isEmpty()) { return; } mEditor->editAggregation( 0 ); // forget it Q_FOREACH(QListWidgetItem * it, list) { AggregationListWidgetItem * item = dynamic_cast< AggregationListWidgetItem * >( it ); if ( !item ) return; if(!item->aggregation()->readOnly()) { delete item; // this will trigger aggregationListCurrentItemChanged() } if ( mAggregationList->count() < 2 ) break; // no way: desperately try to keep at least one option set alive :) } AggregationListWidgetItem *newItem = dynamic_cast< AggregationListWidgetItem * >(mAggregationList->currentItem()); updateButton(newItem); } void ConfigureAggregationsDialog::Private::importAggregationButtonClicked() { const QString filename = KFileDialog::getOpenFileName(QString(),QString::fromLatin1("*"),q,i18n("Import Aggregation")); if(!filename.isEmpty()) { KConfig config(filename); if(config.hasGroup(QLatin1String("MessageListView::Aggregations"))) { KConfigGroup grp( &config, QLatin1String("MessageListView::Aggregations") ); const int cnt = grp.readEntry("Count",0); int idx = 0; while ( idx < cnt ) { const QString data = grp.readEntry( QString::fromLatin1( "Set%1" ).arg( idx ), QString() ); if ( !data.isEmpty() ) { Aggregation * set = new Aggregation(); if ( set->loadFromString( data ) ) { set->setReadOnly( false ); set->generateUniqueId(); // regenerate id so it becomes different set->setName( uniqueNameForAggregation( set->name() ) ); (void)new AggregationListWidgetItem( mAggregationList, *set ); } else { delete set; // b0rken } } ++idx; } } } } void ConfigureAggregationsDialog::Private::exportAggregationButtonClicked() { QList list = mAggregationList->selectedItems(); if(list.isEmpty()) { return; } const QString filename = KFileDialog::getSaveFileName(QString(),QString::fromLatin1("*"),q,i18n("Export Aggregation")); if(!filename.isEmpty()) { KConfig config(filename); KConfigGroup grp( &config, QLatin1String("MessageListView::Aggregations") ); grp.writeEntry( "Count", list.count() ); int idx = 0; Q_FOREACH(QListWidgetItem *item, list) { AggregationListWidgetItem * themeItem = static_cast< AggregationListWidgetItem * >( item ); grp.writeEntry( QString::fromLatin1( "Set%1" ).arg( idx ), themeItem->aggregation()->saveToString() ); ++idx; } } } #include "moc_configureaggregationsdialog.cpp"