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