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