KIO
kurlcombobox.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2000,2001 Carsten Pfeiffer <pfeiffer@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License version 2, as published by the Free Software Foundation. 00007 00008 This library is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 Library General Public License for more details. 00012 00013 You should have received a copy of the GNU Library General Public License 00014 along with this library; see the file COPYING.LIB. If not, write to 00015 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00016 Boston, MA 02110-1301, USA. 00017 */ 00018 00019 #include "kurlcombobox.h" 00020 00021 #include <QtCore/QDir> 00022 #include <QtGui/QMouseEvent> 00023 #include <QtGui/QDrag> 00024 00025 #include <kdebug.h> 00026 #include <kglobal.h> 00027 #include <kicon.h> 00028 #include <klocale.h> 00029 #include <kmimetype.h> 00030 #include <kiconloader.h> 00031 00032 class KUrlComboBox::KUrlComboBoxPrivate 00033 { 00034 public: 00035 KUrlComboBoxPrivate(KUrlComboBox *parent) 00036 : m_parent(parent), 00037 dirIcon(QLatin1String("folder")) 00038 {} 00039 00040 ~KUrlComboBoxPrivate() 00041 { 00042 qDeleteAll( itemList ); 00043 qDeleteAll( defaultList ); 00044 } 00045 00046 typedef struct { 00047 QString text; 00048 KUrl url; 00049 QIcon icon; 00050 } KUrlComboItem; 00051 00052 void init( Mode mode ); 00053 void insertUrlItem( const KUrlComboItem * ); 00054 QIcon getIcon( const KUrl& url ) const; 00055 void updateItem( const KUrlComboItem *item, int index, const QIcon& icon ); 00056 00057 void _k_slotActivated( int ); 00058 00059 KUrlComboBox *m_parent; 00060 KIcon dirIcon; 00061 bool urlAdded; 00062 int myMaximum; 00063 Mode myMode; // can be used as parameter to KUR::path( int ) or url( int ) 00064 // to specify if we want a trailing slash or not 00065 QPoint m_dragPoint; 00066 00067 QList<const KUrlComboItem*> itemList; 00068 QList<const KUrlComboItem*> defaultList; 00069 QMap<int,const KUrlComboItem*> itemMapper; 00070 00071 QIcon opendirIcon; 00072 }; 00073 00074 00075 KUrlComboBox::KUrlComboBox( Mode mode, QWidget *parent) 00076 : KComboBox( parent),d(new KUrlComboBoxPrivate(this)) 00077 { 00078 d->init( mode ); 00079 } 00080 00081 00082 KUrlComboBox::KUrlComboBox( Mode mode, bool rw, QWidget *parent) 00083 : KComboBox( rw, parent),d(new KUrlComboBoxPrivate(this)) 00084 { 00085 d->init( mode ); 00086 } 00087 00088 00089 KUrlComboBox::~KUrlComboBox() 00090 { 00091 delete d; 00092 } 00093 00094 00095 void KUrlComboBox::KUrlComboBoxPrivate::init( Mode mode ) 00096 { 00097 myMode = mode; 00098 urlAdded = false; 00099 myMaximum = 10; // default 00100 m_parent->setInsertPolicy( NoInsert ); 00101 m_parent->setTrapReturnKey( true ); 00102 m_parent->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed )); 00103 m_parent->setLayoutDirection( Qt::LeftToRight ); 00104 if ( m_parent->completionObject() ) { 00105 m_parent->completionObject()->setOrder( KCompletion::Sorted ); 00106 } 00107 00108 opendirIcon = KIcon(QLatin1String("folder-open")); 00109 00110 m_parent->connect( m_parent, SIGNAL( activated( int )), SLOT( _k_slotActivated( int ))); 00111 } 00112 00113 00114 QStringList KUrlComboBox::urls() const 00115 { 00116 kDebug(250) << "::urls()"; 00117 //static const QString &fileProt = KGlobal::staticQString("file:"); 00118 QStringList list; 00119 QString url; 00120 for ( int i = d->defaultList.count(); i < count(); i++ ) { 00121 url = itemText( i ); 00122 if ( !url.isEmpty() ) { 00123 //if ( url.at(0) == '/' ) 00124 // list.append( url.prepend( fileProt ) ); 00125 //else 00126 list.append( url ); 00127 } 00128 } 00129 00130 return list; 00131 } 00132 00133 00134 void KUrlComboBox::addDefaultUrl( const KUrl& url, const QString& text ) 00135 { 00136 addDefaultUrl( url, d->getIcon( url ), text ); 00137 } 00138 00139 00140 void KUrlComboBox::addDefaultUrl( const KUrl& url, const QIcon& icon, 00141 const QString& text ) 00142 { 00143 KUrlComboBoxPrivate::KUrlComboItem *item = new KUrlComboBoxPrivate::KUrlComboItem; 00144 item->url = url; 00145 item->icon = icon; 00146 if ( text.isEmpty() ) 00147 item->text = url.pathOrUrl(d->myMode == Directories 00148 ? KUrl::AddTrailingSlash 00149 : KUrl::RemoveTrailingSlash); 00150 else 00151 item->text = text; 00152 00153 d->defaultList.append( item ); 00154 } 00155 00156 00157 void KUrlComboBox::setDefaults() 00158 { 00159 clear(); 00160 d->itemMapper.clear(); 00161 00162 const KUrlComboBoxPrivate::KUrlComboItem *item; 00163 for ( int id = 0; id < d->defaultList.count(); id++ ) { 00164 item = d->defaultList.at( id ); 00165 d->insertUrlItem( item ); 00166 } 00167 } 00168 00169 void KUrlComboBox::setUrls( const QStringList &urls ) 00170 { 00171 setUrls( urls, RemoveBottom ); 00172 } 00173 00174 void KUrlComboBox::setUrls( const QStringList &_urls, OverLoadResolving remove ) 00175 { 00176 setDefaults(); 00177 qDeleteAll( d->itemList ); 00178 d->itemList.clear(); 00179 d->urlAdded = false; 00180 00181 if ( _urls.isEmpty() ) 00182 return; 00183 00184 QStringList urls; 00185 QStringList::ConstIterator it = _urls.constBegin(); 00186 00187 // kill duplicates 00188 while ( it != _urls.constEnd() ) { 00189 if ( !urls.contains( *it ) ) 00190 urls += *it; 00191 ++it; 00192 } 00193 00194 // limit to myMaximum items 00195 /* Note: overload is an (old) C++ keyword, some compilers (KCC) choke 00196 on that, so call it Overload (capital 'O'). (matz) */ 00197 int Overload = urls.count() - d->myMaximum + d->defaultList.count(); 00198 while ( Overload > 0) { 00199 if (remove == RemoveBottom) { 00200 if (!urls.isEmpty()) 00201 urls.removeLast(); 00202 } 00203 else { 00204 if (!urls.isEmpty()) 00205 urls.removeFirst(); 00206 } 00207 Overload--; 00208 } 00209 00210 it = urls.constBegin(); 00211 00212 KUrlComboBoxPrivate::KUrlComboItem *item = 0L; 00213 00214 while ( it != urls.constEnd() ) { 00215 if ( (*it).isEmpty() ) { 00216 ++it; 00217 continue; 00218 } 00219 KUrl u = *it; 00220 00221 // Don't restore if file doesn't exist anymore 00222 if (u.isLocalFile() && !QFile::exists(u.toLocalFile())) { 00223 ++it; 00224 continue; 00225 } 00226 00227 item = new KUrlComboBoxPrivate::KUrlComboItem; 00228 item->url = u; 00229 item->icon = d->getIcon( u ); 00230 item->text = u.pathOrUrl(d->myMode == Directories 00231 ? KUrl::AddTrailingSlash 00232 : KUrl::RemoveTrailingSlash); 00233 00234 d->insertUrlItem( item ); 00235 d->itemList.append( item ); 00236 ++it; 00237 } 00238 } 00239 00240 00241 void KUrlComboBox::setUrl( const KUrl& url ) 00242 { 00243 if ( url.isEmpty() ) 00244 return; 00245 00246 bool blocked = blockSignals( true ); 00247 00248 // check for duplicates 00249 QMap<int,const KUrlComboBoxPrivate::KUrlComboItem*>::ConstIterator mit = d->itemMapper.constBegin(); 00250 QString urlToInsert = url.url(KUrl::RemoveTrailingSlash); 00251 while ( mit != d->itemMapper.constEnd() ) { 00252 Q_ASSERT( mit.value() ); 00253 00254 if ( urlToInsert == mit.value()->url.url(KUrl::RemoveTrailingSlash) ) { 00255 setCurrentIndex( mit.key() ); 00256 00257 if (d->myMode == Directories) 00258 d->updateItem( mit.value(), mit.key(), d->opendirIcon ); 00259 00260 blockSignals( blocked ); 00261 return; 00262 } 00263 ++mit; 00264 } 00265 00266 // not in the combo yet -> create a new item and insert it 00267 00268 // first remove the old item 00269 if (d->urlAdded) { 00270 Q_ASSERT(!d->itemList.isEmpty()); 00271 d->itemList.removeLast(); 00272 d->urlAdded = false; 00273 } 00274 00275 setDefaults(); 00276 00277 QListIterator<const KUrlComboBoxPrivate::KUrlComboItem*> it( d->itemList ); 00278 while ( it.hasNext() ) 00279 d->insertUrlItem( it.next() ); 00280 00281 KUrlComboBoxPrivate::KUrlComboItem *item = new KUrlComboBoxPrivate::KUrlComboItem; 00282 item->url = url; 00283 item->icon = d->getIcon( url ); 00284 item->text = url.pathOrUrl(d->myMode == Directories 00285 ? KUrl::AddTrailingSlash 00286 : KUrl::RemoveTrailingSlash); 00287 kDebug(250) << "setURL: text=" << item->text; 00288 00289 int id = count(); 00290 QString text = /*isEditable() ? item->url.prettyUrl( (KUrl::AdjustPathOption)myMode ) : */ item->text; 00291 00292 if (d->myMode == Directories) 00293 KComboBox::insertItem( id, d->opendirIcon, text); 00294 else 00295 KComboBox::insertItem( id,item->icon, text); 00296 00297 d->itemMapper.insert( id, item ); 00298 d->itemList.append( item ); 00299 00300 setCurrentIndex( id ); 00301 Q_ASSERT(!d->itemList.isEmpty()); 00302 d->urlAdded = true; 00303 blockSignals( blocked ); 00304 } 00305 00306 00307 void KUrlComboBox::KUrlComboBoxPrivate::_k_slotActivated( int index ) 00308 { 00309 const KUrlComboItem *item = itemMapper.value(index); 00310 00311 if ( item ) { 00312 m_parent->setUrl( item->url ); 00313 emit m_parent->urlActivated( item->url ); 00314 } 00315 } 00316 00317 00318 void KUrlComboBox::KUrlComboBoxPrivate::insertUrlItem( const KUrlComboBoxPrivate::KUrlComboItem *item ) 00319 { 00320 Q_ASSERT( item ); 00321 00322 // kDebug(250) << "insertURLItem " << item->text; 00323 int id = m_parent->count(); 00324 m_parent->KComboBox::insertItem(id, item->icon, item->text); 00325 itemMapper.insert( id, item ); 00326 } 00327 00328 00329 void KUrlComboBox::setMaxItems( int max ) 00330 { 00331 d->myMaximum = max; 00332 00333 if (count() > d->myMaximum) { 00334 int oldCurrent = currentIndex(); 00335 00336 setDefaults(); 00337 00338 QListIterator<const KUrlComboBoxPrivate::KUrlComboItem*> it( d->itemList ); 00339 int Overload = d->itemList.count() - d->myMaximum + d->defaultList.count(); 00340 for ( int i = 0; i <= Overload; i++ ) 00341 it.next(); 00342 00343 while ( it.hasNext() ) 00344 d->insertUrlItem( it.next() ); 00345 00346 if ( count() > 0 ) { // restore the previous currentItem 00347 if ( oldCurrent >= count() ) 00348 oldCurrent = count() -1; 00349 setCurrentIndex( oldCurrent ); 00350 } 00351 } 00352 } 00353 00354 int KUrlComboBox::maxItems() const 00355 { 00356 return d->myMaximum; 00357 } 00358 00359 void KUrlComboBox::removeUrl( const KUrl& url, bool checkDefaultURLs ) 00360 { 00361 QMap<int,const KUrlComboBoxPrivate::KUrlComboItem*>::ConstIterator mit = d->itemMapper.constBegin(); 00362 while ( mit != d->itemMapper.constEnd() ) { 00363 if ( url.url(KUrl::RemoveTrailingSlash) == mit.value()->url.url(KUrl::RemoveTrailingSlash) ) { 00364 if ( !d->itemList.removeAll( mit.value() ) && checkDefaultURLs ) 00365 d->defaultList.removeAll( mit.value() ); 00366 } 00367 ++mit; 00368 } 00369 00370 bool blocked = blockSignals( true ); 00371 setDefaults(); 00372 QListIterator<const KUrlComboBoxPrivate::KUrlComboItem*> it( d->itemList ); 00373 while ( it.hasNext() ) { 00374 d->insertUrlItem( it.next() ); 00375 } 00376 blockSignals( blocked ); 00377 } 00378 00379 void KUrlComboBox::setCompletionObject(KCompletion* compObj, bool hsig) 00380 { 00381 if ( compObj ) { 00382 // on a url combo box we want completion matches to be sorted. This way, if we are given 00383 // a suggestion, we match the "best" one. For instance, if we have "foo" and "foobar", 00384 // and we write "foo", the match is "foo" and never "foobar". (ereslibre) 00385 compObj->setOrder( KCompletion::Sorted ); 00386 } 00387 KComboBox::setCompletionObject( compObj, hsig ); 00388 } 00389 00390 void KUrlComboBox::mousePressEvent(QMouseEvent *event) 00391 { 00392 QStyleOptionComboBox comboOpt; 00393 comboOpt.initFrom(this); 00394 const int x0 = QStyle::visualRect(layoutDirection(), rect(), 00395 style()->subControlRect(QStyle::CC_ComboBox, &comboOpt, QStyle::SC_ComboBoxEditField, this)).x(); 00396 const int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &comboOpt, this); 00397 00398 if (event->x() < (x0 + KIconLoader::SizeSmall + frameWidth)) { 00399 d->m_dragPoint = event->pos(); 00400 } else { 00401 d->m_dragPoint = QPoint(); 00402 } 00403 00404 KComboBox::mousePressEvent(event); 00405 } 00406 00407 void KUrlComboBox::mouseMoveEvent(QMouseEvent *event) 00408 { 00409 const int index = currentIndex(); 00410 00411 if (!itemIcon(index).isNull() && !d->m_dragPoint.isNull() && event->buttons() & Qt::LeftButton && 00412 (event->pos() - d->m_dragPoint).manhattanLength() > KGlobalSettings::dndEventDelay()) { 00413 QDrag *drag = new QDrag(this); 00414 QMimeData *mime = new QMimeData(); 00415 mime->setUrls(QList<QUrl>() << KUrl(itemText(index))); 00416 mime->setText(itemText(index)); 00417 drag->setPixmap(itemIcon(index).pixmap(KIconLoader::SizeMedium)); 00418 drag->setMimeData(mime); 00419 drag->exec(); 00420 } 00421 00422 KComboBox::mouseMoveEvent(event); 00423 } 00424 00425 QIcon KUrlComboBox::KUrlComboBoxPrivate::getIcon( const KUrl& url ) const 00426 { 00427 if (myMode == Directories) 00428 return dirIcon; 00429 else 00430 return KIcon(KMimeType::iconNameForUrl(url, 0)); 00431 } 00432 00433 00434 // updates "item" with icon "icon" and sets the URL instead of text 00435 void KUrlComboBox::KUrlComboBoxPrivate::updateItem( const KUrlComboBoxPrivate::KUrlComboItem *item, 00436 int index, const QIcon& icon) 00437 { 00438 m_parent->setItemIcon(index,icon); 00439 00440 if ( m_parent->isEditable() ) { 00441 m_parent->setItemText(index, item->url.pathOrUrl(myMode == Directories 00442 ? KUrl::AddTrailingSlash 00443 : KUrl::RemoveTrailingSlash)); 00444 } 00445 else { 00446 m_parent->setItemText(index,item->text); 00447 } 00448 } 00449 00450 00451 #include "kurlcombobox.moc"
KDE 4.6 API Reference