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
00446
00447 void _k_slotDbClick();
00448 void _k_slotOK();
00449
00450 bool saveNewApps;
00451 bool m_terminaldirty;
00452 KService::Ptr curService;
00453 KApplicationView *view;
00454 KUrlRequester *edit;
00455 QString m_command;
00456 QLabel *label;
00457 QString qName;
00458 QString qMimeType;
00459 QCheckBox *terminal;
00460 QCheckBox *remember;
00461 QCheckBox *nocloseonexit;
00462 KService::Ptr m_pService;
00463 };
00464
00465 KOpenWithDialog::KOpenWithDialog( const KUrl::List& _urls, QWidget* parent )
00466 : KDialog(parent), d(new KOpenWithDialogPrivate(this))
00467 {
00468 setObjectName( QLatin1String( "openwith" ) );
00469 setModal( true );
00470 setCaption( i18n( "Open With" ) );
00471
00472 QString text;
00473 if( _urls.count() == 1 )
00474 {
00475 text = i18n("<qt>Select the program that should be used to open <b>%1</b>. "
00476 "If the program is not listed, enter the name or click "
00477 "the browse button.</qt>", _urls.first().fileName() );
00478 }
00479 else
00480
00481 text = i18n( "Choose the name of the program with which to open the selected files." );
00482 d->setMimeType(_urls);
00483 d->init(text, QString());
00484 }
00485
00486 KOpenWithDialog::KOpenWithDialog( const KUrl::List& _urls, const QString&_text,
00487 const QString& _value, QWidget *parent)
00488 : KDialog(parent), d(new KOpenWithDialogPrivate(this))
00489 {
00490 setObjectName( QLatin1String( "openwith" ) );
00491 setModal( true );
00492 QString caption;
00493 if (_urls.count()>0 && !_urls.first().isEmpty())
00494 caption = KStringHandler::csqueeze( _urls.first().prettyUrl() );
00495 if (_urls.count() > 1)
00496 caption += QString::fromLatin1("...");
00497 setCaption(caption);
00498 d->setMimeType(_urls);
00499 d->init(_text, _value);
00500 }
00501
00502 KOpenWithDialog::KOpenWithDialog( const QString &mimeType, const QString& value,
00503 QWidget *parent)
00504 : KDialog(parent), d(new KOpenWithDialogPrivate(this))
00505 {
00506 setObjectName( QLatin1String( "openwith" ) );
00507 setModal( true );
00508 setCaption(i18n("Choose Application for %1", mimeType));
00509 QString text = i18n("<qt>Select the program for the file type: <b>%1</b>. "
00510 "If the program is not listed, enter the name or click "
00511 "the browse button.</qt>", mimeType);
00512 d->qMimeType = mimeType;
00513 d->init(text, value);
00514 if (d->remember) {
00515 d->remember->hide();
00516 }
00517 }
00518
00519 KOpenWithDialog::KOpenWithDialog( QWidget *parent)
00520 : KDialog(parent), d(new KOpenWithDialogPrivate(this))
00521 {
00522 setObjectName( QLatin1String( "openwith" ) );
00523 setModal( true );
00524 setCaption(i18n("Choose Application"));
00525 QString text = i18n("<qt>Select a program. "
00526 "If the program is not listed, enter the name or click "
00527 "the browse button.</qt>");
00528 d->qMimeType.clear();
00529 d->init(text, QString());
00530 }
00531
00532 void KOpenWithDialogPrivate::setMimeType(const KUrl::List &_urls)
00533 {
00534 if ( _urls.count() == 1 )
00535 {
00536 qMimeType = KMimeType::findByUrl( _urls.first())->name();
00537 if (qMimeType == QLatin1String("application/octet-stream"))
00538 qMimeType.clear();
00539 }
00540 else
00541 qMimeType.clear();
00542 }
00543
00544 void KOpenWithDialogPrivate::init(const QString &_text, const QString &_value)
00545 {
00546 bool bReadOnly = !KAuthorized::authorize("shell_access");
00547 m_terminaldirty = false;
00548 view = 0;
00549 m_pService = 0L;
00550 curService = 0L;
00551
00552 q->setButtons(KDialog::Ok | KDialog::Cancel);
00553
00554 QWidget *mainWidget = q->mainWidget();
00555
00556 QBoxLayout *topLayout = new QVBoxLayout( mainWidget );
00557 topLayout->setMargin(0);
00558 topLayout->setSpacing( KDialog::spacingHint() );
00559 label = new QLabel(_text, q);
00560 label->setWordWrap(true);
00561 topLayout->addWidget(label);
00562
00563 if (!bReadOnly)
00564 {
00565
00566 KHistoryComboBox *combo = new KHistoryComboBox();
00567 KLineEdit *lineEdit = new KLineEdit(q);
00568 lineEdit->setClearButtonShown(true);
00569 combo->setLineEdit(lineEdit);
00570 combo->setDuplicatesEnabled( false );
00571 KConfigGroup cg( KGlobal::config(), QString::fromLatin1("Open-with settings") );
00572 int max = cg.readEntry( "Maximum history", 15 );
00573 combo->setMaxCount( max );
00574 int mode = cg.readEntry( "CompletionMode", int(KGlobalSettings::completionMode()));
00575 combo->setCompletionMode((KGlobalSettings::Completion)mode);
00576 QStringList list = cg.readEntry( "History", QStringList() );
00577 combo->setHistoryItems( list, true );
00578 edit = new KUrlRequester( combo, mainWidget );
00579 }
00580 else
00581 {
00582 edit = new KUrlRequester( mainWidget );
00583 edit->lineEdit()->setReadOnly(true);
00584 edit->button()->hide();
00585 }
00586
00587 edit->setPath( _value );
00588 edit->setWhatsThis(i18n(
00589 "Following the command, you can have several place holders which will be replaced "
00590 "with the actual values when the actual program is run:\n"
00591 "%f - a single file name\n"
00592 "%F - a list of files; use for applications that can open several local files at once\n"
00593 "%u - a single URL\n"
00594 "%U - a list of URLs\n"
00595 "%d - the directory of the file to open\n"
00596 "%D - a list of directories\n"
00597 "%i - the icon\n"
00598 "%m - the mini-icon\n"
00599 "%c - the comment"));
00600
00601 topLayout->addWidget(edit);
00602
00603 if ( edit->comboBox() ) {
00604 KUrlCompletion *comp = new KUrlCompletion( KUrlCompletion::ExeCompletion );
00605 edit->comboBox()->setCompletionObject( comp );
00606 edit->comboBox()->setAutoDeleteCompletionObject( true );
00607 }
00608
00609 QObject::connect(edit, SIGNAL(returnPressed()), q, SLOT(_k_slotOK()));
00610 QObject::connect(q, SIGNAL(okClicked()), q, SLOT(_k_slotOK()));
00611 QObject::connect(edit, SIGNAL(textChanged(QString)), q, SLOT(slotTextChanged()));
00612
00613 view = new KApplicationView(mainWidget);
00614 view->setModel(new KApplicationModel(view));
00615 topLayout->addWidget(view);
00616
00617 QObject::connect(view, SIGNAL(selected(QString, QString)),
00618 q, SLOT(slotSelected(QString, QString)));
00619 QObject::connect(view, SIGNAL(highlighted(QString, QString)),
00620 q, SLOT(slotHighlighted(QString, QString)));
00621 QObject::connect(view, SIGNAL(doubleClicked(QModelIndex)),
00622 q, SLOT(_k_slotDbClick()));
00623
00624 terminal = new QCheckBox( i18n("Run in &terminal"), mainWidget );
00625 if (bReadOnly)
00626 terminal->hide();
00627 QObject::connect(terminal, SIGNAL(toggled(bool)), q, SLOT(slotTerminalToggled(bool)));
00628
00629 topLayout->addWidget(terminal);
00630
00631 QBoxLayout* nocloseonexitLayout = new QHBoxLayout();
00632 nocloseonexitLayout->setMargin( 0 );
00633 nocloseonexitLayout->setSpacing( KDialog::spacingHint() );
00634 QSpacerItem* spacer = new QSpacerItem( 20, 0, QSizePolicy::Fixed, QSizePolicy::Minimum );
00635 nocloseonexitLayout->addItem( spacer );
00636
00637 nocloseonexit = new QCheckBox( i18n("&Do not close when command exits"), mainWidget );
00638 nocloseonexit->setChecked( false );
00639 nocloseonexit->setDisabled( true );
00640
00641
00642
00643 KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") );
00644 QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
00645
00646 if (bReadOnly || preferredTerminal != "konsole")
00647 nocloseonexit->hide();
00648
00649 nocloseonexitLayout->addWidget( nocloseonexit );
00650 topLayout->addLayout( nocloseonexitLayout );
00651
00652 if (!qMimeType.isNull())
00653 {
00654 remember = new QCheckBox(i18n("&Remember application association for this type of file"), mainWidget);
00655
00656 topLayout->addWidget(remember);
00657 }
00658 else
00659 remember = 0L;
00660
00661
00662
00663
00664
00665 edit->setFocus();
00666 q->slotTextChanged();
00667 }
00668
00669
00670
00671
00672 KOpenWithDialog::~KOpenWithDialog()
00673 {
00674 delete d;
00675 }
00676
00677
00678
00679
00680 void KOpenWithDialog::slotSelected( const QString& , const QString& _exec )
00681 {
00682 kDebug(250)<<"KOpenWithDialog::slotSelected";
00683 KService::Ptr pService = d->curService;
00684 d->edit->setPath(_exec);
00685 d->curService = pService;
00686 }
00687
00688
00689
00690
00691 void KOpenWithDialog::slotHighlighted( const QString& _name, const QString& )
00692 {
00693 kDebug(250)<<"KOpenWithDialog::slotHighlighted";
00694 d->qName = _name;
00695 d->curService = KService::serviceByName(d->qName);
00696 if (!d->m_terminaldirty)
00697 {
00698
00699 d->terminal->setChecked(d->curService->terminal());
00700 QString terminalOptions = d->curService->terminalOptions();
00701 d->nocloseonexit->setChecked((terminalOptions.contains(QLatin1String("--noclose")) > 0));
00702 d->m_terminaldirty = false;
00703 }
00704 }
00705
00706
00707
00708 void KOpenWithDialog::slotTextChanged()
00709 {
00710 kDebug(250)<<"KOpenWithDialog::slotTextChanged" << d->edit->url();
00711
00712 d->curService = 0L;
00713 enableButton(Ok, !d->edit->url().isEmpty());
00714 }
00715
00716
00717
00718 void KOpenWithDialog::slotTerminalToggled(bool)
00719 {
00720
00721 d->m_terminaldirty = true;
00722 d->nocloseonexit->setDisabled(!d->terminal->isChecked());
00723 }
00724
00725
00726
00727 void KOpenWithDialogPrivate::_k_slotDbClick()
00728 {
00729
00730 if (view->isDirSel()) {
00731 return;
00732 }
00733 _k_slotOK();
00734 }
00735
00736 void KOpenWithDialog::setSaveNewApplications(bool b)
00737 {
00738 d->saveNewApps = b;
00739 }
00740
00741 static QString simplifiedExecLineFromService(const QString& fullExec)
00742 {
00743 QString exec = fullExec;
00744 exec.remove("%u", Qt::CaseInsensitive);
00745 exec.remove("%f", Qt::CaseInsensitive);
00746 exec.remove("-caption %c");
00747 exec.remove("-caption \"%c\"");
00748 exec.remove("%i");
00749 exec.remove("%m");
00750 return exec.simplified();
00751 }
00752
00753 void KOpenWithDialogPrivate::addToMimeAppsList(const QString& serviceId )
00754 {
00755 KSharedConfig::Ptr profile = KSharedConfig::openConfig("mimeapps.list", KConfig::NoGlobals, "xdgdata-apps");
00756 KConfigGroup addedApps(profile, "Added Associations");
00757 QStringList apps = addedApps.readXdgListEntry(qMimeType);
00758 apps.removeAll(serviceId);
00759 apps.prepend(serviceId);
00760 addedApps.writeXdgListEntry(qMimeType, apps);
00761 addedApps.sync();
00762
00763
00764 KSharedConfig::Ptr fileTypesConfig = KSharedConfig::openConfig("filetypesrc", KConfig::NoGlobals);
00765 fileTypesConfig->group("EmbedSettings").writeEntry(QString("embed-")+qMimeType, false);
00766 fileTypesConfig->sync();
00767
00768 kDebug(250) << "rebuilding ksycoca...";
00769
00770
00771 KBuildSycocaProgressDialog::rebuildKSycoca(q);
00772
00773 m_pService = KService::serviceByStorageId(serviceId);
00774 Q_ASSERT( m_pService );
00775 }
00776
00777 void KOpenWithDialogPrivate::_k_slotOK()
00778 {
00779 QString typedExec(edit->url().pathOrUrl());
00780 if (typedExec.isEmpty())
00781 return;
00782 QString fullExec(typedExec);
00783
00784 QString serviceName;
00785 QString initialServiceName;
00786 QString preferredTerminal;
00787 m_pService = curService;
00788 if (!m_pService) {
00789
00790
00791
00792 serviceName = KRun::binaryName( typedExec, true );
00793 if (serviceName.isEmpty()) {
00794 KMessageBox::error(q, i18n("Could not extract executable name from '%1', please type a valid program name.", serviceName));
00795 return;
00796 }
00797 initialServiceName = serviceName;
00798 kDebug(250) << "initialServiceName=" << initialServiceName;
00799 int i = 1;
00800 bool ok = false;
00801
00802 do {
00803 kDebug(250) << "looking for service" << serviceName;
00804 KService::Ptr serv = KService::serviceByDesktopName( serviceName );
00805 ok = !serv;
00806
00807 if (serv && serv->isApplication()) {
00808 fullExec = serv->exec();
00809
00810
00811
00812 if (typedExec == simplifiedExecLineFromService(fullExec)) {
00813 ok = true;
00814 m_pService = serv;
00815 kDebug(250) << "OK, found identical service: " << serv->entryPath();
00816 }
00817 }
00818 if (!ok) {
00819 ++i;
00820 serviceName = initialServiceName + '-' + QString::number(i);
00821 }
00822 } while (!ok);
00823 }
00824 if ( m_pService ) {
00825
00826 serviceName = m_pService->name();
00827 initialServiceName = serviceName;
00828 fullExec = m_pService->exec();
00829 }
00830
00831 if (terminal->isChecked()) {
00832 KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") );
00833 preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
00834 m_command = preferredTerminal;
00835
00836 if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
00837 m_command += QString::fromLatin1(" --noclose");
00838 m_command += QString::fromLatin1(" -e ");
00839 m_command += edit->url().pathOrUrl();
00840 kDebug(250) << "Setting m_command to" << m_command;
00841 }
00842 if ( m_pService && terminal->isChecked() != m_pService->terminal() )
00843 m_pService = 0;
00844
00845
00846 const bool bRemember = remember && remember->isChecked();
00847 kDebug(250) << "bRemember=" << bRemember << "service found=" << m_pService;
00848 if (m_pService) {
00849 if (bRemember) {
00850
00851 Q_ASSERT(!qMimeType.isEmpty());
00852 addToMimeAppsList(m_pService->storageId());
00853 }
00854 } else {
00855 const bool createDesktopFile = bRemember || saveNewApps;
00856 if (!createDesktopFile) {
00857
00858 m_pService = new KService(initialServiceName, fullExec, QString());
00859 if (terminal->isChecked()) {
00860 m_pService->setTerminal(true);
00861
00862 if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
00863 m_pService->setTerminalOptions("--noclose");
00864 }
00865 } else {
00866
00867
00868 QString menuId;
00869 QString newPath = KService::newServicePath(false , serviceName, &menuId);
00870 kDebug(250) << "Creating new service" << serviceName << "(" << newPath << ")" << "menuId=" << menuId;
00871
00872 KDesktopFile desktopFile(newPath);
00873 KConfigGroup cg = desktopFile.desktopGroup();
00874 cg.writeEntry("Type", "Application");
00875 cg.writeEntry("Name", initialServiceName);
00876 cg.writeEntry("Exec", fullExec);
00877 cg.writeEntry("NoDisplay", true);
00878 if (terminal->isChecked()) {
00879 cg.writeEntry("Terminal", true);
00880
00881 if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
00882 cg.writeEntry("TerminalOptions", "--noclose");
00883 }
00884 cg.writeXdgListEntry("MimeType", QStringList() << qMimeType);
00885 cg.sync();
00886
00887 addToMimeAppsList(menuId);
00888 }
00889 }
00890 q->accept();
00891 }
00892
00893 QString KOpenWithDialog::text() const
00894 {
00895 if (!d->m_command.isEmpty())
00896 return d->m_command;
00897 else
00898 return d->edit->url().url();
00899 }
00900
00901 void KOpenWithDialog::hideNoCloseOnExit()
00902 {
00903
00904 d->nocloseonexit->setChecked(false);
00905 d->nocloseonexit->hide();
00906 }
00907
00908 void KOpenWithDialog::hideRunInTerminal()
00909 {
00910 d->terminal->hide();
00911 hideNoCloseOnExit();
00912 }
00913
00914 KService::Ptr KOpenWithDialog::service() const
00915 {
00916 return d->m_pService;
00917 }
00918
00919 void KOpenWithDialog::accept()
00920 {
00921 KHistoryComboBox *combo = static_cast<KHistoryComboBox*>(d->edit->comboBox());
00922 if ( combo ) {
00923 combo->addToHistory(d->edit->url().url());
00924
00925 KConfigGroup cg( KGlobal::config(), QString::fromLatin1("Open-with settings") );
00926 cg.writeEntry( "History", combo->historyItems() );
00927 writeEntry( cg, "CompletionMode", combo->completionMode() );
00928
00929
00930 cg.sync();
00931 }
00932
00933 QDialog::accept();
00934 }
00935
00936 #include "kopenwithdialog.moc"
00937 #include "kopenwithdialog_p.moc"