• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KIO

  • kio
  • kfile
kopenwithdialog.cpp
Go to the documentation of this file.
1/* This file is part of the KDE libraries
2
3 Copyright (C) 1997 Torben Weis <weis@stud.uni-frankfurt.de>
4 Copyright (C) 1999 Dirk Mueller <mueller@kde.org>
5 Portions copyright (C) 1999 Preston Brown <pbrown@kde.org>
6 Copyright (C) 2007 Pino Toscano <pino@kde.org>
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22*/
23
24#include "kopenwithdialog.h"
25#include "kopenwithdialog_p.h"
26
27#include <QtCore/QtAlgorithms>
28#include <QtCore/QList>
29#include <QtGui/QLabel>
30#include <QtGui/QLayout>
31#include <QtGui/QCheckBox>
32#include <QtGui/QStyle>
33#include <QtGui/QStyleOptionButton>
34
35#include <kauthorized.h>
36#include <khistorycombobox.h>
37#include <kdesktopfile.h>
38#include <klineedit.h>
39#include <klocale.h>
40#include <kmessagebox.h>
41#include <kshell.h>
42#include <krun.h>
43#include <kstandarddirs.h>
44#include <kstringhandler.h>
45#include <kurlcompletion.h>
46#include <kurlrequester.h>
47#include <kmimetype.h>
48#include <kservicegroup.h>
49#include <kserviceoffer.h>
50#include <kdebug.h>
51
52#include <assert.h>
53#include <stdlib.h>
54#include <kbuildsycocaprogressdialog.h>
55#include <kconfiggroup.h>
56
57inline void writeEntry( KConfigGroup& group, const char* key,
58 const KGlobalSettings::Completion& aValue,
59 KConfigBase::WriteConfigFlags flags = KConfigBase::Normal )
60{
61 group.writeEntry(key, int(aValue), flags);
62}
63
64namespace KDEPrivate {
65
66class AppNode
67{
68public:
69 AppNode()
70 : isDir(false), parent(0), fetched(false)
71 {
72 }
73 ~AppNode()
74 {
75 qDeleteAll(children);
76 }
77
78 QString icon;
79 QString text;
80 QString entryPath;
81 QString exec;
82 bool isDir;
83
84 AppNode *parent;
85 bool fetched;
86
87 QList<AppNode*> children;
88};
89
90bool AppNodeLessThan(KDEPrivate::AppNode *n1, KDEPrivate::AppNode *n2)
91{
92 if (n1->isDir) {
93 if (n2->isDir) {
94 return n1->text.compare(n2->text, Qt::CaseInsensitive) < 0;
95 } else {
96 return true;
97 }
98 } else {
99 if (n2->isDir) {
100 return false;
101 } else {
102 return n1->text.compare(n2->text, Qt::CaseInsensitive) < 0;
103 }
104 }
105 return true;
106}
107
108}
109
110
111class KApplicationModelPrivate
112{
113public:
114 KApplicationModelPrivate(KApplicationModel *qq)
115 : q(qq), root(new KDEPrivate::AppNode())
116 {
117 }
118 ~KApplicationModelPrivate()
119 {
120 delete root;
121 }
122
123 void fillNode(const QString &entryPath, KDEPrivate::AppNode *node);
124
125 KApplicationModel *q;
126
127 KDEPrivate::AppNode *root;
128};
129
130void KApplicationModelPrivate::fillNode(const QString &_entryPath, KDEPrivate::AppNode *node)
131{
132 KServiceGroup::Ptr root = KServiceGroup::group(_entryPath);
133 if (!root || !root->isValid()) return;
134
135 const KServiceGroup::List list = root->entries();
136
137 for( KServiceGroup::List::ConstIterator it = list.begin();
138 it != list.end(); ++it)
139 {
140 QString icon;
141 QString text;
142 QString entryPath;
143 QString exec;
144 bool isDir = false;
145 const KSycocaEntry::Ptr p = (*it);
146 if (p->isType(KST_KService))
147 {
148 const KService::Ptr service = KService::Ptr::staticCast(p);
149
150 if (service->noDisplay())
151 continue;
152
153 icon = service->icon();
154 text = service->name();
155 exec = service->exec();
156 entryPath = service->entryPath();
157 }
158 else if (p->isType(KST_KServiceGroup))
159 {
160 const KServiceGroup::Ptr serviceGroup = KServiceGroup::Ptr::staticCast(p);
161
162 if (serviceGroup->noDisplay() || serviceGroup->childCount() == 0)
163 continue;
164
165 icon = serviceGroup->icon();
166 text = serviceGroup->caption();
167 entryPath = serviceGroup->entryPath();
168 isDir = true;
169 }
170 else
171 {
172 kWarning(250) << "KServiceGroup: Unexpected object in list!";
173 continue;
174 }
175
176 KDEPrivate::AppNode *newnode = new KDEPrivate::AppNode();
177 newnode->icon = icon;
178 newnode->text = text;
179 newnode->entryPath = entryPath;
180 newnode->exec = exec;
181 newnode->isDir = isDir;
182 newnode->parent = node;
183 node->children.append(newnode);
184 }
185 qStableSort(node->children.begin(), node->children.end(), KDEPrivate::AppNodeLessThan);
186}
187
188
189
190KApplicationModel::KApplicationModel(QObject *parent)
191 : QAbstractItemModel(parent), d(new KApplicationModelPrivate(this))
192{
193 d->fillNode(QString(), d->root);
194}
195
196KApplicationModel::~KApplicationModel()
197{
198 delete d;
199}
200
201bool KApplicationModel::canFetchMore(const QModelIndex &parent) const
202{
203 if (!parent.isValid())
204 return false;
205
206 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(parent.internalPointer());
207 return node->isDir && !node->fetched;
208}
209
210int KApplicationModel::columnCount(const QModelIndex &parent) const
211{
212 Q_UNUSED(parent)
213 return 1;
214}
215
216QVariant KApplicationModel::data(const QModelIndex &index, int role) const
217{
218 if (!index.isValid())
219 return QVariant();
220
221 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(index.internalPointer());
222
223 switch (role) {
224 case Qt::DisplayRole:
225 return node->text;
226 break;
227 case Qt::DecorationRole:
228 if (!node->icon.isEmpty()) {
229 return KIcon(node->icon);
230 }
231 break;
232 default:
233 ;
234 }
235 return QVariant();
236}
237
238void KApplicationModel::fetchMore(const QModelIndex &parent)
239{
240 if (!parent.isValid())
241 return;
242
243 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(parent.internalPointer());
244 if (!node->isDir)
245 return;
246
247 emit layoutAboutToBeChanged();
248 d->fillNode(node->entryPath, node);
249 node->fetched = true;
250 emit layoutChanged();
251}
252
253bool KApplicationModel::hasChildren(const QModelIndex &parent) const
254{
255 if (!parent.isValid())
256 return true;
257
258 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(parent.internalPointer());
259 return node->isDir;
260}
261
262QVariant KApplicationModel::headerData(int section, Qt::Orientation orientation, int role) const
263{
264 if (orientation != Qt::Horizontal || section != 0)
265 return QVariant();
266
267 switch (role) {
268 case Qt::DisplayRole:
269 return i18n("Known Applications");
270 break;
271 default:
272 return QVariant();
273 }
274}
275
276QModelIndex KApplicationModel::index(int row, int column, const QModelIndex &parent) const
277{
278 if (row < 0 || column != 0)
279 return QModelIndex();
280
281 KDEPrivate::AppNode *node = d->root;
282 if (parent.isValid())
283 node = static_cast<KDEPrivate::AppNode*>(parent.internalPointer());
284
285 if (row >= node->children.count())
286 return QModelIndex();
287 else
288 return createIndex(row, 0, node->children.at(row));
289}
290
291QModelIndex KApplicationModel::parent(const QModelIndex &index) const
292{
293 if (!index.isValid())
294 return QModelIndex();
295
296 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(index.internalPointer());
297 if (node->parent->parent) {
298 int id = node->parent->parent->children.indexOf(node->parent);
299
300 if (id >= 0 && id < node->parent->parent->children.count())
301 return createIndex(id, 0, node->parent);
302 else
303 return QModelIndex();
304 }
305 else
306 return QModelIndex();
307}
308
309int KApplicationModel::rowCount(const QModelIndex &parent) const
310{
311 if (!parent.isValid())
312 return d->root->children.count();
313
314 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(parent.internalPointer());
315 return node->children.count();
316}
317
318QString KApplicationModel::entryPathFor(const QModelIndex &index) const
319{
320 if (!index.isValid())
321 return QString();
322
323 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(index.internalPointer());
324 return node->entryPath;
325}
326
327QString KApplicationModel::execFor(const QModelIndex &index) const
328{
329 if (!index.isValid())
330 return QString();
331
332 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(index.internalPointer());
333 return node->exec;
334}
335
336bool KApplicationModel::isDirectory(const QModelIndex &index) const
337{
338 if (!index.isValid())
339 return false;
340
341 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(index.internalPointer());
342 return node->isDir;
343}
344
345class KApplicationViewPrivate
346{
347public:
348 KApplicationViewPrivate()
349 : appModel(0)
350 {
351 }
352
353 KApplicationModel *appModel;
354};
355
356KApplicationView::KApplicationView(QWidget *parent)
357 : QTreeView(parent), d(new KApplicationViewPrivate)
358{
359}
360
361KApplicationView::~KApplicationView()
362{
363 delete d;
364}
365
366void KApplicationView::setModel(QAbstractItemModel *model)
367{
368 if (d->appModel) {
369 disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
370 this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection)));
371 }
372
373 QTreeView::setModel(model);
374
375 d->appModel = qobject_cast<KApplicationModel*>(model);
376 if (d->appModel) {
377 connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
378 this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection)));
379 }
380}
381
382bool KApplicationView::isDirSel() const
383{
384 if (d->appModel) {
385 QModelIndex index = selectionModel()->currentIndex();
386 return d->appModel->isDirectory(index);
387 }
388 return false;
389}
390
391void KApplicationView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
392{
393 QTreeView::currentChanged(current, previous);
394
395 if (d->appModel && !d->appModel->isDirectory(current)) {
396 QString exec = d->appModel->execFor(current);
397 if (!exec.isEmpty()) {
398 emit highlighted(d->appModel->entryPathFor(current), exec);
399 }
400 }
401}
402
403void KApplicationView::slotSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
404{
405 Q_UNUSED(deselected)
406
407 const QModelIndexList indexes = selected.indexes();
408 if (indexes.count() == 1 && !d->appModel->isDirectory(indexes.at(0))) {
409 QString exec = d->appModel->execFor(indexes.at(0));
410 if (!exec.isEmpty()) {
411 emit this->selected(d->appModel->entryPathFor(indexes.at(0)), exec);
412 }
413 }
414}
415
416
417
418/***************************************************************
419 *
420 * KOpenWithDialog
421 *
422 ***************************************************************/
423class KOpenWithDialogPrivate
424{
425public:
426 KOpenWithDialogPrivate(KOpenWithDialog *qq)
427 : q(qq), saveNewApps(false)
428 {
429 }
430
431 KOpenWithDialog *q;
432
436 void setMimeType(const KUrl::List &_urls);
437
438 void addToMimeAppsList(const QString& serviceId);
439
447 void init(const QString &text, const QString &value);
448
452 void saveComboboxHistory();
453
458 bool checkAccept();
459
460 // slots
461 void _k_slotDbClick();
462 void _k_slotFileSelected();
463
464 bool saveNewApps;
465 bool m_terminaldirty;
466 KService::Ptr curService;
467 KApplicationView *view;
468 KUrlRequester *edit;
469 QString m_command;
470 QLabel *label;
471 QString qMimeType;
472 QCheckBox *terminal;
473 QCheckBox *remember;
474 QCheckBox *nocloseonexit;
475 KService::Ptr m_pService;
476};
477
478KOpenWithDialog::KOpenWithDialog( const KUrl::List& _urls, QWidget* parent )
479 : KDialog(parent), d(new KOpenWithDialogPrivate(this))
480{
481 setObjectName( QLatin1String( "openwith" ) );
482 setModal( true );
483 setCaption( i18n( "Open With" ) );
484
485 QString text;
486 if( _urls.count() == 1 )
487 {
488 text = i18n("<qt>Select the program that should be used to open <b>%1</b>. "
489 "If the program is not listed, enter the name or click "
490 "the browse button.</qt>", _urls.first().fileName() );
491 }
492 else
493 // Should never happen ??
494 text = i18n( "Choose the name of the program with which to open the selected files." );
495 d->setMimeType(_urls);
496 d->init(text, QString());
497}
498
499KOpenWithDialog::KOpenWithDialog( const KUrl::List& _urls, const QString&_text,
500 const QString& _value, QWidget *parent)
501 : KDialog(parent), d(new KOpenWithDialogPrivate(this))
502{
503 setObjectName( QLatin1String( "openwith" ) );
504 setModal( true );
505 QString caption;
506 if (_urls.count()>0 && !_urls.first().isEmpty())
507 caption = KStringHandler::csqueeze( _urls.first().prettyUrl() );
508 if (_urls.count() > 1)
509 caption += QString::fromLatin1("...");
510 setCaption(caption);
511 d->setMimeType(_urls);
512 d->init(_text, _value);
513}
514
515KOpenWithDialog::KOpenWithDialog( const QString &mimeType, const QString& value,
516 QWidget *parent)
517 : KDialog(parent), d(new KOpenWithDialogPrivate(this))
518{
519 setObjectName( QLatin1String( "openwith" ) );
520 setModal( true );
521 setCaption(i18n("Choose Application for %1", mimeType));
522 QString text = i18n("<qt>Select the program for the file type: <b>%1</b>. "
523 "If the program is not listed, enter the name or click "
524 "the browse button.</qt>", mimeType);
525 d->qMimeType = mimeType;
526 d->init(text, value);
527 if (d->remember) {
528 d->remember->hide();
529 }
530}
531
532KOpenWithDialog::KOpenWithDialog( QWidget *parent)
533 : KDialog(parent), d(new KOpenWithDialogPrivate(this))
534{
535 setObjectName( QLatin1String( "openwith" ) );
536 setModal( true );
537 setCaption(i18n("Choose Application"));
538 QString text = i18n("<qt>Select a program. "
539 "If the program is not listed, enter the name or click "
540 "the browse button.</qt>");
541 d->qMimeType.clear();
542 d->init(text, QString());
543}
544
545void KOpenWithDialogPrivate::setMimeType(const KUrl::List &_urls)
546{
547 if ( _urls.count() == 1 )
548 {
549 qMimeType = KMimeType::findByUrl( _urls.first())->name();
550 if (qMimeType == QLatin1String("application/octet-stream"))
551 qMimeType.clear();
552 }
553 else
554 qMimeType.clear();
555}
556
557void KOpenWithDialogPrivate::init(const QString &_text, const QString &_value)
558{
559 bool bReadOnly = !KAuthorized::authorize("shell_access");
560 m_terminaldirty = false;
561 view = 0;
562 m_pService = 0;
563 curService = 0;
564
565 q->setButtons(KDialog::Ok | KDialog::Cancel);
566
567 QWidget *mainWidget = q->mainWidget();
568
569 QBoxLayout *topLayout = new QVBoxLayout( mainWidget );
570 topLayout->setMargin(0);
571 label = new QLabel(_text, q);
572 label->setWordWrap(true);
573 topLayout->addWidget(label);
574
575 if (!bReadOnly)
576 {
577 // init the history combo and insert it into the URL-Requester
578 KHistoryComboBox *combo = new KHistoryComboBox();
579 KLineEdit *lineEdit = new KLineEdit(q);
580 lineEdit->setClearButtonShown(true);
581 combo->setLineEdit(lineEdit);
582 combo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
583 combo->setDuplicatesEnabled( false );
584 KConfigGroup cg( KGlobal::config(), QString::fromLatin1("Open-with settings") );
585 int max = cg.readEntry( "Maximum history", 15 );
586 combo->setMaxCount( max );
587 int mode = cg.readEntry( "CompletionMode", int(KGlobalSettings::completionMode()));
588 combo->setCompletionMode((KGlobalSettings::Completion)mode);
589 const QStringList list = cg.readEntry( "History", QStringList() );
590 combo->setHistoryItems( list, true );
591 edit = new KUrlRequester( combo, mainWidget );
592 }
593 else
594 {
595 edit = new KUrlRequester( mainWidget );
596 edit->lineEdit()->setReadOnly(true);
597 edit->button()->hide();
598 }
599
600 edit->setText( _value );
601 edit->setWhatsThis(i18n(
602 "Following the command, you can have several place holders which will be replaced "
603 "with the actual values when the actual program is run:\n"
604 "%f - a single file name\n"
605 "%F - a list of files; use for applications that can open several local files at once\n"
606 "%u - a single URL\n"
607 "%U - a list of URLs\n"
608 "%d - the directory of the file to open\n"
609 "%D - a list of directories\n"
610 "%i - the icon\n"
611 "%m - the mini-icon\n"
612 "%c - the comment"));
613
614 topLayout->addWidget(edit);
615
616 if ( edit->comboBox() ) {
617 KUrlCompletion *comp = new KUrlCompletion( KUrlCompletion::ExeCompletion );
618 edit->comboBox()->setCompletionObject( comp );
619 edit->comboBox()->setAutoDeleteCompletionObject( true );
620 }
621
622 QObject::connect(edit, SIGNAL(textChanged(QString)), q, SLOT(slotTextChanged()));
623 QObject::connect(edit, SIGNAL(urlSelected(KUrl)), q, SLOT(_k_slotFileSelected()));
624
625 view = new KApplicationView(mainWidget);
626 view->setModel(new KApplicationModel(view));
627 topLayout->addWidget(view);
628 topLayout->setStretchFactor(view, 1);
629
630 QObject::connect(view, SIGNAL(selected(QString,QString)),
631 q, SLOT(slotSelected(QString,QString)));
632 QObject::connect(view, SIGNAL(highlighted(QString,QString)),
633 q, SLOT(slotHighlighted(QString,QString)));
634 QObject::connect(view, SIGNAL(doubleClicked(QModelIndex)),
635 q, SLOT(_k_slotDbClick()));
636
637 terminal = new QCheckBox( i18n("Run in &terminal"), mainWidget );
638 if (bReadOnly)
639 terminal->hide();
640 QObject::connect(terminal, SIGNAL(toggled(bool)), q, SLOT(slotTerminalToggled(bool)));
641
642 topLayout->addWidget(terminal);
643
644 QStyleOptionButton checkBoxOption;
645 checkBoxOption.initFrom(terminal);
646 int checkBoxIndentation = terminal->style()->pixelMetric( QStyle::PM_IndicatorWidth, &checkBoxOption, terminal );
647 checkBoxIndentation += terminal->style()->pixelMetric( QStyle::PM_CheckBoxLabelSpacing, &checkBoxOption, terminal );
648
649 QBoxLayout* nocloseonexitLayout = new QHBoxLayout();
650 nocloseonexitLayout->setMargin( 0 );
651 QSpacerItem* spacer = new QSpacerItem( checkBoxIndentation, 0, QSizePolicy::Fixed, QSizePolicy::Minimum );
652 nocloseonexitLayout->addItem( spacer );
653
654 nocloseonexit = new QCheckBox( i18n("&Do not close when command exits"), mainWidget );
655 nocloseonexit->setChecked( false );
656 nocloseonexit->setDisabled( true );
657
658 // check to see if we use konsole if not disable the nocloseonexit
659 // because we don't know how to do this on other terminal applications
660 KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") );
661 QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
662
663 if (bReadOnly || preferredTerminal != "konsole")
664 nocloseonexit->hide();
665
666 nocloseonexitLayout->addWidget( nocloseonexit );
667 topLayout->addLayout( nocloseonexitLayout );
668
669 if (!qMimeType.isNull())
670 {
671 remember = new QCheckBox(i18n("&Remember application association for this type of file"), mainWidget);
672 // remember->setChecked(true);
673 topLayout->addWidget(remember);
674 }
675 else
676 remember = 0L;
677
678 q->setMinimumSize(q->minimumSizeHint());
679 //edit->setText( _value );
680 // This is what caused "can't click on items before clicking on Name header".
681 // Probably due to the resizeEvent handler using width().
682 //resize( minimumWidth(), sizeHint().height() );
683 edit->setFocus();
684 q->slotTextChanged();
685}
686
687
688// ----------------------------------------------------------------------
689
690KOpenWithDialog::~KOpenWithDialog()
691{
692 delete d;
693}
694
695
696// ----------------------------------------------------------------------
697
698void KOpenWithDialog::slotSelected( const QString& /*_name*/, const QString& _exec )
699{
700 KService::Ptr pService = d->curService;
701 d->edit->setText(_exec); // calls slotTextChanged :(
702 d->curService = pService;
703}
704
705
706// ----------------------------------------------------------------------
707
708void KOpenWithDialog::slotHighlighted(const QString& entryPath, const QString&)
709{
710 d->curService = KService::serviceByDesktopPath(entryPath);
711 if (d->curService && !d->m_terminaldirty)
712 {
713 // ### indicate that default value was restored
714 d->terminal->setChecked(d->curService->terminal());
715 QString terminalOptions = d->curService->terminalOptions();
716 d->nocloseonexit->setChecked((terminalOptions.contains(QLatin1String("--noclose")) != 0));
717 d->m_terminaldirty = false; // slotTerminalToggled changed it
718 }
719}
720
721// ----------------------------------------------------------------------
722
723void KOpenWithDialog::slotTextChanged()
724{
725 // Forget about the service
726 d->curService = 0L;
727 enableButton(Ok, !d->edit->text().isEmpty());
728}
729
730// ----------------------------------------------------------------------
731
732void KOpenWithDialog::slotTerminalToggled(bool)
733{
734 // ### indicate that default value was overridden
735 d->m_terminaldirty = true;
736 d->nocloseonexit->setDisabled(!d->terminal->isChecked());
737}
738
739// ----------------------------------------------------------------------
740
741void KOpenWithDialogPrivate::_k_slotDbClick()
742{
743 // check if a directory is selected
744 if (view->isDirSel()) {
745 return;
746 }
747 q->accept();
748}
749
750void KOpenWithDialogPrivate::_k_slotFileSelected()
751{
752 // quote the path to avoid unescaped whitespace, backslashes, etc.
753 edit->setText(KShell::quoteArg(edit->text()));
754}
755
756void KOpenWithDialog::setSaveNewApplications(bool b)
757{
758 d->saveNewApps = b;
759}
760
761static QString simplifiedExecLineFromService(const QString& fullExec)
762{
763 QString exec = fullExec;
764 exec.remove("%u", Qt::CaseInsensitive);
765 exec.remove("%f", Qt::CaseInsensitive);
766 exec.remove("-caption %c");
767 exec.remove("-caption \"%c\"");
768 exec.remove("%i");
769 exec.remove("%m");
770 return exec.simplified();
771}
772
773void KOpenWithDialogPrivate::addToMimeAppsList(const QString& serviceId /*menu id or storage id*/)
774{
775 KSharedConfig::Ptr profile = KSharedConfig::openConfig("mimeapps.list", KConfig::NoGlobals, "xdgdata-apps");
776 KConfigGroup addedApps(profile, "Added Associations");
777 QStringList apps = addedApps.readXdgListEntry(qMimeType);
778 apps.removeAll(serviceId);
779 apps.prepend(serviceId); // make it the preferred app
780 addedApps.writeXdgListEntry(qMimeType, apps);
781 addedApps.sync();
782
783 // Also make sure the "auto embed" setting for this mimetype is off
784 KSharedConfig::Ptr fileTypesConfig = KSharedConfig::openConfig("filetypesrc", KConfig::NoGlobals);
785 fileTypesConfig->group("EmbedSettings").writeEntry(QString("embed-")+qMimeType, false);
786 fileTypesConfig->sync();
787
788 kDebug(250) << "rebuilding ksycoca...";
789
790 // kbuildsycoca is the one reading mimeapps.list, so we need to run it now
791 KBuildSycocaProgressDialog::rebuildKSycoca(q);
792
793 m_pService = KService::serviceByStorageId(serviceId);
794 Q_ASSERT( m_pService );
795}
796
797bool KOpenWithDialogPrivate::checkAccept()
798{
799 const QString typedExec(edit->text());
800 if (typedExec.isEmpty())
801 return false;
802 QString fullExec(typedExec);
803
804 QString serviceName;
805 QString initialServiceName;
806 QString preferredTerminal;
807 QString configPath;
808 QString serviceExec;
809 m_pService = curService;
810 if (!m_pService) {
811 // No service selected - check the command line
812
813 // Find out the name of the service from the command line, removing args and paths
814 serviceName = KRun::binaryName( typedExec, true );
815 if (serviceName.isEmpty()) {
816 KMessageBox::error(q, i18n("Could not extract executable name from '%1', please type a valid program name.", serviceName));
817 return false;
818 }
819 initialServiceName = serviceName;
820 // Also remember the binaryName with a path, if any, for the
821 // check that the binary exists.
822 kDebug(250) << "initialServiceName=" << initialServiceName;
823 int i = 1; // We have app, app-2, app-3... Looks better for the user.
824 bool ok = false;
825 // Check if there's already a service by that name, with the same Exec line
826 do {
827 kDebug(250) << "looking for service" << serviceName;
828 KService::Ptr serv = KService::serviceByDesktopName( serviceName );
829 ok = !serv; // ok if no such service yet
830 // also ok if we find the exact same service (well, "kwrite" == "kwrite %U")
831 if (serv && !serv->noDisplay() /* #297720 */) {
832 if (serv->isApplication()) {
833 /*kDebug(250) << "typedExec=" << typedExec
834 << "serv->exec=" << serv->exec()
835 << "simplifiedExecLineFromService=" << simplifiedExecLineFromService(fullExec);*/
836 serviceExec = simplifiedExecLineFromService(serv->exec());
837 if (typedExec == serviceExec){
838 ok = true;
839 m_pService = serv;
840 kDebug(250) << "OK, found identical service: " << serv->entryPath();
841 } else {
842 kDebug(250) << "Exec line differs, service says:" << serviceExec;
843 configPath = serv->entryPath();
844 serviceExec = serv->exec();
845 }
846 } else {
847 kDebug(250) << "Found, but not an application:" << serv->entryPath();
848 }
849 }
850 if (!ok) { // service was found, but it was different -> keep looking
851 ++i;
852 serviceName = initialServiceName + '-' + QString::number(i);
853 }
854 } while (!ok);
855 }
856 if ( m_pService ) {
857 // Existing service selected
858 serviceName = m_pService->name();
859 initialServiceName = serviceName;
860 fullExec = m_pService->exec();
861 } else {
862 const QString binaryName = KRun::binaryName(typedExec, false);
863 kDebug(250) << "binaryName=" << binaryName;
864 // Ensure that the typed binary name actually exists (#81190)
865 if (KStandardDirs::findExe(binaryName).isEmpty()) {
866 KMessageBox::error(q, i18n("'%1' not found, please type a valid program name.", binaryName));
867 return false;
868 }
869 }
870
871 if (terminal->isChecked()) {
872 KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") );
873 preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
874 m_command = preferredTerminal;
875 // only add --noclose when we are sure it is konsole we're using
876 if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
877 m_command += QString::fromLatin1(" --noclose");
878 m_command += QString::fromLatin1(" -e ");
879 m_command += edit->text();
880 kDebug(250) << "Setting m_command to" << m_command;
881 }
882 if ( m_pService && terminal->isChecked() != m_pService->terminal() )
883 m_pService = 0; // It's not exactly this service we're running
884
885
886 const bool bRemember = remember && remember->isChecked();
887 kDebug(250) << "bRemember=" << bRemember << "service found=" << m_pService;
888 if (m_pService) {
889 if (bRemember) {
890 // Associate this app with qMimeType in mimeapps.list
891 Q_ASSERT(!qMimeType.isEmpty()); // we don't show the remember checkbox otherwise
892 addToMimeAppsList(m_pService->storageId());
893 }
894 } else {
895 const bool createDesktopFile = bRemember || saveNewApps;
896 if (!createDesktopFile) {
897 // Create temp service
898 if (configPath.isEmpty())
899 m_pService = new KService(initialServiceName, fullExec, QString());
900 else {
901 if (!typedExec.contains(QLatin1String("%u"), Qt::CaseInsensitive) &&
902 !typedExec.contains(QLatin1String("%f"), Qt::CaseInsensitive)) {
903 int index = serviceExec.indexOf(QLatin1String("%u"), 0, Qt::CaseInsensitive);
904 if (index == -1) {
905 index = serviceExec.indexOf(QLatin1String("%f"), 0, Qt::CaseInsensitive);
906 }
907 if (index > -1) {
908 fullExec += QLatin1Char(' ');
909 fullExec += serviceExec.mid(index, 2);
910 }
911 }
912 kDebug(250) << "Creating service with Exec=" << fullExec;
913 m_pService = new KService(configPath);
914 m_pService->setExec(fullExec);
915 }
916 if (terminal->isChecked()) {
917 m_pService->setTerminal(true);
918 // only add --noclose when we are sure it is konsole we're using
919 if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
920 m_pService->setTerminalOptions("--noclose");
921 }
922 } else {
923 // If we got here, we can't seem to find a service for what they wanted. Create one.
924
925 QString menuId;
926#ifdef Q_WS_WIN32
927 // on windows, do not use the complete path, but only the default name.
928 serviceName = QFileInfo(serviceName).fileName();
929#endif
930 QString newPath = KService::newServicePath(false /* ignored argument */, serviceName, &menuId);
931 kDebug(250) << "Creating new service" << serviceName << "(" << newPath << ")" << "menuId=" << menuId;
932
933 KDesktopFile desktopFile(newPath);
934 KConfigGroup cg = desktopFile.desktopGroup();
935 cg.writeEntry("Type", "Application");
936 cg.writeEntry("Name", initialServiceName);
937 cg.writeEntry("Exec", fullExec);
938 cg.writeEntry("NoDisplay", true); // don't make it appear in the K menu
939 if (terminal->isChecked()) {
940 cg.writeEntry("Terminal", true);
941 // only add --noclose when we are sure it is konsole we're using
942 if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
943 cg.writeEntry("TerminalOptions", "--noclose");
944 }
945 cg.writeXdgListEntry("MimeType", QStringList() << qMimeType);
946 cg.sync();
947
948 addToMimeAppsList(menuId);
949 }
950 }
951
952 saveComboboxHistory();
953 return true;
954}
955
956void KOpenWithDialog::accept()
957{
958 if (d->checkAccept())
959 KDialog::accept();
960}
961
962QString KOpenWithDialog::text() const
963{
964 if (!d->m_command.isEmpty())
965 return d->m_command;
966 else
967 return d->edit->text();
968}
969
970void KOpenWithDialog::hideNoCloseOnExit()
971{
972 // uncheck the checkbox because the value could be used when "Run in Terminal" is selected
973 d->nocloseonexit->setChecked(false);
974 d->nocloseonexit->hide();
975}
976
977void KOpenWithDialog::hideRunInTerminal()
978{
979 d->terminal->hide();
980 hideNoCloseOnExit();
981}
982
983KService::Ptr KOpenWithDialog::service() const
984{
985 return d->m_pService;
986}
987
988void KOpenWithDialogPrivate::saveComboboxHistory()
989{
990 KHistoryComboBox *combo = static_cast<KHistoryComboBox*>(edit->comboBox());
991 if (combo) {
992 combo->addToHistory(edit->text());
993
994 KConfigGroup cg( KGlobal::config(), QString::fromLatin1("Open-with settings") );
995 cg.writeEntry( "History", combo->historyItems() );
996 writeEntry( cg, "CompletionMode", combo->completionMode() );
997 // don't store the completion-list, as it contains all of KUrlCompletion's
998 // executables
999 cg.sync();
1000 }
1001}
1002
1003#include "kopenwithdialog.moc"
1004#include "kopenwithdialog_p.moc"
KApplicationModel
Definition: kopenwithdialog_p.h:33
KApplicationModel::execFor
QString execFor(const QModelIndex &index) const
Definition: kopenwithdialog.cpp:327
KApplicationModel::KApplicationModel
KApplicationModel(QObject *parent=0)
Definition: kopenwithdialog.cpp:190
KApplicationModel::data
virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
Definition: kopenwithdialog.cpp:216
KApplicationModel::parent
virtual QModelIndex parent(const QModelIndex &index) const
Definition: kopenwithdialog.cpp:291
KApplicationModel::rowCount
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const
Definition: kopenwithdialog.cpp:309
KApplicationModel::canFetchMore
virtual bool canFetchMore(const QModelIndex &parent) const
Definition: kopenwithdialog.cpp:201
KApplicationModel::headerData
virtual QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
Definition: kopenwithdialog.cpp:262
KApplicationModel::isDirectory
bool isDirectory(const QModelIndex &index) const
Definition: kopenwithdialog.cpp:336
KApplicationModel::~KApplicationModel
virtual ~KApplicationModel()
Definition: kopenwithdialog.cpp:196
KApplicationModel::index
virtual QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
Definition: kopenwithdialog.cpp:276
KApplicationModel::entryPathFor
QString entryPathFor(const QModelIndex &index) const
Definition: kopenwithdialog.cpp:318
KApplicationModel::columnCount
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const
Definition: kopenwithdialog.cpp:210
KApplicationModel::hasChildren
virtual bool hasChildren(const QModelIndex &parent=QModelIndex()) const
Definition: kopenwithdialog.cpp:253
KApplicationModel::fetchMore
virtual void fetchMore(const QModelIndex &parent)
Definition: kopenwithdialog.cpp:238
KApplicationView
Definition: kopenwithdialog_p.h:67
KApplicationView::setModel
virtual void setModel(QAbstractItemModel *model)
Definition: kopenwithdialog.cpp:366
KApplicationView::selected
void selected(const QString &_name, const QString &_exec)
KApplicationView::currentChanged
virtual void currentChanged(const QModelIndex &current, const QModelIndex &previous)
Definition: kopenwithdialog.cpp:391
KApplicationView::isDirSel
bool isDirSel() const
Definition: kopenwithdialog.cpp:382
KApplicationView::~KApplicationView
~KApplicationView()
Definition: kopenwithdialog.cpp:361
KApplicationView::highlighted
void highlighted(const QString &_name, const QString &_exec)
KApplicationView::KApplicationView
KApplicationView(QWidget *parent=0)
Definition: kopenwithdialog.cpp:356
KBuildSycocaProgressDialog::rebuildKSycoca
static void rebuildKSycoca(QWidget *parent)
Rebuild KSycoca and show a progress dialog while doing so.
Definition: kbuildsycocaprogressdialog.cpp:41
KComboBox::setLineEdit
virtual void setLineEdit(QLineEdit *)
KCompletionBase::completionMode
KGlobalSettings::Completion completionMode() const
KCompletionBase::setCompletionMode
virtual void setCompletionMode(KGlobalSettings::Completion mode)
KConfigBase::Normal
Normal
KConfigGroup
KConfigGroup::writeEntry
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
KConfigGroup::sync
void sync()
KConfigGroup::writeXdgListEntry
void writeXdgListEntry(const char *pKey, const QStringList &value, WriteConfigFlags pFlags=Normal)
KConfig::NoGlobals
NoGlobals
KDesktopFile
KDialog
KDialog::enableButton
void enableButton(ButtonCode id, bool state)
KDialog::Ok
Ok
KDialog::Cancel
Cancel
KDialog::setCaption
virtual void setCaption(const QString &caption)
KGlobalSettings::completionMode
static Completion completionMode()
KGlobalSettings::Completion
Completion
KHistoryComboBox
KHistoryComboBox::addToHistory
void addToHistory(const QString &item)
KHistoryComboBox::historyItems
QStringList historyItems
KHistoryComboBox::setHistoryItems
void setHistoryItems(const QStringList &items)
KIcon
KLineEdit
KLineEdit::setClearButtonShown
void setClearButtonShown(bool show)
KMessageBox::error
static void error(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Notify)
KMimeType::findByUrl
static Ptr findByUrl(const KUrl &url, mode_t mode=0, bool is_local_file=false, bool fast_mode=false, int *accuracy=0)
KOpenWithDialog
"Open With" dialog box.
Definition: kopenwithdialog.h:40
KOpenWithDialog::slotTerminalToggled
void slotTerminalToggled(bool)
Definition: kopenwithdialog.cpp:732
KOpenWithDialog::slotSelected
void slotSelected(const QString &_name, const QString &_exec)
Definition: kopenwithdialog.cpp:698
KOpenWithDialog::service
KService::Ptr service() const
Definition: kopenwithdialog.cpp:983
KOpenWithDialog::text
QString text() const
Definition: kopenwithdialog.cpp:962
KOpenWithDialog::setSaveNewApplications
void setSaveNewApplications(bool b)
Set whether a new .desktop file should be created if the user selects an application for which no cor...
Definition: kopenwithdialog.cpp:756
KOpenWithDialog::slotTextChanged
void slotTextChanged()
Definition: kopenwithdialog.cpp:723
KOpenWithDialog::hideRunInTerminal
void hideRunInTerminal()
Hide the "Run in &terminal" Checkbox.
Definition: kopenwithdialog.cpp:977
KOpenWithDialog::KOpenWithDialog
KOpenWithDialog(const KUrl::List &urls, QWidget *parent=0)
Create a dialog that asks for a application to open a given URL(s) with.
Definition: kopenwithdialog.cpp:478
KOpenWithDialog::~KOpenWithDialog
~KOpenWithDialog()
Destructor.
Definition: kopenwithdialog.cpp:690
KOpenWithDialog::slotHighlighted
void slotHighlighted(const QString &_name, const QString &_exec)
Definition: kopenwithdialog.cpp:708
KOpenWithDialog::accept
virtual void accept()
Reimplemented from QDialog::accept()
Definition: kopenwithdialog.cpp:956
KOpenWithDialog::hideNoCloseOnExit
void hideNoCloseOnExit()
Hide the "Do not &close when command exits" Checkbox.
Definition: kopenwithdialog.cpp:970
KRun::binaryName
static QString binaryName(const QString &execLine, bool removePath)
Given a full command line (e.g.
Definition: krun.cpp:568
KServiceGroup::group
static Ptr group(const QString &relPath)
KService
KService::serviceByStorageId
static Ptr serviceByStorageId(const QString &_storageId)
KService::serviceByDesktopName
static Ptr serviceByDesktopName(const QString &_name)
KService::newServicePath
static QString newServicePath(bool showInMenu, const QString &suggestedName, QString *menuId=0, const QStringList *reservedMenuIds=0)
KService::serviceByDesktopPath
static Ptr serviceByDesktopPath(const QString &_path)
KSharedConfig::openConfig
static KSharedConfig::Ptr openConfig(const KComponentData &componentData, const QString &fileName=QString(), OpenFlags mode=FullConfig, const char *resourceType="config")
KSharedPtr
KSharedPtr::clear
void clear()
KSharedPtr< KService >::staticCast
static KSharedPtr< T > staticCast(const KSharedPtr< U > &o)
KStandardDirs::findExe
static QString findExe(const QString &appname, const QString &pathstr=QString(), SearchOptions options=NoSearchOptions)
KUrlCompletion
This class does completion of URLs including user directories (~user) and environment variables.
Definition: kurlcompletion.h:42
KUrlCompletion::ExeCompletion
@ ExeCompletion
Definition: kurlcompletion.h:53
KUrlRequester
This class is a widget showing a lineedit and a button, which invokes a filedialog.
Definition: kurlrequester.h:61
KUrl::List
KUrl
QAbstractItemModel
QLabel
QList
QObject
QTreeView
QWidget
kDebug
#define kDebug
kWarning
#define kWarning
kauthorized.h
kbuildsycocaprogressdialog.h
kconfiggroup.h
kdebug.h
kdesktopfile.h
khistorycombobox.h
klineedit.h
klocale.h
i18n
QString i18n(const char *text)
kmessagebox.h
kmimetype.h
writeEntry
void writeEntry(KConfigGroup &group, const char *key, const KGlobalSettings::Completion &aValue, KConfigBase::WriteConfigFlags flags=KConfigBase::Normal)
Definition: kopenwithdialog.cpp:57
simplifiedExecLineFromService
static QString simplifiedExecLineFromService(const QString &fullExec)
Definition: kopenwithdialog.cpp:761
kopenwithdialog.h
kopenwithdialog_p.h
krun.h
kservicegroup.h
kserviceoffer.h
kshell.h
kstandarddirs.h
kstringhandler.h
kurlcompletion.h
kurlrequester.h
KAuthorized::authorize
bool authorize(const QString &genericAction)
KDEPrivate
KDEPrivate::AppNodeLessThan
bool AppNodeLessThan(KDEPrivate::AppNode *n1, KDEPrivate::AppNode *n2)
Definition: kopenwithdialog.cpp:90
caption
QString caption()
KGlobal::config
KSharedConfigPtr config()
group
group
KRecentDirs::list
QStringList list(const QString &fileClass)
Returns a list of directories associated with this file-class.
Definition: krecentdirs.cpp:60
KShell::quoteArg
QString quoteArg(const QString &arg)
ok
KGuiItem ok()
label
QString label(StandardShortcut id)
KStringHandler::csqueeze
QString csqueeze(const QString &str, int maxlen=40)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal