00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "kopenwithdialog.h"
00025 #include "kopenwithdialog_p.h"
00026
00027 #include <QtCore/QtAlgorithms>
00028 #include <QtCore/QList>
00029 #include <QtGui/QLabel>
00030 #include <QtGui/QLayout>
00031 #include <QtGui/QCheckBox>
00032 #include <QtGui/QStyle>
00033 #include <QtGui/QStyleOptionButton>
00034
00035 #include <kauthorized.h>
00036 #include <khistorycombobox.h>
00037 #include <kdesktopfile.h>
00038 #include <klineedit.h>
00039 #include <klocale.h>
00040 #include <kiconloader.h>
00041 #include <kmessagebox.h>
00042 #include <krun.h>
00043 #include <kstandarddirs.h>
00044 #include <kstringhandler.h>
00045 #include <kurlcompletion.h>
00046 #include <kurlrequester.h>
00047 #include <kmimetype.h>
00048 #include <kservicegroup.h>
00049 #include <kserviceoffer.h>
00050 #include <kdebug.h>
00051
00052 #include <assert.h>
00053 #include <stdlib.h>
00054 #include <kbuildsycocaprogressdialog.h>
00055 #include <kconfiggroup.h>
00056
00057 inline void writeEntry( KConfigGroup& group, const char* key,
00058 const KGlobalSettings::Completion& aValue,
00059 KConfigBase::WriteConfigFlags flags = KConfigBase::Normal )
00060 {
00061 group.writeEntry(key, int(aValue), flags);
00062 }
00063
00064 namespace KDEPrivate {
00065
00066 class AppNode
00067 {
00068 public:
00069 AppNode()
00070 : isDir(false), parent(0), fetched(false)
00071 {
00072 }
00073 ~AppNode()
00074 {
00075 qDeleteAll(children);
00076 }
00077
00078 QString icon;
00079 QString text;
00080 QString entryPath;
00081 QString exec;
00082 bool isDir;
00083
00084 AppNode *parent;
00085 bool fetched;
00086
00087 QList<AppNode*> children;
00088 };
00089
00090 bool AppNodeLessThan(KDEPrivate::AppNode *n1, KDEPrivate::AppNode *n2)
00091 {
00092 if (n1->isDir) {
00093 if (n2->isDir) {
00094 return n1->text.compare(n2->text, Qt::CaseInsensitive) < 0;
00095 } else {
00096 return true;
00097 }
00098 } else {
00099 if (n2->isDir) {
00100 return false;
00101 } else {
00102 return n1->text.compare(n2->text, Qt::CaseInsensitive) < 0;
00103 }
00104 }
00105 return true;
00106 }
00107
00108 }
00109
00110
00111 class KApplicationModelPrivate
00112 {
00113 public:
00114 KApplicationModelPrivate(KApplicationModel *qq)
00115 : q(qq), root(new KDEPrivate::AppNode())
00116 {
00117 }
00118 ~KApplicationModelPrivate()
00119 {
00120 delete root;
00121 }
00122
00123 void fillNode(const QString &entryPath, KDEPrivate::AppNode *node);
00124
00125 KApplicationModel *q;
00126
00127 KDEPrivate::AppNode *root;
00128 };
00129
00130 void KApplicationModelPrivate::fillNode(const QString &_entryPath, KDEPrivate::AppNode *node)
00131 {
00132 KServiceGroup::Ptr root = KServiceGroup::group(_entryPath);
00133 if (!root || !root->isValid()) return;
00134
00135 const KServiceGroup::List list = root->entries();
00136
00137 for( KServiceGroup::List::ConstIterator it = list.begin();
00138 it != list.end(); ++it)
00139 {
00140 QString icon;
00141 QString text;
00142 QString entryPath;
00143 QString exec;
00144 bool isDir = false;
00145 const KSycocaEntry::Ptr p = (*it);
00146 if (p->isType(KST_KService))
00147 {
00148 const KService::Ptr service = KService::Ptr::staticCast(p);
00149
00150 if (service->noDisplay())
00151 continue;
00152
00153 icon = service->icon();
00154 text = service->name();
00155 exec = service->exec();
00156 entryPath = service->entryPath();
00157 }
00158 else if (p->isType(KST_KServiceGroup))
00159 {
00160 const KServiceGroup::Ptr serviceGroup = KServiceGroup::Ptr::staticCast(p);
00161
00162 if (serviceGroup->noDisplay() || serviceGroup->childCount() == 0)
00163 continue;
00164
00165 icon = serviceGroup->icon();
00166 text = serviceGroup->caption();
00167 entryPath = serviceGroup->entryPath();
00168 isDir = true;
00169 }
00170 else
00171 {
00172 kWarning(250) << "KServiceGroup: Unexpected object in list!";
00173 continue;
00174 }
00175
00176 KDEPrivate::AppNode *newnode = new KDEPrivate::AppNode();
00177 newnode->icon = icon;
00178 newnode->text = text;
00179 newnode->entryPath = entryPath;
00180 newnode->exec = exec;
00181 newnode->isDir = isDir;
00182 newnode->parent = node;
00183 node->children.append(newnode);
00184 }
00185 qStableSort(node->children.begin(), node->children.end(), KDEPrivate::AppNodeLessThan);
00186 }
00187
00188
00189
00190 KApplicationModel::KApplicationModel(QObject *parent)
00191 : QAbstractItemModel(parent), d(new KApplicationModelPrivate(this))
00192 {
00193 d->fillNode(QString(), d->root);
00194 }
00195
00196 KApplicationModel::~KApplicationModel()
00197 {
00198 delete d;
00199 }
00200
00201 bool KApplicationModel::canFetchMore(const QModelIndex &parent) const
00202 {
00203 if (!parent.isValid())
00204 return false;
00205
00206 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(parent.internalPointer());
00207 return node->isDir && !node->fetched;
00208 }
00209
00210 int KApplicationModel::columnCount(const QModelIndex &parent) const
00211 {
00212 Q_UNUSED(parent)
00213 return 1;
00214 }
00215
00216 QVariant KApplicationModel::data(const QModelIndex &index, int role) const
00217 {
00218 if (!index.isValid())
00219 return QVariant();
00220
00221 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(index.internalPointer());
00222
00223 switch (role) {
00224 case Qt::DisplayRole:
00225 return node->text;
00226 break;
00227 case Qt::DecorationRole:
00228 if (!node->icon.isEmpty()) {
00229 return KIcon(node->icon);
00230 }
00231 break;
00232 default:
00233 ;
00234 }
00235 return QVariant();
00236 }
00237
00238 void KApplicationModel::fetchMore(const QModelIndex &parent)
00239 {
00240 if (!parent.isValid())
00241 return;
00242
00243 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(parent.internalPointer());
00244 if (!node->isDir)
00245 return;
00246
00247 emit layoutAboutToBeChanged();
00248 d->fillNode(node->entryPath, node);
00249 node->fetched = true;
00250 emit layoutChanged();
00251 }
00252
00253 bool KApplicationModel::hasChildren(const QModelIndex &parent) const
00254 {
00255 if (!parent.isValid())
00256 return true;
00257
00258 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(parent.internalPointer());
00259 return node->isDir;
00260 }
00261
00262 QVariant KApplicationModel::headerData(int section, Qt::Orientation orientation, int role) const
00263 {
00264 if (orientation != Qt::Horizontal || section != 0)
00265 return QVariant();
00266
00267 switch (role) {
00268 case Qt::DisplayRole:
00269 return i18n("Known Applications");
00270 break;
00271 default:
00272 return QVariant();
00273 }
00274 }
00275
00276 QModelIndex KApplicationModel::index(int row, int column, const QModelIndex &parent) const
00277 {
00278 if (row < 0 || column != 0)
00279 return QModelIndex();
00280
00281 KDEPrivate::AppNode *node = d->root;
00282 if (parent.isValid())
00283 node = static_cast<KDEPrivate::AppNode*>(parent.internalPointer());
00284
00285 if (row >= node->children.count())
00286 return QModelIndex();
00287 else
00288 return createIndex(row, 0, node->children.at(row));
00289 }
00290
00291 QModelIndex KApplicationModel::parent(const QModelIndex &index) const
00292 {
00293 if (!index.isValid())
00294 return QModelIndex();
00295
00296 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(index.internalPointer());
00297 if (node->parent->parent) {
00298 int id = node->parent->parent->children.indexOf(node->parent);
00299
00300 if (id >= 0 && id < node->parent->parent->children.count())
00301 return createIndex(id, 0, node->parent);
00302 else
00303 return QModelIndex();
00304 }
00305 else
00306 return QModelIndex();
00307 }
00308
00309 int KApplicationModel::rowCount(const QModelIndex &parent) const
00310 {
00311 if (!parent.isValid())
00312 return d->root->children.count();
00313
00314 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(parent.internalPointer());
00315 return node->children.count();
00316 }
00317
00318 QString KApplicationModel::entryPathFor(const QModelIndex &index) const
00319 {
00320 if (!index.isValid())
00321 return QString();
00322
00323 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(index.internalPointer());
00324 return node->entryPath;
00325 }
00326
00327 QString KApplicationModel::execFor(const QModelIndex &index) const
00328 {
00329 if (!index.isValid())
00330 return QString();
00331
00332 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(index.internalPointer());
00333 return node->exec;
00334 }
00335
00336 bool KApplicationModel::isDirectory(const QModelIndex &index) const
00337 {
00338 if (!index.isValid())
00339 return false;
00340
00341 KDEPrivate::AppNode *node = static_cast<KDEPrivate::AppNode*>(index.internalPointer());
00342 return node->isDir;
00343 }
00344
00345 class KApplicationViewPrivate
00346 {
00347 public:
00348 KApplicationViewPrivate()
00349 : appModel(0)
00350 {
00351 }
00352
00353 KApplicationModel *appModel;
00354 };
00355
00356 KApplicationView::KApplicationView(QWidget *parent)
00357 : QTreeView(parent), d(new KApplicationViewPrivate)
00358 {
00359 }
00360
00361 KApplicationView::~KApplicationView()
00362 {
00363 delete d;
00364 }
00365
00366 void KApplicationView::setModel(QAbstractItemModel *model)
00367 {
00368 if (d->appModel) {
00369 disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
00370 this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection)));
00371 }
00372
00373 QTreeView::setModel(model);
00374
00375 d->appModel = qobject_cast<KApplicationModel*>(model);
00376 if (d->appModel) {
00377 connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
00378 this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection)));
00379 }
00380 }
00381
00382 bool KApplicationView::isDirSel() const
00383 {
00384 if (d->appModel) {
00385 QModelIndex index = selectionModel()->currentIndex();
00386 return d->appModel->isDirectory(index);
00387 }
00388 return false;
00389 }
00390
00391 void KApplicationView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous)
00392 {
00393 QTreeView::currentChanged(current, previous);
00394
00395 if (d->appModel && !d->appModel->isDirectory(current)) {
00396 QString exec = d->appModel->execFor(current);
00397 if (!exec.isEmpty()) {
00398 emit highlighted(d->appModel->entryPathFor(current), exec);
00399 }
00400 }
00401 }
00402
00403 void KApplicationView::slotSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
00404 {
00405 Q_UNUSED(deselected)
00406
00407 QModelIndexList indexes = selected.indexes();
00408 if (indexes.count() == 1 && !d->appModel->isDirectory(indexes.at(0))) {
00409 QString exec = d->appModel->execFor(indexes.at(0));
00410 if (!exec.isEmpty()) {
00411 emit this->selected(d->appModel->entryPathFor(indexes.at(0)), exec);
00412 }
00413 }
00414 }
00415
00416
00417
00418
00419
00420
00421
00422
00423 class KOpenWithDialogPrivate
00424 {
00425 public:
00426 KOpenWithDialogPrivate(KOpenWithDialog *qq)
00427 : q(qq), saveNewApps(false)
00428 {
00429 }
00430
00431 KOpenWithDialog *q;
00432
00436 void setMimeType(const KUrl::List &_urls);
00437
00438 void addToMimeAppsList(const QString& serviceId);
00439
00447 void init(const QString &text, const QString &value);
00448
00452 void saveComboboxHistory();
00453
00458 bool checkAccept();
00459
00460
00461 void _k_slotDbClick();
00462
00463 bool saveNewApps;
00464 bool m_terminaldirty;
00465 KService::Ptr curService;
00466 KApplicationView *view;
00467 KUrlRequester *edit;
00468 QString m_command;
00469 QLabel *label;
00470 QString qMimeType;
00471 QCheckBox *terminal;
00472 QCheckBox *remember;
00473 QCheckBox *nocloseonexit;
00474 KService::Ptr m_pService;
00475 };
00476
00477 KOpenWithDialog::KOpenWithDialog( const KUrl::List& _urls, QWidget* parent )
00478 : KDialog(parent), d(new KOpenWithDialogPrivate(this))
00479 {
00480 setObjectName( QLatin1String( "openwith" ) );
00481 setModal( true );
00482 setCaption( i18n( "Open With" ) );
00483
00484 QString text;
00485 if( _urls.count() == 1 )
00486 {
00487 text = i18n("<qt>Select the program that should be used to open <b>%1</b>. "
00488 "If the program is not listed, enter the name or click "
00489 "the browse button.</qt>", _urls.first().fileName() );
00490 }
00491 else
00492
00493 text = i18n( "Choose the name of the program with which to open the selected files." );
00494 d->setMimeType(_urls);
00495 d->init(text, QString());
00496 }
00497
00498 KOpenWithDialog::KOpenWithDialog( const KUrl::List& _urls, const QString&_text,
00499 const QString& _value, QWidget *parent)
00500 : KDialog(parent), d(new KOpenWithDialogPrivate(this))
00501 {
00502 setObjectName( QLatin1String( "openwith" ) );
00503 setModal( true );
00504 QString caption;
00505 if (_urls.count()>0 && !_urls.first().isEmpty())
00506 caption = KStringHandler::csqueeze( _urls.first().prettyUrl() );
00507 if (_urls.count() > 1)
00508 caption += QString::fromLatin1("...");
00509 setCaption(caption);
00510 d->setMimeType(_urls);
00511 d->init(_text, _value);
00512 }
00513
00514 KOpenWithDialog::KOpenWithDialog( const QString &mimeType, const QString& value,
00515 QWidget *parent)
00516 : KDialog(parent), d(new KOpenWithDialogPrivate(this))
00517 {
00518 setObjectName( QLatin1String( "openwith" ) );
00519 setModal( true );
00520 setCaption(i18n("Choose Application for %1", mimeType));
00521 QString text = i18n("<qt>Select the program for the file type: <b>%1</b>. "
00522 "If the program is not listed, enter the name or click "
00523 "the browse button.</qt>", mimeType);
00524 d->qMimeType = mimeType;
00525 d->init(text, value);
00526 if (d->remember) {
00527 d->remember->hide();
00528 }
00529 }
00530
00531 KOpenWithDialog::KOpenWithDialog( QWidget *parent)
00532 : KDialog(parent), d(new KOpenWithDialogPrivate(this))
00533 {
00534 setObjectName( QLatin1String( "openwith" ) );
00535 setModal( true );
00536 setCaption(i18n("Choose Application"));
00537 QString text = i18n("<qt>Select a program. "
00538 "If the program is not listed, enter the name or click "
00539 "the browse button.</qt>");
00540 d->qMimeType.clear();
00541 d->init(text, QString());
00542 }
00543
00544 void KOpenWithDialogPrivate::setMimeType(const KUrl::List &_urls)
00545 {
00546 if ( _urls.count() == 1 )
00547 {
00548 qMimeType = KMimeType::findByUrl( _urls.first())->name();
00549 if (qMimeType == QLatin1String("application/octet-stream"))
00550 qMimeType.clear();
00551 }
00552 else
00553 qMimeType.clear();
00554 }
00555
00556 void KOpenWithDialogPrivate::init(const QString &_text, const QString &_value)
00557 {
00558 bool bReadOnly = !KAuthorized::authorize("shell_access");
00559 m_terminaldirty = false;
00560 view = 0;
00561 m_pService = 0;
00562 curService = 0;
00563
00564 q->setButtons(KDialog::Ok | KDialog::Cancel);
00565
00566 QWidget *mainWidget = q->mainWidget();
00567
00568 QBoxLayout *topLayout = new QVBoxLayout( mainWidget );
00569 topLayout->setMargin(0);
00570 label = new QLabel(_text, q);
00571 label->setWordWrap(true);
00572 label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
00573 topLayout->addWidget(label);
00574
00575 if (!bReadOnly)
00576 {
00577
00578 KHistoryComboBox *combo = new KHistoryComboBox();
00579 KLineEdit *lineEdit = new KLineEdit(q);
00580 lineEdit->setClearButtonShown(true);
00581 combo->setLineEdit(lineEdit);
00582 combo->setDuplicatesEnabled( false );
00583 KConfigGroup cg( KGlobal::config(), QString::fromLatin1("Open-with settings") );
00584 int max = cg.readEntry( "Maximum history", 15 );
00585 combo->setMaxCount( max );
00586 int mode = cg.readEntry( "CompletionMode", int(KGlobalSettings::completionMode()));
00587 combo->setCompletionMode((KGlobalSettings::Completion)mode);
00588 QStringList list = cg.readEntry( "History", QStringList() );
00589 combo->setHistoryItems( list, true );
00590 edit = new KUrlRequester( combo, mainWidget );
00591 }
00592 else
00593 {
00594 edit = new KUrlRequester( mainWidget );
00595 edit->lineEdit()->setReadOnly(true);
00596 edit->button()->hide();
00597 }
00598
00599 edit->setText( _value );
00600 edit->setWhatsThis(i18n(
00601 "Following the command, you can have several place holders which will be replaced "
00602 "with the actual values when the actual program is run:\n"
00603 "%f - a single file name\n"
00604 "%F - a list of files; use for applications that can open several local files at once\n"
00605 "%u - a single URL\n"
00606 "%U - a list of URLs\n"
00607 "%d - the directory of the file to open\n"
00608 "%D - a list of directories\n"
00609 "%i - the icon\n"
00610 "%m - the mini-icon\n"
00611 "%c - the comment"));
00612
00613 topLayout->addWidget(edit);
00614
00615 if ( edit->comboBox() ) {
00616 KUrlCompletion *comp = new KUrlCompletion( KUrlCompletion::ExeCompletion );
00617 edit->comboBox()->setCompletionObject( comp );
00618 edit->comboBox()->setAutoDeleteCompletionObject( true );
00619 }
00620
00621 QObject::connect(edit, SIGNAL(textChanged(QString)), q, SLOT(slotTextChanged()));
00622
00623 view = new KApplicationView(mainWidget);
00624 view->setModel(new KApplicationModel(view));
00625 topLayout->addWidget(view);
00626 topLayout->setStretchFactor(view, 1);
00627
00628 QObject::connect(view, SIGNAL(selected(QString, QString)),
00629 q, SLOT(slotSelected(QString, QString)));
00630 QObject::connect(view, SIGNAL(highlighted(QString, QString)),
00631 q, SLOT(slotHighlighted(QString, QString)));
00632 QObject::connect(view, SIGNAL(doubleClicked(QModelIndex)),
00633 q, SLOT(_k_slotDbClick()));
00634
00635 terminal = new QCheckBox( i18n("Run in &terminal"), mainWidget );
00636 if (bReadOnly)
00637 terminal->hide();
00638 QObject::connect(terminal, SIGNAL(toggled(bool)), q, SLOT(slotTerminalToggled(bool)));
00639
00640 topLayout->addWidget(terminal);
00641
00642 QStyleOptionButton checkBoxOption;
00643 checkBoxOption.initFrom(terminal);
00644 int checkBoxIndentation = terminal->style()->pixelMetric( QStyle::PM_IndicatorWidth, &checkBoxOption, terminal );
00645 checkBoxIndentation += terminal->style()->pixelMetric( QStyle::PM_CheckBoxLabelSpacing, &checkBoxOption, terminal );
00646
00647 QBoxLayout* nocloseonexitLayout = new QHBoxLayout();
00648 nocloseonexitLayout->setMargin( 0 );
00649 QSpacerItem* spacer = new QSpacerItem( checkBoxIndentation, 0, QSizePolicy::Fixed, QSizePolicy::Minimum );
00650 nocloseonexitLayout->addItem( spacer );
00651
00652 nocloseonexit = new QCheckBox( i18n("&Do not close when command exits"), mainWidget );
00653 nocloseonexit->setChecked( false );
00654 nocloseonexit->setDisabled( true );
00655
00656
00657
00658 KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") );
00659 QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
00660
00661 if (bReadOnly || preferredTerminal != "konsole")
00662 nocloseonexit->hide();
00663
00664 nocloseonexitLayout->addWidget( nocloseonexit );
00665 topLayout->addLayout( nocloseonexitLayout );
00666
00667 if (!qMimeType.isNull())
00668 {
00669 remember = new QCheckBox(i18n("&Remember application association for this type of file"), mainWidget);
00670
00671 topLayout->addWidget(remember);
00672 }
00673 else
00674 remember = 0L;
00675
00676
00677
00678
00679
00680 edit->setFocus();
00681 q->slotTextChanged();
00682 }
00683
00684
00685
00686
00687 KOpenWithDialog::~KOpenWithDialog()
00688 {
00689 delete d;
00690 }
00691
00692
00693
00694
00695 void KOpenWithDialog::slotSelected( const QString& , const QString& _exec )
00696 {
00697 KService::Ptr pService = d->curService;
00698 d->edit->setText(_exec);
00699 d->curService = pService;
00700 }
00701
00702
00703
00704
00705 void KOpenWithDialog::slotHighlighted(const QString& entryPath, const QString&)
00706 {
00707 d->curService = KService::serviceByDesktopPath(entryPath);
00708 if (!d->m_terminaldirty)
00709 {
00710
00711 d->terminal->setChecked(d->curService->terminal());
00712 QString terminalOptions = d->curService->terminalOptions();
00713 d->nocloseonexit->setChecked((terminalOptions.contains(QLatin1String("--noclose")) > 0));
00714 d->m_terminaldirty = false;
00715 }
00716 }
00717
00718
00719
00720 void KOpenWithDialog::slotTextChanged()
00721 {
00722
00723 d->curService = 0L;
00724 enableButton(Ok, !d->edit->text().isEmpty());
00725 }
00726
00727
00728
00729 void KOpenWithDialog::slotTerminalToggled(bool)
00730 {
00731
00732 d->m_terminaldirty = true;
00733 d->nocloseonexit->setDisabled(!d->terminal->isChecked());
00734 }
00735
00736
00737
00738 void KOpenWithDialogPrivate::_k_slotDbClick()
00739 {
00740
00741 if (view->isDirSel()) {
00742 return;
00743 }
00744 q->accept();
00745 }
00746
00747 void KOpenWithDialog::setSaveNewApplications(bool b)
00748 {
00749 d->saveNewApps = b;
00750 }
00751
00752 static QString simplifiedExecLineFromService(const QString& fullExec)
00753 {
00754 QString exec = fullExec;
00755 exec.remove("%u", Qt::CaseInsensitive);
00756 exec.remove("%f", Qt::CaseInsensitive);
00757 exec.remove("-caption %c");
00758 exec.remove("-caption \"%c\"");
00759 exec.remove("%i");
00760 exec.remove("%m");
00761 return exec.simplified();
00762 }
00763
00764 void KOpenWithDialogPrivate::addToMimeAppsList(const QString& serviceId )
00765 {
00766 KSharedConfig::Ptr profile = KSharedConfig::openConfig("mimeapps.list", KConfig::NoGlobals, "xdgdata-apps");
00767 KConfigGroup addedApps(profile, "Added Associations");
00768 QStringList apps = addedApps.readXdgListEntry(qMimeType);
00769 apps.removeAll(serviceId);
00770 apps.prepend(serviceId);
00771 addedApps.writeXdgListEntry(qMimeType, apps);
00772 addedApps.sync();
00773
00774
00775 KSharedConfig::Ptr fileTypesConfig = KSharedConfig::openConfig("filetypesrc", KConfig::NoGlobals);
00776 fileTypesConfig->group("EmbedSettings").writeEntry(QString("embed-")+qMimeType, false);
00777 fileTypesConfig->sync();
00778
00779 kDebug(250) << "rebuilding ksycoca...";
00780
00781
00782 KBuildSycocaProgressDialog::rebuildKSycoca(q);
00783
00784 m_pService = KService::serviceByStorageId(serviceId);
00785 Q_ASSERT( m_pService );
00786 }
00787
00788 bool KOpenWithDialogPrivate::checkAccept()
00789 {
00790 const QString typedExec(edit->text());
00791 if (typedExec.isEmpty())
00792 return false;
00793 QString fullExec(typedExec);
00794
00795 QString serviceName;
00796 QString initialServiceName;
00797 QString preferredTerminal;
00798 QString binaryName;
00799 m_pService = curService;
00800 if (!m_pService) {
00801
00802
00803
00804 serviceName = KRun::binaryName( typedExec, true );
00805 if (serviceName.isEmpty()) {
00806 KMessageBox::error(q, i18n("Could not extract executable name from '%1', please type a valid program name.", serviceName));
00807 return false;
00808 }
00809 initialServiceName = serviceName;
00810
00811
00812 binaryName = KRun::binaryName(typedExec, false);
00813 kDebug(250) << "initialServiceName=" << initialServiceName << "binaryName=" << binaryName;
00814 int i = 1;
00815 bool ok = false;
00816
00817 do {
00818 kDebug(250) << "looking for service" << serviceName;
00819 KService::Ptr serv = KService::serviceByDesktopName( serviceName );
00820 ok = !serv;
00821
00822 if (serv) {
00823 if (serv->isApplication()) {
00824
00825
00826
00827 if (typedExec == simplifiedExecLineFromService(serv->exec())) {
00828 ok = true;
00829 m_pService = serv;
00830 kDebug(250) << "OK, found identical service: " << serv->entryPath();
00831 } else {
00832 kDebug(250) << "Exec line differs, service says:" << simplifiedExecLineFromService(fullExec);
00833 }
00834 } else {
00835 kDebug(250) << "Found, but not an application:" << serv->entryPath();
00836 }
00837 }
00838 if (!ok) {
00839 ++i;
00840 serviceName = initialServiceName + '-' + QString::number(i);
00841 }
00842 } while (!ok);
00843 }
00844 if ( m_pService ) {
00845
00846 serviceName = m_pService->name();
00847 initialServiceName = serviceName;
00848 fullExec = m_pService->exec();
00849 } else {
00850
00851 if (KStandardDirs::findExe(binaryName).isEmpty()) {
00852 KMessageBox::error(q, i18n("'%1' not found, please type a valid program name.", binaryName));
00853 return false;
00854 }
00855 }
00856
00857 if (terminal->isChecked()) {
00858 KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") );
00859 preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
00860 m_command = preferredTerminal;
00861
00862 if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
00863 m_command += QString::fromLatin1(" --noclose");
00864 m_command += QString::fromLatin1(" -e ");
00865 m_command += edit->text();
00866 kDebug(250) << "Setting m_command to" << m_command;
00867 }
00868 if ( m_pService && terminal->isChecked() != m_pService->terminal() )
00869 m_pService = 0;
00870
00871
00872 const bool bRemember = remember && remember->isChecked();
00873 kDebug(250) << "bRemember=" << bRemember << "service found=" << m_pService;
00874 if (m_pService) {
00875 if (bRemember) {
00876
00877 Q_ASSERT(!qMimeType.isEmpty());
00878 addToMimeAppsList(m_pService->storageId());
00879 }
00880 } else {
00881 const bool createDesktopFile = bRemember || saveNewApps;
00882 if (!createDesktopFile) {
00883
00884 m_pService = new KService(initialServiceName, fullExec, QString());
00885 if (terminal->isChecked()) {
00886 m_pService->setTerminal(true);
00887
00888 if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
00889 m_pService->setTerminalOptions("--noclose");
00890 }
00891 } else {
00892
00893
00894 QString menuId;
00895 QString newPath = KService::newServicePath(false , serviceName, &menuId);
00896 kDebug(250) << "Creating new service" << serviceName << "(" << newPath << ")" << "menuId=" << menuId;
00897
00898 KDesktopFile desktopFile(newPath);
00899 KConfigGroup cg = desktopFile.desktopGroup();
00900 cg.writeEntry("Type", "Application");
00901 cg.writeEntry("Name", initialServiceName);
00902 cg.writeEntry("Exec", fullExec);
00903 cg.writeEntry("NoDisplay", true);
00904 if (terminal->isChecked()) {
00905 cg.writeEntry("Terminal", true);
00906
00907 if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
00908 cg.writeEntry("TerminalOptions", "--noclose");
00909 }
00910 cg.writeXdgListEntry("MimeType", QStringList() << qMimeType);
00911 cg.sync();
00912
00913 addToMimeAppsList(menuId);
00914 }
00915 }
00916
00917 saveComboboxHistory();
00918 return true;
00919 }
00920
00921 void KOpenWithDialog::accept()
00922 {
00923 if (d->checkAccept())
00924 KDialog::accept();
00925 }
00926
00927 QString KOpenWithDialog::text() const
00928 {
00929 if (!d->m_command.isEmpty())
00930 return d->m_command;
00931 else
00932 return d->edit->text();
00933 }
00934
00935 void KOpenWithDialog::hideNoCloseOnExit()
00936 {
00937
00938 d->nocloseonexit->setChecked(false);
00939 d->nocloseonexit->hide();
00940 }
00941
00942 void KOpenWithDialog::hideRunInTerminal()
00943 {
00944 d->terminal->hide();
00945 hideNoCloseOnExit();
00946 }
00947
00948 KService::Ptr KOpenWithDialog::service() const
00949 {
00950 return d->m_pService;
00951 }
00952
00953 void KOpenWithDialogPrivate::saveComboboxHistory()
00954 {
00955 KHistoryComboBox *combo = static_cast<KHistoryComboBox*>(edit->comboBox());
00956 if (combo) {
00957 combo->addToHistory(edit->text());
00958
00959 KConfigGroup cg( KGlobal::config(), QString::fromLatin1("Open-with settings") );
00960 cg.writeEntry( "History", combo->historyItems() );
00961 writeEntry( cg, "CompletionMode", combo->completionMode() );
00962
00963
00964 cg.sync();
00965 }
00966 }
00967
00968 #include "kopenwithdialog.moc"
00969 #include "kopenwithdialog_p.moc"