30 #include <tqpushbutton.h>
31 #include <tqtoolbutton.h>
32 #include <tqcheckbox.h>
33 #include <tqtooltip.h>
35 #include <tqwhatsthis.h>
37 #include <tdeapplication.h>
38 #include <kbuttonbox.h>
39 #include <kcombobox.h>
40 #include <kdesktopfile.h>
42 #include <tdeglobal.h>
43 #include <klineedit.h>
44 #include <tdelocale.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 <tdelistview.h>
57 #include <tdesycoca.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( TDEListView* parent,
const TQString & name,
73 const TQPixmap& pixmap,
bool parse,
bool dir,
74 const TQString &p,
const TQString &c,
const TQString &dp )
75 : TQListViewItem( parent, name )
77 init(pixmap, parse, dir, p, c, dp);
83 KAppTreeListItem::KAppTreeListItem( TQListViewItem* parent,
const TQString & name,
84 const TQPixmap& pixmap,
bool parse,
bool dir,
85 const TQString &p,
const TQString &c,
const TQString &dp )
86 : TQListViewItem( parent, name )
88 init(pixmap, parse, dir, p, c, dp);
94 void KAppTreeListItem::init(
const TQPixmap& pixmap,
bool parse,
bool dir,
95 const TQString &_path,
const TQString &_exec,
const TQString &_desktopPath)
102 desktopPath = _desktopPath;
107 int KAppTreeListItem::compare(TQListViewItem *i,
int col,
bool ascending)
const
109 KAppTreeListItem *other =
dynamic_cast<KAppTreeListItem *
>(i);
112 if (directory && !other->directory)
115 else if (!directory && other->directory)
119 return TQListViewItem::compare(i, col, ascending);
124 TQString KAppTreeListItem::key(
int column,
bool )
const
126 return text(column).upper();
129 void KAppTreeListItem::activate()
135 void KAppTreeListItem::setOpen(
bool o )
138 ((TDEApplicationTree *) parent())->addDesktopGroup( path,
this );
141 TQListViewItem::setOpen( o );
144 bool KAppTreeListItem::isDirectory()
151 TDEApplicationTree::TDEApplicationTree( TQWidget *parent )
152 : TDEListView( parent ), currentitem(0)
154 addColumn( i18n(
"Known Applications") );
155 setRootIsDecorated(
true );
157 addDesktopGroup( TQString::null );
160 connect(
this, TQ_SIGNAL( currentChanged(TQListViewItem*) ),
161 TQ_SLOT( slotItemHighlighted(TQListViewItem*) ) );
162 connect(
this, TQ_SIGNAL( selectionChanged(TQListViewItem*) ),
163 TQ_SLOT( slotSelectionChanged(TQListViewItem*) ) );
168 bool TDEApplicationTree::isDirSel()
170 if (!currentitem)
return false;
171 return currentitem->isDirectory();
176 static TQPixmap appIcon(
const TQString &iconName)
178 TQPixmap normal = TDEGlobal::iconLoader()->loadIcon(iconName, TDEIcon::Small, 0, TDEIcon::DefaultState, 0L,
true);
180 if (normal.width() > 20 || normal.height() > 20)
182 TQImage tmp = normal.convertToImage();
183 tmp = tmp.smoothScale(20, 20);
184 normal.convertFromImage(tmp);
189 void TDEApplicationTree::addDesktopGroup(
const TQString &relPath, KAppTreeListItem *item)
191 KServiceGroup::Ptr root = KServiceGroup::group(relPath);
192 if (!root || !root->isValid())
return;
194 KServiceGroup::List list = root->entries();
196 KAppTreeListItem * newItem;
197 for( KServiceGroup::List::ConstIterator it = list.begin();
198 it != list.end(); it++)
200 TQString icon, text, relPath, exec, desktopPath;
202 KSycocaEntry *p = (*it);
203 if (p->isType(KST_KService))
205 KService *service =
static_cast<KService *
>(p);
207 if (service->noDisplay())
210 icon = service->icon();
211 text = service->name();
212 exec = service->exec();
213 desktopPath = service->desktopEntryPath();
215 else if (p->isType(KST_KServiceGroup))
217 KServiceGroup *serviceGroup =
static_cast<KServiceGroup *
>(p);
219 if (serviceGroup->noDisplay() || serviceGroup->childCount() == 0)
222 icon = serviceGroup->icon();
223 text = serviceGroup->caption();
224 relPath = serviceGroup->relPath();
229 kdWarning(250) <<
"KServiceGroup: Unexpected object in list!" << endl;
233 TQPixmap pixmap = appIcon( icon );
236 newItem =
new KAppTreeListItem( item, text, pixmap,
false, isDir,
237 relPath, exec, desktopPath );
239 newItem =
new KAppTreeListItem(
this, text, pixmap,
false, isDir,
240 relPath, exec, desktopPath );
242 newItem->setExpandable(
true );
249 void TDEApplicationTree::slotItemHighlighted(TQListViewItem* i)
255 KAppTreeListItem *item = (KAppTreeListItem *) i;
259 if( (!item->directory ) && (!item->exec.isEmpty()) )
260 emit highlighted( item->text(0), item->exec, item->desktopPath );
266 void TDEApplicationTree::slotSelectionChanged(TQListViewItem* i)
272 KAppTreeListItem *item = (KAppTreeListItem *) i;
276 if( ( !item->directory ) && (!item->exec.isEmpty() ) )
277 emit selected( item->text(0), item->exec, item->desktopPath );
282 void TDEApplicationTree::resizeEvent( TQResizeEvent * e)
284 setColumnWidth(0, width()-TQApplication::style().pixelMetric(TQStyle::PM_ScrollBarExtent)
285 -2*TQApplication::style().pixelMetric(TQStyle::PM_DefaultFrameWidth));
286 TDEListView::resizeEvent(e);
290 void TDEApplicationTree::cleanupTree()
292 TQListViewItem *item=firstChild();
295 if(item->isExpandable())
297 TQListViewItem *temp=item->itemBelow();
298 if(item->text(0)!=i18n(
"Applications"))
299 item->setOpen(
false);
303 item=item->itemBelow();
312 class KOpenWithDlgPrivate
315 KOpenWithDlgPrivate() : saveNewApps(false) { };
318 KService::Ptr curService;
322 :TQDialog( parent,
"openwith", true )
324 setCaption( i18n(
"Open With" ) );
326 if( _urls.count() == 1 )
328 text = i18n(
"<qt>Select the program that should be used to open <b>%1</b>. "
329 "If the program is not listed, enter the name or click "
330 "the browse button.</qt>").arg( _urls.first().fileName() );
334 text = i18n(
"Choose the name of the program with which to open the selected files." );
340 const TQString& _value, TQWidget *parent)
341 :TQDialog( parent,
"openwith", true )
343 TQString caption = KStringHandler::csqueeze( _urls.first().prettyURL() );
344 if (_urls.count() > 1)
345 caption += TQString::fromLatin1(
"...");
348 init( _text, _value );
353 :TQDialog( parent,
"openwith", true )
355 setCaption(i18n(
"Choose Application for %1").arg(serviceType));
356 TQString
text = i18n(
"<qt>Select the program for the file type: <b>%1</b>. "
357 "If the program is not listed, enter the name or click "
358 "the browse button.</qt>").arg(serviceType);
359 qServiceType = serviceType;
366 :TQDialog( parent,
"openwith", true )
368 setCaption(i18n(
"Choose Application"));
369 TQString
text = i18n(
"<qt>Select a program. "
370 "If the program is not listed, enter the name or click "
371 "the browse button.</qt>");
372 qServiceType = TQString::null;
378 if ( _urls.count() == 1 )
380 qServiceType = KMimeType::findByURL( _urls.first())->name();
381 if (qServiceType == TQString::fromLatin1(
"application/octet-stream"))
382 qServiceType = TQString::null;
385 qServiceType = TQString::null;
390 d =
new KOpenWithDlgPrivate;
391 bool bReadOnly = kapp && !kapp->authorize(
"shell_access");
392 m_terminaldirty =
false;
397 TQBoxLayout *topLayout =
new TQVBoxLayout(
this, KDialog::marginHint(),
398 KDialog::spacingHint() );
399 label =
new TQLabel( _text,
this );
400 topLayout->addWidget(label);
402 TQHBoxLayout* hbox =
new TQHBoxLayout(topLayout);
404 TQToolButton *clearButton =
new TQToolButton(
this );
405 clearButton->setIconSet( BarIcon(
"locationbar_erase" ) );
406 clearButton->setFixedSize( clearButton->sizeHint() );
407 connect( clearButton, TQ_SIGNAL( clicked() ), TQ_SLOT(
slotClear() ) );
408 TQToolTip::add( clearButton, i18n(
"Clear input field" ) );
410 hbox->addWidget( clearButton );
415 KHistoryCombo *combo =
new KHistoryCombo();
416 combo->setDuplicatesEnabled(
false );
417 TDEConfig *kc = TDEGlobal::config();
418 TDEConfigGroupSaver ks( kc, TQString::fromLatin1(
"Open-with settings") );
419 int max = kc->readNumEntry( TQString::fromLatin1(
"Maximum history"), 15 );
420 combo->setMaxCount( max );
421 int mode = kc->readNumEntry(TQString::fromLatin1(
"CompletionMode"),
422 TDEGlobalSettings::completionMode());
423 combo->setCompletionMode((TDEGlobalSettings::Completion)mode);
424 TQStringList list = kc->readListEntry( TQString::fromLatin1(
"History") );
425 combo->setHistoryItems( list,
true );
432 edit->
lineEdit()->setReadOnly(
true);
437 TQWhatsThis::add(edit,i18n(
438 "Following the command, you can have several place holders which will be replaced "
439 "with the actual values when the actual program is run:\n"
440 "%f - a single file name\n"
441 "%F - a list of files; use for applications that can open several local files at once\n"
442 "%u - a single URL\n"
443 "%U - a list of URLs\n"
444 "%d - the directory of the file to open\n"
445 "%D - a list of directories\n"
447 "%m - the mini-icon\n"
448 "%c - the comment"));
450 hbox->addWidget(edit);
453 KURLCompletion *comp =
new KURLCompletion( KURLCompletion::ExeCompletion );
454 edit->
comboBox()->setCompletionObject( comp );
455 edit->
comboBox()->setAutoDeleteCompletionObject(
true );
458 connect ( edit, TQ_SIGNAL(returnPressed()), TQ_SLOT(slotOK()) );
459 connect ( edit, TQ_SIGNAL(textChanged(
const TQString&)), TQ_SLOT(slotTextChanged()) );
461 m_pTree =
new TDEApplicationTree(
this );
462 topLayout->addWidget(m_pTree);
464 connect( m_pTree, TQ_SIGNAL( selected(
const TQString&,
const TQString&,
const TQString& ) ),
465 TQ_SLOT( slotSelected(
const TQString&,
const TQString&,
const TQString& ) ) );
466 connect( m_pTree, TQ_SIGNAL( highlighted(
const TQString&,
const TQString&,
const TQString& ) ),
467 TQ_SLOT( slotHighlighted(
const TQString&,
const TQString&,
const TQString& ) ) );
468 connect( m_pTree, TQ_SIGNAL( doubleClicked(TQListViewItem*) ),
469 TQ_SLOT( slotDbClick() ) );
471 terminal =
new TQCheckBox( i18n(
"Run in &terminal"),
this );
474 connect(terminal, TQ_SIGNAL(toggled(
bool)), TQ_SLOT(slotTerminalToggled(
bool)));
476 topLayout->addWidget(terminal);
478 TQBoxLayout* nocloseonexitLayout =
new TQHBoxLayout( 0, 0, KDialog::spacingHint() );
479 TQSpacerItem* spacer =
new TQSpacerItem( 20, 0, TQSizePolicy::Fixed, TQSizePolicy::Minimum );
480 nocloseonexitLayout->addItem( spacer );
482 nocloseonexit =
new TQCheckBox( i18n(
"&Do not close when command exits"),
this );
483 nocloseonexit->setChecked(
false );
484 nocloseonexit->setDisabled(
true );
488 TDEConfigGroup confGroup( TDEGlobal::config(), TQString::fromLatin1(
"General") );
489 TQString preferredTerminal = confGroup.readPathEntry(
"TerminalApplication", TQString::fromLatin1(
"konsole"));
491 if (bReadOnly || preferredTerminal !=
"konsole")
492 nocloseonexit->hide();
494 nocloseonexitLayout->addWidget( nocloseonexit );
495 topLayout->addLayout( nocloseonexitLayout );
497 if (!qServiceType.isNull())
499 remember =
new TQCheckBox(i18n(
"&Remember application association for this type of file"),
this);
501 topLayout->addWidget(remember);
507 KButtonBox* b =
new KButtonBox(
this );
510 d->ok = b->addButton( KStdGuiItem::ok() );
511 d->ok->setDefault(
true );
512 connect( d->ok, TQ_SIGNAL( clicked() ), TQ_SLOT( slotOK() ) );
514 TQPushButton* cancel = b->addButton( KStdGuiItem::cancel() );
515 connect( cancel, TQ_SIGNAL( clicked() ), TQ_SLOT( reject() ) );
518 topLayout->addWidget( b );
541 edit->
setURL(TQString::null);
548 void KOpenWithDlg::slotSelected(
const TQString& ,
const TQString& _exec,
const TQString& )
550 kdDebug(250)<<
"KOpenWithDlg::slotSelected"<<endl;
551 KService::Ptr pService = d->curService;
553 d->curService = pService;
559 void KOpenWithDlg::slotHighlighted(
const TQString& _name,
const TQString& _exec,
const TQString& _desktopPath )
561 kdDebug(250)<<
"KOpenWithDlg::slotHighlighted"<<endl;
566 d->curService = KService::serviceByDesktopPath( _desktopPath );
569 d->curService = KService::serviceByName( qName );
571 if (!m_terminaldirty)
574 terminal->setChecked(d->curService->terminal());
575 TQString terminalOptions = d->curService->terminalOptions();
576 nocloseonexit->setChecked( (terminalOptions.contains(
"--noclose" ) > 0) );
577 m_terminaldirty =
false;
583 void KOpenWithDlg::slotTextChanged()
585 kdDebug(250)<<
"KOpenWithDlg::slotTextChanged"<<endl;
588 d->ok->setEnabled( !edit->
url().isEmpty());
593 void KOpenWithDlg::slotTerminalToggled(
bool)
596 m_terminaldirty =
true;
597 nocloseonexit->setDisabled( ! terminal->isChecked() );
602 void KOpenWithDlg::slotDbClick()
604 if (m_pTree->isDirSel() )
return;
613 void KOpenWithDlg::slotOK()
615 TQString typedExec(edit->
url());
616 TQString fullExec(typedExec);
618 TQString serviceName;
619 TQString initialServiceName;
620 TQString preferredTerminal;
621 m_pService = d->curService;
626 serviceName = KRun::binaryName( typedExec,
true );
627 if (serviceName.isEmpty())
632 initialServiceName = serviceName;
633 kdDebug(250) <<
"initialServiceName=" << initialServiceName << endl;
638 kdDebug(250) <<
"looking for service " << serviceName << endl;
639 KService::Ptr serv = KService::serviceByDesktopName( serviceName );
642 if ( serv && serv->type() ==
"Application")
644 TQString exec = serv->exec();
646 exec.replace(
"%u",
"",
false);
647 exec.replace(
"%f",
"",
false);
648 exec.replace(
"-caption %c",
"");
649 exec.replace(
"-caption \"%c\"",
"");
650 exec.replace(
"%i",
"");
651 exec.replace(
"%m",
"");
652 exec = exec.simplifyWhiteSpace();
653 if (exec == typedExec)
657 kdDebug(250) << k_funcinfo <<
"OK, found identical service: " << serv->desktopEntryPath() << endl;
663 serviceName = initialServiceName +
"-" + TQString::number(i);
671 serviceName = m_pService->name();
672 initialServiceName = serviceName;
673 fullExec = m_pService->exec();
676 if (terminal->isChecked())
678 TDEConfigGroup confGroup( TDEGlobal::config(), TQString::fromLatin1(
"General") );
679 preferredTerminal = confGroup.readPathEntry(
"TerminalApplication", TQString::fromLatin1(
"konsole"));
680 m_command = preferredTerminal;
682 if (preferredTerminal ==
"konsole" && nocloseonexit->isChecked())
683 m_command += TQString::fromLatin1(
" --noclose");
684 m_command += TQString::fromLatin1(
" -e ");
685 m_command += edit->
url();
686 kdDebug(250) <<
"Setting m_command to " << m_command << endl;
688 if ( m_pService && terminal->isChecked() != m_pService->terminal() )
691 bool bRemember = remember && remember->isChecked();
693 if ( !bRemember && m_pService)
699 if (!bRemember && !d->saveNewApps)
702 m_pService =
new KService(initialServiceName, fullExec, TQString::null);
703 if (terminal->isChecked())
705 m_pService->setTerminal(
true);
707 if (preferredTerminal ==
"konsole" && nocloseonexit->isChecked())
708 m_pService->setTerminalOptions(
"--noclose");
723 oldPath = m_pService->desktopEntryPath();
724 newPath = m_pService->locateLocal();
725 menuId = m_pService->menuId();
726 kdDebug(250) <<
"Updating exitsing service " << m_pService->desktopEntryPath() <<
" ( " << newPath <<
" ) " << endl;
730 newPath = KService::newServicePath(
false , serviceName, &menuId);
731 kdDebug(250) <<
"Creating new service " << serviceName <<
" ( " << newPath <<
" ) " << endl;
734 int maxPreference = 1;
735 if (!qServiceType.isEmpty())
737 KServiceTypeProfile::OfferList offerList = KServiceTypeProfile::offers( qServiceType );
738 if (!offerList.isEmpty())
739 maxPreference = offerList.first().preference();
742 KDesktopFile *desktop = 0;
743 if (!oldPath.isEmpty() && (oldPath != newPath))
745 KDesktopFile orig(oldPath,
true);
746 desktop = orig.copyTo(newPath);
750 desktop =
new KDesktopFile(newPath);
752 desktop->writeEntry(
"Type", TQString::fromLatin1(
"Application"));
753 desktop->writeEntry(
"Name", initialServiceName);
754 desktop->writePathEntry(
"Exec", fullExec);
755 if (terminal->isChecked())
757 desktop->writeEntry(
"Terminal",
true);
759 if (preferredTerminal ==
"konsole" && nocloseonexit->isChecked())
760 desktop->writeEntry(
"TerminalOptions",
"--noclose");
764 desktop->writeEntry(
"Terminal",
false);
766 desktop->writeEntry(
"X-TDE-InitialPreference", maxPreference + 1);
769 if (bRemember || d->saveNewApps)
771 TQStringList mimeList = desktop->readListEntry(
"MimeType",
';');
772 if (!qServiceType.isEmpty() && !mimeList.contains(qServiceType))
773 mimeList.append(qServiceType);
774 desktop->writeEntry(
"MimeType", mimeList,
';');
776 if ( !qServiceType.isEmpty() )
779 KDesktopFile mimeDesktop( locateLocal(
"mime", qServiceType +
".desktop" ) );
780 mimeDesktop.writeEntry(
"X-TDE-AutoEmbed",
false );
789 KService::rebuildKSycoca(
this);
791 m_pService = KService::serviceByMenuId( menuId );
793 Q_ASSERT( m_pService );
800 if (!m_command.isEmpty())
809 nocloseonexit->setChecked(
false );
810 nocloseonexit->hide();
821 KHistoryCombo *combo =
static_cast<KHistoryCombo*
>( edit->
comboBox() );
823 combo->addToHistory( edit->
url() );
825 TDEConfig *kc = TDEGlobal::config();
826 TDEConfigGroupSaver ks( kc, TQString::fromLatin1(
"Open-with settings") );
827 kc->writeEntry( TQString::fromLatin1(
"History"), combo->historyItems() );
828 kc->writeEntry(TQString::fromLatin1(
"CompletionMode"),
829 combo->completionMode());
841 #ifndef KDE_NO_COMPAT
844 KOpenWithDlg l( urls, i18n(
"Open with:"), TQString::null, 0L );
847 KService::Ptr service = l.
service();
849 return KRun::run( *service, urls );
851 kdDebug(250) <<
"No service set, running " << l.
text() << endl;
852 return KRun::run( l.
text(), urls );
858 #include "kopenwith.moc"
859 #include "kopenwith_p.moc"
virtual bool displayOpenWithDialog(const KURL::List &urls)
Opens an open-with dialog box for urls.
KOpenWithDlg(const KURL::List &urls, TQWidget *parent=0L)
Create a dialog that asks for a application to open a given URL(s) with.
~KOpenWithDlg()
Destructor.
void hideRunInTerminal()
Hide the "Run in &terminal" Checkbox.
void init(const TQString &text, const TQString &value)
Create a dialog that asks for a application to open a given URL(s) with.
void setServiceType(const KURL::List &_urls)
Determine service type from URLs.
void slotClear()
The slot for clearing the edit widget.
KService::Ptr service() const
virtual void accept()
Reimplemented from TQDialog::accept() to save history of the combobox.
void hideNoCloseOnExit()
Hide the "Do not &close when command exits" Checkbox.
void setSaveNewApplications(bool b)
Set whether a new .desktop file should be created if the user selects an application for which no cor...
This class is a widget showing a lineedit and a button, which invokes a filedialog.
void setURL(const TQString &url)
Sets the url in the lineedit to url.
KComboBox * comboBox() const
KPushButton * button() const
KLineEdit * lineEdit() const