kio Library API Documentation

kpropertiesdialog.cpp

00001 /* This file is part of the KDE project 00002 00003 Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> 00004 Copyright (c) 1999, 2000 Preston Brown <pbrown@kde.org> 00005 Copyright (c) 2000 Simon Hausmann <hausmann@kde.org> 00006 Copyright (c) 2000 David Faure <faure@kde.org> 00007 Copyright (c) 2003 Waldo Bastian <bastian@kde.org> 00008 00009 This library is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU Library General Public 00011 License as published by the Free Software Foundation; either 00012 version 2 of the License, or (at your option) any later version. 00013 00014 This library is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 Library General Public License for more details. 00018 00019 You should have received a copy of the GNU Library General Public License 00020 along with this library; see the file COPYING.LIB. If not, write to 00021 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00022 Boston, MA 02111-1307, USA. 00023 */ 00024 00025 /* 00026 * kpropertiesdialog.cpp 00027 * View/Edit Properties of files, locally or remotely 00028 * 00029 * some FilePermissionsPropsPlugin-changes by 00030 * Henner Zeller <zeller@think.de> 00031 * some layout management by 00032 * Bertrand Leconte <B.Leconte@mail.dotcom.fr> 00033 * the rest of the layout management, bug fixes, adaptation to libkio, 00034 * template feature by 00035 * David Faure <faure@kde.org> 00036 * More layout, cleanups, and fixes by 00037 * Preston Brown <pbrown@kde.org> 00038 * Plugin capability, cleanups and port to KDialogBase by 00039 * Simon Hausmann <hausmann@kde.org> 00040 * KDesktopPropsPlugin by 00041 * Waldo Bastian <bastian@kde.org> 00042 */ 00043 00044 #include <config.h> 00045 extern "C" { 00046 #include <pwd.h> 00047 #include <grp.h> 00048 #include <time.h> 00049 } 00050 #include <unistd.h> 00051 #include <errno.h> 00052 #include <assert.h> 00053 00054 #include <qfile.h> 00055 #include <qdir.h> 00056 #include <qlabel.h> 00057 #include <qpushbutton.h> 00058 #include <qcheckbox.h> 00059 #include <qstrlist.h> 00060 #include <qstringlist.h> 00061 #include <qtextstream.h> 00062 #include <qpainter.h> 00063 #include <qlayout.h> 00064 #include <qcombobox.h> 00065 #include <qgroupbox.h> 00066 #include <qwhatsthis.h> 00067 #include <qtooltip.h> 00068 #include <qstyle.h> 00069 00070 #include <kapplication.h> 00071 #include <kdialog.h> 00072 #include <kdirsize.h> 00073 #include <kdirwatch.h> 00074 #include <kdirnotify_stub.h> 00075 #include <kdiskfreesp.h> 00076 #include <kdebug.h> 00077 #include <kdesktopfile.h> 00078 #include <kicondialog.h> 00079 #include <kurl.h> 00080 #include <kurlrequester.h> 00081 #include <klocale.h> 00082 #include <kglobal.h> 00083 #include <kglobalsettings.h> 00084 #include <kstandarddirs.h> 00085 #include <kio/job.h> 00086 #include <kio/chmodjob.h> 00087 #include <kio/renamedlg.h> 00088 #include <kio/netaccess.h> 00089 #include <kfiledialog.h> 00090 #include <kmimetype.h> 00091 #include <kmountpoint.h> 00092 #include <kiconloader.h> 00093 #include <kmessagebox.h> 00094 #include <kservice.h> 00095 #include <kcompletion.h> 00096 #include <klineedit.h> 00097 #include <kseparator.h> 00098 #include <ksqueezedtextlabel.h> 00099 #include <klibloader.h> 00100 #include <ktrader.h> 00101 #include <kparts/componentfactory.h> 00102 #include <kmetaprops.h> 00103 #include <kprocess.h> 00104 #include <krun.h> 00105 #include <klistview.h> 00106 #include "kfilesharedlg.h" 00107 00108 #include "kpropertiesdesktopbase.h" 00109 #include "kpropertiesdesktopadvbase.h" 00110 #include "kpropertiesmimetypebase.h" 00111 00112 #include "kpropertiesdialog.h" 00113 00114 static QString nameFromFileName(QString nameStr) 00115 { 00116 if ( nameStr.endsWith(".desktop") ) 00117 nameStr.truncate( nameStr.length() - 8 ); 00118 if ( nameStr.endsWith(".kdelnk") ) 00119 nameStr.truncate( nameStr.length() - 7 ); 00120 // Make it human-readable (%2F => '/', ...) 00121 nameStr = KIO::decodeFileName( nameStr ); 00122 return nameStr; 00123 } 00124 00125 mode_t KFilePermissionsPropsPlugin::fperm[3][4] = { 00126 {S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID}, 00127 {S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID}, 00128 {S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX} 00129 }; 00130 00131 class KPropertiesDialog::KPropertiesDialogPrivate 00132 { 00133 public: 00134 KPropertiesDialogPrivate() 00135 { 00136 m_aborted = false; 00137 fileSharePage = 0; 00138 } 00139 ~KPropertiesDialogPrivate() 00140 { 00141 } 00142 bool m_aborted:1; 00143 QWidget* fileSharePage; 00144 }; 00145 00146 KPropertiesDialog::KPropertiesDialog (KFileItem* item, 00147 QWidget* parent, const char* name, 00148 bool modal, bool autoShow) 00149 : KDialogBase (KDialogBase::Tabbed, i18n( "Properties for %1" ).arg(KIO::decodeFileName(item->url().fileName())), 00150 KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, 00151 parent, name, modal) 00152 { 00153 d = new KPropertiesDialogPrivate; 00154 assert( item ); 00155 m_items.append( new KFileItem(*item) ); // deep copy 00156 00157 m_singleUrl = item->url(); 00158 assert(!m_singleUrl.isEmpty()); 00159 00160 init (modal, autoShow); 00161 } 00162 00163 KPropertiesDialog::KPropertiesDialog (const QString& title, 00164 QWidget* parent, const char* name, bool modal) 00165 : KDialogBase (KDialogBase::Tabbed, i18n ("Properties for %1").arg(title), 00166 KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, 00167 parent, name, modal) 00168 { 00169 d = new KPropertiesDialogPrivate; 00170 00171 init (modal, false); 00172 } 00173 00174 KPropertiesDialog::KPropertiesDialog (KFileItemList _items, 00175 QWidget* parent, const char* name, 00176 bool modal, bool autoShow) 00177 : KDialogBase (KDialogBase::Tabbed, 00178 i18n( "Properties for %1" ).arg(KIO::decodeFileName(_items.first()->url().fileName())), 00179 KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, 00180 parent, name, modal) 00181 { 00182 d = new KPropertiesDialogPrivate; 00183 00184 assert( !_items.isEmpty() ); 00185 m_singleUrl = _items.first()->url(); 00186 assert(!m_singleUrl.isEmpty()); 00187 00188 KFileItemListIterator it ( _items ); 00189 // Deep copy 00190 for ( ; it.current(); ++it ) 00191 m_items.append( new KFileItem( **it ) ); 00192 00193 init (modal, autoShow); 00194 } 00195 00196 #ifndef KDE_NO_COMPAT 00197 KPropertiesDialog::KPropertiesDialog (const KURL& _url, mode_t /* _mode is now unused */, 00198 QWidget* parent, const char* name, 00199 bool modal, bool autoShow) 00200 : KDialogBase (KDialogBase::Tabbed, 00201 i18n( "Properties for %1" ).arg(KIO::decodeFileName(_url.fileName())), 00202 KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, 00203 parent, name, modal), 00204 m_singleUrl( _url ) 00205 { 00206 d = new KPropertiesDialogPrivate; 00207 00208 KIO::UDSEntry entry; 00209 00210 KIO::NetAccess::stat(_url, entry, parent); 00211 00212 m_items.append( new KFileItem( entry, _url ) ); 00213 init (modal, autoShow); 00214 } 00215 #endif 00216 00217 KPropertiesDialog::KPropertiesDialog (const KURL& _url, 00218 QWidget* parent, const char* name, 00219 bool modal, bool autoShow) 00220 : KDialogBase (KDialogBase::Tabbed, 00221 i18n( "Properties for %1" ).arg(KIO::decodeFileName(_url.fileName())), 00222 KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, 00223 parent, name, modal), 00224 m_singleUrl( _url ) 00225 { 00226 d = new KPropertiesDialogPrivate; 00227 00228 KIO::UDSEntry entry; 00229 00230 KIO::NetAccess::stat(_url, entry, parent); 00231 00232 m_items.append( new KFileItem( entry, _url ) ); 00233 init (modal, autoShow); 00234 } 00235 00236 KPropertiesDialog::KPropertiesDialog (const KURL& _tempUrl, const KURL& _currentDir, 00237 const QString& _defaultName, 00238 QWidget* parent, const char* name, 00239 bool modal, bool autoShow) 00240 : KDialogBase (KDialogBase::Tabbed, 00241 i18n( "Properties for %1" ).arg(KIO::decodeFileName(_tempUrl.fileName())), 00242 KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, 00243 parent, name, modal), 00244 00245 m_singleUrl( _tempUrl ), 00246 m_defaultName( _defaultName ), 00247 m_currentDir( _currentDir ) 00248 { 00249 d = new KPropertiesDialogPrivate; 00250 00251 assert(!m_singleUrl.isEmpty()); 00252 00253 // Create the KFileItem for the _template_ file, in order to read from it. 00254 m_items.append( new KFileItem( KFileItem::Unknown, KFileItem::Unknown, m_singleUrl ) ); 00255 init (modal, autoShow); 00256 } 00257 00258 void KPropertiesDialog::init (bool modal, bool autoShow) 00259 { 00260 m_pageList.setAutoDelete( true ); 00261 m_items.setAutoDelete( true ); 00262 00263 insertPages(); 00264 00265 if (autoShow) 00266 { 00267 if (!modal) 00268 show(); 00269 else 00270 exec(); 00271 } 00272 } 00273 00274 void KPropertiesDialog::showFileSharingPage() 00275 { 00276 if (d->fileSharePage) { 00277 showPage( pageIndex( d->fileSharePage)); 00278 } 00279 } 00280 00281 void KPropertiesDialog::setFileSharingPage(QWidget* page) { 00282 d->fileSharePage = page; 00283 } 00284 00285 00286 void KPropertiesDialog::setFileNameReadOnly( bool ro ) 00287 { 00288 KPropsDlgPlugin *it; 00289 00290 for ( it=m_pageList.first(); it != 0L; it=m_pageList.next() ) 00291 { 00292 KFilePropsPlugin* plugin = dynamic_cast<KFilePropsPlugin*>(it); 00293 if ( plugin ) { 00294 plugin->setFileNameReadOnly( ro ); 00295 break; 00296 } 00297 } 00298 } 00299 00300 void KPropertiesDialog::slotStatResult( KIO::Job * ) 00301 { 00302 } 00303 00304 KPropertiesDialog::~KPropertiesDialog() 00305 { 00306 m_pageList.clear(); 00307 delete d; 00308 } 00309 00310 void KPropertiesDialog::insertPlugin (KPropsDlgPlugin* plugin) 00311 { 00312 connect (plugin, SIGNAL (changed ()), 00313 plugin, SLOT (setDirty ())); 00314 00315 m_pageList.append (plugin); 00316 } 00317 00318 bool KPropertiesDialog::canDisplay( KFileItemList _items ) 00319 { 00320 // TODO: cache the result of those calls. Currently we parse .desktop files far too many times 00321 return KFilePropsPlugin::supports( _items ) || 00322 KFilePermissionsPropsPlugin::supports( _items ) || 00323 KDesktopPropsPlugin::supports( _items ) || 00324 KBindingPropsPlugin::supports( _items ) || 00325 KURLPropsPlugin::supports( _items ) || 00326 KDevicePropsPlugin::supports( _items ) || 00327 KFileMetaPropsPlugin::supports( _items ); 00328 } 00329 00330 void KPropertiesDialog::slotOk() 00331 { 00332 KPropsDlgPlugin *page; 00333 d->m_aborted = false; 00334 00335 KFilePropsPlugin * filePropsPlugin = 0L; 00336 if ( m_pageList.first()->isA("KFilePropsPlugin") ) 00337 filePropsPlugin = static_cast<KFilePropsPlugin *>(m_pageList.first()); 00338 00339 // If any page is dirty, then set the main one (KFilePropsPlugin) as 00340 // dirty too. This is what makes it possible to save changes to a global 00341 // desktop file into a local one. In other cases, it doesn't hurt. 00342 for ( page = m_pageList.first(); page != 0L; page = m_pageList.next() ) 00343 if ( page->isDirty() && filePropsPlugin ) 00344 { 00345 filePropsPlugin->setDirty(); 00346 break; 00347 } 00348 00349 // Apply the changes in the _normal_ order of the tabs now 00350 // This is because in case of renaming a file, KFilePropsPlugin will call 00351 // KPropertiesDialog::rename, so other tab will be ok with whatever order 00352 // BUT for file copied from templates, we need to do the renaming first ! 00353 for ( page = m_pageList.first(); page != 0L && !d->m_aborted; page = m_pageList.next() ) 00354 if ( page->isDirty() ) 00355 { 00356 kdDebug( 250 ) << "applying changes for " << page->className() << endl; 00357 page->applyChanges(); 00358 // applyChanges may change d->m_aborted. 00359 } 00360 else 00361 kdDebug( 250 ) << "skipping page " << page->className() << endl; 00362 00363 if ( !d->m_aborted && filePropsPlugin ) 00364 filePropsPlugin->postApplyChanges(); 00365 00366 if ( !d->m_aborted ) 00367 { 00368 emit applied(); 00369 emit propertiesClosed(); 00370 deleteLater(); 00371 accept(); 00372 } // else, keep dialog open for user to fix the problem. 00373 } 00374 00375 void KPropertiesDialog::slotCancel() 00376 { 00377 emit canceled(); 00378 emit propertiesClosed(); 00379 00380 deleteLater(); 00381 done( Rejected ); 00382 } 00383 00384 void KPropertiesDialog::insertPages() 00385 { 00386 if (m_items.isEmpty()) 00387 return; 00388 00389 if ( KFilePropsPlugin::supports( m_items ) ) 00390 { 00391 KPropsDlgPlugin *p = new KFilePropsPlugin( this ); 00392 insertPlugin (p); 00393 } 00394 00395 if ( KFilePermissionsPropsPlugin::supports( m_items ) ) 00396 { 00397 KPropsDlgPlugin *p = new KFilePermissionsPropsPlugin( this ); 00398 insertPlugin (p); 00399 } 00400 00401 if ( KDesktopPropsPlugin::supports( m_items ) ) 00402 { 00403 KPropsDlgPlugin *p = new KDesktopPropsPlugin( this ); 00404 insertPlugin (p); 00405 } 00406 00407 if ( KBindingPropsPlugin::supports( m_items ) ) 00408 { 00409 KPropsDlgPlugin *p = new KBindingPropsPlugin( this ); 00410 insertPlugin (p); 00411 } 00412 00413 if ( KURLPropsPlugin::supports( m_items ) ) 00414 { 00415 KPropsDlgPlugin *p = new KURLPropsPlugin( this ); 00416 insertPlugin (p); 00417 } 00418 00419 if ( KDevicePropsPlugin::supports( m_items ) ) 00420 { 00421 KPropsDlgPlugin *p = new KDevicePropsPlugin( this ); 00422 insertPlugin (p); 00423 } 00424 00425 if ( KFileMetaPropsPlugin::supports( m_items ) ) 00426 { 00427 KPropsDlgPlugin *p = new KFileMetaPropsPlugin( this ); 00428 insertPlugin (p); 00429 } 00430 00431 if ( KFileSharePropsPlugin::supports( m_items ) ) 00432 { 00433 KPropsDlgPlugin *p = new KFileSharePropsPlugin( this ); 00434 insertPlugin (p); 00435 } 00436 00437 //plugins 00438 00439 if ( m_items.count() != 1 ) 00440 return; 00441 00442 KFileItem *item = m_items.first(); 00443 QString mimetype = item->mimetype(); 00444 00445 if ( mimetype.isEmpty() ) 00446 return; 00447 00448 QString query = QString::fromLatin1( 00449 "('KPropsDlg/Plugin' in ServiceTypes) and " 00450 "((not exist [X-KDE-Protocol]) or " 00451 " ([X-KDE-Protocol] == '%1' ) )" ).arg(item->url().protocol()); 00452 00453 kdDebug( 250 ) << "trader query: " << query << endl; 00454 KTrader::OfferList offers = KTrader::self()->query( mimetype, query ); 00455 KTrader::OfferList::ConstIterator it = offers.begin(); 00456 KTrader::OfferList::ConstIterator end = offers.end(); 00457 for (; it != end; ++it ) 00458 { 00459 KPropsDlgPlugin *plugin = KParts::ComponentFactory 00460 ::createInstanceFromLibrary<KPropsDlgPlugin>( (*it)->library().local8Bit().data(), 00461 this, 00462 (*it)->name().latin1() ); 00463 if ( !plugin ) 00464 continue; 00465 00466 insertPlugin( plugin ); 00467 } 00468 } 00469 00470 void KPropertiesDialog::updateUrl( const KURL& _newUrl ) 00471 { 00472 Q_ASSERT( m_items.count() == 1 ); 00473 kdDebug(250) << "KPropertiesDialog::updateUrl (pre)" << _newUrl.url() << endl; 00474 KURL newUrl = _newUrl; 00475 emit saveAs(m_singleUrl, newUrl); 00476 kdDebug(250) << "KPropertiesDialog::updateUrl (post)" << newUrl.url() << endl; 00477 00478 m_singleUrl = newUrl; 00479 m_items.first()->setURL( newUrl ); 00480 assert(!m_singleUrl.isEmpty()); 00481 // If we have an Desktop page, set it dirty, so that a full file is saved locally 00482 // Same for a URL page (because of the Name= hack) 00483 for ( QPtrListIterator<KPropsDlgPlugin> it(m_pageList); it.current(); ++it ) 00484 if ( it.current()->isA("KExecPropsPlugin") || // KDE4 remove me 00485 it.current()->isA("KURLPropsPlugin") || 00486 it.current()->isA("KDesktopPropsPlugin")) 00487 { 00488 //kdDebug(250) << "Setting page dirty" << endl; 00489 it.current()->setDirty(); 00490 break; 00491 } 00492 } 00493 00494 void KPropertiesDialog::rename( const QString& _name ) 00495 { 00496 Q_ASSERT( m_items.count() == 1 ); 00497 kdDebug(250) << "KPropertiesDialog::rename " << _name << endl; 00498 KURL newUrl; 00499 // if we're creating from a template : use currentdir 00500 if ( !m_currentDir.isEmpty() ) 00501 { 00502 newUrl = m_currentDir; 00503 newUrl.addPath( _name ); 00504 } 00505 else 00506 { 00507 QString tmpurl = m_singleUrl.url(); 00508 if ( tmpurl.at(tmpurl.length() - 1) == '/') 00509 // It's a directory, so strip the trailing slash first 00510 tmpurl.truncate( tmpurl.length() - 1); 00511 newUrl = tmpurl; 00512 newUrl.setFileName( _name ); 00513 } 00514 updateUrl( newUrl ); 00515 } 00516 00517 void KPropertiesDialog::abortApplying() 00518 { 00519 d->m_aborted = true; 00520 } 00521 00522 class KPropsDlgPlugin::KPropsDlgPluginPrivate 00523 { 00524 public: 00525 KPropsDlgPluginPrivate() 00526 { 00527 } 00528 ~KPropsDlgPluginPrivate() 00529 { 00530 } 00531 00532 bool m_bDirty; 00533 }; 00534 00535 KPropsDlgPlugin::KPropsDlgPlugin( KPropertiesDialog *_props ) 00536 : QObject( _props, 0L ) 00537 { 00538 d = new KPropsDlgPluginPrivate; 00539 properties = _props; 00540 fontHeight = 2*properties->fontMetrics().height(); 00541 d->m_bDirty = false; 00542 } 00543 00544 KPropsDlgPlugin::~KPropsDlgPlugin() 00545 { 00546 delete d; 00547 } 00548 00549 bool KPropsDlgPlugin::isDesktopFile( KFileItem * _item ) 00550 { 00551 // only local files 00552 if ( !_item->isLocalFile() ) 00553 return false; 00554 00555 // only regular files 00556 if ( !S_ISREG( _item->mode() ) ) 00557 return false; 00558 00559 QString t( _item->url().path() ); 00560 00561 // only if readable 00562 FILE *f = fopen( QFile::encodeName(t), "r" ); 00563 if ( f == 0L ) 00564 return false; 00565 fclose(f); 00566 00567 // return true if desktop file 00568 return ( _item->mimetype() == "application/x-desktop" ); 00569 } 00570 00571 void KPropsDlgPlugin::setDirty( bool b ) 00572 { 00573 d->m_bDirty = b; 00574 } 00575 00576 void KPropsDlgPlugin::setDirty() 00577 { 00578 d->m_bDirty = true; 00579 } 00580 00581 bool KPropsDlgPlugin::isDirty() const 00582 { 00583 return d->m_bDirty; 00584 } 00585 00586 void KPropsDlgPlugin::applyChanges() 00587 { 00588 kdWarning(250) << "applyChanges() not implemented in page !" << endl; 00589 } 00590 00592 00593 class KFilePropsPlugin::KFilePropsPluginPrivate 00594 { 00595 public: 00596 KFilePropsPluginPrivate() 00597 { 00598 dirSizeJob = 0L; 00599 dirSizeUpdateTimer = 0L; 00600 m_lined = 0; 00601 } 00602 ~KFilePropsPluginPrivate() 00603 { 00604 if ( dirSizeJob ) 00605 dirSizeJob->kill(); 00606 } 00607 00608 KDirSize * dirSizeJob; 00609 QTimer *dirSizeUpdateTimer; 00610 QFrame *m_frame; 00611 bool bMultiple; 00612 bool bIconChanged; 00613 bool bKDesktopMode; 00614 bool bDesktopFile; 00615 QLabel *m_freeSpaceLabel; 00616 QString mimeType; 00617 QString oldFileName; 00618 KLineEdit* m_lined; 00619 }; 00620 00621 KFilePropsPlugin::KFilePropsPlugin( KPropertiesDialog *_props ) 00622 : KPropsDlgPlugin( _props ) 00623 { 00624 d = new KFilePropsPluginPrivate; 00625 d->bMultiple = (properties->items().count() > 1); 00626 d->bIconChanged = false; 00627 d->bKDesktopMode = (QCString(qApp->name()) == "kdesktop"); // nasty heh? 00628 d->bDesktopFile = KDesktopPropsPlugin::supports(properties->items()); 00629 kdDebug(250) << "KFilePropsPlugin::KFilePropsPlugin bMultiple=" << d->bMultiple << endl; 00630 00631 // We set this data from the first item, and we'll 00632 // check that the other items match against it, resetting when not. 00633 bool isLocal = properties->kurl().isLocalFile(); 00634 KFileItem * item = properties->item(); 00635 bool bDesktopFile = isDesktopFile(item); 00636 mode_t mode = item->mode(); 00637 bool hasDirs = item->isDir() && !item->isLink(); 00638 bool hasRoot = isLocal && properties->kurl().path() == QString::fromLatin1("/"); 00639 QString iconStr = KMimeType::iconForURL(properties->kurl(), mode); 00640 QString directory = properties->kurl().directory(); 00641 QString protocol = properties->kurl().protocol(); 00642 QString mimeComment = item->mimeComment(); 00643 d->mimeType = item->mimetype(); 00644 KIO::filesize_t totalSize = item->size(); 00645 QString magicMimeComment; 00646 if ( isLocal ) { 00647 KMimeType::Ptr magicMimeType = KMimeType::findByFileContent( properties->kurl().path() ); 00648 if ( magicMimeType->name() != KMimeType::defaultMimeType() ) 00649 magicMimeComment = magicMimeType->comment(); 00650 } 00651 00652 // Those things only apply to 'single file' mode 00653 QString filename = QString::null; 00654 bool isTrash = false; 00655 bool isIntoTrash = false; 00656 bool isDevice = false; 00657 m_bFromTemplate = false; 00658 00659 // And those only to 'multiple' mode 00660 uint iDirCount = hasDirs ? 1 : 0; 00661 uint iFileCount = 1-iDirCount; 00662 00663 d->m_frame = properties->addPage (i18n("&General")); 00664 00665 QVBoxLayout *vbl = new QVBoxLayout( d->m_frame, 0, 00666 KDialog::spacingHint(), "vbl"); 00667 QGridLayout *grid = new QGridLayout(0, 3); // unknown rows 00668 grid->setColStretch(0, 0); 00669 grid->setColStretch(1, 0); 00670 grid->setColStretch(2, 1); 00671 grid->addColSpacing(1, KDialog::spacingHint()); 00672 vbl->addLayout(grid); 00673 int curRow = 0; 00674 00675 if ( !d->bMultiple ) 00676 { 00677 // Extract the file name only 00678 filename = properties->defaultName(); 00679 if ( filename.isEmpty() ) // no template 00680 filename = properties->kurl().fileName(); 00681 else 00682 { 00683 m_bFromTemplate = true; 00684 setDirty(); // to enforce that the copy happens 00685 } 00686 d->oldFileName = filename; 00687 00688 // Make it human-readable 00689 filename = nameFromFileName( filename ); 00690 00691 if ( d->bKDesktopMode && d->bDesktopFile ) { 00692 KDesktopFile config( properties->kurl().path(), true /* readonly */ ); 00693 if ( config.hasKey( "Name" ) ) { 00694 filename = config.readName(); 00695 } 00696 } 00697 00698 oldName = filename; 00699 00700 QString path; 00701 00702 if ( !m_bFromTemplate ) { 00703 QString tmp = properties->kurl().path( 1 ); 00704 // is it the trash bin ? 00705 if ( isLocal ) 00706 { 00707 if ( tmp == KGlobalSettings::trashPath()) 00708 isTrash = true; 00709 if ( tmp.startsWith(KGlobalSettings::trashPath())) 00710 isIntoTrash = true; 00711 } 00712 if ( properties->kurl().protocol().find("device", 0, false)==0) 00713 isDevice = true; 00714 // Extract the full name, but without file: for local files 00715 if ( isLocal ) 00716 path = properties->kurl().path(); 00717 else 00718 path = properties->kurl().prettyURL(); 00719 } else { 00720 path = properties->currentDir().path(1) + properties->defaultName(); 00721 directory = properties->currentDir().prettyURL(); 00722 } 00723 00724 if (KExecPropsPlugin::supports(properties->items()) || // KDE4 remove me 00725 d->bDesktopFile || 00726 KBindingPropsPlugin::supports(properties->items())) { 00727 00728 determineRelativePath( path ); 00729 00730 } 00731 00732 } 00733 else 00734 { 00735 // Multiple items: see what they have in common 00736 KFileItemList items = properties->items(); 00737 KFileItemListIterator it( items ); 00738 for ( ++it /*no need to check the first one again*/ ; it.current(); ++it ) 00739 { 00740 KURL url = (*it)->url(); 00741 kdDebug(250) << "KFilePropsPlugin::KFilePropsPlugin " << url.prettyURL() << endl; 00742 // The list of things we check here should match the variables defined 00743 // at the beginning of this method. 00744 if ( url.isLocalFile() != isLocal ) 00745 isLocal = false; // not all local 00746 if ( bDesktopFile && isDesktopFile(*it) != bDesktopFile ) 00747 bDesktopFile = false; // not all desktop files 00748 if ( (*it)->mode() != mode ) 00749 mode = (mode_t)0; 00750 if ( KMimeType::iconForURL(url, mode) != iconStr ) 00751 iconStr = "kmultiple"; 00752 if ( url.directory() != directory ) 00753 directory = QString::null; 00754 if ( url.protocol() != protocol ) 00755 protocol = QString::null; 00756 if ( !mimeComment.isNull() && (*it)->mimeComment() != mimeComment ) 00757 mimeComment = QString::null; 00758 if ( isLocal && !magicMimeComment.isNull() ) { 00759 KMimeType::Ptr magicMimeType = KMimeType::findByFileContent( url.path() ); 00760 if ( magicMimeType->comment() != magicMimeComment ) 00761 magicMimeComment = QString::null; 00762 } 00763 00764 if ( isLocal && url.path() == QString::fromLatin1("/") ) 00765 hasRoot = true; 00766 if ( (*it)->isDir() && !(*it)->isLink() ) 00767 { 00768 iDirCount++; 00769 hasDirs = true; 00770 } 00771 else 00772 { 00773 iFileCount++; 00774 totalSize += (*it)->size(); 00775 } 00776 } 00777 } 00778 00779 if (!isLocal && !protocol.isEmpty()) 00780 { 00781 directory += ' '; 00782 directory += '('; 00783 directory += protocol; 00784 directory += ')'; 00785 } 00786 00787 if ( !isDevice && !isIntoTrash && (bDesktopFile || S_ISDIR(mode)) && !d->bMultiple /*not implemented for multiple*/ ) 00788 { 00789 KIconButton *iconButton = new KIconButton( d->m_frame ); 00790 int bsize = 66 + 2 * iconButton->style().pixelMetric(QStyle::PM_ButtonMargin); 00791 iconButton->setFixedSize(bsize, bsize); 00792 iconButton->setIconSize(48); 00793 iconButton->setStrictIconSize(false); 00794 // This works for everything except Device icons on unmounted devices 00795 // So we have to really open .desktop files 00796 QString iconStr = KMimeType::findByURL( properties->kurl(), 00797 mode )->icon( properties->kurl(), 00798 isLocal ); 00799 if ( bDesktopFile && isLocal ) 00800 { 00801 KDesktopFile config( properties->kurl().path(), true ); 00802 config.setDesktopGroup(); 00803 iconStr = config.readEntry( "Icon" ); 00804 if ( config.hasDeviceType() ) 00805 iconButton->setIconType( KIcon::Desktop, KIcon::Device ); 00806 else 00807 iconButton->setIconType( KIcon::Desktop, KIcon::Application ); 00808 } else 00809 iconButton->setIconType( KIcon::Desktop, KIcon::FileSystem ); 00810 iconButton->setIcon(iconStr); 00811 iconArea = iconButton; 00812 connect( iconButton, SIGNAL( iconChanged(QString) ), 00813 this, SLOT( slotIconChanged() ) ); 00814 } else { 00815 QLabel *iconLabel = new QLabel( d->m_frame ); 00816 int bsize = 66 + 2 * iconLabel->style().pixelMetric(QStyle::PM_ButtonMargin); 00817 iconLabel->setFixedSize(bsize, bsize); 00818 iconLabel->setPixmap( KGlobal::iconLoader()->loadIcon( iconStr, KIcon::Desktop, 48) ); 00819 iconArea = iconLabel; 00820 } 00821 grid->addWidget(iconArea, curRow, 0, AlignLeft); 00822 00823 if (d->bMultiple || isTrash || isIntoTrash || isDevice || hasRoot) 00824 { 00825 QLabel *lab = new QLabel(d->m_frame ); 00826 if ( d->bMultiple ) 00827 lab->setText( KIO::itemsSummaryString( iFileCount + iDirCount, iFileCount, iDirCount, 0, false ) ); 00828 else 00829 lab->setText( filename ); 00830 nameArea = lab; 00831 } else 00832 { 00833 d->m_lined = new KLineEdit( d->m_frame ); 00834 d->m_lined->setText(filename); 00835 nameArea = d->m_lined; 00836 d->m_lined->setFocus(); 00837 connect( d->m_lined, SIGNAL( textChanged( const QString & ) ), 00838 this, SLOT( nameFileChanged(const QString & ) ) ); 00839 } 00840 00841 grid->addWidget(nameArea, curRow++, 2); 00842 00843 KSeparator* sep = new KSeparator( KSeparator::HLine, d->m_frame); 00844 grid->addMultiCellWidget(sep, curRow, curRow, 0, 2); 00845 ++curRow; 00846 00847 QLabel *l; 00848 if ( !mimeComment.isEmpty() && !isDevice && !isIntoTrash) 00849 { 00850 l = new QLabel(i18n("Type:"), d->m_frame ); 00851 00852 grid->addWidget(l, curRow, 0); 00853 00854 QHBox *box = new QHBox(d->m_frame); 00855 l = new QLabel(mimeComment, box ); 00856 00857 QPushButton *button = new QPushButton(box); 00858 00859 QIconSet iconSet = SmallIconSet(QString::fromLatin1("configure")); 00860 QPixmap pixMap = iconSet.pixmap( QIconSet::Small, QIconSet::Normal ); 00861 button->setIconSet( iconSet ); 00862 button->setFixedSize( pixMap.width()+8, pixMap.height()+8 ); 00863 QToolTip::add(button, i18n("Edit file type")); 00864 00865 connect( button, SIGNAL( clicked() ), SLOT( slotEditFileType() )); 00866 00867 if (!kapp->authorizeKAction("editfiletype")) 00868 button->hide(); 00869 00870 grid->addWidget(box, curRow++, 2); 00871 } 00872 00873 if ( !magicMimeComment.isEmpty() && magicMimeComment != mimeComment ) 00874 { 00875 l = new QLabel(i18n("Contents:"), d->m_frame ); 00876 grid->addWidget(l, curRow, 0); 00877 00878 l = new QLabel(magicMimeComment, d->m_frame ); 00879 grid->addWidget(l, curRow++, 2); 00880 } 00881 00882 if ( !directory.isEmpty() ) 00883 { 00884 l = new QLabel( i18n("Location:"), d->m_frame ); 00885 grid->addWidget(l, curRow, 0); 00886 00887 l = new KSqueezedTextLabel( d->m_frame ); 00888 l->setText( directory ); 00889 grid->addWidget(l, curRow++, 2); 00890 } 00891 00892 l = new QLabel(i18n("Size:"), d->m_frame ); 00893 grid->addWidget(l, curRow, 0); 00894 00895 m_sizeLabel = new QLabel( d->m_frame ); 00896 grid->addWidget( m_sizeLabel, curRow++, 2 ); 00897 00898 if ( !hasDirs ) // Only files [and symlinks] 00899 { 00900 m_sizeLabel->setText(QString::fromLatin1("%1 (%2)").arg(KIO::convertSize(totalSize)) 00901 .arg(KGlobal::locale()->formatNumber(totalSize, 0))); 00902 m_sizeDetermineButton = 0L; 00903 m_sizeStopButton = 0L; 00904 } 00905 else // Directory 00906 { 00907 QHBoxLayout * sizelay = new QHBoxLayout(KDialog::spacingHint()); 00908 grid->addLayout( sizelay, curRow++, 2 ); 00909 00910 // buttons 00911 m_sizeDetermineButton = new QPushButton( i18n("Calculate"), d->m_frame ); 00912 m_sizeStopButton = new QPushButton( i18n("Stop"), d->m_frame ); 00913 connect( m_sizeDetermineButton, SIGNAL( clicked() ), this, SLOT( slotSizeDetermine() ) ); 00914 connect( m_sizeStopButton, SIGNAL( clicked() ), this, SLOT( slotSizeStop() ) ); 00915 sizelay->addWidget(m_sizeDetermineButton, 0); 00916 sizelay->addWidget(m_sizeStopButton, 0); 00917 sizelay->addStretch(10); // so that the buttons don't grow horizontally 00918 00919 // auto-launch for local dirs only, and not for '/' 00920 if ( isLocal && !hasRoot ) 00921 { 00922 m_sizeDetermineButton->setText( i18n("Refresh") ); 00923 slotSizeDetermine(); 00924 } 00925 else 00926 m_sizeStopButton->setEnabled( false ); 00927 } 00928 00929 if ( isLocal ) 00930 { 00931 QString mountPoint = KIO::findPathMountPoint( properties->item()->url().path() ); 00932 00933 if (mountPoint != "/") 00934 { 00935 l = new QLabel(i18n("Mounted on:"), d->m_frame ); 00936 grid->addWidget(l, curRow, 0); 00937 00938 l = new KSqueezedTextLabel( mountPoint, d->m_frame ); 00939 grid->addWidget( l, curRow++, 2 ); 00940 } 00941 00942 l = new QLabel(i18n("Free disk space:"), d->m_frame ); 00943 grid->addWidget(l, curRow, 0); 00944 00945 d->m_freeSpaceLabel = new QLabel( d->m_frame ); 00946 grid->addWidget( d->m_freeSpaceLabel, curRow++, 2 ); 00947 00948 KDiskFreeSp * job = new KDiskFreeSp; 00949 connect( job, SIGNAL( foundMountPoint( const unsigned long&, const unsigned long&, 00950 const unsigned long&, const QString& ) ), 00951 this, SLOT( slotFoundMountPoint( const unsigned long&, const unsigned long&, 00952 const unsigned long&, const QString& ) ) ); 00953 job->readDF( mountPoint ); 00954 } 00955 00956 if (!d->bMultiple && item->isLink()) { 00957 l = new QLabel(i18n("Points to:"), d->m_frame ); 00958 grid->addWidget(l, curRow, 0); 00959 00960 l = new KSqueezedTextLabel(item->linkDest(), d->m_frame ); 00961 grid->addWidget(l, curRow++, 2); 00962 } 00963 00964 if (!d->bMultiple) // Dates for multiple don't make much sense... 00965 { 00966 sep = new KSeparator( KSeparator::HLine, d->m_frame); 00967 grid->addMultiCellWidget(sep, curRow, curRow, 0, 2); 00968 ++curRow; 00969 00970 QDateTime dt; 00971 time_t tim = item->time(KIO::UDS_CREATION_TIME); 00972 if ( tim ) 00973 { 00974 l = new QLabel(i18n("Created:"), d->m_frame ); 00975 grid->addWidget(l, curRow, 0); 00976 00977 dt.setTime_t( tim ); 00978 l = new QLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame ); 00979 grid->addWidget(l, curRow++, 2); 00980 } 00981 00982 tim = item->time(KIO::UDS_MODIFICATION_TIME); 00983 if ( tim ) 00984 { 00985 l = new QLabel(i18n("Modified:"), d->m_frame ); 00986 grid->addWidget(l, curRow, 0); 00987 00988 dt.setTime_t( tim ); 00989 l = new QLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame ); 00990 grid->addWidget(l, curRow++, 2); 00991 } 00992 00993 tim = item->time(KIO::UDS_ACCESS_TIME); 00994 if ( tim ) 00995 { 00996 l = new QLabel(i18n("Accessed:"), d->m_frame ); 00997 grid->addWidget(l, curRow, 0); 00998 00999 dt.setTime_t( tim ); 01000 l = new QLabel(KGlobal::locale()->formatDateTime(dt), d->m_frame ); 01001 grid->addWidget(l, curRow++, 2); 01002 } 01003 } 01004 vbl->addStretch(1); 01005 } 01006 01007 // QString KFilePropsPlugin::tabName () const 01008 // { 01009 // return i18n ("&General"); 01010 // } 01011 01012 void KFilePropsPlugin::setFileNameReadOnly( bool ro ) 01013 { 01014 if ( d->m_lined ) 01015 { 01016 d->m_lined->setReadOnly( ro ); 01017 if (ro) 01018 { 01019 // Don't put the initial focus on the line edit when it is ro 01020 QPushButton *button = properties->actionButton(KDialogBase::Ok); 01021 if (button) 01022 button->setFocus(); 01023 } 01024 } 01025 } 01026 01027 void KFilePropsPlugin::slotEditFileType() 01028 { 01029 QString keditfiletype = QString::fromLatin1("keditfiletype"); 01030 KRun::runCommand( keditfiletype 01031 + " --parent " + QString::number( properties->topLevelWidget()->winId()) 01032 + " " + KProcess::quote(d->mimeType), 01033 keditfiletype, keditfiletype /*unused*/); 01034 } 01035 01036 void KFilePropsPlugin::slotIconChanged() 01037 { 01038 d->bIconChanged = true; 01039 emit changed(); 01040 } 01041 01042 void KFilePropsPlugin::nameFileChanged(const QString &text ) 01043 { 01044 properties->enableButtonOK(!text.isEmpty()); 01045 emit changed(); 01046 } 01047 01048 void KFilePropsPlugin::determineRelativePath( const QString & path ) 01049 { 01050 // now let's make it relative 01051 QStringList dirs; 01052 if (KBindingPropsPlugin::supports(properties->items())) 01053 { 01054 m_sRelativePath =KGlobal::dirs()->relativeLocation("mime", path); 01055 if (m_sRelativePath.startsWith("/")) 01056 m_sRelativePath = QString::null; 01057 } 01058 else 01059 { 01060 m_sRelativePath =KGlobal::dirs()->relativeLocation("apps", path); 01061 if (m_sRelativePath.startsWith("/")) 01062 { 01063 m_sRelativePath =KGlobal::dirs()->relativeLocation("xdgdata-apps", path); 01064 if (m_sRelativePath.startsWith("/")) 01065 m_sRelativePath = QString::null; 01066 else 01067 m_sRelativePath = path; 01068 } 01069 } 01070 if ( m_sRelativePath.isEmpty() ) 01071 { 01072 if (KBindingPropsPlugin::supports(properties->items())) 01073 kdWarning(250) << "Warning : editing a mimetype file out of the mimetype dirs!" << endl; 01074 } 01075 } 01076 01077 void KFilePropsPlugin::slotFoundMountPoint( const QString&, 01078 unsigned long kBSize, 01079 unsigned long /*kBUsed*/, 01080 unsigned long kBAvail ) 01081 { 01082 d->m_freeSpaceLabel->setText( 01083 i18n("Available space out of total partition size (percent used)", "%1 out of %2 (%3% used)") 01084 .arg(KIO::convertSizeFromKB(kBAvail)) 01085 .arg(KIO::convertSizeFromKB(kBSize)) 01086 .arg( 100 - (int)(100.0 * kBAvail / kBSize) )); 01087 } 01088 01089 // attention: copy&paste below, due to compiler bug 01090 // it doesn't like those unsigned long parameters -- unsigned long& are ok :-/ 01091 void KFilePropsPlugin::slotFoundMountPoint( const unsigned long& kBSize, 01092 const unsigned long& /*kBUsed*/, 01093 const unsigned long& kBAvail, 01094 const QString& ) 01095 { 01096 d->m_freeSpaceLabel->setText( 01097 i18n("Available space out of total partition size (percent used)", "%1 out of %2 (%3% used)") 01098 .arg(KIO::convertSizeFromKB(kBAvail)) 01099 .arg(KIO::convertSizeFromKB(kBSize)) 01100 .arg( 100 - (int)(100.0 * kBAvail / kBSize) )); 01101 } 01102 01103 void KFilePropsPlugin::slotDirSizeUpdate() 01104 { 01105 KIO::filesize_t totalSize = d->dirSizeJob->totalSize(); 01106 KIO::filesize_t totalFiles = d->dirSizeJob->totalFiles(); 01107 KIO::filesize_t totalSubdirs = d->dirSizeJob->totalSubdirs(); 01108 m_sizeLabel->setText( i18n("Calculating... %1 (%2)\n%3, %4") 01109 .arg(KIO::convertSize(totalSize)) 01110 .arg(KGlobal::locale()->formatNumber(totalSize, 0)) 01111 .arg(i18n("1 file","%n files",totalFiles)) 01112 .arg(i18n("1 sub-folder","%n sub-folders",totalSubdirs))); 01113 } 01114 01115 void KFilePropsPlugin::slotDirSizeFinished( KIO::Job * job ) 01116 { 01117 if (job->error()) 01118 m_sizeLabel->setText( job->errorString() ); 01119 else 01120 { 01121 KIO::filesize_t totalSize = static_cast<KDirSize*>(job)->totalSize(); 01122 KIO::filesize_t totalFiles = static_cast<KDirSize*>(job)->totalFiles(); 01123 KIO::filesize_t totalSubdirs = static_cast<KDirSize*>(job)->totalSubdirs(); 01124 m_sizeLabel->setText( QString::fromLatin1("%1 (%2)\n%3, %4") 01125 .arg(KIO::convertSize(totalSize)) 01126 .arg(KGlobal::locale()->formatNumber(totalSize, 0)) 01127 .arg(i18n("1 file","%n files",totalFiles)) 01128 .arg(i18n("1 sub-folder","%n sub-folders",totalSubdirs))); 01129 } 01130 m_sizeStopButton->setEnabled(false); 01131 // just in case you change something and try again :) 01132 m_sizeDetermineButton->setText( i18n("Refresh") ); 01133 m_sizeDetermineButton->setEnabled(true); 01134 d->dirSizeJob = 0L; 01135 delete d->dirSizeUpdateTimer; 01136 d->dirSizeUpdateTimer = 0L; 01137 } 01138 01139 void KFilePropsPlugin::slotSizeDetermine() 01140 { 01141 m_sizeLabel->setText( i18n("Calculating...") ); 01142 kdDebug(250) << " KFilePropsPlugin::slotSizeDetermine() properties->item()=" << properties->item() << endl; 01143 kdDebug(250) << " URL=" << properties->item()->url().url() << endl; 01144 d->dirSizeJob = KDirSize::dirSizeJob( properties->items() ); 01145 d->dirSizeUpdateTimer = new QTimer(this); 01146 connect( d->dirSizeUpdateTimer, SIGNAL( timeout() ), 01147 SLOT( slotDirSizeUpdate() ) ); 01148 d->dirSizeUpdateTimer->start(500); 01149 connect( d->dirSizeJob, SIGNAL( result( KIO::Job * ) ), 01150 SLOT( slotDirSizeFinished( KIO::Job * ) ) ); 01151 m_sizeStopButton->setEnabled(true); 01152 m_sizeDetermineButton->setEnabled(false); 01153 } 01154 01155 void KFilePropsPlugin::slotSizeStop() 01156 { 01157 if ( d->dirSizeJob ) 01158 { 01159 m_sizeLabel->setText( i18n("Stopped") ); 01160 d->dirSizeJob->kill(); 01161 d->dirSizeJob = 0; 01162 } 01163 if ( d->dirSizeUpdateTimer ) 01164 d->dirSizeUpdateTimer->stop(); 01165 01166 m_sizeStopButton->setEnabled(false); 01167 m_sizeDetermineButton->setEnabled(true); 01168 } 01169 01170 KFilePropsPlugin::~KFilePropsPlugin() 01171 { 01172 delete d; 01173 } 01174 01175 bool KFilePropsPlugin::supports( KFileItemList /*_items*/ ) 01176 { 01177 return true; 01178 } 01179 01180 // Don't do this at home 01181 void qt_enter_modal( QWidget *widget ); 01182 void qt_leave_modal( QWidget *widget ); 01183 01184 void KFilePropsPlugin::applyChanges() 01185 { 01186 if ( d->dirSizeJob ) 01187 slotSizeStop(); 01188 01189 kdDebug(250) << "KFilePropsPlugin::applyChanges" << endl; 01190 01191 if (nameArea->inherits("QLineEdit")) 01192 { 01193 QString n = ((QLineEdit *) nameArea)->text(); 01194 // Remove trailing spaces (#4345) 01195 while ( n[n.length()-1].isSpace() ) 01196 n.truncate( n.length() - 1 ); 01197 if ( n.isEmpty() ) 01198 { 01199 KMessageBox::sorry( properties, i18n("The new file name is empty.")); 01200 properties->abortApplying(); 01201 return; 01202 } 01203 01204 // Do we need to rename the file ? 01205 kdDebug(250) << "oldname = " << oldName << endl; 01206 kdDebug(250) << "newname = " << n << endl; 01207 if ( oldName != n || m_bFromTemplate ) { // true for any from-template file 01208 KIO::Job * job = 0L; 01209 KURL oldurl = properties->kurl(); 01210 01211 QString newFileName = KIO::encodeFileName(n); 01212 if (d->bDesktopFile && !newFileName.endsWith(".desktop") && !newFileName.endsWith(".kdelnk")) 01213 newFileName += ".desktop"; 01214 01215 // Tell properties. Warning, this changes the result of properties->kurl() ! 01216 properties->rename( newFileName ); 01217 01218 // Update also relative path (for apps and mimetypes) 01219 if ( !m_sRelativePath.isEmpty() ) 01220 determineRelativePath( properties->kurl().path() ); 01221 01222 kdDebug(250) << "New URL = " << properties->kurl().url() << endl; 01223 kdDebug(250) << "old = " << oldurl.url() << endl; 01224 01225 // Don't remove the template !! 01226 if ( !m_bFromTemplate ) // (normal renaming) 01227 job = KIO::move( oldurl, properties->kurl() ); 01228 else // Copying a template 01229 job = KIO::copy( oldurl, properties->kurl() ); 01230 01231 connect( job, SIGNAL( result( KIO::Job * ) ), 01232 SLOT( slotCopyFinished( KIO::Job * ) ) ); 01233 connect( job, SIGNAL( renamed( KIO::Job *, const KURL &, const KURL & ) ), 01234 SLOT( slotFileRenamed( KIO::Job *, const KURL &, const KURL & ) ) ); 01235 // wait for job 01236 QWidget dummy(0,0,WType_Dialog|WShowModal); 01237 qt_enter_modal(&dummy); 01238 qApp->enter_loop(); 01239 qt_leave_modal(&dummy); 01240 return; 01241 } 01242 properties->updateUrl(properties->kurl()); 01243 // Update also relative path (for apps and mimetypes) 01244 if ( !m_sRelativePath.isEmpty() ) 01245 determineRelativePath( properties->kurl().path() ); 01246 } 01247 01248 // No job, keep going 01249 slotCopyFinished( 0L ); 01250 } 01251 01252 void KFilePropsPlugin::slotCopyFinished( KIO::Job * job ) 01253 { 01254 kdDebug(250) << "KFilePropsPlugin::slotCopyFinished" << endl; 01255 if (job) 01256 { 01257 // allow apply() to return 01258 qApp->exit_loop(); 01259 if ( job->error() ) 01260 { 01261 job->showErrorDialog( d->m_frame ); 01262 // Didn't work. Revert the URL to the old one 01263 properties->updateUrl( static_cast<KIO::CopyJob*>(job)->srcURLs().first() ); 01264 properties->abortApplying(); // Don't apply the changes to the wrong file ! 01265 return; 01266 } 01267 } 01268 01269 assert( properties->item() ); 01270 assert( !properties->item()->url().isEmpty() ); 01271 01272 // Save the file where we can -> usually in ~/.kde/... 01273 if (KBindingPropsPlugin::supports(properties->items()) && !m_sRelativePath.isEmpty()) 01274 { 01275 KURL newURL; 01276 newURL.setPath( locateLocal("mime", m_sRelativePath) ); 01277 properties->updateUrl( newURL ); 01278 } 01279 else if (d->bDesktopFile && !m_sRelativePath.isEmpty()) 01280 { 01281 kdDebug(250) << "KFilePropsPlugin::slotCopyFinished " << m_sRelativePath << endl; 01282 KURL newURL; 01283 newURL.setPath( KDesktopFile::locateLocal(m_sRelativePath) ); 01284 kdDebug(250) << "KFilePropsPlugin::slotCopyFinished path=" << newURL.path() << endl; 01285 properties->updateUrl( newURL ); 01286 } 01287 01288 if ( d->bKDesktopMode && d->bDesktopFile ) { 01289 // Renamed? Update Name field 01290 if ( d->oldFileName != properties->kurl().fileName() || m_bFromTemplate ) { 01291 KDesktopFile config( properties->kurl().path() ); 01292 QString nameStr = nameFromFileName(properties->kurl().fileName()); 01293 config.writeEntry( "Name", nameStr ); 01294 config.writeEntry( "Name", nameStr, true, false, true ); 01295 } 01296 } 01297 } 01298 01299 void KFilePropsPlugin::applyIconChanges() 01300 { 01301 // handle icon changes - only local files for now 01302 // TODO: Use KTempFile and KIO::file_copy with overwrite = true 01303 if (!iconArea->isA("QLabel") && properties->kurl().isLocalFile() && d->bIconChanged) { 01304 KIconButton *iconButton = (KIconButton *) iconArea; 01305 QString path; 01306 01307 if (S_ISDIR(properties->item()->mode())) 01308 { 01309 path = properties->kurl().path(1) + QString::fromLatin1(".directory"); 01310 // don't call updateUrl because the other tabs (i.e. permissions) 01311 // apply to the directory, not the .directory file. 01312 } 01313 else 01314 path = properties->kurl().path(); 01315 01316 // Get the default image 01317 QString str = KMimeType::findByURL( properties->kurl(), 01318 properties->item()->mode(), 01319 true )->KServiceType::icon(); 01320 // Is it another one than the default ? 01321 QString sIcon; 01322 if ( str != iconButton->icon() ) 01323 sIcon = iconButton->icon(); 01324 // (otherwise write empty value) 01325 01326 kdDebug(250) << "**" << path << "**" << endl; 01327 QFile f( path ); 01328 01329 // If default icon and no .directory file -> don't create one 01330 if ( !sIcon.isEmpty() || f.exists() ) 01331 { 01332 if ( !f.open( IO_ReadWrite ) ) { 01333 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not " 01334 "have sufficient access to write to <b>%1</b>.</qt>").arg(path)); 01335 return; 01336 } 01337 f.close(); 01338 01339 KDesktopFile cfg(path); 01340 kdDebug(250) << "sIcon = " << (sIcon) << endl; 01341 kdDebug(250) << "str = " << (str) << endl; 01342 cfg.writeEntry( "Icon", sIcon ); 01343 cfg.sync(); 01344 } 01345 } 01346 } 01347 01348 void KFilePropsPlugin::slotFileRenamed( KIO::Job *, const KURL &, const KURL & newUrl ) 01349 { 01350 // This is called in case of an existing local file during the copy/move operation, 01351 // if the user chooses Rename. 01352 properties->updateUrl( newUrl ); 01353 } 01354 01355 void KFilePropsPlugin::postApplyChanges() 01356 { 01357 // Save the icon only after applying the permissions changes (#46192) 01358 applyIconChanges(); 01359 01360 KURL::List lst; 01361 KFileItemList items = properties->items(); 01362 for ( KFileItemListIterator it( items ); it.current(); ++it ) 01363 lst.append((*it)->url()); 01364 KDirNotify_stub allDirNotify("*", "KDirNotify*"); 01365 allDirNotify.FilesChanged( lst ); 01366 } 01367 01368 class KFilePermissionsPropsPlugin::KFilePermissionsPropsPluginPrivate 01369 { 01370 public: 01371 KFilePermissionsPropsPluginPrivate() 01372 { 01373 } 01374 ~KFilePermissionsPropsPluginPrivate() 01375 { 01376 } 01377 01378 QFrame *m_frame; 01379 QCheckBox *cbRecursive; 01380 QLabel *explanationLabel; 01381 QComboBox *ownerPermCombo, *groupPermCombo, *othersPermCombo; 01382 QCheckBox *extraCheckbox; 01383 mode_t partialPermissions; 01384 KFilePermissionsPropsPlugin::PermissionsMode pmode; 01385 bool canChangePermissions; 01386 bool isIrregular; 01387 }; 01388 01389 #define UniOwner (S_IRUSR|S_IWUSR|S_IXUSR) 01390 #define UniGroup (S_IRGRP|S_IWGRP|S_IXGRP) 01391 #define UniOthers (S_IROTH|S_IWOTH|S_IXOTH) 01392 #define UniRead (S_IRUSR|S_IRGRP|S_IROTH) 01393 #define UniWrite (S_IWUSR|S_IWGRP|S_IWOTH) 01394 #define UniExec (S_IXUSR|S_IXGRP|S_IXOTH) 01395 #define UniSpecial (S_ISUID|S_ISGID|S_ISVTX) 01396 01397 // synced with PermissionsTarget 01398 const mode_t KFilePermissionsPropsPlugin::permissionsMasks[3] = {UniOwner, UniGroup, UniOthers}; 01399 const mode_t KFilePermissionsPropsPlugin::standardPermissions[4] = { 0, UniRead, UniRead|UniWrite, (mode_t)-1 }; 01400 01401 // synced with PermissionsMode and standardPermissions 01402 const char *KFilePermissionsPropsPlugin::permissionsTexts[4][4] = { 01403 { I18N_NOOP("Forbidden"), 01404 I18N_NOOP("Can Read"), 01405 I18N_NOOP("Can Read & Write"), 01406 0 }, 01407 { I18N_NOOP("Forbidden"), 01408 I18N_NOOP("Can View Content"), 01409 I18N_NOOP("Can View & Modify Content"), 01410 0 }, 01411 { 0, 0, 0, 0}, // no texts for links 01412 { I18N_NOOP("Forbidden"), 01413 I18N_NOOP("Can View Content & Read"), 01414 I18N_NOOP("Can View/Read & Modify/Write"), 01415 0 } 01416 }; 01417 01418 01419 KFilePermissionsPropsPlugin::KFilePermissionsPropsPlugin( KPropertiesDialog *_props ) 01420 : KPropsDlgPlugin( _props ) 01421 { 01422 d = new KFilePermissionsPropsPluginPrivate; 01423 d->cbRecursive = 0L; 01424 grpCombo = 0L; grpEdit = 0; 01425 usrEdit = 0L; 01426 QString path = properties->kurl().path(-1); 01427 QString fname = properties->kurl().fileName(); 01428 bool isLocal = properties->kurl().isLocalFile(); 01429 bool isIntoTrash = isLocal && path.startsWith(KGlobalSettings::trashPath()); 01430 bool isTrash = isLocal && ( properties->kurl().path( 1 ) == KGlobalSettings::trashPath() ); 01431 bool IamRoot = (geteuid() == 0); 01432 01433 KFileItem * item = properties->item(); 01434 bool isLink = item->isLink(); 01435 bool isDir = item->isDir(); // all dirs 01436 bool hasDir = item->isDir(); // at least one dir 01437 permissions = item->permissions(); // common permissions to all files 01438 d->partialPermissions = permissions; // permissions that only some files have (at first we take everything) 01439 d->isIrregular = isIrregular(permissions, isDir, isLink); 01440 strOwner = item->user(); 01441 strGroup = item->group(); 01442 01443 if ( properties->items().count() > 1 ) 01444 { 01445 // Multiple items: see what they have in common 01446 KFileItemList items = properties->items(); 01447 KFileItemListIterator it( items ); 01448 for ( ++it /*no need to check the first one again*/ ; it.current(); ++it ) 01449 { 01450 if (!d->isIrregular) 01451 d->isIrregular |= isIrregular((*it)->permissions(), 01452 (*it)->isDir() == isDir, 01453 (*it)->isLink() == isLink); 01454 if ( (*it)->isLink() != isLink ) 01455 isLink = false; 01456 if ( (*it)->isDir() != isDir ) 01457 isDir = false; 01458 hasDir |= (*it)->isDir(); 01459 if ( (*it)->permissions() != permissions ) 01460 { 01461 permissions &= (*it)->permissions(); 01462 d->partialPermissions |= (*it)->permissions(); 01463 } 01464 if ( (*it)->user() != strOwner ) 01465 strOwner = QString::null; 01466 if ( (*it)->group() != strGroup ) 01467 strGroup = QString::null; 01468 } 01469 } 01470 01471 if (isLink) 01472 d->pmode = PermissionsOnlyLinks; 01473 else if (isDir) 01474 d->pmode = PermissionsOnlyDirs; 01475 else if (hasDir) 01476 d->pmode = PermissionsMixed; 01477 else 01478 d->pmode = PermissionsOnlyFiles; 01479 01480 // keep only what's not in the common permissions 01481 d->partialPermissions = d->partialPermissions & ~permissions; 01482 01483 bool isMyFile = false; 01484 01485 if (isLocal && !strOwner.isEmpty()) { // local files, and all owned by the same person 01486 struct passwd *myself = getpwuid( geteuid() ); 01487 if ( myself != 0L ) 01488 { 01489 isMyFile = (strOwner == QString::fromLocal8Bit(myself->pw_name)); 01490 } else 01491 kdWarning() << "I don't exist ?! geteuid=" << geteuid() << endl; 01492 } else { 01493 //We don't know, for remote files, if they are ours or not. 01494 //So we let the user change permissions, and 01495 //KIO::chmod will tell, if he had no right to do it. 01496 isMyFile = true; 01497 } 01498 01499 d->canChangePermissions = (isMyFile || IamRoot) && (!isLink); 01500 01501 01502 // create GUI 01503 01504 d->m_frame = properties->addPage(i18n("&Permissions")); 01505 01506 QBoxLayout *box = new QVBoxLayout( d->m_frame, 0, KDialog::spacingHint() ); 01507 01508 QWidget *l; 01509 QLabel *lbl; 01510 QGroupBox *gb; 01511 QGridLayout *gl; 01512 QPushButton* pbAdvancedPerm = 0; 01513 01514 /* Group: Access Permissions */ 01515 gb = new QGroupBox ( 0, Qt::Vertical, i18n("Access Permissions"), d->m_frame ); 01516 gb->layout()->setSpacing(KDialog::spacingHint()); 01517 gb->layout()->setMargin(KDialog::marginHint()); 01518 box->addWidget (gb); 01519 01520 gl = new QGridLayout (gb->layout(), 7, 2); 01521 gl->setColStretch(1, 1); 01522 01523 l = d->explanationLabel = new QLabel( "", gb ); 01524 if (isLink) 01525 d->explanationLabel->setText(i18n("This file is a link and does not have permissions.", 01526 "All files are links and do not have permissions.", 01527 properties->items().count())); 01528 else if (!d->canChangePermissions) 01529 d->explanationLabel->setText(i18n("Only the owner can change permissions.")); 01530 gl->addMultiCellWidget(l, 0, 0, 0, 1); 01531 01532 lbl = new QLabel( i18n("O&wner:"), gb); 01533 gl->addWidget(lbl, 1, 0); 01534 l = d->ownerPermCombo = new QComboBox(gb); 01535 lbl->setBuddy(l); 01536 gl->addWidget(l, 1, 1); 01537 connect(l, SIGNAL( highlighted(int) ), this, SIGNAL( changed() )); 01538 QWhatsThis::add(l, i18n("Specifies the actions that the owner is allowed to do.")); 01539 01540 lbl = new QLabel( i18n("Gro&up:"), gb); 01541 gl->addWidget(lbl, 2, 0); 01542 l = d->groupPermCombo = new QComboBox(gb); 01543 lbl->setBuddy(l); 01544 gl->addWidget(l, 2, 1); 01545 connect(l, SIGNAL( highlighted(int) ), this, SIGNAL( changed() )); 01546 QWhatsThis::add(l, i18n("Specifies the actions that the members of the group are allowed to do.")); 01547 01548 lbl = new QLabel( i18n("O&thers:"), gb); 01549 gl->addWidget(lbl, 3, 0); 01550 l = d->othersPermCombo = new QComboBox(gb); 01551 lbl->setBuddy(l); 01552 gl->addWidget(l, 3, 1); 01553 connect(l, SIGNAL( highlighted(int) ), this, SIGNAL( changed() )); 01554 QWhatsThis::add(l, i18n("Specifies the actions that all users, who are neither " 01555 "owner nor in the group, are allowed to do.")); 01556 01557 if (!isLink) { 01558 l = d->extraCheckbox = new QCheckBox(hasDir ? 01559 i18n("Only own&er can rename and delete folder content") : 01560 i18n("Is &executable"), 01561 gb ); 01562 connect( d->extraCheckbox, SIGNAL( clicked() ), this, SIGNAL( changed() ) ); 01563 gl->addWidget(l, 4, 1); 01564 QWhatsThis::add(l, hasDir ? i18n("Enable this option to allow only the folder's owner to " 01565 "delete or rename the contained files and folders. Other " 01566 "users can only add new files, which requires the 'Modify " 01567 "Content' permission.") 01568 : i18n("Enable this option to mark the file as executable. This only makes " 01569 "sense for programs and scripts. It is required when you want to " 01570 "execute them.")); 01571 01572 QLayoutItem *spacer = new QSpacerItem(0, 20, QSizePolicy::Minimum, QSizePolicy::Expanding); 01573 gl->addMultiCell(spacer, 5, 5, 0, 1); 01574 01575 pbAdvancedPerm = new QPushButton(i18n("A&dvanced Permissions..."), gb); 01576 gl->addMultiCellWidget(pbAdvancedPerm, 6, 6, 0, 1, AlignRight); 01577 connect(pbAdvancedPerm, SIGNAL( clicked() ), this, SLOT( slotShowAdvancedPermissions() )); 01578 } 01579 else 01580 d->extraCheckbox = 0; 01581 01582 01583 /**** Group: Ownership ****/ 01584 gb = new QGroupBox ( i18n("Ownership"), d->m_frame ); 01585 box->addWidget (gb); 01586 01587 gl = new QGridLayout (gb, 4, 3, KDialog::marginHint(), KDialog::spacingHint()); 01588 gl->addRowSpacing(0, 10); 01589 01590 /*** Set Owner ***/ 01591 l = new QLabel( i18n("User:"), gb ); 01592 gl->addWidget (l, 1, 0); 01593 01594 /* GJ: Don't autocomplete more than 1000 users. This is a kind of random 01595 * value. Huge sites having 10.000+ user have a fair chance of using NIS, 01596 * (possibly) making this unacceptably slow. 01597 * OTOH, it is nice to offer this functionality for the standard user. 01598 */ 01599 int i, maxEntries = 1000; 01600 struct passwd *user; 01601 struct group *ge; 01602 01603 /* File owner: For root, offer a KLineEdit with autocompletion. 01604 * For a user, who can never chown() a file, offer a QLabel. 01605 */ 01606 if (IamRoot && isLocal) 01607 { 01608 usrEdit = new KLineEdit( gb ); 01609 KCompletion *kcom = usrEdit->completionObject(); 01610 kcom->setOrder(KCompletion::Sorted); 01611 setpwent(); 01612 for (i=0; ((user = getpwent()) != 0L) && (i < maxEntries); i++) 01613 kcom->addItem(QString::fromLatin1(user->pw_name)); 01614 endpwent(); 01615 usrEdit->setCompletionMode((i < maxEntries) ? KGlobalSettings::CompletionAuto : 01616 KGlobalSettings::CompletionNone); 01617 usrEdit->setText(strOwner); 01618 gl->addWidget(usrEdit, 1, 1); 01619 connect( usrEdit, SIGNAL( textChanged( const QString & ) ), 01620 this, SIGNAL( changed() ) ); 01621 } 01622 else 01623 { 01624 l = new QLabel(strOwner, gb); 01625 gl->addWidget(l, 1, 1); 01626 } 01627 01628 /*** Set Group ***/ 01629 01630 QStringList groupList; 01631 QCString strUser; 01632 user = getpwuid(geteuid()); 01633 if (user != 0L) 01634 strUser = user->pw_name; 01635 01636 setgrent(); 01637 for (i=0; ((ge = getgrent()) != 0L) && (i < maxEntries); i++) 01638 { 01639 if (IamRoot) 01640 groupList += QString::fromLatin1(ge->gr_name); 01641 else 01642 { 01643 /* pick the groups to which the user belongs */ 01644 char ** members = ge->gr_mem; 01645 char * member; 01646 while ((member = *members) != 0L) { 01647 if (strUser == member) { 01648 groupList += QString::fromLocal8Bit(ge->gr_name); 01649 break; 01650 } 01651 ++members; 01652 } 01653 } 01654 } 01655 endgrent(); 01656 01657 /* add the effective Group to the list .. */ 01658 ge = getgrgid (getegid()); 01659 if (ge) { 01660 QString name = QString::fromLatin1(ge->gr_name); 01661 if (name.isEmpty()) 01662 name.setNum(ge->gr_gid); 01663 if (groupList.find(name) == groupList.end()) 01664 groupList += name; 01665 } 01666 01667 bool isMyGroup = groupList.contains(strGroup); 01668 01669 /* add the group the file currently belongs to .. 01670 * .. if its not there already 01671 */ 01672 if (!isMyGroup) 01673 groupList += strGroup; 01674 01675 l = new QLabel( i18n("Group:"), gb ); 01676 gl->addWidget (l, 2, 0); 01677 01678 /* Set group: if possible to change: 01679 * - Offer a KLineEdit for root, since he can change to any group. 01680 * - Offer a QComboBox for a normal user, since he can change to a fixed 01681 * (small) set of groups only. 01682 * If not changeable: offer a QLabel. 01683 */ 01684 if (IamRoot && isLocal) 01685 { 01686 grpEdit = new KLineEdit(gb); 01687 KCompletion *kcom = new KCompletion; 01688 kcom->setItems(groupList); 01689 grpEdit->setCompletionObject(kcom, true); 01690 grpEdit->setAutoDeleteCompletionObject( true ); 01691 grpEdit->setCompletionMode(KGlobalSettings::CompletionAuto); 01692 grpEdit->setText(strGroup); 01693 gl->addWidget(grpEdit, 2, 1); 01694 connect( grpEdit, SIGNAL( textChanged( const QString & ) ), 01695 this, SIGNAL( changed() ) ); 01696 } 01697 else if ((groupList.count() > 1) && isMyFile && isLocal) 01698 { 01699 grpCombo = new QComboBox(gb, "combogrouplist"); 01700 grpCombo->insertStringList(groupList); 01701 grpCombo->setCurrentItem(groupList.findIndex(strGroup)); 01702 gl->addWidget(grpCombo, 2, 1); 01703 connect( grpCombo, SIGNAL( activated( int ) ), 01704 this, SIGNAL( changed() ) ); 01705 } 01706 else 01707 { 01708 l = new QLabel(strGroup, gb); 01709 gl->addWidget(l, 2, 1); 01710 } 01711 01712 gl->setColStretch(2, 10); 01713 01714 // "Apply recursive" checkbox 01715 if ( hasDir && !isLink && !isIntoTrash ) 01716 { 01717 d->cbRecursive = new QCheckBox( i18n("Apply changes to all subfolders and their contents"), d->m_frame ); 01718 connect( d->cbRecursive, SIGNAL( clicked() ), this, SIGNAL( changed() ) ); 01719 box->addWidget( d->cbRecursive ); 01720 } 01721 01722 updateAccessControls(); 01723 01724 01725 if ( isIntoTrash || isTrash ) 01726 { 01727 //don't allow to change properties for file into trash 01728 enableAccessControls(false); 01729 if ( pbAdvancedPerm) 01730 pbAdvancedPerm->setEnabled(false); 01731 } 01732 01733 box->addStretch (10); 01734 } 01735 01736 void KFilePermissionsPropsPlugin::slotShowAdvancedPermissions() { 01737 01738 bool isDir = (d->pmode == PermissionsOnlyDirs) || (d->pmode == PermissionsMixed); 01739 KDialogBase dlg(properties, 0, true, i18n("Advanced Permissions"), 01740 KDialogBase::Ok|KDialogBase::Cancel); 01741 01742 QLabel *l, *cl[3]; 01743 QGroupBox *gb; 01744 QGridLayout *gl; 01745 01746 // Group: Access Permissions 01747 gb = new QGroupBox ( i18n("Access Permissions"), &dlg ); 01748 dlg.setMainWidget(gb); 01749 01750 gl = new QGridLayout (gb, 6, 6, 15); 01751 gl->addRowSpacing(0, 10); 01752 01753 l = new QLabel(i18n("Class"), gb); 01754 gl->addWidget(l, 1, 0); 01755 01756 if (isDir) 01757 l = new QLabel( i18n("Show\nEntries"), gb ); 01758 else 01759 l = new QLabel( i18n("Read"), gb ); 01760 gl->addWidget (l, 1, 1); 01761 QString readWhatsThis; 01762 if (isDir) 01763 readWhatsThis = i18n("This flag allows viewing the content of the folder."); 01764 else 01765 readWhatsThis = i18n("The Read flag allows viewing the content of the file."); 01766 QWhatsThis::add(l, readWhatsThis); 01767 01768 if (isDir) 01769 l = new QLabel( i18n("Write\nEntries"), gb ); 01770 else 01771 l = new QLabel( i18n("Write"), gb ); 01772 gl->addWidget (l, 1, 2); 01773 QString writeWhatsThis; 01774 if (isDir) 01775 writeWhatsThis = i18n("This flag allows adding, renaming and deleting of files. " 01776 "Note that deleting and renaming can be limited using the Sticky flag."); 01777 else 01778 writeWhatsThis = i18n("The Write flag allows modifying the content of the file."); 01779 QWhatsThis::add(l, writeWhatsThis); 01780 01781 QString execWhatsThis; 01782 if (isDir) { 01783 l = new QLabel( i18n("Enter folder", "Enter"), gb ); 01784 execWhatsThis = i18n("Enable this flag to allow entering the folder."); 01785 } 01786 else { 01787 l = new QLabel( i18n("Exec"), gb ); 01788 execWhatsThis = i18n("Enable this flag to allow executing the file as a program."); 01789 } 01790 QWhatsThis::add(l, execWhatsThis); 01791 // GJ: Add space between normal and special modes 01792 QSize size = l->sizeHint(); 01793 size.setWidth(size.width() + 15); 01794 l->setFixedSize(size); 01795 gl->addWidget (l, 1, 3); 01796 01797 l = new QLabel( i18n("Special"), gb ); 01798 gl->addMultiCellWidget(l, 1, 1, 4, 5); 01799 QString specialWhatsThis; 01800 if (isDir) 01801 specialWhatsThis = i18n("Special flag. Valid for the whole folder, the exact " 01802 "meaning of the flag can be seen in the right hand column."); 01803 else 01804 specialWhatsThis = i18n("Special flag. The exact meaning of the flag can be seen " 01805 "in the right hand column."); 01806 QWhatsThis::add(l, specialWhatsThis); 01807 01808 cl[0] = new QLabel( i18n("User"), gb ); 01809 gl->addWidget (cl[0], 2, 0); 01810 01811 cl[1] = new QLabel( i18n("Group"), gb ); 01812 gl->addWidget (cl[1], 3, 0); 01813 01814 cl[2] = new QLabel( i18n("Others"), gb ); 01815 gl->addWidget (cl[2], 4, 0); 01816 01817 l = new QLabel(i18n("Set UID"), gb); 01818 gl->addWidget(l, 2, 5); 01819 QString setUidWhatsThis; 01820 if (isDir) 01821 setUidWhatsThis = i18n("If this flag is set, the owner of this folder will be " 01822 "the owner of all new files."); 01823 else 01824 setUidWhatsThis = i18n("If this file is an executable and the flag is set, it will " 01825 "be executed with the permissions of the owner."); 01826 QWhatsThis::add(l, setUidWhatsThis); 01827 01828 l = new QLabel(i18n("Set GID"), gb); 01829 gl->addWidget(l, 3, 5); 01830 QString setGidWhatsThis; 01831 if (isDir) 01832 setGidWhatsThis = i18n("If this flag is set, the group of this folder will be " 01833 "set for all new files."); 01834 else 01835 setGidWhatsThis = i18n("If this file is an executable and the flag is set, it will " 01836 "be executed with the permissions of the group."); 01837 QWhatsThis::add(l, setGidWhatsThis); 01838 01839 l = new QLabel(i18n("File permission, sets user or group ID on execution", "Sticky"), gb); 01840 gl->addWidget(l, 4, 5); 01841 QString stickyWhatsThis; 01842 if (isDir) 01843 stickyWhatsThis = i18n("If the Sticky flag is set on a folder, only the owner " 01844 "and root can delete or rename files. Otherwise everybody " 01845 "with write permissions can do this."); 01846 else 01847 stickyWhatsThis = i18n("The Sticky flag on a file is ignored on Linux, but may " 01848 "be used on some systems"); 01849 QWhatsThis::add(l, stickyWhatsThis); 01850 01851 mode_t aPermissions, aPartialPermissions; 01852 mode_t dummy1, dummy2; 01853 01854 if (!d->isIrregular) { 01855 switch (d->pmode) { 01856 case PermissionsOnlyFiles: 01857 getPermissionMasks(aPartialPermissions, 01858 dummy1, 01859 aPermissions, 01860 dummy2); 01861 break; 01862 case PermissionsOnlyDirs: 01863 case PermissionsMixed: 01864 getPermissionMasks(dummy1, 01865 aPartialPermissions, 01866 dummy2, 01867 aPermissions); 01868 break; 01869 case PermissionsOnlyLinks: 01870 aPermissions = UniRead | UniWrite | UniExec | UniSpecial; 01871 aPartialPermissions = 0; 01872 break; 01873 } 01874 } 01875 else { 01876 aPermissions = permissions; 01877 aPartialPermissions = d->partialPermissions; 01878 } 01879 01880 // Draw Checkboxes 01881 QCheckBox *cba[3][4]; 01882 for (int row = 0; row < 3 ; ++row) { 01883 for (int col = 0; col < 4; ++col) { 01884 QCheckBox *cb = new QCheckBox(gb); 01885 cba[row][col] = cb; 01886 cb->setChecked(aPermissions & fperm[row][col]); 01887 if ( aPartialPermissions & fperm[row][col] ) 01888 { 01889 cb->setTristate(); 01890 cb->setNoChange(); 01891 } 01892 else if (d->cbRecursive && d->cbRecursive->isChecked()) 01893 cb->setTristate(); 01894 01895 cb->setEnabled( d->canChangePermissions ); 01896 gl->addWidget (cb, row+2, col+1); 01897 switch(col) { 01898 case 0: 01899 QWhatsThis::add(cb, readWhatsThis); 01900 break; 01901 case 1: 01902 QWhatsThis::add(cb, writeWhatsThis); 01903 break; 01904 case 2: 01905 QWhatsThis::add(cb, execWhatsThis); 01906 break; 01907 case 3: 01908 switch(row) { 01909 case 0: 01910 QWhatsThis::add(cb, setUidWhatsThis); 01911 break; 01912 case 1: 01913 QWhatsThis::add(cb, setGidWhatsThis); 01914 break; 01915 case 2: 01916 QWhatsThis::add(cb, stickyWhatsThis); 01917 break; 01918 } 01919 break; 01920 } 01921 } 01922 } 01923 gl->setColStretch(6, 10); 01924 01925 if (dlg.exec() != KDialogBase::Accepted) 01926 return; 01927 01928 mode_t andPermissions = mode_t(~0); 01929 mode_t orPermissions = 0; 01930 for (int row = 0; row < 3; ++row) 01931 for (int col = 0; col < 4; ++col) { 01932 switch (cba[row][col]->state()) 01933 { 01934 case QCheckBox::On: 01935 orPermissions |= fperm[row][col]; 01936 //fall through 01937 case QCheckBox::Off: 01938 andPermissions &= ~fperm[row][col]; 01939 break; 01940 default: // NoChange 01941 break; 01942 } 01943 } 01944 01945 d->isIrregular = false; 01946 KFileItemList items = properties->items(); 01947 for (KFileItemListIterator it(items); it.current(); ++it) { 01948 if (isIrregular(((*it)->permissions() & andPermissions) | orPermissions, 01949 (*it)->isDir(), (*it)->isLink())) { 01950 d->isIrregular = true; 01951 break; 01952 } 01953 } 01954 01955 permissions = orPermissions; 01956 d->partialPermissions = andPermissions; 01957 01958 emit changed(); 01959 updateAccessControls(); 01960 } 01961 01962 // QString KFilePermissionsPropsPlugin::tabName () const 01963 // { 01964 // return i18n ("&Permissions"); 01965 // } 01966 01967 KFilePermissionsPropsPlugin::~KFilePermissionsPropsPlugin() 01968 { 01969 delete d; 01970 } 01971 01972 bool KFilePermissionsPropsPlugin::supports( KFileItemList /*_items*/ ) 01973 { 01974 return true; 01975 } 01976 01977 // sets a combo box in the Access Control frame 01978 void KFilePermissionsPropsPlugin::setComboContent(QComboBox *combo, PermissionsTarget target, 01979 mode_t permissions, mode_t partial) { 01980 combo->clear(); 01981 if (d->pmode == PermissionsOnlyLinks) { 01982 combo->insertItem(i18n("Link")); 01983 combo->setCurrentItem(0); 01984 return; 01985 } 01986 01987 mode_t tMask = permissionsMasks[target]; 01988 int textIndex; 01989 for (textIndex = 0; standardPermissions[textIndex] != (mode_t)-1; textIndex++) 01990 if ((standardPermissions[textIndex]&tMask) == (permissions&tMask&(UniRead|UniWrite))) 01991 break; 01992 Q_ASSERT(standardPermissions[textIndex] != (mode_t)-1); // must not happen, would be irreglar 01993 01994 for (int i = 0; permissionsTexts[(int)d->pmode][i]; i++) 01995 combo->insertItem(i18n(permissionsTexts[(int)d->pmode][i])); 01996 01997 if (partial & tMask & ~UniExec) { 01998 combo->insertItem(i18n("Varying (No Change)")); 01999 combo->setCurrentItem(3); 02000 } 02001 else 02002 combo->setCurrentItem(textIndex); 02003 } 02004 02005 // permissions are irregular if they cant be displayed in a combo box. 02006 bool KFilePermissionsPropsPlugin::isIrregular(mode_t permissions, bool isDir, bool isLink) { 02007 if (isLink) // links are always ok 02008 return false; 02009 02010 mode_t p = permissions; 02011 if (p & (S_ISUID | S_ISGID)) // setuid/setgid -> irregular 02012 return true; 02013 if (isDir) { 02014 p &= ~S_ISVTX; // ignore sticky on dirs 02015 02016 // check supported flag combinations 02017 mode_t p0 = p & UniOwner; 02018 if ((p0 != 0) && (p0 != (S_IRUSR | S_IXUSR)) && (p0 != UniOwner)) 02019 return true; 02020 p0 = p & UniGroup; 02021 if ((p0 != 0) && (p0 != (S_IRGRP | S_IXGRP)) && (p0 != UniGroup)) 02022 return true; 02023 p0 = p & UniOthers; 02024 if ((p0 != 0) && (p0 != (S_IROTH | S_IXOTH)) && (p0 != UniOthers)) 02025 return true; 02026 return false; 02027 } 02028 if (p & S_ISVTX) // sticky on file -> irregular 02029 return true; 02030 02031 // check supported flag combinations 02032 mode_t p0 = p & UniOwner; 02033 bool usrXPossible = !p0; // true if this file could be an executable 02034 if (p0 & S_IXUSR) { 02035 if ((p0 == S_IXUSR) || (p0 == (S_IWUSR | S_IXUSR))) 02036 return true; 02037 usrXPossible = true; 02038 } 02039 else if (p0 == S_IWUSR) 02040 return true; 02041 02042 p0 = p & UniGroup; 02043 bool grpXPossible = !p0; // true if this file could be an executable 02044 if (p0 & S_IXGRP) { 02045 if ((p0 == S_IXGRP) || (p0 == (S_IWGRP | S_IXGRP))) 02046 return true; 02047 grpXPossible = true; 02048 } 02049 else if (p0 == S_IWGRP) 02050 return true; 02051 if (p0 == 0) 02052 grpXPossible = true; 02053 02054 p0 = p & UniOthers; 02055 bool othXPossible = !p0; // true if this file could be an executable 02056 if (p0 & S_IXOTH) { 02057 if ((p0 == S_IXOTH) || (p0 == (S_IWOTH | S_IXOTH))) 02058 return true; 02059 othXPossible = true; 02060 } 02061 else if (p0 == S_IWOTH) 02062 return true; 02063 02064 // check that there either all targets are executable-compatible, or none 02065 return (p & UniExec) && !(usrXPossible && grpXPossible && othXPossible); 02066 } 02067 02068 // enables/disabled the widgets in the Access Control frame 02069 void KFilePermissionsPropsPlugin::enableAccessControls(bool enable) { 02070 d->ownerPermCombo->setEnabled(enable); 02071 d->groupPermCombo->setEnabled(enable); 02072 d->othersPermCombo->setEnabled(enable); 02073 if (d->extraCheckbox) 02074 d->extraCheckbox->setEnabled(enable); 02075 if ( d->cbRecursive ) 02076 d->cbRecursive->setEnabled(enable); 02077 } 02078 02079 // updates all widgets in the Access Control frame 02080 void KFilePermissionsPropsPlugin::updateAccessControls() { 02081 setComboContent(d->ownerPermCombo, PermissionsOwner, 02082 permissions, d->partialPermissions); 02083 setComboContent(d->groupPermCombo, PermissionsGroup, 02084 permissions, d->partialPermissions); 02085 setComboContent(d->othersPermCombo, PermissionsOthers, 02086 permissions, d->partialPermissions); 02087 02088 switch(d->pmode) { 02089 case PermissionsOnlyLinks: 02090 enableAccessControls(false); 02091 break; 02092 case PermissionsOnlyFiles: 02093 enableAccessControls(d->canChangePermissions && !d->isIrregular); 02094 if (d->canChangePermissions) 02095 d->explanationLabel->setText(d->isIrregular ? 02096 i18n("This file uses advanced permissions", 02097 "These files use advanced permissions.", 02098 properties->items().count()) : ""); 02099 if (d->partialPermissions & UniExec) { 02100 d->extraCheckbox->setTristate(); 02101 d->extraCheckbox->setNoChange(); 02102 } 02103 else { 02104 d->extraCheckbox->setTristate(false); 02105 d->extraCheckbox->setChecked(permissions & UniExec); 02106 } 02107 break; 02108 case PermissionsOnlyDirs: 02109 enableAccessControls(d->canChangePermissions && !d->isIrregular); 02110 if (d->canChangePermissions) 02111 d->explanationLabel->setText(d->isIrregular ? 02112 i18n("This folder uses advanced permissions.", 02113 "These folders use advanced permissions.", 02114 properties->items().count()) : ""); 02115 if (d->partialPermissions & S_ISVTX) { 02116 d->extraCheckbox->setTristate(); 02117 d->extraCheckbox->setNoChange(); 02118 } 02119 else { 02120 d->extraCheckbox->setTristate(false); 02121 d->extraCheckbox->setChecked(permissions & S_ISVTX); 02122 } 02123 break; 02124 case PermissionsMixed: 02125 enableAccessControls(d->canChangePermissions && !d->isIrregular); 02126 if (d->canChangePermissions) 02127 d->explanationLabel->setText(d->isIrregular ? 02128 i18n("These files use advanced permissions.") : ""); 02129 break; 02130 if (d->partialPermissions & S_ISVTX) { 02131 d->extraCheckbox->setTristate(); 02132 d->extraCheckbox->setNoChange(); 02133 } 02134 else { 02135 d->extraCheckbox->setTristate(false); 02136 d->extraCheckbox->setChecked(permissions & S_ISVTX); 02137 } 02138 break; 02139 } 02140 } 02141 02142 // gets masks for files and dirs from the Access Control frame widgets 02143 void KFilePermissionsPropsPlugin::getPermissionMasks(mode_t &andFilePermissions, 02144 mode_t &andDirPermissions, 02145 mode_t &orFilePermissions, 02146 mode_t &orDirPermissions) { 02147 andFilePermissions = mode_t(~UniSpecial); 02148 andDirPermissions = mode_t(~(S_ISUID|S_ISGID)); 02149 orFilePermissions = 0; 02150 orDirPermissions = 0; 02151 if (d->isIrregular) 02152 return; 02153 02154 mode_t m = standardPermissions[d->ownerPermCombo->currentItem()]; 02155 if (m != (mode_t) -1) { 02156 orFilePermissions |= m & UniOwner; 02157 if ((m & UniOwner) && 02158 ((d->pmode == PermissionsMixed) || 02159 ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == QButton::NoChange)))) 02160 andFilePermissions &= ~(S_IRUSR | S_IWUSR); 02161 else { 02162 andFilePermissions &= ~(S_IRUSR | S_IWUSR | S_IXUSR); 02163 if ((m & S_IRUSR) && (d->extraCheckbox->state() == QButton::On)) 02164 orFilePermissions |= S_IXUSR; 02165 } 02166 02167 orDirPermissions |= m & UniOwner; 02168 if (m & S_IRUSR) 02169 orDirPermissions |= S_IXUSR; 02170 andDirPermissions &= ~(S_IRUSR | S_IWUSR | S_IXUSR); 02171 } 02172 02173 m = standardPermissions[d->groupPermCombo->currentItem()]; 02174 if (m != (mode_t) -1) { 02175 orFilePermissions |= m & UniGroup; 02176 if ((m & UniGroup) && 02177 ((d->pmode == PermissionsMixed) || 02178 ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == QButton::NoChange)))) 02179 andFilePermissions &= ~(S_IRGRP | S_IWGRP); 02180 else { 02181 andFilePermissions &= ~(S_IRGRP | S_IWGRP | S_IXGRP); 02182 if ((m & S_IRGRP) && (d->extraCheckbox->state() == QButton::On)) 02183 orFilePermissions |= S_IXGRP; 02184 } 02185 02186 orDirPermissions |= m & UniGroup; 02187 if (m & S_IRGRP) 02188 orDirPermissions |= S_IXGRP; 02189 andDirPermissions &= ~(S_IRGRP | S_IWGRP | S_IXGRP); 02190 } 02191 02192 m = standardPermissions[d->othersPermCombo->currentItem()]; 02193 if (m != (mode_t) -1) { 02194 orFilePermissions |= m & UniOthers; 02195 if ((m & UniOthers) && 02196 ((d->pmode == PermissionsMixed) || 02197 ((d->pmode == PermissionsOnlyFiles) && (d->extraCheckbox->state() == QButton::NoChange)))) 02198 andFilePermissions &= ~(S_IROTH | S_IWOTH); 02199 else { 02200 andFilePermissions &= ~(S_IROTH | S_IWOTH | S_IXOTH); 02201 if ((m & S_IROTH) && (d->extraCheckbox->state() == QButton::On)) 02202 orFilePermissions |= S_IXOTH; 02203 } 02204 02205 orDirPermissions |= m & UniOthers; 02206 if (m & S_IROTH) 02207 orDirPermissions |= S_IXOTH; 02208 andDirPermissions &= ~(S_IROTH | S_IWOTH | S_IXOTH); 02209 } 02210 02211 if (((d->pmode == PermissionsMixed) || (d->pmode == PermissionsOnlyDirs)) && 02212 (d->extraCheckbox->state() != QButton::NoChange)) { 02213 andDirPermissions &= ~S_ISVTX; 02214 if (d->extraCheckbox->state() == QButton::On) 02215 orDirPermissions |= S_ISVTX; 02216 } 02217 } 02218 02219 void KFilePermissionsPropsPlugin::applyChanges() 02220 { 02221 mode_t orFilePermissions; 02222 mode_t orDirPermissions; 02223 mode_t andFilePermissions; 02224 mode_t andDirPermissions; 02225 02226 if (!d->canChangePermissions) 02227 return; 02228 02229 if (!d->isIrregular) 02230 getPermissionMasks(andFilePermissions, 02231 andDirPermissions, 02232 orFilePermissions, 02233 orDirPermissions); 02234 else { 02235 orFilePermissions = permissions; 02236 andFilePermissions = d->partialPermissions; 02237 orDirPermissions = permissions; 02238 andDirPermissions = d->partialPermissions; 02239 } 02240 02241 QString owner, group; 02242 if (usrEdit) 02243 owner = usrEdit->text(); 02244 if (grpEdit) 02245 group = grpEdit->text(); 02246 else if (grpCombo) 02247 group = grpCombo->currentText(); 02248 02249 if (owner == strOwner) 02250 owner = QString::null; // no change 02251 02252 if (group == strGroup) 02253 group = QString::null; 02254 02255 bool recursive = d->cbRecursive && d->cbRecursive->isChecked(); 02256 bool permissionChange = false; 02257 02258 KFileItemList files, dirs; 02259 KFileItemList items = properties->items(); 02260 for (KFileItemListIterator it(items); it.current(); ++it) { 02261 if ((*it)->isDir()) { 02262 dirs.append(*it); 02263 if ((*it)->permissions() != (((*it)->permissions() & andDirPermissions) | orDirPermissions)) 02264 permissionChange = true; 02265 } 02266 else if ((*it)->isFile()) { 02267 files.append(*it); 02268 if ((*it)->permissions() != (((*it)->permissions() & andFilePermissions) | orFilePermissions)) 02269 permissionChange = true; 02270 } 02271 } 02272 02273 if ( !owner.isEmpty() || !group.isEmpty() || recursive || permissionChange) 02274 { 02275 KIO::Job * job; 02276 if (files.count() > 0) { 02277 job = KIO::chmod( files, orFilePermissions, ~andFilePermissions, 02278 owner, group, false ); 02279 connect( job, SIGNAL( result( KIO::Job * ) ), 02280 SLOT( slotChmodResult( KIO::Job * ) ) ); 02281 // Wait for job 02282 QWidget dummy(0,0,WType_Dialog|WShowModal); 02283 qt_enter_modal(&dummy); 02284 qApp->enter_loop(); 02285 qt_leave_modal(&dummy); 02286 } 02287 if (dirs.count() > 0) { 02288 job = KIO::chmod( dirs, orDirPermissions, ~andDirPermissions, 02289 owner, group, recursive ); 02290 connect( job, SIGNAL( result( KIO::Job * ) ), 02291 SLOT( slotChmodResult( KIO::Job * ) ) ); 02292 // Wait for job 02293 QWidget dummy(0,0,WType_Dialog|WShowModal); 02294 qt_enter_modal(&dummy); 02295 qApp->enter_loop(); 02296 qt_leave_modal(&dummy); 02297 } 02298 } 02299 } 02300 02301 void KFilePermissionsPropsPlugin::slotChmodResult( KIO::Job * job ) 02302 { 02303 kdDebug(250) << "KFilePermissionsPropsPlugin::slotChmodResult" << endl; 02304 if (job->error()) 02305 job->showErrorDialog( d->m_frame ); 02306 // allow apply() to return 02307 qApp->exit_loop(); 02308 } 02309 02310 02311 02312 02313 class KURLPropsPlugin::KURLPropsPluginPrivate 02314 { 02315 public: 02316 KURLPropsPluginPrivate() 02317 { 02318 } 02319 ~KURLPropsPluginPrivate() 02320 { 02321 } 02322 02323 QFrame *m_frame; 02324 }; 02325 02326 KURLPropsPlugin::KURLPropsPlugin( KPropertiesDialog *_props ) 02327 : KPropsDlgPlugin( _props ) 02328 { 02329 d = new KURLPropsPluginPrivate; 02330 d->m_frame = properties->addPage(i18n("U&RL")); 02331 QVBoxLayout *layout = new QVBoxLayout(d->m_frame, 0, KDialog::spacingHint()); 02332 02333 QLabel *l; 02334 l = new QLabel( d->m_frame, "Label_1" ); 02335 l->setText( i18n("URL:") ); 02336 layout->addWidget(l); 02337 02338 URLEdit = new KURLRequester( d->m_frame, "URL Requester" ); 02339 layout->addWidget(URLEdit); 02340 02341 QString path = properties->kurl().path(); 02342 02343 QFile f( path ); 02344 if ( !f.open( IO_ReadOnly ) ) 02345 return; 02346 f.close(); 02347 02348 KSimpleConfig config( path ); 02349 config.setDesktopGroup(); 02350 URLStr = config.readPathEntry( "URL" ); 02351 02352 if ( !URLStr.isNull() ) 02353 URLEdit->setURL( URLStr ); 02354 02355 connect( URLEdit, SIGNAL( textChanged( const QString & ) ), 02356 this, SIGNAL( changed() ) ); 02357 02358 layout->addStretch (1); 02359 } 02360 02361 KURLPropsPlugin::~KURLPropsPlugin() 02362 { 02363 delete d; 02364 } 02365 02366 // QString KURLPropsPlugin::tabName () const 02367 // { 02368 // return i18n ("U&RL"); 02369 // } 02370 02371 bool KURLPropsPlugin::supports( KFileItemList _items ) 02372 { 02373 if ( _items.count() != 1 ) 02374 return false; 02375 KFileItem * item = _items.first(); 02376 // check if desktop file 02377 if ( !KPropsDlgPlugin::isDesktopFile( item ) ) 02378 return false; 02379 02380 // open file and check type 02381 KDesktopFile config( item->url().path(), true /* readonly */ ); 02382 return config.hasLinkType(); 02383 } 02384 02385 void KURLPropsPlugin::applyChanges() 02386 { 02387 QString path = properties->kurl().path(); 02388 02389 QFile f( path ); 02390 if ( !f.open( IO_ReadWrite ) ) { 02391 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have " 02392 "sufficient access to write to <b>%1</b>.</qt>").arg(path)); 02393 return; 02394 } 02395 f.close(); 02396 02397 KSimpleConfig config( path ); 02398 config.setDesktopGroup(); 02399 config.writeEntry( "Type", QString::fromLatin1("Link")); 02400 config.writePathEntry( "URL", URLEdit->url() ); 02401 // Users can't create a Link .desktop file with a Name field, 02402 // but distributions can. Update the Name field in that case. 02403 if ( config.hasKey("Name") ) 02404 { 02405 QString nameStr = nameFromFileName(properties->kurl().fileName()); 02406 config.writeEntry( "Name", nameStr ); 02407 config.writeEntry( "Name", nameStr, true, false, true ); 02408 02409 } 02410 } 02411 02412 02413 /* ---------------------------------------------------- 02414 * 02415 * KBindingPropsPlugin 02416 * 02417 * -------------------------------------------------- */ 02418 02419 class KBindingPropsPlugin::KBindingPropsPluginPrivate 02420 { 02421 public: 02422 KBindingPropsPluginPrivate() 02423 { 02424 } 02425 ~KBindingPropsPluginPrivate() 02426 { 02427 } 02428 02429 QFrame *m_frame; 02430 }; 02431 02432 KBindingPropsPlugin::KBindingPropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props ) 02433 { 02434 d = new KBindingPropsPluginPrivate; 02435 d->m_frame = properties->addPage(i18n("A&ssociation")); 02436 patternEdit = new KLineEdit( d->m_frame, "LineEdit_1" ); 02437 commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" ); 02438 mimeEdit = new KLineEdit( d->m_frame, "LineEdit_3" ); 02439 02440 QBoxLayout *mainlayout = new QVBoxLayout(d->m_frame, 0, KDialog::spacingHint()); 02441 QLabel* tmpQLabel; 02442 02443 tmpQLabel = new QLabel( d->m_frame, "Label_1" ); 02444 tmpQLabel->setText( i18n("Pattern ( example: *.html;*.htm )") ); 02445 tmpQLabel->setMinimumSize(tmpQLabel->sizeHint()); 02446 mainlayout->addWidget(tmpQLabel, 1); 02447 02448 //patternEdit->setGeometry( 10, 40, 210, 30 ); 02449 //patternEdit->setText( "" ); 02450 patternEdit->setMaxLength( 512 ); 02451 patternEdit->setMinimumSize( patternEdit->sizeHint() ); 02452 patternEdit->setFixedHeight( fontHeight ); 02453 mainlayout->addWidget(patternEdit, 1); 02454 02455 tmpQLabel = new QLabel( d->m_frame, "Label_2" ); 02456 tmpQLabel->setText( i18n("Mime Type") ); 02457 tmpQLabel->setMinimumSize(tmpQLabel->sizeHint()); 02458 mainlayout->addWidget(tmpQLabel, 1); 02459 02460 //mimeEdit->setGeometry( 10, 160, 210, 30 ); 02461 mimeEdit->setMaxLength( 256 ); 02462 mimeEdit->setMinimumSize( mimeEdit->sizeHint() ); 02463 mimeEdit->setFixedHeight( fontHeight ); 02464 mainlayout->addWidget(mimeEdit, 1); 02465 02466 tmpQLabel = new QLabel( d->m_frame, "Label_3" ); 02467 tmpQLabel->setText( i18n("Comment") ); 02468 tmpQLabel->setMinimumSize(tmpQLabel->sizeHint()); 02469 mainlayout->addWidget(tmpQLabel, 1); 02470 02471 //commentEdit->setGeometry( 10, 100, 210, 30 ); 02472 commentEdit->setMaxLength( 256 ); 02473 commentEdit->setMinimumSize( commentEdit->sizeHint() ); 02474 commentEdit->setFixedHeight( fontHeight ); 02475 mainlayout->addWidget(commentEdit, 1); 02476 02477 cbAutoEmbed = new QCheckBox( i18n("Left click previews"), d->m_frame, "cbAutoEmbed" ); 02478 mainlayout->addWidget(cbAutoEmbed, 1); 02479 02480 mainlayout->addStretch (10); 02481 mainlayout->activate(); 02482 02483 QFile f( _props->kurl().path() ); 02484 if ( !f.open( IO_ReadOnly ) ) 02485 return; 02486 f.close(); 02487 02488 KSimpleConfig config( _props->kurl().path() ); 02489 config.setDesktopGroup(); 02490 QString patternStr = config.readEntry( "Patterns" ); 02491 QString iconStr = config.readEntry( "Icon" ); 02492 QString commentStr = config.readEntry( "Comment" ); 02493 m_sMimeStr = config.readEntry( "MimeType" ); 02494 02495 if ( !patternStr.isEmpty() ) 02496 patternEdit->setText( patternStr ); 02497 if ( !commentStr.isEmpty() ) 02498 commentEdit->setText( commentStr ); 02499 if ( !m_sMimeStr.isEmpty() ) 02500 mimeEdit->setText( m_sMimeStr ); 02501 cbAutoEmbed->setTristate(); 02502 if ( config.hasKey( "X-KDE-AutoEmbed" ) ) 02503 cbAutoEmbed->setChecked( config.readBoolEntry( "X-KDE-AutoEmbed" ) ); 02504 else 02505 cbAutoEmbed->setNoChange(); 02506 02507 connect( patternEdit, SIGNAL( textChanged( const QString & ) ), 02508 this, SIGNAL( changed() ) ); 02509 connect( commentEdit, SIGNAL( textChanged( const QString & ) ), 02510 this, SIGNAL( changed() ) ); 02511 connect( mimeEdit, SIGNAL( textChanged( const QString & ) ), 02512 this, SIGNAL( changed() ) ); 02513 connect( cbAutoEmbed, SIGNAL( toggled( bool ) ), 02514 this, SIGNAL( changed() ) ); 02515 } 02516 02517 KBindingPropsPlugin::~KBindingPropsPlugin() 02518 { 02519 delete d; 02520 } 02521 02522 // QString KBindingPropsPlugin::tabName () const 02523 // { 02524 // return i18n ("A&ssociation"); 02525 // } 02526 02527 bool KBindingPropsPlugin::supports( KFileItemList _items ) 02528 { 02529 if ( _items.count() != 1 ) 02530 return false; 02531 KFileItem * item = _items.first(); 02532 // check if desktop file 02533 if ( !KPropsDlgPlugin::isDesktopFile( item ) ) 02534 return false; 02535 02536 // open file and check type 02537 KDesktopFile config( item->url().path(), true /* readonly */ ); 02538 return config.hasMimeTypeType(); 02539 } 02540 02541 void KBindingPropsPlugin::applyChanges() 02542 { 02543 QString path = properties->kurl().path(); 02544 QFile f( path ); 02545 02546 if ( !f.open( IO_ReadWrite ) ) 02547 { 02548 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have " 02549 "sufficient access to write to <b>%1</b>.</qt>").arg(path)); 02550 return; 02551 } 02552 f.close(); 02553 02554 KSimpleConfig config( path ); 02555 config.setDesktopGroup(); 02556 config.writeEntry( "Type", QString::fromLatin1("MimeType") ); 02557 02558 config.writeEntry( "Patterns", patternEdit->text() ); 02559 config.writeEntry( "Comment", commentEdit->text() ); 02560 config.writeEntry( "Comment", 02561 commentEdit->text(), true, false, true ); // for compat 02562 config.writeEntry( "MimeType", mimeEdit->text() ); 02563 if ( cbAutoEmbed->state() == QButton::NoChange ) 02564 config.deleteEntry( "X-KDE-AutoEmbed", false ); 02565 else 02566 config.writeEntry( "X-KDE-AutoEmbed", cbAutoEmbed->isChecked() ); 02567 config.sync(); 02568 } 02569 02570 /* ---------------------------------------------------- 02571 * 02572 * KDevicePropsPlugin 02573 * 02574 * -------------------------------------------------- */ 02575 02576 class KDevicePropsPlugin::KDevicePropsPluginPrivate 02577 { 02578 public: 02579 KDevicePropsPluginPrivate() 02580 { 02581 } 02582 ~KDevicePropsPluginPrivate() 02583 { 02584 } 02585 02586 QFrame *m_frame; 02587 QStringList mountpointlist; 02588 }; 02589 02590 KDevicePropsPlugin::KDevicePropsPlugin( KPropertiesDialog *_props ) : KPropsDlgPlugin( _props ) 02591 { 02592 d = new KDevicePropsPluginPrivate; 02593 d->m_frame = properties->addPage(i18n("De&vice")); 02594 02595 QStringList devices; 02596 KMountPoint::List mountPoints = KMountPoint::possibleMountPoints(); 02597 02598 for(KMountPoint::List::ConstIterator it = mountPoints.begin(); 02599 it != mountPoints.end(); ++it) 02600 { 02601 KMountPoint *mp = *it; 02602 QString mountPoint = mp->mountPoint(); 02603 QString device = mp->mountedFrom(); 02604 kdDebug()<<"mountPoint :"<<mountPoint<<" device :"<<device<<" mp->mountType() :"<<mp->mountType()<<endl; 02605 02606 if ((mountPoint != "-") && (mountPoint != "none") && !mountPoint.isEmpty() 02607 && device != "none") 02608 { 02609 devices.append( device + QString::fromLatin1(" (") 02610 + mountPoint + QString::fromLatin1(")") ); 02611 m_devicelist.append(device); 02612 d->mountpointlist.append(mountPoint); 02613 } 02614 } 02615 02616 QGridLayout *layout = new QGridLayout( d->m_frame, 0, 3, 0, 02617 KDialog::spacingHint()); 02618 layout->setColStretch(1, 1); 02619 02620 QLabel* label; 02621 label = new QLabel( d->m_frame ); 02622 label->setText( devices.count() == 0 ? 02623 i18n("Device (/dev/fd0):") : // old style 02624 i18n("Device:") ); // new style (combobox) 02625 layout->addWidget(label, 0, 0); 02626 02627 device = new QComboBox( true, d->m_frame, "ComboBox_device" ); 02628 device->insertStringList( devices ); 02629 layout->addWidget(device, 0, 1); 02630 connect( device, SIGNAL( activated( int ) ), 02631 this, SLOT( slotActivated( int ) ) ); 02632 02633 readonly = new QCheckBox( d->m_frame, "CheckBox_readonly" ); 02634 readonly->setText( i18n("Read only") ); 02635 layout->addWidget(readonly, 1, 1); 02636 02637 label = new QLabel( d->m_frame ); 02638 label->setText( devices.count()==0 ? 02639 i18n("Mount point (/mnt/floppy):") : // old style 02640 i18n("Mount point:")); // new style (combobox) 02641 layout->addWidget(label, 2, 0); 02642 02643 mountpoint = new QLabel( d->m_frame, "LineEdit_mountpoint" ); 02644 02645 layout->addWidget(mountpoint, 2, 1); 02646 02647 KSeparator* sep = new KSeparator( KSeparator::HLine, d->m_frame); 02648 layout->addMultiCellWidget(sep, 4, 4, 0, 2); 02649 02650 unmounted = new KIconButton( d->m_frame ); 02651 int bsize = 66 + 2 * unmounted->style().pixelMetric(QStyle::PM_ButtonMargin); 02652 unmounted->setFixedSize(bsize, bsize); 02653 unmounted->setIconType(KIcon::Desktop, KIcon::Device); 02654 layout->addWidget(unmounted, 5, 0); 02655 02656 label = new QLabel( i18n("Unmounted Icon"), d->m_frame ); 02657 layout->addWidget(label, 5, 1); 02658 02659 layout->setRowStretch(6, 1); 02660 02661 QString path( _props->kurl().path() ); 02662 02663 QFile f( path ); 02664 if ( !f.open( IO_ReadOnly ) ) 02665 return; 02666 f.close(); 02667 02668 KSimpleConfig config( path ); 02669 config.setDesktopGroup(); 02670 QString deviceStr = config.readEntry( "Dev" ); 02671 QString mountPointStr = config.readEntry( "MountPoint" ); 02672 bool ro = config.readBoolEntry( "ReadOnly", false ); 02673 QString unmountedStr = config.readEntry( "UnmountIcon" ); 02674 02675 device->setEditText( deviceStr ); 02676 if ( !deviceStr.isEmpty() ) { 02677 // Set default options for this device (first matching entry) 02678 int index = m_devicelist.findIndex(deviceStr); 02679 if (index != -1) 02680 { 02681 //kdDebug(250) << "found it " << index << endl; 02682 slotActivated( index ); 02683 } 02684 } 02685 02686 if ( !mountPointStr.isEmpty() ) 02687 mountpoint->setText( mountPointStr ); 02688 02689 readonly->setChecked( ro ); 02690 02691 if ( unmountedStr.isEmpty() ) 02692 unmountedStr = KMimeType::mimeType(QString::fromLatin1("application/octet-stream"))->KServiceType::icon(); // default icon 02693 02694 unmounted->setIcon( unmountedStr ); 02695 02696 connect( device, SIGNAL( activated( int ) ), 02697 this, SIGNAL( changed() ) ); 02698 connect( device, SIGNAL( textChanged( const QString & ) ), 02699 this, SIGNAL( changed() ) ); 02700 connect( readonly, SIGNAL( toggled( bool ) ), 02701 this, SIGNAL( changed() ) ); 02702 connect( unmounted, SIGNAL( iconChanged( QString ) ), 02703 this, SIGNAL( changed() ) ); 02704 02705 connect( device, SIGNAL( textChanged( const QString & ) ), 02706 this, SLOT( slotDeviceChanged() ) ); 02707 } 02708 02709 KDevicePropsPlugin::~KDevicePropsPlugin() 02710 { 02711 delete d; 02712 } 02713 02714 // QString KDevicePropsPlugin::tabName () const 02715 // { 02716 // return i18n ("De&vice"); 02717 // } 02718 02719 void KDevicePropsPlugin::slotActivated( int index ) 02720 { 02721 // Update mountpoint so that it matches the device that was selected in the combo 02722 device->setEditText( m_devicelist[index] ); 02723 mountpoint->setText( d->mountpointlist[index] ); 02724 } 02725 02726 void KDevicePropsPlugin::slotDeviceChanged() 02727 { 02728 // Update mountpoint so that it matches the typed device 02729 int index = m_devicelist.findIndex( device->currentText() ); 02730 if ( index != -1 ) 02731 mountpoint->setText( d->mountpointlist[index] ); 02732 else 02733 mountpoint->setText( QString::null ); 02734 } 02735 02736 bool KDevicePropsPlugin::supports( KFileItemList _items ) 02737 { 02738 if ( _items.count() != 1 ) 02739 return false; 02740 KFileItem * item = _items.first(); 02741 // check if desktop file 02742 if ( !KPropsDlgPlugin::isDesktopFile( item ) ) 02743 return false; 02744 // open file and check type 02745 KDesktopFile config( item->url().path(), true /* readonly */ ); 02746 return config.hasDeviceType(); 02747 } 02748 02749 void KDevicePropsPlugin::applyChanges() 02750 { 02751 QString path = properties->kurl().path(); 02752 QFile f( path ); 02753 if ( !f.open( IO_ReadWrite ) ) 02754 { 02755 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have sufficient " 02756 "access to write to <b>%1</b>.</qt>").arg(path)); 02757 return; 02758 } 02759 f.close(); 02760 02761 KSimpleConfig config( path ); 02762 config.setDesktopGroup(); 02763 config.writeEntry( "Type", QString::fromLatin1("FSDevice") ); 02764 02765 config.writeEntry( "Dev", device->currentText() ); 02766 config.writeEntry( "MountPoint", mountpoint->text() ); 02767 02768 config.writeEntry( "UnmountIcon", unmounted->icon() ); 02769 kdDebug(250) << "unmounted->icon() = " << unmounted->icon() << endl; 02770 02771 config.writeEntry( "ReadOnly", readonly->isChecked() ); 02772 02773 config.sync(); 02774 } 02775 02776 02777 /* ---------------------------------------------------- 02778 * 02779 * KDesktopPropsPlugin 02780 * 02781 * -------------------------------------------------- */ 02782 02783 02784 KDesktopPropsPlugin::KDesktopPropsPlugin( KPropertiesDialog *_props ) 02785 : KPropsDlgPlugin( _props ) 02786 { 02787 QFrame *frame = properties->addPage(i18n("&Application")); 02788 QVBoxLayout *mainlayout = new QVBoxLayout( frame, 0, KDialog::spacingHint() ); 02789 02790 w = new KPropertiesDesktopBase(frame); 02791 mainlayout->addWidget(w); 02792 02793 bool bKDesktopMode = (QCString(qApp->name()) == "kdesktop"); // nasty heh? 02794 02795 if (bKDesktopMode) 02796 { 02797 // Hide Name entry 02798 w->nameEdit->hide(); 02799 w->nameLabel->hide(); 02800 } 02801 02802 w->pathEdit->setMode(KFile::Directory | KFile::LocalOnly); 02803 w->pathEdit->lineEdit()->setAcceptDrops(false); 02804 02805 connect( w->nameEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) ); 02806 connect( w->genNameEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) ); 02807 connect( w->commentEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) ); 02808 connect( w->commandEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) ); 02809 connect( w->pathEdit, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) ); 02810 02811 connect( w->browseButton, SIGNAL( clicked() ), this, SLOT( slotBrowseExec() ) ); 02812 connect( w->addFiletypeButton, SIGNAL( clicked() ), this, SLOT( slotAddFiletype() ) ); 02813 connect( w->delFiletypeButton, SIGNAL( clicked() ), this, SLOT( slotDelFiletype() ) ); 02814 connect( w->advancedButton, SIGNAL( clicked() ), this, SLOT( slotAdvanced() ) ); 02815 02816 // now populate the page 02817 QString path = _props->kurl().path(); 02818 QFile f( path ); 02819 if ( !f.open( IO_ReadOnly ) ) 02820 return; 02821 f.close(); 02822 02823 KSimpleConfig config( path ); 02824 config.setDollarExpansion( false ); 02825 config.setDesktopGroup(); 02826 QString nameStr = config.readEntry( "Name" ); 02827 QString genNameStr = config.readEntry( "GenericName" ); 02828 QString commentStr = config.readEntry( "Comment" ); 02829 QString commandStr = config.readPathEntry( "Exec" ); 02830 if (commandStr.left(12) == "ksystraycmd ") 02831 { 02832 commandStr.remove(0, 12); 02833 m_systrayBool = true; 02834 } 02835 else 02836 m_systrayBool = false; 02837 02838 m_origCommandStr = commandStr; 02839 QString pathStr = config.readPathEntry( "Path" ); 02840 m_terminalBool = config.readBoolEntry( "Terminal" ); 02841 m_terminalOptionStr = config.readEntry( "TerminalOptions" ); 02842 m_suidBool = config.readBoolEntry( "X-KDE-SubstituteUID" ); 02843 m_suidUserStr = config.readEntry( "X-KDE-Username" ); 02844 if( config.hasKey( "StartupNotify" )) 02845 m_startupBool = config.readBoolEntry( "StartupNotify", true ); 02846 else 02847 m_startupBool = config.readBoolEntry( "X-KDE-StartupNotify", true ); 02848 m_dcopServiceType = config.readEntry("X-DCOP-ServiceType").lower(); 02849 02850 QStringList mimeTypes = config.readListEntry( "MimeType", ';' ); 02851 02852 if ( nameStr.isEmpty() || bKDesktopMode ) { 02853 // We'll use the file name if no name is specified 02854 // because we _need_ a Name for a valid file. 02855 // But let's do it in apply, not here, so that we pick up the right name. 02856 setDirty(); 02857 } 02858 if ( !bKDesktopMode ) 02859 w->nameEdit->setText(nameStr); 02860 02861 w->genNameEdit->setText( genNameStr ); 02862 w->commentEdit->setText( commentStr ); 02863 w->commandEdit->setText( commandStr ); 02864 w->pathEdit->lineEdit()->setText( pathStr ); 02865 w->filetypeList->setAllColumnsShowFocus(true); 02866 02867 KMimeType::Ptr defaultMimetype = KMimeType::defaultMimeTypePtr(); 02868 for(QStringList::ConstIterator it = mimeTypes.begin(); 02869 it != mimeTypes.end(); ) 02870 { 02871 KMimeType::Ptr p = KMimeType::mimeType(*it); 02872 ++it; 02873 QString preference; 02874 if (it != mimeTypes.end()) 02875 { 02876 bool numeric; 02877 (*it).toInt(&numeric); 02878 if (numeric) 02879 { 02880 preference = *it; 02881 ++it; 02882 } 02883 } 02884 if (p && (p != defaultMimetype)) 02885 { 02886 new QListViewItem(w->filetypeList, p->name(), p->comment(), preference); 02887 } 02888 } 02889 02890 } 02891 02892 KDesktopPropsPlugin::~KDesktopPropsPlugin() 02893 { 02894 } 02895 02896 void KDesktopPropsPlugin::slotSelectMimetype() 02897 { 02898 QListView *w = (QListView*)sender(); 02899 QListViewItem *item = w->firstChild(); 02900 while(item) 02901 { 02902 if (item->isSelected()) 02903 w->setSelected(item, false); 02904 item = item->nextSibling(); 02905 } 02906 } 02907 02908 void KDesktopPropsPlugin::slotAddFiletype() 02909 { 02910 KDialogBase dlg(w, "KPropertiesMimetypes", true, 02911 i18n("Add File Type for %1").arg(properties->kurl().fileName()), 02912 KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok); 02913 02914 KGuiItem okItem(i18n("&Add"), QString::null /* no icon */, 02915 i18n("Add the selected file types to\nthe list of supported file types."), 02916 i18n("Add the selected file types to\nthe list of supported file types.")); 02917 dlg.setButtonOK(okItem); 02918 02919 KPropertiesMimetypeBase *mw = new KPropertiesMimetypeBase(&dlg); 02920 02921 dlg.setMainWidget(mw); 02922 02923 { 02924 mw->listView->setRootIsDecorated(true); 02925 mw->listView->setSelectionMode(QListView::Extended); 02926 mw->listView->setAllColumnsShowFocus(true); 02927 mw->listView->setFullWidth(true); 02928 mw->listView->setMinimumSize(500,400); 02929 02930 connect(mw->listView, SIGNAL(selectionChanged()), 02931 this, SLOT(slotSelectMimetype())); 02932 connect(mw->listView, SIGNAL(doubleClicked( QListViewItem *, const QPoint &, int )), 02933 &dlg, SLOT( slotOk())); 02934 02935 QMap<QString,QListViewItem*> majorMap; 02936 QListViewItem *majorGroup; 02937 KMimeType::List mimetypes = KMimeType::allMimeTypes(); 02938 QValueListIterator<KMimeType::Ptr> it(mimetypes.begin()); 02939 for (; it != mimetypes.end(); ++it) { 02940 QString mimetype = (*it)->name(); 02941 if (mimetype == "application/octet-stream") 02942 continue; 02943 int index = mimetype.find("/"); 02944 QString maj = mimetype.left(index); 02945 QString min = mimetype.mid(index+1); 02946 02947 QMapIterator<QString,QListViewItem*> mit = majorMap.find( maj ); 02948 if ( mit == majorMap.end() ) { 02949 majorGroup = new QListViewItem( mw->listView, maj ); 02950 majorGroup->setExpandable(true); 02951 mw->listView->setOpen(majorGroup, true); 02952 majorMap.insert( maj, majorGroup ); 02953 } 02954 else 02955 { 02956 majorGroup = mit.data(); 02957 } 02958 02959 QListViewItem *item = new QListViewItem(majorGroup, min, (*it)->comment()); 02960 item->setPixmap(0, (*it)->pixmap(KIcon::Small, IconSize(KIcon::Small))); 02961 } 02962 QMapIterator<QString,QListViewItem*> mit = majorMap.find( "all" ); 02963 if ( mit != majorMap.end()) 02964 { 02965 mw->listView->setCurrentItem(mit.data()); 02966 mw->listView->ensureItemVisible(mit.data()); 02967 } 02968 } 02969 02970 if (dlg.exec() == KDialogBase::Accepted) 02971 { 02972 KMimeType::Ptr defaultMimetype = KMimeType::defaultMimeTypePtr(); 02973 QListViewItem *majorItem = mw->listView->firstChild(); 02974 while(majorItem) 02975 { 02976 QString major = majorItem->text(0); 02977 02978 QListViewItem *minorItem = majorItem->firstChild(); 02979 while(minorItem) 02980 { 02981 if (minorItem->isSelected()) 02982 { 02983 QString mimetype = major + "/" + minorItem->text(0); 02984 KMimeType::Ptr p = KMimeType::mimeType(mimetype); 02985 if (p && (p != defaultMimetype)) 02986 { 02987 mimetype = p->name(); 02988 bool found = false; 02989 QListViewItem *item = w->filetypeList->firstChild(); 02990 while (item) 02991 { 02992 if (mimetype == item->text(0)) 02993 { 02994 found = true; 02995 break; 02996 } 02997 item = item->nextSibling(); 02998 } 02999 if (!found) 03000 new QListViewItem(w->filetypeList, p->name(), p->comment()); 03001 } 03002 } 03003 minorItem = minorItem->nextSibling(); 03004 } 03005 03006 majorItem = majorItem->nextSibling(); 03007 } 03008 03009 } 03010 } 03011 03012 void KDesktopPropsPlugin::slotDelFiletype() 03013 { 03014 delete w->filetypeList->currentItem(); 03015 } 03016 03017 void KDesktopPropsPlugin::checkCommandChanged() 03018 { 03019 if (KRun::binaryName(w->commandEdit->text(), true) != 03020 KRun::binaryName(m_origCommandStr, true)) 03021 { 03022 QString m_origCommandStr = w->commandEdit->text(); 03023 m_dcopServiceType= QString::null; // Reset 03024 } 03025 } 03026 03027 void KDesktopPropsPlugin::applyChanges() 03028 { 03029 kdDebug(250) << "KDesktopPropsPlugin::applyChanges" << endl; 03030 QString path = properties->kurl().path(); 03031 03032 QFile f( path ); 03033 03034 if ( !f.open( IO_ReadWrite ) ) { 03035 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have " 03036 "sufficient access to write to <b>%1</b>.</qt>").arg(path)); 03037 return; 03038 } 03039 f.close(); 03040 03041 // If the command is changed we reset certain settings that are strongly 03042 // coupled to the command. 03043 checkCommandChanged(); 03044 03045 KSimpleConfig config( path ); 03046 config.setDesktopGroup(); 03047 config.writeEntry( "Type", QString::fromLatin1("Application")); 03048 config.writeEntry( "Comment", w->commentEdit->text() ); 03049 config.writeEntry( "Comment", w->commentEdit->text(), true, false, true ); // for compat 03050 config.writeEntry( "GenericName", w->genNameEdit->text() ); 03051 config.writeEntry( "GenericName", w->genNameEdit->text(), true, false, true ); // for compat 03052 03053 if (m_systrayBool) 03054 config.writePathEntry( "Exec", w->commandEdit->text().prepend("ksystraycmd ") ); 03055 else 03056 config.writePathEntry( "Exec", w->commandEdit->text() ); 03057 config.writePathEntry( "Path", w->pathEdit->lineEdit()->text() ); 03058 03059 // Write mimeTypes 03060 QStringList mimeTypes; 03061 for( QListViewItem *item = w->filetypeList->firstChild(); 03062 item; item = item->nextSibling() ) 03063 { 03064 QString preference = item->text(2); 03065 mimeTypes.append(item->text(0)); 03066 if (!preference.isEmpty()) 03067 mimeTypes.append(preference); 03068 } 03069 03070 config.writeEntry( "MimeType", mimeTypes, ';' ); 03071 03072 if ( !w->nameEdit->isHidden() ) { 03073 QString nameStr = w->nameEdit->text(); 03074 config.writeEntry( "Name", nameStr ); 03075 config.writeEntry( "Name", nameStr, true, false, true ); 03076 } 03077 03078 config.writeEntry("Terminal", m_terminalBool); 03079 config.writeEntry("TerminalOptions", m_terminalOptionStr); 03080 config.writeEntry("X-KDE-SubstituteUID", m_suidBool); 03081 config.writeEntry("X-KDE-Username", m_suidUserStr); 03082 config.writeEntry("StartupNotify", m_startupBool); 03083 config.writeEntry("X-DCOP-ServiceType", m_dcopServiceType); 03084 config.sync(); 03085 03086 // KSycoca update needed? 03087 QString sycocaPath = KGlobal::dirs()->relativeLocation("apps", path); 03088 bool updateNeeded = !sycocaPath.startsWith("/"); 03089 if (!updateNeeded) 03090 { 03091 sycocaPath = KGlobal::dirs()->relativeLocation("xdgdata-apps", path); 03092 updateNeeded = !sycocaPath.startsWith("/"); 03093 } 03094 if (updateNeeded) 03095 KService::rebuildKSycoca(w); 03096 } 03097 03098 03099 void KDesktopPropsPlugin::slotBrowseExec() 03100 { 03101 KURL f = KFileDialog::getOpenURL( QString::null, 03102 QString::null, w ); 03103 if ( f.isEmpty() ) 03104 return; 03105 03106 if ( !f.isLocalFile()) { 03107 KMessageBox::sorry(w, i18n("Only executables on local file systems are supported.")); 03108 return; 03109 } 03110 03111 QString path = f.path(); 03112 KRun::shellQuote( path ); 03113 w->commandEdit->setText( path ); 03114 } 03115 03116 void KDesktopPropsPlugin::slotAdvanced() 03117 { 03118 KDialogBase dlg(w, "KPropertiesDesktopAdv", true, 03119 i18n("Advanced Options for %1").arg(properties->kurl().fileName()), 03120 KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok); 03121 KPropertiesDesktopAdvBase *w = new KPropertiesDesktopAdvBase(&dlg); 03122 03123 dlg.setMainWidget(w); 03124 03125 // If the command is changed we reset certain settings that are strongly 03126 // coupled to the command. 03127 checkCommandChanged(); 03128 03129 // check to see if we use konsole if not do not add the nocloseonexit 03130 // because we don't know how to do this on other terminal applications 03131 KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") ); 03132 QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", 03133 QString::fromLatin1("konsole")); 03134 03135 bool terminalCloseBool = false; 03136 03137 if (preferredTerminal == "konsole") 03138 { 03139 terminalCloseBool = (m_terminalOptionStr.contains( "--noclose" ) > 0); 03140 w->terminalCloseCheck->setChecked(terminalCloseBool); 03141 m_terminalOptionStr.replace( "--noclose", ""); 03142 } 03143 else 03144 { 03145 w->terminalCloseCheck->hide(); 03146 } 03147 03148 w->terminalCheck->setChecked(m_terminalBool); 03149 w->terminalEdit->setText(m_terminalOptionStr); 03150 w->terminalCloseCheck->setEnabled(m_terminalBool); 03151 w->terminalEdit->setEnabled(m_terminalBool); 03152 w->terminalEditLabel->setEnabled(m_terminalBool); 03153 03154 w->suidCheck->setChecked(m_suidBool); 03155 w->suidEdit->setText(m_suidUserStr); 03156 w->suidEdit->setEnabled(m_suidBool); 03157 w->suidEditLabel->setEnabled(m_suidBool); 03158 03159 w->startupInfoCheck->setChecked(m_startupBool); 03160 w->systrayCheck->setChecked(m_systrayBool); 03161 03162 if (m_dcopServiceType == "unique") 03163 w->dcopCombo->setCurrentItem(2); 03164 else if (m_dcopServiceType == "multi") 03165 w->dcopCombo->setCurrentItem(1); 03166 else if (m_dcopServiceType == "wait") 03167 w->dcopCombo->setCurrentItem(3); 03168 else 03169 w->dcopCombo->setCurrentItem(0); 03170 03171 // Provide username completion up to 1000 users. 03172 KCompletion *kcom = new KCompletion; 03173 kcom->setOrder(KCompletion::Sorted); 03174 struct passwd *pw; 03175 int i, maxEntries = 1000; 03176 setpwent(); 03177 for (i=0; ((pw = getpwent()) != 0L) && (i < maxEntries); i++) 03178 kcom->addItem(QString::fromLatin1(pw->pw_name)); 03179 endpwent(); 03180 if (i < maxEntries) 03181 { 03182 w->suidEdit->setCompletionObject(kcom, true); 03183 w->suidEdit->setAutoDeleteCompletionObject( true ); 03184 w->suidEdit->setCompletionMode(KGlobalSettings::CompletionAuto); 03185 } 03186 else 03187 { 03188 delete kcom; 03189 } 03190 03191 connect( w->terminalEdit, SIGNAL( textChanged( const QString & ) ), 03192 this, SIGNAL( changed() ) ); 03193 connect( w->terminalCloseCheck, SIGNAL( toggled( bool ) ), 03194 this, SIGNAL( changed() ) ); 03195 connect( w->terminalCheck, SIGNAL( toggled( bool ) ), 03196 this, SIGNAL( changed() ) ); 03197 connect( w->suidCheck, SIGNAL( toggled( bool ) ), 03198 this, SIGNAL( changed() ) ); 03199 connect( w->suidEdit, SIGNAL( textChanged( const QString & ) ), 03200 this, SIGNAL( changed() ) ); 03201 connect( w->startupInfoCheck, SIGNAL( toggled( bool ) ), 03202 this, SIGNAL( changed() ) ); 03203 connect( w->systrayCheck, SIGNAL( toggled( bool ) ), 03204 this, SIGNAL( changed() ) ); 03205 connect( w->dcopCombo, SIGNAL( highlighted( int ) ), 03206 this, SIGNAL( changed() ) ); 03207 03208 if ( dlg.exec() == QDialog::Accepted ) 03209 { 03210 m_terminalOptionStr = w->terminalEdit->text().stripWhiteSpace(); 03211 m_terminalBool = w->terminalCheck->isChecked(); 03212 m_suidBool = w->suidCheck->isChecked(); 03213 m_suidUserStr = w->suidEdit->text().stripWhiteSpace(); 03214 m_startupBool = w->startupInfoCheck->isChecked(); 03215 m_systrayBool = w->systrayCheck->isChecked(); 03216 03217 if (w->terminalCloseCheck->isChecked()) 03218 { 03219 m_terminalOptionStr.append(" --noclose"); 03220 } 03221 03222 switch(w->dcopCombo->currentItem()) 03223 { 03224 case 1: m_dcopServiceType = "multi"; break; 03225 case 2: m_dcopServiceType = "unique"; break; 03226 case 3: m_dcopServiceType = "wait"; break; 03227 default: m_dcopServiceType = "none"; break; 03228 } 03229 } 03230 } 03231 03232 bool KDesktopPropsPlugin::supports( KFileItemList _items ) 03233 { 03234 if ( _items.count() != 1 ) 03235 return false; 03236 KFileItem * item = _items.first(); 03237 // check if desktop file 03238 if ( !KPropsDlgPlugin::isDesktopFile( item ) ) 03239 return false; 03240 // open file and check type 03241 KDesktopFile config( item->url().path(), true /* readonly */ ); 03242 return config.hasApplicationType() && kapp->authorize("run_desktop_files") && kapp->authorize("shell_access"); 03243 } 03244 03245 void KPropertiesDialog::virtual_hook( int id, void* data ) 03246 { KDialogBase::virtual_hook( id, data ); } 03247 03248 void KPropsDlgPlugin::virtual_hook( int, void* ) 03249 { /*BASE::virtual_hook( id, data );*/ } 03250 03251 03252 03253 03254 03260 class KExecPropsPlugin::KExecPropsPluginPrivate 03261 { 03262 public: 03263 KExecPropsPluginPrivate() 03264 { 03265 } 03266 ~KExecPropsPluginPrivate() 03267 { 03268 } 03269 03270 QFrame *m_frame; 03271 QCheckBox *nocloseonexitCheck; 03272 }; 03273 03274 KExecPropsPlugin::KExecPropsPlugin( KPropertiesDialog *_props ) 03275 : KPropsDlgPlugin( _props ) 03276 { 03277 d = new KExecPropsPluginPrivate; 03278 d->m_frame = properties->addPage(i18n("E&xecute")); 03279 QVBoxLayout * mainlayout = new QVBoxLayout( d->m_frame, 0, 03280 KDialog::spacingHint()); 03281 03282 // Now the widgets in the top layout 03283 03284 QLabel* l; 03285 l = new QLabel( i18n( "Comman&d:" ), d->m_frame ); 03286 mainlayout->addWidget(l); 03287 03288 QHBoxLayout * hlayout; 03289 hlayout = new QHBoxLayout(KDialog::spacingHint()); 03290 mainlayout->addLayout(hlayout); 03291 03292 execEdit = new KLineEdit( d->m_frame ); 03293 QWhatsThis::add(execEdit,i18n( 03294 "Following the command, you can have several place holders which will be replaced " 03295 "with the actual values when the actual program is run:\n" 03296 "%f - a single file name\n" 03297 "%F - a list of files; use for applications that can open several local files at once\n" 03298 "%u - a single URL\n" 03299 "%U - a list of URLs\n" 03300 "%d - the folder of the file to open\n" 03301 "%D - a list of folders\n" 03302 "%i - the icon\n" 03303 "%m - the mini-icon\n" 03304 "%c - the caption")); 03305 hlayout->addWidget(execEdit, 1); 03306 03307 l->setBuddy( execEdit ); 03308 03309 execBrowse = new QPushButton( d->m_frame ); 03310 execBrowse->setText( i18n("&Browse...") ); 03311 hlayout->addWidget(execBrowse); 03312 03313 // The groupbox about swallowing 03314 QGroupBox* tmpQGroupBox; 03315 tmpQGroupBox = new QGroupBox( i18n("Panel Embedding"), d->m_frame ); 03316 tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal ); 03317 03318 mainlayout->addWidget(tmpQGroupBox); 03319 03320 QGridLayout *grid = new QGridLayout(tmpQGroupBox->layout(), 2, 2); 03321 grid->setSpacing( KDialog::spacingHint() ); 03322 grid->setColStretch(1, 1); 03323 03324 l = new QLabel( i18n( "&Execute on click:" ), tmpQGroupBox ); 03325 grid->addWidget(l, 0, 0); 03326 03327 swallowExecEdit = new KLineEdit( tmpQGroupBox ); 03328 grid->addWidget(swallowExecEdit, 0, 1); 03329 03330 l->setBuddy( swallowExecEdit ); 03331 03332 l = new QLabel( i18n( "&Window title:" ), tmpQGroupBox ); 03333 grid->addWidget(l, 1, 0); 03334 03335 swallowTitleEdit = new KLineEdit( tmpQGroupBox ); 03336 grid->addWidget(swallowTitleEdit, 1, 1); 03337 03338 l->setBuddy( swallowTitleEdit ); 03339 03340 // The groupbox about run in terminal 03341 03342 tmpQGroupBox = new QGroupBox( d->m_frame ); 03343 tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal ); 03344 03345 mainlayout->addWidget(tmpQGroupBox); 03346 03347 grid = new QGridLayout(tmpQGroupBox->layout(), 3, 2); 03348 grid->setSpacing( KDialog::spacingHint() ); 03349 grid->setColStretch(1, 1); 03350 03351 terminalCheck = new QCheckBox( tmpQGroupBox ); 03352 terminalCheck->setText( i18n("&Run in terminal") ); 03353 grid->addMultiCellWidget(terminalCheck, 0, 0, 0, 1); 03354 03355 // check to see if we use konsole if not do not add the nocloseonexit 03356 // because we don't know how to do this on other terminal applications 03357 KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") ); 03358 QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", 03359 QString::fromLatin1("konsole")); 03360 03361 int posOptions = 1; 03362 d->nocloseonexitCheck = 0L; 03363 if (preferredTerminal == "konsole") 03364 { 03365 posOptions = 2; 03366 d->nocloseonexitCheck = new QCheckBox( tmpQGroupBox ); 03367 d->nocloseonexitCheck->setText( i18n("Do not &close when command exits") ); 03368 grid->addMultiCellWidget(d->nocloseonexitCheck, 1, 1, 0, 1); 03369 } 03370 03371 terminalLabel = new QLabel( i18n( "&Terminal options:" ), tmpQGroupBox ); 03372 grid->addWidget(terminalLabel, posOptions, 0); 03373 03374 terminalEdit = new KLineEdit( tmpQGroupBox ); 03375 grid->addWidget(terminalEdit, posOptions, 1); 03376 03377 terminalLabel->setBuddy( terminalEdit ); 03378 03379 // The groupbox about run with substituted uid. 03380 03381 tmpQGroupBox = new QGroupBox( d->m_frame ); 03382 tmpQGroupBox->setColumnLayout( 0, Qt::Horizontal ); 03383 03384 mainlayout->addWidget(tmpQGroupBox); 03385 03386 grid = new QGridLayout(tmpQGroupBox->layout(), 2, 2); 03387 grid->setSpacing(KDialog::spacingHint()); 03388 grid->setColStretch(1, 1); 03389 03390 suidCheck = new QCheckBox(tmpQGroupBox); 03391 suidCheck->setText(i18n("Ru&n as a different user")); 03392 grid->addMultiCellWidget(suidCheck, 0, 0, 0, 1); 03393 03394 suidLabel = new QLabel(i18n( "&Username:" ), tmpQGroupBox); 03395 grid->addWidget(suidLabel, 1, 0); 03396 03397 suidEdit = new KLineEdit(tmpQGroupBox); 03398 grid->addWidget(suidEdit, 1, 1); 03399 03400 suidLabel->setBuddy( suidEdit ); 03401 03402 mainlayout->addStretch(1); 03403 03404 // now populate the page 03405 QString path = _props->kurl().path(); 03406 QFile f( path ); 03407 if ( !f.open( IO_ReadOnly ) ) 03408 return; 03409 f.close(); 03410 03411 KSimpleConfig config( path ); 03412 config.setDollarExpansion( false ); 03413 config.setDesktopGroup(); 03414 execStr = config.readPathEntry( "Exec" ); 03415 swallowExecStr = config.readPathEntry( "SwallowExec" ); 03416 swallowTitleStr = config.readEntry( "SwallowTitle" ); 03417 termBool = config.readBoolEntry( "Terminal" ); 03418 termOptionsStr = config.readEntry( "TerminalOptions" ); 03419 suidBool = config.readBoolEntry( "X-KDE-SubstituteUID" ); 03420 suidUserStr = config.readEntry( "X-KDE-Username" ); 03421 03422 if ( !swallowExecStr.isNull() ) 03423 swallowExecEdit->setText( swallowExecStr ); 03424 if ( !swallowTitleStr.isNull() ) 03425 swallowTitleEdit->setText( swallowTitleStr ); 03426 03427 if ( !execStr.isNull() ) 03428 execEdit->setText( execStr ); 03429 03430 if ( d->nocloseonexitCheck ) 03431 { 03432 d->nocloseonexitCheck->setChecked( (termOptionsStr.contains( "--noclose" ) > 0) ); 03433 termOptionsStr.replace( "--noclose", ""); 03434 } 03435 if ( !termOptionsStr.isNull() ) 03436 terminalEdit->setText( termOptionsStr ); 03437 03438 terminalCheck->setChecked( termBool ); 03439 enableCheckedEdit(); 03440 03441 suidCheck->setChecked( suidBool ); 03442 suidEdit->setText( suidUserStr ); 03443 enableSuidEdit(); 03444 03445 // Provide username completion up to 1000 users. 03446 KCompletion *kcom = new KCompletion; 03447 kcom->setOrder(KCompletion::Sorted); 03448 struct passwd *pw; 03449 int i, maxEntries = 1000; 03450 setpwent(); 03451 for (i=0; ((pw = getpwent()) != 0L) && (i < maxEntries); i++) 03452 kcom->addItem(QString::fromLatin1(pw->pw_name)); 03453 endpwent(); 03454 if (i < maxEntries) 03455 { 03456 suidEdit->setCompletionObject(kcom, true); 03457 suidEdit->setAutoDeleteCompletionObject( true ); 03458 suidEdit->setCompletionMode(KGlobalSettings::CompletionAuto); 03459 } 03460 else 03461 { 03462 delete kcom; 03463 } 03464 03465 connect( swallowExecEdit, SIGNAL( textChanged( const QString & ) ), 03466 this, SIGNAL( changed() ) ); 03467 connect( swallowTitleEdit, SIGNAL( textChanged( const QString & ) ), 03468 this, SIGNAL( changed() ) ); 03469 connect( execEdit, SIGNAL( textChanged( const QString & ) ), 03470 this, SIGNAL( changed() ) ); 03471 connect( terminalEdit, SIGNAL( textChanged( const QString & ) ), 03472 this, SIGNAL( changed() ) ); 03473 if (d->nocloseonexitCheck) 03474 connect( d->nocloseonexitCheck, SIGNAL( toggled( bool ) ), 03475 this, SIGNAL( changed() ) ); 03476 connect( terminalCheck, SIGNAL( toggled( bool ) ), 03477 this, SIGNAL( changed() ) ); 03478 connect( suidCheck, SIGNAL( toggled( bool ) ), 03479 this, SIGNAL( changed() ) ); 03480 connect( suidEdit, SIGNAL( textChanged( const QString & ) ), 03481 this, SIGNAL( changed() ) ); 03482 03483 connect( execBrowse, SIGNAL( clicked() ), this, SLOT( slotBrowseExec() ) ); 03484 connect( terminalCheck, SIGNAL( clicked() ), this, SLOT( enableCheckedEdit() ) ); 03485 connect( suidCheck, SIGNAL( clicked() ), this, SLOT( enableSuidEdit() ) ); 03486 03487 } 03488 03489 KExecPropsPlugin::~KExecPropsPlugin() 03490 { 03491 delete d; 03492 } 03493 03494 void KExecPropsPlugin::enableCheckedEdit() 03495 { 03496 bool checked = terminalCheck->isChecked(); 03497 terminalLabel->setEnabled( checked ); 03498 if (d->nocloseonexitCheck) 03499 d->nocloseonexitCheck->setEnabled( checked ); 03500 terminalEdit->setEnabled( checked ); 03501 } 03502 03503 void KExecPropsPlugin::enableSuidEdit() 03504 { 03505 bool checked = suidCheck->isChecked(); 03506 suidLabel->setEnabled( checked ); 03507 suidEdit->setEnabled( checked ); 03508 } 03509 03510 bool KExecPropsPlugin::supports( KFileItemList _items ) 03511 { 03512 if ( _items.count() != 1 ) 03513 return false; 03514 KFileItem * item = _items.first(); 03515 // check if desktop file 03516 if ( !KPropsDlgPlugin::isDesktopFile( item ) ) 03517 return false; 03518 // open file and check type 03519 KDesktopFile config( item->url().path(), true /* readonly */ ); 03520 return config.hasApplicationType() && kapp->authorize("run_desktop_files") && kapp->authorize("shell_access"); 03521 } 03522 03523 void KExecPropsPlugin::applyChanges() 03524 { 03525 kdDebug(250) << "KExecPropsPlugin::applyChanges" << endl; 03526 QString path = properties->kurl().path(); 03527 03528 QFile f( path ); 03529 03530 if ( !f.open( IO_ReadWrite ) ) { 03531 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not have " 03532 "sufficient access to write to <b>%1</b>.</qt>").arg(path)); 03533 return; 03534 } 03535 f.close(); 03536 03537 KSimpleConfig config( path ); 03538 config.setDesktopGroup(); 03539 config.writeEntry( "Type", QString::fromLatin1("Application")); 03540 config.writePathEntry( "Exec", execEdit->text() ); 03541 config.writePathEntry( "SwallowExec", swallowExecEdit->text() ); 03542 config.writeEntry( "SwallowTitle", swallowTitleEdit->text() ); 03543 config.writeEntry( "Terminal", terminalCheck->isChecked() ); 03544 QString temp = terminalEdit->text(); 03545 if (d->nocloseonexitCheck ) 03546 if ( d->nocloseonexitCheck->isChecked() ) 03547 temp += QString::fromLatin1("--noclose "); 03548 temp = temp.stripWhiteSpace(); 03549 config.writeEntry( "TerminalOptions", temp ); 03550 config.writeEntry( "X-KDE-SubstituteUID", suidCheck->isChecked() ); 03551 config.writeEntry( "X-KDE-Username", suidEdit->text() ); 03552 } 03553 03554 03555 void KExecPropsPlugin::slotBrowseExec() 03556 { 03557 KURL f = KFileDialog::getOpenURL( QString::null, 03558 QString::null, d->m_frame ); 03559 if ( f.isEmpty() ) 03560 return; 03561 03562 if ( !f.isLocalFile()) { 03563 KMessageBox::sorry(d->m_frame, i18n("Only executables on local file systems are supported.")); 03564 return; 03565 } 03566 03567 QString path = f.path(); 03568 KRun::shellQuote( path ); 03569 execEdit->setText( path ); 03570 } 03571 03572 class KApplicationPropsPlugin::KApplicationPropsPluginPrivate 03573 { 03574 public: 03575 KApplicationPropsPluginPrivate() 03576 { 03577 m_kdesktopMode = QCString(qApp->name()) == "kdesktop"; // nasty heh? 03578 } 03579 ~KApplicationPropsPluginPrivate() 03580 { 03581 } 03582 03583 QFrame *m_frame; 03584 bool m_kdesktopMode; 03585 }; 03586 03587 KApplicationPropsPlugin::KApplicationPropsPlugin( KPropertiesDialog *_props ) 03588 : KPropsDlgPlugin( _props ) 03589 { 03590 d = new KApplicationPropsPluginPrivate; 03591 d->m_frame = properties->addPage(i18n("&Application")); 03592 QVBoxLayout *toplayout = new QVBoxLayout( d->m_frame, 0, KDialog::spacingHint()); 03593 03594 QIconSet iconSet; 03595 QPixmap pixMap; 03596 03597 addExtensionButton = new QPushButton( QString::null, d->m_frame ); 03598 iconSet = SmallIconSet( "back" ); 03599 addExtensionButton->setIconSet( iconSet ); 03600 pixMap = iconSet.pixmap( QIconSet::Small, QIconSet::Normal ); 03601 addExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 ); 03602 connect( addExtensionButton, SIGNAL( clicked() ), 03603 SLOT( slotAddExtension() ) ); 03604 03605 delExtensionButton = new QPushButton( QString::null, d->m_frame ); 03606 iconSet = SmallIconSet( "forward" ); 03607 delExtensionButton->setIconSet( iconSet ); 03608 delExtensionButton->setFixedSize( pixMap.width()+8, pixMap.height()+8 ); 03609 connect( delExtensionButton, SIGNAL( clicked() ), 03610 SLOT( slotDelExtension() ) ); 03611 03612 QLabel *l; 03613 03614 QGridLayout *grid = new QGridLayout(2, 2); 03615 grid->setColStretch(1, 1); 03616 toplayout->addLayout(grid); 03617 03618 if ( d->m_kdesktopMode ) 03619 { 03620 // in kdesktop the name field comes from the first tab 03621 nameEdit = 0L; 03622 } 03623 else 03624 { 03625 l = new QLabel(i18n("Name:"), d->m_frame, "Label_4" ); 03626 grid->addWidget(l, 0, 0); 03627 03628 nameEdit = new KLineEdit( d->m_frame, "LineEdit_3" ); 03629 grid->addWidget(nameEdit, 0, 1); 03630 } 03631 03632 l = new QLabel(i18n("Description:"), d->m_frame, "Label_5" ); 03633 grid->addWidget(l, 1, 0); 03634 03635 genNameEdit = new KLineEdit( d->m_frame, "LineEdit_4" ); 03636 grid->addWidget(genNameEdit, 1, 1); 03637 03638 l = new QLabel(i18n("Comment:"), d->m_frame, "Label_3" ); 03639 grid->addWidget(l, 2, 0); 03640 03641 commentEdit = new KLineEdit( d->m_frame, "LineEdit_2" ); 03642 grid->addWidget(commentEdit, 2, 1); 03643 03644 l = new QLabel(i18n("File types:"), d->m_frame); 03645 toplayout->addWidget(l, 0, AlignLeft); 03646 03647 grid = new QGridLayout(4, 3); 03648 grid->setColStretch(0, 1); 03649 grid->setColStretch(2, 1); 03650 grid->setRowStretch( 0, 1 ); 03651 grid->setRowStretch( 3, 1 ); 03652 toplayout->addLayout(grid, 2); 03653 03654 extensionsList = new QListBox( d->m_frame ); 03655 extensionsList->setSelectionMode( QListBox::Extended ); 03656 grid->addMultiCellWidget(extensionsList, 0, 3, 0, 0); 03657 03658 grid->addWidget(addExtensionButton, 1, 1); 03659 grid->addWidget(delExtensionButton, 2, 1); 03660 03661 availableExtensionsList = new QListBox( d->m_frame ); 03662 availableExtensionsList->setSelectionMode( QListBox::Extended ); 03663 grid->addMultiCellWidget(availableExtensionsList, 0, 3, 2, 2); 03664 03665 QString path = properties->kurl().path() ; 03666 QFile f( path ); 03667 if ( !f.open( IO_ReadOnly ) ) 03668 return; 03669 f.close(); 03670 03671 KSimpleConfig config( path ); 03672 config.setDesktopGroup(); 03673 QString commentStr = config.readEntry( "Comment" ); 03674 QString genNameStr = config.readEntry( "GenericName" ); 03675 03676 QStringList selectedTypes = config.readListEntry( "ServiceTypes" ); 03677 // For compatibility with KDE 1.x 03678 selectedTypes += config.readListEntry( "MimeType", ';' ); 03679 03680 QString nameStr = config.readEntry( QString::fromLatin1("Name") ); 03681 if ( nameStr.isEmpty() || d->m_kdesktopMode ) { 03682 // We'll use the file name if no name is specified 03683 // because we _need_ a Name for a valid file. 03684 // But let's do it in apply, not here, so that we pick up the right name. 03685 setDirty(); 03686 } 03687 03688 commentEdit->setText( commentStr ); 03689 genNameEdit->setText( genNameStr ); 03690 if ( nameEdit ) 03691 nameEdit->setText( nameStr ); 03692 03693 selectedTypes.sort(); 03694 QStringList::Iterator sit = selectedTypes.begin(); 03695 for( ; sit != selectedTypes.end(); ++sit ) { 03696 if ( !((*sit).isEmpty()) ) 03697 extensionsList->insertItem( *sit ); 03698 } 03699 03700 KMimeType::List mimeTypes = KMimeType::allMimeTypes(); 03701 QValueListIterator<KMimeType::Ptr> it2 = mimeTypes.begin(); 03702 for ( ; it2 != mimeTypes.end(); ++it2 ) 03703 addMimeType ( (*it2)->name() ); 03704 03705 updateButton(); 03706 03707 connect( extensionsList, SIGNAL( highlighted( int ) ), 03708 this, SLOT( updateButton() ) ); 03709 connect( availableExtensionsList, SIGNAL( highlighted( int ) ), 03710 this, SLOT( updateButton() ) ); 03711 03712 connect( addExtensionButton, SIGNAL( clicked() ), 03713 this, SIGNAL( changed() ) ); 03714 connect( delExtensionButton, SIGNAL( clicked() ), 03715 this, SIGNAL( changed() ) ); 03716 if ( nameEdit ) 03717 connect( nameEdit, SIGNAL( textChanged( const QString & ) ), 03718 this, SIGNAL( changed() ) ); 03719 connect( commentEdit, SIGNAL( textChanged( const QString & ) ), 03720 this, SIGNAL( changed() ) ); 03721 connect( genNameEdit, SIGNAL( textChanged( const QString & ) ), 03722 this, SIGNAL( changed() ) ); 03723 connect( availableExtensionsList, SIGNAL( selected( int ) ), 03724 this, SIGNAL( changed() ) ); 03725 connect( extensionsList, SIGNAL( selected( int ) ), 03726 this, SIGNAL( changed() ) ); 03727 } 03728 03729 KApplicationPropsPlugin::~KApplicationPropsPlugin() 03730 { 03731 delete d; 03732 } 03733 03734 // QString KApplicationPropsPlugin::tabName () const 03735 // { 03736 // return i18n ("&Application"); 03737 // } 03738 03739 void KApplicationPropsPlugin::updateButton() 03740 { 03741 addExtensionButton->setEnabled(availableExtensionsList->currentItem()>-1); 03742 delExtensionButton->setEnabled(extensionsList->currentItem()>-1); 03743 } 03744 03745 void KApplicationPropsPlugin::addMimeType( const QString & name ) 03746 { 03747 // Add a mimetype to the list of available mime types if not in the extensionsList 03748 03749 bool insert = true; 03750 03751 for ( uint i = 0; i < extensionsList->count(); i++ ) 03752 if ( extensionsList->text( i ) == name ) 03753 insert = false; 03754 03755 if ( insert ) 03756 { 03757 availableExtensionsList->insertItem( name ); 03758 availableExtensionsList->sort(); 03759 } 03760 } 03761 03762 bool KApplicationPropsPlugin::supports( KFileItemList _items ) 03763 { 03764 // same constraints as KExecPropsPlugin : desktop file with Type = Application 03765 return KExecPropsPlugin::supports( _items ); 03766 } 03767 03768 void KApplicationPropsPlugin::applyChanges() 03769 { 03770 QString path = properties->kurl().path(); 03771 03772 QFile f( path ); 03773 03774 if ( !f.open( IO_ReadWrite ) ) { 03775 KMessageBox::sorry( 0, i18n("<qt>Could not save properties. You do not " 03776 "have sufficient access to write to <b>%1</b>.</qt>").arg(path)); 03777 return; 03778 } 03779 f.close(); 03780 03781 KSimpleConfig config( path ); 03782 config.setDesktopGroup(); 03783 config.writeEntry( "Type", QString::fromLatin1("Application")); 03784 config.writeEntry( "Comment", commentEdit->text() ); 03785 config.writeEntry( "Comment", commentEdit->text(), true, false, true ); // for compat 03786 config.writeEntry( "GenericName", genNameEdit->text() ); 03787 config.writeEntry( "GenericName", genNameEdit->text(), true, false, true ); // for compat 03788 03789 QStringList selectedTypes; 03790 for ( uint i = 0; i < extensionsList->count(); i++ ) 03791 selectedTypes.append( extensionsList->text( i ) ); 03792 03793 config.writeEntry( "MimeType", selectedTypes, ';' ); 03794 config.writeEntry( "ServiceTypes", "" ); 03795 // hmm, actually it should probably be the contrary (but see also typeslistitem.cpp) 03796 03797 QString nameStr = nameEdit ? nameEdit->text() : QString::null; 03798 if ( nameStr.isEmpty() ) // nothing entered, or widget not existing at all (kdesktop mode) 03799 nameStr = nameFromFileName(properties->kurl().fileName()); 03800 03801 config.writeEntry( "Name", nameStr ); 03802 config.writeEntry( "Name", nameStr, true, false, true ); 03803 03804 config.sync(); 03805 } 03806 03807 void KApplicationPropsPlugin::slotAddExtension() 03808 { 03809 QListBoxItem *item = availableExtensionsList->firstItem(); 03810 QListBoxItem *nextItem; 03811 03812 while ( item ) 03813 { 03814 nextItem = item->next(); 03815 03816 if ( item->isSelected() ) 03817 { 03818 extensionsList->insertItem( item->text() ); 03819 availableExtensionsList->removeItem( availableExtensionsList->index( item ) ); 03820 } 03821 03822 item = nextItem; 03823 } 03824 03825 extensionsList->sort(); 03826 updateButton(); 03827 } 03828 03829 void KApplicationPropsPlugin::slotDelExtension() 03830 { 03831 QListBoxItem *item = extensionsList->firstItem(); 03832 QListBoxItem *nextItem; 03833 03834 while ( item ) 03835 { 03836 nextItem = item->next(); 03837 03838 if ( item->isSelected() ) 03839 { 03840 availableExtensionsList->insertItem( item->text() ); 03841 extensionsList->removeItem( extensionsList->index( item ) ); 03842 } 03843 03844 item = nextItem; 03845 } 03846 03847 availableExtensionsList->sort(); 03848 updateButton(); 03849 } 03850 03851 03852 03853 #include "kpropertiesdialog.moc"
KDE Logo
This file is part of the documentation for kio Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:29:28 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003