kio Library API Documentation

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    KServiceGroup::List list = root->entries();
00191 
00192    KAppTreeListItem * newItem;
00193    for( KServiceGroup::List::ConstIterator it = list.begin();
00194        it != list.end(); it++)
00195    {
00196       QString icon;
00197       QString text;
00198       QString relPath;
00199       QString exec;
00200       bool isDir = false;
00201       KSycocaEntry *p = (*it);
00202       if (p->isType(KST_KService))
00203       {
00204          KService *service = static_cast<KService *>(p);
00205 
00206          if (service->noDisplay())
00207             continue;
00208 
00209          icon = service->icon();
00210          text = service->name();
00211          exec = service->exec();
00212       }
00213       else if (p->isType(KST_KServiceGroup))
00214       {
00215          KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p);
00216 
00217          if (serviceGroup->noDisplay())
00218             continue;
00219 
00220          icon = serviceGroup->icon();
00221          text = serviceGroup->caption();
00222          relPath = serviceGroup->relPath();
00223          isDir = true;
00224          //if ( text[0] == '.' ) // skip ".hidden" like kicker does
00225            //continue;
00226       }
00227       else
00228       {
00229          kdWarning(250) << "KServiceGroup: Unexpected object in list!" << endl;
00230          continue;
00231       }
00232 
00233       QPixmap pixmap = appIcon( icon );
00234 
00235       if (item)
00236          newItem = new KAppTreeListItem( item, text, pixmap, false, isDir,
00237                                          relPath, exec );
00238       else
00239          newItem = new KAppTreeListItem( this, text, pixmap, false, isDir,
00240                                          relPath, exec );
00241       if (isDir)
00242          newItem->setExpandable( true );
00243    }
00244 }
00245 
00246 
00247 // ----------------------------------------------------------------------
00248 
00249 void KApplicationTree::slotItemHighlighted(QListViewItem* i)
00250 {
00251     // i may be 0 (see documentation)
00252     if(!i)
00253         return;
00254 
00255     KAppTreeListItem *item = (KAppTreeListItem *) i;
00256 
00257     currentitem = item;
00258 
00259     if( (!item->directory ) && (!item->exec.isEmpty()) )
00260         emit highlighted( item->text(0), item->exec );
00261 }
00262 
00263 
00264 // ----------------------------------------------------------------------
00265 
00266 void KApplicationTree::slotSelectionChanged(QListViewItem* i)
00267 {
00268     // i may be 0 (see documentation)
00269     if(!i)
00270         return;
00271 
00272     KAppTreeListItem *item = (KAppTreeListItem *) i;
00273 
00274     currentitem = item;
00275 
00276     if( ( !item->directory ) && (!item->exec.isEmpty() ) )
00277         emit selected( item->text(0), item->exec );
00278 }
00279 
00280 // ----------------------------------------------------------------------
00281 
00282 void KApplicationTree::resizeEvent( QResizeEvent * e)
00283 {
00284     setColumnWidth(0, width()-QApplication::style().pixelMetric(QStyle::PM_ScrollBarExtent)
00285                          -2*QApplication::style().pixelMetric(QStyle::PM_DefaultFrameWidth));
00286     KListView::resizeEvent(e);
00287 }
00288 
00289 // Prune empty directories from the tree
00290 void KApplicationTree::cleanupTree()
00291 {
00292     QListViewItem *item=firstChild();
00293     while(item!=0)
00294     {
00295         if(item->isExpandable())
00296         {
00297             item->setOpen(true);
00298             if(item->childCount()==0) {
00299                 QListViewItem *current=item;
00300                 item=item->itemBelow();
00301                 delete current;
00302                 continue;
00303             }
00304             item=item->itemBelow();
00305             continue;
00306         }
00307         item=item->itemBelow();
00308     }
00309     item=firstChild();
00310     while(item!=0)
00311     {
00312         if(item->isExpandable())
00313         {
00314             QListViewItem *temp=item->itemBelow();
00315             if(item->text(0)!=i18n("Applications"))
00316                 item->setOpen(false);
00317             item=temp;
00318             continue;
00319         }
00320         item=item->itemBelow();
00321     }
00322 }
00323 
00324 /***************************************************************
00325  *
00326  * KOpenWithDlg
00327  *
00328  ***************************************************************/
00329 class KOpenWithDlgPrivate
00330 {
00331 public:
00332     KOpenWithDlgPrivate() : saveNewApps(false) { };
00333     QPushButton* ok;
00334     bool saveNewApps;
00335     KService::Ptr curService;
00336 };
00337 
00338 KOpenWithDlg::KOpenWithDlg( const KURL::List& _urls, QWidget* parent )
00339              :QDialog( parent, "openwith", true )
00340 {
00341     setCaption( i18n( "Open With" ) );
00342     QString text;
00343     if( _urls.count() == 1 )
00344     {
00345         text = i18n("<qt>Select the program that should be used to open <b>%1</b>. "
00346                      "If the program is not listed, enter the name or click "
00347                      "the browse button.</qt>").arg( _urls.first().fileName() );
00348     }
00349     else
00350         // Should never happen ??
00351         text = i18n( "Choose the name of the program with which to open the selected files." );
00352     setServiceType( _urls );
00353     init( text, QString() );
00354 }
00355 
00356 KOpenWithDlg::KOpenWithDlg( const KURL::List& _urls, const QString&_text,
00357                             const QString& _value, QWidget *parent)
00358              :QDialog( parent, "openwith", true )
00359 {
00360   QString caption = KStringHandler::csqueeze( _urls.first().prettyURL() );
00361   if (_urls.count() > 1)
00362       caption += QString::fromLatin1("...");
00363   setCaption(caption);
00364   setServiceType( _urls );
00365   init( _text, _value );
00366 }
00367 
00368 KOpenWithDlg::KOpenWithDlg( const QString &serviceType, const QString& value,
00369                             QWidget *parent)
00370              :QDialog( parent, "openwith", true )
00371 {
00372     setCaption(i18n("Choose Application for %1").arg(serviceType));
00373   QString text = i18n("<qt>Select the program for the file type: <b>%1</b>. "
00374                       "If the program is not listed, enter the name or click "
00375                       "the browse button.</qt>").arg(serviceType);
00376   qServiceType = serviceType;
00377   init( text, value );
00378   if (remember)
00379       remember->hide();
00380 }
00381 
00382 KOpenWithDlg::KOpenWithDlg( QWidget *parent)
00383              :QDialog( parent, "openwith", true )
00384 {
00385   setCaption(i18n("Choose Application"));
00386   QString text = i18n("<qt>Select a program. "
00387                       "If the program is not listed, enter the name or click "
00388                       "the browse button.</qt>");
00389   qServiceType = QString::null;
00390   init( text, QString::null );
00391 }
00392 
00393 void KOpenWithDlg::setServiceType( const KURL::List& _urls )
00394 {
00395   if ( _urls.count() == 1 )
00396   {
00397     qServiceType = KMimeType::findByURL( _urls.first())->name();
00398     if (qServiceType == QString::fromLatin1("application/octet-stream"))
00399       qServiceType = QString::null;
00400   }
00401   else
00402       qServiceType = QString::null;
00403 }
00404 
00405 void KOpenWithDlg::init( const QString& _text, const QString& _value )
00406 {
00407   d = new KOpenWithDlgPrivate;
00408   bool bReadOnly = kapp && !kapp->authorize("shell_access");
00409   m_terminaldirty = false;
00410   m_pTree = 0L;
00411   m_pService = 0L;
00412   d->curService = 0L;
00413 
00414   QBoxLayout *topLayout = new QVBoxLayout( this, KDialog::marginHint(),
00415           KDialog::spacingHint() );
00416   label = new QLabel( _text, this );
00417   topLayout->addWidget(label);
00418 
00419   QHBoxLayout* hbox = new QHBoxLayout(topLayout);
00420 
00421   QToolButton *clearButton = new QToolButton( this );
00422   clearButton->setIconSet( BarIcon( "locationbar_erase" ) );
00423   clearButton->setFixedSize( clearButton->sizeHint() );
00424   connect( clearButton, SIGNAL( clicked() ), SLOT( slotClear() ) );
00425   QToolTip::add( clearButton, i18n( "Clear input field" ) );
00426 
00427   hbox->addWidget( clearButton );
00428 
00429   if (!bReadOnly)
00430   {
00431     // init the history combo and insert it into the URL-Requester
00432     KHistoryCombo *combo = new KHistoryCombo();
00433     combo->setDuplicatesEnabled( false );
00434     KConfig *kc = KGlobal::config();
00435     KConfigGroupSaver ks( kc, QString::fromLatin1("Open-with settings") );
00436     int max = kc->readNumEntry( QString::fromLatin1("Maximum history"), 15 );
00437     combo->setMaxCount( max );
00438     int mode = kc->readNumEntry(QString::fromLatin1("CompletionMode"),
00439                 KGlobalSettings::completionMode());
00440     combo->setCompletionMode((KGlobalSettings::Completion)mode);
00441     QStringList list = kc->readListEntry( QString::fromLatin1("History") );
00442     combo->setHistoryItems( list, true );
00443     edit = new KURLRequester( combo, this );
00444   }
00445   else
00446   {
00447     clearButton->hide();
00448     edit = new KURLRequester( this );
00449     edit->lineEdit()->setReadOnly(true);
00450     edit->button()->hide();
00451   }
00452 
00453   edit->setURL( _value );
00454   QWhatsThis::add(edit,i18n(
00455     "Following the command, you can have several place holders which will be replaced "
00456     "with the actual values when the actual program is run:\n"
00457     "%f - a single file name\n"
00458     "%F - a list of files; use for applications that can open several local files at once\n"
00459     "%u - a single URL\n"
00460     "%U - a list of URLs\n"
00461     "%d - the directory of the file to open\n"
00462     "%D - a list of directories\n"
00463     "%i - the icon\n"
00464     "%m - the mini-icon\n"
00465     "%c - the comment"));
00466 
00467   hbox->addWidget(edit);
00468 
00469   if ( edit->comboBox() ) {
00470     KURLCompletion *comp = new KURLCompletion( KURLCompletion::ExeCompletion );
00471     edit->comboBox()->setCompletionObject( comp );
00472     edit->comboBox()->setAutoDeleteCompletionObject( true );
00473   }
00474 
00475   connect ( edit, SIGNAL(returnPressed()), SLOT(slotOK()) );
00476   connect ( edit, SIGNAL(textChanged(const QString&)), SLOT(slotTextChanged()) );
00477 
00478   m_pTree = new KApplicationTree( this );
00479   topLayout->addWidget(m_pTree);
00480 
00481   connect( m_pTree, SIGNAL( selected( const QString&, const QString& ) ),
00482            SLOT( slotSelected( const QString&, const QString& ) ) );
00483   connect( m_pTree, SIGNAL( highlighted( const QString&, const QString& ) ),
00484            SLOT( slotHighlighted( const QString&, const QString& ) ) );
00485   connect( m_pTree, SIGNAL( doubleClicked(QListViewItem*) ),
00486            SLOT( slotDbClick() ) );
00487 
00488   terminal = new QCheckBox( i18n("Run in &terminal"), this );
00489   if (bReadOnly)
00490      terminal->hide();
00491   connect(terminal, SIGNAL(toggled(bool)), SLOT(slotTerminalToggled(bool)));
00492 
00493   topLayout->addWidget(terminal);
00494 
00495   QBoxLayout* nocloseonexitLayout = new QHBoxLayout( 0, 0, KDialog::spacingHint() );
00496   QSpacerItem* spacer = new QSpacerItem( 20, 0, QSizePolicy::Fixed, QSizePolicy::Minimum );
00497   nocloseonexitLayout->addItem( spacer );
00498 
00499   nocloseonexit = new QCheckBox( i18n("&Do not close when command exits"), this );
00500   nocloseonexit->setChecked( false );
00501   nocloseonexit->setDisabled( true );
00502 
00503   // check to see if we use konsole if not disable the nocloseonexit
00504   // because we don't know how to do this on other terminal applications
00505   KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") );
00506   QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
00507 
00508   if (bReadOnly || preferredTerminal != "konsole")
00509      nocloseonexit->hide();
00510 
00511   nocloseonexitLayout->addWidget( nocloseonexit );
00512   topLayout->addLayout( nocloseonexitLayout );
00513 
00514   if (!qServiceType.isNull())
00515   {
00516     remember = new QCheckBox(i18n("&Remember application association for this type of file"), this);
00517     //    remember->setChecked(true);
00518     topLayout->addWidget(remember);
00519   }
00520   else
00521     remember = 0L;
00522 
00523   // Use KButtonBox for the aligning pushbuttons nicely
00524   KButtonBox* b = new KButtonBox( this );
00525   b->addStretch( 2 );
00526 
00527   d->ok = b->addButton( KStdGuiItem::ok() );
00528   d->ok->setDefault( true );
00529   connect(  d->ok, SIGNAL( clicked() ), SLOT( slotOK() ) );
00530 
00531   QPushButton* cancel = b->addButton(  KStdGuiItem::cancel() );
00532   connect(  cancel, SIGNAL( clicked() ), SLOT( reject() ) );
00533 
00534   b->layout();
00535   topLayout->addWidget( b );
00536 
00537   //edit->setText( _value );
00538   // This is what caused "can't click on items before clicking on Name header".
00539   // Probably due to the resizeEvent handler using width().
00540   //resize( minimumWidth(), sizeHint().height() );
00541   edit->setFocus();
00542   slotTextChanged();
00543 }
00544 
00545 
00546 // ----------------------------------------------------------------------
00547 
00548 KOpenWithDlg::~KOpenWithDlg()
00549 {
00550     delete d;
00551     d = 0;
00552 }
00553 
00554 // ----------------------------------------------------------------------
00555 
00556 void KOpenWithDlg::slotClear()
00557 {
00558     edit->setURL(QString::null);
00559     edit->setFocus();
00560 }
00561 
00562 
00563 // ----------------------------------------------------------------------
00564 
00565 void KOpenWithDlg::slotSelected( const QString& /*_name*/, const QString& _exec )
00566 {
00567     kdDebug(250)<<"KOpenWithDlg::slotSelected"<<endl;
00568     KService::Ptr pService = d->curService;
00569     edit->setURL( _exec ); // calls slotTextChanged :(
00570     d->curService = pService;
00571 }
00572 
00573 
00574 // ----------------------------------------------------------------------
00575 
00576 void KOpenWithDlg::slotHighlighted( const QString& _name, const QString& )
00577 {
00578     kdDebug(250)<<"KOpenWithDlg::slotHighlighted"<<endl;
00579     qName = _name;
00580     d->curService = KService::serviceByName( qName );
00581     if (!m_terminaldirty)
00582     {
00583         // ### indicate that default value was restored
00584         terminal->setChecked(d->curService->terminal());
00585         QString terminalOptions = d->curService->terminalOptions();
00586         nocloseonexit->setChecked( (terminalOptions.contains( "--noclose" ) > 0) );
00587         m_terminaldirty = false; // slotTerminalToggled changed it
00588     }
00589 }
00590 
00591 // ----------------------------------------------------------------------
00592 
00593 void KOpenWithDlg::slotTextChanged()
00594 {
00595     kdDebug(250)<<"KOpenWithDlg::slotTextChanged"<<endl;
00596     // Forget about the service
00597     d->curService = 0L;
00598     d->ok->setEnabled( !edit->url().isEmpty());
00599 }
00600 
00601 // ----------------------------------------------------------------------
00602 
00603 void KOpenWithDlg::slotTerminalToggled(bool)
00604 {
00605     // ### indicate that default value was overridden
00606     m_terminaldirty = true;
00607     nocloseonexit->setDisabled( ! terminal->isChecked() );
00608 }
00609 
00610 // ----------------------------------------------------------------------
00611 
00612 void KOpenWithDlg::slotDbClick()
00613 {
00614    if (m_pTree->isDirSel() ) return; // check if a directory is selected
00615    slotOK();
00616 }
00617 
00618 void KOpenWithDlg::setSaveNewApplications(bool b)
00619 {
00620   d->saveNewApps = b;
00621 }
00622 
00623 void KOpenWithDlg::slotOK()
00624 {
00625   QString fullExec(edit->url());
00626 
00627   QString serviceName;
00628   QString initialServiceName;
00629   QString preferredTerminal;
00630   m_pService = d->curService;
00631   if (!m_pService) {
00632     // No service selected - check the command line
00633 
00634     // Find out the name of the service from the command line, removing args and paths
00635     serviceName = KRun::binaryName( fullExec, true );
00636     if (serviceName.isEmpty())
00637     {
00638       // TODO add a KMessageBox::error here after the end of the message freeze
00639       return;
00640     }
00641     initialServiceName = serviceName;
00642     kdDebug(250) << "initialServiceName=" << initialServiceName << endl;
00643     int i = 1; // We have app, app-2, app-3... Looks better for the user.
00644     bool ok = false;
00645     // Check if there's already a service by that name, with the same Exec line
00646     do {
00647         kdDebug(250) << "looking for service " << serviceName << endl;
00648         KService::Ptr serv = KService::serviceByDesktopName( serviceName );
00649         ok = !serv; // ok if no such service yet
00650         // also ok if we find the exact same service (well, "kwrite" == "kwrite %U"
00651         if ( serv && serv->type() == "Application")
00652         {
00653             QString exec = serv->exec();
00654             exec.replace("%u", "", false);
00655             exec.replace("%f", "", false);
00656             exec.replace("-caption %c", "");
00657             exec.replace("-caption \"%c\"", "");
00658             exec.replace("%i", "");
00659             exec.replace("%m", "");
00660             exec = exec.simplifyWhiteSpace();
00661             if (exec == fullExec)
00662             {
00663                 ok = true;
00664                 m_pService = serv;
00665                 kdDebug(250) << k_funcinfo << "OK, found identical service: " << serv->desktopEntryPath() << endl;
00666             }
00667         }
00668         if (!ok) // service was found, but it was different -> keep looking
00669         {
00670             ++i;
00671             serviceName = initialServiceName + "-" + QString::number(i);
00672         }
00673     }
00674     while (!ok);
00675   }
00676   if ( m_pService )
00677   {
00678     // Existing service selected
00679     serviceName = m_pService->name();
00680     initialServiceName = serviceName;
00681   }
00682 
00683   if (terminal->isChecked())
00684   {
00685     KConfigGroup confGroup( KGlobal::config(), QString::fromLatin1("General") );
00686     preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
00687     m_command = preferredTerminal;
00688     // only add --noclose when we are sure it is konsole we're using
00689     if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
00690       m_command += QString::fromLatin1(" --noclose");
00691     m_command += QString::fromLatin1(" -e ");
00692     m_command += edit->url();
00693     kdDebug(250) << "Setting m_command to " << m_command << endl;
00694   }
00695   if ( m_pService && terminal->isChecked() != m_pService->terminal() )
00696       m_pService = 0L; // It's not exactly this service we're running
00697 
00698   bool bRemember = remember && remember->isChecked();
00699 
00700   if ( !bRemember && m_pService)
00701   {
00702     accept();
00703     return;
00704   }
00705 
00706   if (!bRemember && !d->saveNewApps)
00707   {
00708     // Create temp service
00709     m_pService = new KService(initialServiceName, fullExec, QString::null);
00710     if (terminal->isChecked())
00711     {
00712       m_pService->setTerminal(true);
00713       // only add --noclose when we are sure it is konsole we're using
00714       if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
00715          m_pService->setTerminalOptions("--noclose");
00716     }
00717     accept();
00718     return;
00719   }
00720 
00721   // if we got here, we can't seem to find a service for what they
00722   // wanted.  The other possibility is that they have asked for the
00723   // association to be remembered.  Create/update service.
00724 
00725   QString newPath;
00726   QString oldPath;
00727   QString menuId;
00728   if (m_pService)
00729   {
00730     oldPath = m_pService->desktopEntryPath();
00731     newPath = m_pService->locateLocal();
00732     menuId = m_pService->menuId();
00733     kdDebug(250) << "Updating exitsing service " << m_pService->desktopEntryPath() << " ( " << newPath << " ) " << endl;
00734   }
00735   else
00736   {
00737     newPath = KService::newServicePath(false /* hidden */, serviceName, &menuId);
00738     kdDebug(250) << "Creating new service " << serviceName << " ( " << newPath << " ) " << endl;
00739   }
00740 
00741   int maxPreference = 1;
00742   if (!qServiceType.isEmpty())
00743   {
00744     KServiceTypeProfile::OfferList offerList = KServiceTypeProfile::offers( qServiceType );
00745     if (!offerList.isEmpty())
00746       maxPreference = offerList.first().preference();
00747   }
00748   QString menuElement;
00749   menuElement="?package(menu): needs=\"x11\" section=\".hidden\" ";
00750   KDesktopFile *desktop = 0;
00751   if (!oldPath.isEmpty() && (oldPath != newPath))
00752   {
00753      KDesktopFile orig(oldPath, true);
00754      if ( m_pService )
00755          desktop = orig.copyTo( pathToCopyEntry(newPath, m_pService->menuId() ) );
00756      else
00757          desktop = orig.copyTo(newPath);
00758   }
00759   else
00760   {
00761      if ( m_pService )
00762          desktop = new KDesktopFile(pathToCopyEntry(newPath, m_pService->menuId() ) );
00763      else
00764          desktop = new KDesktopFile(newPath);
00765   }
00766   desktop->writeEntry("Type", QString::fromLatin1("Application"));
00767   desktop->writeEntry("Name", initialServiceName);
00768   desktop->writePathEntry("Exec", fullExec);
00769   menuElement+="command=\"";
00770   menuElement+=fullExec+"\" ";
00771   menuElement+="title=\"";
00772   menuElement+=initialServiceName+"\" ";
00773   QString kdeOpt = "kde_opt=\"";
00774   if (terminal->isChecked())
00775   {
00776     desktop->writeEntry("Terminal", true);
00777     kdeOpt+="Terminal=1\\\\n";
00778     // only add --noclose when we are sure it is konsole we're using
00779     if (preferredTerminal == "konsole" && nocloseonexit->isChecked())
00780     {
00781       desktop->writeEntry("TerminalOptions", "--noclose");
00782     kdeOpt+=" TerminalOptions=--noclose\\\\n";
00783     }
00784   }
00785   else
00786   {
00787     desktop->writeEntry("Terminal", false);
00788   }
00789   desktop->writeEntry("InitialPreference", maxPreference + 1);
00790   kdeOpt+=QString( "InitialPreference=%1\\\\n" ).arg( maxPreference + 1 );
00791 
00792   if (bRemember || d->saveNewApps)
00793   {
00794     QStringList mimeList = desktop->readListEntry("MimeType", ';');
00795     if (!qServiceType.isEmpty() && !mimeList.contains(qServiceType))
00796       mimeList.append(qServiceType);
00797     desktop->writeEntry("MimeType", mimeList, ';');
00798     menuElement+=QString( "mimetypes=\"%1\"" ).arg( mimeList.join( ";") );
00799     if ( !qServiceType.isEmpty() )
00800     {
00801       // Also make sure the "auto embed" setting for this mimetype is off
00802       KDesktopFile mimeDesktop( locateLocal( "mime", qServiceType + ".desktop" ) );
00803       mimeDesktop.writeEntry( "X-KDE-AutoEmbed", false );
00804       mimeDesktop.sync();
00805     }
00806   }
00807 
00808   if ( newPath.contains( "Mandrakelinux/.hidden" ) && ( KStandardDirs::menu_type_by_version()!="kde" ))
00809   {
00810       QStringList categorieList = desktop->readListEntry("Categories", ';');
00811       if ( !categorieList.contains("X-Mandrakelinux-.hidden"))
00812           categorieList.append("X-Mandrakelinux-.hidden");
00813       desktop->writeEntry( "Categories", categorieList, ";" );
00814       //?package(xterm):  needs=X11  section="System/Terminals"  title="XTerm"  longtitle="The standard terminal emulator for the X Window System"  command="/usr/X11R6/bin/xterm -name Terminal"  icon="xterm-terminal.png"
00815       menuElement+=" " +kdeOpt+"\"";
00816       saveInMDKMenuStructure( initialServiceName,menuElement );
00817   }
00818   // write it all out to the file
00819   desktop->sync();
00820   delete desktop;
00821 
00822   KService::rebuildKSycoca(this);
00823 
00824   m_pService = KService::serviceByMenuId( menuId );
00825 
00826   Q_ASSERT( m_pService );
00827 
00828   accept();
00829 }
00830 
00831 void KOpenWithDlg::saveInMDKMenuStructure( const QString & filename, const QString &menuElement )
00832 {
00833     QString menuPath;
00834     QString tmp =KStandardDirs::menu_type_by_version();
00835     if( tmp=="kde")
00836         return;
00837     else if ( tmp=="mdk" )
00838     {
00839         menuPath=".menu/";
00840     }
00841     else if ( tmp == "mdk-simplified" )
00842     {
00843         menuPath=".menu-simplified/";
00844     }
00845     else
00846     {
00847         kdDebug()<<" Error in type of menu\n";
00848         return;
00849     }
00850     QFile menuStamp(QDir::homeDirPath ()+"/.menu-updates.stamp");
00851     if( menuStamp.exists())
00852             menuStamp.remove();
00853     QDir dir;
00854     dir.mkdir( QDir::homeDirPath ()+"/"+menuPath );
00855     QFile saveMenuMDK( QDir::homeDirPath ()+"/"+menuPath+filename );
00856     if ( saveMenuMDK.open( IO_WriteOnly ) ) {
00857         QTextStream stream( &saveMenuMDK );
00858         stream<<menuElement<<"\n";
00859         saveMenuMDK.close();
00860     }
00861 }
00862 
00863 QString KOpenWithDlg::pathToCopyEntry( QString path, QString menuId )
00864 {
00865    if( KStandardDirs::menu_type_by_version()=="kde")
00866            return path;
00867    QString tmpPath = path.remove( menuId );
00868     QString element;
00869     element = menuId.remove( "Mandrakelinux-" );
00870     element=element.replace( QChar( '-' ), "/" );
00871     QString newPath = tmpPath+"Mandrakelinux/"+element;
00872    KURL url(newPath);
00873     KStandardDirs::makeDir( url.directory() );
00874    return newPath;
00875 }
00876 
00877 QString KOpenWithDlg::text() const
00878 {
00879     if (!m_command.isEmpty())
00880         return m_command;
00881     else
00882         return edit->url();
00883 }
00884 
00885 void KOpenWithDlg::hideNoCloseOnExit()
00886 {
00887     // uncheck the checkbox because the value could be used when "Run in Terminal" is selected
00888     nocloseonexit->setChecked( false );
00889     nocloseonexit->hide();
00890 }
00891 
00892 void KOpenWithDlg::hideRunInTerminal()
00893 {
00894     terminal->hide();
00895     hideNoCloseOnExit();
00896 }
00897 
00898 void KOpenWithDlg::accept()
00899 {
00900     KHistoryCombo *combo = static_cast<KHistoryCombo*>( edit->comboBox() );
00901     if ( combo ) {
00902         combo->addToHistory( edit->url() );
00903 
00904         KConfig *kc = KGlobal::config();
00905         KConfigGroupSaver ks( kc, QString::fromLatin1("Open-with settings") );
00906         kc->writeEntry( QString::fromLatin1("History"), combo->historyItems() );
00907     kc->writeEntry(QString::fromLatin1("CompletionMode"),
00908                combo->completionMode());
00909         // don't store the completion-list, as it contains all of KURLCompletion's
00910         // executables
00911         kc->sync();
00912     }
00913 
00914     QDialog::accept();
00915 }
00916 
00917 
00919 
00920 #ifndef KDE_NO_COMPAT
00921 bool KFileOpenWithHandler::displayOpenWithDialog( const KURL::List& urls )
00922 {
00923     KOpenWithDlg l( urls, i18n("Open with:"), QString::null, 0L );
00924     if ( l.exec() )
00925     {
00926       KService::Ptr service = l.service();
00927       if ( !!service )
00928         return KRun::run( *service, urls );
00929 
00930       kdDebug(250) << "No service set, running " << l.text() << endl;
00931       return KRun::run( l.text(), urls );
00932     }
00933     return false;
00934 }
00935 #endif
00936 
00937 #include "kopenwith.moc"
00938 #include "kopenwith_p.moc"
00939 
KDE Logo
This file is part of the documentation for kio Library Version 3.3.90.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 30 10:15:30 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003