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