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 if (!root || !root->isValid()) return; 00191 00192 KServiceGroup::List list = root->entries(); 00193 00194 KAppTreeListItem * newItem; 00195 for( KServiceGroup::List::ConstIterator it = list.begin(); 00196 it != list.end(); it++) 00197 { 00198 QString icon; 00199 QString text; 00200 QString relPath; 00201 QString exec; 00202 bool isDir = false; 00203 KSycocaEntry *p = (*it); 00204 if (p->isType(KST_KService)) 00205 { 00206 KService *service = static_cast<KService *>(p); 00207 00208 if (service->noDisplay()) 00209 continue; 00210 00211 icon = service->icon(); 00212 text = service->name(); 00213 exec = service->exec(); 00214 } 00215 else if (p->isType(KST_KServiceGroup)) 00216 { 00217 KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p); 00218 00219 if (serviceGroup->noDisplay()) 00220 continue; 00221 00222 icon = serviceGroup->icon(); 00223 text = serviceGroup->caption(); 00224 relPath = serviceGroup->relPath(); 00225 isDir = true; 00226 //if ( text[0] == '.' ) // skip ".hidden" like kicker does 00227 //continue; 00228 } 00229 else 00230 { 00231 kdWarning(250) << "KServiceGroup: Unexpected object in list!" << endl; 00232 continue; 00233 } 00234 00235 QPixmap pixmap = appIcon( icon ); 00236 00237 if (item) 00238 newItem = new KAppTreeListItem( item, text, pixmap, false, isDir, 00239 relPath, exec ); 00240 else 00241 newItem = new KAppTreeListItem( this, text, pixmap, false, isDir, 00242 relPath, exec ); 00243 if (isDir) 00244 newItem->setExpandable( true ); 00245 } 00246 } 00247 00248 00249 // ---------------------------------------------------------------------- 00250 00251 void KApplicationTree::slotItemHighlighted(QListViewItem* i) 00252 { 00253 // i may be 0 (see documentation) 00254 if(!i) 00255 return; 00256 00257 KAppTreeListItem *item = (KAppTreeListItem *) i; 00258 00259 currentitem = item; 00260 00261 if( (!item->directory ) && (!item->exec.isEmpty()) ) 00262 emit highlighted( item->text(0), item->exec ); 00263 } 00264 00265 00266 // ---------------------------------------------------------------------- 00267 00268 void KApplicationTree::slotSelectionChanged(QListViewItem* i) 00269 { 00270 // i may be 0 (see documentation) 00271 if(!i) 00272 return; 00273 00274 KAppTreeListItem *item = (KAppTreeListItem *) i; 00275 00276 currentitem = item; 00277 00278 if( ( !item->directory ) && (!item->exec.isEmpty() ) ) 00279 emit selected( item->text(0), item->exec ); 00280 } 00281 00282 // ---------------------------------------------------------------------- 00283 00284 void KApplicationTree::resizeEvent( QResizeEvent * e) 00285 { 00286 setColumnWidth(0, width()-QApplication::style().pixelMetric(QStyle::PM_ScrollBarExtent) 00287 -2*QApplication::style().pixelMetric(QStyle::PM_DefaultFrameWidth)); 00288 KListView::resizeEvent(e); 00289 } 00290 00291 // Prune empty directories from the tree 00292 void KApplicationTree::cleanupTree() 00293 { 00294 QListViewItem *item=firstChild(); 00295 while(item!=0) 00296 { 00297 if(item->isExpandable()) 00298 { 00299 item->setOpen(true); 00300 if(item->childCount()==0) { 00301 QListViewItem *current=item; 00302 item=item->itemBelow(); 00303 delete current; 00304 continue; 00305 } 00306 item=item->itemBelow(); 00307 continue; 00308 } 00309 item=item->itemBelow(); 00310 } 00311 item=firstChild(); 00312 while(item!=0) 00313 { 00314 if(item->isExpandable()) 00315 { 00316 QListViewItem *temp=item->itemBelow(); 00317 if(item->text(0)!=i18n("Applications")) 00318 item->setOpen(false); 00319 item=temp; 00320 continue; 00321 } 00322 item=item->itemBelow(); 00323 } 00324 } 00325 00326 /*************************************************************** 00327 * 00328 * KOpenWithDlg 00329 * 00330 ***************************************************************/ 00331 class KOpenWithDlgPrivate 00332 { 00333 public: 00334 KOpenWithDlgPrivate() : saveNewApps(false) { }; 00335 QPushButton* ok; 00336 bool saveNewApps; 00337 KService::Ptr curService; 00338 }; 00339 00340 KOpenWithDlg::KOpenWithDlg( const KURL::List& _urls, QWidget* parent ) 00341 :QDialog( parent, "openwith", true ) 00342 { 00343 setCaption( i18n( "Open With" ) ); 00344 QString text; 00345 if( _urls.count() == 1 ) 00346 { 00347 text = i18n("<qt>Select the program that should be used to open <b>%1</b>. " 00348 "If the program is not listed, enter the name or click " 00349 "the browse button.</qt>").arg( _urls.first().fileName() ); 00350 } 00351 else 00352 // Should never happen ?? 00353 text = i18n( "Choose the name of the program with which to open the selected files." ); 00354 setServiceType( _urls ); 00355 init( text, QString() ); 00356 } 00357 00358 KOpenWithDlg::KOpenWithDlg( const KURL::List& _urls, const QString&_text, 00359 const QString& _value, QWidget *parent) 00360 :QDialog( parent, "openwith", true ) 00361 { 00362 QString caption = KStringHandler::csqueeze( _urls.first().prettyURL() ); 00363 if (_urls.count() > 1) 00364 caption += QString::fromLatin1("..."); 00365 setCaption(caption); 00366 setServiceType( _urls ); 00367 init( _text, _value ); 00368 } 00369 00370 KOpenWithDlg::KOpenWithDlg( const QString &serviceType, const QString& value, 00371 QWidget *parent) 00372 :QDialog( parent, "openwith", true ) 00373 { 00374 setCaption(i18n("Choose Application for %1").arg(serviceType)); 00375 QString text = i18n("<qt>Select the program for the file type: <b>%1</b>. " 00376 "If the program is not listed, enter the name or click " 00377 "the browse button.</qt>").arg(serviceType); 00378 qServiceType = serviceType; 00379 init( text, value ); 00380 if (remember) 00381 remember->hide(); 00382 } 00383 00384 KOpenWithDlg::KOpenWithDlg( QWidget *parent) 00385 :QDialog( parent, "openwith", true ) 00386 { 00387 setCaption(i18n("Choose Application")); 00388 QString text = i18n("<qt>Select a program. " 00389 "If the program is not listed, enter the name or click " 00390 "the browse button.</qt>"); 00391 qServiceType = QString::null; 00392 init( text, QString::null ); 00393 } 00394 00395 void KOpenWithDlg::setServiceType( const KURL::List& _urls ) 00396 { 00397 if ( _urls.count() == 1 ) 00398 { 00399 qServiceType = KMimeType::findByURL( _urls.first())->name(); 00400 if (qServiceType == QString::fromLatin1("application/octet-stream")) 00401 qServiceType = QString::null; 00402 } 00403 else 00404 qServiceType = QString::null; 00405 } 00406 00407 void KOpenWithDlg::init( const QString& _text, const QString& _value ) 00408 { 00409 d = new KOpenWithDlgPrivate; 00410 bool bReadOnly = kapp && !kapp->authorize("shell_access"); 00411 m_terminaldirty = false; 00412 m_pTree = 0L; 00413 m_pService = 0L; 00414 d->curService = 0L; 00415 00416 QBoxLayout *topLayout = new QVBoxLayout( this, KDialog::marginHint(), 00417 KDialog::spacingHint() ); 00418 label = new QLabel( _text, this ); 00419 topLayout->addWidget(label); 00420 00421 QHBoxLayout* hbox = new QHBoxLayout(topLayout); 00422 00423 QToolButton *clearButton = new QToolButton( this ); 00424 clearButton->setIconSet( BarIcon( "locationbar_erase" ) ); 00425 clearButton->setFixedSize( clearButton->sizeHint() ); 00426 connect( clearButton, SIGNAL( clicked() ), SLOT( slotClear() ) ); 00427 QToolTip::add( clearButton, i18n( "Clear input field" ) ); 00428 00429 hbox->addWidget( clearButton ); 00430 00431 if (!bReadOnly) 00432 { 00433 // init the history combo and insert it into the URL-Requester 00434 KHistoryCombo *combo = new KHistoryCombo(); 00435 combo->setDuplicatesEnabled( false ); 00436 KConfig *kc = KGlobal::config(); 00437 KConfigGroupSaver ks( kc, QString::fromLatin1("Open-with settings") ); 00438 int max = kc->readNumEntry( QString::fromLatin1("Maximum history"), 15 ); 00439 combo->setMaxCount( max ); 00440 int mode = kc->readNumEntry(QString::fromLatin1("CompletionMode"), 00441 KGlobalSettings::completionMode()); 00442 combo->setCompletionMode((KGlobalSettings::Completion)mode); 00443 QStringList list = kc->readListEntry( QString::fromLatin1("History") ); 00444 combo->setHistoryItems( list, true ); 00445 edit = new KURLRequester( combo, this ); 00446 } 00447 else 00448 { 00449 clearButton->hide(); 00450 edit = new KURLRequester( this ); 00451 edit->lineEdit()->setReadOnly(true); 00452 edit->button()->hide(); 00453 } 00454 00455 edit->setURL( _value ); 00456 QWhatsThis::add(edit,i18n( 00457 "Following the command, you can have several place holders which will be replaced " 00458 "with the actual values when the actual program is run:\n" 00459 "%f - a single file name\n" 00460 "%F - a list of files; use for applications that can open several local files at once\n" 00461 "%u - a single URL\n" 00462 "%U - a list of URLs\n" 00463 "%d - the directory of the file to open\n" 00464 "%D - a list of directories\n" 00465 "%i - the icon\n" 00466 "%m - the mini-icon\n" 00467 "%c - the comment")); 00468 00469 hbox->addWidget(edit); 00470 00471 if ( edit->comboBox() ) { 00472 KURLCompletion *comp = new KURLCompletion( KURLCompletion::ExeCompletion ); 00473 edit->comboBox()->setCompletionObject( comp ); 00474 edit->comboBox()->setAutoDeleteCompletionObject( true ); 00475 } 00476 00477 connect ( edit, SIGNAL(returnPressed()), SLOT(slotOK()) ); 00478 connect ( edit, SIGNAL(textChanged(const QString&)), SLOT(slotTextChanged()) ); 00479 00480 m_pTree = new KApplicationTree( this ); 00481 topLayout->addWidget(m_pTree); 00482 00483 connect( m_pTree, SIGNAL( selected( const QString&, const QString& ) ), 00484 SLOT( slotSelected( const QString&, const QString& ) ) ); 00485 connect( m_pTree, SIGNAL( highlighted( const QString&, const QString& ) ), 00486 SLOT( slotHighlighted( const QString&, const QString& ) ) ); 00487 connect( m_pTree, SIGNAL( doubleClicked(QListViewItem*) ), 00488 SLOT( slotDbClick() ) ); 00489 00490 terminal = new QCheckBox( i18n("Run in &terminal"), this ); 00491 if (bReadOnly) 00492 terminal->hide(); 00493 connect(terminal, SIGNAL(toggled(bool)), SLOT(slotTerminalToggled(bool))); 00494 00495 topLayout->addWidget(terminal); 00496 00497 QBoxLayout* nocloseonexitLayout = new QHBoxLayout( 0, 0, KDialog::spacingHint() ); 00498 QSpacerItem* spacer = new QSpacerItem( 20, 0, QSizePolicy::Fixed, QSizePolicy::Minimum ); 00499 nocloseonexitLayout->addItem( spacer ); 00500 00501 nocloseonexit = new QCheckBox( i18n("&Do not close when command exits"), this ); 00502 nocloseonexit->setChecked( false ); 00503 nocloseonexit->setDisabled( true ); 00504 00505 // check to see if we use konsole if not disable the nocloseonexit 00506 // because we don't know how to do this on other terminal applications 00507 KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") ); 00508 QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole")); 00509 00510 if (bReadOnly || preferredTerminal != "konsole") 00511 nocloseonexit->hide(); 00512 00513 nocloseonexitLayout->addWidget( nocloseonexit ); 00514 topLayout->addLayout( nocloseonexitLayout ); 00515 00516 if (!qServiceType.isNull()) 00517 { 00518 remember = new QCheckBox(i18n("&Remember application association for this type of file"), this); 00519 // remember->setChecked(true); 00520 topLayout->addWidget(remember); 00521 } 00522 else 00523 remember = 0L; 00524 00525 // Use KButtonBox for the aligning pushbuttons nicely 00526 KButtonBox* b = new KButtonBox( this ); 00527 b->addStretch( 2 ); 00528 00529 d->ok = b->addButton( KStdGuiItem::ok() ); 00530 d->ok->setDefault( true ); 00531 connect( d->ok, SIGNAL( clicked() ), SLOT( slotOK() ) ); 00532 00533 QPushButton* cancel = b->addButton( KStdGuiItem::cancel() ); 00534 connect( cancel, SIGNAL( clicked() ), SLOT( reject() ) ); 00535 00536 b->layout(); 00537 topLayout->addWidget( b ); 00538 00539 //edit->setText( _value ); 00540 // This is what caused "can't click on items before clicking on Name header". 00541 // Probably due to the resizeEvent handler using width(). 00542 //resize( minimumWidth(), sizeHint().height() ); 00543 edit->setFocus(); 00544 slotTextChanged(); 00545 } 00546 00547 00548 // ---------------------------------------------------------------------- 00549 00550 KOpenWithDlg::~KOpenWithDlg() 00551 { 00552 delete d; 00553 d = 0; 00554 } 00555 00556 // ---------------------------------------------------------------------- 00557 00558 void KOpenWithDlg::slotClear() 00559 { 00560 edit->setURL(QString::null); 00561 edit->setFocus(); 00562 } 00563 00564 00565 // ---------------------------------------------------------------------- 00566 00567 void KOpenWithDlg::slotSelected( const QString& /*_name*/, const QString& _exec ) 00568 { 00569 kdDebug(250)<<"KOpenWithDlg::slotSelected"<<endl; 00570 KService::Ptr pService = d->curService; 00571 edit->setURL( _exec ); // calls slotTextChanged :( 00572 d->curService = pService; 00573 } 00574 00575 00576 // ---------------------------------------------------------------------- 00577 00578 void KOpenWithDlg::slotHighlighted( const QString& _name, const QString& ) 00579 { 00580 kdDebug(250)<<"KOpenWithDlg::slotHighlighted"<<endl; 00581 qName = _name; 00582 d->curService = KService::serviceByName( qName ); 00583 if (!m_terminaldirty) 00584 { 00585 // ### indicate that default value was restored 00586 terminal->setChecked(d->curService->terminal()); 00587 QString terminalOptions = d->curService->terminalOptions(); 00588 nocloseonexit->setChecked( (terminalOptions.contains( "--noclose" ) > 0) ); 00589 m_terminaldirty = false; // slotTerminalToggled changed it 00590 } 00591 } 00592 00593 // ---------------------------------------------------------------------- 00594 00595 void KOpenWithDlg::slotTextChanged() 00596 { 00597 kdDebug(250)<<"KOpenWithDlg::slotTextChanged"<<endl; 00598 // Forget about the service 00599 d->curService = 0L; 00600 d->ok->setEnabled( !edit->url().isEmpty()); 00601 } 00602 00603 // ---------------------------------------------------------------------- 00604 00605 void KOpenWithDlg::slotTerminalToggled(bool) 00606 { 00607 // ### indicate that default value was overridden 00608 m_terminaldirty = true; 00609 nocloseonexit->setDisabled( ! terminal->isChecked() ); 00610 } 00611 00612 // ---------------------------------------------------------------------- 00613 00614 void KOpenWithDlg::slotDbClick() 00615 { 00616 if (m_pTree->isDirSel() ) return; // check if a directory is selected 00617 slotOK(); 00618 } 00619 00620 void KOpenWithDlg::setSaveNewApplications(bool b) 00621 { 00622 d->saveNewApps = b; 00623 } 00624 00625 void KOpenWithDlg::slotOK() 00626 { 00627 QString fullExec(edit->url()); 00628 00629 QString serviceName; 00630 QString initialServiceName; 00631 QString preferredTerminal; 00632 m_pService = d->curService; 00633 if (!m_pService) { 00634 // No service selected - check the command line 00635 00636 // Find out the name of the service from the command line, removing args and paths 00637 serviceName = KRun::binaryName( fullExec, true ); 00638 if (serviceName.isEmpty()) 00639 { 00640 // TODO add a KMessageBox::error here after the end of the message freeze 00641 return; 00642 } 00643 initialServiceName = serviceName; 00644 kdDebug(250) << "initialServiceName=" << initialServiceName << endl; 00645 int i = 1; // We have app, app-2, app-3... Looks better for the user. 00646 bool ok = false; 00647 // Check if there's already a service by that name, with the same Exec line 00648 do { 00649 kdDebug(250) << "looking for service " << serviceName << endl; 00650 KService::Ptr serv = KService::serviceByDesktopName( serviceName ); 00651 ok = !serv; // ok if no such service yet 00652 // also ok if we find the exact same service (well, "kwrite" == "kwrite %U" 00653 if ( serv && serv->type() == "Application") 00654 { 00655 QString exec = serv->exec(); 00656 exec.replace("%u", "", false); 00657 exec.replace("%f", "", false); 00658 exec.replace("-caption %c", ""); 00659 exec.replace("-caption \"%c\"", ""); 00660 exec.replace("%i", ""); 00661 exec.replace("%m", ""); 00662 exec = exec.simplifyWhiteSpace(); 00663 if (exec == fullExec) 00664 { 00665 ok = true; 00666 m_pService = serv; 00667 kdDebug(250) << k_funcinfo << "OK, found identical service: " << serv->desktopEntryPath() << endl; 00668 } 00669 } 00670 if (!ok) // service was found, but it was different -> keep looking 00671 { 00672 ++i; 00673 serviceName = initialServiceName + "-" + QString::number(i); 00674 } 00675 } 00676 while (!ok); 00677 } 00678 if ( m_pService ) 00679 { 00680 // Existing service selected 00681 serviceName = m_pService->name(); 00682 initialServiceName = serviceName; 00683 } 00684 00685 if (terminal->isChecked()) 00686 { 00687 KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") ); 00688 preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole")); 00689 m_command = preferredTerminal; 00690 // only add --noclose when we are sure it is konsole we're using 00691 if (preferredTerminal == "konsole" && nocloseonexit->isChecked()) 00692 m_command += QString::fromLatin1(" --noclose"); 00693 m_command += QString::fromLatin1(" -e "); 00694 m_command += edit->url(); 00695 kdDebug(250) << "Setting m_command to " << m_command << endl; 00696 } 00697 if ( m_pService && terminal->isChecked() != m_pService->terminal() ) 00698 m_pService = 0L; // It's not exactly this service we're running 00699 00700 bool bRemember = remember && remember->isChecked(); 00701 00702 if ( !bRemember && m_pService) 00703 { 00704 accept(); 00705 return; 00706 } 00707 00708 if (!bRemember && !d->saveNewApps) 00709 { 00710 // Create temp service 00711 m_pService = new KService(initialServiceName, fullExec, QString::null); 00712 if (terminal->isChecked()) 00713 { 00714 m_pService->setTerminal(true); 00715 // only add --noclose when we are sure it is konsole we're using 00716 if (preferredTerminal == "konsole" && nocloseonexit->isChecked()) 00717 m_pService->setTerminalOptions("--noclose"); 00718 } 00719 accept(); 00720 return; 00721 } 00722 00723 // if we got here, we can't seem to find a service for what they 00724 // wanted. The other possibility is that they have asked for the 00725 // association to be remembered. Create/update service. 00726 00727 QString newPath; 00728 QString oldPath; 00729 QString menuId; 00730 if (m_pService) 00731 { 00732 oldPath = m_pService->desktopEntryPath(); 00733 newPath = m_pService->locateLocal(); 00734 menuId = m_pService->menuId(); 00735 kdDebug(250) << "Updating exitsing service " << m_pService->desktopEntryPath() << " ( " << newPath << " ) " << endl; 00736 } 00737 else 00738 { 00739 newPath = KService::newServicePath(false /* hidden */, serviceName, &menuId); 00740 kdDebug(250) << "Creating new service " << serviceName << " ( " << newPath << " ) " << endl; 00741 } 00742 00743 int maxPreference = 1; 00744 if (!qServiceType.isEmpty()) 00745 { 00746 KServiceTypeProfile::OfferList offerList = KServiceTypeProfile::offers( qServiceType ); 00747 if (!offerList.isEmpty()) 00748 maxPreference = offerList.first().preference(); 00749 } 00750 QString menuElement; 00751 menuElement="?package(menu): needs=\"x11\" section=\".hidden\" "; 00752 KDesktopFile *desktop = 0; 00753 if (!oldPath.isEmpty() && (oldPath != newPath)) 00754 { 00755 KDesktopFile orig(oldPath, true); 00756 if ( m_pService ) 00757 desktop = orig.copyTo( pathToCopyEntry(newPath, m_pService->menuId() ) ); 00758 else 00759 desktop = orig.copyTo(newPath); 00760 } 00761 else 00762 { 00763 if ( m_pService ) 00764 desktop = new KDesktopFile(pathToCopyEntry(newPath, m_pService->menuId() ) ); 00765 else 00766 desktop = new KDesktopFile(newPath); 00767 } 00768 desktop->writeEntry("Type", QString::fromLatin1("Application")); 00769 desktop->writeEntry("Name", initialServiceName); 00770 desktop->writePathEntry("Exec", fullExec); 00771 menuElement+="command=\""; 00772 menuElement+=fullExec+"\" "; 00773 menuElement+="title=\""; 00774 menuElement+=initialServiceName+"\" "; 00775 QString kdeOpt = "kde_opt=\""; 00776 if (terminal->isChecked()) 00777 { 00778 desktop->writeEntry("Terminal", true); 00779 kdeOpt+="Terminal=1\\\\n"; 00780 // only add --noclose when we are sure it is konsole we're using 00781 if (preferredTerminal == "konsole" && nocloseonexit->isChecked()) 00782 { 00783 desktop->writeEntry("TerminalOptions", "--noclose"); 00784 kdeOpt+=" TerminalOptions=--noclose\\\\n"; 00785 } 00786 } 00787 else 00788 { 00789 desktop->writeEntry("Terminal", false); 00790 } 00791 desktop->writeEntry("InitialPreference", maxPreference + 1); 00792 kdeOpt+=QString( "InitialPreference=%1\\\\n" ).arg( maxPreference + 1 ); 00793 00794 if (bRemember || d->saveNewApps) 00795 { 00796 QStringList mimeList = desktop->readListEntry("MimeType", ';'); 00797 if (!qServiceType.isEmpty() && !mimeList.contains(qServiceType)) 00798 mimeList.append(qServiceType); 00799 desktop->writeEntry("MimeType", mimeList, ';'); 00800 menuElement+=QString( "mimetypes=\"%1\"" ).arg( mimeList.join( ";") ); 00801 if ( !qServiceType.isEmpty() ) 00802 { 00803 // Also make sure the "auto embed" setting for this mimetype is off 00804 KDesktopFile mimeDesktop( locateLocal( "mime", qServiceType + ".desktop" ) ); 00805 mimeDesktop.writeEntry( "X-KDE-AutoEmbed", false ); 00806 mimeDesktop.sync(); 00807 } 00808 } 00809 00810 if ( newPath.contains( "Mandrakelinux/.hidden" ) && ( KStandardDirs::menu_type_by_version()!="kde" )) 00811 { 00812 QStringList categorieList = desktop->readListEntry("Categories", ';'); 00813 if ( !categorieList.contains("X-Mandrakelinux-.hidden")) 00814 categorieList.append("X-Mandrakelinux-.hidden"); 00815 desktop->writeEntry( "Categories", categorieList, ";" ); 00816 //?package(xterm): needs=X11 section="System/Terminals" title="XTerm" longtitle="The standard terminal emulator for the X Window System" command="/usr/X11R6/bin/xterm -name Terminal" icon="xterm-terminal.png" 00817 menuElement+=" " +kdeOpt+"\""; 00818 saveInMDKMenuStructure( initialServiceName,menuElement ); 00819 } 00820 // write it all out to the file 00821 desktop->sync(); 00822 delete desktop; 00823 00824 KService::rebuildKSycoca(this); 00825 00826 m_pService = KService::serviceByMenuId( menuId ); 00827 00828 Q_ASSERT( m_pService ); 00829 00830 accept(); 00831 } 00832 00833 void KOpenWithDlg::saveInMDKMenuStructure( const QString & filename, const QString &menuElement ) 00834 { 00835 QString menuPath; 00836 QString tmp =KStandardDirs::menu_type_by_version(); 00837 if( tmp=="kde") 00838 return; 00839 else if ( tmp=="mdk" ) 00840 { 00841 menuPath=".menu/"; 00842 } 00843 else if ( tmp == "mdk-simplified" ) 00844 { 00845 menuPath=".menu-simplified/"; 00846 } 00847 else 00848 { 00849 kdDebug()<<" Error in type of menu\n"; 00850 return; 00851 } 00852 QFile menuStamp(QDir::homeDirPath ()+"/.menu-updates.stamp"); 00853 if( menuStamp.exists()) 00854 menuStamp.remove(); 00855 QDir dir; 00856 dir.mkdir( QDir::homeDirPath ()+"/"+menuPath ); 00857 QFile saveMenuMDK( QDir::homeDirPath ()+"/"+menuPath+filename ); 00858 if ( saveMenuMDK.open( IO_WriteOnly ) ) { 00859 QTextStream stream( &saveMenuMDK ); 00860 stream<<menuElement<<"\n"; 00861 saveMenuMDK.close(); 00862 } 00863 } 00864 00865 QString KOpenWithDlg::pathToCopyEntry( QString path, QString menuId ) 00866 { 00867 if( KStandardDirs::menu_type_by_version()=="kde") 00868 return path; 00869 QString tmpPath = path.remove( menuId ); 00870 QString element; 00871 element = menuId.remove( "Mandrakelinux-" ); 00872 element=element.replace( QChar( '-' ), "/" ); 00873 QString newPath = tmpPath+"Mandrakelinux/"+element; 00874 KURL url(newPath); 00875 KStandardDirs::makeDir( url.directory() ); 00876 return newPath; 00877 } 00878 00879 QString KOpenWithDlg::text() const 00880 { 00881 if (!m_command.isEmpty()) 00882 return m_command; 00883 else 00884 return edit->url(); 00885 } 00886 00887 void KOpenWithDlg::hideNoCloseOnExit() 00888 { 00889 // uncheck the checkbox because the value could be used when "Run in Terminal" is selected 00890 nocloseonexit->setChecked( false ); 00891 nocloseonexit->hide(); 00892 } 00893 00894 void KOpenWithDlg::hideRunInTerminal() 00895 { 00896 terminal->hide(); 00897 hideNoCloseOnExit(); 00898 } 00899 00900 void KOpenWithDlg::accept() 00901 { 00902 KHistoryCombo *combo = static_cast<KHistoryCombo*>( edit->comboBox() ); 00903 if ( combo ) { 00904 combo->addToHistory( edit->url() ); 00905 00906 KConfig *kc = KGlobal::config(); 00907 KConfigGroupSaver ks( kc, QString::fromLatin1("Open-with settings") ); 00908 kc->writeEntry( QString::fromLatin1("History"), combo->historyItems() ); 00909 kc->writeEntry(QString::fromLatin1("CompletionMode"), 00910 combo->completionMode()); 00911 // don't store the completion-list, as it contains all of KURLCompletion's 00912 // executables 00913 kc->sync(); 00914 } 00915 00916 QDialog::accept(); 00917 } 00918 00919 00921 00922 #ifndef KDE_NO_COMPAT 00923 bool KFileOpenWithHandler::displayOpenWithDialog( const KURL::List& urls ) 00924 { 00925 KOpenWithDlg l( urls, i18n("Open with:"), QString::null, 0L ); 00926 if ( l.exec() ) 00927 { 00928 KService::Ptr service = l.service(); 00929 if ( !!service ) 00930 return KRun::run( *service, urls ); 00931 00932 kdDebug(250) << "No service set, running " << l.text() << endl; 00933 return KRun::run( l.text(), urls ); 00934 } 00935 return false; 00936 } 00937 #endif 00938 00939 #include "kopenwith.moc" 00940 #include "kopenwith_p.moc" 00941
KDE Logo
This file is part of the documentation for kio Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Apr 12 23:09:17 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003