kate Library API Documentation

kateexternaltools.cpp

00001 /*
00002    This file is part of the Kate text editor of the KDE project.
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00016    Boston, MA 02111-1307, USA.
00017 
00018    ---
00019    Copyright (C) 2004, Anders Lund <anders@alweb.dk>
00020 */
00021 // TODO
00022 // Icons
00023 // Direct shortcut setting
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 //BEGIN KateExternalTool
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   //if ( ! tryexec.isEmpty() )
00073     hasexec = checkExec();
00074 }
00075 
00076 bool KateExternalTool::checkExec()
00077 {
00078   // if tryexec is empty, it is the first word of command
00079   if ( tryexec.isEmpty() )
00080     tryexec = command.section( " ", 0, 0, QString::SectionSkipEmpty );
00081 
00082   // NOTE this code is modified taken from kdesktopfile.cpp, from KDesktopFile::tryExec()
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       // !!! Sergey A. Sukiyazov <corwin@micom.don.ru> !!!
00091       // Environment PATH may contain filenames in 8bit locale cpecified
00092       // encoding (Like a filenames).
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       // didn't match at all
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 //END KateExternalTool
00120 
00121 //BEGIN KateExternalToolAction
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" ) // directory of current doc
00142     ret += mw->activeDocumentUrl().directory();
00143   else if ( str == "filename" )
00144     ret += mw->activeDocumentUrl().filename();
00145   else if ( str == "line" ) // cursor line of current doc
00146     ret += QString::number( view->cursorLine() );
00147   else if ( str == "col" ) // cursor col of current doc
00148     ret += QString::number( view->cursorColumn() );
00149   else if ( str == "selection" ) // selection of current doc if any
00150     ret += view->getDoc()->selection();
00151   else if ( str == "text" ) // text of current doc
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   // expand the macros in command if any,
00165   // and construct a command with an absolute path
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 //END KateExternalToolAction
00174 
00175 //BEGIN KateExternalToolsMenuAction
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 //   connect(mw->m_docManager,SIGNAL(documentChanged()),this,SLOT(slotDocumentChanged()));
00187 
00188   reload();
00189 }
00190 
00191 void KateExternalToolsMenuAction::reload()
00192 {
00193   m_actionCollection->clear();
00194 
00195   popupMenu()->clear();
00196 
00197   // load all the tools, and create a action for each of them
00198   KConfig *config = new KConfig("externaltools", false, false, "appdata");
00199   config->setGroup("Global");
00200   QStringList tools = config->readListEntry("tools");
00201 
00202 //   QRegExp re_nw("\\W");
00203 
00204   for( QStringList::Iterator it = tools.begin(); it != tools.end(); ++it )
00205   {
00206     if ( *it == "---" )
00207     {
00208       popupMenu()->insertSeparator();
00209       // a separator
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 //   // enable/disable to match current mime type
00234 //   QString mt = mainwindow->m_docManager->activeDocument()->mimeType();
00235 //
00236 //   KActionPtrList actions = m_actionCollection->actions();
00237 //   for (KActionPtrList::iterator it = actions.begin(); it != actions.end(); ++it )
00238 //   {
00239 //     if ( (KateExternalToolAction *a = dynamic_cast<KateExternalToolAction*>(*it)) )
00240 //     {
00241 //       a->setEnabled a->tool->mimetypes.contain( mt );
00242 //     }
00243 //   }
00244 }
00245 //END KateExternalToolsMenuAction
00246 
00247 //BEGIN ToolItem
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 //END ToolItem
00265 
00266 //BEGIN KateExternalToolServiceEditor
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     // create a entry for each property
00273     // fill in the values from the service if available
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 //END KateExternalToolServiceEditor
00353 
00354 //BEGIN KateExternalToolsConfigWidget
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   //m_tools.clear();
00407   lbTools->clear();
00408 
00409   // load the files from a KConfig
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 ) // we only show tools that are also in the menu.
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   // save a new list
00452   // save each item
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   // update button state
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   // display a editor, and if it is OK'd, create a new tool and
00494   // create a listbox item for it
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     // This is sticky, it does not change again, so that shortcuts sticks
00507     // TODO check for dups
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   // just remove the current listbox item
00519   if ( lbTools->currentItem() > -1 ) {
00520     lbTools->removeItem( lbTools->currentItem() );
00521     slotChanged();
00522   }
00523 }
00524 
00525 void KateExternalToolsConfigWidget::slotEdit()
00526 {
00527   // show the item in an editor
00528   KateExternalTool *t = ((ToolItem*)lbTools->selectedItem())->tool;
00529   KateExternalToolServiceEditor editor( t, this);
00530   if ( editor.exec() /*== KDialogBase::Ok*/ )
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     //if the icon has changed or name changed, I have to renew the listbox item :S
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   // move the current item in the listbox upwards if possible
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 // a separator!
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   // move the current item in the listbox downwards if possible
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 // a separator!
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 //END KateExternalToolsConfigWidget
KDE Logo
This file is part of the documentation for kate Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Sep 8 02:43:13 2005 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003