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