00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00088 d->statusbrowser->installEventFilter(this);
00089 splitter->setResizeMode(d->statusbrowser, QSplitter::KeepSize);
00090
00091 plugSharedAction( "script_execute", this, SLOT(execute()) );
00092 if(KexiEditor::isAdvancedEditor())
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
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
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",
00154 proplist,
00155 d->scriptaction->getInterpreterName(),
00156 i18n("Interpreter"),
00157 i18n("The used scripting interpreter."),
00158 KoProperty::List
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(),
00168 d->scriptaction->getOption(it.key(), option->value),
00169 option->name,
00170 option->comment,
00171 KoProperty::Auto
00172 );
00173 d->properties->addProperty(prop);
00174 }
00175 }
00176
00177
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& , 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
00197
00198 d->editor->setHighlightMode( language );
00199
00200
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() ) )
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
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 )
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()) ) {
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