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  */
00041 
00042 #include <config.h>
00043 extern "C" {
00044 #include <pwd.h>
00045 #include <grp.h>
00046 #include <time.h>
00047 }
00048 #include <unistd.h>
00049 #include <errno.h>
00050 #include <assert.h>
00051 
00052 #ifdef HAVE_MNTENT_H
00053 #include <mntent.h>
00054 #endif
00055 
00056 #include <qfile.h>
00057 #include <qdir.h>
00058 #include <qlabel.h>
00059 #include <qpushbutton.h>
00060 #include <qcheckbox.h>
00061 #include <qstrlist.h>
00062 #include <qstringlist.h>
00063 #include <qtextstream.h>
00064 #include <qpainter.h>
00065 #include <qlayout.h>
00066 #include <qcombobox.h>
00067 #include <qgroupbox.h>
00068 
00069 #include <kapplication.h>
00070 #include <kdialog.h>
00071 #include <kdirsize.h>
00072 #include <kdirwatch.h>
00073 #include <kdirnotify_stub.h>
00074 #include <kdiskfreesp.h>
00075 #include <kdebug.h>
00076 #include <kdesktopfile.h>
00077 #include <kicondialog.h>
00078 #include <kurl.h>
00079 #include <kurlrequester.h>
00080 #include <klocale.h>
00081 #include <kglobal.h>
00082 #include <kglobalsettings.h>
00083 #include <kstandarddirs.h>
00084 #include <kio/job.h>
00085 #include <kio/chmodjob.h>
00086 #include <kio/renamedlg.h>
00087 #include <kfiledialog.h>
00088 #include <kmimetype.h>
00089 #include <kiconloader.h>
00090 #include <kmessagebox.h>
00091 #include <kservice.h>
00092 #include <kcompletion.h>
00093 #include <klineedit.h>
00094 #include <kseparator.h>
00095 #include <ksqueezedtextlabel.h>
00096 #include <klibloader.h>
00097 #include <ktrader.h>
00098 #include <kparts/componentfactory.h>
00099 #include <kmetaprops.h>
00100 #include <krun.h>
00101 #include "kfilesharedlg.h"
00102 
00103 #include "kpropertiesdialog.h"
00104 
00105 #ifdef Q_WS_X11
00106 extern "C" {
00107 #include <X11/Xlib.h> // for XSetTransientForHint
00108 }
00109 #endif
00110 
00111 mode_t KFilePermissionsPropsPlugin::fperm[3][4] = {
00112         {S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID},
00113         {S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID},
00114         {S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX}
00115     };
00116 
00117 class KPropertiesDialog::KPropertiesDialogPrivate
00118 {
00119 public:
00120   KPropertiesDialogPrivate()
00121   {
00122     m_aborted = false;
00123   }
00124   ~KPropertiesDialogPrivate()
00125   {
00126   }
00127   bool m_aborted:1;
00128   bool modal:1;
00129   bool autoShow:1;
00130 };
00131 
00132 KPropertiesDialog::KPropertiesDialog (KFileItem* item,
00133                                       QWidget* parent, const char* name,
00134                                       bool modal, bool autoShow)
00135   : KDialogBase (KDialogBase::Tabbed, i18n( "Properties for %1" ).arg(KIO::decodeFileName(item->url().fileName())),
00136                  KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
00137                  parent, name, modal)
00138 {
00139   d = new KPropertiesDialogPrivate;
00140   assert( item );
00141   m_items.append( new KFileItem(*item) ); // deep copy
00142 
00143   m_singleUrl = item->url();
00144   assert(!m_singleUrl.isEmpty());
00145 
00146   init (modal, autoShow);
00147 }
00148 
00149 KPropertiesDialog::KPropertiesDialog (const QString& title,
00150                                       QWidget* parent, const char* name, bool modal)
00151   : KDialogBase (KDialogBase::Tabbed, i18n ("Properties for %1").arg(title),
00152                  KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
00153                  parent, name, modal)
00154 {
00155   d = new KPropertiesDialogPrivate;
00156 
00157   init (modal, false);
00158 }
00159 
00160 KPropertiesDialog::KPropertiesDialog (KFileItemList _items,
00161                                       QWidget* parent, const char* name,
00162                                       bool modal, bool autoShow)
00163   : KDialogBase (KDialogBase::Tabbed, i18n( "Properties for %1" ).arg(KIO::decodeFileName(_items.first()->url().fileName())),
00164                  KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
00165                  parent, name, modal)
00166 {
00167   d = new KPropertiesDialogPrivate;
00168 
00169   assert( !_items.isEmpty() );
00170   m_singleUrl = _items.first()->url();
00171   assert(!m_singleUrl.isEmpty());
00172 
00173   KFileItemListIterator it ( _items );
00174   // Deep copy
00175   for ( ; it.current(); ++it )
00176       m_items.append( new KFileItem( **it ) );
00177 
00178   init (modal, autoShow);
00179 }
00180 
00181 #ifndef KDE_NO_COMPAT
00182 KPropertiesDialog::KPropertiesDialog (const KURL& _url, mode_t /* _mode is now unused */,
00183                                       QWidget* parent, const char* name,
00184                                       bool modal, bool autoShow)
00185   : KDialogBase (KDialogBase::Tabbed, i18n( "Properties for %1" ).arg(KIO::decodeFileName(_url.fileName())),
00186                  KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
00187                  parent, name, modal),
00188   m_singleUrl( _url )
00189 {
00190   d = new KPropertiesDialogPrivate;
00191   d->modal = modal;
00192   d->autoShow = autoShow;
00193 
00194   assert(!_url.isEmpty());
00195 
00196   KIO::StatJob * job = KIO::stat( _url );
00197   connect( job, SIGNAL( result( KIO::Job * ) ),
00198            SLOT( slotStatResult( KIO::Job * ) ) );
00199 }
00200 #endif
00201 
00202 KPropertiesDialog::KPropertiesDialog (const KURL& _url,
00203                                       QWidget* parent, const char* name,
00204                                       bool modal, bool autoShow)
00205   : KDialogBase (KDialogBase::Tabbed, i18n( "Properties for %1" ).arg(KIO::decodeFileName(_url.fileName())),
00206                  KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
00207                  parent, name, modal),
00208   m_singleUrl( _url )
00209 {
00210   d = new KPropertiesDialogPrivate;
00211   d->modal = modal;
00212   d->autoShow = autoShow;
00213 
00214   assert(!_url.isEmpty());
00215 
00216   KIO::StatJob * job = KIO::stat( _url );
00217   connect( job, SIGNAL( result( KIO::Job * ) ),
00218            SLOT( slotStatResult( KIO::Job * ) ) );
00219 }
00220 
00221 KPropertiesDialog::KPropertiesDialog (const KURL& _tempUrl, const KURL& _currentDir,
00222                                       const QString& _defaultName,
00223                                       QWidget* parent, const char* name,
00224                                       bool modal, bool autoShow)
00225   : KDialogBase (KDialogBase::Tabbed, i18n( "Properties for %1" ).arg(KIO::decodeFileName(_tempUrl.fileName())),
00226                  KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
00227                  parent, name, modal),
00228 
00229   m_singleUrl( _tempUrl ),
00230   m_defaultName( _defaultName ),
00231   m_currentDir( _currentDir )
00232 {
00233   d = new KPropertiesDialogPrivate;
00234 
00235   assert(!m_singleUrl.isEmpty());
00236 
00237   // Create the KFileItem for the _template_ file, in order to read from it.
00238   m_items.append( new KFileItem( KFileItem::Unknown, KFileItem::Unknown, m_singleUrl ) );
00239   init (modal, autoShow);
00240 }
00241 
00242 void KPropertiesDialog::init (bool modal, bool autoShow)
00243 {
00244   m_pageList.setAutoDelete( true );
00245   m_items.setAutoDelete( true );
00246 
00247 #ifdef Q_WS_X11 // FIXME(E): Can we do something similar for Qt Embedded?
00248   // Matthias: let the dialog look like a modal dialog
00249   if (!modal)
00250     XSetTransientForHint(qt_xdisplay(), winId(), winId());
00251 #endif
00252 
00253   //  resize( 400, 400 ); // not sure what that's for
00254 
00255   insertPages();
00256 
00257   //kdDebug(250) << "KPropertiesDialog sizeHint " << sizeHint().width() << "x" << sizeHint().height() << endl;
00258   // This HACK forces KDialogBase to recompute the layout
00259   // It is necessary for the case where init is not called from the constructor,
00260   // but from slotStatResult. And I'm way too lazy to look into KDialogBase...
00261   enableLinkedHelp( true );
00262   enableLinkedHelp( false );
00263   resize(sizeHint());
00264 
00265   if (autoShow)
00266     {
00267       if (!modal)
00268         show();
00269       else
00270         exec();
00271     }
00272 }
00273 
00274 void KPropertiesDialog::showFileSharingPage()
00275 {
00276     KPropsDlgPlugin *it;
00277 
00278     for ( it=m_pageList.first(); it != 0L; it=m_pageList.next() )
00279     {
00280         KFileSharePropsPlugin* plugin = dynamic_cast<KFileSharePropsPlugin*>(it);
00281         if ( plugin )
00282         {
00283             showPage( pageIndex( plugin->page() ) );
00284             break;
00285         }
00286     }
00287 }
00288 
00289 void KPropertiesDialog::slotStatResult( KIO::Job * job )
00290 {
00291     if (job->error())
00292     {
00293         job->showErrorDialog( this );
00294         delete this;
00295     }
00296     else
00297     {
00298         KIO::StatJob * statJob = static_cast<KIO::StatJob*>(job);
00299         m_items.append( new KFileItem( statJob->statResult(), statJob->url() ) );
00300         init (d->modal, d->autoShow);
00301     }
00302 }
00303 
00304 KPropertiesDialog::~KPropertiesDialog()
00305 {
00306   m_pageList.clear();
00307   delete d;
00308 }
00309 
00310 void KPropertiesDialog::insertPlugin (KPropsDlgPlugin* plugin)
00311 {
00312   connect (plugin, SIGNAL (changed ()),
00313            plugin, SLOT (setDirty ()));
00314 
00315   m_pageList.append (plugin);
00316 }
00317 
00318 bool KPropertiesDialog::canDisplay( KFileItemList _items )
00319 {
00320   return KFilePropsPlugin::supports( _items ) ||
00321          KFilePermissionsPropsPlugin::supports( _items ) ||
00322          KExecPropsPlugin::supports( _items ) ||
00323          KApplicationPropsPlugin::supports( _items ) ||
00324          KBindingPropsPlugin::supports( _items ) ||
00325          KURLPropsPlugin::supports( _items ) ||
00326          KDevicePropsPlugin::supports( _items ) ||
00327          KFileMetaPropsPlugin::supports( _items );
00328 }
00329 
00330 void KPropertiesDialog::slotOk()
00331 {
00332   KPropsDlgPlugin *page;
00333   d->m_aborted = false;
00334 
00335   KFilePropsPlugin * filePropsPlugin = 0L;
00336   if ( m_pageList.first()->isA("KFilePropsPlugin") )
00337     filePropsPlugin = static_cast<KFilePropsPlugin *>(m_pageList.first());
00338 
00339   // If any page is dirty, then set the main one (KFilePropsPlugin) as
00340   // dirty too. This is what makes it possible to save changes to a global
00341   // desktop file into a local one. In other cases, it doesn't hurt.
00342   for ( page = m_pageList.first(); page != 0L; page = m_pageList.next() )
00343     if ( page->isDirty() && filePropsPlugin )
00344     {
00345         filePropsPlugin->setDirty();
00346         break;
00347     }
00348 
00349   // Apply the changes in the _normal_ order of the tabs now
00350   // This is because in case of renaming a file, KFilePropsPlugin will call
00351   // KPropertiesDialog::rename, so other tab will be ok with whatever order
00352   // BUT for file copied from templates, we need to do the renaming first !
00353   for ( page = m_pageList.first(); page != 0L && !d->m_aborted; page = m_pageList.next() )
00354     if ( page->isDirty() )
00355     {
00356       kdDebug( 250 ) << "applying changes for " << page->className() << endl;
00357       page->applyChanges();
00358       // applyChanges may change d->m_aborted.
00359     }
00360     else
00361       kdDebug( 250 ) << "skipping page " << page->className() << endl;
00362 
00363   if ( !d->m_aborted && filePropsPlugin )
00364     filePropsPlugin->postApplyChanges();
00365 
00366   if ( !d->m_aborted )
00367   {
00368     emit applied();
00369     emit propertiesClosed();
00370     deleteLater();
00371     accept();
00372   } // else, keep dialog open for user to fix the problem.
00373 }
00374 
00375 void KPropertiesDialog::slotCancel()
00376 {
00377   emit canceled();
00378   emit propertiesClosed();
00379 
00380   deleteLater();
00381   done( Rejected );
00382 }
00383 
00384 void KPropertiesDialog::insertPages()
00385 {
00386   if (m_items.isEmpty())
00387     return;
00388 
00389   if ( KFilePropsPlugin::supports( m_items ) )
00390   {
00391     KPropsDlgPlugin *p = new KFilePropsPlugin( this );
00392     insertPlugin (p);
00393   }
00394 
00395   if ( KFilePermissionsPropsPlugin::supports( m_items ) )
00396   {
00397     KPropsDlgPlugin *p = new KFilePermissionsPropsPlugin( this );
00398     insertPlugin (p);
00399   }
00400 
00401   if ( KExecPropsPlugin::supports( m_items ) )
00402   {
00403     KPropsDlgPlugin *p = new KExecPropsPlugin( this );
00404     insertPlugin (p);
00405   }
00406 
00407   if ( KApplicationPropsPlugin::supports( m_items ) )
00408   {
00409     KPropsDlgPlugin *p = new KApplicationPropsPlugin( this );
00410     insertPlugin (p);
00411   }
00412 
00413   if ( KBindingPropsPlugin::supports( m_items ) )
00414   {
00415     KPropsDlgPlugin *p = new KBindingPropsPlugin( this );
00416     insertPlugin (p);
00417   }
00418 
00419   if ( KURLPropsPlugin::supports( m_items ) )
00420   {
00421     KPropsDlgPlugin *p = new KURLPropsPlugin( this );
00422     insertPlugin (p);
00423   }
00424 
00425   if ( KDevicePropsPlugin::supports( m_items ) )
00426   {
00427     KPropsDlgPlugin *p = new KDevicePropsPlugin( this );
00428     insertPlugin (p);
00429   }
00430 
00431   if ( KFileMetaPropsPlugin::supports( m_items ) )
00432   {
00433     KPropsDlgPlugin *p = new KFileMetaPropsPlugin( this );
00434     insertPlugin (p);
00435   }
00436 
00437   if ( KFileSharePropsPlugin::supports( m_items ) )
00438   {
00439     KPropsDlgPlugin *p = new KFileSharePropsPlugin( this );
00440     insertPlugin (p);
00441   }
00442 
00443   //plugins
00444 
00445   if ( m_items.count() != 1 )
00446     return;
00447 
00448   KFileItem *item = m_items.first();
00449   QString mimetype = item->mimetype();
00450 
00451   if ( mimetype.isEmpty() )
00452     return;
00453 
00454   QString query = QString::fromLatin1(
00455       "('KPropsDlg/Plugin' in ServiceTypes) and "
00456       "((not exist [X-KDE-Protocol]) or "
00457       " ([X-KDE-Protocol] == '%1'  )   )"          ).arg(item->url().protocol());
00458 
00459   kdDebug( 250 ) << "trader query: " << query << endl;
00460   KTrader::OfferList offers = KTrader::self()->query( mimetype, query );
00461   KTrader::OfferList::ConstIterator it = offers.begin();
00462   KTrader::OfferList::ConstIterator end = offers.end();
00463   for (; it != end; ++it )
00464   {
00465     KPropsDlgPlugin *plugin = KParts::ComponentFactory
00466         ::createInstanceFromLibrary<KPropsDlgPlugin>( (*it)->library().local8Bit().data(),
00467                                                       this,
00468                                                       (*it)->name().latin1() );
00469     if ( !plugin )
00470         continue;
00471 
00472     insertPlugin( plugin );
00473   }
00474 }
00475 
00476 void KPropertiesDialog::updateUrl( const KURL& _newUrl )
00477 {
00478   Q_ASSERT( m_items.count() == 1 );
00479   kdDebug(250) << "KPropertiesDialog::updateUrl " << _newUrl.url() << endl;
00480   m_singleUrl = _newUrl;
00481   m_items.first()->setURL( _newUrl );
00482   assert(!m_singleUrl.isEmpty());
00483   // If we have an Exec page, set it dirty, so that a full file is saved locally
00484   // Same for a URL page (because of the Name= hack)
00485   for ( QPtrListIterator<KPropsDlgPlugin> it(m_pageList); it.current(); ++it )
00486    if ( it.current()->isA("KExecPropsPlugin") || it.current()->isA("KURLPropsPlugin") )
00487    {
00488      //kdDebug(250) << "Setting page dirty" << endl;
00489      it.current()->setDirty();
00490      break;
00491    }
00492 }
00493 
00494 void KPropertiesDialog::rename( const QString& _name )
00495 {
00496   Q_ASSERT( m_items.count() == 1 );
00497   kdDebug(250) << "KPropertiesDialog::rename " << _name << endl;
00498   KURL newUrl;
00499   // if we're creating from a template : use currentdir
00500   if ( !m_currentDir.isEmpty() )
00501   {
00502     newUrl = m_currentDir;
00503     newUrl.addPath( _name );
00504   }
00505   else
00506   {
00507     QString tmpurl = m_singleUrl.url();
00508     if ( tmpurl.at(tmpurl.length() - 1) == '/')
00509       // It's a directory, so strip the trailing slash first
00510       tmpurl.truncate( tmpurl.length() - 1);
00511     newUrl = tmpurl;
00512     newUrl.setFileName( _name );
00513   }
00514   updateUrl( newUrl );
00515 }
00516 
00517 void KPropertiesDialog::abortApplying()
00518 {
00519   d->m_aborted = true;
00520 }
00521 
00522 class KPropsDlgPlugin::KPropsDlgPluginPrivate
00523 {
00524 public:
00525   KPropsDlgPluginPrivate()
00526   {
00527   }
00528   ~KPropsDlgPluginPrivate()
00529   {
00530   }
00531 
00532   bool m_bDirty;
00533 };
00534 
00535 KPropsDlgPlugin::KPropsDlgPlugin( KPropertiesDialog *_props )
00536 : QObject( _props, 0L )
00537 {
00538   d = new KPropsDlgPluginPrivate;
00539   properties = _props;
00540   fontHeight = 2*properties->dialog()->fontMetrics().height();
00541   d->m_bDirty = false;
00542 }
00543 
00544 KPropsDlgPlugin::~KPropsDlgPlugin()
00545 {
00546   delete d;
00547 }
00548 
00549 bool KPropsDlgPlugin::isDesktopFile( KFileItem * _item )
00550 {
00551   // only local files
00552   if ( !_item->isLocalFile() )
00553     return false;
00554 
00555   // only regular files
00556   if ( !S_ISREG( _item->mode() ) )
00557     return false;
00558 
00559   QString t( _item->url().path() );
00560 
00561   // only if readable
00562   FILE *f = fopen( QFile::encodeName(t), "r" );
00563   if ( f == 0L )
00564     return false;
00565   fclose(f);
00566 
00567   // return true if desktop file
00568   return ( _item->mimetype() == QString::fromLatin1("application/x-desktop") );
00569 }
00570 
00571 void KPropsDlgPlugin::setDirty( bool b )
00572 {
00573   d->m_bDirty = b;
00574 }
00575 
00576 void KPropsDlgPlugin::setDirty()
00577 {
00578   d->m_bDirty = true;
00579 }
00580 
00581 bool KPropsDlgPlugin::isDirty() const
00582 {
00583   return d->m_bDirty;
00584 }
00585 
00586 void KPropsDlgPlugin::applyChanges()
00587 {
00588   kdWarning(250) << "applyChanges() not implemented in page !" << endl;
00589 }
00590 
00592 
00593 class KFilePropsPlugin::KFilePropsPluginPrivate
00594 {
00595 public:
00596   KFilePropsPluginPrivate()
00597   {
00598     dirSizeJob = 0L;
00599   }
00600   ~KFilePropsPluginPrivate()
00601   {
00602     if ( dirSizeJob )
00603       dirSizeJob->kill();
00604   }
00605 
00606   KDirSize * dirSizeJob;
00607   QFrame *m_frame;
00608   bool bMultiple;
00609   QLabel *m_freeSpaceLabel;
00610 };
00611 
00612 KFilePropsPlugin::KFilePropsPlugin( KPropertiesDialog *_props )
00613   : KPropsDlgPlugin( _props )
00614 {
00615   d = new KFilePropsPluginPrivate;
00616   d->bMultiple = (properties->items().count() > 1);
00617   kdDebug(250) << "KFilePropsPlugin::KFilePropsPlugin bMultiple=" << d->bMultiple << endl;
00618 
00619   // We set this data from the first item, and we'll
00620   // check that the other items match against it, resetting when not.
00621   bool isLocal = properties->kurl().isLocalFile();
00622   KFileItem * item = properties->item();
00623   bool bDesktopFile = isDesktopFile(item);
00624   mode_t mode = item->mode();
00625   bool hasDirs = item->isDir() && !item->isLink();
00626   bool hasRoot = isLocal && properties->kurl().path() == QString::fromLatin1("/");
00627   QString iconStr = KMimeType::iconForURL(properties->kurl(), mode);
00628   QString directory = properties->kurl().directory();
00629   QString protocol = properties->kurl().protocol();
00630   QString mimeComment = item->mimeComment();
00631   KIO::filesize_t totalSize = item->size();
00632   QString magicMimeComment;
00633   if ( isLocal ) {
00634       KMimeType::Ptr magicMimeType = KMimeType::findByFileContent( properties->kurl().path() );
00635       if ( magicMimeType->name() != KMimeType::defaultMimeType() )
00636           magicMimeComment = magicMimeType->comment();
00637   }
00638 
00639   // Those things only apply to 'single file' mode
00640   QString filename = QString::null;
00641   bool isTrash = false;
00642   m_bFromTemplate = false;
00643 
00644   // And those only to 'multiple' mode
00645   uint iDirCount = S_ISDIR(mode) ? 1 : 0;
00646   uint iFileCount = 1-iDirCount;
00647 
00648   d->m_frame = properties->dialog()->addPage (i18n("&General"));
00649 
00650   QVBoxLayout *vbl = new QVBoxLayout( d->m_frame, KDialog::marginHint(),
00651                                       KDialog::spacingHint(), "vbl");
00652   QGridLayout *grid = new QGridLayout(0, 3); // unknown rows
00653   grid->setColStretch(2, 1);
00654   grid->addColSpacing(1, KDialog::spacingHint());
00655   vbl->addLayout(grid);
00656   int curRow = 0;
00657 
00658   if ( !d->bMultiple )
00659   {
00660     // Extract the file name only
00661     filename = properties->defaultName();
00662     if ( filename.isEmpty() ) // no template
00663       filename = properties->kurl().fileName();
00664     else
00665     {
00666       m_bFromTemplate = true;
00667       setDirty(); // to enforce that the copy happens
00668     }
00669     oldName = filename;
00670 
00671     // Make it human-readable (%2F => '/', ...)
00672     filename = KIO::decodeFileName( filename );
00673 
00674     QString path;
00675 
00676     if ( !m_bFromTemplate ) {
00677       QString tmp = properties->kurl().path( 1 );
00678       // is it the trash bin ?
00679       if ( isLocal && tmp == KGlobalSettings::trashPath())
00680         isTrash = true;
00681 
00682       // Extract the full name, but without file: for local files
00683       if ( isLocal )
00684         path = properties->kurl().path();
00685       else
00686         path = properties->kurl().prettyURL();
00687     } else {
00688       path = properties->currentDir().path(1) + properties->defaultName();
00689       directory = properties->currentDir().prettyURL();
00690     }
00691 
00692     if (KExecPropsPlugin::supports(properties->items()) ||
00693         KBindingPropsPlugin::supports(properties->items())) {
00694 
00695       determineRelativePath( path );
00696 
00697     }
00698 
00699   }
00700   else
00701   {
00702     // Multiple items: see what they have in common
00703     KFileItemList items = properties->items();
00704     KFileItemListIterator it( items );
00705     for ( ++it /*no need to check the first one again*/ ; it.current(); ++it )
00706     {
00707       KURL url = (*it)->url();
00708       kdDebug(250) << "KFilePropsPlugin::KFilePropsPlugin " << url.prettyURL() << endl;
00709       // The list of things we check here should match the variables defined
00710       // at the beginning of this method.
00711       if ( url.isLocalFile() != isLocal )
00712         isLocal = false; // not all local
00713       if ( bDesktopFile && isDesktopFile(*it) != bDesktopFile )
00714         bDesktopFile = false; // not all desktop files
00715       if ( (*it)->mode() != mode )
00716         mode = (mode_t)0;
00717       if ( KMimeType::iconForURL(url, mode) != iconStr )
00718         iconStr = "kmultiple";
00719       if ( url.directory() != directory )
00720         directory = QString::null;
00721       if ( url.protocol() != protocol )
00722         protocol = QString::null;
00723       if ( !mimeComment.isNull() && (*it)->mimeComment() != mimeComment )
00724         mimeComment = QString::null;
00725       if ( isLocal && !magicMimeComment.isNull() ) {
00726           KMimeType::Ptr magicMimeType = KMimeType::findByFileContent( url.path() );
00727           if ( magicMimeType->comment() != magicMimeComment )
00728               magicMimeComment = QString::null;
00729       }
00730 
00731       if ( isLocal && url.path() == QString::fromLatin1("/") )
00732         hasRoot = true;
00733       if ( (*it)->isDir() && !(*it)->isLink() )
00734       {
00735         iDirCount++;
00736         hasDirs = true;
00737       }
00738       else
00739       {
00740         iFileCount++;
00741         totalSize += (*it)->size();
00742       }
00743     }
00744   }
00745 
00746   if (!isLocal && !protocol.isEmpty())
00747   {
00748     directory += ' ';
00749     directory += '(';
00750     directory += protocol;
00751     directory += ')';
00752   }
00753 
00754   if ( (bDesktopFile || S_ISDIR(mode)) && !d->bMultiple /*not implemented for multiple*/ )
00755   {
00756     KIconButton *iconButton = new KIconButton( d->m_frame );
00757     iconButton->setFixedSize(70, 70);
00758     iconButton->setStrictIconSize(false);
00759     iconButton->setIconType(KIcon::Desktop, KIcon::Device);
00760     // This works for everything except Device icons on unmounted devices
00761     // So we have to really open .desktop files
00762     QString iconStr = KMimeType::findByURL( properties->kurl(),
00763                                             mode )->icon( properties->kurl(),
00764                                                           isLocal );
00765     if ( bDesktopFile && isLocal )
00766     {
00767       KSimpleConfig config( properties->kurl().path() );
00768       config.setDesktopGroup();
00769       iconStr = config.readEntry( QString::fromLatin1("Icon") );
00770     }
00771     iconButton->setIcon(iconStr);
00772     iconArea = iconButton;
00773     connect( iconButton, SIGNAL( iconChanged(QString) ),
00774              this, SIGNAL( changed() ) );
00775   } else {
00776     QLabel *iconLabel = new QLabel( d->m_frame );
00777     iconLabel->setFixedSize(70, 70);
00778     iconLabel->setPixmap( DesktopIcon( iconStr ) );
00779     iconArea = iconLabel;
00780   }
00781   grid->addWidget(iconArea, curRow, 0, AlignLeft);
00782 
00783   if (d->bMultiple || isTrash || filename == QString::fromLatin1("/"))
00784   {
00785     QLabel *lab = new QLabel(d->m_frame );
00786     if ( d->bMultiple )
00787       lab->setText( KIO::itemsSummaryString( iFileCount + iDirCount, iFileCount, iDirCount, 0, false ) );
00788     else
00789       lab->setText( filename );
00790     nameArea = lab;
00791   } else
00792   {
00793     KLineEdit *lined = new KLineEdit( d->m_frame );
00794     lined->setText(filename);
00795     nameArea = lined;
00796     lined->setFocus();
00797     connect( lined, SIGNAL( textChanged( const QString & ) ),
00798              this, SLOT( nameFileChanged(const QString & ) ) );
00799   }
00800 
00801   grid->addWidget(nameArea, curRow++, 2);
00802 
00803   KSeparator* sep = new KSeparator( KSeparator::HLine, d->m_frame);
00804   grid->addMultiCellWidget(sep, curRow, curRow, 0, 2);
00805   ++curRow;
00806 
00807   QLabel *l;
00808   if ( !mimeComment.isEmpty() )
00809   {
00810     l = new QLabel(i18n("Type:"), d->m_frame );
00811     grid->addWidget(l, curRow, 0);
00812 
00813     l = new QLabel(mimeComment, d->m_frame );
00814     grid->addWidget(l, curRow++, 2);
00815   }
00816 
00817   if ( !magicMimeComment.isEmpty() && magicMimeComment != mimeComment )
00818   {
00819     l = new QLabel(i18n("Contents:"), d->m_frame );
00820     grid->addWidget(l, curRow, 0);
00821 
00822     l = new QLabel(magicMimeComment, d->m_frame );
00823     grid->addWidget(l, curRow++, 2);
00824   }
00825 
00826   if ( !directory.isEmpty() )
00827   {
00828     l = new QLabel( i18n("Location:"), d->m_frame );
00829     grid->addWidget(l, curRow, 0);
00830 
00831     l = new KSqueezedTextLabel( d->m_frame );
00832     l->setText( directory );
00833     grid->addWidget(l, curRow++, 2);
00834   }
00835 
00836   l = new QLabel(i18n("Size:"), d->m_frame );
00837   grid->addWidget(l, curRow, 0);
00838 
00839   m_sizeLabel = new QLabel( d->m_frame );
00840   grid->addWidget( m_sizeLabel, curRow++, 2 );
00841 
00842   if ( !hasDirs ) // Only files [and symlinks]
00843   {
00844     m_sizeLabel->setText(QString::fromLatin1("%1 (%2)").arg(KIO::convertSize(totalSize)).arg(KGlobal::locale()->formatNumber(totalSize, 0)));
00845     m_sizeDetermineButton = 0L;
00846     m_sizeStopButton = 0L;
00847   }
00848   else // Directory
00849   {
00850     QHBoxLayout * sizelay = new QHBoxLayout(KDialog::spacingHint());
00851     grid->addLayout( sizelay, curRow++, 2 );
00852 
00853     // buttons
00854     m_sizeDetermineButton = new QPushButton( i18n("Calculate"), d->m_frame );
00855     m_sizeStopButton = new QPushButton( i18n("Stop"), d->m_frame );
00856     connect( m_sizeDetermineButton, SIGNAL( clicked() ), this, SLOT( slotSizeDetermine() ) );
00857     connect( m_sizeStopButton, SIGNAL( clicked() ), this, SLOT( slotSizeStop() ) );
00858     sizelay->addWidget(m_sizeDetermineButton, 0);
00859     sizelay->addWidget(m_sizeStopButton, 0);
00860     sizelay->addStretch(10); // so that the buttons don't grow horizontally
00861 
00862     // auto-launch for local dirs only, and not for '/'
00863     if ( isLocal && !hasRoot )
00864     {
00865       m_sizeDetermineButton->setText( i18n("Refresh") );
00866       slotSizeDetermine();
00867     }
00868     else
00869       m_sizeStopButton->setEnabled( false );
00870   }
00871 
00872   if ( isLocal )
00873   {
00874       QString mountPoint = KIO::findPathMountPoint( properties->item()->url().path() );
00875 
00876       l = new QLabel(i18n("Free space on %1:").arg(mountPoint), d->m_frame );
00877       grid->addWidget(l, curRow, 0);
00878 
00879       d->m_freeSpaceLabel = new QLabel( d->m_frame );
00880       grid->addWidget( d->m_freeSpaceLabel, curRow++, 2 );
00881 
00882       KDiskFreeSp * job = new KDiskFreeSp;
00883       connect( job, SIGNAL( foundMountPoint( const unsigned long&, const unsigned long&, const unsigned long&, const QString& ) ),
00884                this, SLOT( slotFoundMountPoint( const unsigned long&, const unsigned long&, const unsigned long&, const QString& ) ) );
00885       job->readDF( mountPoint );
00886   }
00887 
00888   if (!d->bMultiple && item->isLink()) {
00889     l = new QLabel(i18n("Points to:"), d->m_frame );
00890     grid->addWidget(l, curRow, 0);
00891 
00892     l = new QLabel(item->linkDest(), d->m_frame );
00893     grid->addWidget(l, curRow++, 2);
00894   }
00895 
00896   if (!d->bMultiple) // Dates for multiple don't make much sense...
00897   {
00898     sep = new KSeparator( KSeparator::HLine, d->m_frame);
00899     grid->addMultiCellWidget(sep, curRow, curRow, 0, 2);
00900     ++curRow;
00901 
00902     grid = new QGridLayout(0, 3); // unknown # of rows
00903     grid->setColStretch(2, 1);
00904     grid->addColSpacing(1, KDialog::spacingHint());
00905     vbl->addLayout(grid);
00906     curRow = 0;
00907 
00908     QDateTime dt;
00909     time_t tim = item->time(KIO::UDS_CREATION_TIME);
00910     if ( tim )
00911     {
00912       l = new QLabel(i18n("Created:"), d->m_frame );
00913       grid->addWidget(l, curRow, 0);
00914 
00915       dt.setTime_t( tim );
00916       l = new QLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame );
00917       grid->addWidget(l, curRow++, 2);
00918     }
00919 
00920     tim = item->time(KIO::UDS_MODIFICATION_TIME);
00921     if ( tim )
00922     {
00923       l = new QLabel(i18n("Modified:"), d->m_frame );
00924       grid->addWidget(l, curRow, 0);
00925 
00926       dt.setTime_t( tim );
00927       l = new QLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame );
00928       grid->addWidget(l, curRow++, 2);
00929     }
00930 
00931     tim = item->time(KIO::UDS_ACCESS_TIME);
00932     if ( tim )
00933     {
00934       l = new QLabel(i18n("Accessed:"), d->m_frame );
00935       grid->addWidget(l, curRow, 0);
00936 
00937       dt.setTime_t( tim );
00938       l = new QLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame );
00939       grid->addWidget(l, curRow++, 2);
00940     }
00941   }
00942 
00943   vbl->addStretch(1);
00944 }
00945 
00946 // QString KFilePropsPlugin::tabName () const
00947 // {
00948 //   return i18n ("&General");
00949 // }
00950 
00951 
00952 void KFilePropsPlugin::nameFileChanged(const QString &text )
00953 {
00954   properties->enableButtonOK(!text.isEmpty());
00955   emit changed();
00956 }
00957 void KFilePropsPlugin::determineRelativePath( const QString & path )
00958 {
00959     m_sRelativePath = "";
00960     // now let's make it relative
00961     QStringList dirs;
00962     if (KBindingPropsPlugin::supports(properties->items()))
00963       dirs = KGlobal::dirs()->resourceDirs("mime");
00964     else
00965       dirs = KGlobal::dirs()->resourceDirs("apps");
00966 
00967     QStringList::ConstIterator it = dirs.begin();
00968     for ( ; it != dirs.end() && m_sRelativePath.isEmpty(); ++it ) {
00969       // might need canonicalPath() ...
00970       if ( path.find( *it ) == 0 ) // path is dirs + relativePath
00971         m_sRelativePath = path.mid( (*it).length() ); // skip appsdirs
00972     }
00973     if ( m_sRelativePath.isEmpty() )
00974     {
00975       if (KBindingPropsPlugin::supports(properties->items()))
00976         kdWarning(250) << "Warning : editing a mimetype file out of the mimetype dirs!" << endl;
00977       // for Application desktop files, no problem : we can editing a .desktop file anywhere...
00978     } else
00979         while ( m_sRelativePath.at(0) == '/' ) m_sRelativePath.remove( 0, 1 );
00980 }
00981 
00982 void KFilePropsPlugin::slotFoundMountPoint( const QString&, unsigned long kBSize, unsigned long /*kBUsed*/, unsigned long kBAvail )
00983 {
00984     d->m_freeSpaceLabel->setText( i18n("Available space out of total partition size (percent used)", "%1/%2 (%3% used)")
00985                                .arg(KIO::convertSizeFromKB(kBAvail))
00986                                .arg(KIO::convertSizeFromKB(kBSize))
00987                                .arg( 100 - (int)(100.0 * kBAvail / kBSize) ));
00988 }
00989 
00990 // attention: copy&paste below, due to compiler bug
00991 // it doesn't like those unsigned long parameters -- unsigned long& are ok :-/
00992 void KFilePropsPlugin::slotFoundMountPoint( const unsigned long& kBSize, const unsigned long& /*kBUsed*/, const unsigned long& kBAvail, const QString& )
00993 {
00994     d->m_freeSpaceLabel->setText( i18n("Available space out of total partition size (percent used)", "%1/%2 (%3% used)")
00995                                .arg(KIO::convertSizeFromKB(kBAvail))
00996                                .arg(KIO::convertSizeFromKB(kBSize))
00997                                .arg( 100 - (int)(100.0 * kBAvail / kBSize) ));
00998 }
00999 
01000 void KFilePropsPlugin::slotDirSizeFinished( KIO::Job * job )
01001 {
01002   if (job->error())
01003     m_sizeLabel->setText( job->errorString() );
01004   else
01005   {
01006     KIO::filesize_t totalSize = static_cast<KDirSize*>(job)->totalSize();
01007     m_sizeLabel->setText( QString::fromLatin1("%1 (%2)").arg(KIO::convertSize(totalSize)).arg(KGlobal::locale()->formatNumber(totalSize, 0)) );
01008   }
01009   m_sizeStopButton->setEnabled(false);
01010   // just in case you change something and try again :)
01011   m_sizeDetermineButton->setText( i18n("Refresh") );
01012   m_sizeDetermineButton->setEnabled(true);
01013   d->dirSizeJob = 0L;
01014 }
01015 
01016 void KFilePropsPlugin::slotSizeDetermine()
01017 {
01018   m_sizeLabel->setText( i18n("Calculating...") );
01019   kdDebug(250) << " KFilePropsPlugin::slotSizeDetermine() properties->item()=" <<  properties->item() << endl;
01020   kdDebug(250) << " URL=" << properties->item()->url().url() << endl;
01021   d->dirSizeJob = KDirSize::dirSizeJob( properties->items() );
01022   connect( d->dirSizeJob, SIGNAL( result( KIO::Job * ) ),
01023            SLOT( slotDirSizeFinished( KIO::Job * ) ) );
01024   m_sizeStopButton->setEnabled(true);
01025   m_sizeDetermineButton->setEnabled(false);
01026 }
01027 
01028 void KFilePropsPlugin::slotSizeStop()
01029 {
01030   if ( d->dirSizeJob )
01031   {
01032     m_sizeLabel->setText( i18n("Stopped") );
01033     d->dirSizeJob->kill();
01034     d->dirSizeJob = 0;
01035   }
01036   m_sizeStopButton->setEnabled(false);
01037   m_sizeDetermineButton->setEnabled(true);
01038 }
01039 
01040 KFilePropsPlugin::~KFilePropsPlugin()
01041 {
01042   delete d;
01043 }
01044 
01045 bool KFilePropsPlugin::supports( KFileItemList /*_items*/ )
01046 {
01047   return true;
01048 }
01049 
01050 // Don't do this at home
01051 void qt_enter_modal( QWidget *widget );
01052 void qt_leave_modal( QWidget *widget );
01053 
01054 void KFilePropsPlugin::applyChanges()
01055 {
01056   if ( d->dirSizeJob )
01057     slotSizeStop();
01058 
01059   kdDebug(250) << "KFilePropsPlugin::applyChanges" << endl;
01060 
01061   if (nameArea->inherits("QLineEdit"))
01062   {
01063     QString n = KIO::encodeFileName(((QLineEdit *) nameArea)->text());
01064     // Remove trailing spaces (#4345)
01065     while ( n[n.length()-1].isSpace() )
01066       n.truncate( n.length() - 1 );
01067     if ( n.isEmpty() )
01068     {
01069       KMessageBox::sorry( properties, i18n("The new file name is empty!"));
01070       properties->abortApplying();
01071       return;
01072     }
01073 
01074     // Do we need to rename the file ?
01075     kdDebug(250) << "oldname = " << oldName << endl;
01076     kdDebug(250) << "newname = " << n << endl;
01077     if ( oldName != n || m_bFromTemplate ) { // true for any from-template file
01078       KIO::Job * job = 0L;
01079       KURL oldurl = properties->kurl();
01080       // Tell properties. Warning, this changes the result of properties->kurl() !
01081       properties->rename( n );
01082 
01083       // Update also relative path (for apps and mimetypes)
01084       if ( !m_sRelativePath.isEmpty() )
01085         determineRelativePath( properties->kurl().path() );
01086 
01087       kdDebug(250) << "New URL = " << properties->kurl().url() << endl;
01088       kdDebug(250) << "old = " << oldurl.url() << endl;
01089 
01090       // Don't remove the template !!
01091       if ( !m_bFromTemplate ) // (normal renaming)
01092         job = KIO::move( oldurl, properties->kurl() );
01093       else // Copying a template
01094         job = KIO::copy( oldurl, properties->kurl() );
01095 
01096       connect( job, SIGNAL( result( KIO::Job * ) ),
01097                SLOT( slotCopyFinished( KIO::Job * ) ) );
01098       connect( job, SIGNAL( renamed( KIO::Job *, const KURL &, const KURL & ) ),
01099                SLOT( slotFileRenamed( KIO::Job *, const KURL &, const KURL & ) ) );
01100       // wait for job
01101       QWidget dummy(0,0,WType_Dialog|WShowModal);
01102       qt_enter_modal(&dummy);
01103       qApp->enter_loop();
01104       qt_leave_modal(&dummy);
01105       return;
01106     }
01107   }
01108 
01109   // No job, keep going
01110   slotCopyFinished( 0L );
01111 }
01112 
01113 void KFilePropsPlugin::slotCopyFinished( KIO::Job * job )
01114 {
01115   kdDebug(250) << "KFilePropsPlugin::slotCopyFinished" << endl;
01116   if (job)
01117   {
01118     // allow apply() to return
01119     qApp->exit_loop();
01120     if ( job->error() )
01121     {
01122         job->showErrorDialog( d->m_frame );
01123         // Didn't work. Revert the URL to the old one
01124         properties->updateUrl( static_cast<KIO::CopyJob*>(job)->srcURLs().first() );
01125         properties->abortApplying(); // Don't apply the changes to the wrong file !
01126         return;
01127     }
01128   }
01129 
01130   assert( properties->item() );
01131   assert( !properties->item()->url().isEmpty() );
01132 
01133   // Save the file where we can -> usually in ~/.kde/...
01134   if (KBindingPropsPlugin::supports(properties->items()) && !m_sRelativePath.isEmpty())
01135   {
01136     KURL newURL;
01137     newURL.setPath( locateLocal("mime", m_sRelativePath) );
01138     properties->updateUrl( newURL );
01139   }
01140   else if (KExecPropsPlugin::supports(properties->items()) && !m_sRelativePath.isEmpty())
01141   {
01142     kdDebug(250) << "KFilePropsPlugin::slotCopyFinished " << m_sRelativePath << endl;
01143     KURL newURL;
01144     newURL.setPath( locateLocal("apps", m_sRelativePath) );
01145     kdDebug(250) << "KFilePropsPlugin::slotCopyFinished path=" << newURL.path() << endl;
01146     properties->updateUrl( newURL );
01147   }
01148 
01149   // handle icon changes - only local files for now
01150   // TODO: Use KTempFile and KIO::file_copy with resume = true
01151   if (!iconArea->isA("QLabel") && properties->kurl().isLocalFile()) {
01152     KIconButton *iconButton = (KIconButton *) iconArea;
01153     QString path;
01154 
01155     if (S_ISDIR(properties->item()->mode()))
01156     {
01157       path = properties->kurl().path(1) + QString::fromLatin1(".directory");
01158       // don't call updateUrl because the other tabs (i.e. permissions)
01159       // apply to the directory, not the .directory file.
01160     }
01161     else
01162       path = properties->kurl().path();
01163 
01164     // Get the default image
01165     QString str = KMimeType::findByURL( properties->kurl(),
01166                                         properties->item()->mode(),
01167                                         true )->KServiceType::icon();
01168     // Is it another one than the default ?
01169     QString sIcon;
01170     if ( str != iconButton->icon() )
01171       sIcon = iconButton->icon();
01172     // (otherwise write empty value)
01173 
01174     kdDebug(250) << "**" << path << "**" << endl;
01175     QFile f( path );
01176 
01177     // If default icon and no .directory file -> don't create one
01178     if ( !sIcon.isEmpty() || f.exists() )
01179     {
01180         if ( !f.open( IO_ReadWrite ) ) {
01181           KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient access to write to <b>%1</b>.</qt>").arg(path));
01182           return;
01183         }
01184         f.close();
01185 
01186         KDesktopFile cfg(path);
01187         kdDebug(250) << "sIcon = " << (sIcon) << endl;
01188         kdDebug(250) << "str = " << (str) << endl;
01189         cfg.writeEntry( QString::fromLatin1("Icon"), sIcon );
01190         cfg.sync();
01191     }
01192   }
01193 }
01194 
01195 void KFilePropsPlugin::slotFileRenamed( KIO::Job *, const KURL &, const KURL & newUrl )
01196 {
01197   // This is called in case of an existing local file during the copy/move operation,
01198   // if the user chooses Rename.
01199   properties->updateUrl( newUrl );
01200 }
01201 
01202 void KFilePropsPlugin::postApplyChanges()
01203 {
01204   KURL::List lst;
01205   KFileItemList items = properties->items();
01206   for ( KFileItemListIterator it( items ); it.current(); ++it )
01207     lst.append((*it)->url());
01208   KDirNotify_stub allDirNotify("*", "KDirNotify*");
01209   allDirNotify.FilesChanged( lst );
01210 }
01211 
01212 class KFilePermissionsPropsPlugin::KFilePermissionsPropsPluginPrivate
01213 {
01214 public:
01215   KFilePermissionsPropsPluginPrivate()
01216   {
01217   }
01218   ~KFilePermissionsPropsPluginPrivate()
01219   {
01220   }
01221 
01222   QFrame *m_frame;
01223   QCheckBox *cbRecursive;
01224   mode_t partialPermissions;
01225 };
01226 
01227 KFilePermissionsPropsPlugin::KFilePermissionsPropsPlugin( KPropertiesDialog *_props )
01228   : KPropsDlgPlugin( _props )
01229 {
01230   d = new KFilePermissionsPropsPluginPrivate;
01231   d->cbRecursive = 0L;
01232   grpCombo = 0L; grpEdit = 0;
01233   usrEdit = 0L;
01234   QString path = properties->kurl().path(-1);
01235   QString fname = properties->kurl().fileName();
01236   bool isLocal = properties->kurl().isLocalFile();
01237 
01238   bool IamRoot = (geteuid() == 0);
01239 
01240   KFileItem * item = properties->item();
01241   bool isLink = item->isLink();
01242   bool isDir = item->isDir(); // all dirs
01243   bool hasDir = item->isDir(); // at least one dir
01244   permissions = item->permissions(); // common permissions to all files
01245   d->partialPermissions = permissions; // permissions that only some files have (at first we take everything)
01246   strOwner = item->user();
01247   strGroup = item->group();
01248 
01249   if ( properties->items().count() > 1 )
01250   {
01251     // Multiple items: see what they have in common
01252     KFileItemList items = properties->items();
01253     KFileItemListIterator it( items );
01254     for ( ++it /*no need to check the first one again*/ ; it.current(); ++it )
01255     {
01256       if ( (*it)->isLink() != isLink )
01257         isLink = false;
01258       if ( (*it)->isDir() != isDir )
01259         isDir = false;
01260       hasDir |= (*it)->isDir();
01261       if ( (*it)->permissions() != permissions )
01262       {
01263         permissions &= (*it)->permissions();
01264         d->partialPermissions |= (*it)->permissions();
01265       }
01266       if ( (*it)->user() != strOwner )
01267         strOwner = QString::null;
01268       if ( (*it)->group() != strGroup )
01269         strGroup = QString::null;
01270     }
01271   }
01272 
01273   // keep only what's not in the common permissions
01274   d->partialPermissions = d->partialPermissions & ~permissions;
01275 
01276   bool isMyFile = false;
01277 
01278   if (isLocal && !strOwner.isEmpty()) { // local files, and all owned by the same person
01279     struct passwd *myself = getpwuid( geteuid() );
01280     if ( myself != 0L )
01281     {
01282       isMyFile = (strOwner == QString::fromLocal8Bit(myself->pw_name));
01283     } else
01284       kdWarning() << "I don't exist ?! geteuid=" << geteuid() << endl;
01285   } else {
01286     //We don't know, for remote files, if they are ours or not.
01287     //So we let the user change permissions, and
01288     //KIO::chmod will tell, if he had no right to do it.
01289     isMyFile = true;
01290   }
01291 
01292   d->m_frame = properties->dialog()->addPage(i18n("&Permissions"));
01293 
01294   QBoxLayout *box = new QVBoxLayout( d->m_frame, KDialog::spacingHint() );
01295 
01296   QLabel *l, *cl[3];
01297   QGroupBox *gb;
01298   QGridLayout *gl;
01299 
01300   /* Group: Access Permissions */
01301   gb = new QGroupBox ( i18n("Access Permissions"), d->m_frame );
01302   box->addWidget (gb);
01303 
01304   gl = new QGridLayout (gb, 6, 6, 15);
01305   gl->addRowSpacing(0, 10);
01306 
01307   l = new QLabel(i18n("Class"), gb);
01308   gl->addWidget(l, 1, 0);
01309 
01310   if (isDir)
01311     l = new QLabel( i18n("Show\nEntries"), gb );
01312   else
01313     l = new QLabel( i18n("Read"), gb );
01314   gl->addWidget (l, 1, 1);
01315 
01316   if (isDir)
01317     l = new QLabel( i18n("Write\nEntries"), gb );
01318   else
01319     l = new QLabel( i18n("Write"), gb );
01320   gl->addWidget (l, 1, 2);
01321 
01322   if (isDir)
01323     l = new QLabel( i18n("Enter directory", "Enter"), gb );
01324   else
01325     l = new QLabel( i18n("Exec"), gb );
01326   // GJ: Add space between normal and special modes
01327   QSize size = l->sizeHint();
01328   size.setWidth(size.width() + 15);
01329   l->setFixedSize(size);
01330   gl->addWidget (l, 1, 3);
01331 
01332   l = new QLabel( i18n("Special"), gb );
01333   gl->addMultiCellWidget(l, 1, 1, 4, 5);
01334 
01335   cl[0] = new QLabel( i18n("User"), gb );
01336   gl->addWidget (cl[0], 2, 0);
01337 
01338   cl[1] = new QLabel( i18n("Group"), gb );
01339   gl->addWidget (cl[1], 3, 0);
01340 
01341   cl[2] = new QLabel( i18n("Others"), gb );
01342   gl->addWidget (cl[2], 4, 0);
01343 
01344   l = new QLabel(i18n("Set UID"), gb);
01345   gl->addWidget(l, 2, 5);
01346 
01347   l = new QLabel(i18n("Set GID"), gb);
01348   gl->addWidget(l, 3, 5);
01349 
01350   l = new QLabel(i18n("File permission, sets user or group ID on execution", "Sticky"), gb);
01351   gl->addWidget(l, 4, 5);
01352 
01353   bool enablePage = (isMyFile || IamRoot) && (!isLink);
01354   /* Draw Checkboxes */
01355   for (int row = 0; row < 3 ; ++row) {
01356     for (int col = 0; col < 4; ++col) {
01357       QCheckBox *cb = new QCheckBox(gb);
01358       cb->setChecked(permissions & fperm[row][col]);
01359       if ( d->partialPermissions & fperm[row][col] )
01360       {
01361         cb->setTristate( true );
01362         cb->setNoChange();
01363       }
01364       cb->setEnabled( enablePage );
01365       permBox[row][col] = cb;
01366       gl->addWidget (permBox[row][col], row+2, col+1);
01367       connect( cb, SIGNAL( clicked() ),
01368                this, SIGNAL( changed() ) );
01369     }
01370   }
01371   gl->setColStretch(6, 10);
01372   gb->setEnabled( enablePage );
01373 
01374   /**** Group: Ownership ****/
01375   gb = new QGroupBox ( i18n("Ownership"), d->m_frame );
01376   box->addWidget (gb);
01377 
01378   gl = new QGridLayout (gb, 4, 3, 15);
01379   gl->addRowSpacing(0, 10);
01380 
01381   /*** Set Owner ***/
01382   l = new QLabel( i18n("User:"), gb );
01383   gl->addWidget (l, 1, 0);
01384 
01385   /* GJ: Don't autocomplete more than 1000 users. This is a kind of random
01386    * value. Huge sites having 10.000+ user have a fair chance of using NIS,
01387    * (possibly) making this unacceptably slow.
01388    * OTOH, it is nice to offer this functionality for the standard user.
01389    */
01390   int i, maxEntries = 1000;
01391   struct passwd *user;
01392   struct group *ge;
01393 
01394   /* File owner: For root, offer a KLineEdit with autocompletion.
01395    * For a user, who can never chown() a file, offer a QLabel.
01396    */
01397   if (IamRoot && isLocal)
01398   {
01399     usrEdit = new KLineEdit( gb );
01400     KCompletion *kcom = usrEdit->completionObject();
01401     kcom->setOrder(KCompletion::Sorted);
01402     setpwent();
01403     for (i=0; ((user = getpwent()) != 0L) && (i < maxEntries); i++)
01404       kcom->addItem(QString::fromLatin1(user->pw_name));
01405     endpwent();
01406     usrEdit->setCompletionMode((i < maxEntries) ? KGlobalSettings::CompletionAuto :
01407                                KGlobalSettings::CompletionNone);
01408     usrEdit->setText(strOwner);
01409     gl->addWidget(usrEdit, 1, 1);
01410     connect( usrEdit, SIGNAL( textChanged( const QString & ) ),
01411              this, SIGNAL( changed() ) );
01412   }
01413   else
01414   {
01415     l = new QLabel(strOwner, gb);
01416     gl->addWidget(l, 1, 1);
01417   }
01418 
01419   /*** Set Group ***/
01420 
01421   QStringList groupList;
01422   QCString strUser;
01423   user = getpwuid(geteuid());
01424   if (user != 0L)
01425     strUser = user->pw_name;
01426 
01427   setgrent();
01428   for (i=0; ((ge = getgrent()) != 0L) && (i < maxEntries); i++)
01429   {
01430     if (IamRoot)
01431       groupList += QString::fromLatin1(ge->gr_name);
01432     else
01433     {
01434       /* pick the groups to which the user belongs */
01435       char ** members = ge->gr_mem;
01436       char * member;
01437       while ((member = *members) != 0L) {
01438         if (strUser == member) {
01439           groupList += QString::fromLocal8Bit(ge->gr_name);
01440           break;
01441         }
01442         ++members;
01443       }
01444     }
01445   }
01446   endgrent();
01447 
01448   /* add the effective Group to the list .. */
01449   ge = getgrgid (getegid());
01450   if (ge) {
01451     QString name = QString::fromLatin1(ge->gr_name);
01452     if (name.isEmpty())
01453       name.setNum(ge->gr_gid);
01454     if (groupList.find(name) == groupList.end())
01455       groupList += name;
01456   }
01457 
01458   bool isMyGroup = groupList.contains(strGroup);
01459 
01460   /* add the group the file currently belongs to ..
01461    * .. if its not there already
01462    */
01463   if (!isMyGroup)
01464     groupList += strGroup;
01465 
01466   l = new QLabel( i18n("Group:"), gb );
01467   gl->addWidget (l, 2, 0);
01468 
01469   /* Set group: if possible to change:
01470    * - Offer a KLineEdit for root, since he can change to any group.
01471    * - Offer a QComboBox for a normal user, since he can change to a fixed
01472    *   (small) set of groups only.
01473    * If not changeable: offer a QLabel.
01474    */
01475   if (IamRoot && isLocal)
01476   {
01477     grpEdit = new KLineEdit(gb);
01478     KCompletion *kcom = new KCompletion;
01479     kcom->setItems(groupList);
01480     grpEdit->setCompletionObject(kcom, true);
01481     grpEdit->setAutoDeleteCompletionObject( true );
01482     grpEdit->setCompletionMode(KGlobalSettings::CompletionAuto);
01483     grpEdit->setText(strGroup);
01484     gl->addWidget(grpEdit, 2, 1);
01485     connect( grpEdit, SIGNAL( textChanged( const QString & ) ),
01486              this, SIGNAL( changed() ) );
01487   }
01488   else if ((groupList.count() > 1) && isMyFile && isLocal)
01489   {
01490     grpCombo = new QComboBox(gb, "combogrouplist");
01491     grpCombo->insertStringList(groupList);
01492     grpCombo->setCurrentItem(groupList.findIndex(strGroup));
01493     gl->addWidget(grpCombo, 2, 1);
01494     connect( grpCombo, SIGNAL( activated( int ) ),
01495              this, SIGNAL( changed() ) );
01496   }
01497   else
01498   {
01499     l = new QLabel(strGroup, gb);
01500     gl->addWidget(l, 2, 1);
01501   }
01502 
01503   gl->setColStretch(2, 10);
01504 
01505   // "Apply recursive" checkbox
01506   if ( hasDir )
01507   {
01508       d->cbRecursive = new QCheckBox( i18n("Apply changes to all subdirectories and their contents"), d->m_frame );
01509       box->addWidget( d->cbRecursive );
01510       connect( d->cbRecursive, SIGNAL( clicked() ),
01511                this, SLOT( slotRecursiveClicked() ) );
01512   }
01513 
01514   box->addStretch (10);
01515 
01516   if (isMyFile)
01517     cl[0]->setText(i18n("<b>User</b>"));
01518   else if (isMyGroup)
01519     cl[1]->setText(i18n("<b>Group</b>"));
01520   else
01521     cl[2]->setText(i18n("<b>Others</b>"));
01522 }
01523 
01524 // QString KFilePermissionsPropsPlugin::tabName () const
01525 // {
01526 //   return i18n ("&Permissions");
01527 // }
01528 
01529 KFilePermissionsPropsPlugin::~KFilePermissionsPropsPlugin()
01530 {
01531   delete d;
01532 }
01533 
01534 bool KFilePermissionsPropsPlugin::supports( KFileItemList /*_items*/ )
01535 {
01536   return true;
01537 }
01538 
01539 void KFilePermissionsPropsPlugin::slotRecursiveClicked()
01540 {
01541   // If we want to apply permissions recursively, then we didn't
01542   // show up the right permissions to start with. Files in subdirs might
01543   // have other flags.... At least, let the user the possibility
01544   // to set any flag to "unchanged", so that he isn't forced to set +x
01545   // on all files !
01546   for (int row = 0;row < 3; ++row)
01547     for (int col = 0; col < 4; ++col)
01548       permBox[row][col]->setTristate();
01549 }
01550 
01551 void KFilePermissionsPropsPlugin::applyChanges()
01552 {
01553   mode_t newPermission = 0;
01554   mode_t newPartialPermission = 0;
01555   mode_t permissionMask = 0;
01556   for (int row = 0;row < 3; ++row)
01557     for (int col = 0; col < 4; ++col)
01558     {
01559       switch (permBox[row][col]->state())
01560       {
01561           case QCheckBox::On:
01562             newPermission |= fperm[row][col];
01563             //fall through
01564           case QCheckBox::Off:
01565             permissionMask |= fperm[row][col];
01566             break;
01567           default: // NoChange
01568             newPartialPermission |= fperm[ row ][ col ];
01569             break;
01570       }
01571     }
01572 
01573   QString owner, group;
01574   if (usrEdit)
01575     owner = usrEdit->text();
01576   if (grpEdit)
01577     group = grpEdit->text();
01578   else if (grpCombo)
01579     group = grpCombo->currentText();
01580 
01581   if (owner == strOwner)
01582       owner = QString::null; // no change
01583 
01584   if (group == strGroup)
01585       group = QString::null;
01586 
01587   kdDebug(250) << "old permissions : " << QString::number(permissions,8) << endl;
01588   kdDebug(250) << "new permissions : " << QString::number(newPermission,8) << endl;
01589   kdDebug(250) << "permissions mask : " << QString::number(permissionMask,8) << endl;
01590   kdDebug(250) << "url=" << properties->items().first()->url().url() << endl;
01591 
01592   if ( permissions != newPermission || d->partialPermissions != newPartialPermission
01593                   || !owner.isEmpty() || !group.isEmpty() )
01594   {
01595     KIO::Job * job = KIO::chmod( properties->items(), newPermission, permissionMask,
01596                                  owner, group,
01597                                  d->cbRecursive && d->cbRecursive->isChecked() );
01598     connect( job, SIGNAL( result( KIO::Job * ) ),
01599              SLOT( slotChmodResult( KIO::Job * ) ) );
01600     // Wait for job
01601     QWidget dummy(0,0,WType_Dialog|WShowModal);
01602     qt_enter_modal(&dummy);
01603     qApp->enter_loop();
01604     qt_leave_modal(&dummy);
01605   }
01606 }
01607 
01608 void KFilePermissionsPropsPlugin::slotChmodResult( KIO::Job * job )
01609 {
01610   kdDebug(250) << "KFilePermissionsPropsPlugin::slotChmodResult" << endl;
01611   if (job->error())
01612     job->showErrorDialog( d->m_frame );
01613   // allow apply() to return
01614   qApp->exit_loop();
01615 }
01616 
01617 class KExecPropsPlugin::KExecPropsPluginPrivate
01618 {
01619 public:
01620   KExecPropsPluginPrivate()
01621   {
01622   }
01623   ~KExecPropsPluginPrivate()
01624   {
01625   }
01626 
01627   QFrame *m_frame;
01628 };
01629 
01630 KExecPropsPlugin::KExecPropsPlugin( KPropertiesDialog *_props )
01631   : KPropsDlgPlugin( _props )
01632 {
01633   d = new KExecPropsPluginPrivate;
01634   d->m_frame = properties->dialog()->addPage(i18n("E&xecute"));
01635   QVBoxLayout * mainlayout = new QVBoxLayout( d->m_frame );
01636   mainlayout->setSpacing( KDialog::spacingHint() );
01637 
01638   // Now the widgets in the top layout
01639 
01640   QLabel* l;
01641   l = new QLabel( i18n( "Comman&d:" ), d->m_frame );
01642   mainlayout->addWidget(l);
01643 
01644   QHBoxLayout * hlayout;
01645   hlayout = new QHBoxLayout(KDialog::spacingHint());
01646   mainlayout->addLayout(hlayout);
01647 
01648   execEdit = new KLineEdit( d->m_frame );
01649   hlayout->addWidget(execEdit, 1);
01650 
01651   l->setBuddy( execEdit );
01652 
01653   execBrowse = new QPushButton( d->m_frame );
01654   execBrowse->setText( i18n("&Browse...") );
01655   hlayout->addWidget(execBrowse);
01656 
01657   // The groupbox about swallowing
01658   QGroupBox* tmpQGroupBox;
01659   tmpQGroupBox = new QGroupBox( i18n("Panel Embedding"), d->m_frame );
01660   tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
01661 
01662   mainlayout->addWidget(tmpQGroupBox);
01663 
01664   QGridLayout *grid = new QGridLayout(tmpQGroupBox->layout(), 2, 2);
01665   grid->setSpacing( KDialog::spacingHint() );
01666   grid->setColStretch(1, 1);
01667 
01668   l = new QLabel( i18n( "&Execute on click:" ), tmpQGroupBox );
01669   grid->addWidget(l, 0, 0);
01670 
01671   swallowExecEdit = new KLineEdit( tmpQGroupBox );
01672   grid->addWidget(swallowExecEdit, 0, 1);
01673 
01674   l->setBuddy( swallowExecEdit );
01675 
01676   l = new QLabel( i18n( "&Window title:" ), tmpQGroupBox );
01677   grid->addWidget(l, 1, 0);
01678 
01679   swallowTitleEdit = new KLineEdit( tmpQGroupBox );
01680   grid->addWidget(swallowTitleEdit, 1, 1);
01681 
01682   l->setBuddy( swallowTitleEdit );
01683 
01684   // The groupbox about run in terminal
01685 
01686   tmpQGroupBox = new QGroupBox( d->m_frame );
01687   tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
01688 
01689   mainlayout->addWidget(tmpQGroupBox);
01690 
01691   grid = new QGridLayout(tmpQGroupBox->layout(), 2, 2);
01692   grid->setSpacing( KDialog::spacingHint() );
01693   grid->setColStretch(1, 1);
01694 
01695   terminalCheck = new QCheckBox( tmpQGroupBox );
01696   terminalCheck->setText( i18n("&Run in terminal") );
01697   grid->addMultiCellWidget(terminalCheck, 0, 0, 0, 1);
01698 
01699   terminalLabel = new QLabel( i18n( "&Terminal options:" ), tmpQGroupBox );
01700   grid->addWidget(terminalLabel, 1, 0);
01701 
01702   terminalEdit = new KLineEdit( tmpQGroupBox );
01703   grid->addWidget(terminalEdit, 1, 1);
01704 
01705   terminalLabel->setBuddy( terminalEdit );
01706 
01707   // The groupbox about run with substituted uid.
01708 
01709   tmpQGroupBox = new QGroupBox( d->m_frame );
01710   tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
01711 
01712   mainlayout->addWidget(tmpQGroupBox);
01713 
01714   grid = new QGridLayout(tmpQGroupBox->layout(), 2, 2);
01715   grid->setSpacing(KDialog::spacingHint());
01716   grid->setColStretch(1, 1);
01717 
01718   suidCheck = new QCheckBox(tmpQGroupBox);
01719   suidCheck->setText(i18n("Ru&n as a different user"));
01720   grid->addMultiCellWidget(suidCheck, 0, 0, 0, 1);
01721 
01722   suidLabel = new QLabel(i18n( "&Username:" ), tmpQGroupBox);
01723   grid->addWidget(suidLabel, 1, 0);
01724 
01725   suidEdit = new KLineEdit(tmpQGroupBox);
01726   grid->addWidget(suidEdit, 1, 1);
01727 
01728   suidLabel->setBuddy( suidEdit );
01729 
01730   mainlayout->addStretch(1);
01731 
01732   // now populate the page
01733   QString path = _props->kurl().path();
01734   QFile f( path );
01735   if ( !f.open( IO_ReadOnly ) )
01736     return;
01737   f.close();
01738 
01739   KSimpleConfig config( path );
01740   config.setDollarExpansion( false );
01741   config.setDesktopGroup();
01742   execStr = config.readPathEntry( QString::fromLatin1("Exec") );
01743   swallowExecStr = config.readPathEntry( QString::fromLatin1("SwallowExec") );
01744   swallowTitleStr = config.readEntry( QString::fromLatin1("SwallowTitle") );
01745   termBool = config.readBoolEntry( QString::fromLatin1("Terminal") );
01746   termOptionsStr = config.readEntry( QString::fromLatin1("TerminalOptions") );
01747   suidBool = config.readBoolEntry( QString::fromLatin1("X-KDE-SubstituteUID") );
01748   suidUserStr = config.readEntry( QString::fromLatin1("X-KDE-Username") );
01749 
01750   if ( !swallowExecStr.isNull() )
01751     swallowExecEdit->setText( swallowExecStr );
01752   if ( !swallowTitleStr.isNull() )
01753     swallowTitleEdit->setText( swallowTitleStr );
01754 
01755   if ( !execStr.isNull() )
01756     execEdit->setText( execStr );
01757   if ( !termOptionsStr.isNull() )
01758     terminalEdit->setText( termOptionsStr );
01759 
01760   terminalCheck->setChecked( termBool );
01761   enableCheckedEdit();
01762 
01763   suidCheck->setChecked( suidBool );
01764   suidEdit->setText( suidUserStr );
01765   enableSuidEdit();
01766 
01767   // Provide username completion up to 1000 users.
01768   KCompletion *kcom = new KCompletion;
01769   kcom->setOrder(KCompletion::Sorted);
01770   struct passwd *pw;
01771   int i, maxEntries = 1000;
01772   setpwent();
01773   for (i=0; ((pw = getpwent()) != 0L) && (i < maxEntries); i++)
01774     kcom->addItem(QString::fromLatin1(pw->pw_name));
01775   endpwent();
01776   if (i < maxEntries)
01777   {
01778     suidEdit->setCompletionObject(kcom, true);
01779     suidEdit->setAutoDeleteCompletionObject( true );
01780     suidEdit->setCompletionMode(KGlobalSettings::CompletionAuto);
01781   }
01782   else
01783   {
01784     delete kcom;
01785   }
01786 
01787   connect( swallowExecEdit, SIGNAL( textChanged( const QString & ) ),
01788            this, SIGNAL( changed() ) );
01789   connect( swallowTitleEdit, SIGNAL( textChanged( const QString & ) ),
01790            this, SIGNAL( changed() ) );
01791   connect( execEdit, SIGNAL( textChanged( const QString & ) ),
01792            this, SIGNAL( changed() ) );
01793   connect( terminalEdit, SIGNAL( textChanged( const QString & ) ),
01794            this, SIGNAL( changed() ) );
01795   connect( terminalCheck, SIGNAL( toggled( bool ) ),
01796            this, SIGNAL( changed() ) );
01797   connect( suidCheck, SIGNAL( toggled( bool ) ),
01798            this, SIGNAL( changed() ) );
01799   connect( suidEdit, SIGNAL( textChanged( const QString & ) ),
01800            this, SIGNAL( changed() ) );
01801 
01802   connect( execBrowse, SIGNAL( clicked() ), this, SLOT( slotBrowseExec() ) );
01803   connect( terminalCheck, SIGNAL( clicked() ), this,  SLOT( enableCheckedEdit() ) );
01804   connect( suidCheck, SIGNAL( clicked() ), this,  SLOT( enableSuidEdit() ) );
01805 
01806 }
01807 
01808 KExecPropsPlugin::~KExecPropsPlugin()
01809 {
01810   delete d;
01811 }
01812 
01813 // QString KExecPropsPlugin::tabName () const
01814 // {
01815 //   return i18n ("E&xecute");
01816 // }
01817 
01818 void KExecPropsPlugin::enableCheckedEdit()
01819 {
01820   bool checked = terminalCheck->isChecked();
01821   terminalLabel->setEnabled( checked );
01822   terminalEdit->setEnabled( checked );
01823 }
01824 
01825 void KExecPropsPlugin::enableSuidEdit()
01826 {
01827   bool checked = suidCheck->isChecked();
01828   suidLabel->setEnabled( checked );
01829   suidEdit->setEnabled( checked );
01830 }
01831 
01832 bool KExecPropsPlugin::supports( KFileItemList _items )
01833 {
01834   if ( _items.count() != 1 )
01835     return false;
01836   KFileItem * item = _items.first();
01837   // check if desktop file
01838   if ( !KPropsDlgPlugin::isDesktopFile( item ) )
01839     return false;
01840   // open file and check type
01841   KDesktopFile config( item->url().path(), true /* readonly */ );
01842   return config.hasApplicationType() && kapp->authorize("run_desktop_files") && kapp->authorize("shell_access");
01843 }
01844 
01845 void KExecPropsPlugin::applyChanges()
01846 {
01847   kdDebug(250) << "KExecPropsPlugin::applyChanges" << endl;
01848   QString path = properties->kurl().path();
01849 
01850   QFile f( path );
01851 
01852   if ( !f.open( IO_ReadWrite ) ) {
01853     KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient access to write to <b>%1</b>.</qt>").arg(path));
01854     return;
01855   }
01856   f.close();
01857 
01858   KSimpleConfig config( path );
01859   config.setDesktopGroup();
01860   config.writeEntry( QString::fromLatin1("Type"), QString::fromLatin1("Application"));
01861   config.writeEntry( QString::fromLatin1("Exec"), execEdit->text() );
01862   config.writeEntry( QString::fromLatin1("SwallowExec"), swallowExecEdit->text() );
01863   config.writeEntry( QString::fromLatin1("SwallowTitle"), swallowTitleEdit->text() );
01864   config.writeEntry( QString::fromLatin1("Terminal"), terminalCheck->isChecked() );
01865   config.writeEntry( QString::fromLatin1("TerminalOptions"), terminalEdit->text() );
01866   config.writeEntry( QString::fromLatin1("X-KDE-SubstituteUID"), suidCheck->isChecked() );
01867   config.writeEntry( QString::fromLatin1("X-KDE-Username"), suidEdit->text() );
01868 }
01869 
01870 
01871 void KExecPropsPlugin::slotBrowseExec()
01872 {
01873     KURL f = KFileDialog::getOpenURL( QString::null,
01874                                       QString::null, d->m_frame );
01875     if ( f.isEmpty() )
01876         return;
01877 
01878     if ( !f.isLocalFile()) {
01879         KMessageBox::sorry(d->m_frame, i18n("Only executables on local file systems are supported."));
01880         return;
01881     }
01882 
01883     QString path = f.path();
01884     KRun::shellQuote( path );
01885     execEdit->setText( path );
01886 }
01887 
01888 class KURLPropsPlugin::KURLPropsPluginPrivate
01889 {
01890 public:
01891   KURLPropsPluginPrivate()
01892   {
01893   }
01894   ~KURLPropsPluginPrivate()
01895   {
01896   }
01897 
01898   QFrame *m_frame;
01899 };
01900 
01901 KURLPropsPlugin::KURLPropsPlugin( KPropertiesDialog *_props )
01902   : KPropsDlgPlugin( _props )
01903 {
01904   d = new KURLPropsPluginPrivate;
01905   d->m_frame = properties->dialog()->addPage(i18n("U&RL"));
01906   QVBoxLayout * layout = new QVBoxLayout(d->m_frame, KDialog::spacingHint());
01907 
01908   QLabel *l;
01909   l = new QLabel( d->m_frame, "Label_1" );
01910   l->setText( i18n("URL:") );
01911   layout->addWidget(l);
01912 
01913   URLEdit = new KURLRequester( d->m_frame, "URL Requester" );
01914   layout->addWidget(URLEdit);
01915 
01916   QString path = properties->kurl().path();
01917 
01918   QFile f( path );
01919   if ( !f.open( IO_ReadOnly ) )
01920     return;
01921   f.close();
01922 
01923   KSimpleConfig config( path );
01924   config.setDesktopGroup();
01925   URLStr = config.readPathEntry( QString::fromLatin1("URL") );
01926 
01927   if ( !URLStr.isNull() )
01928     URLEdit->setURL( URLStr );
01929 
01930   connect( URLEdit, SIGNAL( textChanged( const QString & ) ),
01931            this, SIGNAL( changed() ) );
01932 
01933   layout->addStretch (1);
01934 }
01935 
01936 KURLPropsPlugin::~KURLPropsPlugin()
01937 {
01938   delete d;
01939 }
01940 
01941 // QString KURLPropsPlugin::tabName () const
01942 // {
01943 //   return i18n ("U&RL");
01944 // }
01945 
01946 bool KURLPropsPlugin::supports( KFileItemList _items )
01947 {
01948   if ( _items.count() != 1 )
01949     return false;
01950   KFileItem * item = _items.first();
01951   // check if desktop file
01952   if ( !KPropsDlgPlugin::isDesktopFile( item ) )
01953     return false;
01954 
01955   // open file and check type
01956   KDesktopFile config( item->url().path(), true /* readonly */ );
01957   return config.hasLinkType();
01958 }
01959 
01960 void KURLPropsPlugin::applyChanges()
01961 {
01962   QString path = properties->kurl().path();
01963 
01964   QFile f( path );
01965   if ( !f.open( IO_ReadWrite ) ) {
01966     KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient access to write to <b>%1</b>.</qt>").arg(path));
01967     return;
01968   }
01969   f.close();
01970 
01971   KSimpleConfig config( path );
01972   config.setDesktopGroup();
01973   config.writeEntry( QString::fromLatin1("Type"), QString::fromLatin1("Link"));
01974   config.writeEntry( QString::fromLatin1("URL"), URLEdit->url() );
01975   // Users can't create a Link .desktop file with a Name field,
01976   // but distributions can. Update the Name field in that case.
01977   if ( config.hasKey("Name") )
01978   {
01979     // ### duplicated from KApplicationPropsPlugin
01980     QString nameStr = properties->kurl().fileName();
01981     if ( nameStr.right(8) == QString::fromLatin1(".desktop") )
01982       nameStr.truncate( nameStr.length() - 8 );
01983     if ( nameStr.right(7) == QString::fromLatin1(".kdelnk") )
01984       nameStr.truncate( nameStr.length() - 7 );
01985     config.writeEntry( QString::fromLatin1("Name"), nameStr );
01986         config.writeEntry( QString::fromLatin1("Name"), nameStr, true, false, true );
01987   }
01988 }
01989 
01990 /* ----------------------------------------------------
01991  *
01992  * KApplicationPropsPlugin
01993  *
01994  * -------------------------------------------------- */
01995 
01996 class KApplicationPropsPlugin::KApplicationPropsPluginPrivate
01997 {
01998 public:
01999   KApplicationPropsPluginPrivate()
02000   {
02001       m_kdesktopMode = QCString(qApp->name()) == "kdesktop"; // nasty heh?
02002   }
02003   ~KApplicationPropsPluginPrivate()
02004   {
02005   }
02006 
02007   QFrame *m_frame;
02008   bool m_kdesktopMode;
02009 };
02010 
02011 KApplicationPropsPlugin::KApplicationPropsPlugin( KPropertiesDialog *_props )
02012   : KPropsDlgPlugin( _props )
02013 {
02014   d = new KApplicationPropsPluginPrivate;
02015   d->m_frame = properties->dialog()->addPage(i18n("&Application"));
02016   QVBoxLayout *toplayout = new QVBoxLayout( d->m_frame, KDialog::spacingHint());
02017 
02018   QIconSet iconSet;
02019   QPixmap pixMap;
02020 
02021   addExtensionButton = new QPushButton( QString::null, d->m_frame );
02022   iconSet = SmallIconSet( "back" );
02023   addExtensionButton->setIconSet( iconSet );
02024   pixMap = iconSet.pixmap( QIconSet::Small, QIconSet::Normal );
02025   addExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
02026   connect( addExtensionButton, SIGNAL( clicked() ),
02027             SLOT( slotAddExtension() ) );
02028 
02029   delExtensionButton = new QPushButton( QString::null, d->m_frame );
02030   iconSet = SmallIconSet( "forward" );
02031   delExtensionButton->setIconSet( iconSet );
02032   delExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
02033   connect( delExtensionButton, SIGNAL( clicked() ),
02034             SLOT( slotDelExtension() ) );
02035 
02036   QLabel *l;
02037 
02038   QGridLayout *grid = new QGridLayout(2, 2);
02039   grid->setColStretch(1, 1);
02040   toplayout->addLayout(grid);
02041 
02042   if ( d->m_kdesktopMode )
02043   {
02044       // in kdesktop the name field comes from the first tab
02045       nameEdit = 0L;
02046   }
02047   else
02048   {
02049       l = new QLabel(i18n("Name:"), d->m_frame, "Label_4" );
02050       grid->addWidget(l, 0, 0);
02051 
02052       nameEdit = new KLineEdit( d->m_frame, "LineEdit_3" );
02053       grid->addWidget(nameEdit, 0, 1);
02054   }
02055 
02056   l = new QLabel(i18n("Description:"),  d->m_frame, "Label_5" );
02057   grid->addWidget(l, 1, 0);
02058 
02059   genNameEdit = new KLineEdit( d->m_frame, "LineEdit_4" );
02060   grid->addWidget(genNameEdit, 1, 1);
02061 
02062   l = new QLabel(i18n("Comment:"),  d->m_frame, "Label_3" );
02063   grid->addWidget(l, 2, 0);
02064 
02065   commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" );
02066   grid->addWidget(commentEdit, 2, 1);
02067 
02068   l = new QLabel(i18n("File types:"), d->m_frame);
02069   toplayout->addWidget(l, 0, AlignLeft);
02070 
02071   grid = new QGridLayout(4, 3);
02072   grid->setColStretch(0, 1);
02073   grid->setColStretch(2, 1);
02074   grid->setRowStretch( 0, 1 );
02075   grid->setRowStretch( 3, 1 );
02076   toplayout->addLayout(grid, 2);
02077 
02078   extensionsList = new QListBox( d->m_frame );
02079   extensionsList->setSelectionMode( QListBox::Extended );
02080   grid->addMultiCellWidget(extensionsList, 0, 3, 0, 0);
02081 
02082   grid->addWidget(addExtensionButton, 1, 1);
02083   grid->addWidget(delExtensionButton, 2, 1);
02084 
02085   availableExtensionsList = new QListBox( d->m_frame );
02086   availableExtensionsList->setSelectionMode( QListBox::Extended );
02087   grid->addMultiCellWidget(availableExtensionsList, 0, 3, 2, 2);
02088 
02089   QString path = properties->kurl().path() ;
02090   QFile f( path );
02091   if ( !f.open( IO_ReadOnly ) )
02092     return;
02093   f.close();
02094 
02095   KSimpleConfig config( path );
02096   config.setDesktopGroup();
02097   QString commentStr = config.readEntry( QString::fromLatin1("Comment") );
02098   QString genNameStr = config.readEntry( QString::fromLatin1("GenericName") );
02099 
02100   QStringList selectedTypes = config.readListEntry( "ServiceTypes" );
02101   // For compatibility with KDE 1.x
02102   selectedTypes += config.readListEntry( "MimeType", ';' );
02103 
02104   QString nameStr = config.readEntry( QString::fromLatin1("Name") );
02105   if ( nameStr.isEmpty() || d->m_kdesktopMode ) {
02106     // We'll use the file name if no name is specified
02107     // because we _need_ a Name for a valid file.
02108     // But let's do it in apply, not here, so that we pick up the right name.
02109     setDirty();
02110   }
02111 
02112   commentEdit->setText( commentStr );
02113   genNameEdit->setText( genNameStr );
02114   if ( nameEdit )
02115       nameEdit->setText( nameStr );
02116 
02117   selectedTypes.sort();
02118   QStringList::Iterator sit = selectedTypes.begin();
02119   for( ; sit != selectedTypes.end(); ++sit ) {
02120     if ( !((*sit).isEmpty()) )
02121       extensionsList->insertItem( *sit );
02122   }
02123 
02124   KMimeType::List mimeTypes = KMimeType::allMimeTypes();
02125   QValueListIterator<KMimeType::Ptr> it2 = mimeTypes.begin();
02126   for ( ; it2 != mimeTypes.end(); ++it2 )
02127     addMimeType ( (*it2)->name() );
02128 
02129   updateButton();
02130 
02131   connect( extensionsList, SIGNAL( highlighted( int ) ),
02132            this, SLOT( updateButton() ) );
02133   connect( availableExtensionsList, SIGNAL( highlighted( int ) ),
02134            this, SLOT( updateButton() ) );
02135 
02136   connect( addExtensionButton, SIGNAL( clicked() ),
02137            this, SIGNAL( changed() ) );
02138   connect( delExtensionButton, SIGNAL( clicked() ),
02139            this, SIGNAL( changed() ) );
02140   if ( nameEdit )
02141       connect( nameEdit, SIGNAL( textChanged( const QString & ) ),
02142                this, SIGNAL( changed() ) );
02143   connect( commentEdit, SIGNAL( textChanged( const QString & ) ),
02144            this, SIGNAL( changed() ) );
02145   connect( genNameEdit, SIGNAL( textChanged( const QString & ) ),
02146            this, SIGNAL( changed() ) );
02147   connect( availableExtensionsList, SIGNAL( selected( int ) ),
02148            this, SIGNAL( changed() ) );
02149   connect( extensionsList, SIGNAL( selected( int ) ),
02150            this, SIGNAL( changed() ) );
02151 }
02152 
02153 KApplicationPropsPlugin::~KApplicationPropsPlugin()
02154 {
02155   delete d;
02156 }
02157 
02158 // QString KApplicationPropsPlugin::tabName () const
02159 // {
02160 //   return i18n ("&Application");
02161 // }
02162 
02163 void KApplicationPropsPlugin::updateButton()
02164 {
02165     addExtensionButton->setEnabled(availableExtensionsList->currentItem()>-1);
02166     delExtensionButton->setEnabled(extensionsList->currentItem()>-1);
02167 }
02168 
02169 void KApplicationPropsPlugin::addMimeType( const QString & name )
02170 {
02171   // Add a mimetype to the list of available mime types if not in the extensionsList
02172 
02173   bool insert = true;
02174 
02175   for ( uint i = 0; i < extensionsList->count(); i++ )
02176     if ( extensionsList->text( i ) == name )
02177       insert = false;
02178 
02179   if ( insert )
02180   {
02181     availableExtensionsList->insertItem( name );
02182     availableExtensionsList->sort();
02183   }
02184 }
02185 
02186 bool KApplicationPropsPlugin::supports( KFileItemList _items )
02187 {
02188   // same constraints as KExecPropsPlugin : desktop file with Type = Application
02189   return KExecPropsPlugin::supports( _items );
02190 }
02191 
02192 void KApplicationPropsPlugin::applyChanges()
02193 {
02194   QString path = properties->kurl().path();
02195 
02196   QFile f( path );
02197 
02198   if ( !f.open( IO_ReadWrite ) ) {
02199     KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient access to write to <b>%1</b>.</qt>").arg(path));
02200     return;
02201   }
02202   f.close();
02203 
02204   KSimpleConfig config( path );
02205   config.setDesktopGroup();
02206   config.writeEntry( QString::fromLatin1("Type"), QString::fromLatin1("Application"));
02207   config.writeEntry( QString::fromLatin1("Comment"), commentEdit->text() );
02208   config.writeEntry( QString::fromLatin1("Comment"), commentEdit->text(), true, false, true ); // for compat
02209   config.writeEntry( QString::fromLatin1("GenericName"), genNameEdit->text() );
02210   config.writeEntry( QString::fromLatin1("GenericName"), genNameEdit->text(), true, false, true ); // for compat
02211 
02212   QStringList selectedTypes;
02213   for ( uint i = 0; i < extensionsList->count(); i++ )
02214     selectedTypes.append( extensionsList->text( i ) );
02215 
02216   config.writeEntry( QString::fromLatin1("MimeType"), selectedTypes, ';' );
02217   config.writeEntry( QString::fromLatin1("ServiceTypes"), "" );
02218   // hmm, actually it should probably be the contrary (but see also typeslistitem.cpp)
02219 
02220   QString nameStr = nameEdit ? nameEdit->text() : QString::null;
02221   if ( nameStr.isEmpty() ) // nothing entered, or widget not existing at all (kdesktop mode)
02222   {
02223     nameStr = properties->kurl().fileName();
02224     if ( nameStr.right(8) == QString::fromLatin1(".desktop") )
02225       nameStr.truncate( nameStr.length() - 8 );
02226     if ( nameStr.right(7) == QString::fromLatin1(".kdelnk") )
02227       nameStr.truncate( nameStr.length() - 7 );
02228   }
02229   config.writeEntry( QString::fromLatin1("Name"), nameStr );
02230   config.writeEntry( QString::fromLatin1("Name"), nameStr, true, false, true );
02231 
02232   config.sync();
02233   f.close();
02234 }
02235 
02236 void KApplicationPropsPlugin::slotAddExtension()
02237 {
02238   QListBoxItem *item = availableExtensionsList->firstItem();
02239   QListBoxItem *nextItem;
02240 
02241   while ( item )
02242   {
02243     nextItem = item->next();
02244 
02245     if ( item->isSelected() )
02246     {
02247       extensionsList->insertItem( item->text() );
02248       availableExtensionsList->removeItem( availableExtensionsList->index( item ) );
02249     }
02250 
02251     item = nextItem;
02252   }
02253 
02254   extensionsList->sort();
02255   updateButton();
02256 }
02257 
02258 void KApplicationPropsPlugin::slotDelExtension()
02259 {
02260   QListBoxItem *item = extensionsList->firstItem();
02261   QListBoxItem *nextItem;
02262 
02263   while ( item )
02264   {
02265     nextItem = item->next();
02266 
02267     if ( item->isSelected() )
02268     {
02269       availableExtensionsList->insertItem( item->text() );
02270       extensionsList->removeItem( extensionsList->index( item ) );
02271     }
02272 
02273     item = nextItem;
02274   }
02275 
02276   availableExtensionsList->sort();
02277   updateButton();
02278 }
02279 
02280 /* ----------------------------------------------------
02281  *
02282  * KBindingPropsPlugin
02283  *
02284  * -------------------------------------------------- */
02285 
02286 class KBindingPropsPlugin::KBindingPropsPluginPrivate
02287 {
02288 public:
02289   KBindingPropsPluginPrivate()
02290   {
02291   }
02292   ~KBindingPropsPluginPrivate()
02293   {
02294   }
02295 
02296   QFrame *m_frame;
02297 };
02298 
02299 KBindingPropsPlugin::KBindingPropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props )
02300 {
02301   d = new KBindingPropsPluginPrivate;
02302   d->m_frame = properties->dialog()->addPage(i18n("A&ssociation"));
02303   patternEdit = new KLineEdit( d->m_frame, "LineEdit_1" );
02304   commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" );
02305   mimeEdit = new KLineEdit( d->m_frame, "LineEdit_3" );
02306 
02307   QBoxLayout * mainlayout = new QVBoxLayout(d->m_frame, KDialog::spacingHint());
02308   QLabel* tmpQLabel;
02309 
02310   tmpQLabel = new QLabel( d->m_frame, "Label_1" );
02311   tmpQLabel->setText(  i18n("Pattern ( example: *.html;*.htm )") );
02312   tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
02313   mainlayout->addWidget(tmpQLabel, 1);
02314 
02315   //patternEdit->setGeometry( 10, 40, 210, 30 );
02316   //patternEdit->setText( "" );
02317   patternEdit->setMaxLength( 512 );
02318   patternEdit->setMinimumSize( patternEdit->sizeHint() );
02319   patternEdit->setFixedHeight( fontHeight );
02320   mainlayout->addWidget(patternEdit, 1);
02321 
02322   tmpQLabel = new QLabel( d->m_frame, "Label_2" );
02323   tmpQLabel->setText(  i18n("Mime Type") );
02324   tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
02325   mainlayout->addWidget(tmpQLabel, 1);
02326 
02327   //mimeEdit->setGeometry( 10, 160, 210, 30 );
02328   mimeEdit->setMaxLength( 256 );
02329   mimeEdit->setMinimumSize( mimeEdit->sizeHint() );
02330   mimeEdit->setFixedHeight( fontHeight );
02331   mainlayout->addWidget(mimeEdit, 1);
02332 
02333   tmpQLabel = new QLabel( d->m_frame, "Label_3" );
02334   tmpQLabel->setText(  i18n("Comment") );
02335   tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
02336   mainlayout->addWidget(tmpQLabel, 1);
02337 
02338   //commentEdit->setGeometry( 10, 100, 210, 30 );
02339   commentEdit->setMaxLength( 256 );
02340   commentEdit->setMinimumSize( commentEdit->sizeHint() );
02341   commentEdit->setFixedHeight( fontHeight );
02342   mainlayout->addWidget(commentEdit, 1);
02343 
02344   cbAutoEmbed = new QCheckBox( i18n("Left click previews"), d->m_frame, "cbAutoEmbed" );
02345   mainlayout->addWidget(cbAutoEmbed, 1);
02346 
02347   mainlayout->addStretch (10);
02348   mainlayout->activate();
02349 
02350   QFile f( _props->kurl().path() );
02351   if ( !f.open( IO_ReadOnly ) )
02352     return;
02353   f.close();
02354 
02355   KSimpleConfig config( _props->kurl().path() );
02356   config.setDesktopGroup();
02357   QString patternStr = config.readEntry( QString::fromLatin1("Patterns") );
02358   QString iconStr = config.readEntry( QString::fromLatin1("Icon") );
02359   QString commentStr = config.readEntry( QString::fromLatin1("Comment") );
02360   m_sMimeStr = config.readEntry( QString::fromLatin1("MimeType") );
02361 
02362   if ( !patternStr.isEmpty() )
02363     patternEdit->setText( patternStr );
02364   if ( !commentStr.isEmpty() )
02365     commentEdit->setText( commentStr );
02366   if ( !m_sMimeStr.isEmpty() )
02367     mimeEdit->setText( m_sMimeStr );
02368   cbAutoEmbed->setTristate();
02369   if ( config.hasKey( QString::fromLatin1("X-KDE-AutoEmbed") ) )
02370       cbAutoEmbed->setChecked( config.readBoolEntry( QString::fromLatin1("X-KDE-AutoEmbed") ) );
02371   else
02372       cbAutoEmbed->setNoChange();
02373 
02374   connect( patternEdit, SIGNAL( textChanged( const QString & ) ),
02375            this, SIGNAL( changed() ) );
02376   connect( commentEdit, SIGNAL( textChanged( const QString & ) ),
02377            this, SIGNAL( changed() ) );
02378   connect( mimeEdit, SIGNAL( textChanged( const QString & ) ),
02379            this, SIGNAL( changed() ) );
02380   connect( cbAutoEmbed, SIGNAL( toggled( bool ) ),
02381            this, SIGNAL( changed() ) );
02382 }
02383 
02384 KBindingPropsPlugin::~KBindingPropsPlugin()
02385 {
02386   delete d;
02387 }
02388 
02389 // QString KBindingPropsPlugin::tabName () const
02390 // {
02391 //   return i18n ("A&ssociation");
02392 // }
02393 
02394 bool KBindingPropsPlugin::supports( KFileItemList _items )
02395 {
02396   if ( _items.count() != 1 )
02397     return false;
02398   KFileItem * item = _items.first();
02399   // check if desktop file
02400   if ( !KPropsDlgPlugin::isDesktopFile( item ) )
02401     return false;
02402 
02403   // open file and check type
02404   KDesktopFile config( item->url().path(), true /* readonly */ );
02405   return config.hasMimeTypeType();
02406 }
02407 
02408 void KBindingPropsPlugin::applyChanges()
02409 {
02410   QString path = properties->kurl().path();
02411   QFile f( path );
02412 
02413   if ( !f.open( IO_ReadWrite ) )
02414   {
02415     KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient access to write to <b>%1</b>.</qt>").arg(path));
02416     return;
02417   }
02418   f.close();
02419 
02420   KSimpleConfig config( path );
02421   config.setDesktopGroup();
02422   config.writeEntry( QString::fromLatin1("Type"), QString::fromLatin1("MimeType") );
02423 
02424   config.writeEntry( QString::fromLatin1("Patterns"),  patternEdit->text() );
02425   config.writeEntry( QString::fromLatin1("Comment"), commentEdit->text() );
02426   config.writeEntry( QString::fromLatin1("Comment"), commentEdit->text(), true, false, true ); // for compat
02427   config.writeEntry( QString::fromLatin1("MimeType"), mimeEdit->text() );
02428   if ( cbAutoEmbed->state() == QButton::NoChange )
02429       config.deleteEntry( QString::fromLatin1("X-KDE-AutoEmbed"), false );
02430   else
02431       config.writeEntry( QString::fromLatin1("X-KDE-AutoEmbed"), cbAutoEmbed->isChecked() );
02432   config.sync();
02433 }
02434 
02435 /* ----------------------------------------------------
02436  *
02437  * KDevicePropsPlugin
02438  *
02439  * -------------------------------------------------- */
02440 
02441 class KDevicePropsPlugin::KDevicePropsPluginPrivate
02442 {
02443 public:
02444   KDevicePropsPluginPrivate()
02445   {
02446   }
02447   ~KDevicePropsPluginPrivate()
02448   {
02449   }
02450 
02451   QFrame *m_frame;
02452   QStringList mountpointlist;
02453 };
02454 
02455 KDevicePropsPlugin::KDevicePropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props )
02456 {
02457   d = new KDevicePropsPluginPrivate;
02458   d->m_frame = properties->dialog()->addPage(i18n("De&vice"));
02459 
02460   QStringList devices;
02461   QCString fstabFile;
02462   indexDevice = 0;  // device on first column
02463   indexMountPoint = 1; // mount point on second column
02464   if ( QFile::exists(QString::fromLatin1("/etc/fstab")) ) // Linux, ...
02465   {
02466     fstabFile = "/etc/fstab";
02467   }
02468   else if ( QFile::exists(QString::fromLatin1("/etc/vfstab")) ) // Solaris
02469   {
02470     fstabFile = "/etc/vfstab";
02471     indexMountPoint++;
02472   }
02473 
02474   // insert your favorite location for fstab here
02475   if ( !fstabFile.isEmpty() )
02476   {
02477 #ifdef HAVE_SETMNTENT
02478 
02479 #define SETMNTENT setmntent
02480 #define ENDMNTENT endmntent
02481 #define STRUCT_MNTENT struct mntent *
02482 #define STRUCT_SETMNTENT FILE *
02483 #define GETMNTENT(file, var) ((var = getmntent(file)) != 0)
02484 #define MOUNTPOINT(var) var->mnt_dir
02485 #define MOUNTTYPE(var) var->mnt_type
02486 #define MOUNTOPTIONS(var) var->mnt_opts
02487 #define HASMNTOPT(var, opt) hasmntopt(var, opt)
02488 #define FSNAME(var) var->mnt_fsname
02489 
02490   STRUCT_SETMNTENT fstab = SETMNTENT(fstabFile, "r");
02491   if (fstab)
02492   {
02493     STRUCT_MNTENT fe;
02494     while (GETMNTENT(fstab, fe))
02495     {
02496        QString mountPoint = QFile::decodeName(MOUNTPOINT(fe));
02497        QString device = QFile::decodeName(FSNAME(fe));
02498        if (device.startsWith("/") && (mountPoint != "-") &&
02499            (mountPoint != "none") && !mountPoint.isEmpty())
02500        {
02501           devices.append( device + QString::fromLatin1(" (")
02502                           + mountPoint + QString::fromLatin1(")") );
02503           m_devicelist.append(device);
02504           d->mountpointlist.append(mountPoint);
02505        } 
02506     }
02507   }
02508 #else
02509 
02510     QFile f( fstabFile );
02511     if ( f.open( IO_ReadOnly ) )
02512     {
02513       QTextStream stream( &f );
02514       while ( !stream.eof() )
02515       {
02516         QString line = stream.readLine();
02517         line = line.simplifyWhiteSpace();
02518         if (!line.isEmpty() && line[0] == '/') // skip comments but also
02519         {
02520           QStringList lst = QStringList::split( ' ', line );
02521           if ( lst.count() > 2 && lst[indexDevice] != QString::fromLatin1("/proc")
02522               && lst[indexMountPoint] != QString::fromLatin1("none")
02523               && lst[indexMountPoint] != QString::fromLatin1("-") )
02524           {
02525             devices.append( lst[indexDevice]+QString::fromLatin1(" (")
02526                              +lst[indexMountPoint]+QString::fromLatin1(")") );
02527             m_devicelist.append( lst[indexDevice] );
02528             d->mountpointlist.append( lst[indexMountPoint] );
02529           }
02530         }
02531       }
02532       f.close();
02533     }
02534 #endif
02535   }
02536 
02537 
02538   QGridLayout *layout = new QGridLayout( d->m_frame, 0, 3, KDialog::marginHint(),
02539                                         KDialog::spacingHint());
02540   layout->setColStretch(1, 1);
02541 
02542   QLabel* label;
02543   label = new QLabel( d->m_frame );
02544   label->setText( devices.count() == 0 ?
02545                       i18n("Device (/dev/fd0):") : // old style
02546                       i18n("Device:") ); // new style (combobox)
02547   layout->addWidget(label, 0, 0);
02548 
02549   device = new QComboBox( true, d->m_frame, "ComboBox_device" );
02550   device->insertStringList( devices );
02551   layout->addWidget(device, 0, 1);
02552   connect( device, SIGNAL( activated( int ) ),
02553            this, SLOT( slotActivated( int ) ) );
02554 
02555   readonly = new QCheckBox( d->m_frame, "CheckBox_readonly" );
02556   readonly->setText(  i18n("Read only") );
02557   layout->addWidget(readonly, 1, 1);
02558 
02559   label = new QLabel( d->m_frame );
02560   label->setText( devices.count()==0 ?
02561                       i18n("Mount point (/mnt/floppy):") : // old style
02562                       i18n("Mount point:")); // new style (combobox)
02563   layout->addWidget(label, 2, 0);
02564 
02565   mountpoint = new QLabel( d->m_frame, "LineEdit_mountpoint" );
02566 
02567   layout->addWidget(mountpoint, 2, 1);
02568 
02569   KSeparator* sep = new KSeparator( KSeparator::HLine, d->m_frame);
02570   layout->addMultiCellWidget(sep, 4, 4, 0, 2);
02571 
02572   unmounted = new KIconButton( d->m_frame );
02573   unmounted->setFixedSize(70, 70);
02574   unmounted->setIconType(KIcon::Desktop, KIcon::Device);
02575   layout->addWidget(unmounted, 5, 0);
02576 
02577   label = new QLabel( i18n("Unmounted Icon"),  d->m_frame );
02578   layout->addWidget(label, 5, 1);
02579 
02580   layout->setRowStretch(6, 1);
02581 
02582   QString path( _props->kurl().path() );
02583 
02584   QFile f( path );
02585   if ( !f.open( IO_ReadOnly ) )
02586     return;
02587   f.close();
02588 
02589   KSimpleConfig config( path );
02590   config.setDesktopGroup();
02591   QString deviceStr = config.readEntry( QString::fromLatin1("Dev") );
02592   QString mountPointStr = config.readEntry( QString::fromLatin1("MountPoint") );
02593   bool ro = config.readBoolEntry( QString::fromLatin1("ReadOnly"), false );
02594   QString unmountedStr = config.readEntry( QString::fromLatin1("UnmountIcon") );
02595 
02596   device->setEditText( deviceStr );
02597   if ( !deviceStr.isEmpty() ) {
02598     // Set default options for this device (first matching entry)
02599     int index = m_devicelist.findIndex(deviceStr);
02600     if (index != -1)
02601     {
02602       //kdDebug(250) << "found it " << index << endl;
02603       slotActivated( index );
02604     }
02605   }
02606 
02607   if ( !mountPointStr.isEmpty() )
02608     mountpoint->setText( mountPointStr );
02609 
02610   readonly->setChecked( ro );
02611 
02612   if ( unmountedStr.isEmpty() )
02613     unmountedStr = KMimeType::mimeType(QString::fromLatin1("application/octet-stream"))->KServiceType::icon(); // default icon
02614 
02615   unmounted->setIcon( unmountedStr );
02616 
02617   connect( device, SIGNAL( activated( int ) ),
02618            this, SIGNAL( changed() ) );
02619   connect( device, SIGNAL( textChanged( const QString & ) ),
02620            this, SIGNAL( changed() ) );
02621   connect( readonly, SIGNAL( toggled( bool ) ),
02622            this, SIGNAL( changed() ) );
02623   connect( unmounted, SIGNAL( iconChanged( QString ) ),
02624            this, SIGNAL( changed() ) );
02625 }
02626 
02627 KDevicePropsPlugin::~KDevicePropsPlugin()
02628 {
02629   delete d;
02630 }
02631 
02632 // QString KDevicePropsPlugin::tabName () const
02633 // {
02634 //   return i18n ("De&vice");
02635 // }
02636 
02637 void KDevicePropsPlugin::slotActivated( int index )
02638 {
02639   device->setEditText( m_devicelist[index] );
02640   mountpoint->setText( d->mountpointlist[index] );
02641 }
02642 
02643 bool KDevicePropsPlugin::supports( KFileItemList _items )
02644 {
02645   if ( _items.count() != 1 )
02646     return false;
02647   KFileItem * item = _items.first();
02648   // check if desktop file
02649   if ( !KPropsDlgPlugin::isDesktopFile( item ) )
02650     return false;
02651   // open file and check type
02652   KDesktopFile config( item->url().path(), true /* readonly */ );
02653   return config.hasDeviceType();
02654 }
02655 
02656 void KDevicePropsPlugin::applyChanges()
02657 {
02658   QString path = properties->kurl().path();
02659   QFile f( path );
02660   if ( !f.open( IO_ReadWrite ) )
02661   {
02662     KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient access to write to <b>%1</b>.</qt>").arg(path));
02663     return;
02664   }
02665   f.close();
02666 
02667   KSimpleConfig config( path );
02668   config.setDesktopGroup();
02669   config.writeEntry( QString::fromLatin1("Type"), QString::fromLatin1("FSDevice") );
02670 
02671   config.writeEntry( QString::fromLatin1("Dev"), device->currentText() );
02672   config.writeEntry( QString::fromLatin1("MountPoint"), mountpoint->text() );
02673 
02674   config.writeEntry( QString::fromLatin1("UnmountIcon"), unmounted->icon() );
02675   kdDebug(250) << "unmounted->icon() = " << unmounted->icon() << endl;
02676 
02677   config.writeEntry( QString::fromLatin1("ReadOnly"), readonly->isChecked() );
02678 
02679   config.sync();
02680 }
02681 
02682 void KPropertiesDialog::virtual_hook( int id, void* data )
02683 { KDialogBase::virtual_hook( id, data ); }
02684 
02685 void KPropsDlgPlugin::virtual_hook( int, void* )
02686 { /*BASE::virtual_hook( id, data );*/ }
02687 
02688 #include "kpropertiesdialog.moc"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:14:06 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001