• Skip to content
  • Skip to link menu
KDE 4.1 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 
00446     // slots
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         // Should never happen ??
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     // init the history combo and insert it into the URL-Requester
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   // check to see if we use konsole if not disable the nocloseonexit
00642   // because we don't know how to do this on other terminal applications
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     //    remember->setChecked(true);
00656     topLayout->addWidget(remember);
00657   }
00658   else
00659     remember = 0L;
00660 
00661   //edit->setText( _value );
00662   // This is what caused "can't click on items before clicking on Name header".
00663   // Probably due to the resizeEvent handler using width().
00664   //resize( minimumWidth(), sizeHint().height() );
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& /*_name*/, const QString& _exec )
00681 {
00682     kDebug(250)<<"KOpenWithDialog::slotSelected";
00683     KService::Ptr pService = d->curService;
00684     d->edit->setPath(_exec); // calls slotTextChanged :(
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         // ### indicate that default value was restored
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; // slotTerminalToggled changed it
00703     }
00704 }
00705 
00706 // ----------------------------------------------------------------------
00707 
00708 void KOpenWithDialog::slotTextChanged()
00709 {
00710     kDebug(250)<<"KOpenWithDialog::slotTextChanged" << d->edit->url();
00711     // Forget about the service
00712     d->curService = 0L;
00713     enableButton(Ok, !d->edit->url().isEmpty());
00714 }
00715 
00716 // ----------------------------------------------------------------------
00717 
00718 void KOpenWithDialog::slotTerminalToggled(bool)
00719 {
00720     // ### indicate that default value was overridden
00721     d->m_terminaldirty = true;
00722     d->nocloseonexit->setDisabled(!d->terminal->isChecked());
00723 }
00724 
00725 // ----------------------------------------------------------------------
00726 
00727 void KOpenWithDialogPrivate::_k_slotDbClick()
00728 {
00729     // check if a directory is selected
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 /*menu id or storage id*/)
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); // make it the preferred app
00760     addedApps.writeXdgListEntry(qMimeType, apps);
00761     addedApps.sync();
00762 
00763     // Also make sure the "auto embed" setting for this mimetype is off
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     // kbuildsycoca is the one reading mimeapps.list, so we need to run it now
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         // No service selected - check the command line
00790 
00791         // Find out the name of the service from the command line, removing args and paths
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; // We have app, app-2, app-3... Looks better for the user.
00800         bool ok = false;
00801         // Check if there's already a service by that name, with the same Exec line
00802         do {
00803             kDebug(250) << "looking for service" << serviceName;
00804             KService::Ptr serv = KService::serviceByDesktopName( serviceName );
00805             ok = !serv; // ok if no such service yet
00806             // also ok if we find the exact same service (well, "kwrite" == "kwrite %U")
00807             if (serv && serv->isApplication()) {
00808                 fullExec = serv->exec();
00809                 /*kDebug(250) << "typedExec=" << typedExec
00810                          << "serv->exec=" << fullExec
00811                          << "simplifiedExecLineFromService=" << simplifiedExecLineFromService(fullExec);*/
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) { // service was found, but it was different -> keep looking
00819                 ++i;
00820                 serviceName = initialServiceName + '-' + QString::number(i);
00821             }
00822         } while (!ok);
00823     }
00824     if ( m_pService ) {
00825         // Existing service selected
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         // only add --noclose when we are sure it is konsole we're using
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; // It's not exactly this service we're running
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             // Associate this app with qMimeType in mimeapps.list
00851             Q_ASSERT(!qMimeType.isEmpty()); // we don't show the remember checkbox otherwise
00852             addToMimeAppsList(m_pService->storageId());
00853         }
00854     } else {
00855         const bool createDesktopFile = bRemember || saveNewApps;
00856         if (!createDesktopFile) {
00857             // Create temp service
00858             m_pService = new KService(initialServiceName, fullExec, QString());
00859             if (terminal->isChecked()) {
00860                 m_pService->setTerminal(true);
00861                 // only add --noclose when we are sure it is konsole we're using
00862                 if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
00863                     m_pService->setTerminalOptions("--noclose");
00864             }
00865         } else {
00866             // If we got here, we can't seem to find a service for what they wanted. Create one.
00867 
00868             QString menuId;
00869             QString newPath = KService::newServicePath(false /* ignored argument */, 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); // don't make it appear in the K menu
00878             if (terminal->isChecked()) {
00879                 cg.writeEntry("Terminal", true);
00880                 // only add --noclose when we are sure it is konsole we're using
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     // uncheck the checkbox because the value could be used when "Run in Terminal" is selected
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         // don't store the completion-list, as it contains all of KUrlCompletion's
00929         // executables
00930         cg.sync();
00931     }
00932 
00933     QDialog::accept();
00934 }
00935 
00936 #include "kopenwithdialog.moc"
00937 #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
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
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