|
|
|
/* This file is part of the KDE project
|
|
|
|
Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
|
|
|
|
Copyright (C) 2004-2005 Jaroslaw Staniek <js@iidea.pl>
|
|
|
|
Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
|
|
|
|
Copyright (C) 2005 Sebastian Sauer <mail@dipe.org>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this program; see the file COPYING. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
* Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "kexiscriptdesignview.h"
|
|
|
|
#include "kexiscripteditor.h"
|
|
|
|
|
|
|
|
#include <kross/main/manager.h>
|
|
|
|
#include <kross/main/scriptcontainer.h>
|
|
|
|
#include <kross/main/scriptaction.h>
|
|
|
|
#include <kross/api/interpreter.h>
|
|
|
|
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqsplitter.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqdatetime.h>
|
|
|
|
#include <tqdom.h>
|
|
|
|
#include <tqstylesheet.h>
|
|
|
|
#include <ktextbrowser.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
#include <kexidialogbase.h>
|
|
|
|
#include <kexidb/connection.h>
|
|
|
|
|
|
|
|
/// @internal
|
|
|
|
class KexiScriptDesignViewPrivate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The \a Kross::Api::ScriptAction instance which provides
|
|
|
|
* us access to the scripting framework Kross.
|
|
|
|
*/
|
|
|
|
Kross::Api::ScriptAction* scriptaction;
|
|
|
|
|
|
|
|
/// The \a KexiScriptEditor to edit the scripting code.
|
|
|
|
KexiScriptEditor* editor;
|
|
|
|
|
|
|
|
/// The \a KoProperty::Set used in the propertyeditor.
|
|
|
|
KoProperty::Set* properties;
|
|
|
|
|
|
|
|
/// Boolean flag to avoid infinite recursion.
|
|
|
|
bool updatesProperties;
|
|
|
|
|
|
|
|
/// Used to display statusmessages.
|
|
|
|
KTextBrowser* statusbrowser;
|
|
|
|
};
|
|
|
|
|
|
|
|
KexiScriptDesignView::KexiScriptDesignView(KexiMainWindow *mainWin, TQWidget *parent, Kross::Api::ScriptAction* scriptaction)
|
|
|
|
: KexiViewBase(mainWin, parent, "KexiScriptDesignView")
|
|
|
|
, d( new KexiScriptDesignViewPrivate() )
|
|
|
|
{
|
|
|
|
d->scriptaction = scriptaction;
|
|
|
|
d->updatesProperties = false;
|
|
|
|
|
|
|
|
TQSplitter* splitter = new TQSplitter(this);
|
|
|
|
splitter->setOrientation(TQt::Vertical);
|
|
|
|
TQHBoxLayout* layout = new TQHBoxLayout(this);
|
|
|
|
layout->addWidget(splitter);
|
|
|
|
|
|
|
|
d->editor = new KexiScriptEditor(mainWin, splitter, "ScriptEditor");
|
|
|
|
splitter->setFocusProxy(d->editor);
|
|
|
|
addChildView(d->editor);
|
|
|
|
setViewWidget(d->editor);
|
|
|
|
|
|
|
|
d->statusbrowser = new KTextBrowser(splitter, "ScriptStatusBrowser");
|
|
|
|
d->statusbrowser->setReadOnly(true);
|
|
|
|
d->statusbrowser->setTextFormat(TQTextBrowser::RichText);
|
|
|
|
//d->browser->setWordWrap(TQTextEdit::WidgetWidth);
|
|
|
|
d->statusbrowser->installEventFilter(this);
|
|
|
|
splitter->setResizeMode(d->statusbrowser, TQSplitter::KeepSize);
|
|
|
|
|
|
|
|
plugSharedAction( "data_execute", this, TQT_SLOT(execute()) );
|
|
|
|
if(KexiEditor::isAdvancedEditor()) // the configeditor is only in advanced mode avaiable.
|
|
|
|
plugSharedAction( "script_config_editor", d->editor, TQT_SLOT(slotConfigureEditor()) );
|
|
|
|
|
|
|
|
loadData();
|
|
|
|
|
|
|
|
d->properties = new KoProperty::Set(this, "KexiScripting");
|
|
|
|
connect(d->properties, TQT_SIGNAL( propertyChanged(KoProperty::Set&, KoProperty::Property&) ),
|
|
|
|
this, TQT_SLOT( slotPropertyChanged(KoProperty::Set&, KoProperty::Property&) ));
|
|
|
|
|
|
|
|
// To schedule the initialize fixes a crasher in Kate.
|
|
|
|
TQTimer::singleShot(50, this, TQT_SLOT( initialize() ));
|
|
|
|
}
|
|
|
|
|
|
|
|
KexiScriptDesignView::~KexiScriptDesignView()
|
|
|
|
{
|
|
|
|
delete d->properties;
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
Kross::Api::ScriptAction* KexiScriptDesignView::scriptAction() const
|
|
|
|
{
|
|
|
|
return d->scriptaction;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KexiScriptDesignView::initialize()
|
|
|
|
{
|
|
|
|
updateProperties();
|
|
|
|
d->editor->initialize( d->scriptaction );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KexiScriptDesignView::updateProperties()
|
|
|
|
{
|
|
|
|
if(d->updatesProperties)
|
|
|
|
return;
|
|
|
|
d->updatesProperties = true;
|
|
|
|
|
|
|
|
Kross::Api::Manager* manager = Kross::Api::Manager::scriptManager();
|
|
|
|
|
|
|
|
TQString interpretername = d->scriptaction->getInterpreterName();
|
|
|
|
Kross::Api::InterpreterInfo* info = interpretername.isEmpty() ? 0 : manager->getInterpreterInfo(interpretername);
|
|
|
|
|
|
|
|
{
|
|
|
|
// if interpreter isn't defined or invalid, try to fallback.
|
|
|
|
TQStringList list;
|
|
|
|
list << "python" << "ruby";
|
|
|
|
TQStringList::ConstIterator it( list.constBegin() ), end( list.constEnd() );
|
|
|
|
while( (! info) && (it != end) ) {
|
|
|
|
interpretername = (*it);
|
|
|
|
info = manager->getInterpreterInfo(interpretername);
|
|
|
|
if(info)
|
|
|
|
d->scriptaction->setInterpreterName(interpretername);
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(info) {
|
|
|
|
d->properties->clear();
|
|
|
|
|
|
|
|
TQStringList interpreters = manager->getInterpreters();
|
|
|
|
KoProperty::Property::ListData* proplist = new KoProperty::Property::ListData(interpreters, interpreters);
|
|
|
|
KoProperty::Property* prop = new KoProperty::Property(
|
|
|
|
"language", // name
|
|
|
|
proplist, // ListData
|
|
|
|
d->scriptaction->getInterpreterName(), // value
|
|
|
|
i18n("Interpreter"), // caption
|
|
|
|
i18n("The used scripting interpreter."), // description
|
|
|
|
KoProperty::List // type
|
|
|
|
);
|
|
|
|
d->properties->addProperty(prop);
|
|
|
|
|
|
|
|
Kross::Api::InterpreterInfo::Option::Map options = info->getOptions();
|
|
|
|
Kross::Api::InterpreterInfo::Option::Map::ConstIterator it, end( options.constEnd() );
|
|
|
|
for( it = options.constBegin(); it != end; ++it) {
|
|
|
|
Kross::Api::InterpreterInfo::Option* option = it.data();
|
|
|
|
KoProperty::Property* prop = new KoProperty::Property(
|
|
|
|
it.key().latin1(), // name
|
|
|
|
d->scriptaction->getOption(it.key(), option->value), // value
|
|
|
|
option->name, // caption
|
|
|
|
option->comment, // description
|
|
|
|
KoProperty::Auto // type
|
|
|
|
);
|
|
|
|
d->properties->addProperty(prop);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//propertySetSwitched();
|
|
|
|
propertySetReloaded(true);
|
|
|
|
d->updatesProperties = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
KoProperty::Set* KexiScriptDesignView::propertySet()
|
|
|
|
{
|
|
|
|
return d->properties;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KexiScriptDesignView::slotPropertyChanged(KoProperty::Set& /*set*/, KoProperty::Property& property)
|
|
|
|
{
|
|
|
|
if(property.isNull())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(property.name() == "language") {
|
|
|
|
TQString language = property.value().toString();
|
|
|
|
kdDebug() << TQString("KexiScriptDesignView::slotPropertyChanged() language=%1").arg(language) << endl;
|
|
|
|
d->scriptaction->setInterpreterName( language );
|
|
|
|
// We assume Kross and the HighlightingInterface are using same
|
|
|
|
// names for the support languages...
|
|
|
|
d->editor->setHighlightMode( language );
|
|
|
|
updateProperties();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bool ok = d->scriptaction->setOption( property.name(), property.value() );
|
|
|
|
if(! ok) {
|
|
|
|
kdWarning() << TQString("KexiScriptDesignView::slotPropertyChanged() unknown property '%1'.").arg(TQString(property.name())) << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setDirty(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KexiScriptDesignView::execute()
|
|
|
|
{
|
|
|
|
d->statusbrowser->clear();
|
|
|
|
TQTime time;
|
|
|
|
time.start();
|
|
|
|
d->statusbrowser->append( i18n("Execution of the script \"%1\" started.").arg(d->scriptaction->name()) );
|
|
|
|
|
|
|
|
d->scriptaction->activate();
|
|
|
|
if( d->scriptaction->hadException() ) {
|
|
|
|
TQString errormessage = d->scriptaction->getException()->getError();
|
|
|
|
d->statusbrowser->append(TQString("<b>%2</b><br>").arg(TQStyleSheet::escape(errormessage)) );
|
|
|
|
|
|
|
|
TQString tracedetails = d->scriptaction->getException()->getTrace();
|
|
|
|
d->statusbrowser->append( TQStyleSheet::escape(tracedetails) );
|
|
|
|
|
|
|
|
long lineno = d->scriptaction->getException()->getLineNo();
|
|
|
|
if(lineno >= 0)
|
|
|
|
d->editor->setLineNo(lineno);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
d->statusbrowser->append( i18n("Successfully executed. Time elapsed: %1ms").arg(time.elapsed()) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KexiScriptDesignView::loadData()
|
|
|
|
{
|
|
|
|
TQString data;
|
|
|
|
if(! loadDataBlock(data)) {
|
|
|
|
kexipluginsdbg << "KexiScriptDesignView::loadData(): no DataBlock" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString errMsg;
|
|
|
|
int errLine;
|
|
|
|
int errCol;
|
|
|
|
|
|
|
|
TQDomDocument domdoc;
|
|
|
|
bool parsed = domdoc.setContent(data, false, &errMsg, &errLine, &errCol);
|
|
|
|
|
|
|
|
if(! parsed) {
|
|
|
|
kexipluginsdbg << "KexiScriptDesignView::loadData() XML parsing error line: " << errLine << " col: " << errCol << " message: " << errMsg << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDomElement scriptelem = domdoc.namedItem("script").toElement();
|
|
|
|
if(scriptelem.isNull()) {
|
|
|
|
kexipluginsdbg << "KexiScriptDesignView::loadData(): script domelement is null" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString interpretername = scriptelem.attribute("language");
|
|
|
|
Kross::Api::Manager* manager = Kross::Api::Manager::scriptManager();
|
|
|
|
Kross::Api::InterpreterInfo* info = interpretername.isEmpty() ? 0 : manager->getInterpreterInfo(interpretername);
|
|
|
|
if(info) {
|
|
|
|
d->scriptaction->setInterpreterName(interpretername);
|
|
|
|
|
|
|
|
Kross::Api::InterpreterInfo::Option::Map options = info->getOptions();
|
|
|
|
Kross::Api::InterpreterInfo::Option::Map::ConstIterator it, end = options.constEnd();
|
|
|
|
for( it = options.constBegin(); it != end; ++it) {
|
|
|
|
TQString value = scriptelem.attribute( it.data()->name );
|
|
|
|
if(! value.isNull()) {
|
|
|
|
TQVariant v(value);
|
|
|
|
if( v.cast( it.data()->value.type() ) ) // preserve the TQVariant's type
|
|
|
|
d->scriptaction->setOption(it.data()->name, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
d->scriptaction->setCode( scriptelem.text() );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
KexiDB::SchemaData* KexiScriptDesignView::storeNewData(const KexiDB::SchemaData& sdata, bool &cancel)
|
|
|
|
{
|
|
|
|
KexiDB::SchemaData *s = KexiViewBase::storeNewData(sdata, cancel);
|
|
|
|
kexipluginsdbg << "KexiScriptDesignView::storeNewData(): new id:" << s->id() << endl;
|
|
|
|
|
|
|
|
if(!s || cancel) {
|
|
|
|
delete s;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(! storeData()) {
|
|
|
|
kdWarning() << "KexiScriptDesignView::storeNewData Failed to store the data." << endl;
|
|
|
|
//failure: remove object's schema data to avoid garbage
|
|
|
|
KexiDB::Connection *conn = parentDialog()->mainWin()->project()->dbConnection();
|
|
|
|
conn->removeObject( s->id() );
|
|
|
|
delete s;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
tristate KexiScriptDesignView::storeData(bool /*dontAsk*/)
|
|
|
|
{
|
|
|
|
kexipluginsdbg << "KexiScriptDesignView::storeData(): " << parentDialog()->partItem()->name() << " [" << parentDialog()->id() << "]" << endl;
|
|
|
|
|
|
|
|
TQDomDocument domdoc("script");
|
|
|
|
TQDomElement scriptelem = domdoc.createElement("script");
|
|
|
|
domdoc.appendChild(scriptelem);
|
|
|
|
|
|
|
|
TQString language = d->scriptaction->getInterpreterName();
|
|
|
|
scriptelem.setAttribute("language", language);
|
|
|
|
|
|
|
|
Kross::Api::InterpreterInfo* info = Kross::Api::Manager::scriptManager()->getInterpreterInfo(language);
|
|
|
|
if(info) {
|
|
|
|
Kross::Api::InterpreterInfo::Option::Map defoptions = info->getOptions();
|
|
|
|
TQStringVariantMap& options = d->scriptaction->getOptions();
|
|
|
|
TQStringVariantMap::ConstIterator it, end( options.constEnd() );
|
|
|
|
for( it = options.constBegin(); it != end; ++it) {
|
|
|
|
if( defoptions.contains(it.key()) ) { // only remember options which the InterpreterInfo knows about...
|
|
|
|
scriptelem.setAttribute(it.key(), it.data().toString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDomText scriptcode = domdoc.createTextNode(d->scriptaction->getCode());
|
|
|
|
scriptelem.appendChild(scriptcode);
|
|
|
|
|
|
|
|
return storeDataBlock( domdoc.toString() );
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "kexiscriptdesignview.moc"
|
|
|
|
|