kexiscriptdesignview.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
3 Copyright (C) 2004-2005 Jaroslaw Staniek <js@iidea.pl>
4 Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
5 Copyright (C) 2005 Sebastian Sauer <mail@dipe.org>
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this program; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21*/
22
23#include "kexiscriptdesignview.h"
24#include "kexiscripteditor.h"
25
26#include <kross/main/manager.h>
27#include <kross/main/scriptcontainer.h>
28#include <kross/main/scriptaction.h>
29#include <kross/api/interpreter.h>
30
31#include <tqlayout.h>
32#include <tqsplitter.h>
33#include <tqtimer.h>
34#include <tqdatetime.h>
35#include <tqdom.h>
36#include <tqstylesheet.h>
37#include <ktextbrowser.h>
38#include <kdebug.h>
39
40#include <kexidialogbase.h>
41#include <kexidb/connection.h>
42
44class KexiScriptDesignViewPrivate
45{
46 public:
47
52 Kross::Api::ScriptAction* scriptaction;
53
55 KexiScriptEditor* editor;
56
58 KoProperty::Set* properties;
59
61 bool updatesProperties;
62
64 KTextBrowser* statusbrowser;
65};
66
67KexiScriptDesignView::KexiScriptDesignView(KexiMainWindow *mainWin, TQWidget *parent, Kross::Api::ScriptAction* scriptaction)
68 : KexiViewBase(mainWin, parent, "KexiScriptDesignView")
69 , d( new KexiScriptDesignViewPrivate() )
70{
71 d->scriptaction = scriptaction;
72 d->updatesProperties = false;
73
74 TQSplitter* splitter = new TQSplitter(this);
75 splitter->setOrientation(TQt::Vertical);
76 TQHBoxLayout* layout = new TQHBoxLayout(this);
77 layout->addWidget(splitter);
78
79 d->editor = new KexiScriptEditor(mainWin, splitter, "ScriptEditor");
80 splitter->setFocusProxy(d->editor);
81 addChildView(d->editor);
82 setViewWidget(d->editor);
83
84 d->statusbrowser = new KTextBrowser(splitter, "ScriptStatusBrowser");
85 d->statusbrowser->setReadOnly(true);
86 d->statusbrowser->setTextFormat(TQTextBrowser::RichText);
87 //d->browser->setWordWrap(TQTextEdit::WidgetWidth);
88 d->statusbrowser->installEventFilter(this);
89 splitter->setResizeMode(d->statusbrowser, TQSplitter::KeepSize);
90
91 plugSharedAction( "data_execute", this, TQ_SLOT(execute()) );
92 if(KexiEditor::isAdvancedEditor()) // the configeditor is only in advanced mode avaiable.
93 plugSharedAction( "script_config_editor", d->editor, TQ_SLOT(slotConfigureEditor()) );
94
95 loadData();
96
97 d->properties = new KoProperty::Set(this, "KexiScripting");
98 connect(d->properties, TQ_SIGNAL( propertyChanged(KoProperty::Set&, KoProperty::Property&) ),
99 this, TQ_SLOT( slotPropertyChanged(KoProperty::Set&, KoProperty::Property&) ));
100
101 // To schedule the initialize fixes a crasher in Kate.
102 TQTimer::singleShot(50, this, TQ_SLOT( initialize() ));
103}
104
106{
107 delete d->properties;
108 delete d;
109}
110
111Kross::Api::ScriptAction* KexiScriptDesignView::scriptAction() const
112{
113 return d->scriptaction;
114}
115
116void KexiScriptDesignView::initialize()
117{
118 updateProperties();
119 d->editor->initialize( d->scriptaction );
120}
121
122void KexiScriptDesignView::updateProperties()
123{
124 if(d->updatesProperties)
125 return;
126 d->updatesProperties = true;
127
128 Kross::Api::Manager* manager = Kross::Api::Manager::scriptManager();
129
130 TQString interpretername = d->scriptaction->getInterpreterName();
131 Kross::Api::InterpreterInfo* info = interpretername.isEmpty() ? 0 : manager->getInterpreterInfo(interpretername);
132
133 {
134 // if interpreter isn't defined or invalid, try to fallback.
135 TQStringList list;
136 list << "python" << "ruby";
137 TQStringList::ConstIterator it( list.constBegin() ), end( list.constEnd() );
138 while( (! info) && (it != end) ) {
139 interpretername = (*it);
140 info = manager->getInterpreterInfo(interpretername);
141 if(info)
142 d->scriptaction->setInterpreterName(interpretername);
143 ++it;
144 }
145 }
146
147 if(info) {
148 d->properties->clear();
149
150 TQStringList interpreters = manager->getInterpreters();
151 KoProperty::Property::ListData* proplist = new KoProperty::Property::ListData(interpreters, interpreters);
152 KoProperty::Property* prop = new KoProperty::Property(
153 "language", // name
154 proplist, // ListData
155 d->scriptaction->getInterpreterName(), // value
156 i18n("Interpreter"), // caption
157 i18n("The used scripting interpreter."), // description
158 KoProperty::List // type
159 );
160 d->properties->addProperty(prop);
161
162 Kross::Api::InterpreterInfo::Option::Map options = info->getOptions();
163 Kross::Api::InterpreterInfo::Option::Map::ConstIterator it, end( options.constEnd() );
164 for( it = options.constBegin(); it != end; ++it) {
165 Kross::Api::InterpreterInfo::Option* option = it.data();
166 KoProperty::Property* prop = new KoProperty::Property(
167 it.key().latin1(), // name
168 d->scriptaction->getOption(it.key(), option->value), // value
169 option->name, // caption
170 option->comment, // description
171 KoProperty::Auto // type
172 );
173 d->properties->addProperty(prop);
174 }
175 }
176
177 //propertySetSwitched();
179 d->updatesProperties = false;
180}
181
183{
184 return d->properties;
185}
186
187void KexiScriptDesignView::slotPropertyChanged(KoProperty::Set& /*set*/, KoProperty::Property& property)
188{
189 if(property.isNull())
190 return;
191
192 if(property.name() == "language") {
193 TQString language = property.value().toString();
194 kdDebug() << TQString("KexiScriptDesignView::slotPropertyChanged() language=%1").arg(language) << endl;
195 d->scriptaction->setInterpreterName( language );
196 // We assume Kross and the HighlightingInterface are using same
197 // names for the support languages...
198 d->editor->setHighlightMode( language );
199 updateProperties();
200 }
201 else {
202 bool ok = d->scriptaction->setOption( property.name(), property.value() );
203 if(! ok) {
204 kdWarning() << TQString("KexiScriptDesignView::slotPropertyChanged() unknown property '%1'.").arg(TQString(property.name())) << endl;
205 return;
206 }
207 }
208
209 setDirty(true);
210}
211
212void KexiScriptDesignView::execute()
213{
214 d->statusbrowser->clear();
215 TQTime time;
216 time.start();
217 d->statusbrowser->append( i18n("Execution of the script \"%1\" started.").arg(d->scriptaction->name()) );
218
219 d->scriptaction->activate();
220 if( d->scriptaction->hadException() ) {
221 TQString errormessage = d->scriptaction->getException()->getError();
222 d->statusbrowser->append(TQString("<b>%2</b><br>").arg(TQStyleSheet::escape(errormessage)) );
223
224 TQString tracedetails = d->scriptaction->getException()->getTrace();
225 d->statusbrowser->append( TQStyleSheet::escape(tracedetails) );
226
227 long lineno = d->scriptaction->getException()->getLineNo();
228 if(lineno >= 0)
229 d->editor->setLineNo(lineno);
230 }
231 else {
232 d->statusbrowser->append( i18n("Successfully executed. Time elapsed: %1ms").arg(time.elapsed()) );
233 }
234}
235
236bool KexiScriptDesignView::loadData()
237{
238 TQString data;
239 if(! loadDataBlock(data)) {
240 kexipluginsdbg << "KexiScriptDesignView::loadData(): no DataBlock" << endl;
241 return false;
242 }
243
244 TQString errMsg;
245 int errLine;
246 int errCol;
247
248 TQDomDocument domdoc;
249 bool parsed = domdoc.setContent(data, false, &errMsg, &errLine, &errCol);
250
251 if(! parsed) {
252 kexipluginsdbg << "KexiScriptDesignView::loadData() XML parsing error line: " << errLine << " col: " << errCol << " message: " << errMsg << endl;
253 return false;
254 }
255
256 TQDomElement scriptelem = domdoc.namedItem("script").toElement();
257 if(scriptelem.isNull()) {
258 kexipluginsdbg << "KexiScriptDesignView::loadData(): script domelement is null" << endl;
259 return false;
260 }
261
262 TQString interpretername = scriptelem.attribute("language");
263 Kross::Api::Manager* manager = Kross::Api::Manager::scriptManager();
264 Kross::Api::InterpreterInfo* info = interpretername.isEmpty() ? 0 : manager->getInterpreterInfo(interpretername);
265 if(info) {
266 d->scriptaction->setInterpreterName(interpretername);
267
268 Kross::Api::InterpreterInfo::Option::Map options = info->getOptions();
269 Kross::Api::InterpreterInfo::Option::Map::ConstIterator it, end = options.constEnd();
270 for( it = options.constBegin(); it != end; ++it) {
271 TQString value = scriptelem.attribute( it.data()->name );
272 if(! value.isNull()) {
273 TQVariant v(value);
274 if( v.cast( it.data()->value.type() ) ) // preserve the TQVariant's type
275 d->scriptaction->setOption(it.data()->name, v);
276 }
277 }
278 }
279
280 d->scriptaction->setCode( scriptelem.text() );
281
282 return true;
283}
284
286{
288 kexipluginsdbg << "KexiScriptDesignView::storeNewData(): new id:" << s->id() << endl;
289
290 if(!s || cancel) {
291 delete s;
292 return 0;
293 }
294
295 if(! storeData()) {
296 kdWarning() << "KexiScriptDesignView::storeNewData Failed to store the data." << endl;
297 //failure: remove object's schema data to avoid garbage
298 KexiDB::Connection *conn = parentDialog()->mainWin()->project()->dbConnection();
299 conn->removeObject( s->id() );
300 delete s;
301 return 0;
302 }
303
304 return s;
305}
306
308{
309 kexipluginsdbg << "KexiScriptDesignView::storeData(): " << parentDialog()->partItem()->name() << " [" << parentDialog()->id() << "]" << endl;
310
311 TQDomDocument domdoc("script");
312 TQDomElement scriptelem = domdoc.createElement("script");
313 domdoc.appendChild(scriptelem);
314
315 TQString language = d->scriptaction->getInterpreterName();
316 scriptelem.setAttribute("language", language);
317
318 Kross::Api::InterpreterInfo* info = Kross::Api::Manager::scriptManager()->getInterpreterInfo(language);
319 if(info) {
320 Kross::Api::InterpreterInfo::Option::Map defoptions = info->getOptions();
321 TQStringVariantMap& options = d->scriptaction->getOptions();
322 TQStringVariantMap::ConstIterator it, end( options.constEnd() );
323 for( it = options.constBegin(); it != end; ++it) {
324 if( defoptions.contains(it.key()) ) { // only remember options which the InterpreterInfo knows about...
325 scriptelem.setAttribute(it.key(), it.data().toString());
326 }
327 }
328 }
329
330 TQDomText scriptcode = domdoc.createTextNode(d->scriptaction->getCode());
331 scriptelem.appendChild(scriptcode);
332
333 return storeDataBlock( domdoc.toString() );
334}
335
336#include "kexiscriptdesignview.moc"
337
void plugSharedAction(const char *action_name, TQObject *receiver, const char *slot)
Provides database connection, allowing queries and data modification.
Definition connection.h:62
bool removeObject(uint objId)
KexiPart::Item * partItem() const
static bool isAdvancedEditor()
Kexi's main window interface This interface is implemented by KexiMainWindowImpl class.
virtual KexiProject * project()=0
Project data of currently opened project or NULL if no project here yet.
KexiDB::Connection * dbConnection() const
virtual KexiDB::SchemaData * storeNewData(const KexiDB::SchemaData &sdata, bool &cancel)
Try to call storeData with new data we like to store.
virtual KoProperty::Set * propertySet()
KexiScriptDesignView(KexiMainWindow *mainWin, TQWidget *parent, Kross::Api::ScriptAction *scriptaction)
Constructor.
virtual tristate storeData(bool dontAsk=false)
Try to store the modified data in the already opened and currently used KexiDB::SchemaData instance.
Kross::Api::ScriptAction * scriptAction() const
virtual ~KexiScriptDesignView()
Destructor.
The KexiEditor class embeds text editor for editing scripting code.
Base class for single view embeddable of in KexiDialogBase.
virtual KexiDB::SchemaData * storeNewData(const KexiDB::SchemaData &sdata, bool &cancel)
void propertySetReloaded(bool preservePrevSelection=false, const TQCString &propertyToSelect=TQCString())
bool storeDataBlock(const TQString &dataString, const TQString &dataID=TQString())
bool loadDataBlock(TQString &dataString, const TQString &dataID=TQString(), bool canBeEmpty=false)
KexiDialogBase * parentDialog() const
KexiMainWindow * mainWin() const
3-state logical type with three values: true, false and cancelled and convenient operators.
Definition tristate.h:100