/*************************************************************************** plugin_kateinsertcommand.cpp - description ------------------- begin : THU Apr 19 2001 copyright : (C) 2001 by Anders Lund email : anders@alweb.dk ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ //BEGIN includes #include "plugin_kateinsertcommand.h" #include "plugin_kateinsertcommand.moc" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //END includes K_EXPORT_COMPONENT_FACTORY( kateinsertcommandplugin, KGenericFactory( "kateinsertcommand" ) ) //BEGIN obligatory stuff class PluginView : public KXMLGUIClient { friend class PluginKateInsertCommand; public: Kate::MainWindow *win; }; //END //BEGIN PluginKateInsertCommand PluginKateInsertCommand::PluginKateInsertCommand( TQObject* parent, const char* name, const TQStringList& ) : Kate::Plugin ( (Kate::Application *)parent, name ), kv ( 0 ), sh ( 0 ) { config = new KConfig("kateinsertcommandpluginrc"); cmdhist = config->readListEntry("Command History"); wdlg = 0; workingdir = TQDir::currentDirPath(); } PluginKateInsertCommand::~PluginKateInsertCommand() { // write config file config->writeEntry("Command History", cmdhist); config->writeEntry("Dialog Settings", dialogSettings); config->sync(); delete config; delete sh; } void PluginKateInsertCommand::addView(Kate::MainWindow *win) { // TODO: doesn't this have to be deleted? PluginView *view = new PluginView (); (void) new KAction ( i18n("Insert Command..."), "", 0, this, TQT_SLOT( slotInsertCommand() ), view->actionCollection(), "edit_insert_command" ); view->setInstance (new TDEInstance("kate")); view->setXMLFile("plugins/kateinsertcommand/ui.rc"); win->guiFactory()->addClient (view); view->win = win; m_views.append (view); } void PluginKateInsertCommand::removeView(Kate::MainWindow *win) { for (uint z=0; z < m_views.count(); z++) if (m_views.at(z)->win == win) { PluginView *view = m_views.at(z); m_views.remove (view); win->guiFactory()->removeClient (view); delete view; } } void PluginKateInsertCommand::slotInsertCommand() { if (!kapp->authorize("shell_access")) { KMessageBox::sorry(0,i18n("You are not allowed to execute arbitrary external applications. If you want to be able to do this, contact your system administrator."),i18n("Access Restrictions")); return; } if ( sh && sh->isRunning() ) { KMessageBox::sorry (0, i18n("A process is currently being executed."), i18n("Error")); return; } if (!application()->activeMainWindow() || !application()->activeMainWindow()->viewManager()->activeView()) return; kv = application()->activeMainWindow()->viewManager()->activeView(); TQString dir = workingdir; TQString docdir; KURL docurl = kv->getDoc()->url(); if (docurl.isLocalFile()) docdir = docurl.directory(); TQString lwd( config->readPathEntry("Last WD") ); switch ( (int)config->readNumEntry("Start In", 0) ) { case 1: if ( ! docdir.isEmpty() ) dir = docdir; break; case 2: if ( ! lwd.isEmpty() ) dir = lwd; break; default: break; } dialogSettings = config->readNumEntry("Dialog Settings", 0); CmdPrompt *d = new CmdPrompt((TQWidget*)kv, 0, cmdhist, dir, docdir, dialogSettings); if ( d->exec() && ! d->command().isEmpty() ) { if ( ! sh ) { sh = new KShellProcess; connect ( sh, TQT_SIGNAL(receivedStdout(KProcess*, char*, int)), this, TQT_SLOT(slotReceivedStdout(KProcess*, char*, int)) ); connect ( sh, TQT_SIGNAL(receivedStderr(KProcess*, char*, int)), this, TQT_SLOT(slotReceivedStderr(KProcess*, char*, int)) ); connect ( sh, TQT_SIGNAL(processExited(KProcess*)), this, TQT_SLOT(slotProcessExited(KProcess*)) ) ; } sh->clearArguments(); bInsStdErr = d->insertStdErr(); if ( d->printCmd() ) { if ( ! d->wd().isEmpty() ) kv->insertText( d->wd() + ": "); kv->insertText( d->command()+":\n" ); } if ( ! d->wd().isEmpty() ) { *sh << "cd" << d->wd() << "&&"; config->writePathEntry("Last WD", d->wd()); } *sh << TQFile::encodeName(d->command()).data(); sh->start( KProcess::NotifyOnExit, KProcess::All ); // add command to history if ( cmdhist.contains( d->command() ) ) { cmdhist.remove( d->command() ); } cmdhist.prepend( d->command() ); int cmdhistlen = config->readNumEntry("Command History Length", 20); while ( (int)cmdhist.count() > cmdhistlen ) cmdhist.remove( cmdhist.last() ); // save dialog state dialogSettings = 0; if ( d->insertStdErr() ) dialogSettings += 1; if ( d->printCmd() ) dialogSettings += 2; cmd = d->command(); delete d; // If process is still running, display a dialog to cancel... slotShowWaitDlg(); config->writeEntry("Dialog Settings", dialogSettings); config->sync(); } } void PluginKateInsertCommand::slotAbort() { if ( sh->isRunning() ) if (! sh->kill() ) KMessageBox::sorry(0, i18n("Could not kill command."), i18n("Kill Failed")); } void PluginKateInsertCommand::slotShowWaitDlg() { if ( sh->isRunning() ) { wdlg = new WaitDlg( (TQWidget*)kv, i18n( "Executing command:\n%1\n\nPress 'Cancel' to abort.").arg(cmd) ); connect(wdlg, TQT_SIGNAL(cancelClicked()), this, TQT_SLOT(slotAbort()) ); } if ( sh->isRunning() ) // we may have finished while creating the dialog. wdlg->show(); else if (wdlg) { // process may have exited before the WaitDlg constructor returned. delete wdlg; wdlg = 0; } } void PluginKateInsertCommand::slotReceivedStdout( KProcess* /*p*/, char* text, int len ) { TQString t = TQString::fromLocal8Bit ( text ); t.truncate(len); kv->insertText( t ); } void PluginKateInsertCommand::slotReceivedStderr( KProcess* p, char* text, int len ) { if ( bInsStdErr ) slotReceivedStdout( p, text, len ); } void PluginKateInsertCommand::slotProcessExited( KProcess* p ) { if (wdlg) { wdlg->hide(); delete wdlg; wdlg = 0; } if ( ! p->normalExit() ) KMessageBox::sorry(0, i18n("Command exited with status %1"). arg( p->exitStatus()), i18n("Oops!")); kv->setFocus(); } //END PluginKateInsertCommand //BEGIN PluginConfigPage Kate::PluginConfigPage* PluginKateInsertCommand::configPage (uint, TQWidget *w, const char */*name*/) { InsertCommandConfigPage* p = new InsertCommandConfigPage(this, w); initConfigPage( p ); connect( p, TQT_SIGNAL(configPageApplyRequest(InsertCommandConfigPage*)), this, TQT_SLOT(applyConfig(InsertCommandConfigPage*)) ); return (Kate::PluginConfigPage*)p; } void PluginKateInsertCommand::initConfigPage( InsertCommandConfigPage *p ) { p->sb_cmdhistlen->setValue( config->readNumEntry("Command History Length", 20) ); p->rg_startin->setButton( config->readNumEntry("Start In", 0) ); } void PluginKateInsertCommand::applyConfig( InsertCommandConfigPage *p ) { config->writeEntry( "Command History Length", p->sb_cmdhistlen->value() ); // truncate the cmd hist if nessecary? config->writeEntry( "Start In", p->rg_startin->id(p->rg_startin->selected()) ); config->sync(); } //END PluginConfigPage //BEGIN CmdPrompt // This is a simple dialog to retrieve a command and decide if // stdErr should be included in the text inserted. CmdPrompt::CmdPrompt(TQWidget* parent, const char* name, const TQStringList& cmdhist, const TQString& dir, const TQString& /*docdir*/, int settings) : KDialogBase (parent, name, true, i18n("Insert Command"), Ok|Cancel, Ok, true) { TQWidget *page = new TQWidget( this ); setMainWidget(page); TQVBoxLayout *lo = new TQVBoxLayout( page, 0, spacingHint() ); TQLabel *l = new TQLabel( i18n("Enter &command:"), page ); lo->addWidget( l ); cmb_cmd = new KHistoryCombo(true, page); cmb_cmd->setHistoryItems(cmdhist, true); cmb_cmd->setCurrentItem(0); cmb_cmd->lineEdit()->setSelection(0, cmb_cmd->currentText().length()); l->setBuddy(cmb_cmd); cmb_cmd->setFocus(); lo->addWidget(cmb_cmd); connect( cmb_cmd->lineEdit(),TQT_SIGNAL(textChanged ( const TQString & )), this, TQT_SLOT( slotTextChanged(const TQString &))); TQLabel *lwd = new TQLabel( i18n("Choose &working folder:"), page ); lo->addWidget( lwd ); wdreq = new KURLRequester( page ); if ( ! dir.isEmpty() ) wdreq->setURL( dir ); wdreq->setMode( static_cast(KFile::Directory|KFile::LocalOnly|KFile::ExistingOnly) ); lwd->setBuddy( wdreq ); lo->addWidget( wdreq ); //kdDebug()<<"settings: "<setChecked(settings & 1); lo->addWidget( cb_insStdErr ); cb_printCmd = new TQCheckBox( i18n("&Print command name"), page ); cb_printCmd->setChecked(settings & 2); lo->addWidget( cb_printCmd ); TQWhatsThis::add( cmb_cmd, i18n( "Enter the shell command, the output of which you want inserted into your " "document. Feel free to use a pipe or two if you wish.") ); TQWhatsThis::add( wdreq, i18n( "Sets the working folder of the command. The command executed is 'cd " "&& '") ); TQWhatsThis::add( cb_insStdErr, i18n( "Check this if you want the error output from inserted as well.\n" "Some commands, such as locate, print everything to STDERR") ); TQWhatsThis::add( cb_printCmd, i18n( "If you check this, the command string will be printed followed by a " "newline before the output.") ); slotTextChanged(cmb_cmd->lineEdit()->text()); } CmdPrompt::~CmdPrompt() {} void CmdPrompt::slotTextChanged(const TQString &text) { enableButtonOK( !text.isEmpty()); } //END CmdPrompt //BEGIN WaitDlg implementation // This is a dialog that is displayed while a command is running, // with a cancel button to allow the user to kill the command WaitDlg::WaitDlg(TQWidget* parent, const TQString& text, const TQString& title) : KDialogBase( parent, "wait dialog", true, title, Cancel, Cancel, true ) { TQWidget *page = new TQWidget( this ); setMainWidget( page ); TQHBoxLayout *lo = new TQHBoxLayout( page, 0, spacingHint() ); KAnimWidget *aw = new KAnimWidget( TQString::fromLatin1("kde"), 48, page ); lo->addWidget(aw); TQLabel *l = new TQLabel( text, page ); lo->addWidget( l ); aw->start(); } WaitDlg::~WaitDlg() { } //END WaitDlg //BEGIN InsertCommandConfigPage // This is the config page for this plugin. InsertCommandConfigPage::InsertCommandConfigPage(TQObject* /*parent*/, TQWidget *parentWidget) : Kate::PluginConfigPage( parentWidget ) { TQVBoxLayout* lo = new TQVBoxLayout( this ); lo->setSpacing(KDialogBase::spacingHint()); // command history length TQHBox *hb1 = new TQHBox( this ); hb1->setSpacing(KDialogBase::spacingHint()); (void) new TQLabel( i18n("Remember"), hb1 ); sb_cmdhistlen = new TQSpinBox( hb1 ); TQLabel *l1 = new TQLabel( sb_cmdhistlen, i18n("Co&mmands"), hb1); hb1->setStretchFactor(l1, 1); lo->addWidget( hb1 ); // dir history length // initial dir choice rg_startin = new TQButtonGroup( 1, Qt::Horizontal, i18n("Start In"), this ); rg_startin->setRadioButtonExclusive( true ); (void) new TQRadioButton( i18n("Application &working folder"), rg_startin); (void) new TQRadioButton( i18n("&Document folder"), rg_startin); (void) new TQRadioButton( i18n("&Latest used working folder"), rg_startin); lo->addWidget( rg_startin ); // other? lo->addStretch(1); // look nice // Be helpfull! TQWhatsThis::add( sb_cmdhistlen, i18n( "Sets the number of commands to remember. The command history is saved " "over sessions.") ); TQWhatsThis::add( rg_startin, i18n( "

Decides what is suggested as working folder for the " "command.

Application Working Folder (default): " "The folder from which you launched the application hosting the plugin, " "usually your home folder.

Document Folder: The " "folder of the document. Used only for local documents.

" "Latest Working Folder: The folder used last time you used this " "plugin.

") ); } void InsertCommandConfigPage::apply() { emit configPageApplyRequest( this ); } //END InsertCommandConfigPage // kate: space-indent on; indent-width 2; replace-tabs on;