kio Library: kopenwith.cpp Source File (kio Library)

| # kio Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# kopenwith.cpp

    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 A. Mueller <dmuell@gmx.net>
    00005     Portions copyright (C) 1999 Preston Brown <pbrown@kde.org>
    00006
    00007     This library is free software; you can redistribute it and/or
    00008     modify it under the terms of the GNU Library General Public
    00009     License as published by the Free Software Foundation; either
    00010     version 2 of the License, or (at your option) any later version.
    00011
    00012     This library is distributed in the hope that it will be useful,
    00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00015     Library General Public License for more details.
    00016
    00017     You should have received a copy of the GNU Library General Public License
    00018     along with this library; see the file COPYING.LIB.  If not, write to
    00019     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00020     Boston, MA 02111-1307, USA.
    00021 */
    00022
    00023 #include <qfile.h>
    00024 #include <qdir.h>
    00025 #include <qdialog.h>
    00026 #include <qimage.h>
    00027 #include <qpixmap.h>
    00028 #include <qlabel.h>
    00029 #include <qlayout.h>
    00030 #include <qpushbutton.h>
    00031 #include <qtoolbutton.h>
    00032 #include <qcheckbox.h>
    00033 #include <qtooltip.h>
    00034 #include <qstyle.h>
    00035 #include <qwhatsthis.h>
    00036
    00037 #include <kapplication.h>
    00038 #include <kbuttonbox.h>
    00039 #include <kcombobox.h>
    00040 #include <kdesktopfile.h>
    00041 #include <kdialog.h>
    00042 #include <kglobal.h>
    00043 #include <klineedit.h>
    00044 #include <klocale.h>
    00045 #include <kiconloader.h>
    00046 #include <kmimemagic.h>
    00047 #include <krun.h>
    00048 #include <kstandarddirs.h>
    00049 #include <kstringhandler.h>
    00050 #include <kuserprofile.h>
    00051 #include <kurlcompletion.h>
    00052 #include <kurlrequester.h>
    00053 #include <dcopclient.h>
    00054 #include <kmimetype.h>
    00055 #include <kservicegroup.h>
    00056 #include <klistview.h>
    00057 #include <ksycoca.h>
    00058 #include <kstdguiitem.h>
    00059
    00060 #include "kopenwith.h"
    00061 #include "kopenwith_p.h"
    00062
    00063 #include <kdebug.h>
    00064 #include <assert.h>
    00065 #include <stdlib.h>
    00066
    00067 template class QPtrList<QString>;
    00068
    00069 #define SORT_SPEC (QDir::DirsFirst | QDir::Name | QDir::IgnoreCase)
    00070
    00071
    00072 // ----------------------------------------------------------------------
    00073
    00074 KAppTreeListItem::KAppTreeListItem( KListView* parent, const QString & name,
    00075                                     const QPixmap& pixmap, bool parse, bool dir, const QString &p, const QString &c )
    00076     : QListViewItem( parent, name )
    00077 {
    00078     init(pixmap, parse, dir, p, c);
    00079 }
    00080
    00081
    00082 // ----------------------------------------------------------------------
    00083
    00084 KAppTreeListItem::KAppTreeListItem( QListViewItem* parent, const QString & name,
    00085                                     const QPixmap& pixmap, bool parse, bool dir, const QString &p, const QString &c )
    00086     : QListViewItem( parent, name )
    00087 {
    00088     init(pixmap, parse, dir, p, c);
    00089 }
    00090
    00091
    00092 // ----------------------------------------------------------------------
    00093
    00094 void KAppTreeListItem::init(const QPixmap& pixmap, bool parse, bool dir, const QString &_path, const QString &_exec)
    00095 {
    00096     setPixmap(0, pixmap);
    00097     parsed = parse;
    00098     directory = dir;
    00099     path = _path; // relative path
    00100     exec = _exec;
    00101 }
    00102
    00103
    00104 /* Ensures that directories sort before non-directories */
    00105 int KAppTreeListItem::compare(QListViewItem *i, int col, bool ascending) const
    00106 {
    00107     KAppTreeListItem *other = dynamic_cast<KAppTreeListItem *>(i);
    00108
    00109     // Directories sort first
    00110     if (directory && !other->directory)
    00111         return -1;
    00112
    00113     else if (!directory && other->directory)
    00114         return 1;
    00115
    00116     else // both directories or both not
    00117         return QListViewItem::compare(i, col, ascending);
    00118 }
    00119
    00120 // ----------------------------------------------------------------------
    00121 // Ensure that case is ignored
    00122 QString KAppTreeListItem::key(int column, bool /*ascending*/) const
    00123 {
    00124         return text(column).upper();
    00125 }
    00126
    00127 void KAppTreeListItem::activate()
    00128 {
    00129     if ( directory )
    00130         setOpen(!isOpen());
    00131 }
    00132
    00133 void KAppTreeListItem::setOpen( bool o )
    00134 {
    00135     if( o && !parsed ) { // fill the children before opening
    00136         ((KApplicationTree *) parent())->addDesktopGroup( path, this );
    00137         parsed = true;
    00138     }
    00139     QListViewItem::setOpen( o );
    00140 }
    00141
    00142 bool KAppTreeListItem::isDirectory()
    00143 {
    00144     return directory;
    00145 }
    00146
    00147 // ----------------------------------------------------------------------
    00148
    00149 KApplicationTree::KApplicationTree( QWidget *parent )
    00150     : KListView( parent ), currentitem(0)
    00151 {
    00152     addColumn( i18n("Known Applications") );
    00153     setRootIsDecorated( true );
    00154
    00155     addDesktopGroup( QString::null );
    00156     cleanupTree();
    00157
    00158     connect( this, SIGNAL( currentChanged(QListViewItem*) ),
    00159             SLOT( slotItemHighlighted(QListViewItem*) ) );
    00160     connect( this, SIGNAL( selectionChanged(QListViewItem*) ),
    00161             SLOT( slotSelectionChanged(QListViewItem*) ) );
    00162 }
    00163
    00164 // ----------------------------------------------------------------------
    00165
    00166 bool KApplicationTree::isDirSel()
    00167 {
    00168     if (!currentitem) return false; // if currentitem isn't set
    00169     return currentitem->isDirectory();
    00170 }
    00171
    00172 // ----------------------------------------------------------------------
    00173
    00174 static QPixmap appIcon(const QString &iconName)
    00175 {
    00176     QPixmap normal = KGlobal::iconLoader()->loadIcon(iconName, KIcon::Small, 0, KIcon::DefaultState, 0L, true);
    00177     // make sure they are not larger than 20x20
    00178     if (normal.width() > 20 || normal.height() > 20)
    00179     {
    00180        QImage tmp = normal.convertToImage();
    00181        tmp = tmp.smoothScale(20, 20);
    00182        normal.convertFromImage(tmp);
    00183     }
    00184     return normal;
    00185 }
    00186
    00187 void KApplicationTree::addDesktopGroup( const QString &relPath, KAppTreeListItem *item)
    00188 {
    00189    KServiceGroup::Ptr root = KServiceGroup::group(relPath);
    00190    if (!root || !root->isValid()) return;
    00191
    00192    KServiceGroup::List list = root->entries();
    00193
    00194    KAppTreeListItem * newItem;
    00195    for( KServiceGroup::List::ConstIterator it = list.begin();
    00196        it != list.end(); it++)
    00197    {
    00198       QString icon;
    00199       QString text;
    00200       QString relPath;
    00201       QString exec;
    00202       bool isDir = false;
    00203       KSycocaEntry *p = (*it);
    00204       if (p->isType(KST_KService))
    00205       {
    00206          KService *service = static_cast<KService *>(p);
    00207
    00208          if (service->noDisplay())
    00209             continue;
    00210
    00211          icon = service->icon();
    00212          text = service->name();
    00213          exec = service->exec();
    00214       }
    00215       else if (p->isType(KST_KServiceGroup))
    00216       {
    00217          KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p);
    00218
    00219          if (serviceGroup->noDisplay())
    00220             continue;
    00221
    00222          icon = serviceGroup->icon();
    00223          text = serviceGroup->caption();
    00224          relPath = serviceGroup->relPath();
    00225          isDir = true;
    00226          if ( text[0] == '.' ) // skip ".hidden" like kicker does
    00227            continue;
    00228       }
    00229       else
    00230       {
    00231          kdWarning(250) << "KServiceGroup: Unexpected object in list!" << endl;
    00232          continue;
    00233       }
    00234
    00235       QPixmap pixmap = appIcon( icon );
    00236
    00237       if (item)
    00238          newItem = new KAppTreeListItem( item, text, pixmap, false, isDir,
    00239                                          relPath, exec );
    00240       else
    00241          newItem = new KAppTreeListItem( this, text, pixmap, false, isDir,
    00242                                          relPath, exec );
    00243       if (isDir)
    00244          newItem->setExpandable( true );
    00245    }
    00246 }
    00247
    00248
    00249 // ----------------------------------------------------------------------
    00250
    00251 void KApplicationTree::slotItemHighlighted(QListViewItem* i)
    00252 {
    00253     // i may be 0 (see documentation)
    00254     if(!i)
    00255         return;
    00256
    00257     KAppTreeListItem *item = (KAppTreeListItem *) i;
    00258
    00259     currentitem = item;
    00260
    00261     if( (!item->directory ) && (!item->exec.isEmpty()) )
    00262         emit highlighted( item->text(0), item->exec );
    00263 }
    00264
    00265
    00266 // ----------------------------------------------------------------------
    00267
    00268 void KApplicationTree::slotSelectionChanged(QListViewItem* i)
    00269 {
    00270     // i may be 0 (see documentation)
    00271     if(!i)
    00272         return;
    00273
    00274     KAppTreeListItem *item = (KAppTreeListItem *) i;
    00275
    00276     currentitem = item;
    00277
    00278     if( ( !item->directory ) && (!item->exec.isEmpty() ) )
    00279         emit selected( item->text(0), item->exec );
    00280 }
    00281
    00282 // ----------------------------------------------------------------------
    00283
    00284 void KApplicationTree::resizeEvent( QResizeEvent * e)
    00285 {
    00286     setColumnWidth(0, width()-QApplication::style().pixelMetric(QStyle::PM_ScrollBarExtent)
    00287                          -2*QApplication::style().pixelMetric(QStyle::PM_DefaultFrameWidth));
    00288     KListView::resizeEvent(e);
    00289 }
    00290
    00291 // Prune empty directories from the tree
    00292 void KApplicationTree::cleanupTree()
    00293 {
    00294     QListViewItem *item=firstChild();
    00295     while(item!=0)
    00296     {
    00297         if(item->isExpandable())
    00298         {
    00299             item->setOpen(true);
    00300             if(item->childCount()==0) {
    00301                 QListViewItem *current=item;
    00302                 item=item->itemBelow();
    00303                 delete current;
    00304                 continue;
    00305             }
    00306             item=item->itemBelow();
    00307             continue;
    00308         }
    00309         item=item->itemBelow();
    00310     }
    00311     item=firstChild();
    00312     while(item!=0)
    00313     {
    00314         if(item->isExpandable())
    00315         {
    00316             QListViewItem *temp=item->itemBelow();
    00317             if(item->text(0)!=i18n("Applications"))
    00318                 item->setOpen(false);
    00319             item=temp;
    00320             continue;
    00321         }
    00322         item=item->itemBelow();
    00323     }
    00324 }
    00325
    00326 /***************************************************************
    00327  *
    00328  * KOpenWithDlg
    00329  *
    00330  ***************************************************************/
    00331 class KOpenWithDlgPrivate
    00332 {
    00333 public:
    00334     KOpenWithDlgPrivate() : saveNewApps(false) { };
    00335     QPushButton* ok;
    00336     bool saveNewApps;
    00337     KService::Ptr curService;
    00338 };
    00339
    00340 KOpenWithDlg::KOpenWithDlg( const KURL::List& _urls, QWidget* parent )
    00341              :QDialog( parent, "openwith", true )
    00342 {
    00343     setCaption( i18n( "Open With" ) );
    00344     QString text;
    00345     if( _urls.count() == 1 )
    00346     {
    00347         text = i18n("<qt>Select the program that should be used to open <b>%1</b>. "
    00348                      "If the program is not listed, enter the name or click "
    00349                      "the browse button.</qt>").arg( _urls.first().fileName() );
    00350     }
    00351     else
    00352         // Should never happen ??
    00353         text = i18n( "Choose the name of the program with which to open the selected files." );
    00354     setServiceType( _urls );
    00355     init( text, QString() );
    00356 }
    00357
    00358 KOpenWithDlg::KOpenWithDlg( const KURL::List& _urls, const QString&_text,
    00359                             const QString& _value, QWidget *parent)
    00360              :QDialog( parent, "openwith", true )
    00361 {
    00362   QString caption = KStringHandler::csqueeze( _urls.first().prettyURL() );
    00363   if (_urls.count() > 1)
    00364       caption += QString::fromLatin1("...");
    00365   setCaption(caption);
    00366   setServiceType( _urls );
    00367   init( _text, _value );
    00368 }
    00369
    00370 KOpenWithDlg::KOpenWithDlg( const QString &serviceType, const QString& value,
    00371                             QWidget *parent)
    00372              :QDialog( parent, "openwith", true )
    00373 {
    00374     setCaption(i18n("Choose Application for %1").arg(serviceType));
    00375   QString text = i18n("<qt>Select the program for the file type: <b>%1</b>. "
    00376                       "If the program is not listed, enter the name or click "
    00377                       "the browse button.</qt>").arg(serviceType);
    00378   qServiceType = serviceType;
    00379   init( text, value );
    00380   if (remember)
    00381       remember->hide();
    00382 }
    00383
    00384 KOpenWithDlg::KOpenWithDlg( QWidget *parent)
    00385              :QDialog( parent, "openwith", true )
    00386 {
    00387   setCaption(i18n("Choose Application"));
    00388   QString text = i18n("<qt>Select a program. "
    00389                       "If the program is not listed, enter the name or click "
    00390                       "the browse button.</qt>");
    00391   qServiceType = QString::null;
    00392   init( text, QString::null );
    00393 }
    00394
    00395 void KOpenWithDlg::setServiceType( const KURL::List& _urls )
    00396 {
    00397   if ( _urls.count() == 1 )
    00398   {
    00399     qServiceType = KMimeType::findByURL( _urls.first())->name();
    00400     if (qServiceType == QString::fromLatin1("application/octet-stream"))
    00401       qServiceType = QString::null;
    00402   }
    00403   else
    00404       qServiceType = QString::null;
    00405 }
    00406
    00407 void KOpenWithDlg::init( const QString& _text, const QString& _value )
    00408 {
    00409   d = new KOpenWithDlgPrivate;
    00410   bool bReadOnly = kapp && !kapp->authorize("shell_access");
    00411   m_terminaldirty = false;
    00412   m_pTree = 0L;
    00413   m_pService = 0L;
    00414   d->curService = 0L;
    00415
    00416   QBoxLayout *topLayout = new QVBoxLayout( this, KDialog::marginHint(),
    00417           KDialog::spacingHint() );
    00418   label = new QLabel( _text, this );
    00419   topLayout->addWidget(label);
    00420
    00421   QHBoxLayout* hbox = new QHBoxLayout(topLayout);
    00422
    00423   QToolButton *clearButton = new QToolButton( this );
    00424   clearButton->setIconSet( BarIcon( "locationbar_erase" ) );
    00425   clearButton->setFixedSize( clearButton->sizeHint() );
    00426   connect( clearButton, SIGNAL( clicked() ), SLOT( slotClear() ) );
    00427   QToolTip::add( clearButton, i18n( "Clear input field" ) );
    00428
    00429   hbox->addWidget( clearButton );
    00430
    00431   if (!bReadOnly)
    00432   {
    00433     // init the history combo and insert it into the URL-Requester
    00434     KHistoryCombo *combo = new KHistoryCombo();
    00435     combo->setDuplicatesEnabled( false );
    00436     KConfig *kc = KGlobal::config();
    00437     KConfigGroupSaver ks( kc, QString::fromLatin1("Open-with settings") );
    00438     int max = kc->readNumEntry( QString::fromLatin1("Maximum history"), 15 );
    00439     combo->setMaxCount( max );
    00440     int mode = kc->readNumEntry(QString::fromLatin1("CompletionMode"),
    00441                 KGlobalSettings::completionMode());
    00442     combo->setCompletionMode((KGlobalSettings::Completion)mode);
    00443     QStringList list = kc->readListEntry( QString::fromLatin1("History") );
    00444     combo->setHistoryItems( list, true );
    00445     edit = new KURLRequester( combo, this );
    00446   }
    00447   else
    00448   {
    00449     clearButton->hide();
    00450     edit = new KURLRequester( this );
    00451     edit->lineEdit()->setReadOnly(true);
    00452     edit->button()->hide();
    00453   }
    00454
    00455   edit->setURL( _value );
    00456   QWhatsThis::add(edit,i18n(
    00457     "Following the command, you can have several place holders which will be replaced "
    00458     "with the actual values when the actual program is run:\n"
    00459     "%f - a single file name\n"
    00460     "%F - a list of files; use for applications that can open several local files at once\n"
    00461     "%u - a single URL\n"
    00462     "%U - a list of URLs\n"
    00463     "%d - the directory of the file to open\n"
    00464     "%D - a list of directories\n"
    00465     "%i - the icon\n"
    00466     "%m - the mini-icon\n"
    00467     "%c - the comment"));
    00468
    00469   hbox->addWidget(edit);
    00470
    00471   if ( edit->comboBox() ) {
    00472     KURLCompletion *comp = new KURLCompletion( KURLCompletion::ExeCompletion );
    00473     edit->comboBox()->setCompletionObject( comp );
    00474     edit->comboBox()->setAutoDeleteCompletionObject( true );
    00475   }
    00476
    00477   connect ( edit, SIGNAL(returnPressed()), SLOT(slotOK()) );
    00478   connect ( edit, SIGNAL(textChanged(const QString&)), SLOT(slotTextChanged()) );
    00479
    00480   m_pTree = new KApplicationTree( this );
    00481   topLayout->addWidget(m_pTree);
    00482
    00483   connect( m_pTree, SIGNAL( selected( const QString&, const QString& ) ),
    00484            SLOT( slotSelected( const QString&, const QString& ) ) );
    00485   connect( m_pTree, SIGNAL( highlighted( const QString&, const QString& ) ),
    00486            SLOT( slotHighlighted( const QString&, const QString& ) ) );
    00487   connect( m_pTree, SIGNAL( doubleClicked(QListViewItem*) ),
    00488            SLOT( slotDbClick() ) );
    00489
    00490   terminal = new QCheckBox( i18n("Run in &terminal"), this );
    00491   if (bReadOnly)
    00492      terminal->hide();
    00493   connect(terminal, SIGNAL(toggled(bool)), SLOT(slotTerminalToggled(bool)));
    00494
    00495   topLayout->addWidget(terminal);
    00496
    00497   QBoxLayout* nocloseonexitLayout = new QHBoxLayout( 0, 0, KDialog::spacingHint() );
    00498   QSpacerItem* spacer = new QSpacerItem( 20, 0, QSizePolicy::Fixed, QSizePolicy::Minimum );
    00499   nocloseonexitLayout->addItem( spacer );
    00500
    00501   nocloseonexit = new QCheckBox( i18n("&Do not close when command exits"), this );
    00502   nocloseonexit->setChecked( false );
    00503   nocloseonexit->setDisabled( true );
    00504
    00505   // check to see if we use konsole if not disable the nocloseonexit
    00506   // because we don't know how to do this on other terminal applications
    00507   KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") );
    00508   QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
    00509
    00510   if (bReadOnly || preferredTerminal != "konsole")
    00511      nocloseonexit->hide();
    00512
    00513   nocloseonexitLayout->addWidget( nocloseonexit );
    00514   topLayout->addLayout( nocloseonexitLayout );
    00515
    00516   if (!qServiceType.isNull())
    00517   {
    00518     remember = new QCheckBox(i18n("&Remember application association for this type of file"), this);
    00519     //    remember->setChecked(true);
    00520     topLayout->addWidget(remember);
    00521   }
    00522   else
    00523     remember = 0L;
    00524
    00525   // Use KButtonBox for the aligning pushbuttons nicely
    00526   KButtonBox* b = new KButtonBox( this );
    00527   b->addStretch( 2 );
    00528
    00529   d->ok = b->addButton( KStdGuiItem::ok() );
    00530   d->ok->setDefault( true );
    00531   connect(  d->ok, SIGNAL( clicked() ), SLOT( slotOK() ) );
    00532
    00533   QPushButton* cancel = b->addButton(  KStdGuiItem::cancel() );
    00534   connect(  cancel, SIGNAL( clicked() ), SLOT( reject() ) );
    00535
    00536   b->layout();
    00537   topLayout->addWidget( b );
    00538
    00539   //edit->setText( _value );
    00540   // This is what caused "can't click on items before clicking on Name header".
    00541   // Probably due to the resizeEvent handler using width().
    00542   //resize( minimumWidth(), sizeHint().height() );
    00543   edit->setFocus();
    00544   slotTextChanged();
    00545 }
    00546
    00547
    00548 // ----------------------------------------------------------------------
    00549
    00550 KOpenWithDlg::~KOpenWithDlg()
    00551 {
    00552     delete d;
    00553     d = 0;
    00554 }
    00555
    00556 // ----------------------------------------------------------------------
    00557
    00558 void KOpenWithDlg::slotClear()
    00559 {
    00560     edit->setURL(QString::null);
    00561     edit->setFocus();
    00562 }
    00563
    00564
    00565 // ----------------------------------------------------------------------
    00566
    00567 void KOpenWithDlg::slotSelected( const QString& /*_name*/, const QString& _exec )
    00568 {
    00569     kdDebug(250)<<"KOpenWithDlg::slotSelected"<<endl;
    00570     KService::Ptr pService = d->curService;
    00571     edit->setURL( _exec ); // calls slotTextChanged :(
    00572     d->curService = pService;
    00573 }
    00574
    00575
    00576 // ----------------------------------------------------------------------
    00577
    00578 void KOpenWithDlg::slotHighlighted( const QString& _name, const QString& )
    00579 {
    00580     kdDebug(250)<<"KOpenWithDlg::slotHighlighted"<<endl;
    00581     qName = _name;
    00582     d->curService = KService::serviceByName( qName );
    00583     if (!m_terminaldirty)
    00584     {
    00585         // ### indicate that default value was restored
    00586         terminal->setChecked(d->curService->terminal());
    00587         QString terminalOptions = d->curService->terminalOptions();
    00588         nocloseonexit->setChecked( (terminalOptions.contains( "--noclose" ) > 0) );
    00589         m_terminaldirty = false; // slotTerminalToggled changed it
    00590     }
    00591 }
    00592
    00593 // ----------------------------------------------------------------------
    00594
    00595 void KOpenWithDlg::slotTextChanged()
    00596 {
    00597     kdDebug(250)<<"KOpenWithDlg::slotTextChanged"<<endl;
    00598     // Forget about the service
    00599     d->curService = 0L;
    00600     d->ok->setEnabled( !edit->url().isEmpty());
    00601 }
    00602
    00603 // ----------------------------------------------------------------------
    00604
    00605 void KOpenWithDlg::slotTerminalToggled(bool)
    00606 {
    00607     // ### indicate that default value was overridden
    00608     m_terminaldirty = true;
    00609     nocloseonexit->setDisabled( ! terminal->isChecked() );
    00610 }
    00611
    00612 // ----------------------------------------------------------------------
    00613
    00614 void KOpenWithDlg::slotDbClick()
    00615 {
    00616    if (m_pTree->isDirSel() ) return; // check if a directory is selected
    00617    slotOK();
    00618 }
    00619
    00620 void KOpenWithDlg::setSaveNewApplications(bool b)
    00621 {
    00622   d->saveNewApps = b;
    00623 }
    00624
    00625 void KOpenWithDlg::slotOK()
    00626 {
    00627   QString fullExec(edit->url());
    00628
    00629   QString serviceName;
    00630   QString initialServiceName;
    00631   QString preferredTerminal;
    00632   m_pService = d->curService;
    00633   if (!m_pService) {
    00634     // No service selected - check the command line
    00635
    00636     // Find out the name of the service from the command line, removing args and paths
    00637     serviceName = KRun::binaryName( fullExec, true );
    00638     if (serviceName.isEmpty())
    00639     {
    00640       // TODO add a KMessageBox::error here after the end of the message freeze
    00641       return;
    00642     }
    00643     initialServiceName = serviceName;
    00644     kdDebug(250) << "initialServiceName=" << initialServiceName << endl;
    00645     int i = 1; // We have app, app-2, app-3... Looks better for the user.
    00646     bool ok = false;
    00647     // Check if there's already a service by that name, with the same Exec line
    00648     do {
    00649         kdDebug(250) << "looking for service " << serviceName << endl;
    00650         KService::Ptr serv = KService::serviceByDesktopName( serviceName );
    00651         ok = !serv; // ok if no such service yet
    00652         // also ok if we find the exact same service (well, "kwrite" == "kwrite %U"
    00653         if ( serv && serv->type() == "Application")
    00654         {
    00655             QString exec = serv->exec();
    00656             exec.replace("%u", "", false);
    00657             exec.replace("%f", "", false);
    00658             exec.replace("-caption %c", "");
    00659             exec.replace("-caption \"%c\"", "");
    00660             exec.replace("%i", "");
    00661             exec.replace("%m", "");
    00662             exec = exec.simplifyWhiteSpace();
    00663             if (exec == fullExec)
    00664             {
    00665                 ok = true;
    00666                 m_pService = serv;
    00667                 kdDebug(250) << k_funcinfo << "OK, found identical service: " << serv->desktopEntryPath() << endl;
    00668             }
    00669         }
    00670         if (!ok) // service was found, but it was different -> keep looking
    00671         {
    00672             ++i;
    00673             serviceName = initialServiceName + "-" + QString::number(i);
    00674         }
    00675     }
    00676     while (!ok);
    00677   }
    00678   if ( m_pService )
    00679   {
    00680     // Existing service selected
    00681     serviceName = m_pService->name();
    00682     initialServiceName = serviceName;
    00683   }
    00684
    00685   if (terminal->isChecked())
    00686   {
    00687     KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") );
    00688     preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
    00689     m_command = preferredTerminal;
    00690     // only add --noclose when we are sure it is konsole we're using
    00691     if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
    00692       m_command += QString::fromLatin1(" --noclose");
    00693     m_command += QString::fromLatin1(" -e ");
    00694     m_command += edit->url();
    00695     kdDebug(250) << "Setting m_command to " << m_command << endl;
    00696   }
    00697   if ( m_pService && terminal->isChecked() != m_pService->terminal() )
    00698       m_pService = 0L; // It's not exactly this service we're running
    00699
    00700   bool bRemember = remember && remember->isChecked();
    00701
    00702   if ( !bRemember && m_pService)
    00703   {
    00704     accept();
    00705     return;
    00706   }
    00707
    00708   if (!bRemember && !d->saveNewApps)
    00709   {
    00710     // Create temp service
    00711     m_pService = new KService(initialServiceName, fullExec, QString::null);
    00712     if (terminal->isChecked())
    00713     {
    00714       m_pService->setTerminal(true);
    00715       // only add --noclose when we are sure it is konsole we're using
    00716       if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
    00717          m_pService->setTerminalOptions("--noclose");
    00718     }
    00719     accept();
    00720     return;
    00721   }
    00722
    00723   // if we got here, we can't seem to find a service for what they
    00724   // wanted.  The other possibility is that they have asked for the
    00725   // association to be remembered.  Create/update service.
    00726
    00727   QString newPath;
    00728   QString oldPath;
    00729   QString menuId;
    00730   if (m_pService)
    00731   {
    00732     oldPath = m_pService->desktopEntryPath();
    00733     newPath = m_pService->locateLocal();
    00734     menuId = m_pService->menuId();
    00735     kdDebug(250) << "Updating exitsing service " << m_pService->desktopEntryPath() << " ( " << newPath << " ) " << endl;
    00736   }
    00737   else
    00738   {
    00739     newPath = KService::newServicePath(false /* hidden */, serviceName, &menuId);
    00740     kdDebug(250) << "Creating new service " << serviceName << " ( " << newPath << " ) " << endl;
    00741   }
    00742
    00743   int maxPreference = 1;
    00744   if (!qServiceType.isEmpty())
    00745   {
    00746     KServiceTypeProfile::OfferList offerList = KServiceTypeProfile::offers( qServiceType );
    00747     if (!offerList.isEmpty())
    00748       maxPreference = offerList.first().preference();
    00749   }
    00750
    00751   KDesktopFile *desktop = 0;
    00752   if (!oldPath.isEmpty() && (oldPath != newPath))
    00753   {
    00754      KDesktopFile orig(oldPath, true);
    00755      desktop = orig.copyTo(newPath);
    00756   }
    00757   else
    00758   {
    00759      desktop = new KDesktopFile(newPath);
    00760   }
    00761   desktop->writeEntry("Type", QString::fromLatin1("Application"));
    00762   desktop->writeEntry("Name", initialServiceName);
    00763   desktop->writePathEntry("Exec", fullExec);
    00764   if (terminal->isChecked())
    00765   {
    00766     desktop->writeEntry("Terminal", true);
    00767     // only add --noclose when we are sure it is konsole we're using
    00768     if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
    00769       desktop->writeEntry("TerminalOptions", "--noclose");
    00770   }
    00771   else
    00772   {
    00773     desktop->writeEntry("Terminal", false);
    00774   }
    00775   desktop->writeEntry("InitialPreference", maxPreference + 1);
    00776
    00777
    00778   if (bRemember)
    00779   {
    00780     QStringList mimeList = desktop->readListEntry("MimeType", ';');
    00781     if (!qServiceType.isEmpty() && !mimeList.contains(qServiceType))
    00782       mimeList.append(qServiceType);
    00783     desktop->writeEntry("MimeType", mimeList, ';');
    00784
    00785     if ( !qServiceType.isEmpty() )
    00786     {
    00787       // Also make sure the "auto embed" setting for this mimetype is off
    00788       KDesktopFile mimeDesktop( locateLocal( "mime", qServiceType + ".desktop" ) );
    00789       mimeDesktop.writeEntry( "X-KDE-AutoEmbed", false );
    00790       mimeDesktop.sync();
    00791     }
    00792   }
    00793
    00794   // write it all out to the file
    00795   desktop->sync();
    00796   delete desktop;
    00797
    00798   KService::rebuildKSycoca(this);
    00799
    00800   m_pService = KService::serviceByMenuId( menuId );
    00801
    00802   Q_ASSERT( m_pService );
    00803
    00804   accept();
    00805 }
    00806
    00807 QString KOpenWithDlg::text() const
    00808 {
    00809     if (!m_command.isEmpty())
    00810         return m_command;
    00811     else
    00812         return edit->url();
    00813 }
    00814
    00815 void KOpenWithDlg::hideNoCloseOnExit()
    00816 {
    00817     // uncheck the checkbox because the value could be used when "Run in Terminal" is selected
    00818     nocloseonexit->setChecked( false );
    00819     nocloseonexit->hide();
    00820 }
    00821
    00822 void KOpenWithDlg::hideRunInTerminal()
    00823 {
    00824     terminal->hide();
    00825     hideNoCloseOnExit();
    00826 }
    00827
    00828 void KOpenWithDlg::accept()
    00829 {
    00830     KHistoryCombo *combo = static_cast<KHistoryCombo*>( edit->comboBox() );
    00831     if ( combo ) {
    00832         combo->addToHistory( edit->url() );
    00833
    00834         KConfig *kc = KGlobal::config();
    00835         KConfigGroupSaver ks( kc, QString::fromLatin1("Open-with settings") );
    00836         kc->writeEntry( QString::fromLatin1("History"), combo->historyItems() );
    00837     kc->writeEntry(QString::fromLatin1("CompletionMode"),
    00838                combo->completionMode());
    00839         // don't store the completion-list, as it contains all of KURLCompletion's
    00840         // executables
    00841         kc->sync();
    00842     }
    00843
    00844     QDialog::accept();
    00845 }
    00846
    00847
    00849
    00850 #ifndef KDE_NO_COMPAT
    00851 bool KFileOpenWithHandler::displayOpenWithDialog( const KURL::List& urls )
    00852 {
    00853     KOpenWithDlg l( urls, i18n("Open with:"), QString::null, 0L );
    00854     if ( l.exec() )
    00855     {
    00856       KService::Ptr service = l.service();
    00857       if ( !!service )
    00858         return KRun::run( *service, urls );
    00859
    00860       kdDebug(250) << "No service set, running " << l.text() << endl;
    00861       return KRun::run( l.text(), urls );
    00862     }
    00863     return false;
    00864 }
    00865 #endif
    00866
    00867 #include "kopenwith.moc"
    00868 #include "kopenwith_p.moc"
    00869

This file is part of the documentation for kio Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:24:02 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003