kio Library API Documentation

kpropertiesdialog.cpp

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