diff options
Diffstat (limited to 'src/tagcloud/tagcloud.cpp')
| -rw-r--r-- | src/tagcloud/tagcloud.cpp | 1005 |
1 files changed, 0 insertions, 1005 deletions
diff --git a/src/tagcloud/tagcloud.cpp b/src/tagcloud/tagcloud.cpp deleted file mode 100644 index 0074d1796..000000000 --- a/src/tagcloud/tagcloud.cpp +++ /dev/null @@ -1,1005 +0,0 @@ -/* - This file is part of the Nepomuk KDE project. - Copyright (C) 2007 Sebastian Trueg <[email protected]> - - 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 "tagcloud.h" -#include "newtagdialog.h" - -#include <QtGui/QFont> -#include <QtGui/QFontMetrics> -#include <QtCore/QList> -#include <QtGui/QPushButton> -#include <QtCore/Qt> -#include <QtCore/QTime> -#include <QtGui/QPainter> -#include <QtGui/QMouseEvent> -#include <QtGui/QPalette> -#include <QtGui/QInputDialog> -#include <QtGui/QAction> - -#include <KRandomSequence> -#include <KLocale> -#include <KColorScheme> -#include <KDebug> - -#include <Soprano/Client/DBusModel> -#include <Soprano/QueryResultIterator> -#include <Soprano/Vocabulary/RDF> -#include <Soprano/Vocabulary/NAO> - -#include <nepomuk/resourcemanager.h> - -#include <math.h> - - -namespace { - const int s_hSpacing = 10; - const int s_vSpacing = 5; - - class TagNode { - public: - TagNode() - : weight( 0 ), - selected( false ) { - } - - // fixed info - Nepomuk::Tag tag; - int weight; - - // misc - bool selected; - - // info generated by rebuildCloud - QFont font; - QRect rect; - QRect zoomedRect; - QString text; - }; - - bool tagNodeNameLessThan( const TagNode& n1, const TagNode& n2 ) { - return n1.text < n2.text; - } - - bool tagNodeWeightLessThan( const TagNode& n1, const TagNode& n2 ) { - return n1.weight < n2.weight; - } - - int rowLength( const QList<TagNode*>& row ) { - int rowLen = 0; - for ( int j = 0; j < row.count(); ++j ) { - rowLen += row[j]->rect.width(); - if ( j < row.count()-1 ) { - rowLen += s_hSpacing; - } - } - return rowLen; - } - - int rowHeight( const QList<TagNode*>& row ) { - int h = 0; - for ( int j = 0; j < row.count(); ++j ) { - h = qMax( row[j]->rect.height(), h ); - } - return h; - } - - QSize cloudSize( const QList<QList<TagNode*> >& rows ) { - int w = 0; - int h = 0; - for ( int i = 0; i < rows.count(); ++i ) { - w = qMax( w, rowLength( rows[i] ) ); - h += rowHeight( rows[i] ); - if ( i < rows.count()-1 ) { - h += s_vSpacing; - } - } - return QSize( w, h ); - } -} - - -class Nepomuk::TagCloud::Private -{ -public: - Private( TagCloud* parent ) - : maxFontSize( 0 ), - minFontSize( 0 ), - maxNumberDisplayedTags( 0 ), - selectionEnabled( false ), - newTagButtonEnabled( false ), - alignment( Qt::AlignCenter ), - sorting( SortAlpabetically ), - zoomEnabled( true ), - showAllTags( false ), - customNewTagAction( 0 ), - hoverTag( 0 ), - cachedHfwWidth( -1 ), - m_parent( parent ) { - newTagNode.text = i18nc( "@label", "New Tag..." ); - } - - int maxFontSize; - int minFontSize; - int maxNumberDisplayedTags; - bool selectionEnabled; - bool newTagButtonEnabled; - Qt::Alignment alignment; - Sorting sorting; - bool zoomEnabled; - - // The resource whose tags we are showing - // invalid if we show all tags or a selection - KUrl resource; - bool showAllTags; - - // the actual nodes - QList<TagNode> nodes; - - // just a helper structure for speeding up things - QList<QList<TagNode*> > rows; - - TagNode newTagNode; - QAction* customNewTagAction; - - TagNode* hoverTag; - - QMatrix zoomMatrix; - - QSize cachedSizeHint; - int cachedHfwWidth; - int cachedHfwHeight; - - void invalidateCachedValues() { - cachedSizeHint = QSize(); - cachedHfwWidth = -1; - } - - int getMinFontSize() const; - int getMaxFontSize() const; - void updateNodeWeights(); - void updateNodeFonts(); - void sortNodes(); - void rebuildCloud(); - TagNode* tagAt( const QPoint& pos ); - TagNode* findTagInRow( const QList<TagNode*>& row, const QPoint& pos ); - TagNode* nodeForTag( const Tag& tag ); - int calculateWeight( const Nepomuk::Tag& tag ); - -private: - TagCloud* m_parent; -}; - - -int Nepomuk::TagCloud::Private::getMinFontSize() const -{ - return minFontSize > 0 ? minFontSize : ( 8 * m_parent->font().pointSize() / 10 ); -} - - -int Nepomuk::TagCloud::Private::getMaxFontSize() const -{ - return maxFontSize > 0 ? maxFontSize : ( 22 * m_parent->font().pointSize() / 10 ); -} - - -int Nepomuk::TagCloud::Private::calculateWeight( const Nepomuk::Tag& tag ) -{ - // stupid SPARQL has no functions such as count! - Soprano::QueryResultIterator it - = ResourceManager::instance()->mainModel()->executeQuery( QString( "select ?r where { ?r <%1> <%2> . }" ) - .arg( Soprano::Vocabulary::NAO::hasTag().toString() ) - .arg( QString::fromAscii( tag.resourceUri().toEncoded() ) ), - Soprano::Query::QueryLanguageSparql ); - int w = 0; - while ( it.next() ) { - ++w; - } - return w; -} - - -void Nepomuk::TagCloud::Private::updateNodeWeights() -{ - bool changedWeights = false; - for ( QList<TagNode>::iterator it = nodes.begin(); - it != nodes.end(); ++it ) { - TagNode& node = *it; - int w = calculateWeight( node.tag ); - if ( w != node.weight ) { - node.weight = w; - changedWeights = true; - } - } - if ( changedWeights ) { - updateNodeFonts(); - } -} - - -void Nepomuk::TagCloud::Private::updateNodeFonts() -{ - int maxWeight = 0; - int minWeight = 0; - for ( QList<TagNode>::iterator it = nodes.begin(); - it != nodes.end(); ++it ) { - TagNode& node = *it; - minWeight = qMin( minWeight, node.weight ); - maxWeight = qMax( maxWeight, node.weight ); - } - - // calculate font sizes - // ---------------------------------------------- - int usedMinFontSize = getMinFontSize(); - int usedMaxFontSize = getMaxFontSize(); - for ( QList<TagNode>::iterator it = nodes.begin(); - it != nodes.end(); ++it ) { - TagNode& node = *it; - double normalizedWeight = (double)(node.weight - minWeight) / (double)qMax(maxWeight - minWeight, 1); - node.font = m_parent->font(); - node.font.setPointSize( usedMinFontSize + (int)((double)(usedMaxFontSize-usedMinFontSize) * normalizedWeight) ); - if( normalizedWeight > 0.8 ) - node.font.setBold( true ); - } - - if ( newTagButtonEnabled ) { - newTagNode.font = m_parent->font(); - newTagNode.font.setPointSize( usedMinFontSize ); - newTagNode.font.setUnderline( true ); - } -} - - -void Nepomuk::TagCloud::Private::sortNodes() -{ - if ( sorting == SortAlpabetically ) { - qSort( nodes.begin(), nodes.end(), tagNodeNameLessThan ); - } - else if ( sorting == SortByWeight ) { - qSort( nodes.begin(), nodes.end(), tagNodeWeightLessThan ); - } - else if ( sorting == SortRandom ) { - KRandomSequence().randomize( nodes ); - } -} - - -void Nepomuk::TagCloud::Private::rebuildCloud() -{ - // - Always try to be quadratic - // - Always prefer to expand horizontally - // - If we cannot fit everything into m_parent->contentsRect(), zoom - // - If alignment & Qt::AlignJustify insert spaces between tags - - sortNodes(); - - QRect contentsRect = m_parent->contentsRect(); - - // initialize the nodes' sizes - // ---------------------------------------------- - for ( QList<TagNode>::iterator it = nodes.begin(); - it != nodes.end(); ++it ) { - TagNode& node = *it; - node.rect = QFontMetrics( node.font ).boundingRect( node.text ); - } - if ( newTagButtonEnabled ) { - newTagNode.rect = QFontMetrics( newTagNode.font ).boundingRect( customNewTagAction ? customNewTagAction->text() : newTagNode.text ); - } - - - // and position the nodes - // ---------------------------------------------- - rows.clear(); - if ( !nodes.isEmpty() || newTagButtonEnabled ) { - if ( 0 ) { // FIXME: make it configurable - QRect lineRect; - QRect totalRect; - QList<TagNode*> row; - for ( QList<TagNode>::iterator it = nodes.begin(); - it != nodes.end(); /* We do increment it below */ ) { - TagNode& node = *it; - - int usedSpacing = row.isEmpty() ? 0 : s_hSpacing; - if ( lineRect.width() + usedSpacing + node.rect.width() <= contentsRect.width() ) { - node.rect.moveBottomLeft( QPoint( lineRect.right() + usedSpacing, lineRect.bottom() ) ); - QRect newLineRect = lineRect.united( node.rect ); - newLineRect.moveTopLeft( lineRect.topLeft() ); - lineRect = newLineRect; - row.append( &node ); - - // update all other nodes in this line - Q_FOREACH( TagNode* n, row ) { - n->rect.moveBottom( lineRect.bottom() - ( lineRect.height() - n->rect.height() )/2 ); - } - - ++it; - } - else { - rows.append( row ); - row.clear(); - int newLineTop = lineRect.bottom() + s_vSpacing; - lineRect = QRect(); - lineRect.moveTop( newLineTop ); - } - } - rows.append( row ); - } - else { - // initialize first row - rows.append( QList<TagNode*>() ); - for ( QList<TagNode>::iterator it = nodes.begin(); - it != nodes.end(); ++it ) { - TagNode& node = *it; - rows.first().append( &node ); - } - if ( newTagButtonEnabled ) { - rows.first().append( &newTagNode ); - } - - // calculate the rows - QList<QList<TagNode*> > bestRows( rows ); - QSize size( rowLength( rows.first() ), rowHeight( rows.first() ) ); - QSize bestSize( size ); - while ( ( size.height() < size.width() || - size.width() > contentsRect.width() ) && - size.height() <= contentsRect.height() ) { - // find the longest row - int maxRow = 0; - int maxLen = 0; - for ( int i = 0; i < rows.count(); ++i ) { - int rowLen = rowLength( rows[i] ); - if ( rowLen > maxLen ) { - maxLen = rowLen; - maxRow = i; - } - } - - // move the last item from the longest row to the next row - TagNode* node = rows[maxRow].takeLast(); - if ( rows.count() <= maxRow+1 ) { - rows.append( QList<TagNode*>() ); - } - rows[maxRow+1].prepend( node ); - - // update the size - size = cloudSize( rows ); - - if ( size.width() < bestSize.width() && - ( size.width() > size.height() || - bestSize.width() > contentsRect.width() ) && - size.height() <= contentsRect.height() ) { - bestSize = size; - bestRows = rows; - } - } - rows = bestRows; - - // position the tags - int y = 0; - for ( QList<QList<TagNode*> >::iterator rowIt = rows.begin(); rowIt != rows.end(); ++rowIt ) { - QList<TagNode*>& row = *rowIt; - int h = rowHeight( row ); - int x = 0; - Q_FOREACH( TagNode* node, row ) { - node->rect.moveTop( y + ( h - node->rect.height() )/2 ); - node->rect.moveLeft( x ); - x += s_hSpacing + node->rect.width(); - } - y += h + s_vSpacing; - } - } - - - // let's see if we have to zoom - // ---------------------------------------------- - zoomMatrix = QMatrix(); - int w = contentsRect.width(); - if ( zoomEnabled ) { - for ( QList<QList<TagNode*> >::iterator rowIt = rows.begin(); rowIt != rows.end(); ++rowIt ) { - QList<TagNode*>& row = *rowIt; - w = qMax( w, row.last()->rect.right() ); - } - if ( w > contentsRect.width() ) { - double zoomFactor = ( double )contentsRect.width() / ( double )w; - zoomMatrix.scale( zoomFactor, zoomFactor ); - } - } - - // force horizontal alignment - // ---------------------------------------------- - for ( QList<QList<TagNode*> >::iterator rowIt = rows.begin(); rowIt != rows.end(); ++rowIt ) { - QList<TagNode*>& row = *rowIt; - int space = /*contentsRect.right()*/w - row.last()->rect.right(); - if ( alignment & ( Qt::AlignRight|Qt::AlignHCenter ) ) { - Q_FOREACH( TagNode* node, row ) { - node->rect.moveLeft( node->rect.left() + ( alignment & Qt::AlignRight ? space : space/2 ) ); - } - } - else if ( alignment & Qt::AlignJustify && row.count() > 1 ) { - space /= ( row.count()-1 ); - int i = 0; - Q_FOREACH( TagNode* node, row ) { - node->rect.moveLeft( node->rect.left() + ( space * i++ ) ); - } - } - } - - // force vertical alignment - // ---------------------------------------------- - int verticalSpace = contentsRect.bottom() - rows.last().first()->rect.bottom(); - if ( alignment & ( Qt::AlignBottom|Qt::AlignVCenter ) ) { - for ( QList<QList<TagNode*> >::iterator rowIt = rows.begin(); rowIt != rows.end(); ++rowIt ) { - Q_FOREACH( TagNode* node, *rowIt ) { - node->rect.moveTop( node->rect.top() + ( alignment & Qt::AlignBottom ? verticalSpace : verticalSpace/2 ) ); - } - } - } - - for( QList<TagNode>::iterator it = nodes.begin(); it != nodes.end(); ++it ) { - it->zoomedRect = zoomMatrix.mapRect( it->rect ); - } - newTagNode.zoomedRect = zoomMatrix.mapRect( newTagNode.rect ); - } - - m_parent->updateGeometry(); - m_parent->update(); -} - - -// binary search in row -TagNode* Nepomuk::TagCloud::Private::findTagInRow( const QList<TagNode*>& row, const QPoint& pos ) -{ - int x = m_parent->width() ? row.count() * pos.x() / m_parent->width() : 0; - - int i = 0; - while ( 1 ) { - if ( x-i >= 0 && x-i < row.count() && row[x-i]->zoomedRect.contains( pos ) ) { - return row[x-i]; - } - else if ( x+i >= 0 && x+i < row.count() && row[x+i]->zoomedRect.contains( pos ) ) { - return row[x+i]; - } - if ( x-i < 0 && x+i >= row.count() ) { - return 0; - } - ++i; - } - return 0; -} - - -// binary search in cloud -TagNode* Nepomuk::TagCloud::Private::tagAt( const QPoint& pos ) -{ - int y = m_parent->height() ? rows.count() * pos.y() / m_parent->height() : 0; - - int i = 0; - while ( 1 ) { - if ( y-i >= 0 && y-i < rows.count() ) { - if ( TagNode* node = findTagInRow( rows[y-i], pos ) ) { - return node; - } - } - if ( y+i >= 0 && y+i < rows.count() ) { - if ( TagNode* node = findTagInRow( rows[y+i], pos ) ) { - return node; - } - } - if ( y-i < 0 && y+i >= rows.count() ) { - return 0; - } - ++i; - } - return 0; -} - - -TagNode* Nepomuk::TagCloud::Private::nodeForTag( const Tag& tag ) -{ - for ( QList<TagNode>::iterator it = nodes.begin(); - it != nodes.end(); ++it ) { - TagNode& node = *it; - if ( tag == node.tag ) { - return &node; - } - } - return 0; -} - - - -Nepomuk::TagCloud::TagCloud( QWidget* parent ) - : QFrame( parent ), - d( new Private(this) ) -{ - QSizePolicy policy( QSizePolicy::Preferred, - QSizePolicy::Preferred ); - policy.setHeightForWidth( true ); - setSizePolicy( policy ); - setMouseTracking( true ); - - // Since signals are delivered in no particular order - // our slot might be called before the resources are updated - // Then, we would use invalid cached data. - // By using queued connections this problem should be solved. - connect( ResourceManager::instance()->mainModel(), - SIGNAL( statementAdded( const Soprano::Statement& ) ), - this, - SLOT( slotStatementAdded( const Soprano::Statement& ) ), - Qt::QueuedConnection ); - connect( ResourceManager::instance()->mainModel(), - SIGNAL( statementRemoved( const Soprano::Statement& ) ), - this, - SLOT( slotStatementRemoved( const Soprano::Statement& ) ), - Qt::QueuedConnection ); -} - - -Nepomuk::TagCloud::~TagCloud() -{ - delete d; -} - - -void Nepomuk::TagCloud::setMaxFontSize( int size ) -{ - d->invalidateCachedValues(); - d->maxFontSize = size; - d->updateNodeFonts(); - d->rebuildCloud(); -} - - -void Nepomuk::TagCloud::setMinFontSize( int size ) -{ - d->invalidateCachedValues(); - d->minFontSize = size; - d->updateNodeFonts(); - d->rebuildCloud(); -} - - -void Nepomuk::TagCloud::setMaxNumberDisplayedTags( int n ) -{ - d->maxNumberDisplayedTags = n; - d->rebuildCloud(); -} - - -void Nepomuk::TagCloud::setSelectionEnabled( bool enabled ) -{ - d->selectionEnabled = enabled; - update(); -} - - -void Nepomuk::TagCloud::setNewTagButtonEnabled( bool enabled ) -{ - d->newTagButtonEnabled = enabled; - d->rebuildCloud(); -} - - -bool Nepomuk::TagCloud::zoomEnabled() const -{ - return d->zoomEnabled; -} - - -void Nepomuk::TagCloud::setZoomEnabled( bool zoom ) -{ - if ( d->zoomEnabled != zoom ) { - d->zoomEnabled = zoom; - d->rebuildCloud(); - } -} - - -void Nepomuk::TagCloud::setContextMenuEnabled( bool enabled ) -{ - Q_UNUSED(enabled); -} - - -void Nepomuk::TagCloud::setAlignment( Qt::Alignment alignment ) -{ - d->alignment = alignment; - d->rebuildCloud(); -} - - -void Nepomuk::TagCloud::setSorting( Sorting s ) -{ - d->invalidateCachedValues(); - d->sorting = s; - d->rebuildCloud(); -} - - -void Nepomuk::TagCloud::showAllTags() -{ - showTags( Nepomuk::Tag::allTags() ); - d->showAllTags = true; -} - - -void Nepomuk::TagCloud::showResourceTags( const Resource& resource ) -{ - showTags( resource.tags() ); - d->resource = resource.uri(); -} - - -void Nepomuk::TagCloud::showTags( const QList<Tag>& tags ) -{ - d->resource = QUrl(); - d->showAllTags = false; - d->invalidateCachedValues(); - d->nodes.clear(); - Q_FOREACH( const Tag &tag, tags ) { - TagNode node; - node.tag = tag; - node.weight = d->calculateWeight( tag ); - node.text = node.tag.genericLabel(); - - d->nodes.append( node ); - } - d->updateNodeFonts(); - d->rebuildCloud(); -} - - -void Nepomuk::TagCloud::setTagSelected( const Tag& tag, bool selected ) -{ - if ( TagNode* node = d->nodeForTag( tag ) ) { - node->selected = selected; - if ( d->selectionEnabled ) { - update( node->zoomedRect ); - } - } -} - - -QSize Nepomuk::TagCloud::sizeHint() const -{ - // If we have tags d->rebuildCloud() has been called at least once, - // thus, we have proper rects (i.e. needed sizes) - - if ( !d->cachedSizeHint.isValid() ) { - QList<QList<TagNode*> > rows; - rows.append( QList<TagNode*>() ); - for ( QList<TagNode>::iterator it = d->nodes.begin(); - it != d->nodes.end(); ++it ) { - TagNode& node = *it; - rows.first().append( &node ); - } - if ( d->newTagButtonEnabled ) { - rows.first().append( &d->newTagNode ); - } - - QSize size( rowLength( rows.first() ), rowHeight( rows.first() ) ); - QSize bestSize( size ); - while ( size.height() < size.width() ) { - // find the longest row - int maxRow = 0; - int maxLen = 0; - for ( int i = 0; i < rows.count(); ++i ) { - int rowLen = rowLength( rows[i] ); - if ( rowLen > maxLen ) { - maxLen = rowLen; - maxRow = i; - } - } - - // move the last item from the longest row to the next row - TagNode* node = rows[maxRow].takeLast(); - if ( rows.count() <= maxRow+1 ) { - rows.append( QList<TagNode*>() ); - } - rows[maxRow+1].prepend( node ); - - // update the size - size = cloudSize( rows ); - - if ( size.width() < bestSize.width() && - size.width() > size.height() ) { - bestSize = size; - } - } - - d->cachedSizeHint = QSize( bestSize.width() + frameWidth()*2, - bestSize.height() + frameWidth()*2 ); - } - - return d->cachedSizeHint; -} - - -QSize Nepomuk::TagCloud::minimumSizeHint() const -{ - return QFrame::minimumSizeHint(); - // If we have tags d->rebuildCloud() has been called at least once, - // thus, we have proper rects (i.e. needed sizes) - if ( d->nodes.isEmpty() && !d->newTagButtonEnabled ) { - return QSize( fontMetrics().width( i18nc( "@label Indicator when no tags defined", "No Tags" ) ), fontMetrics().height() ); - } - else { - QSize size; - for ( QList<TagNode>::iterator it = d->nodes.begin(); - it != d->nodes.end(); ++it ) { - size.setWidth( qMax( size.width(), ( *it ).rect.width() ) ); - size.setHeight( qMax( size.height(), ( *it ).rect.height() ) ); - } - if ( d->newTagButtonEnabled ) { - size.setWidth( qMax( size.width(), d->newTagNode.rect.width() ) ); - size.setHeight( qMax( size.height(), d->newTagNode.rect.height() ) ); - } - size.setWidth( size.width() + frameWidth()*2 ); - size.setHeight( size.height() + frameWidth()*2 ); - return size; - } -} - - -int Nepomuk::TagCloud::heightForWidth( int contentsWidth ) const -{ - // If we have tags d->rebuildCloud() has been called at least once, - // thus, we have proper rects (i.e. needed sizes) - - if ( d->cachedHfwWidth != contentsWidth ) { - // have to keep in mind the frame - contentsWidth -= frameWidth()*2; - - QList<TagNode*> allNodes; - for ( QList<TagNode>::iterator it = d->nodes.begin(); - it != d->nodes.end(); ++it ) { - TagNode& node = *it; - allNodes.append( &node ); - } - if ( d->newTagButtonEnabled ) { - allNodes.append( &d->newTagNode ); - } - - int h = 0; - bool newRow = true; - int rowW = 0; - int rowH = 0; - int maxW = 0; - for ( int i = 0; i < allNodes.count(); ++i ) { - int w = rowW; - if ( !newRow ) { - w += s_hSpacing; - } - newRow = false; - w += allNodes[i]->rect.width(); - if ( w <= contentsWidth ) { - rowH = qMax( rowH, allNodes[i]->rect.height() ); - rowW = w; - } - else { - if ( h > 0 ) { - h += s_vSpacing; - } - h += rowH; - rowH = allNodes[i]->rect.height(); - rowW = allNodes[i]->rect.width(); - } - maxW = qMax( maxW, rowW ); - } - if ( rowH > 0 ) { - h += s_vSpacing + rowH; - } - - d->cachedHfwWidth = contentsWidth; - d->cachedHfwHeight = h; - - // zooming - if ( maxW > contentsWidth ) { - d->cachedHfwHeight = d->cachedHfwHeight * contentsWidth / maxW; - } - } - - return d->cachedHfwHeight + frameWidth()*2; -} - - -void Nepomuk::TagCloud::resizeEvent( QResizeEvent* e ) -{ - QFrame::resizeEvent( e ); - d->rebuildCloud(); - update(); -} - - -void Nepomuk::TagCloud::paintEvent( QPaintEvent* e ) -{ - QFrame::paintEvent( e ); - - KStatefulBrush normalTextBrush( KColorScheme::View, KColorScheme::NormalText ); - KStatefulBrush activeTextBrush( KColorScheme::View, KColorScheme::VisitedText ); - KStatefulBrush hoverTextBrush( KColorScheme::View, KColorScheme::ActiveText ); - - QPainter p( this ); - QRegion paintRegion = e->region(); - - p.save(); - p.setMatrix( d->zoomMatrix ); - - for ( QList<TagNode>::iterator it = d->nodes.begin(); - it != d->nodes.end(); ++it ) { - TagNode& node = *it; - - if ( paintRegion.contains( node.zoomedRect ) ) { - p.setFont( node.font ); - - if ( &node == d->hoverTag ) { - p.setPen( hoverTextBrush.brush( this ).color() ); - } - else if ( d->selectionEnabled && node.selected ) { - p.setPen( activeTextBrush.brush( this ).color() ); - } - else { - p.setPen( normalTextBrush.brush( this ).color() ); - } - p.drawText( node.rect, Qt::AlignCenter, node.text ); - } - } - - if ( d->newTagButtonEnabled ) { - p.setFont( d->newTagNode.font ); - if ( &d->newTagNode == d->hoverTag ) { - p.setPen( hoverTextBrush.brush( this ).color() ); - } - else { - p.setPen( normalTextBrush.brush( this ).color() ); - } - p.drawText( d->newTagNode.rect, Qt::AlignCenter, d->customNewTagAction ? d->customNewTagAction->text() : d->newTagNode.text ); - } - - p.restore(); -} - - -void Nepomuk::TagCloud::mousePressEvent( QMouseEvent* e ) -{ - if ( e->button() == Qt::LeftButton ) { - if ( TagNode* node = d->tagAt( e->pos() ) ) { - kDebug() << "clicked" << node->text; - if ( node == &d->newTagNode ) { - if ( d->customNewTagAction ) { - d->customNewTagAction->trigger(); - } - else { - // FIXME: nicer gui - Tag newTag = NewTagDialog::createTag( this ); - if ( newTag.isValid() ) { - emit tagAdded( newTag ); - } - } - } - else { - emit tagClicked( node->tag ); - if ( d->selectionEnabled ) { - kDebug() << "Toggleing tag" << node->text; - node->selected = !node->selected; - emit tagToggled( node->tag, node->selected ); - update( node->zoomedRect ); - } - } - } - } -} - - -void Nepomuk::TagCloud::mouseMoveEvent( QMouseEvent* e ) -{ - if ( e->buttons() == Qt::NoButton ) { - - TagNode* oldHoverTag = d->hoverTag; - - if ( ( d->hoverTag = d->tagAt( e->pos() ) ) && - !d->selectionEnabled ) { - setCursor( Qt::PointingHandCursor ); - } - else if ( d->newTagButtonEnabled && - d->newTagNode.zoomedRect.contains( e->pos() ) ) { - d->hoverTag = &d->newTagNode; - setCursor( Qt::PointingHandCursor ); - } - else { - unsetCursor(); - } - - if ( oldHoverTag || d->hoverTag ) { - QRect updateRect; - if ( d->hoverTag ) - updateRect = updateRect.united( d->hoverTag->zoomedRect ); - if ( oldHoverTag ) - updateRect = updateRect.united( oldHoverTag->zoomedRect ); - - update( updateRect ); - } - } -} - - -void Nepomuk::TagCloud::leaveEvent( QEvent* ) -{ - unsetCursor(); - if ( d->hoverTag ) { - QRect updateRect = d->hoverTag->zoomedRect; - d->hoverTag = 0; - update( updateRect ); - } -} - - -void Nepomuk::TagCloud::slotStatementAdded( const Soprano::Statement& s ) -{ - if ( s.predicate().uri() == Soprano::Vocabulary::RDF::type() && - s.object().uri() == Nepomuk::Tag::resourceTypeUri() ) { - // new tag created - if ( d->showAllTags ) { - showAllTags(); - } - } - else if ( s.predicate().uri() == Nepomuk::Resource::tagUri() ) { - if ( s.subject().uri() == d->resource ) { - showResourceTags( d->resource ); - } - else { - // weights might have changed - d->updateNodeWeights(); - d->rebuildCloud(); - } - } -} - - -void Nepomuk::TagCloud::slotStatementRemoved( const Soprano::Statement& s ) -{ - // FIXME: In theory might contain empty nodes as wildcards - - if ( s.predicate().uri() == Nepomuk::Resource::tagUri() ) { - if ( d->resource.isValid() && - d->resource == s.subject().uri() ) { - showResourceTags( d->resource ); - } - else { - // weights might have changed - d->updateNodeWeights(); - d->rebuildCloud(); - } - } - else if ( s.predicate().uri() == Soprano::Vocabulary::RDF::type() && - s.object().uri() == Nepomuk::Tag::resourceTypeUri() ) { - // tag deleted - if ( d->showAllTags ) { - showAllTags(); - } - } -} - - -void Nepomuk::TagCloud::setCustomNewTagAction( QAction* action ) -{ - d->customNewTagAction = action; - setNewTagButtonEnabled( action != 0 ); -} - -#include "tagcloud.moc" |
