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.
koffice/kexi/plugins/scripting/kexiscripting/kexiscriptdesignview.cpp

338 lines
12 KiB

/* 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 *tqparent, Kross::Api::ScriptAction* scriptaction)
: KexiViewBase(mainWin, tqparent, "KexiScriptDesignView")
, d( new KexiScriptDesignViewPrivate() )
{
d->scriptaction = scriptaction;
d->updatesProperties = false;
TQSplitter* splitter = new TQSplitter(this);
splitter->setOrientation(Qt::Vertical);
TQHBoxLayout* tqlayout = new TQHBoxLayout(this);
tqlayout->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", TQT_TQOBJECT(this), TQT_SLOT(execute()) );
if(KexiEditor::isAdvancedEditor()) // the configeditor is only in advanced mode avaiable.
plugSharedAction( "script_config_editor", TQT_TQOBJECT(d->editor), TQT_SLOT(slotConfigureEditor()) );
loadData();
d->properties = new KoProperty::Set(TQT_TQOBJECT(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").tqarg(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'.").tqarg(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.").tqarg(d->scriptaction->name()) );
d->scriptaction->activate();
if( d->scriptaction->hadException() ) {
TQString errormessage = d->scriptaction->getException()->getError();
d->statusbrowser->append(TQString("<b>%2</b><br>").tqarg(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").tqarg(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 = tqparentDialog()->mainWin()->project()->dbConnection();
conn->removeObject( s->id() );
delete s;
return 0;
}
return s;
}
tristate KexiScriptDesignView::storeData(bool /*dontAsk*/)
{
kexipluginsdbg << "KexiScriptDesignView::storeData(): " << tqparentDialog()->partItem()->name() << " [" << tqparentDialog()->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();
TQMap<TQString, TQVariant>& options = d->scriptaction->getOptions();
TQMap<TQString, TQVariant>::ConstIterator it, end( options.constEnd() );
for( it = options.constBegin(); it != end; ++it) {
if( defoptions.tqcontains(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"