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.
kile/src/kile/kilejscript.cpp

796 lines
26 KiB

/**************************************************************************
* Copyright (C) 2006, 2007 by Michel Ludwig (michel.ludwig@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 "kilejscript.h"
/*
* KJS uses a garbage collection mechanism.
*/
#include <kjs/lookup.h>
#include <kconfig.h>
#include "kiledebug.h"
#include <kinputdialog.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <signal.h>
#include <sys/time.h>
#include <tqevent.h>
#include <tqdir.h>
#include <tqfile.h>
#include <tqfileinfo.h>
#include <tqtextstream.h>
#include <tqvaluelist.h>
#include "kileconfig.h"
#include "kileedit.h"
#include "kileinfo.h"
#include "kileversion.h"
#include "kileviewmanager.h"
#include "editorkeysequencemanager.h"
// Modified declaration from <tdehtml/ecma/kjs_proxy.h>
// Acknowledgements go to:
// Copyright (C) 1999 Harri Porten (porten@kde.org)
// Copyright (C) 2001 Peter Kelly (pmk@post.com)
class KJSCPUGuard {
public:
KJSCPUGuard() {}
void start(unsigned int msec=5000, unsigned int i_msec=0);
void stop();
private:
void (*oldAlarmHandler)(int);
static void alarmHandler(int);
itimerval oldtv;
};
// Modified implementation originating from <tdehtml/ecma/kjs_proxy.cpp>
// Acknowledgements go to:
// Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
// Copyright (C) 2001,2003 Peter Kelly (pmk@post.com)
// Copyright (C) 2001-2003 David Faure (faure@kde.org)
void KJSCPUGuard::start(unsigned int ms, unsigned int i_ms)
{
oldAlarmHandler = signal(SIGVTALRM, alarmHandler);
itimerval tv = {
{ i_ms / 1000, (i_ms % 1000) * 1000 },
{ ms / 1000, (ms % 1000) * 1000 }
};
setitimer(ITIMER_VIRTUAL, &tv, &oldtv);
}
void KJSCPUGuard::stop()
{
setitimer(ITIMER_VIRTUAL, &oldtv, 0L);
signal(SIGVTALRM, oldAlarmHandler);
}
void KJSCPUGuard::alarmHandler(int) {
KJS::ExecState::requestTerminate();
}
namespace KJS {
// Taken from <tdehtml/ecma/kjs_binding.cpp>
// Acknowledgements go to:
// Copyright (C) 1999-2003 Harri Porten (porten@kde.org)
// Copyright (C) 2001-2003 David Faure (faure@kde.org)
// Copyright (C) 2003 Apple Computer, Inc.
UString::UString(const TQString &d) {
unsigned int len = d.length();
UChar *dat = new UChar[len];
memcpy(dat, d.unicode(), len * sizeof(UChar));
rep = UString::Rep::create(dat, len);
}
TQString UString::qstring() const {
return TQString((TQChar*) data(), size());
}
TQConstString UString::qconststring() const {
return TQConstString((TQChar*) data(), size());
}
}
namespace KJS {
class KileJSObjectFunc; // forward declaration
}
class KileJSObject : public KJS::ObjectImp {
friend class KJS::KileJSObjectFunc;
public:
KileJSObject(KJS::ExecState *exec, KileInfo *kileInfo);
virtual ~KileJSObject();
// there are no non-functional properties
// KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const;
// KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
// void put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value& value, int attr = KJS::None);
// void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value& value, int attr);
virtual const KJS::ClassInfo *classInfo() const;
enum {
CurrentTextDocument,
GetInputValue
};
static const KJS::ClassInfo info;
protected:
KileInfo *m_kileInfo;
};
namespace KJS {
class KileTextDocumentJSObjectFunc; // forward declaration
}
class KileTextDocumentJSObject : public KJS::ObjectImp {
friend class KJS::KileTextDocumentJSObjectFunc;
public:
KileTextDocumentJSObject(KJS::ExecState *exec, Kate::View* view, KileInfo *kileInfo);
virtual ~KileTextDocumentJSObject();
// there are no non-functional properties
// KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const;
// KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
// void put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value& value, int attr = KJS::None);
// void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value& value, int attr);
virtual const KJS::ClassInfo *classInfo() const;
enum {
InsertBullet,
InsertText,
NextBullet,
PreviousBullet,
CursorLeft,
CursorRight,
Up,
Down,
CursorLine,
CursorColumn,
SetCursorLine,
SetCursorColumn,
Backspace
};
static const KJS::ClassInfo info;
protected:
Kate::View* view;
KileInfo *m_kileInfo;
};
#include "kilejscript.lut.h"
/*
* The number of supplied arguments is checked automatically.
*/
// Only functional properties:
/*
@begin KileJSObjectProtoTable 2
currentTextDocument KileJSObject::CurrentTextDocument DontDelete|Function 0
getInputValue KileJSObject::GetInputValue DontDelete|Function 2
@end
*/
// Non-functional properties go here:
/*
@begin KileJSObjectTable 0
@end
*/
DEFINE_PROTOTYPE("KileJSObject", KileJSObjectProto)
IMPLEMENT_PROTOFUNC(KileJSObjectFunc)
IMPLEMENT_PROTOTYPE(KileJSObjectProto, KileJSObjectFunc)
const KJS::ClassInfo KileJSObject::info = {"KileJSObject", 0, &KileJSObjectTable, 0};
KileJSObject::KileJSObject(KJS::ExecState *exec, KileInfo *kileInfo) : ObjectImp(KileJSObjectProto::self(exec)), m_kileInfo(kileInfo) {
}
KileJSObject::~KileJSObject() {
}
const KJS::ClassInfo* KileJSObject::classInfo() const {
return &info;
}
/*
KJS::Value KileJSObject::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const {
return KJS::lookupGetValue<KileJSObject, KJS::ObjectImp>(exec, propertyName, &KileJSObjectTable, this);
}
*/
/*
KJS::Value KileJSObject::getValueProperty(KJS::ExecState *exec, int token) const
{
if (!m_kileInfo) {
return KJS::Undefined();
}
switch (token) {
}
return KJS::Undefined();
}
*/
KJS::Value KJS::KileJSObjectFunc::call(KJS::ExecState *exec, KJS::Object &thisObj, const KJS::List &args) {
KJS_CHECK_THIS(KileJSObject, thisObj);
// KileJSObject *obj = static_cast<KileJSObject *>(thisObj.imp())->doc;
KileInfo* kileInfo = static_cast<KileJSObject*>(thisObj.imp())->m_kileInfo;
if(!kileInfo) {
return KJS::Undefined();
}
TQString caption, label, value;
KileTextDocumentJSObject *kileViewJSObject;
Kate::View *kateView;
switch (id) {
case KileJSObject::CurrentTextDocument:
kateView = kileInfo->viewManager()->currentTextView();
if(kateView == 0L) {
return KJS::Null();
}
else {
kileViewJSObject = new KileTextDocumentJSObject(exec, kateView, kileInfo);
return KJS::Object(kileViewJSObject);
}
break;
case KileJSObject::GetInputValue:
caption = args[0].toString(exec).qstring();
label = args[1].toString(exec).qstring();
if(caption.isEmpty()) {
caption = i18n("Enter Value");
}
if(label.isEmpty()) {
label = i18n("Please enter a value");
}
value = KInputDialog::getText(caption, label, TQString(), 0, 0L);
return KJS::String(value);
break;
}
return KJS::Undefined();
}
// Only functional properties:
/*
@begin KileTextDocumentJSObjectProtoTable 13
#
insertText KileTextDocumentJSObject::InsertText DontDelete|Function 1
insertBullet KileTextDocumentJSObject::InsertBullet DontDelete|Function 0
nextBullet KileTextDocumentJSObject::NextBullet DontDelete|Function 0
previousBullet KileTextDocumentJSObject::PreviousBullet DontDelete|Function 0
cursorLeft KileTextDocumentJSObject::CursorLeft DontDelete|Function 0
cursorRight KileTextDocumentJSObject::CursorRight DontDelete|Function 0
up KileTextDocumentJSObject::Up DontDelete|Function 0
down KileTextDocumentJSObject::Down DontDelete|Function 0
cursorLine KileTextDocumentJSObject::CursorLine DontDelete|Function 0
cursorColumn KileTextDocumentJSObject::CursorColumn DontDelete|Function 0
setCursorLine KileTextDocumentJSObject::SetCursorLine DontDelete|Function 1
setCursorColumn KileTextDocumentJSObject::SetCursorColumn DontDelete|Function 1
backspace KileTextDocumentJSObject::Backspace DontDelete|Function 0
#
@end
*/
// Non-functional properties go here:
/*
@begin KileTextDocumentJSObjectTable 0
@end
*/
DEFINE_PROTOTYPE("KileTextDocumentJSObject", KileTextDocumentJSObjectProto)
IMPLEMENT_PROTOFUNC(KileTextDocumentJSObjectFunc)
IMPLEMENT_PROTOTYPE(KileTextDocumentJSObjectProto, KileTextDocumentJSObjectFunc)
KileTextDocumentJSObject::KileTextDocumentJSObject(KJS::ExecState *exec, Kate::View* view, KileInfo *kileInfo) : ObjectImp(KileTextDocumentJSObjectProto::self(exec)), view(view), m_kileInfo(kileInfo) {
}
KileTextDocumentJSObject::~KileTextDocumentJSObject() {
}
/*
KJS::Value KileTextDocumentJSObject::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const {
return KJS::lookupGetValue<KileTextDocumentJSObject, KJS::ObjectImp>(exec, propertyName, &KileTextDocumentJSObjectTable, this);
}
*/
/*
KJS::Value KileTextDocumentJSObject::getValueProperty(KJS::ExecState *exec, int token) const {
return KJS::Undefined ();
}
*/
KJS::Value KJS::KileTextDocumentJSObjectFunc::call(KJS::ExecState *exec, KJS::Object &thisObj, const KJS::List &args) {
KJS_CHECK_THIS(KileTextDocumentJSObject, thisObj);
// KileJSObject *obj = static_cast<KileJSObject *>(thisObj.imp())->doc;
KileInfo* kileInfo = static_cast<KileTextDocumentJSObject *>(thisObj.imp())->m_kileInfo;
Kate::View* view = ((KileTextDocumentJSObject*)(thisObj.imp()))->view;
uint col, line;
switch (id) {
case KileTextDocumentJSObject::InsertText:
view->insertText(args[0].toString(exec).qstring());
break;
case KileTextDocumentJSObject::InsertBullet:
kileInfo->editorExtension()->insertBullet(view);
break;
case KileTextDocumentJSObject::NextBullet:
kileInfo->editorExtension()->nextBullet(view);
break;
case KileTextDocumentJSObject::PreviousBullet:
kileInfo->editorExtension()->prevBullet(view);
break;
case KileTextDocumentJSObject::CursorRight:
view->cursorRight();
break;
case KileTextDocumentJSObject::CursorLeft:
view->cursorLeft();
break;
case KileTextDocumentJSObject::Up:
view->up();
break;
case KileTextDocumentJSObject::Down:
view->down();
break;
case KileTextDocumentJSObject::CursorLine:
view->cursorPositionReal(&line, &col);
return KJS::Number(line);
break;
case KileTextDocumentJSObject::CursorColumn:
view->cursorPositionReal(&line, &col);
return KJS::Number(col);
break;
case KileTextDocumentJSObject::SetCursorLine:
view->cursorPositionReal(&line, &col);
view->setCursorPositionReal(args[0].toUInt32(exec), col);
break;
case KileTextDocumentJSObject::SetCursorColumn:
view->cursorPositionReal(&line, &col);
view->setCursorPositionReal(line, args[0].toUInt32(exec));
break;
case KileTextDocumentJSObject::Backspace:
view->backspace();
break;
}
return KJS::Undefined();
}
const KJS::ClassInfo* KileTextDocumentJSObject::classInfo() const {
return &info;
}
const KJS::ClassInfo KileTextDocumentJSObject::info = {"KileTextDocumentJSObject", 0, &KileTextDocumentJSObjectTable, 0};
namespace KileJScript {
////////////////////////////// JScript //////////////////////////////
/* The IDs of the scripts are used to maintain correct bindings with KAction objects, i.e. for example, we
* want to make sure the action script_execution_0 always refers to same script (the script with id 0 !), even
* after reloading all the scripts.
*/
JScript::JScript(unsigned int id, const TQString& file) : m_id(id), m_file(file), m_action(NULL) {
m_name = TDEGlobal::dirs()->relativeLocation("appdata", file);
if(m_name.startsWith("scripts")) {
m_name = m_name.mid(8); // remove "scripts" + path separator
}
if(m_name.endsWith(".js")) { // remove the extension
m_name = m_name.left(m_name.length() - 3);
}
}
TQString JScript::getName() const {
return m_name;
}
TQString JScript::getCode() const {
TQFile qFile(m_file);
if(qFile.open(IO_ReadOnly)) {
TQTextStream inputStream(&qFile);
// inputStream.setEncoding(TQTextStream::UnicodeUTF8);
TQString code = inputStream.read();
qFile.close();
return code;
}
else {
return TQString();
}
}
TQString JScript::getFileName() const {
return m_file;
}
unsigned int JScript::getID() const {
return m_id;
}
void JScript::setID(unsigned int id) {
m_id = id;
}
void JScript::setActionObject(KAction* action) {
m_action = action;
}
const KAction* JScript::getActionObject() const {
return m_action;
}
KAction* JScript::getActionObject() {
return m_action;
}
void JScript::setKeySequence(const TQString& str) {
m_keySequence = str;
}
TQString JScript::getKeySequence() const {
return m_keySequence;
}
////////////////////////////// JScriptEnvironment //////////////////////////////
JScriptEnvironment::JScriptEnvironment(KileInfo *kileInfo) : m_interpreter(new KJS::Interpreter()), m_kileJSObject(new KJS::Object(new KileJSObject(m_interpreter->globalExec(), kileInfo))), m_kileInfo(kileInfo) {
// no garbage collection because of an external reference
m_interpreter->globalObject().put(m_interpreter->globalExec(), "kile", *m_kileJSObject, KJS::DontDelete|KJS::Internal);
}
JScriptEnvironment::~JScriptEnvironment() {
//kileJSObject->imp() will be deleted during the next garbage cleanup
delete m_kileJSObject;
delete m_interpreter;
}
void JScriptEnvironment::execute(const TQString& s) {
bool useGuard = KileConfig::timeLimitEnabled();
uint timeLimit = (uint)KileConfig::timeLimit();
KJSCPUGuard guard;
if(useGuard) {
guard.start(timeLimit*1000);
}
Completion completion = m_interpreter->evaluate(s);
if(useGuard) {
guard.stop();
}
if(completion.complType() == Throw) {
Value value = completion.value();
if(value.type() == ObjectType) {
Object o = Object::dynamicCast(value);
if(o.isValid()) {
Value lineValue = o.get(m_interpreter->globalExec(), "line");
if(lineValue.type() == NumberType) {
KMessageBox::sorry(0L, i18n("The following exception has occurred at line %1 during execution of the script:\n%2").arg(lineValue.toInt32(m_interpreter->globalExec())).arg(value.toString(m_interpreter->globalExec()).qstring()), i18n("Exception"));
return;
}
}
}
KMessageBox::sorry(0L, i18n("The following exception has occurred during execution of the script:\n%1").arg(value.toString(m_interpreter->globalExec()).qstring()), i18n("Exception"));
}
}
////////////////////////////// Manager //////////////////////////////
Manager::Manager(KileInfo *kileInfo, TDEConfig *config, KActionCollection *actionCollection, TQObject *parent, const char *name) : TQObject(parent, name), m_jScriptDirWatch(NULL), m_kileInfo(kileInfo), m_config(config), m_actionCollection(actionCollection) {
// create a local scripts directory if it doesn't exist yet
m_localJScriptDir = locateLocal("appdata", "scripts/", true);
m_jScriptDirWatch = new KDirWatch(this, "KileJScript::Manager::JScriptDirWatch");
connect(m_jScriptDirWatch, TQT_SIGNAL(dirty(const TQString&)), this, TQT_SLOT(scanJScriptDirectories()));
connect(m_jScriptDirWatch, TQT_SIGNAL(created(const TQString&)), this, TQT_SLOT(scanJScriptDirectories()));
connect(m_jScriptDirWatch, TQT_SIGNAL(deleted(const TQString&)), this, TQT_SLOT(scanJScriptDirectories()));
m_jScriptDirWatch->startScan();
}
Manager::~Manager() {
delete m_jScriptDirWatch;
//still need to delete the scripts
for(TQValueList<JScript*>::iterator it = m_jScriptList.begin(); it != m_jScriptList.end(); ++it) {
delete *it;
}
}
void Manager::executeJScript(const JScript *script) {
JScriptEnvironment env(m_kileInfo);
// demonstrate repainting bug:
/*KMessageBox::information(0L, "works!!!");
m_kileInfo->viewManager()->currentView()->down();
m_kileInfo->viewManager()->currentView()->down();
m_kileInfo->viewManager()->currentView()->down();
m_kileInfo->viewManager()->currentView()->down();
m_kileInfo->viewManager()->currentView()->down();*/
TQString code = script->getCode();
TQRegExp endOfLineExp("(\r\n)|\n|\r");
int i = code.find(endOfLineExp);
TQString firstLine = (i >= 0 ? code.left(i) : code);
TQRegExp requiredVersionTagExp("(kile-version:\\s*)(\\d+\\.\\d+(.\\d+)?)");
if(requiredVersionTagExp.search(firstLine) != -1) {
TQString requiredKileVersion = requiredVersionTagExp.cap(2);
if(compareVersionStrings(requiredKileVersion, kileFullVersion) > 0) {
KMessageBox::sorry(0L, i18n("Version %1 of Kile is at least required to execute the script \"%2\". The execution has been aborted.").arg(requiredKileVersion).arg(script->getName()), i18n("Version Error"));
return;
}
}
env.execute(code);
}
void Manager::executeJScript(unsigned int id) {
TQMap<unsigned int, JScript*>::iterator i = m_idScriptMap.find(id);
if(i != m_idScriptMap.end()) {
executeJScript(*i);
}
}
const JScript* Manager::getScript(unsigned int id) {
TQMap<unsigned int, JScript*>::iterator i = m_idScriptMap.find(id);
return ((i != m_idScriptMap.end()) ? (*i) : NULL);
}
void Manager::scanJScriptDirectories() {
if(!KileConfig::scriptingEnabled()) {
return;
}
deleteJScripts();
populateDirWatch();
m_config->setGroup("Scripts");
TQValueList<unsigned int> idList = readUnsignedIntListEntry("IDs");
unsigned int maxID = 0;
TQMap<TQString, unsigned int> pathIDMap;
TQMap<unsigned int, bool> takenIDMap;
for(TQValueList<unsigned int>::iterator i = idList.begin(); i != idList.end(); ++i) {
TQString fileName = m_config->readPathEntry("Script" + TQString::number(*i));
if(!fileName.isEmpty()) {
unsigned int id = *i;
pathIDMap[fileName] = id;
takenIDMap[id] = true;
maxID = TQMAX(maxID, id);
}
}
m_config->setGroup(TQString());
TQStringList scriptFileNamesList = TDEGlobal::dirs()->findAllResources("appdata", "scripts/*.js", true, true);
for(TQStringList::iterator i = scriptFileNamesList.begin(); i != scriptFileNamesList.end(); ++i) {
registerScript(*i, pathIDMap, takenIDMap, maxID);
}
//rewrite the IDs that are currently in use
writeIDs();
m_actionCollection->readShortcutSettings("Shortcuts");
emit jScriptsChanged();
}
void Manager::deleteJScripts() {
TQValueList<JScript*> scriptList = m_jScriptList;
m_jScriptList.clear(); // pretend that there are no scripts left
TQStringList keySequenceList;
for(TQValueList<JScript*>::iterator it = scriptList.begin(); it != scriptList.end(); ++it) {
keySequenceList.push_back((*it)->getKeySequence());
}
m_idScriptMap.clear();
m_kileInfo->editorKeySequenceManager()->removeKeySequence(keySequenceList);
for(TQValueList<JScript*>::iterator it = scriptList.begin(); it != scriptList.end(); ++it) {
KAction *action = (*it)->getActionObject();
if(action) {
action->unplugAll();
delete action;
}
delete *it;
}
emit jScriptsChanged();
}
TQValueList<JScript*> Manager::getJScripts() {
return m_jScriptList;
}
void Manager::registerScript(const TQString& fileName, TQMap<TQString, unsigned int>& pathIDMap, TQMap<unsigned int, bool>& takenIDMap, unsigned int &maxID) {
unsigned int id;
TQMap<TQString, unsigned int>::iterator it = pathIDMap.find(fileName);
if(it != pathIDMap.end()) {
id = *it;
}
else {
id = findFreeID(takenIDMap, maxID);
pathIDMap[fileName] = id;
takenIDMap[id] = true;
maxID = TQMAX(maxID, id);
}
JScript* script = new JScript(id, fileName);
m_jScriptList.push_back(script);
m_idScriptMap[id] = script;
// start with setting up the key sequence
m_config->setGroup("Scripts");
TQString editorKeySequence = m_config->readEntry("Script" + TQString::number(id) + "KeySequence");
m_config->setGroup(TQString());
if(!editorKeySequence.isEmpty()) {
script->setKeySequence(editorKeySequence);
m_kileInfo->editorKeySequenceManager()->addAction(editorKeySequence, new KileEditorKeySequence::ExecuteJScriptAction(script, this));
}
// now set up a regular action object
ScriptExecutionAction *action = new ScriptExecutionAction(id, this, m_actionCollection);
script->setActionObject(action);
}
void Manager::writeConfig() {
// don't delete the key sequence settings if scripting has been disabled
if(!KileConfig::scriptingEnabled()) {
return;
}
m_config->deleteGroup("Scripts");
writeIDs();
// write the key sequences
m_config->setGroup("Scripts");
for(TQValueList<JScript*>::iterator i = m_jScriptList.begin(); i != m_jScriptList.end(); ++i) {
m_config->writeEntry("Script" + TQString::number((*i)->getID()) + "KeySequence", (*i)->getKeySequence());
}
m_config->setGroup(TQString());
}
void Manager::setEditorKeySequence(JScript* script, const TQString& keySequence) {
if(keySequence.isEmpty()) {
return;
}
if(script) {
TQString oldSequence = script->getKeySequence();
if(oldSequence == keySequence) {
return;
}
m_kileInfo->editorKeySequenceManager()->removeKeySequence(oldSequence);
script->setKeySequence(keySequence);
m_kileInfo->editorKeySequenceManager()->addAction(keySequence, new KileEditorKeySequence::ExecuteJScriptAction(script, this));
writeConfig();
}
}
void Manager::removeEditorKeySequence(JScript* script) {
if(script) {
TQString keySequence = script->getKeySequence();
if(keySequence.isEmpty()) {
return;
}
script->setKeySequence(TQString());
m_kileInfo->editorKeySequenceManager()->removeKeySequence(keySequence);
writeConfig();
}
}
void Manager::populateDirWatch() {
TQStringList jScriptDirectories = TDEGlobal::dirs()->findDirs("appdata", "scripts");
for(TQStringList::iterator i = jScriptDirectories.begin(); i != jScriptDirectories.end(); ++i) {
// FIXME: future KDE versions could support the recursive
// watching of directories out of the box.
addDirectoryToDirWatch(*i);
}
//we do not remove the directories that were once added as this apparently causes some strange
//bugs (on KDE 3.5.x)
}
TQString Manager::getLocalJScriptDirectory() const {
return m_localJScriptDir;
}
void Manager::readConfig() {
deleteJScripts();
scanJScriptDirectories();
}
TQValueList<unsigned int> Manager::readUnsignedIntListEntry(const TQString& key) {
TQValueList<unsigned int> toReturn;
TQStringList stringList = m_config->readListEntry(key);
for(TQStringList::iterator i = stringList.begin(); i != stringList.end(); ++i) {
toReturn.push_back((*i).toUInt());
}
return toReturn;
}
void Manager::writeEntry(const TQString& key, const TQValueList<unsigned int>& l) {
TQStringList stringList;
for(TQValueList<unsigned int>::const_iterator i = l.begin(); i != l.end(); ++i) {
stringList.push_back(TQString::number(*i));
}
m_config->writeEntry(key, stringList);
}
unsigned int Manager::findFreeID(const TQMap<unsigned int, bool>& takenIDMap, unsigned int maxID) {
if(takenIDMap.size() == 0) {
return 0;
}
// maxID should have a real meaning now
for(unsigned int i = 0; i < maxID; ++i) {
if(takenIDMap.find(i) == takenIDMap.end()) {
return i;
}
}
return (maxID + 1);
}
void Manager::writeIDs() {
m_config->setGroup("Scripts");
//delete old entries
TQValueList<unsigned int> idList = readUnsignedIntListEntry("IDs");
for(TQValueList<unsigned int>::iterator i = idList.begin(); i != idList.end(); ++i) {
m_config->deleteEntry("Script" + TQString::number(*i));
}
//write new ones
idList.clear();
for(TQMap<unsigned int, JScript*>::iterator i = m_idScriptMap.begin(); i != m_idScriptMap.end(); ++i) {
unsigned int id = i.key();
idList.push_back(id);
m_config->writePathEntry("Script" + TQString::number(id), (*i)->getFileName());
}
writeEntry("IDs", idList);
m_config->setGroup(TQString());
}
void Manager::addDirectoryToDirWatch(const TQString& dir) {
//FIXME: no recursive watching and no watching of files as it isn't implemented
// yet
if(!m_jScriptDirWatch->contains(dir)) {
m_jScriptDirWatch->addDir(dir, false, false);
}
TQDir qDir(dir);
TQStringList list = qDir.entryList(TQDir::Dirs);
for(TQStringList::iterator i = list.begin(); i != list.end(); ++i) {
TQString subdir = *i;
if(subdir != "." && subdir != "..") {
addDirectoryToDirWatch(qDir.filePath(subdir));
}
}
}
////////////////////////////// ScriptExecutionAction //////////////////////////////
ScriptExecutionAction::ScriptExecutionAction(unsigned int id, KileJScript::Manager *manager, KActionCollection* parent) : KAction(TQString(), KShortcut(), NULL, NULL, parent, TQString("script_execution_" + TQString::number(id)).ascii()), m_manager(manager), m_id(id) {
const KileJScript::JScript *script = m_manager->getScript(m_id);
Q_ASSERT(script);
setText(i18n("Execution of %1").arg(script->getName()));
connect(this, TQT_SIGNAL(activated()), this, TQT_SLOT(executeScript()));
}
ScriptExecutionAction::~ScriptExecutionAction() {
}
void ScriptExecutionAction::executeScript() {
m_manager->executeJScript(m_id);
}
};
#include "kilejscript.moc"