• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KIO

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

KDE's Doxygen guidelines are available online.

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal