This is the first step towards a better looking and more usable metadata GUI.

- A nicer comment widget shows a popup to edit the comment.
- A tag cloud replaces the ugly tagwidget from libnepomuk.
The plan is to use Dolphin as a testbed to optimize the look and then 
move at least the tagcloud to libnepomuk to make it available for all apps
since this is a common feature.

So please test it and provide feedback. The layout is still cluttered. So we
also need feedback on that. And of course on the usability.

Apart from the GUI Dolphin now uses the mass metadata update job to perform
metadata updates on many files in an async KJob without blocking the GUI.
This is another candidate for public API at some point.

svn path=/trunk/KDE/kdebase/apps/; revision=788565
This commit is contained in:
Sebastian Trueg 2008-03-21 21:05:05 +00:00
parent 9ceab694e2
commit d3a0432188
21 changed files with 2583 additions and 519 deletions

View file

@ -5,6 +5,7 @@ add_subdirectory( tests )
macro_optional_find_package(Soprano)
include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${BLITZ_INCLUDES} )
if (Soprano_FOUND)
include_directories( ${SOPRANO_INCLUDE_DIR} )
endif (Soprano_FOUND)
@ -27,7 +28,6 @@ set(dolphinprivate_LIB_SRCS
dolphinview.cpp
dolphinviewactionhandler.cpp
iconmanager.cpp
ratingpainter.cpp
renamedialog.cpp
selectiontoggle.cpp
selectionmanager.cpp
@ -103,6 +103,8 @@ set(dolphin_SRCS
infosidebarpage.cpp
main.cpp
metadatawidget.cpp
commentwidget.cpp
commenteditwidget.cpp
metatextlabel.cpp
pixmapviewer.cpp
settingspagebase.cpp
@ -117,6 +119,19 @@ set(dolphin_SRCS
viewsettingspage.cpp
viewpropsprogressinfo.cpp )
if(Nepomuk_FOUND)
set(dolphin_SRCS
${dolphin_SRCS}
nepomukmassupdatejob.cpp
tagcloud/tagcloud.cpp
tagcloud/resourcetaggingwidget.cpp
tagcloud/taggingpopup.cpp
tagcloud/newtagdialog.cpp
)
kde4_add_ui_files(dolphin_SRCS tagcloud/newtagdialog.ui)
endif(Nepomuk_FOUND)
if(NOT WIN32)
set(dolphin_SRCS ${dolphin_SRCS} terminalsidebarpage.cpp)
endif(NOT WIN32)

241
src/commenteditwidget.cpp Normal file
View file

@ -0,0 +1,241 @@
/***************************************************************************
* 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/QTextEdit>
#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>
class CommentEditWidget::Private
{
public:
Private( CommentEditWidget* parent )
: eventLoop( 0 ),
q( parent ) {
}
QEventLoop* eventLoop;
bool success;
QTextEdit* 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::Box|QFrame::Plain );
setWindowFlags( Qt::Popup );
d->textEdit = new QTextEdit( 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( i18n( "Save" ) );
d->buttonCancel->setText( i18n( "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->setText( 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"

62
src/commenteditwidget.h Normal file
View file

@ -0,0 +1,62 @@
/***************************************************************************
* 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

114
src/commentwidget.cpp Normal file
View file

@ -0,0 +1,114 @@
/***************************************************************************
* 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 "commentwidget.h"
#include "commenteditwidget.h"
#include <QtGui/QLabel>
#include <QtGui/QTextEdit>
#include <QtGui/QLayout>
#include <QtGui/QCursor>
#include <QtCore/QEvent>
#include <KLocale>
class CommentWidget::Private
{
public:
Private( CommentWidget* parent )
: q( parent ) {
}
void update();
void _k_slotEnableEditing();
QLabel* label;
CommentEditWidget* edit;
QString comment;
private:
CommentWidget* q;
};
void CommentWidget::Private::update()
{
if ( comment.isEmpty() ) {
label->setText( "<p align=center><a style=\"font-size:small;\" href=\"addComment\">" + i18n( "Click to add comment..." ) + "</a>" );
}
else {
label->setText( "<p>" + comment + "<p align=right><a style=\"font-size:small;\" href=\"addComment\">" + i18n( "Change comment..." ) + "</a>" );
}
}
void CommentWidget::Private::_k_slotEnableEditing()
{
CommentEditWidget w;
w.setComment( comment );
if ( w.exec( QCursor::pos() ) ) {
comment = w.comment();
update();
emit q->commentChanged( comment );
}
}
CommentWidget::CommentWidget( QWidget* parent )
: QWidget( parent ),
d( new Private( this ) )
{
d->label = new QLabel( this );
d->label->setWordWrap( true );
QVBoxLayout* layout = new QVBoxLayout( this );
layout->setMargin( 0 );
layout->addWidget( d->label );
d->update();
connect( d->label, SIGNAL( linkActivated( const QString& ) ), this, SLOT( _k_slotEnableEditing() ) );
}
CommentWidget::~CommentWidget()
{
delete d;
}
void CommentWidget::setComment( const QString& comment )
{
d->comment = comment;
d->update();
}
QString CommentWidget::comment() const
{
return d->comment;
}
bool CommentWidget::eventFilter( QObject* watched, QEvent* event )
{
return QWidget::eventFilter( watched, event );
}
#include "commentwidget.moc"

48
src/commentwidget.h Normal file
View file

@ -0,0 +1,48 @@
/***************************************************************************
* 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 _NEPOMUK_COMMENT_WIDGET_H_
#define _NEPOMUK_COMMENT_WIDGET_H_
#include <QtGui/QWidget>
class CommentWidget : public QWidget
{
Q_OBJECT
public:
CommentWidget( QWidget* parent = 0 );
~CommentWidget();
void setComment( const QString& comment );
QString comment() const;
Q_SIGNALS:
void commentChanged( const QString& );
private:
bool eventFilter( QObject* watched, QEvent* event );
class Private;
Private* const d;
Q_PRIVATE_SLOT( d, void _k_slotEnableEditing() )
};
#endif

View file

@ -18,24 +18,22 @@
* Boston, MA 02110-1301, USA.
*/
#include "config-nepomuk.h"
#include "dolphincategorydrawer.h"
#include "ratingpainter.h"
#include <QPainter>
#include <QFile>
#include <QDir>
#ifdef HAVE_NEPOMUK
#include <nepomuk/kratingpainter.h>
#endif
#include <kiconloader.h>
#include <kcategorizedsortfilterproxymodel.h>
#include <qimageblitz.h>
#include <kuser.h>
#include <config-nepomuk.h>
#ifdef HAVE_NEPOMUK
#include <nepomuk/global.h>
#include <nepomuk/resource.h>
#include <nepomuk/tag.h>
#endif
#include "dolphinview.h"
#include "dolphinmodel.h"
@ -217,7 +215,7 @@ void DolphinCategoryDrawer::drawCategory(const QModelIndex &index, int sortRole,
QRect ratingRect( option.rect );
ratingRect.setTop(option.rect.top() + (option.rect.height() / 2) - (iconSize / 2));
ratingRect.setHeight( iconSize );
Nepomuk::RatingPainter::drawRating( painter, ratingRect, Qt::AlignLeft, category.toInt() );
KRatingPainter::paintRating( painter, ratingRect, Qt::AlignLeft, category.toInt() );
break;
}

View file

@ -19,9 +19,13 @@
#include "metadatawidget.h"
#include "commentwidget.h"
#include <config-nepomuk.h>
#include <klocale.h>
#include <KDebug>
#include <KMessageBox>
#include <QtCore/QEvent>
#include <QtGui/QLabel>
@ -29,13 +33,14 @@
#include <QtGui/QTextEdit>
#ifdef HAVE_NEPOMUK
#include "nepomukmassupdatejob.h"
#include <nepomuk/kmetadatatagwidget.h>
#include <nepomuk/resourcemanager.h>
#include <nepomuk/resource.h>
#include <nepomuk/variant.h>
#include <nepomuk/kratingwidget.h>
#include <nepomuk/global.h>
#include <Soprano/Vocabulary/Xesam>
#include "tagcloud/resourcetaggingwidget.h"
#endif
@ -57,24 +62,16 @@ public:
QMap<KUrl, Nepomuk::Resource> files;
QTextEdit* editComment;
CommentWidget* editComment;
KRatingWidget* ratingWidget;
Nepomuk::TagWidget* tagWidget;
Nepomuk::ResourceTaggingWidget* tagWidget;
#endif
};
#ifdef HAVE_NEPOMUK
void MetaDataWidget::Private::loadComment(const QString& comment)
{
editComment->blockSignals(true);
if (comment.isEmpty()) {
editComment->setFontItalic(true);
editComment->setText(i18nc("@info:tooltip", "Click to add comment..."));
} else {
editComment->setFontItalic(false);
editComment->setText(comment);
}
editComment->blockSignals(false);
editComment->setComment( comment );
}
#endif
@ -84,28 +81,21 @@ MetaDataWidget::MetaDataWidget(QWidget* parent) :
{
#ifdef HAVE_NEPOMUK
d = new Private;
d->editComment = new QTextEdit(this);
d->editComment = new CommentWidget(this);
d->editComment->setFocusPolicy(Qt::ClickFocus);
d->ratingWidget = new KRatingWidget(this);
d->tagWidget = new Nepomuk::TagWidget(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(textChanged()), this, SLOT(slotCommentChanged()));
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& ) ) );
QVBoxLayout* lay = new QVBoxLayout(this);
lay->setMargin(0);
QHBoxLayout* hbox = new QHBoxLayout;
hbox->addWidget(new QLabel(i18nc("@label:slider", "Rating:"), this));
hbox->addStretch(1);
hbox->addWidget(d->ratingWidget);
lay->addLayout(hbox);
lay->addWidget(d->ratingWidget);
lay->addWidget(d->editComment);
hbox = new QHBoxLayout;
hbox->addWidget(new QLabel(i18nc("@label:textbox", "Tags:"), this));
hbox->addWidget(d->tagWidget, 1);
lay->addLayout(hbox);
d->editComment->installEventFilter(this);
d->editComment->viewport()->installEventFilter(this);
QHBoxLayout* hbox = new QHBoxLayout;
lay->addWidget( d->tagWidget );
#else
d = 0;
#endif
@ -120,6 +110,7 @@ MetaDataWidget::~MetaDataWidget()
void MetaDataWidget::setFile(const KUrl& url)
{
kDebug() << url;
KUrl::List urls;
urls.append( url );
setFiles( urls );
@ -129,52 +120,44 @@ void MetaDataWidget::setFile(const KUrl& url)
void MetaDataWidget::setFiles(const KUrl::List& urls)
{
#ifdef HAVE_NEPOMUK
// FIXME #1: For 100 files MetaDataWidget::setFiles() blocks
// for around 15 seconds (maybe we should delegate this to a KJob).
// In the meantime we temporary just reset the widgets:
d->ratingWidget->setRating( 0 );
d->loadComment( QString() );
return;
// FIXME #2: replace with KMetaData::File once we have it again
d->files.clear();
bool first = true;
QList<Nepomuk::Resource> fileRes;
Q_FOREACH( KUrl url, urls ) {
Nepomuk::Resource file( url.url(), Soprano::Vocabulary::Xesam::File() );
// file.setLocation(url.url());
Nepomuk::Resource file( url, Soprano::Vocabulary::Xesam::File() );
d->files.insert( url, file );
fileRes.append( file );
if ( !first &&
d->ratingWidget->rating() != file.rating() ) {
d->ratingWidget->setRating( 0 ); // reset rating
}
else if ( first ) {
d->ratingWidget->setRating( (qint32)(file.rating()) );
}
if ( !first &&
d->ratingWidget->rating() != file.rating() ) {
d->ratingWidget->setRating( 0 ); // reset rating
}
else if ( first ) {
d->ratingWidget->setRating( (qint32)(file.rating()) );
}
if ( !first &&
d->editComment->toPlainText() != file.description() ) {
d->loadComment( QString() );
}
else if ( first ) {
d->loadComment( file.description() );
}
first = false;
if ( !first &&
d->editComment->comment() != file.description() ) {
d->loadComment( QString() );
}
else if ( first ) {
d->loadComment( file.description() );
}
first = false;
}
d->tagWidget->setTaggedResources(fileRes);
d->tagWidget->setResource( fileRes.first() );
#endif
}
void MetaDataWidget::slotCommentChanged()
void MetaDataWidget::slotCommentChanged( const QString& s )
{
#ifdef HAVE_NEPOMUK
for ( QMap<KUrl, Nepomuk::Resource>::iterator it = d->files.begin();
it != d->files.end(); ++it ) {
it.value().setDescription(d->editComment->toPlainText());
}
Nepomuk::MassUpdateJob* job = Nepomuk::MassUpdateJob::commentResources( d->files.values(), s );
connect( job, SIGNAL( result( KJob* ) ),
this, SLOT( metadataUpdateDone() ) );
setEnabled( false ); // no updates during execution
job->start();
#endif
}
@ -182,31 +165,31 @@ void MetaDataWidget::slotCommentChanged()
void MetaDataWidget::slotRatingChanged(unsigned int rating)
{
#ifdef HAVE_NEPOMUK
for ( QMap<KUrl, Nepomuk::Resource>::iterator it = d->files.begin();
it != d->files.end(); ++it ) {
it.value().setRating(rating);
}
Nepomuk::MassUpdateJob* job = Nepomuk::MassUpdateJob::rateResources( d->files.values(), rating );
connect( job, SIGNAL( result( KJob* ) ),
this, SLOT( metadataUpdateDone() ) );
setEnabled( false ); // no updates during execution
job->start();
#endif
}
void MetaDataWidget::metadataUpdateDone()
{
setEnabled( true );
}
bool MetaDataWidget::eventFilter(QObject* obj, QEvent* event)
{
#ifdef HAVE_NEPOMUK
if (obj == d->editComment->viewport() || obj == d->editComment) {
if (event->type() == QEvent::FocusOut) {
// make sure the info text is displayed again
d->loadComment(d->editComment->toPlainText());
} else if (event->type() == QEvent::FocusIn) {
d->editComment->setFontItalic(false);
if (!d->files.isEmpty() && d->files.begin().value().description().isEmpty()) {
d->editComment->setText(QString());
}
}
}
#endif
return QWidget::eventFilter(obj, event);
}
void MetaDataWidget::slotTagClicked( const Nepomuk::Tag& tag )
{
// FIXME
KMessageBox::information( this, "FIXME: connect me to the dolphinmodel: tags:/" + tag.genericLabel() );
}
#include "metadatawidget.moc"

View file

@ -24,6 +24,9 @@
#include <kurl.h>
namespace Nepomuk {
class Tag;
}
class MetaDataWidget : public QWidget
{
@ -52,8 +55,10 @@ signals:
void metaDataChanged();
private Q_SLOTS:
void slotCommentChanged();
void slotCommentChanged(const QString&);
void slotRatingChanged(unsigned int rating);
void metadataUpdateDone();
void slotTagClicked( const Nepomuk::Tag& );
protected:
bool eventFilter(QObject* obj, QEvent* event);

View file

@ -0,0 +1,163 @@
/***************************************************************************
* 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 "nepomukmassupdatejob.h"
#include <klocale.h>
#include <kdebug.h>
#include <nepomuk/tag.h>
#include <nepomuk/tools.h>
Nepomuk::MassUpdateJob::MassUpdateJob( QObject* parent )
: KJob( parent ),
m_index( -1 )
{
kDebug();
setCapabilities( Killable|Suspendable );
connect( &m_processTimer, SIGNAL( timeout() ),
this, SLOT( slotNext() ) );
}
Nepomuk::MassUpdateJob::~MassUpdateJob()
{
kDebug();
}
void Nepomuk::MassUpdateJob::setFiles( const KUrl::List& urls )
{
m_resources.clear();
foreach( KUrl url, urls ) {
m_resources.append( Resource( url ) );
}
setTotalAmount( KJob::Files, m_resources.count() );
}
void Nepomuk::MassUpdateJob::setResources( const QList<Nepomuk::Resource>& rl )
{
m_resources = rl;
setTotalAmount( KJob::Files, m_resources.count() );
}
void Nepomuk::MassUpdateJob::setProperties( const QList<QPair<QUrl,Nepomuk::Variant> >& props )
{
m_properties = props;
}
void Nepomuk::MassUpdateJob::start()
{
if ( m_index < 0 ) {
kDebug();
emit description( this,
i18n("Changing annotations") );
m_index = 0;
m_processTimer.start();
}
else {
kDebug() << "Job has already been started";
}
}
bool Nepomuk::MassUpdateJob::doKill()
{
if ( m_index > 0 ) {
m_processTimer.stop();
m_index = -1;
return true;
}
else {
return false;
}
}
bool Nepomuk::MassUpdateJob::doSuspend()
{
m_processTimer.stop();
return true;
}
bool Nepomuk::MassUpdateJob::doResume()
{
if ( m_index > 0 ) {
m_processTimer.start();
return true;
}
else {
return false;
}
}
void Nepomuk::MassUpdateJob::slotNext()
{
if ( !isSuspended() ) {
if ( m_index < m_resources.count() ) {
Nepomuk::Resource& res = m_resources[m_index];
for ( int i = 0; i < m_properties.count(); ++i ) {
res.setProperty( m_properties[i].first, m_properties[i].second );
}
++m_index;
setProcessedAmount( KJob::Files, m_index );
}
else if ( m_index >= m_resources.count() ) {
kDebug() << "done";
m_index = -1;
m_processTimer.stop();
emitResult();
}
}
}
Nepomuk::MassUpdateJob* Nepomuk::MassUpdateJob::tagResources( const QList<Nepomuk::Resource>& rl, const QList<Nepomuk::Tag>& tags )
{
Nepomuk::MassUpdateJob* job = new Nepomuk::MassUpdateJob();
job->setResources( rl );
job->setProperties( QList<QPair<QUrl,Nepomuk::Variant> >() << qMakePair( QUrl( Nepomuk::Resource::tagUri() ), Nepomuk::Variant( convertResourceList<Tag>( tags ) ) ) );
return job;
}
Nepomuk::MassUpdateJob* Nepomuk::MassUpdateJob::rateResources( const QList<Nepomuk::Resource>& rl, int rating )
{
Nepomuk::MassUpdateJob* job = new Nepomuk::MassUpdateJob();
job->setResources( rl );
job->setProperties( QList<QPair<QUrl,Nepomuk::Variant> >() << qMakePair( QUrl( Nepomuk::Resource::ratingUri() ), Nepomuk::Variant( rating ) ) );
return job;
}
Nepomuk::MassUpdateJob* Nepomuk::MassUpdateJob::commentResources( const QList<Nepomuk::Resource>& rl, const QString& comment )
{
Nepomuk::MassUpdateJob* job = new Nepomuk::MassUpdateJob();
job->setResources( rl );
job->setProperties( QList<QPair<QUrl,Nepomuk::Variant> >() << qMakePair( QUrl( Nepomuk::Resource::descriptionUri() ), Nepomuk::Variant( comment ) ) );
return job;
}
#include "nepomukmassupdatejob.moc"

View file

@ -0,0 +1,85 @@
/***************************************************************************
* 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 _NEPOMUK_MASS_UPDATE_JOB_H_
#define _NEPOMUK_MASS_UPDATE_JOB_H_
#include <kjob.h>
#include <kurl.h>
#include <QtCore/QList>
#include <QtCore/QPair>
#include <QtCore/QTimer>
#include <nepomuk/resource.h>
#include <nepomuk/variant.h>
namespace Nepomuk {
class MassUpdateJob : public KJob
{
Q_OBJECT
public:
MassUpdateJob( QObject* parent = 0 );
~MassUpdateJob();
/**
* Set a list of files to change
* This has the same effect as using setResources
* with a list of manually created resources.
*/
void setFiles( const KUrl::List& urls );
/**
* Set a list of resources to change.
*/
void setResources( const QList<Nepomuk::Resource>& );
/**
* Set the properties to change in the mass update.
*/
void setProperties( const QList<QPair<QUrl,Nepomuk::Variant> >& props );
/**
* Actually start the job.
*/
void start();
static MassUpdateJob* tagResources( const QList<Nepomuk::Resource>&, const QList<Nepomuk::Tag>& tags );
static MassUpdateJob* commentResources( const QList<Nepomuk::Resource>&, const QString& comment );
static MassUpdateJob* rateResources( const QList<Nepomuk::Resource>&, int rating );
protected:
bool doKill();
bool doSuspend();
bool doResume();
private Q_SLOTS:
void slotNext();
private:
QList<Nepomuk::Resource> m_resources;
QList<QPair<QUrl,Nepomuk::Variant> > m_properties;
int m_index;
QTimer m_processTimer;
};
}
#endif

View file

@ -1,310 +0,0 @@
/*
This file is part of the Nepomuk KDE project.
Copyright (C) 2007 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 version 2 as published by the Free Software Foundation.
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 "ratingpainter.h"
#include <QtGui/QPainter>
#include <QtGui/QPixmap>
#include <kicon.h>
#include <kiconeffect.h>
#include <kdebug.h>
class Nepomuk::RatingPainter::Private
{
public:
Private()
: maxRating(10),
icon( "rating" ),
bHalfSteps(true),
alignment(Qt::AlignCenter),
direction(Qt::LeftToRight) {
}
int maxRating;
KIcon icon;
bool bHalfSteps;
Qt::Alignment alignment;
Qt::LayoutDirection direction;
QPixmap customPixmap;
};
Nepomuk::RatingPainter::RatingPainter()
: d(new Private())
{
}
Nepomuk::RatingPainter::~RatingPainter()
{
delete d;
}
int Nepomuk::RatingPainter::maxRating() const
{
return d->maxRating;
}
bool Nepomuk::RatingPainter::halfStepsEnabled() const
{
return d->bHalfSteps;
}
Qt::Alignment Nepomuk::RatingPainter::alignment() const
{
return d->alignment;
}
Qt::LayoutDirection Nepomuk::RatingPainter::direction() const
{
return d->direction;
}
KIcon Nepomuk::RatingPainter::icon() const
{
return d->icon;
}
QPixmap Nepomuk::RatingPainter::customPixmap() const
{
return d->customPixmap;
}
void Nepomuk::RatingPainter::setMaxRating( int max )
{
d->maxRating = max;
}
void Nepomuk::RatingPainter::setHalfStepsEnabled( bool enabled )
{
d->bHalfSteps = enabled;
}
void Nepomuk::RatingPainter::setAlignment( Qt::Alignment align )
{
d->alignment = align;
}
void Nepomuk::RatingPainter::setLayoutDirection( Qt::LayoutDirection direction )
{
d->direction = direction;
}
void Nepomuk::RatingPainter::setIcon( const KIcon& icon )
{
d->icon = icon;
}
void Nepomuk::RatingPainter::setCustomPixmap( const QPixmap& pixmap )
{
d->customPixmap = pixmap;
}
void Nepomuk::RatingPainter::draw( QPainter* painter, const QRect& rect, int rating, int hoverRating )
{
rating = qMin( rating, d->maxRating );
hoverRating = qMin( hoverRating, d->maxRating );
int numUsedStars = d->bHalfSteps ? d->maxRating/2 : d->maxRating;
if ( hoverRating > 0 && hoverRating < rating ) {
int tmp = hoverRating;
hoverRating = rating;
rating = tmp;
}
// get the rating pixmaps
QPixmap ratingPix;
if ( !d->customPixmap.isNull() ) {
ratingPix = d->customPixmap;
}
else {
KIcon ratingIcon( "rating" );
int iconSize = qMin( rect.height(), rect.width() / numUsedStars );
ratingPix = ratingIcon.pixmap( iconSize );
}
QPixmap disabledRatingPix = KIconEffect().apply( ratingPix, KIconEffect::ToGray, 1.0, QColor(), false );
QPixmap hoverPix;
bool half = d->bHalfSteps && rating%2;
int numRatingStars = d->bHalfSteps ? rating/2 : rating;
int numHoverStars = 0;
bool halfHover = false;
if ( hoverRating > 0 && rating != hoverRating ) {
numHoverStars = d->bHalfSteps ? hoverRating/2 : hoverRating;
halfHover = d->bHalfSteps && hoverRating%2;
hoverPix = KIconEffect().apply( ratingPix, KIconEffect::ToGray, 0.5, QColor(), false );
}
int usedSpacing = 0;
if ( d->alignment & Qt::AlignJustify ) {
int w = rect.width();
w -= numUsedStars * ratingPix.width();
usedSpacing = w / ( numUsedStars-1 );
}
int i = 0;
int x = rect.x();
if ( d->alignment & Qt::AlignRight ) {
x += ( rect.width() - ratingPix.width()*numUsedStars );
}
else if ( d->alignment & Qt::AlignCenter ) {
x += ( rect.width() - ratingPix.width()*numUsedStars )/2;
}
int xInc = ratingPix.width() + usedSpacing;
if ( d->direction == Qt::RightToLeft ) {
x = rect.width() - ratingPix.width() - x;
xInc = -xInc;
}
int y = rect.y();
if( d->alignment & Qt::AlignVCenter ) {
y += ( rect.height() / 2 - ratingPix.height() / 2 );
}
else if ( d->alignment & Qt::AlignBottom ) {
y += ( rect.height() - ratingPix.height() );
}
for(; i < numRatingStars; ++i ) {
painter->drawPixmap( x, y, ratingPix );
x += xInc;
}
if( half ) {
painter->drawPixmap( x, y, ratingPix.width()/2, ratingPix.height(),
d->direction == Qt::LeftToRight ? ratingPix : ( numHoverStars > 0 ? hoverPix : disabledRatingPix ),
0, 0, ratingPix.width()/2, ratingPix.height() );
painter->drawPixmap( x + ratingPix.width()/2, y, ratingPix.width()/2, ratingPix.height(),
d->direction == Qt::LeftToRight ? ( numHoverStars > 0 ? hoverPix : disabledRatingPix ) : ratingPix,
ratingPix.width()/2, 0, ratingPix.width()/2, ratingPix.height() );
x += xInc;
++i;
}
for(; i < numHoverStars; ++i ) {
painter->drawPixmap( x, y, hoverPix );
x += xInc;
}
if( halfHover ) {
painter->drawPixmap( x, y, ratingPix.width()/2, ratingPix.height(),
d->direction == Qt::LeftToRight ? hoverPix : disabledRatingPix,
0, 0, ratingPix.width()/2, ratingPix.height() );
painter->drawPixmap( x + ratingPix.width()/2, y, ratingPix.width()/2, ratingPix.height(),
d->direction == Qt::LeftToRight ? disabledRatingPix : hoverPix,
ratingPix.width()/2, 0, ratingPix.width()/2, ratingPix.height() );
x += xInc;
++i;
}
for(; i < numUsedStars; ++i ) {
painter->drawPixmap( x, y, disabledRatingPix );
x += xInc;
}
}
int Nepomuk::RatingPainter::fromPosition( const QRect& rect, const QPoint& pos )
{
int numUsedStars = d->bHalfSteps ? d->maxRating/2 : d->maxRating;
QPixmap ratingPix;
if ( !d->customPixmap.isNull() ) {
ratingPix = d->customPixmap;
}
else {
KIcon ratingIcon( "rating" );
int iconSize = qMin( rect.height(), rect.width() / numUsedStars );
ratingPix = ratingIcon.pixmap( iconSize );
}
QRect usedRect( rect );
if ( d->alignment & Qt::AlignRight ) {
usedRect.setLeft( rect.right() - numUsedStars * ratingPix.width() );
}
else if ( d->alignment & Qt::AlignHCenter ) {
int x = ( rect.width() - numUsedStars * ratingPix.width() )/2;
usedRect.setLeft( rect.left() + x );
usedRect.setRight( rect.right() - x );
}
else { // d->alignment & Qt::AlignLeft
usedRect.setRight( rect.left() + numUsedStars * ratingPix.width() - 1 );
}
if ( d->alignment & Qt::AlignBottom ) {
usedRect.setTop( rect.bottom() - ratingPix.height() + 1 );
}
else if ( d->alignment & Qt::AlignVCenter ) {
int x = ( rect.height() - ratingPix.height() )/2;
usedRect.setTop( rect.top() + x );
usedRect.setBottom( rect.bottom() - x );
}
else { // d->alignment & Qt::AlignTop
usedRect.setBottom( rect.top() + ratingPix.height() - 1 );
}
if ( usedRect.contains( pos ) ) {
int x = 0;
if ( d->direction == Qt::RightToLeft ) {
x = usedRect.right() - pos.x();
}
else {
x = pos.x() - usedRect.left();
}
double one = ( double )usedRect.width() / ( double )d->maxRating;
kDebug() << "rating:" << ( int )( ( double )x/one + 0.5 );
return ( int )( ( double )x/one + 0.5 );
}
else {
return -1;
}
}
void Nepomuk::RatingPainter::drawRating( QPainter* painter, const QRect& rect, Qt::Alignment align, int rating, int hoverRating )
{
RatingPainter rp;
rp.setAlignment( align );
rp.setLayoutDirection( painter->layoutDirection() );
rp.draw( painter, rect, rating, hoverRating );
}
int Nepomuk::RatingPainter::getRatingFromPosition( const QRect& rect, Qt::Alignment align, Qt::LayoutDirection direction, const QPoint& pos )
{
RatingPainter rp;
rp.setAlignment( align );
rp.setLayoutDirection( direction );
return rp.fromPosition( rect, pos );
}

View file

@ -1,122 +0,0 @@
/*
This file is part of the Nepomuk KDE project.
Copyright (C) 2007 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 version 2 as published by the Free Software Foundation.
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.
*/
#ifndef _NEPOMUK_RATING_PAINTER_H_
#define _NEPOMUK_RATING_PAINTER_H_
class QPainter;
#include <QtCore/QRect>
#include <QtCore/QPoint>
#include <kicon.h>
namespace Nepomuk {
/**
* Utility class that draws a row of stars for a rating value.
*/
class RatingPainter
{
public:
/**
* Create a new RatingPainter.
* Normally the static methods should be sufficient.
*/
RatingPainter();
~RatingPainter();
int maxRating() const;
bool halfStepsEnabled() const;
Qt::Alignment alignment() const;
Qt::LayoutDirection direction() const;
KIcon icon() const;
QPixmap customPixmap() const;
/**
* The maximum rating. Defaults to 10.
*/
void setMaxRating( int max );
/**
* If half steps are enabled (the default) then
* one rating step corresponds to half a star.
*/
void setHalfStepsEnabled( bool enabled );
/**
* The alignment of the stars in the drawing rect.
* All alignment flags are supported.
*/
void setAlignment( Qt::Alignment align );
/**
* LTR or RTL
*/
void setLayoutDirection( Qt::LayoutDirection direction );
/**
* Set a custom icon. Defaults to "rating".
*/
void setIcon( const KIcon& icon );
/**
* Set a custom pixmap.
*/
void setCustomPixmap( const QPixmap& pixmap );
/**
* Draw the rating into the configured rect.
*/
void draw( QPainter* painter, const QRect& rect, int rating, int hoverRating = -1 );
/**
* Calculate the rating value from mouse position pos.
*
* \return The rating corresponding to pos or -1 if pos is
* outside of the configured rect.
*/
int fromPosition( const QRect& rect, const QPoint& pos );
/**
* Convenience method that draws a rating into the given rect.
*
* LayoutDirection is read from QPainter.
*
* \param align can be aligned vertically and horizontally. Using Qt::AlignJustify will insert spacing
* between the stars.
*/
static void drawRating( QPainter* p, const QRect& rect, Qt::Alignment align, int rating, int hoverRating = -1 );
/**
* Get the rating that would be selected if the user clicked position pos
* within rect if the rating has been drawn with drawRating() using the same
* rect and align values.
*
* \return The new rating or -1 if pos is outside of the rating area.
*/
static int getRatingFromPosition( const QRect& rect, Qt::Alignment align, Qt::LayoutDirection direction, const QPoint& pos );
private:
class Private;
Private* const d;
};
}
#endif

View file

@ -0,0 +1,83 @@
/*
Copyright (C) 2008 by Sebastian Trueg <trueg at 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, 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 "newtagdialog.h"
#include <nepomuk/tag.h>
#include <KDebug>
#include <KLocale>
#include <KTitleWidget>
NewTagDialog::NewTagDialog( QWidget* parent )
: KDialog( parent )
{
setCaption( i18n( "Create new Tag" ) );
setButtons( Ok|Cancel );
enableButtonOk( false );
setupUi( mainWidget() );
connect( m_editTagLabel, SIGNAL( textChanged(const QString&) ),
this, SLOT( slotLabelChanged(const QString&) ) );
}
NewTagDialog::~NewTagDialog()
{
}
void NewTagDialog::slotLabelChanged( const QString& text )
{
enableButtonOk( !text.isEmpty() );
}
Nepomuk::Tag NewTagDialog::createTag( QWidget* parent )
{
NewTagDialog dlg( parent );
dlg.m_labelTitle->setText( i18n( "Create New Tag" ) );
dlg.m_labelTitle->setComment( i18n( "with optional icon and description" ) );
dlg.m_labelTitle->setPixmap( KIcon( "nepomuk" ).pixmap( 32, 32 ) );
dlg.m_editTagLabel->setFocus();
if ( dlg.exec() ) {
QString name = dlg.m_editTagLabel->text();
QString comment = dlg.m_editTagComment->text();
QString icon = dlg.m_buttonTagIcon->icon();
Nepomuk::Tag newTag( name );
newTag.setLabel( name );
newTag.addIdentifier( name );
if ( !comment.isEmpty() ) {
newTag.setDescription( comment );
}
if ( !icon.isEmpty() ) {
newTag.addSymbol( icon );
}
return newTag;
}
else {
return Nepomuk::Tag();
}
}
#include "newtagdialog.moc"

View file

@ -0,0 +1,45 @@
/*
Copyright (C) 2008 by Sebastian Trueg <trueg at 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, 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 _NEW_TAG_DIALOG_H_
#define _NEW_TAG_DIALOG_H_
#include <KDialog>
#include "ui_newtagdialog.h"
namespace Nepomuk {
class Tag;
}
class NewTagDialog : public KDialog, public Ui_NewTagDialog
{
Q_OBJECT
public:
~NewTagDialog();
static Nepomuk::Tag createTag( QWidget* parent = 0 );
private Q_SLOTS:
void slotLabelChanged( const QString& text );
private:
NewTagDialog( QWidget* parent = 0 );
};
#endif

View file

@ -0,0 +1,113 @@
<ui version="4.0" >
<class>NewTagDialog</class>
<widget class="QWidget" name="NewTagDialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>390</width>
<height>149</height>
</rect>
</property>
<property name="windowTitle" >
<string>Form</string>
</property>
<layout class="QVBoxLayout" >
<item>
<widget class="KTitleWidget" native="1" name="m_labelTitle" />
</item>
<item>
<layout class="QHBoxLayout" >
<item>
<layout class="QVBoxLayout" >
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Name:</string>
</property>
</widget>
</item>
<item>
<widget class="KLineEdit" name="m_editTagLabel" />
</item>
</layout>
</item>
<item>
<widget class="KIconButton" name="m_buttonTagIcon" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="icon" >
<iconset/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label" >
<property name="text" >
<string>Detailed Desctiption (optional):</string>
</property>
</widget>
</item>
<item>
<widget class="KLineEdit" name="m_editTagComment" />
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KIconButton</class>
<extends>QPushButton</extends>
<header>kicondialog.h</header>
</customwidget>
<customwidget>
<class>KLineEdit</class>
<extends>QLineEdit</extends>
<header>klineedit.h</header>
</customwidget>
<customwidget>
<class>KTitleWidget</class>
<extends>QWidget</extends>
<header>ktitlewidget.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,138 @@
/*
This file is part of the Nepomuk KDE project.
Copyright (C) 2007 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 version 2 as published by the Free Software Foundation.
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 "resourcetaggingwidget.h"
#include "tagcloud.h"
#include "taggingpopup.h"
#include <QtGui/QVBoxLayout>
#include <QtGui/QContextMenuEvent>
#include <QtGui/QCursor>
#include <QtGui/QAction>
#include <KLocale>
class Nepomuk::ResourceTaggingWidget::Private
{
public:
Nepomuk::Resource resource;
TagCloud* resourceTagCloud;
TaggingPopup* popup;
QList<Tag> resourceTags;
QAction* changeTagsAction;
void showTaggingPopup( const QPoint& );
void _k_slotShowTaggingPopup();
};
void Nepomuk::ResourceTaggingWidget::Private::showTaggingPopup( const QPoint& pos )
{
popup->showAllTags();
resourceTags = resource.tags();
Q_FOREACH( Tag tag, resourceTags ) {
popup->setTagSelected( tag, true );
}
popup->exec( pos );
resource.setTags( resourceTags );
}
void Nepomuk::ResourceTaggingWidget::Private::_k_slotShowTaggingPopup()
{
showTaggingPopup( QCursor::pos() );
}
Nepomuk::ResourceTaggingWidget::ResourceTaggingWidget( QWidget* parent )
: QWidget( parent ),
d( new Private() )
{
QVBoxLayout* layout = new QVBoxLayout( this );
layout->setMargin( 0 );
d->resourceTagCloud = new TagCloud( this );
layout->addWidget( d->resourceTagCloud );
d->changeTagsAction = new QAction( i18n( "Change tags..." ), this );
d->resourceTagCloud->setCustomNewTagAction( d->changeTagsAction );
// the popup tag cloud
d->popup = new TaggingPopup;
d->popup->setSelectionEnabled( true );
d->popup->setNewTagButtonEnabled( true );
connect( d->popup, SIGNAL( tagToggled( const Nepomuk::Tag&, bool ) ),
this, SLOT( slotTagToggled( const Nepomuk::Tag&, bool ) ) );
connect( d->popup, SIGNAL( tagAdded( const Nepomuk::Tag& ) ),
this, SLOT( slotTagAdded( const Nepomuk::Tag& ) ) );
connect( d->changeTagsAction, SIGNAL( activated() ),
this, SLOT( _k_slotShowTaggingPopup() ) );
connect( d->resourceTagCloud, SIGNAL( tagClicked( const Nepomuk::Tag& ) ),
this, SIGNAL( tagClicked( const Nepomuk::Tag& ) ) );
}
Nepomuk::ResourceTaggingWidget::~ResourceTaggingWidget()
{
delete d->popup;
delete d;
}
void Nepomuk::ResourceTaggingWidget::setResource( const Nepomuk::Resource& res )
{
d->resource = res;
d->resourceTagCloud->showResourceTags( res );
}
void Nepomuk::ResourceTaggingWidget::slotTagToggled( const Nepomuk::Tag& tag, bool enabled )
{
if ( enabled ) {
d->resourceTags.append( tag );
}
else {
d->resourceTags.removeAll( tag );
}
d->popup->hide();
}
void Nepomuk::ResourceTaggingWidget::slotTagAdded( const Nepomuk::Tag& tag )
{
// assign it right away
d->resourceTags.append( tag );
d->resource.addTag( tag );
}
void Nepomuk::ResourceTaggingWidget::contextMenuEvent( QContextMenuEvent* e )
{
d->showTaggingPopup( e->globalPos() );
}
#include "resourcetaggingwidget.moc"

View file

@ -0,0 +1,60 @@
/*
This file is part of the Nepomuk KDE project.
Copyright (C) 2007 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 version 2 as published by the Free Software Foundation.
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.
*/
#ifndef _NEPOMUK_RESOURCE_TAGGING_WIDGET_H_
#define _NEPOMUK_RESOURCE_TAGGING_WIDGET_H_
#include <QtGui/QWidget>
#include <nepomuk/tag.h>
class QEvent;
class QContextMenuEvent;
namespace Nepomuk {
class ResourceTaggingWidget : public QWidget
{
Q_OBJECT
public:
ResourceTaggingWidget( QWidget* parent = 0 );
~ResourceTaggingWidget();
Q_SIGNALS:
void tagClicked( const Nepomuk::Tag& tag );
public Q_SLOTS:
void setResource( const Nepomuk::Resource& );
private Q_SLOTS:
void slotTagToggled( const Nepomuk::Tag& tag, bool enabled );
void slotTagAdded( const Nepomuk::Tag& tag );
protected:
void contextMenuEvent( QContextMenuEvent* e );
private:
class Private;
Private* const d;
Q_PRIVATE_SLOT( d, void _k_slotShowTaggingPopup() )
};
}
#endif

1002
src/tagcloud/tagcloud.cpp Normal file

File diff suppressed because it is too large Load diff

143
src/tagcloud/tagcloud.h Normal file
View file

@ -0,0 +1,143 @@
/*
This file is part of the Nepomuk KDE project.
Copyright (C) 2007 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 version 2 as published by the Free Software Foundation.
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.
*/
#ifndef _NEPOMUK_TAG_CLOUD_H_
#define _NEPOMUK_TAG_CLOUD_H_
#include <QtGui/QFrame>
#include <QtCore/QList>
#include <nepomuk/tag.h>
#include <nepomuk/nepomuk_export.h>
#include <Soprano/Statement>
class QResizeEvent;
class QPaintEvent;
class QMouseEvent;
class QEvent;
namespace Nepomuk {
class NEPOMUK_EXPORT TagCloud : public QFrame
{
Q_OBJECT
public:
TagCloud( QWidget* parent = 0 );
~TagCloud();
enum Sorting {
SortAlpabetically,
SortByWeight,
SortRandom
};
int heightForWidth( int w ) const;
QSize sizeHint() const;
QSize minimumSizeHint() const;
bool zoomEnabled() const;
public Q_SLOTS:
/**
* Set the maximum used font size. The default is 0
* which means to calculate proper values from the KDE
* defaults.
*/
void setMaxFontSize( int size );
/**
* Set the minimum used font size. The default is 0
* which means to calculate proper values from the KDE
* defaults.
*/
void setMinFontSize( int size );
/**
* Set the maximum number of displayed tags. The default is 0
* which means to display all tags.
*
* NOT IMPLEMENTED YET
*/
void setMaxNumberDisplayedTags( int n );
/**
* Allow selection of tags, i.e. enabling and disabling of tags.
*/
void setSelectionEnabled( bool enabled );
void setNewTagButtonEnabled( bool enabled );
void setContextMenuEnabled( bool enabled );
void setAlignment( Qt::Alignment alignment );
void setZoomEnabled( bool zoom );
/**
* Default: SortAlpabetically
*/
void setSorting( Sorting );
/**
* Will reset tags set via showTags()
*/
void showAllTags();
/**
* Set the tags to be shown in the tag cloud.
* If the new tag button is enabled (setEnableNewTagButton())
* new tags will automatically be added to the list of shown tags.
*/
void showTags( const QList<Tag>& tags );
void showResourceTags( const Resource& resource );
/**
* Select or deselect a tag. This does only make sense
* if selection is enabled and \p tag is actually
* displayed.
*
* \sa setSelectionEnabled
*/
void setTagSelected( const Tag& tag, bool selected );
void setCustomNewTagAction( QAction* action );
Q_SIGNALS:
void tagClicked( const Nepomuk::Tag& tag );
void tagAdded( const Nepomuk::Tag& tag );
void tagToggled( const Nepomuk::Tag& tag, bool enabled );
protected:
void resizeEvent( QResizeEvent* e );
void paintEvent( QPaintEvent* e );
void mousePressEvent( QMouseEvent* );
void mouseMoveEvent( QMouseEvent* );
void leaveEvent( QEvent* );
private Q_SLOTS:
void slotStatementAdded( const Soprano::Statement& s );
void slotStatementRemoved( const Soprano::Statement& s );
private:
class Private;
Private* const d;
};
}
#endif

View file

@ -0,0 +1,148 @@
/*
This file is part of the Nepomuk KDE project.
Copyright (C) 2007 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 version 2 as published by the Free Software Foundation.
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 "taggingpopup.h"
#include <QtCore/QEventLoop>
#include <QtCore/QPointer>
#include <QtGui/QApplication>
#include <QtGui/QDesktopWidget>
#include <QtGui/QMouseEvent>
#include <KDebug>
#include <KDialog>
class Nepomuk::TaggingPopup::Private
{
public:
Private( TaggingPopup* parent )
: eventLoop( 0 ),
m_parent( parent ) {
}
QEventLoop* eventLoop;
QPoint popupPos;
QRect geometryForPopupPos( const QPoint& p ) {
QSize size = m_parent->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 );
}
private:
TaggingPopup* m_parent;
};
Nepomuk::TaggingPopup::TaggingPopup( QWidget* parent )
: TagCloud( parent ),
d( new Private( this ) )
{
setFrameStyle( QFrame::Box|QFrame::Plain );
setWindowFlags( Qt::Popup );
}
Nepomuk::TaggingPopup::~TaggingPopup()
{
delete d;
}
void Nepomuk::TaggingPopup::popup( const QPoint& p )
{
setGeometry( d->geometryForPopupPos( p ) );
d->popupPos = p;
show();
}
void Nepomuk::TaggingPopup::exec( const QPoint& pos )
{
QEventLoop eventLoop;
d->eventLoop = &eventLoop;
popup( pos );
QPointer<QObject> guard = this;
(void) eventLoop.exec();
if ( !guard.isNull() )
d->eventLoop = 0;
}
void Nepomuk::TaggingPopup::mousePressEvent( QMouseEvent* e )
{
if ( !rect().contains( e->pos() ) ) {
hide();
}
else {
TagCloud::mousePressEvent( e );
}
}
void Nepomuk::TaggingPopup::hideEvent( QHideEvent* e )
{
Q_UNUSED( e );
if ( d->eventLoop ) {
d->eventLoop->exit();
}
}
bool Nepomuk::TaggingPopup::event( QEvent* e )
{
if ( e->type() == QEvent::LayoutRequest ) {
if ( isVisible() ) {
setGeometry( d->geometryForPopupPos( d->popupPos ) );
return true;
}
}
return TagCloud::event( e );
}
#include "taggingpopup.moc"

View file

@ -0,0 +1,50 @@
/*
This file is part of the Nepomuk KDE project.
Copyright (C) 2007 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 version 2 as published by the Free Software Foundation.
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.
*/
#ifndef _NEPOMUK_TAGGING_POPUP_H_
#define _NEPOMUK_TAGGING_POPUP_H_
#include "tagcloud.h"
class QMouseEvent;
class QHideEvent;
namespace Nepomuk {
class TaggingPopup : public TagCloud
{
public:
TaggingPopup( QWidget* parent = 0 );
~TaggingPopup();
void popup( const QPoint& pos );
void exec( const QPoint& pos );
bool event( QEvent* e );
protected:
void mousePressEvent( QMouseEvent* e );
void hideEvent( QHideEvent* e );
private:
class Private;
Private* const d;
};
}
#endif