00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <qfile.h>
00026 #include <qdir.h>
00027 #include <qdialog.h>
00028 #include <qpixmap.h>
00029 #include <qlabel.h>
00030 #include <qlayout.h>
00031 #include <qpushbutton.h>
00032 #include <qtoolbutton.h>
00033 #include <qcheckbox.h>
00034 #include <qtooltip.h>
00035 #include <qstyle.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
00059 #include "kopenwith.h"
00060 #include "kopenwith_p.h"
00061
00062 #include <kdebug.h>
00063 #include <assert.h>
00064 #include <stdlib.h>
00065
00066 template class QPtrList<QString>;
00067
00068 #define SORT_SPEC (QDir::DirsFirst | QDir::Name | QDir::IgnoreCase)
00069
00070
00071
00072
00073 KAppTreeListItem::KAppTreeListItem( KListView* parent, const QString & name,
00074 const QPixmap& pixmap, bool parse, bool dir, QString p, QString c )
00075 : QListViewItem( parent, name )
00076 {
00077 init(pixmap, parse, dir, p, c);
00078 }
00079
00080
00081
00082
00083 KAppTreeListItem::KAppTreeListItem( QListViewItem* parent, const QString & name,
00084 const QPixmap& pixmap, bool parse, bool dir, QString p, QString c )
00085 : QListViewItem( parent, name )
00086 {
00087 init(pixmap, parse, dir, p, c);
00088 }
00089
00090
00091
00092
00093 void KAppTreeListItem::init(const QPixmap& pixmap, bool parse, bool dir, QString _path, QString _exec)
00094 {
00095 setPixmap(0, pixmap);
00096 parsed = parse;
00097 directory = dir;
00098 path = _path;
00099 exec = _exec;
00100 }
00101
00102
00103
00104
00105
00106 QString KAppTreeListItem::key(int column, bool ) const
00107 {
00108 if (directory)
00109 return QString::fromLatin1(" ") + text(column).upper();
00110 else
00111 return text(column).upper();
00112 }
00113
00114 void KAppTreeListItem::activate()
00115 {
00116 if ( directory )
00117 setOpen(!isOpen());
00118 }
00119
00120 void KAppTreeListItem::setOpen( bool o )
00121 {
00122 if( o && !parsed ) {
00123 ((KApplicationTree *) parent())->addDesktopGroup( path, this );
00124 parsed = true;
00125 }
00126 QListViewItem::setOpen( o );
00127 }
00128
00129 bool KAppTreeListItem::isDirectory()
00130 {
00131 return directory;
00132 }
00133
00134
00135
00136 KApplicationTree::KApplicationTree( QWidget *parent )
00137 : KListView( parent ), currentitem(0)
00138 {
00139 addColumn( i18n("Known Applications") );
00140 setRootIsDecorated( true );
00141
00142 addDesktopGroup( QString::null );
00143
00144 connect( this, SIGNAL( currentChanged(QListViewItem*) ),
00145 SLOT( slotItemHighlighted(QListViewItem*) ) );
00146 connect( this, SIGNAL( selectionChanged(QListViewItem*) ),
00147 SLOT( slotSelectionChanged(QListViewItem*) ) );
00148 }
00149
00150
00151
00152 bool KApplicationTree::isDirSel()
00153 {
00154 if (!currentitem) return false;
00155 return currentitem->isDirectory();
00156 }
00157
00158
00159
00160 void KApplicationTree::addDesktopGroup( QString relPath, KAppTreeListItem *item)
00161 {
00162 KServiceGroup::Ptr root = KServiceGroup::group(relPath);
00163 if (!root || !root->isValid()) return;
00164
00165 KServiceGroup::List list = root->entries();
00166
00167 KAppTreeListItem * newItem;
00168 for( KServiceGroup::List::ConstIterator it = list.begin();
00169 it != list.end(); it++)
00170 {
00171 QString icon;
00172 QString text;
00173 QString relPath;
00174 QString exec;
00175 bool isDir = false;
00176 KSycocaEntry *p = (*it);
00177 if (p->isType(KST_KService))
00178 {
00179 KService *service = static_cast<KService *>(p);
00180
00181 if (service->noDisplay())
00182 continue;
00183
00184 icon = service->icon();
00185 text = service->name();
00186 exec = service->exec();
00187 }
00188 else if (p->isType(KST_KServiceGroup))
00189 {
00190 KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p);
00191
00192 if (serviceGroup->noDisplay())
00193 continue;
00194
00195 icon = serviceGroup->icon();
00196 text = serviceGroup->caption();
00197 relPath = serviceGroup->relPath();
00198 isDir = true;
00199 if ( text[0] == '.' )
00200 continue;
00201 }
00202 else
00203 {
00204 kdWarning(250) << "KServiceGroup: Unexpected object in list!" << endl;
00205 continue;
00206 }
00207
00208 QPixmap pixmap = SmallIcon( icon );
00209
00210 if (item)
00211 newItem = new KAppTreeListItem( item, text, pixmap, false, isDir,
00212 relPath, exec );
00213 else
00214 newItem = new KAppTreeListItem( this, text, pixmap, false, isDir,
00215 relPath, exec );
00216 if (isDir)
00217 newItem->setExpandable( true );
00218 }
00219 }
00220
00221
00222
00223
00224 void KApplicationTree::slotItemHighlighted(QListViewItem* i)
00225 {
00226
00227 if(!i)
00228 return;
00229
00230 KAppTreeListItem *item = (KAppTreeListItem *) i;
00231
00232 currentitem = item;
00233
00234 if( (!item->directory ) && (!item->exec.isEmpty()) )
00235 emit highlighted( item->text(0), item->exec );
00236 }
00237
00238
00239
00240
00241 void KApplicationTree::slotSelectionChanged(QListViewItem* i)
00242 {
00243
00244 if(!i)
00245 return;
00246
00247 KAppTreeListItem *item = (KAppTreeListItem *) i;
00248
00249 currentitem = item;
00250
00251 if( ( !item->directory ) && (!item->exec.isEmpty() ) )
00252 emit selected( item->text(0), item->exec );
00253 }
00254
00255
00256
00257 void KApplicationTree::resizeEvent( QResizeEvent * e)
00258 {
00259 setColumnWidth(0, width()-QApplication::style().pixelMetric(QStyle::PM_ScrollBarExtent)
00260 -2*QApplication::style().pixelMetric(QStyle::PM_DefaultFrameWidth));
00261 KListView::resizeEvent(e);
00262 }
00263
00264
00265
00266
00267
00268
00269
00270
00271 KOpenWithDlg::KOpenWithDlg( const KURL::List& _urls, QWidget* parent )
00272 :QDialog( parent, 0L, true )
00273 {
00274 setCaption( i18n( "Open With" ) );
00275 QString text;
00276 if( _urls.count() == 1 )
00277 {
00278 text = i18n("<qt>Select the program that should be used to open <b>%1</b>. "
00279 "If the program is not listed, enter the name or click "
00280 "the browse button.</qt>").arg( _urls.first().fileName() );
00281 }
00282 else
00283
00284 text = i18n( "Choose the name of the program with which to open the selected files." );
00285 setServiceType( _urls );
00286 init( text, QString() );
00287 }
00288
00289 KOpenWithDlg::KOpenWithDlg( const KURL::List& _urls, const QString&_text,
00290 const QString& _value, QWidget *parent)
00291 :QDialog( parent, 0L, true )
00292 {
00293 QString caption = KStringHandler::csqueeze( _urls.first().prettyURL() );
00294 if (_urls.count() > 1)
00295 caption += QString::fromLatin1("...");
00296 setCaption(caption);
00297 setServiceType( _urls );
00298 init( _text, _value );
00299 }
00300
00301 KOpenWithDlg::KOpenWithDlg( const QString &serviceType, const QString& value,
00302 QWidget *parent)
00303 :QDialog( parent, 0L, true )
00304 {
00305 setCaption(i18n("Choose Application for %1").arg(serviceType));
00306 QString text = i18n("<qt>Select the program for the file type: <b>%1</b>. "
00307 "If the program is not listed, enter the name or click "
00308 "the browse button.</qt>").arg(serviceType);
00309 qServiceType = serviceType;
00310 init( text, value );
00311 if (remember)
00312 {
00313 remember->setChecked( true );
00314 remember->hide();
00315 }
00316 }
00317
00318 KOpenWithDlg::KOpenWithDlg( QWidget *parent)
00319 :QDialog( parent, 0L, true )
00320 {
00321 setCaption(i18n("Choose Application"));
00322 QString text = i18n("<qt>Select a program. "
00323 "If the program is not listed, enter the name or click "
00324 "the browse button.</qt>");
00325 qServiceType = QString::null;
00326 init( text, QString::null );
00327 }
00328
00329 void KOpenWithDlg::setServiceType( const KURL::List& _urls )
00330 {
00331 if ( _urls.count() == 1 )
00332 {
00333 qServiceType = KMimeType::findByURL( _urls.first())->name();
00334 if (qServiceType == QString::fromLatin1("application/octet-stream"))
00335 qServiceType = QString::null;
00336 }
00337 else
00338 qServiceType = QString::null;
00339 }
00340
00341 void KOpenWithDlg::init( const QString& _text, const QString& _value )
00342 {
00343 bool bReadOnly = kapp && !kapp->authorize("shell_access");
00344 m_terminaldirty = false;
00345 m_pTree = 0L;
00346 m_pService = 0L;
00347
00348 QBoxLayout *topLayout = new QVBoxLayout( this, KDialog::marginHint(),
00349 KDialog::spacingHint() );
00350 label = new QLabel( _text, this );
00351 topLayout->addWidget(label);
00352
00353 QHBoxLayout* hbox = new QHBoxLayout(topLayout);
00354
00355 QToolButton *clearButton = new QToolButton( this );
00356 clearButton->setIconSet( BarIcon( "locationbar_erase" ) );
00357 clearButton->setFixedSize( clearButton->sizeHint() );
00358 connect( clearButton, SIGNAL( pressed() ), SLOT( slotClear() ) );
00359 QToolTip::add( clearButton, i18n( "Clear input field" ) );
00360
00361 hbox->addWidget( clearButton );
00362
00363 if (!bReadOnly)
00364 {
00365
00366 KHistoryCombo *combo = new KHistoryCombo();
00367 combo->setDuplicatesEnabled( false );
00368 KConfig *kc = KGlobal::config();
00369 KConfigGroupSaver ks( kc, QString::fromLatin1("Open-with settings") );
00370 int max = kc->readNumEntry( QString::fromLatin1("Maximum history"), 15 );
00371 combo->setMaxCount( max );
00372 int mode = kc->readNumEntry(QString::fromLatin1("CompletionMode"),
00373 KGlobalSettings::completionMode());
00374 combo->setCompletionMode((KGlobalSettings::Completion)mode);
00375 QStringList list = kc->readListEntry( QString::fromLatin1("History") );
00376 combo->setHistoryItems( list, true );
00377 edit = new KURLRequester( combo, this );
00378 }
00379 else
00380 {
00381 clearButton->hide();
00382 edit = new KURLRequester( this );
00383 edit->lineEdit()->setReadOnly(true);
00384 edit->button()->hide();
00385 }
00386
00387 edit->setURL( _value );
00388
00389 hbox->addWidget(edit);
00390
00391 if ( edit->comboBox() ) {
00392 KURLCompletion *comp = new KURLCompletion( KURLCompletion::ExeCompletion );
00393 edit->comboBox()->setCompletionObject( comp );
00394 }
00395
00396 connect ( edit, SIGNAL(returnPressed()), SLOT(slotOK()) );
00397 connect ( edit, SIGNAL(textChanged(const QString&)), SLOT(slotTextChanged()) );
00398
00399 m_pTree = new KApplicationTree( this );
00400 topLayout->addWidget(m_pTree);
00401
00402 connect( m_pTree, SIGNAL( selected( const QString&, const QString& ) ),
00403 SLOT( slotSelected( const QString&, const QString& ) ) );
00404 connect( m_pTree, SIGNAL( highlighted( const QString&, const QString& ) ),
00405 SLOT( slotHighlighted( const QString&, const QString& ) ) );
00406 connect( m_pTree, SIGNAL( doubleClicked(QListViewItem*) ),
00407 SLOT( slotDbClick() ) );
00408
00409 terminal = new QCheckBox( i18n("Run in &terminal"), this );
00410 if (bReadOnly)
00411 terminal->hide();
00412 connect(terminal, SIGNAL(toggled(bool)), SLOT(slotTerminalToggled(bool)));
00413
00414 topLayout->addWidget(terminal);
00415
00416 if (!qServiceType.isNull())
00417 {
00418 remember = new QCheckBox(i18n("&Remember application association for this type of file"), this);
00419
00420 topLayout->addWidget(remember);
00421 }
00422 else
00423 remember = 0L;
00424
00425
00426 KButtonBox* b = new KButtonBox( this );
00427 b->addStretch( 2 );
00428
00429 ok = b->addButton( i18n ( "&OK" ) );
00430 ok->setDefault( true );
00431 connect( ok, SIGNAL( clicked() ), SLOT( slotOK() ) );
00432
00433 cancel = b->addButton( i18n( "&Cancel" ) );
00434 connect( cancel, SIGNAL( clicked() ), SLOT( reject() ) );
00435
00436 b->layout();
00437 topLayout->addWidget( b );
00438
00439
00440
00441
00442
00443 edit->setFocus();
00444 }
00445
00446
00447
00448
00449 KOpenWithDlg::~KOpenWithDlg()
00450 {
00451 }
00452
00453
00454
00455 void KOpenWithDlg::slotClear()
00456 {
00457 edit->setURL(QString::null);
00458 edit->setFocus();
00459 }
00460
00461
00462
00463
00464 void KOpenWithDlg::slotSelected( const QString& , const QString& _exec )
00465 {
00466 kdDebug(250)<<"KOpenWithDlg::slotSelected"<<endl;
00467 KService::Ptr pService = m_pService;
00468 edit->setURL( _exec );
00469 m_pService = pService;
00470 }
00471
00472
00473
00474
00475 void KOpenWithDlg::slotHighlighted( const QString& _name, const QString& )
00476 {
00477 kdDebug(250)<<"KOpenWithDlg::slotHighlighted"<<endl;
00478 qName = _name;
00479 m_pService = KService::serviceByName( qName );
00480 if (!m_terminaldirty)
00481 {
00482
00483 terminal->setChecked(m_pService->terminal());
00484 m_terminaldirty = false;
00485 }
00486 }
00487
00488
00489
00490 void KOpenWithDlg::slotTextChanged()
00491 {
00492 kdDebug(250)<<"KOpenWithDlg::slotTextChanged"<<endl;
00493
00494 m_pService = 0L;
00495 }
00496
00497
00498
00499 void KOpenWithDlg::slotTerminalToggled(bool)
00500 {
00501
00502 m_terminaldirty = true;
00503 }
00504
00505
00506
00507 void KOpenWithDlg::slotDbClick()
00508 {
00509 if (m_pTree->isDirSel() ) return;
00510 slotOK();
00511 }
00512
00513 void KOpenWithDlg::slotOK()
00514 {
00515 QString fullExec(edit->url());
00516
00517 QString serviceName;
00518 QString pathName;
00519 QString initialServiceName;
00520 if (!m_pService) {
00521
00522
00523
00524 serviceName = KRun::binaryName( fullExec, true );
00525 if (serviceName.isEmpty())
00526 {
00527
00528 return;
00529 }
00530 initialServiceName = serviceName;
00531 int i = 1;
00532
00533 do {
00534 KService::Ptr serv = KService::serviceByDesktopName( serviceName );
00535 bool ok = !serv;
00536
00537 if ( serv &&
00538 serv->type() == "Application" && (
00539 serv->exec() == fullExec ||
00540 serv->exec() == fullExec + " %u" ||
00541 serv->exec() == fullExec + " %U" ||
00542 serv->exec() == fullExec + " %f" ||
00543 serv->exec() == fullExec + " %F"
00544 ) )
00545 {
00546 ok = true;
00547 m_pService = serv;
00548 }
00549 if (!ok)
00550 {
00551 ++i;
00552 serviceName = initialServiceName + "-" + QString::number(i);
00553 }
00554 }
00555 while (!ok);
00556 if ( !m_pService )
00557 {
00558
00559 pathName = ".hidden/";
00560 pathName += serviceName;
00561 }
00562 }
00563 if ( m_pService )
00564 {
00565
00566 serviceName = m_pService->name();
00567 initialServiceName = serviceName;
00568 pathName = m_pService->desktopEntryPath();
00569 }
00570
00571 if (terminal->isChecked()) {
00572 KSimpleConfig conf(QString::fromLatin1("konquerorrc"), true);
00573 conf.setGroup(QString::fromLatin1("Misc Defaults"));
00574 m_command = conf.readEntry(QString::fromLatin1("Terminal"), QString::fromLatin1("konsole"));
00575
00576 m_command += QString::fromLatin1(" -e ");
00577 m_command += edit->url();
00578 kdDebug(250) << "Setting m_command to " << m_command << endl;
00579 }
00580 if ( m_pService && terminal->isChecked() != m_pService->terminal() )
00581 m_pService = 0L;
00582
00583 if ( m_pService && ( !remember || !remember->isChecked() ) ) {
00584 accept();
00585 return;
00586 }
00587
00588
00589
00590
00591
00592 kdDebug(250) << "service pathName=" << pathName << endl;
00593 if (pathName.right(8) != QString::fromLatin1(".desktop"))
00594 pathName += QString::fromLatin1(".desktop");
00595 QString path(locateLocal("apps", pathName));
00596
00597 int maxPreference = 1;
00598 if (!qServiceType.isEmpty())
00599 {
00600 KServiceTypeProfile::OfferList offerList = KServiceTypeProfile::offers( qServiceType );
00601 if (!offerList.isEmpty())
00602 maxPreference = offerList.first().preference();
00603 }
00604
00605 KDesktopFile desktop(path);
00606 desktop.writeEntry(QString::fromLatin1("Type"), QString::fromLatin1("Application"));
00607 desktop.writeEntry(QString::fromLatin1("Name"), initialServiceName);
00608 desktop.writeEntry(QString::fromLatin1("Exec"), fullExec);
00609 desktop.writeEntry(QString::fromLatin1("InitialPreference"), maxPreference + 1);
00610 if (remember)
00611 if (remember->isChecked()) {
00612 QStringList mimeList;
00613 KDesktopFile oldDesktop(locate("apps", pathName), true);
00614 mimeList = oldDesktop.readListEntry(QString::fromLatin1("MimeType"), ';');
00615 if (!qServiceType.isEmpty() && !mimeList.contains(qServiceType))
00616 mimeList.append(qServiceType);
00617 desktop.writeEntry(QString::fromLatin1("MimeType"), mimeList, ';');
00618 if (terminal->isChecked())
00619 desktop.writeEntry(QString::fromLatin1("Terminal"), true);
00620 else
00621 desktop.writeEntry(QString::fromLatin1("Terminal"), false);
00622
00623 if ( !qServiceType.isEmpty() )
00624 {
00625
00626 KDesktopFile mimeDesktop( locateLocal( "mime", qServiceType + ".desktop" ) );
00627 mimeDesktop.writeEntry( QString::fromLatin1( "X-KDE-AutoEmbed" ), false );
00628 mimeDesktop.sync();
00629 }
00630 }
00631
00632
00633
00634 desktop.sync();
00635
00636 QApplication::setOverrideCursor( waitCursor );
00637
00638
00639 QStringList args;
00640 args.append("--incremental");
00641 KApplication::kdeinitExecWait( "kbuildsycoca", args );
00642
00643
00644 kdDebug(250) << "kbuildsycoca finished, looking for service " << pathName << endl;
00645
00646
00647
00648 QStringList lst;
00649 lst << QString::fromLatin1("apps");
00650 KSycoca::self()->notifyDatabaseChanged( lst );
00651
00652 m_pService = KService::serviceByDesktopPath( pathName );
00653 QApplication::restoreOverrideCursor();
00654
00655 Q_ASSERT( m_pService );
00656
00657 accept();
00658 }
00659
00660 QString KOpenWithDlg::text() const
00661 {
00662 if (!m_command.isEmpty())
00663 return m_command;
00664 else
00665 return edit->url();
00666 }
00667
00668 void KOpenWithDlg::accept()
00669 {
00670 KHistoryCombo *combo = static_cast<KHistoryCombo*>( edit->comboBox() );
00671 if ( combo ) {
00672 combo->addToHistory( edit->url() );
00673
00674 KConfig *kc = KGlobal::config();
00675 KConfigGroupSaver ks( kc, QString::fromLatin1("Open-with settings") );
00676 kc->writeEntry( QString::fromLatin1("History"), combo->historyItems() );
00677 kc->writeEntry(QString::fromLatin1("CompletionMode"),
00678 combo->completionMode());
00679
00680
00681 kc->sync();
00682 }
00683
00684 QDialog::accept();
00685 }
00686
00687
00689
00690 #ifndef KDE_NO_COMPAT
00691 bool KFileOpenWithHandler::displayOpenWithDialog( const KURL::List& urls )
00692 {
00693 KOpenWithDlg l( urls, i18n("Open with:"), QString::null, 0L );
00694 if ( l.exec() )
00695 {
00696 KService::Ptr service = l.service();
00697 if ( !!service )
00698 return KRun::run( *service, urls );
00699
00700 kdDebug(250) << "No service set, running " << l.text() << endl;
00701 return KRun::run( l.text(), urls );
00702 }
00703 return false;
00704 }
00705 #endif
00706
00707 #include "kopenwith.moc"
00708 #include "kopenwith_p.moc"
00709