TDE core libraries
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4171 lines
128 KiB

  1. /* This file is part of the KDE project
  2. Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
  3. Copyright (c) 1999, 2000 Preston Brown <pbrown@kde.org>
  4. Copyright (c) 2000 Simon Hausmann <hausmann@kde.org>
  5. Copyright (c) 2000 David Faure <faure@kde.org>
  6. Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
  7. This library is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU Library General Public
  9. License as published by the Free Software Foundation; either
  10. version 2 of the License, or (at your option) any later version.
  11. This library is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. Library General Public License for more details.
  15. You should have received a copy of the GNU Library General Public License
  16. along with this library; see the file COPYING.LIB. If not, write to
  17. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  18. Boston, MA 02110-1301, USA.
  19. */
  20. /*
  21. * kpropertiesdialog.cpp
  22. * View/Edit Properties of files, locally or remotely
  23. *
  24. * some FilePermissionsPropsPlugin-changes by
  25. * Henner Zeller <zeller@think.de>
  26. * some layout management by
  27. * Bertrand Leconte <B.Leconte@mail.dotcom.fr>
  28. * the rest of the layout management, bug fixes, adaptation to libkio,
  29. * template feature by
  30. * David Faure <faure@kde.org>
  31. * More layout, cleanups, and fixes by
  32. * Preston Brown <pbrown@kde.org>
  33. * Plugin capability, cleanups and port to KDialogBase by
  34. * Simon Hausmann <hausmann@kde.org>
  35. * KDesktopPropsPlugin by
  36. * Waldo Bastian <bastian@kde.org>
  37. */
  38. #include <config.h>
  39. extern "C" {
  40. #include <pwd.h>
  41. #include <grp.h>
  42. #include <time.h>
  43. #include <sys/types.h>
  44. }
  45. #include <unistd.h>
  46. #include <errno.h>
  47. #include <assert.h>
  48. #include <algorithm>
  49. #include <functional>
  50. #include <tqfile.h>
  51. #include <tqdir.h>
  52. #include <tqlabel.h>
  53. #include <tqpushbutton.h>
  54. #include <tqcheckbox.h>
  55. #include <tqstrlist.h>
  56. #include <tqstringlist.h>
  57. #include <tqtextstream.h>
  58. #include <tqpainter.h>
  59. #include <tqlayout.h>
  60. #include <tqcombobox.h>
  61. #include <tqgroupbox.h>
  62. #include <tqwhatsthis.h>
  63. #include <tqtooltip.h>
  64. #include <tqstyle.h>
  65. #include <tqprogressbar.h>
  66. #include <tqvbox.h>
  67. #include <tqvaluevector.h>
  68. #ifdef USE_POSIX_ACL
  69. extern "C" {
  70. #include <sys/param.h>
  71. #ifdef HAVE_SYS_MOUNT_H
  72. #include <sys/mount.h>
  73. #endif
  74. #ifdef HAVE_SYS_XATTR_H
  75. #include <sys/xattr.h>
  76. #endif
  77. }
  78. #endif
  79. #include <kapplication.h>
  80. #include <kdialog.h>
  81. #include <kdirsize.h>
  82. #include <kdirwatch.h>
  83. #include <kdirnotify_stub.h>
  84. #include <kdiskfreesp.h>
  85. #include <kdebug.h>
  86. #include <kdesktopfile.h>
  87. #include <kicondialog.h>
  88. #include <kurl.h>
  89. #include <kurlrequester.h>
  90. #include <klocale.h>
  91. #include <kglobal.h>
  92. #include <kglobalsettings.h>
  93. #include <kstandarddirs.h>
  94. #include <kio/job.h>
  95. #include <kio/chmodjob.h>
  96. #include <kio/renamedlg.h>
  97. #include <kio/netaccess.h>
  98. #include <kio/kservicetypefactory.h>
  99. #include <kfiledialog.h>
  100. #include <kmimetype.h>
  101. #include <kmountpoint.h>
  102. #include <kiconloader.h>
  103. #include <kmessagebox.h>
  104. #include <kservice.h>
  105. #include <kcompletion.h>
  106. #include <klineedit.h>
  107. #include <kseparator.h>
  108. #include <ksqueezedtextlabel.h>
  109. #include <klibloader.h>
  110. #include <ktrader.h>
  111. #include <kparts/componentfactory.h>
  112. #include <kmetaprops.h>
  113. #include <kpreviewprops.h>
  114. #include <kprocess.h>
  115. #include <krun.h>
  116. #include <klistview.h>
  117. #include <kacl.h>
  118. #include "kfilesharedlg.h"
  119. #include "kpropertiesdesktopbase.h"
  120. #include "kpropertiesdesktopadvbase.h"
  121. #include "kpropertiesmimetypebase.h"
  122. #ifdef USE_POSIX_ACL
  123. #include "kacleditwidget.h"
  124. #endif
  125. #include "kpropertiesdialog.h"
  126. #ifdef Q_WS_WIN
  127. # include <win32_utils.h>
  128. #endif
  129. static TQString nameFromFileName(TQString nameStr)
  130. {
  131. if ( nameStr.endsWith(".desktop") )
  132. nameStr.truncate( nameStr.length() - 8 );
  133. if ( nameStr.endsWith(".kdelnk") )
  134. nameStr.truncate( nameStr.length() - 7 );
  135. // Make it human-readable (%2F => '/', ...)
  136. nameStr = KIO::decodeFileName( nameStr );
  137. return nameStr;
  138. }
  139. mode_t KFilePermissionsPropsPlugin::fperm[3][4] = {
  140. {S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID},
  141. {S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID},
  142. {S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX}
  143. };
  144. class KPropertiesDialog::KPropertiesDialogPrivate
  145. {
  146. public:
  147. KPropertiesDialogPrivate()
  148. {
  149. m_aborted = false;
  150. fileSharePage = 0;
  151. }
  152. ~KPropertiesDialogPrivate()
  153. {
  154. }
  155. bool m_aborted:1;
  156. TQWidget* fileSharePage;
  157. };
  158. KPropertiesDialog::KPropertiesDialog (KFileItem* item,
  159. TQWidget* parent, const char* name,
  160. bool modal, bool autoShow)
  161. : KDialogBase (KDialogBase::Tabbed, i18n( "Properties for %1" ).arg(KIO::decodeFileName(item->url().fileName())),
  162. KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
  163. parent, name, modal)
  164. {
  165. d = new KPropertiesDialogPrivate;
  166. assert( item );
  167. m_items.append( new KFileItem(*item) ); // deep copy
  168. m_singleUrl = item->url();
  169. assert(!m_singleUrl.isEmpty());
  170. init (modal, autoShow);
  171. }
  172. KPropertiesDialog::KPropertiesDialog (const TQString& title,
  173. TQWidget* parent, const char* name, bool modal)
  174. : KDialogBase (KDialogBase::Tabbed, i18n ("Properties for %1").arg(title),
  175. KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
  176. parent, name, modal)
  177. {
  178. d = new KPropertiesDialogPrivate;
  179. init (modal, false);
  180. }
  181. KPropertiesDialog::KPropertiesDialog (KFileItemList _items,
  182. TQWidget* parent, const char* name,
  183. bool modal, bool autoShow)
  184. : KDialogBase (KDialogBase::Tabbed,
  185. // TODO: replace <never used> with "Properties for 1 item". It's very confusing how it has to be translated otherwise
  186. // (empty translation before the "\n" is not allowed by msgfmt...)
  187. _items.count()>1 ? i18n( "<never used>","Properties for %n Selected Items",_items.count()) :
  188. i18n( "Properties for %1" ).arg(KIO::decodeFileName(_items.first()->url().fileName())),
  189. KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
  190. parent, name, modal)
  191. {
  192. d = new KPropertiesDialogPrivate;
  193. assert( !_items.isEmpty() );
  194. m_singleUrl = _items.first()->url();
  195. assert(!m_singleUrl.isEmpty());
  196. KFileItemListIterator it ( _items );
  197. // Deep copy
  198. for ( ; it.current(); ++it )
  199. m_items.append( new KFileItem( **it ) );
  200. init (modal, autoShow);
  201. }
  202. #ifndef KDE_NO_COMPAT
  203. KPropertiesDialog::KPropertiesDialog (const KURL& _url, mode_t /* _mode is now unused */,
  204. TQWidget* parent, const char* name,
  205. bool modal, bool autoShow)
  206. : KDialogBase (KDialogBase::Tabbed,
  207. i18n( "Properties for %1" ).arg(KIO::decodeFileName(_url.fileName())),
  208. KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
  209. parent, name, modal),
  210. m_singleUrl( _url )
  211. {
  212. d = new KPropertiesDialogPrivate;
  213. KIO::UDSEntry entry;
  214. KIO::NetAccess::stat(_url, entry, parent);
  215. m_items.append( new KFileItem( entry, _url ) );
  216. init (modal, autoShow);
  217. }
  218. #endif
  219. KPropertiesDialog::KPropertiesDialog (const KURL& _url,
  220. TQWidget* parent, const char* name,
  221. bool modal, bool autoShow)
  222. : KDialogBase (KDialogBase::Tabbed,
  223. i18n( "Properties for %1" ).arg(KIO::decodeFileName(_url.fileName())),
  224. KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
  225. parent, name, modal),
  226. m_singleUrl( _url )
  227. {
  228. d = new KPropertiesDialogPrivate;
  229. KIO::UDSEntry entry;
  230. KIO::NetAccess::stat(_url, entry, parent);
  231. m_items.append( new KFileItem( entry, _url ) );
  232. init (modal, autoShow);
  233. }
  234. KPropertiesDialog::KPropertiesDialog (const KURL& _tempUrl, const KURL& _currentDir,
  235. const TQString& _defaultName,
  236. TQWidget* parent, const char* name,
  237. bool modal, bool autoShow)
  238. : KDialogBase (KDialogBase::Tabbed,
  239. i18n( "Properties for %1" ).arg(KIO::decodeFileName(_tempUrl.fileName())),
  240. KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
  241. parent, name, modal),
  242. m_singleUrl( _tempUrl ),
  243. m_defaultName( _defaultName ),
  244. m_currentDir( _currentDir )
  245. {
  246. d = new KPropertiesDialogPrivate;
  247. assert(!m_singleUrl.isEmpty());
  248. // Create the KFileItem for the _template_ file, in order to read from it.
  249. m_items.append( new KFileItem( KFileItem::Unknown, KFileItem::Unknown, m_singleUrl ) );
  250. init (modal, autoShow);
  251. }
  252. bool KPropertiesDialog::showDialog(KFileItem* item, TQWidget* parent,
  253. const char* name, bool modal)
  254. {
  255. #ifdef Q_WS_WIN
  256. TQString localPath = item->localPath();
  257. if (!localPath.isEmpty())
  258. return showWin32FilePropertyDialog(localPath);
  259. #endif
  260. new KPropertiesDialog(item, parent, name, modal);
  261. return true;
  262. }
  263. bool KPropertiesDialog::showDialog(const KURL& _url, TQWidget* parent,
  264. const char* name, bool modal)
  265. {
  266. #ifdef Q_WS_WIN
  267. if (_url.isLocalFile())
  268. return showWin32FilePropertyDialog( _url.path() );
  269. #endif
  270. new KPropertiesDialog(_url, parent, name, modal);
  271. return true;
  272. }
  273. bool KPropertiesDialog::showDialog(const KFileItemList& _items, TQWidget* parent,
  274. const char* name, bool modal)
  275. {
  276. if (_items.count()==1)
  277. return KPropertiesDialog::showDialog(_items.getFirst(), parent, name, modal);
  278. new KPropertiesDialog(_items, parent, name, modal);
  279. return true;
  280. }
  281. void KPropertiesDialog::init (bool modal, bool autoShow)
  282. {
  283. m_pageList.setAutoDelete( true );
  284. m_items.setAutoDelete( true );
  285. insertPages();
  286. if (autoShow)
  287. {
  288. if (!modal)
  289. show();
  290. else
  291. exec();
  292. }
  293. }
  294. void KPropertiesDialog::showFileSharingPage()
  295. {
  296. if (d->fileSharePage) {
  297. showPage( pageIndex( d->fileSharePage));
  298. }
  299. }
  300. void KPropertiesDialog::setFileSharingPage(TQWidget* page) {
  301. d->fileSharePage = page;
  302. }
  303. void KPropertiesDialog::setFileNameReadOnly( bool ro )
  304. {
  305. KPropsDlgPlugin *it;
  306. for ( it=m_pageList.first(); it != 0L; it=m_pageList.next() )
  307. {
  308. KFilePropsPlugin* plugin = dynamic_cast<KFilePropsPlugin*>(it);
  309. if ( plugin ) {
  310. plugin->setFileNameReadOnly( ro );
  311. break;
  312. }
  313. }
  314. }
  315. void KPropertiesDialog::slotStatResult( KIO::Job * )
  316. {
  317. }
  318. KPropertiesDialog::~KPropertiesDialog()
  319. {
  320. m_pageList.clear();
  321. delete d;
  322. }
  323. void KPropertiesDialog::insertPlugin (KPropsDlgPlugin* plugin)
  324. {
  325. connect (plugin, TQT_SIGNAL (changed ()),
  326. plugin, TQT_SLOT (setDirty ()));
  327. m_pageList.append (plugin);
  328. }
  329. bool KPropertiesDialog::canDisplay( KFileItemList _items )
  330. {
  331. // TODO: cache the result of those calls. Currently we parse .desktop files far too many times
  332. return KFilePropsPlugin::supports( _items ) ||
  333. KFilePermissionsPropsPlugin::supports( _items ) ||
  334. KDesktopPropsPlugin::supports( _items ) ||
  335. KBindingPropsPlugin::supports( _items ) ||
  336. KURLPropsPlugin::supports( _items ) ||
  337. KDevicePropsPlugin::supports( _items ) ||
  338. KFileMetaPropsPlugin::supports( _items ) ||
  339. KPreviewPropsPlugin::supports( _items );
  340. }
  341. void KPropertiesDialog::slotOk()
  342. {
  343. KPropsDlgPlugin *page;
  344. d->m_aborted = false;
  345. KFilePropsPlugin * filePropsPlugin = 0L;
  346. if ( m_pageList.first()->isA("KFilePropsPlugin") )
  347. filePropsPlugin = static_cast<KFilePropsPlugin *>(m_pageList.first());
  348. // If any page is dirty, then set the main one (KFilePropsPlugin) as
  349. // dirty too. This is what makes it possible to save changes to a global
  350. // desktop file into a local one. In other cases, it doesn't hurt.
  351. for ( page = m_pageList.first(); page != 0L; page = m_pageList.next() )
  352. if ( page->isDirty() && filePropsPlugin )
  353. {
  354. filePropsPlugin->setDirty();
  355. break;
  356. }
  357. // Apply the changes in the _normal_ order of the tabs now
  358. // This is because in case of renaming a file, KFilePropsPlugin will call
  359. // KPropertiesDialog::rename, so other tab will be ok with whatever order
  360. // BUT for file copied from templates, we need to do the renaming first !
  361. for ( page = m_pageList.first(); page != 0L && !d->m_aborted; page = m_pageList.next() )
  362. if ( page->isDirty() )
  363. {
  364. kdDebug( 250 ) << "applying changes for " << page->className() << endl;
  365. page->applyChanges();
  366. // applyChanges may change d->m_aborted.
  367. }
  368. else
  369. kdDebug( 250 ) << "skipping page " << page->className() << endl;
  370. if ( !d->m_aborted && filePropsPlugin )
  371. filePropsPlugin->postApplyChanges();
  372. if ( !d->m_aborted )
  373. {
  374. emit applied();
  375. emit propertiesClosed();
  376. deleteLater();
  377. accept();
  378. } // else, keep dialog open for user to fix the problem.
  379. }
  380. void KPropertiesDialog::slotCancel()
  381. {
  382. emit canceled();
  383. emit propertiesClosed();
  384. deleteLater();
  385. done( Rejected );
  386. }
  387. void KPropertiesDialog::insertPages()
  388. {
  389. if (m_items.isEmpty())
  390. return;
  391. if ( KFilePropsPlugin::supports( m_items ) )
  392. {
  393. KPropsDlgPlugin *p = new KFilePropsPlugin( this );
  394. insertPlugin (p);
  395. }
  396. if ( KFilePermissionsPropsPlugin::supports( m_items ) )
  397. {
  398. KPropsDlgPlugin *p = new KFilePermissionsPropsPlugin( this );
  399. insertPlugin (p);
  400. }
  401. if ( KDesktopPropsPlugin::supports( m_items ) )
  402. {
  403. KPropsDlgPlugin *p = new KDesktopPropsPlugin( this );
  404. insertPlugin (p);
  405. }
  406. if ( KBindingPropsPlugin::supports( m_items ) )
  407. {
  408. KPropsDlgPlugin *p = new KBindingPropsPlugin( this );
  409. insertPlugin (p);
  410. }
  411. if ( KURLPropsPlugin::supports( m_items ) )
  412. {
  413. KPropsDlgPlugin *p = new KURLPropsPlugin( this );
  414. insertPlugin (p);
  415. }
  416. if ( KDevicePropsPlugin::supports( m_items ) )
  417. {
  418. KPropsDlgPlugin *p = new KDevicePropsPlugin( this );
  419. insertPlugin (p);
  420. }
  421. if ( KFileMetaPropsPlugin::supports( m_items ) )
  422. {
  423. KPropsDlgPlugin *p = new KFileMetaPropsPlugin( this );
  424. insertPlugin (p);
  425. }
  426. if ( KPreviewPropsPlugin::supports( m_items ) )
  427. {
  428. KPropsDlgPlugin *p = new KPreviewPropsPlugin( this );
  429. insertPlugin (p);
  430. }
  431. if ( kapp->authorizeKAction("sharefile") &&
  432. KFileSharePropsPlugin::supports( m_items ) )
  433. {
  434. KPropsDlgPlugin *p = new KFileSharePropsPlugin( this );
  435. insertPlugin (p);
  436. }
  437. //plugins
  438. if ( m_items.count() != 1 )
  439. return;
  440. KFileItem *item = m_items.first();
  441. TQString mimetype = item->mimetype();
  442. if ( mimetype.isEmpty() )
  443. return;
  444. TQString query = TQString::fromLatin1(
  445. "('KPropsDlg/Plugin' in ServiceTypes) and "
  446. "((not exist [X-TDE-Protocol]) or "
  447. " ([X-TDE-Protocol] == '%1' ) )" ).arg(item->url().protocol());
  448. kdDebug( 250 ) << "trader query: " << query << endl;
  449. KTrader::OfferList offers = KTrader::self()->query( mimetype, query );
  450. KTrader::OfferList::ConstIterator it = offers.begin();
  451. KTrader::OfferList::ConstIterator end = offers.end();
  452. for (; it != end; ++it )
  453. {
  454. KPropsDlgPlugin *plugin = KParts::ComponentFactory
  455. ::createInstanceFromLibrary<KPropsDlgPlugin>( (*it)->library().local8Bit().data(),
  456. TQT_TQOBJECT(this),
  457. (*it)->name().latin1() );
  458. if ( !plugin )
  459. continue;
  460. insertPlugin( plugin );
  461. }
  462. }
  463. void KPropertiesDialog::updateUrl( const KURL& _newUrl )
  464. {
  465. Q_ASSERT( m_items.count() == 1 );
  466. kdDebug(250) << "KPropertiesDialog::updateUrl (pre)" << _newUrl.url() << endl;
  467. KURL newUrl = _newUrl;
  468. emit saveAs(m_singleUrl, newUrl);
  469. kdDebug(250) << "KPropertiesDialog::updateUrl (post)" << newUrl.url() << endl;
  470. m_singleUrl = newUrl;
  471. m_items.first()->setURL( newUrl );
  472. assert(!m_singleUrl.isEmpty());
  473. // If we have an Desktop page, set it dirty, so that a full file is saved locally
  474. // Same for a URL page (because of the Name= hack)
  475. for ( TQPtrListIterator<KPropsDlgPlugin> it(m_pageList); it.current(); ++it )
  476. if ( it.current()->isA("KExecPropsPlugin") || // KDE4 remove me
  477. it.current()->isA("KURLPropsPlugin") ||
  478. it.current()->isA("KDesktopPropsPlugin"))
  479. {
  480. //kdDebug(250) << "Setting page dirty" << endl;
  481. it.current()->setDirty();
  482. break;
  483. }
  484. }
  485. void KPropertiesDialog::rename( const TQString& _name )
  486. {
  487. Q_ASSERT( m_items.count() == 1 );
  488. kdDebug(250) << "KPropertiesDialog::rename " << _name << endl;
  489. KURL newUrl;
  490. // if we're creating from a template : use currentdir
  491. if ( !m_currentDir.isEmpty() )
  492. {
  493. newUrl = m_currentDir;
  494. newUrl.addPath( _name );
  495. }
  496. else
  497. {
  498. TQString tmpurl = m_singleUrl.url();
  499. if ( tmpurl.at(tmpurl.length() - 1) == '/')
  500. // It's a directory, so strip the trailing slash first
  501. tmpurl.truncate( tmpurl.length() - 1);
  502. newUrl = tmpurl;
  503. newUrl.setFileName( _name );
  504. }
  505. updateUrl( newUrl );
  506. }
  507. void KPropertiesDialog::abortApplying()
  508. {
  509. d->m_aborted = true;
  510. }
  511. class KPropsDlgPlugin::KPropsDlgPluginPrivate
  512. {
  513. public:
  514. KPropsDlgPluginPrivate()
  515. {
  516. }
  517. ~KPropsDlgPluginPrivate()
  518. {
  519. }
  520. bool m_bDirty;
  521. };
  522. KPropsDlgPlugin::KPropsDlgPlugin( KPropertiesDialog *_props )
  523. : TQObject( _props, 0L )
  524. {
  525. d = new KPropsDlgPluginPrivate;
  526. properties = _props;
  527. fontHeight = 2*properties->fontMetrics().height();
  528. d->m_bDirty = false;
  529. }
  530. KPropsDlgPlugin::~KPropsDlgPlugin()
  531. {
  532. delete d;
  533. }
  534. bool KPropsDlgPlugin::isDesktopFile( KFileItem * _item )
  535. {
  536. // only local files
  537. bool isLocal;
  538. KURL url = _item->mostLocalURL( isLocal );
  539. if ( !isLocal )
  540. return false;
  541. // only regular files
  542. if ( !S_ISREG( _item->mode() ) )
  543. return false;
  544. TQString t( url.path() );
  545. // only if readable
  546. FILE *f = fopen( TQFile::encodeName(t), "r" );
  547. if ( f == 0L )
  548. return false;
  549. fclose(f);
  550. // return true if desktop file
  551. return ( (_item->mimetype() == "application/x-desktop")
  552. || (_item->mimetype() == "media/builtin-mydocuments")
  553. || (_item->mimetype() == "media/builtin-mycomputer")
  554. || (_item->mimetype() == "media/builtin-mynetworkplaces")
  555. || (_item->mimetype() == "media/builtin-printers")
  556. || (_item->mimetype() == "media/builtin-trash")
  557. || (_item->mimetype() == "media/builtin-webbrowser") );
  558. }
  559. void KPropsDlgPlugin::setDirty( bool b )
  560. {
  561. d->m_bDirty = b;
  562. }
  563. void KPropsDlgPlugin::setDirty()
  564. {
  565. d->m_bDirty = true;
  566. }
  567. bool KPropsDlgPlugin::isDirty() const
  568. {
  569. return d->m_bDirty;
  570. }
  571. void KPropsDlgPlugin::applyChanges()
  572. {
  573. kdWarning(250) << "applyChanges() not implemented in page !" << endl;
  574. }
  575. ///////////////////////////////////////////////////////////////////////////////
  576. class KFilePropsPlugin::KFilePropsPluginPrivate
  577. {
  578. public:
  579. KFilePropsPluginPrivate()
  580. {
  581. dirSizeJob = 0L;
  582. dirSizeUpdateTimer = 0L;
  583. m_lined = 0;
  584. m_freeSpaceLabel = 0;
  585. }
  586. ~KFilePropsPluginPrivate()
  587. {
  588. if ( dirSizeJob )
  589. dirSizeJob->kill();
  590. }
  591. KDirSize * dirSizeJob;
  592. TQTimer *dirSizeUpdateTimer;
  593. TQFrame *m_frame;
  594. bool bMultiple;
  595. bool bIconChanged;
  596. bool bKDesktopMode;
  597. bool bDesktopFile;
  598. TQLabel *m_freeSpaceLabel;
  599. TQString mimeType;
  600. TQString oldFileName;
  601. KLineEdit* m_lined;
  602. };
  603. KFilePropsPlugin::KFilePropsPlugin( KPropertiesDialog *_props )
  604. : KPropsDlgPlugin( _props )
  605. {
  606. d = new KFilePropsPluginPrivate;
  607. d->bMultiple = (properties->items().count() > 1);
  608. d->bIconChanged = false;
  609. d->bKDesktopMode = (TQCString(tqApp->name()) == "kdesktop"); // nasty heh?
  610. d->bDesktopFile = KDesktopPropsPlugin::supports(properties->items());
  611. kdDebug(250) << "KFilePropsPlugin::KFilePropsPlugin bMultiple=" << d->bMultiple << endl;
  612. // We set this data from the first item, and we'll
  613. // check that the other items match against it, resetting when not.
  614. bool isLocal;
  615. KFileItem * item = properties->item();
  616. KURL url = item->mostLocalURL( isLocal );
  617. bool isReallyLocal = item->url().isLocalFile();
  618. bool bDesktopFile = isDesktopFile(item);
  619. kdDebug() << "url=" << url << " bDesktopFile=" << bDesktopFile << " isLocal=" << isLocal << " isReallyLocal=" << isReallyLocal << endl;
  620. mode_t mode = item->mode();
  621. bool hasDirs = item->isDir() && !item->isLink();
  622. bool hasRoot = url.path() == TQString::fromLatin1("/");
  623. TQString iconStr = KMimeType::iconForURL(url, mode);
  624. TQString directory = properties->kurl().directory();
  625. TQString protocol = properties->kurl().protocol();
  626. TQString mimeComment = item->mimeComment();
  627. d->mimeType = item->mimetype();
  628. bool hasTotalSize;
  629. KIO::filesize_t totalSize = item->size(hasTotalSize);
  630. TQString magicMimeComment;
  631. if ( isLocal ) {
  632. KMimeType::Ptr magicMimeType = KMimeType::findByFileContent( url.path() );
  633. if ( magicMimeType->name() != KMimeType::defaultMimeType() )
  634. magicMimeComment = magicMimeType->comment();
  635. }
  636. // Those things only apply to 'single file' mode
  637. TQString filename = TQString::null;
  638. bool isTrash = false;
  639. bool isDevice = false;
  640. m_bFromTemplate = false;
  641. // And those only to 'multiple' mode
  642. uint iDirCount = hasDirs ? 1 : 0;
  643. uint iFileCount = 1-iDirCount;
  644. d->m_frame = properties->addPage (i18n("&General"));
  645. TQVBoxLayout *vbl = new TQVBoxLayout( d->m_frame, 0,
  646. KDialog::spacingHint(), "vbl");
  647. TQGridLayout *grid = new TQGridLayout(0, 3); // unknown rows
  648. grid->setColStretch(0, 0);
  649. grid->setColStretch(1, 0);
  650. grid->setColStretch(2, 1);
  651. grid->addColSpacing(1, KDialog::spacingHint());
  652. vbl->addLayout(TQT_TQLAYOUT(grid));
  653. int curRow = 0;
  654. if ( !d->bMultiple )
  655. {
  656. TQString path;
  657. if ( !m_bFromTemplate ) {
  658. isTrash = ( properties->kurl().protocol().find( "trash", 0, false)==0 );
  659. if ( properties->kurl().protocol().find("device", 0, false)==0)
  660. isDevice = true;
  661. // Extract the full name, but without file: for local files
  662. if ( isReallyLocal )
  663. path = properties->kurl().path();
  664. else
  665. path = properties->kurl().prettyURL();
  666. } else {
  667. path = properties->currentDir().path(1) + properties->defaultName();
  668. directory = properties->currentDir().prettyURL();
  669. }
  670. if (KExecPropsPlugin::supports(properties->items()) || // KDE4 remove me
  671. d->bDesktopFile ||
  672. KBindingPropsPlugin::supports(properties->items())) {
  673. determineRelativePath( path );
  674. }
  675. // Extract the file name only
  676. filename = properties->defaultName();
  677. if ( filename.isEmpty() ) { // no template
  678. filename = item->name(); // this gives support for UDS_NAME, e.g. for kio_trash or kio_system
  679. } else {
  680. m_bFromTemplate = true;
  681. setDirty(); // to enforce that the copy happens
  682. }
  683. d->oldFileName = filename;
  684. // Make it human-readable
  685. filename = nameFromFileName( filename );
  686. if ( d->bKDesktopMode && d->bDesktopFile ) {
  687. KDesktopFile config( url.path(), true /* readonly */ );
  688. if ( config.hasKey( "Name" ) ) {
  689. filename = config.readName();
  690. }
  691. }
  692. oldName = filename;
  693. }
  694. else
  695. {
  696. // Multiple items: see what they have in common
  697. KFileItemList items = properties->items();
  698. KFileItemListIterator it( items );
  699. for ( ++it /*no need to check the first one again*/ ; it.current(); ++it )
  700. {
  701. KURL url = (*it)->url();
  702. kdDebug(250) << "KFilePropsPlugin::KFilePropsPlugin " << url.prettyURL() << endl;
  703. // The list of things we check here should match the variables defined
  704. // at the beginning of this method.
  705. if ( url.isLocalFile() != isLocal )
  706. isLocal = false; // not all local
  707. if ( bDesktopFile && isDesktopFile(*it) != bDesktopFile )
  708. bDesktopFile = false; // not all desktop files
  709. if ( (*it)->mode() != mode )
  710. mode = (mode_t)0;
  711. if ( KMimeType::iconForURL(url, mode) != iconStr )
  712. iconStr = "kmultiple";
  713. if ( url.directory() != directory )
  714. directory = TQString::null;
  715. if ( url.protocol() != protocol )
  716. protocol = TQString::null;
  717. if ( !mimeComment.isNull() && (*it)->mimeComment() != mimeComment )
  718. mimeComment = TQString::null;
  719. if ( isLocal && !magicMimeComment.isNull() ) {
  720. KMimeType::Ptr magicMimeType = KMimeType::findByFileContent( url.path() );
  721. if ( magicMimeType->comment() != magicMimeComment )
  722. magicMimeComment = TQString::null;
  723. }
  724. if ( url.path() == TQString::fromLatin1("/") )
  725. hasRoot = true;
  726. if ( (*it)->isDir() && !(*it)->isLink() )
  727. {
  728. iDirCount++;
  729. hasDirs = true;
  730. }
  731. else
  732. {
  733. iFileCount++;
  734. bool hasSize;
  735. totalSize += (*it)->size(hasSize);
  736. hasTotalSize = hasTotalSize || hasSize;
  737. }
  738. }
  739. }
  740. if (!isReallyLocal && !protocol.isEmpty())
  741. {
  742. directory += ' ';
  743. directory += '(';
  744. directory += protocol;
  745. directory += ')';
  746. }
  747. if ( !isDevice && !isTrash && (bDesktopFile || S_ISDIR(mode)) && !d->bMultiple /*not implemented for multiple*/ )
  748. {
  749. KIconButton *iconButton = new KIconButton( d->m_frame );
  750. int bsize = 66 + 2 * iconButton->style().pixelMetric(TQStyle::PM_ButtonMargin);
  751. iconButton->setFixedSize(bsize, bsize);
  752. iconButton->setIconSize(48);
  753. iconButton->setStrictIconSize(false);
  754. // This works for everything except Device icons on unmounted devices
  755. // So we have to really open .desktop files
  756. TQString iconStr = KMimeType::findByURL( url, mode )->icon( url, isLocal );
  757. if ( bDesktopFile && isLocal )
  758. {
  759. KDesktopFile config( url.path(), true );
  760. config.setDesktopGroup();
  761. iconStr = config.readEntry( "Icon" );
  762. if ( config.hasDeviceType() )
  763. iconButton->setIconType( KIcon::Desktop, KIcon::Device );
  764. else
  765. iconButton->setIconType( KIcon::Desktop, KIcon::Application );
  766. } else
  767. iconButton->setIconType( KIcon::Desktop, KIcon::FileSystem );
  768. iconButton->setIcon(iconStr);
  769. iconArea = iconButton;
  770. connect( iconButton, TQT_SIGNAL( iconChanged(TQString) ),
  771. this, TQT_SLOT( slotIconChanged() ) );
  772. } else {
  773. TQLabel *iconLabel = new TQLabel( d->m_frame );
  774. int bsize = 66 + 2 * iconLabel->style().pixelMetric(TQStyle::PM_ButtonMargin);
  775. iconLabel->setFixedSize(bsize, bsize);
  776. iconLabel->setPixmap( KGlobal::iconLoader()->loadIcon( iconStr, KIcon::Desktop, 48) );
  777. iconArea = iconLabel;
  778. }
  779. grid->addWidget(iconArea, curRow, 0, Qt::AlignLeft);
  780. if (d->bMultiple || isTrash || isDevice || hasRoot)
  781. {
  782. TQLabel *lab = new TQLabel(d->m_frame );
  783. if ( d->bMultiple )
  784. lab->setText( KIO::itemsSummaryString( iFileCount + iDirCount, iFileCount, iDirCount, 0, false ) );
  785. else
  786. lab->setText( filename );
  787. nameArea = lab;
  788. } else
  789. {
  790. d->m_lined = new KLineEdit( d->m_frame );
  791. d->m_lined->setText(filename);
  792. nameArea = d->m_lined;
  793. d->m_lined->setFocus();
  794. // Enhanced rename: Don't highlight the file extension.
  795. TQString pattern;
  796. KServiceTypeFactory::self()->findFromPattern( filename, &pattern );
  797. if (!pattern.isEmpty() && pattern.at(0)=='*' && pattern.find('*',1)==-1)
  798. d->m_lined->setSelection(0, filename.length()-pattern.stripWhiteSpace().length()+1);
  799. else
  800. {
  801. int lastDot = filename.findRev('.');
  802. if (lastDot > 0)
  803. d->m_lined->setSelection(0, lastDot);
  804. }
  805. connect( d->m_lined, TQT_SIGNAL( textChanged( const TQString & ) ),
  806. this, TQT_SLOT( nameFileChanged(const TQString & ) ) );
  807. }
  808. grid->addWidget(nameArea, curRow++, 2);
  809. KSeparator* sep = new KSeparator( KSeparator::HLine, d->m_frame);
  810. grid->addMultiCellWidget(sep, curRow, curRow, 0, 2);
  811. ++curRow;
  812. TQLabel *l;
  813. if ( !mimeComment.isEmpty() && !isDevice && !isTrash)
  814. {
  815. l = new TQLabel(i18n("Type:"), d->m_frame );
  816. grid->addWidget(l, curRow, 0);
  817. TQHBox *box = new TQHBox(d->m_frame);
  818. box->setSpacing(20);
  819. l = new TQLabel(mimeComment, box );
  820. #ifdef Q_WS_X11
  821. //TODO: wrap for win32 or mac?
  822. TQPushButton *button = new TQPushButton(box);
  823. TQIconSet iconSet = SmallIconSet(TQString::fromLatin1("configure"));
  824. TQPixmap pixMap = iconSet.pixmap( TQIconSet::Small, TQIconSet::Normal );
  825. button->setIconSet( iconSet );
  826. button->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
  827. if ( d->mimeType == KMimeType::defaultMimeType() )
  828. TQToolTip::add(button, i18n("Create new file type"));
  829. else
  830. TQToolTip::add(button, i18n("Edit file type"));
  831. connect( button, TQT_SIGNAL( clicked() ), TQT_SLOT( slotEditFileType() ));
  832. if (!kapp->authorizeKAction("editfiletype"))
  833. button->hide();
  834. #endif
  835. grid->addWidget(box, curRow++, 2);
  836. }
  837. if ( !magicMimeComment.isEmpty() && magicMimeComment != mimeComment )
  838. {
  839. l = new TQLabel(i18n("Contents:"), d->m_frame );
  840. grid->addWidget(l, curRow, 0);
  841. l = new TQLabel(magicMimeComment, d->m_frame );
  842. grid->addWidget(l, curRow++, 2);
  843. }
  844. if ( !directory.isEmpty() )
  845. {
  846. l = new TQLabel( i18n("Location:"), d->m_frame );
  847. grid->addWidget(l, curRow, 0);
  848. l = new KSqueezedTextLabel( d->m_frame );
  849. l->setText( directory );
  850. grid->addWidget(l, curRow++, 2);
  851. }
  852. if( hasDirs || hasTotalSize ) {
  853. l = new TQLabel(i18n("Size:"), d->m_frame );
  854. grid->addWidget(l, curRow, 0);
  855. m_sizeLabel = new TQLabel( d->m_frame );
  856. grid->addWidget( m_sizeLabel, curRow++, 2 );
  857. } else {
  858. m_sizeLabel = 0;
  859. }
  860. if ( !hasDirs ) // Only files [and symlinks]
  861. {
  862. if(hasTotalSize) {
  863. m_sizeLabel->setText(KIO::convertSizeWithBytes(totalSize));
  864. }
  865. m_sizeDetermineButton = 0L;
  866. m_sizeStopButton = 0L;
  867. }
  868. else // Directory
  869. {
  870. TQHBoxLayout * sizelay = new TQHBoxLayout(KDialog::spacingHint());
  871. grid->addLayout( sizelay, curRow++, 2 );
  872. // buttons
  873. m_sizeDetermineButton = new TQPushButton( i18n("Calculate"), d->m_frame );
  874. m_sizeStopButton = new TQPushButton( i18n("Stop"), d->m_frame );
  875. connect( m_sizeDetermineButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotSizeDetermine() ) );
  876. connect( m_sizeStopButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotSizeStop() ) );
  877. sizelay->addWidget(m_sizeDetermineButton, 0);
  878. sizelay->addWidget(m_sizeStopButton, 0);
  879. sizelay->addStretch(10); // so that the buttons don't grow horizontally
  880. // auto-launch for local dirs only, and not for '/'
  881. if ( isLocal && !hasRoot )
  882. {
  883. m_sizeDetermineButton->setText( i18n("Refresh") );
  884. slotSizeDetermine();
  885. }
  886. else
  887. m_sizeStopButton->setEnabled( false );
  888. }
  889. if (!d->bMultiple && item->isLink()) {
  890. l = new TQLabel(i18n("Points to:"), d->m_frame );
  891. grid->addWidget(l, curRow, 0);
  892. l = new KSqueezedTextLabel(item->linkDest(), d->m_frame );
  893. grid->addWidget(l, curRow++, 2);
  894. }
  895. if (!d->bMultiple) // Dates for multiple don't make much sense...
  896. {
  897. TQDateTime dt;
  898. bool hasTime;
  899. time_t tim = item->time(KIO::UDS_CREATION_TIME, hasTime);
  900. if ( hasTime )
  901. {
  902. l = new TQLabel(i18n("Created:"), d->m_frame );
  903. grid->addWidget(l, curRow, 0);
  904. dt.setTime_t( tim );
  905. l = new TQLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame );
  906. grid->addWidget(l, curRow++, 2);
  907. }
  908. tim = item->time(KIO::UDS_MODIFICATION_TIME, hasTime);
  909. if ( hasTime )
  910. {
  911. l = new TQLabel(i18n("Modified:"), d->m_frame );
  912. grid->addWidget(l, curRow, 0);
  913. dt.setTime_t( tim );
  914. l = new TQLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame );
  915. grid->addWidget(l, curRow++, 2);
  916. }
  917. tim = item->time(KIO::UDS_ACCESS_TIME, hasTime);
  918. if ( hasTime )
  919. {
  920. l = new TQLabel(i18n("Accessed:"), d->m_frame );
  921. grid->addWidget(l, curRow, 0);
  922. dt.setTime_t( tim );
  923. l = new TQLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame );
  924. grid->addWidget(l, curRow++, 2);
  925. }
  926. }
  927. if ( isLocal && hasDirs ) // only for directories
  928. {
  929. sep = new KSeparator( KSeparator::HLine, d->m_frame);
  930. grid->addMultiCellWidget(sep, curRow, curRow, 0, 2);
  931. ++curRow;
  932. TQString mountPoint = KIO::findPathMountPoint( url.path() );
  933. if (mountPoint != "/")
  934. {
  935. l = new TQLabel(i18n("Mounted on:"), d->m_frame );
  936. grid->addWidget(l, curRow, 0);
  937. l = new KSqueezedTextLabel( mountPoint, d->m_frame );
  938. grid->addWidget( l, curRow++, 2 );
  939. }
  940. l = new TQLabel(i18n("Free disk space:"), d->m_frame );
  941. grid->addWidget(l, curRow, 0);
  942. d->m_freeSpaceLabel = new TQLabel( d->m_frame );
  943. grid->addWidget( d->m_freeSpaceLabel, curRow++, 2 );
  944. KDiskFreeSp * job = new KDiskFreeSp;
  945. connect( job, TQT_SIGNAL( foundMountPoint( const unsigned long&, const unsigned long&,
  946. const unsigned long&, const TQString& ) ),
  947. this, TQT_SLOT( slotFoundMountPoint( const unsigned long&, const unsigned long&,
  948. const unsigned long&, const TQString& ) ) );
  949. job->readDF( mountPoint );
  950. }
  951. vbl->addStretch(1);
  952. }
  953. // TQString KFilePropsPlugin::tabName () const
  954. // {
  955. // return i18n ("&General");
  956. // }
  957. void KFilePropsPlugin::setFileNameReadOnly( bool ro )
  958. {
  959. if ( d->m_lined )
  960. {
  961. d->m_lined->setReadOnly( ro );
  962. if (ro)
  963. {
  964. // Don't put the initial focus on the line edit when it is ro
  965. TQPushButton *button = properties->actionButton(KDialogBase::Ok);
  966. if (button)
  967. button->setFocus();
  968. }
  969. }
  970. }
  971. void KFilePropsPlugin::slotEditFileType()
  972. {
  973. #ifdef Q_WS_X11
  974. TQString mime;
  975. if ( d->mimeType == KMimeType::defaultMimeType() ) {
  976. int pos = d->oldFileName.findRev( '.' );
  977. if ( pos != -1 )
  978. mime = "*" + d->oldFileName.mid(pos);
  979. else
  980. mime = "*";
  981. }
  982. else
  983. mime = d->mimeType;
  984. //TODO: wrap for win32 or mac?
  985. TQString keditfiletype = TQString::fromLatin1("keditfiletype");
  986. KRun::runCommand( keditfiletype
  987. + " --parent " + TQString::number( (ulong)properties->topLevelWidget()->winId())
  988. + " " + KProcess::quote(mime),
  989. keditfiletype, keditfiletype /*unused*/);
  990. #endif
  991. }
  992. void KFilePropsPlugin::slotIconChanged()
  993. {
  994. d->bIconChanged = true;
  995. emit changed();
  996. }
  997. void KFilePropsPlugin::nameFileChanged(const TQString &text )
  998. {
  999. properties->enableButtonOK(!text.isEmpty());
  1000. emit changed();
  1001. }
  1002. void KFilePropsPlugin::determineRelativePath( const TQString & path )
  1003. {
  1004. // now let's make it relative
  1005. TQStringList dirs;
  1006. if (KBindingPropsPlugin::supports(properties->items()))
  1007. {
  1008. m_sRelativePath =KGlobal::dirs()->relativeLocation("mime", path);
  1009. if (m_sRelativePath.startsWith("/"))
  1010. m_sRelativePath = TQString::null;
  1011. }
  1012. else
  1013. {
  1014. m_sRelativePath =KGlobal::dirs()->relativeLocation("apps", path);
  1015. if (m_sRelativePath.startsWith("/"))
  1016. {
  1017. m_sRelativePath =KGlobal::dirs()->relativeLocation("xdgdata-apps", path);
  1018. if (m_sRelativePath.startsWith("/"))
  1019. m_sRelativePath = TQString::null;
  1020. else
  1021. m_sRelativePath = path;
  1022. }
  1023. }
  1024. if ( m_sRelativePath.isEmpty() )
  1025. {
  1026. if (KBindingPropsPlugin::supports(properties->items()))
  1027. kdWarning(250) << "Warning : editing a mimetype file out of the mimetype dirs!" << endl;
  1028. }
  1029. }
  1030. void KFilePropsPlugin::slotFoundMountPoint( const TQString&,
  1031. unsigned long kBSize,
  1032. unsigned long /*kBUsed*/,
  1033. unsigned long kBAvail )
  1034. {
  1035. d->m_freeSpaceLabel->setText(
  1036. // xgettext:no-c-format -- Don't warn about translating the %1 out of %2 part.
  1037. i18n("Available space out of total partition size (percent used)", "%1 out of %2 (%3% used)")
  1038. .arg(KIO::convertSizeFromKB(kBAvail))
  1039. .arg(KIO::convertSizeFromKB(kBSize))
  1040. .arg( 100 - (int)(100.0 * kBAvail / kBSize) ));
  1041. }
  1042. // attention: copy&paste below, due to compiler bug
  1043. // it doesn't like those unsigned long parameters -- unsigned long& are ok :-/
  1044. void KFilePropsPlugin::slotFoundMountPoint( const unsigned long& kBSize,
  1045. const unsigned long& /*kBUsed*/,
  1046. const unsigned long& kBAvail,
  1047. const TQString& )
  1048. {
  1049. d->m_freeSpaceLabel->setText(
  1050. // xgettext:no-c-format -- Don't warn about translating the %1 out of %2 part.
  1051. i18n("Available space out of total partition size (percent used)", "%1 out of %2 (%3% used)")
  1052. .arg(KIO::convertSizeFromKB(kBAvail))
  1053. .arg(KIO::convertSizeFromKB(kBSize))
  1054. .arg( 100 - (int)(100.0 * kBAvail / kBSize) ));
  1055. }
  1056. void KFilePropsPlugin::slotDirSizeUpdate()
  1057. {
  1058. KIO::filesize_t totalSize = d->dirSizeJob->totalSize();
  1059. KIO::filesize_t totalFiles = d->dirSizeJob->totalFiles();
  1060. KIO::filesize_t totalSubdirs = d->dirSizeJob->totalSubdirs();
  1061. m_sizeLabel->setText( i18n("Calculating... %1 (%2)\n%3, %4")
  1062. .arg(KIO::convertSize(totalSize))
  1063. .arg(KGlobal::locale()->formatNumber(totalSize, 0))
  1064. .arg(i18n("1 file","%n files",totalFiles))
  1065. .arg(i18n("1 sub-folder","%n sub-folders",totalSubdirs)));
  1066. }
  1067. void KFilePropsPlugin::slotDirSizeFinished( KIO::Job * job )
  1068. {
  1069. if (job->error())
  1070. m_sizeLabel->setText( job->errorString() );
  1071. else
  1072. {
  1073. KIO::filesize_t totalSize = static_cast<KDirSize*>(job)->totalSize();
  1074. KIO::filesize_t totalFiles = static_cast<KDirSize*>(job)->totalFiles();
  1075. KIO::filesize_t totalSubdirs = static_cast<KDirSize*>(job)->totalSubdirs();
  1076. m_sizeLabel->setText( TQString::fromLatin1("%1 (%2)\n%3, %4")
  1077. .arg(KIO::convertSize(totalSize))
  1078. .arg(KGlobal::locale()->formatNumber(totalSize, 0))
  1079. .arg(i18n("1 file","%n files",totalFiles))
  1080. .arg(i18n("1 sub-folder","%n sub-folders",totalSubdirs)));
  1081. }
  1082. m_sizeStopButton->setEnabled(false);
  1083. // just in case you change something and try again :)
  1084. m_sizeDetermineButton->setText( i18n("Refresh") );
  1085. m_sizeDetermineButton->setEnabled(true);
  1086. d->dirSizeJob = 0L;
  1087. delete d->dirSizeUpdateTimer;
  1088. d->dirSizeUpdateTimer = 0L;
  1089. }
  1090. void KFilePropsPlugin::slotSizeDetermine()
  1091. {
  1092. m_sizeLabel->setText( i18n("Calculating...") );
  1093. kdDebug(250) << " KFilePropsPlugin::slotSizeDetermine() properties->item()=" << properties->item() << endl;
  1094. kdDebug(250) << " URL=" << properties->item()->url().url() << endl;
  1095. d->dirSizeJob = KDirSize::dirSizeJob( properties->items() );
  1096. d->dirSizeUpdateTimer = new TQTimer(this);
  1097. connect( d->dirSizeUpdateTimer, TQT_SIGNAL( timeout() ),
  1098. TQT_SLOT( slotDirSizeUpdate() ) );
  1099. d->dirSizeUpdateTimer->start(500);
  1100. connect( d->dirSizeJob, TQT_SIGNAL( result( KIO::Job * ) ),
  1101. TQT_SLOT( slotDirSizeFinished( KIO::Job * ) ) );
  1102. m_sizeStopButton->setEnabled(true);
  1103. m_sizeDetermineButton->setEnabled(false);
  1104. // also update the "Free disk space" display
  1105. if ( d->m_freeSpaceLabel )
  1106. {
  1107. bool isLocal;
  1108. KFileItem * item = properties->item();
  1109. KURL url = item->mostLocalURL( isLocal );
  1110. TQString mountPoint = KIO::findPathMountPoint( url.path() );
  1111. KDiskFreeSp * job = new KDiskFreeSp;
  1112. connect( job, TQT_SIGNAL( foundMountPoint( const unsigned long&, const unsigned long&,
  1113. const unsigned long&, const TQString& ) ),
  1114. this, TQT_SLOT( slotFoundMountPoint( const unsigned long&, const unsigned long&,
  1115. const unsigned long&, const TQString& ) ) );
  1116. job->readDF( mountPoint );
  1117. }
  1118. }
  1119. void KFilePropsPlugin::slotSizeStop()
  1120. {
  1121. if ( d->dirSizeJob )
  1122. {
  1123. m_sizeLabel->setText( i18n("Stopped") );
  1124. d->dirSizeJob->kill();
  1125. d->dirSizeJob = 0;
  1126. }
  1127. if ( d->dirSizeUpdateTimer )
  1128. d->dirSizeUpdateTimer->stop();
  1129. m_sizeStopButton->setEnabled(false);
  1130. m_sizeDetermineButton->setEnabled(true);
  1131. }
  1132. KFilePropsPlugin::~KFilePropsPlugin()
  1133. {
  1134. delete d;
  1135. }
  1136. bool KFilePropsPlugin::supports( KFileItemList /*_items*/ )
  1137. {
  1138. return true;
  1139. }
  1140. // Don't do this at home
  1141. void tqt_enter_modal( TQWidget *widget );
  1142. void tqt_leave_modal( TQWidget *widget );
  1143. void KFilePropsPlugin::applyChanges()
  1144. {
  1145. if ( d->dirSizeJob )
  1146. slotSizeStop();
  1147. kdDebug(250) << "KFilePropsPlugin::applyChanges" << endl;
  1148. if (nameArea->inherits(TQLINEEDIT_OBJECT_NAME_STRING))
  1149. {
  1150. TQString n = ((TQLineEdit *) nameArea)->text();
  1151. // Remove trailing spaces (#4345)
  1152. while ( n[n.length()-1].isSpace() )
  1153. n.truncate( n.length() - 1 );
  1154. if ( n.isEmpty() )
  1155. {
  1156. KMessageBox::sorry( properties, i18n("The new file name is empty."));
  1157. properties->abortApplying();
  1158. return;
  1159. }
  1160. // Do we need to rename the file ?
  1161. kdDebug(250) << "oldname = " << oldName << endl;
  1162. kdDebug(250) << "newname = " << n << endl;
  1163. if ( oldName != n || m_bFromTemplate ) { // true for any from-template file
  1164. KIO::Job * job = 0L;
  1165. KURL oldurl = properties->kurl();
  1166. TQString newFileName = KIO::encodeFileName(n);
  1167. if (d->bDesktopFile && !newFileName.endsWith(".desktop") && !newFileName.endsWith(".kdelnk"))
  1168. newFileName += ".desktop";
  1169. // Tell properties. Warning, this changes the result of properties->kurl() !
  1170. properties->rename( newFileName );
  1171. // Update also relative path (for apps and mimetypes)
  1172. if ( !m_sRelativePath.isEmpty() )
  1173. determineRelativePath( properties->kurl().path() );
  1174. kdDebug(250) << "New URL = " << properties->kurl().url() << endl;
  1175. kdDebug(250) << "old = " << oldurl.url() << endl;
  1176. // Don't remove the template !!
  1177. if ( !m_bFromTemplate ) // (normal renaming)
  1178. job = KIO::move( oldurl, properties->kurl() );
  1179. else // Copying a template
  1180. job = KIO::copy( oldurl, properties->kurl() );
  1181. connect( job, TQT_SIGNAL( result( KIO::Job * ) ),
  1182. TQT_SLOT( slotCopyFinished( KIO::Job * ) ) );
  1183. connect( job, TQT_SIGNAL( renamed( KIO::Job *, const KURL &, const KURL & ) ),
  1184. TQT_SLOT( slotFileRenamed( KIO::Job *, const KURL &, const KURL & ) ) );
  1185. // wait for job
  1186. TQWidget dummy(0,0,(WFlags)(WType_Dialog|WShowModal));
  1187. tqt_enter_modal(&dummy);
  1188. tqApp->enter_loop();
  1189. tqt_leave_modal(&dummy);
  1190. return;
  1191. }
  1192. properties->updateUrl(properties->kurl());
  1193. // Update also relative path (for apps and mimetypes)
  1194. if ( !m_sRelativePath.isEmpty() )
  1195. determineRelativePath( properties->kurl().path() );
  1196. }
  1197. // No job, keep going
  1198. slotCopyFinished( 0L );
  1199. }
  1200. void KFilePropsPlugin::slotCopyFinished( KIO::Job * job )
  1201. {
  1202. kdDebug(250) << "KFilePropsPlugin::slotCopyFinished" << endl;
  1203. if (job)
  1204. {
  1205. // allow apply() to return
  1206. tqApp->exit_loop();
  1207. if ( job->error() )
  1208. {
  1209. job->showErrorDialog( d->m_frame );
  1210. // Didn't work. Revert the URL to the old one
  1211. properties->updateUrl( static_cast<KIO::CopyJob*>(job)->srcURLs().first() );
  1212. properties->abortApplying(); // Don't apply the changes to the wrong file !
  1213. return;
  1214. }
  1215. }
  1216. assert( properties->item() );
  1217. assert( !properties->item()->url().isEmpty() );
  1218. // Save the file where we can -> usually in ~/.trinity/...
  1219. if (KBindingPropsPlugin::supports(properties->items()) && !m_sRelativePath.isEmpty())
  1220. {
  1221. KURL newURL;
  1222. newURL.setPath( locateLocal("mime", m_sRelativePath) );
  1223. properties->updateUrl( newURL );
  1224. }
  1225. else if (d->bDesktopFile && !m_sRelativePath.isEmpty())
  1226. {
  1227. kdDebug(250) << "KFilePropsPlugin::slotCopyFinished " << m_sRelativePath << endl;
  1228. KURL newURL;
  1229. newURL.setPath( KDesktopFile::locateLocal(m_sRelativePath) );
  1230. kdDebug(250) << "KFilePropsPlugin::slotCopyFinished path=" << newURL.path() << endl;
  1231. properties->updateUrl( newURL );
  1232. }
  1233. if ( d->bKDesktopMode && d->bDesktopFile ) {
  1234. // Renamed? Update Name field
  1235. if ( d->oldFileName != properties->kurl().fileName() || m_bFromTemplate ) {
  1236. KDesktopFile config( properties->kurl().path() );
  1237. TQString nameStr = nameFromFileName(properties->kurl().fileName());
  1238. config.writeEntry( "Name", nameStr );
  1239. config.writeEntry( "Name", nameStr, true, false, true );
  1240. }
  1241. }
  1242. }
  1243. void KFilePropsPlugin::applyIconChanges()
  1244. {
  1245. KIconButton *iconButton = ::tqqt_cast<KIconButton *>( iconArea );
  1246. if ( !iconButton || !d->bIconChanged )
  1247. return;
  1248. // handle icon changes - only local files (or pseudo-local) for now
  1249. // TODO: Use KTempFile and KIO::file_copy with overwrite = true
  1250. KURL url = properties->kurl();
  1251. url = KIO::NetAccess::mostLocalURL( url, properties );
  1252. if (url.isLocalFile()) {
  1253. TQString path;
  1254. if (S_ISDIR(properties->item()->mode()))
  1255. {
  1256. path = url.path(1) + TQString::fromLatin1(".directory");
  1257. // don't call updateUrl because the other tabs (i.e. permissions)
  1258. // apply to the directory, not the .directory file.
  1259. }
  1260. else
  1261. path = url.path();
  1262. // Get the default image
  1263. TQString str = KMimeType::findByURL( url,
  1264. properties->item()->mode(),
  1265. true )->KServiceType::icon();
  1266. // Is it another one than the default ?
  1267. TQString sIcon;
  1268. if ( str != iconButton->icon() )
  1269. sIcon = iconButton->icon();
  1270. // (otherwise write empty value)
  1271. kdDebug(250) << "**" << path << "**" << endl;
  1272. TQFile f( path );
  1273. // If default icon and no .directory file -> don't create one
  1274. if ( !sIcon.isEmpty() || f.exists() )
  1275. {
  1276. if ( !f.open( IO_ReadWrite ) ) {
  1277. KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not "
  1278. "have sufficient access to write to <b>%1</b>.</qt>").arg(path));
  1279. return;
  1280. }
  1281. f.close();
  1282. KDesktopFile cfg(path);
  1283. kdDebug(250) << "sIcon = " << (sIcon) << endl;
  1284. kdDebug(250) << "str = " << (str) << endl;
  1285. cfg.writeEntry( "Icon", sIcon );
  1286. cfg.sync();
  1287. }
  1288. }
  1289. }
  1290. void KFilePropsPlugin::slotFileRenamed( KIO::Job *, const KURL &, const KURL & newUrl )
  1291. {
  1292. // This is called in case of an existing local file during the copy/move operation,
  1293. // if the user chooses Rename.
  1294. properties->updateUrl( newUrl );
  1295. }
  1296. void KFilePropsPlugin::postApplyChanges()
  1297. {
  1298. // Save the icon only after applying the permissions changes (#46192)
  1299. applyIconChanges();
  1300. KURL::List lst;
  1301. KFileItemList items = properties->items();
  1302. for ( KFileItemListIterator it( items ); it.current(); ++it )
  1303. lst.append((*it)->url());
  1304. KDirNotify_stub allDirNotify("*", "KDirNotify*");
  1305. allDirNotify.FilesChanged( lst );
  1306. }
  1307. class KFilePermissionsPropsPlugin::KFilePermissionsPropsPluginPrivate
  1308. {
  1309. public:
  1310. KFilePermissionsPropsPluginPrivate()
  1311. {
  1312. }
  1313. ~KFilePermissionsPropsPluginPrivate()
  1314. {
  1315. }
  1316. TQFrame *m_frame;
  1317. TQCheckBox *cbRecursive;
  1318. TQLabel *explanationLabel;
  1319. TQComboBox *ownerPermCombo, *groupPermCombo, *othersPermCombo;
  1320. TQCheckBox *extraCheckbox;
  1321. mode_t partialPermissions;
  1322. KFilePermissionsPropsPlugin::PermissionsMode pmode;
  1323. bool canChangePermissions;
  1324. bool isIrregular;
  1325. bool hasExtendedACL;
  1326. KACL extendedACL;
  1327. KACL defaultACL;
  1328. bool fileSystemSupportsACLs;
  1329. };
  1330. #define UniOwner (S_IRUSR|S_IWUSR|S_IXUSR)
  1331. #define UniGroup (S_IRGRP|S_IWGRP|S_IXGRP)
  1332. #define UniOthers (S_IROTH|S_IWOTH|S_IXOTH)
  1333. #define UniRead (S_IRUSR|S_IRGRP|S_IROTH)
  1334. #define UniWrite (S_IWUSR|S_IWGRP|S_IWOTH)
  1335. #define UniExec (S_IXUSR|S_IXGRP|S_IXOTH)
  1336. #define UniSpecial (S_ISUID|S_ISGID|S_ISVTX)
  1337. // synced with PermissionsTarget
  1338. const mode_t KFilePermissionsPropsPlugin::permissionsMasks[3] = {UniOwner, UniGroup, UniOthers};
  1339. const mode_t KFilePermissionsPropsPlugin::standardPermissions[4] = { 0, UniRead, UniRead|UniWrite, (mode_t)-1 };
  1340. // synced with PermissionsMode and standardPermissions
  1341. const char *KFilePermissionsPropsPlugin::permissionsTexts[4][4] = {
  1342. { I18N_NOOP("Forbidden"),
  1343. I18N_NOOP("Can Read"),
  1344. I18N_NOOP("Can Read & Write"),
  1345. 0 },
  1346. { I18N_NOOP("Forbidden"),
  1347. I18N_NOOP("Can View Content"),
  1348. I18N_NOOP("Can View & Modify Content"),
  1349. 0 },
  1350. { 0, 0, 0, 0}, // no texts for links
  1351. { I18N_NOOP("Forbidden"),
  1352. I18N_NOOP("Can View Content & Read"),
  1353. I18N_NOOP("Can View/Read & Modify/Write"),
  1354. 0 }
  1355. };
  1356. KFilePermissionsPropsPlugin::KFilePermissionsPropsPlugin( KPropertiesDialog *_props )
  1357. : KPropsDlgPlugin( _props )
  1358. {
  1359. d = new KFilePermissionsPropsPluginPrivate;
  1360. d->cbRecursive = 0L;
  1361. grpCombo = 0L; grpEdit = 0;
  1362. usrEdit = 0L;
  1363. TQString path = properties->kurl().path(-1);
  1364. TQString fname = properties->kurl().fileName();
  1365. bool isLocal = properties->kurl().isLocalFile();
  1366. bool isTrash = ( properties->kurl().protocol().find("trash", 0, false)==0 );
  1367. bool IamRoot = (geteuid() == 0);
  1368. KFileItem * item = properties->item();
  1369. bool isLink = item->isLink();
  1370. bool isDir = item->isDir(); // all dirs
  1371. bool hasDir = item->isDir(); // at least one dir
  1372. permissions = item->permissions(); // common permissions to all files
  1373. d->partialPermissions = permissions; // permissions that only some files have (at first we take everything)
  1374. d->isIrregular = isIrregular(permissions, isDir, isLink);
  1375. strOwner = item->user();
  1376. strGroup = item->group();
  1377. d->hasExtendedACL = item->ACL().isExtended() || item->defaultACL().isValid();
  1378. d->extendedACL = item->ACL();
  1379. d->defaultACL = item->defaultACL();
  1380. d->fileSystemSupportsACLs = false;
  1381. if ( properties->items().count() > 1 )
  1382. {
  1383. // Multiple items: see what they have in common
  1384. KFileItemList items = properties->items();
  1385. KFileItemListIterator it( items );
  1386. for ( ++it /*no need to check the first one again*/ ; it.current(); ++it )
  1387. {
  1388. if (!d->isIrregular)
  1389. d->isIrregular |= isIrregular((*it)->permissions(),
  1390. (*it)->isDir() == isDir,
  1391. (*it)->isLink() == isLink);
  1392. d->hasExtendedACL = d->hasExtendedACL || (*it)->hasExtendedACL();
  1393. if ( (*it)->isLink() != isLink )
  1394. isLink = false;
  1395. if ( (*it)->isDir() != isDir )
  1396. isDir = false;
  1397. hasDir |= (*it)->isDir();
  1398. if ( (*it)->permissions() != permissions )
  1399. {
  1400. permissions &= (*it)->permissions();
  1401. d->partialPermissions |= (*it)->permissions();
  1402. }
  1403. if ( (*it)->user() != strOwner )
  1404. strOwner = TQString::null;
  1405. if ( (*it)->group() != strGroup )
  1406. strGroup = TQString::null;
  1407. }
  1408. }
  1409. if (isLink)
  1410. d->pmode = PermissionsOnlyLinks;
  1411. else if (isDir)
  1412. d->pmode = PermissionsOnlyDirs;
  1413. else if (hasDir)
  1414. d->pmode = PermissionsMixed;
  1415. else
  1416. d->pmode = PermissionsOnlyFiles;
  1417. // keep only what's not in the common permissions
  1418. d->partialPermissions = d->partialPermissions & ~permissions;
  1419. bool isMyFile = false;
  1420. if (isLocal && !strOwner.isEmpty()) { // local files, and all owned by the same person
  1421. struct passwd *myself = getpwuid( geteuid() );
  1422. if ( myself != 0L )
  1423. {
  1424. isMyFile = (strOwner == TQString::fromLocal8Bit(myself->pw_name));
  1425. } else
  1426. kdWarning() << "I don't exist ?! geteuid=" << geteuid() << endl;
  1427. } else {
  1428. //We don't know, for remote files, if they are ours or not.
  1429. //So we let the user change permissions, and
  1430. //KIO::chmod will tell, if he had no right to do it.
  1431. isMyFile = true;
  1432. }
  1433. d->canChangePermissions = (isMyFile || IamRoot) && (!isLink);
  1434. // create GUI
  1435. d->m_frame = properties->addPage(i18n("&Permissions"));
  1436. TQBoxLayout *box = new TQVBoxLayout( d->m_frame, 0, KDialog::spacingHint() );
  1437. TQWidget *l;
  1438. TQLabel *lbl;
  1439. TQGroupBox *gb;
  1440. TQGridLayout *gl;
  1441. TQPushButton* pbAdvancedPerm = 0;
  1442. /* Group: Access Permissions */
  1443. gb = new TQGroupBox ( 0, Qt::Vertical, i18n("Access Permissions"), d->m_frame );
  1444. gb->layout()->setSpacing(KDialog::spacingHint());
  1445. gb->layout()->setMargin(KDialog::marginHint());
  1446. box->addWidget (gb);
  1447. gl = new TQGridLayout (gb->layout(), 7, 2);
  1448. gl->setColStretch(1, 1);
  1449. l = d->explanationLabel = new TQLabel( "", gb );
  1450. if (isLink)
  1451. d->explanationLabel->setText(i18n("This file is a link and does not have permissions.",
  1452. "All files are links and do not have permissions.",
  1453. properties->items().count()));
  1454. else if (!d->canChangePermissions)
  1455. d->explanationLabel->setText(i18n("Only the owner can change permissions."));
  1456. gl->addMultiCellWidget(l, 0, 0, 0, 1);
  1457. lbl = new TQLabel( i18n("O&wner:"), gb);
  1458. gl->addWidget(lbl, 1, 0);
  1459. l = d->ownerPermCombo = new TQComboBox(gb);
  1460. lbl->setBuddy(l);
  1461. gl->addWidget(l, 1, 1);
  1462. connect(l, TQT_SIGNAL( highlighted(int) ), this, TQT_SIGNAL( changed() ));
  1463. TQWhatsThis::add(l, i18n("Specifies the actions that the owner is allowed to do."));
  1464. lbl = new TQLabel( i18n("Gro&up:"), gb);
  1465. gl->addWidget(lbl, 2, 0);
  1466. l = d->groupPermCombo = new TQComboBox(gb);
  1467. lbl->setBuddy(l);
  1468. gl->addWidget(l, 2, 1);
  1469. connect(l, TQT_SIGNAL( highlighted(int) ), this, TQT_SIGNAL( changed() ));
  1470. TQWhatsThis::add(l, i18n("Specifies the actions that the members of the group are allowed to do."));
  1471. lbl = new TQLabel( i18n("O&thers:"), gb);
  1472. gl->addWidget(lbl, 3, 0);
  1473. l = d->othersPermCombo = new TQComboBox(gb);
  1474. lbl->setBuddy(l);
  1475. gl->addWidget(l, 3, 1);
  1476. connect(l, TQT_SIGNAL( highlighted(int) ), this, TQT_SIGNAL( changed() ));
  1477. TQWhatsThis::add(l, i18n("Specifies the actions that all users, who are neither "
  1478. "owner nor in the group, are allowed to do."));
  1479. if (!isLink) {
  1480. l = d->extraCheckbox = new TQCheckBox(hasDir ?
  1481. i18n("Only own&er can rename and delete folder content") :
  1482. i18n("Is &executable"),
  1483. gb );
  1484. connect( d->extraCheckbox, TQT_SIGNAL( clicked() ), this, TQT_SIGNAL( changed() ) );
  1485. gl->addWidget(l, 4, 1);
  1486. TQWhatsThis::add(l, hasDir ? i18n("Enable this option to allow only the folder's owner to "
  1487. "delete or rename the contained files and folders. Other "
  1488. "users can only add new files, which requires the 'Modify "
  1489. "Content' permission.")
  1490. : i18n("Enable this option to mark the file as executable. This only makes "
  1491. "sense for programs and scripts. It is required when you want to "
  1492. "execute them."));
  1493. TQLayoutItem *spacer = TQT_TQLAYOUTITEM(new TQSpacerItem(0, 20, TQSizePolicy::Minimum, TQSizePolicy::Expanding));
  1494. gl->addMultiCell(spacer, 5, 5, 0, 1);
  1495. pbAdvancedPerm = new TQPushButton(i18n("A&dvanced Permissions"), gb);
  1496. gl->addMultiCellWidget(pbAdvancedPerm, 6, 6, 0, 1, Qt::AlignRight);
  1497. connect(pbAdvancedPerm, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotShowAdvancedPermissions() ));
  1498. }
  1499. else
  1500. d->extraCheckbox = 0;
  1501. /**** Group: Ownership ****/
  1502. gb = new TQGroupBox ( 0, Qt::Vertical, i18n("Ownership"), d->m_frame );
  1503. gb->layout()->setSpacing(KDialog::spacingHint());
  1504. gb->layout()->setMargin(KDialog::marginHint());
  1505. box->addWidget (gb);
  1506. gl = new TQGridLayout (gb->layout(), 4, 3);
  1507. gl->addRowSpacing(0, 10);
  1508. /*** Set Owner ***/
  1509. l = new TQLabel( i18n("User:"), gb );
  1510. gl->addWidget (l, 1, 0);
  1511. /* GJ: Don't autocomplete more than 1000 users. This is a kind of random
  1512. * value. Huge sites having 10.000+ user have a fair chance of using NIS,
  1513. * (possibly) making this unacceptably slow.
  1514. * OTOH, it is nice to offer this functionality for the standard user.
  1515. */
  1516. int i, maxEntries = 1000;
  1517. struct passwd *user;
  1518. struct group *ge;
  1519. /* File owner: For root, offer a KLineEdit with autocompletion.
  1520. * For a user, who can never chown() a file, offer a TQLabel.
  1521. */
  1522. if (IamRoot && isLocal)
  1523. {
  1524. usrEdit = new KLineEdit( gb );
  1525. KCompletion *kcom = usrEdit->completionObject();
  1526. kcom->setOrder(KCompletion::Sorted);
  1527. setpwent();
  1528. for (i=0; ((user = getpwent()) != 0L) && (i < maxEntries); i++)
  1529. kcom->addItem(TQString::fromLatin1(user->pw_name));
  1530. endpwent();
  1531. usrEdit->setCompletionMode((i < maxEntries) ? KGlobalSettings::CompletionAuto :
  1532. KGlobalSettings::CompletionNone);
  1533. usrEdit->setText(strOwner);
  1534. gl->addWidget(usrEdit, 1, 1);
  1535. connect( usrEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
  1536. this, TQT_SIGNAL( changed() ) );
  1537. }
  1538. else
  1539. {
  1540. l = new TQLabel(strOwner, gb);
  1541. gl->addWidget(l, 1, 1);
  1542. }
  1543. /*** Set Group ***/
  1544. TQStringList groupList;
  1545. TQCString strUser;
  1546. user = getpwuid(geteuid());
  1547. if (user != 0L)
  1548. strUser = user->pw_name;
  1549. #ifdef Q_OS_UNIX
  1550. setgrent();
  1551. for (i=0; ((ge = getgrent()) != 0L) && (i < maxEntries); i++)
  1552. {
  1553. if (IamRoot)
  1554. groupList += TQString::fromLatin1(ge->gr_name);
  1555. else
  1556. {
  1557. /* pick the groups to which the user belongs */
  1558. char ** members = ge->gr_mem;
  1559. char * member;
  1560. while ((member = *members) != 0L) {
  1561. if (strUser == member) {
  1562. groupList += TQString::fromLocal8Bit(ge->gr_name);
  1563. break;
  1564. }
  1565. ++members;
  1566. }
  1567. }
  1568. }
  1569. endgrent();
  1570. #endif //Q_OS_UNIX
  1571. /* add the effective Group to the list .. */
  1572. ge = getgrgid (getegid());
  1573. if (ge) {
  1574. TQString name = TQString::fromLatin1(ge->gr_name);
  1575. if (name.isEmpty())
  1576. name.setNum(ge->gr_gid);
  1577. if (groupList.find(name) == groupList.end())
  1578. groupList += name;
  1579. }
  1580. bool isMyGroup = groupList.contains(strGroup);
  1581. /* add the group the file currently belongs to ..
  1582. * .. if its not there already
  1583. */
  1584. if (!isMyGroup)
  1585. groupList += strGroup;
  1586. l = new TQLabel( i18n("Group:"), gb );
  1587. gl->addWidget (l, 2, 0);
  1588. /* Set group: if possible to change:
  1589. * - Offer a KLineEdit for root, since he can change to any group.
  1590. * - Offer a TQComboBox for a normal user, since he can change to a fixed
  1591. * (small) set of groups only.
  1592. * If not changeable: offer a TQLabel.
  1593. */
  1594. if (IamRoot && isLocal)
  1595. {
  1596. grpEdit = new KLineEdit(gb);
  1597. KCompletion *kcom = new KCompletion;
  1598. kcom->setItems(groupList);
  1599. grpEdit->setCompletionObject(kcom, true);
  1600. grpEdit->setAutoDeleteCompletionObject( true );
  1601. grpEdit->setCompletionMode(KGlobalSettings::CompletionAuto);
  1602. grpEdit->setText(strGroup);
  1603. gl->addWidget(grpEdit, 2, 1);
  1604. connect( grpEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
  1605. this, TQT_SIGNAL( changed() ) );
  1606. }
  1607. else if ((groupList.count() > 1) && isMyFile && isLocal)
  1608. {
  1609. grpCombo = new TQComboBox(gb, "combogrouplist");
  1610. grpCombo->insertStringList(groupList);
  1611. grpCombo->setCurrentItem(groupList.findIndex(strGroup));
  1612. gl->addWidget(grpCombo, 2, 1);
  1613. connect( grpCombo, TQT_SIGNAL( activated( int ) ),
  1614. this, TQT_SIGNAL( changed() ) );
  1615. }
  1616. else
  1617. {
  1618. l = new TQLabel(strGroup, gb);
  1619. gl->addWidget(l, 2, 1);
  1620. }
  1621. gl->setColStretch(2, 10);
  1622. // "Apply recursive" checkbox
  1623. if ( hasDir && !isLink && !isTrash )
  1624. {
  1625. d->cbRecursive = new TQCheckBox( i18n("Apply changes to all subfolders and their contents"), d->m_frame );
  1626. connect( d->cbRecursive, TQT_SIGNAL( clicked() ), this, TQT_SIGNAL( changed() ) );
  1627. box->addWidget( d->cbRecursive );
  1628. }
  1629. updateAccessControls();
  1630. if ( isTrash || !d->canChangePermissions )
  1631. {
  1632. //don't allow to change properties for file into trash
  1633. enableAccessControls(false);
  1634. if ( pbAdvancedPerm && !d->hasExtendedACL )
  1635. pbAdvancedPerm->setEnabled(false);
  1636. }
  1637. box->addStretch (10);
  1638. }
  1639. #ifdef USE_POSIX_ACL
  1640. static bool fileSystemSupportsACL( const TQCString& pathCString )
  1641. {
  1642. bool fileSystemSupportsACLs = false;
  1643. #ifdef Q_OS_FREEBSD
  1644. struct statfs buf;
  1645. fileSystemSupportsACLs = ( statfs( pathCString.data(), &buf ) == 0 ) && ( buf.f_flags & MNT_ACLS );
  1646. #else
  1647. fileSystemSupportsACLs =
  1648. getxattr( pathCString.data(), "system.posix_acl_access", NULL, 0 ) >= 0
  1649. #ifdef ENODATA
  1650. || (errno == ENODATA)
  1651. #endif
  1652. #ifdef ENOATTR
  1653. || (errno == ENOATTR)
  1654. #endif
  1655. ;
  1656. #endif
  1657. return fileSystemSupportsACLs;
  1658. }
  1659. #endif
  1660. void KFilePermissionsPropsPlugin::slotShowAdvancedPermissions() {
  1661. bool isDir = (d->pmode == PermissionsOnlyDirs) || (d->pmode == PermissionsMixed);
  1662. KDialogBase dlg(properties, 0, true, i18n("Advanced Permissions"),
  1663. KDialogBase::Ok|KDialogBase::Cancel);
  1664. TQLabel *l, *cl[3];
  1665. TQGroupBox *gb;
  1666. TQGridLayout *gl;
  1667. TQVBox *mainVBox = dlg.makeVBoxMainWidget();
  1668. // Group: Access Permissions
  1669. gb = new TQGroupBox ( 0, Qt::Vertical, i18n("Access Permissions"), mainVBox );
  1670. gb->layout()->setSpacing(KDialog::spacingHint());
  1671. gb->layout()->setMargin(KDialog::marginHint());
  1672. gl = new TQGridLayout (gb->layout(), 6, 6);
  1673. gl->addRowSpacing(0, 10);
  1674. TQValueVector<TQWidget*> theNotSpecials;
  1675. l = new TQLabel(i18n("Class"), gb );
  1676. gl->addWidget(l, 1, 0);
  1677. theNotSpecials.append( l );
  1678. if (isDir)
  1679. l = new TQLabel( i18n("Show\nEntries"), gb );
  1680. else
  1681. l = new TQLabel( i18n("Read"), gb );
  1682. gl->addWidget (l, 1, 1);
  1683. theNotSpecials.append( l );
  1684. TQString readWhatsThis;
  1685. if (isDir)
  1686. readWhatsThis = i18n("This flag allows viewing the content of the folder.");
  1687. else
  1688. readWhatsThis = i18n("The Read flag allows viewing the content of the file.");
  1689. TQWhatsThis::add(l, readWhatsThis);
  1690. if (isDir)
  1691. l = new TQLabel( i18n("Write\nEntries"), gb );
  1692. else
  1693. l = new TQLabel( i18n("Write"), gb );
  1694. gl->addWidget (l, 1, 2);
  1695. theNotSpecials.append( l );
  1696. TQString writeWhatsThis;
  1697. if (isDir)
  1698. writeWhatsThis = i18n("This flag allows adding, renaming and deleting of files. "
  1699. "Note that deleting and renaming can be limited using the Sticky flag.");
  1700. else
  1701. writeWhatsThis = i18n("The Write flag allows modifying the content of the file.");
  1702. TQWhatsThis::add(l, writeWhatsThis);
  1703. TQString execWhatsThis;
  1704. if (isDir) {
  1705. l = new TQLabel( i18n("Enter folder", "Enter"), gb );
  1706. execWhatsThis = i18n("Enable this flag to allow entering the folder.");
  1707. }
  1708. else {
  1709. l = new TQLabel( i18n("Exec"), gb );
  1710. execWhatsThis = i18n("Enable this flag to allow executing the file as a program.");
  1711. }
  1712. TQWhatsThis::add(l, execWhatsThis);
  1713. theNotSpecials.append( l );
  1714. // GJ: Add space between normal and special modes
  1715. TQSize size = l->sizeHint();
  1716. size.setWidth(size.width() + 15);
  1717. l->setFixedSize(size);
  1718. gl->addWidget (l, 1, 3);
  1719. l = new TQLabel( i18n("Special"), gb );
  1720. gl->addMultiCellWidget(l, 1, 1, 4, 5);
  1721. TQString specialWhatsThis;
  1722. if (isDir)
  1723. specialWhatsThis = i18n("Special flag. Valid for the whole folder, the exact "
  1724. "meaning of the flag can be seen in the right hand column.");
  1725. else
  1726. specialWhatsThis = i18n("Special flag. The exact meaning of the flag can be seen "
  1727. "in the right hand column.");
  1728. TQWhatsThis::add(l, specialWhatsThis);
  1729. cl[0] = new TQLabel( i18n("User"), gb );
  1730. gl->addWidget (cl[0], 2, 0);
  1731. theNotSpecials.append( cl[0] );
  1732. cl[1] = new TQLabel( i18n("Group"), gb );
  1733. gl->addWidget (cl[1], 3, 0);
  1734. theNotSpecials.append( cl[1] );
  1735. cl[2] = new TQLabel( i18n("Others"), gb );
  1736. gl->addWidget (cl[2], 4, 0);
  1737. theNotSpecials.append( cl[2] );
  1738. l = new TQLabel(i18n("Set UID"), gb);
  1739. gl->addWidget(l, 2, 5);
  1740. TQString setUidWhatsThis;
  1741. if (isDir)
  1742. setUidWhatsThis = i18n("If this flag is set, the owner of this folder will be "
  1743. "the owner of all new files.");
  1744. else
  1745. setUidWhatsThis = i18n("If this file is an executable and the flag is set, it will "
  1746. "be executed with the permissions of the owner.");
  1747. TQWhatsThis::add(l, setUidWhatsThis);
  1748. l = new TQLabel(i18n("Set GID"), gb);
  1749. gl->addWidget(l, 3, 5);
  1750. TQString setGidWhatsThis;
  1751. if (isDir)
  1752. setGidWhatsThis = i18n("If this flag is set, the group of this folder will be "
  1753. "set for all new files.");
  1754. else
  1755. setGidWhatsThis = i18n("If this file is an executable and the flag is set, it will "
  1756. "be executed with the permissions of the group.");
  1757. TQWhatsThis::add(l, setGidWhatsThis);
  1758. l = new TQLabel(i18n("File permission", "Sticky"), gb);
  1759. gl->addWidget(l, 4, 5);
  1760. TQString stickyWhatsThis;
  1761. if (isDir)
  1762. stickyWhatsThis = i18n("If the Sticky flag is set on a folder, only the owner "
  1763. "and root can delete or rename files. Otherwise everybody "
  1764. "with write permissions can do this.");
  1765. else
  1766. stickyWhatsThis = i18n("The Sticky flag on a file is ignored on Linux, but may "
  1767. "be used on some systems");
  1768. TQWhatsThis::add(l, stickyWhatsThis);
  1769. mode_t aPermissions, aPartialPermissions;
  1770. mode_t dummy1, dummy2;
  1771. if (!d->isIrregular) {
  1772. switch (d->pmode) {
  1773. case PermissionsOnlyFiles:
  1774. getPermissionMasks(aPartialPermissions,
  1775. dummy1,
  1776. aPermissions,
  1777. dummy2);
  1778. break;
  1779. case PermissionsOnlyDirs:
  1780. case PermissionsMixed:
  1781. getPermissionMasks(dummy1,
  1782. aPartialPermissions,
  1783. dummy2,
  1784. aPermissions);
  1785. break;
  1786. case PermissionsOnlyLinks:
  1787. aPermissions = UniRead | UniWrite | UniExec | UniSpecial;
  1788. aPartialPermissions = 0;
  1789. break;
  1790. }
  1791. }
  1792. else {
  1793. aPermissions = permissions;
  1794. aPartialPermissions = d->partialPermissions;
  1795. }
  1796. // Draw Checkboxes
  1797. TQCheckBox *cba[3][4];
  1798. for (int row = 0; row < 3 ; ++row) {
  1799. for (int col = 0; col < 4; ++col) {
  1800. TQCheckBox *cb = new TQCheckBox( gb );
  1801. if ( col != 3 ) theNotSpecials.append( cb );
  1802. cba[row][col] = cb;
  1803. cb->setChecked(aPermissions & fperm[row][col]);
  1804. if ( aPartialPermissions & fperm[row][col] )
  1805. {
  1806. cb->setTristate();
  1807. cb->setNoChange();
  1808. }
  1809. else if (d->cbRecursive && d->cbRecursive->isChecked())
  1810. cb->setTristate();
  1811. cb->setEnabled( d->canChangePermissions );
  1812. gl->addWidget (cb, row+2, col+1);
  1813. switch(col) {
  1814. case 0:
  1815. TQWhatsThis::add(cb, readWhatsThis);
  1816. break;
  1817. case 1:
  1818. TQWhatsThis::add(cb, writeWhatsThis);
  1819. break;
  1820. case 2:
  1821. TQWhatsThis::add(cb, execWhatsThis);
  1822. break;
  1823. case 3:
  1824. switch(row) {
  1825. case 0:
  1826. TQWhatsThis::add(cb, setUidWhatsThis);
  1827. break;
  1828. case 1:
  1829. TQWhatsThis::add(cb, setGidWhatsThis);
  1830. break;
  1831. case 2:
  1832. TQWhatsThis::add(cb, stickyWhatsThis);
  1833. break;
  1834. }
  1835. break;
  1836. }
  1837. }
  1838. }
  1839. gl->setColStretch(6, 10);
  1840. #ifdef USE_POSIX_ACL
  1841. KACLEditWidget *extendedACLs = 0;
  1842. // FIXME make it work with partial entries
  1843. if ( properties->items().count() == 1 ) {
  1844. TQCString pathCString = TQFile::encodeName( properties->item()->url().path() );
  1845. d->fileSystemSupportsACLs = fileSystemSupportsACL( pathCString );
  1846. }
  1847. if ( d->fileSystemSupportsACLs ) {
  1848. std::for_each( theNotSpecials.begin(), theNotSpecials.end(), std::mem_fun( &TQWidget::hide ) );
  1849. extendedACLs = new KACLEditWidget( mainVBox );
  1850. if ( d->extendedACL.isValid() && d->extendedACL.isExtended() )
  1851. extendedACLs->setACL( d->extendedACL );
  1852. else
  1853. extendedACLs->setACL( KACL( aPermissions ) );
  1854. if ( d->defaultACL.isValid() )
  1855. extendedACLs->setDefaultACL( d->defaultACL );
  1856. if ( properties->items().first()->isDir() )
  1857. extendedACLs->setAllowDefaults( true );
  1858. if ( !d->canChangePermissions )
  1859. extendedACLs->setReadOnly( true );
  1860. }
  1861. #endif
  1862. if (dlg.exec() != KDialogBase::Accepted)
  1863. return;
  1864. mode_t andPermissions = mode_t(~0);
  1865. mode_t orPermissions = 0;
  1866. for (int row = 0; row < 3; ++row)
  1867. for (int col = 0; col < 4; ++col) {
  1868. switch (cba[row][col]->state())
  1869. {
  1870. case TQCheckBox::On:
  1871. orPermissions |= fperm[row][col];
  1872. //fall through
  1873. case TQCheckBox::Off:
  1874. andPermissions &= ~fperm[row][col];
  1875. break;
  1876. default: // NoChange
  1877. break;
  1878. }
  1879. }
  1880. d->isIrregular = false;
  1881. KFileItemList items = properties->items();
  1882. for (KFileItemListIterator it(items); it.current(); ++it) {
  1883. if (isIrregular(((*it)->permissions() & andPermissions) | orPermissions,
  1884. (*it)->isDir(), (*it)->isLink())) {
  1885. d->isIrregular = true;
  1886. break;
  1887. }
  1888. }
  1889. permissions = orPermissions;
  1890. d->partialPermissions = andPermissions;
  1891. #ifdef USE_POSIX_ACL
  1892. // override with the acls, if present
  1893. if ( extendedACLs ) {
  1894. d->extendedACL = extendedACLs->getACL();
  1895. d->defaultACL = extendedACLs->getDefaultACL();
  1896. d->hasExtendedACL = d->extendedACL.isExtended() || d->defaultACL.isValid();
  1897. permissions = d->extendedACL.basePermissions();
  1898. permissions |= ( andPermissions | orPermissions ) & ( S_ISUID|S_ISGID|S_ISVTX );
  1899. }
  1900. #endif
  1901. updateAccessControls();
  1902. emit changed();
  1903. }
  1904. // TQString KFilePermissionsPropsPlugin::tabName () const
  1905. // {
  1906. // return i18n ("&Permissions");
  1907. // }
  1908. KFilePermissionsPropsPlugin::~KFilePermissionsPropsPlugin()
  1909. {
  1910. delete d;
  1911. }
  1912. bool KFilePermissionsPropsPlugin::supports( KFileItemList _items )
  1913. {
  1914. KFileItemList::const_iterator it = _items.constBegin();
  1915. for ( ; it != _items.constEnd(); ++it ) {
  1916. KFileItem *item = *it;
  1917. if( !item->user().isEmpty() || !item->group().isEmpty() )
  1918. return true;
  1919. }
  1920. return false;
  1921. }
  1922. // sets a combo box in the Access Control frame
  1923. void KFilePermissionsPropsPlugin::setComboContent(TQComboBox *combo, PermissionsTarget target,
  1924. mode_t permissions, mode_t partial) {
  1925. combo->clear();
  1926. if (d->pmode == PermissionsOnlyLinks) {
  1927. combo->insertItem(i18n("Link"));
  1928. combo->setCurrentItem(0);
  1929. return;
  1930. }
  1931. mode_t tMask = permissionsMasks[target];
  1932. int textIndex;
  1933. for (textIndex = 0; standardPermissions[textIndex] != (mode_t)-1; textIndex++)
  1934. if ((standardPermissions[textIndex]&tMask) == (permissions&tMask&(UniRead|UniWrite)))
  1935. break;
  1936. Q_ASSERT(standardPermissions[textIndex] != (mode_t)-1); // must not happen, would be irreglar
  1937. for (int i = 0; permissionsTexts[(int)d->pmode][i]; i++)
  1938. combo->insertItem(i18n(permissionsTexts[(int)d->pmode][i]));
  1939. if (partial & tMask & ~UniExec) {
  1940. combo->insertItem(i18n("Varying (No Change)"));
  1941. combo->setCurrentItem(3);
  1942. }
  1943. else
  1944. combo->setCurrentItem(textIndex);
  1945. }
  1946. // permissions are irregular if they cant be displayed in a combo box.
  1947. bool KFilePermissionsPropsPlugin::isIrregular(mode_t permissions, bool isDir, bool isLink) {
  1948. if (isLink) // links are always ok
  1949. return false;
  1950. mode_t p = permissions;
  1951. if (p & (S_ISUID | S_ISGID)) // setuid/setgid -> irregular
  1952. return true;
  1953. if (isDir) {
  1954. p &= ~S_ISVTX; // ignore sticky on dirs
  1955. // check supported flag combinations
  1956. mode_t p0 = p & UniOwner;
  1957. if ((p0 != 0) && (p0 != (S_IRUSR | S_IXUSR)) && (p0 != UniOwner))
  1958. return true;
  1959. p0 = p & UniGroup;
  1960. if ((p0 != 0) && (p0 != (S_IRGRP | S_IXGRP)) && (p0 != UniGroup))
  1961. return true;
  1962. p0 = p & UniOthers;
  1963. if ((p0 != 0) && (p0 != (S_IROTH | S_IXOTH)) && (p0 != UniOthers))
  1964. return true;
  1965. return false;
  1966. }
  1967. if (p & S_ISVTX) // sticky on file -> irregular
  1968. return true;
  1969. // check supported flag combinations
  1970. mode_t p0 = p & UniOwner;
  1971. bool usrXPossible = !p0; // true if this file could be an executable
  1972. if (p0 & S_IXUSR) {
  1973. if ((p0 == S_IXUSR) || (p0 == (S_IWUSR | S_IXUSR)))
  1974. return true;
  1975. usrXPossible = true;
  1976. }
  1977. else if (p0 == S_IWUSR)
  1978. return true;
  1979. p0 = p & UniGroup;
  1980. bool grpXPossible = !p0; // true if this file could be an executable
  1981. if (p0 & S_IXGRP) {
  1982. if ((p0 == S_IXGRP) || (p0 == (S_IWGRP | S_IXGRP)))
  1983. return true;
  1984. grpXPossible = true;
  1985. }
  1986. else if (p0 == S_IWGRP)
  1987. return true;
  1988. if (p0 == 0)
  1989. grpXPossible = true;
  1990. p0 = p & UniOthers;
  1991. bool othXPossible = !p0; // true if this file could be an executable
  1992. if (p0 & S_IXOTH) {
  1993. if ((p0 == S_IXOTH) || (p0 == (S_IWOTH | S_IXOTH)))
  1994. return true;
  1995. othXPossible = true;
  1996. }
  1997. else if (p0 == S_IWOTH)
  1998. return true;
  1999. // check that there either all targets are executable-compatible, or none
  2000. return (p & UniExec) && !(usrXPossible && grpXPossible && othXPossible);
  2001. }
  2002. // enables/disabled the widgets in the Access Control frame
  2003. void KFilePermissionsPropsPlugin::enableAccessControls(bool enable) {
  2004. d->ownerPermCombo->setEnabled(enable);
  2005. d->groupPermCombo->setEnabled(enable);
  2006. d->othersPermCombo->setEnabled(enable);
  2007. if (d->extraCheckbox)
  2008. d->extraCheckbox->setEnabled(enable);
  2009. if ( d->cbRecursive )
  2010. d->cbRecursive->setEnabled(enable);
  2011. }
  2012. // updates all widgets in the Access Control frame
  2013. void KFilePermissionsPropsPlugin::updateAccessControls() {
  2014. setComboContent(d->ownerPermCombo, PermissionsOwner,
  2015. permissions, d->partialPermissions);
  2016. setComboContent(d->groupPermCombo, PermissionsGroup,
  2017. permissions, d->partialPermissions);
  2018. setComboContent(d->othersPermCombo, PermissionsOthers,
  2019. permissions, d->partialPermissions);
  2020. switch(d->pmode) {
  2021. case PermissionsOnlyLinks:
  2022. enableAccessControls(false);
  2023. break;
  2024. case PermissionsOnlyFiles:
  2025. enableAccessControls(d->canChangePermissions && !d->isIrregular && !d->hasExtendedACL);
  2026. if (d->canChangePermissions)
  2027. d->explanationLabel->setText(d->isIrregular || d->hasExtendedACL ?
  2028. i18n("This file uses advanced permissions",
  2029. "These files use advanced permissions.",
  2030. properties->items().count()) : "");
  2031. if (d->partialPermissions & UniExec) {
  2032. d->extraCheckbox->setTristate();
  2033. d->extraCheckbox->setNoChange();
  2034. }
  2035. else {
  2036. d->extraCheckbox->setTristate(false);
  2037. d->extraCheckbox->setChecked(permissions & UniExec);
  2038. }
  2039. break;
  2040. case PermissionsOnlyDirs:
  2041. enableAccessControls(d->canChangePermissions && !d->isIrregular && !d->hasExtendedACL);
  2042. // if this is a dir, and we can change permissions, don't dis-allow
  2043. // recursive, we can do that for ACL setting.
  2044. if ( d->cbRecursive )
  2045. d->cbRecursive->setEnabled( d->canChangePermissions && !d->isIrregular );
  2046. if (d->canChangePermissions)
  2047. d->explanationLabel->setText(d->isIrregular || d->hasExtendedACL ?
  2048. i18n("This folder uses advanced permissions.",
  2049. "These folders use advanced permissions.",
  2050. properties->items().count()) : "");
  2051. if (d->partialPermissions & S_ISVTX) {
  2052. d->extraCheckbox->setTristate();
  2053. d->extraCheckbox->setNoChange();
  2054. }
  2055. else {
  2056. d->extraCheckbox->setTristate(false);
  2057. d->extraCheckbox->setChecked(permissions & S_ISVTX);
  2058. }
  2059. break;
  2060. case PermissionsMixed:
  2061. enableAccessControls(d->canChangePermissions && !d->isIrregular && !d->hasExtendedACL);
  2062. if (d->canChangePermissions)
  2063. d->explanationLabel->setText(d->isIrregular || d->hasExtendedACL ?
  2064. i18n("These files use advanced permissions.") : "");
  2065. break;
  2066. if (d->partialPermissions & S_ISVTX) {
  2067. d->extraCheckbox->setTristate();
  2068. d->extraCheckbox->setNoChange();
  2069. }
  2070. else {
  2071. d->extraCheckbox->setTristate(false);
  2072. d->extraCheckbox->setChecked(permissions & S_ISVTX);
  2073. }
  2074. break;
  2075. }
  2076. }
  2077. // gets masks for files and dirs from the Access Control frame widgets
  2078. void KFilePermissionsPropsPlugin::getPermissionMasks(mode_t &andFilePermissions,
  2079. mode_t &andDirPermissions,
  2080. mode_t &orFilePermissions,
  2081. mode_t &orDirPermissions) {
  2082. andFilePermissions = mode_t(~UniSpecial);
  2083. andDirPermissions = mode_t(~(S_ISUID|S_ISGID));
  2084. orFilePermissions = 0;
  2085. orDirPermissions = 0;
  2086. if (d->isIrregular)
  2087. return;
  2088. mode_t m = standardPermissions[d->ownerPermCombo->currentItem()];
  2089. if (m != (mode_t) -1) {
  2090. orFilePermissions |= m & UniOwner;
  2091. if ((m & UniOwner) &&
  2092. ((d->pmode == PermissionsMixed) ||
  2093. ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == TQButton::NoChange))))
  2094. andFilePermissions &= ~(S_IRUSR | S_IWUSR);
  2095. else {
  2096. andFilePermissions &= ~(S_IRUSR | S_IWUSR | S_IXUSR);
  2097. if ((m & S_IRUSR) && (d->extraCheckbox->state() == TQButton::On))
  2098. orFilePermissions |= S_IXUSR;
  2099. }
  2100. orDirPermissions |= m & UniOwner;
  2101. if (m & S_IRUSR)
  2102. orDirPermissions |= S_IXUSR;
  2103. andDirPermissions &= ~(S_IRUSR | S_IWUSR | S_IXUSR);
  2104. }
  2105. m = standardPermissions[d->groupPermCombo->currentItem()];
  2106. if (m != (mode_t) -1) {
  2107. orFilePermissions |= m & UniGroup;
  2108. if ((m & UniGroup) &&
  2109. ((d->pmode == PermissionsMixed) ||
  2110. ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == TQButton::NoChange))))
  2111. andFilePermissions &= ~(S_IRGRP | S_IWGRP);
  2112. else {
  2113. andFilePermissions &= ~(S_IRGRP | S_IWGRP | S_IXGRP);
  2114. if ((m & S_IRGRP) && (d->extraCheckbox->state() == TQButton::On))
  2115. orFilePermissions |= S_IXGRP;
  2116. }
  2117. orDirPermissions |= m & UniGroup;
  2118. if (m & S_IRGRP)
  2119. orDirPermissions |= S_IXGRP;
  2120. andDirPermissions &= ~(S_IRGRP | S_IWGRP | S_IXGRP);
  2121. }
  2122. m = standardPermissions[d->othersPermCombo->currentItem()];
  2123. if (m != (mode_t) -1) {
  2124. orFilePermissions |= m & UniOthers;
  2125. if ((m & UniOthers) &&
  2126. ((d->pmode == PermissionsMixed) ||
  2127. ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == TQButton::NoChange))))
  2128. andFilePermissions &= ~(S_IROTH | S_IWOTH);
  2129. else {
  2130. andFilePermissions &= ~(S_IROTH | S_IWOTH | S_IXOTH);
  2131. if ((m & S_IROTH) && (d->extraCheckbox->state() == TQButton::On))
  2132. orFilePermissions |= S_IXOTH;
  2133. }
  2134. orDirPermissions |= m & UniOthers;
  2135. if (m & S_IROTH)
  2136. orDirPermissions |= S_IXOTH;
  2137. andDirPermissions &= ~(S_IROTH | S_IWOTH | S_IXOTH);
  2138. }
  2139. if (((d->pmode == PermissionsMixed) || (d->pmode == PermissionsOnlyDirs)) &&
  2140. (d->extraCheckbox->state() != TQButton::NoChange)) {
  2141. andDirPermissions &= ~S_ISVTX;
  2142. if (d->extraCheckbox->state() == TQButton::On)
  2143. orDirPermissions |= S_ISVTX;
  2144. }
  2145. }
  2146. void KFilePermissionsPropsPlugin::applyChanges()
  2147. {
  2148. mode_t orFilePermissions;
  2149. mode_t orDirPermissions;
  2150. mode_t andFilePermissions;
  2151. mode_t andDirPermissions;
  2152. if (!d->canChangePermissions)
  2153. return;
  2154. if (!d->isIrregular)
  2155. getPermissionMasks(andFilePermissions,
  2156. andDirPermissions,
  2157. orFilePermissions,
  2158. orDirPermissions);
  2159. else {
  2160. orFilePermissions = permissions;
  2161. andFilePermissions = d->partialPermissions;
  2162. orDirPermissions = permissions;
  2163. andDirPermissions = d->partialPermissions;
  2164. }
  2165. TQString owner, group;
  2166. if (usrEdit)
  2167. owner = usrEdit->text();
  2168. if (grpEdit)
  2169. group = grpEdit->text();
  2170. else if (grpCombo)
  2171. group = grpCombo->currentText();
  2172. if (owner == strOwner)
  2173. owner = TQString::null; // no change
  2174. if (group == strGroup)
  2175. group = TQString::null;
  2176. bool recursive = d->cbRecursive && d->cbRecursive->isChecked();
  2177. bool permissionChange = false;
  2178. KFileItemList files, dirs;
  2179. KFileItemList items = properties->items();
  2180. for (KFileItemListIterator it(items); it.current(); ++it) {
  2181. if ((*it)->isDir()) {
  2182. dirs.append(*it);
  2183. if ((*it)->permissions() != (((*it)->permissions() & andDirPermissions) | orDirPermissions))
  2184. permissionChange = true;
  2185. }
  2186. else if ((*it)->isFile()) {
  2187. files.append(*it);
  2188. if ((*it)->permissions() != (((*it)->permissions() & andFilePermissions) | orFilePermissions))
  2189. permissionChange = true;
  2190. }
  2191. }
  2192. const bool ACLChange = ( d->extendedACL != properties->item()->ACL() );
  2193. const bool defaultACLChange = ( d->defaultACL != properties->item()->defaultACL() );
  2194. if ( owner.isEmpty() && group.isEmpty() && !recursive
  2195. && !permissionChange && !ACLChange && !defaultACLChange )
  2196. return;
  2197. KIO::Job * job;
  2198. if (files.count() > 0) {
  2199. job = KIO::chmod( files, orFilePermissions, ~andFilePermissions,
  2200. owner, group, false );
  2201. if ( ACLChange && d->fileSystemSupportsACLs )
  2202. job->addMetaData( "ACL_STRING", d->extendedACL.isValid()?d->extendedACL.asString():"ACL_DELETE" );
  2203. if ( defaultACLChange && d->fileSystemSupportsACLs )
  2204. job->addMetaData( "DEFAULT_ACL_STRING", d->defaultACL.isValid()?d->defaultACL.asString():"ACL_DELETE" );
  2205. connect( job, TQT_SIGNAL( result( KIO::Job * ) ),
  2206. TQT_SLOT( slotChmodResult( KIO::Job * ) ) );
  2207. // Wait for job
  2208. TQWidget dummy(0,0,(WFlags)(WType_Dialog|WShowModal));
  2209. tqt_enter_modal(&dummy);
  2210. tqApp->enter_loop();
  2211. tqt_leave_modal(&dummy);
  2212. }
  2213. if (dirs.count() > 0) {
  2214. job = KIO::chmod( dirs, orDirPermissions, ~andDirPermissions,
  2215. owner, group, recursive );
  2216. if ( ACLChange && d->fileSystemSupportsACLs )
  2217. job->addMetaData( "ACL_STRING", d->extendedACL.isValid()?d->extendedACL.asString():"ACL_DELETE" );
  2218. if ( defaultACLChange && d->fileSystemSupportsACLs )
  2219. job->addMetaData( "DEFAULT_ACL_STRING", d->defaultACL.isValid()?d->defaultACL.asString():"ACL_DELETE" );
  2220. connect( job, TQT_SIGNAL( result( KIO::Job * ) ),
  2221. TQT_SLOT( slotChmodResult( KIO::Job * ) ) );
  2222. // Wait for job
  2223. TQWidget dummy(0,0,(WFlags)(WType_Dialog|WShowModal));
  2224. tqt_enter_modal(&dummy);
  2225. tqApp->enter_loop();
  2226. tqt_leave_modal(&dummy);
  2227. }
  2228. }
  2229. void KFilePermissionsPropsPlugin::slotChmodResult( KIO::Job * job )
  2230. {
  2231. kdDebug(250) << "KFilePermissionsPropsPlugin::slotChmodResult" << endl;
  2232. if (job->error())
  2233. job->showErrorDialog( d->m_frame );
  2234. // allow apply() to return
  2235. tqApp->exit_loop();
  2236. }
  2237. class KURLPropsPlugin::KURLPropsPluginPrivate
  2238. {
  2239. public:
  2240. KURLPropsPluginPrivate()
  2241. {
  2242. }
  2243. ~KURLPropsPluginPrivate()
  2244. {
  2245. }
  2246. TQFrame *m_frame;
  2247. };
  2248. KURLPropsPlugin::KURLPropsPlugin( KPropertiesDialog *_props )
  2249. : KPropsDlgPlugin( _props )
  2250. {
  2251. d = new KURLPropsPluginPrivate;
  2252. d->m_frame = properties->addPage(i18n("U&RL"));
  2253. TQVBoxLayout *layout = new TQVBoxLayout(d->m_frame, 0, KDialog::spacingHint());
  2254. TQLabel *l;
  2255. l = new TQLabel( d->m_frame, "Label_1" );
  2256. l->setText( i18n("URL:") );
  2257. layout->addWidget(l);
  2258. URLEdit = new KURLRequester( d->m_frame, "URL Requester" );
  2259. layout->addWidget(URLEdit);
  2260. TQString path = properties->kurl().path();
  2261. TQFile f( path );
  2262. if ( !f.open( IO_ReadOnly ) )
  2263. return;
  2264. f.close();
  2265. KSimpleConfig config( path );
  2266. config.setDesktopGroup();
  2267. URLStr = config.readPathEntry( "URL" );
  2268. if ( !URLStr.isNull() )
  2269. URLEdit->setURL( URLStr );
  2270. connect( URLEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
  2271. this, TQT_SIGNAL( changed() ) );
  2272. layout->addStretch (1);
  2273. }
  2274. KURLPropsPlugin::~KURLPropsPlugin()
  2275. {
  2276. delete d;
  2277. }
  2278. // TQString KURLPropsPlugin::tabName () const
  2279. // {
  2280. // return i18n ("U&RL");
  2281. // }
  2282. bool KURLPropsPlugin::supports( KFileItemList _items )
  2283. {
  2284. if ( _items.count() != 1 )
  2285. return false;
  2286. KFileItem * item = _items.first();
  2287. // check if desktop file
  2288. if ( !KPropsDlgPlugin::isDesktopFile( item ) )
  2289. return false;
  2290. // open file and check type
  2291. KDesktopFile config( item->url().path(), true /* readonly */ );
  2292. return config.hasLinkType();
  2293. }
  2294. void KURLPropsPlugin::applyChanges()
  2295. {
  2296. TQString path = properties->kurl().path();
  2297. TQFile f( path );
  2298. if ( !f.open( IO_ReadWrite ) ) {
  2299. KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
  2300. "sufficient access to write to <b>%1</b>.</qt>").arg(path));
  2301. return;
  2302. }
  2303. f.close();
  2304. KSimpleConfig config( path );
  2305. config.setDesktopGroup();
  2306. config.writeEntry( "Type", TQString::fromLatin1("Link"));
  2307. config.writePathEntry( "URL", URLEdit->url() );
  2308. // Users can't create a Link .desktop file with a Name field,
  2309. // but distributions can. Update the Name field in that case.
  2310. if ( config.hasKey("Name") )
  2311. {
  2312. TQString nameStr = nameFromFileName(properties->kurl().fileName());
  2313. config.writeEntry( "Name", nameStr );
  2314. config.writeEntry( "Name", nameStr, true, false, true );
  2315. }
  2316. }
  2317. /* ----------------------------------------------------
  2318. *
  2319. * KBindingPropsPlugin
  2320. *
  2321. * -------------------------------------------------- */
  2322. class KBindingPropsPlugin::KBindingPropsPluginPrivate
  2323. {
  2324. public:
  2325. KBindingPropsPluginPrivate()
  2326. {
  2327. }
  2328. ~KBindingPropsPluginPrivate()
  2329. {
  2330. }
  2331. TQFrame *m_frame;
  2332. };
  2333. KBindingPropsPlugin::KBindingPropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props )
  2334. {
  2335. d = new KBindingPropsPluginPrivate;
  2336. d->m_frame = properties->addPage(i18n("A&ssociation"));
  2337. patternEdit = new KLineEdit( d->m_frame, "LineEdit_1" );
  2338. commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" );
  2339. mimeEdit = new KLineEdit( d->m_frame, "LineEdit_3" );
  2340. TQBoxLayout *mainlayout = new TQVBoxLayout(d->m_frame, 0, KDialog::spacingHint());
  2341. TQLabel* tmpQLabel;
  2342. tmpQLabel = new TQLabel( d->m_frame, "Label_1" );
  2343. tmpQLabel->setText( i18n("Pattern ( example: *.html;*.htm )") );
  2344. tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
  2345. mainlayout->addWidget(tmpQLabel, 1);
  2346. //patternEdit->setGeometry( 10, 40, 210, 30 );
  2347. //patternEdit->setText( "" );
  2348. patternEdit->setMaxLength( 512 );
  2349. patternEdit->setMinimumSize( patternEdit->sizeHint() );
  2350. patternEdit->setFixedHeight( fontHeight );
  2351. mainlayout->addWidget(patternEdit, 1);
  2352. tmpQLabel = new TQLabel( d->m_frame, "Label_2" );
  2353. tmpQLabel->setText( i18n("Mime Type") );
  2354. tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
  2355. mainlayout->addWidget(tmpQLabel, 1);
  2356. //mimeEdit->setGeometry( 10, 160, 210, 30 );
  2357. mimeEdit->setMaxLength( 256 );
  2358. mimeEdit->setMinimumSize( mimeEdit->sizeHint() );
  2359. mimeEdit->setFixedHeight( fontHeight );
  2360. mainlayout->addWidget(mimeEdit, 1);
  2361. tmpQLabel = new TQLabel( d->m_frame, "Label_3" );
  2362. tmpQLabel->setText( i18n("Comment") );
  2363. tmpQLabel->setMinimumSize(tmpQLabel->sizeHint());
  2364. mainlayout->addWidget(tmpQLabel, 1);
  2365. //commentEdit->setGeometry( 10, 100, 210, 30 );
  2366. commentEdit->setMaxLength( 256 );
  2367. commentEdit->setMinimumSize( commentEdit->sizeHint() );
  2368. commentEdit->setFixedHeight( fontHeight );
  2369. mainlayout->addWidget(commentEdit, 1);
  2370. cbAutoEmbed = new TQCheckBox( i18n("Left click previews"), d->m_frame, "cbAutoEmbed" );
  2371. mainlayout->addWidget(cbAutoEmbed, 1);
  2372. mainlayout->addStretch (10);
  2373. mainlayout->activate();
  2374. TQFile f( _props->kurl().path() );
  2375. if ( !f.open( IO_ReadOnly ) )
  2376. return;
  2377. f.close();
  2378. KSimpleConfig config( _props->kurl().path() );
  2379. config.setDesktopGroup();
  2380. TQString patternStr = config.readEntry( "Patterns" );
  2381. TQString iconStr = config.readEntry( "Icon" );
  2382. TQString commentStr = config.readEntry( "Comment" );
  2383. m_sMimeStr = config.readEntry( "MimeType" );
  2384. if ( !patternStr.isEmpty() )
  2385. patternEdit->setText( patternStr );
  2386. if ( !commentStr.isEmpty() )
  2387. commentEdit->setText( commentStr );
  2388. if ( !m_sMimeStr.isEmpty() )
  2389. mimeEdit->setText( m_sMimeStr );
  2390. cbAutoEmbed->setTristate();
  2391. if ( config.hasKey( "X-TDE-AutoEmbed" ) )
  2392. cbAutoEmbed->setChecked( config.readBoolEntry( "X-TDE-AutoEmbed" ) );
  2393. else
  2394. cbAutoEmbed->setNoChange();
  2395. connect( patternEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
  2396. this, TQT_SIGNAL( changed() ) );
  2397. connect( commentEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
  2398. this, TQT_SIGNAL( changed() ) );
  2399. connect( mimeEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
  2400. this, TQT_SIGNAL( changed() ) );
  2401. connect( cbAutoEmbed, TQT_SIGNAL( toggled( bool ) ),
  2402. this, TQT_SIGNAL( changed() ) );
  2403. }
  2404. KBindingPropsPlugin::~KBindingPropsPlugin()
  2405. {
  2406. delete d;
  2407. }
  2408. // TQString KBindingPropsPlugin::tabName () const
  2409. // {
  2410. // return i18n ("A&ssociation");
  2411. // }
  2412. bool KBindingPropsPlugin::supports( KFileItemList _items )
  2413. {
  2414. if ( _items.count() != 1 )
  2415. return false;
  2416. KFileItem * item = _items.first();
  2417. // check if desktop file
  2418. if ( !KPropsDlgPlugin::isDesktopFile( item ) )
  2419. return false;
  2420. // open file and check type
  2421. KDesktopFile config( item->url().path(), true /* readonly */ );
  2422. return config.hasMimeTypeType();
  2423. }
  2424. void KBindingPropsPlugin::applyChanges()
  2425. {
  2426. TQString path = properties->kurl().path();
  2427. TQFile f( path );
  2428. if ( !f.open( IO_ReadWrite ) )
  2429. {
  2430. KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
  2431. "sufficient access to write to <b>%1</b>.</qt>").arg(path));
  2432. return;
  2433. }
  2434. f.close();
  2435. KSimpleConfig config( path );
  2436. config.setDesktopGroup();
  2437. config.writeEntry( "Type", TQString::fromLatin1("MimeType") );
  2438. config.writeEntry( "Patterns", patternEdit->text() );
  2439. config.writeEntry( "Comment", commentEdit->text() );
  2440. config.writeEntry( "Comment",
  2441. commentEdit->text(), true, false, true ); // for compat
  2442. config.writeEntry( "MimeType", mimeEdit->text() );
  2443. if ( cbAutoEmbed->state() == TQButton::NoChange )
  2444. config.deleteEntry( "X-TDE-AutoEmbed", false );
  2445. else
  2446. config.writeEntry( "X-TDE-AutoEmbed", cbAutoEmbed->isChecked() );
  2447. config.sync();
  2448. }
  2449. /* ----------------------------------------------------
  2450. *
  2451. * KDevicePropsPlugin
  2452. *
  2453. * -------------------------------------------------- */
  2454. class KDevicePropsPlugin::KDevicePropsPluginPrivate
  2455. {
  2456. public:
  2457. KDevicePropsPluginPrivate()
  2458. {
  2459. }
  2460. ~KDevicePropsPluginPrivate()
  2461. {
  2462. }
  2463. TQFrame *m_frame;
  2464. TQStringList mountpointlist;
  2465. TQLabel *m_freeSpaceText;
  2466. TQLabel *m_freeSpaceLabel;
  2467. TQProgressBar *m_freeSpaceBar;
  2468. };
  2469. KDevicePropsPlugin::KDevicePropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props )
  2470. {
  2471. d = new KDevicePropsPluginPrivate;
  2472. d->m_frame = properties->addPage(i18n("De&vice"));
  2473. TQStringList devices;
  2474. KMountPoint::List mountPoints = KMountPoint::possibleMountPoints();
  2475. for(KMountPoint::List::ConstIterator it = mountPoints.begin();
  2476. it != mountPoints.end(); ++it)
  2477. {
  2478. KMountPoint *mp = *it;
  2479. TQString mountPoint = mp->mountPoint();
  2480. TQString device = mp->mountedFrom();
  2481. kdDebug()<<"mountPoint :"<<mountPoint<<" device :"<<device<<" mp->mountType() :"<<mp->mountType()<<endl;
  2482. if ((mountPoint != "-") && (mountPoint != "none") && !mountPoint.isEmpty()
  2483. && device != "none")
  2484. {
  2485. devices.append( device + TQString::fromLatin1(" (")
  2486. + mountPoint + TQString::fromLatin1(")") );
  2487. m_devicelist.append(device);
  2488. d->mountpointlist.append(mountPoint);
  2489. }
  2490. }
  2491. TQGridLayout *layout = new TQGridLayout( d->m_frame, 0, 2, 0,
  2492. KDialog::spacingHint());
  2493. layout->setColStretch(1, 1);
  2494. TQLabel* label;
  2495. label = new TQLabel( d->m_frame );
  2496. label->setText( devices.count() == 0 ?
  2497. i18n("Device (/dev/fd0):") : // old style
  2498. i18n("Device:") ); // new style (combobox)
  2499. layout->addWidget(label, 0, 0);
  2500. device = new TQComboBox( true, d->m_frame, "ComboBox_device" );
  2501. device->insertStringList( devices );
  2502. layout->addWidget(device, 0, 1);
  2503. connect( device, TQT_SIGNAL( activated( int ) ),
  2504. this, TQT_SLOT( slotActivated( int ) ) );
  2505. readonly = new TQCheckBox( d->m_frame, "CheckBox_readonly" );
  2506. readonly->setText( i18n("Read only") );
  2507. layout->addWidget(readonly, 1, 1);
  2508. label = new TQLabel( d->m_frame );
  2509. label->setText( i18n("File system:") );
  2510. layout->addWidget(label, 2, 0);
  2511. TQLabel *fileSystem = new TQLabel( d->m_frame );
  2512. layout->addWidget(fileSystem, 2, 1);
  2513. label = new TQLabel( d->m_frame );
  2514. label->setText( devices.count()==0 ?
  2515. i18n("Mount point (/mnt/floppy):") : // old style
  2516. i18n("Mount point:")); // new style (combobox)
  2517. layout->addWidget(label, 3, 0);
  2518. mountpoint = new TQLabel( d->m_frame, "LineEdit_mountpoint" );
  2519. layout->addWidget(mountpoint, 3, 1);
  2520. // show disk free
  2521. d->m_freeSpaceText = new TQLabel(i18n("Free disk space:"), d->m_frame );
  2522. layout->addWidget(d->m_freeSpaceText, 4, 0);
  2523. d->m_freeSpaceLabel = new TQLabel( d->m_frame );
  2524. layout->addWidget( d->m_freeSpaceLabel, 4, 1 );
  2525. d->m_freeSpaceBar = new TQProgressBar( d->m_frame, "freeSpaceBar" );
  2526. layout->addMultiCellWidget(d->m_freeSpaceBar, 5, 5, 0, 1);
  2527. // we show it in the slot when we know the values
  2528. d->m_freeSpaceText->hide();
  2529. d->m_freeSpaceLabel->hide();
  2530. d->m_freeSpaceBar->hide();
  2531. KSeparator* sep = new KSeparator( KSeparator::HLine, d->m_frame);
  2532. layout->addMultiCellWidget(sep, 6, 6, 0, 1);
  2533. unmounted = new KIconButton( d->m_frame );
  2534. int bsize = 66 + 2 * unmounted->style().pixelMetric(TQStyle::PM_ButtonMargin);
  2535. unmounted->setFixedSize(bsize, bsize);
  2536. unmounted->setIconType(KIcon::Desktop, KIcon::Device);
  2537. layout->addWidget(unmounted, 7, 0);
  2538. label = new TQLabel( i18n("Unmounted Icon"), d->m_frame );
  2539. layout->addWidget(label, 7, 1);
  2540. layout->setRowStretch(8, 1);
  2541. TQString path( _props->kurl().path() );
  2542. TQFile f( path );
  2543. if ( !f.open( IO_ReadOnly ) )
  2544. return;
  2545. f.close();
  2546. KSimpleConfig config( path );
  2547. config.setDesktopGroup();
  2548. TQString deviceStr = config.readEntry( "Dev" );
  2549. TQString mountPointStr = config.readEntry( "MountPoint" );
  2550. bool ro = config.readBoolEntry( "ReadOnly", false );
  2551. TQString unmountedStr = config.readEntry( "UnmountIcon" );
  2552. fileSystem->setText( i18n(config.readEntry("FSType").local8Bit()) );
  2553. device->setEditText( deviceStr );
  2554. if ( !deviceStr.isEmpty() ) {
  2555. // Set default options for this device (first matching entry)
  2556. int index = m_devicelist.findIndex(deviceStr);
  2557. if (index != -1)
  2558. {
  2559. //kdDebug(250) << "found it " << index << endl;
  2560. slotActivated( index );
  2561. }
  2562. }
  2563. if ( !mountPointStr.isEmpty() )
  2564. {
  2565. mountpoint->setText( mountPointStr );
  2566. updateInfo();
  2567. }
  2568. readonly->setChecked( ro );
  2569. if ( unmountedStr.isEmpty() )
  2570. unmountedStr = KMimeType::defaultMimeTypePtr()->KServiceType::icon(); // default icon
  2571. unmounted->setIcon( unmountedStr );
  2572. connect( device, TQT_SIGNAL( activated( int ) ),
  2573. this, TQT_SIGNAL( changed() ) );
  2574. connect( device, TQT_SIGNAL( textChanged( const TQString & ) ),
  2575. this, TQT_SIGNAL( changed() ) );
  2576. connect( readonly, TQT_SIGNAL( toggled( bool ) ),
  2577. this, TQT_SIGNAL( changed() ) );
  2578. connect( unmounted, TQT_SIGNAL( iconChanged( TQString ) ),
  2579. this, TQT_SIGNAL( changed() ) );
  2580. connect( device, TQT_SIGNAL( textChanged( const TQString & ) ),
  2581. this, TQT_SLOT( slotDeviceChanged() ) );
  2582. }
  2583. KDevicePropsPlugin::~KDevicePropsPlugin()
  2584. {
  2585. delete d;
  2586. }
  2587. // TQString KDevicePropsPlugin::tabName () const
  2588. // {
  2589. // return i18n ("De&vice");
  2590. // }
  2591. void KDevicePropsPlugin::updateInfo()
  2592. {
  2593. // we show it in the slot when we know the values
  2594. d->m_freeSpaceText->hide();
  2595. d->m_freeSpaceLabel->hide();
  2596. d->m_freeSpaceBar->hide();
  2597. if ( !mountpoint->text().isEmpty() )
  2598. {
  2599. KDiskFreeSp * job = new KDiskFreeSp;
  2600. connect( job, TQT_SIGNAL( foundMountPoint( const unsigned long&, const unsigned long&,
  2601. const unsigned long&, const TQString& ) ),
  2602. this, TQT_SLOT( slotFoundMountPoint( const unsigned long&, const unsigned long&,
  2603. const unsigned long&, const TQString& ) ) );
  2604. job->readDF( mountpoint->text() );
  2605. }
  2606. }
  2607. void KDevicePropsPlugin::slotActivated( int index )
  2608. {
  2609. // Update mountpoint so that it matches the device that was selected in the combo
  2610. device->setEditText( m_devicelist[index] );
  2611. mountpoint->setText( d->mountpointlist[index] );
  2612. updateInfo();
  2613. }
  2614. void KDevicePropsPlugin::slotDeviceChanged()
  2615. {
  2616. // Update mountpoint so that it matches the typed device
  2617. int index = m_devicelist.findIndex( device->currentText() );
  2618. if ( index != -1 )
  2619. mountpoint->setText( d->mountpointlist[index] );
  2620. else
  2621. mountpoint->setText( TQString::null );
  2622. updateInfo();
  2623. }
  2624. void KDevicePropsPlugin::slotFoundMountPoint( const unsigned long& kBSize,
  2625. const unsigned long& /*kBUsed*/,
  2626. const unsigned long& kBAvail,
  2627. const TQString& )
  2628. {
  2629. d->m_freeSpaceText->show();
  2630. d->m_freeSpaceLabel->show();
  2631. int percUsed = 100 - (int)(100.0 * kBAvail / kBSize);
  2632. d->m_freeSpaceLabel->setText(
  2633. // xgettext:no-c-format -- Don't warn about translating the %1 out of %2 part.
  2634. i18n("Available space out of total partition size (percent used)", "%1 out of %2 (%3% used)")
  2635. .arg(KIO::convertSizeFromKB(kBAvail))
  2636. .arg(KIO::convertSizeFromKB(kBSize))
  2637. .arg( 100 - (int)(100.0 * kBAvail / kBSize) ));
  2638. d->m_freeSpaceBar->setProgress(percUsed, 100);
  2639. d->m_freeSpaceBar->show();
  2640. }
  2641. bool KDevicePropsPlugin::supports( KFileItemList _items )
  2642. {
  2643. if ( _items.count() != 1 )
  2644. return false;
  2645. KFileItem * item = _items.first();
  2646. // check if desktop file
  2647. if ( !KPropsDlgPlugin::isDesktopFile( item ) )
  2648. return false;
  2649. // open file and check type
  2650. KDesktopFile config( item->url().path(), true /* readonly */ );
  2651. return config.hasDeviceType();
  2652. }
  2653. void KDevicePropsPlugin::applyChanges()
  2654. {
  2655. TQString path = properties->kurl().path();
  2656. TQFile f( path );
  2657. if ( !f.open( IO_ReadWrite ) )
  2658. {
  2659. KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient "
  2660. "access to write to <b>%1</b>.</qt>").arg(path));
  2661. return;
  2662. }
  2663. f.close();
  2664. KSimpleConfig config( path );
  2665. config.setDesktopGroup();
  2666. config.writeEntry( "Type", TQString::fromLatin1("FSDevice") );
  2667. config.writeEntry( "Dev", device->currentText() );
  2668. config.writeEntry( "MountPoint", mountpoint->text() );
  2669. config.writeEntry( "UnmountIcon", unmounted->icon() );
  2670. kdDebug(250) << "unmounted->icon() = " << unmounted->icon() << endl;
  2671. config.writeEntry( "ReadOnly", readonly->isChecked() );
  2672. config.sync();
  2673. }
  2674. /* ----------------------------------------------------
  2675. *
  2676. * KDesktopPropsPlugin
  2677. *
  2678. * -------------------------------------------------- */
  2679. KDesktopPropsPlugin::KDesktopPropsPlugin( KPropertiesDialog *_props )
  2680. : KPropsDlgPlugin( _props )
  2681. {
  2682. TQFrame *frame = properties->addPage(i18n("&Application"));
  2683. TQVBoxLayout *mainlayout = new TQVBoxLayout( frame, 0, KDialog::spacingHint() );
  2684. w = new KPropertiesDesktopBase(frame);
  2685. mainlayout->addWidget(w);
  2686. bool bKDesktopMode = (TQCString(tqApp->name()) == "kdesktop"); // nasty heh?
  2687. if (bKDesktopMode)
  2688. {
  2689. // Hide Name entry
  2690. w->nameEdit->hide();
  2691. w->nameLabel->hide();
  2692. }
  2693. w->pathEdit->setMode(KFile::Directory | KFile::LocalOnly);
  2694. w->pathEdit->lineEdit()->setAcceptDrops(false);
  2695. connect( w->nameEdit, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SIGNAL( changed() ) );
  2696. connect( w->genNameEdit, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SIGNAL( changed() ) );
  2697. connect( w->commentEdit, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SIGNAL( changed() ) );
  2698. connect( w->commandEdit, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SIGNAL( changed() ) );
  2699. connect( w->pathEdit, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SIGNAL( changed() ) );
  2700. connect( w->browseButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotBrowseExec() ) );
  2701. connect( w->addFiletypeButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotAddFiletype() ) );
  2702. connect( w->delFiletypeButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotDelFiletype() ) );
  2703. connect( w->advancedButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotAdvanced() ) );
  2704. // now populate the page
  2705. TQString path = _props->kurl().path();
  2706. TQFile f( path );
  2707. if ( !f.open( IO_ReadOnly ) )
  2708. return;
  2709. f.close();
  2710. KDesktopFile config( path );
  2711. TQString nameStr = config.readName();
  2712. TQString genNameStr = config.readGenericName();
  2713. TQString commentStr = config.readComment();
  2714. TQString commandStr = config.readPathEntry( "Exec" );
  2715. if (commandStr.left(12) == "ksystraycmd ")
  2716. {
  2717. commandStr.remove(0, 12);
  2718. m_systrayBool = true;
  2719. }
  2720. else
  2721. m_systrayBool = false;
  2722. m_origCommandStr = commandStr;
  2723. TQString pathStr = config.readPathEntry( "Path" );
  2724. m_terminalBool = config.readBoolEntry( "Terminal" );
  2725. m_terminalOptionStr = config.readEntry( "TerminalOptions" );
  2726. m_suidBool = config.readBoolEntry( "X-TDE-SubstituteUID" );
  2727. m_suidUserStr = config.readEntry( "X-TDE-Username" );
  2728. if( config.hasKey( "StartupNotify" ))
  2729. m_startupBool = config.readBoolEntry( "StartupNotify", true );
  2730. else
  2731. m_startupBool = config.readBoolEntry( "X-TDE-StartupNotify", true );
  2732. m_dcopServiceType = config.readEntry("X-DCOP-ServiceType").lower();
  2733. TQStringList mimeTypes = config.readListEntry( "MimeType", ';' );
  2734. if ( nameStr.isEmpty() || bKDesktopMode ) {
  2735. // We'll use the file name if no name is specified
  2736. // because we _need_ a Name for a valid file.
  2737. // But let's do it in apply, not here, so that we pick up the right name.
  2738. setDirty();
  2739. }
  2740. if ( !bKDesktopMode )
  2741. w->nameEdit->setText(nameStr);
  2742. w->genNameEdit->setText( genNameStr );
  2743. w->commentEdit->setText( commentStr );
  2744. w->commandEdit->setText( commandStr );
  2745. w->pathEdit->lineEdit()->setText( pathStr );
  2746. w->filetypeList->setAllColumnsShowFocus(true);
  2747. KMimeType::Ptr defaultMimetype = KMimeType::defaultMimeTypePtr();
  2748. for(TQStringList::ConstIterator it = mimeTypes.begin();
  2749. it != mimeTypes.end(); )
  2750. {
  2751. KMimeType::Ptr p = KMimeType::mimeType(*it);
  2752. ++it;
  2753. TQString preference;
  2754. if (it != mimeTypes.end())
  2755. {
  2756. bool numeric;
  2757. (*it).toInt(&numeric);
  2758. if (numeric)
  2759. {
  2760. preference = *it;
  2761. ++it;
  2762. }
  2763. }
  2764. if (p && (p != defaultMimetype))
  2765. {
  2766. new TQListViewItem(w->filetypeList, p->name(), p->comment(), preference);
  2767. }
  2768. }
  2769. }
  2770. KDesktopPropsPlugin::~KDesktopPropsPlugin()
  2771. {
  2772. }
  2773. void KDesktopPropsPlugin::slotSelectMimetype()
  2774. {
  2775. TQListView *w = (TQListView*)sender();
  2776. TQListViewItem *item = w->firstChild();
  2777. while(item)
  2778. {
  2779. if (item->isSelected())
  2780. w->setSelected(item, false);
  2781. item = item->nextSibling();
  2782. }
  2783. }
  2784. void KDesktopPropsPlugin::slotAddFiletype()
  2785. {
  2786. KDialogBase dlg(w, "KPropertiesMimetypes", true,
  2787. i18n("Add File Type for %1").arg(properties->kurl().fileName()),
  2788. KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok);
  2789. KGuiItem okItem(i18n("&Add"), TQString::null /* no icon */,
  2790. i18n("Add the selected file types to\nthe list of supported file types."),
  2791. i18n("Add the selected file types to\nthe list of supported file types."));
  2792. dlg.setButtonOK(okItem);
  2793. KPropertiesMimetypeBase *mw = new KPropertiesMimetypeBase(&dlg);
  2794. dlg.setMainWidget(mw);
  2795. {
  2796. mw->listView->setRootIsDecorated(true);
  2797. mw->listView->setSelectionMode(TQListView::Extended);
  2798. mw->listView->setAllColumnsShowFocus(true);
  2799. mw->listView->setFullWidth(true);
  2800. mw->listView->setMinimumSize(500,400);
  2801. connect(mw->listView, TQT_SIGNAL(selectionChanged()),
  2802. this, TQT_SLOT(slotSelectMimetype()));
  2803. connect(mw->listView, TQT_SIGNAL(doubleClicked( TQListViewItem *, const TQPoint &, int )),
  2804. &dlg, TQT_SLOT( slotOk()));
  2805. TQMap<TQString,TQListViewItem*> majorMap;
  2806. TQListViewItem *majorGroup;
  2807. KMimeType::List mimetypes = KMimeType::allMimeTypes();
  2808. TQValueListIterator<KMimeType::Ptr> it(mimetypes.begin());
  2809. for (; it != mimetypes.end(); ++it) {
  2810. TQString mimetype = (*it)->name();
  2811. if (mimetype == KMimeType::defaultMimeType())
  2812. continue;
  2813. int index = mimetype.find("/");
  2814. TQString maj = mimetype.left(index);
  2815. TQString min = mimetype.mid(index+1);
  2816. TQMapIterator<TQString,TQListViewItem*> mit = majorMap.find( maj );
  2817. if ( mit == majorMap.end() ) {
  2818. majorGroup = new TQListViewItem( mw->listView, maj );
  2819. majorGroup->setExpandable(true);
  2820. mw->listView->setOpen(majorGroup, true);
  2821. majorMap.insert( maj, majorGroup );
  2822. }
  2823. else
  2824. {
  2825. majorGroup = mit.data();
  2826. }
  2827. TQListViewItem *item = new TQListViewItem(majorGroup, min, (*it)->comment());
  2828. item->setPixmap(0, (*it)->pixmap(KIcon::Small, IconSize(KIcon::Small)));
  2829. }
  2830. TQMapIterator<TQString,TQListViewItem*> mit = majorMap.find( "all" );
  2831. if ( mit != majorMap.end())
  2832. {
  2833. mw->listView->setCurrentItem(mit.data());
  2834. mw->listView->ensureItemVisible(mit.data());
  2835. }
  2836. }
  2837. if (dlg.exec() == KDialogBase::Accepted)
  2838. {
  2839. KMimeType::Ptr defaultMimetype = KMimeType::defaultMimeTypePtr();
  2840. TQListViewItem *majorItem = mw->listView->firstChild();
  2841. while(majorItem)
  2842. {
  2843. TQString major = majorItem->text(0);
  2844. TQListViewItem *minorItem = majorItem->firstChild();
  2845. while(minorItem)
  2846. {
  2847. if (minorItem->isSelected())
  2848. {
  2849. TQString mimetype = major + "/" + minorItem->text(0);
  2850. KMimeType::Ptr p = KMimeType::mimeType(mimetype);
  2851. if (p && (p != defaultMimetype))
  2852. {
  2853. mimetype = p->name();
  2854. bool found = false;
  2855. TQListViewItem *item = w->filetypeList->firstChild();
  2856. while (item)
  2857. {
  2858. if (mimetype == item->text(0))
  2859. {
  2860. found = true;
  2861. break;
  2862. }
  2863. item = item->nextSibling();
  2864. }
  2865. if (!found) {
  2866. new TQListViewItem(w->filetypeList, p->name(), p->comment());
  2867. emit changed();
  2868. }
  2869. }
  2870. }
  2871. minorItem = minorItem->nextSibling();
  2872. }
  2873. majorItem = majorItem->nextSibling();
  2874. }
  2875. }
  2876. }
  2877. void KDesktopPropsPlugin::slotDelFiletype()
  2878. {
  2879. delete w->filetypeList->currentItem();
  2880. emit changed();
  2881. }
  2882. void KDesktopPropsPlugin::checkCommandChanged()
  2883. {
  2884. if (KRun::binaryName(w->commandEdit->text(), true) !=
  2885. KRun::binaryName(m_origCommandStr, true))
  2886. {
  2887. TQString m_origCommandStr = w->commandEdit->text();
  2888. m_dcopServiceType= TQString::null; // Reset
  2889. }
  2890. }
  2891. void KDesktopPropsPlugin::applyChanges()
  2892. {
  2893. kdDebug(250) << "KDesktopPropsPlugin::applyChanges" << endl;
  2894. TQString path = properties->kurl().path();
  2895. TQFile f( path );
  2896. if ( !f.open( IO_ReadWrite ) ) {
  2897. KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
  2898. "sufficient access to write to <b>%1</b>.</qt>").arg(path));
  2899. return;
  2900. }
  2901. f.close();
  2902. // If the command is changed we reset certain settings that are strongly
  2903. // coupled to the command.
  2904. checkCommandChanged();
  2905. KSimpleConfig config( path );
  2906. config.setDesktopGroup();
  2907. config.writeEntry( "Type", TQString::fromLatin1("Application"));
  2908. config.writeEntry( "Comment", w->commentEdit->text() );
  2909. config.writeEntry( "Comment", w->commentEdit->text(), true, false, true ); // for compat
  2910. config.writeEntry( "GenericName", w->genNameEdit->text() );
  2911. config.writeEntry( "GenericName", w->genNameEdit->text(), true, false, true ); // for compat
  2912. if (m_systrayBool)
  2913. config.writePathEntry( "Exec", w->commandEdit->text().prepend("ksystraycmd ") );
  2914. else
  2915. config.writePathEntry( "Exec", w->commandEdit->text() );
  2916. config.writePathEntry( "Path", w->pathEdit->lineEdit()->text() );
  2917. // Write mimeTypes
  2918. TQStringList mimeTypes;
  2919. for( TQListViewItem *item = w->filetypeList->firstChild();
  2920. item; item = item->nextSibling() )
  2921. {
  2922. TQString preference = item->text(2);
  2923. mimeTypes.append(item->text(0));
  2924. if (!preference.isEmpty())
  2925. mimeTypes.append(preference);
  2926. }
  2927. config.writeEntry( "MimeType", mimeTypes, ';' );
  2928. if ( !w->nameEdit->isHidden() ) {
  2929. TQString nameStr = w->nameEdit->text();
  2930. config.writeEntry( "Name", nameStr );
  2931. config.writeEntry( "Name", nameStr, true, false, true );
  2932. }
  2933. config.writeEntry("Terminal", m_terminalBool);
  2934. config.writeEntry("TerminalOptions", m_terminalOptionStr);
  2935. config.writeEntry("X-TDE-SubstituteUID", m_suidBool);
  2936. config.writeEntry("X-TDE-Username", m_suidUserStr);
  2937. config.writeEntry("StartupNotify", m_startupBool);
  2938. config.writeEntry("X-DCOP-ServiceType", m_dcopServiceType);
  2939. config.sync();
  2940. // KSycoca update needed?
  2941. TQString sycocaPath = KGlobal::dirs()->relativeLocation("apps", path);
  2942. bool updateNeeded = !sycocaPath.startsWith("/");
  2943. if (!updateNeeded)
  2944. {
  2945. sycocaPath = KGlobal::dirs()->relativeLocation("xdgdata-apps", path);
  2946. updateNeeded = !sycocaPath.startsWith("/");
  2947. }
  2948. if (updateNeeded)
  2949. KService::rebuildKSycoca(w);
  2950. }
  2951. void KDesktopPropsPlugin::slotBrowseExec()
  2952. {
  2953. KURL f = KFileDialog::getOpenURL( TQString::null,
  2954. TQString::null, w );
  2955. if ( f.isEmpty() )
  2956. return;
  2957. if ( !f.isLocalFile()) {
  2958. KMessageBox::sorry(w, i18n("Only executables on local file systems are supported."));
  2959. return;
  2960. }
  2961. TQString path = f.path();
  2962. KRun::shellQuote( path );
  2963. w->commandEdit->setText( path );
  2964. }
  2965. void KDesktopPropsPlugin::slotAdvanced()
  2966. {
  2967. KDialogBase dlg(w, "KPropertiesDesktopAdv", true,
  2968. i18n("Advanced Options for %1").arg(properties->kurl().fileName()),
  2969. KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok);
  2970. KPropertiesDesktopAdvBase *w = new KPropertiesDesktopAdvBase(&dlg);
  2971. dlg.setMainWidget(w);
  2972. // If the command is changed we reset certain settings that are strongly
  2973. // coupled to the command.
  2974. checkCommandChanged();
  2975. // check to see if we use konsole if not do not add the nocloseonexit
  2976. // because we don't know how to do this on other terminal applications
  2977. KConfigGroup confGroup( KGlobal::config(), TQString::fromLatin1("General") );
  2978. TQString preferredTerminal = confGroup.readPathEntry("TerminalApplication",
  2979. TQString::fromLatin1("konsole"));
  2980. bool terminalCloseBool = false;
  2981. if (preferredTerminal == "konsole")
  2982. {
  2983. terminalCloseBool = (m_terminalOptionStr.contains( "--noclose" ) > 0);
  2984. w->terminalCloseCheck->setChecked(terminalCloseBool);
  2985. m_terminalOptionStr.replace( "--noclose", "");
  2986. }
  2987. else
  2988. {
  2989. w->terminalCloseCheck->hide();
  2990. }
  2991. w->terminalCheck->setChecked(m_terminalBool);
  2992. w->terminalEdit->setText(m_terminalOptionStr);
  2993. w->terminalCloseCheck->setEnabled(m_terminalBool);
  2994. w->terminalEdit->setEnabled(m_terminalBool);
  2995. w->terminalEditLabel->setEnabled(m_terminalBool);
  2996. w->suidCheck->setChecked(m_suidBool);
  2997. w->suidEdit->setText(m_suidUserStr);
  2998. w->suidEdit->setEnabled(m_suidBool);
  2999. w->suidEditLabel->setEnabled(m_suidBool);
  3000. w->startupInfoCheck->setChecked(m_startupBool);
  3001. w->systrayCheck->setChecked(m_systrayBool);
  3002. if (m_dcopServiceType == "unique")
  3003. w->dcopCombo->setCurrentItem(2);
  3004. else if (m_dcopServiceType == "multi")
  3005. w->dcopCombo->setCurrentItem(1);
  3006. else if (m_dcopServiceType == "wait")
  3007. w->dcopCombo->setCurrentItem(3);
  3008. else
  3009. w->dcopCombo->setCurrentItem(0);
  3010. // Provide username completion up to 1000 users.
  3011. KCompletion *kcom = new KCompletion;
  3012. kcom->setOrder(KCompletion::Sorted);
  3013. struct passwd *pw;
  3014. int i, maxEntries = 1000;
  3015. setpwent();
  3016. for (i=0; ((pw = getpwent()) != 0L) && (i < maxEntries); i++)
  3017. kcom->addItem(TQString::fromLatin1(pw->pw_name));
  3018. endpwent();
  3019. if (i < maxEntries)
  3020. {
  3021. w->suidEdit->setCompletionObject(kcom, true);
  3022. w->suidEdit->setAutoDeleteCompletionObject( true );
  3023. w->suidEdit->setCompletionMode(KGlobalSettings::CompletionAuto);
  3024. }
  3025. else
  3026. {
  3027. delete kcom;
  3028. }
  3029. connect( w->terminalEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
  3030. this, TQT_SIGNAL( changed() ) );
  3031. connect( w->terminalCloseCheck, TQT_SIGNAL( toggled( bool ) ),
  3032. this, TQT_SIGNAL( changed() ) );
  3033. connect( w->terminalCheck, TQT_SIGNAL( toggled( bool ) ),
  3034. this, TQT_SIGNAL( changed() ) );
  3035. connect( w->suidCheck, TQT_SIGNAL( toggled( bool ) ),
  3036. this, TQT_SIGNAL( changed() ) );
  3037. connect( w->suidEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
  3038. this, TQT_SIGNAL( changed() ) );
  3039. connect( w->startupInfoCheck, TQT_SIGNAL( toggled( bool ) ),
  3040. this, TQT_SIGNAL( changed() ) );
  3041. connect( w->systrayCheck, TQT_SIGNAL( toggled( bool ) ),
  3042. this, TQT_SIGNAL( changed() ) );
  3043. connect( w->dcopCombo, TQT_SIGNAL( highlighted( int ) ),
  3044. this, TQT_SIGNAL( changed() ) );
  3045. if ( dlg.exec() == TQDialog::Accepted )
  3046. {
  3047. m_terminalOptionStr = w->terminalEdit->text().stripWhiteSpace();
  3048. m_terminalBool = w->terminalCheck->isChecked();
  3049. m_suidBool = w->suidCheck->isChecked();
  3050. m_suidUserStr = w->suidEdit->text().stripWhiteSpace();
  3051. m_startupBool = w->startupInfoCheck->isChecked();
  3052. m_systrayBool = w->systrayCheck->isChecked();
  3053. if (w->terminalCloseCheck->isChecked())
  3054. {
  3055. m_terminalOptionStr.append(" --noclose");
  3056. }
  3057. switch(w->dcopCombo->currentItem())
  3058. {
  3059. case 1: m_dcopServiceType = "multi"; break;
  3060. case 2: m_dcopServiceType = "unique"; break;
  3061. case 3: m_dcopServiceType = "wait"; break;
  3062. default: m_dcopServiceType = "none"; break;
  3063. }
  3064. }
  3065. }
  3066. bool KDesktopPropsPlugin::supports( KFileItemList _items )
  3067. {
  3068. if ( _items.count() != 1 )
  3069. return false;
  3070. KFileItem * item = _items.first();
  3071. // check if desktop file
  3072. if ( !KPropsDlgPlugin::isDesktopFile( item ) )
  3073. return false;
  3074. // open file and check type
  3075. KDesktopFile config( item->url().path(), true /* readonly */ );
  3076. return config.hasApplicationType() && kapp->authorize("run_desktop_files") && kapp->authorize("shell_access");
  3077. }
  3078. void KPropertiesDialog::virtual_hook( int id, void* data )
  3079. { KDialogBase::virtual_hook( id, data ); }
  3080. void KPropsDlgPlugin::virtual_hook( int, void* )
  3081. { /*BASE::virtual_hook( id, data );*/ }
  3082. /**
  3083. * The following code is obsolete and only kept for binary compatibility
  3084. * To be removed in KDE 4
  3085. */
  3086. class KExecPropsPlugin::KExecPropsPluginPrivate
  3087. {
  3088. public:
  3089. KExecPropsPluginPrivate()
  3090. {
  3091. }
  3092. ~KExecPropsPluginPrivate()
  3093. {
  3094. }
  3095. TQFrame *m_frame;
  3096. TQCheckBox *nocloseonexitCheck;
  3097. };
  3098. KExecPropsPlugin::KExecPropsPlugin( KPropertiesDialog *_props )
  3099. : KPropsDlgPlugin( _props )
  3100. {
  3101. d = new KExecPropsPluginPrivate;
  3102. d->m_frame = properties->addPage(i18n("E&xecute"));
  3103. TQVBoxLayout * mainlayout = new TQVBoxLayout( d->m_frame, 0,
  3104. KDialog::spacingHint());
  3105. // Now the widgets in the top layout
  3106. TQLabel* l;
  3107. l = new TQLabel( i18n( "Comman&d:" ), d->m_frame );
  3108. mainlayout->addWidget(l);
  3109. TQHBoxLayout * hlayout;
  3110. hlayout = new TQHBoxLayout(KDialog::spacingHint());
  3111. mainlayout->addLayout(hlayout);
  3112. execEdit = new KLineEdit( d->m_frame );
  3113. TQWhatsThis::add(execEdit,i18n(
  3114. "Following the command, you can have several place holders which will be replaced "
  3115. "with the actual values when the actual program is run:\n"
  3116. "%f - a single file name\n"
  3117. "%F - a list of files; use for applications that can open several local files at once\n"
  3118. "%u - a single URL\n"
  3119. "%U - a list of URLs\n"
  3120. "%d - the folder of the file to open\n"
  3121. "%D - a list of folders\n"
  3122. "%i - the icon\n"
  3123. "%m - the mini-icon\n"
  3124. "%c - the caption"));
  3125. hlayout->addWidget(execEdit, 1);
  3126. l->setBuddy( execEdit );
  3127. execBrowse = new TQPushButton( d->m_frame );
  3128. execBrowse->setText( i18n("&Browse...") );
  3129. hlayout->addWidget(execBrowse);
  3130. // The groupbox about swallowing
  3131. TQGroupBox* tmpQGroupBox;
  3132. tmpQGroupBox = new TQGroupBox( i18n("Panel Embedding"), d->m_frame );
  3133. tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
  3134. mainlayout->addWidget(tmpQGroupBox);
  3135. TQGridLayout *grid = new TQGridLayout(tmpQGroupBox->layout(), 2, 2);
  3136. grid->setSpacing( KDialog::spacingHint() );
  3137. grid->setColStretch(1, 1);
  3138. l = new TQLabel( i18n( "&Execute on click:" ), tmpQGroupBox );
  3139. grid->addWidget(l, 0, 0);
  3140. swallowExecEdit = new KLineEdit( tmpQGroupBox );
  3141. grid->addWidget(swallowExecEdit, 0, 1);
  3142. l->setBuddy( swallowExecEdit );
  3143. l = new TQLabel( i18n( "&Window title:" ), tmpQGroupBox );
  3144. grid->addWidget(l, 1, 0);
  3145. swallowTitleEdit = new KLineEdit( tmpQGroupBox );
  3146. grid->addWidget(swallowTitleEdit, 1, 1);
  3147. l->setBuddy( swallowTitleEdit );
  3148. // The groupbox about run in terminal
  3149. tmpQGroupBox = new TQGroupBox( d->m_frame );
  3150. tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
  3151. mainlayout->addWidget(tmpQGroupBox);
  3152. grid = new TQGridLayout(tmpQGroupBox->layout(), 3, 2);
  3153. grid->setSpacing( KDialog::spacingHint() );
  3154. grid->setColStretch(1, 1);
  3155. terminalCheck = new TQCheckBox( tmpQGroupBox );
  3156. terminalCheck->setText( i18n("&Run in terminal") );
  3157. grid->addMultiCellWidget(terminalCheck, 0, 0, 0, 1);
  3158. // check to see if we use konsole if not do not add the nocloseonexit
  3159. // because we don't know how to do this on other terminal applications
  3160. KConfigGroup confGroup( KGlobal::config(), TQString::fromLatin1("General") );
  3161. TQString preferredTerminal = confGroup.readPathEntry("TerminalApplication",
  3162. TQString::fromLatin1("konsole"));
  3163. int posOptions = 1;
  3164. d->nocloseonexitCheck = 0L;
  3165. if (preferredTerminal == "konsole")
  3166. {
  3167. posOptions = 2;
  3168. d->nocloseonexitCheck = new TQCheckBox( tmpQGroupBox );
  3169. d->nocloseonexitCheck->setText( i18n("Do not &close when command exits") );
  3170. grid->addMultiCellWidget(d->nocloseonexitCheck, 1, 1, 0, 1);
  3171. }
  3172. terminalLabel = new TQLabel( i18n( "&Terminal options:" ), tmpQGroupBox );
  3173. grid->addWidget(terminalLabel, posOptions, 0);
  3174. terminalEdit = new KLineEdit( tmpQGroupBox );
  3175. grid->addWidget(terminalEdit, posOptions, 1);
  3176. terminalLabel->setBuddy( terminalEdit );
  3177. // The groupbox about run with substituted uid.
  3178. tmpQGroupBox = new TQGroupBox( d->m_frame );
  3179. tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal );
  3180. mainlayout->addWidget(tmpQGroupBox);
  3181. grid = new TQGridLayout(tmpQGroupBox->layout(), 2, 2);
  3182. grid->setSpacing(KDialog::spacingHint());
  3183. grid->setColStretch(1, 1);
  3184. suidCheck = new TQCheckBox(tmpQGroupBox);
  3185. suidCheck->setText(i18n("Ru&n as a different user"));
  3186. grid->addMultiCellWidget(suidCheck, 0, 0, 0, 1);
  3187. suidLabel = new TQLabel(i18n( "&Username:" ), tmpQGroupBox);
  3188. grid->addWidget(suidLabel, 1, 0);
  3189. suidEdit = new KLineEdit(tmpQGroupBox);
  3190. grid->addWidget(suidEdit, 1, 1);
  3191. suidLabel->setBuddy( suidEdit );
  3192. mainlayout->addStretch(1);
  3193. // now populate the page
  3194. TQString path = _props->kurl().path();
  3195. TQFile f( path );
  3196. if ( !f.open( IO_ReadOnly ) )
  3197. return;
  3198. f.close();
  3199. KSimpleConfig config( path );
  3200. config.setDollarExpansion( false );
  3201. config.setDesktopGroup();
  3202. execStr = config.readPathEntry( "Exec" );
  3203. swallowExecStr = config.readPathEntry( "SwallowExec" );
  3204. swallowTitleStr = config.readEntry( "SwallowTitle" );
  3205. termBool = config.readBoolEntry( "Terminal" );
  3206. termOptionsStr = config.readEntry( "TerminalOptions" );
  3207. suidBool = config.readBoolEntry( "X-TDE-SubstituteUID" );
  3208. suidUserStr = config.readEntry( "X-TDE-Username" );
  3209. if ( !swallowExecStr.isNull() )
  3210. swallowExecEdit->setText( swallowExecStr );
  3211. if ( !swallowTitleStr.isNull() )
  3212. swallowTitleEdit->setText( swallowTitleStr );
  3213. if ( !execStr.isNull() )
  3214. execEdit->setText( execStr );
  3215. if ( d->nocloseonexitCheck )
  3216. {
  3217. d->nocloseonexitCheck->setChecked( (termOptionsStr.contains( "--noclose" ) > 0) );
  3218. termOptionsStr.replace( "--noclose", "");
  3219. }
  3220. if ( !termOptionsStr.isNull() )
  3221. terminalEdit->setText( termOptionsStr );
  3222. terminalCheck->setChecked( termBool );
  3223. enableCheckedEdit();
  3224. suidCheck->setChecked( suidBool );
  3225. suidEdit->setText( suidUserStr );
  3226. enableSuidEdit();
  3227. // Provide username completion up to 1000 users.
  3228. KCompletion *kcom = new KCompletion;
  3229. kcom->setOrder(KCompletion::Sorted);
  3230. struct passwd *pw;
  3231. int i, maxEntries = 1000;
  3232. setpwent();
  3233. for (i=0; ((pw = getpwent()) != 0L) && (i < maxEntries); i++)
  3234. kcom->addItem(TQString::fromLatin1(pw->pw_name));
  3235. endpwent();
  3236. if (i < maxEntries)
  3237. {
  3238. suidEdit->setCompletionObject(kcom, true);
  3239. suidEdit->setAutoDeleteCompletionObject( true );
  3240. suidEdit->setCompletionMode(KGlobalSettings::CompletionAuto);
  3241. }
  3242. else
  3243. {
  3244. delete kcom;
  3245. }
  3246. connect( swallowExecEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
  3247. this, TQT_SIGNAL( changed() ) );
  3248. connect( swallowTitleEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
  3249. this, TQT_SIGNAL( changed() ) );
  3250. connect( execEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
  3251. this, TQT_SIGNAL( changed() ) );
  3252. connect( terminalEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
  3253. this, TQT_SIGNAL( changed() ) );
  3254. if (d->nocloseonexitCheck)
  3255. connect( d->nocloseonexitCheck, TQT_SIGNAL( toggled( bool ) ),
  3256. this, TQT_SIGNAL( changed() ) );
  3257. connect( terminalCheck, TQT_SIGNAL( toggled( bool ) ),
  3258. this, TQT_SIGNAL( changed() ) );
  3259. connect( suidCheck, TQT_SIGNAL( toggled( bool ) ),
  3260. this, TQT_SIGNAL( changed() ) );
  3261. connect( suidEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
  3262. this, TQT_SIGNAL( changed() ) );
  3263. connect( execBrowse, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotBrowseExec() ) );
  3264. connect( terminalCheck, TQT_SIGNAL( clicked() ), this, TQT_SLOT( enableCheckedEdit() ) );
  3265. connect( suidCheck, TQT_SIGNAL( clicked() ), this, TQT_SLOT( enableSuidEdit() ) );
  3266. }
  3267. KExecPropsPlugin::~KExecPropsPlugin()
  3268. {
  3269. delete d;
  3270. }
  3271. void KExecPropsPlugin::enableCheckedEdit()
  3272. {
  3273. bool checked = terminalCheck->isChecked();
  3274. terminalLabel->setEnabled( checked );
  3275. if (d->nocloseonexitCheck)
  3276. d->nocloseonexitCheck->setEnabled( checked );
  3277. terminalEdit->setEnabled( checked );
  3278. }
  3279. void KExecPropsPlugin::enableSuidEdit()
  3280. {
  3281. bool checked = suidCheck->isChecked();
  3282. suidLabel->setEnabled( checked );
  3283. suidEdit->setEnabled( checked );
  3284. }
  3285. bool KExecPropsPlugin::supports( KFileItemList _items )
  3286. {
  3287. if ( _items.count() != 1 )
  3288. return false;
  3289. KFileItem * item = _items.first();
  3290. // check if desktop file
  3291. if ( !KPropsDlgPlugin::isDesktopFile( item ) )
  3292. return false;
  3293. // open file and check type
  3294. KDesktopFile config( item->url().path(), true /* readonly */ );
  3295. return config.hasApplicationType() && kapp->authorize("run_desktop_files") && kapp->authorize("shell_access");
  3296. }
  3297. void KExecPropsPlugin::applyChanges()
  3298. {
  3299. kdDebug(250) << "KExecPropsPlugin::applyChanges" << endl;
  3300. TQString path = properties->kurl().path();
  3301. TQFile f( path );
  3302. if ( !f.open( IO_ReadWrite ) ) {
  3303. KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
  3304. "sufficient access to write to <b>%1</b>.</qt>").arg(path));
  3305. return;
  3306. }
  3307. f.close();
  3308. KSimpleConfig config( path );
  3309. config.setDesktopGroup();
  3310. config.writeEntry( "Type", TQString::fromLatin1("Application"));
  3311. config.writePathEntry( "Exec", execEdit->text() );
  3312. config.writePathEntry( "SwallowExec", swallowExecEdit->text() );
  3313. config.writeEntry( "SwallowTitle", swallowTitleEdit->text() );
  3314. config.writeEntry( "Terminal", terminalCheck->isChecked() );
  3315. TQString temp = terminalEdit->text();
  3316. if (d->nocloseonexitCheck )
  3317. if ( d->nocloseonexitCheck->isChecked() )
  3318. temp += TQString::fromLatin1("--noclose ");
  3319. temp = temp.stripWhiteSpace();
  3320. config.writeEntry( "TerminalOptions", temp );
  3321. config.writeEntry( "X-TDE-SubstituteUID", suidCheck->isChecked() );
  3322. config.writeEntry( "X-TDE-Username", suidEdit->text() );
  3323. }
  3324. void KExecPropsPlugin::slotBrowseExec()
  3325. {
  3326. KURL f = KFileDialog::getOpenURL( TQString::null,
  3327. TQString::null, d->m_frame );
  3328. if ( f.isEmpty() )
  3329. return;
  3330. if ( !f.isLocalFile()) {
  3331. KMessageBox::sorry(d->m_frame, i18n("Only executables on local file systems are supported."));
  3332. return;
  3333. }
  3334. TQString path = f.path();
  3335. KRun::shellQuote( path );
  3336. execEdit->setText( path );
  3337. }
  3338. class KApplicationPropsPlugin::KApplicationPropsPluginPrivate
  3339. {
  3340. public:
  3341. KApplicationPropsPluginPrivate()
  3342. {
  3343. m_kdesktopMode = TQCString(tqApp->name()) == "kdesktop"; // nasty heh?
  3344. }
  3345. ~KApplicationPropsPluginPrivate()
  3346. {
  3347. }
  3348. TQFrame *m_frame;
  3349. bool m_kdesktopMode;
  3350. };
  3351. KApplicationPropsPlugin::KApplicationPropsPlugin( KPropertiesDialog *_props )
  3352. : KPropsDlgPlugin( _props )
  3353. {
  3354. d = new KApplicationPropsPluginPrivate;
  3355. d->m_frame = properties->addPage(i18n("&Application"));
  3356. TQVBoxLayout *toplayout = new TQVBoxLayout( d->m_frame, 0, KDialog::spacingHint());
  3357. TQIconSet iconSet;
  3358. TQPixmap pixMap;
  3359. addExtensionButton = new TQPushButton( TQString::null, d->m_frame );
  3360. iconSet = SmallIconSet( "back" );
  3361. addExtensionButton->setIconSet( iconSet );
  3362. pixMap = iconSet.pixmap( TQIconSet::Small, TQIconSet::Normal );
  3363. addExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
  3364. connect( addExtensionButton, TQT_SIGNAL( clicked() ),
  3365. TQT_SLOT( slotAddExtension() ) );
  3366. delExtensionButton = new TQPushButton( TQString::null, d->m_frame );
  3367. iconSet = SmallIconSet( "forward" );
  3368. delExtensionButton->setIconSet( iconSet );
  3369. delExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 );
  3370. connect( delExtensionButton, TQT_SIGNAL( clicked() ),
  3371. TQT_SLOT( slotDelExtension() ) );
  3372. TQLabel *l;
  3373. TQGridLayout *grid = new TQGridLayout(2, 2);
  3374. grid->setColStretch(1, 1);
  3375. toplayout->addLayout(TQT_TQLAYOUT(grid));
  3376. if ( d->m_kdesktopMode )
  3377. {
  3378. // in kdesktop the name field comes from the first tab
  3379. nameEdit = 0L;
  3380. }
  3381. else
  3382. {
  3383. l = new TQLabel(i18n("Name:"), d->m_frame, "Label_4" );
  3384. grid->addWidget(l, 0, 0);
  3385. nameEdit = new KLineEdit( d->m_frame, "LineEdit_3" );
  3386. grid->addWidget(nameEdit, 0, 1);
  3387. }
  3388. l = new TQLabel(i18n("Description:"), d->m_frame, "Label_5" );
  3389. grid->addWidget(l, 1, 0);
  3390. genNameEdit = new KLineEdit( d->m_frame, "LineEdit_4" );
  3391. grid->addWidget(genNameEdit, 1, 1);
  3392. l = new TQLabel(i18n("Comment:"), d->m_frame, "Label_3" );
  3393. grid->addWidget(l, 2, 0);
  3394. commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" );
  3395. grid->addWidget(commentEdit, 2, 1);
  3396. l = new TQLabel(i18n("File types:"), d->m_frame);
  3397. toplayout->addWidget(l, 0, AlignLeft);
  3398. grid = new TQGridLayout(4, 3);
  3399. grid->setColStretch(0, 1);
  3400. grid->setColStretch(2, 1);
  3401. grid->setRowStretch( 0, 1 );
  3402. grid->setRowStretch( 3, 1 );
  3403. toplayout->addLayout(TQT_TQLAYOUT(grid), 2);
  3404. extensionsList = new TQListBox( d->m_frame );
  3405. extensionsList->setSelectionMode( TQListBox::Extended );
  3406. grid->addMultiCellWidget(extensionsList, 0, 3, 0, 0);
  3407. grid->addWidget(addExtensionButton, 1, 1);
  3408. grid->addWidget(delExtensionButton, 2, 1);
  3409. availableExtensionsList = new TQListBox( d->m_frame );
  3410. availableExtensionsList->setSelectionMode( TQListBox::Extended );
  3411. grid->addMultiCellWidget(availableExtensionsList, 0, 3, 2, 2);
  3412. TQString path = properties->kurl().path() ;
  3413. TQFile f( path );
  3414. if ( !f.open( IO_ReadOnly ) )
  3415. return;
  3416. f.close();
  3417. KDesktopFile config( path );
  3418. TQString commentStr = config.readComment();
  3419. TQString genNameStr = config.readGenericName();
  3420. TQStringList selectedTypes = config.readListEntry( "ServiceTypes" );
  3421. // For compatibility with KDE 1.x
  3422. selectedTypes += config.readListEntry( "MimeType", ';' );
  3423. TQString nameStr = config.readName();
  3424. if ( nameStr.isEmpty() || d->m_kdesktopMode ) {
  3425. // We'll use the file name if no name is specified
  3426. // because we _need_ a Name for a valid file.
  3427. // But let's do it in apply, not here, so that we pick up the right name.
  3428. setDirty();
  3429. }
  3430. commentEdit->setText( commentStr );
  3431. genNameEdit->setText( genNameStr );
  3432. if ( nameEdit )
  3433. nameEdit->setText( nameStr );
  3434. selectedTypes.sort();
  3435. TQStringList::Iterator sit = selectedTypes.begin();
  3436. for( ; sit != selectedTypes.end(); ++sit ) {
  3437. if ( !((*sit).isEmpty()) )
  3438. extensionsList->insertItem( *sit );
  3439. }
  3440. KMimeType::List mimeTypes = KMimeType::allMimeTypes();
  3441. TQValueListIterator<KMimeType::Ptr> it2 = mimeTypes.begin();
  3442. for ( ; it2 != mimeTypes.end(); ++it2 )
  3443. addMimeType ( (*it2)->name() );
  3444. updateButton();
  3445. connect( extensionsList, TQT_SIGNAL( highlighted( int ) ),
  3446. this, TQT_SLOT( updateButton() ) );
  3447. connect( availableExtensionsList, TQT_SIGNAL( highlighted( int ) ),
  3448. this, TQT_SLOT( updateButton() ) );
  3449. connect( addExtensionButton, TQT_SIGNAL( clicked() ),
  3450. this, TQT_SIGNAL( changed() ) );
  3451. connect( delExtensionButton, TQT_SIGNAL( clicked() ),
  3452. this, TQT_SIGNAL( changed() ) );
  3453. if ( nameEdit )
  3454. connect( nameEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
  3455. this, TQT_SIGNAL( changed() ) );
  3456. connect( commentEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
  3457. this, TQT_SIGNAL( changed() ) );
  3458. connect( genNameEdit, TQT_SIGNAL( textChanged( const TQString & ) ),
  3459. this, TQT_SIGNAL( changed() ) );
  3460. connect( availableExtensionsList, TQT_SIGNAL( selected( int ) ),
  3461. this, TQT_SIGNAL( changed() ) );
  3462. connect( extensionsList, TQT_SIGNAL( selected( int ) ),
  3463. this, TQT_SIGNAL( changed() ) );
  3464. }
  3465. KApplicationPropsPlugin::~KApplicationPropsPlugin()
  3466. {
  3467. delete d;
  3468. }
  3469. // TQString KApplicationPropsPlugin::tabName () const
  3470. // {
  3471. // return i18n ("&Application");
  3472. // }
  3473. void KApplicationPropsPlugin::updateButton()
  3474. {
  3475. addExtensionButton->setEnabled(availableExtensionsList->currentItem()>-1);
  3476. delExtensionButton->setEnabled(extensionsList->currentItem()>-1);
  3477. }
  3478. void KApplicationPropsPlugin::addMimeType( const TQString & name )
  3479. {
  3480. // Add a mimetype to the list of available mime types if not in the extensionsList
  3481. bool insert = true;
  3482. for ( uint i = 0; i < extensionsList->count(); i++ )
  3483. if ( extensionsList->text( i ) == name )
  3484. insert = false;
  3485. if ( insert )
  3486. {
  3487. availableExtensionsList->insertItem( name );
  3488. availableExtensionsList->sort();
  3489. }
  3490. }
  3491. bool KApplicationPropsPlugin::supports( KFileItemList _items )
  3492. {
  3493. // same constraints as KExecPropsPlugin : desktop file with Type = Application
  3494. return KExecPropsPlugin::supports( _items );
  3495. }
  3496. void KApplicationPropsPlugin::applyChanges()
  3497. {
  3498. TQString path = properties->kurl().path();
  3499. TQFile f( path );
  3500. if ( !f.open( IO_ReadWrite ) ) {
  3501. KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not "
  3502. "have sufficient access to write to <b>%1</b>.</qt>").arg(path));
  3503. return;
  3504. }
  3505. f.close();
  3506. KSimpleConfig config( path );
  3507. config.setDesktopGroup();
  3508. config.writeEntry( "Type", TQString::fromLatin1("Application"));
  3509. config.writeEntry( "Comment", commentEdit->text() );
  3510. config.writeEntry( "Comment", commentEdit->text(), true, false, true ); // for compat
  3511. config.writeEntry( "GenericName", genNameEdit->text() );
  3512. config.writeEntry( "GenericName", genNameEdit->text(), true, false, true ); // for compat
  3513. TQStringList selectedTypes;
  3514. for ( uint i = 0; i < extensionsList->count(); i++ )
  3515. selectedTypes.append( extensionsList->text( i ) );
  3516. config.writeEntry( "MimeType", selectedTypes, ';' );
  3517. config.writeEntry( "ServiceTypes", "" );
  3518. // hmm, actually it should probably be the contrary (but see also typeslistitem.cpp)
  3519. TQString nameStr = nameEdit ? nameEdit->text() : TQString::null;
  3520. if ( nameStr.isEmpty() ) // nothing entered, or widget not existing at all (kdesktop mode)
  3521. nameStr = nameFromFileName(properties->kurl().fileName());
  3522. config.writeEntry( "Name", nameStr );
  3523. config.writeEntry( "Name", nameStr, true, false, true );
  3524. config.sync();
  3525. }
  3526. void KApplicationPropsPlugin::slotAddExtension()
  3527. {
  3528. TQListBoxItem *item = availableExtensionsList->firstItem();
  3529. TQListBoxItem *nextItem;
  3530. while ( item )
  3531. {
  3532. nextItem = item->next();
  3533. if ( item->isSelected() )
  3534. {
  3535. extensionsList->insertItem( item->text() );
  3536. availableExtensionsList->removeItem( availableExtensionsList->index( item ) );
  3537. }
  3538. item = nextItem;
  3539. }
  3540. extensionsList->sort();
  3541. updateButton();
  3542. }
  3543. void KApplicationPropsPlugin::slotDelExtension()
  3544. {
  3545. TQListBoxItem *item = extensionsList->firstItem();
  3546. TQListBoxItem *nextItem;
  3547. while ( item )
  3548. {
  3549. nextItem = item->next();
  3550. if ( item->isSelected() )
  3551. {
  3552. availableExtensionsList->insertItem( item->text() );
  3553. extensionsList->removeItem( extensionsList->index( item ) );
  3554. }
  3555. item = nextItem;
  3556. }
  3557. availableExtensionsList->sort();
  3558. updateButton();
  3559. }
  3560. #include "kpropertiesdialog.moc"