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