You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
678 lines
17 KiB
678 lines
17 KiB
/***************************************************************************
|
|
begin : mon 3-11 20:40:00 CEST 2003
|
|
copyright : (C) 2003 by Jeroen Wijnhout
|
|
email : Jeroen.Wijnhout@kdemail.net
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* 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. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "kiletool.h"
|
|
|
|
#include <tqdir.h>
|
|
#include <tqfileinfo.h>
|
|
#include <tqmetaobject.h>
|
|
#include <tqregexp.h>
|
|
#include <tqtimer.h>
|
|
|
|
#include <tdelocale.h>
|
|
#include <tdeconfig.h>
|
|
#include <kurl.h>
|
|
|
|
#include "kileconfig.h"
|
|
#include "kileuntitled.h"
|
|
#include "kiletool_enums.h"
|
|
#include "kilestdtools.h" //for the factory
|
|
#include "kiletoolmanager.h"
|
|
#include "kiledocmanager.h"
|
|
#include "kileinfo.h"
|
|
#include "kiledocumentinfo.h"
|
|
#include "kileproject.h"
|
|
|
|
namespace KileTool
|
|
{
|
|
Base::Base(const TQString &name, Manager * manager, bool prepare /* = true */) :
|
|
m_manager(manager),
|
|
m_name(name),
|
|
m_from(TQString()),
|
|
m_to(TQString()),
|
|
m_target(TQString()),
|
|
m_basedir(TQString()),
|
|
m_relativedir(TQString()),
|
|
m_targetdir(TQString()),
|
|
m_source(TQString()),
|
|
m_S(TQString()),
|
|
m_options(TQString()),
|
|
m_resolution(TQString()),
|
|
m_launcher(0L),
|
|
m_quickie(false),
|
|
m_bPrepareToRun(prepare)
|
|
{
|
|
m_manager->initTool(this);
|
|
|
|
m_flags = NeedTargetDirExec | NeedTargetDirWrite | NeedActiveDoc | NeedMasterDoc | NoUntitledDoc | NeedSourceExists | NeedSourceRead;
|
|
|
|
setMsg(NeedTargetDirExec, i18n("Could not change to the folder %1."));
|
|
setMsg(NeedTargetDirWrite, i18n("The folder %1 is not writable, therefore %2 will not be able to save its results."));
|
|
setMsg(NeedTargetExists, i18n("The file %1/%2 does not exist. If you're surprised, check the file permissions."));
|
|
setMsg(NeedTargetRead, i18n("The file %1/%2 is not readable. If you're surprised, check the file permissions."));
|
|
setMsg(NeedActiveDoc, i18n("Could not determine on which file to run %1, because there is no active document."));
|
|
setMsg(NeedMasterDoc, i18n("Could not determine the master file for this document."));
|
|
setMsg(NoUntitledDoc, i18n("Please save the untitled document first."));
|
|
setMsg(NeedSourceExists, i18n("Sorry, the file %1 does not exist."));
|
|
setMsg(NeedSourceRead, i18n("Sorry, the file %1 is not readable."));
|
|
|
|
m_bPrepared = false;
|
|
}
|
|
|
|
Base::~Base()
|
|
{
|
|
KILE_DEBUG() << "DELETING TOOL: " << name() << endl;
|
|
delete m_launcher;
|
|
}
|
|
|
|
const TQString Base::source(bool absolute /* = true */) const
|
|
{
|
|
if (m_source.isNull())
|
|
return TQString();
|
|
|
|
TQString src = m_source;
|
|
if (absolute)
|
|
src = m_basedir + '/' + src;
|
|
|
|
return src;
|
|
}
|
|
|
|
void Base::setMsg(long n, const TQString & msg)
|
|
{
|
|
m_messages[n] = msg;
|
|
}
|
|
|
|
void Base::translate(TQString &str)
|
|
{
|
|
TQDictIterator<TQString> it(*paramDict());
|
|
for( it.toFirst() ; it.current(); ++it )
|
|
{
|
|
// KILE_DEBUG() << "translate " << str << " /// key=" << it.currentKey() << " value=" << *(it.current()) << endl;
|
|
str.replace(it.currentKey(), *( it.current() ) );
|
|
}
|
|
}
|
|
|
|
void Base::prepareToRun(const TQString &cfg)
|
|
{
|
|
KILE_DEBUG() << "==Base::prepareToRun()=======" << endl;
|
|
|
|
m_bPrepared = true;
|
|
m_nPreparationResult = Running;
|
|
|
|
//configure me
|
|
if (!configure(cfg))
|
|
{
|
|
m_nPreparationResult = ConfigureFailed;
|
|
m_bPrepared = false;
|
|
return;
|
|
}
|
|
|
|
//install a launcher
|
|
if (!installLauncher())
|
|
{
|
|
m_nPreparationResult = NoLauncherInstalled;
|
|
m_bPrepared = false;
|
|
return;
|
|
}
|
|
|
|
if (!determineSource())
|
|
{
|
|
m_nPreparationResult = NoValidSource;
|
|
m_bPrepared = false;
|
|
return;
|
|
}
|
|
|
|
if (!determineTarget())
|
|
{
|
|
m_nPreparationResult = NoValidTarget;
|
|
m_bPrepared = false;
|
|
return;
|
|
}
|
|
|
|
if ( m_launcher == 0 )
|
|
{
|
|
m_nPreparationResult = NoLauncherInstalled;
|
|
m_bPrepared = false;
|
|
return;
|
|
}
|
|
|
|
m_launcher->setWorkingDirectory(workingDir());
|
|
|
|
//fill in the dictionary
|
|
addDict("%options", m_options);
|
|
|
|
m_resolution = KileConfig::dvipngResolution() ;
|
|
addDict("%res",m_resolution);
|
|
}
|
|
|
|
int Base::run()
|
|
{
|
|
KILE_DEBUG() << "==KileTool::Base::run()=================" << endl;
|
|
|
|
if ( m_nPreparationResult != 0 )
|
|
return m_nPreparationResult;
|
|
|
|
if (!checkSource())
|
|
return NoValidSource;
|
|
|
|
if (!checkTarget())
|
|
return TargetHasWrongPermissions;
|
|
|
|
if (!checkPrereqs())
|
|
return NoValidPrereqs;
|
|
|
|
//everything ok so far
|
|
emit(requestSaveAll(false, true));
|
|
emit(start(this));
|
|
|
|
if (!m_launcher->launch())
|
|
{
|
|
KILE_DEBUG() << "\tlaunching failed" << endl;
|
|
if (!m_launcher->selfCheck())
|
|
return SelfCheckFailed;
|
|
else
|
|
return CouldNotLaunch;
|
|
}
|
|
|
|
KILE_DEBUG() << "\trunning..." << endl;
|
|
|
|
return Running;
|
|
|
|
}
|
|
|
|
bool Base::determineSource()
|
|
{
|
|
TQString src = source();
|
|
|
|
//the basedir is determined from the current compile target
|
|
//determined by getCompileName()
|
|
if (src.isNull()) src = m_ki->getCompileName();
|
|
|
|
setSource(src);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Base::checkSource()
|
|
{
|
|
//FIXME deal with tools that do not need a source or target (yes they exist)
|
|
//Is there an active document? Only check if the source file is not explicitly set.
|
|
if ( (m_source.isNull()) && (m_manager->info()->activeTextDocument() == 0L) )
|
|
{
|
|
sendMessage(Error, msg(NeedActiveDoc).arg(name()));
|
|
return false;
|
|
}
|
|
|
|
if ( (m_source.isNull()) && (m_manager->info()->activeTextDocument() != 0L) )
|
|
{
|
|
//couldn't find a source file, huh?
|
|
//we know there is an active document, the only reason is could have failed is because
|
|
//we couldn't find a LaTeX root document
|
|
sendMessage(Error, msg(NeedMasterDoc));
|
|
return false;
|
|
}
|
|
|
|
if ( KileUntitled::isUntitled(m_source) && (flags() & NoUntitledDoc) )
|
|
{
|
|
sendMessage(Error, msg(NoUntitledDoc));
|
|
emit(requestSaveAll());
|
|
return false;
|
|
}
|
|
|
|
TQFileInfo fi(source());
|
|
if ( (flags() & NeedSourceExists) && !fi.exists() )
|
|
{
|
|
sendMessage(Error, msg(NeedSourceExists).arg(fi.absFilePath()));
|
|
return false;
|
|
}
|
|
|
|
if ( (flags() & NeedSourceRead) && !fi.isReadable() )
|
|
{
|
|
sendMessage(Error, msg(NeedSourceRead).arg(fi.absFilePath()));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Base::setSource(const TQString &source)
|
|
{
|
|
m_from = readEntry("from");
|
|
|
|
TQFileInfo info(source);
|
|
|
|
if (!m_from.isNull())
|
|
{
|
|
TQString src = source;
|
|
if ( (m_from.length() > 0) && (info.extension(false).length() > 0) )
|
|
src.replace(TQRegExp(info.extension(false) + '$'), m_from);
|
|
info.setFile(src);
|
|
}
|
|
|
|
m_basedir = info.dirPath(true);
|
|
m_source = info.fileName();
|
|
m_S = info.baseName(true);
|
|
|
|
addDict("%dir_base", m_basedir);
|
|
addDict("%source", m_source);
|
|
addDict("%S",m_S);
|
|
|
|
KILE_DEBUG() << "===KileTool::Base::setSource()==============" << endl;
|
|
KILE_DEBUG() << "using " << source << endl;
|
|
KILE_DEBUG() << "source="<<m_source<<endl;
|
|
KILE_DEBUG() << "S=" << m_S << endl;
|
|
KILE_DEBUG() << "basedir=" << m_basedir << endl;
|
|
}
|
|
|
|
bool Base::determineTarget()
|
|
{
|
|
TQFileInfo info(source());
|
|
|
|
m_to = readEntry("to");
|
|
|
|
//if the target is not set previously, use the source filename
|
|
if (m_target.isNull())
|
|
{
|
|
//test for explicit override
|
|
if ( !readEntry("target").isEmpty() )
|
|
{
|
|
KILE_DEBUG() << "USING target SETTING" << endl;
|
|
m_target = readEntry("target");
|
|
}
|
|
else if ( to().length() > 0)
|
|
m_target = S() + '.' + to();
|
|
else
|
|
m_target = source(false);
|
|
}
|
|
|
|
if ( m_relativedir.isNull() && (!readEntry("relDir").isEmpty()) )
|
|
{
|
|
m_relativedir = readEntry("relDir");
|
|
}
|
|
|
|
KURL url = KURL::fromPathOrURL(m_basedir);
|
|
url.addPath(m_relativedir);
|
|
url.cleanPath();
|
|
m_targetdir = url.path();
|
|
|
|
setTarget(m_target);
|
|
setTargetDir(m_targetdir);
|
|
|
|
KILE_DEBUG() << "==KileTool::Base::determineTarget()=========" << endl;
|
|
KILE_DEBUG() << "\tm_targetdir=" << m_targetdir << endl;
|
|
KILE_DEBUG() << "\tm_target=" << m_target << endl;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Base::checkTarget()
|
|
{
|
|
//check if the target directory is accessible
|
|
TQFileInfo info(m_targetdir);
|
|
|
|
if ( (flags() & NeedTargetDirExec ) && (! info.isExecutable()) )
|
|
{
|
|
sendMessage(Error, msg(NeedTargetDirExec).arg(m_targetdir));
|
|
return false;
|
|
}
|
|
|
|
if ((flags() & NeedTargetDirWrite) && (! info.isWritable()) )
|
|
{
|
|
sendMessage(Error, msg(NeedTargetDirWrite).arg(m_targetdir).arg(m_name));
|
|
return false;
|
|
}
|
|
|
|
info.setFile(m_targetdir + '/' + m_target);
|
|
|
|
if ( (flags() & NeedTargetExists) && ( ! info.exists() ))
|
|
{
|
|
sendMessage(Error, msg(NeedTargetExists).arg(m_targetdir).arg(m_target));
|
|
return false;
|
|
}
|
|
|
|
if ( (flags() & NeedTargetRead) && ( ! info.isReadable() ))
|
|
{
|
|
sendMessage(Error, msg(NeedTargetRead).arg(m_targetdir).arg(m_target));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Base::setTarget(const TQString &target)
|
|
{
|
|
m_target = target;
|
|
addDict("%target", m_target);
|
|
}
|
|
|
|
void Base::setTargetDir(const TQString &target)
|
|
{
|
|
m_targetdir = target;
|
|
addDict("%dir_target", m_targetdir);
|
|
}
|
|
|
|
void Base::setTargetPath(const TQString &target)
|
|
{
|
|
TQFileInfo fi(target);
|
|
setTarget(fi.fileName());
|
|
setTargetDir(fi.dirPath(true));
|
|
}
|
|
|
|
bool Base::checkPrereqs()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool Base::configure(const TQString &cfg)
|
|
{
|
|
return m_manager->configure(this, cfg);
|
|
}
|
|
|
|
void Base::stop()
|
|
{
|
|
if (m_launcher)
|
|
m_launcher->kill();
|
|
|
|
//emit(done(this, Aborted));
|
|
}
|
|
|
|
bool Base::finish(int result)
|
|
{
|
|
KILE_DEBUG() << "==KileTool::Base::finish()==============" << endl;
|
|
if (sender())
|
|
{
|
|
KILE_DEBUG() << "\tcalled by " << sender()->name() << " " << sender()->className() << endl;
|
|
}
|
|
|
|
if ( result == Aborted )
|
|
sendMessage(Error, "Aborted");
|
|
|
|
if ( result == Success )
|
|
sendMessage(Info,"Done!");
|
|
|
|
KILE_DEBUG() << "\temitting done(Base*, int) " << name() << endl;
|
|
emit(done(this, result));
|
|
|
|
//we will only get here if the done() signal is not connected to the manager (who will destroy this object)
|
|
if (result == Success)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void Base::installLauncher(Launcher *lr)
|
|
{
|
|
if(m_launcher != lr)
|
|
delete m_launcher;
|
|
|
|
m_launcher = lr;
|
|
//lr->setParamDict(paramDict());
|
|
lr->setTool(this);
|
|
|
|
connect(lr, TQ_SIGNAL(message(int, const TQString &)), this, TQ_SLOT(sendMessage(int, const TQString &)));
|
|
connect(lr, TQ_SIGNAL(output(const TQString &)), this, TQ_SLOT(filterOutput(const TQString &)));
|
|
connect(lr, TQ_SIGNAL(done(int)), this, TQ_SLOT(finish(int)));
|
|
}
|
|
|
|
bool Base::installLauncher()
|
|
{
|
|
if (m_launcher)
|
|
return true;
|
|
|
|
TQString type = readEntry("type");
|
|
KILE_DEBUG() << "installing launcher of type " << type << endl;
|
|
Launcher *lr = 0;
|
|
|
|
if ( type == "Process" )
|
|
{
|
|
lr = new ProcessLauncher();
|
|
}
|
|
else if ( type == "Konsole" )
|
|
{
|
|
lr = new KonsoleLauncher();
|
|
}
|
|
else if ( type == "Part" )
|
|
{
|
|
lr = new PartLauncher();
|
|
}
|
|
else if ( type == "DocPart" )
|
|
{
|
|
lr = new DocPartLauncher();
|
|
}
|
|
|
|
if (lr)
|
|
{
|
|
installLauncher(lr);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
m_launcher = 0;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void Base::sendMessage(int type, const TQString &msg)
|
|
{
|
|
emit(message(type, msg, name()));
|
|
}
|
|
|
|
void Base::filterOutput(const TQString & str)
|
|
{
|
|
//here you have the change to filter the output and do some error extraction for example
|
|
//this should be done by a OutputFilter class
|
|
|
|
//idea: store the buffer until a complete line (or more) has been received then parse these lines
|
|
//just send the buf immediately to the output widget, the results of the parsing are displayed in
|
|
//the log widget anyway.
|
|
emit(output(str));
|
|
}
|
|
|
|
bool Base::addDict(const TQString & key, const TQString & value)
|
|
{
|
|
bool e = (paramDict()->find(key) == 0);
|
|
paramDict()->replace(key, &value);
|
|
return e;
|
|
}
|
|
|
|
bool Base::needsUpdate(const TQString &target, const TQString &source)
|
|
{
|
|
KILE_DEBUG() << "==Base::needsUpdate(" << target << "," << source << endl;
|
|
TQFileInfo targetinfo(target);
|
|
TQFileInfo sourceinfo(source);
|
|
TQDateTime currDateTime = TQDateTime::currentDateTime();
|
|
|
|
if ( !(sourceinfo.exists() && sourceinfo.isReadable()) )
|
|
{
|
|
KILE_DEBUG() << "\treturning false: source doesn't exist" << endl;
|
|
return false;
|
|
}
|
|
|
|
if ( ! targetinfo.exists() )
|
|
{
|
|
KILE_DEBUG() << "\treturning true: target doesn't exist" << endl;
|
|
return true;
|
|
}
|
|
|
|
KILE_DEBUG() << "\ttarget: " << targetinfo.lastModified().toString() << endl;
|
|
KILE_DEBUG() << "\tsource: " << sourceinfo.lastModified().toString() << endl;
|
|
|
|
if( targetinfo.lastModified() > currDateTime ){
|
|
|
|
KILE_DEBUG() << "targetinfo.lastModifiedTime() is in the future" << endl;
|
|
return false;
|
|
}
|
|
else if( sourceinfo.lastModified() > currDateTime ){
|
|
|
|
KILE_DEBUG() << "sourceinfo.lastModifiedTime() is in the future" << endl;
|
|
return false;
|
|
}
|
|
|
|
KILE_DEBUG() << "\treturning " << (targetinfo.lastModified() < sourceinfo.lastModified()) << endl;
|
|
return targetinfo.lastModified() < sourceinfo.lastModified();
|
|
}
|
|
|
|
Compile::Compile(const TQString &name, Manager * manager, bool prepare /*= true*/)
|
|
: Base(name, manager, prepare)
|
|
{
|
|
setFlags( flags() | NeedTargetDirExec | NeedTargetDirWrite);
|
|
}
|
|
|
|
Compile::~Compile()
|
|
{}
|
|
|
|
bool Compile::checkSource()
|
|
{
|
|
if ( !Base::checkSource() ) return false;
|
|
|
|
bool isRoot = true;
|
|
KileDocument::TextInfo *docinfo = manager()->info()->docManager()->textInfoFor(source());
|
|
if (docinfo) isRoot = (readEntry("checkForRoot") == "yes") ? docinfo->isLaTeXRoot() : true;
|
|
|
|
if (!isRoot)
|
|
{
|
|
return manager()->queryContinue(i18n("The document %1 is not a LaTeX root document; continue anyway?").arg(source()), i18n("Continue?"));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
View::View(const TQString &name, Manager * manager, bool prepare /*= true*/)
|
|
: Base(name, manager, prepare)
|
|
{
|
|
setFlags( NeedTargetDirExec | NeedTargetExists | NeedTargetRead);
|
|
|
|
KILE_DEBUG() << "View: flag " << (flags() & NeedTargetExists) << endl;
|
|
setMsg(NeedTargetExists, i18n("The file %2/%3 does not exist; did you compile the source file?"));
|
|
}
|
|
|
|
View::~View()
|
|
{
|
|
}
|
|
|
|
|
|
Archive::Archive(const TQString &name, Manager * manager, bool prepare /* = true*/)
|
|
: Base(name, manager,prepare)
|
|
{
|
|
setFlags( NeedTargetDirExec | NeedTargetDirWrite );
|
|
}
|
|
|
|
Archive::~Archive()
|
|
{}
|
|
|
|
bool Archive::checkPrereqs()
|
|
{
|
|
if(m_project == 0L)
|
|
{
|
|
sendMessage(Error,i18n("The current document is not associated to a project. Please activate a document that is associated to the project you want to archive, then choose Archive again."));
|
|
return false;
|
|
}
|
|
else if(m_fileList.isEmpty())
|
|
{
|
|
sendMessage(Error,i18n("No files have been chosen for archiving."));
|
|
return false;
|
|
}
|
|
else
|
|
return true;
|
|
}
|
|
|
|
void Archive::setSource(const TQString &source)
|
|
{
|
|
KURL url = KURL::fromPathOrURL(source);
|
|
m_project = manager()->info()->docManager()->projectFor(url);
|
|
if ( !m_project )
|
|
m_project = manager()->info()->docManager()->activeProject();
|
|
if ( !m_project )
|
|
m_project = manager()->info()->docManager()->selectProject(i18n("Archive Project"));
|
|
if ( !m_project )
|
|
{
|
|
Base::setSource(source);
|
|
return;
|
|
}
|
|
manager()->info()->docManager()->projectSave(m_project);
|
|
Base::setSource(m_project->url().path());
|
|
m_fileList = m_project->archiveFileList();
|
|
|
|
addDict("%AFL", m_fileList);
|
|
|
|
KILE_DEBUG() << "===KileTool::Archive::setSource("<< source << ")==============" << endl;
|
|
KILE_DEBUG() << "m_fileList="<<m_fileList<<endl;
|
|
}
|
|
|
|
Convert::Convert(const TQString &name, Manager * manager, bool prepare /*= true*/)
|
|
: Base(name, manager,prepare)
|
|
{
|
|
setFlags( flags() | NeedTargetDirExec | NeedTargetDirWrite );
|
|
}
|
|
|
|
Convert::~Convert()
|
|
{
|
|
}
|
|
|
|
bool Convert::determineSource()
|
|
{
|
|
bool br = Base::determineSource();
|
|
setSource(baseDir() + '/' + S() + '.' + from());
|
|
return br;
|
|
}
|
|
|
|
Sequence::Sequence(const TQString &name, Manager * manager, bool prepare /*= true*/) :
|
|
Base(name, manager, prepare)
|
|
{
|
|
}
|
|
|
|
int Sequence::run()
|
|
{
|
|
KILE_DEBUG() << "==KileTool::Sequence::run()==================" << endl;
|
|
|
|
configure();
|
|
determineSource();
|
|
if (!checkSource()) return NoValidSource;
|
|
|
|
TQStringList tools = TQStringList::split(',',readEntry("sequence"));
|
|
TQString tl, cfg;
|
|
Base *tool;
|
|
for (uint i=0; i < tools.count(); ++i)
|
|
{
|
|
tools[i] = tools[i].stripWhiteSpace();
|
|
extract(tools[i], tl, cfg);
|
|
|
|
tool = manager()->factory()->create(tl, false); //create tool with delayed preparation
|
|
if (tool)
|
|
{
|
|
KILE_DEBUG() << "===tool created with name " << tool->name() << endl;
|
|
if ( ! (manager()->info()->watchFile() && tool->isViewer() ) )
|
|
{
|
|
KILE_DEBUG() << "\tqueueing " << tl << "(" << cfg << ") with " << source() << endl;
|
|
tool->setSource(source());
|
|
manager()->run(tool, cfg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sendMessage(Error, i18n("Unknown tool %1.").arg(tools[i]));
|
|
emit(done(this, Failed));
|
|
return ConfigureFailed;
|
|
}
|
|
}
|
|
|
|
emit(done(this,Silent));
|
|
|
|
return Success;
|
|
}
|
|
}
|
|
|
|
#include "kiletool.moc"
|