summaryrefslogtreecommitdiffstats
path: root/kmrml/kmrml/mrml_view.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kmrml/kmrml/mrml_view.cpp')
-rw-r--r--kmrml/kmrml/mrml_view.cpp480
1 files changed, 480 insertions, 0 deletions
diff --git a/kmrml/kmrml/mrml_view.cpp b/kmrml/kmrml/mrml_view.cpp
new file mode 100644
index 00000000..71f3c741
--- /dev/null
+++ b/kmrml/kmrml/mrml_view.cpp
@@ -0,0 +1,480 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qdom.h>
+#include <qlabel.h>
+#include <qpainter.h>
+#include <qtimer.h>
+#include <qtooltip.h>
+
+#include <kcursor.h>
+#include <kdatastream.h>
+#include <klocale.h>
+#include <kcombobox.h>
+#include <kmimetype.h>
+#include <kurl.h>
+#include <kurldrag.h>
+
+#include "loader.h"
+#include "mrml_creator.h"
+#include "mrml_view.h"
+
+using namespace KMrml;
+
+MrmlView::MrmlView( QWidget *parent, const char *name )
+ : QScrollView( parent, name )
+{
+ setStaticBackground( true );
+ setResizePolicy( Manual );
+ setHScrollBarMode( AlwaysOff );
+ enableClipper( true ); // ### test this
+
+ m_items.setAutoDelete( true );
+
+ connect( Loader::self(), SIGNAL( finished(const KURL&, const QByteArray&)),
+ SLOT( slotDownloadFinished( const KURL&, const QByteArray& )));
+
+ m_timer = new QTimer( this );
+ connect( m_timer, SIGNAL( timeout() ), SLOT( slotLayout() ));
+
+ // we need a pixmap to be shown when no thumbnail is available for a
+ // query result image
+ QLabel l( i18n( "No thumbnail available" ), 0L );
+ l.setFixedSize( 80, 80 );
+ l.setAlignment( WordBreak | AlignCenter );
+// l.setFrameStyle( QLabel::Box | QLabel::Plain );
+// l.setLineWidth( 1 );
+ l.setPaletteBackgroundColor( Qt::white );
+ l.setPaletteForegroundColor( Qt::black );
+ m_unavailablePixmap = QPixmap::grabWidget( &l );
+}
+
+MrmlView::~MrmlView()
+{
+}
+
+MrmlViewItem * MrmlView::addItem( const KURL& url, const KURL& thumbURL,
+ const QString& similarity )
+{
+ bool ok;
+ double value = similarity.toDouble( &ok );
+ if ( !ok || value < 0.05 )
+ return 0L;
+
+ return addItem( url, thumbURL, value );
+}
+
+MrmlViewItem * MrmlView::addItem( const KURL& url, const KURL& thumbURL,
+ double similarity )
+{
+ if ( !url.isValid() ) {
+ qWarning( "MrmlPart: received malformed URL from query: %s",
+ url.prettyURL().isNull() ? "(null)" : url.prettyURL().latin1() );
+ return 0L;
+ }
+
+// qDebug("** url: %s", thumbURL.url().latin1());
+
+ MrmlViewItem *item = new MrmlViewItem( url, thumbURL, similarity, this );
+ QPixmap *pixmap = getPixmap( thumbURL );
+ if ( pixmap )
+ item->setPixmap( *pixmap );
+
+ m_items.append( item );
+
+ m_timer->start( 0, true );
+ return item;
+}
+
+void MrmlView::addRelevanceToQuery( QDomDocument& document,
+ QDomElement& parent )
+{
+ QPtrListIterator<MrmlViewItem> it( m_items );
+ for( ; it.current(); ++it ) {
+ it.current()->createRelevanceElement( document, parent );
+ }
+}
+
+void MrmlView::clear()
+{
+ m_items.clear(); // items are deleted and removed from scrollview
+ setContentsPos( 0, 0 );
+}
+
+QPixmap * MrmlView::getPixmap( const KURL& url )
+{
+ QString u = url.url();
+ QPixmap *pix = m_pixmapCache.find( u );
+ if ( pix )
+ return pix;
+
+ if ( url.isLocalFile() ) {
+ QPixmap p;
+ if ( !p.load( url.path() ) )
+ p = m_unavailablePixmap;
+
+ m_pixmapCache.insert( u, p );
+ return m_pixmapCache.find( u );
+ }
+ else { // remote url, download with KIO
+ Loader::self()->requestDownload( url );
+ }
+
+ return 0L;
+}
+
+void MrmlView::slotDownloadFinished( const KURL& url, const QByteArray& data )
+{
+ QPtrListIterator<MrmlViewItem> it( m_items );
+ for( ; it.current(); ++it ) {
+ MrmlViewItem *item = it.current();
+ if ( item->thumbURL() == url )
+ {
+ QPixmap p;
+ if ( data.isEmpty() || !p.loadFromData( data ) )
+ p = m_unavailablePixmap;
+
+ m_pixmapCache.insert( url.url(), p );
+ item->setPixmap( p );
+
+ slotLayout();
+ return;
+ }
+ }
+}
+
+void MrmlView::stopDownloads()
+{
+ Loader *loader = Loader::self();
+ QPtrListIterator<MrmlViewItem> it( m_items );
+ for( ; it.current(); ++it ) {
+ MrmlViewItem *item = it.current();
+ if ( !item->hasRemotePixmap() )
+ loader->removeDownload( item->url() );
+ }
+}
+
+void MrmlView::slotLayout()
+{
+ int itemWidth = 0;
+ QPtrListIterator<MrmlViewItem> it( m_items );
+
+ for ( ; it.current(); ++it ) {
+ itemWidth = QMAX( itemWidth, it.current()->sizeHint().width() );
+ }
+
+ if ( itemWidth == 0 )
+ return;
+
+
+ uint itemsPerRow = visibleWidth() / itemWidth;
+ int margin = (visibleWidth() - (itemsPerRow * itemWidth)) / 2;
+ int rowHeight = 0;
+ uint item = 0;
+ uint y = 5;
+
+ // pointing to the first item of a row
+ QPtrListIterator<MrmlViewItem> rowIt( m_items );
+
+ for ( it.toFirst(); it.current(); ++it ) {
+ if ( item >= itemsPerRow ) {
+ item = 0;
+ y += rowHeight;
+ rowHeight = 0;
+ }
+
+ if ( item == 0 )
+ rowIt = it;
+
+ rowHeight = QMAX( rowHeight, it.current()->sizeHint().height() );
+ addChild( it.current(), margin + item * itemWidth, y );
+ it.current()->show();
+
+ item++;
+
+ // resize all items of the current row so they all have the same size
+ if ( item >= itemsPerRow || it.atLast() )
+ {
+ for ( uint i = 0; (i < itemsPerRow && rowIt.current()); i++ )
+ {
+ rowIt.current()->resize( itemWidth, rowHeight );
+ ++rowIt;
+ }
+ }
+ }
+
+ resizeContents( visibleWidth(), y + rowHeight );
+}
+
+void MrmlView::resizeEvent( QResizeEvent *e )
+{
+ int oldW = visibleWidth();
+ QScrollView::resizeEvent( e );
+
+ if ( visibleWidth() != oldW )
+ slotLayout();
+}
+
+void MrmlView::saveState( QDataStream& stream )
+{
+ stream << m_items.count();
+ QPtrListIterator<MrmlViewItem> it( m_items );
+ for( ; it.current(); ++it ) {
+ stream << *it.current();
+ }
+
+}
+
+void MrmlView::restoreState( QDataStream& stream )
+{
+ stopDownloads();
+ clear();
+
+ int count;
+ stream >> count;
+
+ KURL url, thumbURL;
+ double similarity;
+ Q_UINT32 relevance;
+ MrmlViewItem *item;
+
+
+ for ( int i = 0; i < count; i++ )
+ {
+ stream >> url;
+ stream >> thumbURL;
+ stream >> similarity;
+ stream >> relevance;
+
+ item = addItem( url, thumbURL, similarity );
+ if ( item )
+ item->setRelevance( (MrmlViewItem::Relevance) relevance );
+ }
+}
+
+QDataStream& KMrml::operator<<( QDataStream& stream,
+ const KMrml::MrmlViewItem& item )
+{
+ return stream << item.url()
+ << item.thumbURL()
+ << item.similarity()
+ << static_cast<Q_UINT32>( item.relevance() );
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+MrmlViewItem::MrmlViewItem( const KURL& url, const KURL& thumbURL,
+ double similarity, MrmlView *view,
+ const char *name )
+ : QFrame( view->viewport() , name ),
+ m_view( view ),
+ m_url( url ),
+ m_thumbURL( thumbURL ),
+ similarityFullWidth( 120 ), // ###
+ m_hasRemotePixmap( false )
+{
+ if ( m_similarity != -1 )
+ m_similarity = QMAX( 0.0, QMIN( 1.0, similarity ));
+ setFrameStyle( Panel | Sunken );
+ setMouseTracking( true );
+
+ m_combo = new KComboBox( this );
+ QToolTip::add( m_combo, i18n("You can refine queries by giving feedback about the current result and pressing the Search button again.") );
+ m_combo->insertItem( i18n("Relevant"), Relevant );
+ m_combo->insertItem( i18n("Neutral"), Neutral );
+ m_combo->insertItem( i18n("Irrelevant"), Irrelevant );
+ m_combo->adjustSize();
+ m_combo->setCurrentItem( Neutral );
+
+ /*
+ if ( similarity > -1 )
+ QToolTip::add( this, QString::fromLatin1("<qt>%1<br>%1</qt>")
+ .arg( url )
+ .arg(i18n("Similarity: %1").arg( QString::number(similarity))));
+ else
+ QToolTip::add( this, QString::fromLatin1("<qt>%1</qt>").arg( url ) );
+ */
+
+ setMinimumSize( 130, 130 ); // ###
+}
+
+MrmlViewItem::~MrmlViewItem()
+{
+}
+
+void MrmlViewItem::setPixmap( const QPixmap& pix )
+{
+ if ( !m_url.isLocalFile() )
+ m_hasRemotePixmap = true;
+
+ m_pixmap = pix;
+ adjustSize();
+ update();
+}
+
+void MrmlViewItem::paintEvent( QPaintEvent *e )
+{
+ QFrame::paintEvent( e );
+
+ if ( !m_pixmap.isNull() ) {
+ bitBlt( this, pixmapX(), pixmapY(),
+ &m_pixmap, 0, 0, m_pixmap.width(), m_pixmap.height(),
+ CopyROP );
+ }
+
+ if ( m_similarity >= 0 ) {
+ QPainter p( this );
+ QPen pen( colorGroup().highlight(), 1, QPen::SolidLine );
+ p.setPen( pen );
+ int x = margin;
+ int y = m_combo->y() - similarityHeight - 2;
+ int w = (int) (similarityFullWidth * m_similarity);
+ int h = similarityHeight;
+ p.drawRect( x, y, similarityFullWidth, h );
+ p.fillRect( x, y, w, h, colorGroup().highlight() );
+ }
+}
+
+void MrmlViewItem::resizeEvent( QResizeEvent *e )
+{
+ QFrame::resizeEvent( e );
+
+ int y = height() - m_combo->height() - margin;
+ m_combo->move( width()/2 - m_combo->width()/2, y );
+}
+
+QSize MrmlViewItem::sizeHint() const
+{
+ int w = QMAX( QMAX(minimumHeight(), m_combo->width()), m_pixmap.width() );
+ w += 2 * margin;
+
+ int h = m_pixmap.isNull() ? margin : margin + spacing + m_pixmap.height();
+ h += (m_similarity > -1) ? similarityHeight + spacing : 0;
+ h += m_combo->height() + margin;
+
+ return QSize( w, h );
+}
+
+void MrmlViewItem::mousePressEvent( QMouseEvent *e )
+{
+ QFrame::mousePressEvent( e );
+ pressedPos.setX( 0 );
+ pressedPos.setY( 0 );
+
+
+ if ( e->button() == LeftButton || e->button() == MidButton ) {
+ if ( hitsPixmap( e->pos() ) )
+ pressedPos = e->pos();
+ }
+ else if ( e->button() == RightButton && hitsPixmap( e->pos() ) )
+ emit view()->activated( m_url, e->button() );
+}
+
+void MrmlViewItem::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( hitsPixmap( e->pos() ) ) {
+ if ( !ownCursor() ) { // nice hacklet :)
+ setCursor( KCursor::handCursor() );
+ emit view()->onItem( m_url );
+ }
+ }
+ else {
+ if ( ownCursor() ) {
+ unsetCursor();
+ emit view()->onItem( KURL() );
+ }
+ }
+
+ if ( (e->state() & LeftButton) && !pressedPos.isNull() ) {
+ QPoint dist = e->pos() - pressedPos;
+ if ( dist.manhattanLength() > KGlobalSettings::dndEventDelay() ) {
+ // start drag here
+ KURL::List urls;
+ // ### support multiple files?
+ urls.append( m_url );
+ KURLDrag *drag = new KURLDrag( urls, this );
+ drag->setPixmap( KMimeType::pixmapForURL( m_url ) );
+ drag->drag();
+ }
+ }
+}
+
+void MrmlViewItem::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( hitsPixmap( e->pos() )) {
+ QPoint dist = e->pos() - pressedPos;
+ if ( dist.manhattanLength() < KGlobalSettings::dndEventDelay() ) {
+ emit view()->activated( m_url, e->button() );
+ }
+ }
+}
+
+bool MrmlViewItem::hitsPixmap( const QPoint& pos ) const
+{
+ if ( m_pixmap.isNull() )
+ return false;
+
+ if ( pos.x() > pixmapX() && pos.x() < pixmapX() + m_pixmap.width() &&
+ pos.y() > pixmapY() && pos.y() < pixmapY() + m_pixmap.height() )
+ return true;
+ return false;
+}
+
+void MrmlViewItem::createRelevanceElement( QDomDocument& document,
+ QDomElement& parent )
+{
+ int rel = m_combo->currentItem();
+ if ( rel == Neutral )
+ return;
+
+ MrmlCreator::createRelevanceElement( document, parent, m_url.url(),
+ (rel == Relevant) ? MrmlCreator::Relevant : MrmlCreator::Irrelevant );
+}
+
+MrmlViewItem::Relevance MrmlViewItem::relevance() const
+{
+ return (Relevance) m_combo->currentItem();
+}
+
+void MrmlViewItem::setRelevance( Relevance relevance )
+{
+ m_combo->setCurrentItem( relevance );
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+int MrmlViewItemList::compareItems( QPtrCollection::Item item1,
+ QPtrCollection::Item item2 )
+{
+ double s1 = (static_cast<MrmlViewItem*>( item1 ))->similarity();
+ double s2 = (static_cast<MrmlViewItem*>( item2 ))->similarity();
+
+ if ( s1 < s2 )
+ return 1;
+ else if ( s1 > s2 )
+ return -1;
+ else
+ return 0;
+}
+
+#include "mrml_view.moc"