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