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();
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()
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()
~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;
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()
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<QPushButton*>(m_modemap->mapping(pg));
}
-void MWizard::saleMode()
+QWidget* MWizard::pageWidget(int pg)
{
- m_mode=SaleMode;
+ return m_stack->widget(pg);
}
#include <QDialog>
+class QSignalMapper;
+class QVBoxLayout;
+class QStackedLayout;
class MScriptEngine;
class MOverview;
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
{
return "profsettings/"+profileid;
}
+QString MSInterface::configSettingsGroup()const
+{
+ return "profiles/"+profileid;
+}
QString MSInterface::repoPart()
{
/**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();
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)
/**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)*/
/**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();
--- /dev/null
+//initialize environment
+importExtension("qt.core");
+importExtension("qt.gui");
#include "jsengine.h"
#include "overview.h"
#include "msinterface.h"
+#include "main.h"
+#include "templates.h"
#include <QAction>
+#include <QDebug>
+#include <QDir>
+#include <QFileInfo>
#include <QScriptEngineDebugger>
#include <QSettings>
+#include <QUnZip>
+
+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<MScriptEngine*>(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);
if(dm>1)
deb->action(QScriptEngineDebugger::InterruptAction)->trigger();
}
+ //load init script
+ evalFile("init.js");
}
void MScriptEngine::addObject(QString name, QObject* object)
{
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 && v<debugModes().size())
- QSettings().setValue("profiles/"+req->profileId()+"/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;i<fnl.size();i++){
+ if(fnl[i]==".")continue;
+ if(fnl[i]==".."){
+ if(fnt.size()==0)return false;
+ fnt.takeLast();
+ continue;
+ }
+ if(!allow.exactMatch(fnl[i]))return false;
+ fnt<<fnl[i];
+ }
+ fn.clear();
+ for(int i=0;i<fnt.size();i++){
+ if(i)fn+="/";
+ fn+=fnt[i];
+ }
+ return true;
+}
+
+QScriptValue MScriptEngine::evalFile(QString fn)
+{
+ QScriptContext*context=currentContext();
+ //normalize file name
+ if(!normalizeFile(fn)){
+ return context->throwError("Unable to normalize file name or illegal path component.");
+ }
+ //find file
+ for(int i=0;i<m_basepath.size();i++){
+ QString fn2=m_basepath[i]+"/"+fn;
+ QFileInfo fi(fn2);
+ if(fi.exists()&&fi.isFile()&&fi.isReadable()){
+ QFile fd(fn2);
+ fd.open(QIODevice::ReadOnly);
+ QString prg=QString::fromLocal8Bit(fd.readAll());
+ fd.close();
+ return evaluate(prg,fn2);
+ }
+ }
+ //nothing found
+ return context->throwError("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;i<ifl.size();i++){
+ if(ifl[i].isDir()){
+ clearDir(ifl[i].absoluteFilePath());
+ dir.rmdir(ifl[i].fileName());
+ }else{
+ dir.remove(ifl[i].fileName());
+ }
+ }
+}
+
+void MScriptEngine::initScriptPath()
+{
+ QSettings set;
+ //retrieve settings (or defaults)
+ set.beginGroup(req->configSettingsGroup()+"/script");
+ QMultiMap<int,QString>paths;
+ 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<<paths.values(i);
+ //retrieve scripts
+ if(!allowserver)return;
+ MTemplateStore*store=req->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"<<fn;
+ continue;
+ }
+ fn=mydir+fn.toLower();
+ //create parent path
+ QDir().mkpath(QFileInfo(fn).dir().path());
+ //create file
+ QFile fdo(fn);
+ if(!fdo.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+ qDebug()<<"Warning: cannot create file"<<fn;
+ continue;
+ }
+ qDebug()<<"creating script file"<<fn;
+ zip.getCurrentFile(fdo);
+ fdo.close();
+ }while(zip.gotoNextFile());
+ qDebug()<<"end of scripts.zip";
}
class MOverview;
+/**MagicSmoke Scripting Engine
+
+This class already wraps all important objects and functions necessary for MagicSmoke in general.*/
class MScriptEngine:public QScriptEngine
{
Q_OBJECT
public:
+ ///construct the engine with pointer to the main window
MScriptEngine(MOverview*);
+ ///add another object and its meta object
void addObject(QString name,QObject*object);
+ ///execute a specific file, the engine searches for it
+ QScriptValue evalFile(QString);
+ ///returns valid debugger modes - this decides when a debugger opens for a script
static QStringList debugModes();
+ ///returns the index of the debug mode that is currently active
static int debugMode();
+ ///sets the index of the debug mode
static void setDebugMode(int);
+ private:
+ static QStringList m_basepath;
+ ///helper: init m_basepath
+ static void initScriptPath();
};
#endif
HEADERS += \
script/jsengine.h
-INCLUDEPATH += ./script
\ No newline at end of file
+INCLUDEPATH += ./script
+
+RESOURCES += script/scriptfiles.qrc
\ No newline at end of file
--- /dev/null
+<!DOCTYPE RCC>
+<RCC version="1.0">
+ <qresource>
+ <file alias="scripts/init.js">init.js</file>
+ <file alias="scripts/startup.js">startup.js</file>
+ <file alias="scripts/wizard.js">wizard.js</file>
+ </qresource>
+</RCC>
--- /dev/null
+//startup code
+mainWindow.wizardMode();
\ No newline at end of file
--- /dev/null
+//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<fls.length;i++){
+ var fl=fls[i];
+ if(fl.isDir()){
+ tdir.mkdir(fl.fileName());
+ dumpDump(path+"/"+fl.fileName());
+ dumplog.append("creating dir "+fl.fileName());
+ }else{
+ QFile.copy(dir.absolutePath()+"/"+fl.fileName(), tdir.absolutePath()+"/"+fl.fileName());
+ dumplog.append("copying "+fl.fileName());
+ }
+ }
+ dumplog.append("done in "+path);
+}
+startDump();
+
+
+wizard.gotoStart();
+
+//wizard.show();
+
+//debugger
\ No newline at end of file
QStringList MTemplate::legalBaseNames()
{
if(tempBaseNames.size()==0){
- tempBaseNames<<"ticket"<<"voucher"<<"bill"<<"eventsummary";
+ tempBaseNames<<"ticket"<<"voucher"<<"bill"<<"eventsummary"<<"scripts";
}
return tempBaseNames;
}
return LabelTemplate;
if(bn=="bill" || bn=="eventsummary")
return OdfTemplate;
+ if(bn=="scripts")
+ return ZipTemplate;
return UnknownTemplate;
}
return QStringList()<<"xtt";
if(bn=="bill" || bn=="eventsummary")
return QStringList()<<"odtt"<<"odst"<<"odpt"<<"odgt"<<"odbt";
+ if(bn=="scripts")
+ return QStringList()<<"zip";
return QStringList();
}
/**ODF template*/
OdfTemplate=0xff,
/**Label template*/
- LabelTemplate=0x100
+ LabelTemplate=0x100,
+ /**Script-Zip template*/
+ ZipTemplate=0x200
};
Q_DECLARE_FLAGS(Types,Type)