1 /* This file is part of the KDE project
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>
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.
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.
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.
26 * kpropertiesdialog.cpp
27 * View/Edit Properties of files, locally or remotely
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,
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 KDialog by
39 * Simon Hausmann <hausmann@kde.org>
40 * KDesktopPropsPlugin by
41 * Waldo Bastian <bastian@kde.org>
44 #include "kpropertiesdialog.h"
45 #include "kpropertiesdialog_p.h"
49 #include <config-acl.h>
55 #include <sys/types.h>
63 #include <QtCore/QFile>
64 #include <QtCore/QDir>
65 #include <QtGui/QLabel>
66 #include <QtGui/QPushButton>
67 #include <QtGui/QCheckBox>
68 #include <QtCore/QMutableStringListIterator>
69 #include <QtCore/QTextIStream>
70 #include <QtGui/QPainter>
71 #include <QtGui/QLayout>
72 #include <QtGui/QStyle>
73 #include <QtGui/QProgressBar>
78 # include <sys/xattr.h>
82 #include <kauthorized.h>
84 #include <kdirwatch.h>
85 #include <kdirnotify.h>
86 #include <kdiskfreespaceinfo.h>
88 #include <kdesktopfile.h>
89 #include <kicondialog.h>
91 #include <kurlrequester.h>
94 #include <kglobalsettings.h>
95 #include <kstandarddirs.h>
96 #include <kjobuidelegate.h>
98 #include <kio/copyjob.h>
99 #include <kio/chmodjob.h>
100 #include <kio/directorysizejob.h>
101 #include <kio/renamedialog.h>
102 #include <kio/netaccess.h>
103 #include <kio/jobuidelegate.h>
104 #include <kfiledialog.h>
105 #include <kmimetype.h>
106 #include <kmountpoint.h>
107 #include <kiconloader.h>
108 #include <kmessagebox.h>
109 #include <kservice.h>
110 #include <kcombobox.h>
111 #include <kcompletion.h>
112 #include <klineedit.h>
113 #include <kseparator.h>
114 #include <ksqueezedtextlabel.h>
115 #include <klibloader.h>
116 #include <kmimetypetrader.h>
117 #include <kmetaprops.h>
118 #include <kpreviewprops.h>
122 #include <kconfiggroup.h>
124 #include <kcapacitybar.h>
126 #include "kfilesharedialog.h"
129 #include "ui_kpropertiesdesktopbase.h"
130 #include "ui_kpropertiesdesktopadvbase.h"
131 #ifdef HAVE_POSIX_ACL
132 #include "kacleditwidget.h"
135 #include <kbuildsycocaprogressdialog.h>
136 #include <kmimetypechooser.h>
139 # include <kkernel_win.h>
141 # warning TODO: port completely to win32
145 using namespace KDEPrivate
;
147 static QString
nameFromFileName(QString nameStr
)
149 if ( nameStr
.endsWith(".desktop") )
150 nameStr
.truncate( nameStr
.length() - 8 );
151 if ( nameStr
.endsWith(".kdelnk") )
152 nameStr
.truncate( nameStr
.length() - 7 );
153 // Make it human-readable (%2F => '/', ...)
154 nameStr
= KIO::decodeFileName( nameStr
);
158 mode_t
KFilePermissionsPropsPlugin::fperm
[3][4] = {
159 {S_IRUSR
, S_IWUSR
, S_IXUSR
, S_ISUID
},
160 {S_IRGRP
, S_IWGRP
, S_IXGRP
, S_ISGID
},
161 {S_IROTH
, S_IWOTH
, S_IXOTH
, S_ISVTX
}
164 class KPropertiesDialog::KPropertiesDialogPrivate
167 KPropertiesDialogPrivate(KPropertiesDialog
*qq
)
173 ~KPropertiesDialogPrivate()
178 * Common initialization for all constructors
182 * Inserts all pages in the dialog.
186 KPropertiesDialog
*q
;
188 QWidget
* fileSharePage
;
190 * The URL of the props dialog (when shown for only one file)
194 * List of items this props dialog is shown for
196 KFileItemList m_items
;
200 QString m_defaultName
;
203 * List of all plugins inserted ( first one first )
205 QList
<KPropertiesDialogPlugin
*> m_pageList
;
208 KPropertiesDialog::KPropertiesDialog (const KFileItem
& item
,
210 : KPageDialog(parent
), d(new KPropertiesDialogPrivate(this))
212 setCaption( i18n( "Properties for %1" , KIO::decodeFileName(item
.url().fileName())) );
214 assert( !item
.isNull() );
215 d
->m_items
.append(item
);
217 d
->m_singleUrl
= item
.url();
218 assert(!d
->m_singleUrl
.isEmpty());
223 KPropertiesDialog::KPropertiesDialog (const QString
& title
,
225 : KPageDialog(parent
), d(new KPropertiesDialogPrivate(this))
227 setCaption( i18n( "Properties for %1", title
) );
232 KPropertiesDialog::KPropertiesDialog(const KFileItemList
& _items
,
234 : KPageDialog(parent
), d(new KPropertiesDialogPrivate(this))
236 if ( _items
.count() > 1 )
237 setCaption( i18np( "Properties for 1 item", "Properties for %1 Selected Items", _items
.count() ) );
239 setCaption( i18n( "Properties for %1" , KIO::decodeFileName(_items
.first().url().fileName())) );
241 assert( !_items
.isEmpty() );
242 d
->m_singleUrl
= _items
.first().url();
243 assert(!d
->m_singleUrl
.isEmpty());
250 KPropertiesDialog::KPropertiesDialog (const KUrl
& _url
,
252 : KPageDialog(parent
), d(new KPropertiesDialogPrivate(this))
254 setCaption( i18n( "Properties for %1" , KIO::decodeFileName(_url
.fileName())) );
256 d
->m_singleUrl
= _url
;
259 KIO::NetAccess::stat(_url
, entry
, parent
);
261 d
->m_items
.append(KFileItem(entry
, _url
));
265 KPropertiesDialog::KPropertiesDialog (const KUrl
& _tempUrl
, const KUrl
& _currentDir
,
266 const QString
& _defaultName
,
268 : KPageDialog(parent
), d(new KPropertiesDialogPrivate(this))
270 setCaption( i18n( "Properties for %1" , KIO::decodeFileName(_tempUrl
.fileName())) );
272 d
->m_singleUrl
= _tempUrl
;
273 d
->m_defaultName
= _defaultName
;
274 d
->m_currentDir
= _currentDir
;
275 assert(!d
->m_singleUrl
.isEmpty());
277 // Create the KFileItem for the _template_ file, in order to read from it.
278 d
->m_items
.append(KFileItem(KFileItem::Unknown
, KFileItem::Unknown
, d
->m_singleUrl
));
282 bool KPropertiesDialog::showDialog(const KFileItem
& item
, QWidget
* parent
,
285 // TODO: do we really want to show the win32 property dialog?
286 // This means we lose metainfo, support for .desktop files, etc. (DF)
288 QString localPath
= item
.localPath();
289 if (!localPath
.isEmpty())
290 return showWin32FilePropertyDialog(localPath
);
292 KPropertiesDialog
* dlg
= new KPropertiesDialog(item
, parent
);
302 bool KPropertiesDialog::showDialog(const KUrl
& _url
, QWidget
* parent
,
306 if (_url
.isLocalFile())
307 return showWin32FilePropertyDialog( _url
.toLocalFile() );
309 KPropertiesDialog
* dlg
= new KPropertiesDialog(_url
, parent
);
319 bool KPropertiesDialog::showDialog(const KFileItemList
& _items
, QWidget
* parent
,
322 if (_items
.count()==1) {
323 const KFileItem item
= _items
.first();
324 if (item
.entry().count() == 0 && item
.localPath().isEmpty()) // this remote item wasn't listed by a slave
325 // Let's stat to get more info on the file
326 return KPropertiesDialog::showDialog(item
.url(), parent
, modal
);
328 return KPropertiesDialog::showDialog(_items
.first(), parent
, modal
);
330 KPropertiesDialog
* dlg
= new KPropertiesDialog(_items
, parent
);
339 void KPropertiesDialog::KPropertiesDialogPrivate::init()
341 q
->setFaceType(KPageDialog::Tabbed
);
342 q
->setButtons(KDialog::Ok
| KDialog::Cancel
);
343 q
->setDefaultButton(KDialog::Ok
);
345 connect(q
, SIGNAL(okClicked()), q
, SLOT(slotOk()));
346 connect(q
, SIGNAL(cancelClicked()), q
, SLOT(slotCancel()));
350 KConfigGroup
group(KGlobal::config(), "KPropertiesDialog");
351 q
->restoreDialogSize(group
);
354 void KPropertiesDialog::showFileSharingPage()
356 if (d
->fileSharePage
) {
357 // FIXME: this showFileSharingPage thingy looks broken! (tokoe)
358 // showPage( pageIndex( d->fileSharePage));
362 void KPropertiesDialog::setFileSharingPage(QWidget
* page
) {
363 d
->fileSharePage
= page
;
367 void KPropertiesDialog::setFileNameReadOnly( bool ro
)
369 foreach(KPropertiesDialogPlugin
*it
, d
->m_pageList
) {
370 KFilePropsPlugin
* plugin
= dynamic_cast<KFilePropsPlugin
*>(it
);
372 plugin
->setFileNameReadOnly( ro
);
378 KPropertiesDialog::~KPropertiesDialog()
380 qDeleteAll(d
->m_pageList
);
383 KConfigGroup
group(KGlobal::config(), "KPropertiesDialog");
384 saveDialogSize(group
, KConfigBase::Persistent
);
387 void KPropertiesDialog::insertPlugin (KPropertiesDialogPlugin
* plugin
)
389 connect (plugin
, SIGNAL (changed ()),
390 plugin
, SLOT (setDirty ()));
392 d
->m_pageList
.append(plugin
);
395 KUrl
KPropertiesDialog::kurl() const
397 return d
->m_singleUrl
;
400 KFileItem
& KPropertiesDialog::item()
402 return d
->m_items
.first();
405 KFileItemList
KPropertiesDialog::items() const
410 KUrl
KPropertiesDialog::currentDir() const
412 return d
->m_currentDir
;
415 QString
KPropertiesDialog::defaultName() const
417 return d
->m_defaultName
;
420 bool KPropertiesDialog::canDisplay( const KFileItemList
& _items
)
422 // TODO: cache the result of those calls. Currently we parse .desktop files far too many times
423 return KFilePropsPlugin::supports( _items
) ||
424 KFilePermissionsPropsPlugin::supports( _items
) ||
425 KDesktopPropsPlugin::supports( _items
) ||
426 KUrlPropsPlugin::supports( _items
) ||
427 KDevicePropsPlugin::supports( _items
) ||
428 KFileMetaPropsPlugin::supports( _items
) ||
429 KPreviewPropsPlugin::supports( _items
);
432 void KPropertiesDialog::slotOk()
434 QList
<KPropertiesDialogPlugin
*>::const_iterator pageListIt
;
435 d
->m_aborted
= false;
437 KFilePropsPlugin
* filePropsPlugin
= 0L;
438 if (qobject_cast
<KFilePropsPlugin
*>(d
->m_pageList
.first()))
439 filePropsPlugin
= static_cast<KFilePropsPlugin
*>(d
->m_pageList
.first());
441 // If any page is dirty, then set the main one (KFilePropsPlugin) as
442 // dirty too. This is what makes it possible to save changes to a global
443 // desktop file into a local one. In other cases, it doesn't hurt.
444 for (pageListIt
= d
->m_pageList
.constBegin(); pageListIt
!= d
->m_pageList
.constEnd(); ++pageListIt
) {
445 if ( (*pageListIt
)->isDirty() && filePropsPlugin
)
447 filePropsPlugin
->setDirty();
452 // Apply the changes in the _normal_ order of the tabs now
453 // This is because in case of renaming a file, KFilePropsPlugin will call
454 // KPropertiesDialog::rename, so other tab will be ok with whatever order
455 // BUT for file copied from templates, we need to do the renaming first !
456 for (pageListIt
= d
->m_pageList
.constBegin(); pageListIt
!= d
->m_pageList
.constEnd() && !d
->m_aborted
; ++pageListIt
) {
457 if ( (*pageListIt
)->isDirty() )
459 kDebug( 250 ) << "applying changes for " << (*pageListIt
)->metaObject()->className();
460 (*pageListIt
)->applyChanges();
461 // applyChanges may change d->m_aborted.
464 kDebug( 250 ) << "skipping page " << (*pageListIt
)->metaObject()->className();
468 if ( !d
->m_aborted
&& filePropsPlugin
)
469 filePropsPlugin
->postApplyChanges();
474 emit
propertiesClosed();
475 deleteLater(); // somewhat like Qt::WA_DeleteOnClose would do.
477 } // else, keep dialog open for user to fix the problem.
480 void KPropertiesDialog::slotCancel()
483 emit
propertiesClosed();
489 void KPropertiesDialog::KPropertiesDialogPrivate::insertPages()
491 if (m_items
.isEmpty())
494 if ( KFilePropsPlugin::supports( m_items
) )
496 KPropertiesDialogPlugin
*p
= new KFilePropsPlugin(q
);
500 if ( KFilePermissionsPropsPlugin::supports( m_items
) )
502 KPropertiesDialogPlugin
*p
= new KFilePermissionsPropsPlugin(q
);
506 if ( KDesktopPropsPlugin::supports( m_items
) )
508 KPropertiesDialogPlugin
*p
= new KDesktopPropsPlugin(q
);
512 if ( KUrlPropsPlugin::supports( m_items
) )
514 KPropertiesDialogPlugin
*p
= new KUrlPropsPlugin(q
);
518 if ( KDevicePropsPlugin::supports( m_items
) )
520 KPropertiesDialogPlugin
*p
= new KDevicePropsPlugin(q
);
524 if ( KFileMetaPropsPlugin::supports( m_items
) )
526 KPropertiesDialogPlugin
*p
= new KFileMetaPropsPlugin(q
);
530 if ( KPreviewPropsPlugin::supports( m_items
) )
532 KPropertiesDialogPlugin
*p
= new KPreviewPropsPlugin(q
);
537 if ( KAuthorized::authorizeKAction("sharefile") &&
538 KFileSharePropsPlugin::supports( m_items
) )
540 KPropertiesDialogPlugin
*p
= new KFileSharePropsPlugin(q
);
547 if ( m_items
.count() != 1 )
550 const KFileItem item
= m_items
.first();
551 const QString mimetype
= item
.mimetype();
553 if ( mimetype
.isEmpty() )
556 QString query
= QString::fromLatin1(
557 "((not exist [X-KDE-Protocol]) or "
558 " ([X-KDE-Protocol] == '%1' ) )"
559 ).arg(item
.url().protocol());
561 kDebug( 250 ) << "trader query: " << query
;
562 KService::List offers
= KMimeTypeTrader::self()->query( mimetype
, "KPropertiesDialog/Plugin", query
);
563 foreach (const KService::Ptr
&ptr
, offers
) {
564 KPropertiesDialogPlugin
*plugin
= ptr
->createInstance
<KPropertiesDialogPlugin
>(q
);
567 plugin
->setObjectName(ptr
->name());
569 q
->insertPlugin(plugin
);
573 void KPropertiesDialog::updateUrl( const KUrl
& _newUrl
)
575 Q_ASSERT(d
->m_items
.count() == 1);
576 kDebug(250) << "KPropertiesDialog::updateUrl (pre)" << _newUrl
.url();
577 KUrl newUrl
= _newUrl
;
578 emit
saveAs(d
->m_singleUrl
, newUrl
);
579 kDebug(250) << "KPropertiesDialog::updateUrl (post)" << newUrl
.url();
581 d
->m_singleUrl
= newUrl
;
582 d
->m_items
.first().setUrl(newUrl
);
583 assert(!d
->m_singleUrl
.isEmpty());
584 // If we have an Desktop page, set it dirty, so that a full file is saved locally
585 // Same for a URL page (because of the Name= hack)
586 foreach (KPropertiesDialogPlugin
*it
, d
->m_pageList
) {
587 if ( qobject_cast
<KUrlPropsPlugin
*>(it
) ||
588 qobject_cast
<KDesktopPropsPlugin
*>(it
) )
590 //kDebug(250) << "Setting page dirty";
597 void KPropertiesDialog::rename( const QString
& _name
)
599 Q_ASSERT(d
->m_items
.count() == 1);
600 kDebug(250) << "KPropertiesDialog::rename " << _name
;
602 // if we're creating from a template : use currentdir
603 if (!d
->m_currentDir
.isEmpty()) {
604 newUrl
= d
->m_currentDir
;
605 newUrl
.addPath(_name
);
607 QString tmpurl
= d
->m_singleUrl
.url();
608 if (!tmpurl
.isEmpty() && tmpurl
.at(tmpurl
.length() - 1) == '/') {
609 // It's a directory, so strip the trailing slash first
610 tmpurl
.truncate(tmpurl
.length() - 1);
614 newUrl
.setFileName(_name
);
619 void KPropertiesDialog::abortApplying()
624 class KPropertiesDialogPlugin::KPropertiesDialogPluginPrivate
627 KPropertiesDialogPluginPrivate()
630 ~KPropertiesDialogPluginPrivate()
638 KPropertiesDialogPlugin::KPropertiesDialogPlugin( KPropertiesDialog
*_props
)
639 : QObject( _props
),d(new KPropertiesDialogPluginPrivate
)
642 d
->fontHeight
= 2*properties
->fontMetrics().height();
646 KPropertiesDialogPlugin::~KPropertiesDialogPlugin()
651 bool KPropertiesDialogPlugin::isDesktopFile( const KFileItem
& _item
)
653 return _item
.isDesktopFile();
656 void KPropertiesDialogPlugin::setDirty( bool b
)
661 void KPropertiesDialogPlugin::setDirty()
666 bool KPropertiesDialogPlugin::isDirty() const
671 void KPropertiesDialogPlugin::applyChanges()
673 kWarning(250) << "applyChanges() not implemented in page !";
676 int KPropertiesDialogPlugin::fontHeight() const
678 return d
->fontHeight
;
681 ///////////////////////////////////////////////////////////////////////////////
683 class KFilePropsPlugin::KFilePropsPluginPrivate
686 KFilePropsPluginPrivate()
689 dirSizeUpdateTimer
= 0L;
692 m_linkTargetLineEdit
= 0;
694 ~KFilePropsPluginPrivate()
700 KIO::DirectorySizeJob
* dirSizeJob
;
701 QTimer
*dirSizeUpdateTimer
;
707 KCapacityBar
*m_capacityBar
;
716 QPushButton
*m_sizeDetermineButton
;
717 QPushButton
*m_sizeStopButton
;
718 KLineEdit
* m_linkTargetLineEdit
;
720 QString m_sRelativePath
;
721 bool m_bFromTemplate
;
724 * The initial filename
729 KFilePropsPlugin::KFilePropsPlugin( KPropertiesDialog
*_props
)
730 : KPropertiesDialogPlugin( _props
),d(new KFilePropsPluginPrivate
)
732 d
->bMultiple
= (properties
->items().count() > 1);
733 d
->bIconChanged
= false;
734 d
->bKDesktopMode
= (qApp
->objectName() == "kdesktop");
735 d
->bDesktopFile
= KDesktopPropsPlugin::supports(properties
->items());
736 kDebug(250) << "KFilePropsPlugin::KFilePropsPlugin bMultiple=" << d
->bMultiple
;
738 // We set this data from the first item, and we'll
739 // check that the other items match against it, resetting when not.
741 const KFileItem item
= properties
->item();
742 KUrl url
= item
.mostLocalUrl( isLocal
);
743 bool isReallyLocal
= item
.url().isLocalFile();
744 bool bDesktopFile
= item
.isDesktopFile();
745 mode_t mode
= item
.mode();
746 bool hasDirs
= item
.isDir() && !item
.isLink();
747 bool hasRoot
= url
.path() == QLatin1String("/");
748 QString iconStr
= KMimeType::iconNameForUrl(url
, mode
);
749 QString directory
= properties
->kurl().directory();
750 QString protocol
= properties
->kurl().protocol();
751 QString mimeComment
= item
.mimeComment();
752 d
->mimeType
= item
.mimetype();
753 KIO::filesize_t totalSize
= item
.size();
754 QString magicMimeComment
;
756 KMimeType::Ptr magicMimeType
= KMimeType::findByFileContent( url
.path() );
757 if ( magicMimeType
->name() != KMimeType::defaultMimeType() )
758 magicMimeComment
= magicMimeType
->comment();
761 if ( isReallyLocal
) {
762 directory
= QDir::toNativeSeparators( directory
.mid( 1 ) );
766 // Those things only apply to 'single file' mode
768 bool isTrash
= false;
769 bool isDevice
= false;
770 d
->m_bFromTemplate
= false;
772 // And those only to 'multiple' mode
773 uint iDirCount
= hasDirs
? 1 : 0;
774 uint iFileCount
= 1-iDirCount
;
776 d
->m_frame
= new QFrame();
777 properties
->addPage(d
->m_frame
, i18nc("@title:tab File properties", "&General"));
779 QVBoxLayout
*vbl
= new QVBoxLayout( d
->m_frame
);
781 vbl
->setSpacing( KDialog::spacingHint() );
782 vbl
->setObjectName( QLatin1String( "vbl" ) );
783 QGridLayout
*grid
= new QGridLayout(); // unknown rows
784 grid
->setColumnStretch(0, 0);
785 grid
->setColumnStretch(1, 0);
786 grid
->setColumnStretch(2, 1);
787 grid
->addItem(new QSpacerItem(KDialog::spacingHint(),0), 0, 1);
788 vbl
->addLayout(grid
);
794 if ( !d
->m_bFromTemplate
) {
795 isTrash
= ( properties
->kurl().protocol().toLower() == "trash" );
796 isDevice
= ( properties
->kurl().protocol().toLower() == "device" );
797 // Extract the full name, but without file: for local files
799 path
= properties
->kurl().toLocalFile();
801 path
= properties
->kurl().prettyUrl();
803 path
= properties
->currentDir().path(KUrl::AddTrailingSlash
) + properties
->defaultName();
804 directory
= properties
->currentDir().prettyUrl();
807 if (d
->bDesktopFile
) {
808 determineRelativePath( path
);
811 // Extract the file name only
812 filename
= properties
->defaultName();
813 if ( filename
.isEmpty() ) { // no template
814 filename
= item
.name(); // this gives support for UDS_NAME, e.g. for kio_trash or kio_system
816 d
->m_bFromTemplate
= true;
817 setDirty(); // to enforce that the copy happens
819 d
->oldFileName
= filename
;
821 // Make it human-readable
822 filename
= nameFromFileName( filename
);
824 if ( d
->bKDesktopMode
&& d
->bDesktopFile
) {
825 KDesktopFile
config( url
.path() );
826 if ( config
.desktopGroup().hasKey( "Name" ) ) {
827 filename
= config
.readName();
831 d
->oldName
= filename
;
835 // Multiple items: see what they have in common
836 const KFileItemList items
= properties
->items();
837 KFileItemList::const_iterator kit
= items
.begin();
838 const KFileItemList::const_iterator kend
= items
.end();
839 for ( ++kit
/*no need to check the first one again*/ ; kit
!= kend
; ++kit
)
841 const KUrl url
= (*kit
).url();
842 kDebug(250) << "KFilePropsPlugin::KFilePropsPlugin " << url
.prettyUrl();
843 // The list of things we check here should match the variables defined
844 // at the beginning of this method.
845 if ( url
.isLocalFile() != isLocal
)
846 isLocal
= false; // not all local
847 if ( bDesktopFile
&& (*kit
).isDesktopFile() != bDesktopFile
)
848 bDesktopFile
= false; // not all desktop files
849 if ( (*kit
).mode() != mode
)
851 if ( KMimeType::iconNameForUrl(url
, mode
) != iconStr
)
852 iconStr
= "document-multiple";
853 if ( url
.directory() != directory
)
855 if ( url
.protocol() != protocol
)
857 if ( !mimeComment
.isNull() && (*kit
).mimeComment() != mimeComment
)
859 if ( isLocal
&& !magicMimeComment
.isNull() ) {
860 KMimeType::Ptr magicMimeType
= KMimeType::findByFileContent( url
.path() );
861 if ( magicMimeType
->comment() != magicMimeComment
)
862 magicMimeComment
.clear();
865 if ( isLocal
&& url
.path() == QLatin1String("/") )
867 if ( (*kit
).isDir() && !(*kit
).isLink() )
875 totalSize
+= (*kit
).size();
880 if (!isReallyLocal
&& !protocol
.isEmpty())
884 directory
+= protocol
;
888 if ( !isDevice
&& !isTrash
&& (bDesktopFile
|| S_ISDIR(mode
)) && !d
->bMultiple
/*not implemented for multiple*/ )
890 KIconButton
*iconButton
= new KIconButton( d
->m_frame
);
891 int bsize
= 66 + 2 * iconButton
->style()->pixelMetric(QStyle::PM_ButtonMargin
);
892 iconButton
->setFixedSize(bsize
, bsize
);
893 iconButton
->setIconSize(48);
894 iconButton
->setStrictIconSize(false);
895 // This works for everything except Device icons on unmounted devices
896 // So we have to really open .desktop files
897 QString iconStr
= KMimeType::findByUrl( url
, mode
)->iconName( url
);
898 if ( bDesktopFile
&& isLocal
)
900 KDesktopFile
config( url
.path() );
901 KConfigGroup group
= config
.desktopGroup();
902 iconStr
= group
.readEntry( "Icon" );
903 if ( config
.hasDeviceType() )
904 iconButton
->setIconType( KIconLoader::Desktop
, KIconLoader::Device
);
906 iconButton
->setIconType( KIconLoader::Desktop
, KIconLoader::Application
);
908 iconButton
->setIconType( KIconLoader::Desktop
, KIconLoader::Place
);
909 iconButton
->setIcon(iconStr
);
910 d
->iconArea
= iconButton
;
911 connect( iconButton
, SIGNAL( iconChanged(const QString
&) ),
912 this, SLOT( slotIconChanged() ) );
914 QLabel
*iconLabel
= new QLabel( d
->m_frame
);
915 int bsize
= 66 + 2 * iconLabel
->style()->pixelMetric(QStyle::PM_ButtonMargin
);
916 iconLabel
->setFixedSize(bsize
, bsize
);
917 iconLabel
->setPixmap( KIconLoader::global()->loadIcon( iconStr
, KIconLoader::Desktop
, 48) );
918 d
->iconArea
= iconLabel
;
920 grid
->addWidget(d
->iconArea
, curRow
, 0, Qt::AlignLeft
);
922 if (d
->bMultiple
|| isTrash
|| isDevice
|| hasRoot
)
924 QLabel
*lab
= new QLabel(d
->m_frame
);
926 lab
->setText( KIO::itemsSummaryString( iFileCount
+ iDirCount
, iFileCount
, iDirCount
, 0, false ) );
928 lab
->setText( filename
);
932 d
->m_lined
= new KLineEdit( d
->m_frame
);
933 d
->m_lined
->setText(filename
);
934 d
->nameArea
= d
->m_lined
;
935 d
->m_lined
->setFocus();
937 // Enhanced rename: Don't highlight the file extension.
938 QString extension
= KMimeType::extractKnownExtension( filename
);
939 if ( !extension
.isEmpty() )
940 d
->m_lined
->setSelection( 0, filename
.length() - extension
.length() - 1 );
943 int lastDot
= filename
.lastIndexOf('.');
945 d
->m_lined
->setSelection(0, lastDot
);
948 connect( d
->m_lined
, SIGNAL( textChanged( const QString
& ) ),
949 this, SLOT( nameFileChanged(const QString
& ) ) );
952 grid
->addWidget(d
->nameArea
, curRow
++, 2);
954 KSeparator
* sep
= new KSeparator( Qt::Horizontal
, d
->m_frame
);
955 grid
->addWidget(sep
, curRow
, 0, 1, 3);
959 if ( !mimeComment
.isEmpty() && !isDevice
&& !isTrash
)
961 l
= new QLabel(i18n("Type:"), d
->m_frame
);
963 grid
->addWidget(l
, curRow
, 0, Qt::AlignRight
);
965 KHBox
*box
= new KHBox(d
->m_frame
);
967 l
= new QLabel(mimeComment
, box
);
970 //TODO: wrap for win32 or mac?
971 QPushButton
*button
= new QPushButton(box
);
973 button
->setIcon( KIcon(QString::fromLatin1("configure")) );
974 const int pixmapSize
= button
->style()->pixelMetric(QStyle::PM_SmallIconSize
);
975 button
->setFixedSize( pixmapSize
+8, pixmapSize
+8 );
976 if ( d
->mimeType
== KMimeType::defaultMimeType() )
977 button
->setToolTip(i18n("Create new file type"));
979 button
->setToolTip(i18n("Edit file type"));
981 connect( button
, SIGNAL( clicked() ), SLOT( slotEditFileType() ));
983 if (!KAuthorized::authorizeKAction("editfiletype"))
987 grid
->addWidget(box
, curRow
++, 2);
990 if ( !magicMimeComment
.isEmpty() && magicMimeComment
!= mimeComment
)
992 l
= new QLabel(i18n("Contents:"), d
->m_frame
);
993 grid
->addWidget(l
, curRow
, 0, Qt::AlignRight
);
995 l
= new QLabel(magicMimeComment
, d
->m_frame
);
996 grid
->addWidget(l
, curRow
++, 2);
999 if ( !directory
.isEmpty() )
1001 l
= new QLabel( i18n("Location:"), d
->m_frame
);
1002 grid
->addWidget(l
, curRow
, 0, Qt::AlignRight
);
1004 l
= new KSqueezedTextLabel( directory
, d
->m_frame
);
1005 // force the layout direction to be always LTR
1006 l
->setLayoutDirection(Qt::LeftToRight
);
1007 // but if we are in RTL mode, align the text to the right
1008 // otherwise the text is on the wrong side of the dialog
1009 if (properties
->layoutDirection() == Qt::RightToLeft
)
1010 l
->setAlignment( Qt::AlignRight
);
1011 l
->setTextInteractionFlags(Qt::TextSelectableByMouse
|Qt::TextSelectableByKeyboard
);
1012 grid
->addWidget(l
, curRow
++, 2);
1015 l
= new QLabel(i18n("Size:"), d
->m_frame
);
1016 grid
->addWidget(l
, curRow
, 0, Qt::AlignRight
);
1018 d
->m_sizeLabel
= new QLabel( d
->m_frame
);
1019 grid
->addWidget( d
->m_sizeLabel
, curRow
++, 2 );
1021 if ( !hasDirs
) // Only files [and symlinks]
1023 d
->m_sizeLabel
->setText(QString::fromLatin1("%1 (%2)").arg(KIO::convertSize(totalSize
))
1024 .arg(KGlobal::locale()->formatNumber(totalSize
, 0)));
1025 d
->m_sizeDetermineButton
= 0L;
1026 d
->m_sizeStopButton
= 0L;
1030 QHBoxLayout
* sizelay
= new QHBoxLayout();
1031 sizelay
->setSpacing(KDialog::spacingHint());
1032 grid
->addLayout( sizelay
, curRow
++, 2 );
1035 d
->m_sizeDetermineButton
= new QPushButton( i18n("Calculate"), d
->m_frame
);
1036 d
->m_sizeStopButton
= new QPushButton( i18n("Stop"), d
->m_frame
);
1037 connect( d
->m_sizeDetermineButton
, SIGNAL( clicked() ), this, SLOT( slotSizeDetermine() ) );
1038 connect( d
->m_sizeStopButton
, SIGNAL( clicked() ), this, SLOT( slotSizeStop() ) );
1039 sizelay
->addWidget(d
->m_sizeDetermineButton
, 0);
1040 sizelay
->addWidget(d
->m_sizeStopButton
, 0);
1041 sizelay
->addStretch(10); // so that the buttons don't grow horizontally
1043 // auto-launch for local dirs only, and not for '/'
1044 if ( isLocal
&& !hasRoot
)
1046 d
->m_sizeDetermineButton
->setText( i18n("Refresh") );
1047 slotSizeDetermine();
1050 d
->m_sizeStopButton
->setEnabled( false );
1053 if (!d
->bMultiple
&& item
.isLink()) {
1054 l
= new QLabel(i18n("Points to:"), d
->m_frame
);
1055 grid
->addWidget(l
, curRow
, 0, Qt::AlignRight
);
1057 d
->m_linkTargetLineEdit
= new KLineEdit(item
.linkDest(), d
->m_frame
);
1058 grid
->addWidget(d
->m_linkTargetLineEdit
, curRow
++, 2);
1061 if (!d
->bMultiple
) // Dates for multiple don't make much sense...
1063 KDateTime dt
= item
.time(KFileItem::CreationTime
);
1066 l
= new QLabel(i18n("Created:"), d
->m_frame
);
1067 grid
->addWidget(l
, curRow
, 0, Qt::AlignRight
);
1069 l
= new QLabel(KGlobal::locale()->formatDateTime(dt
), d
->m_frame
);
1070 grid
->addWidget(l
, curRow
++, 2);
1073 dt
= item
.time(KFileItem::ModificationTime
);
1076 l
= new QLabel(i18n("Modified:"), d
->m_frame
);
1077 grid
->addWidget(l
, curRow
, 0, Qt::AlignRight
);
1079 l
= new QLabel(KGlobal::locale()->formatDateTime(dt
), d
->m_frame
);
1080 grid
->addWidget(l
, curRow
++, 2);
1083 dt
= item
.time(KFileItem::AccessTime
);
1086 l
= new QLabel(i18n("Accessed:"), d
->m_frame
);
1087 grid
->addWidget(l
, curRow
, 0, Qt::AlignRight
);
1089 l
= new QLabel(KGlobal::locale()->formatDateTime(dt
), d
->m_frame
);
1090 grid
->addWidget(l
, curRow
++, 2);
1094 if ( isLocal
&& hasDirs
) // only for directories
1097 KMountPoint::Ptr mp
= KMountPoint::currentMountPoints().findByPath( url
.path() );
1099 KDiskFreeSpaceInfo info
= KDiskFreeSpaceInfo::freeSpaceInfo( mp
->mountPoint() );
1100 if(info
.size() != 0 )
1102 sep
= new KSeparator( Qt::Horizontal
, d
->m_frame
);
1103 grid
->addWidget(sep
, curRow
, 0, 1, 3);
1105 if (mp
->mountPoint() != "/")
1107 l
= new QLabel(i18n("Mounted on:"), d
->m_frame
);
1108 grid
->addWidget(l
, curRow
, 0, Qt::AlignRight
);
1110 l
= new KSqueezedTextLabel( mp
->mountPoint(), d
->m_frame
);
1111 l
->setTextInteractionFlags(Qt::TextSelectableByMouse
|Qt::TextSelectableByKeyboard
);
1112 grid
->addWidget( l
, curRow
++, 2 );
1115 l
= new QLabel(i18n("Device usage:"), d
->m_frame
);
1116 grid
->addWidget(l
, curRow
, 0, Qt::AlignRight
);
1118 d
->m_capacityBar
= new KCapacityBar( KCapacityBar::DrawTextOutline
, d
->m_frame
);
1119 grid
->addWidget( d
->m_capacityBar
, curRow
++, 2);
1121 slotFoundMountPoint( info
.mountPoint(), info
.size()/1024, info
.used()/1024, info
.available()/1024);
1129 // QString KFilePropsPlugin::tabName () const
1131 // return i18n ("&General");
1134 void KFilePropsPlugin::setFileNameReadOnly( bool ro
)
1138 d
->m_lined
->setReadOnly( ro
);
1141 // Don't put the initial focus on the line edit when it is ro
1142 properties
->setButtonFocus(KDialog::Ok
);
1147 void KFilePropsPlugin::slotEditFileType()
1151 if ( d
->mimeType
== KMimeType::defaultMimeType() ) {
1152 int pos
= d
->oldFileName
.lastIndexOf( '.' );
1154 mime
= '*' + d
->oldFileName
.mid(pos
);
1160 //TODO: wrap for win32 or mac?
1161 QString keditfiletype
= QString::fromLatin1("keditfiletype");
1162 KRun::runCommand( keditfiletype
1163 + " --parent " + QString::number( (ulong
)properties
->topLevelWidget()->winId())
1164 + ' ' + KShell::quoteArg(mime
),
1165 keditfiletype
, keditfiletype
/*unused*/, properties
->topLevelWidget());
1169 void KFilePropsPlugin::slotIconChanged()
1171 d
->bIconChanged
= true;
1175 void KFilePropsPlugin::nameFileChanged(const QString
&text
)
1177 properties
->enableButtonOk(!text
.isEmpty());
1181 void KFilePropsPlugin::determineRelativePath( const QString
& path
)
1183 // now let's make it relative
1184 d
->m_sRelativePath
= KGlobal::dirs()->relativeLocation("apps", path
);
1185 if (d
->m_sRelativePath
.startsWith('/'))
1187 d
->m_sRelativePath
=KGlobal::dirs()->relativeLocation("xdgdata-apps", path
);
1188 if (d
->m_sRelativePath
.startsWith('/'))
1189 d
->m_sRelativePath
.clear();
1191 d
->m_sRelativePath
= path
;
1195 void KFilePropsPlugin::slotFoundMountPoint( const QString
&,
1197 quint64
/*kibUsed*/,
1200 d
->m_capacityBar
->setText(
1201 i18nc("Available space out of total partition size (percent used)", "%1 free of %2 (%3% used)",
1202 KIO::convertSizeFromKiB(kibAvail
),
1203 KIO::convertSizeFromKiB(kibSize
),
1204 100 - (int)(100.0 * kibAvail
/ kibSize
) ));
1206 d
->m_capacityBar
->setValue(100 - (int)(100.0 * kibAvail
/ kibSize
));
1209 void KFilePropsPlugin::slotDirSizeUpdate()
1211 KIO::filesize_t totalSize
= d
->dirSizeJob
->totalSize();
1212 KIO::filesize_t totalFiles
= d
->dirSizeJob
->totalFiles();
1213 KIO::filesize_t totalSubdirs
= d
->dirSizeJob
->totalSubdirs();
1214 d
->m_sizeLabel
->setText(
1215 i18n("Calculating... %1 (%2)\n%3, %4",
1216 KIO::convertSize(totalSize
),
1218 i18np("1 file", "%1 files", totalFiles
),
1219 i18np("1 sub-folder", "%1 sub-folders", totalSubdirs
)));
1222 void KFilePropsPlugin::slotDirSizeFinished( KJob
* job
)
1225 d
->m_sizeLabel
->setText( job
->errorString() );
1228 KIO::filesize_t totalSize
= d
->dirSizeJob
->totalSize();
1229 KIO::filesize_t totalFiles
= d
->dirSizeJob
->totalFiles();
1230 KIO::filesize_t totalSubdirs
= d
->dirSizeJob
->totalSubdirs();
1231 d
->m_sizeLabel
->setText( QString::fromLatin1("%1 (%2)\n%3, %4")
1232 .arg(KIO::convertSize(totalSize
))
1233 .arg(KGlobal::locale()->formatNumber(totalSize
, 0))
1234 .arg(i18np("1 file","%1 files",totalFiles
))
1235 .arg(i18np("1 sub-folder","%1 sub-folders",totalSubdirs
)));
1237 d
->m_sizeStopButton
->setEnabled(false);
1238 // just in case you change something and try again :)
1239 d
->m_sizeDetermineButton
->setText( i18n("Refresh") );
1240 d
->m_sizeDetermineButton
->setEnabled(true);
1242 delete d
->dirSizeUpdateTimer
;
1243 d
->dirSizeUpdateTimer
= 0;
1246 void KFilePropsPlugin::slotSizeDetermine()
1248 d
->m_sizeLabel
->setText( i18n("Calculating...") );
1249 kDebug(250) << " KFilePropsPlugin::slotSizeDetermine() properties->item()=" << properties
->item();
1250 kDebug(250) << " URL=" << properties
->item().url().url();
1252 d
->dirSizeJob
= KIO::directorySize( properties
->items() );
1253 d
->dirSizeUpdateTimer
= new QTimer(this);
1254 connect( d
->dirSizeUpdateTimer
, SIGNAL( timeout() ),
1255 SLOT( slotDirSizeUpdate() ) );
1256 d
->dirSizeUpdateTimer
->start(500);
1257 connect( d
->dirSizeJob
, SIGNAL( result( KJob
* ) ),
1258 SLOT( slotDirSizeFinished( KJob
* ) ) );
1259 d
->m_sizeStopButton
->setEnabled(true);
1260 d
->m_sizeDetermineButton
->setEnabled(false);
1262 // also update the "Free disk space" display
1263 if ( d
->m_capacityBar
)
1266 const KFileItem item
= properties
->item();
1267 KUrl url
= item
.mostLocalUrl( isLocal
);
1268 KMountPoint::Ptr mp
= KMountPoint::currentMountPoints().findByPath( url
.path() );
1270 KDiskFreeSpaceInfo info
= KDiskFreeSpaceInfo::freeSpaceInfo( mp
->mountPoint() );
1271 slotFoundMountPoint( info
.mountPoint(), info
.size()/1024, info
.used()/1024, info
.available()/1024);
1276 void KFilePropsPlugin::slotSizeStop()
1278 if ( d
->dirSizeJob
)
1280 KIO::filesize_t totalSize
= d
->dirSizeJob
->totalSize();
1281 d
->m_sizeLabel
->setText(i18n("At least %1",
1282 KIO::convertSize(totalSize
)));
1283 d
->dirSizeJob
->kill();
1286 if ( d
->dirSizeUpdateTimer
)
1287 d
->dirSizeUpdateTimer
->stop();
1289 d
->m_sizeStopButton
->setEnabled(false);
1290 d
->m_sizeDetermineButton
->setEnabled(true);
1293 KFilePropsPlugin::~KFilePropsPlugin()
1298 bool KFilePropsPlugin::supports( const KFileItemList
& /*_items*/ )
1303 void KFilePropsPlugin::applyChanges()
1305 if ( d
->dirSizeJob
)
1308 kDebug(250) << "KFilePropsPlugin::applyChanges";
1310 if (qobject_cast
<QLineEdit
*>(d
->nameArea
))
1312 QString n
= ((QLineEdit
*) d
->nameArea
)->text();
1313 // Remove trailing spaces (#4345)
1314 while ( ! n
.isEmpty() && n
[n
.length()-1].isSpace() )
1315 n
.truncate( n
.length() - 1 );
1318 KMessageBox::sorry( properties
, i18n("The new file name is empty."));
1319 properties
->abortApplying();
1323 // Do we need to rename the file ?
1324 kDebug(250) << "oldname = " << d
->oldName
;
1325 kDebug(250) << "newname = " << n
;
1326 if ( d
->oldName
!= n
|| d
->m_bFromTemplate
) { // true for any from-template file
1327 KIO::Job
* job
= 0L;
1328 KUrl oldurl
= properties
->kurl();
1330 QString newFileName
= KIO::encodeFileName(n
);
1331 if (d
->bDesktopFile
&& !newFileName
.endsWith(".desktop") && !newFileName
.endsWith(".kdelnk"))
1332 newFileName
+= ".desktop";
1334 // Tell properties. Warning, this changes the result of properties->kurl() !
1335 properties
->rename( newFileName
);
1337 // Update also relative path (for apps and mimetypes)
1338 if ( !d
->m_sRelativePath
.isEmpty() )
1339 determineRelativePath( properties
->kurl().toLocalFile() );
1341 kDebug(250) << "New URL = " << properties
->kurl().url();
1342 kDebug(250) << "old = " << oldurl
.url();
1344 // Don't remove the template !!
1345 if ( !d
->m_bFromTemplate
) // (normal renaming)
1346 job
= KIO::move( oldurl
, properties
->kurl() );
1347 else // Copying a template
1348 job
= KIO::copy( oldurl
, properties
->kurl() );
1350 connect( job
, SIGNAL( result( KJob
* ) ),
1351 SLOT( slotCopyFinished( KJob
* ) ) );
1352 connect( job
, SIGNAL( renamed( KIO::Job
*, const KUrl
&, const KUrl
& ) ),
1353 SLOT( slotFileRenamed( KIO::Job
*, const KUrl
&, const KUrl
& ) ) );
1355 QEventLoop eventLoop
;
1356 connect(this, SIGNAL(leaveModality()),
1357 &eventLoop
, SLOT(quit()));
1358 eventLoop
.exec(QEventLoop::ExcludeUserInputEvents
);
1361 properties
->updateUrl(properties
->kurl());
1362 // Update also relative path (for apps and mimetypes)
1363 if ( !d
->m_sRelativePath
.isEmpty() )
1364 determineRelativePath( properties
->kurl().toLocalFile() );
1367 // No job, keep going
1368 slotCopyFinished( 0L );
1371 void KFilePropsPlugin::slotCopyFinished( KJob
* job
)
1373 kDebug(250) << "KFilePropsPlugin::slotCopyFinished";
1376 // allow apply() to return
1377 emit
leaveModality();
1380 job
->uiDelegate()->showErrorMessage();
1381 // Didn't work. Revert the URL to the old one
1382 properties
->updateUrl( static_cast<KIO::CopyJob
*>(job
)->srcUrls().first() );
1383 properties
->abortApplying(); // Don't apply the changes to the wrong file !
1388 assert( !properties
->item().isNull() );
1389 assert( !properties
->item().url().isEmpty() );
1391 // Save the file where we can -> usually in ~/.kde/...
1392 if (d
->bDesktopFile
&& !d
->m_sRelativePath
.isEmpty())
1394 kDebug(250) << "KFilePropsPlugin::slotCopyFinished " << d
->m_sRelativePath
;
1396 newURL
.setPath( KDesktopFile::locateLocal(d
->m_sRelativePath
) );
1397 kDebug(250) << "KFilePropsPlugin::slotCopyFinished path=" << newURL
.path();
1398 properties
->updateUrl( newURL
);
1401 if ( d
->bKDesktopMode
&& d
->bDesktopFile
) {
1402 // Renamed? Update Name field
1403 if ( d
->oldFileName
!= properties
->kurl().fileName() || d
->m_bFromTemplate
) {
1404 KDesktopFile
config( properties
->kurl().toLocalFile() );
1405 KConfigGroup cg
= config
.desktopGroup();
1406 QString nameStr
= nameFromFileName(properties
->kurl().fileName());
1407 cg
.writeEntry( "Name", nameStr
);
1408 cg
.writeEntry( "Name", nameStr
, KConfigGroup::Persistent
|KConfigGroup::Localized
);
1412 if (d
->m_linkTargetLineEdit
&& !d
->bMultiple
) {
1413 const KFileItem item
= properties
->item();
1414 const QString newTarget
= d
->m_linkTargetLineEdit
->text();
1415 if (newTarget
!= item
.linkDest()) {
1416 kDebug(250) << "Updating target of symlink to" << newTarget
;
1417 KIO::Job
* job
= KIO::symlink(newTarget
, item
.url(), KIO::Overwrite
);
1418 job
->ui()->setAutoErrorHandlingEnabled(true);
1423 // "Link to Application" templates need to be made executable
1424 // Instead of matching against a filename we check if the destination
1425 // is an Application now.
1426 if ( d
->m_bFromTemplate
) {
1427 // destination is not necessarily local, use the src template
1428 KDesktopFile
templateResult ( static_cast<KIO::CopyJob
*>(job
)->srcUrls().first().toLocalFile() );
1429 if ( templateResult
.hasApplicationType() ) {
1430 // We can either stat the file and add the +x bit or use the larger chmod() job
1431 // with a umask designed to only touch u+x. This is only one KIO job, so let's
1434 KFileItem
appLink ( properties
->item() );
1435 KFileItemList fileItemList
;
1436 fileItemList
<< appLink
;
1438 // first 0100 adds u+x, second 0100 only allows chmod to change u+x
1439 KIO::Job
* chmodJob
= KIO::chmod( fileItemList
, 0100, 0100, QString(), QString(), KIO::HideProgressInfo
);
1445 void KFilePropsPlugin::applyIconChanges()
1447 KIconButton
*iconButton
= qobject_cast
<KIconButton
*>(d
->iconArea
);
1448 if ( !iconButton
|| !d
->bIconChanged
)
1450 // handle icon changes - only local files (or pseudo-local) for now
1451 // TODO: Use KTempFile and KIO::file_copy with overwrite = true
1452 KUrl url
= properties
->kurl();
1453 url
= KIO::NetAccess::mostLocalUrl( url
, properties
);
1454 if ( url
.isLocalFile()) {
1457 if (S_ISDIR(properties
->item().mode()))
1459 path
= url
.toLocalFile(KUrl::AddTrailingSlash
) + QString::fromLatin1(".directory");
1460 // don't call updateUrl because the other tabs (i.e. permissions)
1461 // apply to the directory, not the .directory file.
1464 path
= url
.toLocalFile();
1466 // Get the default image
1467 QString str
= KMimeType::findByUrl( url
,
1468 properties
->item().mode(),
1470 // Is it another one than the default ?
1472 if ( str
!= iconButton
->icon() )
1473 sIcon
= iconButton
->icon();
1474 // (otherwise write empty value)
1476 kDebug(250) << "**" << path
<< "**";
1479 // If default icon and no .directory file -> don't create one
1480 if ( !sIcon
.isEmpty() || f
.exists() )
1482 if ( !f
.open( QIODevice::ReadWrite
) ) {
1483 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not "
1484 "have sufficient access to write to <b>%1</b>.</qt>", path
));
1489 KDesktopFile
cfg(path
);
1490 kDebug(250) << "sIcon = " << (sIcon
);
1491 kDebug(250) << "str = " << (str
);
1492 cfg
.desktopGroup().writeEntry( "Icon", sIcon
);
1498 void KFilePropsPlugin::slotFileRenamed( KIO::Job
*, const KUrl
&, const KUrl
& newUrl
)
1500 // This is called in case of an existing local file during the copy/move operation,
1501 // if the user chooses Rename.
1502 properties
->updateUrl( newUrl
);
1505 void KFilePropsPlugin::postApplyChanges()
1507 // Save the icon only after applying the permissions changes (#46192)
1510 const KFileItemList items
= properties
->items();
1511 const KUrl::List lst
= items
.urlList();
1512 org::kde::KDirNotify::emitFilesChanged( lst
.toStringList() );
1515 class KFilePermissionsPropsPlugin::KFilePermissionsPropsPluginPrivate
1518 KFilePermissionsPropsPluginPrivate()
1521 ~KFilePermissionsPropsPluginPrivate()
1526 QCheckBox
*cbRecursive
;
1527 QLabel
*explanationLabel
;
1528 KComboBox
*ownerPermCombo
, *groupPermCombo
, *othersPermCombo
;
1529 QCheckBox
*extraCheckbox
;
1530 mode_t partialPermissions
;
1531 KFilePermissionsPropsPlugin::PermissionsMode pmode
;
1532 bool canChangePermissions
;
1534 bool hasExtendedACL
;
1537 bool fileSystemSupportsACLs
;
1539 KComboBox
*grpCombo
;
1552 #define UniOwner (S_IRUSR|S_IWUSR|S_IXUSR)
1553 #define UniGroup (S_IRGRP|S_IWGRP|S_IXGRP)
1554 #define UniOthers (S_IROTH|S_IWOTH|S_IXOTH)
1555 #define UniRead (S_IRUSR|S_IRGRP|S_IROTH)
1556 #define UniWrite (S_IWUSR|S_IWGRP|S_IWOTH)
1557 #define UniExec (S_IXUSR|S_IXGRP|S_IXOTH)
1558 #define UniSpecial (S_ISUID|S_ISGID|S_ISVTX)
1560 // synced with PermissionsTarget
1561 const mode_t
KFilePermissionsPropsPlugin::permissionsMasks
[3] = {UniOwner
, UniGroup
, UniOthers
};
1562 const mode_t
KFilePermissionsPropsPlugin::standardPermissions
[4] = { 0, UniRead
, UniRead
|UniWrite
, (mode_t
)-1 };
1564 // synced with PermissionsMode and standardPermissions
1565 const char *KFilePermissionsPropsPlugin::permissionsTexts
[4][4] = {
1566 { I18N_NOOP("Forbidden"),
1567 I18N_NOOP("Can Read"),
1568 I18N_NOOP("Can Read & Write"),
1570 { I18N_NOOP("Forbidden"),
1571 I18N_NOOP("Can View Content"),
1572 I18N_NOOP("Can View & Modify Content"),
1574 { 0, 0, 0, 0}, // no texts for links
1575 { I18N_NOOP("Forbidden"),
1576 I18N_NOOP("Can View Content & Read"),
1577 I18N_NOOP("Can View/Read & Modify/Write"),
1582 KFilePermissionsPropsPlugin::KFilePermissionsPropsPlugin( KPropertiesDialog
*_props
)
1583 : KPropertiesDialogPlugin( _props
),d(new KFilePermissionsPropsPluginPrivate
)
1585 d
->cbRecursive
= 0L;
1586 d
->grpCombo
= 0L; d
->grpEdit
= 0;
1588 QString path
= properties
->kurl().path(KUrl::RemoveTrailingSlash
);
1589 QString fname
= properties
->kurl().fileName();
1590 bool isLocal
= properties
->kurl().isLocalFile();
1591 bool isTrash
= ( properties
->kurl().protocol().toLower() == "trash" );
1592 bool IamRoot
= (geteuid() == 0);
1594 const KFileItem item
= properties
->item();
1595 bool isLink
= item
.isLink();
1596 bool isDir
= item
.isDir(); // all dirs
1597 bool hasDir
= item
.isDir(); // at least one dir
1598 d
->permissions
= item
.permissions(); // common permissions to all files
1599 d
->partialPermissions
= d
->permissions
; // permissions that only some files have (at first we take everything)
1600 d
->isIrregular
= isIrregular(d
->permissions
, isDir
, isLink
);
1601 d
->strOwner
= item
.user();
1602 d
->strGroup
= item
.group();
1603 d
->hasExtendedACL
= item
.ACL().isExtended() || item
.defaultACL().isValid();
1604 d
->extendedACL
= item
.ACL();
1605 d
->defaultACL
= item
.defaultACL();
1606 d
->fileSystemSupportsACLs
= false;
1608 if ( properties
->items().count() > 1 )
1610 // Multiple items: see what they have in common
1611 const KFileItemList items
= properties
->items();
1612 KFileItemList::const_iterator it
= items
.begin();
1613 const KFileItemList::const_iterator kend
= items
.end();
1614 for ( ++it
/*no need to check the first one again*/ ; it
!= kend
; ++it
)
1616 const KUrl url
= (*it
).url();
1617 if (!d
->isIrregular
)
1618 d
->isIrregular
|= isIrregular((*it
).permissions(),
1619 (*it
).isDir() == isDir
,
1620 (*it
).isLink() == isLink
);
1621 d
->hasExtendedACL
= d
->hasExtendedACL
|| (*it
).hasExtendedACL();
1622 if ( (*it
).isLink() != isLink
)
1624 if ( (*it
).isDir() != isDir
)
1626 hasDir
|= (*it
).isDir();
1627 if ( (*it
).permissions() != d
->permissions
)
1629 d
->permissions
&= (*it
).permissions();
1630 d
->partialPermissions
|= (*it
).permissions();
1632 if ( (*it
).user() != d
->strOwner
)
1633 d
->strOwner
.clear();
1634 if ( (*it
).group() != d
->strGroup
)
1635 d
->strGroup
.clear();
1640 d
->pmode
= PermissionsOnlyLinks
;
1642 d
->pmode
= PermissionsOnlyDirs
;
1644 d
->pmode
= PermissionsMixed
;
1646 d
->pmode
= PermissionsOnlyFiles
;
1648 // keep only what's not in the common permissions
1649 d
->partialPermissions
= d
->partialPermissions
& ~d
->permissions
;
1651 bool isMyFile
= false;
1653 if (isLocal
&& !d
->strOwner
.isEmpty()) { // local files, and all owned by the same person
1654 struct passwd
*myself
= getpwuid( geteuid() );
1657 isMyFile
= (d
->strOwner
== QString::fromLocal8Bit(myself
->pw_name
));
1659 kWarning() << "I don't exist ?! geteuid=" << geteuid();
1661 //We don't know, for remote files, if they are ours or not.
1662 //So we let the user change permissions, and
1663 //KIO::chmod will tell, if he had no right to do it.
1667 d
->canChangePermissions
= (isMyFile
|| IamRoot
) && (!isLink
);
1672 d
->m_frame
= new QFrame();
1673 properties
->addPage( d
->m_frame
, i18n("&Permissions") );
1675 QBoxLayout
*box
= new QVBoxLayout( d
->m_frame
);
1676 box
->setMargin( 0 );
1677 box
->setSpacing( KDialog::spacingHint() );
1683 QPushButton
* pbAdvancedPerm
= 0;
1685 /* Group: Access Permissions */
1686 gb
= new QGroupBox ( i18n("Access Permissions"), d
->m_frame
);
1687 box
->addWidget (gb
);
1689 gl
= new QGridLayout (gb
);
1690 gl
->setSpacing(KDialog::spacingHint());
1691 gl
->setMargin(KDialog::marginHint());
1692 gl
->setColumnStretch(1, 1);
1694 l
= d
->explanationLabel
= new QLabel( "", gb
);
1696 d
->explanationLabel
->setText(i18np("This file is a link and does not have permissions.",
1697 "All files are links and do not have permissions.",
1698 properties
->items().count()));
1699 else if (!d
->canChangePermissions
)
1700 d
->explanationLabel
->setText(i18n("Only the owner can change permissions."));
1701 gl
->addWidget(l
, 0, 0, 1, 2);
1703 lbl
= new QLabel( i18n("O&wner:"), gb
);
1704 gl
->addWidget(lbl
, 1, 0, Qt::AlignRight
);
1705 l
= d
->ownerPermCombo
= new KComboBox(gb
);
1707 gl
->addWidget(l
, 1, 1);
1708 connect(l
, SIGNAL( activated(int) ), this, SIGNAL( changed() ));
1709 l
->setWhatsThis(i18n("Specifies the actions that the owner is allowed to do."));
1711 lbl
= new QLabel( i18n("Gro&up:"), gb
);
1712 gl
->addWidget(lbl
, 2, 0, Qt::AlignRight
);
1713 l
= d
->groupPermCombo
= new KComboBox(gb
);
1715 gl
->addWidget(l
, 2, 1);
1716 connect(l
, SIGNAL( activated(int) ), this, SIGNAL( changed() ));
1717 l
->setWhatsThis(i18n("Specifies the actions that the members of the group are allowed to do."));
1719 lbl
= new QLabel( i18n("O&thers:"), gb
);
1720 gl
->addWidget(lbl
, 3, 0, Qt::AlignRight
);
1721 l
= d
->othersPermCombo
= new KComboBox(gb
);
1723 gl
->addWidget(l
, 3, 1);
1724 connect(l
, SIGNAL( activated(int) ), this, SIGNAL( changed() ));
1725 l
->setWhatsThis(i18n("Specifies the actions that all users, who are neither "
1726 "owner nor in the group, are allowed to do."));
1729 l
= d
->extraCheckbox
= new QCheckBox(hasDir
?
1730 i18n("Only own&er can rename and delete folder content") :
1731 i18n("Is &executable"),
1733 connect( d
->extraCheckbox
, SIGNAL( clicked() ), this, SIGNAL( changed() ) );
1734 gl
->addWidget(l
, 4, 1);
1735 l
->setWhatsThis(hasDir
? i18n("Enable this option to allow only the folder's owner to "
1736 "delete or rename the contained files and folders. Other "
1737 "users can only add new files, which requires the 'Modify "
1738 "Content' permission.")
1739 : i18n("Enable this option to mark the file as executable. This only makes "
1740 "sense for programs and scripts. It is required when you want to "
1743 QLayoutItem
*spacer
= new QSpacerItem(0, 20, QSizePolicy::Minimum
, QSizePolicy::Expanding
);
1744 gl
->addItem(spacer
, 5, 0, 1, 3);
1746 pbAdvancedPerm
= new QPushButton(i18n("A&dvanced Permissions"), gb
);
1747 gl
->addWidget(pbAdvancedPerm
, 6, 0, 1, 2, Qt::AlignRight
);
1748 connect(pbAdvancedPerm
, SIGNAL( clicked() ), this, SLOT( slotShowAdvancedPermissions() ));
1751 d
->extraCheckbox
= 0;
1754 /**** Group: Ownership ****/
1755 gb
= new QGroupBox ( i18n("Ownership"), d
->m_frame
);
1756 box
->addWidget (gb
);
1758 gl
= new QGridLayout (gb
);
1759 gl
->setSpacing(KDialog::spacingHint());
1760 gl
->setMargin(KDialog::marginHint());
1761 gl
->addItem(new QSpacerItem(0, 10), 0, 0);
1764 l
= new QLabel( i18n("User:"), gb
);
1765 gl
->addWidget (l
, 1, 0, Qt::AlignRight
);
1767 /* GJ: Don't autocomplete more than 1000 users. This is a kind of random
1768 * value. Huge sites having 10.000+ user have a fair chance of using NIS,
1769 * (possibly) making this unacceptably slow.
1770 * OTOH, it is nice to offer this functionality for the standard user.
1772 int i
, maxEntries
= 1000;
1773 struct passwd
*user
;
1775 /* File owner: For root, offer a KLineEdit with autocompletion.
1776 * For a user, who can never chown() a file, offer a QLabel.
1778 if (IamRoot
&& isLocal
)
1780 d
->usrEdit
= new KLineEdit( gb
);
1781 KCompletion
*kcom
= d
->usrEdit
->completionObject();
1782 kcom
->setOrder(KCompletion::Sorted
);
1784 for (i
=0; ((user
= getpwent()) != 0L) && (i
< maxEntries
); ++i
)
1785 kcom
->addItem(QString::fromLatin1(user
->pw_name
));
1787 d
->usrEdit
->setCompletionMode((i
< maxEntries
) ? KGlobalSettings::CompletionAuto
:
1788 KGlobalSettings::CompletionNone
);
1789 d
->usrEdit
->setText(d
->strOwner
);
1790 gl
->addWidget(d
->usrEdit
, 1, 1);
1791 connect( d
->usrEdit
, SIGNAL( textChanged( const QString
& ) ),
1792 this, SIGNAL( changed() ) );
1796 l
= new QLabel(d
->strOwner
, gb
);
1797 gl
->addWidget(l
, 1, 1);
1802 QStringList groupList
;
1804 user
= getpwuid(geteuid());
1806 strUser
= user
->pw_name
;
1809 // pick the groups to which the user belongs
1812 QVarLengthArray
<int> groups
;
1814 QVarLengthArray
<gid_t
> groups
;
1816 if (getgrouplist(strUser
, user
->pw_gid
, NULL
, &groupCount
) < 0) {
1817 groups
.resize(groupCount
);
1819 getgrouplist(strUser
, user
->pw_gid
, groups
.data(), &groupCount
);
1824 for (i
= 0; i
< groupCount
; i
++) {
1825 struct group
*mygroup
= getgrgid(groups
[i
]);
1827 groupList
+= QString::fromLocal8Bit(mygroup
->gr_name
);
1831 bool isMyGroup
= groupList
.contains(d
->strGroup
);
1833 /* add the group the file currently belongs to ..
1834 * .. if it is not there already
1837 groupList
+= d
->strGroup
;
1839 l
= new QLabel( i18n("Group:"), gb
);
1840 gl
->addWidget (l
, 2, 0, Qt::AlignRight
);
1842 /* Set group: if possible to change:
1843 * - Offer a KLineEdit for root, since he can change to any group.
1844 * - Offer a KComboBox for a normal user, since he can change to a fixed
1845 * (small) set of groups only.
1846 * If not changeable: offer a QLabel.
1848 if (IamRoot
&& isLocal
)
1850 d
->grpEdit
= new KLineEdit(gb
);
1851 KCompletion
*kcom
= new KCompletion
;
1852 kcom
->setItems(groupList
);
1853 d
->grpEdit
->setCompletionObject(kcom
, true);
1854 d
->grpEdit
->setAutoDeleteCompletionObject( true );
1855 d
->grpEdit
->setCompletionMode(KGlobalSettings::CompletionAuto
);
1856 d
->grpEdit
->setText(d
->strGroup
);
1857 gl
->addWidget(d
->grpEdit
, 2, 1);
1858 connect( d
->grpEdit
, SIGNAL( textChanged( const QString
& ) ),
1859 this, SIGNAL( changed() ) );
1861 else if ((groupList
.count() > 1) && isMyFile
&& isLocal
)
1863 d
->grpCombo
= new KComboBox(gb
);
1864 d
->grpCombo
->setObjectName(QLatin1String("combogrouplist"));
1865 d
->grpCombo
->addItems(groupList
);
1866 d
->grpCombo
->setCurrentIndex(groupList
.indexOf(d
->strGroup
));
1867 gl
->addWidget(d
->grpCombo
, 2, 1);
1868 connect( d
->grpCombo
, SIGNAL( activated( int ) ),
1869 this, SIGNAL( changed() ) );
1873 l
= new QLabel(d
->strGroup
, gb
);
1874 gl
->addWidget(l
, 2, 1);
1877 gl
->setColumnStretch(2, 10);
1879 // "Apply recursive" checkbox
1880 if ( hasDir
&& !isLink
&& !isTrash
)
1882 d
->cbRecursive
= new QCheckBox( i18n("Apply changes to all subfolders and their contents"), d
->m_frame
);
1883 connect( d
->cbRecursive
, SIGNAL( clicked() ), this, SIGNAL( changed() ) );
1884 box
->addWidget( d
->cbRecursive
);
1887 updateAccessControls();
1892 //don't allow to change properties for file into trash
1893 enableAccessControls(false);
1894 if ( pbAdvancedPerm
)
1895 pbAdvancedPerm
->setEnabled(false);
1898 box
->addStretch (10);
1901 #ifdef HAVE_POSIX_ACL
1902 static bool fileSystemSupportsACL( const QByteArray
& path
)
1904 bool fileSystemSupportsACLs
= false;
1907 fileSystemSupportsACLs
= ( statfs( path
.data(), &buf
) == 0 ) && ( buf
.f_flags
& MNT_ACLS
);
1909 fileSystemSupportsACLs
=
1910 getxattr( path
.data(), "system.posix_acl_access", NULL
, 0 ) >= 0 || errno
== ENODATA
;
1912 return fileSystemSupportsACLs
;
1917 void KFilePermissionsPropsPlugin::slotShowAdvancedPermissions() {
1919 bool isDir
= (d
->pmode
== PermissionsOnlyDirs
) || (d
->pmode
== PermissionsMixed
);
1920 KDialog
dlg( properties
);
1921 dlg
.setModal( true );
1922 dlg
.setCaption( i18n("Advanced Permissions") );
1923 dlg
.setButtons( KDialog::Ok
| KDialog::Cancel
);
1929 QWidget
*mainw
= new QWidget( &dlg
);
1930 QVBoxLayout
*vbox
= new QVBoxLayout(mainw
);
1931 // Group: Access Permissions
1932 gb
= new QGroupBox ( i18n("Access Permissions"), mainw
);
1933 vbox
->addWidget(gb
);
1935 gl
= new QGridLayout (gb
);
1936 gl
->setSpacing(KDialog::spacingHint());
1937 gl
->setMargin(KDialog::marginHint());
1938 gl
->addItem(new QSpacerItem(0, 10), 0, 0);
1940 QVector
<QWidget
*> theNotSpecials
;
1942 l
= new QLabel(i18n("Class"), gb
);
1943 gl
->addWidget(l
, 1, 0);
1944 theNotSpecials
.append( l
);
1947 l
= new QLabel( i18n("Show\nEntries"), gb
);
1949 l
= new QLabel( i18n("Read"), gb
);
1950 gl
->addWidget (l
, 1, 1);
1951 theNotSpecials
.append( l
);
1952 QString readWhatsThis
;
1954 readWhatsThis
= i18n("This flag allows viewing the content of the folder.");
1956 readWhatsThis
= i18n("The Read flag allows viewing the content of the file.");
1957 l
->setWhatsThis(readWhatsThis
);
1960 l
= new QLabel( i18n("Write\nEntries"), gb
);
1962 l
= new QLabel( i18n("Write"), gb
);
1963 gl
->addWidget (l
, 1, 2);
1964 theNotSpecials
.append( l
);
1965 QString writeWhatsThis
;
1967 writeWhatsThis
= i18n("This flag allows adding, renaming and deleting of files. "
1968 "Note that deleting and renaming can be limited using the Sticky flag.");
1970 writeWhatsThis
= i18n("The Write flag allows modifying the content of the file.");
1971 l
->setWhatsThis(writeWhatsThis
);
1973 QString execWhatsThis
;
1975 l
= new QLabel( i18nc("Enter folder", "Enter"), gb
);
1976 execWhatsThis
= i18n("Enable this flag to allow entering the folder.");
1979 l
= new QLabel( i18n("Exec"), gb
);
1980 execWhatsThis
= i18n("Enable this flag to allow executing the file as a program.");
1982 l
->setWhatsThis(execWhatsThis
);
1983 theNotSpecials
.append( l
);
1984 // GJ: Add space between normal and special modes
1985 QSize size
= l
->sizeHint();
1986 size
.setWidth(size
.width() + 15);
1987 l
->setFixedSize(size
);
1988 gl
->addWidget (l
, 1, 3);
1990 l
= new QLabel( i18n("Special"), gb
);
1991 gl
->addWidget(l
, 1, 4, 1, 2);
1992 QString specialWhatsThis
;
1994 specialWhatsThis
= i18n("Special flag. Valid for the whole folder, the exact "
1995 "meaning of the flag can be seen in the right hand column.");
1997 specialWhatsThis
= i18n("Special flag. The exact meaning of the flag can be seen "
1998 "in the right hand column.");
1999 l
->setWhatsThis(specialWhatsThis
);
2001 cl
[0] = new QLabel( i18n("User"), gb
);
2002 gl
->addWidget (cl
[0], 2, 0);
2003 theNotSpecials
.append( cl
[0] );
2005 cl
[1] = new QLabel( i18n("Group"), gb
);
2006 gl
->addWidget (cl
[1], 3, 0);
2007 theNotSpecials
.append( cl
[1] );
2009 cl
[2] = new QLabel( i18n("Others"), gb
);
2010 gl
->addWidget (cl
[2], 4, 0);
2011 theNotSpecials
.append( cl
[2] );
2013 l
= new QLabel(i18n("Set UID"), gb
);
2014 gl
->addWidget(l
, 2, 5);
2015 QString setUidWhatsThis
;
2017 setUidWhatsThis
= i18n("If this flag is set, the owner of this folder will be "
2018 "the owner of all new files.");
2020 setUidWhatsThis
= i18n("If this file is an executable and the flag is set, it will "
2021 "be executed with the permissions of the owner.");
2022 l
->setWhatsThis(setUidWhatsThis
);
2024 l
= new QLabel(i18n("Set GID"), gb
);
2025 gl
->addWidget(l
, 3, 5);
2026 QString setGidWhatsThis
;
2028 setGidWhatsThis
= i18n("If this flag is set, the group of this folder will be "
2029 "set for all new files.");
2031 setGidWhatsThis
= i18n("If this file is an executable and the flag is set, it will "
2032 "be executed with the permissions of the group.");
2033 l
->setWhatsThis(setGidWhatsThis
);
2035 l
= new QLabel(i18nc("File permission", "Sticky"), gb
);
2036 gl
->addWidget(l
, 4, 5);
2037 QString stickyWhatsThis
;
2039 stickyWhatsThis
= i18n("If the Sticky flag is set on a folder, only the owner "
2040 "and root can delete or rename files. Otherwise everybody "
2041 "with write permissions can do this.");
2043 stickyWhatsThis
= i18n("The Sticky flag on a file is ignored on Linux, but may "
2044 "be used on some systems");
2045 l
->setWhatsThis(stickyWhatsThis
);
2047 mode_t aPermissions
, aPartialPermissions
;
2048 mode_t dummy1
, dummy2
;
2050 if (!d
->isIrregular
) {
2052 case PermissionsOnlyFiles
:
2053 getPermissionMasks(aPartialPermissions
,
2058 case PermissionsOnlyDirs
:
2059 case PermissionsMixed
:
2060 getPermissionMasks(dummy1
,
2061 aPartialPermissions
,
2065 case PermissionsOnlyLinks
:
2066 aPermissions
= UniRead
| UniWrite
| UniExec
| UniSpecial
;
2067 aPartialPermissions
= 0;
2072 aPermissions
= d
->permissions
;
2073 aPartialPermissions
= d
->partialPermissions
;
2077 QCheckBox
*cba
[3][4];
2078 for (int row
= 0; row
< 3 ; ++row
) {
2079 for (int col
= 0; col
< 4; ++col
) {
2080 QCheckBox
*cb
= new QCheckBox(gb
);
2081 if ( col
!= 3 ) theNotSpecials
.append( cb
);
2083 cb
->setChecked(aPermissions
& fperm
[row
][col
]);
2084 if ( aPartialPermissions
& fperm
[row
][col
] )
2087 cb
->setCheckState(Qt::PartiallyChecked
);
2089 else if (d
->cbRecursive
&& d
->cbRecursive
->isChecked())
2092 cb
->setEnabled( d
->canChangePermissions
);
2093 gl
->addWidget (cb
, row
+2, col
+1);
2096 cb
->setWhatsThis(readWhatsThis
);
2099 cb
->setWhatsThis(writeWhatsThis
);
2102 cb
->setWhatsThis(execWhatsThis
);
2107 cb
->setWhatsThis(setUidWhatsThis
);
2110 cb
->setWhatsThis(setGidWhatsThis
);
2113 cb
->setWhatsThis(stickyWhatsThis
);
2120 gl
->setColumnStretch(6, 10);
2122 #ifdef HAVE_POSIX_ACL
2123 KACLEditWidget
*extendedACLs
= 0;
2125 // FIXME make it work with partial entries
2126 if ( properties
->items().count() == 1 ) {
2127 QByteArray path
= QFile::encodeName( properties
->item().url().toLocalFile() );
2128 d
->fileSystemSupportsACLs
= fileSystemSupportsACL( path
);
2130 if ( d
->fileSystemSupportsACLs
) {
2131 std::for_each( theNotSpecials
.begin(), theNotSpecials
.end(), std::mem_fun( &QWidget::hide
) );
2132 extendedACLs
= new KACLEditWidget( mainw
);
2133 vbox
->addWidget(extendedACLs
);
2134 if ( d
->extendedACL
.isValid() && d
->extendedACL
.isExtended() )
2135 extendedACLs
->setACL( d
->extendedACL
);
2137 extendedACLs
->setACL( KACL( aPermissions
) );
2139 if ( d
->defaultACL
.isValid() )
2140 extendedACLs
->setDefaultACL( d
->defaultACL
);
2142 if ( properties
->items().first().isDir() )
2143 extendedACLs
->setAllowDefaults( true );
2146 dlg
.setMainWidget( mainw
);
2147 if (dlg
.exec() != KDialog::Accepted
)
2150 mode_t andPermissions
= mode_t(~0);
2151 mode_t orPermissions
= 0;
2152 for (int row
= 0; row
< 3; ++row
)
2153 for (int col
= 0; col
< 4; ++col
) {
2154 switch (cba
[row
][col
]->checkState())
2157 orPermissions
|= fperm
[row
][col
];
2160 andPermissions
&= ~fperm
[row
][col
];
2162 default: // NoChange
2167 d
->isIrregular
= false;
2168 const KFileItemList items
= properties
->items();
2169 KFileItemList::const_iterator it
= items
.begin();
2170 const KFileItemList::const_iterator kend
= items
.end();
2171 for ( ; it
!= kend
; ++it
) {
2172 if (isIrregular(((*it
).permissions() & andPermissions
) | orPermissions
,
2173 (*it
).isDir(), (*it
).isLink())) {
2174 d
->isIrregular
= true;
2179 d
->permissions
= orPermissions
;
2180 d
->partialPermissions
= andPermissions
;
2182 #ifdef HAVE_POSIX_ACL
2183 // override with the acls, if present
2184 if ( extendedACLs
) {
2185 d
->extendedACL
= extendedACLs
->getACL();
2186 d
->defaultACL
= extendedACLs
->getDefaultACL();
2187 d
->hasExtendedACL
= d
->extendedACL
.isExtended() || d
->defaultACL
.isValid();
2188 d
->permissions
= d
->extendedACL
.basePermissions();
2189 d
->permissions
|= ( andPermissions
| orPermissions
) & ( S_ISUID
|S_ISGID
|S_ISVTX
);
2193 updateAccessControls();
2197 // QString KFilePermissionsPropsPlugin::tabName () const
2199 // return i18n ("&Permissions");
2202 KFilePermissionsPropsPlugin::~KFilePermissionsPropsPlugin()
2207 bool KFilePermissionsPropsPlugin::supports( const KFileItemList
& /*_items*/ )
2212 // sets a combo box in the Access Control frame
2213 void KFilePermissionsPropsPlugin::setComboContent(QComboBox
*combo
, PermissionsTarget target
,
2214 mode_t permissions
, mode_t partial
) {
2216 if (d
->isIrregular
) //#176876
2219 if (d
->pmode
== PermissionsOnlyLinks
) {
2220 combo
->addItem(i18n("Link"));
2221 combo
->setCurrentIndex(0);
2225 mode_t tMask
= permissionsMasks
[target
];
2227 for (textIndex
= 0; standardPermissions
[textIndex
] != (mode_t
)-1; textIndex
++) {
2228 if ((standardPermissions
[textIndex
]&tMask
) == (permissions
&tMask
&(UniRead
|UniWrite
)))
2231 Q_ASSERT(standardPermissions
[textIndex
] != (mode_t
)-1); // must not happen, would be irreglar
2233 for (int i
= 0; permissionsTexts
[(int)d
->pmode
][i
]; i
++)
2234 combo
->addItem(i18n(permissionsTexts
[(int)d
->pmode
][i
]));
2236 if (partial
& tMask
& ~UniExec
) {
2237 combo
->addItem(i18n("Varying (No Change)"));
2238 combo
->setCurrentIndex(3);
2241 combo
->setCurrentIndex(textIndex
);
2245 // permissions are irregular if they cant be displayed in a combo box.
2246 bool KFilePermissionsPropsPlugin::isIrregular(mode_t permissions
, bool isDir
, bool isLink
) {
2247 if (isLink
) // links are always ok
2250 mode_t p
= permissions
;
2251 if (p
& (S_ISUID
| S_ISGID
)) // setuid/setgid -> irregular
2254 p
&= ~S_ISVTX
; // ignore sticky on dirs
2256 // check supported flag combinations
2257 mode_t p0
= p
& UniOwner
;
2258 if ((p0
!= 0) && (p0
!= (S_IRUSR
| S_IXUSR
)) && (p0
!= UniOwner
))
2261 if ((p0
!= 0) && (p0
!= (S_IRGRP
| S_IXGRP
)) && (p0
!= UniGroup
))
2264 if ((p0
!= 0) && (p0
!= (S_IROTH
| S_IXOTH
)) && (p0
!= UniOthers
))
2268 if (p
& S_ISVTX
) // sticky on file -> irregular
2271 // check supported flag combinations
2272 mode_t p0
= p
& UniOwner
;
2273 bool usrXPossible
= !p0
; // true if this file could be an executable
2275 if ((p0
== S_IXUSR
) || (p0
== (S_IWUSR
| S_IXUSR
)))
2277 usrXPossible
= true;
2279 else if (p0
== S_IWUSR
)
2283 bool grpXPossible
= !p0
; // true if this file could be an executable
2285 if ((p0
== S_IXGRP
) || (p0
== (S_IWGRP
| S_IXGRP
)))
2287 grpXPossible
= true;
2289 else if (p0
== S_IWGRP
)
2292 grpXPossible
= true;
2295 bool othXPossible
= !p0
; // true if this file could be an executable
2297 if ((p0
== S_IXOTH
) || (p0
== (S_IWOTH
| S_IXOTH
)))
2299 othXPossible
= true;
2301 else if (p0
== S_IWOTH
)
2304 // check that there either all targets are executable-compatible, or none
2305 return (p
& UniExec
) && !(usrXPossible
&& grpXPossible
&& othXPossible
);
2308 // enables/disabled the widgets in the Access Control frame
2309 void KFilePermissionsPropsPlugin::enableAccessControls(bool enable
) {
2310 d
->ownerPermCombo
->setEnabled(enable
);
2311 d
->groupPermCombo
->setEnabled(enable
);
2312 d
->othersPermCombo
->setEnabled(enable
);
2313 if (d
->extraCheckbox
)
2314 d
->extraCheckbox
->setEnabled(enable
);
2315 if ( d
->cbRecursive
)
2316 d
->cbRecursive
->setEnabled(enable
);
2319 // updates all widgets in the Access Control frame
2320 void KFilePermissionsPropsPlugin::updateAccessControls() {
2321 setComboContent(d
->ownerPermCombo
, PermissionsOwner
,
2322 d
->permissions
, d
->partialPermissions
);
2323 setComboContent(d
->groupPermCombo
, PermissionsGroup
,
2324 d
->permissions
, d
->partialPermissions
);
2325 setComboContent(d
->othersPermCombo
, PermissionsOthers
,
2326 d
->permissions
, d
->partialPermissions
);
2329 case PermissionsOnlyLinks
:
2330 enableAccessControls(false);
2332 case PermissionsOnlyFiles
:
2333 enableAccessControls(d
->canChangePermissions
&& !d
->isIrregular
&& !d
->hasExtendedACL
);
2334 if (d
->canChangePermissions
)
2335 d
->explanationLabel
->setText(d
->isIrregular
|| d
->hasExtendedACL
?
2336 i18np("This file uses advanced permissions",
2337 "These files use advanced permissions.",
2338 properties
->items().count()) : "");
2339 if (d
->partialPermissions
& UniExec
) {
2340 d
->extraCheckbox
->setTristate();
2341 d
->extraCheckbox
->setCheckState(Qt::PartiallyChecked
);
2344 d
->extraCheckbox
->setTristate(false);
2345 d
->extraCheckbox
->setChecked(d
->permissions
& UniExec
);
2348 case PermissionsOnlyDirs
:
2349 enableAccessControls(d
->canChangePermissions
&& !d
->isIrregular
&& !d
->hasExtendedACL
);
2350 // if this is a dir, and we can change permissions, don't dis-allow
2351 // recursive, we can do that for ACL setting.
2352 if ( d
->cbRecursive
)
2353 d
->cbRecursive
->setEnabled( d
->canChangePermissions
&& !d
->isIrregular
);
2355 if (d
->canChangePermissions
)
2356 d
->explanationLabel
->setText(d
->isIrregular
|| d
->hasExtendedACL
?
2357 i18np("This folder uses advanced permissions.",
2358 "These folders use advanced permissions.",
2359 properties
->items().count()) : "");
2360 if (d
->partialPermissions
& S_ISVTX
) {
2361 d
->extraCheckbox
->setTristate();
2362 d
->extraCheckbox
->setCheckState(Qt::PartiallyChecked
);
2365 d
->extraCheckbox
->setTristate(false);
2366 d
->extraCheckbox
->setChecked(d
->permissions
& S_ISVTX
);
2369 case PermissionsMixed
:
2370 enableAccessControls(d
->canChangePermissions
&& !d
->isIrregular
&& !d
->hasExtendedACL
);
2371 if (d
->canChangePermissions
)
2372 d
->explanationLabel
->setText(d
->isIrregular
|| d
->hasExtendedACL
?
2373 i18n("These files use advanced permissions.") : "");
2375 if (d
->partialPermissions
& S_ISVTX
) {
2376 d
->extraCheckbox
->setTristate();
2377 d
->extraCheckbox
->setCheckState(Qt::PartiallyChecked
);
2380 d
->extraCheckbox
->setTristate(false);
2381 d
->extraCheckbox
->setChecked(d
->permissions
& S_ISVTX
);
2387 // gets masks for files and dirs from the Access Control frame widgets
2388 void KFilePermissionsPropsPlugin::getPermissionMasks(mode_t
&andFilePermissions
,
2389 mode_t
&andDirPermissions
,
2390 mode_t
&orFilePermissions
,
2391 mode_t
&orDirPermissions
) {
2392 andFilePermissions
= mode_t(~UniSpecial
);
2393 andDirPermissions
= mode_t(~(S_ISUID
|S_ISGID
));
2394 orFilePermissions
= 0;
2395 orDirPermissions
= 0;
2399 mode_t m
= standardPermissions
[d
->ownerPermCombo
->currentIndex()];
2400 if (m
!= (mode_t
) -1) {
2401 orFilePermissions
|= m
& UniOwner
;
2402 if ((m
& UniOwner
) &&
2403 ((d
->pmode
== PermissionsMixed
) ||
2404 ((d
->pmode
== PermissionsOnlyFiles
) && (d
->extraCheckbox
->checkState() == Qt::PartiallyChecked
))))
2405 andFilePermissions
&= ~(S_IRUSR
| S_IWUSR
);
2407 andFilePermissions
&= ~(S_IRUSR
| S_IWUSR
| S_IXUSR
);
2408 if ((m
& S_IRUSR
) && (d
->extraCheckbox
->checkState() == Qt::Checked
))
2409 orFilePermissions
|= S_IXUSR
;
2412 orDirPermissions
|= m
& UniOwner
;
2414 orDirPermissions
|= S_IXUSR
;
2415 andDirPermissions
&= ~(S_IRUSR
| S_IWUSR
| S_IXUSR
);
2418 m
= standardPermissions
[d
->groupPermCombo
->currentIndex()];
2419 if (m
!= (mode_t
) -1) {
2420 orFilePermissions
|= m
& UniGroup
;
2421 if ((m
& UniGroup
) &&
2422 ((d
->pmode
== PermissionsMixed
) ||
2423 ((d
->pmode
== PermissionsOnlyFiles
) && (d
->extraCheckbox
->checkState() == Qt::PartiallyChecked
))))
2424 andFilePermissions
&= ~(S_IRGRP
| S_IWGRP
);
2426 andFilePermissions
&= ~(S_IRGRP
| S_IWGRP
| S_IXGRP
);
2427 if ((m
& S_IRGRP
) && (d
->extraCheckbox
->checkState() == Qt::Checked
))
2428 orFilePermissions
|= S_IXGRP
;
2431 orDirPermissions
|= m
& UniGroup
;
2433 orDirPermissions
|= S_IXGRP
;
2434 andDirPermissions
&= ~(S_IRGRP
| S_IWGRP
| S_IXGRP
);
2437 m
= d
->othersPermCombo
->currentIndex() >= 0 ? standardPermissions
[d
->othersPermCombo
->currentIndex()] : (mode_t
)-1;
2438 if (m
!= (mode_t
) -1) {
2439 orFilePermissions
|= m
& UniOthers
;
2440 if ((m
& UniOthers
) &&
2441 ((d
->pmode
== PermissionsMixed
) ||
2442 ((d
->pmode
== PermissionsOnlyFiles
) && (d
->extraCheckbox
->checkState() == Qt::PartiallyChecked
))))
2443 andFilePermissions
&= ~(S_IROTH
| S_IWOTH
);
2445 andFilePermissions
&= ~(S_IROTH
| S_IWOTH
| S_IXOTH
);
2446 if ((m
& S_IROTH
) && (d
->extraCheckbox
->checkState() == Qt::Checked
))
2447 orFilePermissions
|= S_IXOTH
;
2450 orDirPermissions
|= m
& UniOthers
;
2452 orDirPermissions
|= S_IXOTH
;
2453 andDirPermissions
&= ~(S_IROTH
| S_IWOTH
| S_IXOTH
);
2456 if (((d
->pmode
== PermissionsMixed
) || (d
->pmode
== PermissionsOnlyDirs
)) &&
2457 (d
->extraCheckbox
->checkState() != Qt::PartiallyChecked
)) {
2458 andDirPermissions
&= ~S_ISVTX
;
2459 if (d
->extraCheckbox
->checkState() == Qt::Checked
)
2460 orDirPermissions
|= S_ISVTX
;
2464 void KFilePermissionsPropsPlugin::applyChanges()
2466 mode_t orFilePermissions
;
2467 mode_t orDirPermissions
;
2468 mode_t andFilePermissions
;
2469 mode_t andDirPermissions
;
2471 if (!d
->canChangePermissions
)
2474 if (!d
->isIrregular
)
2475 getPermissionMasks(andFilePermissions
,
2480 orFilePermissions
= d
->permissions
;
2481 andFilePermissions
= d
->partialPermissions
;
2482 orDirPermissions
= d
->permissions
;
2483 andDirPermissions
= d
->partialPermissions
;
2486 QString owner
, group
;
2488 owner
= d
->usrEdit
->text();
2490 group
= d
->grpEdit
->text();
2491 else if (d
->grpCombo
)
2492 group
= d
->grpCombo
->currentText();
2494 if (owner
== d
->strOwner
)
2495 owner
.clear(); // no change
2497 if (group
== d
->strGroup
)
2500 bool recursive
= d
->cbRecursive
&& d
->cbRecursive
->isChecked();
2501 bool permissionChange
= false;
2503 KFileItemList files
, dirs
;
2504 const KFileItemList items
= properties
->items();
2505 KFileItemList::const_iterator it
= items
.begin();
2506 const KFileItemList::const_iterator kend
= items
.end();
2507 for ( ; it
!= kend
; ++it
) {
2508 if ((*it
).isDir()) {
2510 if ((*it
).permissions() != (((*it
).permissions() & andDirPermissions
) | orDirPermissions
))
2511 permissionChange
= true;
2513 else if ((*it
).isFile()) {
2515 if ((*it
).permissions() != (((*it
).permissions() & andFilePermissions
) | orFilePermissions
))
2516 permissionChange
= true;
2520 const bool ACLChange
= ( d
->extendedACL
!= properties
->item().ACL() );
2521 const bool defaultACLChange
= ( d
->defaultACL
!= properties
->item().defaultACL() );
2523 if (owner
.isEmpty() && group
.isEmpty() && !recursive
2524 && !permissionChange
&& !ACLChange
&& !defaultACLChange
)
2528 if (files
.count() > 0) {
2529 job
= KIO::chmod( files
, orFilePermissions
, ~andFilePermissions
,
2530 owner
, group
, false );
2531 if ( ACLChange
&& d
->fileSystemSupportsACLs
)
2532 job
->addMetaData( "ACL_STRING", d
->extendedACL
.isValid()?d
->extendedACL
.asString():"ACL_DELETE" );
2533 if ( defaultACLChange
&& d
->fileSystemSupportsACLs
)
2534 job
->addMetaData( "DEFAULT_ACL_STRING", d
->defaultACL
.isValid()?d
->defaultACL
.asString():"ACL_DELETE" );
2536 connect( job
, SIGNAL( result( KJob
* ) ),
2537 SLOT( slotChmodResult( KJob
* ) ) );
2538 QEventLoop eventLoop
;
2539 connect(this, SIGNAL(leaveModality()),
2540 &eventLoop
, SLOT(quit()));
2541 eventLoop
.exec(QEventLoop::ExcludeUserInputEvents
);
2543 if (dirs
.count() > 0) {
2544 job
= KIO::chmod( dirs
, orDirPermissions
, ~andDirPermissions
,
2545 owner
, group
, recursive
);
2546 if ( ACLChange
&& d
->fileSystemSupportsACLs
)
2547 job
->addMetaData( "ACL_STRING", d
->extendedACL
.isValid()?d
->extendedACL
.asString():"ACL_DELETE" );
2548 if ( defaultACLChange
&& d
->fileSystemSupportsACLs
)
2549 job
->addMetaData( "DEFAULT_ACL_STRING", d
->defaultACL
.isValid()?d
->defaultACL
.asString():"ACL_DELETE" );
2551 connect( job
, SIGNAL( result( KJob
* ) ),
2552 SLOT( slotChmodResult( KJob
* ) ) );
2553 QEventLoop eventLoop
;
2554 connect(this, SIGNAL(leaveModality()),
2555 &eventLoop
, SLOT(quit()));
2556 eventLoop
.exec(QEventLoop::ExcludeUserInputEvents
);
2560 void KFilePermissionsPropsPlugin::slotChmodResult( KJob
* job
)
2562 kDebug(250) << "KFilePermissionsPropsPlugin::slotChmodResult";
2564 job
->uiDelegate()->showErrorMessage();
2565 // allow apply() to return
2566 emit
leaveModality();
2572 class KUrlPropsPlugin::KUrlPropsPluginPrivate
2575 KUrlPropsPluginPrivate()
2578 ~KUrlPropsPluginPrivate()
2583 KUrlRequester
*URLEdit
;
2587 KUrlPropsPlugin::KUrlPropsPlugin( KPropertiesDialog
*_props
)
2588 : KPropertiesDialogPlugin( _props
),d(new KUrlPropsPluginPrivate
)
2590 d
->m_frame
= new QFrame();
2591 properties
->addPage(d
->m_frame
, i18n("U&RL"));
2592 QVBoxLayout
*layout
= new QVBoxLayout(d
->m_frame
);
2593 layout
->setMargin(0);
2594 layout
->setSpacing(KDialog::spacingHint());
2597 l
= new QLabel( d
->m_frame
);
2598 l
->setObjectName( QLatin1String( "Label_1" ) );
2599 l
->setText( i18n("URL:") );
2600 layout
->addWidget(l
, Qt::AlignRight
);
2602 d
->URLEdit
= new KUrlRequester( d
->m_frame
);
2603 layout
->addWidget(d
->URLEdit
);
2605 KUrl url
= KIO::NetAccess::mostLocalUrl( properties
->kurl(), properties
);
2606 if (url
.isLocalFile()) {
2607 QString path
= url
.toLocalFile();
2610 if ( !f
.open( QIODevice::ReadOnly
) ) {
2615 KDesktopFile
config( path
);
2616 const KConfigGroup dg
= config
.desktopGroup();
2617 d
->URLStr
= dg
.readPathEntry( "URL", QString() );
2619 if (!d
->URLStr
.isEmpty()) {
2620 d
->URLEdit
->setUrl( KUrl(d
->URLStr
) );
2624 connect( d
->URLEdit
, SIGNAL( textChanged( const QString
& ) ),
2625 this, SIGNAL( changed() ) );
2627 layout
->addStretch (1);
2630 KUrlPropsPlugin::~KUrlPropsPlugin()
2635 // QString KUrlPropsPlugin::tabName () const
2637 // return i18n ("U&RL");
2640 bool KUrlPropsPlugin::supports( const KFileItemList
& _items
)
2642 if ( _items
.count() != 1 )
2644 const KFileItem item
= _items
.first();
2645 // check if desktop file
2646 if (!item
.isDesktopFile())
2649 // open file and check type
2651 KUrl url
= item
.mostLocalUrl(isLocal
);
2656 KDesktopFile
config( url
.path() );
2657 return config
.hasLinkType();
2660 void KUrlPropsPlugin::applyChanges()
2662 KUrl url
= KIO::NetAccess::mostLocalUrl( properties
->kurl(), properties
);
2663 if (!url
.isLocalFile()) {
2664 //FIXME: 4.2 add this: KMessageBox::sorry(0, i18n("Could not save properties. Only entries on local file systems are supported."));
2668 QString path
= url
.path();
2671 if ( !f
.open( QIODevice::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>", path
));
2678 KDesktopFile
config( path
);
2679 KConfigGroup dg
= config
.desktopGroup();
2680 dg
.writeEntry( "Type", QString::fromLatin1("Link"));
2681 dg
.writePathEntry( "URL", d
->URLEdit
->url().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 ( dg
.hasKey("Name") )
2686 QString nameStr
= nameFromFileName(properties
->kurl().fileName());
2687 dg
.writeEntry( "Name", nameStr
);
2688 dg
.writeEntry( "Name", nameStr
, KConfigBase::Persistent
|KConfigBase::Localized
);
2694 /* ----------------------------------------------------
2696 * KDevicePropsPlugin
2698 * -------------------------------------------------- */
2700 class KDevicePropsPlugin::KDevicePropsPluginPrivate
2703 KDevicePropsPluginPrivate()
2706 ~KDevicePropsPluginPrivate()
2711 QStringList mountpointlist
;
2712 QLabel
*m_freeSpaceText
;
2713 QLabel
*m_freeSpaceLabel
;
2714 QProgressBar
*m_freeSpaceBar
;
2718 QCheckBox
* readonly
;
2719 KIconButton
* unmounted
;
2721 QStringList m_devicelist
;
2724 KDevicePropsPlugin::KDevicePropsPlugin( KPropertiesDialog
*_props
) : KPropertiesDialogPlugin( _props
),d(new KDevicePropsPluginPrivate
)
2726 d
->m_frame
= new QFrame();
2727 properties
->addPage(d
->m_frame
, i18n("De&vice"));
2729 QStringList devices
;
2730 const KMountPoint::List mountPoints
= KMountPoint::possibleMountPoints();
2732 for(KMountPoint::List::ConstIterator it
= mountPoints
.begin();
2733 it
!= mountPoints
.end(); ++it
)
2735 const KMountPoint::Ptr mp
= (*it
);
2736 QString mountPoint
= mp
->mountPoint();
2737 QString device
= mp
->mountedFrom();
2738 kDebug()<<"mountPoint :"<<mountPoint
<<" device :"<<device
<<" mp->mountType() :"<<mp
->mountType();
2740 if ((mountPoint
!= "-") && (mountPoint
!= "none") && !mountPoint
.isEmpty()
2741 && device
!= "none")
2743 devices
.append( device
+ QString::fromLatin1(" (")
2744 + mountPoint
+ QString::fromLatin1(")") );
2745 d
->m_devicelist
.append(device
);
2746 d
->mountpointlist
.append(mountPoint
);
2750 QGridLayout
*layout
= new QGridLayout( d
->m_frame
);
2752 layout
->setMargin(0);
2753 layout
->setSpacing(KDialog::spacingHint());
2754 layout
->setColumnStretch(1, 1);
2757 label
= new QLabel( d
->m_frame
);
2758 label
->setText( devices
.count() == 0 ?
2759 i18n("Device (/dev/fd0):") : // old style
2760 i18n("Device:") ); // new style (combobox)
2761 layout
->addWidget(label
, 0, 0, Qt::AlignRight
);
2763 d
->device
= new KComboBox( d
->m_frame
);
2764 d
->device
->setObjectName( QLatin1String( "ComboBox_device" ) );
2765 d
->device
->setEditable( true );
2766 d
->device
->addItems( devices
);
2767 layout
->addWidget(d
->device
, 0, 1);
2768 connect( d
->device
, SIGNAL( activated( int ) ),
2769 this, SLOT( slotActivated( int ) ) );
2771 d
->readonly
= new QCheckBox( d
->m_frame
);
2772 d
->readonly
->setObjectName( QLatin1String( "CheckBox_readonly" ) );
2773 d
->readonly
->setText( i18n("Read only") );
2774 layout
->addWidget(d
->readonly
, 1, 1);
2776 label
= new QLabel( d
->m_frame
);
2777 label
->setText( i18n("File system:") );
2778 layout
->addWidget(label
, 2, 0, Qt::AlignRight
);
2780 QLabel
*fileSystem
= new QLabel( d
->m_frame
);
2781 layout
->addWidget(fileSystem
, 2, 1);
2783 label
= new QLabel( d
->m_frame
);
2784 label
->setText( devices
.count()==0 ?
2785 i18n("Mount point (/mnt/floppy):") : // old style
2786 i18n("Mount point:")); // new style (combobox)
2787 layout
->addWidget(label
, 3, 0, Qt::AlignRight
);
2789 d
->mountpoint
= new QLabel( d
->m_frame
);
2790 d
->mountpoint
->setObjectName( QLatin1String( "LineEdit_mountpoint" ) );
2792 layout
->addWidget(d
->mountpoint
, 3, 1);
2795 d
->m_freeSpaceText
= new QLabel(i18n("Device usage:"), d
->m_frame
);
2796 layout
->addWidget(d
->m_freeSpaceText
, 4, 0, Qt::AlignRight
);
2798 d
->m_freeSpaceLabel
= new QLabel( d
->m_frame
);
2799 layout
->addWidget( d
->m_freeSpaceLabel
, 4, 1 );
2801 d
->m_freeSpaceBar
= new QProgressBar( d
->m_frame
);
2802 d
->m_freeSpaceBar
->setObjectName( "freeSpaceBar" );
2803 layout
->addWidget(d
->m_freeSpaceBar
, 5, 0, 1, 2);
2805 // we show it in the slot when we know the values
2806 d
->m_freeSpaceText
->hide();
2807 d
->m_freeSpaceLabel
->hide();
2808 d
->m_freeSpaceBar
->hide();
2810 KSeparator
* sep
= new KSeparator( Qt::Horizontal
, d
->m_frame
);
2811 layout
->addWidget(sep
, 6, 0, 1, 2);
2813 d
->unmounted
= new KIconButton( d
->m_frame
);
2814 int bsize
= 66 + 2 * d
->unmounted
->style()->pixelMetric(QStyle::PM_ButtonMargin
);
2815 d
->unmounted
->setFixedSize(bsize
, bsize
);
2816 d
->unmounted
->setIconType(KIconLoader::Desktop
, KIconLoader::Device
);
2817 layout
->addWidget(d
->unmounted
, 7, 0);
2819 label
= new QLabel( i18n("Unmounted Icon"), d
->m_frame
);
2820 layout
->addWidget(label
, 7, 1);
2822 layout
->setRowStretch(8, 1);
2824 KUrl url
= KIO::NetAccess::mostLocalUrl( _props
->kurl(), _props
);
2825 if (!url
.isLocalFile()) {
2828 QString path
= url
.toLocalFile();
2831 if ( !f
.open( QIODevice::ReadOnly
) )
2835 const KDesktopFile
_config( path
);
2836 const KConfigGroup config
= _config
.desktopGroup();
2837 QString deviceStr
= config
.readEntry( "Dev" );
2838 QString mountPointStr
= config
.readEntry( "MountPoint" );
2839 bool ro
= config
.readEntry( "ReadOnly", false );
2840 QString unmountedStr
= config
.readEntry( "UnmountIcon" );
2842 fileSystem
->setText(config
.readEntry("FSType"));
2844 d
->device
->setEditText( deviceStr
);
2845 if ( !deviceStr
.isEmpty() ) {
2846 // Set default options for this device (first matching entry)
2847 int index
= d
->m_devicelist
.indexOf(deviceStr
);
2850 //kDebug(250) << "found it " << index;
2851 slotActivated( index
);
2855 if ( !mountPointStr
.isEmpty() )
2857 d
->mountpoint
->setText( mountPointStr
);
2861 d
->readonly
->setChecked( ro
);
2863 if ( unmountedStr
.isEmpty() )
2864 unmountedStr
= KMimeType::defaultMimeTypePtr()->iconName(); // default icon
2866 d
->unmounted
->setIcon( unmountedStr
);
2868 connect( d
->device
, SIGNAL( activated( int ) ),
2869 this, SIGNAL( changed() ) );
2870 connect( d
->device
, SIGNAL( textChanged( const QString
& ) ),
2871 this, SIGNAL( changed() ) );
2872 connect( d
->readonly
, SIGNAL( toggled( bool ) ),
2873 this, SIGNAL( changed() ) );
2874 connect( d
->unmounted
, SIGNAL( iconChanged( const QString
& ) ),
2875 this, SIGNAL( changed() ) );
2877 connect( d
->device
, SIGNAL( textChanged( const QString
& ) ),
2878 this, SLOT( slotDeviceChanged() ) );
2881 KDevicePropsPlugin::~KDevicePropsPlugin()
2886 // QString KDevicePropsPlugin::tabName () const
2888 // return i18n ("De&vice");
2891 void KDevicePropsPlugin::updateInfo()
2893 // we show it in the slot when we know the values
2894 d
->m_freeSpaceText
->hide();
2895 d
->m_freeSpaceLabel
->hide();
2896 d
->m_freeSpaceBar
->hide();
2898 if ( !d
->mountpoint
->text().isEmpty() )
2900 KDiskFreeSpaceInfo info
= KDiskFreeSpaceInfo::freeSpaceInfo( d
->mountpoint
->text() );
2901 slotFoundMountPoint( info
.mountPoint(), info
.size()/1024, info
.used()/1024, info
.available()/1024);
2905 void KDevicePropsPlugin::slotActivated( int index
)
2907 // Update mountpoint so that it matches the device that was selected in the combo
2908 d
->device
->setEditText( d
->m_devicelist
[index
] );
2909 d
->mountpoint
->setText( d
->mountpointlist
[index
] );
2914 void KDevicePropsPlugin::slotDeviceChanged()
2916 // Update mountpoint so that it matches the typed device
2917 int index
= d
->m_devicelist
.indexOf( d
->device
->currentText() );
2919 d
->mountpoint
->setText( d
->mountpointlist
[index
] );
2921 d
->mountpoint
->setText( QString() );
2926 void KDevicePropsPlugin::slotFoundMountPoint( const QString
&,
2928 quint64
/*kibUsed*/,
2931 d
->m_freeSpaceText
->show();
2932 d
->m_freeSpaceLabel
->show();
2934 int percUsed
= 100 - (int)(100.0 * kibAvail
/ kibSize
);
2936 d
->m_freeSpaceLabel
->setText(
2937 i18nc("Available space out of total partition size (percent used)", "%1 out of %2 (%3% used)",
2938 KIO::convertSizeFromKiB(kibAvail
),
2939 KIO::convertSizeFromKiB(kibSize
),
2940 100 - (int)(100.0 * kibAvail
/ kibSize
) ));
2942 d
->m_freeSpaceBar
->setRange(0, 100);
2943 d
->m_freeSpaceBar
->setValue(percUsed
);
2944 d
->m_freeSpaceBar
->show();
2947 bool KDevicePropsPlugin::supports( const KFileItemList
& _items
)
2949 if ( _items
.count() != 1 )
2951 const KFileItem item
= _items
.first();
2952 // check if desktop file
2953 if (!item
.isDesktopFile())
2956 // open file and check type
2958 KUrl url
= item
.mostLocalUrl(isLocal
);
2963 KDesktopFile
config( url
.path() );
2964 return config
.hasDeviceType();
2967 void KDevicePropsPlugin::applyChanges()
2969 KUrl url
= KIO::NetAccess::mostLocalUrl( properties
->kurl(), properties
);
2970 if ( !url
.isLocalFile() )
2972 QString path
= url
.toLocalFile();
2975 if ( !f
.open( QIODevice::ReadWrite
) )
2977 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient "
2978 "access to write to <b>%1</b>.</qt>", path
));
2983 KDesktopFile
_config( path
);
2984 KConfigGroup config
= _config
.desktopGroup();
2985 config
.writeEntry( "Type", QString::fromLatin1("FSDevice") );
2987 config
.writeEntry( "Dev", d
->device
->currentText() );
2988 config
.writeEntry( "MountPoint", d
->mountpoint
->text() );
2990 config
.writeEntry( "UnmountIcon", d
->unmounted
->icon() );
2991 kDebug(250) << "d->unmounted->icon() = " << d
->unmounted
->icon();
2993 config
.writeEntry( "ReadOnly", d
->readonly
->isChecked() );
2999 /* ----------------------------------------------------
3001 * KDesktopPropsPlugin
3003 * -------------------------------------------------- */
3005 class KDesktopPropsPlugin::KDesktopPropsPluginPrivate
3008 KDesktopPropsPluginPrivate()
3009 : w( new Ui_KPropertiesDesktopBase
)
3010 , m_frame( new QFrame() )
3013 ~KDesktopPropsPluginPrivate()
3017 Ui_KPropertiesDesktopBase
* w
;
3020 QString m_origCommandStr
;
3021 QString m_terminalOptionStr
;
3022 QString m_suidUserStr
;
3023 QString m_dbusStartupType
;
3024 QString m_dbusServiceName
;
3025 bool m_terminalBool
;
3031 KDesktopPropsPlugin::KDesktopPropsPlugin( KPropertiesDialog
*_props
)
3032 : KPropertiesDialogPlugin( _props
), d( new KDesktopPropsPluginPrivate
)
3034 properties
->addPage(d
->m_frame
, i18n("&Application"));
3036 d
->w
->setupUi(d
->m_frame
);
3038 bool bKDesktopMode
= (qApp
->objectName() == "kdesktop");
3043 d
->w
->nameEdit
->hide();
3044 d
->w
->nameLabel
->hide();
3047 d
->w
->pathEdit
->setMode(KFile::Directory
| KFile::LocalOnly
);
3048 d
->w
->pathEdit
->lineEdit()->setAcceptDrops(false);
3050 connect( d
->w
->nameEdit
, SIGNAL( textChanged( const QString
& ) ), this, SIGNAL( changed() ) );
3051 connect( d
->w
->genNameEdit
, SIGNAL( textChanged( const QString
& ) ), this, SIGNAL( changed() ) );
3052 connect( d
->w
->commentEdit
, SIGNAL( textChanged( const QString
& ) ), this, SIGNAL( changed() ) );
3053 connect( d
->w
->commandEdit
, SIGNAL( textChanged( const QString
& ) ), this, SIGNAL( changed() ) );
3054 connect( d
->w
->pathEdit
, SIGNAL( textChanged( const QString
& ) ), this, SIGNAL( changed() ) );
3056 connect( d
->w
->browseButton
, SIGNAL( clicked() ), this, SLOT( slotBrowseExec() ) );
3057 connect( d
->w
->addFiletypeButton
, SIGNAL( clicked() ), this, SLOT( slotAddFiletype() ) );
3058 connect( d
->w
->delFiletypeButton
, SIGNAL( clicked() ), this, SLOT( slotDelFiletype() ) );
3059 connect( d
->w
->advancedButton
, SIGNAL( clicked() ), this, SLOT( slotAdvanced() ) );
3061 // now populate the page
3063 KUrl url
= KIO::NetAccess::mostLocalUrl( _props
->kurl(), _props
);
3064 if (!url
.isLocalFile()) {
3067 QString path
= url
.toLocalFile();
3070 if ( !f
.open( QIODevice::ReadOnly
) )
3074 KDesktopFile
_config( path
);
3075 KConfigGroup config
= _config
.desktopGroup();
3076 QString nameStr
= _config
.readName();
3077 QString genNameStr
= _config
.readGenericName();
3078 QString commentStr
= _config
.readComment();
3079 QString commandStr
= config
.readEntry( "Exec", QString() );
3080 if (commandStr
.startsWith(QLatin1String("ksystraycmd ")))
3082 commandStr
.remove(0, 12);
3083 d
->m_systrayBool
= true;
3086 d
->m_systrayBool
= false;
3088 d
->m_origCommandStr
= commandStr
;
3089 QString pathStr
= config
.readEntry( "Path", QString() ); // not readPathEntry, see kservice.cpp
3090 d
->m_terminalBool
= config
.readEntry( "Terminal", false );
3091 d
->m_terminalOptionStr
= config
.readEntry( "TerminalOptions" );
3092 d
->m_suidBool
= config
.readEntry( "X-KDE-SubstituteUID", false );
3093 d
->m_suidUserStr
= config
.readEntry( "X-KDE-Username" );
3094 if( config
.hasKey( "StartupNotify" ))
3095 d
->m_startupBool
= config
.readEntry( "StartupNotify", true );
3097 d
->m_startupBool
= config
.readEntry( "X-KDE-StartupNotify", true );
3098 d
->m_dbusStartupType
= config
.readEntry("X-DBUS-StartupType").toLower();
3100 if( d
->m_dbusStartupType
.isEmpty() && config
.hasKey("X-DCOP-ServiceType"))
3101 d
->m_dbusStartupType
= config
.readEntry("X-DCOP-ServiceType").toLower();
3102 // ### should there be a GUI for this setting?
3103 // At least we're copying it over to the local file, to avoid side effects (#157853)
3104 d
->m_dbusServiceName
= config
.readEntry("X-DBUS-ServiceName");
3106 const QStringList mimeTypes
= config
.readXdgListEntry( "MimeType" );
3108 if ( nameStr
.isEmpty() || bKDesktopMode
) {
3109 // We'll use the file name if no name is specified
3110 // because we _need_ a Name for a valid file.
3111 // But let's do it in apply, not here, so that we pick up the right name.
3114 if ( !bKDesktopMode
)
3115 d
->w
->nameEdit
->setText(nameStr
);
3117 d
->w
->genNameEdit
->setText( genNameStr
);
3118 d
->w
->commentEdit
->setText( commentStr
);
3119 d
->w
->commandEdit
->setText( commandStr
);
3120 d
->w
->pathEdit
->lineEdit()->setText( pathStr
);
3122 // was: d->w->filetypeList->setFullWidth(true);
3123 // d->w->filetypeList->header()->setStretchEnabled(true, d->w->filetypeList->columns()-1);
3125 KMimeType::Ptr defaultMimetype
= KMimeType::defaultMimeTypePtr();
3126 for(QStringList::ConstIterator it
= mimeTypes
.begin();
3127 it
!= mimeTypes
.end(); )
3129 KMimeType::Ptr p
= KMimeType::mimeType(*it
, KMimeType::ResolveAliases
);
3132 if (it
!= mimeTypes
.end())
3135 (*it
).toInt(&numeric
);
3144 QTreeWidgetItem
*item
= new QTreeWidgetItem();
3145 item
->setText(0, p
->name());
3146 item
->setText(1, p
->comment());
3147 item
->setText(2, preference
);
3148 d
->w
->filetypeList
->addTopLevelItem(item
);
3151 d
->w
->filetypeList
->resizeColumnToContents(0);
3155 KDesktopPropsPlugin::~KDesktopPropsPlugin()
3160 void KDesktopPropsPlugin::slotAddFiletype()
3162 KMimeTypeChooserDialog
dlg( i18n("Add File Type for %1", properties
->kurl().fileName()),
3163 i18n("Select one or more file types to add:"),
3164 QStringList(), // no preselected mimetypes
3167 KMimeTypeChooser::Comments
|KMimeTypeChooser::Patterns
,
3170 if (dlg
.exec() == KDialog::Accepted
)
3172 foreach(const QString
&mimetype
, dlg
.chooser()->mimeTypes())
3174 KMimeType::Ptr p
= KMimeType::mimeType(mimetype
);
3179 int count
= d
->w
->filetypeList
->topLevelItemCount();
3180 for (int i
= 0; !found
&& i
< count
; ++i
) {
3181 if (d
->w
->filetypeList
->topLevelItem(i
)->text(0) == mimetype
) {
3186 QTreeWidgetItem
*item
= new QTreeWidgetItem();
3187 item
->setText(0, p
->name());
3188 item
->setText(1, p
->comment());
3189 d
->w
->filetypeList
->addTopLevelItem(item
);
3191 d
->w
->filetypeList
->resizeColumnToContents(0);
3197 void KDesktopPropsPlugin::slotDelFiletype()
3199 QTreeWidgetItem
*cur
= d
->w
->filetypeList
->currentItem();
3206 void KDesktopPropsPlugin::checkCommandChanged()
3208 if (KRun::binaryName(d
->w
->commandEdit
->text(), true) !=
3209 KRun::binaryName(d
->m_origCommandStr
, true))
3211 d
->m_origCommandStr
= d
->w
->commandEdit
->text();
3212 d
->m_dbusStartupType
.clear(); // Reset
3213 d
->m_dbusServiceName
.clear();
3217 void KDesktopPropsPlugin::applyChanges()
3219 kDebug(250) << "KDesktopPropsPlugin::applyChanges";
3221 KUrl url
= KIO::NetAccess::mostLocalUrl( properties
->kurl(), properties
);
3222 if (!url
.isLocalFile()) {
3223 //FIXME: 4.2 add this: KMessageBox::sorry(0, i18n("Could not save properties. Only entries on local file systems are supported."));
3226 QString path
= url
.toLocalFile();
3230 if ( !f
.open( QIODevice::ReadWrite
) ) {
3231 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have "
3232 "sufficient access to write to <b>%1</b>.</qt>", path
));
3237 // If the command is changed we reset certain settings that are strongly
3238 // coupled to the command.
3239 checkCommandChanged();
3241 KDesktopFile
_config( path
);
3242 KConfigGroup config
= _config
.desktopGroup();
3243 config
.writeEntry( "Type", QString::fromLatin1("Application"));
3244 config
.writeEntry( "Comment", d
->w
->commentEdit
->text() );
3245 config
.writeEntry( "Comment", d
->w
->commentEdit
->text(), KConfigGroup::Persistent
|KConfigGroup::Localized
); // for compat
3246 config
.writeEntry( "GenericName", d
->w
->genNameEdit
->text() );
3247 config
.writeEntry( "GenericName", d
->w
->genNameEdit
->text(), KConfigGroup::Persistent
|KConfigGroup::Localized
); // for compat
3249 if (d
->m_systrayBool
)
3250 config
.writeEntry( "Exec", d
->w
->commandEdit
->text().prepend("ksystraycmd ") );
3252 config
.writeEntry( "Exec", d
->w
->commandEdit
->text() );
3253 config
.writeEntry( "Path", d
->w
->pathEdit
->lineEdit()->text() ); // not writePathEntry, see kservice.cpp
3256 QStringList mimeTypes
;
3257 int count
= d
->w
->filetypeList
->topLevelItemCount();
3258 for (int i
= 0; i
< count
; ++i
) {
3259 QTreeWidgetItem
*item
= d
->w
->filetypeList
->topLevelItem(i
);
3260 QString preference
= item
->text(2);
3261 mimeTypes
.append(item
->text(0));
3262 if (!preference
.isEmpty())
3263 mimeTypes
.append(preference
);
3266 kDebug() << mimeTypes
;
3267 config
.writeXdgListEntry( "MimeType", mimeTypes
);
3269 if ( !d
->w
->nameEdit
->isHidden() ) {
3270 QString nameStr
= d
->w
->nameEdit
->text();
3271 config
.writeEntry( "Name", nameStr
);
3272 config
.writeEntry( "Name", nameStr
, KConfigGroup::Persistent
|KConfigGroup::Localized
);
3275 config
.writeEntry("Terminal", d
->m_terminalBool
);
3276 config
.writeEntry("TerminalOptions", d
->m_terminalOptionStr
);
3277 config
.writeEntry("X-KDE-SubstituteUID", d
->m_suidBool
);
3278 config
.writeEntry("X-KDE-Username", d
->m_suidUserStr
);
3279 config
.writeEntry("StartupNotify", d
->m_startupBool
);
3280 config
.writeEntry("X-DBUS-StartupType", d
->m_dbusStartupType
);
3281 config
.writeEntry("X-DBUS-ServiceName", d
->m_dbusServiceName
);
3284 // KSycoca update needed?
3285 QString sycocaPath
= KGlobal::dirs()->relativeLocation("apps", path
);
3286 bool updateNeeded
= !sycocaPath
.startsWith('/');
3289 sycocaPath
= KGlobal::dirs()->relativeLocation("xdgdata-apps", path
);
3290 updateNeeded
= !sycocaPath
.startsWith('/');
3293 KBuildSycocaProgressDialog::rebuildKSycoca(d
->m_frame
);
3297 void KDesktopPropsPlugin::slotBrowseExec()
3299 KUrl f
= KFileDialog::getOpenUrl( KUrl(),
3300 QString(), d
->m_frame
);
3304 if ( !f
.isLocalFile()) {
3305 KMessageBox::sorry(d
->m_frame
, i18n("Only executables on local file systems are supported."));
3309 QString path
= f
.toLocalFile();
3310 path
= KShell::quoteArg( path
);
3311 d
->w
->commandEdit
->setText( path
);
3314 void KDesktopPropsPlugin::slotAdvanced()
3316 KDialog
dlg( d
->m_frame
);
3317 dlg
.setObjectName( "KPropertiesDesktopAdv" );
3318 dlg
.setModal( true );
3319 dlg
.setCaption( i18n("Advanced Options for %1", properties
->kurl().fileName()) );
3320 dlg
.setButtons( KDialog::Ok
| KDialog::Cancel
);
3321 dlg
.setDefaultButton( KDialog::Ok
);
3322 Ui_KPropertiesDesktopAdvBase w
;
3323 w
.setupUi(dlg
.mainWidget());
3325 // If the command is changed we reset certain settings that are strongly
3326 // coupled to the command.
3327 checkCommandChanged();
3329 // check to see if we use konsole if not do not add the nocloseonexit
3330 // because we don't know how to do this on other terminal applications
3331 KConfigGroup
confGroup( KGlobal::config(), QString::fromLatin1("General") );
3332 QString preferredTerminal
= confGroup
.readPathEntry("TerminalApplication",
3333 QString::fromLatin1("konsole"));
3335 bool terminalCloseBool
= false;
3337 if (preferredTerminal
== "konsole")
3339 terminalCloseBool
= (d
->m_terminalOptionStr
.contains( "--noclose" ) > 0);
3340 w
.terminalCloseCheck
->setChecked(terminalCloseBool
);
3341 d
->m_terminalOptionStr
.remove( "--noclose");
3345 w
.terminalCloseCheck
->hide();
3348 w
.terminalCheck
->setChecked(d
->m_terminalBool
);
3349 w
.terminalEdit
->setText(d
->m_terminalOptionStr
);
3350 w
.terminalCloseCheck
->setEnabled(d
->m_terminalBool
);
3351 w
.terminalEdit
->setEnabled(d
->m_terminalBool
);
3352 w
.terminalEditLabel
->setEnabled(d
->m_terminalBool
);
3354 w
.suidCheck
->setChecked(d
->m_suidBool
);
3355 w
.suidEdit
->setText(d
->m_suidUserStr
);
3356 w
.suidEdit
->setEnabled(d
->m_suidBool
);
3357 w
.suidEditLabel
->setEnabled(d
->m_suidBool
);
3359 w
.startupInfoCheck
->setChecked(d
->m_startupBool
);
3360 w
.systrayCheck
->setChecked(d
->m_systrayBool
);
3362 if (d
->m_dbusStartupType
== "unique")
3363 w
.dbusCombo
->setCurrentIndex(2);
3364 else if (d
->m_dbusStartupType
== "multi")
3365 w
.dbusCombo
->setCurrentIndex(1);
3366 else if (d
->m_dbusStartupType
== "wait")
3367 w
.dbusCombo
->setCurrentIndex(3);
3369 w
.dbusCombo
->setCurrentIndex(0);
3371 // Provide username completion up to 1000 users.
3372 KCompletion
*kcom
= new KCompletion
;
3373 kcom
->setOrder(KCompletion::Sorted
);
3375 int i
, maxEntries
= 1000;
3377 for (i
=0; ((pw
= getpwent()) != 0L) && (i
< maxEntries
); i
++)
3378 kcom
->addItem(QString::fromLatin1(pw
->pw_name
));
3382 w
.suidEdit
->setCompletionObject(kcom
, true);
3383 w
.suidEdit
->setAutoDeleteCompletionObject( true );
3384 w
.suidEdit
->setCompletionMode(KGlobalSettings::CompletionAuto
);
3391 connect( w
.terminalEdit
, SIGNAL( textChanged( const QString
& ) ),
3392 this, SIGNAL( changed() ) );
3393 connect( w
.terminalCloseCheck
, SIGNAL( toggled( bool ) ),
3394 this, SIGNAL( changed() ) );
3395 connect( w
.terminalCheck
, SIGNAL( toggled( bool ) ),
3396 this, SIGNAL( changed() ) );
3397 connect( w
.suidCheck
, SIGNAL( toggled( bool ) ),
3398 this, SIGNAL( changed() ) );
3399 connect( w
.suidEdit
, SIGNAL( textChanged( const QString
& ) ),
3400 this, SIGNAL( changed() ) );
3401 connect( w
.startupInfoCheck
, SIGNAL( toggled( bool ) ),
3402 this, SIGNAL( changed() ) );
3403 connect( w
.systrayCheck
, SIGNAL( toggled( bool ) ),
3404 this, SIGNAL( changed() ) );
3405 connect( w
.dbusCombo
, SIGNAL( activated( int ) ),
3406 this, SIGNAL( changed() ) );
3408 if ( dlg
.exec() == QDialog::Accepted
)
3410 d
->m_terminalOptionStr
= w
.terminalEdit
->text().trimmed();
3411 d
->m_terminalBool
= w
.terminalCheck
->isChecked();
3412 d
->m_suidBool
= w
.suidCheck
->isChecked();
3413 d
->m_suidUserStr
= w
.suidEdit
->text().trimmed();
3414 d
->m_startupBool
= w
.startupInfoCheck
->isChecked();
3415 d
->m_systrayBool
= w
.systrayCheck
->isChecked();
3417 if (w
.terminalCloseCheck
->isChecked())
3419 d
->m_terminalOptionStr
.append(" --noclose");
3422 switch(w
.dbusCombo
->currentIndex())
3424 case 1: d
->m_dbusStartupType
= "multi"; break;
3425 case 2: d
->m_dbusStartupType
= "unique"; break;
3426 case 3: d
->m_dbusStartupType
= "wait"; break;
3427 default: d
->m_dbusStartupType
= "none"; break;
3432 bool KDesktopPropsPlugin::supports( const KFileItemList
& _items
)
3434 if ( _items
.count() != 1 ) {
3438 const KFileItem item
= _items
.first();
3440 // check if desktop file
3441 if (!item
.isDesktopFile()) {
3445 // open file and check type
3447 KUrl url
= item
.mostLocalUrl( isLocal
);
3452 KDesktopFile
config( url
.path() );
3453 return config
.hasApplicationType() &&
3454 KAuthorized::authorize("run_desktop_files") &&
3455 KAuthorized::authorize("shell_access");
3458 #include "kpropertiesdialog.moc"
3459 #include "kpropertiesdialog_p.moc"