kio Library API Documentation

kpropertiesdialog.cpp

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