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