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() == "media/builtin-mydocuments") { 02634 URLStr = TQString::null; 02635 TDEConfig xdguserconfig( TQDir::homeDirPath()+"/.config/user-dirs.dirs" ); 02636 URLEdit->setMode(KFile::Directory); 02637 URLEdit->setURL( xdguserconfig.readPathEntry( "XDG_DOCUMENTS_DIR", TQDir::homeDirPath() + "/Documents").remove( "\"" )); 02638 } 02639 else if (item && item->mimetype().startsWith("media/builtin-")) { 02640 URLEdit->setEnabled(false); 02641 } 02642 02643 if ( !URLStr.isNull() ) { 02644 URLEdit->setURL( URLStr ); 02645 } 02646 02647 connect( URLEdit, TQT_SIGNAL( textChanged( const TQString & ) ), 02648 this, TQT_SIGNAL( changed() ) ); 02649 02650 layout->addStretch (1); 02651 } 02652 02653 KURLPropsPlugin::~KURLPropsPlugin() 02654 { 02655 delete d; 02656 } 02657 02658 // TQString KURLPropsPlugin::tabName () const 02659 // { 02660 // return i18n ("U&RL"); 02661 // } 02662 02663 bool KURLPropsPlugin::supports( KFileItemList _items ) 02664 { 02665 if ( _items.count() != 1 ) 02666 return false; 02667 KFileItem * item = _items.first(); 02668 // check if desktop file 02669 if ( !KPropsDlgPlugin::isDesktopFile( item ) ) 02670 return false; 02671 02672 // open file and check type 02673 KDesktopFile config( item->url().path(), true /* readonly */ ); 02674 return config.hasLinkType(); 02675 } 02676 02677 void KURLPropsPlugin::applyChanges() 02678 { 02679 TQString path = properties->kurl().path(); 02680 KFileItem * item = properties->item(); 02681 02682 if (item && item->mimetype() == "media/builtin-mydocuments") { 02683 TDEConfig xdgconfig(TQDir::homeDirPath()+"/.config/user-dirs.dirs" ); 02684 if (xdgconfig.isReadOnly()) { 02685 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have " 02686 "sufficient access to write to <b>%1</b>.</qt>").arg(path)); 02687 return; 02688 } 02689 else { 02690 xdgconfig.writePathEntry( "XDG_DOCUMENTS_DIR", '"'+ URLEdit->url() + '"', true, false, false, false ); 02691 xdgconfig.sync(); 02692 return; 02693 } 02694 } 02695 else if (item && item->mimetype().startsWith("media/builtin-")) { 02696 return; 02697 } 02698 02699 TQFile f( path ); 02700 if ( !f.open( IO_ReadWrite ) ) { 02701 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have " 02702 "sufficient access to write to <b>%1</b>.</qt>").arg(path)); 02703 return; 02704 } 02705 f.close(); 02706 02707 KSimpleConfig config( path ); 02708 config.setDesktopGroup(); 02709 config.writeEntry( "Type", TQString::fromLatin1("Link")); 02710 config.writePathEntry( "URL", URLEdit->url() ); 02711 // Users can't create a Link .desktop file with a Name field, 02712 // but distributions can. Update the Name field in that case. 02713 if ( config.hasKey("Name") ) 02714 { 02715 TQString nameStr = nameFromFileName(properties->kurl().fileName()); 02716 config.writeEntry( "Name", nameStr ); 02717 config.writeEntry( "Name", nameStr, true, false, true ); 02718 02719 } 02720 } 02721 02722 02723 /* ---------------------------------------------------- 02724 * 02725 * KBindingPropsPlugin 02726 * 02727 * -------------------------------------------------- */ 02728 02729 class KBindingPropsPlugin::KBindingPropsPluginPrivate 02730 { 02731 public: 02732 KBindingPropsPluginPrivate() 02733 { 02734 } 02735 ~KBindingPropsPluginPrivate() 02736 { 02737 } 02738 02739 TQFrame *m_frame; 02740 }; 02741 02742 KBindingPropsPlugin::KBindingPropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props ) 02743 { 02744 d = new KBindingPropsPluginPrivate; 02745 d->m_frame = properties->addPage(i18n("A&ssociation")); 02746 patternEdit = new KLineEdit( d->m_frame, "LineEdit_1" ); 02747 commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" ); 02748 mimeEdit = new KLineEdit( d->m_frame, "LineEdit_3" ); 02749 02750 TQBoxLayout *mainlayout = new TQVBoxLayout(d->m_frame, 0, KDialog::spacingHint()); 02751 TQLabel* tmpQLabel; 02752 02753 tmpQLabel = new TQLabel( d->m_frame, "Label_1" ); 02754 tmpQLabel->setText( i18n("Pattern ( example: *.html;*.htm )") ); 02755 tmpQLabel->setMinimumSize(tmpQLabel->sizeHint()); 02756 mainlayout->addWidget(tmpQLabel, 1); 02757 02758 //patternEdit->setGeometry( 10, 40, 210, 30 ); 02759 //patternEdit->setText( "" ); 02760 patternEdit->setMaxLength( 512 ); 02761 patternEdit->setMinimumSize( patternEdit->sizeHint() ); 02762 patternEdit->setFixedHeight( fontHeight ); 02763 mainlayout->addWidget(patternEdit, 1); 02764 02765 tmpQLabel = new TQLabel( d->m_frame, "Label_2" ); 02766 tmpQLabel->setText( i18n("Mime Type") ); 02767 tmpQLabel->setMinimumSize(tmpQLabel->sizeHint()); 02768 mainlayout->addWidget(tmpQLabel, 1); 02769 02770 //mimeEdit->setGeometry( 10, 160, 210, 30 ); 02771 mimeEdit->setMaxLength( 256 ); 02772 mimeEdit->setMinimumSize( mimeEdit->sizeHint() ); 02773 mimeEdit->setFixedHeight( fontHeight ); 02774 mainlayout->addWidget(mimeEdit, 1); 02775 02776 tmpQLabel = new TQLabel( d->m_frame, "Label_3" ); 02777 tmpQLabel->setText( i18n("Comment") ); 02778 tmpQLabel->setMinimumSize(tmpQLabel->sizeHint()); 02779 mainlayout->addWidget(tmpQLabel, 1); 02780 02781 //commentEdit->setGeometry( 10, 100, 210, 30 ); 02782 commentEdit->setMaxLength( 256 ); 02783 commentEdit->setMinimumSize( commentEdit->sizeHint() ); 02784 commentEdit->setFixedHeight( fontHeight ); 02785 mainlayout->addWidget(commentEdit, 1); 02786 02787 cbAutoEmbed = new TQCheckBox( i18n("Left click previews"), d->m_frame, "cbAutoEmbed" ); 02788 mainlayout->addWidget(cbAutoEmbed, 1); 02789 02790 mainlayout->addStretch (10); 02791 mainlayout->activate(); 02792 02793 TQFile f( _props->kurl().path() ); 02794 if ( !f.open( IO_ReadOnly ) ) 02795 return; 02796 f.close(); 02797 02798 KSimpleConfig config( _props->kurl().path() ); 02799 config.setDesktopGroup(); 02800 TQString patternStr = config.readEntry( "Patterns" ); 02801 TQString iconStr = config.readEntry( "Icon" ); 02802 TQString commentStr = config.readEntry( "Comment" ); 02803 m_sMimeStr = config.readEntry( "MimeType" ); 02804 02805 if ( !patternStr.isEmpty() ) 02806 patternEdit->setText( patternStr ); 02807 if ( !commentStr.isEmpty() ) 02808 commentEdit->setText( commentStr ); 02809 if ( !m_sMimeStr.isEmpty() ) 02810 mimeEdit->setText( m_sMimeStr ); 02811 cbAutoEmbed->setTristate(); 02812 if ( config.hasKey( "X-TDE-AutoEmbed" ) ) 02813 cbAutoEmbed->setChecked( config.readBoolEntry( "X-TDE-AutoEmbed" ) ); 02814 else 02815 cbAutoEmbed->setNoChange(); 02816 02817 connect( patternEdit, TQT_SIGNAL( textChanged( const TQString & ) ), 02818 this, TQT_SIGNAL( changed() ) ); 02819 connect( commentEdit, TQT_SIGNAL( textChanged( const TQString & ) ), 02820 this, TQT_SIGNAL( changed() ) ); 02821 connect( mimeEdit, TQT_SIGNAL( textChanged( const TQString & ) ), 02822 this, TQT_SIGNAL( changed() ) ); 02823 connect( cbAutoEmbed, TQT_SIGNAL( toggled( bool ) ), 02824 this, TQT_SIGNAL( changed() ) ); 02825 } 02826 02827 KBindingPropsPlugin::~KBindingPropsPlugin() 02828 { 02829 delete d; 02830 } 02831 02832 // TQString KBindingPropsPlugin::tabName () const 02833 // { 02834 // return i18n ("A&ssociation"); 02835 // } 02836 02837 bool KBindingPropsPlugin::supports( KFileItemList _items ) 02838 { 02839 if ( _items.count() != 1 ) 02840 return false; 02841 KFileItem * item = _items.first(); 02842 // check if desktop file 02843 if ( !KPropsDlgPlugin::isDesktopFile( item ) ) 02844 return false; 02845 02846 // open file and check type 02847 KDesktopFile config( item->url().path(), true /* readonly */ ); 02848 return config.hasMimeTypeType(); 02849 } 02850 02851 void KBindingPropsPlugin::applyChanges() 02852 { 02853 TQString path = properties->kurl().path(); 02854 TQFile f( path ); 02855 02856 if ( !f.open( IO_ReadWrite ) ) 02857 { 02858 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have " 02859 "sufficient access to write to <b>%1</b>.</qt>").arg(path)); 02860 return; 02861 } 02862 f.close(); 02863 02864 KSimpleConfig config( path ); 02865 config.setDesktopGroup(); 02866 config.writeEntry( "Type", TQString::fromLatin1("MimeType") ); 02867 02868 config.writeEntry( "Patterns", patternEdit->text() ); 02869 config.writeEntry( "Comment", commentEdit->text() ); 02870 config.writeEntry( "Comment", 02871 commentEdit->text(), true, false, true ); // for compat 02872 config.writeEntry( "MimeType", mimeEdit->text() ); 02873 if ( cbAutoEmbed->state() == TQButton::NoChange ) 02874 config.deleteEntry( "X-TDE-AutoEmbed", false ); 02875 else 02876 config.writeEntry( "X-TDE-AutoEmbed", cbAutoEmbed->isChecked() ); 02877 config.sync(); 02878 } 02879 02880 /* ---------------------------------------------------- 02881 * 02882 * KDevicePropsPlugin 02883 * 02884 * -------------------------------------------------- */ 02885 02886 class KDevicePropsPlugin::KDevicePropsPluginPrivate 02887 { 02888 public: 02889 KDevicePropsPluginPrivate() 02890 { 02891 } 02892 ~KDevicePropsPluginPrivate() 02893 { 02894 } 02895 02896 TQFrame *m_frame; 02897 TQStringList mountpointlist; 02898 TQLabel *m_freeSpaceText; 02899 TQLabel *m_freeSpaceLabel; 02900 TQProgressBar *m_freeSpaceBar; 02901 }; 02902 02903 KDevicePropsPlugin::KDevicePropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props ) 02904 { 02905 d = new KDevicePropsPluginPrivate; 02906 d->m_frame = properties->addPage(i18n("De&vice")); 02907 02908 TQStringList devices; 02909 KMountPoint::List mountPoints = KMountPoint::possibleMountPoints(); 02910 02911 for(KMountPoint::List::ConstIterator it = mountPoints.begin(); 02912 it != mountPoints.end(); ++it) 02913 { 02914 KMountPoint *mp = *it; 02915 TQString mountPoint = mp->mountPoint(); 02916 TQString device = mp->mountedFrom(); 02917 kdDebug()<<"mountPoint :"<<mountPoint<<" device :"<<device<<" mp->mountType() :"<<mp->mountType()<<endl; 02918 02919 if ((mountPoint != "-") && (mountPoint != "none") && !mountPoint.isEmpty() 02920 && device != "none") 02921 { 02922 devices.append( device + TQString::fromLatin1(" (") 02923 + mountPoint + TQString::fromLatin1(")") ); 02924 m_devicelist.append(device); 02925 d->mountpointlist.append(mountPoint); 02926 } 02927 } 02928 02929 TQGridLayout *layout = new TQGridLayout( d->m_frame, 0, 2, 0, 02930 KDialog::spacingHint()); 02931 layout->setColStretch(1, 1); 02932 02933 TQLabel* label; 02934 label = new TQLabel( d->m_frame ); 02935 label->setText( devices.count() == 0 ? 02936 i18n("Device (/dev/fd0):") : // old style 02937 i18n("Device:") ); // new style (combobox) 02938 layout->addWidget(label, 0, 0); 02939 02940 device = new TQComboBox( true, d->m_frame, "ComboBox_device" ); 02941 device->insertStringList( devices ); 02942 layout->addWidget(device, 0, 1); 02943 connect( device, TQT_SIGNAL( activated( int ) ), 02944 this, TQT_SLOT( slotActivated( int ) ) ); 02945 02946 readonly = new TQCheckBox( d->m_frame, "CheckBox_readonly" ); 02947 readonly->setText( i18n("Read only") ); 02948 layout->addWidget(readonly, 1, 1); 02949 02950 label = new TQLabel( d->m_frame ); 02951 label->setText( i18n("File system:") ); 02952 layout->addWidget(label, 2, 0); 02953 02954 TQLabel *fileSystem = new TQLabel( d->m_frame ); 02955 layout->addWidget(fileSystem, 2, 1); 02956 02957 label = new TQLabel( d->m_frame ); 02958 label->setText( devices.count()==0 ? 02959 i18n("Mount point (/mnt/floppy):") : // old style 02960 i18n("Mount point:")); // new style (combobox) 02961 layout->addWidget(label, 3, 0); 02962 02963 mountpoint = new TQLabel( d->m_frame, "LineEdit_mountpoint" ); 02964 02965 layout->addWidget(mountpoint, 3, 1); 02966 02967 // show disk free 02968 d->m_freeSpaceText = new TQLabel(i18n("Free disk space:"), d->m_frame ); 02969 layout->addWidget(d->m_freeSpaceText, 4, 0); 02970 02971 d->m_freeSpaceLabel = new TQLabel( d->m_frame ); 02972 layout->addWidget( d->m_freeSpaceLabel, 4, 1 ); 02973 02974 d->m_freeSpaceBar = new TQProgressBar( d->m_frame, "freeSpaceBar" ); 02975 layout->addMultiCellWidget(d->m_freeSpaceBar, 5, 5, 0, 1); 02976 02977 // we show it in the slot when we know the values 02978 d->m_freeSpaceText->hide(); 02979 d->m_freeSpaceLabel->hide(); 02980 d->m_freeSpaceBar->hide(); 02981 02982 KSeparator* sep = new KSeparator( KSeparator::HLine, d->m_frame); 02983 layout->addMultiCellWidget(sep, 6, 6, 0, 1); 02984 02985 unmounted = new TDEIconButton( d->m_frame ); 02986 int bsize = 66 + 2 * unmounted->style().pixelMetric(TQStyle::PM_ButtonMargin); 02987 unmounted->setFixedSize(bsize, bsize); 02988 unmounted->setIconType(TDEIcon::Desktop, TDEIcon::Device); 02989 layout->addWidget(unmounted, 7, 0); 02990 02991 label = new TQLabel( i18n("Unmounted Icon"), d->m_frame ); 02992 layout->addWidget(label, 7, 1); 02993 02994 layout->setRowStretch(8, 1); 02995 02996 TQString path( _props->kurl().path() ); 02997 02998 TQFile f( path ); 02999 if ( !f.open( IO_ReadOnly ) ) 03000 return; 03001 f.close(); 03002 03003 KSimpleConfig config( path ); 03004 config.setDesktopGroup(); 03005 TQString deviceStr = config.readEntry( "Dev" ); 03006 TQString mountPointStr = config.readEntry( "MountPoint" ); 03007 bool ro = config.readBoolEntry( "ReadOnly", false ); 03008 TQString unmountedStr = config.readEntry( "UnmountIcon" ); 03009 03010 TQString fsType = config.readEntry("FSType"); 03011 fileSystem->setText( (fsType.stripWhiteSpace() != "") ? i18n(fsType.local8Bit()) : "" ); 03012 03013 device->setEditText( deviceStr ); 03014 if ( !deviceStr.isEmpty() ) { 03015 // Set default options for this device (first matching entry) 03016 int index = m_devicelist.findIndex(deviceStr); 03017 if (index != -1) 03018 { 03019 //kdDebug(250) << "found it " << index << endl; 03020 slotActivated( index ); 03021 } 03022 } 03023 03024 if ( !mountPointStr.isEmpty() ) 03025 { 03026 mountpoint->setText( mountPointStr ); 03027 updateInfo(); 03028 } 03029 03030 readonly->setChecked( ro ); 03031 03032 if ( unmountedStr.isEmpty() ) 03033 unmountedStr = KMimeType::defaultMimeTypePtr()->KServiceType::icon(); // default icon 03034 03035 unmounted->setIcon( unmountedStr ); 03036 03037 connect( device, TQT_SIGNAL( activated( int ) ), 03038 this, TQT_SIGNAL( changed() ) ); 03039 connect( device, TQT_SIGNAL( textChanged( const TQString & ) ), 03040 this, TQT_SIGNAL( changed() ) ); 03041 connect( readonly, TQT_SIGNAL( toggled( bool ) ), 03042 this, TQT_SIGNAL( changed() ) ); 03043 connect( unmounted, TQT_SIGNAL( iconChanged( TQString ) ), 03044 this, TQT_SIGNAL( changed() ) ); 03045 03046 connect( device, TQT_SIGNAL( textChanged( const TQString & ) ), 03047 this, TQT_SLOT( slotDeviceChanged() ) ); 03048 03049 processLockouts(); 03050 } 03051 03052 KDevicePropsPlugin::~KDevicePropsPlugin() 03053 { 03054 delete d; 03055 } 03056 03057 // TQString KDevicePropsPlugin::tabName () const 03058 // { 03059 // return i18n ("De&vice"); 03060 // } 03061 03062 void KDevicePropsPlugin::processLockouts() 03063 { 03064 if (device->currentText().stripWhiteSpace() != "") 03065 { 03066 properties->enableButtonOK(true); 03067 } 03068 else 03069 { 03070 properties->enableButtonOK(false); 03071 } 03072 } 03073 03074 void KDevicePropsPlugin::updateInfo() 03075 { 03076 // we show it in the slot when we know the values 03077 d->m_freeSpaceText->hide(); 03078 d->m_freeSpaceLabel->hide(); 03079 d->m_freeSpaceBar->hide(); 03080 03081 if ( !mountpoint->text().isEmpty() ) 03082 { 03083 KDiskFreeSp * job = new KDiskFreeSp; 03084 connect( job, TQT_SIGNAL( foundMountPoint( const unsigned long&, const unsigned long&, 03085 const unsigned long&, const TQString& ) ), 03086 this, TQT_SLOT( slotFoundMountPoint( const unsigned long&, const unsigned long&, 03087 const unsigned long&, const TQString& ) ) ); 03088 03089 job->readDF( mountpoint->text() ); 03090 } 03091 03092 processLockouts(); 03093 } 03094 03095 void KDevicePropsPlugin::slotActivated( int index ) 03096 { 03097 // Update mountpoint so that it matches the device that was selected in the combo 03098 device->setEditText( m_devicelist[index] ); 03099 mountpoint->setText( d->mountpointlist[index] ); 03100 03101 updateInfo(); 03102 } 03103 03104 void KDevicePropsPlugin::slotDeviceChanged() 03105 { 03106 // Update mountpoint so that it matches the typed device 03107 int index = m_devicelist.findIndex( device->currentText() ); 03108 if ( index != -1 ) 03109 mountpoint->setText( d->mountpointlist[index] ); 03110 else 03111 mountpoint->setText( TQString::null ); 03112 03113 updateInfo(); 03114 } 03115 03116 void KDevicePropsPlugin::slotFoundMountPoint( const unsigned long& kBSize, 03117 const unsigned long& /*kBUsed*/, 03118 const unsigned long& kBAvail, 03119 const TQString& ) 03120 { 03121 d->m_freeSpaceText->show(); 03122 d->m_freeSpaceLabel->show(); 03123 03124 int percUsed = 100 - (int)(100.0 * kBAvail / kBSize); 03125 03126 d->m_freeSpaceLabel->setText( 03127 // xgettext:no-c-format -- Don't warn about translating the %1 out of %2 part. 03128 i18n("Available space out of total partition size (percent used)", "%1 out of %2 (%3% used)") 03129 .arg(TDEIO::convertSizeFromKB(kBAvail)) 03130 .arg(TDEIO::convertSizeFromKB(kBSize)) 03131 .arg( 100 - (int)(100.0 * kBAvail / kBSize) )); 03132 03133 d->m_freeSpaceBar->setProgress(percUsed, 100); 03134 d->m_freeSpaceBar->show(); 03135 } 03136 03137 bool KDevicePropsPlugin::supports( KFileItemList _items ) 03138 { 03139 if ( _items.count() != 1 ) 03140 return false; 03141 KFileItem * item = _items.first(); 03142 // check if desktop file 03143 if ( !KPropsDlgPlugin::isDesktopFile( item ) ) 03144 return false; 03145 // open file and check type 03146 KDesktopFile config( item->url().path(), true /* readonly */ ); 03147 return config.hasDeviceType(); 03148 } 03149 03150 void KDevicePropsPlugin::applyChanges() 03151 { 03152 TQString path = properties->kurl().path(); 03153 TQFile f( path ); 03154 if ( !f.open( IO_ReadWrite ) ) 03155 { 03156 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient " 03157 "access to write to <b>%1</b>.</qt>").arg(path)); 03158 return; 03159 } 03160 f.close(); 03161 03162 KSimpleConfig config( path ); 03163 config.setDesktopGroup(); 03164 config.writeEntry( "Type", TQString::fromLatin1("FSDevice") ); 03165 03166 config.writeEntry( "Dev", device->currentText() ); 03167 config.writeEntry( "MountPoint", mountpoint->text() ); 03168 03169 config.writeEntry( "UnmountIcon", unmounted->icon() ); 03170 kdDebug(250) << "unmounted->icon() = " << unmounted->icon() << endl; 03171 03172 config.writeEntry( "ReadOnly", readonly->isChecked() ); 03173 03174 config.sync(); 03175 } 03176 03177 03178 /* ---------------------------------------------------- 03179 * 03180 * KDesktopPropsPlugin 03181 * 03182 * -------------------------------------------------- */ 03183 03184 03185 KDesktopPropsPlugin::KDesktopPropsPlugin( KPropertiesDialog *_props ) 03186 : KPropsDlgPlugin( _props ) 03187 { 03188 TQFrame *frame = properties->addPage(i18n("&Application")); 03189 TQVBoxLayout *mainlayout = new TQVBoxLayout( frame, 0, KDialog::spacingHint() ); 03190 03191 w = new KPropertiesDesktopBase(frame); 03192 mainlayout->addWidget(w); 03193 03194 bool bKDesktopMode = (TQCString(tqApp->name()) == "kdesktop"); // nasty heh? 03195 03196 if (bKDesktopMode) 03197 { 03198 // Hide Name entry 03199 w->nameEdit->hide(); 03200 w->nameLabel->hide(); 03201 } 03202 03203 w->pathEdit->setMode(KFile::Directory | KFile::LocalOnly); 03204 w->pathEdit->lineEdit()->setAcceptDrops(false); 03205 03206 connect( w->nameEdit, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SIGNAL( changed() ) ); 03207 connect( w->genNameEdit, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SIGNAL( changed() ) ); 03208 connect( w->commentEdit, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SIGNAL( changed() ) ); 03209 connect( w->commandEdit, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SIGNAL( changed() ) ); 03210 connect( w->pathEdit, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SIGNAL( changed() ) ); 03211 03212 connect( w->browseButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotBrowseExec() ) ); 03213 connect( w->addFiletypeButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotAddFiletype() ) ); 03214 connect( w->delFiletypeButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotDelFiletype() ) ); 03215 connect( w->advancedButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotAdvanced() ) ); 03216 03217 // now populate the page 03218 TQString path = _props->kurl().path(); 03219 TQFile f( path ); 03220 if ( !f.open( IO_ReadOnly ) ) 03221 return; 03222 f.close(); 03223 03224 KDesktopFile config( path ); 03225 TQString nameStr = config.readName(); 03226 TQString genNameStr = config.readGenericName(); 03227 TQString commentStr = config.readComment(); 03228 TQString commandStr = config.readPathEntry( "Exec" ); 03229 if (commandStr.left(12) == "ksystraycmd ") 03230 { 03231 commandStr.remove(0, 12); 03232 m_systrayBool = true; 03233 } 03234 else 03235 m_systrayBool = false; 03236 03237 m_origCommandStr = commandStr; 03238 TQString pathStr = config.readPathEntry( "Path" ); 03239 m_terminalBool = config.readBoolEntry( "Terminal" ); 03240 m_terminalOptionStr = config.readEntry( "TerminalOptions" ); 03241 m_suidBool = config.readBoolEntry( "X-TDE-SubstituteUID" ) || config.readBoolEntry( "X-KDE-SubstituteUID" ); 03242 if( config.hasKey( "X-TDE-Username" )) 03243 m_suidUserStr = config.readEntry( "X-TDE-Username" ); 03244 else 03245 m_suidUserStr = config.readEntry( "X-KDE-Username" ); 03246 if( config.hasKey( "StartupNotify" )) 03247 m_startupBool = config.readBoolEntry( "StartupNotify", true ); 03248 else 03249 m_startupBool = config.readBoolEntry( "X-TDE-StartupNotify", true ); 03250 m_dcopServiceType = config.readEntry("X-DCOP-ServiceType").lower(); 03251 03252 TQStringList mimeTypes = config.readListEntry( "MimeType", ';' ); 03253 03254 if ( nameStr.isEmpty() || bKDesktopMode ) { 03255 // We'll use the file name if no name is specified 03256 // because we _need_ a Name for a valid file. 03257 // But let's do it in apply, not here, so that we pick up the right name. 03258 setDirty(); 03259 } 03260 if ( !bKDesktopMode ) 03261 w->nameEdit->setText(nameStr); 03262 03263 w->genNameEdit->setText( genNameStr ); 03264 w->commentEdit->setText( commentStr ); 03265 w->commandEdit->setText( commandStr ); 03266 w->pathEdit->lineEdit()->setText( pathStr ); 03267 w->filetypeList->setAllColumnsShowFocus(true); 03268 03269 KMimeType::Ptr defaultMimetype = KMimeType::defaultMimeTypePtr(); 03270 for(TQStringList::ConstIterator it = mimeTypes.begin(); 03271 it != mimeTypes.end(); ) 03272 { 03273 KMimeType::Ptr p = KMimeType::mimeType(*it); 03274 ++it; 03275 TQString preference; 03276 if (it != mimeTypes.end()) 03277 { 03278 bool numeric; 03279 (*it).toInt(&numeric); 03280 if (numeric) 03281 { 03282 preference = *it; 03283 ++it; 03284 } 03285 } 03286 if (p && (p != defaultMimetype)) 03287 { 03288 new TQListViewItem(w->filetypeList, p->name(), p->comment(), preference); 03289 } 03290 } 03291 03292 } 03293 03294 KDesktopPropsPlugin::~KDesktopPropsPlugin() 03295 { 03296 } 03297 03298 void KDesktopPropsPlugin::slotSelectMimetype() 03299 { 03300 TQListView *w = (TQListView*)sender(); 03301 TQListViewItem *item = w->firstChild(); 03302 while(item) 03303 { 03304 if (item->isSelected()) 03305 w->setSelected(item, false); 03306 item = item->nextSibling(); 03307 } 03308 } 03309 03310 void KDesktopPropsPlugin::slotAddFiletype() 03311 { 03312 KDialogBase dlg(w, "KPropertiesMimetypes", true, 03313 i18n("Add File Type for %1").arg(properties->kurl().fileName()), 03314 KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok); 03315 03316 KGuiItem okItem(i18n("&Add"), TQString::null /* no icon */, 03317 i18n("Add the selected file types to\nthe list of supported file types."), 03318 i18n("Add the selected file types to\nthe list of supported file types.")); 03319 dlg.setButtonOK(okItem); 03320 03321 KPropertiesMimetypeBase *mw = new KPropertiesMimetypeBase(&dlg); 03322 03323 dlg.setMainWidget(mw); 03324 03325 { 03326 mw->listView->setRootIsDecorated(true); 03327 mw->listView->setSelectionMode(TQListView::Extended); 03328 mw->listView->setAllColumnsShowFocus(true); 03329 mw->listView->setFullWidth(true); 03330 mw->listView->setMinimumSize(500,400); 03331 03332 connect(mw->listView, TQT_SIGNAL(selectionChanged()), 03333 this, TQT_SLOT(slotSelectMimetype())); 03334 connect(mw->listView, TQT_SIGNAL(doubleClicked( TQListViewItem *, const TQPoint &, int )), 03335 &dlg, TQT_SLOT( slotOk())); 03336 03337 TQMap<TQString,TQListViewItem*> majorMap; 03338 TQListViewItem *majorGroup; 03339 KMimeType::List mimetypes = KMimeType::allMimeTypes(); 03340 TQValueListIterator<KMimeType::Ptr> it(mimetypes.begin()); 03341 for (; it != mimetypes.end(); ++it) { 03342 TQString mimetype = (*it)->name(); 03343 if (mimetype == KMimeType::defaultMimeType()) 03344 continue; 03345 int index = mimetype.find("/"); 03346 TQString maj = mimetype.left(index); 03347 TQString min = mimetype.mid(index+1); 03348 03349 TQMapIterator<TQString,TQListViewItem*> mit = majorMap.find( maj ); 03350 if ( mit == majorMap.end() ) { 03351 majorGroup = new TQListViewItem( mw->listView, maj ); 03352 majorGroup->setExpandable(true); 03353 mw->listView->setOpen(majorGroup, true); 03354 majorMap.insert( maj, majorGroup ); 03355 } 03356 else 03357 { 03358 majorGroup = mit.data(); 03359 } 03360 03361 TQListViewItem *item = new TQListViewItem(majorGroup, min, (*it)->comment()); 03362 item->setPixmap(0, (*it)->pixmap(TDEIcon::Small, IconSize(TDEIcon::Small))); 03363 } 03364 TQMapIterator<TQString,TQListViewItem*> mit = majorMap.find( "all" ); 03365 if ( mit != majorMap.end()) 03366 { 03367 mw->listView->setCurrentItem(mit.data()); 03368 mw->listView->ensureItemVisible(mit.data()); 03369 } 03370 } 03371 03372 if (dlg.exec() == KDialogBase::Accepted) 03373 { 03374 KMimeType::Ptr defaultMimetype = KMimeType::defaultMimeTypePtr(); 03375 TQListViewItem *majorItem = mw->listView->firstChild(); 03376 while(majorItem) 03377 { 03378 TQString major = majorItem->text(0); 03379 03380 TQListViewItem *minorItem = majorItem->firstChild(); 03381 while(minorItem) 03382 { 03383 if (minorItem->isSelected()) 03384 { 03385 TQString mimetype = major + "/" + minorItem->text(0); 03386 KMimeType::Ptr p = KMimeType::mimeType(mimetype); 03387 if (p && (p != defaultMimetype)) 03388 { 03389 mimetype = p->name(); 03390 bool found = false; 03391 TQListViewItem *item = w->filetypeList->firstChild(); 03392 while (item) 03393 { 03394 if (mimetype == item->text(0)) 03395 { 03396 found = true; 03397 break; 03398 } 03399 item = item->nextSibling(); 03400 } 03401 if (!found) { 03402 new TQListViewItem(w->filetypeList, p->name(), p->comment()); 03403 emit changed(); 03404 } 03405 } 03406 } 03407 minorItem = minorItem->nextSibling(); 03408 } 03409 03410 majorItem = majorItem->nextSibling(); 03411 } 03412 03413 } 03414 } 03415 03416 void KDesktopPropsPlugin::slotDelFiletype() 03417 { 03418 delete w->filetypeList->currentItem(); 03419 emit changed(); 03420 } 03421 03422 void KDesktopPropsPlugin::checkCommandChanged() 03423 { 03424 if (KRun::binaryName(w->commandEdit->text(), true) != 03425 KRun::binaryName(m_origCommandStr, true)) 03426 { 03427 TQString m_origCommandStr = w->commandEdit->text(); 03428 m_dcopServiceType= TQString::null; // Reset 03429 } 03430 } 03431 03432 void KDesktopPropsPlugin::applyChanges() 03433 { 03434 kdDebug(250) << "KDesktopPropsPlugin::applyChanges" << endl; 03435 TQString path = properties->kurl().path(); 03436 03437 TQFile f( path ); 03438 03439 if ( !f.open( IO_ReadWrite ) ) { 03440 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have " 03441 "sufficient access to write to <b>%1</b>.</qt>").arg(path)); 03442 return; 03443 } 03444 f.close(); 03445 03446 // If the command is changed we reset certain settings that are strongly 03447 // coupled to the command. 03448 checkCommandChanged(); 03449 03450 KSimpleConfig config( path ); 03451 config.setDesktopGroup(); 03452 config.writeEntry( "Type", TQString::fromLatin1("Application")); 03453 config.writeEntry( "Comment", w->commentEdit->text() ); 03454 config.writeEntry( "Comment", w->commentEdit->text(), true, false, true ); // for compat 03455 config.writeEntry( "GenericName", w->genNameEdit->text() ); 03456 config.writeEntry( "GenericName", w->genNameEdit->text(), true, false, true ); // for compat 03457 03458 if (m_systrayBool) 03459 config.writePathEntry( "Exec", w->commandEdit->text().prepend("ksystraycmd ") ); 03460 else 03461 config.writePathEntry( "Exec", w->commandEdit->text() ); 03462 config.writePathEntry( "Path", w->pathEdit->lineEdit()->text() ); 03463 03464 // Write mimeTypes 03465 TQStringList mimeTypes; 03466 for( TQListViewItem *item = w->filetypeList->firstChild(); 03467 item; item = item->nextSibling() ) 03468 { 03469 TQString preference = item->text(2); 03470 mimeTypes.append(item->text(0)); 03471 if (!preference.isEmpty()) 03472 mimeTypes.append(preference); 03473 } 03474 03475 config.writeEntry( "MimeType", mimeTypes, ';' ); 03476 03477 if ( !w->nameEdit->isHidden() ) { 03478 TQString nameStr = w->nameEdit->text(); 03479 config.writeEntry( "Name", nameStr ); 03480 config.writeEntry( "Name", nameStr, true, false, true ); 03481 } 03482 03483 config.writeEntry("Terminal", m_terminalBool); 03484 config.writeEntry("TerminalOptions", m_terminalOptionStr); 03485 config.writeEntry("X-TDE-SubstituteUID", m_suidBool); 03486 config.writeEntry("X-TDE-Username", m_suidUserStr); 03487 config.writeEntry("StartupNotify", m_startupBool); 03488 config.writeEntry("X-DCOP-ServiceType", m_dcopServiceType); 03489 config.sync(); 03490 03491 // KSycoca update needed? 03492 TQString sycocaPath = TDEGlobal::dirs()->relativeLocation("apps", path); 03493 bool updateNeeded = !sycocaPath.startsWith("/"); 03494 if (!updateNeeded) 03495 { 03496 sycocaPath = TDEGlobal::dirs()->relativeLocation("xdgdata-apps", path); 03497 updateNeeded = !sycocaPath.startsWith("/"); 03498 } 03499 if (updateNeeded) 03500 KService::rebuildKSycoca(w); 03501 } 03502 03503 03504 void KDesktopPropsPlugin::slotBrowseExec() 03505 { 03506 KURL f = KFileDialog::getOpenURL( TQString::null, 03507 TQString::null, w ); 03508 if ( f.isEmpty() ) 03509 return; 03510 03511 if ( !f.isLocalFile()) { 03512 KMessageBox::sorry(w, i18n("Only executables on local file systems are supported.")); 03513 return; 03514 } 03515 03516 TQString path = f.path(); 03517 KRun::shellQuote( path ); 03518 w->commandEdit->setText( path ); 03519 } 03520 03521 void KDesktopPropsPlugin::slotAdvanced() 03522 { 03523 KDialogBase dlg(w, "KPropertiesDesktopAdv", true, 03524 i18n("Advanced Options for %1").arg(properties->kurl().fileName()), 03525 KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok); 03526 KPropertiesDesktopAdvBase *w = new KPropertiesDesktopAdvBase(&dlg); 03527 03528 dlg.setMainWidget(w); 03529 03530 // If the command is changed we reset certain settings that are strongly 03531 // coupled to the command. 03532 checkCommandChanged(); 03533 03534 // check to see if we use konsole if not do not add the nocloseonexit 03535 // because we don't know how to do this on other terminal applications 03536 TDEConfigGroup confGroup( TDEGlobal::config(), TQString::fromLatin1("General") ); 03537 TQString preferredTerminal = confGroup.readPathEntry("TerminalApplication", 03538 TQString::fromLatin1("konsole")); 03539 03540 bool terminalCloseBool = false; 03541 03542 if (preferredTerminal == "konsole") 03543 { 03544 terminalCloseBool = (m_terminalOptionStr.contains( "--noclose" ) > 0); 03545 w->terminalCloseCheck->setChecked(terminalCloseBool); 03546 m_terminalOptionStr.replace( "--noclose", ""); 03547 } 03548 else 03549 { 03550 w->terminalCloseCheck->hide(); 03551 } 03552 03553 w->terminalCheck->setChecked(m_terminalBool); 03554 w->terminalEdit->setText(m_terminalOptionStr); 03555 w->terminalCloseCheck->setEnabled(m_terminalBool); 03556 w->terminalEdit->setEnabled(m_terminalBool); 03557 w->terminalEditLabel->setEnabled(m_terminalBool); 03558 03559 w->suidCheck->setChecked(m_suidBool); 03560 w->suidEdit->setText(m_suidUserStr); 03561 w->suidEdit->setEnabled(m_suidBool); 03562 w->suidEditLabel->setEnabled(m_suidBool); 03563 03564 w->startupInfoCheck->setChecked(m_startupBool); 03565 w->systrayCheck->setChecked(m_systrayBool); 03566 03567 if (m_dcopServiceType == "unique") 03568 w->dcopCombo->setCurrentItem(2); 03569 else if (m_dcopServiceType == "multi") 03570 w->dcopCombo->setCurrentItem(1); 03571 else if (m_dcopServiceType == "wait") 03572 w->dcopCombo->setCurrentItem(3); 03573 else 03574 w->dcopCombo->setCurrentItem(0); 03575 03576 // Provide username completion up to 1000 users. 03577 TDECompletion *kcom = new TDECompletion; 03578 kcom->setOrder(TDECompletion::Sorted); 03579 struct passwd *pw; 03580 int i, maxEntries = 1000; 03581 setpwent(); 03582 for (i=0; ((pw = getpwent()) != 0L) && (i < maxEntries); i++) 03583 kcom->addItem(TQString::fromLatin1(pw->pw_name)); 03584 endpwent(); 03585 if (i < maxEntries) 03586 { 03587 w->suidEdit->setCompletionObject(kcom, true); 03588 w->suidEdit->setAutoDeleteCompletionObject( true ); 03589 w->suidEdit->setCompletionMode(TDEGlobalSettings::CompletionAuto); 03590 } 03591 else 03592 { 03593 delete kcom; 03594 } 03595 03596 connect( w->terminalEdit, TQT_SIGNAL( textChanged( const TQString & ) ), 03597 this, TQT_SIGNAL( changed() ) ); 03598 connect( w->terminalCloseCheck, TQT_SIGNAL( toggled( bool ) ), 03599 this, TQT_SIGNAL( changed() ) ); 03600 connect( w->terminalCheck, TQT_SIGNAL( toggled( bool ) ), 03601 this, TQT_SIGNAL( changed() ) ); 03602 connect( w->suidCheck, TQT_SIGNAL( toggled( bool ) ), 03603 this, TQT_SIGNAL( changed() ) ); 03604 connect( w->suidEdit, TQT_SIGNAL( textChanged( const TQString & ) ), 03605 this, TQT_SIGNAL( changed() ) ); 03606 connect( w->startupInfoCheck, TQT_SIGNAL( toggled( bool ) ), 03607 this, TQT_SIGNAL( changed() ) ); 03608 connect( w->systrayCheck, TQT_SIGNAL( toggled( bool ) ), 03609 this, TQT_SIGNAL( changed() ) ); 03610 connect( w->dcopCombo, TQT_SIGNAL( highlighted( int ) ), 03611 this, TQT_SIGNAL( changed() ) ); 03612 03613 if ( dlg.exec() == TQDialog::Accepted ) 03614 { 03615 m_terminalOptionStr = w->terminalEdit->text().stripWhiteSpace(); 03616 m_terminalBool = w->terminalCheck->isChecked(); 03617 m_suidBool = w->suidCheck->isChecked(); 03618 m_suidUserStr = w->suidEdit->text().stripWhiteSpace(); 03619 m_startupBool = w->startupInfoCheck->isChecked(); 03620 m_systrayBool = w->systrayCheck->isChecked(); 03621 03622 if (w->terminalCloseCheck->isChecked()) 03623 { 03624 m_terminalOptionStr.append(" --noclose"); 03625 } 03626 03627 switch(w->dcopCombo->currentItem()) 03628 { 03629 case 1: m_dcopServiceType = "multi"; break; 03630 case 2: m_dcopServiceType = "unique"; break; 03631 case 3: m_dcopServiceType = "wait"; break; 03632 default: m_dcopServiceType = "none"; break; 03633 } 03634 } 03635 } 03636 03637 bool KDesktopPropsPlugin::supports( KFileItemList _items ) 03638 { 03639 if ( _items.count() != 1 ) 03640 return false; 03641 KFileItem * item = _items.first(); 03642 // check if desktop file 03643 if ( !KPropsDlgPlugin::isDesktopFile( item ) ) 03644 return false; 03645 // open file and check type 03646 KDesktopFile config( item->url().path(), true /* readonly */ ); 03647 return config.hasApplicationType() && kapp->authorize("run_desktop_files") && kapp->authorize("shell_access"); 03648 } 03649 03650 void KPropertiesDialog::virtual_hook( int id, void* data ) 03651 { KDialogBase::virtual_hook( id, data ); } 03652 03653 void KPropsDlgPlugin::virtual_hook( int, void* ) 03654 { /*BASE::virtual_hook( id, data );*/ } 03655 03656 03657 03658 03659 03665 class KExecPropsPlugin::KExecPropsPluginPrivate 03666 { 03667 public: 03668 KExecPropsPluginPrivate() 03669 { 03670 } 03671 ~KExecPropsPluginPrivate() 03672 { 03673 } 03674 03675 TQFrame *m_frame; 03676 TQCheckBox *nocloseonexitCheck; 03677 }; 03678 03679 KExecPropsPlugin::KExecPropsPlugin( KPropertiesDialog *_props ) 03680 : KPropsDlgPlugin( _props ) 03681 { 03682 d = new KExecPropsPluginPrivate; 03683 d->m_frame = properties->addPage(i18n("E&xecute")); 03684 TQVBoxLayout * mainlayout = new TQVBoxLayout( d->m_frame, 0, 03685 KDialog::spacingHint()); 03686 03687 // Now the widgets in the top layout 03688 03689 TQLabel* l; 03690 l = new TQLabel( i18n( "Comman&d:" ), d->m_frame ); 03691 mainlayout->addWidget(l); 03692 03693 TQHBoxLayout * hlayout; 03694 hlayout = new TQHBoxLayout(KDialog::spacingHint()); 03695 mainlayout->addLayout(hlayout); 03696 03697 execEdit = new KLineEdit( d->m_frame ); 03698 TQWhatsThis::add(execEdit,i18n( 03699 "Following the command, you can have several place holders which will be replaced " 03700 "with the actual values when the actual program is run:\n" 03701 "%f - a single file name\n" 03702 "%F - a list of files; use for applications that can open several local files at once\n" 03703 "%u - a single URL\n" 03704 "%U - a list of URLs\n" 03705 "%d - the folder of the file to open\n" 03706 "%D - a list of folders\n" 03707 "%i - the icon\n" 03708 "%m - the mini-icon\n" 03709 "%c - the caption")); 03710 hlayout->addWidget(execEdit, 1); 03711 03712 l->setBuddy( execEdit ); 03713 03714 execBrowse = new TQPushButton( d->m_frame ); 03715 execBrowse->setText( i18n("&Browse...") ); 03716 hlayout->addWidget(execBrowse); 03717 03718 // The groupbox about swallowing 03719 TQGroupBox* tmpQGroupBox; 03720 tmpQGroupBox = new TQGroupBox( i18n("Panel Embedding"), d->m_frame ); 03721 tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal ); 03722 03723 mainlayout->addWidget(tmpQGroupBox); 03724 03725 TQGridLayout *grid = new TQGridLayout(tmpQGroupBox->layout(), 2, 2); 03726 grid->setSpacing( KDialog::spacingHint() ); 03727 grid->setColStretch(1, 1); 03728 03729 l = new TQLabel( i18n( "&Execute on click:" ), tmpQGroupBox ); 03730 grid->addWidget(l, 0, 0); 03731 03732 swallowExecEdit = new KLineEdit( tmpQGroupBox ); 03733 grid->addWidget(swallowExecEdit, 0, 1); 03734 03735 l->setBuddy( swallowExecEdit ); 03736 03737 l = new TQLabel( i18n( "&Window title:" ), tmpQGroupBox ); 03738 grid->addWidget(l, 1, 0); 03739 03740 swallowTitleEdit = new KLineEdit( tmpQGroupBox ); 03741 grid->addWidget(swallowTitleEdit, 1, 1); 03742 03743 l->setBuddy( swallowTitleEdit ); 03744 03745 // The groupbox about run in terminal 03746 03747 tmpQGroupBox = new TQGroupBox( d->m_frame ); 03748 tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal ); 03749 03750 mainlayout->addWidget(tmpQGroupBox); 03751 03752 grid = new TQGridLayout(tmpQGroupBox->layout(), 3, 2); 03753 grid->setSpacing( KDialog::spacingHint() ); 03754 grid->setColStretch(1, 1); 03755 03756 terminalCheck = new TQCheckBox( tmpQGroupBox ); 03757 terminalCheck->setText( i18n("&Run in terminal") ); 03758 grid->addMultiCellWidget(terminalCheck, 0, 0, 0, 1); 03759 03760 // check to see if we use konsole if not do not add the nocloseonexit 03761 // because we don't know how to do this on other terminal applications 03762 TDEConfigGroup confGroup( TDEGlobal::config(), TQString::fromLatin1("General") ); 03763 TQString preferredTerminal = confGroup.readPathEntry("TerminalApplication", 03764 TQString::fromLatin1("konsole")); 03765 03766 int posOptions = 1; 03767 d->nocloseonexitCheck = 0L; 03768 if (preferredTerminal == "konsole") 03769 { 03770 posOptions = 2; 03771 d->nocloseonexitCheck = new TQCheckBox( tmpQGroupBox ); 03772 d->nocloseonexitCheck->setText( i18n("Do not &close when command exits") ); 03773 grid->addMultiCellWidget(d->nocloseonexitCheck, 1, 1, 0, 1); 03774 } 03775 03776 terminalLabel = new TQLabel( i18n( "&Terminal options:" ), tmpQGroupBox ); 03777 grid->addWidget(terminalLabel, posOptions, 0); 03778 03779 terminalEdit = new KLineEdit( tmpQGroupBox ); 03780 grid->addWidget(terminalEdit, posOptions, 1); 03781 03782 terminalLabel->setBuddy( terminalEdit ); 03783 03784 // The groupbox about run with substituted uid. 03785 03786 tmpQGroupBox = new TQGroupBox( d->m_frame ); 03787 tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal ); 03788 03789 mainlayout->addWidget(tmpQGroupBox); 03790 03791 grid = new TQGridLayout(tmpQGroupBox->layout(), 2, 2); 03792 grid->setSpacing(KDialog::spacingHint()); 03793 grid->setColStretch(1, 1); 03794 03795 suidCheck = new TQCheckBox(tmpQGroupBox); 03796 suidCheck->setText(i18n("Ru&n as a different user")); 03797 grid->addMultiCellWidget(suidCheck, 0, 0, 0, 1); 03798 03799 suidLabel = new TQLabel(i18n( "&Username:" ), tmpQGroupBox); 03800 grid->addWidget(suidLabel, 1, 0); 03801 03802 suidEdit = new KLineEdit(tmpQGroupBox); 03803 grid->addWidget(suidEdit, 1, 1); 03804 03805 suidLabel->setBuddy( suidEdit ); 03806 03807 mainlayout->addStretch(1); 03808 03809 // now populate the page 03810 TQString path = _props->kurl().path(); 03811 TQFile f( path ); 03812 if ( !f.open( IO_ReadOnly ) ) 03813 return; 03814 f.close(); 03815 03816 KSimpleConfig config( path ); 03817 config.setDollarExpansion( false ); 03818 config.setDesktopGroup(); 03819 execStr = config.readPathEntry( "Exec" ); 03820 swallowExecStr = config.readPathEntry( "SwallowExec" ); 03821 swallowTitleStr = config.readEntry( "SwallowTitle" ); 03822 termBool = config.readBoolEntry( "Terminal" ); 03823 termOptionsStr = config.readEntry( "TerminalOptions" ); 03824 suidBool = config.readBoolEntry( "X-TDE-SubstituteUID" ); 03825 suidUserStr = config.readEntry( "X-TDE-Username" ); 03826 03827 if ( !swallowExecStr.isNull() ) 03828 swallowExecEdit->setText( swallowExecStr ); 03829 if ( !swallowTitleStr.isNull() ) 03830 swallowTitleEdit->setText( swallowTitleStr ); 03831 03832 if ( !execStr.isNull() ) 03833 execEdit->setText( execStr ); 03834 03835 if ( d->nocloseonexitCheck ) 03836 { 03837 d->nocloseonexitCheck->setChecked( (termOptionsStr.contains( "--noclose" ) > 0) ); 03838 termOptionsStr.replace( "--noclose", ""); 03839 } 03840 if ( !termOptionsStr.isNull() ) 03841 terminalEdit->setText( termOptionsStr ); 03842 03843 terminalCheck->setChecked( termBool ); 03844 enableCheckedEdit(); 03845 03846 suidCheck->setChecked( suidBool ); 03847 suidEdit->setText( suidUserStr ); 03848 enableSuidEdit(); 03849 03850 // Provide username completion up to 1000 users. 03851 TDECompletion *kcom = new TDECompletion; 03852 kcom->setOrder(TDECompletion::Sorted); 03853 struct passwd *pw; 03854 int i, maxEntries = 1000; 03855 setpwent(); 03856 for (i=0; ((pw = getpwent()) != 0L) && (i < maxEntries); i++) 03857 kcom->addItem(TQString::fromLatin1(pw->pw_name)); 03858 endpwent(); 03859 if (i < maxEntries) 03860 { 03861 suidEdit->setCompletionObject(kcom, true); 03862 suidEdit->setAutoDeleteCompletionObject( true ); 03863 suidEdit->setCompletionMode(TDEGlobalSettings::CompletionAuto); 03864 } 03865 else 03866 { 03867 delete kcom; 03868 } 03869 03870 connect( swallowExecEdit, TQT_SIGNAL( textChanged( const TQString & ) ), 03871 this, TQT_SIGNAL( changed() ) ); 03872 connect( swallowTitleEdit, TQT_SIGNAL( textChanged( const TQString & ) ), 03873 this, TQT_SIGNAL( changed() ) ); 03874 connect( execEdit, TQT_SIGNAL( textChanged( const TQString & ) ), 03875 this, TQT_SIGNAL( changed() ) ); 03876 connect( terminalEdit, TQT_SIGNAL( textChanged( const TQString & ) ), 03877 this, TQT_SIGNAL( changed() ) ); 03878 if (d->nocloseonexitCheck) 03879 connect( d->nocloseonexitCheck, TQT_SIGNAL( toggled( bool ) ), 03880 this, TQT_SIGNAL( changed() ) ); 03881 connect( terminalCheck, TQT_SIGNAL( toggled( bool ) ), 03882 this, TQT_SIGNAL( changed() ) ); 03883 connect( suidCheck, TQT_SIGNAL( toggled( bool ) ), 03884 this, TQT_SIGNAL( changed() ) ); 03885 connect( suidEdit, TQT_SIGNAL( textChanged( const TQString & ) ), 03886 this, TQT_SIGNAL( changed() ) ); 03887 03888 connect( execBrowse, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotBrowseExec() ) ); 03889 connect( terminalCheck, TQT_SIGNAL( clicked() ), this, TQT_SLOT( enableCheckedEdit() ) ); 03890 connect( suidCheck, TQT_SIGNAL( clicked() ), this, TQT_SLOT( enableSuidEdit() ) ); 03891 03892 } 03893 03894 KExecPropsPlugin::~KExecPropsPlugin() 03895 { 03896 delete d; 03897 } 03898 03899 void KExecPropsPlugin::enableCheckedEdit() 03900 { 03901 bool checked = terminalCheck->isChecked(); 03902 terminalLabel->setEnabled( checked ); 03903 if (d->nocloseonexitCheck) 03904 d->nocloseonexitCheck->setEnabled( checked ); 03905 terminalEdit->setEnabled( checked ); 03906 } 03907 03908 void KExecPropsPlugin::enableSuidEdit() 03909 { 03910 bool checked = suidCheck->isChecked(); 03911 suidLabel->setEnabled( checked ); 03912 suidEdit->setEnabled( checked ); 03913 } 03914 03915 bool KExecPropsPlugin::supports( KFileItemList _items ) 03916 { 03917 if ( _items.count() != 1 ) 03918 return false; 03919 KFileItem * item = _items.first(); 03920 // check if desktop file 03921 if ( !KPropsDlgPlugin::isDesktopFile( item ) ) 03922 return false; 03923 // open file and check type 03924 KDesktopFile config( item->url().path(), true /* readonly */ ); 03925 return config.hasApplicationType() && kapp->authorize("run_desktop_files") && kapp->authorize("shell_access"); 03926 } 03927 03928 void KExecPropsPlugin::applyChanges() 03929 { 03930 kdDebug(250) << "KExecPropsPlugin::applyChanges" << endl; 03931 TQString path = properties->kurl().path(); 03932 03933 TQFile f( path ); 03934 03935 if ( !f.open( IO_ReadWrite ) ) { 03936 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have " 03937 "sufficient access to write to <b>%1</b>.</qt>").arg(path)); 03938 return; 03939 } 03940 f.close(); 03941 03942 KSimpleConfig config( path ); 03943 config.setDesktopGroup(); 03944 config.writeEntry( "Type", TQString::fromLatin1("Application")); 03945 config.writePathEntry( "Exec", execEdit->text() ); 03946 config.writePathEntry( "SwallowExec", swallowExecEdit->text() ); 03947 config.writeEntry( "SwallowTitle", swallowTitleEdit->text() ); 03948 config.writeEntry( "Terminal", terminalCheck->isChecked() ); 03949 TQString temp = terminalEdit->text(); 03950 if (d->nocloseonexitCheck ) 03951 if ( d->nocloseonexitCheck->isChecked() ) 03952 temp += TQString::fromLatin1("--noclose "); 03953 temp = temp.stripWhiteSpace(); 03954 config.writeEntry( "TerminalOptions", temp ); 03955 config.writeEntry( "X-TDE-SubstituteUID", suidCheck->isChecked() ); 03956 config.writeEntry( "X-TDE-Username", suidEdit->text() ); 03957 } 03958 03959 03960 void KExecPropsPlugin::slotBrowseExec() 03961 { 03962 KURL f = KFileDialog::getOpenURL( TQString::null, 03963 TQString::null, d->m_frame ); 03964 if ( f.isEmpty() ) 03965 return; 03966 03967 if ( !f.isLocalFile()) { 03968 KMessageBox::sorry(d->m_frame, i18n("Only executables on local file systems are supported.")); 03969 return; 03970 } 03971 03972 TQString path = f.path(); 03973 KRun::shellQuote( path ); 03974 execEdit->setText( path ); 03975 } 03976 03977 class TDEApplicationPropsPlugin::TDEApplicationPropsPluginPrivate 03978 { 03979 public: 03980 TDEApplicationPropsPluginPrivate() 03981 { 03982 m_kdesktopMode = TQCString(tqApp->name()) == "kdesktop"; // nasty heh? 03983 } 03984 ~TDEApplicationPropsPluginPrivate() 03985 { 03986 } 03987 03988 TQFrame *m_frame; 03989 bool m_kdesktopMode; 03990 }; 03991 03992 TDEApplicationPropsPlugin::TDEApplicationPropsPlugin( KPropertiesDialog *_props ) 03993 : KPropsDlgPlugin( _props ) 03994 { 03995 d = new TDEApplicationPropsPluginPrivate; 03996 d->m_frame = properties->addPage(i18n("&Application")); 03997 TQVBoxLayout *toplayout = new TQVBoxLayout( d->m_frame, 0, KDialog::spacingHint()); 03998 03999 TQIconSet iconSet; 04000 TQPixmap pixMap; 04001 04002 addExtensionButton = new TQPushButton( TQString::null, d->m_frame ); 04003 iconSet = SmallIconSet( "back" ); 04004 addExtensionButton->setIconSet( iconSet ); 04005 pixMap = iconSet.pixmap( TQIconSet::Small, TQIconSet::Normal ); 04006 addExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 ); 04007 connect( addExtensionButton, TQT_SIGNAL( clicked() ), 04008 TQT_SLOT( slotAddExtension() ) ); 04009 04010 delExtensionButton = new TQPushButton( TQString::null, d->m_frame ); 04011 iconSet = SmallIconSet( "forward" ); 04012 delExtensionButton->setIconSet( iconSet ); 04013 delExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 ); 04014 connect( delExtensionButton, TQT_SIGNAL( clicked() ), 04015 TQT_SLOT( slotDelExtension() ) ); 04016 04017 TQLabel *l; 04018 04019 TQGridLayout *grid = new TQGridLayout(2, 2); 04020 grid->setColStretch(1, 1); 04021 toplayout->addLayout(TQT_TQLAYOUT(grid)); 04022 04023 if ( d->m_kdesktopMode ) 04024 { 04025 // in kdesktop the name field comes from the first tab 04026 nameEdit = 0L; 04027 } 04028 else 04029 { 04030 l = new TQLabel(i18n("Name:"), d->m_frame, "Label_4" ); 04031 grid->addWidget(l, 0, 0); 04032 04033 nameEdit = new KLineEdit( d->m_frame, "LineEdit_3" ); 04034 grid->addWidget(nameEdit, 0, 1); 04035 } 04036 04037 l = new TQLabel(i18n("Description:"), d->m_frame, "Label_5" ); 04038 grid->addWidget(l, 1, 0); 04039 04040 genNameEdit = new KLineEdit( d->m_frame, "LineEdit_4" ); 04041 grid->addWidget(genNameEdit, 1, 1); 04042 04043 l = new TQLabel(i18n("Comment:"), d->m_frame, "Label_3" ); 04044 grid->addWidget(l, 2, 0); 04045 04046 commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" ); 04047 grid->addWidget(commentEdit, 2, 1); 04048 04049 l = new TQLabel(i18n("File types:"), d->m_frame); 04050 toplayout->addWidget(l, 0, AlignLeft); 04051 04052 grid = new TQGridLayout(4, 3); 04053 grid->setColStretch(0, 1); 04054 grid->setColStretch(2, 1); 04055 grid->setRowStretch( 0, 1 ); 04056 grid->setRowStretch( 3, 1 ); 04057 toplayout->addLayout(TQT_TQLAYOUT(grid), 2); 04058 04059 extensionsList = new TQListBox( d->m_frame ); 04060 extensionsList->setSelectionMode( TQListBox::Extended ); 04061 grid->addMultiCellWidget(extensionsList, 0, 3, 0, 0); 04062 04063 grid->addWidget(addExtensionButton, 1, 1); 04064 grid->addWidget(delExtensionButton, 2, 1); 04065 04066 availableExtensionsList = new TQListBox( d->m_frame ); 04067 availableExtensionsList->setSelectionMode( TQListBox::Extended ); 04068 grid->addMultiCellWidget(availableExtensionsList, 0, 3, 2, 2); 04069 04070 TQString path = properties->kurl().path() ; 04071 TQFile f( path ); 04072 if ( !f.open( IO_ReadOnly ) ) 04073 return; 04074 f.close(); 04075 04076 KDesktopFile config( path ); 04077 TQString commentStr = config.readComment(); 04078 TQString genNameStr = config.readGenericName(); 04079 04080 TQStringList selectedTypes = config.readListEntry( "X-TDE-ServiceTypes" ); 04081 // For compatibility with KDE 1.x 04082 selectedTypes += config.readListEntry( "MimeType", ';' ); 04083 04084 TQString nameStr = config.readName(); 04085 if ( nameStr.isEmpty() || d->m_kdesktopMode ) { 04086 // We'll use the file name if no name is specified 04087 // because we _need_ a Name for a valid file. 04088 // But let's do it in apply, not here, so that we pick up the right name. 04089 setDirty(); 04090 } 04091 04092 commentEdit->setText( commentStr ); 04093 genNameEdit->setText( genNameStr ); 04094 if ( nameEdit ) 04095 nameEdit->setText( nameStr ); 04096 04097 selectedTypes.sort(); 04098 TQStringList::Iterator sit = selectedTypes.begin(); 04099 for( ; sit != selectedTypes.end(); ++sit ) { 04100 if ( !((*sit).isEmpty()) ) 04101 extensionsList->insertItem( *sit ); 04102 } 04103 04104 KMimeType::List mimeTypes = KMimeType::allMimeTypes(); 04105 TQValueListIterator<KMimeType::Ptr> it2 = mimeTypes.begin(); 04106 for ( ; it2 != mimeTypes.end(); ++it2 ) 04107 addMimeType ( (*it2)->name() ); 04108 04109 updateButton(); 04110 04111 connect( extensionsList, TQT_SIGNAL( highlighted( int ) ), 04112 this, TQT_SLOT( updateButton() ) ); 04113 connect( availableExtensionsList, TQT_SIGNAL( highlighted( int ) ), 04114 this, TQT_SLOT( updateButton() ) ); 04115 04116 connect( addExtensionButton, TQT_SIGNAL( clicked() ), 04117 this, TQT_SIGNAL( changed() ) ); 04118 connect( delExtensionButton, TQT_SIGNAL( clicked() ), 04119 this, TQT_SIGNAL( changed() ) ); 04120 if ( nameEdit ) 04121 connect( nameEdit, TQT_SIGNAL( textChanged( const TQString & ) ), 04122 this, TQT_SIGNAL( changed() ) ); 04123 connect( commentEdit, TQT_SIGNAL( textChanged( const TQString & ) ), 04124 this, TQT_SIGNAL( changed() ) ); 04125 connect( genNameEdit, TQT_SIGNAL( textChanged( const TQString & ) ), 04126 this, TQT_SIGNAL( changed() ) ); 04127 connect( availableExtensionsList, TQT_SIGNAL( selected( int ) ), 04128 this, TQT_SIGNAL( changed() ) ); 04129 connect( extensionsList, TQT_SIGNAL( selected( int ) ), 04130 this, TQT_SIGNAL( changed() ) ); 04131 } 04132 04133 TDEApplicationPropsPlugin::~TDEApplicationPropsPlugin() 04134 { 04135 delete d; 04136 } 04137 04138 // TQString TDEApplicationPropsPlugin::tabName () const 04139 // { 04140 // return i18n ("&Application"); 04141 // } 04142 04143 void TDEApplicationPropsPlugin::updateButton() 04144 { 04145 addExtensionButton->setEnabled(availableExtensionsList->currentItem()>-1); 04146 delExtensionButton->setEnabled(extensionsList->currentItem()>-1); 04147 } 04148 04149 void TDEApplicationPropsPlugin::addMimeType( const TQString & name ) 04150 { 04151 // Add a mimetype to the list of available mime types if not in the extensionsList 04152 04153 bool insert = true; 04154 04155 for ( uint i = 0; i < extensionsList->count(); i++ ) 04156 if ( extensionsList->text( i ) == name ) 04157 insert = false; 04158 04159 if ( insert ) 04160 { 04161 availableExtensionsList->insertItem( name ); 04162 availableExtensionsList->sort(); 04163 } 04164 } 04165 04166 bool TDEApplicationPropsPlugin::supports( KFileItemList _items ) 04167 { 04168 // same constraints as KExecPropsPlugin : desktop file with Type = Application 04169 return KExecPropsPlugin::supports( _items ); 04170 } 04171 04172 void TDEApplicationPropsPlugin::applyChanges() 04173 { 04174 TQString path = properties->kurl().path(); 04175 04176 TQFile f( path ); 04177 04178 if ( !f.open( IO_ReadWrite ) ) { 04179 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not " 04180 "have sufficient access to write to <b>%1</b>.</qt>").arg(path)); 04181 return; 04182 } 04183 f.close(); 04184 04185 KSimpleConfig config( path ); 04186 config.setDesktopGroup(); 04187 config.writeEntry( "Type", TQString::fromLatin1("Application")); 04188 config.writeEntry( "Comment", commentEdit->text() ); 04189 config.writeEntry( "Comment", commentEdit->text(), true, false, true ); // for compat 04190 config.writeEntry( "GenericName", genNameEdit->text() ); 04191 config.writeEntry( "GenericName", genNameEdit->text(), true, false, true ); // for compat 04192 04193 TQStringList selectedTypes; 04194 for ( uint i = 0; i < extensionsList->count(); i++ ) 04195 selectedTypes.append( extensionsList->text( i ) ); 04196 04197 config.writeEntry( "MimeType", selectedTypes, ';' ); 04198 config.writeEntry( "X-TDE-ServiceTypes", "" ); 04199 // hmm, actually it should probably be the contrary (but see also typeslistitem.cpp) 04200 04201 TQString nameStr = nameEdit ? nameEdit->text() : TQString::null; 04202 if ( nameStr.isEmpty() ) // nothing entered, or widget not existing at all (kdesktop mode) 04203 nameStr = nameFromFileName(properties->kurl().fileName()); 04204 04205 config.writeEntry( "Name", nameStr ); 04206 config.writeEntry( "Name", nameStr, true, false, true ); 04207 04208 config.sync(); 04209 } 04210 04211 void TDEApplicationPropsPlugin::slotAddExtension() 04212 { 04213 TQListBoxItem *item = availableExtensionsList->firstItem(); 04214 TQListBoxItem *nextItem; 04215 04216 while ( item ) 04217 { 04218 nextItem = item->next(); 04219 04220 if ( item->isSelected() ) 04221 { 04222 extensionsList->insertItem( item->text() ); 04223 availableExtensionsList->removeItem( availableExtensionsList->index( item ) ); 04224 } 04225 04226 item = nextItem; 04227 } 04228 04229 extensionsList->sort(); 04230 updateButton(); 04231 } 04232 04233 void TDEApplicationPropsPlugin::slotDelExtension() 04234 { 04235 TQListBoxItem *item = extensionsList->firstItem(); 04236 TQListBoxItem *nextItem; 04237 04238 while ( item ) 04239 { 04240 nextItem = item->next(); 04241 04242 if ( item->isSelected() ) 04243 { 04244 availableExtensionsList->insertItem( item->text() ); 04245 extensionsList->removeItem( extensionsList->index( item ) ); 04246 } 04247 04248 item = nextItem; 04249 } 04250 04251 availableExtensionsList->sort(); 04252 updateButton(); 04253 } 04254 04255 04256 04257 #include "kpropertiesdialog.moc"
Trinity API Reference