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 "kateexternaltools.h"
00026 #include "kateexternaltools.moc"
00027 #include "katedocmanager.h"
00028
00029 #include "katemainwindow.h"
00030
00031 #include <kate/view.h>
00032 #include <kate/document.h>
00033
00034 #include <klistbox.h>
00035 #include <klocale.h>
00036 #include <kiconloader.h>
00037 #include <kmessagebox.h>
00038 #include <kconfig.h>
00039 #include <krun.h>
00040 #include <kicondialog.h>
00041
00042 #include <qbitmap.h>
00043 #include <qfile.h>
00044 #include <qpushbutton.h>
00045 #include <qlineedit.h>
00046 #include <qlayout.h>
00047 #include <qlabel.h>
00048 #include <qlistbox.h>
00049 #include <qmap.h>
00050 #include <qregexp.h>
00051 #include <qwhatsthis.h>
00052
00053 #include <stdlib.h>
00054 #include <unistd.h>
00055
00056 #include <kdebug.h>
00057
00058
00059 KateExternalTool::KateExternalTool( const QString &name,
00060 const QString &command,
00061 const QString &icon,
00062 const QString &tryexec,
00063 const QStringList &mimetypes,
00064 const QString &acname )
00065 : name ( name ),
00066 command ( command ),
00067 icon ( icon ),
00068 tryexec ( tryexec ),
00069 mimetypes ( mimetypes ),
00070 acname ( acname )
00071 {
00072
00073 hasexec = checkExec();
00074 }
00075
00076 bool KateExternalTool::checkExec()
00077 {
00078
00079 if ( tryexec.isEmpty() )
00080 tryexec = command.section( " ", 0, 0, QString::SectionSkipEmpty );
00081
00082
00083 if (!tryexec.isEmpty()) {
00084 if (tryexec[0] == '/') {
00085 if (::access(QFile::encodeName(tryexec), R_OK | X_OK))
00086 return false;
00087
00088 m_exec = tryexec;
00089 } else {
00090
00091
00092
00093 QStringList dirs = QStringList::split(':', QFile::decodeName(::getenv("PATH")));
00094 QStringList::Iterator it(dirs.begin());
00095 bool match = false;
00096 for (; it != dirs.end(); ++it)
00097 {
00098 QString fName = *it + "/" + tryexec;
00099 if (::access(QFile::encodeName(fName), R_OK | X_OK) == 0)
00100 {
00101 match = true;
00102 m_exec = fName;
00103 break;
00104 }
00105 }
00106
00107 if (!match)
00108 return false;
00109 }
00110 return true;
00111 }
00112 return false;
00113 }
00114
00115 bool KateExternalTool::valid( QString mt ) const
00116 {
00117 return mimetypes.isEmpty() || mimetypes.contains( mt );
00118 }
00119
00120
00121
00122 KateExternalToolAction::KateExternalToolAction( QObject *parent,
00123 const char *name, KateExternalTool *t)
00124 : KAction( parent, name ),
00125 tool ( t )
00126 {
00127 setText( t->name );
00128 if ( ! t->icon.isEmpty() )
00129 setIconSet( SmallIconSet( t->icon ) );
00130
00131 connect( this ,SIGNAL(activated()), this, SLOT(slotRun()) );
00132 }
00133
00134 bool KateExternalToolAction::expandMacro( const QString &str, QStringList &ret )
00135 {
00136 KateMainWindow *mw = ((KateExternalToolsMenuAction*)parent()->parent())->mainwindow;
00137 Kate::View *view = mw->viewManager()->activeView();
00138
00139 if ( str == "URL" )
00140 ret += mw->activeDocumentUrl().url();
00141 else if ( str == "directory" )
00142 ret += mw->activeDocumentUrl().directory();
00143 else if ( str == "filename" )
00144 ret += mw->activeDocumentUrl().filename();
00145 else if ( str == "line" )
00146 ret += QString::number( view->cursorLine() );
00147 else if ( str == "col" )
00148 ret += QString::number( view->cursorColumn() );
00149 else if ( str == "selection" )
00150 ret += view->getDoc()->selection();
00151 else if ( str == "text" )
00152 ret += view->getDoc()->text();
00153 else if ( str == "URLs" ) {
00154 for( Kate::Document *doc = mw->m_docManager->firstDocument(); doc; doc = mw->m_docManager->nextDocument() )
00155 if ( ! doc->url().isEmpty() )
00156 ret += doc->url().url();
00157 } else
00158 return false;
00159 return true;
00160 }
00161
00162 void KateExternalToolAction::slotRun()
00163 {
00164
00165
00166 QString cmd = tool->command;
00167
00168 expandMacrosShellQuote( cmd );
00169
00170 kdDebug()<<"=== Running command: "<<cmd<<endl;
00171 KRun::runCommand( cmd, tool->tryexec, tool->icon );
00172 }
00173
00174
00175
00176 KateExternalToolsMenuAction::KateExternalToolsMenuAction( const QString &text,
00177 QObject *parent,
00178 const char* name,
00179 KateMainWindow *mw )
00180 : KActionMenu( text, parent, name ),
00181 mainwindow( mw )
00182 {
00183
00184 m_actionCollection = new KActionCollection( this );
00185
00186
00187
00188 reload();
00189 }
00190
00191 void KateExternalToolsMenuAction::reload()
00192 {
00193 m_actionCollection->clear();
00194
00195 popupMenu()->clear();
00196
00197
00198 KConfig *config = new KConfig("externaltools", false, false, "appdata");
00199 config->setGroup("Global");
00200 QStringList tools = config->readListEntry("tools");
00201
00202
00203
00204 for( QStringList::Iterator it = tools.begin(); it != tools.end(); ++it )
00205 {
00206 if ( *it == "---" )
00207 {
00208 popupMenu()->insertSeparator();
00209
00210 continue;
00211 }
00212
00213 config->setGroup( *it );
00214
00215 KateExternalTool *t = new KateExternalTool(
00216 config->readEntry( "name", "" ),
00217 config->readEntry( "command", ""),
00218 config->readEntry( "icon", ""),
00219 config->readEntry( "executable", ""),
00220 config->readListEntry( "mimetypes" ),
00221 config->readEntry( "acname", "" ) );
00222
00223 if ( t->hasexec )
00224 insert( new KateExternalToolAction( m_actionCollection, t->acname.ascii(), t ) );
00225 }
00226
00227 m_actionCollection->readShortcutSettings( "Shortcuts", config );
00228 delete config;
00229 }
00230
00231 void KateExternalToolsMenuAction::slotDocumentChanged()
00232 {
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244 }
00245
00246
00247
00252 class ToolItem : public QListBoxPixmap
00253 {
00254 public:
00255 ToolItem( QListBox *lb, const QPixmap &icon, KateExternalTool *tool )
00256 : QListBoxPixmap( lb, icon, tool->name ),
00257 tool ( tool )
00258 {;}
00259
00260 ~ToolItem() {};
00261
00262 KateExternalTool *tool;
00263 };
00264
00265
00266
00267 KateExternalToolServiceEditor::KateExternalToolServiceEditor( KateExternalTool *tool,
00268 QWidget *parent, const char *name )
00269 : KDialogBase( parent, name, true, i18n("Edit External Tool"), KDialogBase::Ok|KDialogBase::Cancel ),
00270 tool( tool )
00271 {
00272
00273
00274 QWidget *w = new QWidget( this );
00275 setMainWidget( w );
00276 QGridLayout *lo = new QGridLayout( w );
00277 lo->setSpacing( KDialogBase::spacingHint() );
00278
00279 QLabel *l;
00280
00281 leName = new QLineEdit( w );
00282 lo->addWidget( leName, 1, 2 );
00283 l = new QLabel( leName, i18n("&Name:"), w );
00284 l->setAlignment( l->alignment()|Qt::AlignRight );
00285 lo->addWidget( l, 1, 1 );
00286 if ( tool ) leName->setText( tool->name );
00287 QWhatsThis::add( leName, i18n(
00288 "The name will be displayed in the 'Tools->External' menu") );
00289
00290 leCommand = new QLineEdit( w );
00291 lo->addWidget( leCommand, 2, 2 );
00292 l = new QLabel( leCommand, i18n("Co&mmand:"), w );
00293 l->setAlignment( l->alignment()|Qt::AlignRight );
00294 lo->addWidget( l, 2, 1 );
00295 if ( tool ) leCommand->setText( tool->command );
00296 QWhatsThis::add( leCommand, i18n(
00297 "<p>The command to execute to invoke the tool. The following macros "
00298 "will be expanded:</p>"
00299 "<ul><li><code>%URL</code> - the URL of the current document."
00300 "<li><code>%URLs</code> - a list of the URLs of all open documents."
00301 "<li><code>%directory</code> - the URL of the directory containing "
00302 "the current document."
00303 "<li><code>%filename</code> - the filename of the current document."
00304 "<li><code>%line</code> - the current line of the text cursor in the "
00305 "current view."
00306 "<li><code>%column</code> - the column of the text cursor in the "
00307 "current view."
00308 "<li><code>%selection</code> - the selected text in the current view."
00309 "<li><code>%text</code> - the text of the current document.</ul>" ) );
00310
00311 btnIcon = new KIconButton( w );
00312 btnIcon->setIconSize( KIcon::SizeMedium );
00313 lo->addMultiCellWidget( btnIcon, 1, 2, 3, 3 );
00314 if ( tool && !tool->icon.isEmpty() )
00315 btnIcon->setIcon( tool->icon );
00316
00317
00318 leExecutable = new QLineEdit( w );
00319 lo->addWidget( leExecutable, 3, 2 );
00320 l = new QLabel( leExecutable, i18n("&Executable:"), w );
00321 l->setAlignment( l->alignment()|Qt::AlignRight );
00322 lo->addWidget( l, 3, 1 );
00323 if ( tool ) leExecutable->setText( tool->tryexec );
00324 QWhatsThis::add( leExecutable, i18n(
00325 "The executable used by the command. This is used to check if a tool "
00326 "should be displayed; if not set, the first word of <em>command</em> "
00327 "will be used.") );
00328
00329 leMimetypes = new QLineEdit( w );
00330 lo->addWidget( leMimetypes, 4, 2 );
00331 l = new QLabel( leMimetypes, i18n("&Mime types:"), w );
00332 l->setAlignment( l->alignment()|Qt::AlignRight );
00333 lo->addWidget( l, 4, 1 );
00334 if ( tool ) leMimetypes->setText( tool->mimetypes.join("; ") );
00335 QWhatsThis::add( leMimetypes, i18n(
00336 "A semicolon-separated list of mime types for which this tool should "
00337 "be available; if this is left empty, the tool is always available. "
00338 "To choose from known mimetypes, press the button on the right.") );
00339 }
00340
00341 void KateExternalToolServiceEditor::slotOk()
00342 {
00343 if ( leName->text().isEmpty() ||
00344 leCommand->text().isEmpty() )
00345 {
00346 KMessageBox::information( this, i18n("You must specify at least a name and a command") );
00347 return;
00348 }
00349
00350 KDialogBase::slotOk();
00351 }
00352
00353
00354
00355 KateExternalToolsConfigWidget::KateExternalToolsConfigWidget( QWidget *parent, const char* name )
00356 : Kate::ConfigPage( parent, name )
00357 {
00358 QGridLayout *lo = new QGridLayout( this, 5, 5, 0, KDialog::spacingHint() );
00359
00360 lbTools = new KListBox( this );
00361 lo->addMultiCellWidget( lbTools, 1, 4, 0, 3 );
00362 connect( lbTools, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()) );
00363
00364 btnNew = new QPushButton( i18n("&New..."), this );
00365 lo->addWidget( btnNew, 5, 0 );
00366 connect( btnNew, SIGNAL(clicked()), this, SLOT(slotNew()) );
00367
00368 btnRemove = new QPushButton( i18n("&Remove"), this );
00369 lo->addWidget( btnRemove, 5, 2 );
00370 connect( btnRemove, SIGNAL(clicked()), this, SLOT(slotRemove()) );
00371
00372 btnEdit = new QPushButton( i18n("&Edit..."), this );
00373 lo->addWidget( btnEdit, 5, 1 );
00374 connect( btnEdit, SIGNAL(clicked()), this, SLOT(slotEdit()) );
00375
00376 QPushButton *b = new QPushButton( i18n("Insert &Separator"), this );
00377 lo->addWidget( b, 5, 3 );
00378 connect( b, SIGNAL(clicked()), this, SLOT(slotInsertSeparator()) );
00379
00380 btnMoveUp = new QPushButton( SmallIconSet("up"), "", this );
00381 lo->addWidget( btnMoveUp, 2, 4 );
00382 connect( btnMoveUp, SIGNAL(clicked()), this, SLOT(slotMoveUp()) );
00383
00384 btnMoveDwn = new QPushButton( SmallIconSet("down"), "", this );
00385 lo->addWidget( btnMoveDwn, 3, 4 );
00386 connect( btnMoveDwn, SIGNAL(clicked()), this, SLOT(slotMoveDown()) );
00387
00388 lo->setRowStretch( 1, 1 );
00389 lo->setRowStretch( 4, 1 );
00390 lo->setColStretch( 0, 1 );
00391 lo->setColStretch( 1, 1 );
00392 lo->setColStretch( 2, 1 );
00393
00394
00395 QWhatsThis::add( lbTools, i18n(
00396 "This list shows all the configured tools, represented by their menu text.") );
00397
00398
00399
00400 reload();
00401 slotSelectionChanged();
00402 }
00403
00404 void KateExternalToolsConfigWidget::reload()
00405 {
00406
00407 lbTools->clear();
00408
00409
00410 KConfig *config = new KConfig("externaltools", false, false, "appdata");
00411 config->setGroup( "Global" );
00412 QStringList tools = config->readListEntry("tools");
00413
00414 for( QStringList::Iterator it = tools.begin(); it != tools.end(); ++it )
00415 {
00416 if ( *it == "---" )
00417 {
00418 new QListBoxText( lbTools, "---" );
00419 }
00420 else
00421 {
00422 config->setGroup( *it );
00423
00424 KateExternalTool *t = new KateExternalTool(
00425 config->readEntry( "name", "" ),
00426 config->readEntry( "command", ""),
00427 config->readEntry( "icon", ""),
00428 config->readEntry( "executable", ""),
00429 config->readListEntry( "mimetypes" ),
00430 config->readEntry( "acname" ) );
00431
00432 if ( t->hasexec )
00433 new ToolItem( lbTools, t->icon.isEmpty() ? blankIcon() : SmallIcon( t->icon ), t );
00434 }
00435 }
00436 delete config;
00437
00438 }
00439
00440 QPixmap KateExternalToolsConfigWidget::blankIcon()
00441 {
00442 QPixmap pm( KIcon::SizeSmall, KIcon::SizeSmall );
00443 pm.fill();
00444 pm.setMask( pm.createHeuristicMask() );
00445 return pm;
00446 }
00447
00448 void KateExternalToolsConfigWidget::apply()
00449 {
00450 KConfig *config = new KConfig("externaltools", false, false, "appdata");
00451
00452
00453 QStringList tools;
00454 for ( uint i = 0; i < lbTools->count(); i++ )
00455 {
00456 if ( lbTools->text( i ) == "---" )
00457 {
00458 tools << "---";
00459 continue;
00460 }
00461 KateExternalTool *t = ((ToolItem*)lbTools->item( i ))->tool;
00462 kdDebug()<<"adding tool: "<<t->name<<endl;
00463 tools << t->acname;
00464
00465 config->setGroup( t->acname );
00466 config->writeEntry( "name", t->name );
00467 config->writeEntry( "command", t->command );
00468 config->writeEntry( "icon", t->icon );
00469 config->writeEntry( "executable", t->tryexec );
00470 config->writeEntry( "mimetypes", t->mimetypes );
00471 config->writeEntry( "acname", t->acname );
00472 }
00473
00474 config->setGroup("Global");
00475 config->writeEntry( "tools", tools );
00476
00477 config->sync();
00478 delete config;
00479 }
00480
00481 void KateExternalToolsConfigWidget::slotSelectionChanged()
00482 {
00483
00484 bool hs = lbTools->selectedItem() != 0;
00485 btnEdit->setEnabled( hs && static_cast<ToolItem*>(lbTools->selectedItem()) );
00486 btnRemove->setEnabled( hs );
00487 btnMoveUp->setEnabled( (lbTools->currentItem() > 0) && hs );
00488 btnMoveDwn->setEnabled( (lbTools->currentItem() < (int)lbTools->count()-1) && hs );
00489 }
00490
00491 void KateExternalToolsConfigWidget::slotNew()
00492 {
00493
00494
00495 KateExternalToolServiceEditor editor( 0, this );
00496
00497 if ( editor.exec() )
00498 {
00499 KateExternalTool *t = new KateExternalTool(
00500 editor.leName->text(),
00501 editor.leCommand->text(),
00502 editor.btnIcon->icon(),
00503 editor.leExecutable->text(),
00504 QStringList::split( QRegExp("\\s*;\\s*"), editor.leMimetypes->text() ) );
00505
00506
00507
00508 t->acname = "externaltool_" + QString(t->name).replace( QRegExp("\\W+"), "" );
00509
00510 new ToolItem ( lbTools, t->icon.isEmpty() ? blankIcon() : SmallIcon( t->icon ), t );
00511
00512 slotChanged();
00513 }
00514 }
00515
00516 void KateExternalToolsConfigWidget::slotRemove()
00517 {
00518
00519 if ( lbTools->currentItem() > -1 ) {
00520 lbTools->removeItem( lbTools->currentItem() );
00521 slotChanged();
00522 }
00523 }
00524
00525 void KateExternalToolsConfigWidget::slotEdit()
00526 {
00527
00528 KateExternalTool *t = ((ToolItem*)lbTools->selectedItem())->tool;
00529 KateExternalToolServiceEditor editor( t, this);
00530 if ( editor.exec() )
00531 {
00532
00533 bool elementChanged = (( editor.btnIcon->icon() != t->icon ) || (editor.leName->text() != t->name ) );
00534
00535 t->name = editor.leName->text();
00536 t->command = editor.leCommand->text();
00537 t->icon = editor.btnIcon->icon();
00538 t->tryexec = editor.leExecutable->text();
00539 t->mimetypes = QStringList::split( QRegExp("\\s*;\\s*"), editor.leMimetypes->text() );
00540
00541
00542 if ( elementChanged )
00543 {
00544 int idx = lbTools->index( lbTools->selectedItem() );
00545 lbTools->removeItem( idx );
00546 lbTools->insertItem( new ToolItem( 0, t->icon.isEmpty() ? blankIcon() : SmallIcon( t->icon ), t ), idx );
00547 }
00548
00549 slotChanged();
00550 }
00551 }
00552
00553 void KateExternalToolsConfigWidget::slotInsertSeparator()
00554 {
00555 lbTools->insertItem( "---", lbTools->currentItem()+1 );
00556 slotChanged();
00557 }
00558
00559 void KateExternalToolsConfigWidget::slotMoveUp()
00560 {
00561
00562 QListBoxItem *item = lbTools->selectedItem();
00563 if ( ! item ) return;
00564
00565 int idx = lbTools->index( item );
00566
00567 if ( idx < 1 ) return;
00568
00569 if ( dynamic_cast<ToolItem*>(item) )
00570 {
00571 KateExternalTool *tool = ((ToolItem*)item)->tool;
00572 lbTools->removeItem( idx );
00573 lbTools->insertItem( new ToolItem( 0, tool->icon.isEmpty() ? blankIcon() : SmallIcon( tool->icon ), tool ), idx-1 );
00574 }
00575 else
00576 {
00577 lbTools->removeItem( idx );
00578 lbTools->insertItem( new QListBoxText( 0, "---" ), idx-1 );
00579 }
00580
00581 lbTools->setCurrentItem( idx - 1 );
00582 slotSelectionChanged();
00583 slotChanged();
00584 }
00585
00586 void KateExternalToolsConfigWidget::slotMoveDown()
00587 {
00588
00589 QListBoxItem *item = lbTools->selectedItem();
00590 if ( ! item ) return;
00591
00592 uint idx = lbTools->index( item );
00593
00594 if ( idx > lbTools->count()-1 ) return;
00595
00596 if ( dynamic_cast<ToolItem*>(item) )
00597 {
00598 KateExternalTool *tool = ((ToolItem*)item)->tool;
00599 lbTools->removeItem( idx );
00600 lbTools->insertItem( new ToolItem( 0, tool->icon.isEmpty() ? blankIcon() : SmallIcon( tool->icon ), tool ), idx+1 );
00601 }
00602 else
00603 {
00604 lbTools->removeItem( idx );
00605 lbTools->insertItem( new QListBoxText( 0, "---" ), idx+1 );
00606 }
00607
00608 lbTools->setCurrentItem( idx+1 );
00609 slotSelectionChanged();
00610 slotChanged();
00611 }
00612