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