kio Library API Documentation

kpropertiesdialog.cpp

00001 /* This file is part of the KDE project 00002 00003 Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> 00004 Copyright (c) 1999, 2000 Preston Brown <pbrown@kde.org> 00005 Copyright (c) 2000 Simon Hausmann <hausmann@kde.org> 00006 Copyright (c) 2000 David Faure <faure@kde.org> 00007 Copyright (c) 2003 Waldo Bastian <bastian@kde.org> 00008 00009 This library is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU Library General Public 00011 License as published by the Free Software Foundation; either 00012 version 2 of the License, or (at your option) any later version. 00013 00014 This library is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 Library General Public License for more details. 00018 00019 You should have received a copy of the GNU Library General Public License 00020 along with this library; see the file COPYING.LIB. If not, write to 00021 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00022 Boston, MA 02111-1307, USA. 00023 */ 00024 00025 /* 00026 * kpropertiesdialog.cpp 00027 * View/Edit Properties of files, locally or remotely 00028 * 00029 * some FilePermissionsPropsPlugin-changes by 00030 * Henner Zeller <zeller@think.de> 00031 * some layout management by 00032 * Bertrand Leconte <B.Leconte@mail.dotcom.fr> 00033 * the rest of the layout management, bug fixes, adaptation to libkio, 00034 * template feature by 00035 * David Faure <faure@kde.org> 00036 * More layout, cleanups, and fixes by 00037 * Preston Brown <pbrown@kde.org> 00038 * Plugin capability, cleanups and port to KDialogBase by 00039 * Simon Hausmann <hausmann@kde.org> 00040 * KDesktopPropsPlugin by 00041 * Waldo Bastian <bastian@kde.org> 00042 */ 00043 00044 #include <config.h> 00045 extern "C" { 00046 #include <pwd.h> 00047 #include <grp.h> 00048 #include <time.h> 00049 } 00050 #include <unistd.h> 00051 #include <errno.h> 00052 #include <assert.h> 00053 00054 #include <qfile.h> 00055 #include <qdir.h> 00056 #include <qlabel.h> 00057 #include <qpushbutton.h> 00058 #include <qcheckbox.h> 00059 #include <qstrlist.h> 00060 #include <qstringlist.h> 00061 #include <qtextstream.h> 00062 #include <qpainter.h> 00063 #include <qlayout.h> 00064 #include <qcombobox.h> 00065 #include <qgroupbox.h> 00066 #include <qwhatsthis.h> 00067 #include <qtooltip.h> 00068 #include <qstyle.h> 00069 00070 #include <kapplication.h> 00071 #include <kdialog.h> 00072 #include <kdirsize.h> 00073 #include <kdirwatch.h> 00074 #include <kdirnotify_stub.h> 00075 #include <kdiskfreesp.h> 00076 #include <kdebug.h> 00077 #include <kdesktopfile.h> 00078 #include <kicondialog.h> 00079 #include <kurl.h> 00080 #include <kurlrequester.h> 00081 #include <klocale.h> 00082 #include <kglobal.h> 00083 #include <kglobalsettings.h> 00084 #include <kstandarddirs.h> 00085 #include <kio/job.h> 00086 #include <kio/chmodjob.h> 00087 #include <kio/renamedlg.h> 00088 #include <kio/netaccess.h> 00089 #include <kfiledialog.h> 00090 #include <kmimetype.h> 00091 #include <kmountpoint.h> 00092 #include <kiconloader.h> 00093 #include <kmessagebox.h> 00094 #include <kservice.h> 00095 #include <kcompletion.h> 00096 #include <klineedit.h> 00097 #include <kseparator.h> 00098 #include <ksqueezedtextlabel.h> 00099 #include <klibloader.h> 00100 #include <ktrader.h> 00101 #include <kparts/componentfactory.h> 00102 #include <kmetaprops.h> 00103 #include <kprocess.h> 00104 #include <krun.h> 00105 #include <klistview.h> 00106 #include "kfilesharedlg.h" 00107 00108 #include "kpropertiesdesktopbase.h" 00109 #include "kpropertiesdesktopadvbase.h" 00110 #include "kpropertiesmimetypebase.h" 00111 00112 #include "kpropertiesdialog.h" 00113 00114 static QString nameFromFileName(QString nameStr) 00115 { 00116 if ( nameStr.endsWith(".desktop") ) 00117 nameStr.truncate( nameStr.length() - 8 ); 00118 if ( nameStr.endsWith(".kdelnk") ) 00119 nameStr.truncate( nameStr.length() - 7 ); 00120 // Make it human-readable (%2F => '/', ...) 00121 nameStr = KIO::decodeFileName( nameStr ); 00122 return nameStr; 00123 } 00124 00125 mode_t KFilePermissionsPropsPlugin::fperm[3][4] = { 00126 {S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID}, 00127 {S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID}, 00128 {S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX} 00129 }; 00130 00131 class KPropertiesDialog::KPropertiesDialogPrivate 00132 { 00133 public: 00134 KPropertiesDialogPrivate() 00135 { 00136 m_aborted = false; 00137 } 00138 ~KPropertiesDialogPrivate() 00139 { 00140 } 00141 bool m_aborted:1; 00142 }; 00143 00144 KPropertiesDialog::KPropertiesDialog (KFileItem* item, 00145 QWidget* parent, const char* name, 00146 bool modal, bool autoShow) 00147 : KDialogBase (KDialogBase::Tabbed, i18n( "Properties for %1" ).arg(KIO::decodeFileName(item->url().fileName())), 00148 KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, 00149 parent, name, modal) 00150 { 00151 d = new KPropertiesDialogPrivate; 00152 assert( item ); 00153 m_items.append( new KFileItem(*item) ); // deep copy 00154 00155 m_singleUrl = item->url(); 00156 assert(!m_singleUrl.isEmpty()); 00157 00158 init (modal, autoShow); 00159 } 00160 00161 KPropertiesDialog::KPropertiesDialog (const QString& title, 00162 QWidget* parent, const char* name, bool modal) 00163 : KDialogBase (KDialogBase::Tabbed, i18n ("Properties for %1").arg(title), 00164 KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, 00165 parent, name, modal) 00166 { 00167 d = new KPropertiesDialogPrivate; 00168 00169 init (modal, false); 00170 } 00171 00172 KPropertiesDialog::KPropertiesDialog (KFileItemList _items, 00173 QWidget* parent, const char* name, 00174 bool modal, bool autoShow) 00175 : KDialogBase (KDialogBase::Tabbed, 00176 i18n( "Properties for %1" ).arg(KIO::decodeFileName(_items.first()->url().fileName())), 00177 KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, 00178 parent, name, modal) 00179 { 00180 d = new KPropertiesDialogPrivate; 00181 00182 assert( !_items.isEmpty() ); 00183 m_singleUrl = _items.first()->url(); 00184 assert(!m_singleUrl.isEmpty()); 00185 00186 KFileItemListIterator it ( _items ); 00187 // Deep copy 00188 for ( ; it.current(); ++it ) 00189 m_items.append( new KFileItem( **it ) ); 00190 00191 init (modal, autoShow); 00192 } 00193 00194 #ifndef KDE_NO_COMPAT 00195 KPropertiesDialog::KPropertiesDialog (const KURL& _url, mode_t /* _mode is now unused */, 00196 QWidget* parent, const char* name, 00197 bool modal, bool autoShow) 00198 : KDialogBase (KDialogBase::Tabbed, 00199 i18n( "Properties for %1" ).arg(KIO::decodeFileName(_url.fileName())), 00200 KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, 00201 parent, name, modal), 00202 m_singleUrl( _url ) 00203 { 00204 d = new KPropertiesDialogPrivate; 00205 00206 KIO::UDSEntry entry; 00207 00208 KIO::NetAccess::stat(_url, entry, parent); 00209 00210 m_items.append( new KFileItem( entry, _url ) ); 00211 init (modal, autoShow); 00212 } 00213 #endif 00214 00215 KPropertiesDialog::KPropertiesDialog (const KURL& _url, 00216 QWidget* parent, const char* name, 00217 bool modal, bool autoShow) 00218 : KDialogBase (KDialogBase::Tabbed, 00219 i18n( "Properties for %1" ).arg(KIO::decodeFileName(_url.fileName())), 00220 KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, 00221 parent, name, modal), 00222 m_singleUrl( _url ) 00223 { 00224 d = new KPropertiesDialogPrivate; 00225 00226 KIO::UDSEntry entry; 00227 00228 KIO::NetAccess::stat(_url, entry, parent); 00229 00230 m_items.append( new KFileItem( entry, _url ) ); 00231 init (modal, autoShow); 00232 } 00233 00234 KPropertiesDialog::KPropertiesDialog (const KURL& _tempUrl, const KURL& _currentDir, 00235 const QString& _defaultName, 00236 QWidget* parent, const char* name, 00237 bool modal, bool autoShow) 00238 : KDialogBase (KDialogBase::Tabbed, 00239 i18n( "Properties for %1" ).arg(KIO::decodeFileName(_tempUrl.fileName())), 00240 KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, 00241 parent, name, modal), 00242 00243 m_singleUrl( _tempUrl ), 00244 m_defaultName( _defaultName ), 00245 m_currentDir( _currentDir ) 00246 { 00247 d = new KPropertiesDialogPrivate; 00248 00249 assert(!m_singleUrl.isEmpty()); 00250 00251 // Create the KFileItem for the _template_ file, in order to read from it. 00252 m_items.append( new KFileItem( KFileItem::Unknown, KFileItem::Unknown, m_singleUrl ) ); 00253 init (modal, autoShow); 00254 } 00255 00256 void KPropertiesDialog::init (bool modal, bool autoShow) 00257 { 00258 m_pageList.setAutoDelete( true ); 00259 m_items.setAutoDelete( true ); 00260 00261 insertPages(); 00262 00263 if (autoShow) 00264 { 00265 if (!modal) 00266 show(); 00267 else 00268 exec(); 00269 } 00270 } 00271 00272 void KPropertiesDialog::showFileSharingPage() 00273 { 00274 KPropsDlgPlugin *it; 00275 00276 for ( it=m_pageList.first(); it != 0L; it=m_pageList.next() ) 00277 { 00278 KFileSharePropsPlugin* plugin = dynamic_cast<KFileSharePropsPlugin*>(it); 00279 if ( plugin ) 00280 { 00281 showPage( pageIndex( plugin->page() ) ); 00282 break; 00283 } 00284 } 00285 } 00286 00287 void KPropertiesDialog::setFileNameReadOnly( bool ro ) 00288 { 00289 KPropsDlgPlugin *it; 00290 00291 for ( it=m_pageList.first(); it != 0L; it=m_pageList.next() ) 00292 { 00293 KFilePropsPlugin* plugin = dynamic_cast<KFilePropsPlugin*>(it); 00294 if ( plugin ) { 00295 plugin->setFileNameReadOnly( ro ); 00296 break; 00297 } 00298 } 00299 } 00300 00301 void KPropertiesDialog::slotStatResult( KIO::Job * ) 00302 { 00303 } 00304 00305 KPropertiesDialog::~KPropertiesDialog() 00306 { 00307 m_pageList.clear(); 00308 delete d; 00309 } 00310 00311 void KPropertiesDialog::insertPlugin (KPropsDlgPlugin* plugin) 00312 { 00313 connect (plugin, SIGNAL (changed ()), 00314 plugin, SLOT (setDirty ())); 00315 00316 m_pageList.append (plugin); 00317 } 00318 00319 bool KPropertiesDialog::canDisplay( KFileItemList _items ) 00320 { 00321 // TODO: cache the result of those calls. Currently we parse .desktop files far too many times 00322 return KFilePropsPlugin::supports( _items ) || 00323 KFilePermissionsPropsPlugin::supports( _items ) || 00324 KDesktopPropsPlugin::supports( _items ) || 00325 KBindingPropsPlugin::supports( _items ) || 00326 KURLPropsPlugin::supports( _items ) || 00327 KDevicePropsPlugin::supports( _items ) || 00328 KFileMetaPropsPlugin::supports( _items ); 00329 } 00330 00331 void KPropertiesDialog::slotOk() 00332 { 00333 KPropsDlgPlugin *page; 00334 d->m_aborted = false; 00335 00336 KFilePropsPlugin * filePropsPlugin = 0L; 00337 if ( m_pageList.first()->isA("KFilePropsPlugin") ) 00338 filePropsPlugin = static_cast<KFilePropsPlugin *>(m_pageList.first()); 00339 00340 // If any page is dirty, then set the main one (KFilePropsPlugin) as 00341 // dirty too. This is what makes it possible to save changes to a global 00342 // desktop file into a local one. In other cases, it doesn't hurt. 00343 for ( page = m_pageList.first(); page != 0L; page = m_pageList.next() ) 00344 if ( page->isDirty() && filePropsPlugin ) 00345 { 00346 filePropsPlugin->setDirty(); 00347 break; 00348 } 00349 00350 // Apply the changes in the _normal_ order of the tabs now 00351 // This is because in case of renaming a file, KFilePropsPlugin will call 00352 // KPropertiesDialog::rename, so other tab will be ok with whatever order 00353 // BUT for file copied from templates, we need to do the renaming first ! 00354 for ( page = m_pageList.first(); page != 0L && !d->m_aborted; page = m_pageList.next() ) 00355 if ( page->isDirty() ) 00356 { 00357 kdDebug( 250 ) << "applying changes for " << page->className() << endl; 00358 page->applyChanges(); 00359 // applyChanges may change d->m_aborted. 00360 } 00361 else 00362 kdDebug( 250 ) << "skipping page " << page->className() << endl; 00363 00364 if ( !d->m_aborted && filePropsPlugin ) 00365 filePropsPlugin->postApplyChanges(); 00366 00367 if ( !d->m_aborted ) 00368 { 00369 emit applied(); 00370 emit propertiesClosed(); 00371 deleteLater(); 00372 accept(); 00373 } // else, keep dialog open for user to fix the problem. 00374 } 00375 00376 void KPropertiesDialog::slotCancel() 00377 { 00378 emit canceled(); 00379 emit propertiesClosed(); 00380 00381 deleteLater(); 00382 done( Rejected ); 00383 } 00384 00385 void KPropertiesDialog::insertPages() 00386 { 00387 if (m_items.isEmpty()) 00388 return; 00389 00390 if ( KFilePropsPlugin::supports( m_items ) ) 00391 { 00392 KPropsDlgPlugin *p = new KFilePropsPlugin( this ); 00393 insertPlugin (p); 00394 } 00395 00396 if ( KFilePermissionsPropsPlugin::supports( m_items ) ) 00397 { 00398 KPropsDlgPlugin *p = new KFilePermissionsPropsPlugin( this ); 00399 insertPlugin (p); 00400 } 00401 00402 if ( KDesktopPropsPlugin::supports( m_items ) ) 00403 { 00404 KPropsDlgPlugin *p = new KDesktopPropsPlugin( this ); 00405 insertPlugin (p); 00406 } 00407 00408 if ( KBindingPropsPlugin::supports( m_items ) ) 00409 { 00410 KPropsDlgPlugin *p = new KBindingPropsPlugin( this ); 00411 insertPlugin (p); 00412 } 00413 00414 if ( KURLPropsPlugin::supports( m_items ) ) 00415 { 00416 KPropsDlgPlugin *p = new KURLPropsPlugin( this ); 00417 insertPlugin (p); 00418 } 00419 00420 if ( KDevicePropsPlugin::supports( m_items ) ) 00421 { 00422 KPropsDlgPlugin *p = new KDevicePropsPlugin( this ); 00423 insertPlugin (p); 00424 } 00425 00426 if ( KFileMetaPropsPlugin::supports( m_items ) ) 00427 { 00428 KPropsDlgPlugin *p = new KFileMetaPropsPlugin( this ); 00429 insertPlugin (p); 00430 } 00431 00432 00433 if ( KFileSharePropsPlugin::supports( m_items ) ) 00434 { 00435 00436 QString path = m_items.first()->url().path(-1); 00437 bool isLocal = m_items.first()->url().isLocalFile(); 00438 bool isIntoTrash = isLocal && path.startsWith(KGlobalSettings::trashPath()); 00439 if ( !isIntoTrash ) 00440 { 00441 KPropsDlgPlugin *p = new KFileSharePropsPlugin( this ); 00442 insertPlugin (p); 00443 } 00444 } 00445 00446 //plugins 00447 00448 if ( m_items.count() != 1 ) 00449 return; 00450 00451 KFileItem *item = m_items.first(); 00452 QString mimetype = item->mimetype(); 00453 00454 if ( mimetype.isEmpty() ) 00455 return; 00456 00457 QString query = QString::fromLatin1( 00458 "('KPropsDlg/Plugin' in ServiceTypes) and " 00459 "((not exist [X-KDE-Protocol]) or " 00460 " ([X-KDE-Protocol] == '%1' ) )" ).arg(item->url().protocol()); 00461 00462 kdDebug( 250 ) << "trader query: " << query << endl; 00463 KTrader::OfferList offers = KTrader::self()->query( mimetype, query ); 00464 KTrader::OfferList::ConstIterator it = offers.begin(); 00465 KTrader::OfferList::ConstIterator end = offers.end(); 00466 for (; it != end; ++it ) 00467 { 00468 KPropsDlgPlugin *plugin = KParts::ComponentFactory 00469 ::createInstanceFromLibrary<KPropsDlgPlugin>( (*it)->library().local8Bit().data(), 00470 this, 00471 (*it)->name().latin1() ); 00472 if ( !plugin ) 00473 continue; 00474 00475 insertPlugin( plugin ); 00476 } 00477 } 00478 00479 void KPropertiesDialog::updateUrl( const KURL& _newUrl ) 00480 { 00481 Q_ASSERT( m_items.count() == 1 ); 00482 kdDebug(250) << "KPropertiesDialog::updateUrl (pre)" << _newUrl.url() << endl; 00483 KURL newUrl = _newUrl; 00484 emit saveAs(m_singleUrl, newUrl); 00485 kdDebug(250) << "KPropertiesDialog::updateUrl (post)" << newUrl.url() << endl; 00486 00487 m_singleUrl = newUrl; 00488 m_items.first()->setURL( newUrl ); 00489 assert(!m_singleUrl.isEmpty()); 00490 // If we have an Desktop page, set it dirty, so that a full file is saved locally 00491 // Same for a URL page (because of the Name= hack) 00492 for ( QPtrListIterator<KPropsDlgPlugin> it(m_pageList); it.current(); ++it ) 00493 if ( it.current()->isA("KExecPropsPlugin") || // KDE4 remove me 00494 it.current()->isA("KURLPropsPlugin") || 00495 it.current()->isA("KDesktopPropsPlugin")) 00496 { 00497 //kdDebug(250) << "Setting page dirty" << endl; 00498 it.current()->setDirty(); 00499 break; 00500 } 00501 } 00502 00503 void KPropertiesDialog::rename( const QString& _name ) 00504 { 00505 Q_ASSERT( m_items.count() == 1 ); 00506 kdDebug(250) << "KPropertiesDialog::rename " << _name << endl; 00507 KURL newUrl; 00508 // if we're creating from a template : use currentdir 00509 if ( !m_currentDir.isEmpty() ) 00510 { 00511 newUrl = m_currentDir; 00512 newUrl.addPath( _name ); 00513 } 00514 else 00515 { 00516 QString tmpurl = m_singleUrl.url(); 00517 if ( tmpurl.at(tmpurl.length() - 1) == '/') 00518 // It's a directory, so strip the trailing slash first 00519 tmpurl.truncate( tmpurl.length() - 1); 00520 newUrl = tmpurl; 00521 newUrl.setFileName( _name ); 00522 } 00523 updateUrl( newUrl ); 00524 } 00525 00526 void KPropertiesDialog::abortApplying() 00527 { 00528 d->m_aborted = true; 00529 } 00530 00531 class KPropsDlgPlugin::KPropsDlgPluginPrivate 00532 { 00533 public: 00534 KPropsDlgPluginPrivate() 00535 { 00536 } 00537 ~KPropsDlgPluginPrivate() 00538 { 00539 } 00540 00541 bool m_bDirty; 00542 }; 00543 00544 KPropsDlgPlugin::KPropsDlgPlugin( KPropertiesDialog *_props ) 00545 : QObject( _props, 0L ) 00546 { 00547 d = new KPropsDlgPluginPrivate; 00548 properties = _props; 00549 fontHeight = 2*properties->fontMetrics().height(); 00550 d->m_bDirty = false; 00551 } 00552 00553 KPropsDlgPlugin::~KPropsDlgPlugin() 00554 { 00555 delete d; 00556 } 00557 00558 bool KPropsDlgPlugin::isDesktopFile( KFileItem * _item ) 00559 { 00560 // only local files 00561 if ( !_item->isLocalFile() ) 00562 return false; 00563 00564 // only regular files 00565 if ( !S_ISREG( _item->mode() ) ) 00566 return false; 00567 00568 QString t( _item->url().path() ); 00569 00570 // only if readable 00571 FILE *f = fopen( QFile::encodeName(t), "r" ); 00572 if ( f == 0L ) 00573 return false; 00574 fclose(f); 00575 00576 // return true if desktop file 00577 return ( _item->mimetype() == "application/x-desktop" ); 00578 } 00579 00580 void KPropsDlgPlugin::setDirty( bool b ) 00581 { 00582 d->m_bDirty = b; 00583 } 00584 00585 void KPropsDlgPlugin::setDirty() 00586 { 00587 d->m_bDirty = true; 00588 } 00589 00590 bool KPropsDlgPlugin::isDirty() const 00591 { 00592 return d->m_bDirty; 00593 } 00594 00595 void KPropsDlgPlugin::applyChanges() 00596 { 00597 kdWarning(250) << "applyChanges() not implemented in page !" << endl; 00598 } 00599 00601 00602 class KFilePropsPlugin::KFilePropsPluginPrivate 00603 { 00604 public: 00605 KFilePropsPluginPrivate() 00606 { 00607 dirSizeJob = 0L; 00608 dirSizeUpdateTimer = 0L; 00609 m_lined = 0; 00610 } 00611 ~KFilePropsPluginPrivate() 00612 { 00613 if ( dirSizeJob ) 00614 dirSizeJob->kill(); 00615 } 00616 00617 KDirSize * dirSizeJob; 00618 QTimer *dirSizeUpdateTimer; 00619 QFrame *m_frame; 00620 bool bMultiple; 00621 bool bIconChanged; 00622 bool bKDesktopMode; 00623 bool bDesktopFile; 00624 QLabel *m_freeSpaceLabel; 00625 QString mimeType; 00626 QString oldFileName; 00627 KLineEdit* m_lined; 00628 }; 00629 00630 KFilePropsPlugin::KFilePropsPlugin( KPropertiesDialog *_props ) 00631 : KPropsDlgPlugin( _props ) 00632 { 00633 d = new KFilePropsPluginPrivate; 00634 d->bMultiple = (properties->items().count() > 1); 00635 d->bIconChanged = false; 00636 d->bKDesktopMode = (QCString(qApp->name()) == "kdesktop"); // nasty heh? 00637 d->bDesktopFile = KDesktopPropsPlugin::supports(properties->items()); 00638 kdDebug(250) << "KFilePropsPlugin::KFilePropsPlugin bMultiple=" << d->bMultiple << endl; 00639 00640 // We set this data from the first item, and we'll 00641 // check that the other items match against it, resetting when not. 00642 bool isLocal = properties->kurl().isLocalFile(); 00643 KFileItem * item = properties->item(); 00644 bool bDesktopFile = isDesktopFile(item); 00645 mode_t mode = item->mode(); 00646 bool hasDirs = item->isDir() && !item->isLink(); 00647 bool hasRoot = isLocal && properties->kurl().path() == QString::fromLatin1("/"); 00648 QString iconStr = KMimeType::iconForURL(properties->kurl(), mode); 00649 QString directory = properties->kurl().directory(); 00650 QString protocol = properties->kurl().protocol(); 00651 QString mimeComment = item->mimeComment(); 00652 d->mimeType = item->mimetype(); 00653 KIO::filesize_t totalSize = item->size(); 00654 QString magicMimeComment; 00655 if ( isLocal ) { 00656 KMimeType::Ptr magicMimeType = KMimeType::findByFileContent( properties->kurl().path() ); 00657 if ( magicMimeType->name() != KMimeType::defaultMimeType() ) 00658 magicMimeComment = magicMimeType->comment(); 00659 } 00660 00661 // Those things only apply to 'single file' mode 00662 QString filename = QString::null; 00663 bool isTrash = false; 00664 bool isIntoTrash = false; 00665 bool isDevice = false; 00666 m_bFromTemplate = false; 00667 00668 // And those only to 'multiple' mode 00669 uint iDirCount = S_ISDIR(mode) ? 1 : 0; 00670 uint iFileCount = 1-iDirCount; 00671 00672 d->m_frame = properties->addPage (i18n("&General")); 00673 00674 QVBoxLayout *vbl = new QVBoxLayout( d->m_frame, 0, 00675 KDialog::spacingHint(), "vbl"); 00676 QGridLayout *grid = new QGridLayout(0, 3); // unknown rows 00677 grid->setColStretch(0, 0); 00678 grid->setColStretch(1, 0); 00679 grid->setColStretch(2, 1); 00680 grid->addColSpacing(1, KDialog::spacingHint()); 00681 vbl->addLayout(grid); 00682 int curRow = 0; 00683 00684 if ( !d->bMultiple ) 00685 { 00686 // Extract the file name only 00687 filename = properties->defaultName(); 00688 if ( filename.isEmpty() ) // no template 00689 filename = properties->kurl().fileName(); 00690 else 00691 { 00692 m_bFromTemplate = true; 00693 setDirty(); // to enforce that the copy happens 00694 } 00695 d->oldFileName = filename; 00696 00697 // Make it human-readable 00698 filename = nameFromFileName( filename ); 00699 00700 if ( d->bKDesktopMode && d->bDesktopFile ) { 00701 KDesktopFile config( properties->kurl().path(), true /* readonly */ ); 00702 if ( config.hasKey( "Name" ) ) { 00703 filename = config.readName(); 00704 } 00705 } 00706 00707 oldName = filename; 00708 00709 QString path; 00710 00711 if ( !m_bFromTemplate ) { 00712 QString tmp = properties->kurl().path( 1 ); 00713 // is it the trash bin ? 00714 if ( isLocal ) 00715 { 00716 if ( tmp == KGlobalSettings::trashPath()) 00717 isTrash = true; 00718 if ( tmp.startsWith(KGlobalSettings::trashPath())) 00719 isIntoTrash = true; 00720 } 00721 if ( properties->kurl().protocol().find("device", 0, false)==0) 00722 isDevice = true; 00723 // Extract the full name, but without file: for local files 00724 if ( isLocal ) 00725 path = properties->kurl().path(); 00726 else 00727 path = properties->kurl().prettyURL(); 00728 } else { 00729 path = properties->currentDir().path(1) + properties->defaultName(); 00730 directory = properties->currentDir().prettyURL(); 00731 } 00732 00733 if (KExecPropsPlugin::supports(properties->items()) || // KDE4 remove me 00734 d->bDesktopFile || 00735 KBindingPropsPlugin::supports(properties->items())) { 00736 00737 determineRelativePath( path ); 00738 00739 } 00740 00741 } 00742 else 00743 { 00744 // Multiple items: see what they have in common 00745 KFileItemList items = properties->items(); 00746 KFileItemListIterator it( items ); 00747 for ( ++it /*no need to check the first one again*/ ; it.current(); ++it ) 00748 { 00749 KURL url = (*it)->url(); 00750 kdDebug(250) << "KFilePropsPlugin::KFilePropsPlugin " << url.prettyURL() << endl; 00751 // The list of things we check here should match the variables defined 00752 // at the beginning of this method. 00753 if ( url.isLocalFile() != isLocal ) 00754 isLocal = false; // not all local 00755 if ( bDesktopFile && isDesktopFile(*it) != bDesktopFile ) 00756 bDesktopFile = false; // not all desktop files 00757 if ( (*it)->mode() != mode ) 00758 mode = (mode_t)0; 00759 if ( KMimeType::iconForURL(url, mode) != iconStr ) 00760 iconStr = "kmultiple"; 00761 if ( url.directory() != directory ) 00762 directory = QString::null; 00763 if ( url.protocol() != protocol ) 00764 protocol = QString::null; 00765 if ( !mimeComment.isNull() && (*it)->mimeComment() != mimeComment ) 00766 mimeComment = QString::null; 00767 if ( isLocal && !magicMimeComment.isNull() ) { 00768 KMimeType::Ptr magicMimeType = KMimeType::findByFileContent( url.path() ); 00769 if ( magicMimeType->comment() != magicMimeComment ) 00770 magicMimeComment = QString::null; 00771 } 00772 00773 if ( isLocal && url.path() == QString::fromLatin1("/") ) 00774 hasRoot = true; 00775 if ( (*it)->isDir() && !(*it)->isLink() ) 00776 { 00777 iDirCount++; 00778 hasDirs = true; 00779 } 00780 else 00781 { 00782 iFileCount++; 00783 totalSize += (*it)->size(); 00784 } 00785 } 00786 } 00787 00788 if (!isLocal && !protocol.isEmpty()) 00789 { 00790 directory += ' '; 00791 directory += '('; 00792 directory += protocol; 00793 directory += ')'; 00794 } 00795 00796 if ( !isDevice && !isIntoTrash && (bDesktopFile || S_ISDIR(mode)) && !d->bMultiple /*not implemented for multiple*/ ) 00797 { 00798 KIconButton *iconButton = new KIconButton( d->m_frame ); 00799 int bsize = 66 + 2 * iconButton->style().pixelMetric(QStyle::PM_ButtonMargin); 00800 iconButton->setFixedSize(bsize, bsize); 00801 iconButton->setStrictIconSize(false); 00802 // This works for everything except Device icons on unmounted devices 00803 // So we have to really open .desktop files 00804 QString iconStr = KMimeType::findByURL( properties->kurl(), 00805 mode )->icon( properties->kurl(), 00806 isLocal ); 00807 if ( bDesktopFile && isLocal ) 00808 { 00809 KDesktopFile config( properties->kurl().path(), true ); 00810 config.setDesktopGroup(); 00811 iconStr = config.readEntry( "Icon" ); 00812 if ( config.hasDeviceType() ) 00813 iconButton->setIconType( KIcon::Desktop, KIcon::Device ); 00814 else 00815 iconButton->setIconType( KIcon::Desktop, KIcon::Application ); 00816 } else 00817 iconButton->setIconType( KIcon::Desktop, KIcon::FileSystem ); 00818 iconButton->setIcon(iconStr); 00819 iconArea = iconButton; 00820 connect( iconButton, SIGNAL( iconChanged(QString) ), 00821 this, SLOT( slotIconChanged() ) ); 00822 } else { 00823 QLabel *iconLabel = new QLabel( d->m_frame ); 00824 int bsize = 66 + 2 * iconLabel->style().pixelMetric(QStyle::PM_ButtonMargin); 00825 iconLabel->setFixedSize(bsize, bsize); 00826 iconLabel->setPixmap( DesktopIcon( iconStr ) ); 00827 iconArea = iconLabel; 00828 } 00829 grid->addWidget(iconArea, curRow, 0, AlignLeft); 00830 00831 if (d->bMultiple || isTrash || isIntoTrash || isDevice || filename == QString::fromLatin1("/")) 00832 { 00833 QLabel *lab = new QLabel(d->m_frame ); 00834 if ( d->bMultiple ) 00835 lab->setText( KIO::itemsSummaryString( iFileCount + iDirCount, iFileCount, iDirCount, 0, false ) ); 00836 else 00837 lab->setText( filename ); 00838 nameArea = lab; 00839 } else 00840 { 00841 d->m_lined = new KLineEdit( d->m_frame ); 00842 d->m_lined->setText(filename); 00843 nameArea = d->m_lined; 00844 d->m_lined->setFocus(); 00845 connect( d->m_lined, SIGNAL( textChanged( const QString & ) ), 00846 this, SLOT( nameFileChanged(const QString & ) ) ); 00847 } 00848 00849 grid->addWidget(nameArea, curRow++, 2); 00850 00851 KSeparator* sep = new KSeparator( KSeparator::HLine, d->m_frame); 00852 grid->addMultiCellWidget(sep, curRow, curRow, 0, 2); 00853 ++curRow; 00854 00855 QLabel *l; 00856 if ( !mimeComment.isEmpty() && !isDevice && !isIntoTrash) 00857 { 00858 l = new QLabel(i18n("Type:"), d->m_frame ); 00859 00860 grid->addWidget(l, curRow, 0); 00861 00862 QHBox *box = new QHBox(d->m_frame); 00863 l = new QLabel(mimeComment, box ); 00864 00865 QPushButton *button = new QPushButton(box); 00866 00867 QIconSet iconSet = SmallIconSet(QString::fromLatin1("configure")); 00868 QPixmap pixMap = iconSet.pixmap( QIconSet::Small, QIconSet::Normal ); 00869 button->setIconSet( iconSet ); 00870 button->setFixedSize( pixMap.width()+8, pixMap.height()+8 ); 00871 QToolTip::add(button, i18n("Edit file type")); 00872 00873 connect( button, SIGNAL( clicked() ), SLOT( slotEditFileType() )); 00874 00875 00876 grid->addWidget(box, curRow++, 2); 00877 } 00878 00879 if ( !magicMimeComment.isEmpty() && magicMimeComment != mimeComment ) 00880 { 00881 l = new QLabel(i18n("Contents:"), d->m_frame ); 00882 grid->addWidget(l, curRow, 0); 00883 00884 l = new QLabel(magicMimeComment, d->m_frame ); 00885 grid->addWidget(l, curRow++, 2); 00886 } 00887 00888 if ( !directory.isEmpty() ) 00889 { 00890 l = new QLabel( i18n("Location:"), d->m_frame ); 00891 grid->addWidget(l, curRow, 0); 00892 00893 l = new KSqueezedTextLabel( d->m_frame ); 00894 l->setText( directory ); 00895 grid->addWidget(l, curRow++, 2); 00896 } 00897 00898 l = new QLabel(i18n("Size:"), d->m_frame ); 00899 grid->addWidget(l, curRow, 0); 00900 00901 m_sizeLabel = new QLabel( d->m_frame ); 00902 grid->addWidget( m_sizeLabel, curRow++, 2 ); 00903 00904 if ( !hasDirs ) // Only files [and symlinks] 00905 { 00906 m_sizeLabel->setText(QString::fromLatin1("%1 (%2)").arg(KIO::convertSize(totalSize)) 00907 .arg(KGlobal::locale()->formatNumber(totalSize, 0))); 00908 m_sizeDetermineButton = 0L; 00909 m_sizeStopButton = 0L; 00910 } 00911 else // Directory 00912 { 00913 QHBoxLayout * sizelay = new QHBoxLayout(KDialog::spacingHint()); 00914 grid->addLayout( sizelay, curRow++, 2 ); 00915 00916 // buttons 00917 m_sizeDetermineButton = new QPushButton( i18n("Calculate"), d->m_frame ); 00918 m_sizeStopButton = new QPushButton( i18n("Stop"), d->m_frame ); 00919 connect( m_sizeDetermineButton, SIGNAL( clicked() ), this, SLOT( slotSizeDetermine() ) ); 00920 connect( m_sizeStopButton, SIGNAL( clicked() ), this, SLOT( slotSizeStop() ) ); 00921 sizelay->addWidget(m_sizeDetermineButton, 0); 00922 sizelay->addWidget(m_sizeStopButton, 0); 00923 sizelay->addStretch(10); // so that the buttons don't grow horizontally 00924 00925 // auto-launch for local dirs only, and not for '/' 00926 if ( isLocal && !hasRoot ) 00927 { 00928 m_sizeDetermineButton->setText( i18n("Refresh") ); 00929 slotSizeDetermine(); 00930 } 00931 else 00932 m_sizeStopButton->setEnabled( false ); 00933 } 00934 00935 if ( isLocal ) 00936 { 00937 QString mountPoint = KIO::findPathMountPoint( properties->item()->url().path() ); 00938 00939 if (mountPoint != "/") 00940 { 00941 l = new QLabel(i18n("Mounted on:"), d->m_frame ); 00942 grid->addWidget(l, curRow, 0); 00943 00944 l = new KSqueezedTextLabel( mountPoint, d->m_frame ); 00945 grid->addWidget( l, curRow++, 2 ); 00946 } 00947 00948 l = new QLabel(i18n("Free disk space:"), d->m_frame ); 00949 grid->addWidget(l, curRow, 0); 00950 00951 d->m_freeSpaceLabel = new QLabel( d->m_frame ); 00952 grid->addWidget( d->m_freeSpaceLabel, curRow++, 2 ); 00953 00954 KDiskFreeSp * job = new KDiskFreeSp; 00955 connect( job, SIGNAL( foundMountPoint( const unsigned long&, const unsigned long&, 00956 const unsigned long&, const QString& ) ), 00957 this, SLOT( slotFoundMountPoint( const unsigned long&, const unsigned long&, 00958 const unsigned long&, const QString& ) ) ); 00959 job->readDF( mountPoint ); 00960 } 00961 00962 if (!d->bMultiple && item->isLink()) { 00963 l = new QLabel(i18n("Points to:"), d->m_frame ); 00964 grid->addWidget(l, curRow, 0); 00965 00966 l = new QLabel(item->linkDest(), d->m_frame ); 00967 grid->addWidget(l, curRow++, 2); 00968 } 00969 00970 if (!d->bMultiple) // Dates for multiple don't make much sense... 00971 { 00972 sep = new KSeparator( KSeparator::HLine, d->m_frame); 00973 grid->addMultiCellWidget(sep, curRow, curRow, 0, 2); 00974 ++curRow; 00975 00976 QDateTime dt; 00977 time_t tim = item->time(KIO::UDS_CREATION_TIME); 00978 if ( tim ) 00979 { 00980 l = new QLabel(i18n("Created:"), d->m_frame ); 00981 grid->addWidget(l, curRow, 0); 00982 00983 dt.setTime_t( tim ); 00984 l = new QLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame ); 00985 grid->addWidget(l, curRow++, 2); 00986 } 00987 00988 tim = item->time(KIO::UDS_MODIFICATION_TIME); 00989 if ( tim ) 00990 { 00991 l = new QLabel(i18n("Modified:"), d->m_frame ); 00992 grid->addWidget(l, curRow, 0); 00993 00994 dt.setTime_t( tim ); 00995 l = new QLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame ); 00996 grid->addWidget(l, curRow++, 2); 00997 } 00998 00999 tim = item->time(KIO::UDS_ACCESS_TIME); 01000 if ( tim ) 01001 { 01002 l = new QLabel(i18n("Accessed:"), d->m_frame ); 01003 grid->addWidget(l, curRow, 0); 01004 01005 dt.setTime_t( tim ); 01006 l = new QLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame ); 01007 grid->addWidget(l, curRow++, 2); 01008 } 01009 } 01010 vbl->addStretch(1); 01011 } 01012 01013 // QString KFilePropsPlugin::tabName () const 01014 // { 01015 // return i18n ("&General"); 01016 // } 01017 01018 void KFilePropsPlugin::setFileNameReadOnly( bool ro ) 01019 { 01020 if ( d->m_lined ) 01021 d->m_lined->setReadOnly( ro ); 01022 } 01023 01024 void KFilePropsPlugin::slotEditFileType() 01025 { 01026 QString keditfiletype = QString::fromLatin1("keditfiletype"); 01027 KRun::runCommand( keditfiletype 01028 + " --parent " + QString::number( properties->topLevelWidget()->winId()) 01029 + " " + KProcess::quote(d->mimeType), 01030 keditfiletype, keditfiletype /*unused*/); 01031 } 01032 01033 void KFilePropsPlugin::slotIconChanged() 01034 { 01035 d->bIconChanged = true; 01036 emit changed(); 01037 } 01038 01039 void KFilePropsPlugin::nameFileChanged(const QString &text ) 01040 { 01041 properties->enableButtonOK(!text.isEmpty()); 01042 emit changed(); 01043 } 01044 01045 void KFilePropsPlugin::determineRelativePath( const QString & path ) 01046 { 01047 // now let's make it relative 01048 QStringList dirs; 01049 if (KBindingPropsPlugin::supports(properties->items())) 01050 { 01051 m_sRelativePath =KGlobal::dirs()->relativeLocation("mime", path); 01052 if (m_sRelativePath.startsWith("/")) 01053 m_sRelativePath = QString::null; 01054 } 01055 else 01056 { 01057 m_sRelativePath =KGlobal::dirs()->relativeLocation("apps", path); 01058 if (m_sRelativePath.startsWith("/")) 01059 { 01060 m_sRelativePath =KGlobal::dirs()->relativeLocation("xdgdata-apps", path); 01061 if (m_sRelativePath.startsWith("/")) 01062 m_sRelativePath = QString::null; 01063 else 01064 m_sRelativePath = path; 01065 } 01066 } 01067 if ( m_sRelativePath.isEmpty() ) 01068 { 01069 if (KBindingPropsPlugin::supports(properties->items())) 01070 kdWarning(250) << "Warning : editing a mimetype file out of the mimetype dirs!" << endl; 01071 } 01072 } 01073 01074 void KFilePropsPlugin::slotFoundMountPoint( const QString&, 01075 unsigned long kBSize, 01076 unsigned long /*kBUsed*/, 01077 unsigned long kBAvail ) 01078 { 01079 d->m_freeSpaceLabel->setText( 01080 i18n("Available space out of total partition size (percent used)", "%1 out of %2 (%3% used)") 01081 .arg(KIO::convertSizeFromKB(kBAvail)) 01082 .arg(KIO::convertSizeFromKB(kBSize)) 01083 .arg( 100 - (int)(100.0 * kBAvail / kBSize) )); 01084 } 01085 01086 // attention: copy&paste below, due to compiler bug 01087 // it doesn't like those unsigned long parameters -- unsigned long& are ok :-/ 01088 void KFilePropsPlugin::slotFoundMountPoint( const unsigned long& kBSize, 01089 const unsigned long& /*kBUsed*/, 01090 const unsigned long& kBAvail, 01091 const QString& ) 01092 { 01093 d->m_freeSpaceLabel->setText( 01094 i18n("Available space out of total partition size (percent used)", "%1 out of %2 (%3% used)") 01095 .arg(KIO::convertSizeFromKB(kBAvail)) 01096 .arg(KIO::convertSizeFromKB(kBSize)) 01097 .arg( 100 - (int)(100.0 * kBAvail / kBSize) )); 01098 } 01099 01100 void KFilePropsPlugin::slotDirSizeUpdate() 01101 { 01102 KIO::filesize_t totalSize = d->dirSizeJob->totalSize(); 01103 m_sizeLabel->setText( i18n("Calculating... %1 (%2)") 01104 .arg(KIO::convertSize(totalSize)) 01105 .arg(KGlobal::locale()->formatNumber(totalSize, 0)) ); 01106 } 01107 01108 void KFilePropsPlugin::slotDirSizeFinished( KIO::Job * job ) 01109 { 01110 if (job->error()) 01111 m_sizeLabel->setText( job->errorString() ); 01112 else 01113 { 01114 KIO::filesize_t totalSize = static_cast<KDirSize*>(job)->totalSize(); 01115 m_sizeLabel->setText( QString::fromLatin1("%1 (%2)") 01116 .arg(KIO::convertSize(totalSize)) 01117 .arg(KGlobal::locale()->formatNumber(totalSize, 0)) ); 01118 } 01119 m_sizeStopButton->setEnabled(false); 01120 // just in case you change something and try again :) 01121 m_sizeDetermineButton->setText( i18n("Refresh") ); 01122 m_sizeDetermineButton->setEnabled(true); 01123 d->dirSizeJob = 0L; 01124 delete d->dirSizeUpdateTimer; 01125 d->dirSizeUpdateTimer = 0L; 01126 } 01127 01128 void KFilePropsPlugin::slotSizeDetermine() 01129 { 01130 m_sizeLabel->setText( i18n("Calculating...") ); 01131 kdDebug(250) << " KFilePropsPlugin::slotSizeDetermine() properties->item()=" << properties->item() << endl; 01132 kdDebug(250) << " URL=" << properties->item()->url().url() << endl; 01133 d->dirSizeJob = KDirSize::dirSizeJob( properties->items() ); 01134 d->dirSizeUpdateTimer = new QTimer(this); 01135 connect( d->dirSizeUpdateTimer, SIGNAL( timeout() ), 01136 SLOT( slotDirSizeUpdate() ) ); 01137 d->dirSizeUpdateTimer->start(500); 01138 connect( d->dirSizeJob, SIGNAL( result( KIO::Job * ) ), 01139 SLOT( slotDirSizeFinished( KIO::Job * ) ) ); 01140 m_sizeStopButton->setEnabled(true); 01141 m_sizeDetermineButton->setEnabled(false); 01142 } 01143 01144 void KFilePropsPlugin::slotSizeStop() 01145 { 01146 if ( d->dirSizeJob ) 01147 { 01148 m_sizeLabel->setText( i18n("Stopped") ); 01149 d->dirSizeJob->kill(); 01150 d->dirSizeJob = 0; 01151 } 01152 if ( d->dirSizeUpdateTimer ) 01153 d->dirSizeUpdateTimer->stop(); 01154 01155 m_sizeStopButton->setEnabled(false); 01156 m_sizeDetermineButton->setEnabled(true); 01157 } 01158 01159 KFilePropsPlugin::~KFilePropsPlugin() 01160 { 01161 delete d; 01162 } 01163 01164 bool KFilePropsPlugin::supports( KFileItemList /*_items*/ ) 01165 { 01166 return true; 01167 } 01168 01169 // Don't do this at home 01170 void qt_enter_modal( QWidget *widget ); 01171 void qt_leave_modal( QWidget *widget ); 01172 01173 void KFilePropsPlugin::applyChanges() 01174 { 01175 if ( d->dirSizeJob ) 01176 slotSizeStop(); 01177 01178 kdDebug(250) << "KFilePropsPlugin::applyChanges" << endl; 01179 01180 if (nameArea->inherits("QLineEdit")) 01181 { 01182 QString n = ((QLineEdit *) nameArea)->text(); 01183 // Remove trailing spaces (#4345) 01184 while ( n[n.length()-1].isSpace() ) 01185 n.truncate( n.length() - 1 ); 01186 if ( n.isEmpty() ) 01187 { 01188 KMessageBox::sorry( properties, i18n("The new file name is empty!")); 01189 properties->abortApplying(); 01190 return; 01191 } 01192 01193 // Do we need to rename the file ? 01194 kdDebug(250) << "oldname = " << oldName << endl; 01195 kdDebug(250) << "newname = " << n << endl; 01196 if ( oldName != n || m_bFromTemplate ) { // true for any from-template file 01197 KIO::Job * job = 0L; 01198 KURL oldurl = properties->kurl(); 01199 01200 QString newFileName = KIO::encodeFileName(n); 01201 if (d->bDesktopFile && !newFileName.endsWith(".desktop") && !newFileName.endsWith(".kdelnk")) 01202 newFileName += ".desktop"; 01203 01204 // Tell properties. Warning, this changes the result of properties->kurl() ! 01205 properties->rename( newFileName ); 01206 01207 // Update also relative path (for apps and mimetypes) 01208 if ( !m_sRelativePath.isEmpty() ) 01209 determineRelativePath( properties->kurl().path() ); 01210 01211 kdDebug(250) << "New URL = " << properties->kurl().url() << endl; 01212 kdDebug(250) << "old = " << oldurl.url() << endl; 01213 01214 // Don't remove the template !! 01215 if ( !m_bFromTemplate ) // (normal renaming) 01216 job = KIO::move( oldurl, properties->kurl() ); 01217 else // Copying a template 01218 job = KIO::copy( oldurl, properties->kurl() ); 01219 01220 connect( job, SIGNAL( result( KIO::Job * ) ), 01221 SLOT( slotCopyFinished( KIO::Job * ) ) ); 01222 connect( job, SIGNAL( renamed( KIO::Job *, const KURL &, const KURL & ) ), 01223 SLOT( slotFileRenamed( KIO::Job *, const KURL &, const KURL & ) ) ); 01224 // wait for job 01225 QWidget dummy(0,0,WType_Dialog|WShowModal); 01226 qt_enter_modal(&dummy); 01227 qApp->enter_loop(); 01228 qt_leave_modal(&dummy); 01229 return; 01230 } 01231 } 01232 01233 // No job, keep going 01234 slotCopyFinished( 0L ); 01235 } 01236 01237 void KFilePropsPlugin::slotCopyFinished( KIO::Job * job ) 01238 { 01239 kdDebug(250) << "KFilePropsPlugin::slotCopyFinished" << endl; 01240 if (job) 01241 { 01242 // allow apply() to return 01243 qApp->exit_loop(); 01244 if ( job->error() ) 01245 { 01246 job->showErrorDialog( d->m_frame ); 01247 // Didn't work. Revert the URL to the old one 01248 properties->updateUrl( static_cast<KIO::CopyJob*>(job)->srcURLs().first() ); 01249 properties->abortApplying(); // Don't apply the changes to the wrong file ! 01250 return; 01251 } 01252 } 01253 01254 assert( properties->item() ); 01255 assert( !properties->item()->url().isEmpty() ); 01256 01257 // Save the file where we can -> usually in ~/.kde/... 01258 if (KBindingPropsPlugin::supports(properties->items()) && !m_sRelativePath.isEmpty()) 01259 { 01260 KURL newURL; 01261 newURL.setPath( locateLocal("mime", m_sRelativePath) ); 01262 properties->updateUrl( newURL ); 01263 } 01264 else if (d->bDesktopFile && !m_sRelativePath.isEmpty()) 01265 { 01266 kdDebug(250) << "KFilePropsPlugin::slotCopyFinished " << m_sRelativePath << endl; 01267 KURL newURL; 01268 newURL.setPath( KDesktopFile::locateLocal(m_sRelativePath) ); 01269 kdDebug(250) << "KFilePropsPlugin::slotCopyFinished path=" << newURL.path() << endl; 01270 properties->updateUrl( newURL ); 01271 } 01272 01273 if ( d->bKDesktopMode && d->bDesktopFile ) { 01274 // Renamed? Update Name field 01275 if ( d->oldFileName != properties->kurl().fileName() || m_bFromTemplate ) { 01276 KDesktopFile config( properties->kurl().path() ); 01277 QString nameStr = nameFromFileName(properties->kurl().fileName()); 01278 config.writeEntry( "Name", nameStr ); 01279 config.writeEntry( "Name", nameStr, true, false, true ); 01280 } 01281 } 01282 } 01283 01284 void KFilePropsPlugin::applyIconChanges() 01285 { 01286 // handle icon changes - only local files for now 01287 // TODO: Use KTempFile and KIO::file_copy with overwrite = true 01288 if (!iconArea->isA("QLabel") && properties->kurl().isLocalFile() && d->bIconChanged) { 01289 KIconButton *iconButton = (KIconButton *) iconArea; 01290 QString path; 01291 01292 if (S_ISDIR(properties->item()->mode())) 01293 { 01294 path = properties->kurl().path(1) + QString::fromLatin1(".directory"); 01295 // don't call updateUrl because the other tabs (i.e. permissions) 01296 // apply to the directory, not the .directory file. 01297 } 01298 else 01299 path = properties->kurl().path(); 01300 01301 // Get the default image 01302 QString str = KMimeType::findByURL( properties->kurl(), 01303 properties->item()->mode(), 01304 true )->KServiceType::icon(); 01305 // Is it another one than the default ? 01306 QString sIcon; 01307 if ( str != iconButton->icon() ) 01308 sIcon = iconButton->icon(); 01309 // (otherwise write empty value) 01310 01311 kdDebug(250) << "**" << path << "**" << endl; 01312 QFile f( path ); 01313 01314 // If default icon and no .directory file -> don't create one 01315 if ( !sIcon.isEmpty() || f.exists() ) 01316 { 01317 if ( !f.open( IO_ReadWrite ) ) { 01318 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not " 01319 "have sufficient access to write to <b>%1</b>.</qt>").arg(path)); 01320 return; 01321 } 01322 f.close(); 01323 01324 KDesktopFile cfg(path); 01325 kdDebug(250) << "sIcon = " << (sIcon) << endl; 01326 kdDebug(250) << "str = " << (str) << endl; 01327 cfg.writeEntry( "Icon", sIcon ); 01328 cfg.sync(); 01329 } 01330 } 01331 } 01332 01333 void KFilePropsPlugin::slotFileRenamed( KIO::Job *, const KURL &, const KURL & newUrl ) 01334 { 01335 // This is called in case of an existing local file during the copy/move operation, 01336 // if the user chooses Rename. 01337 properties->updateUrl( newUrl ); 01338 } 01339 01340 void KFilePropsPlugin::postApplyChanges() 01341 { 01342 // Save the icon only after applying the permissions changes (#46192) 01343 applyIconChanges(); 01344 01345 KURL::List lst; 01346 KFileItemList items = properties->items(); 01347 for ( KFileItemListIterator it( items ); it.current(); ++it ) 01348 lst.append((*it)->url()); 01349 KDirNotify_stub allDirNotify("*", "KDirNotify*"); 01350 allDirNotify.FilesChanged( lst ); 01351 } 01352 01353 class KFilePermissionsPropsPlugin::KFilePermissionsPropsPluginPrivate 01354 { 01355 public: 01356 KFilePermissionsPropsPluginPrivate() 01357 { 01358 } 01359 ~KFilePermissionsPropsPluginPrivate() 01360 { 01361 } 01362 01363 QFrame *m_frame; 01364 QCheckBox *cbRecursive; 01365 QLabel *explanationLabel; 01366 QComboBox *ownerPermCombo, *groupPermCombo, *othersPermCombo; 01367 QCheckBox *extraCheckbox; 01368 mode_t partialPermissions; 01369 KFilePermissionsPropsPlugin::PermissionsMode pmode; 01370 bool canChangePermissions; 01371 bool isIrregular; 01372 }; 01373 01374 #define UniOwner (S_IRUSR|S_IWUSR|S_IXUSR) 01375 #define UniGroup (S_IRGRP|S_IWGRP|S_IXGRP) 01376 #define UniOthers (S_IROTH|S_IWOTH|S_IXOTH) 01377 #define UniRead (S_IRUSR|S_IRGRP|S_IROTH) 01378 #define UniWrite (S_IWUSR|S_IWGRP|S_IWOTH) 01379 #define UniExec (S_IXUSR|S_IXGRP|S_IXOTH) 01380 #define UniSpecial (S_ISUID|S_ISGID|S_ISVTX) 01381 01382 // synced with PermissionsTarget 01383 const mode_t KFilePermissionsPropsPlugin::permissionsMasks[3] = {UniOwner, UniGroup, UniOthers}; 01384 const mode_t KFilePermissionsPropsPlugin::standardPermissions[4] = { 0, UniRead, UniRead|UniWrite, (mode_t)-1 }; 01385 01386 // synced with PermissionsMode and standardPermissions 01387 const char *KFilePermissionsPropsPlugin::permissionsTexts[4][4] = { 01388 { I18N_NOOP("Forbidden"), 01389 I18N_NOOP("Can Read"), 01390 I18N_NOOP("Can Read & Write"), 01391 0 }, 01392 { I18N_NOOP("Forbidden"), 01393 I18N_NOOP("Can View Content"), 01394 I18N_NOOP("Can View & Modify Content"), 01395 0 }, 01396 { 0, 0, 0, 0}, // no texts for links 01397 { I18N_NOOP("Forbidden"), 01398 I18N_NOOP("Can View Content & Read"), 01399 I18N_NOOP("Can View/Read & Modify/Write"), 01400 0 } 01401 }; 01402 01403 01404 KFilePermissionsPropsPlugin::KFilePermissionsPropsPlugin( KPropertiesDialog *_props ) 01405 : KPropsDlgPlugin( _props ) 01406 { 01407 d = new KFilePermissionsPropsPluginPrivate; 01408 d->cbRecursive = 0L; 01409 grpCombo = 0L; grpEdit = 0; 01410 usrEdit = 0L; 01411 QString path = properties->kurl().path(-1); 01412 QString fname = properties->kurl().fileName(); 01413 bool isLocal = properties->kurl().isLocalFile(); 01414 bool isIntoTrash = isLocal && path.startsWith(KGlobalSettings::trashPath()); 01415 bool isTrash = isLocal && ( properties->kurl().path( 1 ) == KGlobalSettings::trashPath() ); 01416 bool IamRoot = (geteuid() == 0); 01417 01418 KFileItem * item = properties->item(); 01419 bool isLink = item->isLink(); 01420 bool isDir = item->isDir(); // all dirs 01421 bool hasDir = item->isDir(); // at least one dir 01422 permissions = item->permissions(); // common permissions to all files 01423 d->partialPermissions = permissions; // permissions that only some files have (at first we take everything) 01424 d->isIrregular = isIrregular(permissions, isDir, isLink); 01425 strOwner = item->user(); 01426 strGroup = item->group(); 01427 01428 if ( properties->items().count() > 1 ) 01429 { 01430 // Multiple items: see what they have in common 01431 KFileItemList items = properties->items(); 01432 KFileItemListIterator it( items ); 01433 for ( ++it /*no need to check the first one again*/ ; it.current(); ++it ) 01434 { 01435 if (!d->isIrregular) 01436 d->isIrregular |= isIrregular((*it)->permissions(), 01437 (*it)->isDir() == isDir, 01438 (*it)->isLink() == isLink); 01439 if ( (*it)->isLink() != isLink ) 01440 isLink = false; 01441 if ( (*it)->isDir() != isDir ) 01442 isDir = false; 01443 hasDir |= (*it)->isDir(); 01444 if ( (*it)->permissions() != permissions ) 01445 { 01446 permissions &= (*it)->permissions(); 01447 d->partialPermissions |= (*it)->permissions(); 01448 } 01449 if ( (*it)->user() != strOwner ) 01450 strOwner = QString::null; 01451 if ( (*it)->group() != strGroup ) 01452 strGroup = QString::null; 01453 } 01454 } 01455 01456 if (isLink) 01457 d->pmode = PermissionsOnlyLinks; 01458 else if (isDir) 01459 d->pmode = PermissionsOnlyDirs; 01460 else if (hasDir) 01461 d->pmode = PermissionsMixed; 01462 else 01463 d->pmode = PermissionsOnlyFiles; 01464 01465 // keep only what's not in the common permissions 01466 d->partialPermissions = d->partialPermissions & ~permissions; 01467 01468 bool isMyFile = false; 01469 01470 if (isLocal && !strOwner.isEmpty()) { // local files, and all owned by the same person 01471 struct passwd *myself = getpwuid( geteuid() ); 01472 if ( myself != 0L ) 01473 { 01474 isMyFile = (strOwner == QString::fromLocal8Bit(myself->pw_name)); 01475 } else 01476 kdWarning() << "I don't exist ?! geteuid=" << geteuid() << endl; 01477 } else { 01478 //We don't know, for remote files, if they are ours or not. 01479 //So we let the user change permissions, and 01480 //KIO::chmod will tell, if he had no right to do it. 01481 isMyFile = true; 01482 } 01483 01484 d->canChangePermissions = (isMyFile || IamRoot) && (!isLink); 01485 01486 01487 // create GUI 01488 01489 d->m_frame = properties->addPage(i18n("&Permissions")); 01490 01491 QBoxLayout *box = new QVBoxLayout( d->m_frame, 0, KDialog::spacingHint() ); 01492 01493 QWidget *l; 01494 QLabel *lbl; 01495 QGroupBox *gb; 01496 QGridLayout *gl; 01497 QPushButton* pbAdvancedPerm = 0; 01498 01499 /* Group: Access Permissions */ 01500 gb = new QGroupBox ( 0, Qt::Vertical, i18n("Access Permissions"), d->m_frame ); 01501 gb->layout()->setSpacing(KDialog::spacingHint()); 01502 gb->layout()->setMargin(KDialog::marginHint()); 01503 box->addWidget (gb); 01504 01505 gl = new QGridLayout (gb->layout(), 7, 2); 01506 gl->setColStretch(1, 1); 01507 01508 l = d->explanationLabel = new QLabel( "", gb ); 01509 if (isLink) 01510 d->explanationLabel->setText(i18n("This file is a link and does not have permissions.", 01511 "All files are links and do not have permissions.", 01512 properties->items().count())); 01513 else if (!d->canChangePermissions) 01514 d->explanationLabel->setText(i18n("Only the owner can change permissions.")); 01515 gl->addMultiCellWidget(l, 0, 0, 0, 1); 01516 01517 lbl = new QLabel( i18n("O&wner:"), gb); 01518 gl->addWidget(lbl, 1, 0); 01519 l = d->ownerPermCombo = new QComboBox(gb); 01520 lbl->setBuddy(l); 01521 gl->addWidget(l, 1, 1); 01522 connect(l, SIGNAL( highlighted(int) ), this, SIGNAL( changed() )); 01523 QWhatsThis::add(l, i18n("Specifies the actions that the owner is allowed to do.")); 01524 01525 lbl = new QLabel( i18n("Gro&up:"), gb); 01526 gl->addWidget(lbl, 2, 0); 01527 l = d->groupPermCombo = new QComboBox(gb); 01528 lbl->setBuddy(l); 01529 gl->addWidget(l, 2, 1); 01530 connect(l, SIGNAL( highlighted(int) ), this, SIGNAL( changed() )); 01531 QWhatsThis::add(l, i18n("Specifies the actions that the members of the group are allowed to do.")); 01532 01533 lbl = new QLabel( i18n("O&thers:"), gb); 01534 gl->addWidget(lbl, 3, 0); 01535 l = d->othersPermCombo = new QComboBox(gb); 01536 lbl->setBuddy(l); 01537 gl->addWidget(l, 3, 1); 01538 connect(l, SIGNAL( highlighted(int) ), this, SIGNAL( changed() )); 01539 QWhatsThis::add(l, i18n("Specifies the actions that all users, who are neither " 01540 "owner nor in the group, are allowed to do.")); 01541 01542 if (!isLink) { 01543 l = d->extraCheckbox = new QCheckBox(hasDir ? 01544 i18n("Only own&er can rename and delete folder content") : 01545 i18n("Is &executable"), 01546 gb ); 01547 connect( d->extraCheckbox, SIGNAL( clicked() ), this, SIGNAL( changed() ) ); 01548 gl->addWidget(l, 4, 1); 01549 QWhatsThis::add(l, hasDir ? i18n("Enable this option to allow only the folder's owner to " 01550 "delete or rename the contained files and folders. Other " 01551 "users can only add new files, which requires the 'Modify " 01552 "Content' permission.") 01553 : i18n("Enable this option to mark the file as executable. This only makes " 01554 "sense for programs and scripts. It is required when you want to " 01555 "execute them.")); 01556 01557 QLayoutItem *spacer = new QSpacerItem(0, 20, QSizePolicy::Minimum, QSizePolicy::Expanding); 01558 gl->addMultiCell(spacer, 5, 5, 0, 1); 01559 01560 pbAdvancedPerm = new QPushButton(i18n("A&dvanced Permissions..."), gb); 01561 gl->addMultiCellWidget(pbAdvancedPerm, 6, 6, 0, 1, AlignRight); 01562 connect(pbAdvancedPerm, SIGNAL( clicked() ), this, SLOT( slotShowAdvancedPermissions() )); 01563 } 01564 else 01565 d->extraCheckbox = 0; 01566 01567 01568 /**** Group: Ownership ****/ 01569 gb = new QGroupBox ( i18n("Ownership"), d->m_frame ); 01570 box->addWidget (gb); 01571 01572 gl = new QGridLayout (gb, 4, 3, KDialog::marginHint(), KDialog::spacingHint()); 01573 gl->addRowSpacing(0, 10); 01574 01575 /*** Set Owner ***/ 01576 l = new QLabel( i18n("User:"), gb ); 01577 gl->addWidget (l, 1, 0); 01578 01579 /* GJ: Don't autocomplete more than 1000 users. This is a kind of random 01580 * value. Huge sites having 10.000+ user have a fair chance of using NIS, 01581 * (possibly) making this unacceptably slow. 01582 * OTOH, it is nice to offer this functionality for the standard user. 01583 */ 01584 int i, maxEntries = 1000; 01585 struct passwd *user; 01586 struct group *ge; 01587 01588 /* File owner: For root, offer a KLineEdit with autocompletion. 01589 * For a user, who can never chown() a file, offer a QLabel. 01590 */ 01591 if (IamRoot && isLocal) 01592 { 01593 usrEdit = new KLineEdit( gb ); 01594 KCompletion *kcom = usrEdit->completionObject(); 01595 kcom->setOrder(KCompletion::Sorted); 01596 setpwent(); 01597 for (i=0; ((user = getpwent()) != 0L) && (i < maxEntries); i++) 01598 kcom->addItem(QString::fromLatin1(user->pw_name)); 01599 endpwent(); 01600 usrEdit->setCompletionMode((i < maxEntries) ? KGlobalSettings::CompletionAuto : 01601 KGlobalSettings::CompletionNone); 01602 usrEdit->setText(strOwner); 01603 gl->addWidget(usrEdit, 1, 1); 01604 connect( usrEdit, SIGNAL( textChanged( const QString & ) ), 01605 this, SIGNAL( changed() ) ); 01606 } 01607 else 01608 { 01609 l = new QLabel(strOwner, gb); 01610 gl->addWidget(l, 1, 1); 01611 } 01612 01613 /*** Set Group ***/ 01614 01615 QStringList groupList; 01616 QCString strUser; 01617 user = getpwuid(geteuid()); 01618 if (user != 0L) 01619 strUser = user->pw_name; 01620 01621 setgrent(); 01622 for (i=0; ((ge = getgrent()) != 0L) && (i < maxEntries); i++) 01623 { 01624 if (IamRoot) 01625 groupList += QString::fromLatin1(ge->gr_name); 01626 else 01627 { 01628 /* pick the groups to which the user belongs */ 01629 char ** members = ge->gr_mem; 01630 char * member; 01631 while ((member = *members) != 0L) { 01632 if (strUser == member) { 01633 groupList += QString::fromLocal8Bit(ge->gr_name); 01634 break; 01635 } 01636 ++members; 01637 } 01638 } 01639 } 01640 endgrent(); 01641 01642 /* add the effective Group to the list .. */ 01643 ge = getgrgid (getegid()); 01644 if (ge) { 01645 QString name = QString::fromLatin1(ge->gr_name); 01646 if (name.isEmpty()) 01647 name.setNum(ge->gr_gid); 01648 if (groupList.find(name) == groupList.end()) 01649 groupList += name; 01650 } 01651 01652 bool isMyGroup = groupList.contains(strGroup); 01653 01654 /* add the group the file currently belongs to .. 01655 * .. if its not there already 01656 */ 01657 if (!isMyGroup) 01658 groupList += strGroup; 01659 01660 l = new QLabel( i18n("Group:"), gb ); 01661 gl->addWidget (l, 2, 0); 01662 01663 /* Set group: if possible to change: 01664 * - Offer a KLineEdit for root, since he can change to any group. 01665 * - Offer a QComboBox for a normal user, since he can change to a fixed 01666 * (small) set of groups only. 01667 * If not changeable: offer a QLabel. 01668 */ 01669 if (IamRoot && isLocal) 01670 { 01671 grpEdit = new KLineEdit(gb); 01672 KCompletion *kcom = new KCompletion; 01673 kcom->setItems(groupList); 01674 grpEdit->setCompletionObject(kcom, true); 01675 grpEdit->setAutoDeleteCompletionObject( true ); 01676 grpEdit->setCompletionMode(KGlobalSettings::CompletionAuto); 01677 grpEdit->setText(strGroup); 01678 gl->addWidget(grpEdit, 2, 1); 01679 connect( grpEdit, SIGNAL( textChanged( const QString & ) ), 01680 this, SIGNAL( changed() ) ); 01681 } 01682 else if ((groupList.count() > 1) && isMyFile && isLocal) 01683 { 01684 grpCombo = new QComboBox(gb, "combogrouplist"); 01685 grpCombo->insertStringList(groupList); 01686 grpCombo->setCurrentItem(groupList.findIndex(strGroup)); 01687 gl->addWidget(grpCombo, 2, 1); 01688 connect( grpCombo, SIGNAL( activated( int ) ), 01689 this, SIGNAL( changed() ) ); 01690 } 01691 else 01692 { 01693 l = new QLabel(strGroup, gb); 01694 gl->addWidget(l, 2, 1); 01695 } 01696 01697 gl->setColStretch(2, 10); 01698 01699 // "Apply recursive" checkbox 01700 if ( hasDir && !isLink && !isIntoTrash ) 01701 { 01702 d->cbRecursive = new QCheckBox( i18n("Apply changes to all subfolders and their contents"), d->m_frame ); 01703 connect( d->cbRecursive, SIGNAL( clicked() ), this, SIGNAL( changed() ) ); 01704 box->addWidget( d->cbRecursive ); 01705 } 01706 01707 updateAccessControls(); 01708 01709 01710 if ( isIntoTrash || isTrash ) 01711 { 01712 //don't allow to change properties for file into trash 01713 enableAccessControls(false); 01714 if ( pbAdvancedPerm) 01715 pbAdvancedPerm->setEnabled(false); 01716 } 01717 01718 box->addStretch (10); 01719 } 01720 01721 void KFilePermissionsPropsPlugin::slotShowAdvancedPermissions() { 01722 01723 bool isDir = (d->pmode == PermissionsOnlyDirs) || (d->pmode == PermissionsMixed); 01724 KDialogBase dlg(properties, 0, true, i18n("Advanced Permissions"), 01725 KDialogBase::Ok|KDialogBase::Cancel); 01726 01727 QLabel *l, *cl[3]; 01728 QGroupBox *gb; 01729 QGridLayout *gl; 01730 01731 // Group: Access Permissions 01732 gb = new QGroupBox ( i18n("Access Permissions"), &dlg ); 01733 dlg.setMainWidget(gb); 01734 01735 gl = new QGridLayout (gb, 6, 6, 15); 01736 gl->addRowSpacing(0, 10); 01737 01738 l = new QLabel(i18n("Class"), gb); 01739 gl->addWidget(l, 1, 0); 01740 01741 if (isDir) 01742 l = new QLabel( i18n("Show\nEntries"), gb ); 01743 else 01744 l = new QLabel( i18n("Read"), gb ); 01745 gl->addWidget (l, 1, 1); 01746 QString readWhatsThis; 01747 if (isDir) 01748 readWhatsThis = i18n("This flag allows viewing the content of the folder."); 01749 else 01750 readWhatsThis = i18n("The Read flag allows viewing the content of the file."); 01751 QWhatsThis::add(l, readWhatsThis); 01752 01753 if (isDir) 01754 l = new QLabel( i18n("Write\nEntries"), gb ); 01755 else 01756 l = new QLabel( i18n("Write"), gb ); 01757 gl->addWidget (l, 1, 2); 01758 QString writeWhatsThis; 01759 if (isDir) 01760 writeWhatsThis = i18n("This flag allows adding, renaming and deleting of files. " 01761 "Note that deleting and renaming can be limited using the Sticky flag."); 01762 else 01763 writeWhatsThis = i18n("The Write flag allows modifying the content of the file."); 01764 QWhatsThis::add(l, writeWhatsThis); 01765 01766 QString execWhatsThis; 01767 if (isDir) { 01768 l = new QLabel( i18n("Enter folder", "Enter"), gb ); 01769 execWhatsThis = i18n("Enable this flag to allow entering the folder."); 01770 } 01771 else { 01772 l = new QLabel( i18n("Exec"), gb ); 01773 execWhatsThis = i18n("Enable this flag to allow executing the file as a program."); 01774 } 01775 QWhatsThis::add(l, execWhatsThis); 01776 // GJ: Add space between normal and special modes 01777 QSize size = l->sizeHint(); 01778 size.setWidth(size.width() + 15); 01779 l->setFixedSize(size); 01780 gl->addWidget (l, 1, 3); 01781 01782 l = new QLabel( i18n("Special"), gb ); 01783 gl->addMultiCellWidget(l, 1, 1, 4, 5); 01784 QString specialWhatsThis; 01785 if (isDir) 01786 specialWhatsThis = i18n("Special flag. Valid for the whole folder, the exact " 01787 "meaning of the flag can be seen in the right hand column."); 01788 else 01789 specialWhatsThis = i18n("Special flag. The exact meaning of the flag can be seen " 01790 "in the right hand column."); 01791 QWhatsThis::add(l, specialWhatsThis); 01792 01793 cl[0] = new QLabel( i18n("User"), gb ); 01794 gl->addWidget (cl[0], 2, 0); 01795 01796 cl[1] = new QLabel( i18n("Group"), gb ); 01797 gl->addWidget (cl[1], 3, 0); 01798 01799 cl[2] = new QLabel( i18n("Others"), gb ); 01800 gl->addWidget (cl[2], 4, 0); 01801 01802 l = new QLabel(i18n("Set UID"), gb); 01803 gl->addWidget(l, 2, 5); 01804 QString setUidWhatsThis; 01805 if (isDir) 01806 setUidWhatsThis = i18n("If this flag is set, the owner of this folder will be " 01807 "the owner of all new files."); 01808 else 01809 setUidWhatsThis = i18n("If this file is an executable and the flag is set, it will " 01810 "be executed with the permissions of the owner."); 01811 QWhatsThis::add(l, setUidWhatsThis); 01812 01813 l = new QLabel(i18n("Set GID"), gb); 01814 gl->addWidget(l, 3, 5); 01815 QString setGidWhatsThis; 01816 if (isDir) 01817 setGidWhatsThis = i18n("If this flag is set, the group of this folder will be " 01818 "set for all new files."); 01819 else 01820 setGidWhatsThis = i18n("If this file is an executable and the flag is set, it will " 01821 "be executed with the permissions of the group."); 01822 QWhatsThis::add(l, setGidWhatsThis); 01823 01824 l = new QLabel(i18n("File permission, sets user or group ID on execution", "Sticky"), gb); 01825 gl->addWidget(l, 4, 5); 01826 QString stickyWhatsThis; 01827 if (isDir) 01828 stickyWhatsThis = i18n("If the Sticky flag is set on a folder, only the owner " 01829 "and root can delete or rename files. Otherwise everybody " 01830 "with write permissions can do this."); 01831 else 01832 stickyWhatsThis = i18n("The Sticky flag on a file is ignored on Linux, but may " 01833 "be used on some systems"); 01834 QWhatsThis::add(l, stickyWhatsThis); 01835 01836 mode_t aPermissions, aPartialPermissions; 01837 mode_t dummy1, dummy2; 01838 01839 if (!d->isIrregular) { 01840 switch (d->pmode) { 01841 case PermissionsOnlyFiles: 01842 getPermissionMasks(aPartialPermissions, 01843 dummy1, 01844 aPermissions, 01845 dummy2); 01846 break; 01847 case PermissionsOnlyDirs: 01848 case PermissionsMixed: 01849 getPermissionMasks(dummy1, 01850 aPartialPermissions, 01851 dummy2, 01852 aPermissions); 01853 break; 01854 case PermissionsOnlyLinks: 01855 aPermissions = UniRead | UniWrite | UniExec | UniSpecial; 01856 aPartialPermissions = 0; 01857 break; 01858 } 01859 } 01860 else { 01861 aPermissions = permissions; 01862 aPartialPermissions = d->partialPermissions; 01863 } 01864 01865 // Draw Checkboxes 01866 QCheckBox *cba[3][4]; 01867 for (int row = 0; row < 3 ; ++row) { 01868 for (int col = 0; col < 4; ++col) { 01869 QCheckBox *cb = new QCheckBox(gb); 01870 cba[row][col] = cb; 01871 cb->setChecked(aPermissions & fperm[row][col]); 01872 if ( aPartialPermissions & fperm[row][col] ) 01873 { 01874 cb->setTristate(); 01875 cb->setNoChange(); 01876 } 01877 else if (d->cbRecursive && d->cbRecursive->isChecked()) 01878 cb->setTristate(); 01879 01880 cb->setEnabled( d->canChangePermissions ); 01881 gl->addWidget (cb, row+2, col+1); 01882 switch(col) { 01883 case 0: 01884 QWhatsThis::add(cb, readWhatsThis); 01885 break; 01886 case 1: 01887 QWhatsThis::add(cb, writeWhatsThis); 01888 break; 01889 case 2: 01890 QWhatsThis::add(cb, execWhatsThis); 01891 break; 01892 case 3: 01893 switch(row) { 01894 case 0: 01895 QWhatsThis::add(cb, setUidWhatsThis); 01896 break; 01897 case 1: 01898 QWhatsThis::add(cb, setGidWhatsThis); 01899 break; 01900 case 2: 01901 QWhatsThis::add(cb, stickyWhatsThis); 01902 break; 01903 } 01904 break; 01905 } 01906 } 01907 } 01908 gl->setColStretch(6, 10); 01909 01910 if (dlg.exec() != KDialogBase::Accepted) 01911 return; 01912 01913 mode_t andPermissions = mode_t(~0); 01914 mode_t orPermissions = 0; 01915 for (int row = 0; row < 3; ++row) 01916 for (int col = 0; col < 4; ++col) { 01917 switch (cba[row][col]->state()) 01918 { 01919 case QCheckBox::On: 01920 orPermissions |= fperm[row][col]; 01921 //fall through 01922 case QCheckBox::Off: 01923 andPermissions &= ~fperm[row][col]; 01924 break; 01925 default: // NoChange 01926 break; 01927 } 01928 } 01929 01930 d->isIrregular = false; 01931 KFileItemList items = properties->items(); 01932 for (KFileItemListIterator it(items); it.current(); ++it) { 01933 if (isIrregular(((*it)->permissions() & andPermissions) | orPermissions, 01934 (*it)->isDir(), (*it)->isLink())) { 01935 d->isIrregular = true; 01936 break; 01937 } 01938 } 01939 01940 permissions = orPermissions; 01941 d->partialPermissions = andPermissions; 01942 01943 emit changed(); 01944 updateAccessControls(); 01945 } 01946 01947 // QString KFilePermissionsPropsPlugin::tabName () const 01948 // { 01949 // return i18n ("&Permissions"); 01950 // } 01951 01952 KFilePermissionsPropsPlugin::~KFilePermissionsPropsPlugin() 01953 { 01954 delete d; 01955 } 01956 01957 bool KFilePermissionsPropsPlugin::supports( KFileItemList /*_items*/ ) 01958 { 01959 return true; 01960 } 01961 01962 // sets a combo box in the Access Control frame 01963 void KFilePermissionsPropsPlugin::setComboContent(QComboBox *combo, PermissionsTarget target, 01964 mode_t permissions, mode_t partial) { 01965 combo->clear(); 01966 if (d->pmode == PermissionsOnlyLinks) { 01967 combo->insertItem(i18n("Link")); 01968 combo->setCurrentItem(0); 01969 return; 01970 } 01971 01972 mode_t tMask = permissionsMasks[target]; 01973 int textIndex; 01974 for (textIndex = 0; standardPermissions[textIndex] != (mode_t)-1; textIndex++) 01975 if ((standardPermissions[textIndex]&tMask) == (permissions&tMask&(UniRead|UniWrite))) 01976 break; 01977 Q_ASSERT(standardPermissions[textIndex] != (mode_t)-1); // must not happen, would be irreglar 01978 01979 for (int i = 0; permissionsTexts[(int)d->pmode][i]; i++) 01980 combo->insertItem(i18n(permissionsTexts[(int)d->pmode][i])); 01981 01982 if (partial & tMask & ~UniExec) { 01983 combo->insertItem(i18n("Varying (No Change)")); 01984 combo->setCurrentItem(3); 01985 } 01986 else 01987 combo->setCurrentItem(textIndex); 01988 } 01989 01990 // permissions are irregular if they cant be displayed in a combo box. 01991 bool KFilePermissionsPropsPlugin::isIrregular(mode_t permissions, bool isDir, bool isLink) { 01992 if (isLink) // links are always ok 01993 return false; 01994 01995 mode_t p = permissions; 01996 if (p & (S_ISUID | S_ISGID)) // setuid/setgid -> irregular 01997 return true; 01998 if (isDir) { 01999 p &= ~S_ISVTX; // ignore sticky on dirs 02000 02001 // check supported flag combinations 02002 mode_t p0 = p & UniOwner; 02003 if ((p0 != 0) && (p0 != (S_IRUSR | S_IXUSR)) && (p0 != UniOwner)) 02004 return true; 02005 p0 = p & UniGroup; 02006 if ((p0 != 0) && (p0 != (S_IRGRP | S_IXGRP)) && (p0 != UniGroup)) 02007 return true; 02008 p0 = p & UniOthers; 02009 if ((p0 != 0) && (p0 != (S_IROTH | S_IXOTH)) && (p0 != UniOthers)) 02010 return true; 02011 return false; 02012 } 02013 if (p & S_ISVTX) // sticky on file -> irregular 02014 return true; 02015 02016 // check supported flag combinations 02017 mode_t p0 = p & UniOwner; 02018 bool usrXPossible = !p0; // true if this file could be an executable 02019 if (p0 & S_IXUSR) { 02020 if ((p0 == S_IXUSR) || (p0 == (S_IWUSR | S_IXUSR))) 02021 return true; 02022 usrXPossible = true; 02023 } 02024 else if (p0 == S_IWUSR) 02025 return true; 02026 02027 p0 = p & UniGroup; 02028 bool grpXPossible = !p0; // true if this file could be an executable 02029 if (p0 & S_IXGRP) { 02030 if ((p0 == S_IXGRP) || (p0 == (S_IWGRP | S_IXGRP))) 02031 return true; 02032 grpXPossible = true; 02033 } 02034 else if (p0 == S_IWGRP) 02035 return true; 02036 if (p0 == 0) 02037 grpXPossible = true; 02038 02039 p0 = p & UniOthers; 02040 bool othXPossible = !p0; // true if this file could be an executable 02041 if (p0 & S_IXOTH) { 02042 if ((p0 == S_IXOTH) || (p0 == (S_IWOTH | S_IXOTH))) 02043 return true; 02044 othXPossible = true; 02045 } 02046 else if (p0 == S_IWOTH) 02047 return true; 02048 02049 // check that there either all targets are executable-compatible, or none 02050 return (p & UniExec) && !(usrXPossible && grpXPossible && othXPossible); 02051 } 02052 02053 // enables/disabled the widgets in the Access Control frame 02054 void KFilePermissionsPropsPlugin::enableAccessControls(bool enable) { 02055 d->ownerPermCombo->setEnabled(enable); 02056 d->groupPermCombo->setEnabled(enable); 02057 d->othersPermCombo->setEnabled(enable); 02058 if (d->extraCheckbox) 02059 d->extraCheckbox->setEnabled(enable); 02060 if ( d->cbRecursive ) 02061 d->cbRecursive->setEnabled(enable); 02062 } 02063 02064 // updates all widgets in the Access Control frame 02065 void KFilePermissionsPropsPlugin::updateAccessControls() { 02066 setComboContent(d->ownerPermCombo, PermissionsOwner, 02067 permissions, d->partialPermissions); 02068 setComboContent(d->groupPermCombo, PermissionsGroup, 02069 permissions, d->partialPermissions); 02070 setComboContent(d->othersPermCombo, PermissionsOthers, 02071 permissions, d->partialPermissions); 02072 02073 switch(d->pmode) { 02074 case PermissionsOnlyLinks: 02075 enableAccessControls(false); 02076 break; 02077 case PermissionsOnlyFiles: 02078 enableAccessControls(d->canChangePermissions && !d->isIrregular); 02079 if (d->canChangePermissions) 02080 d->explanationLabel->setText(d->isIrregular ? 02081 i18n("This file uses advanced permissions", 02082 "These files use advanced permissions.", 02083 properties->items().count()) : ""); 02084 if (d->partialPermissions & UniExec) { 02085 d->extraCheckbox->setTristate(); 02086 d->extraCheckbox->setNoChange(); 02087 } 02088 else { 02089 d->extraCheckbox->setTristate(false); 02090 d->extraCheckbox->setChecked(permissions & UniExec); 02091 } 02092 break; 02093 case PermissionsOnlyDirs: 02094 enableAccessControls(d->canChangePermissions && !d->isIrregular); 02095 if (d->canChangePermissions) 02096 d->explanationLabel->setText(d->isIrregular ? 02097 i18n("This folder uses advanced permissions.", 02098 "These folders use advanced permissions.", 02099 properties->items().count()) : ""); 02100 if (d->partialPermissions & S_ISVTX) { 02101 d->extraCheckbox->setTristate(); 02102 d->extraCheckbox->setNoChange(); 02103 } 02104 else { 02105 d->extraCheckbox->setTristate(false); 02106 d->extraCheckbox->setChecked(permissions & S_ISVTX); 02107 } 02108 break; 02109 case PermissionsMixed: 02110 enableAccessControls(d->canChangePermissions && !d->isIrregular); 02111 if (d->canChangePermissions) 02112 d->explanationLabel->setText(d->isIrregular ? 02113 i18n("These files use advanced permissions.") : ""); 02114 break; 02115 if (d->partialPermissions & S_ISVTX) { 02116 d->extraCheckbox->setTristate(); 02117 d->extraCheckbox->setNoChange(); 02118 } 02119 else { 02120 d->extraCheckbox->setTristate(false); 02121 d->extraCheckbox->setChecked(permissions & S_ISVTX); 02122 } 02123 break; 02124 } 02125 } 02126 02127 // gets masks for files and dirs from the Access Control frame widgets 02128 void KFilePermissionsPropsPlugin::getPermissionMasks(mode_t &andFilePermissions, 02129 mode_t &andDirPermissions, 02130 mode_t &orFilePermissions, 02131 mode_t &orDirPermissions) { 02132 andFilePermissions = mode_t(~UniSpecial); 02133 andDirPermissions = mode_t(~(S_ISUID|S_ISGID)); 02134 orFilePermissions = 0; 02135 orDirPermissions = 0; 02136 if (d->isIrregular) 02137 return; 02138 02139 mode_t m = standardPermissions[d->ownerPermCombo->currentItem()]; 02140 if (m != (mode_t) -1) { 02141 orFilePermissions |= m & UniOwner; 02142 if ((m & UniOwner) && 02143 ((d->pmode == PermissionsMixed) || 02144 ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == QButton::NoChange)))) 02145 andFilePermissions &= ~(S_IRUSR | S_IWUSR); 02146 else { 02147 andFilePermissions &= ~(S_IRUSR | S_IWUSR | S_IXUSR); 02148 if ((m & S_IRUSR) && (d->extraCheckbox->state() == QButton::On)) 02149 orFilePermissions |= S_IXUSR; 02150 } 02151 02152 orDirPermissions |= m & UniOwner; 02153 if (m & S_IRUSR) 02154 orDirPermissions |= S_IXUSR; 02155 andDirPermissions &= ~(S_IRUSR | S_IWUSR | S_IXUSR); 02156 } 02157 02158 m = standardPermissions[d->groupPermCombo->currentItem()]; 02159 if (m != (mode_t) -1) { 02160 orFilePermissions |= m & UniGroup; 02161 if ((m & UniGroup) && 02162 ((d->pmode == PermissionsMixed) || 02163 ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == QButton::NoChange)))) 02164 andFilePermissions &= ~(S_IRGRP | S_IWGRP); 02165 else { 02166 andFilePermissions &= ~(S_IRGRP | S_IWGRP | S_IXGRP); 02167 if ((m & S_IRGRP) && (d->extraCheckbox->state() == QButton::On)) 02168 orFilePermissions |= S_IXGRP; 02169 } 02170 02171 orDirPermissions |= m & UniGroup; 02172 if (m & S_IRGRP) 02173 orDirPermissions |= S_IXGRP; 02174 andDirPermissions &= ~(S_IRGRP | S_IWGRP | S_IXGRP); 02175 } 02176 02177 m = standardPermissions[d->othersPermCombo->currentItem()]; 02178 if (m != (mode_t) -1) { 02179 orFilePermissions |= m & UniOthers; 02180 if ((m & UniOthers) && 02181 ((d->pmode == PermissionsMixed) || 02182 ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == QButton::NoChange)))) 02183 andFilePermissions &= ~(S_IROTH | S_IWOTH); 02184 else { 02185 andFilePermissions &= ~(S_IROTH | S_IWOTH | S_IXOTH); 02186 if ((m & S_IROTH) && (d->extraCheckbox->state() == QButton::On)) 02187 orFilePermissions |= S_IXOTH; 02188 } 02189 02190 orDirPermissions |= m & UniOthers; 02191 if (m & S_IROTH) 02192 orDirPermissions |= S_IXOTH; 02193 andDirPermissions &= ~(S_IROTH | S_IWOTH | S_IXOTH); 02194 } 02195 02196 if (((d->pmode == PermissionsMixed) || (d->pmode == PermissionsOnlyDirs)) && 02197 (d->extraCheckbox->state() != QButton::NoChange)) { 02198 andDirPermissions &= ~S_ISVTX; 02199 if (d->extraCheckbox->state() == QButton::On) 02200 orDirPermissions |= S_ISVTX; 02201 } 02202 } 02203 02204 void KFilePermissionsPropsPlugin::applyChanges() 02205 { 02206 mode_t orFilePermissions; 02207 mode_t orDirPermissions; 02208 mode_t andFilePermissions; 02209 mode_t andDirPermissions; 02210 02211 if (!d->canChangePermissions) 02212 return; 02213 02214 if (!d->isIrregular) 02215 getPermissionMasks(andFilePermissions, 02216 andDirPermissions, 02217 orFilePermissions, 02218 orDirPermissions); 02219 else { 02220 orFilePermissions = permissions; 02221 andFilePermissions = d->partialPermissions; 02222 orDirPermissions = permissions; 02223 andDirPermissions = d->partialPermissions; 02224 } 02225 02226 QString owner, group; 02227 if (usrEdit) 02228 owner = usrEdit->text(); 02229 if (grpEdit) 02230 group = grpEdit->text(); 02231 else if (grpCombo) 02232 group = grpCombo->currentText(); 02233 02234 if (owner == strOwner) 02235 owner = QString::null; // no change 02236 02237 if (group == strGroup) 02238 group = QString::null; 02239 02240 bool recursive = d->cbRecursive && d->cbRecursive->isChecked(); 02241 bool permissionChange = false; 02242 02243 KFileItemList files, dirs; 02244 KFileItemList items = properties->items(); 02245 for (KFileItemListIterator it(items); it.current(); ++it) { 02246 if ((*it)->isDir()) { 02247 dirs.append(*it); 02248 if ((*it)->permissions() != (((*it)->permissions() & andDirPermissions) | orDirPermissions)) 02249 permissionChange = true; 02250 } 02251 else if ((*it)->isFile()) { 02252 files.append(*it); 02253 if ((*it)->permissions() != (((*it)->permissions() & andFilePermissions) | orFilePermissions)) 02254 permissionChange = true; 02255 } 02256 } 02257 02258 if ( !owner.isEmpty() || !group.isEmpty() || recursive || permissionChange) 02259 { 02260 KIO::Job * job; 02261 if (files.count() > 0) { 02262 job = KIO::chmod( files, orFilePermissions, ~andFilePermissions, 02263 owner, group, false ); 02264 connect( job, SIGNAL( result( KIO::Job * ) ), 02265 SLOT( slotChmodResult( KIO::Job * ) ) ); 02266 // Wait for job 02267 QWidget dummy(0,0,WType_Dialog|WShowModal); 02268 qt_enter_modal(&dummy); 02269 qApp->enter_loop(); 02270 qt_leave_modal(&dummy); 02271 } 02272 if (dirs.count() > 0) { 02273 job = KIO::chmod( dirs, orDirPermissions, ~andDirPermissions, 02274 owner, group, recursive ); 02275 connect( job, SIGNAL( result( KIO::Job * ) ), 02276 SLOT( slotChmodResult( KIO::Job * ) ) ); 02277 // Wait for job 02278 QWidget dummy(0,0,WType_Dialog|WShowModal); 02279 qt_enter_modal(&dummy); 02280 qApp->enter_loop(); 02281 qt_leave_modal(&dummy); 02282 } 02283 } 02284 } 02285 02286 void KFilePermissionsPropsPlugin::slotChmodResult( KIO::Job * job ) 02287 { 02288 kdDebug(250) << "KFilePermissionsPropsPlugin::slotChmodResult" << endl; 02289 if (job->error()) 02290 job->showErrorDialog( d->m_frame ); 02291 // allow apply() to return 02292 qApp->exit_loop(); 02293 } 02294 02295 02296 02297 02298 class KURLPropsPlugin::KURLPropsPluginPrivate 02299 { 02300 public: 02301 KURLPropsPluginPrivate() 02302 { 02303 } 02304 ~KURLPropsPluginPrivate() 02305 { 02306 } 02307 02308 QFrame *m_frame; 02309 }; 02310 02311 KURLPropsPlugin::KURLPropsPlugin( KPropertiesDialog *_props ) 02312 : KPropsDlgPlugin( _props ) 02313 { 02314 d = new KURLPropsPluginPrivate; 02315 d->m_frame = properties->addPage(i18n("U&RL")); 02316 QVBoxLayout *layout = new QVBoxLayout(d->m_frame, 0, KDialog::spacingHint()); 02317 02318 QLabel *l; 02319 l = new QLabel( d->m_frame, "Label_1" ); 02320 l->setText( i18n("URL:") ); 02321 layout->addWidget(l); 02322 02323 URLEdit = new KURLRequester( d->m_frame, "URL Requester" ); 02324 layout->addWidget(URLEdit); 02325 02326 QString path = properties->kurl().path(); 02327 02328 QFile f( path ); 02329 if ( !f.open( IO_ReadOnly ) ) 02330 return; 02331 f.close(); 02332 02333 KSimpleConfig config( path ); 02334 config.setDesktopGroup(); 02335 URLStr = config.readPathEntry( "URL" ); 02336 02337 if ( !URLStr.isNull() ) 02338 URLEdit->setURL( URLStr ); 02339 02340 connect( URLEdit, SIGNAL( textChanged( const QString & ) ), 02341 this, SIGNAL( changed() ) ); 02342 02343 layout->addStretch (1); 02344 } 02345 02346 KURLPropsPlugin::~KURLPropsPlugin() 02347 { 02348 delete d; 02349 } 02350 02351 // QString KURLPropsPlugin::tabName () const 02352 // { 02353 // return i18n ("U&RL"); 02354 // } 02355 02356 bool KURLPropsPlugin::supports( KFileItemList _items ) 02357 { 02358 if ( _items.count() != 1 ) 02359 return false; 02360 KFileItem * item = _items.first(); 02361 // check if desktop file 02362 if ( !KPropsDlgPlugin::isDesktopFile( item ) ) 02363 return false; 02364 02365 // open file and check type 02366 KDesktopFile config( item->url().path(), true /* readonly */ ); 02367 return config.hasLinkType(); 02368 } 02369 02370 void KURLPropsPlugin::applyChanges() 02371 { 02372 QString path = properties->kurl().path(); 02373 02374 QFile f( path ); 02375 if ( !f.open( IO_ReadWrite ) ) { 02376 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have " 02377 "sufficient access to write to <b>%1</b>.</qt>").arg(path)); 02378 return; 02379 } 02380 f.close(); 02381 02382 KSimpleConfig config( path ); 02383 config.setDesktopGroup(); 02384 config.writeEntry( "Type", QString::fromLatin1("Link")); 02385 config.writePathEntry( "URL", URLEdit->url() ); 02386 // Users can't create a Link .desktop file with a Name field, 02387 // but distributions can. Update the Name field in that case. 02388 if ( config.hasKey("Name") ) 02389 { 02390 QString nameStr = nameFromFileName(properties->kurl().fileName()); 02391 config.writeEntry( "Name", nameStr ); 02392 config.writeEntry( "Name", nameStr, true, false, true ); 02393 02394 } 02395 } 02396 02397 02398 /* ---------------------------------------------------- 02399 * 02400 * KBindingPropsPlugin 02401 * 02402 * -------------------------------------------------- */ 02403 02404 class KBindingPropsPlugin::KBindingPropsPluginPrivate 02405 { 02406 public: 02407 KBindingPropsPluginPrivate() 02408 { 02409 } 02410 ~KBindingPropsPluginPrivate() 02411 { 02412 } 02413 02414 QFrame *m_frame; 02415 }; 02416 02417 KBindingPropsPlugin::KBindingPropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props ) 02418 { 02419 d = new KBindingPropsPluginPrivate; 02420 d->m_frame = properties->addPage(i18n("A&ssociation")); 02421 patternEdit = new KLineEdit( d->m_frame, "LineEdit_1" ); 02422 commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" ); 02423 mimeEdit = new KLineEdit( d->m_frame, "LineEdit_3" ); 02424 02425 QBoxLayout *mainlayout = new QVBoxLayout(d->m_frame, 0, KDialog::spacingHint()); 02426 QLabel* tmpQLabel; 02427 02428 tmpQLabel = new QLabel( d->m_frame, "Label_1" ); 02429 tmpQLabel->setText( i18n("Pattern ( example: *.html;*.htm )") ); 02430 tmpQLabel->setMinimumSize(tmpQLabel->sizeHint()); 02431 mainlayout->addWidget(tmpQLabel, 1); 02432 02433 //patternEdit->setGeometry( 10, 40, 210, 30 ); 02434 //patternEdit->setText( "" ); 02435 patternEdit->setMaxLength( 512 ); 02436 patternEdit->setMinimumSize( patternEdit->sizeHint() ); 02437 patternEdit->setFixedHeight( fontHeight ); 02438 mainlayout->addWidget(patternEdit, 1); 02439 02440 tmpQLabel = new QLabel( d->m_frame, "Label_2" ); 02441 tmpQLabel->setText( i18n("Mime Type") ); 02442 tmpQLabel->setMinimumSize(tmpQLabel->sizeHint()); 02443 mainlayout->addWidget(tmpQLabel, 1); 02444 02445 //mimeEdit->setGeometry( 10, 160, 210, 30 ); 02446 mimeEdit->setMaxLength( 256 ); 02447 mimeEdit->setMinimumSize( mimeEdit->sizeHint() ); 02448 mimeEdit->setFixedHeight( fontHeight ); 02449 mainlayout->addWidget(mimeEdit, 1); 02450 02451 tmpQLabel = new QLabel( d->m_frame, "Label_3" ); 02452 tmpQLabel->setText( i18n("Comment") ); 02453 tmpQLabel->setMinimumSize(tmpQLabel->sizeHint()); 02454 mainlayout->addWidget(tmpQLabel, 1); 02455 02456 //commentEdit->setGeometry( 10, 100, 210, 30 ); 02457 commentEdit->setMaxLength( 256 ); 02458 commentEdit->setMinimumSize( commentEdit->sizeHint() ); 02459 commentEdit->setFixedHeight( fontHeight ); 02460 mainlayout->addWidget(commentEdit, 1); 02461 02462 cbAutoEmbed = new QCheckBox( i18n("Left click previews"), d->m_frame, "cbAutoEmbed" ); 02463 mainlayout->addWidget(cbAutoEmbed, 1); 02464 02465 mainlayout->addStretch (10); 02466 mainlayout->activate(); 02467 02468 QFile f( _props->kurl().path() ); 02469 if ( !f.open( IO_ReadOnly ) ) 02470 return; 02471 f.close(); 02472 02473 KSimpleConfig config( _props->kurl().path() ); 02474 config.setDesktopGroup(); 02475 QString patternStr = config.readEntry( "Patterns" ); 02476 QString iconStr = config.readEntry( "Icon" ); 02477 QString commentStr = config.readEntry( "Comment" ); 02478 m_sMimeStr = config.readEntry( "MimeType" ); 02479 02480 if ( !patternStr.isEmpty() ) 02481 patternEdit->setText( patternStr ); 02482 if ( !commentStr.isEmpty() ) 02483 commentEdit->setText( commentStr ); 02484 if ( !m_sMimeStr.isEmpty() ) 02485 mimeEdit->setText( m_sMimeStr ); 02486 cbAutoEmbed->setTristate(); 02487 if ( config.hasKey( "X-KDE-AutoEmbed" ) ) 02488 cbAutoEmbed->setChecked( config.readBoolEntry( "X-KDE-AutoEmbed" ) ); 02489 else 02490 cbAutoEmbed->setNoChange(); 02491 02492 connect( patternEdit, SIGNAL( textChanged( const QString & ) ), 02493 this, SIGNAL( changed() ) ); 02494 connect( commentEdit, SIGNAL( textChanged( const QString & ) ), 02495 this, SIGNAL( changed() ) ); 02496 connect( mimeEdit, SIGNAL( textChanged( const QString & ) ), 02497 this, SIGNAL( changed() ) ); 02498 connect( cbAutoEmbed, SIGNAL( toggled( bool ) ), 02499 this, SIGNAL( changed() ) ); 02500 } 02501 02502 KBindingPropsPlugin::~KBindingPropsPlugin() 02503 { 02504 delete d; 02505 } 02506 02507 // QString KBindingPropsPlugin::tabName () const 02508 // { 02509 // return i18n ("A&ssociation"); 02510 // } 02511 02512 bool KBindingPropsPlugin::supports( KFileItemList _items ) 02513 { 02514 if ( _items.count() != 1 ) 02515 return false; 02516 KFileItem * item = _items.first(); 02517 // check if desktop file 02518 if ( !KPropsDlgPlugin::isDesktopFile( item ) ) 02519 return false; 02520 02521 // open file and check type 02522 KDesktopFile config( item->url().path(), true /* readonly */ ); 02523 return config.hasMimeTypeType(); 02524 } 02525 02526 void KBindingPropsPlugin::applyChanges() 02527 { 02528 QString path = properties->kurl().path(); 02529 QFile f( path ); 02530 02531 if ( !f.open( IO_ReadWrite ) ) 02532 { 02533 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have " 02534 "sufficient access to write to <b>%1</b>.</qt>").arg(path)); 02535 return; 02536 } 02537 f.close(); 02538 02539 KSimpleConfig config( path ); 02540 config.setDesktopGroup(); 02541 config.writeEntry( "Type", QString::fromLatin1("MimeType") ); 02542 02543 config.writeEntry( "Patterns", patternEdit->text() ); 02544 config.writeEntry( "Comment", commentEdit->text() ); 02545 config.writeEntry( "Comment", 02546 commentEdit->text(), true, false, true ); // for compat 02547 config.writeEntry( "MimeType", mimeEdit->text() ); 02548 if ( cbAutoEmbed->state() == QButton::NoChange ) 02549 config.deleteEntry( "X-KDE-AutoEmbed", false ); 02550 else 02551 config.writeEntry( "X-KDE-AutoEmbed", cbAutoEmbed->isChecked() ); 02552 config.sync(); 02553 } 02554 02555 /* ---------------------------------------------------- 02556 * 02557 * KDevicePropsPlugin 02558 * 02559 * -------------------------------------------------- */ 02560 02561 class KDevicePropsPlugin::KDevicePropsPluginPrivate 02562 { 02563 public: 02564 KDevicePropsPluginPrivate() 02565 { 02566 } 02567 ~KDevicePropsPluginPrivate() 02568 { 02569 } 02570 02571 QFrame *m_frame; 02572 QStringList mountpointlist; 02573 }; 02574 02575 KDevicePropsPlugin::KDevicePropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props ) 02576 { 02577 d = new KDevicePropsPluginPrivate; 02578 d->m_frame = properties->addPage(i18n("De&vice")); 02579 02580 QStringList devices; 02581 KMountPoint::List mountPoints = KMountPoint::possibleMountPoints(); 02582 02583 for(KMountPoint::List::ConstIterator it = mountPoints.begin(); 02584 it != mountPoints.end(); ++it) 02585 { 02586 KMountPoint *mp = *it; 02587 QString mountPoint = mp->mountPoint(); 02588 QString device = mp->mountedFrom(); 02589 kdDebug()<<"mountPoint :"<<mountPoint<<" device :"<<device<<" mp->mountType() :"<<mp->mountType()<<endl; 02590 02591 if ((mountPoint != "-") && (mountPoint != "none") && !mountPoint.isEmpty() 02592 && device != "none") 02593 { 02594 devices.append( device + QString::fromLatin1(" (") 02595 + mountPoint + QString::fromLatin1(")") ); 02596 m_devicelist.append(device); 02597 d->mountpointlist.append(mountPoint); 02598 } 02599 } 02600 02601 QGridLayout *layout = new QGridLayout( d->m_frame, 0, 3, 0, 02602 KDialog::spacingHint()); 02603 layout->setColStretch(1, 1); 02604 02605 QLabel* label; 02606 label = new QLabel( d->m_frame ); 02607 label->setText( devices.count() == 0 ? 02608 i18n("Device (/dev/fd0):") : // old style 02609 i18n("Device:") ); // new style (combobox) 02610 layout->addWidget(label, 0, 0); 02611 02612 device = new QComboBox( true, d->m_frame, "ComboBox_device" ); 02613 device->insertStringList( devices ); 02614 layout->addWidget(device, 0, 1); 02615 connect( device, SIGNAL( activated( int ) ), 02616 this, SLOT( slotActivated( int ) ) ); 02617 02618 readonly = new QCheckBox( d->m_frame, "CheckBox_readonly" ); 02619 readonly->setText( i18n("Read only") ); 02620 layout->addWidget(readonly, 1, 1); 02621 02622 label = new QLabel( d->m_frame ); 02623 label->setText( devices.count()==0 ? 02624 i18n("Mount point (/mnt/floppy):") : // old style 02625 i18n("Mount point:")); // new style (combobox) 02626 layout->addWidget(label, 2, 0); 02627 02628 mountpoint = new QLabel( d->m_frame, "LineEdit_mountpoint" ); 02629 02630 layout->addWidget(mountpoint, 2, 1); 02631 02632 KSeparator* sep = new KSeparator( KSeparator::HLine, d->m_frame); 02633 layout->addMultiCellWidget(sep, 4, 4, 0, 2); 02634 02635 unmounted = new KIconButton( d->m_frame ); 02636 int bsize = 66 + 2 * unmounted->style().pixelMetric(QStyle::PM_ButtonMargin); 02637 unmounted->setFixedSize(bsize, bsize); 02638 unmounted->setIconType(KIcon::Desktop, KIcon::Device); 02639 layout->addWidget(unmounted, 5, 0); 02640 02641 label = new QLabel( i18n("Unmounted Icon"), d->m_frame ); 02642 layout->addWidget(label, 5, 1); 02643 02644 layout->setRowStretch(6, 1); 02645 02646 QString path( _props->kurl().path() ); 02647 02648 QFile f( path ); 02649 if ( !f.open( IO_ReadOnly ) ) 02650 return; 02651 f.close(); 02652 02653 KSimpleConfig config( path ); 02654 config.setDesktopGroup(); 02655 QString deviceStr = config.readEntry( "Dev" ); 02656 QString mountPointStr = config.readEntry( "MountPoint" ); 02657 bool ro = config.readBoolEntry( "ReadOnly", false ); 02658 QString unmountedStr = config.readEntry( "UnmountIcon" ); 02659 02660 device->setEditText( deviceStr ); 02661 if ( !deviceStr.isEmpty() ) { 02662 // Set default options for this device (first matching entry) 02663 int index = m_devicelist.findIndex(deviceStr); 02664 if (index != -1) 02665 { 02666 //kdDebug(250) << "found it " << index << endl; 02667 slotActivated( index ); 02668 } 02669 } 02670 02671 if ( !mountPointStr.isEmpty() ) 02672 mountpoint->setText( mountPointStr ); 02673 02674 readonly->setChecked( ro ); 02675 02676 if ( unmountedStr.isEmpty() ) 02677 unmountedStr = KMimeType::mimeType(QString::fromLatin1("application/octet-stream"))->KServiceType::icon(); // default icon 02678 02679 unmounted->setIcon( unmountedStr ); 02680 02681 connect( device, SIGNAL( activated( int ) ), 02682 this, SIGNAL( changed() ) ); 02683 connect( device, SIGNAL( textChanged( const QString & ) ), 02684 this, SIGNAL( changed() ) ); 02685 connect( readonly, SIGNAL( toggled( bool ) ), 02686 this, SIGNAL( changed() ) ); 02687 connect( unmounted, SIGNAL( iconChanged( QString ) ), 02688 this, SIGNAL( changed() ) ); 02689 02690 connect( device, SIGNAL( textChanged( const QString & ) ), 02691 this, SLOT( slotDeviceChanged() ) ); 02692 } 02693 02694 KDevicePropsPlugin::~KDevicePropsPlugin() 02695 { 02696 delete d; 02697 } 02698 02699 // QString KDevicePropsPlugin::tabName () const 02700 // { 02701 // return i18n ("De&vice"); 02702 // } 02703 02704 void KDevicePropsPlugin::slotActivated( int index ) 02705 { 02706 // Update mountpoint so that it matches the device that was selected in the combo 02707 device->setEditText( m_devicelist[index] ); 02708 mountpoint->setText( d->mountpointlist[index] ); 02709 } 02710 02711 void KDevicePropsPlugin::slotDeviceChanged() 02712 { 02713 // Update mountpoint so that it matches the typed device 02714 int index = m_devicelist.findIndex( device->currentText() ); 02715 if ( index != -1 ) 02716 mountpoint->setText( d->mountpointlist[index] ); 02717 else 02718 mountpoint->setText( QString::null ); 02719 } 02720 02721 bool KDevicePropsPlugin::supports( KFileItemList _items ) 02722 { 02723 if ( _items.count() != 1 ) 02724 return false; 02725 KFileItem * item = _items.first(); 02726 // check if desktop file 02727 if ( !KPropsDlgPlugin::isDesktopFile( item ) ) 02728 return false; 02729 // open file and check type 02730 KDesktopFile config( item->url().path(), true /* readonly */ ); 02731 return config.hasDeviceType(); 02732 } 02733 02734 void KDevicePropsPlugin::applyChanges() 02735 { 02736 QString path = properties->kurl().path(); 02737 QFile f( path ); 02738 if ( !f.open( IO_ReadWrite ) ) 02739 { 02740 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient " 02741 "access to write to <b>%1</b>.</qt>").arg(path)); 02742 return; 02743 } 02744 f.close(); 02745 02746 KSimpleConfig config( path ); 02747 config.setDesktopGroup(); 02748 config.writeEntry( "Type", QString::fromLatin1("FSDevice") ); 02749 02750 config.writeEntry( "Dev", device->currentText() ); 02751 config.writeEntry( "MountPoint", mountpoint->text() ); 02752 02753 config.writeEntry( "UnmountIcon", unmounted->icon() ); 02754 kdDebug(250) << "unmounted->icon() = " << unmounted->icon() << endl; 02755 02756 config.writeEntry( "ReadOnly", readonly->isChecked() ); 02757 02758 config.sync(); 02759 } 02760 02761 02762 /* ---------------------------------------------------- 02763 * 02764 * KDesktopPropsPlugin 02765 * 02766 * -------------------------------------------------- */ 02767 02768 02769 KDesktopPropsPlugin::KDesktopPropsPlugin( KPropertiesDialog *_props ) 02770 : KPropsDlgPlugin( _props ) 02771 { 02772 QFrame *frame = properties->addPage(i18n("&Application")); 02773 QVBoxLayout *mainlayout = new QVBoxLayout( frame, 0, KDialog::spacingHint() ); 02774 02775 w = new KPropertiesDesktopBase(frame); 02776 mainlayout->addWidget(w); 02777 02778 bool bKDesktopMode = (QCString(qApp->name()) == "kdesktop"); // nasty heh? 02779 02780 if (bKDesktopMode) 02781 { 02782 // Hide Name entry 02783 w->nameEdit->hide(); 02784 w->nameLabel->hide(); 02785 } 02786 02787 connect( w->nameEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) ); 02788 connect( w->genNameEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) ); 02789 connect( w->commentEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) ); 02790 connect( w->commandEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) ); 02791 02792 connect( w->browseButton, SIGNAL( clicked() ), this, SLOT( slotBrowseExec() ) ); 02793 connect( w->addFiletypeButton, SIGNAL( clicked() ), this, SLOT( slotAddFiletype() ) ); 02794 connect( w->delFiletypeButton, SIGNAL( clicked() ), this, SLOT( slotDelFiletype() ) ); 02795 connect( w->advancedButton, SIGNAL( clicked() ), this, SLOT( slotAdvanced() ) ); 02796 02797 // now populate the page 02798 QString path = _props->kurl().path(); 02799 QFile f( path ); 02800 if ( !f.open( IO_ReadOnly ) ) 02801 return; 02802 f.close(); 02803 02804 KSimpleConfig config( path ); 02805 config.setDollarExpansion( false ); 02806 config.setDesktopGroup(); 02807 QString nameStr = config.readEntry( "Name" ); 02808 QString genNameStr = config.readEntry( "GenericName" ); 02809 QString commentStr = config.readEntry( "Comment" ); 02810 QString commandStr = config.readPathEntry( "Exec" ); 02811 m_origCommandStr = commandStr; 02812 m_terminalBool = config.readBoolEntry( "Terminal" ); 02813 m_terminalOptionStr = config.readEntry( "TerminalOptions" ); 02814 m_suidBool = config.readBoolEntry( "X-KDE-SubstituteUID" ); 02815 m_suidUserStr = config.readEntry( "X-KDE-Username" ); 02816 if( config.hasKey( "StartupNotify" )) 02817 m_startupBool = config.readBoolEntry( "StartupNotify", true ); 02818 else 02819 m_startupBool = config.readBoolEntry( "X-KDE-StartupNotify", true ); 02820 m_dcopServiceType = config.readEntry("X-DCOP-ServiceType").lower(); 02821 02822 QStringList mimeTypes = config.readListEntry( "MimeType", ';' ); 02823 02824 if ( nameStr.isEmpty() || bKDesktopMode ) { 02825 // We'll use the file name if no name is specified 02826 // because we _need_ a Name for a valid file. 02827 // But let's do it in apply, not here, so that we pick up the right name. 02828 setDirty(); 02829 } 02830 if ( !bKDesktopMode ) 02831 w->nameEdit->setText(nameStr); 02832 02833 w->genNameEdit->setText( genNameStr ); 02834 w->commentEdit->setText( commentStr ); 02835 w->commandEdit->setText( commandStr ); 02836 w->filetypeList->setAllColumnsShowFocus(true); 02837 02838 KMimeType::Ptr defaultMimetype = KMimeType::defaultMimeTypePtr(); 02839 for(QStringList::ConstIterator it = mimeTypes.begin(); 02840 it != mimeTypes.end(); ) 02841 { 02842 KMimeType::Ptr p = KMimeType::mimeType(*it); 02843 ++it; 02844 QString preference; 02845 if (it != mimeTypes.end()) 02846 { 02847 bool numeric; 02848 (*it).toInt(&numeric); 02849 if (numeric) 02850 { 02851 preference = *it; 02852 ++it; 02853 } 02854 } 02855 if (p && (p != defaultMimetype)) 02856 { 02857 new QListViewItem(w->filetypeList, p->name(), p->comment(), preference); 02858 } 02859 } 02860 02861 } 02862 02863 KDesktopPropsPlugin::~KDesktopPropsPlugin() 02864 { 02865 } 02866 02867 void KDesktopPropsPlugin::slotSelectMimetype() 02868 { 02869 QListView *w = (QListView*)sender(); 02870 QListViewItem *item = w->firstChild(); 02871 while(item) 02872 { 02873 if (item->isSelected()) 02874 w->setSelected(item, false); 02875 item = item->nextSibling(); 02876 } 02877 } 02878 02879 void KDesktopPropsPlugin::slotAddFiletype() 02880 { 02881 KDialogBase dlg(w, "KPropertiesMimetypes", true, 02882 i18n("Add File Type for %1").arg(properties->kurl().fileName()), 02883 KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok); 02884 02885 dlg.setButtonOKText(i18n("&Add"), i18n("Add the selected file types to\nthe list of supported file types."), 02886 i18n("Add the selected file types to\nthe list of supported file types.")); 02887 02888 KPropertiesMimetypeBase *mw = new KPropertiesMimetypeBase(&dlg); 02889 02890 dlg.setMainWidget(mw); 02891 02892 { 02893 mw->listView->setRootIsDecorated(true); 02894 mw->listView->setSelectionMode(QListView::Extended); 02895 mw->listView->setAllColumnsShowFocus(true); 02896 mw->listView->setFullWidth(true); 02897 mw->listView->setMinimumSize(500,400); 02898 02899 connect(mw->listView, SIGNAL(selectionChanged()), 02900 this, SLOT(slotSelectMimetype())); 02901 connect(mw->listView, SIGNAL(doubleClicked( QListViewItem *, const QPoint &, int )), 02902 &dlg, SLOT( slotOk())); 02903 02904 QMap<QString,QListViewItem*> majorMap; 02905 QListViewItem *majorGroup; 02906 KMimeType::List mimetypes = KMimeType::allMimeTypes(); 02907 QValueListIterator<KMimeType::Ptr> it(mimetypes.begin()); 02908 for (; it != mimetypes.end(); ++it) { 02909 QString mimetype = (*it)->name(); 02910 if (mimetype == "application/octet-stream") 02911 continue; 02912 int index = mimetype.find("/"); 02913 QString maj = mimetype.left(index); 02914 QString min = mimetype.mid(index+1); 02915 02916 QMapIterator<QString,QListViewItem*> mit = majorMap.find( maj ); 02917 if ( mit == majorMap.end() ) { 02918 majorGroup = new QListViewItem( mw->listView, maj ); 02919 majorGroup->setExpandable(true); 02920 mw->listView->setOpen(majorGroup, true); 02921 majorMap.insert( maj, majorGroup ); 02922 } 02923 else 02924 { 02925 majorGroup = mit.data(); 02926 } 02927 02928 QListViewItem *item = new QListViewItem(majorGroup, min, (*it)->comment()); 02929 item->setPixmap(0, (*it)->pixmap(KIcon::Small, IconSize(KIcon::Small))); 02930 } 02931 QMapIterator<QString,QListViewItem*> mit = majorMap.find( "all" ); 02932 if ( mit != majorMap.end()) 02933 { 02934 mw->listView->setCurrentItem(mit.data()); 02935 mw->listView->ensureItemVisible(mit.data()); 02936 } 02937 } 02938 02939 if (dlg.exec() == KDialogBase::Accepted) 02940 { 02941 KMimeType::Ptr defaultMimetype = KMimeType::defaultMimeTypePtr(); 02942 QListViewItem *majorItem = mw->listView->firstChild(); 02943 while(majorItem) 02944 { 02945 QString major = majorItem->text(0); 02946 02947 QListViewItem *minorItem = majorItem->firstChild(); 02948 while(minorItem) 02949 { 02950 if (minorItem->isSelected()) 02951 { 02952 QString mimetype = major + "/" + minorItem->text(0); 02953 KMimeType::Ptr p = KMimeType::mimeType(mimetype); 02954 if (p && (p != defaultMimetype)) 02955 { 02956 mimetype = p->name(); 02957 bool found = false; 02958 QListViewItem *item = w->filetypeList->firstChild(); 02959 while (item) 02960 { 02961 if (mimetype == item->text(0)) 02962 { 02963 found = true; 02964 break; 02965 } 02966 item = item->nextSibling(); 02967 } 02968 if (!found) 02969 new QListViewItem(w->filetypeList, p->name(), p->comment()); 02970 } 02971 } 02972 minorItem = minorItem->nextSibling(); 02973 } 02974 02975 majorItem = majorItem->nextSibling(); 02976 } 02977 02978 } 02979 } 02980 02981 void KDesktopPropsPlugin::slotDelFiletype() 02982 { 02983 delete w->filetypeList->currentItem(); 02984 } 02985 02986 void KDesktopPropsPlugin::checkCommandChanged() 02987 { 02988 if (KRun::binaryName(w->commandEdit->text(), true) != 02989 KRun::binaryName(m_origCommandStr, true)) 02990 { 02991 QString m_origCommandStr = w->commandEdit->text(); 02992 m_dcopServiceType= QString::null; // Reset 02993 } 02994 } 02995 02996 void KDesktopPropsPlugin::applyChanges() 02997 { 02998 kdDebug(250) << "KDesktopPropsPlugin::applyChanges" << endl; 02999 QString path = properties->kurl().path(); 03000 03001 QFile f( path ); 03002 03003 if ( !f.open( IO_ReadWrite ) ) { 03004 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have " 03005 "sufficient access to write to <b>%1</b>.</qt>").arg(path)); 03006 return; 03007 } 03008 f.close(); 03009 03010 // If the command is changed we reset certain settings that are strongly 03011 // coupled to the command. 03012 checkCommandChanged(); 03013 03014 KSimpleConfig config( path ); 03015 config.setDesktopGroup(); 03016 config.writeEntry( "Type", QString::fromLatin1("Application")); 03017 config.writeEntry( "Comment", w->commentEdit->text() ); 03018 config.writeEntry( "Comment", w->commentEdit->text(), true, false, true ); // for compat 03019 config.writeEntry( "GenericName", w->genNameEdit->text() ); 03020 config.writeEntry( "GenericName", w->genNameEdit->text(), true, false, true ); // for compat 03021 03022 config.writePathEntry( "Exec", w->commandEdit->text() ); 03023 03024 // Write mimeTypes 03025 QStringList mimeTypes; 03026 for( QListViewItem *item = w->filetypeList->firstChild(); 03027 item; item = item->nextSibling() ) 03028 { 03029 QString preference = item->text(2); 03030 mimeTypes.append(item->text(0)); 03031 if (!preference.isEmpty()) 03032 mimeTypes.append(preference); 03033 } 03034 03035 config.writeEntry( "MimeType", mimeTypes, ';' ); 03036 03037 if ( !w->nameEdit->isHidden() ) { 03038 QString nameStr = w->nameEdit->text(); 03039 config.writeEntry( "Name", nameStr ); 03040 config.writeEntry( "Name", nameStr, true, false, true ); 03041 } 03042 03043 config.writeEntry("Terminal", m_terminalBool); 03044 config.writeEntry("TerminalOptions", m_terminalOptionStr); 03045 config.writeEntry("X-KDE-SubstituteUID", m_suidBool); 03046 config.writeEntry("X-KDE-Username", m_suidUserStr); 03047 config.writeEntry("StartupNotify", m_startupBool); 03048 config.writeEntry("X-DCOP-ServiceType", m_dcopServiceType); 03049 config.sync(); 03050 03051 // KSycoca update needed? 03052 QString sycocaPath = KGlobal::dirs()->relativeLocation("apps", path); 03053 bool updateNeeded = !sycocaPath.startsWith("/"); 03054 if (!updateNeeded) 03055 { 03056 sycocaPath = KGlobal::dirs()->relativeLocation("xdgdata-apps", path); 03057 updateNeeded = !sycocaPath.startsWith("/"); 03058 } 03059 if (updateNeeded) 03060 KService::rebuildKSycoca(w); 03061 } 03062 03063 03064 void KDesktopPropsPlugin::slotBrowseExec() 03065 { 03066 KURL f = KFileDialog::getOpenURL( QString::null, 03067 QString::null, w ); 03068 if ( f.isEmpty() ) 03069 return; 03070 03071 if ( !f.isLocalFile()) { 03072 KMessageBox::sorry(w, i18n("Only executables on local file systems are supported.")); 03073 return; 03074 } 03075 03076 QString path = f.path(); 03077 KRun::shellQuote( path ); 03078 w->commandEdit->setText( path ); 03079 } 03080 03081 void KDesktopPropsPlugin::slotAdvanced() 03082 { 03083 KDialogBase dlg(w, "KPropertiesDesktopAdv", true, 03084 i18n("Advanced Options for %1").arg(properties->kurl().fileName()), 03085 KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok); 03086 KPropertiesDesktopAdvBase *w = new KPropertiesDesktopAdvBase(&dlg); 03087 03088 dlg.setMainWidget(w); 03089 03090 // If the command is changed we reset certain settings that are strongly 03091 // coupled to the command. 03092 checkCommandChanged(); 03093 03094 // check to see if we use konsole if not do not add the nocloseonexit 03095 // because we don't know how to do this on other terminal applications 03096 KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") ); 03097 QString preferredTerminal = confGroup.readEntry("TerminalApplication", 03098 QString::fromLatin1("konsole")); 03099 03100 bool terminalCloseBool = false; 03101 03102 if (preferredTerminal == "konsole") 03103 { 03104 terminalCloseBool = (m_terminalOptionStr.contains( "--noclose" ) > 0); 03105 w->terminalCloseCheck->setChecked(terminalCloseBool); 03106 m_terminalOptionStr.replace( "--noclose", ""); 03107 } 03108 else 03109 { 03110 w->terminalCloseCheck->hide(); 03111 } 03112 03113 w->terminalCheck->setChecked(m_terminalBool); 03114 w->terminalEdit->setText(m_terminalOptionStr); 03115 w->terminalCloseCheck->setEnabled(m_terminalBool); 03116 w->terminalEdit->setEnabled(m_terminalBool); 03117 w->terminalEditLabel->setEnabled(m_terminalBool); 03118 03119 w->suidCheck->setChecked(m_suidBool); 03120 w->suidEdit->setText(m_suidUserStr); 03121 w->suidEdit->setEnabled(m_suidBool); 03122 w->suidEditLabel->setEnabled(m_suidBool); 03123 03124 w->startupInfoCheck->setChecked(m_startupBool); 03125 03126 if (m_dcopServiceType == "unique") 03127 w->dcopCombo->setCurrentItem(2); 03128 else if (m_dcopServiceType == "multi") 03129 w->dcopCombo->setCurrentItem(1); 03130 else if (m_dcopServiceType == "wait") 03131 w->dcopCombo->setCurrentItem(3); 03132 else 03133 w->dcopCombo->setCurrentItem(0); 03134 03135 // Provide username completion up to 1000 users. 03136 KCompletion *kcom = new KCompletion; 03137 kcom->setOrder(KCompletion::Sorted); 03138 struct passwd *pw; 03139 int i, maxEntries = 1000; 03140 setpwent(); 03141 for (i=0; ((pw = getpwent()) != 0L) && (i < maxEntries); i++) 03142 kcom->addItem(QString::fromLatin1(pw->pw_name)); 03143 endpwent(); 03144 if (i < maxEntries) 03145 { 03146 w->suidEdit->setCompletionObject(kcom, true); 03147 w->suidEdit->setAutoDeleteCompletionObject( true ); 03148 w->suidEdit->setCompletionMode(KGlobalSettings::CompletionAuto); 03149 } 03150 else 03151 { 03152 delete kcom; 03153 } 03154 03155 connect( w->terminalEdit, SIGNAL( textChanged( const QString & ) ), 03156 this, SIGNAL( changed() ) ); 03157 connect( w->terminalCloseCheck, SIGNAL( toggled( bool ) ), 03158 this, SIGNAL( changed() ) ); 03159 connect( w->terminalCheck, SIGNAL( toggled( bool ) ), 03160 this, SIGNAL( changed() ) ); 03161 connect( w->suidCheck, SIGNAL( toggled( bool ) ), 03162 this, SIGNAL( changed() ) ); 03163 connect( w->suidEdit, SIGNAL( textChanged( const QString & ) ), 03164 this, SIGNAL( changed() ) ); 03165 connect( w->startupInfoCheck, SIGNAL( toggled( bool ) ), 03166 this, SIGNAL( changed() ) ); 03167 connect( w->dcopCombo, SIGNAL( highlighted( int ) ), 03168 this, SIGNAL( changed() ) ); 03169 03170 if ( dlg.exec() == QDialog::Accepted ) 03171 { 03172 m_terminalOptionStr = w->terminalEdit->text().stripWhiteSpace(); 03173 m_terminalBool = w->terminalCheck->isChecked(); 03174 m_suidBool = w->suidCheck->isChecked(); 03175 m_suidUserStr = w->suidEdit->text().stripWhiteSpace(); 03176 m_startupBool = w->startupInfoCheck->isChecked(); 03177 03178 if (w->terminalCloseCheck->isChecked()) 03179 { 03180 m_terminalOptionStr.append(" --noclose"); 03181 } 03182 03183 switch(w->dcopCombo->currentItem()) 03184 { 03185 case 1: m_dcopServiceType = "multi"; break; 03186 case 2: m_dcopServiceType = "unique"; break; 03187 case 3: m_dcopServiceType = "wait"; break; 03188 default: m_dcopServiceType = "none"; break; 03189 } 03190 } 03191 } 03192 03193 bool KDesktopPropsPlugin::supports( KFileItemList _items ) 03194 { 03195 if ( _items.count() != 1 ) 03196 return false; 03197 KFileItem * item = _items.first(); 03198 // check if desktop file 03199 if ( !KPropsDlgPlugin::isDesktopFile( item ) ) 03200 return false; 03201 // open file and check type 03202 KDesktopFile config( item->url().path(), true /* readonly */ ); 03203 return config.hasApplicationType() && kapp->authorize("run_desktop_files") && kapp->authorize("shell_access"); 03204 } 03205 03206 void KPropertiesDialog::virtual_hook( int id, void* data ) 03207 { KDialogBase::virtual_hook( id, data ); } 03208 03209 void KPropsDlgPlugin::virtual_hook( int, void* ) 03210 { /*BASE::virtual_hook( id, data );*/ } 03211 03212 03213 03214 03215 03221 class KExecPropsPlugin::KExecPropsPluginPrivate 03222 { 03223 public: 03224 KExecPropsPluginPrivate() 03225 { 03226 } 03227 ~KExecPropsPluginPrivate() 03228 { 03229 } 03230 03231 QFrame *m_frame; 03232 QCheckBox *nocloseonexitCheck; 03233 }; 03234 03235 KExecPropsPlugin::KExecPropsPlugin( KPropertiesDialog *_props ) 03236 : KPropsDlgPlugin( _props ) 03237 { 03238 d = new KExecPropsPluginPrivate; 03239 d->m_frame = properties->addPage(i18n("E&xecute")); 03240 QVBoxLayout * mainlayout = new QVBoxLayout( d->m_frame, 0, 03241 KDialog::spacingHint()); 03242 03243 // Now the widgets in the top layout 03244 03245 QLabel* l; 03246 l = new QLabel( i18n( "Comman&d:" ), d->m_frame ); 03247 mainlayout->addWidget(l); 03248 03249 QHBoxLayout * hlayout; 03250 hlayout = new QHBoxLayout(KDialog::spacingHint()); 03251 mainlayout->addLayout(hlayout); 03252 03253 execEdit = new KLineEdit( d->m_frame ); 03254 QWhatsThis::add(execEdit,i18n( 03255 "Following the command, you can have several place holders which will be replaced " 03256 "with the actual values when the actual program is run:\n" 03257 "%f - a single file name\n" 03258 "%F - a list of files; use for applications that can open several local files at once\n" 03259 "%u - a single URL\n" 03260 "%U - a list of URLs\n" 03261 "%d - the folder of the file to open\n" 03262 "%D - a list of folders\n" 03263 "%i - the icon\n" 03264 "%m - the mini-icon\n" 03265 "%c - the caption")); 03266 hlayout->addWidget(execEdit, 1); 03267 03268 l->setBuddy( execEdit ); 03269 03270 execBrowse = new QPushButton( d->m_frame ); 03271 execBrowse->setText( i18n("&Browse...") ); 03272 hlayout->addWidget(execBrowse); 03273 03274 // The groupbox about swallowing 03275 QGroupBox* tmpQGroupBox; 03276 tmpQGroupBox = new QGroupBox( i18n("Panel Embedding"), d->m_frame ); 03277 tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal ); 03278 03279 mainlayout->addWidget(tmpQGroupBox); 03280 03281 QGridLayout *grid = new QGridLayout(tmpQGroupBox->layout(), 2, 2); 03282 grid->setSpacing( KDialog::spacingHint() ); 03283 grid->setColStretch(1, 1); 03284 03285 l = new QLabel( i18n( "&Execute on click:" ), tmpQGroupBox ); 03286 grid->addWidget(l, 0, 0); 03287 03288 swallowExecEdit = new KLineEdit( tmpQGroupBox ); 03289 grid->addWidget(swallowExecEdit, 0, 1); 03290 03291 l->setBuddy( swallowExecEdit ); 03292 03293 l = new QLabel( i18n( "&Window title:" ), tmpQGroupBox ); 03294 grid->addWidget(l, 1, 0); 03295 03296 swallowTitleEdit = new KLineEdit( tmpQGroupBox ); 03297 grid->addWidget(swallowTitleEdit, 1, 1); 03298 03299 l->setBuddy( swallowTitleEdit ); 03300 03301 // The groupbox about run in terminal 03302 03303 tmpQGroupBox = new QGroupBox( d->m_frame ); 03304 tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal ); 03305 03306 mainlayout->addWidget(tmpQGroupBox); 03307 03308 grid = new QGridLayout(tmpQGroupBox->layout(), 3, 2); 03309 grid->setSpacing( KDialog::spacingHint() ); 03310 grid->setColStretch(1, 1); 03311 03312 terminalCheck = new QCheckBox( tmpQGroupBox ); 03313 terminalCheck->setText( i18n("&Run in terminal") ); 03314 grid->addMultiCellWidget(terminalCheck, 0, 0, 0, 1); 03315 03316 // check to see if we use konsole if not do not add the nocloseonexit 03317 // because we don't know how to do this on other terminal applications 03318 KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") ); 03319 QString preferredTerminal = confGroup.readEntry("TerminalApplication", 03320 QString::fromLatin1("konsole")); 03321 03322 int posOptions = 1; 03323 d->nocloseonexitCheck = 0L; 03324 if (preferredTerminal == "konsole") 03325 { 03326 posOptions = 2; 03327 d->nocloseonexitCheck = new QCheckBox( tmpQGroupBox ); 03328 d->nocloseonexitCheck->setText( i18n("Do not &close when command exits") ); 03329 grid->addMultiCellWidget(d->nocloseonexitCheck, 1, 1, 0, 1); 03330 } 03331 03332 terminalLabel = new QLabel( i18n( "&Terminal options:" ), tmpQGroupBox ); 03333 grid->addWidget(terminalLabel, posOptions, 0); 03334 03335 terminalEdit = new KLineEdit( tmpQGroupBox ); 03336 grid->addWidget(terminalEdit, posOptions, 1); 03337 03338 terminalLabel->setBuddy( terminalEdit ); 03339 03340 // The groupbox about run with substituted uid. 03341 03342 tmpQGroupBox = new QGroupBox( d->m_frame ); 03343 tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal ); 03344 03345 mainlayout->addWidget(tmpQGroupBox); 03346 03347 grid = new QGridLayout(tmpQGroupBox->layout(), 2, 2); 03348 grid->setSpacing(KDialog::spacingHint()); 03349 grid->setColStretch(1, 1); 03350 03351 suidCheck = new QCheckBox(tmpQGroupBox); 03352 suidCheck->setText(i18n("Ru&n as a different user")); 03353 grid->addMultiCellWidget(suidCheck, 0, 0, 0, 1); 03354 03355 suidLabel = new QLabel(i18n( "&Username:" ), tmpQGroupBox); 03356 grid->addWidget(suidLabel, 1, 0); 03357 03358 suidEdit = new KLineEdit(tmpQGroupBox); 03359 grid->addWidget(suidEdit, 1, 1); 03360 03361 suidLabel->setBuddy( suidEdit ); 03362 03363 mainlayout->addStretch(1); 03364 03365 // now populate the page 03366 QString path = _props->kurl().path(); 03367 QFile f( path ); 03368 if ( !f.open( IO_ReadOnly ) ) 03369 return; 03370 f.close(); 03371 03372 KSimpleConfig config( path ); 03373 config.setDollarExpansion( false ); 03374 config.setDesktopGroup(); 03375 execStr = config.readPathEntry( "Exec" ); 03376 swallowExecStr = config.readPathEntry( "SwallowExec" ); 03377 swallowTitleStr = config.readEntry( "SwallowTitle" ); 03378 termBool = config.readBoolEntry( "Terminal" ); 03379 termOptionsStr = config.readEntry( "TerminalOptions" ); 03380 suidBool = config.readBoolEntry( "X-KDE-SubstituteUID" ); 03381 suidUserStr = config.readEntry( "X-KDE-Username" ); 03382 03383 if ( !swallowExecStr.isNull() ) 03384 swallowExecEdit->setText( swallowExecStr ); 03385 if ( !swallowTitleStr.isNull() ) 03386 swallowTitleEdit->setText( swallowTitleStr ); 03387 03388 if ( !execStr.isNull() ) 03389 execEdit->setText( execStr ); 03390 03391 if ( d->nocloseonexitCheck ) 03392 { 03393 d->nocloseonexitCheck->setChecked( (termOptionsStr.contains( "--noclose" ) > 0) ); 03394 termOptionsStr.replace( "--noclose", ""); 03395 } 03396 if ( !termOptionsStr.isNull() ) 03397 terminalEdit->setText( termOptionsStr ); 03398 03399 terminalCheck->setChecked( termBool ); 03400 enableCheckedEdit(); 03401 03402 suidCheck->setChecked( suidBool ); 03403 suidEdit->setText( suidUserStr ); 03404 enableSuidEdit(); 03405 03406 // Provide username completion up to 1000 users. 03407 KCompletion *kcom = new KCompletion; 03408 kcom->setOrder(KCompletion::Sorted); 03409 struct passwd *pw; 03410 int i, maxEntries = 1000; 03411 setpwent(); 03412 for (i=0; ((pw = getpwent()) != 0L) && (i < maxEntries); i++) 03413 kcom->addItem(QString::fromLatin1(pw->pw_name)); 03414 endpwent(); 03415 if (i < maxEntries) 03416 { 03417 suidEdit->setCompletionObject(kcom, true); 03418 suidEdit->setAutoDeleteCompletionObject( true ); 03419 suidEdit->setCompletionMode(KGlobalSettings::CompletionAuto); 03420 } 03421 else 03422 { 03423 delete kcom; 03424 } 03425 03426 connect( swallowExecEdit, SIGNAL( textChanged( const QString & ) ), 03427 this, SIGNAL( changed() ) ); 03428 connect( swallowTitleEdit, SIGNAL( textChanged( const QString & ) ), 03429 this, SIGNAL( changed() ) ); 03430 connect( execEdit, SIGNAL( textChanged( const QString & ) ), 03431 this, SIGNAL( changed() ) ); 03432 connect( terminalEdit, SIGNAL( textChanged( const QString & ) ), 03433 this, SIGNAL( changed() ) ); 03434 if (d->nocloseonexitCheck) 03435 connect( d->nocloseonexitCheck, SIGNAL( toggled( bool ) ), 03436 this, SIGNAL( changed() ) ); 03437 connect( terminalCheck, SIGNAL( toggled( bool ) ), 03438 this, SIGNAL( changed() ) ); 03439 connect( suidCheck, SIGNAL( toggled( bool ) ), 03440 this, SIGNAL( changed() ) ); 03441 connect( suidEdit, SIGNAL( textChanged( const QString & ) ), 03442 this, SIGNAL( changed() ) ); 03443 03444 connect( execBrowse, SIGNAL( clicked() ), this, SLOT( slotBrowseExec() ) ); 03445 connect( terminalCheck, SIGNAL( clicked() ), this, SLOT( enableCheckedEdit() ) ); 03446 connect( suidCheck, SIGNAL( clicked() ), this, SLOT( enableSuidEdit() ) ); 03447 03448 } 03449 03450 KExecPropsPlugin::~KExecPropsPlugin() 03451 { 03452 delete d; 03453 } 03454 03455 void KExecPropsPlugin::enableCheckedEdit() 03456 { 03457 bool checked = terminalCheck->isChecked(); 03458 terminalLabel->setEnabled( checked ); 03459 if (d->nocloseonexitCheck) 03460 d->nocloseonexitCheck->setEnabled( checked ); 03461 terminalEdit->setEnabled( checked ); 03462 } 03463 03464 void KExecPropsPlugin::enableSuidEdit() 03465 { 03466 bool checked = suidCheck->isChecked(); 03467 suidLabel->setEnabled( checked ); 03468 suidEdit->setEnabled( checked ); 03469 } 03470 03471 bool KExecPropsPlugin::supports( KFileItemList _items ) 03472 { 03473 if ( _items.count() != 1 ) 03474 return false; 03475 KFileItem * item = _items.first(); 03476 // check if desktop file 03477 if ( !KPropsDlgPlugin::isDesktopFile( item ) ) 03478 return false; 03479 // open file and check type 03480 KDesktopFile config( item->url().path(), true /* readonly */ ); 03481 return config.hasApplicationType() && kapp->authorize("run_desktop_files") && kapp->authorize("shell_access"); 03482 } 03483 03484 void KExecPropsPlugin::applyChanges() 03485 { 03486 kdDebug(250) << "KExecPropsPlugin::applyChanges" << endl; 03487 QString path = properties->kurl().path(); 03488 03489 QFile f( path ); 03490 03491 if ( !f.open( IO_ReadWrite ) ) { 03492 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have " 03493 "sufficient access to write to <b>%1</b>.</qt>").arg(path)); 03494 return; 03495 } 03496 f.close(); 03497 03498 KSimpleConfig config( path ); 03499 config.setDesktopGroup(); 03500 config.writeEntry( "Type", QString::fromLatin1("Application")); 03501 config.writePathEntry( "Exec", execEdit->text() ); 03502 config.writePathEntry( "SwallowExec", swallowExecEdit->text() ); 03503 config.writeEntry( "SwallowTitle", swallowTitleEdit->text() ); 03504 config.writeEntry( "Terminal", terminalCheck->isChecked() ); 03505 QString temp = terminalEdit->text(); 03506 if (d->nocloseonexitCheck ) 03507 if ( d->nocloseonexitCheck->isChecked() ) 03508 temp += QString::fromLatin1("--noclose "); 03509 temp = temp.stripWhiteSpace(); 03510 config.writeEntry( "TerminalOptions", temp ); 03511 config.writeEntry( "X-KDE-SubstituteUID", suidCheck->isChecked() ); 03512 config.writeEntry( "X-KDE-Username", suidEdit->text() ); 03513 } 03514 03515 03516 void KExecPropsPlugin::slotBrowseExec() 03517 { 03518 KURL f = KFileDialog::getOpenURL( QString::null, 03519 QString::null, d->m_frame ); 03520 if ( f.isEmpty() ) 03521 return; 03522 03523 if ( !f.isLocalFile()) { 03524 KMessageBox::sorry(d->m_frame, i18n("Only executables on local file systems are supported.")); 03525 return; 03526 } 03527 03528 QString path = f.path(); 03529 KRun::shellQuote( path ); 03530 execEdit->setText( path ); 03531 } 03532 03533 class KApplicationPropsPlugin::KApplicationPropsPluginPrivate 03534 { 03535 public: 03536 KApplicationPropsPluginPrivate() 03537 { 03538 m_kdesktopMode = QCString(qApp->name()) == "kdesktop"; // nasty heh? 03539 } 03540 ~KApplicationPropsPluginPrivate() 03541 { 03542 } 03543 03544 QFrame *m_frame; 03545 bool m_kdesktopMode; 03546 }; 03547 03548 KApplicationPropsPlugin::KApplicationPropsPlugin( KPropertiesDialog *_props ) 03549 : KPropsDlgPlugin( _props ) 03550 { 03551 d = new KApplicationPropsPluginPrivate; 03552 d->m_frame = properties->addPage(i18n("&Application")); 03553 QVBoxLayout *toplayout = new QVBoxLayout( d->m_frame, 0, KDialog::spacingHint()); 03554 03555 QIconSet iconSet; 03556 QPixmap pixMap; 03557 03558 addExtensionButton = new QPushButton( QString::null, d->m_frame ); 03559 iconSet = SmallIconSet( "back" ); 03560 addExtensionButton->setIconSet( iconSet ); 03561 pixMap = iconSet.pixmap( QIconSet::Small, QIconSet::Normal ); 03562 addExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 ); 03563 connect( addExtensionButton, SIGNAL( clicked() ), 03564 SLOT( slotAddExtension() ) ); 03565 03566 delExtensionButton = new QPushButton( QString::null, d->m_frame ); 03567 iconSet = SmallIconSet( "forward" ); 03568 delExtensionButton->setIconSet( iconSet ); 03569 delExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 ); 03570 connect( delExtensionButton, SIGNAL( clicked() ), 03571 SLOT( slotDelExtension() ) ); 03572 03573 QLabel *l; 03574 03575 QGridLayout *grid = new QGridLayout(2, 2); 03576 grid->setColStretch(1, 1); 03577 toplayout->addLayout(grid); 03578 03579 if ( d->m_kdesktopMode ) 03580 { 03581 // in kdesktop the name field comes from the first tab 03582 nameEdit = 0L; 03583 } 03584 else 03585 { 03586 l = new QLabel(i18n("Name:"), d->m_frame, "Label_4" ); 03587 grid->addWidget(l, 0, 0); 03588 03589 nameEdit = new KLineEdit( d->m_frame, "LineEdit_3" ); 03590 grid->addWidget(nameEdit, 0, 1); 03591 } 03592 03593 l = new QLabel(i18n("Description:"), d->m_frame, "Label_5" ); 03594 grid->addWidget(l, 1, 0); 03595 03596 genNameEdit = new KLineEdit( d->m_frame, "LineEdit_4" ); 03597 grid->addWidget(genNameEdit, 1, 1); 03598 03599 l = new QLabel(i18n("Comment:"), d->m_frame, "Label_3" ); 03600 grid->addWidget(l, 2, 0); 03601 03602 commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" ); 03603 grid->addWidget(commentEdit, 2, 1); 03604 03605 l = new QLabel(i18n("File types:"), d->m_frame); 03606 toplayout->addWidget(l, 0, AlignLeft); 03607 03608 grid = new QGridLayout(4, 3); 03609 grid->setColStretch(0, 1); 03610 grid->setColStretch(2, 1); 03611 grid->setRowStretch( 0, 1 ); 03612 grid->setRowStretch( 3, 1 ); 03613 toplayout->addLayout(grid, 2); 03614 03615 extensionsList = new QListBox( d->m_frame ); 03616 extensionsList->setSelectionMode( QListBox::Extended ); 03617 grid->addMultiCellWidget(extensionsList, 0, 3, 0, 0); 03618 03619 grid->addWidget(addExtensionButton, 1, 1); 03620 grid->addWidget(delExtensionButton, 2, 1); 03621 03622 availableExtensionsList = new QListBox( d->m_frame ); 03623 availableExtensionsList->setSelectionMode( QListBox::Extended ); 03624 grid->addMultiCellWidget(availableExtensionsList, 0, 3, 2, 2); 03625 03626 QString path = properties->kurl().path() ; 03627 QFile f( path ); 03628 if ( !f.open( IO_ReadOnly ) ) 03629 return; 03630 f.close(); 03631 03632 KSimpleConfig config( path ); 03633 config.setDesktopGroup(); 03634 QString commentStr = config.readEntry( "Comment" ); 03635 QString genNameStr = config.readEntry( "GenericName" ); 03636 03637 QStringList selectedTypes = config.readListEntry( "ServiceTypes" ); 03638 // For compatibility with KDE 1.x 03639 selectedTypes += config.readListEntry( "MimeType", ';' ); 03640 03641 QString nameStr = config.readEntry( QString::fromLatin1("Name") ); 03642 if ( nameStr.isEmpty() || d->m_kdesktopMode ) { 03643 // We'll use the file name if no name is specified 03644 // because we _need_ a Name for a valid file. 03645 // But let's do it in apply, not here, so that we pick up the right name. 03646 setDirty(); 03647 } 03648 03649 commentEdit->setText( commentStr ); 03650 genNameEdit->setText( genNameStr ); 03651 if ( nameEdit ) 03652 nameEdit->setText( nameStr ); 03653 03654 selectedTypes.sort(); 03655 QStringList::Iterator sit = selectedTypes.begin(); 03656 for( ; sit != selectedTypes.end(); ++sit ) { 03657 if ( !((*sit).isEmpty()) ) 03658 extensionsList->insertItem( *sit ); 03659 } 03660 03661 KMimeType::List mimeTypes = KMimeType::allMimeTypes(); 03662 QValueListIterator<KMimeType::Ptr> it2 = mimeTypes.begin(); 03663 for ( ; it2 != mimeTypes.end(); ++it2 ) 03664 addMimeType ( (*it2)->name() ); 03665 03666 updateButton(); 03667 03668 connect( extensionsList, SIGNAL( highlighted( int ) ), 03669 this, SLOT( updateButton() ) ); 03670 connect( availableExtensionsList, SIGNAL( highlighted( int ) ), 03671 this, SLOT( updateButton() ) ); 03672 03673 connect( addExtensionButton, SIGNAL( clicked() ), 03674 this, SIGNAL( changed() ) ); 03675 connect( delExtensionButton, SIGNAL( clicked() ), 03676 this, SIGNAL( changed() ) ); 03677 if ( nameEdit ) 03678 connect( nameEdit, SIGNAL( textChanged( const QString & ) ), 03679 this, SIGNAL( changed() ) ); 03680 connect( commentEdit, SIGNAL( textChanged( const QString & ) ), 03681 this, SIGNAL( changed() ) ); 03682 connect( genNameEdit, SIGNAL( textChanged( const QString & ) ), 03683 this, SIGNAL( changed() ) ); 03684 connect( availableExtensionsList, SIGNAL( selected( int ) ), 03685 this, SIGNAL( changed() ) ); 03686 connect( extensionsList, SIGNAL( selected( int ) ), 03687 this, SIGNAL( changed() ) ); 03688 } 03689 03690 KApplicationPropsPlugin::~KApplicationPropsPlugin() 03691 { 03692 delete d; 03693 } 03694 03695 // QString KApplicationPropsPlugin::tabName () const 03696 // { 03697 // return i18n ("&Application"); 03698 // } 03699 03700 void KApplicationPropsPlugin::updateButton() 03701 { 03702 addExtensionButton->setEnabled(availableExtensionsList->currentItem()>-1); 03703 delExtensionButton->setEnabled(extensionsList->currentItem()>-1); 03704 } 03705 03706 void KApplicationPropsPlugin::addMimeType( const QString & name ) 03707 { 03708 // Add a mimetype to the list of available mime types if not in the extensionsList 03709 03710 bool insert = true; 03711 03712 for ( uint i = 0; i < extensionsList->count(); i++ ) 03713 if ( extensionsList->text( i ) == name ) 03714 insert = false; 03715 03716 if ( insert ) 03717 { 03718 availableExtensionsList->insertItem( name ); 03719 availableExtensionsList->sort(); 03720 } 03721 } 03722 03723 bool KApplicationPropsPlugin::supports( KFileItemList _items ) 03724 { 03725 // same constraints as KExecPropsPlugin : desktop file with Type = Application 03726 return KExecPropsPlugin::supports( _items ); 03727 } 03728 03729 void KApplicationPropsPlugin::applyChanges() 03730 { 03731 QString path = properties->kurl().path(); 03732 03733 QFile f( path ); 03734 03735 if ( !f.open( IO_ReadWrite ) ) { 03736 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not " 03737 "have sufficient access to write to <b>%1</b>.</qt>").arg(path)); 03738 return; 03739 } 03740 f.close(); 03741 03742 KSimpleConfig config( path ); 03743 config.setDesktopGroup(); 03744 config.writeEntry( "Type", QString::fromLatin1("Application")); 03745 config.writeEntry( "Comment", commentEdit->text() ); 03746 config.writeEntry( "Comment", commentEdit->text(), true, false, true ); // for compat 03747 config.writeEntry( "GenericName", genNameEdit->text() ); 03748 config.writeEntry( "GenericName", genNameEdit->text(), true, false, true ); // for compat 03749 03750 QStringList selectedTypes; 03751 for ( uint i = 0; i < extensionsList->count(); i++ ) 03752 selectedTypes.append( extensionsList->text( i ) ); 03753 03754 config.writeEntry( "MimeType", selectedTypes, ';' ); 03755 config.writeEntry( "ServiceTypes", "" ); 03756 // hmm, actually it should probably be the contrary (but see also typeslistitem.cpp) 03757 03758 QString nameStr = nameEdit ? nameEdit->text() : QString::null; 03759 if ( nameStr.isEmpty() ) // nothing entered, or widget not existing at all (kdesktop mode) 03760 nameStr = nameFromFileName(properties->kurl().fileName()); 03761 03762 config.writeEntry( "Name", nameStr ); 03763 config.writeEntry( "Name", nameStr, true, false, true ); 03764 03765 config.sync(); 03766 } 03767 03768 void KApplicationPropsPlugin::slotAddExtension() 03769 { 03770 QListBoxItem *item = availableExtensionsList->firstItem(); 03771 QListBoxItem *nextItem; 03772 03773 while ( item ) 03774 { 03775 nextItem = item->next(); 03776 03777 if ( item->isSelected() ) 03778 { 03779 extensionsList->insertItem( item->text() ); 03780 availableExtensionsList->removeItem( availableExtensionsList->index( item ) ); 03781 } 03782 03783 item = nextItem; 03784 } 03785 03786 extensionsList->sort(); 03787 updateButton(); 03788 } 03789 03790 void KApplicationPropsPlugin::slotDelExtension() 03791 { 03792 QListBoxItem *item = extensionsList->firstItem(); 03793 QListBoxItem *nextItem; 03794 03795 while ( item ) 03796 { 03797 nextItem = item->next(); 03798 03799 if ( item->isSelected() ) 03800 { 03801 availableExtensionsList->insertItem( item->text() ); 03802 extensionsList->removeItem( extensionsList->index( item ) ); 03803 } 03804 03805 item = nextItem; 03806 } 03807 03808 availableExtensionsList->sort(); 03809 updateButton(); 03810 } 03811 03812 03813 03814 #include "kpropertiesdialog.moc"
KDE Logo
This file is part of the documentation for kio Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Aug 30 22:54:41 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003