• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeio/tdefile
 

tdeio/tdefile

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"

tdeio/tdefile

Skip menu "tdeio/tdefile"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

tdeio/tdefile

Skip menu "tdeio/tdefile"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeio/tdefile by doxygen 1.6.3
This website is maintained by Timothy Pearson.