TDE graphics utilities
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.

mrml_view.cpp 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. /* This file is part of the KDE project
  2. Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@kde.org>
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public
  5. License as published by the Free Software Foundation; either
  6. version 2 of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; see the file COPYING. If not, write to
  13. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  14. Boston, MA 02110-1301, USA.
  15. */
  16. #include <tqdom.h>
  17. #include <tqlabel.h>
  18. #include <tqpainter.h>
  19. #include <tqtimer.h>
  20. #include <tqtooltip.h>
  21. #include <kcursor.h>
  22. #include <kdatastream.h>
  23. #include <klocale.h>
  24. #include <kcombobox.h>
  25. #include <kmimetype.h>
  26. #include <kurl.h>
  27. #include <kurldrag.h>
  28. #include "loader.h"
  29. #include "mrml_creator.h"
  30. #include "mrml_view.h"
  31. using namespace KMrml;
  32. MrmlView::MrmlView( TQWidget *parent, const char *name )
  33. : TQScrollView( parent, name )
  34. {
  35. setStaticBackground( true );
  36. setResizePolicy( Manual );
  37. setHScrollBarMode( AlwaysOff );
  38. enableClipper( true ); // ### test this
  39. m_items.setAutoDelete( true );
  40. connect( Loader::self(), TQT_SIGNAL( finished(const KURL&, const TQByteArray&)),
  41. TQT_SLOT( slotDownloadFinished( const KURL&, const TQByteArray& )));
  42. m_timer = new TQTimer( this );
  43. connect( m_timer, TQT_SIGNAL( timeout() ), TQT_SLOT( slotLayout() ));
  44. // we need a pixmap to be shown when no thumbnail is available for a
  45. // query result image
  46. TQLabel l( i18n( "No thumbnail available" ), 0L );
  47. l.setFixedSize( 80, 80 );
  48. l.setAlignment( WordBreak | AlignCenter );
  49. // l.setFrameStyle( TQLabel::Box | TQLabel::Plain );
  50. // l.setLineWidth( 1 );
  51. l.setPaletteBackgroundColor( TQt::white );
  52. l.setPaletteForegroundColor( TQt::black );
  53. m_unavailablePixmap = TQPixmap::grabWidget( &l );
  54. }
  55. MrmlView::~MrmlView()
  56. {
  57. }
  58. MrmlViewItem * MrmlView::addItem( const KURL& url, const KURL& thumbURL,
  59. const TQString& similarity )
  60. {
  61. bool ok;
  62. double value = similarity.toDouble( &ok );
  63. if ( !ok || value < 0.05 )
  64. return 0L;
  65. return addItem( url, thumbURL, value );
  66. }
  67. MrmlViewItem * MrmlView::addItem( const KURL& url, const KURL& thumbURL,
  68. double similarity )
  69. {
  70. if ( !url.isValid() ) {
  71. qWarning( "MrmlPart: received malformed URL from query: %s",
  72. url.prettyURL().isNull() ? "(null)" : url.prettyURL().latin1() );
  73. return 0L;
  74. }
  75. // qDebug("** url: %s", thumbURL.url().latin1());
  76. MrmlViewItem *item = new MrmlViewItem( url, thumbURL, similarity, this );
  77. TQPixmap *pixmap = getPixmap( thumbURL );
  78. if ( pixmap )
  79. item->setPixmap( *pixmap );
  80. m_items.append( item );
  81. m_timer->start( 0, true );
  82. return item;
  83. }
  84. void MrmlView::addRelevanceToQuery( TQDomDocument& document,
  85. TQDomElement& parent )
  86. {
  87. TQPtrListIterator<MrmlViewItem> it( m_items );
  88. for( ; it.current(); ++it ) {
  89. it.current()->createRelevanceElement( document, parent );
  90. }
  91. }
  92. void MrmlView::clear()
  93. {
  94. m_items.clear(); // items are deleted and removed from scrollview
  95. setContentsPos( 0, 0 );
  96. }
  97. TQPixmap * MrmlView::getPixmap( const KURL& url )
  98. {
  99. TQString u = url.url();
  100. TQPixmap *pix = m_pixmapCache.find( u );
  101. if ( pix )
  102. return pix;
  103. if ( url.isLocalFile() ) {
  104. TQPixmap p;
  105. if ( !p.load( url.path() ) )
  106. p = m_unavailablePixmap;
  107. m_pixmapCache.insert( u, p );
  108. return m_pixmapCache.find( u );
  109. }
  110. else { // remote url, download with KIO
  111. Loader::self()->requestDownload( url );
  112. }
  113. return 0L;
  114. }
  115. void MrmlView::slotDownloadFinished( const KURL& url, const TQByteArray& data )
  116. {
  117. TQPtrListIterator<MrmlViewItem> it( m_items );
  118. for( ; it.current(); ++it ) {
  119. MrmlViewItem *item = it.current();
  120. if ( item->thumbURL() == url )
  121. {
  122. TQPixmap p;
  123. if ( data.isEmpty() || !p.loadFromData( data ) )
  124. p = m_unavailablePixmap;
  125. m_pixmapCache.insert( url.url(), p );
  126. item->setPixmap( p );
  127. slotLayout();
  128. return;
  129. }
  130. }
  131. }
  132. void MrmlView::stopDownloads()
  133. {
  134. Loader *loader = Loader::self();
  135. TQPtrListIterator<MrmlViewItem> it( m_items );
  136. for( ; it.current(); ++it ) {
  137. MrmlViewItem *item = it.current();
  138. if ( !item->hasRemotePixmap() )
  139. loader->removeDownload( item->url() );
  140. }
  141. }
  142. void MrmlView::slotLayout()
  143. {
  144. int itemWidth = 0;
  145. TQPtrListIterator<MrmlViewItem> it( m_items );
  146. for ( ; it.current(); ++it ) {
  147. itemWidth = TQMAX( itemWidth, it.current()->sizeHint().width() );
  148. }
  149. if ( itemWidth == 0 )
  150. return;
  151. uint itemsPerRow = visibleWidth() / itemWidth;
  152. int margin = (visibleWidth() - (itemsPerRow * itemWidth)) / 2;
  153. int rowHeight = 0;
  154. uint item = 0;
  155. uint y = 5;
  156. // pointing to the first item of a row
  157. TQPtrListIterator<MrmlViewItem> rowIt( m_items );
  158. for ( it.toFirst(); it.current(); ++it ) {
  159. if ( item >= itemsPerRow ) {
  160. item = 0;
  161. y += rowHeight;
  162. rowHeight = 0;
  163. }
  164. if ( item == 0 )
  165. rowIt = it;
  166. rowHeight = TQMAX( rowHeight, it.current()->sizeHint().height() );
  167. addChild( it.current(), margin + item * itemWidth, y );
  168. it.current()->show();
  169. item++;
  170. // resize all items of the current row so they all have the same size
  171. if ( item >= itemsPerRow || it.atLast() )
  172. {
  173. for ( uint i = 0; (i < itemsPerRow && rowIt.current()); i++ )
  174. {
  175. rowIt.current()->resize( itemWidth, rowHeight );
  176. ++rowIt;
  177. }
  178. }
  179. }
  180. resizeContents( visibleWidth(), y + rowHeight );
  181. }
  182. void MrmlView::resizeEvent( TQResizeEvent *e )
  183. {
  184. int oldW = visibleWidth();
  185. TQScrollView::resizeEvent( e );
  186. if ( visibleWidth() != oldW )
  187. slotLayout();
  188. }
  189. void MrmlView::saveState( TQDataStream& stream )
  190. {
  191. stream << m_items.count();
  192. TQPtrListIterator<MrmlViewItem> it( m_items );
  193. for( ; it.current(); ++it ) {
  194. stream << *it.current();
  195. }
  196. }
  197. void MrmlView::restoreState( TQDataStream& stream )
  198. {
  199. stopDownloads();
  200. clear();
  201. int count;
  202. stream >> count;
  203. KURL url, thumbURL;
  204. double similarity;
  205. TQ_UINT32 relevance;
  206. MrmlViewItem *item;
  207. for ( int i = 0; i < count; i++ )
  208. {
  209. stream >> url;
  210. stream >> thumbURL;
  211. stream >> similarity;
  212. stream >> relevance;
  213. item = addItem( url, thumbURL, similarity );
  214. if ( item )
  215. item->setRelevance( (MrmlViewItem::Relevance) relevance );
  216. }
  217. }
  218. TQDataStream& KMrml::operator<<( TQDataStream& stream,
  219. const KMrml::MrmlViewItem& item )
  220. {
  221. return stream << item.url()
  222. << item.thumbURL()
  223. << item.similarity()
  224. << static_cast<TQ_UINT32>( item.relevance() );
  225. }
  226. ///////////////////////////////////////////////////////////////////
  227. ///////////////////////////////////////////////////////////////////
  228. MrmlViewItem::MrmlViewItem( const KURL& url, const KURL& thumbURL,
  229. double similarity, MrmlView *view,
  230. const char *name )
  231. : TQFrame( view->viewport() , name ),
  232. m_view( view ),
  233. m_url( url ),
  234. m_thumbURL( thumbURL ),
  235. similarityFullWidth( 120 ), // ###
  236. m_hasRemotePixmap( false )
  237. {
  238. if ( m_similarity != -1 )
  239. m_similarity = TQMAX( 0.0, TQMIN( 1.0, similarity ));
  240. setFrameStyle( Panel | Sunken );
  241. setMouseTracking( true );
  242. m_combo = new KComboBox( this );
  243. TQToolTip::add( m_combo, i18n("You can refine queries by giving feedback about the current result and pressing the Search button again.") );
  244. m_combo->insertItem( i18n("Relevant"), Relevant );
  245. m_combo->insertItem( i18n("Neutral"), Neutral );
  246. m_combo->insertItem( i18n("Irrelevant"), Irrelevant );
  247. m_combo->adjustSize();
  248. m_combo->setCurrentItem( Neutral );
  249. /*
  250. if ( similarity > -1 )
  251. TQToolTip::add( this, TQString::fromLatin1("<qt>%1<br>%1</qt>")
  252. .arg( url )
  253. .arg(i18n("Similarity: %1").arg( TQString::number(similarity))));
  254. else
  255. TQToolTip::add( this, TQString::fromLatin1("<qt>%1</qt>").arg( url ) );
  256. */
  257. setMinimumSize( 130, 130 ); // ###
  258. }
  259. MrmlViewItem::~MrmlViewItem()
  260. {
  261. }
  262. void MrmlViewItem::setPixmap( const TQPixmap& pix )
  263. {
  264. if ( !m_url.isLocalFile() )
  265. m_hasRemotePixmap = true;
  266. m_pixmap = pix;
  267. adjustSize();
  268. update();
  269. }
  270. void MrmlViewItem::paintEvent( TQPaintEvent *e )
  271. {
  272. TQFrame::paintEvent( e );
  273. if ( !m_pixmap.isNull() ) {
  274. bitBlt( this, pixmapX(), pixmapY(),
  275. &m_pixmap, 0, 0, m_pixmap.width(), m_pixmap.height(),
  276. CopyROP );
  277. }
  278. if ( m_similarity >= 0 ) {
  279. TQPainter p( this );
  280. TQPen pen( colorGroup().highlight(), 1, TQPen::SolidLine );
  281. p.setPen( pen );
  282. int x = margin;
  283. int y = m_combo->y() - similarityHeight - 2;
  284. int w = (int) (similarityFullWidth * m_similarity);
  285. int h = similarityHeight;
  286. p.drawRect( x, y, similarityFullWidth, h );
  287. p.fillRect( x, y, w, h, colorGroup().highlight() );
  288. }
  289. }
  290. void MrmlViewItem::resizeEvent( TQResizeEvent *e )
  291. {
  292. TQFrame::resizeEvent( e );
  293. int y = height() - m_combo->height() - margin;
  294. m_combo->move( width()/2 - m_combo->width()/2, y );
  295. }
  296. TQSize MrmlViewItem::sizeHint() const
  297. {
  298. int w = TQMAX( TQMAX(minimumHeight(), m_combo->width()), m_pixmap.width() );
  299. w += 2 * margin;
  300. int h = m_pixmap.isNull() ? margin : margin + spacing + m_pixmap.height();
  301. h += (m_similarity > -1) ? similarityHeight + spacing : 0;
  302. h += m_combo->height() + margin;
  303. return TQSize( w, h );
  304. }
  305. void MrmlViewItem::mousePressEvent( TQMouseEvent *e )
  306. {
  307. TQFrame::mousePressEvent( e );
  308. pressedPos.setX( 0 );
  309. pressedPos.setY( 0 );
  310. if ( e->button() == Qt::LeftButton || e->button() == Qt::MidButton ) {
  311. if ( hitsPixmap( e->pos() ) )
  312. pressedPos = e->pos();
  313. }
  314. else if ( e->button() == Qt::RightButton && hitsPixmap( e->pos() ) )
  315. emit view()->activated( m_url, e->button() );
  316. }
  317. void MrmlViewItem::mouseMoveEvent( TQMouseEvent *e )
  318. {
  319. if ( hitsPixmap( e->pos() ) ) {
  320. if ( !ownCursor() ) { // nice hacklet :)
  321. setCursor( KCursor::handCursor() );
  322. emit view()->onItem( m_url );
  323. }
  324. }
  325. else {
  326. if ( ownCursor() ) {
  327. unsetCursor();
  328. emit view()->onItem( KURL() );
  329. }
  330. }
  331. if ( (e->state() & Qt::LeftButton) && !pressedPos.isNull() ) {
  332. TQPoint dist = e->pos() - pressedPos;
  333. if ( dist.manhattanLength() > KGlobalSettings::dndEventDelay() ) {
  334. // start drag here
  335. KURL::List urls;
  336. // ### support multiple files?
  337. urls.append( m_url );
  338. KURLDrag *drag = new KURLDrag( urls, this );
  339. drag->setPixmap( KMimeType::pixmapForURL( m_url ) );
  340. drag->drag();
  341. }
  342. }
  343. }
  344. void MrmlViewItem::mouseReleaseEvent( TQMouseEvent *e )
  345. {
  346. if ( hitsPixmap( e->pos() )) {
  347. TQPoint dist = e->pos() - pressedPos;
  348. if ( dist.manhattanLength() < KGlobalSettings::dndEventDelay() ) {
  349. emit view()->activated( m_url, e->button() );
  350. }
  351. }
  352. }
  353. bool MrmlViewItem::hitsPixmap( const TQPoint& pos ) const
  354. {
  355. if ( m_pixmap.isNull() )
  356. return false;
  357. if ( pos.x() > pixmapX() && pos.x() < pixmapX() + m_pixmap.width() &&
  358. pos.y() > pixmapY() && pos.y() < pixmapY() + m_pixmap.height() )
  359. return true;
  360. return false;
  361. }
  362. void MrmlViewItem::createRelevanceElement( TQDomDocument& document,
  363. TQDomElement& parent )
  364. {
  365. int rel = m_combo->currentItem();
  366. if ( rel == Neutral )
  367. return;
  368. MrmlCreator::createRelevanceElement( document, parent, m_url.url(),
  369. (rel == Relevant) ? MrmlCreator::Relevant : MrmlCreator::Irrelevant );
  370. }
  371. MrmlViewItem::Relevance MrmlViewItem::relevance() const
  372. {
  373. return (Relevance) m_combo->currentItem();
  374. }
  375. void MrmlViewItem::setRelevance( Relevance relevance )
  376. {
  377. m_combo->setCurrentItem( relevance );
  378. }
  379. ///////////////////////////////////////////////////////////////////
  380. ///////////////////////////////////////////////////////////////////
  381. int MrmlViewItemList::compareItems( TQPtrCollection::Item item1,
  382. TQPtrCollection::Item item2 )
  383. {
  384. double s1 = (static_cast<MrmlViewItem*>( item1 ))->similarity();
  385. double s2 = (static_cast<MrmlViewItem*>( item2 ))->similarity();
  386. if ( s1 < s2 )
  387. return 1;
  388. else if ( s1 > s2 )
  389. return -1;
  390. else
  391. return 0;
  392. }
  393. #include "mrml_view.moc"