kexi

kexiscriptdesignview.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
00003    Copyright (C) 2004-2005 Jaroslaw Staniek <js@iidea.pl>
00004    Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
00005    Copyright (C) 2005 Sebastian Sauer <mail@dipe.org>
00006 
00007    This program is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Library General Public
00009    License as published by the Free Software Foundation; either
00010    version 2 of the License, or (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Library General Public License for more details.
00016 
00017    You should have received a copy of the GNU Library General Public License
00018    along with this program; see the file COPYING.  If not, write to
00019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020  * Boston, MA 02110-1301, USA.
00021 */
00022 
00023 #include "kexiscriptdesignview.h"
00024 #include "kexiscripteditor.h"
00025 
00026 #include <kross/main/manager.h>
00027 #include <kross/main/scriptcontainer.h>
00028 #include <kross/main/scriptaction.h>
00029 #include <kross/api/interpreter.h>
00030 
00031 #include <qlayout.h>
00032 #include <qsplitter.h>
00033 #include <qtimer.h>
00034 #include <qdatetime.h>
00035 #include <qdom.h>
00036 #include <qstylesheet.h>
00037 #include <ktextbrowser.h>
00038 #include <kdebug.h>
00039 
00040 #include <kexidialogbase.h>
00041 #include <kexidb/connection.h>
00042 
00044 class KexiScriptDesignViewPrivate
00045 {
00046     public:
00047 
00052         Kross::Api::ScriptAction* scriptaction;
00053 
00055         KexiScriptEditor* editor;
00056 
00058         KoProperty::Set* properties;
00059 
00061         KTextBrowser* statusbrowser;
00062 };
00063 
00064 KexiScriptDesignView::KexiScriptDesignView(KexiMainWindow *mainWin, QWidget *parent, Kross::Api::ScriptAction* scriptaction)
00065     : KexiViewBase(mainWin, parent, "KexiScriptDesignView")
00066     , d( new KexiScriptDesignViewPrivate() )
00067 {
00068     d->scriptaction = scriptaction;
00069 
00070     QSplitter* splitter = new QSplitter(this);
00071     splitter->setOrientation(Vertical);
00072     QHBoxLayout* layout = new QHBoxLayout(this);
00073     layout->addWidget(splitter);
00074 
00075     d->editor = new KexiScriptEditor(mainWin, splitter, "ScriptEditor");
00076     splitter->setFocusProxy(d->editor);
00077     addChildView(d->editor);
00078     setViewWidget(d->editor);
00079 
00080     d->statusbrowser = new KTextBrowser(splitter, "ScriptStatusBrowser");
00081     d->statusbrowser->setReadOnly(true);
00082     d->statusbrowser->setTextFormat(QTextBrowser::RichText);
00083     //d->browser->setWordWrap(QTextEdit::WidgetWidth);
00084     d->statusbrowser->installEventFilter(this);
00085     splitter->setResizeMode(d->statusbrowser, QSplitter::KeepSize);
00086 
00087     plugSharedAction( "script_execute", this, SLOT(execute()) );
00088     if(KexiEditor::isAdvancedEditor()) // the configeditor is only in advanced mode avaiable.
00089         plugSharedAction( "script_config_editor", d->editor, SLOT(slotConfigureEditor()) );
00090 
00091     loadData();
00092 
00093     d->properties = new KoProperty::Set(this, "KexiScripting");
00094     updateProperties();
00095 
00096     d->editor->initialize( d->scriptaction );
00097 }
00098 
00099 KexiScriptDesignView::~KexiScriptDesignView()
00100 {
00101     delete d;
00102 }
00103 
00104 Kross::Api::ScriptAction* KexiScriptDesignView::scriptAction() const
00105 {
00106     return d->scriptaction;
00107 }
00108 
00109 void KexiScriptDesignView::updateProperties()
00110 {
00111     Kross::Api::Manager* manager = Kross::Api::Manager::scriptManager();
00112 
00113     QString interpretername = d->scriptaction->getInterpreterName();
00114     Kross::Api::InterpreterInfo* info = interpretername.isEmpty() ? 0 : manager->getInterpreterInfo(interpretername);
00115 
00116     {
00117         // if interpreter isn't defined or invalid, try to fallback.
00118         QStringList list;
00119         list << "python" << "ruby";
00120         QStringList::Iterator it( list.begin() );
00121         while( (! info) && (it != list.end()) ) {
00122             interpretername = (*it);
00123             info = manager->getInterpreterInfo(interpretername);
00124             if(info)
00125                 d->scriptaction->setInterpreterName(interpretername);
00126             ++it;
00127         }
00128     }
00129 
00130     if(info) {
00131         disconnect(d->properties, SIGNAL( propertyChanged(KoProperty::Set&, KoProperty::Property&) ),
00132                    this, SLOT( slotPropertyChanged(KoProperty::Set&, KoProperty::Property&) ));
00133 
00134         d->properties->clear();
00135 
00136         QStringList interpreters = manager->getInterpreters();
00137         KoProperty::Property::ListData* proplist = new KoProperty::Property::ListData(interpreters, interpreters);
00138         KoProperty::Property* prop = new KoProperty::Property(
00139             "language", // name
00140             proplist, // ListData
00141             d->scriptaction->getInterpreterName(), // value
00142             i18n("Interpreter"), // caption
00143             i18n("The used scripting interpreter."), // description
00144             KoProperty::List // type
00145         );
00146         d->properties->addProperty(prop);
00147 
00148         Kross::Api::InterpreterInfo::Option::Map options = info->getOptions();
00149         Kross::Api::InterpreterInfo::Option::Map::Iterator it( options.begin() );
00150         for(; it != options.end(); ++it) {
00151             Kross::Api::InterpreterInfo::Option* option = it.data();
00152             KoProperty::Property* prop = new KoProperty::Property(
00153                     it.key().latin1(), // name
00154                     d->scriptaction->getOption(it.key(), option->value), // value
00155                     option->name, // caption
00156                     option->comment, // description
00157                     KoProperty::Auto // type
00158             );
00159             d->properties->addProperty(prop);
00160         }
00161 
00162         connect(d->properties, SIGNAL( propertyChanged(KoProperty::Set&, KoProperty::Property&) ),
00163                 this, SLOT( slotPropertyChanged(KoProperty::Set&, KoProperty::Property&) ));
00164     }
00165 
00166     //propertySetSwitched();
00167     propertySetReloaded(true);
00168 }
00169 
00170 KoProperty::Set* KexiScriptDesignView::propertySet()
00171 {
00172     return d->properties;
00173 }
00174 
00175 void KexiScriptDesignView::slotPropertyChanged(KoProperty::Set& /*set*/, KoProperty::Property& property)
00176 {
00177     if(property.isNull()) 
00178         return;
00179 
00180     if(property.name() == "language") {
00181         QString language = property.value().toString();
00182         kdDebug() << QString("KexiScriptDesignView::slotPropertyChanged() language=%1").arg(language) << endl;
00183         d->scriptaction->setInterpreterName( language );
00184         // We assume Kross and the HighlightingInterface are using same
00185         // names for the support languages...
00186         d->editor->setHighlightMode( language );
00187 
00188         // Update the properties. We need to call it delayed cause
00189         // else we may crash whyever...
00190         QTimer::singleShot(150, this, SLOT( updateProperties() ));
00191     }
00192     else {
00193         bool ok = d->scriptaction->setOption( property.name(), property.value() );
00194         if(! ok) {
00195             kdWarning() << QString("KexiScriptDesignView::slotPropertyChanged() unknown property '%1'.").arg(property.name()) << endl;
00196             return;
00197         }
00198     }
00199 
00200     setDirty(true);
00201 }
00202 
00203 void KexiScriptDesignView::execute()
00204 {
00205     d->statusbrowser->clear();
00206     QTime time;
00207     time.start();
00208     d->statusbrowser->append( i18n("Execution of the script \"%1\" started.").arg(d->scriptaction->name()) );
00209 
00210     d->scriptaction->activate();
00211     if( d->scriptaction->hadException() ) {
00212         QString errormessage = d->scriptaction->getException()->getError();
00213         d->statusbrowser->append(QString("<b>%2</b><br>").arg(QStyleSheet::escape(errormessage)) );
00214 
00215         QString tracedetails = d->scriptaction->getException()->getTrace();
00216         d->statusbrowser->append( QStyleSheet::escape(tracedetails) );
00217 
00218         long lineno = d->scriptaction->getException()->getLineNo();
00219         if(lineno >= 0)
00220             d->editor->setLineNo(lineno);
00221     }
00222     else {
00223         d->statusbrowser->append( i18n("Successfully executed. Time elapsed: %1ms").arg(time.elapsed()) );
00224     }
00225 }
00226 
00227 bool KexiScriptDesignView::loadData()
00228 {
00229     QString data;
00230     if(! loadDataBlock(data)) {
00231         kexipluginsdbg << "KexiScriptDesignView::loadData(): no DataBlock" << endl;
00232         return false;
00233     }
00234 
00235     QString errMsg;
00236     int errLine;
00237     int errCol;
00238 
00239     QDomDocument domdoc;
00240     bool parsed = domdoc.setContent(data, false, &errMsg, &errLine, &errCol);
00241 
00242     if(! parsed) {
00243         kexipluginsdbg << "KexiScriptDesignView::loadData() XML parsing error line: " << errLine << " col: " << errCol << " message: " << errMsg << endl;
00244         return false;
00245     }
00246 
00247     QDomElement scriptelem = domdoc.namedItem("script").toElement();
00248     if(scriptelem.isNull()) {
00249         kexipluginsdbg << "KexiScriptDesignView::loadData(): script domelement is null" << endl;
00250         return false;
00251     }
00252 
00253     QString interpretername = scriptelem.attribute("language");
00254     Kross::Api::Manager* manager = Kross::Api::Manager::scriptManager();
00255     Kross::Api::InterpreterInfo* info = interpretername.isEmpty() ? 0 : manager->getInterpreterInfo(interpretername);
00256     if(info) {
00257         d->scriptaction->setInterpreterName(interpretername);
00258 
00259         Kross::Api::InterpreterInfo::Option::Map options = info->getOptions();
00260         Kross::Api::InterpreterInfo::Option::Map::Iterator it = options.begin();
00261         for(; it != options.end(); ++it) {
00262             QString value = scriptelem.attribute( it.data()->name );
00263             if(! value.isNull()) {
00264                 QVariant v(value);
00265                 if( v.cast( it.data()->value.type() ) ) // preserve the QVariant's type
00266                     d->scriptaction->setOption(it.data()->name, v);
00267             }
00268         }
00269     }
00270 
00271     d->scriptaction->setCode( scriptelem.text() );
00272 
00273     return true;
00274 }
00275 
00276 KexiDB::SchemaData* KexiScriptDesignView::storeNewData(const KexiDB::SchemaData& sdata, bool &cancel)
00277 {
00278     KexiDB::SchemaData *s = KexiViewBase::storeNewData(sdata, cancel);
00279     kexipluginsdbg << "KexiScriptDesignView::storeNewData(): new id:" << s->id() << endl;
00280 
00281     if(!s || cancel) {
00282         delete s;
00283         return 0;
00284     }
00285 
00286     if(! storeData()) {
00287         kdWarning() << "KexiScriptDesignView::storeNewData Failed to store the data." << endl;
00288         //failure: remove object's schema data to avoid garbage
00289         KexiDB::Connection *conn = parentDialog()->mainWin()->project()->dbConnection();
00290         conn->removeObject( s->id() );
00291         delete s;
00292         return 0;
00293     }
00294 
00295     return s;
00296 }
00297 
00298 tristate KexiScriptDesignView::storeData(bool /*dontAsk*/)
00299 {
00300     kexipluginsdbg << "KexiScriptDesignView::storeData(): " << parentDialog()->partItem()->name() << " [" << parentDialog()->id() << "]" << endl;
00301 
00302     QDomDocument domdoc("script");
00303     QDomElement scriptelem = domdoc.createElement("script");
00304     domdoc.appendChild(scriptelem);
00305 
00306     QString language = d->scriptaction->getInterpreterName();
00307     scriptelem.setAttribute("language", language);
00308 
00309     Kross::Api::InterpreterInfo* info = Kross::Api::Manager::scriptManager()->getInterpreterInfo(language);
00310     if(info) {
00311         Kross::Api::InterpreterInfo::Option::Map defoptions = info->getOptions();
00312         QMap<QString, QVariant>& options = d->scriptaction->getOptions();
00313         for(QMap<QString, QVariant>::Iterator it = options.begin(); it != options.end(); ++it) {
00314             if( defoptions.contains(it.key()) ) { // only remember options which the InterpreterInfo knows about...
00315                 scriptelem.setAttribute(it.key(), it.data().toString());
00316             }
00317         }
00318     }
00319 
00320     QDomText scriptcode = domdoc.createTextNode(d->scriptaction->getCode());
00321     scriptelem.appendChild(scriptcode);
00322 
00323     return storeDataBlock( domdoc.toString() );
00324 }
00325 
00326 #include "kexiscriptdesignview.moc"
00327 
KDE Home | KDE Accessibility Home | Description of Access Keys