• 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::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< KPropertiesDialogPlugin * >
QObject
QPushButton
QWidget
copyjob.h
f
static quint32 f(DES_KEY *key, quint32 r, char *subkey)
Definition: des.cpp:378
directorysizejob.h
kWarning
static QDebug kWarning(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
kDebug
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
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
KIO::number
QString number(KIO::filesize_t size)
Converts a size to a string representation Not unlike QString::number(...)
Definition: global.cpp:63
KImageIO::mimeTypes
QStringList mimeTypes(Mode mode=Writing)
Returns a list of MIME types for all KImageIO supported formats.
Definition: kimageio.cpp:64
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-2022 The KDE developers.
Generated on Thu Jul 21 2022 00:00:00 by doxygen 1.9.4 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