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