From f1d7b69062179561f2b73ebc7576a919df9f9e89 Mon Sep 17 00:00:00 2001 From: konrad Date: Thu, 21 Oct 2010 20:08:55 +0000 Subject: [PATCH] wizard: make it fully scriptable jsengine: load extensions, exec files config: add script config templates: add script templates overview: make more accessable to scripting, exec startup script git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@607 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33 --- src/dialogs/configdialog.cpp | 43 ++++++++++++ src/dialogs/configdialog.h | 7 +- src/dialogs/wizard.cpp | 78 ++++++++++++---------- src/dialogs/wizard.h | 21 +++++-- src/iface/msinterface.cpp | 4 + src/iface/msinterface.h | 4 +- src/mwin/overview.cpp | 9 +++ src/mwin/overview.h | 32 +++++---- src/script/init.js | 3 + src/script/jsengine.cpp | 151 +++++++++++++++++++++++++++++++++++++++++- src/script/jsengine.h | 14 ++++ src/script/script.pri | 4 +- src/script/scriptfiles.qrc | 8 ++ src/script/startup.js | 2 + src/script/wizard.js | 83 +++++++++++++++++++++++ src/templates/templates.cpp | 6 ++- src/templates/templates.h | 4 +- 17 files changed, 409 insertions(+), 64 deletions(-) create mode 100644 src/script/init.js create mode 100644 src/script/scriptfiles.qrc create mode 100644 src/script/startup.js create mode 100644 src/script/wizard.js diff --git a/src/dialogs/configdialog.cpp b/src/dialogs/configdialog.cpp index 4d04e5a..0a7e722 100644 --- a/src/dialogs/configdialog.cpp +++ b/src/dialogs/configdialog.cpp @@ -146,6 +146,35 @@ MConfigDialog::MConfigDialog() hl->addWidget(pb=new QPushButton(tr("Probe Server"))); connect(pb,SIGNAL(clicked()),this,SLOT(serverProbe())); + tab->addTab(w=new QWidget,tr("Scripting")); + w->setLayout(gl=new QGridLayout); + gl->setColumnStretch(4,1); + lctr=0; + gl->addWidget(lab=new QLabel(tr("You can set scripting preferences here. You have the following options:\nAllow: if active scripts from this source are allowed to run.\nPriority: locations with the lowest value are searched first, when a script it found the other locations are ignored.")),lctr,0,1,5); + lab->setWordWrap(true); + gl->addWidget(lab=new QLabel(tr("Server side scripts:")),++lctr,0); + lab->setAlignment(Qt::AlignRight); + gl->addWidget(asrscript=new QCheckBox(tr("allow")),lctr,1); + gl->addWidget(new QLabel(tr("Prio:")),lctr,2); + gl->addWidget(psrscript=new QSpinBox,lctr,3); + psrscript->setRange(0,100); + gl->addWidget(lab=new QLabel(tr("Built in scripts:")),++lctr,0); + lab->setAlignment(Qt::AlignRight); + gl->addWidget(abiscript=new QCheckBox(tr("allow")),lctr,1); + gl->addWidget(new QLabel(tr("Prio:")),lctr,2); + gl->addWidget(pbiscript=new QSpinBox,lctr,3); + pbiscript->setRange(0,100); + gl->addWidget(lab=new QLabel(tr("User local scripts:")),++lctr,0); + lab->setAlignment(Qt::AlignRight); + gl->addWidget(ausscript=new QCheckBox(tr("allow")),lctr,1); + gl->addWidget(new QLabel(tr("Prio:")),lctr,2); + gl->addWidget(pusscript=new QSpinBox,lctr,3); + pusscript->setRange(0,100); + gl->addWidget(lab=new QLabel(tr("User script path:")),++lctr,0); + lab->setAlignment(Qt::AlignRight); + gl->addWidget(usrscript=new QLineEdit,lctr,1,1,4); + gl->setRowStretch(++lctr,1); + setSizeGripEnabled(true); initProfiles(); @@ -211,6 +240,13 @@ void MConfigDialog::loadProfile() username->setText(set.value("username").toString()); sslexcept=new MSslExceptions(::dataDir+"/profile."+key+"/sslexceptions.xml"); sslFillModel(); + abiscript->setChecked(set.value("script/allowbuiltin",true).toBool()); + ausscript->setChecked(set.value("script/allowuser",false).toBool()); + asrscript->setChecked(set.value("script/allowserver",false).toBool()); + pbiscript->setValue(set.value("script/priobuiltin",10).toInt()); + pusscript->setValue(set.value("script/priouser",0).toInt()); + psrscript->setValue(set.value("script/prioserver",20).toInt()); + usrscript->setText(set.value("script/userpath",dataDir+"/userscripts").toString()); } void MConfigDialog::saveProfile() @@ -230,6 +266,13 @@ void MConfigDialog::saveProfile() set.setValue("username",username->text()); QDir(::dataDir).mkdir("profile."+key); if(sslexcept)sslexcept->savesslexcept(); + set.setValue("script/allowbuiltin",abiscript->isChecked()); + set.setValue("script/allowuser",ausscript->isChecked()); + set.setValue("script/allowserver",asrscript->isChecked()); + set.setValue("script/priobuiltin",pbiscript->value()); + set.setValue("script/priouser",pusscript->value()); + set.setValue("script/prioserver",psrscript->value()); + set.setValue("script/userpath",usrscript->text()); } void MConfigDialog::newProfile() diff --git a/src/dialogs/configdialog.h b/src/dialogs/configdialog.h index c5fe29e..423c722 100644 --- a/src/dialogs/configdialog.h +++ b/src/dialogs/configdialog.h @@ -36,9 +36,10 @@ class MConfigDialog:public QDialog ~MConfigDialog(); private: - QCheckBox*useproxy; - QLineEdit*hostname,*hostkey,*serverurl,*proxyname,*username,*proxyuser,*proxypass; - QSpinBox*proxyport; + QCheckBox*useproxy,*abiscript,*ausscript,*asrscript; + QLineEdit*hostname,*hostkey,*serverurl,*proxyname,*username, + *proxyuser,*proxypass,*usrscript; + QSpinBox*proxyport,*pbiscript,*pusscript,*psrscript; QListView*profiles; QStandardItemModel*profilemodel,*sslmodel; QTableView*ssltable; diff --git a/src/dialogs/wizard.cpp b/src/dialogs/wizard.cpp index c3cf986..a43e03e 100644 --- a/src/dialogs/wizard.cpp +++ b/src/dialogs/wizard.cpp @@ -23,58 +23,40 @@ MWizard::MWizard(MOverview* parent, Qt::WindowFlags f) :QDialog(parent, f),m_parent(parent) { + setWindowTitle(tr("Wizard")); //main layout QVBoxLayout*vl; - QStackedLayout*stack; QHBoxLayout*hl; setLayout(vl=new QVBoxLayout); - vl->addLayout(stack=new QStackedLayout,1); + vl->addLayout(m_stack=new QStackedLayout,1); //bottom buttons vl->addLayout(hl=new QHBoxLayout); hl->addStretch(1); QPushButton*p; + hl->addWidget(p=new QPushButton(tr("Start Over"))); + connect(p,SIGNAL(clicked()),this,SLOT(gotoStart())); hl->addWidget(p=new QPushButton(tr("Close Wizard"))); connect(p,SIGNAL(clicked()),this,SLOT(accept())); hl->addWidget(p=new QPushButton(tr("Exit"))); connect(p,SIGNAL(clicked()),this,SLOT(accept())); connect(p,SIGNAL(clicked()),parent,SLOT(close())); - //paging - QSignalMapper*map=new QSignalMapper(this); - connect(map,SIGNAL(mapped(int)),stack,SLOT(setCurrentIndex(int))); - QWidget*w; - int istart,ivou,ievt,icust,iexec; - //page: start - istart=stack->addWidget(w=new QWidget); + QWidget*w; + m_startid=m_stack->addWidget(w=new QWidget); w->setLayout(vl=new QVBoxLayout); vl->addStretch(1); - vl->addWidget(p=new QPushButton(tr("Sell Tickets"))); - p->setEnabled(req->hasRight(req->PCreateOrder_CanSell)); - connect(p,SIGNAL(clicked()),map,SLOT(map())); - connect(p,SIGNAL(clicked()),this,SLOT(saleMode())); - map->setMapping(p,ievt); - vl->addWidget(p=new QPushButton(tr("Order Tickets"))); - p->setEnabled(req->hasRight(req->PCreateOrder_CanSell)); - connect(p,SIGNAL(clicked()),map,SLOT(map())); - connect(p,SIGNAL(clicked()),this,SLOT(orderMode())); - map->setMapping(p,ievt); - vl->addWidget(p=new QPushButton(tr("Sell Voucher"))); - p->setEnabled(req->hasRight(req->PCreateOrder_CanOrder)); - connect(p,SIGNAL(clicked()),map,SLOT(map())); - connect(p,SIGNAL(clicked()),this,SLOT(saleMode())); - map->setMapping(p,ivou); - vl->addWidget(p=new QPushButton(tr("Order Voucher"))); - p->setEnabled(req->hasRight(req->PCreateOrder_CanOrder)); - connect(p,SIGNAL(clicked()),map,SLOT(map())); - connect(p,SIGNAL(clicked()),this,SLOT(orderMode())); - map->setMapping(p,ivou); + vl->addLayout(m_modelayout=new QVBoxLayout); vl->addStretch(1); - //page: events + //mode mapping... + m_modemap=new QSignalMapper(this); + connect(m_modemap,SIGNAL(mapped(int)),this,SLOT(gotoPage(int))); + + //engine m_jseng=new MScriptEngine(parent); - m_jseng->addObject("Wizard",this); - m_jseng->evaluate("debugger"); + m_jseng->addObject("wizard",this); + m_jseng->evalFile("wizard.js"); } MWizard::~MWizard() @@ -82,13 +64,37 @@ MWizard::~MWizard() delete m_jseng; } +int MWizard::addMode(QString md) +{ + int r=addPage(); + QPushButton*p; + m_modelayout->addWidget(p=new QPushButton(md)); + m_modemap->setMapping(p,r); + connect(p,SIGNAL(clicked()),m_modemap,SLOT(map())); + return r; +} + +int MWizard::addPage() +{ + return m_stack->addWidget(new QWidget); +} + +void MWizard::gotoStart() +{ + m_stack->setCurrentIndex(m_startid); +} + +void MWizard::gotoPage(int pg) +{ + m_stack->setCurrentIndex(pg); +} -void MWizard::orderMode() +QPushButton* MWizard::modeButton(int pg) { - m_mode=OrderMode; + return qobject_cast(m_modemap->mapping(pg)); } -void MWizard::saleMode() +QWidget* MWizard::pageWidget(int pg) { - m_mode=SaleMode; + return m_stack->widget(pg); } diff --git a/src/dialogs/wizard.h b/src/dialogs/wizard.h index d9451f4..9e054f6 100644 --- a/src/dialogs/wizard.h +++ b/src/dialogs/wizard.h @@ -15,6 +15,9 @@ #include +class QSignalMapper; +class QVBoxLayout; +class QStackedLayout; class MScriptEngine; class MOverview; class MWizard:public QDialog @@ -23,14 +26,22 @@ class MWizard:public QDialog public: MWizard(MOverview* parent = 0, Qt::WindowFlags f = 0); virtual ~MWizard(); - private slots: - void saleMode(); - void orderMode(); + + public slots: + int addPage(); + int addMode(QString); + void gotoStart(); + void gotoPage(int); + QWidget* pageWidget(int); + QPushButton* modeButton(int); + private: MOverview*m_parent; - enum Mode {SaleMode,OrderMode}; - Mode m_mode; MScriptEngine*m_jseng; + QStackedLayout*m_stack; + QVBoxLayout*m_modelayout; + QSignalMapper*m_modemap; + int m_startid; }; #endif diff --git a/src/iface/msinterface.cpp b/src/iface/msinterface.cpp index 6fb983e..d01aa70 100644 --- a/src/iface/msinterface.cpp +++ b/src/iface/msinterface.cpp @@ -147,6 +147,10 @@ QString MSInterface::settingsGroup()const { return "profsettings/"+profileid; } +QString MSInterface::configSettingsGroup()const +{ + return "profiles/"+profileid; +} QString MSInterface::repoPart() { diff --git a/src/iface/msinterface.h b/src/iface/msinterface.h index db18893..6dc7bf0 100644 --- a/src/iface/msinterface.h +++ b/src/iface/msinterface.h @@ -55,8 +55,10 @@ class MSInterface:public MInterface /**returns the directory where to store data retrieved from the server*/ QString dataDir()const; - /**returns the group in which to find settings in QSettings*/ + /**returns the group in which to find settings in QSettings, this group can be used by any class that accesses the profile*/ QString settingsGroup()const; + /**returns the group where central profile settings are stored, this group is read-only for anything but the configuration dialog*/ + QString configSettingsGroup()const; /**checks the server for compatibility*/ bool checkServer(); diff --git a/src/mwin/overview.cpp b/src/mwin/overview.cpp index f9ac0c5..d5a4f04 100644 --- a/src/mwin/overview.cpp +++ b/src/mwin/overview.cpp @@ -159,6 +159,15 @@ MOverview::MOverview(QString pk) if(!req->hasRight(req->RGetOrderList)){ tab->setTabEnabled(tab->indexOf(ordertab),false); } + + //run init script + QTimer::singleShot(0,this,SLOT(runStartupScript())); +} + +void MOverview::runStartupScript() +{ + MScriptEngine engine(this); + engine.evalFile("startup.js"); } void MOverview::closeEvent(QCloseEvent*ce) diff --git a/src/mwin/overview.h b/src/mwin/overview.h index 8efba67..64f8394 100644 --- a/src/mwin/overview.h +++ b/src/mwin/overview.h @@ -55,18 +55,33 @@ class MOverview:public QMainWindow /**try to log in again*/ void relogin(); + /**generic check which tab is active*/ + void tabChanged(int); + + /**set refresh timeout*/ + void setRefresh(); + + /**web request settings dialog; shows the dialog per default, just copies settings from registry to webrequest object if false*/ + void webSettings(bool dlg=true); + /**set my own password*/ void setMyPassword(); + /**display property settings*/ + void displaySettings(); + /**settings for backup*/ + void backupSettings(); + + ///\internal run init scripts + void runStartupScript(); + + public slots: /**manage customers*/ void customerMgmt(); /**edit shipping options*/ void editShipping(); - /**generic check which tab is active*/ - void tabChanged(int); - /**return a ticket or voucher*/ void ticketReturn(); /**deduct some money from a voucher (to pay outside the system)*/ @@ -76,21 +91,10 @@ class MOverview:public QMainWindow /**refresh data that we can refresh*/ void refreshData(); - /**set refresh timeout*/ - void setRefresh(); - - /**web request settings dialog; shows the dialog per default, just copies settings from registry to webrequest object if false*/ - void webSettings(bool dlg=true); - - /**display property settings*/ - void displaySettings(); /**do a backup now*/ void doBackup(); - /**settings for backup*/ - void backupSettings(); - /**switch to the cart tab*/ void switchToCartTab(); diff --git a/src/script/init.js b/src/script/init.js new file mode 100644 index 0000000..2b17c6a --- /dev/null +++ b/src/script/init.js @@ -0,0 +1,3 @@ +//initialize environment +importExtension("qt.core"); +importExtension("qt.gui"); diff --git a/src/script/jsengine.cpp b/src/script/jsengine.cpp index 91b2e31..a3d4d83 100644 --- a/src/script/jsengine.cpp +++ b/src/script/jsengine.cpp @@ -13,16 +13,45 @@ #include "jsengine.h" #include "overview.h" #include "msinterface.h" +#include "main.h" +#include "templates.h" #include +#include +#include +#include #include #include +#include + +static QScriptValue importExtension(QScriptContext *context, QScriptEngine *engine) +{ + return engine->importExtension(context->argument(0).toString()); +} + +static QScriptValue evalFile(QScriptContext *context, QScriptEngine *engine_) +{ + MScriptEngine*engine=qobject_cast(engine_); + if(engine==0) + return context->throwError("Oops: Cannot use this engine."); + return engine->evalFile(context->argument(0).toString()); +} + +QStringList MScriptEngine::m_basepath; MScriptEngine::MScriptEngine(MOverview* par) :QScriptEngine(par) { + //register main window addObject("MainWindow",par); + //init wob interface req->initScriptEngine(this); + //utility functions + globalObject().setProperty("importExtension", newFunction(::importExtension)); + globalObject().setProperty("evalFile", newFunction(::evalFile)); + //initialize script sources + if(m_basepath.size()<1)initScriptPath(); + //debugger anybody? int dm=debugMode(); if(dm>0){ QScriptEngineDebugger* deb=new QScriptEngineDebugger(this); @@ -30,6 +59,8 @@ MScriptEngine::MScriptEngine(MOverview* par) if(dm>1) deb->action(QScriptEngineDebugger::InterruptAction)->trigger(); } + //load init script + evalFile("init.js"); } void MScriptEngine::addObject(QString name, QObject* object) { @@ -52,11 +83,127 @@ QStringList MScriptEngine::debugModes() int MScriptEngine::debugMode() { - return QSettings().value("profiles/"+req->profileId()+"/JSdebugMode",0).toInt(); + return QSettings().value(req->settingsGroup()+"/JSdebugMode",0).toInt(); } void MScriptEngine::setDebugMode(int v) { if(v>=0 && vprofileId()+"/JSdebugMode",v); + QSettings().setValue(req->settingsGroup()+"/JSdebugMode",v); +} + +static inline bool normalizeFile(QString &fn) +{ + QStringList fnl=fn.replace("\\","/").split("/",QString::SkipEmptyParts); + QRegExp allow("[a-zA-Z0-9\\._]+"); + QStringList fnt; + for(int i=0;ithrowError("Unable to normalize file name or illegal path component."); + } + //find file + for(int i=0;ithrowError("Unable to find this script."); +} + +static inline void clearDir(QString dn) +{ + QDir dir(dn); + if(!dir.exists())return; + QFileInfoList ifl=dir.entryInfoList(QDir::AllEntries|QDir::NoDotAndDotDot); + for(int i=0;iconfigSettingsGroup()+"/script"); + QMultiMappaths; + if(set.value("allowbuiltin",true).toBool()) + paths.insert(set.value("priobuiltin",10).toInt(),":/scripts"); + if(set.value("allowuser",false).toBool()) + paths.insert(set.value("priouser",0).toInt(), set.value("userpath",dataDir+"/userscripts").toString()); + bool allowserver=set.value("allowserver",false).toBool(); + QString mydir=req->dataDir()+"/scripts"; + if(allowserver) + paths.insert(set.value("prioserver",20).toInt(),mydir); + //sort and append to path + for(int i=0;i<=100;i++) + if(paths.contains(i)) + m_basepath<templateStore(); + if(store==0)return; + QString fn=store->getTemplate("scripts.zip").cacheFileName(); + if(fn=="")return; + QFile fd(fn); + if(!fd.open(QIODevice::ReadOnly))return; + QUnZip zip; + if(!zip.open(&fd))return; + //clear old directory + clearDir(mydir);QDir().mkpath(mydir);mydir+="/"; + if(!zip.gotoFirstFile())return; + do{ + //get file name + QString fn; + if(!zip.getCurrentFileInfo(fn))break; + if(!normalizeFile(fn)){ + qDebug()<<"Warning: cannot normalize script file name"< + + + init.js + startup.js + wizard.js + + diff --git a/src/script/startup.js b/src/script/startup.js new file mode 100644 index 0000000..117cb33 --- /dev/null +++ b/src/script/startup.js @@ -0,0 +1,2 @@ +//startup code +mainWindow.wizardMode(); \ No newline at end of file diff --git a/src/script/wizard.js b/src/script/wizard.js new file mode 100644 index 0000000..f1b8329 --- /dev/null +++ b/src/script/wizard.js @@ -0,0 +1,83 @@ +//example ticket sale wizard +function startSale() +{ + //main page + var ispg=wizard.addMode("Sell a Ticket"); + var spg=wizard.pageWidget(ispg); + var vl;var hl;var p; + spg.setLayout(vl=new QVBoxLayout); + vl.addWidget(new QLabel("Hallo Welt!"),1,0); + vl.addLayout(hl=new QHBoxLayout); + hl.addStretch(1); + hl.addWidget(p=new QPushButton("Continue>>"),0,0); + //customer pages + var icpg=wizard.addPage(); + var incpg=wizard.addPage(); + var ikcpg=wizard.addPage(); + p.clicked.connect(function(){wizard.gotoPage(icpg);}); + //customer fork + var cpg=wizard.pageWidget(icpg); + cpg.setLayout(vl=new QVBoxLayout); + vl.addWidget(new QLabel("Has this customer been here before?"),0,0); + vl.addWidget(new QPushButton("Yes, select from list of known customers..."),0,0); + vl.addWidget(new QPushButton("No, create new customer..."),0,0); + vl.addStretch(1); +} +startSale(); + +//dump built in scripts +var dumpbtn; +var dumppath; +var dumplog; +function startDump() +{ + var idpg=wizard.addMode("Dump built in scripts"); + var dpg=wizard.pageWidget(idpg); + var vl;var p; + dpg.setLayout(vl=new QVBoxLayout); + vl.addWidget(dumpbtn=new QPushButton("Chose path..."),0,0) + dumpbtn.clicked.connect(dumpSelectPath); + vl.addWidget(dumppath=new QLineEdit,0,0); + vl.addSpacing(20); + vl.addWidget(p=new QPushButton("Start Dump"),0,0); + p.clicked.connect(dumpDump); + vl.addSpacing(20); + vl.addWidget(dumplog=new QTextEdit,0,0); + vl.addStretch(1); +} +function dumpSelectPath() +{ + var dp=QFileDialog.getExistingDirectory(); + if(dp!="")dumppath.setText(dp); +} +function dumpDump(path) +{ + if(!path){ + path=""; + dumplog.setPlainText("Starting dump..."); + } + var dir=new QDir(":/scripts/"+path); + var tdir=new QDir(dumppath.text+"/"+path); + var fls=dir.entryInfoList(QDir.Filters(QDir.AllEntries|QDir.NoDotAndDotDot), QDir.SortFlags(QDir.NoSort)); + dumplog.append("going into "+dir.absolutePath()); + for(var i=0;i