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   bool allDisable = true;
01887   QCheckBox *cba[3][4];
01888   for (int row = 0; row < 3 ; ++row) {
01889     for (int col = 0; col < 4; ++col) {
01890       QCheckBox *cb = new QCheckBox(gb);
01891       cba[row][col] = cb;
01892       cb->setChecked(aPermissions & fperm[row][col]);
01893       if ( aPartialPermissions & fperm[row][col] )
01894       {
01895         cb->setTristate();
01896         cb->setNoChange();
01897       }
01898       else if (d->cbRecursive && d->cbRecursive->isChecked())
01899     cb->setTristate();
01900 
01901       if( d->canChangePermissions)
01902         allDisable = false;
01903       cb->setEnabled( d->canChangePermissions );
01904       gl->addWidget (cb, row+2, col+1);
01905       switch(col) {
01906       case 0:
01907     QWhatsThis::add(cb, readWhatsThis);
01908     break;
01909       case 1:
01910     QWhatsThis::add(cb, writeWhatsThis);
01911     break;
01912       case 2:
01913     QWhatsThis::add(cb, execWhatsThis);
01914     break;
01915       case 3:
01916     switch(row) {
01917     case 0:
01918       QWhatsThis::add(cb, setUidWhatsThis);
01919       break;
01920     case 1:
01921       QWhatsThis::add(cb, setGidWhatsThis);
01922       break;
01923     case 2:
01924       QWhatsThis::add(cb, stickyWhatsThis);
01925       break;
01926     }
01927     break;
01928       }
01929     }
01930   }
01931   gl->setColStretch(6, 10);
01932 
01933   if( allDisable )
01934           dlg.enableButtonOK(false );
01935   if (dlg.exec() != KDialogBase::Accepted)
01936     return;
01937 
01938   mode_t andPermissions = mode_t(~0);
01939   mode_t orPermissions = 0;
01940   for (int row = 0; row < 3; ++row)
01941     for (int col = 0; col < 4; ++col) {
01942       switch (cba[row][col]->state())
01943       {
01944       case QCheckBox::On:
01945     orPermissions |= fperm[row][col];
01946     //fall through
01947       case QCheckBox::Off:
01948     andPermissions &= ~fperm[row][col];
01949     break;
01950       default: // NoChange
01951     break;
01952       }
01953     }
01954 
01955   d->isIrregular = false;
01956   KFileItemList items = properties->items();
01957   for (KFileItemListIterator it(items); it.current(); ++it) {
01958     if (isIrregular(((*it)->permissions() & andPermissions) | orPermissions,
01959             (*it)->isDir(), (*it)->isLink())) {
01960       d->isIrregular = true;
01961       break;
01962     }
01963   }
01964 
01965   permissions = orPermissions;
01966   d->partialPermissions = andPermissions;
01967 
01968   emit changed();
01969   updateAccessControls();
01970 }
01971 
01972 // QString KFilePermissionsPropsPlugin::tabName () const
01973 // {
01974 //   return i18n ("&Permissions");
01975 // }
01976 
01977 KFilePermissionsPropsPlugin::~KFilePermissionsPropsPlugin()
01978 {
01979   delete d;
01980 }
01981 
01982 bool KFilePermissionsPropsPlugin::supports( KFileItemList _items )
01983 {
01984   for (KFileItemListIterator it(_items); it.current(); ++it) {
01985     if ( (*it)->url().protocol().find("device", 0, false)!=-1)
01986       return false;
01987   }
01988 
01989   return true;
01990 }
01991 
01992 // sets a combo box in the Access Control frame
01993 void KFilePermissionsPropsPlugin::setComboContent(QComboBox *combo, PermissionsTarget target,
01994                           mode_t permissions, mode_t partial) {
01995   combo->clear();
01996   if (d->pmode == PermissionsOnlyLinks) {
01997     combo->insertItem(i18n("Link"));
01998     combo->setCurrentItem(0);
01999     return;
02000   }
02001 
02002   mode_t tMask = permissionsMasks[target];
02003   int textIndex;
02004   for (textIndex = 0; standardPermissions[textIndex] != (mode_t)-1; textIndex++)
02005     if ((standardPermissions[textIndex]&tMask) == (permissions&tMask&(UniRead|UniWrite)))
02006       break;
02007   Q_ASSERT(standardPermissions[textIndex] != (mode_t)-1); // must not happen, would be irreglar
02008 
02009   for (int i = 0; permissionsTexts[(int)d->pmode][i]; i++)
02010     combo->insertItem(i18n(permissionsTexts[(int)d->pmode][i]));
02011 
02012   if (partial & tMask & ~UniExec) {
02013     combo->insertItem(i18n("Varying (No Change)"));
02014     combo->setCurrentItem(3);
02015   }
02016   else
02017     combo->setCurrentItem(textIndex);
02018 }
02019 
02020 // permissions are irregular if they cant be displayed in a combo box.
02021 bool KFilePermissionsPropsPlugin::isIrregular(mode_t permissions, bool isDir, bool isLink) {
02022   if (isLink)                             // links are always ok
02023     return false;
02024 
02025   mode_t p = permissions;
02026   if (p & (S_ISUID | S_ISGID))  // setuid/setgid -> irregular
02027     return true;
02028   if (isDir) {
02029     p &= ~S_ISVTX;          // ignore sticky on dirs
02030 
02031     // check supported flag combinations
02032     mode_t p0 = p & UniOwner;
02033     if ((p0 != 0) && (p0 != (S_IRUSR | S_IXUSR)) && (p0 != UniOwner))
02034       return true;
02035     p0 = p & UniGroup;
02036     if ((p0 != 0) && (p0 != (S_IRGRP | S_IXGRP)) && (p0 != UniGroup))
02037       return true;
02038     p0 = p & UniOthers;
02039     if ((p0 != 0) && (p0 != (S_IROTH | S_IXOTH)) && (p0 != UniOthers))
02040       return true;
02041     return false;
02042   }
02043   if (p & S_ISVTX) // sticky on file -> irregular
02044     return true;
02045 
02046   // check supported flag combinations
02047   mode_t p0 = p & UniOwner;
02048   bool usrXPossible = !p0; // true if this file could be an executable
02049   if (p0 & S_IXUSR) {
02050     if ((p0 == S_IXUSR) || (p0 == (S_IWUSR | S_IXUSR)))
02051       return true;
02052     usrXPossible = true;
02053   }
02054   else if (p0 == S_IWUSR)
02055     return true;
02056 
02057   p0 = p & UniGroup;
02058   bool grpXPossible = !p0; // true if this file could be an executable
02059   if (p0 & S_IXGRP) {
02060     if ((p0 == S_IXGRP) || (p0 == (S_IWGRP | S_IXGRP)))
02061       return true;
02062     grpXPossible = true;
02063   }
02064   else if (p0 == S_IWGRP)
02065     return true;
02066   if (p0 == 0)
02067     grpXPossible = true;
02068 
02069   p0 = p & UniOthers;
02070   bool othXPossible = !p0; // true if this file could be an executable
02071   if (p0 & S_IXOTH) {
02072     if ((p0 == S_IXOTH) || (p0 == (S_IWOTH | S_IXOTH)))
02073       return true;
02074     othXPossible = true;
02075   }
02076   else if (p0 == S_IWOTH)
02077     return true;
02078 
02079   // check that there either all targets are executable-compatible, or none
02080   return (p & UniExec) && !(usrXPossible && grpXPossible && othXPossible);
02081 }
02082 
02083 // enables/disabled the widgets in the Access Control frame
02084 void KFilePermissionsPropsPlugin::enableAccessControls(bool enable) {
02085     d->ownerPermCombo->setEnabled(enable);
02086     d->groupPermCombo->setEnabled(enable);
02087     d->othersPermCombo->setEnabled(enable);
02088     if (d->extraCheckbox)
02089       d->extraCheckbox->setEnabled(enable);
02090         if ( d->cbRecursive )
02091             d->cbRecursive->setEnabled(enable);
02092 }
02093 
02094 // updates all widgets in the Access Control frame
02095 void KFilePermissionsPropsPlugin::updateAccessControls() {
02096   setComboContent(d->ownerPermCombo, PermissionsOwner,
02097           permissions, d->partialPermissions);
02098   setComboContent(d->groupPermCombo, PermissionsGroup,
02099           permissions, d->partialPermissions);
02100   setComboContent(d->othersPermCombo, PermissionsOthers,
02101           permissions, d->partialPermissions);
02102 
02103   switch(d->pmode) {
02104   case PermissionsOnlyLinks:
02105     enableAccessControls(false);
02106     break;
02107   case PermissionsOnlyFiles:
02108     enableAccessControls(d->canChangePermissions && !d->isIrregular);
02109     if (d->canChangePermissions)
02110       d->explanationLabel->setText(d->isIrregular ?
02111                    i18n("This file uses advanced permissions",
02112                       "These files use advanced permissions.",
02113                       properties->items().count()) : "");
02114     if (d->partialPermissions & UniExec) {
02115       d->extraCheckbox->setTristate();
02116       d->extraCheckbox->setNoChange();
02117     }
02118     else {
02119       d->extraCheckbox->setTristate(false);
02120       d->extraCheckbox->setChecked(permissions & UniExec);
02121     }
02122     break;
02123   case PermissionsOnlyDirs:
02124     enableAccessControls(d->canChangePermissions && !d->isIrregular);
02125     if (d->canChangePermissions)
02126       d->explanationLabel->setText(d->isIrregular ?
02127                    i18n("This folder uses advanced permissions.",
02128                       "These folders use advanced permissions.",
02129                       properties->items().count()) : "");
02130     if (d->partialPermissions & S_ISVTX) {
02131       d->extraCheckbox->setTristate();
02132       d->extraCheckbox->setNoChange();
02133     }
02134     else {
02135       d->extraCheckbox->setTristate(false);
02136       d->extraCheckbox->setChecked(permissions & S_ISVTX);
02137     }
02138     break;
02139   case PermissionsMixed:
02140     enableAccessControls(d->canChangePermissions && !d->isIrregular);
02141     if (d->canChangePermissions)
02142       d->explanationLabel->setText(d->isIrregular ?
02143                    i18n("These files use advanced permissions.") : "");
02144     break;
02145     if (d->partialPermissions & S_ISVTX) {
02146       d->extraCheckbox->setTristate();
02147       d->extraCheckbox->setNoChange();
02148     }
02149     else {
02150       d->extraCheckbox->setTristate(false);
02151       d->extraCheckbox->setChecked(permissions & S_ISVTX);
02152     }
02153     break;
02154   }
02155 }
02156 
02157 // gets masks for files and dirs from the Access Control frame widgets
02158 void KFilePermissionsPropsPlugin::getPermissionMasks(mode_t &andFilePermissions,
02159                              mode_t &andDirPermissions,
02160                              mode_t &orFilePermissions,
02161                              mode_t &orDirPermissions) {
02162   andFilePermissions = mode_t(~UniSpecial);
02163   andDirPermissions = mode_t(~(S_ISUID|S_ISGID));
02164   orFilePermissions = 0;
02165   orDirPermissions = 0;
02166   if (d->isIrregular)
02167     return;
02168 
02169   mode_t m = standardPermissions[d->ownerPermCombo->currentItem()];
02170   if (m != (mode_t) -1) {
02171     orFilePermissions |= m & UniOwner;
02172     if ((m & UniOwner) &&
02173     ((d->pmode == PermissionsMixed) ||
02174      ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == QButton::NoChange))))
02175       andFilePermissions &= ~(S_IRUSR | S_IWUSR);
02176     else {
02177       andFilePermissions &= ~(S_IRUSR | S_IWUSR | S_IXUSR);
02178       if ((m & S_IRUSR) && (d->extraCheckbox->state() == QButton::On))
02179     orFilePermissions |= S_IXUSR;
02180     }
02181 
02182     orDirPermissions |= m & UniOwner;
02183     if (m & S_IRUSR)
02184     orDirPermissions |= S_IXUSR;
02185     andDirPermissions &= ~(S_IRUSR | S_IWUSR | S_IXUSR);
02186   }
02187 
02188   m = standardPermissions[d->groupPermCombo->currentItem()];
02189   if (m != (mode_t) -1) {
02190     orFilePermissions |= m & UniGroup;
02191     if ((m & UniGroup) &&
02192     ((d->pmode == PermissionsMixed) ||
02193      ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == QButton::NoChange))))
02194       andFilePermissions &= ~(S_IRGRP | S_IWGRP);
02195     else {
02196       andFilePermissions &= ~(S_IRGRP | S_IWGRP | S_IXGRP);
02197       if ((m & S_IRGRP) && (d->extraCheckbox->state() == QButton::On))
02198     orFilePermissions |= S_IXGRP;
02199     }
02200 
02201     orDirPermissions |= m & UniGroup;
02202     if (m & S_IRGRP)
02203     orDirPermissions |= S_IXGRP;
02204     andDirPermissions &= ~(S_IRGRP | S_IWGRP | S_IXGRP);
02205   }
02206 
02207   m = standardPermissions[d->othersPermCombo->currentItem()];
02208   if (m != (mode_t) -1) {
02209     orFilePermissions |= m & UniOthers;
02210     if ((m & UniOthers) &&
02211     ((d->pmode == PermissionsMixed) ||
02212      ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == QButton::NoChange))))
02213       andFilePermissions &= ~(S_IROTH | S_IWOTH);
02214     else {
02215       andFilePermissions &= ~(S_IROTH | S_IWOTH | S_IXOTH);
02216       if ((m & S_IROTH) && (d->extraCheckbox->state() == QButton::On))
02217     orFilePermissions |= S_IXOTH;
02218     }
02219 
02220     orDirPermissions |= m & UniOthers;
02221     if (m & S_IROTH)
02222     orDirPermissions |= S_IXOTH;
02223     andDirPermissions &= ~(S_IROTH | S_IWOTH | S_IXOTH);
02224   }
02225 
02226   if (((d->pmode == PermissionsMixed) || (d->pmode == PermissionsOnlyDirs)) &&
02227       (d->extraCheckbox->state() != QButton::NoChange)) {
02228     andDirPermissions &= ~S_ISVTX;
02229     if (d->extraCheckbox->state() == QButton::On)
02230       orDirPermissions |= S_ISVTX;
02231   }
02232 }
02233 
02234 void KFilePermissionsPropsPlugin::applyChanges()
02235 {
02236   mode_t orFilePermissions;
02237   mode_t orDirPermissions;
02238   mode_t andFilePermissions;
02239   mode_t andDirPermissions;
02240 
02241   if (!d->canChangePermissions)
02242     return;
02243 
02244   if (!d->isIrregular)
02245     getPermissionMasks(andFilePermissions,
02246                andDirPermissions,
02247                orFilePermissions,
02248                orDirPermissions);
02249   else {
02250     orFilePermissions = permissions;
02251     andFilePermissions = d->partialPermissions;
02252     orDirPermissions = permissions;
02253     andDirPermissions = d->partialPermissions;
02254   }
02255 
02256   QString owner, group;
02257   if (usrEdit)
02258     owner = usrEdit->text();
02259   if (grpEdit)
02260     group = grpEdit->text();
02261   else if (grpCombo)
02262     group = grpCombo->currentText();
02263 
02264   if (owner == strOwner)
02265       owner = QString::null; // no change
02266 
02267   if (group == strGroup)
02268       group = QString::null;
02269 
02270   bool recursive = d->cbRecursive && d->cbRecursive->isChecked();
02271   bool permissionChange = false;
02272 
02273   KFileItemList files, dirs;
02274   KFileItemList items = properties->items();
02275   for (KFileItemListIterator it(items); it.current(); ++it) {
02276     if ((*it)->isDir()) {
02277       dirs.append(*it);
02278       if ((*it)->permissions() != (((*it)->permissions() & andDirPermissions) | orDirPermissions))
02279     permissionChange = true;
02280     }
02281     else if ((*it)->isFile()) {
02282       files.append(*it);
02283       if ((*it)->permissions() != (((*it)->permissions() & andFilePermissions) | orFilePermissions))
02284     permissionChange = true;
02285     }
02286   }
02287 
02288   if ( !owner.isEmpty() || !group.isEmpty() || recursive || permissionChange)
02289   {
02290     KIO::Job * job;
02291     if (files.count() > 0) {
02292       job = KIO::chmod( files, orFilePermissions, ~andFilePermissions,
02293             owner, group, false );
02294       connect( job, SIGNAL( result( KIO::Job * ) ),
02295            SLOT( slotChmodResult( KIO::Job * ) ) );
02296       // Wait for job
02297       QWidget dummy(0,0,WType_Dialog|WShowModal);
02298       qt_enter_modal(&dummy);
02299       qApp->enter_loop();
02300       qt_leave_modal(&dummy);
02301     }
02302     if (dirs.count() > 0) {
02303       job = KIO::chmod( dirs, orDirPermissions, ~andDirPermissions,
02304             owner, group, recursive );
02305       connect( job, SIGNAL( result( KIO::Job * ) ),
02306            SLOT( slotChmodResult( KIO::Job * ) ) );
02307       // Wait for job
02308       QWidget dummy(0,0,WType_Dialog|WShowModal);
02309       qt_enter_modal(&dummy);
02310       qApp->enter_loop();
02311       qt_leave_modal(&dummy);
02312     }
02313   }
02314 }
02315 
02316 void KFilePermissionsPropsPlugin::slotChmodResult( KIO::Job * job )
02317 {
02318   kdDebug(250) << "KFilePermissionsPropsPlugin::slotChmodResult" << endl;
02319   if (job->error())
02320     job->showErrorDialog( d->m_frame );
02321   // allow apply() to return
02322   qApp->exit_loop();
02323 }
02324 
02325 
02326 
02327 
02328 class KURLPropsPlugin::KURLPropsPluginPrivate
02329 {
02330 public:
02331   KURLPropsPluginPrivate()
02332   {
02333   }
02334   ~KURLPropsPluginPrivate()
02335   {
02336   }
02337 
02338   QFrame *m_frame;
02339 };
02340 
02341 KURLPropsPlugin::KURLPropsPlugin( KPropertiesDialog *_props )
02342   : KPropsDlgPlugin( _props )
02343 {
02344   d = new KURLPropsPluginPrivate;
02345   d->m_frame = properties->addPage(i18n("U&RL"));
02346   QVBoxLayout *layout = new QVBoxLayout(d->m_frame, 0, KDialog::spacingHint());
02347 
02348   QLabel *l;
02349   l = new QLabel( d->m_frame, "Label_1" );
02350   l->setText( i18n("URL:") );
02351   layout->addWidget(l);
02352 
02353   URLEdit = new KURLRequester( d->m_frame, "URL Requester" );
02354   layout->addWidget(URLEdit);
02355 
02356   QString path = properties->kurl().path();
02357 
02358   QFile f( path );
02359   if ( !f.open( IO_ReadOnly ) )
02360     return;
02361   f.close();
02362 
02363   KSimpleConfig config( path );
02364   config.setDesktopGroup();
02365   URLStr = config.readPathEntry( "URL" );
02366 
02367   if ( !URLStr.isNull() )
02368     URLEdit->setURL( URLStr );
02369 
02370   connect( URLEdit, SIGNAL( textChanged( const QString & ) ),
02371            this, SIGNAL( changed() ) );
02372 
02373   layout->addStretch (1);
02374 }
02375 
02376 KURLPropsPlugin::~KURLPropsPlugin()
02377 {
02378   delete d;
02379 }
02380 
02381 // QString KURLPropsPlugin::tabName () const
02382 // {
02383 //   return i18n ("U&RL");
02384 // }
02385 
02386 bool KURLPropsPlugin::supports( KFileItemList _items )
02387 {
02388   if ( _items.count() != 1 )
02389     return false;
02390   KFileItem * item = _items.first();
02391   // check if desktop file
02392   if ( !KPropsDlgPlugin::isDesktopFile( item ) )
02393     return false;
02394 
02395   // open file and check type
02396   KDesktopFile config( item->url().path(), true /* readonly */ );
02397   return config.hasLinkType();
02398 }
02399 
02400 void KURLPropsPlugin::applyChanges()
02401 {
02402   QString path = properties->kurl().path();
02403 
02404   QFile f( path );
02405   if ( !f.open( IO_ReadWrite ) ) {
02406     KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
02407                 "sufficient access to write to <b>%1</b>.</qt>").arg(path));
02408     return;
02409   }
02410   f.close();
02411 
02412   KSimpleConfig config( path );
02413   config.setDesktopGroup();
02414   config.writeEntry( "Type", QString::fromLatin1("Link"));
02415   config.writePathEntry( "URL", URLEdit->url() );
02416   // Users can't create a Link .desktop file with a Name field,
02417   // but distributions can. Update the Name field in that case.
02418   if ( config.hasKey("Name") )
02419   {
02420     QString nameStr = nameFromFileName(properties->kurl().fileName());
02421     config.writeEntry( "Name", nameStr );
02422     config.writeEntry( "Name", nameStr, true, false, true );
02423 
02424   }
02425 }
02426 
02427 
02428 /* ----------------------------------------------------
02429  *
02430  * KBindingPropsPlugin
02431  *
02432  * -------------------------------------------------- */
02433 
02434 class KBindingPropsPlugin::KBindingPropsPluginPrivate
02435 {
02436 public:
02437   KBindingPropsPluginPrivate()
02438   {
02439   }
02440   ~KBindingPropsPluginPrivate()
02441   {
02442   }
02443 
02444   QFrame *m_frame;
02445 };
02446 
02447 KBindingPropsPlugin::KBindingPropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props )
02448 {
02449   d = new KBindingPropsPluginPrivate;
02450   d->m_frame = properties->addPage(i18n("A&ssociation"));
02451   patternEdit = new KLineEdit( d->m_frame, "LineEdit_1" );
02452   commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" );
02453   mimeEdit = new KLineEdit( d->m_frame, "LineEdit_3" );
02454 
02455   QBoxLayout *mainlayout = new QVBoxLayout(d->m_frame, 0, KDialog::spacingHint());
02456   QLabel* tmpQLabel;
02457 
02458   tmpQLabel = new QLabel( d->m_frame, "Label_1" );
02459   tmpQLabel->setText(  i18n("Pattern ( example: *.html;*.htm )") );
02460   tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
02461   mainlayout->addWidget(tmpQLabel, 1);
02462 
02463   //patternEdit->setGeometry( 10, 40, 210, 30 );
02464   //patternEdit->setText( "" );
02465   patternEdit->setMaxLength( 512 );
02466   patternEdit->setMinimumSize( patternEdit->sizeHint() );
02467   patternEdit->setFixedHeight( fontHeight );
02468   mainlayout->addWidget(patternEdit, 1);
02469 
02470   tmpQLabel = new QLabel( d->m_frame, "Label_2" );
02471   tmpQLabel->setText(  i18n("Mime Type") );
02472   tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
02473   mainlayout->addWidget(tmpQLabel, 1);
02474 
02475   //mimeEdit->setGeometry( 10, 160, 210, 30 );
02476   mimeEdit->setMaxLength( 256 );
02477   mimeEdit->setMinimumSize( mimeEdit->sizeHint() );
02478   mimeEdit->setFixedHeight( fontHeight );
02479   mainlayout->addWidget(mimeEdit, 1);
02480 
02481   tmpQLabel = new QLabel( d->m_frame, "Label_3" );
02482   tmpQLabel->setText(  i18n("Comment") );
02483   tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
02484   mainlayout->addWidget(tmpQLabel, 1);
02485 
02486   //commentEdit->setGeometry( 10, 100, 210, 30 );
02487   commentEdit->setMaxLength( 256 );
02488   commentEdit->setMinimumSize( commentEdit->sizeHint() );
02489   commentEdit->setFixedHeight( fontHeight );
02490   mainlayout->addWidget(commentEdit, 1);
02491 
02492   cbAutoEmbed = new QCheckBox( i18n("Left click previews"), d->m_frame, "cbAutoEmbed" );
02493   mainlayout->addWidget(cbAutoEmbed, 1);
02494 
02495   mainlayout->addStretch (10);
02496   mainlayout->activate();
02497 
02498   QFile f( _props->kurl().path() );
02499   if ( !f.open( IO_ReadOnly ) )
02500     return;
02501   f.close();
02502 
02503   KSimpleConfig config( _props->kurl().path() );
02504   config.setDesktopGroup();
02505   QString patternStr = config.readEntry( "Patterns" );
02506   QString iconStr = config.readEntry( "Icon" );
02507   QString commentStr = config.readEntry( "Comment" );
02508   m_sMimeStr = config.readEntry( "MimeType" );
02509 
02510   if ( !patternStr.isEmpty() )
02511     patternEdit->setText( patternStr );
02512   if ( !commentStr.isEmpty() )
02513     commentEdit->setText( commentStr );
02514   if ( !m_sMimeStr.isEmpty() )
02515     mimeEdit->setText( m_sMimeStr );
02516   cbAutoEmbed->setTristate();
02517   if ( config.hasKey( "X-KDE-AutoEmbed" ) )
02518       cbAutoEmbed->setChecked( config.readBoolEntry( "X-KDE-AutoEmbed" ) );
02519   else
02520       cbAutoEmbed->setNoChange();
02521 
02522   connect( patternEdit, SIGNAL( textChanged( const QString & ) ),
02523            this, SIGNAL( changed() ) );
02524   connect( commentEdit, SIGNAL( textChanged( const QString & ) ),
02525            this, SIGNAL( changed() ) );
02526   connect( mimeEdit, SIGNAL( textChanged( const QString & ) ),
02527            this, SIGNAL( changed() ) );
02528   connect( cbAutoEmbed, SIGNAL( toggled( bool ) ),
02529            this, SIGNAL( changed() ) );
02530 }
02531 
02532 KBindingPropsPlugin::~KBindingPropsPlugin()
02533 {
02534   delete d;
02535 }
02536 
02537 // QString KBindingPropsPlugin::tabName () const
02538 // {
02539 //   return i18n ("A&ssociation");
02540 // }
02541 
02542 bool KBindingPropsPlugin::supports( KFileItemList _items )
02543 {
02544   if ( _items.count() != 1 )
02545     return false;
02546   KFileItem * item = _items.first();
02547   // check if desktop file
02548   if ( !KPropsDlgPlugin::isDesktopFile( item ) )
02549     return false;
02550 
02551   // open file and check type
02552   KDesktopFile config( item->url().path(), true /* readonly */ );
02553   return config.hasMimeTypeType();
02554 }
02555 
02556 void KBindingPropsPlugin::applyChanges()
02557 {
02558   QString path = properties->kurl().path();
02559   QFile f( path );
02560 
02561   if ( !f.open( IO_ReadWrite ) )
02562   {
02563     KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
02564                 "sufficient access to write to <b>%1</b>.</qt>").arg(path));
02565     return;
02566   }
02567   f.close();
02568 
02569   KSimpleConfig config( path );
02570   config.setDesktopGroup();
02571   config.writeEntry( "Type", QString::fromLatin1("MimeType") );
02572 
02573   config.writeEntry( "Patterns",  patternEdit->text() );
02574   config.writeEntry( "Comment", commentEdit->text() );
02575   config.writeEntry( "Comment",
02576              commentEdit->text(), true, false, true ); // for compat
02577   config.writeEntry( "MimeType", mimeEdit->text() );
02578   if ( cbAutoEmbed->state() == QButton::NoChange )
02579       config.deleteEntry( "X-KDE-AutoEmbed", false );
02580   else
02581       config.writeEntry( "X-KDE-AutoEmbed", cbAutoEmbed->isChecked() );
02582   config.sync();
02583 }
02584 
02585 /* ----------------------------------------------------
02586  *
02587  * KDevicePropsPlugin
02588  *
02589  * -------------------------------------------------- */
02590 
02591 class KDevicePropsPlugin::KDevicePropsPluginPrivate
02592 {
02593 public:
02594   KDevicePropsPluginPrivate()
02595   {
02596   }
02597   ~KDevicePropsPluginPrivate()
02598   {
02599   }
02600 
02601   QFrame *m_frame;
02602   QStringList mountpointlist;
02603 };
02604 
02605 KDevicePropsPlugin::KDevicePropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props )
02606 {
02607   d = new KDevicePropsPluginPrivate;
02608   d->m_frame = properties->addPage(i18n("De&vice"));
02609 
02610   QStringList devices;
02611   KMountPoint::List mountPoints = KMountPoint::possibleMountPoints();
02612 
02613   for(KMountPoint::List::ConstIterator it = mountPoints.begin();
02614       it != mountPoints.end(); ++it)
02615   {
02616      KMountPoint *mp = *it;
02617      QString mountPoint = mp->mountPoint();
02618      QString device = mp->mountedFrom();
02619      kdDebug()<<"mountPoint :"<<mountPoint<<" device :"<<device<<" mp->mountType() :"<<mp->mountType()<<endl;
02620 
02621      if ((mountPoint != "-") && (mountPoint != "none") && !mountPoint.isEmpty()
02622           && device != "none")
02623      {
02624         devices.append( device + QString::fromLatin1(" (")
02625                         + mountPoint + QString::fromLatin1(")") );
02626         m_devicelist.append(device);
02627         d->mountpointlist.append(mountPoint);
02628      }
02629   }
02630 
02631   QGridLayout *layout = new QGridLayout( d->m_frame, 0, 3, 0,
02632                                         KDialog::spacingHint());
02633   layout->setColStretch(1, 1);
02634 
02635   QLabel* label;
02636   label = new QLabel( d->m_frame );
02637   label->setText( devices.count() == 0 ?
02638                       i18n("Device (/dev/fd0):") : // old style
02639                       i18n("Device:") ); // new style (combobox)
02640   layout->addWidget(label, 0, 0);
02641 
02642   device = new QComboBox( true, d->m_frame, "ComboBox_device" );
02643   device->insertStringList( devices );
02644   layout->addWidget(device, 0, 1);
02645   connect( device, SIGNAL( activated( int ) ),
02646            this, SLOT( slotActivated( int ) ) );
02647 
02648   readonly = new QCheckBox( d->m_frame, "CheckBox_readonly" );
02649   readonly->setText(  i18n("Read only") );
02650   layout->addWidget(readonly, 1, 1);
02651 
02652   label = new QLabel( d->m_frame );
02653   label->setText( devices.count()==0 ?
02654                       i18n("Mount point (/mnt/floppy):") : // old style
02655                       i18n("Mount point:")); // new style (combobox)
02656   layout->addWidget(label, 2, 0);
02657 
02658   mountpoint = new QLabel( d->m_frame, "LineEdit_mountpoint" );
02659 
02660   layout->addWidget(mountpoint, 2, 1);
02661 
02662   KSeparator* sep = new KSeparator( KSeparator::HLine, d->m_frame);
02663   layout->addMultiCellWidget(sep, 4, 4, 0, 2);
02664 
02665   unmounted = new KIconButton( d->m_frame );
02666   int bsize = 66 + 2 * unmounted->style().pixelMetric(QStyle::PM_ButtonMargin);
02667   unmounted->setFixedSize(bsize, bsize);
02668   unmounted->setIconType(KIcon::Desktop, KIcon::Device);
02669   layout->addWidget(unmounted, 5, 0);
02670 
02671   label = new QLabel( i18n("Unmounted Icon"),  d->m_frame );
02672   layout->addWidget(label, 5, 1);
02673 
02674   layout->setRowStretch(6, 1);
02675 
02676   QString path( _props->kurl().path() );
02677 
02678   QFile f( path );
02679   if ( !f.open( IO_ReadOnly ) )
02680     return;
02681   f.close();
02682 
02683   KSimpleConfig config( path );
02684   config.setDesktopGroup();
02685   QString deviceStr = config.readEntry( "Dev" );
02686   QString mountPointStr = config.readEntry( "MountPoint" );
02687   bool ro = config.readBoolEntry( "ReadOnly", false );
02688   QString unmountedStr = config.readEntry( "UnmountIcon" );
02689 
02690   device->setEditText( deviceStr );
02691   if ( !deviceStr.isEmpty() ) {
02692     // Set default options for this device (first matching entry)
02693     int index = m_devicelist.findIndex(deviceStr);
02694     if (index != -1)
02695     {
02696       //kdDebug(250) << "found it " << index << endl;
02697       slotActivated( index );
02698     }
02699   }
02700 
02701   if ( !mountPointStr.isEmpty() )
02702     mountpoint->setText( mountPointStr );
02703 
02704   readonly->setChecked( ro );
02705 
02706   if ( unmountedStr.isEmpty() )
02707     unmountedStr = KMimeType::mimeType(QString::fromLatin1("application/octet-stream"))->KServiceType::icon(); // default icon
02708 
02709   unmounted->setIcon( unmountedStr );
02710 
02711   connect( device, SIGNAL( activated( int ) ),
02712            this, SIGNAL( changed() ) );
02713   connect( device, SIGNAL( textChanged( const QString & ) ),
02714            this, SIGNAL( changed() ) );
02715   connect( readonly, SIGNAL( toggled( bool ) ),
02716            this, SIGNAL( changed() ) );
02717   connect( unmounted, SIGNAL( iconChanged( QString ) ),
02718            this, SIGNAL( changed() ) );
02719 
02720   connect( device, SIGNAL( textChanged( const QString & ) ),
02721            this, SLOT( slotDeviceChanged() ) );
02722 }
02723 
02724 KDevicePropsPlugin::~KDevicePropsPlugin()
02725 {
02726   delete d;
02727 }
02728 
02729 // QString KDevicePropsPlugin::tabName () const
02730 // {
02731 //   return i18n ("De&vice");
02732 // }
02733 
02734 void KDevicePropsPlugin::slotActivated( int index )
02735 {
02736   // Update mountpoint so that it matches the device that was selected in the combo
02737   device->setEditText( m_devicelist[index] );
02738   mountpoint->setText( d->mountpointlist[index] );
02739 }
02740 
02741 void KDevicePropsPlugin::slotDeviceChanged()
02742 {
02743   // Update mountpoint so that it matches the typed device
02744   int index = m_devicelist.findIndex( device->currentText() );
02745   if ( index != -1 )
02746     mountpoint->setText( d->mountpointlist[index] );
02747   else
02748     mountpoint->setText( QString::null );
02749 }
02750 
02751 bool KDevicePropsPlugin::supports( KFileItemList _items )
02752 {
02753   if ( _items.count() != 1 )
02754     return false;
02755   KFileItem * item = _items.first();
02756   // check if desktop file
02757   if ( !KPropsDlgPlugin::isDesktopFile( item ) )
02758     return false;
02759   // open file and check type
02760   KDesktopFile config( item->url().path(), true /* readonly */ );
02761   return config.hasDeviceType();
02762 }
02763 
02764 void KDevicePropsPlugin::applyChanges()
02765 {
02766   QString path = properties->kurl().path();
02767   QFile f( path );
02768   if ( !f.open( IO_ReadWrite ) )
02769   {
02770     KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient "
02771                 "access to write to <b>%1</b>.</qt>").arg(path));
02772     return;
02773   }
02774   f.close();
02775 
02776   KSimpleConfig config( path );
02777   config.setDesktopGroup();
02778   config.writeEntry( "Type", QString::fromLatin1("FSDevice") );
02779 
02780   config.writeEntry( "Dev", device->currentText() );
02781   config.writeEntry( "MountPoint", mountpoint->text() );
02782 
02783   config.writeEntry( "UnmountIcon", unmounted->icon() );
02784   kdDebug(250) << "unmounted->icon() = " << unmounted->icon() << endl;
02785 
02786   config.writeEntry( "ReadOnly", readonly->isChecked() );
02787 
02788   config.sync();
02789 }
02790 
02791 
02792 /* ----------------------------------------------------
02793  *
02794  * KDesktopPropsPlugin
02795  *
02796  * -------------------------------------------------- */
02797 
02798 
02799 KDesktopPropsPlugin::KDesktopPropsPlugin( KPropertiesDialog *_props )
02800   : KPropsDlgPlugin( _props )
02801 {
02802   QFrame *frame = properties->addPage(i18n("&Application"));
02803   QVBoxLayout *mainlayout = new QVBoxLayout( frame, 0, KDialog::spacingHint() );
02804 
02805   w = new KPropertiesDesktopBase(frame);
02806   mainlayout->addWidget(w);
02807 
02808   bool bKDesktopMode = (QCString(qApp->name()) == "kdesktop"); // nasty heh?
02809 
02810   if (bKDesktopMode)
02811   {
02812     // Hide Name entry
02813     w->nameEdit->hide();
02814     w->nameLabel->hide();
02815   }
02816 
02817   w->pathEdit->setMode(KFile::Directory | KFile::LocalOnly);
02818   w->pathEdit->lineEdit()->setAcceptDrops(false);
02819 
02820   connect( w->nameEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) );
02821   connect( w->genNameEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) );
02822   connect( w->commentEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) );
02823   connect( w->commandEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) );
02824   connect( w->pathEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) );
02825 
02826   connect( w->browseButton, SIGNAL( clicked() ), this, SLOT( slotBrowseExec() ) );
02827   connect( w->addFiletypeButton, SIGNAL( clicked() ), this, SLOT( slotAddFiletype() ) );
02828   connect( w->delFiletypeButton, SIGNAL( clicked() ), this, SLOT( slotDelFiletype() ) );
02829   connect( w->advancedButton, SIGNAL( clicked() ), this, SLOT( slotAdvanced() ) );
02830 
02831   // now populate the page
02832   QString path = _props->kurl().path();
02833   QFile f( path );
02834   if ( !f.open( IO_ReadOnly ) )
02835     return;
02836   f.close();
02837 
02838   KSimpleConfig config( path );
02839   config.setDollarExpansion( false );
02840   config.setDesktopGroup();
02841   QString nameStr = config.readEntry( "Name" );
02842   QString genNameStr = config.readEntry( "GenericName" );
02843   QString commentStr = config.readEntry( "Comment" );
02844   QString commandStr = config.readPathEntry( "Exec" );
02845   if (commandStr.left(12) == "ksystraycmd ")
02846   {
02847     commandStr.remove(0, 12);
02848     m_systrayBool = true;
02849   }
02850   else
02851     m_systrayBool = false;
02852 
02853   m_origCommandStr = commandStr;
02854   QString pathStr = config.readPathEntry( "Path" );
02855   m_terminalBool = config.readBoolEntry( "Terminal" );
02856   m_terminalOptionStr = config.readEntry( "TerminalOptions" );
02857   m_suidBool = config.readBoolEntry( "X-KDE-SubstituteUID" );
02858   m_suidUserStr = config.readEntry( "X-KDE-Username" );
02859   if( config.hasKey( "StartupNotify" ))
02860     m_startupBool = config.readBoolEntry( "StartupNotify", true );
02861   else
02862     m_startupBool = config.readBoolEntry( "X-KDE-StartupNotify", true );
02863   m_dcopServiceType = config.readEntry("X-DCOP-ServiceType").lower();
02864 
02865   QStringList mimeTypes = config.readListEntry( "MimeType", ';' );
02866 
02867   if ( nameStr.isEmpty() || bKDesktopMode ) {
02868     // We'll use the file name if no name is specified
02869     // because we _need_ a Name for a valid file.
02870     // But let's do it in apply, not here, so that we pick up the right name.
02871     setDirty();
02872   }
02873   if ( !bKDesktopMode )
02874     w->nameEdit->setText(nameStr);
02875 
02876   w->genNameEdit->setText( genNameStr );
02877   w->commentEdit->setText( commentStr );
02878   w->commandEdit->setText( commandStr );
02879   w->pathEdit->lineEdit()->setText( pathStr );
02880   w->filetypeList->setAllColumnsShowFocus(true);
02881 
02882   KMimeType::Ptr defaultMimetype = KMimeType::defaultMimeTypePtr();
02883   for(QStringList::ConstIterator it = mimeTypes.begin();
02884       it != mimeTypes.end(); )
02885   {
02886     KMimeType::Ptr p = KMimeType::mimeType(*it);
02887     ++it;
02888     QString preference;
02889     if (it != mimeTypes.end())
02890     {
02891        bool numeric;
02892        (*it).toInt(&numeric);
02893        if (numeric)
02894        {
02895          preference = *it;
02896          ++it;
02897        }
02898     }
02899     if (p && (p != defaultMimetype))
02900     {
02901        new QListViewItem(w->filetypeList, p->name(), p->comment(), preference);
02902     }
02903   }
02904 
02905 }
02906 
02907 KDesktopPropsPlugin::~KDesktopPropsPlugin()
02908 {
02909 }
02910 
02911 void KDesktopPropsPlugin::slotSelectMimetype()
02912 {
02913   QListView *w = (QListView*)sender();
02914   QListViewItem *item = w->firstChild();
02915   while(item)
02916   {
02917      if (item->isSelected())
02918         w->setSelected(item, false);
02919      item = item->nextSibling();
02920   }
02921 }
02922 
02923 void KDesktopPropsPlugin::slotAddFiletype()
02924 {
02925   KDialogBase dlg(w, "KPropertiesMimetypes", true,
02926                   i18n("Add File Type for %1").arg(properties->kurl().fileName()),
02927                   KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok);
02928 
02929   KGuiItem okItem(i18n("&Add"), QString::null /* no icon */,
02930                   i18n("Add the selected file types to\nthe list of supported file types."),
02931                   i18n("Add the selected file types to\nthe list of supported file types."));
02932   dlg.setButtonOK(okItem);
02933 
02934   KPropertiesMimetypeBase *mw = new KPropertiesMimetypeBase(&dlg);
02935 
02936   dlg.setMainWidget(mw);
02937 
02938   {
02939      mw->listView->setRootIsDecorated(true);
02940      mw->listView->setSelectionMode(QListView::Extended);
02941      mw->listView->setAllColumnsShowFocus(true);
02942      mw->listView->setFullWidth(true);
02943      mw->listView->setMinimumSize(500,400);
02944 
02945      connect(mw->listView, SIGNAL(selectionChanged()),
02946              this, SLOT(slotSelectMimetype()));
02947      connect(mw->listView, SIGNAL(doubleClicked( QListViewItem *, const QPoint &, int )),
02948              &dlg, SLOT( slotOk()));
02949 
02950      QMap<QString,QListViewItem*> majorMap;
02951      QListViewItem *majorGroup;
02952      KMimeType::List mimetypes = KMimeType::allMimeTypes();
02953      QValueListIterator<KMimeType::Ptr> it(mimetypes.begin());
02954      for (; it != mimetypes.end(); ++it) {
02955         QString mimetype = (*it)->name();
02956         if (mimetype == "application/octet-stream")
02957            continue;
02958         int index = mimetype.find("/");
02959         QString maj = mimetype.left(index);
02960         QString min = mimetype.mid(index+1);
02961 
02962         QMapIterator<QString,QListViewItem*> mit = majorMap.find( maj );
02963         if ( mit == majorMap.end() ) {
02964            majorGroup = new QListViewItem( mw->listView, maj );
02965            majorGroup->setExpandable(true);
02966            mw->listView->setOpen(majorGroup, true);
02967            majorMap.insert( maj, majorGroup );
02968         }
02969         else
02970         {
02971            majorGroup = mit.data();
02972         }
02973 
02974         QListViewItem *item = new QListViewItem(majorGroup, min, (*it)->comment());
02975         item->setPixmap(0, (*it)->pixmap(KIcon::Small, IconSize(KIcon::Small)));
02976      }
02977      QMapIterator<QString,QListViewItem*> mit = majorMap.find( "all" );
02978      if ( mit != majorMap.end())
02979      {
02980         mw->listView->setCurrentItem(mit.data());
02981         mw->listView->ensureItemVisible(mit.data());
02982      }
02983   }
02984 
02985   if (dlg.exec() == KDialogBase::Accepted)
02986   {
02987      KMimeType::Ptr defaultMimetype = KMimeType::defaultMimeTypePtr();
02988      QListViewItem *majorItem = mw->listView->firstChild();
02989      while(majorItem)
02990      {
02991         QString major = majorItem->text(0);
02992 
02993         QListViewItem *minorItem = majorItem->firstChild();
02994         while(minorItem)
02995         {
02996            if (minorItem->isSelected())
02997            {
02998               QString mimetype = major + "/" + minorItem->text(0);
02999               KMimeType::Ptr p = KMimeType::mimeType(mimetype);
03000               if (p && (p != defaultMimetype))
03001               {
03002                  mimetype = p->name();
03003                  bool found = false;
03004                  QListViewItem *item = w->filetypeList->firstChild();
03005                  while (item)
03006                  {
03007                     if (mimetype == item->text(0))
03008                     {
03009                        found = true;
03010                        break;
03011                     }
03012                     item = item->nextSibling();
03013                  }
03014                  if (!found)
03015                     new QListViewItem(w->filetypeList, p->name(), p->comment());
03016               }
03017            }
03018            minorItem = minorItem->nextSibling();
03019         }
03020 
03021         majorItem = majorItem->nextSibling();
03022      }
03023 
03024   }
03025 }
03026 
03027 void KDesktopPropsPlugin::slotDelFiletype()
03028 {
03029   delete w->filetypeList->currentItem();
03030 }
03031 
03032 void KDesktopPropsPlugin::checkCommandChanged()
03033 {
03034   if (KRun::binaryName(w->commandEdit->text(), true) !=
03035       KRun::binaryName(m_origCommandStr, true))
03036   {
03037     QString m_origCommandStr = w->commandEdit->text();
03038     m_dcopServiceType= QString::null; // Reset
03039   }
03040 }
03041 
03042 void KDesktopPropsPlugin::applyChanges()
03043 {
03044   kdDebug(250) << "KDesktopPropsPlugin::applyChanges" << endl;
03045   QString path = properties->kurl().path();
03046 
03047   QFile f( path );
03048 
03049   if ( !f.open( IO_ReadWrite ) ) {
03050     KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
03051                 "sufficient access to write to <b>%1</b>.</qt>").arg(path));
03052     return;
03053   }
03054   f.close();
03055 
03056   // If the command is changed we reset certain settings that are strongly
03057   // coupled to the command.
03058   checkCommandChanged();
03059 
03060   KSimpleConfig config( path );
03061   config.setDesktopGroup();
03062   config.writeEntry( "Type", QString::fromLatin1("Application"));
03063   config.writeEntry( "Comment", w->commentEdit->text() );
03064   config.writeEntry( "Comment", w->commentEdit->text(), true, false, true ); // for compat
03065   config.writeEntry( "GenericName", w->genNameEdit->text() );
03066   config.writeEntry( "GenericName", w->genNameEdit->text(), true, false, true ); // for compat
03067 
03068   if (m_systrayBool)
03069     config.writePathEntry( "Exec", w->commandEdit->text().prepend("ksystraycmd ") );
03070   else
03071     config.writePathEntry( "Exec", w->commandEdit->text() );
03072   config.writePathEntry( "Path", w->pathEdit->lineEdit()->text() );
03073 
03074   // Write mimeTypes
03075   QStringList mimeTypes;
03076   for( QListViewItem *item = w->filetypeList->firstChild();
03077        item; item = item->nextSibling() )
03078   {
03079     QString preference = item->text(2);
03080     mimeTypes.append(item->text(0));
03081     if (!preference.isEmpty())
03082        mimeTypes.append(preference);
03083   }
03084 
03085   config.writeEntry( "MimeType", mimeTypes, ';' );
03086 
03087   if ( !w->nameEdit->isHidden() ) {
03088       QString nameStr = w->nameEdit->text();
03089       config.writeEntry( "Name", nameStr );
03090       config.writeEntry( "Name", nameStr, true, false, true );
03091   }
03092 
03093   config.writeEntry("Terminal", m_terminalBool);
03094   config.writeEntry("TerminalOptions", m_terminalOptionStr);
03095   config.writeEntry("X-KDE-SubstituteUID", m_suidBool);
03096   config.writeEntry("X-KDE-Username", m_suidUserStr);
03097   config.writeEntry("StartupNotify", m_startupBool);
03098   config.writeEntry("X-DCOP-ServiceType", m_dcopServiceType);
03099   config.sync();
03100 
03101   // KSycoca update needed?
03102   QString sycocaPath = KGlobal::dirs()->relativeLocation("apps", path);
03103   bool updateNeeded = !sycocaPath.startsWith("/");
03104   if (!updateNeeded)
03105   {
03106      sycocaPath = KGlobal::dirs()->relativeLocation("xdgdata-apps", path);
03107      updateNeeded = !sycocaPath.startsWith("/");
03108   }
03109   if (updateNeeded)
03110      KService::rebuildKSycoca(w);
03111 }
03112 
03113 
03114 void KDesktopPropsPlugin::slotBrowseExec()
03115 {
03116   KURL f = KFileDialog::getOpenURL( QString::null,
03117                                       QString::null, w );
03118   if ( f.isEmpty() )
03119     return;
03120 
03121   if ( !f.isLocalFile()) {
03122     KMessageBox::sorry(w, i18n("Only executables on local file systems are supported."));
03123     return;
03124   }
03125 
03126   QString path = f.path();
03127   KRun::shellQuote( path );
03128   w->commandEdit->setText( path );
03129 }
03130 
03131 void KDesktopPropsPlugin::slotAdvanced()
03132 {
03133   KDialogBase dlg(w, "KPropertiesDesktopAdv", true,
03134       i18n("Advanced Options for %1").arg(properties->kurl().fileName()),
03135       KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok);
03136   KPropertiesDesktopAdvBase *w = new KPropertiesDesktopAdvBase(&dlg);
03137 
03138   dlg.setMainWidget(w);
03139 
03140   // If the command is changed we reset certain settings that are strongly
03141   // coupled to the command.
03142   checkCommandChanged();
03143 
03144   // check to see if we use konsole if not do not add the nocloseonexit
03145   // because we don't know how to do this on other terminal applications
03146   KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") );
03147   QString preferredTerminal = confGroup.readPathEntry("TerminalApplication",
03148                           QString::fromLatin1("konsole"));
03149 
03150   bool terminalCloseBool = false;
03151 
03152   if (preferredTerminal == "konsole")
03153   {
03154      terminalCloseBool = (m_terminalOptionStr.contains( "--noclose" ) > 0);
03155      w->terminalCloseCheck->setChecked(terminalCloseBool);
03156      m_terminalOptionStr.replace( "--noclose", "");
03157   }
03158   else
03159   {
03160      w->terminalCloseCheck->hide();
03161   }
03162 
03163   w->terminalCheck->setChecked(m_terminalBool);
03164   w->terminalEdit->setText(m_terminalOptionStr);
03165   w->terminalCloseCheck->setEnabled(m_terminalBool);
03166   w->terminalEdit->setEnabled(m_terminalBool);
03167   w->terminalEditLabel->setEnabled(m_terminalBool);
03168 
03169   w->suidCheck->setChecked(m_suidBool);
03170   w->suidEdit->setText(m_suidUserStr);
03171   w->suidEdit->setEnabled(m_suidBool);
03172   w->suidEditLabel->setEnabled(m_suidBool);
03173 
03174   w->startupInfoCheck->setChecked(m_startupBool);
03175   w->systrayCheck->setChecked(m_systrayBool);
03176 
03177   if (m_dcopServiceType == "unique")
03178     w->dcopCombo->setCurrentItem(2);
03179   else if (m_dcopServiceType == "multi")
03180     w->dcopCombo->setCurrentItem(1);
03181   else if (m_dcopServiceType == "wait")
03182     w->dcopCombo->setCurrentItem(3);
03183   else
03184     w->dcopCombo->setCurrentItem(0);
03185 
03186   // Provide username completion up to 1000 users.
03187   KCompletion *kcom = new KCompletion;
03188   kcom->setOrder(KCompletion::Sorted);
03189   struct passwd *pw;
03190   int i, maxEntries = 1000;
03191   setpwent();
03192   for (i=0; ((pw = getpwent()) != 0L) && (i < maxEntries); i++)
03193     kcom->addItem(QString::fromLatin1(pw->pw_name));
03194   endpwent();
03195   if (i < maxEntries)
03196   {
03197     w->suidEdit->setCompletionObject(kcom, true);
03198     w->suidEdit->setAutoDeleteCompletionObject( true );
03199     w->suidEdit->setCompletionMode(KGlobalSettings::CompletionAuto);
03200   }
03201   else
03202   {
03203     delete kcom;
03204   }
03205 
03206   connect( w->terminalEdit, SIGNAL( textChanged( const QString & ) ),
03207            this, SIGNAL( changed() ) );
03208   connect( w->terminalCloseCheck, SIGNAL( toggled( bool ) ),
03209            this, SIGNAL( changed() ) );
03210   connect( w->terminalCheck, SIGNAL( toggled( bool ) ),
03211            this, SIGNAL( changed() ) );
03212   connect( w->suidCheck, SIGNAL( toggled( bool ) ),
03213            this, SIGNAL( changed() ) );
03214   connect( w->suidEdit, SIGNAL( textChanged( const QString & ) ),
03215            this, SIGNAL( changed() ) );
03216   connect( w->startupInfoCheck, SIGNAL( toggled( bool ) ),
03217            this, SIGNAL( changed() ) );
03218   connect( w->systrayCheck, SIGNAL( toggled( bool ) ),
03219            this, SIGNAL( changed() ) );
03220   connect( w->dcopCombo, SIGNAL( highlighted( int ) ),
03221            this, SIGNAL( changed() ) );
03222 
03223   if ( dlg.exec() == QDialog::Accepted )
03224   {
03225     m_terminalOptionStr = w->terminalEdit->text().stripWhiteSpace();
03226     m_terminalBool = w->terminalCheck->isChecked();
03227     m_suidBool = w->suidCheck->isChecked();
03228     m_suidUserStr = w->suidEdit->text().stripWhiteSpace();
03229     m_startupBool = w->startupInfoCheck->isChecked();
03230     m_systrayBool = w->systrayCheck->isChecked();
03231 
03232     if (w->terminalCloseCheck->isChecked())
03233     {
03234       m_terminalOptionStr.append(" --noclose");
03235     }
03236 
03237     switch(w->dcopCombo->currentItem())
03238     {
03239       case 1:  m_dcopServiceType = "multi"; break;
03240       case 2:  m_dcopServiceType = "unique"; break;
03241       case 3:  m_dcopServiceType = "wait"; break;
03242       default: m_dcopServiceType = "none"; break;
03243     }
03244   }
03245 }
03246 
03247 bool KDesktopPropsPlugin::supports( KFileItemList _items )
03248 {
03249   if ( _items.count() != 1 )
03250     return false;
03251   KFileItem * item = _items.first();
03252   // check if desktop file
03253   if ( !KPropsDlgPlugin::isDesktopFile( item ) )
03254     return false;
03255   // open file and check type
03256   KDesktopFile config( item->url().path(), true /* readonly */ );
03257   return config.hasApplicationType() && kapp->authorize("run_desktop_files") && kapp->authorize("shell_access");
03258 }
03259 
03260 void KPropertiesDialog::virtual_hook( int id, void* data )
03261 { KDialogBase::virtual_hook( id, data ); }
03262 
03263 void KPropsDlgPlugin::virtual_hook( int, void* )
03264 { /*BASE::virtual_hook( id, data );*/ }
03265 
03266 
03267 
03268 
03269 
03275 class KExecPropsPlugin::KExecPropsPluginPrivate
03276 {
03277 public:
03278   KExecPropsPluginPrivate()
03279   {
03280   }
03281   ~KExecPropsPluginPrivate()
03282   {
03283   }
03284 
03285   QFrame *m_frame;
03286   QCheckBox *nocloseonexitCheck;
03287 };
03288 
03289 KExecPropsPlugin::KExecPropsPlugin( KPropertiesDialog *_props )
03290   : KPropsDlgPlugin( _props )
03291 {
03292   d = new KExecPropsPluginPrivate;
03293   d->m_frame = properties->addPage(i18n("E&xecute"));
03294   QVBoxLayout * mainlayout = new QVBoxLayout( d->m_frame, 0,
03295       KDialog::spacingHint());
03296 
03297   // Now the widgets in the top layout
03298 
03299   QLabel* l;
03300   l = new QLabel( i18n( "Comman&d:" ), d->m_frame );
03301   mainlayout->addWidget(l);
03302 
03303   QHBoxLayout * hlayout;
03304   hlayout = new QHBoxLayout(KDialog::spacingHint());
03305   mainlayout->addLayout(hlayout);
03306 
03307   execEdit = new KLineEdit( d->m_frame );
03308   QWhatsThis::add(execEdit,i18n(
03309     "Following the command, you can have several place holders which will be replaced "
03310     "with the actual values when the actual program is run:\n"
03311     "%f - a single file name\n"
03312     "%F - a list of files; use for applications that can open several local files at once\n"
03313     "%u - a single URL\n"
03314     "%U - a list of URLs\n"
03315     "%d - the folder of the file to open\n"
03316     "%D - a list of folders\n"
03317     "%i - the icon\n"
03318     "%m - the mini-icon\n"
03319     "%c - the caption"));
03320   hlayout->addWidget(execEdit, 1);
03321 
03322   l->setBuddy( execEdit );
03323 
03324   execBrowse = new QPushButton( d->m_frame );
03325   execBrowse->setText( i18n("&Browse...") );
03326   hlayout->addWidget(execBrowse);
03327 
03328   // The groupbox about swallowing
03329   QGroupBox* tmpQGroupBox;
03330   tmpQGroupBox = new QGroupBox( i18n("Panel Embedding"), d->m_frame );
03331   tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
03332 
03333   mainlayout->addWidget(tmpQGroupBox);
03334 
03335   QGridLayout *grid = new QGridLayout(tmpQGroupBox->layout(), 2, 2);
03336   grid->setSpacing( KDialog::spacingHint() );
03337   grid->setColStretch(1, 1);
03338 
03339   l = new QLabel( i18n( "&Execute on click:" ), tmpQGroupBox );
03340   grid->addWidget(l, 0, 0);
03341 
03342   swallowExecEdit = new KLineEdit( tmpQGroupBox );
03343   grid->addWidget(swallowExecEdit, 0, 1);
03344 
03345   l->setBuddy( swallowExecEdit );
03346 
03347   l = new QLabel( i18n( "&Window title:" ), tmpQGroupBox );
03348   grid->addWidget(l, 1, 0);
03349 
03350   swallowTitleEdit = new KLineEdit( tmpQGroupBox );
03351   grid->addWidget(swallowTitleEdit, 1, 1);
03352 
03353   l->setBuddy( swallowTitleEdit );
03354 
03355   // The groupbox about run in terminal
03356 
03357   tmpQGroupBox = new QGroupBox( d->m_frame );
03358   tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
03359 
03360   mainlayout->addWidget(tmpQGroupBox);
03361 
03362   grid = new QGridLayout(tmpQGroupBox->layout(), 3, 2);
03363   grid->setSpacing( KDialog::spacingHint() );
03364   grid->setColStretch(1, 1);
03365 
03366   terminalCheck = new QCheckBox( tmpQGroupBox );
03367   terminalCheck->setText( i18n("&Run in terminal") );
03368   grid->addMultiCellWidget(terminalCheck, 0, 0, 0, 1);
03369 
03370   // check to see if we use konsole if not do not add the nocloseonexit
03371   // because we don't know how to do this on other terminal applications
03372   KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") );
03373   QString preferredTerminal = confGroup.readPathEntry("TerminalApplication",
03374                           QString::fromLatin1("konsole"));
03375 
03376   int posOptions = 1;
03377   d->nocloseonexitCheck = 0L;
03378   if (preferredTerminal == "konsole")
03379   {
03380     posOptions = 2;
03381     d->nocloseonexitCheck = new QCheckBox( tmpQGroupBox );
03382     d->nocloseonexitCheck->setText( i18n("Do not &close when command exits") );
03383     grid->addMultiCellWidget(d->nocloseonexitCheck, 1, 1, 0, 1);
03384   }
03385 
03386   terminalLabel = new QLabel( i18n( "&Terminal options:" ), tmpQGroupBox );
03387   grid->addWidget(terminalLabel, posOptions, 0);
03388 
03389   terminalEdit = new KLineEdit( tmpQGroupBox );
03390   grid->addWidget(terminalEdit, posOptions, 1);
03391 
03392   terminalLabel->setBuddy( terminalEdit );
03393 
03394   // The groupbox about run with substituted uid.
03395 
03396   tmpQGroupBox = new QGroupBox( d->m_frame );
03397   tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
03398 
03399   mainlayout->addWidget(tmpQGroupBox);
03400 
03401   grid = new QGridLayout(tmpQGroupBox->layout(), 2, 2);
03402   grid->setSpacing(KDialog::spacingHint());
03403   grid->setColStretch(1, 1);
03404 
03405   suidCheck = new QCheckBox(tmpQGroupBox);
03406   suidCheck->setText(i18n("Ru&n as a different user"));
03407   grid->addMultiCellWidget(suidCheck, 0, 0, 0, 1);
03408 
03409   suidLabel = new QLabel(i18n( "&Username:" ), tmpQGroupBox);
03410   grid->addWidget(suidLabel, 1, 0);
03411 
03412   suidEdit = new KLineEdit(tmpQGroupBox);
03413   grid->addWidget(suidEdit, 1, 1);
03414 
03415   suidLabel->setBuddy( suidEdit );
03416 
03417   mainlayout->addStretch(1);
03418 
03419   // now populate the page
03420   QString path = _props->kurl().path();
03421   QFile f( path );
03422   if ( !f.open( IO_ReadOnly ) )
03423     return;
03424   f.close();
03425 
03426   KSimpleConfig config( path );
03427   config.setDollarExpansion( false );
03428   config.setDesktopGroup();
03429   execStr = config.readPathEntry( "Exec" );
03430   swallowExecStr = config.readPathEntry( "SwallowExec" );
03431   swallowTitleStr = config.readEntry( "SwallowTitle" );
03432   termBool = config.readBoolEntry( "Terminal" );
03433   termOptionsStr = config.readEntry( "TerminalOptions" );
03434   suidBool = config.readBoolEntry( "X-KDE-SubstituteUID" );
03435   suidUserStr = config.readEntry( "X-KDE-Username" );
03436 
03437   if ( !swallowExecStr.isNull() )
03438     swallowExecEdit->setText( swallowExecStr );
03439   if ( !swallowTitleStr.isNull() )
03440     swallowTitleEdit->setText( swallowTitleStr );
03441 
03442   if ( !execStr.isNull() )
03443     execEdit->setText( execStr );
03444 
03445   if ( d->nocloseonexitCheck )
03446   {
03447     d->nocloseonexitCheck->setChecked( (termOptionsStr.contains( "--noclose" ) > 0) );
03448     termOptionsStr.replace( "--noclose", "");
03449   }
03450   if ( !termOptionsStr.isNull() )
03451     terminalEdit->setText( termOptionsStr );
03452 
03453   terminalCheck->setChecked( termBool );
03454   enableCheckedEdit();
03455 
03456   suidCheck->setChecked( suidBool );
03457   suidEdit->setText( suidUserStr );
03458   enableSuidEdit();
03459 
03460   // Provide username completion up to 1000 users.
03461   KCompletion *kcom = new KCompletion;
03462   kcom->setOrder(KCompletion::Sorted);
03463   struct passwd *pw;
03464   int i, maxEntries = 1000;
03465   setpwent();
03466   for (i=0; ((pw = getpwent()) != 0L) && (i < maxEntries); i++)
03467     kcom->addItem(QString::fromLatin1(pw->pw_name));
03468   endpwent();
03469   if (i < maxEntries)
03470   {
03471     suidEdit->setCompletionObject(kcom, true);
03472     suidEdit->setAutoDeleteCompletionObject( true );
03473     suidEdit->setCompletionMode(KGlobalSettings::CompletionAuto);
03474   }
03475   else
03476   {
03477     delete kcom;
03478   }
03479 
03480   connect( swallowExecEdit, SIGNAL( textChanged( const QString & ) ),
03481            this, SIGNAL( changed() ) );
03482   connect( swallowTitleEdit, SIGNAL( textChanged( const QString & ) ),
03483            this, SIGNAL( changed() ) );
03484   connect( execEdit, SIGNAL( textChanged( const QString & ) ),
03485            this, SIGNAL( changed() ) );
03486   connect( terminalEdit, SIGNAL( textChanged( const QString & ) ),
03487            this, SIGNAL( changed() ) );
03488   if (d->nocloseonexitCheck)
03489     connect( d->nocloseonexitCheck, SIGNAL( toggled( bool ) ),
03490            this, SIGNAL( changed() ) );
03491   connect( terminalCheck, SIGNAL( toggled( bool ) ),
03492            this, SIGNAL( changed() ) );
03493   connect( suidCheck, SIGNAL( toggled( bool ) ),
03494            this, SIGNAL( changed() ) );
03495   connect( suidEdit, SIGNAL( textChanged( const QString & ) ),
03496            this, SIGNAL( changed() ) );
03497 
03498   connect( execBrowse, SIGNAL( clicked() ), this, SLOT( slotBrowseExec() ) );
03499   connect( terminalCheck, SIGNAL( clicked() ), this,  SLOT( enableCheckedEdit() ) );
03500   connect( suidCheck, SIGNAL( clicked() ), this,  SLOT( enableSuidEdit() ) );
03501 
03502 }
03503 
03504 KExecPropsPlugin::~KExecPropsPlugin()
03505 {
03506   delete d;
03507 }
03508 
03509 void KExecPropsPlugin::enableCheckedEdit()
03510 {
03511   bool checked = terminalCheck->isChecked();
03512   terminalLabel->setEnabled( checked );
03513   if (d->nocloseonexitCheck)
03514     d->nocloseonexitCheck->setEnabled( checked );
03515   terminalEdit->setEnabled( checked );
03516 }
03517 
03518 void KExecPropsPlugin::enableSuidEdit()
03519 {
03520   bool checked = suidCheck->isChecked();
03521   suidLabel->setEnabled( checked );
03522   suidEdit->setEnabled( checked );
03523 }
03524 
03525 bool KExecPropsPlugin::supports( KFileItemList _items )
03526 {
03527   if ( _items.count() != 1 )
03528     return false;
03529   KFileItem * item = _items.first();
03530   // check if desktop file
03531   if ( !KPropsDlgPlugin::isDesktopFile( item ) )
03532     return false;
03533   // open file and check type
03534   KDesktopFile config( item->url().path(), true /* readonly */ );
03535   return config.hasApplicationType() && kapp->authorize("run_desktop_files") && kapp->authorize("shell_access");
03536 }
03537 
03538 void KExecPropsPlugin::applyChanges()
03539 {
03540   kdDebug(250) << "KExecPropsPlugin::applyChanges" << endl;
03541   QString path = properties->kurl().path();
03542 
03543   QFile f( path );
03544 
03545   if ( !f.open( IO_ReadWrite ) ) {
03546     KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
03547                 "sufficient access to write to <b>%1</b>.</qt>").arg(path));
03548     return;
03549   }
03550   f.close();
03551 
03552   KSimpleConfig config( path );
03553   config.setDesktopGroup();
03554   config.writeEntry( "Type", QString::fromLatin1("Application"));
03555   config.writePathEntry( "Exec", execEdit->text() );
03556   config.writePathEntry( "SwallowExec", swallowExecEdit->text() );
03557   config.writeEntry( "SwallowTitle", swallowTitleEdit->text() );
03558   config.writeEntry( "Terminal", terminalCheck->isChecked() );
03559   QString temp = terminalEdit->text();
03560   if (d->nocloseonexitCheck )
03561     if ( d->nocloseonexitCheck->isChecked() )
03562       temp += QString::fromLatin1("--noclose ");
03563   temp = temp.stripWhiteSpace();
03564   config.writeEntry( "TerminalOptions", temp );
03565   config.writeEntry( "X-KDE-SubstituteUID", suidCheck->isChecked() );
03566   config.writeEntry( "X-KDE-Username", suidEdit->text() );
03567 }
03568 
03569 
03570 void KExecPropsPlugin::slotBrowseExec()
03571 {
03572     KURL f = KFileDialog::getOpenURL( QString::null,
03573                                       QString::null, d->m_frame );
03574     if ( f.isEmpty() )
03575         return;
03576 
03577     if ( !f.isLocalFile()) {
03578         KMessageBox::sorry(d->m_frame, i18n("Only executables on local file systems are supported."));
03579         return;
03580     }
03581 
03582     QString path = f.path();
03583     KRun::shellQuote( path );
03584     execEdit->setText( path );
03585 }
03586 
03587 class KApplicationPropsPlugin::KApplicationPropsPluginPrivate
03588 {
03589 public:
03590   KApplicationPropsPluginPrivate()
03591   {
03592       m_kdesktopMode = QCString(qApp->name()) == "kdesktop"; // nasty heh?
03593   }
03594   ~KApplicationPropsPluginPrivate()
03595   {
03596   }
03597 
03598   QFrame *m_frame;
03599   bool m_kdesktopMode;
03600 };
03601 
03602 KApplicationPropsPlugin::KApplicationPropsPlugin( KPropertiesDialog *_props )
03603   : KPropsDlgPlugin( _props )
03604 {
03605   d = new KApplicationPropsPluginPrivate;
03606   d->m_frame = properties->addPage(i18n("&Application"));
03607   QVBoxLayout *toplayout = new QVBoxLayout( d->m_frame, 0, KDialog::spacingHint());
03608 
03609   QIconSet iconSet;
03610   QPixmap pixMap;
03611 
03612   addExtensionButton = new QPushButton( QString::null, d->m_frame );
03613   iconSet = SmallIconSet( "back" );
03614   addExtensionButton->setIconSet( iconSet );
03615   pixMap = iconSet.pixmap( QIconSet::Small, QIconSet::Normal );
03616   addExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
03617   connect( addExtensionButton, SIGNAL( clicked() ),
03618             SLOT( slotAddExtension() ) );
03619 
03620   delExtensionButton = new QPushButton( QString::null, d->m_frame );
03621   iconSet = SmallIconSet( "forward" );
03622   delExtensionButton->setIconSet( iconSet );
03623   delExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
03624   connect( delExtensionButton, SIGNAL( clicked() ),
03625             SLOT( slotDelExtension() ) );
03626 
03627   QLabel *l;
03628 
03629   QGridLayout *grid = new QGridLayout(2, 2);
03630   grid->setColStretch(1, 1);
03631   toplayout->addLayout(grid);
03632 
03633   if ( d->m_kdesktopMode )
03634   {
03635       // in kdesktop the name field comes from the first tab
03636       nameEdit = 0L;
03637   }
03638   else
03639   {
03640       l = new QLabel(i18n("Name:"), d->m_frame, "Label_4" );
03641       grid->addWidget(l, 0, 0);
03642 
03643       nameEdit = new KLineEdit( d->m_frame, "LineEdit_3" );
03644       grid->addWidget(nameEdit, 0, 1);
03645   }
03646 
03647   l = new QLabel(i18n("Description:"),  d->m_frame, "Label_5" );
03648   grid->addWidget(l, 1, 0);
03649 
03650   genNameEdit = new KLineEdit( d->m_frame, "LineEdit_4" );
03651   grid->addWidget(genNameEdit, 1, 1);
03652 
03653   l = new QLabel(i18n("Comment:"),  d->m_frame, "Label_3" );
03654   grid->addWidget(l, 2, 0);
03655 
03656   commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" );
03657   grid->addWidget(commentEdit, 2, 1);
03658 
03659   l = new QLabel(i18n("File types:"), d->m_frame);
03660   toplayout->addWidget(l, 0, AlignLeft);
03661 
03662   grid = new QGridLayout(4, 3);
03663   grid->setColStretch(0, 1);
03664   grid->setColStretch(2, 1);
03665   grid->setRowStretch( 0, 1 );
03666   grid->setRowStretch( 3, 1 );
03667   toplayout->addLayout(grid, 2);
03668 
03669   extensionsList = new QListBox( d->m_frame );
03670   extensionsList->setSelectionMode( QListBox::Extended );
03671   grid->addMultiCellWidget(extensionsList, 0, 3, 0, 0);
03672 
03673   grid->addWidget(addExtensionButton, 1, 1);
03674   grid->addWidget(delExtensionButton, 2, 1);
03675 
03676   availableExtensionsList = new QListBox( d->m_frame );
03677   availableExtensionsList->setSelectionMode( QListBox::Extended );
03678   grid->addMultiCellWidget(availableExtensionsList, 0, 3, 2, 2);
03679 
03680   QString path = properties->kurl().path() ;
03681   QFile f( path );
03682   if ( !f.open( IO_ReadOnly ) )
03683     return;
03684   f.close();
03685 
03686   KSimpleConfig config( path );
03687   config.setDesktopGroup();
03688   QString commentStr = config.readEntry( "Comment" );
03689   QString genNameStr = config.readEntry( "GenericName" );
03690 
03691   QStringList selectedTypes = config.readListEntry( "ServiceTypes" );
03692   // For compatibility with KDE 1.x
03693   selectedTypes += config.readListEntry( "MimeType", ';' );
03694 
03695   QString nameStr = config.readEntry( QString::fromLatin1("Name") );
03696   if ( nameStr.isEmpty() || d->m_kdesktopMode ) {
03697     // We'll use the file name if no name is specified
03698     // because we _need_ a Name for a valid file.
03699     // But let's do it in apply, not here, so that we pick up the right name.
03700     setDirty();
03701   }
03702 
03703   commentEdit->setText( commentStr );
03704   genNameEdit->setText( genNameStr );
03705   if ( nameEdit )
03706       nameEdit->setText( nameStr );
03707 
03708   selectedTypes.sort();
03709   QStringList::Iterator sit = selectedTypes.begin();
03710   for( ; sit != selectedTypes.end(); ++sit ) {
03711     if ( !((*sit).isEmpty()) )
03712       extensionsList->insertItem( *sit );
03713   }
03714 
03715   KMimeType::List mimeTypes = KMimeType::allMimeTypes();
03716   QValueListIterator<KMimeType::Ptr> it2 = mimeTypes.begin();
03717   for ( ; it2 != mimeTypes.end(); ++it2 )
03718     addMimeType ( (*it2)->name() );
03719 
03720   updateButton();
03721 
03722   connect( extensionsList, SIGNAL( highlighted( int ) ),
03723            this, SLOT( updateButton() ) );
03724   connect( availableExtensionsList, SIGNAL( highlighted( int ) ),
03725            this, SLOT( updateButton() ) );
03726 
03727   connect( addExtensionButton, SIGNAL( clicked() ),
03728            this, SIGNAL( changed() ) );
03729   connect( delExtensionButton, SIGNAL( clicked() ),
03730            this, SIGNAL( changed() ) );
03731   if ( nameEdit )
03732       connect( nameEdit, SIGNAL( textChanged( const QString & ) ),
03733                this, SIGNAL( changed() ) );
03734   connect( commentEdit, SIGNAL( textChanged( const QString & ) ),
03735            this, SIGNAL( changed() ) );
03736   connect( genNameEdit, SIGNAL( textChanged( const QString & ) ),
03737            this, SIGNAL( changed() ) );
03738   connect( availableExtensionsList, SIGNAL( selected( int ) ),
03739            this, SIGNAL( changed() ) );
03740   connect( extensionsList, SIGNAL( selected( int ) ),
03741            this, SIGNAL( changed() ) );
03742 }
03743 
03744 KApplicationPropsPlugin::~KApplicationPropsPlugin()
03745 {
03746   delete d;
03747 }
03748 
03749 // QString KApplicationPropsPlugin::tabName () const
03750 // {
03751 //   return i18n ("&Application");
03752 // }
03753 
03754 void KApplicationPropsPlugin::updateButton()
03755 {
03756     addExtensionButton->setEnabled(availableExtensionsList->currentItem()>-1);
03757     delExtensionButton->setEnabled(extensionsList->currentItem()>-1);
03758 }
03759 
03760 void KApplicationPropsPlugin::addMimeType( const QString & name )
03761 {
03762   // Add a mimetype to the list of available mime types if not in the extensionsList
03763 
03764   bool insert = true;
03765 
03766   for ( uint i = 0; i < extensionsList->count(); i++ )
03767     if ( extensionsList->text( i ) == name )
03768       insert = false;
03769 
03770   if ( insert )
03771   {
03772     availableExtensionsList->insertItem( name );
03773     availableExtensionsList->sort();
03774   }
03775 }
03776 
03777 bool KApplicationPropsPlugin::supports( KFileItemList _items )
03778 {
03779   // same constraints as KExecPropsPlugin : desktop file with Type = Application
03780   return KExecPropsPlugin::supports( _items );
03781 }
03782 
03783 void KApplicationPropsPlugin::applyChanges()
03784 {
03785   QString path = properties->kurl().path();
03786 
03787   QFile f( path );
03788 
03789   if ( !f.open( IO_ReadWrite ) ) {
03790     KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not "
03791                 "have sufficient access to write to <b>%1</b>.</qt>").arg(path));
03792     return;
03793   }
03794   f.close();
03795 
03796   KSimpleConfig config( path );
03797   config.setDesktopGroup();
03798   config.writeEntry( "Type", QString::fromLatin1("Application"));
03799   config.writeEntry( "Comment", commentEdit->text() );
03800   config.writeEntry( "Comment", commentEdit->text(), true, false, true ); // for compat
03801   config.writeEntry( "GenericName", genNameEdit->text() );
03802   config.writeEntry( "GenericName", genNameEdit->text(), true, false, true ); // for compat
03803 
03804   QStringList selectedTypes;
03805   for ( uint i = 0; i < extensionsList->count(); i++ )
03806     selectedTypes.append( extensionsList->text( i ) );
03807 
03808   config.writeEntry( "MimeType", selectedTypes, ';' );
03809   config.writeEntry( "ServiceTypes", "" );
03810   // hmm, actually it should probably be the contrary (but see also typeslistitem.cpp)
03811 
03812   QString nameStr = nameEdit ? nameEdit->text() : QString::null;
03813   if ( nameStr.isEmpty() ) // nothing entered, or widget not existing at all (kdesktop mode)
03814     nameStr = nameFromFileName(properties->kurl().fileName());
03815 
03816   config.writeEntry( "Name", nameStr );
03817   config.writeEntry( "Name", nameStr, true, false, true );
03818 
03819   config.sync();
03820 }
03821 
03822 void KApplicationPropsPlugin::slotAddExtension()
03823 {
03824   QListBoxItem *item = availableExtensionsList->firstItem();
03825   QListBoxItem *nextItem;
03826 
03827   while ( item )
03828   {
03829     nextItem = item->next();
03830 
03831     if ( item->isSelected() )
03832     {
03833       extensionsList->insertItem( item->text() );
03834       availableExtensionsList->removeItem( availableExtensionsList->index( item ) );
03835     }
03836 
03837     item = nextItem;
03838   }
03839 
03840   extensionsList->sort();
03841   updateButton();
03842 }
03843 
03844 void KApplicationPropsPlugin::slotDelExtension()
03845 {
03846   QListBoxItem *item = extensionsList->firstItem();
03847   QListBoxItem *nextItem;
03848 
03849   while ( item )
03850   {
03851     nextItem = item->next();
03852 
03853     if ( item->isSelected() )
03854     {
03855       availableExtensionsList->insertItem( item->text() );
03856       extensionsList->removeItem( extensionsList->index( item ) );
03857     }
03858 
03859     item = nextItem;
03860   }
03861 
03862   availableExtensionsList->sort();
03863   updateButton();
03864 }
03865 
03866 
03867 
03868 #include "kpropertiesdialog.moc"
KDE Logo
This file is part of the documentation for kio Library Version 3.3.90.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 30 10:15:30 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003