• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kio/kfile
 

kio/kfile

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

kio/kfile

Skip menu "kio/kfile"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kio/kfile

Skip menu "kio/kfile"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kio/kfile by doxygen 1.8.3.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |