30 #include <tqpushbutton.h>
31 #include <tqtoolbutton.h>
32 #include <tqcheckbox.h>
33 #include <tqtooltip.h>
35 #include <tqwhatsthis.h>
37 #include <kapplication.h>
38 #include <kbuttonbox.h>
39 #include <kcombobox.h>
40 #include <kdesktopfile.h>
43 #include <klineedit.h>
45 #include <kiconloader.h>
46 #include <kmimemagic.h>
48 #include <kstandarddirs.h>
49 #include <kstringhandler.h>
50 #include <kuserprofile.h>
51 #include <kurlcompletion.h>
52 #include <kurlrequester.h>
53 #include <dcopclient.h>
54 #include <kmimetype.h>
55 #include <kservicegroup.h>
56 #include <klistview.h>
58 #include <kstdguiitem.h>
60 #include "kopenwith.h"
61 #include "kopenwith_p.h"
67 #define SORT_SPEC (TQDir::DirsFirst | TQDir::Name | TQDir::IgnoreCase)
72 KAppTreeListItem::KAppTreeListItem( KListView* parent,
const TQString & name,
73 const TQPixmap& pixmap,
bool parse,
bool dir,
const TQString &p,
const TQString &c )
74 : TQListViewItem( parent, name )
76 init(pixmap, parse, dir, p, c);
82 KAppTreeListItem::KAppTreeListItem( TQListViewItem* parent,
const TQString & name,
83 const TQPixmap& pixmap,
bool parse,
bool dir,
const TQString &p,
const TQString &c )
84 : TQListViewItem( parent, name )
86 init(pixmap, parse, dir, p, c);
92 void KAppTreeListItem::init(
const TQPixmap& pixmap,
bool parse,
bool dir,
const TQString &_path,
const TQString &_exec)
103 int KAppTreeListItem::compare(TQListViewItem *i,
int col,
bool ascending)
const
105 KAppTreeListItem *other =
dynamic_cast<KAppTreeListItem *
>(i);
108 if (directory && !other->directory)
111 else if (!directory && other->directory)
115 return TQListViewItem::compare(i, col, ascending);
120 TQString KAppTreeListItem::key(
int column,
bool )
const
122 return text(column).upper();
125 void KAppTreeListItem::activate()
131 void KAppTreeListItem::setOpen(
bool o )
134 ((KApplicationTree *) parent())->addDesktopGroup( path,
this );
137 TQListViewItem::setOpen( o );
140 bool KAppTreeListItem::isDirectory()
147 KApplicationTree::KApplicationTree( TQWidget *parent )
148 : KListView( parent ), currentitem(0)
150 addColumn( i18n(
"Known Applications") );
151 setRootIsDecorated(
true );
153 addDesktopGroup( TQString::null );
156 connect(
this, TQT_SIGNAL( currentChanged(TQListViewItem*) ),
157 TQT_SLOT( slotItemHighlighted(TQListViewItem*) ) );
158 connect(
this, TQT_SIGNAL( selectionChanged(TQListViewItem*) ),
159 TQT_SLOT( slotSelectionChanged(TQListViewItem*) ) );
164 bool KApplicationTree::isDirSel()
166 if (!currentitem)
return false;
167 return currentitem->isDirectory();
172 static TQPixmap appIcon(
const TQString &iconName)
174 TQPixmap normal = KGlobal::iconLoader()->loadIcon(iconName, KIcon::Small, 0, KIcon::DefaultState, 0L,
true);
176 if (normal.width() > 20 || normal.height() > 20)
178 TQImage tmp = normal.convertToImage();
179 tmp = tmp.smoothScale(20, 20);
180 normal.convertFromImage(tmp);
185 void KApplicationTree::addDesktopGroup(
const TQString &relPath, KAppTreeListItem *item)
187 KServiceGroup::Ptr root = KServiceGroup::group(relPath);
188 if (!root || !root->isValid())
return;
190 KServiceGroup::List list = root->entries();
192 KAppTreeListItem * newItem;
193 for( KServiceGroup::List::ConstIterator it = list.begin();
194 it != list.end(); it++)
201 KSycocaEntry *p = (*it);
202 if (p->isType(KST_KService))
204 KService *service =
static_cast<KService *
>(p);
206 if (service->noDisplay())
209 icon = service->icon();
210 text = service->name();
211 exec = service->exec();
213 else if (p->isType(KST_KServiceGroup))
215 KServiceGroup *serviceGroup =
static_cast<KServiceGroup *
>(p);
217 if (serviceGroup->noDisplay() || serviceGroup->childCount() == 0)
220 icon = serviceGroup->icon();
221 text = serviceGroup->caption();
222 relPath = serviceGroup->relPath();
227 kdWarning(250) <<
"KServiceGroup: Unexpected object in list!" << endl;
231 TQPixmap pixmap = appIcon( icon );
234 newItem =
new KAppTreeListItem( item, text, pixmap,
false, isDir,
237 newItem =
new KAppTreeListItem(
this, text, pixmap,
false, isDir,
240 newItem->setExpandable(
true );
247 void KApplicationTree::slotItemHighlighted(TQListViewItem* i)
253 KAppTreeListItem *item = (KAppTreeListItem *) i;
257 if( (!item->directory ) && (!item->exec.isEmpty()) )
258 emit highlighted( item->text(0), item->exec );
264 void KApplicationTree::slotSelectionChanged(TQListViewItem* i)
270 KAppTreeListItem *item = (KAppTreeListItem *) i;
274 if( ( !item->directory ) && (!item->exec.isEmpty() ) )
275 emit selected( item->text(0), item->exec );
280 void KApplicationTree::resizeEvent( TQResizeEvent * e)
282 setColumnWidth(0, width()-TQApplication::style().pixelMetric(TQStyle::PM_ScrollBarExtent)
283 -2*TQApplication::style().pixelMetric(TQStyle::PM_DefaultFrameWidth));
284 KListView::resizeEvent(e);
288 void KApplicationTree::cleanupTree()
290 TQListViewItem *item=firstChild();
293 if(item->isExpandable())
295 TQListViewItem *temp=item->itemBelow();
296 if(item->text(0)!=i18n(
"Applications"))
297 item->setOpen(
false);
301 item=item->itemBelow();
310 class KOpenWithDlgPrivate
313 KOpenWithDlgPrivate() : saveNewApps(false) { };
316 KService::Ptr curService;
320 :TQDialog( parent,
"openwith", true )
322 setCaption( i18n(
"Open With" ) );
324 if( _urls.count() == 1 )
326 text = i18n(
"<qt>Select the program that should be used to open <b>%1</b>. "
327 "If the program is not listed, enter the name or click "
328 "the browse button.</qt>").arg( _urls.first().fileName() );
332 text = i18n(
"Choose the name of the program with which to open the selected files." );
334 init( text, TQString() );
338 const TQString& _value, TQWidget *parent)
339 :TQDialog( parent,
"openwith", true )
341 TQString caption = KStringHandler::csqueeze( _urls.first().prettyURL() );
342 if (_urls.count() > 1)
343 caption += TQString::fromLatin1(
"...");
346 init( _text, _value );
351 :TQDialog( parent,
"openwith", true )
353 setCaption(i18n(
"Choose Application for %1").arg(serviceType));
354 TQString text = i18n(
"<qt>Select the program for the file type: <b>%1</b>. "
355 "If the program is not listed, enter the name or click "
356 "the browse button.</qt>").arg(serviceType);
357 qServiceType = serviceType;
364 :TQDialog( parent,
"openwith", true )
366 setCaption(i18n(
"Choose Application"));
367 TQString text = i18n(
"<qt>Select a program. "
368 "If the program is not listed, enter the name or click "
369 "the browse button.</qt>");
370 qServiceType = TQString::null;
371 init( text, TQString::null );
376 if ( _urls.count() == 1 )
378 qServiceType = KMimeType::findByURL( _urls.first())->name();
379 if (qServiceType == TQString::fromLatin1(
"application/octet-stream"))
380 qServiceType = TQString::null;
383 qServiceType = TQString::null;
388 d =
new KOpenWithDlgPrivate;
389 bool bReadOnly = kapp && !kapp->authorize(
"shell_access");
390 m_terminaldirty =
false;
395 TQBoxLayout *topLayout =
new TQVBoxLayout(
this, KDialog::marginHint(),
396 KDialog::spacingHint() );
397 label =
new TQLabel( _text,
this );
398 topLayout->addWidget(label);
400 TQHBoxLayout* hbox =
new TQHBoxLayout(topLayout);
402 TQToolButton *clearButton =
new TQToolButton(
this );
403 clearButton->setIconSet( BarIcon(
"locationbar_erase" ) );
404 clearButton->setFixedSize( clearButton->sizeHint() );
405 connect( clearButton, TQT_SIGNAL( clicked() ), TQT_SLOT(
slotClear() ) );
406 TQToolTip::add( clearButton, i18n(
"Clear input field" ) );
408 hbox->addWidget( clearButton );
413 KHistoryCombo *combo =
new KHistoryCombo();
414 combo->setDuplicatesEnabled(
false );
415 KConfig *kc = KGlobal::config();
416 KConfigGroupSaver ks( kc, TQString::fromLatin1(
"Open-with settings") );
417 int max = kc->readNumEntry( TQString::fromLatin1(
"Maximum history"), 15 );
418 combo->setMaxCount( max );
419 int mode = kc->readNumEntry(TQString::fromLatin1(
"CompletionMode"),
420 KGlobalSettings::completionMode());
421 combo->setCompletionMode((KGlobalSettings::Completion)mode);
422 TQStringList list = kc->readListEntry( TQString::fromLatin1(
"History") );
423 combo->setHistoryItems( list,
true );
430 edit->
lineEdit()->setReadOnly(
true);
435 TQWhatsThis::add(edit,i18n(
436 "Following the command, you can have several place holders which will be replaced "
437 "with the actual values when the actual program is run:\n"
438 "%f - a single file name\n"
439 "%F - a list of files; use for applications that can open several local files at once\n"
440 "%u - a single URL\n"
441 "%U - a list of URLs\n"
442 "%d - the directory of the file to open\n"
443 "%D - a list of directories\n"
445 "%m - the mini-icon\n"
446 "%c - the comment"));
448 hbox->addWidget(edit);
451 KURLCompletion *comp =
new KURLCompletion( KURLCompletion::ExeCompletion );
452 edit->
comboBox()->setCompletionObject( comp );
453 edit->
comboBox()->setAutoDeleteCompletionObject(
true );
456 connect ( edit, TQT_SIGNAL(returnPressed()), TQT_SLOT(slotOK()) );
457 connect ( edit, TQT_SIGNAL(textChanged(
const TQString&)), TQT_SLOT(slotTextChanged()) );
459 m_pTree =
new KApplicationTree(
this );
460 topLayout->addWidget(m_pTree);
462 connect( m_pTree, TQT_SIGNAL( selected(
const TQString&,
const TQString& ) ),
463 TQT_SLOT( slotSelected(
const TQString&,
const TQString& ) ) );
464 connect( m_pTree, TQT_SIGNAL( highlighted(
const TQString&,
const TQString& ) ),
465 TQT_SLOT( slotHighlighted(
const TQString&,
const TQString& ) ) );
466 connect( m_pTree, TQT_SIGNAL( doubleClicked(TQListViewItem*) ),
467 TQT_SLOT( slotDbClick() ) );
469 terminal =
new TQCheckBox( i18n(
"Run in &terminal"),
this );
472 connect(terminal, TQT_SIGNAL(toggled(
bool)), TQT_SLOT(slotTerminalToggled(
bool)));
474 topLayout->addWidget(terminal);
476 TQBoxLayout* nocloseonexitLayout =
new TQHBoxLayout( 0, 0, KDialog::spacingHint() );
477 TQSpacerItem* spacer =
new TQSpacerItem( 20, 0, TQSizePolicy::Fixed, TQSizePolicy::Minimum );
478 nocloseonexitLayout->addItem( spacer );
480 nocloseonexit =
new TQCheckBox( i18n(
"&Do not close when command exits"),
this );
481 nocloseonexit->setChecked(
false );
482 nocloseonexit->setDisabled(
true );
486 KConfigGroup confGroup( KGlobal::config(), TQString::fromLatin1(
"General") );
487 TQString preferredTerminal = confGroup.readPathEntry(
"TerminalApplication", TQString::fromLatin1(
"konsole"));
489 if (bReadOnly || preferredTerminal !=
"konsole")
490 nocloseonexit->hide();
492 nocloseonexitLayout->addWidget( nocloseonexit );
493 topLayout->addLayout( nocloseonexitLayout );
495 if (!qServiceType.isNull())
497 remember =
new TQCheckBox(i18n(
"&Remember application association for this type of file"),
this);
499 topLayout->addWidget(remember);
505 KButtonBox* b =
new KButtonBox(
this );
508 d->ok = b->addButton( KStdGuiItem::ok() );
509 d->ok->setDefault(
true );
510 connect( d->ok, TQT_SIGNAL( clicked() ), TQT_SLOT( slotOK() ) );
512 TQPushButton* cancel = b->addButton( KStdGuiItem::cancel() );
513 connect( cancel, TQT_SIGNAL( clicked() ), TQT_SLOT( reject() ) );
516 topLayout->addWidget( b );
539 edit->
setURL(TQString::null);
546 void KOpenWithDlg::slotSelected(
const TQString& ,
const TQString& _exec )
548 kdDebug(250)<<
"KOpenWithDlg::slotSelected"<<endl;
549 KService::Ptr pService = d->curService;
551 d->curService = pService;
557 void KOpenWithDlg::slotHighlighted(
const TQString& _name,
const TQString& )
559 kdDebug(250)<<
"KOpenWithDlg::slotHighlighted"<<endl;
561 d->curService = KService::serviceByName( qName );
562 if (!m_terminaldirty)
565 terminal->setChecked(d->curService->terminal());
566 TQString terminalOptions = d->curService->terminalOptions();
567 nocloseonexit->setChecked( (terminalOptions.contains(
"--noclose" ) > 0) );
568 m_terminaldirty =
false;
574 void KOpenWithDlg::slotTextChanged()
576 kdDebug(250)<<
"KOpenWithDlg::slotTextChanged"<<endl;
579 d->ok->setEnabled( !edit->url().isEmpty());
584 void KOpenWithDlg::slotTerminalToggled(
bool)
587 m_terminaldirty =
true;
588 nocloseonexit->setDisabled( ! terminal->isChecked() );
593 void KOpenWithDlg::slotDbClick()
595 if (m_pTree->isDirSel() )
return;
604 void KOpenWithDlg::slotOK()
606 TQString typedExec(edit->url());
607 TQString fullExec(typedExec);
609 TQString serviceName;
610 TQString initialServiceName;
611 TQString preferredTerminal;
612 m_pService = d->curService;
617 serviceName = KRun::binaryName( typedExec,
true );
618 if (serviceName.isEmpty())
623 initialServiceName = serviceName;
624 kdDebug(250) <<
"initialServiceName=" << initialServiceName << endl;
629 kdDebug(250) <<
"looking for service " << serviceName << endl;
630 KService::Ptr serv = KService::serviceByDesktopName( serviceName );
633 if ( serv && serv->type() ==
"Application")
635 TQString exec = serv->exec();
637 exec.replace(
"%u",
"",
false);
638 exec.replace(
"%f",
"",
false);
639 exec.replace(
"-caption %c",
"");
640 exec.replace(
"-caption \"%c\"",
"");
641 exec.replace(
"%i",
"");
642 exec.replace(
"%m",
"");
643 exec = exec.simplifyWhiteSpace();
644 if (exec == typedExec)
648 kdDebug(250) << k_funcinfo <<
"OK, found identical service: " << serv->desktopEntryPath() << endl;
654 serviceName = initialServiceName +
"-" + TQString::number(i);
662 serviceName = m_pService->name();
663 initialServiceName = serviceName;
664 fullExec = m_pService->exec();
667 if (terminal->isChecked())
669 KConfigGroup confGroup( KGlobal::config(), TQString::fromLatin1(
"General") );
670 preferredTerminal = confGroup.readPathEntry(
"TerminalApplication", TQString::fromLatin1(
"konsole"));
671 m_command = preferredTerminal;
673 if (preferredTerminal ==
"konsole" && nocloseonexit->isChecked())
674 m_command += TQString::fromLatin1(
" --noclose");
675 m_command += TQString::fromLatin1(
" -e ");
676 m_command += edit->url();
677 kdDebug(250) <<
"Setting m_command to " << m_command << endl;
679 if ( m_pService && terminal->isChecked() != m_pService->terminal() )
682 bool bRemember = remember && remember->isChecked();
684 if ( !bRemember && m_pService)
690 if (!bRemember && !d->saveNewApps)
693 m_pService =
new KService(initialServiceName, fullExec, TQString::null);
694 if (terminal->isChecked())
696 m_pService->setTerminal(
true);
698 if (preferredTerminal ==
"konsole" && nocloseonexit->isChecked())
699 m_pService->setTerminalOptions(
"--noclose");
714 oldPath = m_pService->desktopEntryPath();
715 newPath = m_pService->locateLocal();
716 menuId = m_pService->menuId();
717 kdDebug(250) <<
"Updating exitsing service " << m_pService->desktopEntryPath() <<
" ( " << newPath <<
" ) " << endl;
721 newPath = KService::newServicePath(
false , serviceName, &menuId);
722 kdDebug(250) <<
"Creating new service " << serviceName <<
" ( " << newPath <<
" ) " << endl;
725 int maxPreference = 1;
726 if (!qServiceType.isEmpty())
728 KServiceTypeProfile::OfferList offerList = KServiceTypeProfile::offers( qServiceType );
729 if (!offerList.isEmpty())
730 maxPreference = offerList.first().preference();
733 KDesktopFile *desktop = 0;
734 if (!oldPath.isEmpty() && (oldPath != newPath))
736 KDesktopFile orig(oldPath,
true);
737 desktop = orig.copyTo(newPath);
741 desktop =
new KDesktopFile(newPath);
743 desktop->writeEntry(
"Type", TQString::fromLatin1(
"Application"));
744 desktop->writeEntry(
"Name", initialServiceName);
745 desktop->writePathEntry(
"Exec", fullExec);
746 if (terminal->isChecked())
748 desktop->writeEntry(
"Terminal",
true);
750 if (preferredTerminal ==
"konsole" && nocloseonexit->isChecked())
751 desktop->writeEntry(
"TerminalOptions",
"--noclose");
755 desktop->writeEntry(
"Terminal",
false);
757 desktop->writeEntry(
"InitialPreference", maxPreference + 1);
760 if (bRemember || d->saveNewApps)
762 TQStringList mimeList = desktop->readListEntry(
"MimeType",
';');
763 if (!qServiceType.isEmpty() && !mimeList.contains(qServiceType))
764 mimeList.append(qServiceType);
765 desktop->writeEntry(
"MimeType", mimeList,
';');
767 if ( !qServiceType.isEmpty() )
770 KDesktopFile mimeDesktop( locateLocal(
"mime", qServiceType +
".desktop" ) );
771 mimeDesktop.writeEntry(
"X-KDE-AutoEmbed",
false );
780 KService::rebuildKSycoca(
this);
782 m_pService = KService::serviceByMenuId( menuId );
784 Q_ASSERT( m_pService );
791 if (!m_command.isEmpty())
800 nocloseonexit->setChecked(
false );
801 nocloseonexit->hide();
812 KHistoryCombo *combo =
static_cast<KHistoryCombo*
>( edit->
comboBox() );
814 combo->addToHistory( edit->url() );
816 KConfig *kc = KGlobal::config();
817 KConfigGroupSaver ks( kc, TQString::fromLatin1(
"Open-with settings") );
818 kc->writeEntry( TQString::fromLatin1(
"History"), combo->historyItems() );
819 kc->writeEntry(TQString::fromLatin1(
"CompletionMode"),
820 combo->completionMode());
832 #ifndef KDE_NO_COMPAT
835 KOpenWithDlg l( urls, i18n(
"Open with:"), TQString::null, 0L );
838 KService::Ptr service = l.
service();
840 return KRun::run( *service, urls );
842 kdDebug(250) <<
"No service set, running " << l.
text() << endl;
843 return KRun::run( l.
text(), urls );
849 #include "kopenwith.moc"
850 #include "kopenwith_p.moc"