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         bool updatesProperties;
00062 
00064         KTextBrowser* statusbrowser;
00065 };
00066 
00067 KexiScriptDesignView::KexiScriptDesignView(KexiMainWindow *mainWin, QWidget *parent, Kross::Api::ScriptAction* scriptaction)
00068     : KexiViewBase(mainWin, parent, "KexiScriptDesignView")
00069     , d( new KexiScriptDesignViewPrivate() )
00070 {
00071     d->scriptaction = scriptaction;
00072     d->updatesProperties = false;
00073 
00074     QSplitter* splitter = new QSplitter(this);
00075     splitter->setOrientation(Vertical);
00076     QHBoxLayout* layout = new QHBoxLayout(this);
00077     layout->addWidget(splitter);
00078 
00079     d->editor = new KexiScriptEditor(mainWin, splitter, "ScriptEditor");
00080     splitter->setFocusProxy(d->editor);
00081     addChildView(d->editor);
00082     setViewWidget(d->editor);
00083 
00084     d->statusbrowser = new KTextBrowser(splitter, "ScriptStatusBrowser");
00085     d->statusbrowser->setReadOnly(true);
00086     d->statusbrowser->setTextFormat(QTextBrowser::RichText);
00087     //d->browser->setWordWrap(QTextEdit::WidgetWidth);
00088     d->statusbrowser->installEventFilter(this);
00089     splitter->setResizeMode(d->statusbrowser, QSplitter::KeepSize);
00090 
00091     plugSharedAction( "script_execute", this, SLOT(execute()) );
00092     if(KexiEditor::isAdvancedEditor()) // the configeditor is only in advanced mode avaiable.
00093         plugSharedAction( "script_config_editor", d->editor, SLOT(slotConfigureEditor()) );
00094 
00095     loadData();
00096 
00097     d->properties = new KoProperty::Set(this, "KexiScripting");
00098     connect(d->properties, SIGNAL( propertyChanged(KoProperty::Set&, KoProperty::Property&) ),
00099             this, SLOT( slotPropertyChanged(KoProperty::Set&, KoProperty::Property&) ));
00100 
00101     // To schedule the initialize fixes a crasher in Kate.
00102     QTimer::singleShot(50, this, SLOT( initialize() ));
00103 }
00104 
00105 KexiScriptDesignView::~KexiScriptDesignView()
00106 {
00107     delete d->properties;
00108     delete d;
00109 }
00110 
00111 Kross::Api::ScriptAction* KexiScriptDesignView::scriptAction() const
00112 {
00113     return d->scriptaction;
00114 }
00115 
00116 void KexiScriptDesignView::initialize()
00117 {
00118     updateProperties();
00119     d->editor->initialize( d->scriptaction );
00120 }
00121 
00122 void KexiScriptDesignView::updateProperties()
00123 {
00124     if(d->updatesProperties)
00125         return;
00126     d->updatesProperties = true;
00127 
00128     Kross::Api::Manager* manager = Kross::Api::Manager::scriptManager();
00129 
00130     QString interpretername = d->scriptaction->getInterpreterName();
00131     Kross::Api::InterpreterInfo* info = interpretername.isEmpty() ? 0 : manager->getInterpreterInfo(interpretername);
00132 
00133     {
00134         // if interpreter isn't defined or invalid, try to fallback.
00135         QStringList list;
00136         list << "python" << "ruby";
00137         QStringList::Iterator it( list.begin() );
00138         while( (! info) && (it != list.end()) ) {
00139             interpretername = (*it);
00140             info = manager->getInterpreterInfo(interpretername);
00141             if(info)
00142                 d->scriptaction->setInterpreterName(interpretername);
00143             ++it;
00144         }
00145     }
00146 
00147     if(info) {
00148         d->properties->clear();
00149 
00150         QStringList interpreters = manager->getInterpreters();
00151         KoProperty::Property::ListData* proplist = new KoProperty::Property::ListData(interpreters, interpreters);
00152         KoProperty::Property* prop = new KoProperty::Property(
00153             "language", // name
00154             proplist, // ListData
00155             d->scriptaction->getInterpreterName(), // value
00156             i18n("Interpreter"), // caption
00157             i18n("The used scripting interpreter."), // description
00158             KoProperty::List // type
00159         );
00160         d->properties->addProperty(prop);
00161 
00162         Kross::Api::InterpreterInfo::Option::Map options = info->getOptions();
00163         Kross::Api::InterpreterInfo::Option::Map::Iterator it( options.begin() );
00164         for(; it != options.end(); ++it) {
00165             Kross::Api::InterpreterInfo::Option* option = it.data();
00166             KoProperty::Property* prop = new KoProperty::Property(
00167                     it.key().latin1(), // name
00168                     d->scriptaction->getOption(it.key(), option->value), // value
00169                     option->name, // caption
00170                     option->comment, // description
00171                     KoProperty::Auto // type
00172             );
00173             d->properties->addProperty(prop);
00174         }
00175     }
00176 
00177     //propertySetSwitched();
00178     propertySetReloaded(true);
00179     d->updatesProperties = false;
00180 }
00181 
00182 KoProperty::Set* KexiScriptDesignView::propertySet()
00183 {
00184     return d->properties;
00185 }
00186 
00187 void KexiScriptDesignView::slotPropertyChanged(KoProperty::Set& /*set*/, KoProperty::Property& property)
00188 {
00189     if(property.isNull()) 
00190         return;
00191 
00192     if(property.name() == "language") {
00193         QString language = property.value().toString();
00194         kdDebug() << QString("KexiScriptDesignView::slotPropertyChanged() language=%1").arg(language) << endl;
00195         d->scriptaction->setInterpreterName( language );
00196         // We assume Kross and the HighlightingInterface are using same
00197         // names for the support languages...
00198         d->editor->setHighlightMode( language );
00199         // Update the properties. We need to call it delayed cause
00200         // else we may crash whyever...
00201         QTimer::singleShot(50, this, SLOT( updateProperties() ));
00202     }
00203     else {
00204         bool ok = d->scriptaction->setOption( property.name(), property.value() );
00205         if(! ok) {
00206             kdWarning() << QString("KexiScriptDesignView::slotPropertyChanged() unknown property '%1'.").arg(property.name()) << endl;
00207             return;
00208         }
00209     }
00210 
00211     setDirty(true);
00212 }
00213 
00214 void KexiScriptDesignView::execute()
00215 {
00216     d->statusbrowser->clear();
00217     QTime time;
00218     time.start();
00219     d->statusbrowser->append( i18n("Execution of the script \"%1\" started.").arg(d->scriptaction->name()) );
00220 
00221     d->scriptaction->activate();
00222     if( d->scriptaction->hadException() ) {
00223         QString errormessage = d->scriptaction->getException()->getError();
00224         d->statusbrowser->append(QString("<b>%2</b><br>").arg(QStyleSheet::escape(errormessage)) );
00225 
00226         QString tracedetails = d->scriptaction->getException()->getTrace();
00227         d->statusbrowser->append( QStyleSheet::escape(tracedetails) );
00228 
00229         long lineno = d->scriptaction->getException()->getLineNo();
00230         if(lineno >= 0)
00231             d->editor->setLineNo(lineno);
00232     }
00233     else {
00234         d->statusbrowser->append( i18n("Successfully executed. Time elapsed: %1ms").arg(time.elapsed()) );
00235     }
00236 }
00237 
00238 bool KexiScriptDesignView::loadData()
00239 {
00240     QString data;
00241     if(! loadDataBlock(data)) {
00242         kexipluginsdbg << "KexiScriptDesignView::loadData(): no DataBlock" << endl;
00243         return false;
00244     }
00245 
00246     QString errMsg;
00247     int errLine;
00248     int errCol;
00249 
00250     QDomDocument domdoc;
00251     bool parsed = domdoc.setContent(data, false, &errMsg, &errLine, &errCol);
00252 
00253     if(! parsed) {
00254         kexipluginsdbg << "KexiScriptDesignView::loadData() XML parsing error line: " << errLine << " col: " << errCol << " message: " << errMsg << endl;
00255         return false;
00256     }
00257 
00258     QDomElement scriptelem = domdoc.namedItem("script").toElement();
00259     if(scriptelem.isNull()) {
00260         kexipluginsdbg << "KexiScriptDesignView::loadData(): script domelement is null" << endl;
00261         return false;
00262     }
00263 
00264     QString interpretername = scriptelem.attribute("language");
00265     Kross::Api::Manager* manager = Kross::Api::Manager::scriptManager();
00266     Kross::Api::InterpreterInfo* info = interpretername.isEmpty() ? 0 : manager->getInterpreterInfo(interpretername);
00267     if(info) {
00268         d->scriptaction->setInterpreterName(interpretername);
00269 
00270         Kross::Api::InterpreterInfo::Option::Map options = info->getOptions();
00271         Kross::Api::InterpreterInfo::Option::Map::Iterator it = options.begin();
00272         for(; it != options.end(); ++it) {
00273             QString value = scriptelem.attribute( it.data()->name );
00274             if(! value.isNull()) {
00275                 QVariant v(value);
00276                 if( v.cast( it.data()->value.type() ) ) // preserve the QVariant's type
00277                     d->scriptaction->setOption(it.data()->name, v);
00278             }
00279         }
00280     }
00281 
00282     d->scriptaction->setCode( scriptelem.text() );
00283 
00284     return true;
00285 }
00286 
00287 KexiDB::SchemaData* KexiScriptDesignView::storeNewData(const KexiDB::SchemaData& sdata, bool &cancel)
00288 {
00289     KexiDB::SchemaData *s = KexiViewBase::storeNewData(sdata, cancel);
00290     kexipluginsdbg << "KexiScriptDesignView::storeNewData(): new id:" << s->id() << endl;
00291 
00292     if(!s || cancel) {
00293         delete s;
00294         return 0;
00295     }
00296 
00297     if(! storeData()) {
00298         kdWarning() << "KexiScriptDesignView::storeNewData Failed to store the data." << endl;
00299         //failure: remove object's schema data to avoid garbage
00300         KexiDB::Connection *conn = parentDialog()->mainWin()->project()->dbConnection();
00301         conn->removeObject( s->id() );
00302         delete s;
00303         return 0;
00304     }
00305 
00306     return s;
00307 }
00308 
00309 tristate KexiScriptDesignView::storeData(bool /*dontAsk*/)
00310 {
00311     kexipluginsdbg << "KexiScriptDesignView::storeData(): " << parentDialog()->partItem()->name() << " [" << parentDialog()->id() << "]" << endl;
00312 
00313     QDomDocument domdoc("script");
00314     QDomElement scriptelem = domdoc.createElement("script");
00315     domdoc.appendChild(scriptelem);
00316 
00317     QString language = d->scriptaction->getInterpreterName();
00318     scriptelem.setAttribute("language", language);
00319 
00320     Kross::Api::InterpreterInfo* info = Kross::Api::Manager::scriptManager()->getInterpreterInfo(language);
00321     if(info) {
00322         Kross::Api::InterpreterInfo::Option::Map defoptions = info->getOptions();
00323         QMap<QString, QVariant>& options = d->scriptaction->getOptions();
00324         for(QMap<QString, QVariant>::Iterator it = options.begin(); it != options.end(); ++it) {
00325             if( defoptions.contains(it.key()) ) { // only remember options which the InterpreterInfo knows about...
00326                 scriptelem.setAttribute(it.key(), it.data().toString());
00327             }
00328         }
00329     }
00330 
00331     QDomText scriptcode = domdoc.createTextNode(d->scriptaction->getCode());
00332     scriptelem.appendChild(scriptcode);
00333 
00334     return storeDataBlock( domdoc.toString() );
00335 }
00336 
00337 #include "kexiscriptdesignview.moc"
00338 
KDE Home | KDE Accessibility Home | Description of Access Keys