tdebase
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.

konq_combo.cc 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. /* This file is part of the KDE project
  2. Copyright (C) 2001 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 <tqpainter.h>
  17. #include <tqstyle.h>
  18. #include <tdeapplication.h>
  19. #include <tdeconfig.h>
  20. #include <tdecompletionbox.h>
  21. #include <kdebug.h>
  22. #include <kiconloader.h>
  23. #include <kicontheme.h>
  24. #include <klineedit.h>
  25. #include <konq_pixmapprovider.h>
  26. #include <tdestdaccel.h>
  27. #include <kurldrag.h>
  28. #include <konq_mainwindow.h>
  29. #include <kstringhandler.h>
  30. #include <dcopclient.h>
  31. #include "konq_combo.h"
  32. TDEConfig * KonqCombo::s_config = 0L;
  33. const int KonqCombo::temporary = 0;
  34. static TQString titleOfURL( const TQString& urlStr )
  35. {
  36. KURL url = KURL::fromPathOrURL( urlStr );
  37. KonqHistoryList& historylist = const_cast<KonqHistoryList&>( KonqHistoryManager::kself()->entries() );
  38. KonqHistoryEntry *historyentry = historylist.findEntry( url );
  39. if ( !historyentry && !url.url().endsWith( "/" ) ) {
  40. url.setPath( url.path()+'/' );
  41. historyentry = historylist.findEntry( url );
  42. }
  43. return ( historyentry ? historyentry->title : TQString() );
  44. }
  45. class TQ_EXPORT KonqComboListBoxPixmap : public TQListBoxItem
  46. {
  47. public:
  48. KonqComboListBoxPixmap( const TQString& text );
  49. KonqComboListBoxPixmap( const TQPixmap &, const TQString& text, const TQString& title );
  50. const TQPixmap *pixmap() const { return &pm; }
  51. int height( const TQListBox * ) const;
  52. int width( const TQListBox * ) const;
  53. int rtti() const;
  54. static int RTTI;
  55. bool reuse( const TQString& newText );
  56. protected:
  57. void paint( TQPainter * );
  58. private:
  59. bool lookup_pending;
  60. TQPixmap pm;
  61. TQString title;
  62. };
  63. class KonqComboLineEdit : public KLineEdit
  64. {
  65. public:
  66. KonqComboLineEdit( TQWidget *parent=0, const char *name=0 );
  67. void setCompletedItems( const TQStringList& items );
  68. };
  69. class KonqComboCompletionBox : public TDECompletionBox
  70. {
  71. public:
  72. KonqComboCompletionBox( TQWidget *parent, const char *name = 0 );
  73. void setItems( const TQStringList& items );
  74. void insertStringList( const TQStringList & list, int index = -1 );
  75. };
  76. KonqCombo::KonqCombo( TQWidget *parent, const char *name )
  77. : KHistoryCombo( parent, name ),
  78. m_returnPressed( false ),
  79. m_permanent( false ),
  80. m_modifier( Qt::NoButton ),
  81. m_pageSecurity( KonqMainWindow::NotCrypted )
  82. {
  83. setInsertionPolicy( NoInsertion );
  84. setSizePolicy( TQSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Fixed ));
  85. Q_ASSERT( s_config );
  86. TDEConfigGroupSaver cs( s_config, "Location Bar" );
  87. setMaxCount( s_config->readNumEntry("Maximum of URLs in combo", 20 ));
  88. // We should also connect the completionBox' highlighted signal to
  89. // our setEditText() slot, because we're handling the signals ourselves.
  90. // But we're lazy and let TDECompletionBox do this and simply switch off
  91. // handling of signals later.
  92. setHandleSignals( true );
  93. KonqComboLineEdit *edit = new KonqComboLineEdit( this, "combo lineedit" );
  94. edit->setHandleSignals( true );
  95. edit->setCompletionBox( new KonqComboCompletionBox( edit, "completion box" ) );
  96. setLineEdit( edit );
  97. completionBox()->setTabHandling( true );
  98. // Make the lineedit consume the Key_Enter event...
  99. setTrapReturnKey( true );
  100. connect( KonqHistoryManager::kself(), TQT_SIGNAL(cleared()), TQT_SLOT(slotCleared()) );
  101. connect( this, TQT_SIGNAL(cleared() ), TQT_SLOT(slotCleared()) );
  102. connect( this, TQT_SIGNAL(highlighted( int )), TQT_SLOT(slotSetIcon( int )) );
  103. connect( this, TQT_SIGNAL(activated( const TQString& )),
  104. TQT_SLOT(slotActivated( const TQString& )) );
  105. setHistoryEditorEnabled( true );
  106. connect( this, TQT_SIGNAL(removed( const TQString&) ), TQT_SLOT(slotRemoved( const TQString& )) );
  107. if ( !kapp->dcopClient()->isAttached() )
  108. kapp->dcopClient()->attach();
  109. }
  110. KonqCombo::~KonqCombo()
  111. {
  112. }
  113. void KonqCombo::init( TDECompletion *completion )
  114. {
  115. setCompletionObject( completion, false ); //KonqMainWindow handles signals
  116. setAutoDeleteCompletionObject( false );
  117. setCompletionMode( completion->completionMode() );
  118. loadItems();
  119. }
  120. void KonqCombo::setURL( const TQString& url )
  121. {
  122. //kdDebug(1202) << "KonqCombo::setURL: " << url << ", returnPressed ? " << m_returnPressed << endl;
  123. setTemporary( url );
  124. if ( m_returnPressed ) { // Really insert...
  125. m_returnPressed = false;
  126. TQByteArray data;
  127. TQDataStream s( data, IO_WriteOnly );
  128. s << url << kapp->dcopClient()->defaultObject();
  129. kapp->dcopClient()->send( "konqueror*", "KonquerorIface",
  130. "addToCombo(TQString,TQCString)", data);
  131. }
  132. // important security consideration: always display the beginning
  133. // of the url rather than its end to prevent spoofing attempts.
  134. lineEdit()->setCursorPosition( 0 );
  135. }
  136. void KonqCombo::setTemporary( const TQString& text )
  137. {
  138. setTemporary( text, KonqPixmapProvider::self()->pixmapFor(text) );
  139. }
  140. void KonqCombo::setTemporary( const TQString& url, const TQPixmap& pix )
  141. {
  142. //kdDebug(1202) << "KonqCombo::setTemporary: " << url << ", temporary = " << temporary << endl;
  143. // Insert a temporary item when we don't have one yet
  144. if ( count() == 0 )
  145. insertItem( pix, url, temporary, titleOfURL( url ) );
  146. else
  147. {
  148. if (url != temporaryItem())
  149. applyPermanent();
  150. updateItem( pix, url, temporary, titleOfURL( url ) );
  151. }
  152. setCurrentItem( temporary );
  153. }
  154. void KonqCombo::removeDuplicates( int index )
  155. {
  156. //kdDebug(1202) << "KonqCombo::removeDuplicates: Starting index = " << index << endl;
  157. TQString url (temporaryItem());
  158. if (url.endsWith("/"))
  159. url.truncate(url.length()-1);
  160. // Remove all dupes, if available...
  161. for ( int i = index; i < count(); i++ )
  162. {
  163. TQString item (text(i));
  164. if (item.endsWith("/"))
  165. item.truncate(item.length()-1);
  166. if ( item == url )
  167. removeItem( i );
  168. }
  169. lineEdit()->setCursorPosition( 0 );
  170. }
  171. // called via DCOP in all instances
  172. void KonqCombo::insertPermanent( const TQString& url )
  173. {
  174. //kdDebug(1202) << "KonqCombo::insertPermanent: URL = " << url << endl;
  175. saveState();
  176. setTemporary( url );
  177. m_permanent = true;
  178. restoreState();
  179. }
  180. // called right before a new (different!) temporary item will be set. So we
  181. // insert an item that was marked permanent properly at position 1.
  182. void KonqCombo::applyPermanent()
  183. {
  184. if ( m_permanent && !temporaryItem().isEmpty() ) {
  185. // Remove as many items as needed to honour maxCount()
  186. int index = count();
  187. while ( count() >= maxCount() )
  188. removeItem( --index );
  189. TQString url (temporaryItem());
  190. insertItem( KonqPixmapProvider::self()->pixmapFor( url ), url, 1, titleOfURL( url ) );
  191. //kdDebug(1202) << "KonqCombo::applyPermanent: " << url << endl;
  192. // Remove all duplicates starting from index = 2
  193. removeDuplicates( 2 );
  194. m_permanent = false;
  195. }
  196. }
  197. void KonqCombo::insertItem( const TQString &text, int index, const TQString& title )
  198. {
  199. KonqComboListBoxPixmap* item = new KonqComboListBoxPixmap( 0, text, title );
  200. listBox()->insertItem( item, index );
  201. }
  202. void KonqCombo::insertItem( const TQPixmap &pixmap, const TQString& text, int index, const TQString& title )
  203. {
  204. KonqComboListBoxPixmap* item = new KonqComboListBoxPixmap( pixmap, text, title );
  205. listBox()->insertItem( item, index );
  206. }
  207. void KonqCombo::updateItem( const TQPixmap& pix, const TQString& t, int index, const TQString& title )
  208. {
  209. // No need to flicker
  210. if (text( index ) == t &&
  211. (pixmap(index) && pixmap(index)->serialNumber() == pix.serialNumber()))
  212. return;
  213. // kdDebug(1202) << "KonqCombo::updateItem: item='" << t << "', index='"
  214. // << index << "'" << endl;
  215. // TQComboBox::changeItem() doesn't honour the pixmap when
  216. // using an editable combobox, so we just remove and insert
  217. // ### use TQComboBox::changeItem(), once that finally works
  218. // Well lets try it now as it seems to work fine for me. We
  219. // can always revert :)
  220. KonqComboListBoxPixmap* item = new KonqComboListBoxPixmap( pix, t, title );
  221. listBox()->changeItem( item, index );
  222. /*
  223. setUpdatesEnabled( false );
  224. lineEdit()->setUpdatesEnabled( false );
  225. removeItem( index );
  226. insertItem( pix, t, index );
  227. setUpdatesEnabled( true );
  228. lineEdit()->setUpdatesEnabled( true );
  229. update();
  230. */
  231. }
  232. void KonqCombo::saveState()
  233. {
  234. m_cursorPos = cursorPosition();
  235. m_currentText = currentText();
  236. m_currentIndex = currentItem();
  237. }
  238. void KonqCombo::restoreState()
  239. {
  240. setTemporary( m_currentText );
  241. lineEdit()->setCursorPosition( m_cursorPos );
  242. }
  243. void KonqCombo::updatePixmaps()
  244. {
  245. saveState();
  246. setUpdatesEnabled( false );
  247. KonqPixmapProvider *prov = KonqPixmapProvider::self();
  248. for ( int i = 1; i < count(); i++ ) {
  249. updateItem( prov->pixmapFor( text( i ) ), text( i ), i, titleOfURL( text( i ) ) );
  250. }
  251. setUpdatesEnabled( true );
  252. repaint();
  253. restoreState();
  254. }
  255. void KonqCombo::loadItems()
  256. {
  257. clear();
  258. int i = 0;
  259. s_config->setGroup( "History" ); // delete the old 2.0.x completion
  260. s_config->writeEntry( "CompletionItems", "unused" );
  261. s_config->setGroup( "Location Bar" );
  262. TQStringList items = s_config->readPathListEntry( "ComboContents" );
  263. TQStringList::ConstIterator it = items.begin();
  264. TQString item;
  265. bool first = true;
  266. while ( it != items.end() ) {
  267. item = *it;
  268. if ( !item.isEmpty() ) { // only insert non-empty items
  269. if( first ) {
  270. insertItem( KonqPixmapProvider::self()->pixmapFor( item, TDEIcon::SizeSmall ),
  271. item, i++, titleOfURL( item ) );
  272. }
  273. else
  274. // icons will be loaded on-demand
  275. insertItem( item, i++, titleOfURL( item ) );
  276. first = false;
  277. }
  278. ++it;
  279. }
  280. if ( count() > 0 )
  281. m_permanent = true; // we want the first loaded item to stay
  282. }
  283. void KonqCombo::slotSetIcon( int index )
  284. {
  285. if( pixmap( index ) == NULL )
  286. // on-demand icon loading
  287. updateItem( KonqPixmapProvider::self()->pixmapFor( text( index ),
  288. TDEIcon::SizeSmall ), text( index ), index,
  289. titleOfURL( text( index ) ) );
  290. update();
  291. }
  292. void KonqCombo::popup()
  293. {
  294. for( int i = 0; i < count(); ++i )
  295. {
  296. if( pixmap( i ) == NULL || pixmap( i )->isNull() )
  297. {
  298. // on-demand icon loading
  299. updateItem( KonqPixmapProvider::self()->pixmapFor( text( i ),
  300. TDEIcon::SizeSmall), text( i ), i, titleOfURL( text( i ) ) );
  301. }
  302. }
  303. KHistoryCombo::popup();
  304. }
  305. void KonqCombo::saveItems()
  306. {
  307. TQStringList items;
  308. int i = m_permanent ? 0 : 1;
  309. for ( ; i < count(); i++ )
  310. items.append( text( i ) );
  311. s_config->setGroup( "Location Bar" );
  312. s_config->writePathEntry( "ComboContents", items );
  313. KonqPixmapProvider::self()->save( s_config, "ComboIconCache", items );
  314. s_config->sync();
  315. }
  316. void KonqCombo::clearTemporary( bool makeCurrent )
  317. {
  318. applyPermanent();
  319. changeItem( TQString::null, temporary ); // ### default pixmap?
  320. if ( makeCurrent )
  321. setCurrentItem( temporary );
  322. }
  323. bool KonqCombo::eventFilter( TQObject *o, TQEvent *ev )
  324. {
  325. // Handle Ctrl+Del/Backspace etc better than the Qt widget, which always
  326. // jumps to the next whitespace.
  327. TQLineEdit *edit = lineEdit();
  328. if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(edit) ) {
  329. int type = ev->type();
  330. if ( type == TQEvent::KeyPress ) {
  331. TQKeyEvent *e = TQT_TQKEYEVENT( ev );
  332. if ( e->key() == Key_Return || e->key() == Key_Enter ) {
  333. m_modifier = e->state();
  334. return false;
  335. }
  336. if ( KKey( e ) == KKey( int( TDEStdAccel::deleteWordBack() ) ) ||
  337. KKey( e ) == KKey( int( TDEStdAccel::deleteWordForward() ) ) ||
  338. ((e->state() & ControlButton) &&
  339. (e->key() == Key_Left || e->key() == Key_Right) ) ) {
  340. selectWord(e);
  341. e->accept();
  342. return true;
  343. }
  344. }
  345. else if ( type == TQEvent::MouseButtonDblClick ) {
  346. edit->selectAll();
  347. return true;
  348. }
  349. }
  350. return KComboBox::eventFilter( o, ev );
  351. }
  352. void KonqCombo::keyPressEvent( TQKeyEvent *e )
  353. {
  354. KHistoryCombo::keyPressEvent( e );
  355. // we have to set it as temporary, otherwise we wouldn't get our nice
  356. // pixmap. Yes, TQComboBox still sucks.
  357. if ( KKey( e ) == KKey( int( TDEStdAccel::rotateUp() ) ) ||
  358. KKey( e ) == KKey( int( TDEStdAccel::rotateDown() ) ) )
  359. setTemporary( currentText() );
  360. }
  361. /*
  362. Handle Ctrl+Cursor etc better than the Qt widget, which always
  363. jumps to the next whitespace. This code additionally jumps to
  364. the next [/#?:], which makes more sense for URLs. The list of
  365. chars that will stop the cursor are '/', '.', '?', '#', ':'.
  366. */
  367. void KonqCombo::selectWord(TQKeyEvent *e)
  368. {
  369. TQLineEdit* edit = lineEdit();
  370. TQString text = edit->text();
  371. int pos = edit->cursorPosition();
  372. int pos_old = pos;
  373. int count = 0;
  374. // TODO: make these a parameter when in tdelibs/tdeui...
  375. TQValueList<TQChar> chars;
  376. chars << TQChar('/') << TQChar('.') << TQChar('?') << TQChar('#') << TQChar(':');
  377. bool allow_space_break = true;
  378. if( e->key() == Key_Left || e->key() == Key_Backspace ) {
  379. do {
  380. pos--;
  381. count++;
  382. if( allow_space_break && text[pos].isSpace() && count > 1 )
  383. break;
  384. } while( pos >= 0 && (chars.findIndex(text[pos]) == -1 || count <= 1) );
  385. if( e->state() & ShiftButton ) {
  386. edit->cursorForward(true, 1-count);
  387. }
  388. else if( e->key() == Key_Backspace ) {
  389. edit->cursorForward(false, 1-count);
  390. TQString text = edit->text();
  391. int pos_to_right = edit->text().length() - pos_old;
  392. TQString cut = text.left(edit->cursorPosition()) + text.right(pos_to_right);
  393. edit->setText(cut);
  394. edit->setCursorPosition(pos_old-count+1);
  395. }
  396. else {
  397. edit->cursorForward(false, 1-count);
  398. }
  399. }
  400. else if( e->key() == Key_Right || e->key() == Key_Delete ){
  401. do {
  402. pos++;
  403. count++;
  404. if( allow_space_break && text[pos].isSpace() )
  405. break;
  406. } while( pos < (int) text.length() && chars.findIndex(text[pos]) == -1 );
  407. if( e->state() & ShiftButton ) {
  408. edit->cursorForward(true, count+1);
  409. }
  410. else if( e->key() == Key_Delete ) {
  411. edit->cursorForward(false, -count-1);
  412. TQString text = edit->text();
  413. int pos_to_right = text.length() - pos - 1;
  414. TQString cut = text.left(pos_old) +
  415. (pos_to_right > 0 ? text.right(pos_to_right) : TQString::null );
  416. edit->setText(cut);
  417. edit->setCursorPosition(pos_old);
  418. }
  419. else {
  420. edit->cursorForward(false, count+1);
  421. }
  422. }
  423. }
  424. void KonqCombo::slotCleared()
  425. {
  426. TQByteArray data;
  427. TQDataStream s( data, IO_WriteOnly );
  428. s << kapp->dcopClient()->defaultObject();
  429. kapp->dcopClient()->send( "konqueror*", "KonquerorIface", "comboCleared(TQCString)", data);
  430. }
  431. void KonqCombo::slotRemoved( const TQString& item )
  432. {
  433. TQByteArray data;
  434. TQDataStream s( data, IO_WriteOnly );
  435. s << item << kapp->dcopClient()->defaultObject();
  436. kapp->dcopClient()->send( "konqueror*", "KonquerorIface",
  437. "removeFromCombo(TQString,TQCString)", data);
  438. }
  439. void KonqCombo::removeURL( const TQString& url )
  440. {
  441. setUpdatesEnabled( false );
  442. lineEdit()->setUpdatesEnabled( false );
  443. removeFromHistory( url );
  444. applyPermanent();
  445. setTemporary( currentText() );
  446. setUpdatesEnabled( true );
  447. lineEdit()->setUpdatesEnabled( true );
  448. update();
  449. }
  450. void KonqCombo::mousePressEvent( TQMouseEvent *e )
  451. {
  452. m_dragStart = TQPoint(); // null QPoint
  453. if ( e->button() == Qt::LeftButton && pixmap( currentItem()) ) {
  454. // check if the pixmap was clicked
  455. int x = e->pos().x();
  456. int x0 = TQStyle::visualRect( style().querySubControlMetrics( TQStyle::CC_ComboBox, this, TQStyle::SC_ComboBoxEditField ), this ).x();
  457. if ( x > x0 + 2 && x < lineEdit()->x() ) {
  458. m_dragStart = e->pos();
  459. return; // don't call KComboBox::mousePressEvent!
  460. }
  461. }
  462. if ( e->button() == Qt::LeftButton && m_pageSecurity!=KonqMainWindow::NotCrypted ) {
  463. // check if the lock icon was clicked
  464. int x = e->pos().x();
  465. int x0 = TQStyle::visualRect( style().querySubControlMetrics( TQStyle::CC_ComboBox, this, TQStyle::SC_ComboBoxArrow ), this ).x();
  466. if ( x < x0 )
  467. emit showPageSecurity();
  468. }
  469. KComboBox::mousePressEvent( e );
  470. }
  471. void KonqCombo::mouseMoveEvent( TQMouseEvent *e )
  472. {
  473. KComboBox::mouseMoveEvent( e );
  474. if ( m_dragStart.isNull() || currentText().isEmpty() )
  475. return;
  476. if ( e->state() & Qt::LeftButton &&
  477. (e->pos() - m_dragStart).manhattanLength() >
  478. TDEGlobalSettings::dndEventDelay() )
  479. {
  480. KURL url = KURL::fromPathOrURL( currentText() );
  481. if ( url.isValid() )
  482. {
  483. KURL::List list;
  484. list.append( url );
  485. KURLDrag *drag = new KURLDrag( list, this );
  486. TQPixmap pix = KonqPixmapProvider::self()->pixmapFor( currentText(),
  487. TDEIcon::SizeMedium );
  488. if ( !pix.isNull() )
  489. drag->setPixmap( pix );
  490. drag->dragCopy();
  491. }
  492. }
  493. }
  494. void KonqCombo::slotActivated( const TQString& text )
  495. {
  496. //kdDebug(1202) << "KonqCombo::slotActivated: " << text << endl;
  497. applyPermanent();
  498. m_returnPressed = true;
  499. emit activated( text, m_modifier );
  500. m_modifier = Qt::NoButton;
  501. }
  502. void KonqCombo::setConfig( TDEConfig *kc )
  503. {
  504. s_config = kc;
  505. }
  506. void KonqCombo::paintEvent( TQPaintEvent *pe )
  507. {
  508. TQComboBox::paintEvent( pe );
  509. TQLineEdit *edit = lineEdit();
  510. TQRect re = style().querySubControlMetrics( TQStyle::CC_ComboBox, this, TQStyle::SC_ComboBoxEditField );
  511. re = TQStyle::visualRect(re, this);
  512. if ( m_pageSecurity!=KonqMainWindow::NotCrypted ) {
  513. TQColor color(245, 246, 190);
  514. bool useColor = hasSufficientContrast(color,edit->paletteForegroundColor());
  515. TQPainter p( this );
  516. p.setClipRect( re );
  517. TQPixmap pix = KonqPixmapProvider::self()->pixmapFor( currentText() );
  518. if ( useColor ) {
  519. p.fillRect( re.x(), re.y(), pix.width() + 4, re.height(), TQBrush( color ));
  520. p.drawPixmap( re.x() + 2, re.y() + ( re.height() - pix.height() ) / 2, pix );
  521. }
  522. TQRect r = edit->geometry();
  523. r.setRight( re.right() - pix.width() - 4 );
  524. if ( r != edit->geometry() )
  525. edit->setGeometry( r );
  526. if ( useColor)
  527. edit->setPaletteBackgroundColor( color );
  528. pix = SmallIcon( m_pageSecurity==KonqMainWindow::Encrypted ? "encrypted" : "halfencrypted" );
  529. p.fillRect( re.right() - pix.width() - 3 , re.y(), pix.width() + 4, re.height(),
  530. TQBrush( useColor ? color : edit->paletteBackgroundColor() ));
  531. p.drawPixmap( re.right() - pix.width() -1 , re.y() + ( re.height() - pix.height() ) / 2, pix );
  532. p.setClipping( FALSE );
  533. }
  534. else {
  535. TQRect r = edit->geometry();
  536. r.setRight( re.right() );
  537. if ( r != edit->geometry() )
  538. edit->setGeometry( r );
  539. edit->setPaletteBackgroundColor( TQApplication::palette( edit ).color( TQPalette::Active, TQColorGroup::Base ) );
  540. }
  541. }
  542. void KonqCombo::setPageSecurity( int pageSecurity )
  543. {
  544. m_pageSecurity = pageSecurity;
  545. repaint();
  546. }
  547. bool KonqCombo::hasSufficientContrast(const TQColor &c1, const TQColor &c2)
  548. {
  549. // Taken from tdehtml/misc/helper.cc
  550. #define HUE_DISTANCE 40
  551. #define CONTRAST_DISTANCE 10
  552. int h1, s1, v1, h2, s2, v2;
  553. int hdist = -CONTRAST_DISTANCE;
  554. c1.hsv(&h1,&s1,&v1);
  555. c2.hsv(&h2,&s2,&v2);
  556. if(h1!=-1 && h2!=-1) { // grey values have no hue
  557. hdist = kAbs(h1-h2);
  558. if (hdist > 180) hdist = 360-hdist;
  559. if (hdist < HUE_DISTANCE) {
  560. hdist -= HUE_DISTANCE;
  561. // see if they are high key or low key colours
  562. bool hk1 = h1>=45 && h1<=225;
  563. bool hk2 = h2>=45 && h2<=225;
  564. if (hk1 && hk2)
  565. hdist = (5*hdist)/3;
  566. else if (!hk1 && !hk2)
  567. hdist = (7*hdist)/4;
  568. }
  569. hdist = kMin(hdist, HUE_DISTANCE*2);
  570. }
  571. return hdist + (kAbs(s1-s2)*128)/(160+kMin(s1,s2)) + kAbs(v1-v2) > CONTRAST_DISTANCE;
  572. }
  573. ///////////////////////////////////////////////////////////////////////////////
  574. KonqComboListBoxPixmap::KonqComboListBoxPixmap( const TQString& text )
  575. : TQListBoxItem()
  576. {
  577. setText( text );
  578. lookup_pending = true;
  579. }
  580. KonqComboListBoxPixmap::KonqComboListBoxPixmap( const TQPixmap & pix, const TQString& text, const TQString& _title )
  581. : TQListBoxItem()
  582. {
  583. pm = pix;
  584. title = _title;
  585. setText( text );
  586. lookup_pending = false;
  587. }
  588. void KonqComboListBoxPixmap::paint( TQPainter *painter )
  589. {
  590. if ( lookup_pending ) {
  591. title = titleOfURL( text() );
  592. if ( !title.isEmpty() )
  593. pm = KonqPixmapProvider::self()->pixmapFor( text(), TDEIcon::SizeSmall );
  594. else if ( text().find( "://" ) == -1 ) {
  595. title = titleOfURL( "http://"+text() );
  596. if ( !title.isEmpty() )
  597. pm = KonqPixmapProvider::self()->pixmapFor( "http://"+text(), TDEIcon::SizeSmall );
  598. else
  599. pm = KonqPixmapProvider::self()->pixmapFor( text(), TDEIcon::SizeSmall );
  600. }
  601. else
  602. pm = TQPixmap();
  603. lookup_pending = false;
  604. }
  605. int itemHeight = height( listBox() );
  606. int yPos, pmWidth = 0;
  607. const TQPixmap *pm = pixmap();
  608. if ( pm && ! pm->isNull() ) {
  609. yPos = ( itemHeight - pm->height() ) / 2;
  610. painter->drawPixmap( 3, yPos, *pm );
  611. pmWidth = pm->width() + 5;
  612. }
  613. int entryWidth = listBox()->width() - listBox()->style().pixelMetric( TQStyle::PM_ScrollBarExtent ) -
  614. 2 * listBox()->style().pixelMetric( TQStyle::PM_DefaultFrameWidth );
  615. int titleWidth = ( entryWidth / 3 ) - 1;
  616. int urlWidth = entryWidth - titleWidth - pmWidth - 2;
  617. if ( !text().isEmpty() ) {
  618. TQString squeezedText = KStringHandler::rPixelSqueeze( text(), listBox()->fontMetrics(), urlWidth );
  619. painter->drawText( pmWidth, 0, urlWidth + pmWidth, itemHeight,
  620. Qt::AlignLeft | Qt::AlignTop, squeezedText );
  621. //painter->setPen( TDEGlobalSettings::inactiveTextColor() );
  622. squeezedText = KStringHandler::rPixelSqueeze( title, listBox()->fontMetrics(), titleWidth );
  623. TQFont font = painter->font();
  624. font.setItalic( true );
  625. painter->setFont( font );
  626. painter->drawText( entryWidth - titleWidth, 0, titleWidth,
  627. itemHeight, Qt::AlignLeft | Qt::AlignTop, squeezedText );
  628. }
  629. }
  630. int KonqComboListBoxPixmap::height( const TQListBox* lb ) const
  631. {
  632. int h;
  633. if ( text().isEmpty() )
  634. h = pm.height();
  635. else
  636. h = TQMAX( pm.height(), lb->fontMetrics().lineSpacing() + 2 );
  637. return TQMAX( h, TQApplication::globalStrut().height() );
  638. }
  639. int KonqComboListBoxPixmap::width( const TQListBox* lb ) const
  640. {
  641. if ( text().isEmpty() )
  642. return TQMAX( pm.width() + 6, TQApplication::globalStrut().width() );
  643. return TQMAX( pm.width() + lb->fontMetrics().width( text() ) + 6,
  644. TQApplication::globalStrut().width() );
  645. }
  646. int KonqComboListBoxPixmap::RTTI = 1003;
  647. int KonqComboListBoxPixmap::rtti() const
  648. {
  649. return RTTI;
  650. }
  651. bool KonqComboListBoxPixmap::reuse( const TQString& newText )
  652. {
  653. if ( text() == newText )
  654. return false;
  655. lookup_pending = true;
  656. setText( newText );
  657. return true;
  658. }
  659. ///////////////////////////////////////////////////////////////////////////////
  660. KonqComboLineEdit::KonqComboLineEdit( TQWidget *parent, const char *name )
  661. :KLineEdit( parent, name ) {}
  662. void KonqComboLineEdit::setCompletedItems( const TQStringList& items )
  663. {
  664. TQString txt;
  665. KonqComboCompletionBox *completionbox = static_cast<KonqComboCompletionBox*>( completionBox() );
  666. if ( completionbox && completionbox->isVisible() )
  667. // The popup is visible already - do the matching on the initial string,
  668. // not on the currently selected one.
  669. txt = completionbox->cancelledText();
  670. else
  671. txt = text();
  672. if ( !items.isEmpty() && !(items.count() == 1 && txt == items.first()) ) {
  673. if ( !completionBox( false ) )
  674. setCompletionBox( new KonqComboCompletionBox( this, "completion box" ) );
  675. if ( completionbox->isVisible() ) {
  676. bool wasSelected = completionbox->isSelected( completionbox->currentItem() );
  677. const TQString currentSelection = completionbox->currentText();
  678. completionbox->setItems( items );
  679. TQListBoxItem* item = completionbox->findItem( currentSelection, TQt::ExactMatch );
  680. if( !item || !wasSelected )
  681. {
  682. wasSelected = false;
  683. item = completionbox->item( 0 );
  684. }
  685. if ( item ) {
  686. completionbox->blockSignals( true );
  687. completionbox->setCurrentItem( item );
  688. completionbox->setSelected( item, wasSelected );
  689. completionbox->blockSignals( false );
  690. }
  691. }
  692. else { // completion box not visible yet -> show it
  693. if ( !txt.isEmpty() )
  694. completionbox->setCancelledText( txt );
  695. completionbox->setItems( items );
  696. completionbox->popup();
  697. }
  698. if ( autoSuggest() ) {
  699. int index = items.first().find( txt );
  700. TQString newText = items.first().mid( index );
  701. setUserSelection( false );
  702. setCompletedText( newText, true );
  703. }
  704. }
  705. else
  706. if ( completionbox && completionbox->isVisible() )
  707. completionbox->hide();
  708. }
  709. ///////////////////////////////////////////////////////////////////////////////
  710. KonqComboCompletionBox::KonqComboCompletionBox( TQWidget *parent, const char *name )
  711. :TDECompletionBox( parent, name ) {}
  712. void KonqComboCompletionBox::setItems( const TQStringList& items )
  713. {
  714. bool block = signalsBlocked();
  715. blockSignals( true );
  716. TQListBoxItem* item = firstItem();
  717. if ( !item )
  718. insertStringList( items );
  719. else {
  720. //Keep track of whether we need to change anything,
  721. //so we can avoid a repaint for identical updates,
  722. //to reduce flicker
  723. bool dirty = false;
  724. TQStringList::ConstIterator it = items.constBegin();
  725. const TQStringList::ConstIterator itEnd = items.constEnd();
  726. for ( ; it != itEnd; ++it) {
  727. if ( item ) {
  728. const bool changed = ((KonqComboListBoxPixmap*)item)->reuse( *it );
  729. dirty = dirty || changed;
  730. item = item->next();
  731. }
  732. else {
  733. dirty = true;
  734. //Inserting an item is a way of making this dirty
  735. insertItem( new KonqComboListBoxPixmap( *it ) );
  736. }
  737. }
  738. //If there is an unused item, mark as dirty -> less items now
  739. if ( item )
  740. dirty = true;
  741. TQListBoxItem* tmp = item;
  742. while ( (item = tmp ) ) {
  743. tmp = item->next();
  744. delete item;
  745. }
  746. if ( dirty )
  747. triggerUpdate( false );
  748. }
  749. if ( isVisible() && size().height() != sizeHint().height() )
  750. sizeAndPosition();
  751. blockSignals( block );
  752. // Trigger d->down_workaround = true within TDECompletionBox
  753. TQStringList dummy;
  754. TDECompletionBox::insertItems( dummy, 1 );
  755. }
  756. void KonqComboCompletionBox::insertStringList( const TQStringList & list, int index )
  757. {
  758. if ( index < 0 )
  759. index = count();
  760. for ( TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it )
  761. insertItem( new KonqComboListBoxPixmap( *it ), index++ );
  762. }
  763. #include "konq_combo.moc"