kio Library API Documentation

kpropertiesdialog.cpp

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