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.
796 lines
26 KiB
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 <tdeconfig.h>
|
|
#include "kiledebug.h"
|
|
#include <kinputdialog.h>
|
|
#include <tdelocale.h>
|
|
#include <tdemessagebox.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 = {
|
|
{ static_cast<time_t>( i_ms / 1000 ), static_cast<suseconds_t>( (i_ms % 1000) * 1000 ) },
|
|
{ static_cast<time_t>( ms / 1000 ), static_cast<suseconds_t>( (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 TDEAction 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(TDEAction* action) {
|
|
m_action = action;
|
|
}
|
|
|
|
const TDEAction* JScript::getActionObject() const {
|
|
return m_action;
|
|
}
|
|
|
|
TDEAction* 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, TDEActionCollection *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, TQ_SIGNAL(dirty(const TQString&)), this, TQ_SLOT(scanJScriptDirectories()));
|
|
connect(m_jScriptDirWatch, TQ_SIGNAL(created(const TQString&)), this, TQ_SLOT(scanJScriptDirectories()));
|
|
connect(m_jScriptDirWatch, TQ_SIGNAL(deleted(const TQString&)), this, TQ_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) {
|
|
TDEAction *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, TDEActionCollection* parent) : TDEAction(TQString(), TDEShortcut(), 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, TQ_SIGNAL(activated()), this, TQ_SLOT(executeScript()));
|
|
}
|
|
|
|
ScriptExecutionAction::~ScriptExecutionAction() {
|
|
}
|
|
|
|
void ScriptExecutionAction::executeScript() {
|
|
m_manager->executeJScript(m_id);
|
|
}
|
|
|
|
};
|
|
|
|
#include "kilejscript.moc"
|