kio Library API Documentation

kpropertiesdialog.cpp

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