Simplify how Nepomuk comments can be edited by the user:

- don't provide any mode for editing, just let the user directly manipulate the comment inside the text widget
- automatically save changes, no explicit confirmation required

svn path=/trunk/KDE/kdebase/apps/; revision=984592
This commit is contained in:
Peter Penz 2009-06-21 08:16:03 +00:00
parent 356c81cbf8
commit 6e3e08e33c
7 changed files with 58 additions and 359 deletions

View file

@ -102,7 +102,6 @@ set(dolphin_SRCS
main.cpp
pixmapviewer.cpp
panels/information/commentwidget.cpp
panels/information/commenteditwidget.cpp
panels/information/informationpanel.cpp
panels/information/metadatawidget.cpp
panels/information/metatextlabel.cpp

View file

@ -1,241 +0,0 @@
/***************************************************************************
* Copyright (C) 2008 by Sebastian Trueg <trueg@kde.org> *
* *
* 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 "commenteditwidget.h"
#include <QtGui/QToolButton>
#include <QtGui/QVBoxLayout>
#include <QtCore/QEventLoop>
#include <QtCore/QPointer>
#include <QtGui/QApplication>
#include <QtGui/QDesktopWidget>
#include <QtGui/QMouseEvent>
#include <QtGui/QFont>
#include <KIcon>
#include <KDialog>
#include <KLocale>
#include <KDebug>
#include <KTextEdit>
class CommentEditWidget::Private
{
public:
Private( CommentEditWidget* parent )
: eventLoop( 0 ),
q( parent ) {
}
QEventLoop* eventLoop;
bool success;
KTextEdit* textEdit;
QToolButton* buttonSave;
QToolButton* buttonCancel;
QString comment;
QRect geometryForPopupPos( const QPoint& p ) {
QSize size = q->sizeHint();
// we want a little margin
const int margin = KDialog::marginHint();
size.setHeight( size.height() + margin*2 );
size.setWidth( size.width() + margin*2 );
QRect screen = QApplication::desktop()->screenGeometry( QApplication::desktop()->screenNumber( p ) );
// calculate popup position
QPoint pos( p.x() - size.width()/2, p.y() - size.height()/2 );
// ensure we do not leave the desktop
if ( pos.x() + size.width() > screen.right() ) {
pos.setX( screen.right() - size.width() );
}
else if ( pos.x() < screen.left() ) {
pos.setX( screen.left() );
}
if ( pos.y() + size.height() > screen.bottom() ) {
pos.setY( screen.bottom() - size.height() );
}
else if ( pos.y() < screen.top() ) {
pos.setY( screen.top() );
}
return QRect( pos, size );
}
void _k_saveClicked();
void _k_cancelClicked();
private:
CommentEditWidget* q;
};
void CommentEditWidget::Private::_k_saveClicked()
{
comment = textEdit->toPlainText();
success = true;
q->hide();
}
void CommentEditWidget::Private::_k_cancelClicked()
{
success = false;
q->hide();
}
CommentEditWidget::CommentEditWidget( QWidget* parent )
: QFrame( parent ),
d( new Private( this ) )
{
setFrameStyle( QFrame::StyledPanel );
setWindowFlags( Qt::Popup );
d->textEdit = new KTextEdit( this );
d->textEdit->installEventFilter( this );
QVBoxLayout* layout = new QVBoxLayout( this );
layout->setMargin( 0 );
layout->addWidget( d->textEdit );
d->buttonSave = new QToolButton( d->textEdit );
d->buttonCancel = new QToolButton( d->textEdit );
d->buttonSave->setToolButtonStyle( Qt::ToolButtonTextBesideIcon );
d->buttonCancel->setToolButtonStyle( Qt::ToolButtonTextBesideIcon );
d->buttonSave->setAutoRaise( true );
d->buttonCancel->setAutoRaise( true );
d->buttonSave->setIcon( KIcon( "document-save" ) );
d->buttonCancel->setIcon( KIcon( "edit-delete" ) );
d->buttonSave->setText( i18nc( "@action:button", "Save" ) );
d->buttonCancel->setText( i18nc( "@action:button", "Cancel" ) );
QFont fnt( font() );
fnt.setPointSize( fnt.pointSize()-2 );
d->buttonSave->setFont( fnt );
d->buttonCancel->setFont( fnt );
connect( d->buttonSave, SIGNAL(clicked()),
this, SLOT( _k_saveClicked() ) );
connect( d->buttonCancel, SIGNAL(clicked()),
this, SLOT( _k_cancelClicked() ) );
}
CommentEditWidget::~CommentEditWidget()
{
delete d;
}
void CommentEditWidget::setComment( const QString& s )
{
d->comment = s;
}
QString CommentEditWidget::comment()
{
return d->comment;
}
bool CommentEditWidget::exec( const QPoint& pos )
{
d->success = false;
d->textEdit->setPlainText( d->comment );
d->textEdit->setFocus();
d->textEdit->moveCursor( QTextCursor::End );
QEventLoop eventLoop;
d->eventLoop = &eventLoop;
setGeometry( d->geometryForPopupPos( pos ) );
show();
QPointer<QObject> guard = this;
(void) eventLoop.exec();
if ( !guard.isNull() )
d->eventLoop = 0;
return d->success;
}
void CommentEditWidget::mousePressEvent( QMouseEvent* e )
{
// clicking outside of the widget means cancel
if ( !rect().contains( e->pos() ) ) {
d->success = false;
hide();
}
else {
QWidget::mousePressEvent( e );
}
}
void CommentEditWidget::hideEvent( QHideEvent* e )
{
Q_UNUSED( e );
if ( d->eventLoop ) {
d->eventLoop->exit();
}
}
void CommentEditWidget::updateButtons()
{
QSize sbs = d->buttonSave->sizeHint();
QSize cbs = d->buttonCancel->sizeHint();
// FIXME: button order
d->buttonCancel->setGeometry( QRect( QPoint( d->textEdit->width() - cbs.width() - frameWidth(),
d->textEdit->height() - cbs.height() - frameWidth() ),
cbs ) );
d->buttonSave->setGeometry( QRect( QPoint( d->textEdit->width() - cbs.width() - sbs.width() - frameWidth(),
d->textEdit->height() - sbs.height() - frameWidth() ),
sbs ) );
}
void CommentEditWidget::resizeEvent( QResizeEvent* e )
{
QWidget::resizeEvent( e );
updateButtons();
}
bool CommentEditWidget::eventFilter( QObject* watched, QEvent* event )
{
if ( watched == d->textEdit && event->type() == QEvent::KeyPress ) {
QKeyEvent* ke = static_cast<QKeyEvent*>( event );
kDebug() << "keypress:" << ke->key() << ke->modifiers();
if ( ( ke->key() == Qt::Key_Enter ||
ke->key() == Qt::Key_Return ) &&
ke->modifiers() & Qt::ControlModifier ) {
d->_k_saveClicked();
return true;
}
}
return QFrame::eventFilter( watched, event );
}
#include "commenteditwidget.moc"

View file

@ -1,62 +0,0 @@
/***************************************************************************
* Copyright (C) 2008 by Sebastian Trueg <trueg@kde.org> *
* *
* 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 *
***************************************************************************/
#ifndef _COMMENT_EDIT_WIDGET_H_
#define _COMMENT_EDIT_WIDGET_H_
#include <QtGui/QFrame>
class QResizeEvent;
class QMouseEvent;
class QHideEvent;
class CommentEditWidget : public QFrame
{
Q_OBJECT
public:
CommentEditWidget( QWidget* parent = 0 );
~CommentEditWidget();
void setComment( const QString& s );
QString comment();
/**
* Show the comment widget at position pos.
* \return true if the user chose to save the comment,
* false otherwise.
*/
bool exec( const QPoint& pos );
bool eventFilter( QObject* watched, QEvent* event );
private:
void updateButtons();
void resizeEvent( QResizeEvent* );
void mousePressEvent( QMouseEvent* e );
void hideEvent( QHideEvent* e );
class Private;
Private* const d;
Q_PRIVATE_SLOT( d, void _k_saveClicked() )
Q_PRIVATE_SLOT( d, void _k_cancelClicked() )
};
#endif

View file

@ -18,13 +18,11 @@
***************************************************************************/
#include "commentwidget.h"
#include "commenteditwidget.h"
#include <QtGui/QLabel>
#include <QtGui/QTextEdit>
#include <QtGui/QLayout>
#include <QtGui/QCursor>
#include <QtGui/QScrollArea>
#include <QtCore/QEvent>
#include <KLocale>
@ -40,10 +38,8 @@ public:
void update();
void _k_slotEnableEditing();
QLabel* commentLabel;
QScrollArea* scrollArea;
QLabel* commentLink;
CommentEditWidget* edit;
QTextEdit* textEdit;
QLabel* addComment;
QString comment;
@ -54,27 +50,18 @@ private:
void CommentWidget::Private::update()
{
commentLabel->setText( comment );
if ( comment.isEmpty() ) {
scrollArea->hide();
commentLink->setText( "<p align=center><a style=\"font-size:small;\" href=\"addComment\">" + i18nc( "@label", "Add Comment..." ) + "</a>" );
}
else {
scrollArea->show();
commentLink->setText( "<p align=center><a style=\"font-size:small;\" href=\"addComment\">" + i18nc( "@label", "Change Comment..." ) + "</a>" );
}
textEdit->setText( comment );
const bool hasComment = !comment.isEmpty();
textEdit->setVisible(hasComment);
addComment->setVisible(!hasComment);
}
void CommentWidget::Private::_k_slotEnableEditing()
{
CommentEditWidget w;
w.setComment( comment );
if ( w.exec( QCursor::pos() ) ) {
comment = w.comment();
update();
emit q->commentChanged( comment );
}
textEdit->show();
textEdit->setFocus();
addComment->hide();
}
@ -83,22 +70,20 @@ CommentWidget::CommentWidget( QWidget* parent )
: QWidget( parent ),
d( new Private( this ) )
{
d->commentLabel = new QLabel( this );
d->commentLabel->setWordWrap( true );
d->textEdit = new QTextEdit( this );
d->textEdit->installEventFilter( this );
d->textEdit->setMinimumHeight( 100 );
d->textEdit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored);
d->scrollArea = new QScrollArea( this );
d->scrollArea->setWidget( d->commentLabel );
d->scrollArea->setWidgetResizable( true );
d->scrollArea->setFrameShape( QFrame::StyledPanel );
d->commentLink = new QLabel( this );
d->addComment = new QLabel( this );
d->addComment->setText( "<p align=center><a style=\"font-size:small;\" href=\"addComment\">" + i18nc( "@label", "Add Comment..." ) + "</a>" );
QVBoxLayout* layout = new QVBoxLayout( this );
layout->setMargin( 0 );
layout->addWidget( d->scrollArea );
layout->addWidget( d->commentLink );
layout->addWidget( d->textEdit );
layout->addWidget( d->addComment );
d->update();
connect( d->commentLink, SIGNAL( linkActivated( const QString& ) ), this, SLOT( _k_slotEnableEditing() ) );
connect( d->addComment, SIGNAL( linkActivated( const QString& ) ), this, SLOT( _k_slotEnableEditing() ) );
}
@ -121,8 +106,21 @@ QString CommentWidget::comment() const
}
QString CommentWidget::editorText() const
{
return d->textEdit->toPlainText();
}
bool CommentWidget::eventFilter( QObject* watched, QEvent* event )
{
if ( watched == d->textEdit && event->type() == QEvent::FocusOut ) {
const QString currentComment = editorText();
if ( currentComment != d->comment ) {
d->comment = currentComment;
emit commentChanged( currentComment );
}
d->update();
}
return QWidget::eventFilter( watched, event );
}

View file

@ -28,17 +28,19 @@ class CommentWidget : public QWidget
public:
CommentWidget( QWidget* parent = 0 );
~CommentWidget();
virtual ~CommentWidget();
void setComment( const QString& comment );
QString comment() const;
QString editorText() const;
virtual bool eventFilter( QObject* watched, QEvent* event );
Q_SIGNALS:
void commentChanged( const QString& );
private:
bool eventFilter( QObject* watched, QEvent* event );
class Private;
Private* const d;

View file

@ -302,7 +302,7 @@ void InformationPanel::contextMenuEvent(QContextMenuEvent* event)
}
if (!skip) {
const QString label = key; // TODO
const QString label = tunedLabel(key); // TODO
QAction* action = new QAction(label, &popup);
action->setCheckable(true);
action->setChecked(settings.readEntry(key, true));
@ -587,7 +587,7 @@ void InformationPanel::showMetaInfo()
// instead of it.value().toString()
// TODO #2: using tunedLabel() is a workaround for KDE 4.3 until
// we get translated labels
m_metaTextLabel->add(tunedLabel(label), it.value().toString());
m_metaTextLabel->add(tunedLabel(label) + ':', it.value().toString());
}
++it;
}

View file

@ -24,7 +24,6 @@
#include <config-nepomuk.h>
#include <klocale.h>
#include <KDebug>
#include <KMessageBox>
#include <QtCore/QEvent>
@ -61,9 +60,7 @@ class MetaDataWidget::Private
{
public:
#ifdef HAVE_NEPOMUK
void loadComment(const QString& comment);
CommentWidget* editComment;
CommentWidget* commentWidget;
KRatingWidget* ratingWidget;
Nepomuk::ResourceTaggingWidget* tagWidget;
@ -103,10 +100,6 @@ public:
};
#ifdef HAVE_NEPOMUK
void MetaDataWidget::Private::loadComment(const QString& comment)
{
editComment->setComment( comment );
}
MetaDataWidget::Private::LoadFilesThread::LoadFilesThread(
MetaDataWidget::Private::SharedData* sharedData,
@ -181,14 +174,14 @@ MetaDataWidget::MetaDataWidget(QWidget* parent) :
{
#ifdef HAVE_NEPOMUK
d = new Private;
d->editComment = new CommentWidget(this);
d->editComment->setFocusPolicy(Qt::ClickFocus);
d->commentWidget = new CommentWidget(this);
d->commentWidget->setFocusPolicy(Qt::ClickFocus);
d->ratingWidget = new KRatingWidget(this);
d->ratingWidget->setAlignment( Qt::AlignCenter );
d->tagWidget = new Nepomuk::ResourceTaggingWidget(this);
connect(d->ratingWidget, SIGNAL(ratingChanged(unsigned int)), this, SLOT(slotRatingChanged(unsigned int)));
connect(d->editComment, SIGNAL(commentChanged(const QString&)), this, SLOT(slotCommentChanged(const QString&)));
connect( d->tagWidget, SIGNAL( tagClicked( const Nepomuk::Tag& ) ), this, SLOT( slotTagClicked( const Nepomuk::Tag& ) ) );
connect(d->commentWidget, SIGNAL(commentChanged(const QString&)), this, SLOT(slotCommentChanged(const QString&)));
connect(d->tagWidget, SIGNAL(tagClicked(const Nepomuk::Tag&)), this, SLOT(slotTagClicked( const Nepomuk::Tag&)));
d->sharedData.rating = 0;
d->loadFilesThread = new Private::LoadFilesThread(&d->sharedData, &d->mutex);
@ -197,7 +190,7 @@ MetaDataWidget::MetaDataWidget(QWidget* parent) :
QVBoxLayout* lay = new QVBoxLayout(this);
lay->setMargin(0);
lay->addWidget(d->ratingWidget);
lay->addWidget(d->editComment);
lay->addWidget(d->commentWidget);
lay->addWidget( d->tagWidget );
#else
d = 0;
@ -236,7 +229,7 @@ bool MetaDataWidget::isRatingVisible() const
void MetaDataWidget::setCommentVisible(bool visible)
{
#ifdef HAVE_NEPOMUK
d->editComment->setVisible(visible);
d->commentWidget->setVisible(visible);
#else
Q_UNUSED(visible);
#endif
@ -246,7 +239,7 @@ void MetaDataWidget::setCommentVisible(bool visible)
bool MetaDataWidget::isCommentVisible() const
{
#ifdef HAVE_NEPOMUK
return d->editComment->isVisible();
return d->commentWidget->isVisible();
#else
return false;
#endif
@ -275,7 +268,6 @@ bool MetaDataWidget::areTagsVisible() const
void MetaDataWidget::setFile(const KUrl& url)
{
kDebug() << url;
KUrl::List urls;
urls.append( url );
setFiles( urls );
@ -284,6 +276,13 @@ void MetaDataWidget::setFile(const KUrl& url)
void MetaDataWidget::setFiles(const KUrl::List& urls)
{
#ifdef HAVE_NEPOMUK
// Assure that the currently edited text is stored before
// loading the meta data for new files.
const QString currentComment = d->commentWidget->editorText();
if ( currentComment != d->commentWidget->comment() ) {
slotCommentChanged( currentComment );
}
d->loadFilesThread->loadFiles( urls );
#else
Q_UNUSED( urls );
@ -294,12 +293,16 @@ void MetaDataWidget::setFiles(const KUrl::List& urls)
void MetaDataWidget::slotCommentChanged( const QString& s )
{
#ifdef HAVE_NEPOMUK
disconnect(d->commentWidget, SIGNAL(commentChanged(const QString&)), this, SLOT(slotCommentChanged(const QString&)));
QMutexLocker locker( &d->mutex );
Nepomuk::MassUpdateJob* job = Nepomuk::MassUpdateJob::commentResources( d->sharedData.files.values(), s );
connect( job, SIGNAL( result( KJob* ) ),
this, SLOT( metadataUpdateDone() ) );
setEnabled( false ); // no updates during execution
job->start();
connect(d->commentWidget, SIGNAL(commentChanged(const QString&)), this, SLOT(slotCommentChanged(const QString&)));
#else
Q_UNUSED( s );
#endif
@ -346,7 +349,7 @@ void MetaDataWidget::slotLoadingFinished()
#ifdef HAVE_NEPOMUK
QMutexLocker locker( &d->mutex );
d->ratingWidget->setRating( d->sharedData.rating );
d->loadComment( d->sharedData.comment );
d->commentWidget->setComment( d->sharedData.comment );
d->tagWidget->setResources( d->sharedData.fileRes );
#endif
}