/* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2004-2005 Jaroslaw Staniek Copyright (C) 2005 Cedric Pasteur Copyright (C) 2005 Sebastian Sauer 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 #include #include #include #include #include #include #include #include #include #include #include #include #include /// @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("%2
").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"