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 }
00229
00230
void KateExternalToolsMenuAction::slotDocumentChanged()
00231 {
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243 }
00244
00245
00246
00251
class ToolItem :
public QListBoxPixmap
00252 {
00253
public:
00254 ToolItem( QListBox *lb,
const QPixmap &icon,
KateExternalTool *tool )
00255 : QListBoxPixmap( lb, icon, tool->name ),
00256 tool ( tool )
00257 {;}
00258
00259 ~ToolItem() {};
00260
00261
KateExternalTool *tool;
00262 };
00263
00264
00265
00266 KateExternalToolServiceEditor::KateExternalToolServiceEditor(
KateExternalTool *tool,
00267 QWidget *parent,
const char *name )
00268 : KDialogBase( parent, name, true, i18n(
"Edit External Tool"), KDialogBase::Ok|KDialogBase::Cancel ),
00269 tool( tool )
00270 {
00271
00272
00273 QWidget *w =
new QWidget(
this );
00274 setMainWidget( w );
00275 QGridLayout *lo =
new QGridLayout( w );
00276 lo->setSpacing( KDialogBase::spacingHint() );
00277
00278 QLabel *l;
00279
00280 leName =
new QLineEdit( w );
00281 lo->addWidget( leName, 1, 2 );
00282 l =
new QLabel( leName, i18n(
"&Name:"), w );
00283 l->setAlignment( l->alignment()|Qt::AlignRight );
00284 lo->addWidget( l, 1, 1 );
00285
if ( tool ) leName->setText( tool->
name );
00286 QWhatsThis::add( leName, i18n(
00287
"The name will be displayed in the 'Tools->External' menu") );
00288
00289 leCommand =
new QLineEdit( w );
00290 lo->addWidget( leCommand, 2, 2 );
00291 l =
new QLabel( leCommand, i18n(
"Co&mmand:"), w );
00292 l->setAlignment( l->alignment()|Qt::AlignRight );
00293 lo->addWidget( l, 2, 1 );
00294
if ( tool ) leCommand->setText( tool->
command );
00295 QWhatsThis::add( leCommand, i18n(
00296
"<p>The command to execute to invoke the tool. The following macros "
00297
"will be expanded:</p>"
00298
"<ul><li><code>%URL</code> - the URL of the current document."
00299
"<li><code>%URLs</code> - a list of the URLs of all open documents."
00300
"<li><code>%directory</code> - the URL of the directory containing "
00301
"the current document."
00302
"<li><code>filename</code> - the filename of the current document."
00303
"<li><code>%line</code> - the current line of the text cursor in the "
00304
"current view."
00305
"<li><code>%column</code> - the column of the text cursor in the "
00306
"current view."
00307
"<li><code>%selection</code> - the selected text in the current view."
00308
"<li><code>%text</code> - the text of the current document.</ul>" ) );
00309
00310 btnIcon =
new KIconButton( w );
00311 btnIcon->setIconSize( KIcon::SizeMedium );
00312 lo->addMultiCellWidget( btnIcon, 1, 2, 3, 3 );
00313
if ( tool && !tool->
icon.isEmpty() )
00314 btnIcon->setIcon( tool->
icon );
00315
00316
00317 leExecutable =
new QLineEdit( w );
00318 lo->addWidget( leExecutable, 3, 2 );
00319 l =
new QLabel( leExecutable, i18n(
"&Executable:"), w );
00320 l->setAlignment( l->alignment()|Qt::AlignRight );
00321 lo->addWidget( l, 3, 1 );
00322
if ( tool ) leExecutable->setText( tool->
tryexec );
00323 QWhatsThis::add( leExecutable, i18n(
00324
"The executable used by the command. This is used to check if a tool "
00325
"should be displayed; if not set, the first word of <em>command</em> "
00326
"will be used.") );
00327
00328 leMimetypes =
new QLineEdit( w );
00329 lo->addWidget( leMimetypes, 4, 2 );
00330 l =
new QLabel( leMimetypes, i18n(
"&Mime types:"), w );
00331 l->setAlignment( l->alignment()|Qt::AlignRight );
00332 lo->addWidget( l, 4, 1 );
00333
if ( tool ) leMimetypes->setText( tool->
mimetypes.join(
"; ") );
00334 QWhatsThis::add( leMimetypes, i18n(
00335
"A semicolon-separated list of mime types for which this tool should "
00336
"be available; if this is left empty, the tool is always available."
00337
"To choose from known mimetypes, press the button on the right.") );
00338 }
00339
00340
void KateExternalToolServiceEditor::slotOk()
00341 {
00342
if ( leName->text().isEmpty() ||
00343 leCommand->text().isEmpty() )
00344 {
00345 KMessageBox::information(
this, i18n(
"You must specify at least a name and a command") );
00346
return;
00347 }
00348
00349 KDialogBase::slotOk();
00350 }
00351
00352
00353
00354 KateExternalToolsConfigWidget::KateExternalToolsConfigWidget( QWidget *parent,
const char* name )
00355 : Kate::ConfigPage( parent, name )
00356 {
00357 QGridLayout *lo =
new QGridLayout(
this, 5, 5, 0, KDialog::spacingHint() );
00358
00359 lbTools =
new KListBox(
this );
00360 lo->addMultiCellWidget( lbTools, 1, 4, 0, 3 );
00361 connect( lbTools, SIGNAL(selectionChanged()),
this, SLOT(slotSelectionChanged()) );
00362
00363 btnNew =
new QPushButton( i18n(
"&New..."),
this );
00364 lo->addWidget( btnNew, 5, 0 );
00365 connect( btnNew, SIGNAL(clicked()),
this, SLOT(slotNew()) );
00366
00367 btnRemove =
new QPushButton( i18n(
"&Remove"),
this );
00368 lo->addWidget( btnRemove, 5, 2 );
00369 connect( btnRemove, SIGNAL(clicked()),
this, SLOT(slotRemove()) );
00370
00371 btnEdit =
new QPushButton( i18n(
"&Edit..."),
this );
00372 lo->addWidget( btnEdit, 5, 1 );
00373 connect( btnEdit, SIGNAL(clicked()),
this, SLOT(slotEdit()) );
00374
00375 QPushButton *b =
new QPushButton( i18n(
"Insert &Separator"),
this );
00376 lo->addWidget( b, 5, 3 );
00377 connect( b, SIGNAL(clicked()),
this, SLOT(slotInsertSeparator()) );
00378
00379 btnMoveUp =
new QPushButton( SmallIconSet(
"up"),
"",
this );
00380 lo->addWidget( btnMoveUp, 2, 4 );
00381 connect( btnMoveUp, SIGNAL(clicked()),
this, SLOT(slotMoveUp()) );
00382
00383 btnMoveDwn =
new QPushButton( SmallIconSet(
"down"),
"",
this );
00384 lo->addWidget( btnMoveDwn, 3, 4 );
00385 connect( btnMoveDwn, SIGNAL(clicked()),
this, SLOT(slotMoveDown()) );
00386
00387 lo->setRowStretch( 1, 1 );
00388 lo->setRowStretch( 4, 1 );
00389 lo->setColStretch( 0, 1 );
00390 lo->setColStretch( 1, 1 );
00391 lo->setColStretch( 2, 1 );
00392
00393
00394 QWhatsThis::add( lbTools, i18n(
00395
"This list shows all the configured tools, represented by their menu text.") );
00396
00397
00398
00399
reload();
00400 slotSelectionChanged();
00401 }
00402
00403
void KateExternalToolsConfigWidget::reload()
00404 {
00405
00406 lbTools->clear();
00407
00408
00409 KConfig *config =
new KConfig(
"externaltools",
false,
false,
"appdata");
00410 config->setGroup(
"Global" );
00411 QStringList tools = config->readListEntry(
"tools");
00412
00413
for( QStringList::Iterator it = tools.begin(); it != tools.end(); ++it )
00414 {
00415
if ( *it ==
"---" )
00416 {
00417
new QListBoxText( lbTools,
"---" );
00418 }
00419
else
00420 {
00421 config->setGroup( *it );
00422
00423
KateExternalTool *t =
new KateExternalTool(
00424 config->readEntry(
"name",
"" ),
00425 config->readEntry(
"command",
""),
00426 config->readEntry(
"icon",
""),
00427 config->readEntry(
"executable",
""),
00428 config->readListEntry(
"mimetypes" ),
00429 config->readEntry(
"acname" ) );
00430
00431
if ( t->
hasexec )
00432
new ToolItem( lbTools, t->
icon.isEmpty() ? blankIcon() : SmallIcon( t->icon ), t );
00433 }
00434 }
00435
00436
00437 }
00438
00439 QPixmap KateExternalToolsConfigWidget::blankIcon()
00440 {
00441 QPixmap pm( KIcon::SizeSmall, KIcon::SizeSmall );
00442 pm.fill();
00443 pm.setMask( pm.createHeuristicMask() );
00444
return pm;
00445 }
00446
00447
void KateExternalToolsConfigWidget::apply()
00448 {
00449 KConfig *config =
new KConfig(
"externaltools",
false,
false,
"appdata");
00450
00451
00452 QStringList tools;
00453
for ( uint i = 0; i < lbTools->count(); i++ )
00454 {
00455
if ( lbTools->text( i ) ==
"---" )
00456 {
00457 tools <<
"---";
00458
continue;
00459 }
00460
KateExternalTool *t = ((ToolItem*)lbTools->item( i ))->tool;
00461 kdDebug()<<
"adding tool: "<<t->
name<<endl;
00462 tools << t->
acname;
00463
00464 config->setGroup( t->
acname );
00465 config->writeEntry(
"name", t->
name );
00466 config->writeEntry(
"command", t->
command );
00467 config->writeEntry(
"icon", t->
icon );
00468 config->writeEntry(
"executable", t->
tryexec );
00469 config->writeEntry(
"mimetypes", t->
mimetypes );
00470 config->writeEntry(
"acname", t->
acname );
00471 }
00472
00473 config->setGroup(
"Global");
00474 config->writeEntry(
"tools", tools );
00475
00476 config->sync();
00477 }
00478
00479
void KateExternalToolsConfigWidget::slotSelectionChanged()
00480 {
00481
00482
bool hs = lbTools->selectedItem() != 0;
00483 btnEdit->setEnabled( hs && static_cast<ToolItem*>(lbTools->selectedItem()) );
00484 btnRemove->setEnabled( hs );
00485 btnMoveUp->setEnabled( lbTools->currentItem() > 0 );
00486 btnMoveDwn->setEnabled( lbTools->currentItem() < (
int)lbTools->count()-1 );
00487 }
00488
00489
void KateExternalToolsConfigWidget::slotNew()
00490 {
00491
00492
00493
KateExternalToolServiceEditor editor( 0,
this );
00494
00495
if ( editor.exec() )
00496 {
00497
KateExternalTool *t =
new KateExternalTool(
00498 editor.leName->text(),
00499 editor.leCommand->text(),
00500 editor.btnIcon->icon(),
00501 editor.leExecutable->text(),
00502 QStringList::split( QRegExp(
"\\s*;\\s*"), editor.leMimetypes->text() ) );
00503
00504
00505
00506 t->
acname =
"externaltool_" + QString(t->
name).replace( QRegExp(
"\\W+"),
"" );
00507
00508
new ToolItem ( lbTools, t->
icon.isEmpty() ? blankIcon() : SmallIcon( t->icon ), t );
00509
00510 slotChanged();
00511 }
00512 }
00513
00514
void KateExternalToolsConfigWidget::slotRemove()
00515 {
00516
00517
if ( lbTools->currentItem() > -1 ) {
00518 lbTools->removeItem( lbTools->currentItem() );
00519 slotChanged();
00520 }
00521 }
00522
00523
void KateExternalToolsConfigWidget::slotEdit()
00524 {
00525
00526
KateExternalTool *t = ((ToolItem*)lbTools->selectedItem())->tool;
00527
KateExternalToolServiceEditor editor( t,
this);
00528
if ( editor.exec() )
00529 {
00530
00531
bool iconChanged = ( editor.btnIcon->icon() != t->
icon );
00532
00533 t->
name = editor.leName->text();
00534 t->
command = editor.leCommand->text();
00535 t->
icon = editor.btnIcon->icon();
00536 t->
tryexec = editor.leExecutable->text();
00537 t->
mimetypes = QStringList::split( QRegExp(
"\\s*;\\s*"), editor.leMimetypes->text() );
00538
00539
00540
if ( iconChanged )
00541 {
00542
int idx = lbTools->index( lbTools->selectedItem() );
00543 lbTools->removeItem( idx );
00544 lbTools->insertItem(
new ToolItem( 0, t->
icon.isEmpty() ? blankIcon() : SmallIcon( t->icon ), t ), idx );
00545 }
00546
00547 slotChanged();
00548 }
00549 }
00550
00551
void KateExternalToolsConfigWidget::slotInsertSeparator()
00552 {
00553 lbTools->insertItem(
"---", lbTools->currentItem()+1 );
00554 }
00555
00556
void KateExternalToolsConfigWidget::slotMoveUp()
00557 {
00558
00559 QListBoxItem *item = lbTools->selectedItem();
00560
if ( ! item )
return;
00561
00562
int idx = lbTools->index( item );
00563
00564
if ( idx < 1 )
return;
00565
00566
if ( dynamic_cast<ToolItem*>(item) )
00567 {
00568
KateExternalTool *tool = ((ToolItem*)item)->tool;
00569 lbTools->removeItem( idx );
00570 lbTools->insertItem(
new ToolItem( 0, tool->
icon.isEmpty() ? blankIcon() : SmallIcon( tool->icon ), tool ), idx-1 );
00571 }
00572
else
00573 {
00574 lbTools->removeItem( idx );
00575 lbTools->insertItem(
new QListBoxText( 0,
"---" ), idx-1 );
00576 }
00577
00578 lbTools->setCurrentItem( idx - 1 );
00579 slotSelectionChanged();
00580 }
00581
00582
void KateExternalToolsConfigWidget::slotMoveDown()
00583 {
00584
00585 QListBoxItem *item = lbTools->selectedItem();
00586
if ( ! item )
return;
00587
00588 uint idx = lbTools->index( item );
00589
00590
if ( idx > lbTools->count()-1 )
return;
00591
00592
if ( dynamic_cast<ToolItem*>(item) )
00593 {
00594
KateExternalTool *tool = ((ToolItem*)item)->tool;
00595 lbTools->removeItem( idx );
00596 lbTools->insertItem(
new ToolItem( 0, tool->
icon.isEmpty() ? blankIcon() : SmallIcon( tool->icon ), tool ), idx+1 );
00597 }
00598
else
00599 {
00600 lbTools->removeItem( idx );
00601 lbTools->insertItem(
new QListBoxText( 0,
"---" ), idx+1 );
00602 }
00603
00604 lbTools->setCurrentItem( idx+1 );
00605 slotSelectionChanged();
00606 }
00607