kio Library API Documentation

kpropertiesdialog.cpp

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