/* Copyright (c) 2013 Montel Laurent This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation. 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 "searchdebugwidget.h" #include "sparqlsyntaxhighlighter.h" #include "searchdebugnepomukshowdialog.h" #include "util.h" #include "pimcommon/texteditor/plaintexteditor/plaintexteditorwidget.h" #include "pimcommon/texteditor/plaintexteditor/plaintexteditor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SearchResultListView::SearchResultListView(QWidget *parent) : QListView(parent) { } SearchResultListView::~SearchResultListView() { } void SearchResultListView::contextMenuEvent( QContextMenuEvent * event ) { const QModelIndex index = indexAt( event->pos() ); if (!index.isValid()) return; QMenu *popup = new QMenu(this); QAction *searchNepomukShow = new QAction(i18n("Search with nepomuk show..."), popup); popup->addAction(searchNepomukShow); QAction *act = popup->exec( event->globalPos() ); delete popup; if (act == searchNepomukShow) { const QString uid = QLatin1String("akonadi:?item=") + index.data( Qt::DisplayRole ).toString(); QPointer dlg = new SearchDebugNepomukShowDialog(uid, this); dlg->exec(); delete dlg; } } SearchDebugListDelegate::SearchDebugListDelegate( QObject *parent ) : QStyledItemDelegate ( parent ) { } SearchDebugListDelegate::~SearchDebugListDelegate() { } QWidget *SearchDebugListDelegate::createEditor( QWidget *, const QStyleOptionViewItem &, const QModelIndex & ) const { return 0; } SearchDebugWidget::SearchDebugWidget(const QString &query, QWidget *parent) : QWidget(parent) { QGridLayout *layout = new QGridLayout; mTextEdit = new PimCommon::PlainTextEditorWidget( this ); // we install an event filter to catch Ctrl+Return for quick query execution mTextEdit->installEventFilter( this ); indentQuery(query); new Nepomuk2::SparqlSyntaxHighlighter( mTextEdit->editor()->document() ); mResultView = new SearchResultListView; mResultView->setItemDelegate(new SearchDebugListDelegate(this)); mItemView = new PimCommon::PlainTextEditorWidget; mItemView->setReadOnly(true); layout->addWidget( mTextEdit, 0, 0, 1, 2); layout->addWidget( new QLabel( i18n("Akonadi Id:") ), 1, 0 ); layout->addWidget( new QLabel( i18n("Messages:") ), 1, 1 ); layout->addWidget( mResultView, 2, 0, 1, 1 ); layout->addWidget( mItemView, 2, 1, 1, 1 ); mReduceQuery = new QPushButton( i18n("Reduce query") ); connect(mReduceQuery, SIGNAL(clicked()), SLOT(slotReduceQuery())); mSearchButton = new QPushButton( i18n("Search") ); mSearchButton->setEnabled(false); connect( mSearchButton, SIGNAL(clicked()), this, SLOT(slotSearch()) ); mProgressIndicator = new KPIMUtils::ProgressIndicatorLabel(i18n("Searching...")); mResultLabel = new QLabel; layout->addWidget( mResultLabel, 3, 0, Qt::AlignLeft ); layout->addWidget( mProgressIndicator, 4, 0, Qt::AlignLeft ); layout->addWidget( mSearchButton, 4, 1, Qt::AlignRight ); layout->addWidget( mReduceQuery, 5, 1, Qt::AlignRight ); setLayout(layout); connect( mResultView, SIGNAL(activated(QModelIndex)), this, SLOT(slotFetchItem(QModelIndex)) ); connect(mTextEdit->editor(), SIGNAL(textChanged()), SLOT(slotUpdateSearchButton())); mResultModel = new QStringListModel( this ); mResultView->setModel( mResultModel ); slotSearch(); } SearchDebugWidget::~SearchDebugWidget() { } bool SearchDebugWidget::eventFilter( QObject *watched, QEvent *event ) { if( watched == mTextEdit && event->type() == QEvent::KeyPress ) { QKeyEvent* kev = static_cast(event); if( kev->key() == Qt::Key_Return && kev->modifiers() == Qt::ControlModifier ) { slotSearch(); return true; } } return QWidget::eventFilter( watched, event ); } void SearchDebugWidget::slotUpdateSearchButton() { mSearchButton->setEnabled(!mTextEdit->editor()->toPlainText().isEmpty()); } QString SearchDebugWidget::queryStr() const { return mTextEdit->editor()->toPlainText(); } void SearchDebugWidget::slotSearch() { const QString query = mTextEdit->editor()->toPlainText(); if (query.isEmpty()) { mResultLabel->setText(i18n("Query is empty.")); mSearchButton->setEnabled(false); mReduceQuery->setEnabled(false); return; } mResultModel->setStringList( QStringList() ); mItemView->editor()->clear(); mResultLabel->clear(); mProgressIndicator->start(); mSearchButton->setEnabled(false); mReduceQuery->setEnabled(false); Akonadi::ItemSearchJob *job = new Akonadi::ItemSearchJob( query ); connect( job, SIGNAL(result(KJob*)), this, SLOT(slotSearchFinished(KJob*)) ); } void SearchDebugWidget::indentQuery(QString query) { query = query.simplified(); QString newQuery; int i = 0; int indent = 0; const int space = 4; while(i < query.size()) { newQuery.append(query[i]); if (query[i] != QLatin1Char('"') && query[i] != QLatin1Char('<') && query[i] != QLatin1Char('\'')) { if (query[i] == QLatin1Char('{')) { ++indent; newQuery.append(QLatin1Char('\n')); newQuery.append(QString().fill(QLatin1Char(' '), indent*space)); } else if (query[i] == QLatin1Char('.')) { if(i+2') || query[i] == QLatin1Char('\'')) { newQuery.append(query[i]); break; } newQuery.append(query[i]); ++i; } } ++i; } mTextEdit->editor()->setPlainText( newQuery ); } void SearchDebugWidget::slotReduceQuery() { QString query = mTextEdit->editor()->toPlainText(); KMail::Util::reduceQuery(query); indentQuery(query); } void SearchDebugWidget::slotSearchFinished(KJob *job) { mProgressIndicator->stop(); mSearchButton->setEnabled(true); mReduceQuery->setEnabled(true); if ( job->error() ) { KMessageBox::error( this, job->errorString() ); return; } QStringList uidList; Akonadi::ItemSearchJob *searchJob = qobject_cast( job ); const Akonadi::Item::List items = searchJob->items(); Q_FOREACH ( const Akonadi::Item &item, items ) { uidList << QString::number( item.id() ); } mResultModel->setStringList( uidList ); if (uidList.isEmpty()) { mResultLabel->setText(i18n("No message found")); } else { mResultLabel->setText(i18np("1 message found", "%1 messages found", uidList.count())); } } void SearchDebugWidget::slotFetchItem( const QModelIndex &index ) { if ( !index.isValid() ) return; const QString uid = index.data( Qt::DisplayRole ).toString(); Akonadi::ItemFetchJob *fetchJob = new Akonadi::ItemFetchJob( Akonadi::Item( uid.toLongLong() ) ); fetchJob->fetchScope().fetchFullPayload(); connect( fetchJob, SIGNAL(result(KJob*)), this, SLOT(slotItemFetched(KJob*)) ); } void SearchDebugWidget::slotItemFetched( KJob *job ) { mItemView->editor()->clear(); if ( job->error() ) { KMessageBox::error( this, i18n("Error on fetching item") ); return; } Akonadi::ItemFetchJob *fetchJob = qobject_cast( job ); if ( !fetchJob->items().isEmpty() ) { const Akonadi::Item item = fetchJob->items().first(); mItemView->editor()->setPlainText( QString::fromUtf8( item.payloadData() ) ); } }