• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIO

kopenwithdialog.cpp

Go to the documentation of this file.
00001 /*  This file is part of the KDE libraries
00002 
00003     Copyright (C) 1997 Torben Weis <weis@stud.uni-frankfurt.de>
00004     Copyright (C) 1999 Dirk Mueller <mueller@kde.org>
00005     Portions copyright (C) 1999 Preston Brown <pbrown@kde.org>
00006     Copyright (C) 2007 Pino Toscano <pino@kde.org>
00007 
00008     This library is free software; you can redistribute it and/or
00009     modify it under the terms of the GNU Library General Public
00010     License as published by the Free Software Foundation; either
00011     version 2 of the License, or (at your option) any later version.
00012 
00013     This library is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016     Library General Public License for more details.
00017 
00018     You should have received a copy of the GNU Library General Public License
00019     along with this library; see the file COPYING.LIB.  If not, write to
00020     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00021     Boston, MA 02110-1301, USA.
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 &current, 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  * KOpenWithDialog
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     // slots
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         // Should never happen ??
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     // init the history combo and insert it into the URL-Requester
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   // check to see if we use konsole if not disable the nocloseonexit
00650   // because we don't know how to do this on other terminal applications
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     //    remember->setChecked(true);
00664     topLayout->addWidget(remember);
00665   }
00666   else
00667     remember = 0L;
00668 
00669   //edit->setText( _value );
00670   // This is what caused "can't click on items before clicking on Name header".
00671   // Probably due to the resizeEvent handler using width().
00672   //resize( minimumWidth(), sizeHint().height() );
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& /*_name*/, const QString& _exec )
00689 {
00690     KService::Ptr pService = d->curService;
00691     d->edit->setPath(_exec); // calls slotTextChanged :(
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         // ### indicate that default value was restored
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; // slotTerminalToggled changed it
00710     }
00711 }
00712 
00713 // ----------------------------------------------------------------------
00714 
00715 void KOpenWithDialog::slotTextChanged()
00716 {
00717     // Forget about the service
00718     d->curService = 0L;
00719     enableButton(Ok, !d->edit->text().isEmpty());
00720 }
00721 
00722 // ----------------------------------------------------------------------
00723 
00724 void KOpenWithDialog::slotTerminalToggled(bool)
00725 {
00726     // ### indicate that default value was overridden
00727     d->m_terminaldirty = true;
00728     d->nocloseonexit->setDisabled(!d->terminal->isChecked());
00729 }
00730 
00731 // ----------------------------------------------------------------------
00732 
00733 void KOpenWithDialogPrivate::_k_slotDbClick()
00734 {
00735     // check if a directory is selected
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 /*menu id or storage id*/)
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); // make it the preferred app
00766     addedApps.writeXdgListEntry(qMimeType, apps);
00767     addedApps.sync();
00768 
00769     // Also make sure the "auto embed" setting for this mimetype is off
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     // kbuildsycoca is the one reading mimeapps.list, so we need to run it now
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         // No service selected - check the command line
00797 
00798         // Find out the name of the service from the command line, removing args and paths
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         // Also remember the binaryName with a path, if any, for the
00806         // check that the binary exists.
00807         binaryName = KRun::binaryName(typedExec, false);
00808         kDebug(250) << "initialServiceName=" << initialServiceName << "binaryName=" << binaryName;
00809         int i = 1; // We have app, app-2, app-3... Looks better for the user.
00810         bool ok = false;
00811         // Check if there's already a service by that name, with the same Exec line
00812         do {
00813             kDebug(250) << "looking for service" << serviceName;
00814             KService::Ptr serv = KService::serviceByDesktopName( serviceName );
00815             ok = !serv; // ok if no such service yet
00816             // also ok if we find the exact same service (well, "kwrite" == "kwrite %U")
00817             if (serv) {
00818                 if (serv->isApplication()) {
00819                     /*kDebug(250) << "typedExec=" << typedExec
00820                       << "serv->exec=" << serv->exec()
00821                       << "simplifiedExecLineFromService=" << simplifiedExecLineFromService(fullExec);*/
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) { // service was found, but it was different -> keep looking
00834                 ++i;
00835                 serviceName = initialServiceName + '-' + QString::number(i);
00836             }
00837         } while (!ok);
00838     }
00839     if ( m_pService ) {
00840         // Existing service selected
00841         serviceName = m_pService->name();
00842         initialServiceName = serviceName;
00843         fullExec = m_pService->exec();
00844     } else {
00845         // Ensure that the typed binary name actually exists (#81190)
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         // only add --noclose when we are sure it is konsole we're using
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; // It's not exactly this service we're running
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             // Associate this app with qMimeType in mimeapps.list
00872             Q_ASSERT(!qMimeType.isEmpty()); // we don't show the remember checkbox otherwise
00873             addToMimeAppsList(m_pService->storageId());
00874         }
00875     } else {
00876         const bool createDesktopFile = bRemember || saveNewApps;
00877         if (!createDesktopFile) {
00878             // Create temp service
00879             m_pService = new KService(initialServiceName, fullExec, QString());
00880             if (terminal->isChecked()) {
00881                 m_pService->setTerminal(true);
00882                 // only add --noclose when we are sure it is konsole we're using
00883                 if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
00884                     m_pService->setTerminalOptions("--noclose");
00885             }
00886         } else {
00887             // If we got here, we can't seem to find a service for what they wanted. Create one.
00888 
00889             QString menuId;
00890             QString newPath = KService::newServicePath(false /* ignored argument */, 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); // don't make it appear in the K menu
00899             if (terminal->isChecked()) {
00900                 cg.writeEntry("Terminal", true);
00901                 // only add --noclose when we are sure it is konsole we're using
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     // uncheck the checkbox because the value could be used when "Run in Terminal" is selected
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         // don't store the completion-list, as it contains all of KUrlCompletion's
00958         // executables
00959         cg.sync();
00960     }
00961 }
00962 
00963 #include "kopenwithdialog.moc"
00964 #include "kopenwithdialog_p.moc"

KIO

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal