Changeset View
Changeset View
Standalone View
Standalone View
src/plugins/scripting/kexiscripting/kexiscriptpart.cpp
Show All 16 Lines | 1 | /* This file is part of the KDE project | |||
---|---|---|---|---|---|
17 | along with this library; see the file COPYING.LIB. If not, write to | 17 | along with this library; see the file COPYING.LIB. If not, write to | ||
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
19 | * Boston, MA 02110-1301, USA. | 19 | * Boston, MA 02110-1301, USA. | ||
20 | */ | 20 | */ | ||
21 | 21 | | |||
22 | #include "kexiscriptpart.h" | 22 | #include "kexiscriptpart.h" | ||
23 | #include "kexiscriptdesignview.h" | 23 | #include "kexiscriptdesignview.h" | ||
24 | #include "kexiscriptadaptor.h" | 24 | #include "kexiscriptadaptor.h" | ||
25 | #include "../kexidb/kexidbmodule.h" | ||||
26 | | ||||
25 | #include <kexipart.h> | 27 | #include <kexipart.h> | ||
26 | #include <kexipartitem.h> | 28 | #include <kexipartitem.h> | ||
27 | #include <KexiIcon.h> | 29 | #include <KexiIcon.h> | ||
28 | #include <KexiView.h> | 30 | #include <KexiView.h> | ||
29 | #include <KexiWindow.h> | 31 | #include <KexiWindow.h> | ||
30 | #include <KexiMainWindowIface.h> | 32 | #include <KexiMainWindowIface.h> | ||
31 | #include <kexiproject.h> | 33 | #include <kexiproject.h> | ||
32 | 34 | #include <KDbConnection> | |||
33 | #include <Kross/Manager> | | |||
34 | #include <Kross/ActionCollection> | | |||
35 | 35 | | |||
36 | #include <KConfig> | 36 | #include <KConfig> | ||
37 | #include <KConfigGroup> | 37 | #include <KConfigGroup> | ||
38 | #include <KSharedConfig> | 38 | #include <KSharedConfig> | ||
39 | #include <KMessageBox> | 39 | #include <KMessageBox> | ||
40 | 40 | | |||
41 | #include <QDebug> | 41 | #include <QDebug> | ||
42 | #include <QJSEngine> | ||||
43 | #include <QJSValue> | ||||
44 | #include <QJSValueIterator> | ||||
45 | #include <QDomDocument> | ||||
42 | 46 | | |||
43 | KEXI_PLUGIN_FACTORY(KexiScriptPart, "kexi_scriptplugin.json") | 47 | KEXI_PLUGIN_FACTORY(KexiScriptPart, "kexi_scriptplugin.json") | ||
44 | 48 | | |||
45 | /// \internal | 49 | /// \internal | ||
46 | class Q_DECL_HIDDEN KexiScriptPart::Private | 50 | class Q_DECL_HIDDEN KexiScriptPart::Private | ||
47 | { | 51 | { | ||
48 | public: | 52 | public: | ||
49 | explicit Private(KexiScriptPart* p) | 53 | explicit Private(KexiScriptPart* p) | ||
50 | : p(p) | 54 | : p(p) {} | ||
51 | , actioncollection(new Kross::ActionCollection("projectscripts")) | | |||
52 | , adaptor(0) {} | | |||
53 | ~Private() { | 55 | ~Private() { | ||
54 | delete actioncollection; delete adaptor; | | |||
55 | } | 56 | } | ||
56 | 57 | | |||
58 | QJSEngine engine; | ||||
57 | KexiScriptPart* p; | 59 | KexiScriptPart* p; | ||
58 | Kross::ActionCollection* actioncollection; | 60 | KexiScriptAdaptor adaptor; | ||
59 | KexiScriptAdaptor* adaptor; | 61 | Scripting::KexiDBModule kexidbmodule; | ||
60 | | ||||
61 | Kross::Action* action(const QString &partname) { | | |||
62 | Kross::Action *action = actioncollection->action(partname); | | |||
63 | if (! action) { | | |||
64 | if (! adaptor) | | |||
65 | adaptor = new KexiScriptAdaptor(); | | |||
66 | action = new Kross::Action(p, partname); | | |||
67 | actioncollection->addAction(action); | | |||
68 | action->addObject(adaptor); | | |||
69 | } | | |||
70 | return action; | | |||
71 | } | | |||
72 | }; | 62 | }; | ||
73 | 63 | | |||
74 | KexiScriptPart::KexiScriptPart(QObject *parent, const QVariantList& l) | 64 | KexiScriptPart::KexiScriptPart(QObject *parent, const QVariantList& l) | ||
75 | : KexiPart::Part(parent, | 65 | : KexiPart::Part(parent, | ||
76 | xi18nc("Translate this word using only lowercase alphanumeric characters (a..z, 0..9). " | 66 | xi18nc("Translate this word using only lowercase alphanumeric characters (a..z, 0..9). " | ||
77 | "Use '_' character instead of spaces. First character should be a..z character. " | 67 | "Use '_' character instead of spaces. First character should be a..z character. " | ||
78 | "If you cannot use latin characters in your language, use english word.", | 68 | "If you cannot use latin characters in your language, use english word.", | ||
79 | "script"), | 69 | "script"), | ||
80 | xi18nc("tooltip", "Create new script"), | 70 | xi18nc("tooltip", "Create new script"), | ||
81 | xi18nc("what's this", "Creates new script."), | 71 | xi18nc("what's this", "Creates new script."), | ||
82 | l) | 72 | l) | ||
83 | , d(new Private(this)) | 73 | , d(new Private(this)) | ||
84 | { | 74 | { | ||
85 | } | 75 | QJSValue val = d->engine.newQObject(&d->adaptor); | ||
staniek: Maybe we can move this code to execute() and make sure it's executed once? This way we delay… | |||||
76 | d->engine.globalObject().setProperty("Project", val); | ||||
77 | val = d->engine.newQObject(&d->kexidbmodule); | ||||
78 | d->engine.globalObject().setProperty("KDb", val); | ||||
79 | | ||||
80 | | ||||
81 | | ||||
82 | d->engine.installExtensions(QJSEngine::ConsoleExtension);} | ||||
staniek: } -> \n} | |||||
86 | 83 | | |||
87 | KexiScriptPart::~KexiScriptPart() | 84 | KexiScriptPart::~KexiScriptPart() | ||
88 | { | 85 | { | ||
89 | delete d; | 86 | delete d; | ||
90 | } | 87 | } | ||
91 | 88 | | |||
92 | bool KexiScriptPart::execute(KexiPart::Item* item, QObject* sender) | 89 | bool KexiScriptPart::execute(KexiPart::Item* item, QObject* sender) | ||
93 | { | 90 | { | ||
94 | Q_UNUSED(sender); | 91 | Q_UNUSED(sender); | ||
95 | if (!item) { | 92 | if (!item) { | ||
96 | qWarning() << "Invalid item."; | 93 | qWarning() << "Invalid item."; | ||
97 | return false; | 94 | return false; | ||
98 | } | 95 | } | ||
99 | 96 | | |||
100 | #if 0 | 97 | QString p = loadData(item); | ||
101 | KexiDialogBase* dialog = new KexiDialogBase(m_mainWin); | | |||
102 | dialog->setId(item->identifier()); | | |||
103 | KexiScriptDesignView* view = dynamic_cast<KexiScriptDesignView*>( | | |||
104 | createView(dialog, dialog, *item, Kexi::DesignViewMode)); | | |||
105 | if (! view) { | | |||
106 | qWarning() << "Failed to create a view."; | | |||
107 | return false; | | |||
108 | } | | |||
109 | | ||||
110 | Kross::Action* scriptaction = view->scriptAction(); | | |||
111 | if (scriptaction) { | | |||
112 | 98 | | |||
113 | const QString dontAskAgainName = "askExecuteScript"; | 99 | qDebug() << "Executing:\n" << p; | ||
Let's define and use KexiScriptingDebug the same way KexiMigrateManagerDebug is used. staniek: Let's define and use KexiScriptingDebug the same way KexiMigrateManagerDebug is used. | |||||
114 | KSharedConfig::Ptr config = KSharedConfig::openConfig(); | 100 | if (!p.isNull()) { | ||
staniek: Use isEmpty()
If true, should we return true? | |||||
115 | QString dontask = config->readEntry(dontAskAgainName).toLower(); | 101 | d->engine.evaluate(p); | ||
staniek: Check QJSValue::isError() | |||||
116 | 102 | } | |||
117 | bool exec = (dontask == "yes"); | | |||
118 | if (!exec && dontask != "no") { | | |||
119 | exec = KMessageBox::Yes == KMessageBox::questionYesNo(view, | | |||
120 | futureI18n("Do you want to execute the script \"%1\"?\n\n" | | |||
121 | "Scripts obtained from unknown sources can contain dangerous code.", scriptaction->text()), | | |||
122 | futureI18n("Execute Script?"), KGuiItem(futureI18nc("@action:button", "Execute"), koIconName("system-run")), | | |||
123 | dontAskAgainName, KMessageBox::Notify | KMessageBox::Dangerous | | |||
124 | ); | | |||
125 | } | | |||
126 | | ||||
127 | if (exec) { | | |||
128 | //QTimer::singleShot(10, scriptaction, SLOT(activate())); | | |||
129 | d->scriptguiclient->executeScriptAction(scriptaction); | | |||
130 | } | | |||
131 | } | | |||
132 | view->deleteLater(); // not needed any longer. | | |||
133 | #else | | |||
134 | | ||||
135 | Kross::Action *action = d->action(item->name()); | | |||
136 | Q_ASSERT(action); | | |||
137 | action->trigger(); | | |||
138 | #endif | | |||
139 | return true; | 103 | return true; | ||
140 | } | 104 | } | ||
141 | 105 | | |||
142 | void KexiScriptPart::initPartActions() | 106 | void KexiScriptPart::initPartActions() | ||
143 | { | 107 | { | ||
144 | qDebug() << "............."; | 108 | | ||
145 | #if 0 | | |||
146 | if (m_mainWin) { | | |||
147 | // At this stage the KexiPart::Part::m_mainWin should be defined, so | | |||
148 | // that we are able to use it's KXMLGUIClient. | | |||
149 | | ||||
150 | // Initialize the ScriptGUIClient. | | |||
151 | d->scriptguiclient = new Kross::Api::ScriptGUIClient(m_mainWin); | | |||
152 | | ||||
153 | // Publish the KexiMainWindow singelton instance. At least the KexiApp | | |||
154 | // scripting-plugin depends on this instance and loading the plugin will | | |||
155 | // fail if it's not avaiable. | | |||
156 | if (! Kross::Api::Manager::scriptManager()->hasChild("KexiMainWindow")) { | | |||
157 | Kross::Api::Manager::scriptManager()->addQObject(m_mainWin, "KexiMainWindow"); | | |||
158 | | ||||
159 | // Add the QAction's provided by the ScriptGUIClient to the | | |||
160 | // KexiMainWindow. | | |||
161 | //FIXME: fix+use createSharedPartAction() whyever it doesn't work as expected right now... | | |||
162 | Q3PopupMenu* popup = m_mainWin->findPopupMenu("tools"); | | |||
163 | if (popup) { | | |||
164 | QAction* execscriptaction = d->scriptguiclient->action("executescriptfile"); | | |||
165 | if (execscriptaction) | | |||
166 | execscriptaction->plug(popup); | | |||
167 | QAction* configscriptaction = d->scriptguiclient->action("configurescripts"); | | |||
168 | if (configscriptaction) | | |||
169 | configscriptaction->plug(popup); | | |||
170 | QAction* scriptmenuaction = d->scriptguiclient->action("installedscripts"); | | |||
171 | if (scriptmenuaction) | | |||
172 | scriptmenuaction->plug(popup); | | |||
173 | /* | | |||
174 | QAction * execscriptmenuaction = d->scriptguiclient->action("executedscripts"); | | |||
175 | if(execscriptmenuaction) | | |||
176 | execscriptmenuaction->plug( popup ); | | |||
177 | QAction * loadedscriptmenuaction = d->scriptguiclient->action("loadedscripts"); | | |||
178 | if(loadedscriptmenuaction) | | |||
179 | loadedscriptmenuaction->plug( popup ); | | |||
180 | */ | | |||
181 | } | | |||
182 | } | | |||
183 | } | | |||
184 | #endif | | |||
185 | } | 109 | } | ||
186 | 110 | | |||
187 | void KexiScriptPart::initInstanceActions() | 111 | void KexiScriptPart::initInstanceActions() | ||
188 | { | 112 | { | ||
staniek: Better: xi18n("Error executing script at line %1:\n%2") | |||||
189 | createSharedAction(Kexi::DesignViewMode, xi18n("Configure Editor..."), | 113 | createSharedAction(Kexi::DesignViewMode, xi18n("Configure Editor..."), | ||
190 | koIconName("configure"), QKeySequence(), "script_config_editor"); | 114 | koIconName("configure"), QKeySequence(), "script_config_editor"); | ||
191 | } | 115 | } | ||
192 | 116 | | |||
193 | KexiView* KexiScriptPart::createView(QWidget *parent, | 117 | KexiView* KexiScriptPart::createView(QWidget *parent, | ||
194 | KexiWindow *window, | 118 | KexiWindow *window, | ||
195 | KexiPart::Item *item, | 119 | KexiPart::Item *item, | ||
196 | Kexi::ViewMode viewMode, | 120 | Kexi::ViewMode viewMode, | ||
197 | QMap<QString, QVariant>* staticObjectArgs) | 121 | QMap<QString, QVariant>* staticObjectArgs) | ||
198 | { | 122 | { | ||
199 | Q_ASSERT(item); | 123 | Q_ASSERT(item); | ||
200 | Q_UNUSED(window); | 124 | Q_UNUSED(window); | ||
201 | Q_UNUSED(staticObjectArgs); | 125 | Q_UNUSED(staticObjectArgs); | ||
202 | qDebug() << "............. createView"; | 126 | qDebug() << "............. createView"; | ||
203 | QString partname = item->name(); | 127 | QString partname = item->name(); | ||
204 | if (! partname.isNull()) { | 128 | if (! partname.isNull()) { | ||
205 | Kross::Action *action = d->action(partname); | | |||
206 | #if 0 | | |||
207 | KexiMainWindow *win = dialog->mainWin(); | | |||
208 | if (!win || !win->project() || !win->project()->dbConnection()) | | |||
209 | return 0; | | |||
210 | Kross::Api::ScriptActionCollection* collection = d->scriptguiclient->getActionCollection("projectscripts"); | | |||
211 | if (! collection) { | | |||
212 | collection = new Kross::Api::ScriptActionCollection(xi18n("Scripts"), d->scriptguiclient->actionCollection(), "projectscripts"); | | |||
213 | d->scriptguiclient->addActionCollection("projectscripts", collection); | | |||
214 | } | | |||
215 | const char* name = partname.toLatin1(); | | |||
216 | Kross::Api::ScriptAction::Ptr scriptaction = collection->action(name); | | |||
217 | if (! scriptaction) { | | |||
218 | scriptaction = new Kross::Api::ScriptAction(partname); | | |||
219 | collection->attach(scriptaction); //!< @todo remove again on unload! | | |||
220 | } | | |||
221 | #endif | | |||
222 | if (viewMode == Kexi::DesignViewMode) { | 129 | if (viewMode == Kexi::DesignViewMode) { | ||
223 | return new KexiScriptDesignView(parent, action); | 130 | return new KexiScriptDesignView(parent); | ||
224 | } | 131 | } | ||
225 | } | 132 | } | ||
226 | return 0; | 133 | return 0; | ||
227 | } | 134 | } | ||
228 | 135 | | |||
229 | KLocalizedString KexiScriptPart::i18nMessage( | 136 | KLocalizedString KexiScriptPart::i18nMessage( | ||
230 | const QString& englishMessage, KexiWindow* window) const | 137 | const QString& englishMessage, KexiWindow* window) const | ||
231 | { | 138 | { | ||
232 | if (englishMessage == "Design of object <resource>%1</resource> has been modified.") | 139 | if (englishMessage == "Design of object <resource>%1</resource> has been modified.") | ||
233 | return kxi18nc(I18NC_NOOP("@info", "Design of script <resource>%1</resource> has been modified.")); | 140 | return kxi18nc(I18NC_NOOP("@info", "Design of script <resource>%1</resource> has been modified.")); | ||
234 | if (englishMessage == "Object <resource>%1</resource> already exists.") | 141 | if (englishMessage == "Object <resource>%1</resource> already exists.") | ||
235 | return kxi18nc(I18NC_NOOP("@info", "Script <resource>%1</resource> already exists.")); | 142 | return kxi18nc(I18NC_NOOP("@info", "Script <resource>%1</resource> already exists.")); | ||
236 | return Part::i18nMessage(englishMessage, window); | 143 | return Part::i18nMessage(englishMessage, window); | ||
237 | } | 144 | } | ||
238 | 145 | | |||
146 | QString KexiScriptPart::loadData(KexiPart::Item* item) | ||||
We have KexiPart::Part::loadSchemaObject() dedicated for reimplementing object loading. Look e.g. how reports use it. staniek: We have KexiPart::Part::loadSchemaObject() dedicated for reimplementing object loading. Look e. | |||||
147 | { | ||||
148 | QString data; | ||||
149 | if (!item) { | ||||
150 | return QString(); | ||||
151 | } | ||||
152 | | ||||
153 | if (true != KexiMainWindowIface::global()->project()->dbConnection()->loadDataBlock( | ||||
staniek: We have more specialized Part::loadDataBlock() | |||||
Yes, however it takes a Window*. This is called only from the execute() method to execute a script without creating a window. Suggestions? piggz: Yes, however it takes a Window*. This is called only from the execute() method to execute a… | |||||
I see. KexiPart::Part::loadSchemaObject() can be still useful if implemented, right? staniek: I see. KexiPart::Part::loadSchemaObject() can be still useful if implemented, right? | |||||
154 | item->identifier(), &data)) | ||||
155 | { | ||||
156 | return QString(); | ||||
157 | } | ||||
158 | | ||||
159 | QString errMsg; | ||||
160 | int errLine; | ||||
161 | int errCol; | ||||
162 | | ||||
163 | QString scriptType; | ||||
164 | | ||||
165 | QDomDocument domdoc; | ||||
166 | bool parsed = domdoc.setContent(data, false, &errMsg, &errLine, &errCol); | ||||
167 | | ||||
168 | if (! parsed) { | ||||
staniek: ! parsed -> !parsed | |||||
169 | qDebug() << "XML parsing error line: " << errLine << " col: " << errCol << " message: " << errMsg; | ||||
staniek: -> KexiScriptingWarning | |||||
170 | return QString(); | ||||
171 | } | ||||
172 | | ||||
173 | QDomElement scriptelem = domdoc.namedItem("script").toElement(); | ||||
174 | if (scriptelem.isNull()) { | ||||
175 | qDebug() << "script domelement is null"; | ||||
staniek: -> KexiScriptingWarning | |||||
176 | return QString(); | ||||
177 | } | ||||
178 | | ||||
179 | scriptType = scriptelem.attribute("scripttype"); | ||||
180 | if (scriptType.isEmpty()) { | ||||
181 | scriptType = "executable"; | ||||
182 | } | ||||
183 | | ||||
184 | if (scriptType == "executable") { | ||||
185 | return scriptelem.text().toUtf8(); | ||||
186 | } else { | ||||
187 | return QString(); | ||||
188 | } | ||||
189 | } | ||||
190 | | ||||
239 | #include "kexiscriptpart.moc" | 191 | #include "kexiscriptpart.moc" |
Maybe we can move this code to execute() and make sure it's executed once? This way we delay the initialization.
We will obviously also run this code if project-global and app-global scripts exist.
Not to myself: Even later we will run this code only if there's user's consent to do it.