kio Library API Documentation

kopenwith.cpp

00001 /* This file is part of the KDE libraries 00002 00003 Copyright (C) 1997 Torben Weis <weis@stud.uni-frankfurt.de> 00004 Copyright (C) 1999 Dirk A. Mueller <dmuell@gmx.net> 00005 Portions copyright (C) 1999 Preston Brown <pbrown@kde.org> 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00020 Boston, MA 02111-1307, USA. 00021 */ 00022 00023 #include <qfile.h> 00024 #include <qdir.h> 00025 #include <qdialog.h> 00026 #include <qimage.h> 00027 #include <qpixmap.h> 00028 #include <qlabel.h> 00029 #include <qlayout.h> 00030 #include <qpushbutton.h> 00031 #include <qtoolbutton.h> 00032 #include <qcheckbox.h> 00033 #include <qtooltip.h> 00034 #include <qstyle.h> 00035 #include <qwhatsthis.h> 00036 00037 #include <kapplication.h> 00038 #include <kbuttonbox.h> 00039 #include <kcombobox.h> 00040 #include <kdesktopfile.h> 00041 #include <kdialog.h> 00042 #include <kglobal.h> 00043 #include <klineedit.h> 00044 #include <klocale.h> 00045 #include <kiconloader.h> 00046 #include <kmimemagic.h> 00047 #include <krun.h> 00048 #include <kstandarddirs.h> 00049 #include <kstringhandler.h> 00050 #include <kuserprofile.h> 00051 #include <kurlcompletion.h> 00052 #include <kurlrequester.h> 00053 #include <dcopclient.h> 00054 #include <kmimetype.h> 00055 #include <kservicegroup.h> 00056 #include <klistview.h> 00057 #include <ksycoca.h> 00058 #include <kstdguiitem.h> 00059 00060 #include "kopenwith.h" 00061 #include "kopenwith_p.h" 00062 00063 #include <kdebug.h> 00064 #include <assert.h> 00065 #include <stdlib.h> 00066 00067 template class QPtrList<QString>; 00068 00069 #define SORT_SPEC (QDir::DirsFirst | QDir::Name | QDir::IgnoreCase) 00070 00071 00072 // ---------------------------------------------------------------------- 00073 00074 KAppTreeListItem::KAppTreeListItem( KListView* parent, const QString & name, 00075 const QPixmap& pixmap, bool parse, bool dir, const QString &p, const QString &c ) 00076 : QListViewItem( parent, name ) 00077 { 00078 init(pixmap, parse, dir, p, c); 00079 } 00080 00081 00082 // ---------------------------------------------------------------------- 00083 00084 KAppTreeListItem::KAppTreeListItem( QListViewItem* parent, const QString & name, 00085 const QPixmap& pixmap, bool parse, bool dir, const QString &p, const QString &c ) 00086 : QListViewItem( parent, name ) 00087 { 00088 init(pixmap, parse, dir, p, c); 00089 } 00090 00091 00092 // ---------------------------------------------------------------------- 00093 00094 void KAppTreeListItem::init(const QPixmap& pixmap, bool parse, bool dir, const QString &_path, const QString &_exec) 00095 { 00096 setPixmap(0, pixmap); 00097 parsed = parse; 00098 directory = dir; 00099 path = _path; // relative path 00100 exec = _exec; 00101 } 00102 00103 00104 /* Ensures that directories sort before non-directories */ 00105 int KAppTreeListItem::compare(QListViewItem *i, int col, bool ascending) const 00106 { 00107 KAppTreeListItem *other = dynamic_cast<KAppTreeListItem *>(i); 00108 00109 // Directories sort first 00110 if (directory && !other->directory) 00111 return -1; 00112 00113 else if (!directory && other->directory) 00114 return 1; 00115 00116 else // both directories or both not 00117 return QListViewItem::compare(i, col, ascending); 00118 } 00119 00120 // ---------------------------------------------------------------------- 00121 // Ensure that case is ignored 00122 QString KAppTreeListItem::key(int column, bool /*ascending*/) const 00123 { 00124 return text(column).upper(); 00125 } 00126 00127 void KAppTreeListItem::activate() 00128 { 00129 if ( directory ) 00130 setOpen(!isOpen()); 00131 } 00132 00133 void KAppTreeListItem::setOpen( bool o ) 00134 { 00135 if( o && !parsed ) { // fill the children before opening 00136 ((KApplicationTree *) parent())->addDesktopGroup( path, this ); 00137 parsed = true; 00138 } 00139 QListViewItem::setOpen( o ); 00140 } 00141 00142 bool KAppTreeListItem::isDirectory() 00143 { 00144 return directory; 00145 } 00146 00147 // ---------------------------------------------------------------------- 00148 00149 KApplicationTree::KApplicationTree( QWidget *parent ) 00150 : KListView( parent ), currentitem(0) 00151 { 00152 addColumn( i18n("Known Applications") ); 00153 setRootIsDecorated( true ); 00154 00155 addDesktopGroup( QString::null ); 00156 cleanupTree(); 00157 00158 connect( this, SIGNAL( currentChanged(QListViewItem*) ), 00159 SLOT( slotItemHighlighted(QListViewItem*) ) ); 00160 connect( this, SIGNAL( selectionChanged(QListViewItem*) ), 00161 SLOT( slotSelectionChanged(QListViewItem*) ) ); 00162 } 00163 00164 // ---------------------------------------------------------------------- 00165 00166 bool KApplicationTree::isDirSel() 00167 { 00168 if (!currentitem) return false; // if currentitem isn't set 00169 return currentitem->isDirectory(); 00170 } 00171 00172 // ---------------------------------------------------------------------- 00173 00174 static QPixmap appIcon(const QString &iconName) 00175 { 00176 QPixmap normal = KGlobal::iconLoader()->loadIcon(iconName, KIcon::Small, 0, KIcon::DefaultState, 0L, true); 00177 // make sure they are not larger than 20x20 00178 if (normal.width() > 20 || normal.height() > 20) 00179 { 00180 QImage tmp = normal.convertToImage(); 00181 tmp = tmp.smoothScale(20, 20); 00182 normal.convertFromImage(tmp); 00183 } 00184 return normal; 00185 } 00186 00187 void KApplicationTree::addDesktopGroup( const QString &relPath, KAppTreeListItem *item) 00188 { 00189 KServiceGroup::Ptr root = KServiceGroup::group(relPath); 00190 KServiceGroup::List list = root->entries(); 00191 00192 KAppTreeListItem * newItem; 00193 for( KServiceGroup::List::ConstIterator it = list.begin(); 00194 it != list.end(); it++) 00195 { 00196 QString icon; 00197 QString text; 00198 QString relPath; 00199 QString exec; 00200 bool isDir = false; 00201 KSycocaEntry *p = (*it); 00202 if (p->isType(KST_KService)) 00203 { 00204 KService *service = static_cast<KService *>(p); 00205 00206 if (service->noDisplay()) 00207 continue; 00208 00209 icon = service->icon(); 00210 text = service->name(); 00211 exec = service->exec(); 00212 } 00213 else if (p->isType(KST_KServiceGroup)) 00214 { 00215 KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p); 00216 00217 if (serviceGroup->noDisplay()) 00218 continue; 00219 00220 icon = serviceGroup->icon(); 00221 text = serviceGroup->caption(); 00222 relPath = serviceGroup->relPath(); 00223 isDir = true; 00224 if ( text[0] == '.' ) // skip ".hidden" like kicker does 00225 continue; 00226 } 00227 else 00228 { 00229 kdWarning(250) << "KServiceGroup: Unexpected object in list!" << endl; 00230 continue; 00231 } 00232 00233 QPixmap pixmap = appIcon( icon ); 00234 00235 if (item) 00236 newItem = new KAppTreeListItem( item, text, pixmap, false, isDir, 00237 relPath, exec ); 00238 else 00239 newItem = new KAppTreeListItem( this, text, pixmap, false, isDir, 00240 relPath, exec ); 00241 if (isDir) 00242 newItem->setExpandable( true ); 00243 } 00244 } 00245 00246 00247 // ---------------------------------------------------------------------- 00248 00249 void KApplicationTree::slotItemHighlighted(QListViewItem* i) 00250 { 00251 // i may be 0 (see documentation) 00252 if(!i) 00253 return; 00254 00255 KAppTreeListItem *item = (KAppTreeListItem *) i; 00256 00257 currentitem = item; 00258 00259 if( (!item->directory ) && (!item->exec.isEmpty()) ) 00260 emit highlighted( item->text(0), item->exec ); 00261 } 00262 00263 00264 // ---------------------------------------------------------------------- 00265 00266 void KApplicationTree::slotSelectionChanged(QListViewItem* i) 00267 { 00268 // i may be 0 (see documentation) 00269 if(!i) 00270 return; 00271 00272 KAppTreeListItem *item = (KAppTreeListItem *) i; 00273 00274 currentitem = item; 00275 00276 if( ( !item->directory ) && (!item->exec.isEmpty() ) ) 00277 emit selected( item->text(0), item->exec ); 00278 } 00279 00280 // ---------------------------------------------------------------------- 00281 00282 void KApplicationTree::resizeEvent( QResizeEvent * e) 00283 { 00284 setColumnWidth(0, width()-QApplication::style().pixelMetric(QStyle::PM_ScrollBarExtent) 00285 -2*QApplication::style().pixelMetric(QStyle::PM_DefaultFrameWidth)); 00286 KListView::resizeEvent(e); 00287 } 00288 00289 // Prune empty directories from the tree 00290 void KApplicationTree::cleanupTree() 00291 { 00292 QListViewItem *item=firstChild(); 00293 while(item!=0) 00294 { 00295 if(item->isExpandable()) 00296 { 00297 item->setOpen(true); 00298 if(item->childCount()==0) { 00299 QListViewItem *current=item; 00300 item=item->itemBelow(); 00301 delete current; 00302 continue; 00303 } 00304 item=item->itemBelow(); 00305 continue; 00306 } 00307 item=item->itemBelow(); 00308 } 00309 item=firstChild(); 00310 while(item!=0) 00311 { 00312 if(item->isExpandable()) 00313 { 00314 QListViewItem *temp=item->itemBelow(); 00315 if(item->text(0)!=i18n("Applications")) 00316 item->setOpen(false); 00317 item=temp; 00318 continue; 00319 } 00320 item=item->itemBelow(); 00321 } 00322 } 00323 00324 /*************************************************************** 00325 * 00326 * KOpenWithDlg 00327 * 00328 ***************************************************************/ 00329 class KOpenWithDlgPrivate 00330 { 00331 public: 00332 KOpenWithDlgPrivate() : saveNewApps(false) { }; 00333 QPushButton* ok; 00334 bool saveNewApps; 00335 KService::Ptr curService; 00336 }; 00337 00338 KOpenWithDlg::KOpenWithDlg( const KURL::List& _urls, QWidget* parent ) 00339 :QDialog( parent, "openwith", true ) 00340 { 00341 setCaption( i18n( "Open With" ) ); 00342 QString text; 00343 if( _urls.count() == 1 ) 00344 { 00345 text = i18n("<qt>Select the program that should be used to open <b>%1</b>. " 00346 "If the program is not listed, enter the name or click " 00347 "the browse button.</qt>").arg( _urls.first().fileName() ); 00348 } 00349 else 00350 // Should never happen ?? 00351 text = i18n( "Choose the name of the program with which to open the selected files." ); 00352 setServiceType( _urls ); 00353 init( text, QString() ); 00354 } 00355 00356 KOpenWithDlg::KOpenWithDlg( const KURL::List& _urls, const QString&_text, 00357 const QString& _value, QWidget *parent) 00358 :QDialog( parent, "openwith", true ) 00359 { 00360 QString caption = KStringHandler::csqueeze( _urls.first().prettyURL() ); 00361 if (_urls.count() > 1) 00362 caption += QString::fromLatin1("..."); 00363 setCaption(caption); 00364 setServiceType( _urls ); 00365 init( _text, _value ); 00366 } 00367 00368 KOpenWithDlg::KOpenWithDlg( const QString &serviceType, const QString& value, 00369 QWidget *parent) 00370 :QDialog( parent, "openwith", true ) 00371 { 00372 setCaption(i18n("Choose Application for %1").arg(serviceType)); 00373 QString text = i18n("<qt>Select the program for the file type: <b>%1</b>. " 00374 "If the program is not listed, enter the name or click " 00375 "the browse button.</qt>").arg(serviceType); 00376 qServiceType = serviceType; 00377 init( text, value ); 00378 if (remember) 00379 remember->hide(); 00380 } 00381 00382 KOpenWithDlg::KOpenWithDlg( QWidget *parent) 00383 :QDialog( parent, "openwith", true ) 00384 { 00385 setCaption(i18n("Choose Application")); 00386 QString text = i18n("<qt>Select a program. " 00387 "If the program is not listed, enter the name or click " 00388 "the browse button.</qt>"); 00389 qServiceType = QString::null; 00390 init( text, QString::null ); 00391 } 00392 00393 void KOpenWithDlg::setServiceType( const KURL::List& _urls ) 00394 { 00395 if ( _urls.count() == 1 ) 00396 { 00397 qServiceType = KMimeType::findByURL( _urls.first())->name(); 00398 if (qServiceType == QString::fromLatin1("application/octet-stream")) 00399 qServiceType = QString::null; 00400 } 00401 else 00402 qServiceType = QString::null; 00403 } 00404 00405 void KOpenWithDlg::init( const QString& _text, const QString& _value ) 00406 { 00407 d = new KOpenWithDlgPrivate; 00408 bool bReadOnly = kapp && !kapp->authorize("shell_access"); 00409 m_terminaldirty = false; 00410 m_pTree = 0L; 00411 m_pService = 0L; 00412 d->curService = 0L; 00413 00414 QBoxLayout *topLayout = new QVBoxLayout( this, KDialog::marginHint(), 00415 KDialog::spacingHint() ); 00416 label = new QLabel( _text, this ); 00417 topLayout->addWidget(label); 00418 00419 QHBoxLayout* hbox = new QHBoxLayout(topLayout); 00420 00421 QToolButton *clearButton = new QToolButton( this ); 00422 clearButton->setIconSet( BarIcon( "locationbar_erase" ) ); 00423 clearButton->setFixedSize( clearButton->sizeHint() ); 00424 connect( clearButton, SIGNAL( clicked() ), SLOT( slotClear() ) ); 00425 QToolTip::add( clearButton, i18n( "Clear input field" ) ); 00426 00427 hbox->addWidget( clearButton ); 00428 00429 if (!bReadOnly) 00430 { 00431 // init the history combo and insert it into the URL-Requester 00432 KHistoryCombo *combo = new KHistoryCombo(); 00433 combo->setDuplicatesEnabled( false ); 00434 KConfig *kc = KGlobal::config(); 00435 KConfigGroupSaver ks( kc, QString::fromLatin1("Open-with settings") ); 00436 int max = kc->readNumEntry( QString::fromLatin1("Maximum history"), 15 ); 00437 combo->setMaxCount( max ); 00438 int mode = kc->readNumEntry(QString::fromLatin1("CompletionMode"), 00439 KGlobalSettings::completionMode()); 00440 combo->setCompletionMode((KGlobalSettings::Completion)mode); 00441 QStringList list = kc->readListEntry( QString::fromLatin1("History") ); 00442 combo->setHistoryItems( list, true ); 00443 edit = new KURLRequester( combo, this ); 00444 } 00445 else 00446 { 00447 clearButton->hide(); 00448 edit = new KURLRequester( this ); 00449 edit->lineEdit()->setReadOnly(true); 00450 edit->button()->hide(); 00451 } 00452 00453 edit->setURL( _value ); 00454 QWhatsThis::add(edit,i18n( 00455 "Following the command, you can have several place holders which will be replaced " 00456 "with the actual values when the actual program is run:\n" 00457 "%f - a single file name\n" 00458 "%F - a list of files; use for applications that can open several local files at once\n" 00459 "%u - a single URL\n" 00460 "%U - a list of URLs\n" 00461 "%d - the directory of the file to open\n" 00462 "%D - a list of directories\n" 00463 "%i - the icon\n" 00464 "%m - the mini-icon\n" 00465 "%c - the comment")); 00466 00467 hbox->addWidget(edit); 00468 00469 if ( edit->comboBox() ) { 00470 KURLCompletion *comp = new KURLCompletion( KURLCompletion::ExeCompletion ); 00471 edit->comboBox()->setCompletionObject( comp ); 00472 edit->comboBox()->setAutoDeleteCompletionObject( true ); 00473 } 00474 00475 connect ( edit, SIGNAL(returnPressed()), SLOT(slotOK()) ); 00476 connect ( edit, SIGNAL(textChanged(const QString&)), SLOT(slotTextChanged()) ); 00477 00478 m_pTree = new KApplicationTree( this ); 00479 topLayout->addWidget(m_pTree); 00480 00481 connect( m_pTree, SIGNAL( selected( const QString&, const QString& ) ), 00482 SLOT( slotSelected( const QString&, const QString& ) ) ); 00483 connect( m_pTree, SIGNAL( highlighted( const QString&, const QString& ) ), 00484 SLOT( slotHighlighted( const QString&, const QString& ) ) ); 00485 connect( m_pTree, SIGNAL( doubleClicked(QListViewItem*) ), 00486 SLOT( slotDbClick() ) ); 00487 00488 terminal = new QCheckBox( i18n("Run in &terminal"), this ); 00489 if (bReadOnly) 00490 terminal->hide(); 00491 connect(terminal, SIGNAL(toggled(bool)), SLOT(slotTerminalToggled(bool))); 00492 00493 topLayout->addWidget(terminal); 00494 00495 QBoxLayout* nocloseonexitLayout = new QHBoxLayout( 0, 0, KDialog::spacingHint() ); 00496 QSpacerItem* spacer = new QSpacerItem( 20, 0, QSizePolicy::Fixed, QSizePolicy::Minimum ); 00497 nocloseonexitLayout->addItem( spacer ); 00498 00499 nocloseonexit = new QCheckBox( i18n("&Do not close when command exits"), this ); 00500 nocloseonexit->setChecked( false ); 00501 nocloseonexit->setDisabled( true ); 00502 00503 // check to see if we use konsole if not disable the nocloseonexit 00504 // because we don't know how to do this on other terminal applications 00505 KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") ); 00506 QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole")); 00507 00508 if (bReadOnly || preferredTerminal != "konsole") 00509 nocloseonexit->hide(); 00510 00511 nocloseonexitLayout->addWidget( nocloseonexit ); 00512 topLayout->addLayout( nocloseonexitLayout ); 00513 00514 if (!qServiceType.isNull()) 00515 { 00516 remember = new QCheckBox(i18n("&Remember application association for this type of file"), this); 00517 // remember->setChecked(true); 00518 topLayout->addWidget(remember); 00519 } 00520 else 00521 remember = 0L; 00522 00523 // Use KButtonBox for the aligning pushbuttons nicely 00524 KButtonBox* b = new KButtonBox( this ); 00525 b->addStretch( 2 ); 00526 00527 d->ok = b->addButton( KStdGuiItem::ok() ); 00528 d->ok->setDefault( true ); 00529 connect( d->ok, SIGNAL( clicked() ), SLOT( slotOK() ) ); 00530 00531 QPushButton* cancel = b->addButton( KStdGuiItem::cancel() ); 00532 connect( cancel, SIGNAL( clicked() ), SLOT( reject() ) ); 00533 00534 b->layout(); 00535 topLayout->addWidget( b ); 00536 00537 //edit->setText( _value ); 00538 // This is what caused "can't click on items before clicking on Name header". 00539 // Probably due to the resizeEvent handler using width(). 00540 //resize( minimumWidth(), sizeHint().height() ); 00541 edit->setFocus(); 00542 slotTextChanged(); 00543 } 00544 00545 00546 // ---------------------------------------------------------------------- 00547 00548 KOpenWithDlg::~KOpenWithDlg() 00549 { 00550 delete d; 00551 d = 0; 00552 } 00553 00554 // ---------------------------------------------------------------------- 00555 00556 void KOpenWithDlg::slotClear() 00557 { 00558 edit->setURL(QString::null); 00559 edit->setFocus(); 00560 } 00561 00562 00563 // ---------------------------------------------------------------------- 00564 00565 void KOpenWithDlg::slotSelected( const QString& /*_name*/, const QString& _exec ) 00566 { 00567 kdDebug(250)<<"KOpenWithDlg::slotSelected"<<endl; 00568 KService::Ptr pService = d->curService; 00569 edit->setURL( _exec ); // calls slotTextChanged :( 00570 d->curService = pService; 00571 } 00572 00573 00574 // ---------------------------------------------------------------------- 00575 00576 void KOpenWithDlg::slotHighlighted( const QString& _name, const QString& ) 00577 { 00578 kdDebug(250)<<"KOpenWithDlg::slotHighlighted"<<endl; 00579 qName = _name; 00580 d->curService = KService::serviceByName( qName ); 00581 if (!m_terminaldirty) 00582 { 00583 // ### indicate that default value was restored 00584 terminal->setChecked(d->curService->terminal()); 00585 QString terminalOptions = d->curService->terminalOptions(); 00586 nocloseonexit->setChecked( (terminalOptions.contains( "--noclose" ) > 0) ); 00587 m_terminaldirty = false; // slotTerminalToggled changed it 00588 } 00589 } 00590 00591 // ---------------------------------------------------------------------- 00592 00593 void KOpenWithDlg::slotTextChanged() 00594 { 00595 kdDebug(250)<<"KOpenWithDlg::slotTextChanged"<<endl; 00596 // Forget about the service 00597 d->curService = 0L; 00598 d->ok->setEnabled( !edit->url().isEmpty()); 00599 } 00600 00601 // ---------------------------------------------------------------------- 00602 00603 void KOpenWithDlg::slotTerminalToggled(bool) 00604 { 00605 // ### indicate that default value was overridden 00606 m_terminaldirty = true; 00607 nocloseonexit->setDisabled( ! terminal->isChecked() ); 00608 } 00609 00610 // ---------------------------------------------------------------------- 00611 00612 void KOpenWithDlg::slotDbClick() 00613 { 00614 if (m_pTree->isDirSel() ) return; // check if a directory is selected 00615 slotOK(); 00616 } 00617 00618 void KOpenWithDlg::setSaveNewApplications(bool b) 00619 { 00620 d->saveNewApps = b; 00621 } 00622 00623 void KOpenWithDlg::slotOK() 00624 { 00625 QString fullExec(edit->url()); 00626 00627 QString serviceName; 00628 QString initialServiceName; 00629 QString preferredTerminal; 00630 m_pService = d->curService; 00631 if (!m_pService) { 00632 // No service selected - check the command line 00633 00634 // Find out the name of the service from the command line, removing args and paths 00635 serviceName = KRun::binaryName( fullExec, true ); 00636 if (serviceName.isEmpty()) 00637 { 00638 // TODO add a KMessageBox::error here after the end of the message freeze 00639 return; 00640 } 00641 initialServiceName = serviceName; 00642 kdDebug(250) << "initialServiceName=" << initialServiceName << endl; 00643 int i = 1; // We have app, app-2, app-3... Looks better for the user. 00644 bool ok = false; 00645 // Check if there's already a service by that name, with the same Exec line 00646 do { 00647 kdDebug(250) << "looking for service " << serviceName << endl; 00648 KService::Ptr serv = KService::serviceByDesktopName( serviceName ); 00649 ok = !serv; // ok if no such service yet 00650 // also ok if we find the exact same service (well, "kwrite" == "kwrite %U" 00651 if ( serv && serv->type() == "Application") 00652 { 00653 QString exec = serv->exec(); 00654 exec.replace("%u", "", false); 00655 exec.replace("%f", "", false); 00656 exec.replace("-caption %c", ""); 00657 exec.replace("-caption \"%c\"", ""); 00658 exec.replace("%i", ""); 00659 exec.replace("%m", ""); 00660 exec = exec.simplifyWhiteSpace(); 00661 if (exec == fullExec) 00662 { 00663 ok = true; 00664 m_pService = serv; 00665 kdDebug(250) << k_funcinfo << "OK, found identical service: " << serv->desktopEntryPath() << endl; 00666 } 00667 } 00668 if (!ok) // service was found, but it was different -> keep looking 00669 { 00670 ++i; 00671 serviceName = initialServiceName + "-" + QString::number(i); 00672 } 00673 } 00674 while (!ok); 00675 } 00676 if ( m_pService ) 00677 { 00678 // Existing service selected 00679 serviceName = m_pService->name(); 00680 initialServiceName = serviceName; 00681 } 00682 00683 if (terminal->isChecked()) 00684 { 00685 KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") ); 00686 preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole")); 00687 m_command = preferredTerminal; 00688 // only add --noclose when we are sure it is konsole we're using 00689 if (preferredTerminal == "konsole" && nocloseonexit->isChecked()) 00690 m_command += QString::fromLatin1(" --noclose"); 00691 m_command += QString::fromLatin1(" -e "); 00692 m_command += edit->url(); 00693 kdDebug(250) << "Setting m_command to " << m_command << endl; 00694 } 00695 if ( m_pService && terminal->isChecked() != m_pService->terminal() ) 00696 m_pService = 0L; // It's not exactly this service we're running 00697 00698 bool bRemember = remember && remember->isChecked(); 00699 00700 if ( !bRemember && m_pService) 00701 { 00702 accept(); 00703 return; 00704 } 00705 00706 if (!bRemember && !d->saveNewApps) 00707 { 00708 // Create temp service 00709 m_pService = new KService(initialServiceName, fullExec, QString::null); 00710 if (terminal->isChecked()) 00711 { 00712 m_pService->setTerminal(true); 00713 // only add --noclose when we are sure it is konsole we're using 00714 if (preferredTerminal == "konsole" && nocloseonexit->isChecked()) 00715 m_pService->setTerminalOptions("--noclose"); 00716 } 00717 accept(); 00718 return; 00719 } 00720 00721 // if we got here, we can't seem to find a service for what they 00722 // wanted. The other possibility is that they have asked for the 00723 // association to be remembered. Create/update service. 00724 00725 QString newPath; 00726 QString oldPath; 00727 QString menuId; 00728 if (m_pService) 00729 { 00730 oldPath = m_pService->desktopEntryPath(); 00731 newPath = m_pService->locateLocal(); 00732 menuId = m_pService->menuId(); 00733 kdDebug(250) << "Updating exitsing service " << m_pService->desktopEntryPath() << " ( " << newPath << " ) " << endl; 00734 } 00735 else 00736 { 00737 newPath = KService::newServicePath(false /* hidden */, serviceName, &menuId); 00738 kdDebug(250) << "Creating new service " << serviceName << " ( " << newPath << " ) " << endl; 00739 } 00740 00741 int maxPreference = 1; 00742 if (!qServiceType.isEmpty()) 00743 { 00744 KServiceTypeProfile::OfferList offerList = KServiceTypeProfile::offers( qServiceType ); 00745 if (!offerList.isEmpty()) 00746 maxPreference = offerList.first().preference(); 00747 } 00748 00749 KDesktopFile *desktop = 0; 00750 if (!oldPath.isEmpty() && (oldPath != newPath)) 00751 { 00752 KDesktopFile orig(oldPath, true); 00753 desktop = orig.copyTo(newPath); 00754 } 00755 else 00756 { 00757 desktop = new KDesktopFile(newPath); 00758 } 00759 desktop->writeEntry("Type", QString::fromLatin1("Application")); 00760 desktop->writeEntry("Name", initialServiceName); 00761 desktop->writePathEntry("Exec", fullExec); 00762 if (terminal->isChecked()) 00763 { 00764 desktop->writeEntry("Terminal", true); 00765 // only add --noclose when we are sure it is konsole we're using 00766 if (preferredTerminal == "konsole" && nocloseonexit->isChecked()) 00767 desktop->writeEntry("TerminalOptions", "--noclose"); 00768 } 00769 else 00770 { 00771 desktop->writeEntry("Terminal", false); 00772 } 00773 desktop->writeEntry("InitialPreference", maxPreference + 1); 00774 00775 00776 if (bRemember) 00777 { 00778 QStringList mimeList = desktop->readListEntry("MimeType", ';'); 00779 if (!qServiceType.isEmpty() && !mimeList.contains(qServiceType)) 00780 mimeList.append(qServiceType); 00781 desktop->writeEntry("MimeType", mimeList, ';'); 00782 00783 if ( !qServiceType.isEmpty() ) 00784 { 00785 // Also make sure the "auto embed" setting for this mimetype is off 00786 KDesktopFile mimeDesktop( locateLocal( "mime", qServiceType + ".desktop" ) ); 00787 mimeDesktop.writeEntry( "X-KDE-AutoEmbed", false ); 00788 mimeDesktop.sync(); 00789 } 00790 } 00791 00792 // write it all out to the file 00793 desktop->sync(); 00794 delete desktop; 00795 00796 KService::rebuildKSycoca(this); 00797 00798 m_pService = KService::serviceByMenuId( menuId ); 00799 00800 Q_ASSERT( m_pService ); 00801 00802 accept(); 00803 } 00804 00805 QString KOpenWithDlg::text() const 00806 { 00807 if (!m_command.isEmpty()) 00808 return m_command; 00809 else 00810 return edit->url(); 00811 } 00812 00813 void KOpenWithDlg::hideNoCloseOnExit() 00814 { 00815 // uncheck the checkbox because the value could be used when "Run in Terminal" is selected 00816 nocloseonexit->setChecked( false ); 00817 nocloseonexit->hide(); 00818 } 00819 00820 void KOpenWithDlg::hideRunInTerminal() 00821 { 00822 terminal->hide(); 00823 hideNoCloseOnExit(); 00824 } 00825 00826 void KOpenWithDlg::accept() 00827 { 00828 KHistoryCombo *combo = static_cast<KHistoryCombo*>( edit->comboBox() ); 00829 if ( combo ) { 00830 combo->addToHistory( edit->url() ); 00831 00832 KConfig *kc = KGlobal::config(); 00833 KConfigGroupSaver ks( kc, QString::fromLatin1("Open-with settings") ); 00834 kc->writeEntry( QString::fromLatin1("History"), combo->historyItems() ); 00835 kc->writeEntry(QString::fromLatin1("CompletionMode"), 00836 combo->completionMode()); 00837 // don't store the completion-list, as it contains all of KURLCompletion's 00838 // executables 00839 kc->sync(); 00840 } 00841 00842 QDialog::accept(); 00843 } 00844 00845 00847 00848 #ifndef KDE_NO_COMPAT 00849 bool KFileOpenWithHandler::displayOpenWithDialog( const KURL::List& urls ) 00850 { 00851 KOpenWithDlg l( urls, i18n("Open with:"), QString::null, 0L ); 00852 if ( l.exec() ) 00853 { 00854 KService::Ptr service = l.service(); 00855 if ( !!service ) 00856 return KRun::run( *service, urls ); 00857 00858 kdDebug(250) << "No service set, running " << l.text() << endl; 00859 return KRun::run( l.text(), urls ); 00860 } 00861 return false; 00862 } 00863 #endif 00864 00865 #include "kopenwith.moc" 00866 #include "kopenwith_p.moc" 00867
KDE Logo
This file is part of the documentation for kio Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:29:27 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003