| # kio Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# 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  */
    00041
    00042 #include <config.h>
    00043 extern "C" {
    00044 #include <pwd.h>
    00045 #include <grp.h>
    00046 #include <time.h>
    00047 }
    00048 #include <unistd.h>
    00049 #include <errno.h>
    00050 #include <assert.h>
    00051
    00052 #ifdef HAVE_MNTENT_H
    00053 #include <mntent.h>
    00054 #endif
    00055
    00056 #include <qfile.h>
    00057 #include <qdir.h>
    00058 #include <qlabel.h>
    00059 #include <qpushbutton.h>
    00060 #include <qcheckbox.h>
    00061 #include <qstrlist.h>
    00062 #include <qstringlist.h>
    00063 #include <qtextstream.h>
    00064 #include <qpainter.h>
    00065 #include <qlayout.h>
    00066 #include <qcombobox.h>
    00067 #include <qgroupbox.h>
    00068
    00069 #include <kapplication.h>
    00070 #include <kdialog.h>
    00071 #include <kdirsize.h>
    00072 #include <kdirwatch.h>
    00073 #include <kdirnotify_stub.h>
    00074 #include <kdiskfreesp.h>
    00075 #include <kdebug.h>
    00076 #include <kdesktopfile.h>
    00077 #include <kicondialog.h>
    00078 #include <kurl.h>
    00079 #include <kurlrequester.h>
    00080 #include <klocale.h>
    00081 #include <kglobal.h>
    00082 #include <kglobalsettings.h>
    00083 #include <kstandarddirs.h>
    00084 #include <kio/job.h>
    00085 #include <kio/chmodjob.h>
    00086 #include <kio/renamedlg.h>
    00087 #include <kfiledialog.h>
    00088 #include <kmimetype.h>
    00089 #include <kiconloader.h>
    00090 #include <kmessagebox.h>
    00091 #include <kservice.h>
    00092 #include <kcompletion.h>
    00093 #include <klineedit.h>
    00094 #include <kseparator.h>
    00095 #include <ksqueezedtextlabel.h>
    00096 #include <klibloader.h>
    00097 #include <ktrader.h>
    00098 #include <kparts/componentfactory.h>
    00099 #include <kmetaprops.h>
    00100 #include <krun.h>
    00101 #include "kfilesharedlg.h"
    00102
    00103 #include "kpropertiesdialog.h"
    00104
    00105 #ifdef Q_WS_X11
    00106 extern "C" {
    00107 #include <X11/Xlib.h> // for XSetTransientForHint
    00108 }
    00109 #endif
    00110
    00111 mode_t KFilePermissionsPropsPlugin::fperm[3][4] = {
    00112         {S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID},
    00113         {S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID},
    00114         {S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX}
    00115     };
    00116
    00117 class KPropertiesDialog::KPropertiesDialogPrivate
    00118 {
    00119 public:
    00120   KPropertiesDialogPrivate()
    00121   {
    00122     m_aborted = false;
    00123   }
    00124   ~KPropertiesDialogPrivate()
    00125   {
    00126   }
    00127   bool m_aborted:1;
    00128   bool modal:1;
    00129   bool autoShow:1;
    00130 };
    00131
    00132 KPropertiesDialog::KPropertiesDialog (KFileItem* item,
    00133                                       QWidget* parent, const char* name,
    00134                                       bool modal, bool autoShow)
    00135   : KDialogBase (KDialogBase::Tabbed, i18n( "Properties for %1" ).arg(KIO::decodeFileName(item->url().fileName())),
    00136                  KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
    00137                  parent, name, modal)
    00138 {
    00139   d = new KPropertiesDialogPrivate;
    00140   assert( item );
    00141   m_items.append( new KFileItem(*item) ); // deep copy
    00142
    00143   m_singleUrl = item->url();
    00144   assert(!m_singleUrl.isEmpty());
    00145
    00146   init (modal, autoShow);
    00147 }
    00148
    00149 KPropertiesDialog::KPropertiesDialog (const QString& title,
    00150                                       QWidget* parent, const char* name, bool modal)
    00151   : KDialogBase (KDialogBase::Tabbed, i18n ("Properties for %1").arg(title),
    00152                  KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
    00153                  parent, name, modal)
    00154 {
    00155   d = new KPropertiesDialogPrivate;
    00156
    00157   init (modal, false);
    00158 }
    00159
    00160 KPropertiesDialog::KPropertiesDialog (KFileItemList _items,
    00161                                       QWidget* parent, const char* name,
    00162                                       bool modal, bool autoShow)
    00163   : KDialogBase (KDialogBase::Tabbed, i18n( "Properties for %1" ).arg(KIO::decodeFileName(_items.first()->url().fileName())),
    00164                  KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
    00165                  parent, name, modal)
    00166 {
    00167   d = new KPropertiesDialogPrivate;
    00168
    00169   assert( !_items.isEmpty() );
    00170   m_singleUrl = _items.first()->url();
    00171   assert(!m_singleUrl.isEmpty());
    00172
    00173   KFileItemListIterator it ( _items );
    00174   // Deep copy
    00175   for ( ; it.current(); ++it )
    00176       m_items.append( new KFileItem( **it ) );
    00177
    00178   init (modal, autoShow);
    00179 }
    00180
    00181 #ifndef KDE_NO_COMPAT
    00182 KPropertiesDialog::KPropertiesDialog (const KURL& _url, mode_t /* _mode is now unused */,
    00183                                       QWidget* parent, const char* name,
    00184                                       bool modal, bool autoShow)
    00185   : KDialogBase (KDialogBase::Tabbed, i18n( "Properties for %1" ).arg(KIO::decodeFileName(_url.fileName())),
    00186                  KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
    00187                  parent, name, modal),
    00188   m_singleUrl( _url )
    00189 {
    00190   d = new KPropertiesDialogPrivate;
    00191   d->modal = modal;
    00192   d->autoShow = autoShow;
    00193
    00194   assert(!_url.isEmpty());
    00195
    00196   KIO::StatJob * job = KIO::stat( _url );
    00197   connect( job, SIGNAL( result( KIO::Job * ) ),
    00198            SLOT( slotStatResult( KIO::Job * ) ) );
    00199 }
    00200 #endif
    00201
    00202 KPropertiesDialog::KPropertiesDialog (const KURL& _url,
    00203                                       QWidget* parent, const char* name,
    00204                                       bool modal, bool autoShow)
    00205   : KDialogBase (KDialogBase::Tabbed, i18n( "Properties for %1" ).arg(KIO::decodeFileName(_url.fileName())),
    00206                  KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
    00207                  parent, name, modal),
    00208   m_singleUrl( _url )
    00209 {
    00210   d = new KPropertiesDialogPrivate;
    00211   d->modal = modal;
    00212   d->autoShow = autoShow;
    00213
    00214   assert(!_url.isEmpty());
    00215
    00216   KIO::StatJob * job = KIO::stat( _url );
    00217   connect( job, SIGNAL( result( KIO::Job * ) ),
    00218            SLOT( slotStatResult( KIO::Job * ) ) );
    00219 }
    00220
    00221 KPropertiesDialog::KPropertiesDialog (const KURL& _tempUrl, const KURL& _currentDir,
    00222                                       const QString& _defaultName,
    00223                                       QWidget* parent, const char* name,
    00224                                       bool modal, bool autoShow)
    00225   : KDialogBase (KDialogBase::Tabbed, i18n( "Properties for %1" ).arg(KIO::decodeFileName(_tempUrl.fileName())),
    00226                  KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
    00227                  parent, name, modal),
    00228
    00229   m_singleUrl( _tempUrl ),
    00230   m_defaultName( _defaultName ),
    00231   m_currentDir( _currentDir )
    00232 {
    00233   d = new KPropertiesDialogPrivate;
    00234
    00235   assert(!m_singleUrl.isEmpty());
    00236
    00237   // Create the KFileItem for the _template_ file, in order to read from it.
    00238   m_items.append( new KFileItem( KFileItem::Unknown, KFileItem::Unknown, m_singleUrl ) );
    00239   init (modal, autoShow);
    00240 }
    00241
    00242 void KPropertiesDialog::init (bool modal, bool autoShow)
    00243 {
    00244   m_pageList.setAutoDelete( true );
    00245   m_items.setAutoDelete( true );
    00246
    00247 #ifdef Q_WS_X11 // FIXME(E): Can we do something similar for Qt Embedded?
    00248   // Matthias: let the dialog look like a modal dialog
    00249   if (!modal)
    00250     XSetTransientForHint(qt_xdisplay(), winId(), winId());
    00251 #endif
    00252
    00253   //  resize( 400, 400 ); // not sure what that's for
    00254
    00255   insertPages();
    00256
    00257   //kdDebug(250) << "KPropertiesDialog sizeHint " << sizeHint().width() << "x" << sizeHint().height() << endl;
    00258   // This HACK forces KDialogBase to recompute the layout
    00259   // It is necessary for the case where init is not called from the constructor,
    00260   // but from slotStatResult. And I'm way too lazy to look into KDialogBase...
    00261   enableLinkedHelp( true );
    00262   enableLinkedHelp( false );
    00263   resize(sizeHint());
    00264
    00265   if (autoShow)
    00266     {
    00267       if (!modal)
    00268         show();
    00269       else
    00270         exec();
    00271     }
    00272 }
    00273
    00274 void KPropertiesDialog::showFileSharingPage()
    00275 {
    00276     KPropsDlgPlugin *it;
    00277
    00278     for ( it=m_pageList.first(); it != 0L; it=m_pageList.next() )
    00279     {
    00280         KFileSharePropsPlugin* plugin = dynamic_cast<KFileSharePropsPlugin*>(it);
    00281         if ( plugin )
    00282         {
    00283             showPage( pageIndex( plugin->page() ) );
    00284             break;
    00285         }
    00286     }
    00287 }
    00288
    00289 void KPropertiesDialog::slotStatResult( KIO::Job * job )
    00290 {
    00291     if (job->error())
    00292     {
    00293         job->showErrorDialog( this );
    00294         delete this;
    00295     }
    00296     else
    00297     {
    00298         KIO::StatJob * statJob = static_cast<KIO::StatJob*>(job);
    00299         m_items.append( new KFileItem( statJob->statResult(), statJob->url() ) );
    00300         init (d->modal, d->autoShow);
    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   return KFilePropsPlugin::supports( _items ) ||
    00321          KFilePermissionsPropsPlugin::supports( _items ) ||
    00322          KExecPropsPlugin::supports( _items ) ||
    00323          KApplicationPropsPlugin::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 ( KExecPropsPlugin::supports( m_items ) )
    00402   {
    00403     KPropsDlgPlugin *p = new KExecPropsPlugin( this );
    00404     insertPlugin (p);
    00405   }
    00406
    00407   if ( KApplicationPropsPlugin::supports( m_items ) )
    00408   {
    00409     KPropsDlgPlugin *p = new KApplicationPropsPlugin( this );
    00410     insertPlugin (p);
    00411   }
    00412
    00413   if ( KBindingPropsPlugin::supports( m_items ) )
    00414   {
    00415     KPropsDlgPlugin *p = new KBindingPropsPlugin( this );
    00416     insertPlugin (p);
    00417   }
    00418
    00419   if ( KURLPropsPlugin::supports( m_items ) )
    00420   {
    00421     KPropsDlgPlugin *p = new KURLPropsPlugin( this );
    00422     insertPlugin (p);
    00423   }
    00424
    00425   if ( KDevicePropsPlugin::supports( m_items ) )
    00426   {
    00427     KPropsDlgPlugin *p = new KDevicePropsPlugin( this );
    00428     insertPlugin (p);
    00429   }
    00430
    00431   if ( KFileMetaPropsPlugin::supports( m_items ) )
    00432   {
    00433     KPropsDlgPlugin *p = new KFileMetaPropsPlugin( this );
    00434     insertPlugin (p);
    00435   }
    00436
    00437   if ( KFileSharePropsPlugin::supports( m_items ) )
    00438   {
    00439     KPropsDlgPlugin *p = new KFileSharePropsPlugin( this );
    00440     insertPlugin (p);
    00441   }
    00442
    00443   //plugins
    00444
    00445   if ( m_items.count() != 1 )
    00446     return;
    00447
    00448   KFileItem *item = m_items.first();
    00449   QString mimetype = item->mimetype();
    00450
    00451   if ( mimetype.isEmpty() )
    00452     return;
    00453
    00454   QString query = QString::fromLatin1(
    00455       "('KPropsDlg/Plugin' in ServiceTypes) and "
    00456       "((not exist [X-KDE-Protocol]) or "
    00457       " ([X-KDE-Protocol] == '%1'  )   )"          ).arg(item->url().protocol());
    00458
    00459   kdDebug( 250 ) << "trader query: " << query << endl;
    00460   KTrader::OfferList offers = KTrader::self()->query( mimetype, query );
    00461   KTrader::OfferList::ConstIterator it = offers.begin();
    00462   KTrader::OfferList::ConstIterator end = offers.end();
    00463   for (; it != end; ++it )
    00464   {
    00465     KPropsDlgPlugin *plugin = KParts::ComponentFactory
    00466         ::createInstanceFromLibrary<KPropsDlgPlugin>( (*it)->library().local8Bit().data(),
    00467                                                       this,
    00468                                                       (*it)->name().latin1() );
    00469     if ( !plugin )
    00470         continue;
    00471
    00472     insertPlugin( plugin );
    00473   }
    00474 }
    00475
    00476 void KPropertiesDialog::updateUrl( const KURL& _newUrl )
    00477 {
    00478   Q_ASSERT( m_items.count() == 1 );
    00479   kdDebug(250) << "KPropertiesDialog::updateUrl " << _newUrl.url() << endl;
    00480   m_singleUrl = _newUrl;
    00481   m_items.first()->setURL( _newUrl );
    00482   assert(!m_singleUrl.isEmpty());
    00483   // If we have an Exec page, set it dirty, so that a full file is saved locally
    00484   // Same for a URL page (because of the Name= hack)
    00485   for ( QPtrListIterator<KPropsDlgPlugin> it(m_pageList); it.current(); ++it )
    00486    if ( it.current()->isA("KExecPropsPlugin") || it.current()->isA("KURLPropsPlugin") )
    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->dialog()->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() == QString::fromLatin1("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   }
    00600   ~KFilePropsPluginPrivate()
    00601   {
    00602     if ( dirSizeJob )
    00603       dirSizeJob->kill();
    00604   }
    00605
    00606   KDirSize * dirSizeJob;
    00607   QFrame *m_frame;
    00608   bool bMultiple;
    00609   QLabel *m_freeSpaceLabel;
    00610 };
    00611
    00612 KFilePropsPlugin::KFilePropsPlugin( KPropertiesDialog *_props )
    00613   : KPropsDlgPlugin( _props )
    00614 {
    00615   d = new KFilePropsPluginPrivate;
    00616   d->bMultiple = (properties->items().count() > 1);
    00617   kdDebug(250) << "KFilePropsPlugin::KFilePropsPlugin bMultiple=" << d->bMultiple << endl;
    00618
    00619   // We set this data from the first item, and we'll
    00620   // check that the other items match against it, resetting when not.
    00621   bool isLocal = properties->kurl().isLocalFile();
    00622   KFileItem * item = properties->item();
    00623   bool bDesktopFile = isDesktopFile(item);
    00624   mode_t mode = item->mode();
    00625   bool hasDirs = item->isDir() && !item->isLink();
    00626   bool hasRoot = isLocal && properties->kurl().path() == QString::fromLatin1("/");
    00627   QString iconStr = KMimeType::iconForURL(properties->kurl(), mode);
    00628   QString directory = properties->kurl().directory();
    00629   QString protocol = properties->kurl().protocol();
    00630   QString mimeComment = item->mimeComment();
    00631   KIO::filesize_t totalSize = item->size();
    00632   QString magicMimeComment;
    00633   if ( isLocal ) {
    00634       KMimeType::Ptr magicMimeType = KMimeType::findByFileContent( properties->kurl().path() );
    00635       if ( magicMimeType->name() != KMimeType::defaultMimeType() )
    00636           magicMimeComment = magicMimeType->comment();
    00637   }
    00638
    00639   // Those things only apply to 'single file' mode
    00640   QString filename = QString::null;
    00641   bool isTrash = false;
    00642   m_bFromTemplate = false;
    00643
    00644   // And those only to 'multiple' mode
    00645   uint iDirCount = S_ISDIR(mode) ? 1 : 0;
    00646   uint iFileCount = 1-iDirCount;
    00647
    00648   d->m_frame = properties->dialog()->addPage (i18n("&General"));
    00649
    00650   QVBoxLayout *vbl = new QVBoxLayout( d->m_frame, KDialog::marginHint(),
    00651                                       KDialog::spacingHint(), "vbl");
    00652   QGridLayout *grid = new QGridLayout(0, 3); // unknown rows
    00653   grid->setColStretch(2, 1);
    00654   grid->addColSpacing(1, KDialog::spacingHint());
    00655   vbl->addLayout(grid);
    00656   int curRow = 0;
    00657
    00658   if ( !d->bMultiple )
    00659   {
    00660     // Extract the file name only
    00661     filename = properties->defaultName();
    00662     if ( filename.isEmpty() ) // no template
    00663       filename = properties->kurl().fileName();
    00664     else
    00665     {
    00666       m_bFromTemplate = true;
    00667       setDirty(); // to enforce that the copy happens
    00668     }
    00669     oldName = filename;
    00670
    00671     // Make it human-readable (%2F => '/', ...)
    00672     filename = KIO::decodeFileName( filename );
    00673
    00674     QString path;
    00675
    00676     if ( !m_bFromTemplate ) {
    00677       QString tmp = properties->kurl().path( 1 );
    00678       // is it the trash bin ?
    00679       if ( isLocal && tmp == KGlobalSettings::trashPath())
    00680         isTrash = true;
    00681
    00682       // Extract the full name, but without file: for local files
    00683       if ( isLocal )
    00684         path = properties->kurl().path();
    00685       else
    00686         path = properties->kurl().prettyURL();
    00687     } else {
    00688       path = properties->currentDir().path(1) + properties->defaultName();
    00689       directory = properties->currentDir().prettyURL();
    00690     }
    00691
    00692     if (KExecPropsPlugin::supports(properties->items()) ||
    00693         KBindingPropsPlugin::supports(properties->items())) {
    00694
    00695       determineRelativePath( path );
    00696
    00697     }
    00698
    00699   }
    00700   else
    00701   {
    00702     // Multiple items: see what they have in common
    00703     KFileItemList items = properties->items();
    00704     KFileItemListIterator it( items );
    00705     for ( ++it /*no need to check the first one again*/ ; it.current(); ++it )
    00706     {
    00707       KURL url = (*it)->url();
    00708       kdDebug(250) << "KFilePropsPlugin::KFilePropsPlugin " << url.prettyURL() << endl;
    00709       // The list of things we check here should match the variables defined
    00710       // at the beginning of this method.
    00711       if ( url.isLocalFile() != isLocal )
    00712         isLocal = false; // not all local
    00713       if ( bDesktopFile && isDesktopFile(*it) != bDesktopFile )
    00714         bDesktopFile = false; // not all desktop files
    00715       if ( (*it)->mode() != mode )
    00716         mode = (mode_t)0;
    00717       if ( KMimeType::iconForURL(url, mode) != iconStr )
    00718         iconStr = "kmultiple";
    00719       if ( url.directory() != directory )
    00720         directory = QString::null;
    00721       if ( url.protocol() != protocol )
    00722         protocol = QString::null;
    00723       if ( !mimeComment.isNull() && (*it)->mimeComment() != mimeComment )
    00724         mimeComment = QString::null;
    00725       if ( isLocal && !magicMimeComment.isNull() ) {
    00726           KMimeType::Ptr magicMimeType = KMimeType::findByFileContent( url.path() );
    00727           if ( magicMimeType->comment() != magicMimeComment )
    00728               magicMimeComment = QString::null;
    00729       }
    00730
    00731       if ( isLocal && url.path() == QString::fromLatin1("/") )
    00732         hasRoot = true;
    00733       if ( (*it)->isDir() && !(*it)->isLink() )
    00734       {
    00735         iDirCount++;
    00736         hasDirs = true;
    00737       }
    00738       else
    00739       {
    00740         iFileCount++;
    00741         totalSize += (*it)->size();
    00742       }
    00743     }
    00744   }
    00745
    00746   if (!isLocal && !protocol.isEmpty())
    00747   {
    00748     directory += ' ';
    00749     directory += '(';
    00750     directory += protocol;
    00751     directory += ')';
    00752   }
    00753
    00754   if ( (bDesktopFile || S_ISDIR(mode)) && !d->bMultiple /*not implemented for multiple*/ )
    00755   {
    00756     KIconButton *iconButton = new KIconButton( d->m_frame );
    00757     iconButton->setFixedSize(70, 70);
    00758     iconButton->setStrictIconSize(false);
    00759     iconButton->setIconType(KIcon::Desktop, KIcon::Device);
    00760     // This works for everything except Device icons on unmounted devices
    00761     // So we have to really open .desktop files
    00762     QString iconStr = KMimeType::findByURL( properties->kurl(),
    00763                                             mode )->icon( properties->kurl(),
    00764                                                           isLocal );
    00765     if ( bDesktopFile && isLocal )
    00766     {
    00767       KSimpleConfig config( properties->kurl().path() );
    00768       config.setDesktopGroup();
    00769       iconStr = config.readEntry( QString::fromLatin1("Icon") );
    00770     }
    00771     iconButton->setIcon(iconStr);
    00772     iconArea = iconButton;
    00773     connect( iconButton, SIGNAL( iconChanged(QString) ),
    00774              this, SIGNAL( changed() ) );
    00775   } else {
    00776     QLabel *iconLabel = new QLabel( d->m_frame );
    00777     iconLabel->setFixedSize(70, 70);
    00778     iconLabel->setPixmap( DesktopIcon( iconStr ) );
    00779     iconArea = iconLabel;
    00780   }
    00781   grid->addWidget(iconArea, curRow, 0, AlignLeft);
    00782
    00783   if (d->bMultiple || isTrash || filename == QString::fromLatin1("/"))
    00784   {
    00785     QLabel *lab = new QLabel(d->m_frame );
    00786     if ( d->bMultiple )
    00787       lab->setText( KIO::itemsSummaryString( iFileCount + iDirCount, iFileCount, iDirCount, 0, false ) );
    00788     else
    00789       lab->setText( filename );
    00790     nameArea = lab;
    00791   } else
    00792   {
    00793     KLineEdit *lined = new KLineEdit( d->m_frame );
    00794     lined->setText(filename);
    00795     nameArea = lined;
    00796     lined->setFocus();
    00797     connect( lined, SIGNAL( textChanged( const QString & ) ),
    00798              this, SLOT( nameFileChanged(const QString & ) ) );
    00799   }
    00800
    00801   grid->addWidget(nameArea, curRow++, 2);
    00802
    00803   KSeparator* sep = new KSeparator( KSeparator::HLine, d->m_frame);
    00804   grid->addMultiCellWidget(sep, curRow, curRow, 0, 2);
    00805   ++curRow;
    00806
    00807   QLabel *l;
    00808   if ( !mimeComment.isEmpty() )
    00809   {
    00810     l = new QLabel(i18n("Type:"), d->m_frame );
    00811     grid->addWidget(l, curRow, 0);
    00812
    00813     l = new QLabel(mimeComment, d->m_frame );
    00814     grid->addWidget(l, curRow++, 2);
    00815   }
    00816
    00817   if ( !magicMimeComment.isEmpty() && magicMimeComment != mimeComment )
    00818   {
    00819     l = new QLabel(i18n("Contents:"), d->m_frame );
    00820     grid->addWidget(l, curRow, 0);
    00821
    00822     l = new QLabel(magicMimeComment, d->m_frame );
    00823     grid->addWidget(l, curRow++, 2);
    00824   }
    00825
    00826   if ( !directory.isEmpty() )
    00827   {
    00828     l = new QLabel( i18n("Location:"), d->m_frame );
    00829     grid->addWidget(l, curRow, 0);
    00830
    00831     l = new KSqueezedTextLabel( d->m_frame );
    00832     l->setText( directory );
    00833     grid->addWidget(l, curRow++, 2);
    00834   }
    00835
    00836   l = new QLabel(i18n("Size:"), d->m_frame );
    00837   grid->addWidget(l, curRow, 0);
    00838
    00839   m_sizeLabel = new QLabel( d->m_frame );
    00840   grid->addWidget( m_sizeLabel, curRow++, 2 );
    00841
    00842   if ( !hasDirs ) // Only files [and symlinks]
    00843   {
    00844     m_sizeLabel->setText(QString::fromLatin1("%1 (%2)").arg(KIO::convertSize(totalSize)).arg(KGlobal::locale()->formatNumber(totalSize, 0)));
    00845     m_sizeDetermineButton = 0L;
    00846     m_sizeStopButton = 0L;
    00847   }
    00848   else // Directory
    00849   {
    00850     QHBoxLayout * sizelay = new QHBoxLayout(KDialog::spacingHint());
    00851     grid->addLayout( sizelay, curRow++, 2 );
    00852
    00853     // buttons
    00854     m_sizeDetermineButton = new QPushButton( i18n("Calculate"), d->m_frame );
    00855     m_sizeStopButton = new QPushButton( i18n("Stop"), d->m_frame );
    00856     connect( m_sizeDetermineButton, SIGNAL( clicked() ), this, SLOT( slotSizeDetermine() ) );
    00857     connect( m_sizeStopButton, SIGNAL( clicked() ), this, SLOT( slotSizeStop() ) );
    00858     sizelay->addWidget(m_sizeDetermineButton, 0);
    00859     sizelay->addWidget(m_sizeStopButton, 0);
    00860     sizelay->addStretch(10); // so that the buttons don't grow horizontally
    00861
    00862     // auto-launch for local dirs only, and not for '/'
    00863     if ( isLocal && !hasRoot )
    00864     {
    00865       m_sizeDetermineButton->setText( i18n("Refresh") );
    00866       slotSizeDetermine();
    00867     }
    00868     else
    00869       m_sizeStopButton->setEnabled( false );
    00870   }
    00871
    00872   if ( isLocal )
    00873   {
    00874       QString mountPoint = KIO::findPathMountPoint( properties->item()->url().path() );
    00875
    00876       l = new QLabel(i18n("Free space on %1:").arg(mountPoint), d->m_frame );
    00877       grid->addWidget(l, curRow, 0);
    00878
    00879       d->m_freeSpaceLabel = new QLabel( d->m_frame );
    00880       grid->addWidget( d->m_freeSpaceLabel, curRow++, 2 );
    00881
    00882       KDiskFreeSp * job = new KDiskFreeSp;
    00883       connect( job, SIGNAL( foundMountPoint( const unsigned long&, const unsigned long&, const unsigned long&, const QString& ) ),
    00884                this, SLOT( slotFoundMountPoint( const unsigned long&, const unsigned long&, const unsigned long&, const QString& ) ) );
    00885       job->readDF( mountPoint );
    00886   }
    00887
    00888   if (!d->bMultiple && item->isLink()) {
    00889     l = new QLabel(i18n("Points to:"), d->m_frame );
    00890     grid->addWidget(l, curRow, 0);
    00891
    00892     l = new QLabel(item->linkDest(), d->m_frame );
    00893     grid->addWidget(l, curRow++, 2);
    00894   }
    00895
    00896   if (!d->bMultiple) // Dates for multiple don't make much sense...
    00897   {
    00898     sep = new KSeparator( KSeparator::HLine, d->m_frame);
    00899     grid->addMultiCellWidget(sep, curRow, curRow, 0, 2);
    00900     ++curRow;
    00901
    00902     grid = new QGridLayout(0, 3); // unknown # of rows
    00903     grid->setColStretch(2, 1);
    00904     grid->addColSpacing(1, KDialog::spacingHint());
    00905     vbl->addLayout(grid);
    00906     curRow = 0;
    00907
    00908     QDateTime dt;
    00909     time_t tim = item->time(KIO::UDS_CREATION_TIME);
    00910     if ( tim )
    00911     {
    00912       l = new QLabel(i18n("Created:"), d->m_frame );
    00913       grid->addWidget(l, curRow, 0);
    00914
    00915       dt.setTime_t( tim );
    00916       l = new QLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame );
    00917       grid->addWidget(l, curRow++, 2);
    00918     }
    00919
    00920     tim = item->time(KIO::UDS_MODIFICATION_TIME);
    00921     if ( tim )
    00922     {
    00923       l = new QLabel(i18n("Modified:"), d->m_frame );
    00924       grid->addWidget(l, curRow, 0);
    00925
    00926       dt.setTime_t( tim );
    00927       l = new QLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame );
    00928       grid->addWidget(l, curRow++, 2);
    00929     }
    00930
    00931     tim = item->time(KIO::UDS_ACCESS_TIME);
    00932     if ( tim )
    00933     {
    00934       l = new QLabel(i18n("Accessed:"), d->m_frame );
    00935       grid->addWidget(l, curRow, 0);
    00936
    00937       dt.setTime_t( tim );
    00938       l = new QLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame );
    00939       grid->addWidget(l, curRow++, 2);
    00940     }
    00941   }
    00942
    00943   vbl->addStretch(1);
    00944 }
    00945
    00946 // QString KFilePropsPlugin::tabName () const
    00947 // {
    00948 //   return i18n ("&General");
    00949 // }
    00950
    00951
    00952 void KFilePropsPlugin::nameFileChanged(const QString &text )
    00953 {
    00954   properties->enableButtonOK(!text.isEmpty());
    00955   emit changed();
    00956 }
    00957 void KFilePropsPlugin::determineRelativePath( const QString & path )
    00958 {
    00959     m_sRelativePath = "";
    00960     // now let's make it relative
    00961     QStringList dirs;
    00962     if (KBindingPropsPlugin::supports(properties->items()))
    00963       dirs = KGlobal::dirs()->resourceDirs("mime");
    00964     else
    00965       dirs = KGlobal::dirs()->resourceDirs("apps");
    00966
    00967     QStringList::ConstIterator it = dirs.begin();
    00968     for ( ; it != dirs.end() && m_sRelativePath.isEmpty(); ++it ) {
    00969       // might need canonicalPath() ...
    00970       if ( path.find( *it ) == 0 ) // path is dirs + relativePath
    00971         m_sRelativePath = path.mid( (*it).length() ); // skip appsdirs
    00972     }
    00973     if ( m_sRelativePath.isEmpty() )
    00974     {
    00975       if (KBindingPropsPlugin::supports(properties->items()))
    00976         kdWarning(250) << "Warning : editing a mimetype file out of the mimetype dirs!" << endl;
    00977       // for Application desktop files, no problem : we can editing a .desktop file anywhere...
    00978     } else
    00979         while ( m_sRelativePath.at(0) == '/' ) m_sRelativePath.remove( 0, 1 );
    00980 }
    00981
    00982 void KFilePropsPlugin::slotFoundMountPoint( const QString&, unsigned long kBSize, unsigned long /*kBUsed*/, unsigned long kBAvail )
    00983 {
    00984     d->m_freeSpaceLabel->setText( i18n("Available space out of total partition size (percent used)", "%1/%2 (%3% used)")
    00985                                .arg(KIO::convertSizeFromKB(kBAvail))
    00986                                .arg(KIO::convertSizeFromKB(kBSize))
    00987                                .arg( 100 - (int)(100.0 * kBAvail / kBSize) ));
    00988 }
    00989
    00990 // attention: copy&paste below, due to compiler bug
    00991 // it doesn't like those unsigned long parameters -- unsigned long& are ok :-/
    00992 void KFilePropsPlugin::slotFoundMountPoint( const unsigned long& kBSize, const unsigned long& /*kBUsed*/, const unsigned long& kBAvail, const QString& )
    00993 {
    00994     d->m_freeSpaceLabel->setText( i18n("Available space out of total partition size (percent used)", "%1/%2 (%3% used)")
    00995                                .arg(KIO::convertSizeFromKB(kBAvail))
    00996                                .arg(KIO::convertSizeFromKB(kBSize))
    00997                                .arg( 100 - (int)(100.0 * kBAvail / kBSize) ));
    00998 }
    00999
    01000 void KFilePropsPlugin::slotDirSizeFinished( KIO::Job * job )
    01001 {
    01002   if (job->error())
    01003     m_sizeLabel->setText( job->errorString() );
    01004   else
    01005   {
    01006     KIO::filesize_t totalSize = static_cast<KDirSize*>(job)->totalSize();
    01007     m_sizeLabel->setText( QString::fromLatin1("%1 (%2)").arg(KIO::convertSize(totalSize)).arg(KGlobal::locale()->formatNumber(totalSize, 0)) );
    01008   }
    01009   m_sizeStopButton->setEnabled(false);
    01010   // just in case you change something and try again :)
    01011   m_sizeDetermineButton->setText( i18n("Refresh") );
    01012   m_sizeDetermineButton->setEnabled(true);
    01013   d->dirSizeJob = 0L;
    01014 }
    01015
    01016 void KFilePropsPlugin::slotSizeDetermine()
    01017 {
    01018   m_sizeLabel->setText( i18n("Calculating...") );
    01019   kdDebug(250) << " KFilePropsPlugin::slotSizeDetermine() properties->item()=" <<  properties->item() << endl;
    01020   kdDebug(250) << " URL=" << properties->item()->url().url() << endl;
    01021   d->dirSizeJob = KDirSize::dirSizeJob( properties->items() );
    01022   connect( d->dirSizeJob, SIGNAL( result( KIO::Job * ) ),
    01023            SLOT( slotDirSizeFinished( KIO::Job * ) ) );
    01024   m_sizeStopButton->setEnabled(true);
    01025   m_sizeDetermineButton->setEnabled(false);
    01026 }
    01027
    01028 void KFilePropsPlugin::slotSizeStop()
    01029 {
    01030   if ( d->dirSizeJob )
    01031   {
    01032     m_sizeLabel->setText( i18n("Stopped") );
    01033     d->dirSizeJob->kill();
    01034     d->dirSizeJob = 0;
    01035   }
    01036   m_sizeStopButton->setEnabled(false);
    01037   m_sizeDetermineButton->setEnabled(true);
    01038 }
    01039
    01040 KFilePropsPlugin::~KFilePropsPlugin()
    01041 {
    01042   delete d;
    01043 }
    01044
    01045 bool KFilePropsPlugin::supports( KFileItemList /*_items*/ )
    01046 {
    01047   return true;
    01048 }
    01049
    01050 // Don't do this at home
    01051 void qt_enter_modal( QWidget *widget );
    01052 void qt_leave_modal( QWidget *widget );
    01053
    01054 void KFilePropsPlugin::applyChanges()
    01055 {
    01056   if ( d->dirSizeJob )
    01057     slotSizeStop();
    01058
    01059   kdDebug(250) << "KFilePropsPlugin::applyChanges" << endl;
    01060
    01061   if (nameArea->inherits("QLineEdit"))
    01062   {
    01063     QString n = KIO::encodeFileName(((QLineEdit *) nameArea)->text());
    01064     // Remove trailing spaces (#4345)
    01065     while ( n[n.length()-1].isSpace() )
    01066       n.truncate( n.length() - 1 );
    01067     if ( n.isEmpty() )
    01068     {
    01069       KMessageBox::sorry( properties, i18n("The new file name is empty!"));
    01070       properties->abortApplying();
    01071       return;
    01072     }
    01073
    01074     // Do we need to rename the file ?
    01075     kdDebug(250) << "oldname = " << oldName << endl;
    01076     kdDebug(250) << "newname = " << n << endl;
    01077     if ( oldName != n || m_bFromTemplate ) { // true for any from-template file
    01078       KIO::Job * job = 0L;
    01079       KURL oldurl = properties->kurl();
    01080       // Tell properties. Warning, this changes the result of properties->kurl() !
    01081       properties->rename( n );
    01082
    01083       // Update also relative path (for apps and mimetypes)
    01084       if ( !m_sRelativePath.isEmpty() )
    01085         determineRelativePath( properties->kurl().path() );
    01086
    01087       kdDebug(250) << "New URL = " << properties->kurl().url() << endl;
    01088       kdDebug(250) << "old = " << oldurl.url() << endl;
    01089
    01090       // Don't remove the template !!
    01091       if ( !m_bFromTemplate ) // (normal renaming)
    01092         job = KIO::move( oldurl, properties->kurl() );
    01093       else // Copying a template
    01094         job = KIO::copy( oldurl, properties->kurl() );
    01095
    01096       connect( job, SIGNAL( result( KIO::Job * ) ),
    01097                SLOT( slotCopyFinished( KIO::Job * ) ) );
    01098       connect( job, SIGNAL( renamed( KIO::Job *, const KURL &, const KURL & ) ),
    01099                SLOT( slotFileRenamed( KIO::Job *, const KURL &, const KURL & ) ) );
    01100       // wait for job
    01101       QWidget dummy(0,0,WType_Dialog|WShowModal);
    01102       qt_enter_modal(&dummy);
    01103       qApp->enter_loop();
    01104       qt_leave_modal(&dummy);
    01105       return;
    01106     }
    01107   }
    01108
    01109   // No job, keep going
    01110   slotCopyFinished( 0L );
    01111 }
    01112
    01113 void KFilePropsPlugin::slotCopyFinished( KIO::Job * job )
    01114 {
    01115   kdDebug(250) << "KFilePropsPlugin::slotCopyFinished" << endl;
    01116   if (job)
    01117   {
    01118     // allow apply() to return
    01119     qApp->exit_loop();
    01120     if ( job->error() )
    01121     {
    01122         job->showErrorDialog( d->m_frame );
    01123         // Didn't work. Revert the URL to the old one
    01124         properties->updateUrl( static_cast<KIO::CopyJob*>(job)->srcURLs().first() );
    01125         properties->abortApplying(); // Don't apply the changes to the wrong file !
    01126         return;
    01127     }
    01128   }
    01129
    01130   assert( properties->item() );
    01131   assert( !properties->item()->url().isEmpty() );
    01132
    01133   // Save the file where we can -> usually in ~/.kde/...
    01134   if (KBindingPropsPlugin::supports(properties->items()) && !m_sRelativePath.isEmpty())
    01135   {
    01136     KURL newURL;
    01137     newURL.setPath( locateLocal("mime", m_sRelativePath) );
    01138     properties->updateUrl( newURL );
    01139   }
    01140   else if (KExecPropsPlugin::supports(properties->items()) && !m_sRelativePath.isEmpty())
    01141   {
    01142     kdDebug(250) << "KFilePropsPlugin::slotCopyFinished " << m_sRelativePath << endl;
    01143     KURL newURL;
    01144     newURL.setPath( locateLocal("apps", m_sRelativePath) );
    01145     kdDebug(250) << "KFilePropsPlugin::slotCopyFinished path=" << newURL.path() << endl;
    01146     properties->updateUrl( newURL );
    01147   }
    01148
    01149   // handle icon changes - only local files for now
    01150   // TODO: Use KTempFile and KIO::file_copy with resume = true
    01151   if (!iconArea->isA("QLabel") && properties->kurl().isLocalFile()) {
    01152     KIconButton *iconButton = (KIconButton *) iconArea;
    01153     QString path;
    01154
    01155     if (S_ISDIR(properties->item()->mode()))
    01156     {
    01157       path = properties->kurl().path(1) + QString::fromLatin1(".directory");
    01158       // don't call updateUrl because the other tabs (i.e. permissions)
    01159       // apply to the directory, not the .directory file.
    01160     }
    01161     else
    01162       path = properties->kurl().path();
    01163
    01164     // Get the default image
    01165     QString str = KMimeType::findByURL( properties->kurl(),
    01166                                         properties->item()->mode(),
    01167                                         true )->KServiceType::icon();
    01168     // Is it another one than the default ?
    01169     QString sIcon;
    01170     if ( str != iconButton->icon() )
    01171       sIcon = iconButton->icon();
    01172     // (otherwise write empty value)
    01173
    01174     kdDebug(250) << "**" << path << "**" << endl;
    01175     QFile f( path );
    01176
    01177     // If default icon and no .directory file -> don't create one
    01178     if ( !sIcon.isEmpty() || f.exists() )
    01179     {
    01180         if ( !f.open( IO_ReadWrite ) ) {
    01181           KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient access to write to <b>%1</b>.</qt>").arg(path));
    01182           return;
    01183         }
    01184         f.close();
    01185
    01186         KDesktopFile cfg(path);
    01187         kdDebug(250) << "sIcon = " << (sIcon) << endl;
    01188         kdDebug(250) << "str = " << (str) << endl;
    01189         cfg.writeEntry( QString::fromLatin1("Icon"), sIcon );
    01190         cfg.sync();
    01191     }
    01192   }
    01193 }
    01194
    01195 void KFilePropsPlugin::slotFileRenamed( KIO::Job *, const KURL &, const KURL & newUrl )
    01196 {
    01197   // This is called in case of an existing local file during the copy/move operation,
    01198   // if the user chooses Rename.
    01199   properties->updateUrl( newUrl );
    01200 }
    01201
    01202 void KFilePropsPlugin::postApplyChanges()
    01203 {
    01204   KURL::List lst;
    01205   KFileItemList items = properties->items();
    01206   for ( KFileItemListIterator it( items ); it.current(); ++it )
    01207     lst.append((*it)->url());
    01208   KDirNotify_stub allDirNotify("*", "KDirNotify*");
    01209   allDirNotify.FilesChanged( lst );
    01210 }
    01211
    01212 class KFilePermissionsPropsPlugin::KFilePermissionsPropsPluginPrivate
    01213 {
    01214 public:
    01215   KFilePermissionsPropsPluginPrivate()
    01216   {
    01217   }
    01218   ~KFilePermissionsPropsPluginPrivate()
    01219   {
    01220   }
    01221
    01222   QFrame *m_frame;
    01223   QCheckBox *cbRecursive;
    01224   mode_t partialPermissions;
    01225 };
    01226
    01227 KFilePermissionsPropsPlugin::KFilePermissionsPropsPlugin( KPropertiesDialog *_props )
    01228   : KPropsDlgPlugin( _props )
    01229 {
    01230   d = new KFilePermissionsPropsPluginPrivate;
    01231   d->cbRecursive = 0L;
    01232   grpCombo = 0L; grpEdit = 0;
    01233   usrEdit = 0L;
    01234   QString path = properties->kurl().path(-1);
    01235   QString fname = properties->kurl().fileName();
    01236   bool isLocal = properties->kurl().isLocalFile();
    01237
    01238   bool IamRoot = (geteuid() == 0);
    01239
    01240   KFileItem * item = properties->item();
    01241   bool isLink = item->isLink();
    01242   bool isDir = item->isDir(); // all dirs
    01243   bool hasDir = item->isDir(); // at least one dir
    01244   permissions = item->permissions(); // common permissions to all files
    01245   d->partialPermissions = permissions; // permissions that only some files have (at first we take everything)
    01246   strOwner = item->user();
    01247   strGroup = item->group();
    01248
    01249   if ( properties->items().count() > 1 )
    01250   {
    01251     // Multiple items: see what they have in common
    01252     KFileItemList items = properties->items();
    01253     KFileItemListIterator it( items );
    01254     for ( ++it /*no need to check the first one again*/ ; it.current(); ++it )
    01255     {
    01256       if ( (*it)->isLink() != isLink )
    01257         isLink = false;
    01258       if ( (*it)->isDir() != isDir )
    01259         isDir = false;
    01260       hasDir |= (*it)->isDir();
    01261       if ( (*it)->permissions() != permissions )
    01262       {
    01263         permissions &= (*it)->permissions();
    01264         d->partialPermissions |= (*it)->permissions();
    01265       }
    01266       if ( (*it)->user() != strOwner )
    01267         strOwner = QString::null;
    01268       if ( (*it)->group() != strGroup )
    01269         strGroup = QString::null;
    01270     }
    01271   }
    01272
    01273   // keep only what's not in the common permissions
    01274   d->partialPermissions = d->partialPermissions & ~permissions;
    01275
    01276   bool isMyFile = false;
    01277
    01278   if (isLocal && !strOwner.isEmpty()) { // local files, and all owned by the same person
    01279     struct passwd *myself = getpwuid( geteuid() );
    01280     if ( myself != 0L )
    01281     {
    01282       isMyFile = (strOwner == QString::fromLocal8Bit(myself->pw_name));
    01283     } else
    01284       kdWarning() << "I don't exist ?! geteuid=" << geteuid() << endl;
    01285   } else {
    01286     //We don't know, for remote files, if they are ours or not.
    01287     //So we let the user change permissions, and
    01288     //KIO::chmod will tell, if he had no right to do it.
    01289     isMyFile = true;
    01290   }
    01291
    01292   d->m_frame = properties->dialog()->addPage(i18n("&Permissions"));
    01293
    01294   QBoxLayout *box = new QVBoxLayout( d->m_frame, KDialog::spacingHint() );
    01295
    01296   QLabel *l, *cl[3];
    01297   QGroupBox *gb;
    01298   QGridLayout *gl;
    01299
    01300   /* Group: Access Permissions */
    01301   gb = new QGroupBox ( i18n("Access Permissions"), d->m_frame );
    01302   box->addWidget (gb);
    01303
    01304   gl = new QGridLayout (gb, 6, 6, 15);
    01305   gl->addRowSpacing(0, 10);
    01306
    01307   l = new QLabel(i18n("Class"), gb);
    01308   gl->addWidget(l, 1, 0);
    01309
    01310   if (isDir)
    01311     l = new QLabel( i18n("Show\nEntries"), gb );
    01312   else
    01313     l = new QLabel( i18n("Read"), gb );
    01314   gl->addWidget (l, 1, 1);
    01315
    01316   if (isDir)
    01317     l = new QLabel( i18n("Write\nEntries"), gb );
    01318   else
    01319     l = new QLabel( i18n("Write"), gb );
    01320   gl->addWidget (l, 1, 2);
    01321
    01322   if (isDir)
    01323     l = new QLabel( i18n("Enter directory", "Enter"), gb );
    01324   else
    01325     l = new QLabel( i18n("Exec"), gb );
    01326   // GJ: Add space between normal and special modes
    01327   QSize size = l->sizeHint();
    01328   size.setWidth(size.width() + 15);
    01329   l->setFixedSize(size);
    01330   gl->addWidget (l, 1, 3);
    01331
    01332   l = new QLabel( i18n("Special"), gb );
    01333   gl->addMultiCellWidget(l, 1, 1, 4, 5);
    01334
    01335   cl[0] = new QLabel( i18n("User"), gb );
    01336   gl->addWidget (cl[0], 2, 0);
    01337
    01338   cl[1] = new QLabel( i18n("Group"), gb );
    01339   gl->addWidget (cl[1], 3, 0);
    01340
    01341   cl[2] = new QLabel( i18n("Others"), gb );
    01342   gl->addWidget (cl[2], 4, 0);
    01343
    01344   l = new QLabel(i18n("Set UID"), gb);
    01345   gl->addWidget(l, 2, 5);
    01346
    01347   l = new QLabel(i18n("Set GID"), gb);
    01348   gl->addWidget(l, 3, 5);
    01349
    01350   l = new QLabel(i18n("File permission, sets user or group ID on execution", "Sticky"), gb);
    01351   gl->addWidget(l, 4, 5);
    01352
    01353   bool enablePage = (isMyFile || IamRoot) && (!isLink);
    01354   /* Draw Checkboxes */
    01355   for (int row = 0; row < 3 ; ++row) {
    01356     for (int col = 0; col < 4; ++col) {
    01357       QCheckBox *cb = new QCheckBox(gb);
    01358       cb->setChecked(permissions & fperm[row][col]);
    01359       if ( d->partialPermissions & fperm[row][col] )
    01360       {
    01361         cb->setTristate( true );
    01362         cb->setNoChange();
    01363       }
    01364       cb->setEnabled( enablePage );
    01365       permBox[row][col] = cb;
    01366       gl->addWidget (permBox[row][col], row+2, col+1);
    01367       connect( cb, SIGNAL( clicked() ),
    01368                this, SIGNAL( changed() ) );
    01369     }
    01370   }
    01371   gl->setColStretch(6, 10);
    01372   gb->setEnabled( enablePage );
    01373
    01374   /**** Group: Ownership ****/
    01375   gb = new QGroupBox ( i18n("Ownership"), d->m_frame );
    01376   box->addWidget (gb);
    01377
    01378   gl = new QGridLayout (gb, 4, 3, 15);
    01379   gl->addRowSpacing(0, 10);
    01380
    01381   /*** Set Owner ***/
    01382   l = new QLabel( i18n("User:"), gb );
    01383   gl->addWidget (l, 1, 0);
    01384
    01385   /* GJ: Don't autocomplete more than 1000 users. This is a kind of random
    01386    * value. Huge sites having 10.000+ user have a fair chance of using NIS,
    01387    * (possibly) making this unacceptably slow.
    01388    * OTOH, it is nice to offer this functionality for the standard user.
    01389    */
    01390   int i, maxEntries = 1000;
    01391   struct passwd *user;
    01392   struct group *ge;
    01393
    01394   /* File owner: For root, offer a KLineEdit with autocompletion.
    01395    * For a user, who can never chown() a file, offer a QLabel.
    01396    */
    01397   if (IamRoot && isLocal)
    01398   {
    01399     usrEdit = new KLineEdit( gb );
    01400     KCompletion *kcom = usrEdit->completionObject();
    01401     kcom->setOrder(KCompletion::Sorted);
    01402     setpwent();
    01403     for (i=0; ((user = getpwent()) != 0L) && (i < maxEntries); i++)
    01404       kcom->addItem(QString::fromLatin1(user->pw_name));
    01405     endpwent();
    01406     usrEdit->setCompletionMode((i < maxEntries) ? KGlobalSettings::CompletionAuto :
    01407                                KGlobalSettings::CompletionNone);
    01408     usrEdit->setText(strOwner);
    01409     gl->addWidget(usrEdit, 1, 1);
    01410     connect( usrEdit, SIGNAL( textChanged( const QString & ) ),
    01411              this, SIGNAL( changed() ) );
    01412   }
    01413   else
    01414   {
    01415     l = new QLabel(strOwner, gb);
    01416     gl->addWidget(l, 1, 1);
    01417   }
    01418
    01419   /*** Set Group ***/
    01420
    01421   QStringList groupList;
    01422   QCString strUser;
    01423   user = getpwuid(geteuid());
    01424   if (user != 0L)
    01425     strUser = user->pw_name;
    01426
    01427   setgrent();
    01428   for (i=0; ((ge = getgrent()) != 0L) && (i < maxEntries); i++)
    01429   {
    01430     if (IamRoot)
    01431       groupList += QString::fromLatin1(ge->gr_name);
    01432     else
    01433     {
    01434       /* pick the groups to which the user belongs */
    01435       char ** members = ge->gr_mem;
    01436       char * member;
    01437       while ((member = *members) != 0L) {
    01438         if (strUser == member) {
    01439           groupList += QString::fromLocal8Bit(ge->gr_name);
    01440           break;
    01441         }
    01442         ++members;
    01443       }
    01444     }
    01445   }
    01446   endgrent();
    01447
    01448   /* add the effective Group to the list .. */
    01449   ge = getgrgid (getegid());
    01450   if (ge) {
    01451     QString name = QString::fromLatin1(ge->gr_name);
    01452     if (name.isEmpty())
    01453       name.setNum(ge->gr_gid);
    01454     if (groupList.find(name) == groupList.end())
    01455       groupList += name;
    01456   }
    01457
    01458   bool isMyGroup = groupList.contains(strGroup);
    01459
    01460   /* add the group the file currently belongs to ..
    01461    * .. if its not there already
    01462    */
    01463   if (!isMyGroup)
    01464     groupList += strGroup;
    01465
    01466   l = new QLabel( i18n("Group:"), gb );
    01467   gl->addWidget (l, 2, 0);
    01468
    01469   /* Set group: if possible to change:
    01470    * - Offer a KLineEdit for root, since he can change to any group.
    01471    * - Offer a QComboBox for a normal user, since he can change to a fixed
    01472    *   (small) set of groups only.
    01473    * If not changeable: offer a QLabel.
    01474    */
    01475   if (IamRoot && isLocal)
    01476   {
    01477     grpEdit = new KLineEdit(gb);
    01478     KCompletion *kcom = new KCompletion;
    01479     kcom->setItems(groupList);
    01480     grpEdit->setCompletionObject(kcom, true);
    01481     grpEdit->setAutoDeleteCompletionObject( true );
    01482     grpEdit->setCompletionMode(KGlobalSettings::CompletionAuto);
    01483     grpEdit->setText(strGroup);
    01484     gl->addWidget(grpEdit, 2, 1);
    01485     connect( grpEdit, SIGNAL( textChanged( const QString & ) ),
    01486              this, SIGNAL( changed() ) );
    01487   }
    01488   else if ((groupList.count() > 1) && isMyFile && isLocal)
    01489   {
    01490     grpCombo = new QComboBox(gb, "combogrouplist");
    01491     grpCombo->insertStringList(groupList);
    01492     grpCombo->setCurrentItem(groupList.findIndex(strGroup));
    01493     gl->addWidget(grpCombo, 2, 1);
    01494     connect( grpCombo, SIGNAL( activated( int ) ),
    01495              this, SIGNAL( changed() ) );
    01496   }
    01497   else
    01498   {
    01499     l = new QLabel(strGroup, gb);
    01500     gl->addWidget(l, 2, 1);
    01501   }
    01502
    01503   gl->setColStretch(2, 10);
    01504
    01505   // "Apply recursive" checkbox
    01506   if ( hasDir )
    01507   {
    01508       d->cbRecursive = new QCheckBox( i18n("Apply changes to all subdirectories and their contents"), d->m_frame );
    01509       box->addWidget( d->cbRecursive );
    01510       connect( d->cbRecursive, SIGNAL( clicked() ),
    01511                this, SLOT( slotRecursiveClicked() ) );
    01512   }
    01513
    01514   box->addStretch (10);
    01515
    01516   if (isMyFile)
    01517     cl[0]->setText(i18n("<b>User</b>"));
    01518   else if (isMyGroup)
    01519     cl[1]->setText(i18n("<b>Group</b>"));
    01520   else
    01521     cl[2]->setText(i18n("<b>Others</b>"));
    01522 }
    01523
    01524 // QString KFilePermissionsPropsPlugin::tabName () const
    01525 // {
    01526 //   return i18n ("&Permissions");
    01527 // }
    01528
    01529 KFilePermissionsPropsPlugin::~KFilePermissionsPropsPlugin()
    01530 {
    01531   delete d;
    01532 }
    01533
    01534 bool KFilePermissionsPropsPlugin::supports( KFileItemList /*_items*/ )
    01535 {
    01536   return true;
    01537 }
    01538
    01539 void KFilePermissionsPropsPlugin::slotRecursiveClicked()
    01540 {
    01541   // If we want to apply permissions recursively, then we didn't
    01542   // show up the right permissions to start with. Files in subdirs might
    01543   // have other flags.... At least, let the user the possibility
    01544   // to set any flag to "unchanged", so that he isn't forced to set +x
    01545   // on all files !
    01546   for (int row = 0;row < 3; ++row)
    01547     for (int col = 0; col < 4; ++col)
    01548       permBox[row][col]->setTristate();
    01549 }
    01550
    01551 void KFilePermissionsPropsPlugin::applyChanges()
    01552 {
    01553   mode_t newPermission = 0;
    01554   mode_t newPartialPermission = 0;
    01555   mode_t permissionMask = 0;
    01556   for (int row = 0;row < 3; ++row)
    01557     for (int col = 0; col < 4; ++col)
    01558     {
    01559       switch (permBox[row][col]->state())
    01560       {
    01561           case QCheckBox::On:
    01562             newPermission |= fperm[row][col];
    01563             //fall through
    01564           case QCheckBox::Off:
    01565             permissionMask |= fperm[row][col];
    01566             break;
    01567           default: // NoChange
    01568             newPartialPermission |= fperm[ row ][ col ];
    01569             break;
    01570       }
    01571     }
    01572
    01573   QString owner, group;
    01574   if (usrEdit)
    01575     owner = usrEdit->text();
    01576   if (grpEdit)
    01577     group = grpEdit->text();
    01578   else if (grpCombo)
    01579     group = grpCombo->currentText();
    01580
    01581   if (owner == strOwner)
    01582       owner = QString::null; // no change
    01583
    01584   if (group == strGroup)
    01585       group = QString::null;
    01586
    01587   kdDebug(250) << "old permissions : " << QString::number(permissions,8) << endl;
    01588   kdDebug(250) << "new permissions : " << QString::number(newPermission,8) << endl;
    01589   kdDebug(250) << "permissions mask : " << QString::number(permissionMask,8) << endl;
    01590   kdDebug(250) << "url=" << properties->items().first()->url().url() << endl;
    01591
    01592   if ( permissions != newPermission || d->partialPermissions != newPartialPermission
    01593                   || !owner.isEmpty() || !group.isEmpty() )
    01594   {
    01595     KIO::Job * job = KIO::chmod( properties->items(), newPermission, permissionMask,
    01596                                  owner, group,
    01597                                  d->cbRecursive && d->cbRecursive->isChecked() );
    01598     connect( job, SIGNAL( result( KIO::Job * ) ),
    01599              SLOT( slotChmodResult( KIO::Job * ) ) );
    01600     // Wait for job
    01601     QWidget dummy(0,0,WType_Dialog|WShowModal);
    01602     qt_enter_modal(&dummy);
    01603     qApp->enter_loop();
    01604     qt_leave_modal(&dummy);
    01605   }
    01606 }
    01607
    01608 void KFilePermissionsPropsPlugin::slotChmodResult( KIO::Job * job )
    01609 {
    01610   kdDebug(250) << "KFilePermissionsPropsPlugin::slotChmodResult" << endl;
    01611   if (job->error())
    01612     job->showErrorDialog( d->m_frame );
    01613   // allow apply() to return
    01614   qApp->exit_loop();
    01615 }
    01616
    01617 class KExecPropsPlugin::KExecPropsPluginPrivate
    01618 {
    01619 public:
    01620   KExecPropsPluginPrivate()
    01621   {
    01622   }
    01623   ~KExecPropsPluginPrivate()
    01624   {
    01625   }
    01626
    01627   QFrame *m_frame;
    01628 };
    01629
    01630 KExecPropsPlugin::KExecPropsPlugin( KPropertiesDialog *_props )
    01631   : KPropsDlgPlugin( _props )
    01632 {
    01633   d = new KExecPropsPluginPrivate;
    01634   d->m_frame = properties->dialog()->addPage(i18n("E&xecute"));
    01635   QVBoxLayout * mainlayout = new QVBoxLayout( d->m_frame );
    01636   mainlayout->setSpacing( KDialog::spacingHint() );
    01637
    01638   // Now the widgets in the top layout
    01639
    01640   QLabel* l;
    01641   l = new QLabel( i18n( "Comman&d:" ), d->m_frame );
    01642   mainlayout->addWidget(l);
    01643
    01644   QHBoxLayout * hlayout;
    01645   hlayout = new QHBoxLayout(KDialog::spacingHint());
    01646   mainlayout->addLayout(hlayout);
    01647
    01648   execEdit = new KLineEdit( d->m_frame );
    01649   hlayout->addWidget(execEdit, 1);
    01650
    01651   l->setBuddy( execEdit );
    01652
    01653   execBrowse = new QPushButton( d->m_frame );
    01654   execBrowse->setText( i18n("&Browse...") );
    01655   hlayout->addWidget(execBrowse);
    01656
    01657   // The groupbox about swallowing
    01658   QGroupBox* tmpQGroupBox;
    01659   tmpQGroupBox = new QGroupBox( i18n("Panel Embedding"), d->m_frame );
    01660   tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
    01661
    01662   mainlayout->addWidget(tmpQGroupBox);
    01663
    01664   QGridLayout *grid = new QGridLayout(tmpQGroupBox->layout(), 2, 2);
    01665   grid->setSpacing( KDialog::spacingHint() );
    01666   grid->setColStretch(1, 1);
    01667
    01668   l = new QLabel( i18n( "&Execute on click:" ), tmpQGroupBox );
    01669   grid->addWidget(l, 0, 0);
    01670
    01671   swallowExecEdit = new KLineEdit( tmpQGroupBox );
    01672   grid->addWidget(swallowExecEdit, 0, 1);
    01673
    01674   l->setBuddy( swallowExecEdit );
    01675
    01676   l = new QLabel( i18n( "&Window title:" ), tmpQGroupBox );
    01677   grid->addWidget(l, 1, 0);
    01678
    01679   swallowTitleEdit = new KLineEdit( tmpQGroupBox );
    01680   grid->addWidget(swallowTitleEdit, 1, 1);
    01681
    01682   l->setBuddy( swallowTitleEdit );
    01683
    01684   // The groupbox about run in terminal
    01685
    01686   tmpQGroupBox = new QGroupBox( d->m_frame );
    01687   tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
    01688
    01689   mainlayout->addWidget(tmpQGroupBox);
    01690
    01691   grid = new QGridLayout(tmpQGroupBox->layout(), 2, 2);
    01692   grid->setSpacing( KDialog::spacingHint() );
    01693   grid->setColStretch(1, 1);
    01694
    01695   terminalCheck = new QCheckBox( tmpQGroupBox );
    01696   terminalCheck->setText( i18n("&Run in terminal") );
    01697   grid->addMultiCellWidget(terminalCheck, 0, 0, 0, 1);
    01698
    01699   terminalLabel = new QLabel( i18n( "&Terminal options:" ), tmpQGroupBox );
    01700   grid->addWidget(terminalLabel, 1, 0);
    01701
    01702   terminalEdit = new KLineEdit( tmpQGroupBox );
    01703   grid->addWidget(terminalEdit, 1, 1);
    01704
    01705   terminalLabel->setBuddy( terminalEdit );
    01706
    01707   // The groupbox about run with substituted uid.
    01708
    01709   tmpQGroupBox = new QGroupBox( d->m_frame );
    01710   tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
    01711
    01712   mainlayout->addWidget(tmpQGroupBox);
    01713
    01714   grid = new QGridLayout(tmpQGroupBox->layout(), 2, 2);
    01715   grid->setSpacing(KDialog::spacingHint());
    01716   grid->setColStretch(1, 1);
    01717
    01718   suidCheck = new QCheckBox(tmpQGroupBox);
    01719   suidCheck->setText(i18n("Ru&n as a different user"));
    01720   grid->addMultiCellWidget(suidCheck, 0, 0, 0, 1);
    01721
    01722   suidLabel = new QLabel(i18n( "&Username:" ), tmpQGroupBox);
    01723   grid->addWidget(suidLabel, 1, 0);
    01724
    01725   suidEdit = new KLineEdit(tmpQGroupBox);
    01726   grid->addWidget(suidEdit, 1, 1);
    01727
    01728   suidLabel->setBuddy( suidEdit );
    01729
    01730   mainlayout->addStretch(1);
    01731
    01732   // now populate the page
    01733   QString path = _props->kurl().path();
    01734   QFile f( path );
    01735   if ( !f.open( IO_ReadOnly ) )
    01736     return;
    01737   f.close();
    01738
    01739   KSimpleConfig config( path );
    01740   config.setDollarExpansion( false );
    01741   config.setDesktopGroup();
    01742   execStr = config.readPathEntry( QString::fromLatin1("Exec") );
    01743   swallowExecStr = config.readPathEntry( QString::fromLatin1("SwallowExec") );
    01744   swallowTitleStr = config.readEntry( QString::fromLatin1("SwallowTitle") );
    01745   termBool = config.readBoolEntry( QString::fromLatin1("Terminal") );
    01746   termOptionsStr = config.readEntry( QString::fromLatin1("TerminalOptions") );
    01747   suidBool = config.readBoolEntry( QString::fromLatin1("X-KDE-SubstituteUID") );
    01748   suidUserStr = config.readEntry( QString::fromLatin1("X-KDE-Username") );
    01749
    01750   if ( !swallowExecStr.isNull() )
    01751     swallowExecEdit->setText( swallowExecStr );
    01752   if ( !swallowTitleStr.isNull() )
    01753     swallowTitleEdit->setText( swallowTitleStr );
    01754
    01755   if ( !execStr.isNull() )
    01756     execEdit->setText( execStr );
    01757   if ( !termOptionsStr.isNull() )
    01758     terminalEdit->setText( termOptionsStr );
    01759
    01760   terminalCheck->setChecked( termBool );
    01761   enableCheckedEdit();
    01762
    01763   suidCheck->setChecked( suidBool );
    01764   suidEdit->setText( suidUserStr );
    01765   enableSuidEdit();
    01766
    01767   // Provide username completion up to 1000 users.
    01768   KCompletion *kcom = new KCompletion;
    01769   kcom->setOrder(KCompletion::Sorted);
    01770   struct passwd *pw;
    01771   int i, maxEntries = 1000;
    01772   setpwent();
    01773   for (i=0; ((pw = getpwent()) != 0L) && (i < maxEntries); i++)
    01774     kcom->addItem(QString::fromLatin1(pw->pw_name));
    01775   endpwent();
    01776   if (i < maxEntries)
    01777   {
    01778     suidEdit->setCompletionObject(kcom, true);
    01779     suidEdit->setAutoDeleteCompletionObject( true );
    01780     suidEdit->setCompletionMode(KGlobalSettings::CompletionAuto);
    01781   }
    01782   else
    01783   {
    01784     delete kcom;
    01785   }
    01786
    01787   connect( swallowExecEdit, SIGNAL( textChanged( const QString & ) ),
    01788            this, SIGNAL( changed() ) );
    01789   connect( swallowTitleEdit, SIGNAL( textChanged( const QString & ) ),
    01790            this, SIGNAL( changed() ) );
    01791   connect( execEdit, SIGNAL( textChanged( const QString & ) ),
    01792            this, SIGNAL( changed() ) );
    01793   connect( terminalEdit, SIGNAL( textChanged( const QString & ) ),
    01794            this, SIGNAL( changed() ) );
    01795   connect( terminalCheck, SIGNAL( toggled( bool ) ),
    01796            this, SIGNAL( changed() ) );
    01797   connect( suidCheck, SIGNAL( toggled( bool ) ),
    01798            this, SIGNAL( changed() ) );
    01799   connect( suidEdit, SIGNAL( textChanged( const QString & ) ),
    01800            this, SIGNAL( changed() ) );
    01801
    01802   connect( execBrowse, SIGNAL( clicked() ), this, SLOT( slotBrowseExec() ) );
    01803   connect( terminalCheck, SIGNAL( clicked() ), this,  SLOT( enableCheckedEdit() ) );
    01804   connect( suidCheck, SIGNAL( clicked() ), this,  SLOT( enableSuidEdit() ) );
    01805
    01806 }
    01807
    01808 KExecPropsPlugin::~KExecPropsPlugin()
    01809 {
    01810   delete d;
    01811 }
    01812
    01813 // QString KExecPropsPlugin::tabName () const
    01814 // {
    01815 //   return i18n ("E&xecute");
    01816 // }
    01817
    01818 void KExecPropsPlugin::enableCheckedEdit()
    01819 {
    01820   bool checked = terminalCheck->isChecked();
    01821   terminalLabel->setEnabled( checked );
    01822   terminalEdit->setEnabled( checked );
    01823 }
    01824
    01825 void KExecPropsPlugin::enableSuidEdit()
    01826 {
    01827   bool checked = suidCheck->isChecked();
    01828   suidLabel->setEnabled( checked );
    01829   suidEdit->setEnabled( checked );
    01830 }
    01831
    01832 bool KExecPropsPlugin::supports( KFileItemList _items )
    01833 {
    01834   if ( _items.count() != 1 )
    01835     return false;
    01836   KFileItem * item = _items.first();
    01837   // check if desktop file
    01838   if ( !KPropsDlgPlugin::isDesktopFile( item ) )
    01839     return false;
    01840   // open file and check type
    01841   KDesktopFile config( item->url().path(), true /* readonly */ );
    01842   return config.hasApplicationType() && kapp->authorize("run_desktop_files") && kapp->authorize("shell_access");
    01843 }
    01844
    01845 void KExecPropsPlugin::applyChanges()
    01846 {
    01847   kdDebug(250) << "KExecPropsPlugin::applyChanges" << endl;
    01848   QString path = properties->kurl().path();
    01849
    01850   QFile f( path );
    01851
    01852   if ( !f.open( IO_ReadWrite ) ) {
    01853     KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient access to write to <b>%1</b>.</qt>").arg(path));
    01854     return;
    01855   }
    01856   f.close();
    01857
    01858   KSimpleConfig config( path );
    01859   config.setDesktopGroup();
    01860   config.writeEntry( QString::fromLatin1("Type"), QString::fromLatin1("Application"));
    01861   config.writeEntry( QString::fromLatin1("Exec"), execEdit->text() );
    01862   config.writeEntry( QString::fromLatin1("SwallowExec"), swallowExecEdit->text() );
    01863   config.writeEntry( QString::fromLatin1("SwallowTitle"), swallowTitleEdit->text() );
    01864   config.writeEntry( QString::fromLatin1("Terminal"), terminalCheck->isChecked() );
    01865   config.writeEntry( QString::fromLatin1("TerminalOptions"), terminalEdit->text() );
    01866   config.writeEntry( QString::fromLatin1("X-KDE-SubstituteUID"), suidCheck->isChecked() );
    01867   config.writeEntry( QString::fromLatin1("X-KDE-Username"), suidEdit->text() );
    01868 }
    01869
    01870
    01871 void KExecPropsPlugin::slotBrowseExec()
    01872 {
    01873     KURL f = KFileDialog::getOpenURL( QString::null,
    01874                                       QString::null, d->m_frame );
    01875     if ( f.isEmpty() )
    01876         return;
    01877
    01878     if ( !f.isLocalFile()) {
    01879         KMessageBox::sorry(d->m_frame, i18n("Only executables on local file systems are supported."));
    01880         return;
    01881     }
    01882
    01883     QString path = f.path();
    01884     KRun::shellQuote( path );
    01885     execEdit->setText( path );
    01886 }
    01887
    01888 class KURLPropsPlugin::KURLPropsPluginPrivate
    01889 {
    01890 public:
    01891   KURLPropsPluginPrivate()
    01892   {
    01893   }
    01894   ~KURLPropsPluginPrivate()
    01895   {
    01896   }
    01897
    01898   QFrame *m_frame;
    01899 };
    01900
    01901 KURLPropsPlugin::KURLPropsPlugin( KPropertiesDialog *_props )
    01902   : KPropsDlgPlugin( _props )
    01903 {
    01904   d = new KURLPropsPluginPrivate;
    01905   d->m_frame = properties->dialog()->addPage(i18n("U&RL"));
    01906   QVBoxLayout * layout = new QVBoxLayout(d->m_frame, KDialog::spacingHint());
    01907
    01908   QLabel *l;
    01909   l = new QLabel( d->m_frame, "Label_1" );
    01910   l->setText( i18n("URL:") );
    01911   layout->addWidget(l);
    01912
    01913   URLEdit = new KURLRequester( d->m_frame, "URL Requester" );
    01914   layout->addWidget(URLEdit);
    01915
    01916   QString path = properties->kurl().path();
    01917
    01918   QFile f( path );
    01919   if ( !f.open( IO_ReadOnly ) )
    01920     return;
    01921   f.close();
    01922
    01923   KSimpleConfig config( path );
    01924   config.setDesktopGroup();
    01925   URLStr = config.readPathEntry( QString::fromLatin1("URL") );
    01926
    01927   if ( !URLStr.isNull() )
    01928     URLEdit->setURL( URLStr );
    01929
    01930   connect( URLEdit, SIGNAL( textChanged( const QString & ) ),
    01931            this, SIGNAL( changed() ) );
    01932
    01933   layout->addStretch (1);
    01934 }
    01935
    01936 KURLPropsPlugin::~KURLPropsPlugin()
    01937 {
    01938   delete d;
    01939 }
    01940
    01941 // QString KURLPropsPlugin::tabName () const
    01942 // {
    01943 //   return i18n ("U&RL");
    01944 // }
    01945
    01946 bool KURLPropsPlugin::supports( KFileItemList _items )
    01947 {
    01948   if ( _items.count() != 1 )
    01949     return false;
    01950   KFileItem * item = _items.first();
    01951   // check if desktop file
    01952   if ( !KPropsDlgPlugin::isDesktopFile( item ) )
    01953     return false;
    01954
    01955   // open file and check type
    01956   KDesktopFile config( item->url().path(), true /* readonly */ );
    01957   return config.hasLinkType();
    01958 }
    01959
    01960 void KURLPropsPlugin::applyChanges()
    01961 {
    01962   QString path = properties->kurl().path();
    01963
    01964   QFile f( path );
    01965   if ( !f.open( IO_ReadWrite ) ) {
    01966     KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient access to write to <b>%1</b>.</qt>").arg(path));
    01967     return;
    01968   }
    01969   f.close();
    01970
    01971   KSimpleConfig config( path );
    01972   config.setDesktopGroup();
    01973   config.writeEntry( QString::fromLatin1("Type"), QString::fromLatin1("Link"));
    01974   config.writeEntry( QString::fromLatin1("URL"), URLEdit->url() );
    01975   // Users can't create a Link .desktop file with a Name field,
    01976   // but distributions can. Update the Name field in that case.
    01977   if ( config.hasKey("Name") )
    01978   {
    01979     // ### duplicated from KApplicationPropsPlugin
    01980     QString nameStr = properties->kurl().fileName();
    01981     if ( nameStr.right(8) == QString::fromLatin1(".desktop") )
    01982       nameStr.truncate( nameStr.length() - 8 );
    01983     if ( nameStr.right(7) == QString::fromLatin1(".kdelnk") )
    01984       nameStr.truncate( nameStr.length() - 7 );
    01985     config.writeEntry( QString::fromLatin1("Name"), nameStr );
    01986         config.writeEntry( QString::fromLatin1("Name"), nameStr, true, false, true );
    01987   }
    01988 }
    01989
    01990 /* ----------------------------------------------------
    01991  *
    01992  * KApplicationPropsPlugin
    01993  *
    01994  * -------------------------------------------------- */
    01995
    01996 class KApplicationPropsPlugin::KApplicationPropsPluginPrivate
    01997 {
    01998 public:
    01999   KApplicationPropsPluginPrivate()
    02000   {
    02001       m_kdesktopMode = QCString(qApp->name()) == "kdesktop"; // nasty heh?
    02002   }
    02003   ~KApplicationPropsPluginPrivate()
    02004   {
    02005   }
    02006
    02007   QFrame *m_frame;
    02008   bool m_kdesktopMode;
    02009 };
    02010
    02011 KApplicationPropsPlugin::KApplicationPropsPlugin( KPropertiesDialog *_props )
    02012   : KPropsDlgPlugin( _props )
    02013 {
    02014   d = new KApplicationPropsPluginPrivate;
    02015   d->m_frame = properties->dialog()->addPage(i18n("&Application"));
    02016   QVBoxLayout *toplayout = new QVBoxLayout( d->m_frame, KDialog::spacingHint());
    02017
    02018   QIconSet iconSet;
    02019   QPixmap pixMap;
    02020
    02021   addExtensionButton = new QPushButton( QString::null, d->m_frame );
    02022   iconSet = SmallIconSet( "back" );
    02023   addExtensionButton->setIconSet( iconSet );
    02024   pixMap = iconSet.pixmap( QIconSet::Small, QIconSet::Normal );
    02025   addExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
    02026   connect( addExtensionButton, SIGNAL( clicked() ),
    02027             SLOT( slotAddExtension() ) );
    02028
    02029   delExtensionButton = new QPushButton( QString::null, d->m_frame );
    02030   iconSet = SmallIconSet( "forward" );
    02031   delExtensionButton->setIconSet( iconSet );
    02032   delExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
    02033   connect( delExtensionButton, SIGNAL( clicked() ),
    02034             SLOT( slotDelExtension() ) );
    02035
    02036   QLabel *l;
    02037
    02038   QGridLayout *grid = new QGridLayout(2, 2);
    02039   grid->setColStretch(1, 1);
    02040   toplayout->addLayout(grid);
    02041
    02042   if ( d->m_kdesktopMode )
    02043   {
    02044       // in kdesktop the name field comes from the first tab
    02045       nameEdit = 0L;
    02046   }
    02047   else
    02048   {
    02049       l = new QLabel(i18n("Name:"), d->m_frame, "Label_4" );
    02050       grid->addWidget(l, 0, 0);
    02051
    02052       nameEdit = new KLineEdit( d->m_frame, "LineEdit_3" );
    02053       grid->addWidget(nameEdit, 0, 1);
    02054   }
    02055
    02056   l = new QLabel(i18n("Description:"),  d->m_frame, "Label_5" );
    02057   grid->addWidget(l, 1, 0);
    02058
    02059   genNameEdit = new KLineEdit( d->m_frame, "LineEdit_4" );
    02060   grid->addWidget(genNameEdit, 1, 1);
    02061
    02062   l = new QLabel(i18n("Comment:"),  d->m_frame, "Label_3" );
    02063   grid->addWidget(l, 2, 0);
    02064
    02065   commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" );
    02066   grid->addWidget(commentEdit, 2, 1);
    02067
    02068   l = new QLabel(i18n("File types:"), d->m_frame);
    02069   toplayout->addWidget(l, 0, AlignLeft);
    02070
    02071   grid = new QGridLayout(4, 3);
    02072   grid->setColStretch(0, 1);
    02073   grid->setColStretch(2, 1);
    02074   grid->setRowStretch( 0, 1 );
    02075   grid->setRowStretch( 3, 1 );
    02076   toplayout->addLayout(grid, 2);
    02077
    02078   extensionsList = new QListBox( d->m_frame );
    02079   extensionsList->setSelectionMode( QListBox::Extended );
    02080   grid->addMultiCellWidget(extensionsList, 0, 3, 0, 0);
    02081
    02082   grid->addWidget(addExtensionButton, 1, 1);
    02083   grid->addWidget(delExtensionButton, 2, 1);
    02084
    02085   availableExtensionsList = new QListBox( d->m_frame );
    02086   availableExtensionsList->setSelectionMode( QListBox::Extended );
    02087   grid->addMultiCellWidget(availableExtensionsList, 0, 3, 2, 2);
    02088
    02089   QString path = properties->kurl().path() ;
    02090   QFile f( path );
    02091   if ( !f.open( IO_ReadOnly ) )
    02092     return;
    02093   f.close();
    02094
    02095   KSimpleConfig config( path );
    02096   config.setDesktopGroup();
    02097   QString commentStr = config.readEntry( QString::fromLatin1("Comment") );
    02098   QString genNameStr = config.readEntry( QString::fromLatin1("GenericName") );
    02099
    02100   QStringList selectedTypes = config.readListEntry( "ServiceTypes" );
    02101   // For compatibility with KDE 1.x
    02102   selectedTypes += config.readListEntry( "MimeType", ';' );
    02103
    02104   QString nameStr = config.readEntry( QString::fromLatin1("Name") );
    02105   if ( nameStr.isEmpty() || d->m_kdesktopMode ) {
    02106     // We'll use the file name if no name is specified
    02107     // because we _need_ a Name for a valid file.
    02108     // But let's do it in apply, not here, so that we pick up the right name.
    02109     setDirty();
    02110   }
    02111
    02112   commentEdit->setText( commentStr );
    02113   genNameEdit->setText( genNameStr );
    02114   if ( nameEdit )
    02115       nameEdit->setText( nameStr );
    02116
    02117   selectedTypes.sort();
    02118   QStringList::Iterator sit = selectedTypes.begin();
    02119   for( ; sit != selectedTypes.end(); ++sit ) {
    02120     if ( !((*sit).isEmpty()) )
    02121       extensionsList->insertItem( *sit );
    02122   }
    02123
    02124   KMimeType::List mimeTypes = KMimeType::allMimeTypes();
    02125   QValueListIterator<KMimeType::Ptr> it2 = mimeTypes.begin();
    02126   for ( ; it2 != mimeTypes.end(); ++it2 )
    02127     addMimeType ( (*it2)->name() );
    02128
    02129   updateButton();
    02130
    02131   connect( extensionsList, SIGNAL( highlighted( int ) ),
    02132            this, SLOT( updateButton() ) );
    02133   connect( availableExtensionsList, SIGNAL( highlighted( int ) ),
    02134            this, SLOT( updateButton() ) );
    02135
    02136   connect( addExtensionButton, SIGNAL( clicked() ),
    02137            this, SIGNAL( changed() ) );
    02138   connect( delExtensionButton, SIGNAL( clicked() ),
    02139            this, SIGNAL( changed() ) );
    02140   if ( nameEdit )
    02141       connect( nameEdit, SIGNAL( textChanged( const QString & ) ),
    02142                this, SIGNAL( changed() ) );
    02143   connect( commentEdit, SIGNAL( textChanged( const QString & ) ),
    02144            this, SIGNAL( changed() ) );
    02145   connect( genNameEdit, SIGNAL( textChanged( const QString & ) ),
    02146            this, SIGNAL( changed() ) );
    02147   connect( availableExtensionsList, SIGNAL( selected( int ) ),
    02148            this, SIGNAL( changed() ) );
    02149   connect( extensionsList, SIGNAL( selected( int ) ),
    02150            this, SIGNAL( changed() ) );
    02151 }
    02152
    02153 KApplicationPropsPlugin::~KApplicationPropsPlugin()
    02154 {
    02155   delete d;
    02156 }
    02157
    02158 // QString KApplicationPropsPlugin::tabName () const
    02159 // {
    02160 //   return i18n ("&Application");
    02161 // }
    02162
    02163 void KApplicationPropsPlugin::updateButton()
    02164 {
    02165     addExtensionButton->setEnabled(availableExtensionsList->currentItem()>-1);
    02166     delExtensionButton->setEnabled(extensionsList->currentItem()>-1);
    02167 }
    02168
    02169 void KApplicationPropsPlugin::addMimeType( const QString & name )
    02170 {
    02171   // Add a mimetype to the list of available mime types if not in the extensionsList
    02172
    02173   bool insert = true;
    02174
    02175   for ( uint i = 0; i < extensionsList->count(); i++ )
    02176     if ( extensionsList->text( i ) == name )
    02177       insert = false;
    02178
    02179   if ( insert )
    02180   {
    02181     availableExtensionsList->insertItem( name );
    02182     availableExtensionsList->sort();
    02183   }
    02184 }
    02185
    02186 bool KApplicationPropsPlugin::supports( KFileItemList _items )
    02187 {
    02188   // same constraints as KExecPropsPlugin : desktop file with Type = Application
    02189   return KExecPropsPlugin::supports( _items );
    02190 }
    02191
    02192 void KApplicationPropsPlugin::applyChanges()
    02193 {
    02194   QString path = properties->kurl().path();
    02195
    02196   QFile f( path );
    02197
    02198   if ( !f.open( IO_ReadWrite ) ) {
    02199     KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient access to write to <b>%1</b>.</qt>").arg(path));
    02200     return;
    02201   }
    02202   f.close();
    02203
    02204   KSimpleConfig config( path );
    02205   config.setDesktopGroup();
    02206   config.writeEntry( QString::fromLatin1("Type"), QString::fromLatin1("Application"));
    02207   config.writeEntry( QString::fromLatin1("Comment"), commentEdit->text() );
    02208   config.writeEntry( QString::fromLatin1("Comment"), commentEdit->text(), true, false, true ); // for compat
    02209   config.writeEntry( QString::fromLatin1("GenericName"), genNameEdit->text() );
    02210   config.writeEntry( QString::fromLatin1("GenericName"), genNameEdit->text(), true, false, true ); // for compat
    02211
    02212   QStringList selectedTypes;
    02213   for ( uint i = 0; i < extensionsList->count(); i++ )
    02214     selectedTypes.append( extensionsList->text( i ) );
    02215
    02216   config.writeEntry( QString::fromLatin1("MimeType"), selectedTypes, ';' );
    02217   config.writeEntry( QString::fromLatin1("ServiceTypes"), "" );
    02218   // hmm, actually it should probably be the contrary (but see also typeslistitem.cpp)
    02219
    02220   QString nameStr = nameEdit ? nameEdit->text() : QString::null;
    02221   if ( nameStr.isEmpty() ) // nothing entered, or widget not existing at all (kdesktop mode)
    02222   {
    02223     nameStr = properties->kurl().fileName();
    02224     if ( nameStr.right(8) == QString::fromLatin1(".desktop") )
    02225       nameStr.truncate( nameStr.length() - 8 );
    02226     if ( nameStr.right(7) == QString::fromLatin1(".kdelnk") )
    02227       nameStr.truncate( nameStr.length() - 7 );
    02228   }
    02229   config.writeEntry( QString::fromLatin1("Name"), nameStr );
    02230   config.writeEntry( QString::fromLatin1("Name"), nameStr, true, false, true );
    02231
    02232   config.sync();
    02233   f.close();
    02234 }
    02235
    02236 void KApplicationPropsPlugin::slotAddExtension()
    02237 {
    02238   QListBoxItem *item = availableExtensionsList->firstItem();
    02239   QListBoxItem *nextItem;
    02240
    02241   while ( item )
    02242   {
    02243     nextItem = item->next();
    02244
    02245     if ( item->isSelected() )
    02246     {
    02247       extensionsList->insertItem( item->text() );
    02248       availableExtensionsList->removeItem( availableExtensionsList->index( item ) );
    02249     }
    02250
    02251     item = nextItem;
    02252   }
    02253
    02254   extensionsList->sort();
    02255   updateButton();
    02256 }
    02257
    02258 void KApplicationPropsPlugin::slotDelExtension()
    02259 {
    02260   QListBoxItem *item = extensionsList->firstItem();
    02261   QListBoxItem *nextItem;
    02262
    02263   while ( item )
    02264   {
    02265     nextItem = item->next();
    02266
    02267     if ( item->isSelected() )
    02268     {
    02269       availableExtensionsList->insertItem( item->text() );
    02270       extensionsList->removeItem( extensionsList->index( item ) );
    02271     }
    02272
    02273     item = nextItem;
    02274   }
    02275
    02276   availableExtensionsList->sort();
    02277   updateButton();
    02278 }
    02279
    02280 /* ----------------------------------------------------
    02281  *
    02282  * KBindingPropsPlugin
    02283  *
    02284  * -------------------------------------------------- */
    02285
    02286 class KBindingPropsPlugin::KBindingPropsPluginPrivate
    02287 {
    02288 public:
    02289   KBindingPropsPluginPrivate()
    02290   {
    02291   }
    02292   ~KBindingPropsPluginPrivate()
    02293   {
    02294   }
    02295
    02296   QFrame *m_frame;
    02297 };
    02298
    02299 KBindingPropsPlugin::KBindingPropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props )
    02300 {
    02301   d = new KBindingPropsPluginPrivate;
    02302   d->m_frame = properties->dialog()->addPage(i18n("A&ssociation"));
    02303   patternEdit = new KLineEdit( d->m_frame, "LineEdit_1" );
    02304   commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" );
    02305   mimeEdit = new KLineEdit( d->m_frame, "LineEdit_3" );
    02306
    02307   QBoxLayout * mainlayout = new QVBoxLayout(d->m_frame, KDialog::spacingHint());
    02308   QLabel* tmpQLabel;
    02309
    02310   tmpQLabel = new QLabel( d->m_frame, "Label_1" );
    02311   tmpQLabel->setText(  i18n("Pattern ( example: *.html;*.htm )") );
    02312   tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
    02313   mainlayout->addWidget(tmpQLabel, 1);
    02314
    02315   //patternEdit->setGeometry( 10, 40, 210, 30 );
    02316   //patternEdit->setText( "" );
    02317   patternEdit->setMaxLength( 512 );
    02318   patternEdit->setMinimumSize( patternEdit->sizeHint() );
    02319   patternEdit->setFixedHeight( fontHeight );
    02320   mainlayout->addWidget(patternEdit, 1);
    02321
    02322   tmpQLabel = new QLabel( d->m_frame, "Label_2" );
    02323   tmpQLabel->setText(  i18n("Mime Type") );
    02324   tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
    02325   mainlayout->addWidget(tmpQLabel, 1);
    02326
    02327   //mimeEdit->setGeometry( 10, 160, 210, 30 );
    02328   mimeEdit->setMaxLength( 256 );
    02329   mimeEdit->setMinimumSize( mimeEdit->sizeHint() );
    02330   mimeEdit->setFixedHeight( fontHeight );
    02331   mainlayout->addWidget(mimeEdit, 1);
    02332
    02333   tmpQLabel = new QLabel( d->m_frame, "Label_3" );
    02334   tmpQLabel->setText(  i18n("Comment") );
    02335   tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
    02336   mainlayout->addWidget(tmpQLabel, 1);
    02337
    02338   //commentEdit->setGeometry( 10, 100, 210, 30 );
    02339   commentEdit->setMaxLength( 256 );
    02340   commentEdit->setMinimumSize( commentEdit->sizeHint() );
    02341   commentEdit->setFixedHeight( fontHeight );
    02342   mainlayout->addWidget(commentEdit, 1);
    02343
    02344   cbAutoEmbed = new QCheckBox( i18n("Left click previews"), d->m_frame, "cbAutoEmbed" );
    02345   mainlayout->addWidget(cbAutoEmbed, 1);
    02346
    02347   mainlayout->addStretch (10);
    02348   mainlayout->activate();
    02349
    02350   QFile f( _props->kurl().path() );
    02351   if ( !f.open( IO_ReadOnly ) )
    02352     return;
    02353   f.close();
    02354
    02355   KSimpleConfig config( _props->kurl().path() );
    02356   config.setDesktopGroup();
    02357   QString patternStr = config.readEntry( QString::fromLatin1("Patterns") );
    02358   QString iconStr = config.readEntry( QString::fromLatin1("Icon") );
    02359   QString commentStr = config.readEntry( QString::fromLatin1("Comment") );
    02360   m_sMimeStr = config.readEntry( QString::fromLatin1("MimeType") );
    02361
    02362   if ( !patternStr.isEmpty() )
    02363     patternEdit->setText( patternStr );
    02364   if ( !commentStr.isEmpty() )
    02365     commentEdit->setText( commentStr );
    02366   if ( !m_sMimeStr.isEmpty() )
    02367     mimeEdit->setText( m_sMimeStr );
    02368   cbAutoEmbed->setTristate();
    02369   if ( config.hasKey( QString::fromLatin1("X-KDE-AutoEmbed") ) )
    02370       cbAutoEmbed->setChecked( config.readBoolEntry( QString::fromLatin1("X-KDE-AutoEmbed") ) );
    02371   else
    02372       cbAutoEmbed->setNoChange();
    02373
    02374   connect( patternEdit, SIGNAL( textChanged( const QString & ) ),
    02375            this, SIGNAL( changed() ) );
    02376   connect( commentEdit, SIGNAL( textChanged( const QString & ) ),
    02377            this, SIGNAL( changed() ) );
    02378   connect( mimeEdit, SIGNAL( textChanged( const QString & ) ),
    02379            this, SIGNAL( changed() ) );
    02380   connect( cbAutoEmbed, SIGNAL( toggled( bool ) ),
    02381            this, SIGNAL( changed() ) );
    02382 }
    02383
    02384 KBindingPropsPlugin::~KBindingPropsPlugin()
    02385 {
    02386   delete d;
    02387 }
    02388
    02389 // QString KBindingPropsPlugin::tabName () const
    02390 // {
    02391 //   return i18n ("A&ssociation");
    02392 // }
    02393
    02394 bool KBindingPropsPlugin::supports( KFileItemList _items )
    02395 {
    02396   if ( _items.count() != 1 )
    02397     return false;
    02398   KFileItem * item = _items.first();
    02399   // check if desktop file
    02400   if ( !KPropsDlgPlugin::isDesktopFile( item ) )
    02401     return false;
    02402
    02403   // open file and check type
    02404   KDesktopFile config( item->url().path(), true /* readonly */ );
    02405   return config.hasMimeTypeType();
    02406 }
    02407
    02408 void KBindingPropsPlugin::applyChanges()
    02409 {
    02410   QString path = properties->kurl().path();
    02411   QFile f( path );
    02412
    02413   if ( !f.open( IO_ReadWrite ) )
    02414   {
    02415     KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient access to write to <b>%1</b>.</qt>").arg(path));
    02416     return;
    02417   }
    02418   f.close();
    02419
    02420   KSimpleConfig config( path );
    02421   config.setDesktopGroup();
    02422   config.writeEntry( QString::fromLatin1("Type"), QString::fromLatin1("MimeType") );
    02423
    02424   config.writeEntry( QString::fromLatin1("Patterns"),  patternEdit->text() );
    02425   config.writeEntry( QString::fromLatin1("Comment"), commentEdit->text() );
    02426   config.writeEntry( QString::fromLatin1("Comment"), commentEdit->text(), true, false, true ); // for compat
    02427   config.writeEntry( QString::fromLatin1("MimeType"), mimeEdit->text() );
    02428   if ( cbAutoEmbed->state() == QButton::NoChange )
    02429       config.deleteEntry( QString::fromLatin1("X-KDE-AutoEmbed"), false );
    02430   else
    02431       config.writeEntry( QString::fromLatin1("X-KDE-AutoEmbed"), cbAutoEmbed->isChecked() );
    02432   config.sync();
    02433 }
    02434
    02435 /* ----------------------------------------------------
    02436  *
    02437  * KDevicePropsPlugin
    02438  *
    02439  * -------------------------------------------------- */
    02440
    02441 class KDevicePropsPlugin::KDevicePropsPluginPrivate
    02442 {
    02443 public:
    02444   KDevicePropsPluginPrivate()
    02445   {
    02446   }
    02447   ~KDevicePropsPluginPrivate()
    02448   {
    02449   }
    02450
    02451   QFrame *m_frame;
    02452   QStringList mountpointlist;
    02453 };
    02454
    02455 KDevicePropsPlugin::KDevicePropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props )
    02456 {
    02457   d = new KDevicePropsPluginPrivate;
    02458   d->m_frame = properties->dialog()->addPage(i18n("De&vice"));
    02459
    02460   QStringList devices;
    02461   QCString fstabFile;
    02462   indexDevice = 0;  // device on first column
    02463   indexMountPoint = 1; // mount point on second column
    02464   if ( QFile::exists(QString::fromLatin1("/etc/fstab")) ) // Linux, ...
    02465   {
    02466     fstabFile = "/etc/fstab";
    02467   }
    02468   else if ( QFile::exists(QString::fromLatin1("/etc/vfstab")) ) // Solaris
    02469   {
    02470     fstabFile = "/etc/vfstab";
    02471     indexMountPoint++;
    02472   }
    02473
    02474   // insert your favorite location for fstab here
    02475   if ( !fstabFile.isEmpty() )
    02476   {
    02477 #ifdef HAVE_SETMNTENT
    02478
    02479 #define SETMNTENT setmntent
    02480 #define ENDMNTENT endmntent
    02481 #define STRUCT_MNTENT struct mntent *
    02482 #define STRUCT_SETMNTENT FILE *
    02483 #define GETMNTENT(file, var) ((var = getmntent(file)) != 0)
    02484 #define MOUNTPOINT(var) var->mnt_dir
    02485 #define MOUNTTYPE(var) var->mnt_type
    02486 #define MOUNTOPTIONS(var) var->mnt_opts
    02487 #define HASMNTOPT(var, opt) hasmntopt(var, opt)
    02488 #define FSNAME(var) var->mnt_fsname
    02489
    02490   STRUCT_SETMNTENT fstab = SETMNTENT(fstabFile, "r");
    02491   if (fstab)
    02492   {
    02493     STRUCT_MNTENT fe;
    02494     while (GETMNTENT(fstab, fe))
    02495     {
    02496        QString mountPoint = QFile::decodeName(MOUNTPOINT(fe));
    02497        QString device = QFile::decodeName(FSNAME(fe));
    02498        if (device.startsWith("/") && (mountPoint != "-") &&
    02499            (mountPoint != "none") && !mountPoint.isEmpty())
    02500        {
    02501           devices.append( device + QString::fromLatin1(" (")
    02502                           + mountPoint + QString::fromLatin1(")") );
    02503           m_devicelist.append(device);
    02504           d->mountpointlist.append(mountPoint);
    02505        }
    02506     }
    02507   }
    02508 #else
    02509
    02510     QFile f( fstabFile );
    02511     if ( f.open( IO_ReadOnly ) )
    02512     {
    02513       QTextStream stream( &f );
    02514       while ( !stream.eof() )
    02515       {
    02516         QString line = stream.readLine();
    02517         line = line.simplifyWhiteSpace();
    02518         if (!line.isEmpty() && line[0] == '/') // skip comments but also
    02519         {
    02520           QStringList lst = QStringList::split( ' ', line );
    02521           if ( lst.count() > 2 && lst[indexDevice] != QString::fromLatin1("/proc")
    02522               && lst[indexMountPoint] != QString::fromLatin1("none")
    02523               && lst[indexMountPoint] != QString::fromLatin1("-") )
    02524           {
    02525             devices.append( lst[indexDevice]+QString::fromLatin1(" (")
    02526                              +lst[indexMountPoint]+QString::fromLatin1(")") );
    02527             m_devicelist.append( lst[indexDevice] );
    02528             d->mountpointlist.append( lst[indexMountPoint] );
    02529           }
    02530         }
    02531       }
    02532       f.close();
    02533     }
    02534 #endif
    02535   }
    02536
    02537
    02538   QGridLayout *layout = new QGridLayout( d->m_frame, 0, 3, KDialog::marginHint(),
    02539                                         KDialog::spacingHint());
    02540   layout->setColStretch(1, 1);
    02541
    02542   QLabel* label;
    02543   label = new QLabel( d->m_frame );
    02544   label->setText( devices.count() == 0 ?
    02545                       i18n("Device (/dev/fd0):") : // old style
    02546                       i18n("Device:") ); // new style (combobox)
    02547   layout->addWidget(label, 0, 0);
    02548
    02549   device = new QComboBox( true, d->m_frame, "ComboBox_device" );
    02550   device->insertStringList( devices );
    02551   layout->addWidget(device, 0, 1);
    02552   connect( device, SIGNAL( activated( int ) ),
    02553            this, SLOT( slotActivated( int ) ) );
    02554
    02555   readonly = new QCheckBox( d->m_frame, "CheckBox_readonly" );
    02556   readonly->setText(  i18n("Read only") );
    02557   layout->addWidget(readonly, 1, 1);
    02558
    02559   label = new QLabel( d->m_frame );
    02560   label->setText( devices.count()==0 ?
    02561                       i18n("Mount point (/mnt/floppy):") : // old style
    02562                       i18n("Mount point:")); // new style (combobox)
    02563   layout->addWidget(label, 2, 0);
    02564
    02565   mountpoint = new QLabel( d->m_frame, "LineEdit_mountpoint" );
    02566
    02567   layout->addWidget(mountpoint, 2, 1);
    02568
    02569   KSeparator* sep = new KSeparator( KSeparator::HLine, d->m_frame);
    02570   layout->addMultiCellWidget(sep, 4, 4, 0, 2);
    02571
    02572   unmounted = new KIconButton( d->m_frame );
    02573   unmounted->setFixedSize(70, 70);
    02574   unmounted->setIconType(KIcon::Desktop, KIcon::Device);
    02575   layout->addWidget(unmounted, 5, 0);
    02576
    02577   label = new QLabel( i18n("Unmounted Icon"),  d->m_frame );
    02578   layout->addWidget(label, 5, 1);
    02579
    02580   layout->setRowStretch(6, 1);
    02581
    02582   QString path( _props->kurl().path() );
    02583
    02584   QFile f( path );
    02585   if ( !f.open( IO_ReadOnly ) )
    02586     return;
    02587   f.close();
    02588
    02589   KSimpleConfig config( path );
    02590   config.setDesktopGroup();
    02591   QString deviceStr = config.readEntry( QString::fromLatin1("Dev") );
    02592   QString mountPointStr = config.readEntry( QString::fromLatin1("MountPoint") );
    02593   bool ro = config.readBoolEntry( QString::fromLatin1("ReadOnly"), false );
    02594   QString unmountedStr = config.readEntry( QString::fromLatin1("UnmountIcon") );
    02595
    02596   device->setEditText( deviceStr );
    02597   if ( !deviceStr.isEmpty() ) {
    02598     // Set default options for this device (first matching entry)
    02599     int index = m_devicelist.findIndex(deviceStr);
    02600     if (index != -1)
    02601     {
    02602       //kdDebug(250) << "found it " << index << endl;
    02603       slotActivated( index );
    02604     }
    02605   }
    02606
    02607   if ( !mountPointStr.isEmpty() )
    02608     mountpoint->setText( mountPointStr );
    02609
    02610   readonly->setChecked( ro );
    02611
    02612   if ( unmountedStr.isEmpty() )
    02613     unmountedStr = KMimeType::mimeType(QString::fromLatin1("application/octet-stream"))->KServiceType::icon(); // default icon
    02614
    02615   unmounted->setIcon( unmountedStr );
    02616
    02617   connect( device, SIGNAL( activated( int ) ),
    02618            this, SIGNAL( changed() ) );
    02619   connect( device, SIGNAL( textChanged( const QString & ) ),
    02620            this, SIGNAL( changed() ) );
    02621   connect( readonly, SIGNAL( toggled( bool ) ),
    02622            this, SIGNAL( changed() ) );
    02623   connect( unmounted, SIGNAL( iconChanged( QString ) ),
    02624            this, SIGNAL( changed() ) );
    02625 }
    02626
    02627 KDevicePropsPlugin::~KDevicePropsPlugin()
    02628 {
    02629   delete d;
    02630 }
    02631
    02632 // QString KDevicePropsPlugin::tabName () const
    02633 // {
    02634 //   return i18n ("De&vice");
    02635 // }
    02636
    02637 void KDevicePropsPlugin::slotActivated( int index )
    02638 {
    02639   device->setEditText( m_devicelist[index] );
    02640   mountpoint->setText( d->mountpointlist[index] );
    02641 }
    02642
    02643 bool KDevicePropsPlugin::supports( KFileItemList _items )
    02644 {
    02645   if ( _items.count() != 1 )
    02646     return false;
    02647   KFileItem * item = _items.first();
    02648   // check if desktop file
    02649   if ( !KPropsDlgPlugin::isDesktopFile( item ) )
    02650     return false;
    02651   // open file and check type
    02652   KDesktopFile config( item->url().path(), true /* readonly */ );
    02653   return config.hasDeviceType();
    02654 }
    02655
    02656 void KDevicePropsPlugin::applyChanges()
    02657 {
    02658   QString path = properties->kurl().path();
    02659   QFile f( path );
    02660   if ( !f.open( IO_ReadWrite ) )
    02661   {
    02662     KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient access to write to <b>%1</b>.</qt>").arg(path));
    02663     return;
    02664   }
    02665   f.close();
    02666
    02667   KSimpleConfig config( path );
    02668   config.setDesktopGroup();
    02669   config.writeEntry( QString::fromLatin1("Type"), QString::fromLatin1("FSDevice") );
    02670
    02671   config.writeEntry( QString::fromLatin1("Dev"), device->currentText() );
    02672   config.writeEntry( QString::fromLatin1("MountPoint"), mountpoint->text() );
    02673
    02674   config.writeEntry( QString::fromLatin1("UnmountIcon"), unmounted->icon() );
    02675   kdDebug(250) << "unmounted->icon() = " << unmounted->icon() << endl;
    02676
    02677   config.writeEntry( QString::fromLatin1("ReadOnly"), readonly->isChecked() );
    02678
    02679   config.sync();
    02680 }
    02681
    02682 void KPropertiesDialog::virtual_hook( int id, void* data )
    02683 { KDialogBase::virtual_hook( id, data ); }
    02684
    02685 void KPropsDlgPlugin::virtual_hook( int, void* )
    02686 { /*BASE::virtual_hook( id, data );*/ }
    02687
    02688 #include "kpropertiesdialog.moc"

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:14:06 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001