You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
481 lines
13 KiB
481 lines
13 KiB
/* 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 <tqdom.h>
|
|
#include <tqlabel.h>
|
|
#include <tqpainter.h>
|
|
#include <tqtimer.h>
|
|
#include <tqtooltip.h>
|
|
|
|
#include <kcursor.h>
|
|
#include <kdatastream.h>
|
|
#include <tdelocale.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( TQWidget *parent, const char *name )
|
|
: TQScrollView( parent, name )
|
|
{
|
|
setStaticBackground( true );
|
|
setResizePolicy( Manual );
|
|
setHScrollBarMode( AlwaysOff );
|
|
enableClipper( true ); // ### test this
|
|
|
|
m_items.setAutoDelete( true );
|
|
|
|
connect( Loader::self(), TQT_SIGNAL( finished(const KURL&, const TQByteArray&)),
|
|
TQT_SLOT( slotDownloadFinished( const KURL&, const TQByteArray& )));
|
|
|
|
m_timer = new TQTimer( this );
|
|
connect( m_timer, TQT_SIGNAL( timeout() ), TQT_SLOT( slotLayout() ));
|
|
|
|
// we need a pixmap to be shown when no thumbnail is available for a
|
|
// query result image
|
|
TQLabel l( i18n( "No thumbnail available" ), 0L );
|
|
l.setFixedSize( 80, 80 );
|
|
l.setAlignment( WordBreak | AlignCenter );
|
|
// l.setFrameStyle( TQLabel::Box | TQLabel::Plain );
|
|
// l.setLineWidth( 1 );
|
|
l.setPaletteBackgroundColor( TQt::white );
|
|
l.setPaletteForegroundColor( TQt::black );
|
|
m_unavailablePixmap = TQPixmap::grabWidget( &l );
|
|
}
|
|
|
|
MrmlView::~MrmlView()
|
|
{
|
|
}
|
|
|
|
MrmlViewItem * MrmlView::addItem( const KURL& url, const KURL& thumbURL,
|
|
const TQString& 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() ) {
|
|
tqWarning( "MrmlPart: received malformed URL from query: %s",
|
|
url.prettyURL().isNull() ? "(null)" : url.prettyURL().latin1() );
|
|
return 0L;
|
|
}
|
|
|
|
// tqDebug("** url: %s", thumbURL.url().latin1());
|
|
|
|
MrmlViewItem *item = new MrmlViewItem( url, thumbURL, similarity, this );
|
|
TQPixmap *pixmap = getPixmap( thumbURL );
|
|
if ( pixmap )
|
|
item->setPixmap( *pixmap );
|
|
|
|
m_items.append( item );
|
|
|
|
m_timer->start( 0, true );
|
|
return item;
|
|
}
|
|
|
|
void MrmlView::addRelevanceToQuery( TQDomDocument& document,
|
|
TQDomElement& parent )
|
|
{
|
|
TQPtrListIterator<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 );
|
|
}
|
|
|
|
TQPixmap * MrmlView::getPixmap( const KURL& url )
|
|
{
|
|
TQString u = url.url();
|
|
TQPixmap *pix = m_pixmapCache.find( u );
|
|
if ( pix )
|
|
return pix;
|
|
|
|
if ( url.isLocalFile() ) {
|
|
TQPixmap p;
|
|
if ( !p.load( url.path() ) )
|
|
p = m_unavailablePixmap;
|
|
|
|
m_pixmapCache.insert( u, p );
|
|
return m_pixmapCache.find( u );
|
|
}
|
|
else { // remote url, download with TDEIO
|
|
Loader::self()->requestDownload( url );
|
|
}
|
|
|
|
return 0L;
|
|
}
|
|
|
|
void MrmlView::slotDownloadFinished( const KURL& url, const TQByteArray& data )
|
|
{
|
|
TQPtrListIterator<MrmlViewItem> it( m_items );
|
|
for( ; it.current(); ++it ) {
|
|
MrmlViewItem *item = it.current();
|
|
if ( item->thumbURL() == url )
|
|
{
|
|
TQPixmap 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();
|
|
TQPtrListIterator<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;
|
|
TQPtrListIterator<MrmlViewItem> it( m_items );
|
|
|
|
for ( ; it.current(); ++it ) {
|
|
itemWidth = TQMAX( 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
|
|
TQPtrListIterator<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 = TQMAX( 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( TQResizeEvent *e )
|
|
{
|
|
int oldW = visibleWidth();
|
|
TQScrollView::resizeEvent( e );
|
|
|
|
if ( visibleWidth() != oldW )
|
|
slotLayout();
|
|
}
|
|
|
|
void MrmlView::saveState( TQDataStream& stream )
|
|
{
|
|
stream << m_items.count();
|
|
TQPtrListIterator<MrmlViewItem> it( m_items );
|
|
for( ; it.current(); ++it ) {
|
|
stream << *it.current();
|
|
}
|
|
|
|
}
|
|
|
|
void MrmlView::restoreState( TQDataStream& stream )
|
|
{
|
|
stopDownloads();
|
|
clear();
|
|
|
|
int count;
|
|
stream >> count;
|
|
|
|
KURL url, thumbURL;
|
|
double similarity;
|
|
TQ_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 );
|
|
}
|
|
}
|
|
|
|
TQDataStream& KMrml::operator<<( TQDataStream& stream,
|
|
const KMrml::MrmlViewItem& item )
|
|
{
|
|
return stream << item.url()
|
|
<< item.thumbURL()
|
|
<< item.similarity()
|
|
<< static_cast<TQ_UINT32>( item.relevance() );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
MrmlViewItem::MrmlViewItem( const KURL& url, const KURL& thumbURL,
|
|
double similarity, MrmlView *view,
|
|
const char *name )
|
|
: TQFrame( view->viewport() , name ),
|
|
m_view( view ),
|
|
m_url( url ),
|
|
m_thumbURL( thumbURL ),
|
|
similarityFullWidth( 120 ), // ###
|
|
m_hasRemotePixmap( false )
|
|
{
|
|
if ( m_similarity != -1 )
|
|
m_similarity = TQMAX( 0.0, TQMIN( 1.0, similarity ));
|
|
setFrameStyle( Panel | Sunken );
|
|
setMouseTracking( true );
|
|
|
|
m_combo = new KComboBox( this );
|
|
TQToolTip::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 )
|
|
TQToolTip::add( this, TQString::fromLatin1("<qt>%1<br>%1</qt>")
|
|
.arg( url )
|
|
.arg(i18n("Similarity: %1").arg( TQString::number(similarity))));
|
|
else
|
|
TQToolTip::add( this, TQString::fromLatin1("<qt>%1</qt>").arg( url ) );
|
|
*/
|
|
|
|
setMinimumSize( 130, 130 ); // ###
|
|
}
|
|
|
|
MrmlViewItem::~MrmlViewItem()
|
|
{
|
|
}
|
|
|
|
void MrmlViewItem::setPixmap( const TQPixmap& pix )
|
|
{
|
|
if ( !m_url.isLocalFile() )
|
|
m_hasRemotePixmap = true;
|
|
|
|
m_pixmap = pix;
|
|
adjustSize();
|
|
update();
|
|
}
|
|
|
|
void MrmlViewItem::paintEvent( TQPaintEvent *e )
|
|
{
|
|
TQFrame::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 ) {
|
|
TQPainter p( this );
|
|
TQPen pen( colorGroup().highlight(), 1, TQPen::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( TQResizeEvent *e )
|
|
{
|
|
TQFrame::resizeEvent( e );
|
|
|
|
int y = height() - m_combo->height() - margin;
|
|
m_combo->move( width()/2 - m_combo->width()/2, y );
|
|
}
|
|
|
|
TQSize MrmlViewItem::sizeHint() const
|
|
{
|
|
int w = TQMAX( TQMAX(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 TQSize( w, h );
|
|
}
|
|
|
|
void MrmlViewItem::mousePressEvent( TQMouseEvent *e )
|
|
{
|
|
TQFrame::mousePressEvent( e );
|
|
pressedPos.setX( 0 );
|
|
pressedPos.setY( 0 );
|
|
|
|
|
|
if ( e->button() == Qt::LeftButton || e->button() == Qt::MidButton ) {
|
|
if ( hitsPixmap( e->pos() ) )
|
|
pressedPos = e->pos();
|
|
}
|
|
else if ( e->button() == Qt::RightButton && hitsPixmap( e->pos() ) )
|
|
emit view()->activated( m_url, e->button() );
|
|
}
|
|
|
|
void MrmlViewItem::mouseMoveEvent( TQMouseEvent *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() & Qt::LeftButton) && !pressedPos.isNull() ) {
|
|
TQPoint dist = e->pos() - pressedPos;
|
|
if ( dist.manhattanLength() > TDEGlobalSettings::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( TQMouseEvent *e )
|
|
{
|
|
if ( hitsPixmap( e->pos() )) {
|
|
TQPoint dist = e->pos() - pressedPos;
|
|
if ( dist.manhattanLength() < TDEGlobalSettings::dndEventDelay() ) {
|
|
emit view()->activated( m_url, e->button() );
|
|
}
|
|
}
|
|
}
|
|
|
|
bool MrmlViewItem::hitsPixmap( const TQPoint& 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( TQDomDocument& document,
|
|
TQDomElement& 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( TQPtrCollection::Item item1,
|
|
TQPtrCollection::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"
|