started to refactor main overview window:
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sun, 27 Dec 2009 10:53:41 +0000 (10:53 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sun, 27 Dec 2009 10:53:41 +0000 (10:53 +0000)
*copied files
*extracted events list
*more tabs to come...

git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@355 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

13 files changed:
src/mwin/acltabs.cpp [new file with mode: 0644]
src/mwin/acltabs.h [new file with mode: 0644]
src/mwin/carttab.cpp [new file with mode: 0644]
src/mwin/carttab.h [new file with mode: 0644]
src/mwin/entrancetab.cpp [new file with mode: 0644]
src/mwin/entrancetab.h [new file with mode: 0644]
src/mwin/eventstab.cpp [new file with mode: 0644]
src/mwin/eventstab.h [new file with mode: 0644]
src/mwin/mwin.pri
src/mwin/orderstab.cpp [new file with mode: 0644]
src/mwin/orderstab.h [new file with mode: 0644]
src/mwin/overview.cpp
src/mwin/overview.h

diff --git a/src/mwin/acltabs.cpp b/src/mwin/acltabs.cpp
new file mode 100644 (file)
index 0000000..33d9424
--- /dev/null
@@ -0,0 +1,1753 @@
+//
+// C++ Implementation: overview
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2007
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "centbox.h"
+#include "checkdlg.h"
+#include "eventedit.h"
+#include "eventsummary.h"
+#include "main.h"
+#include "misc.h"
+#include "moneylog.h"
+#include "msinterface.h"
+#include "orderwin.h"
+#include "overview.h"
+
+#include <QApplication>
+#include <QBoxLayout>
+#include <QCheckBox>
+#include <QComboBox>
+#include <QCryptographicHash>
+#include <QDomDocument>
+#include <QDomElement>
+#include <QFile>
+#include <QFileDialog>
+#include <QFrame>
+#include <QInputDialog>
+#include <QLabel>
+#include <QMenu>
+#include <QMenuBar>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QSettings>
+#include <QSpinBox>
+#include <QStandardItemModel>
+#include <QStatusBar>
+#include <QTabWidget>
+#include <QTableView>
+#include <QTextEdit>
+
+#define ORDERNONE      0
+#define ORDERALL       0xff
+#define ORDEROPEN      0xf
+#define ORDERPAY       1
+#define ORDERREFUND    2
+#define ORDERUNSENT    4
+#define ORDERRESERVE   8
+
+#define req (MSInterface::instance())
+
+MOverview::MOverview(QString pk)
+{
+       profilekey=pk;
+       setAttribute(Qt::WA_DeleteOnClose);
+       setWindowTitle("MagicSmoke: "+req->currentUser()+"@"+QSettings().value("profiles/"+pk+"/name").toString());
+       rtimer.setInterval(QSettings().value("profiles/"+pk+"/refresh",300).toInt()*1000);
+       rtimer.start();
+       connect(&rtimer,SIGNAL(timeout()),this,SLOT(refreshData()));
+       //check backup timing
+       int btm=QSettings().value("profiles/"+pk+"/backupinterval",0).toInt()*86400;
+       if(btm){
+               //adjust for last backup time
+               int iv=QDateTime::currentDateTime().toTime_t() - QSettings().value("profiles/"+pk+"/backuptime",0).toInt();
+               if(iv>=btm)btm=0;
+               else btm-=iv;
+               //earliest allowed backup is 30s from now
+               if(btm<30)btm=30;
+               //start timer
+               baktimer.start(btm*1000);
+               connect(&baktimer,SIGNAL(timeout()),this,SLOT(doBackup()));
+       }
+       
+       //menu
+       QMenuBar*mb=menuBar();
+       QMenu*m=mb->addMenu(tr("&Session"));
+       m->addAction(tr("&Re-Login"),this,SLOT(relogin()));
+       m->addAction(tr("Change my &Password"),this,SLOT(setMyPassword()))
+        ->setEnabled(req->hasRight(req->RChangeMyPassword));
+       m->addSeparator();
+       m->addAction(tr("&Edit Templates..."),req,SLOT(editTemplates()));
+       m->addAction(tr("&Update Templates Now"),req,SLOT(updateTemplates()));
+       m->addSeparator();
+       m->addAction(tr("&Close Session"),this,SLOT(close()));
+       
+       m=mb->addMenu(tr("&Event"));
+       m->addAction(tr("&Update Event List"),this,SLOT(updateEvents()))
+        ->setEnabled(req->hasRight(req->RGetAllEvents));
+       m->addAction(tr("&Show/Edit details..."),this,SLOT(editEvent()))
+        ->setEnabled(req->hasRight(req->RGetEvent));
+       m->addAction(tr("&New Event..."),this,SLOT(newEvent()))->setEnabled(req->hasRole("createevent"));
+       m->addSeparator();
+       showoldevents=m->addAction(tr("Show &old Events"),this,SLOT(updateEvents()));
+       showoldevents->setEnabled(req->hasRight(req->RGetAllEvents));
+       showoldevents->setCheckable(true);
+       showoldevents->setChecked(QSettings().value("profiles/"+pk+"/showOldEvents",false).toBool());
+       
+       m=mb->addMenu(tr("&Customer"));
+       m->addAction(tr("&Show all customers"),this,SLOT(customerMgmt()));
+       
+       m=mb->addMenu(tr("C&art"));
+       m->addAction(tr("Add &Ticket"),this,SLOT(cartAddTicket()));
+       m->addAction(tr("Add &Voucher"),this,SLOT(cartAddVoucher()));
+       m->addAction(tr("&Remove Item"),this,SLOT(cartRemoveItem()));
+       m->addAction(tr("&Abort Shopping"),this,SLOT(initCart()));
+       m->addSeparator();
+       m->addAction(tr("&Update Shipping Options"),this,SLOT(updateShipping()));
+       
+       m=mb->addMenu(tr("&Misc"));
+       m->addAction(tr("Return &ticket..."),this,SLOT(ticketReturn()));
+       m->addAction(tr("Return &voucher..."),this,SLOT(voucherReturn()));
+       m->addSeparator();
+       m->addAction(tr("Edit &Shipping Options..."),this,SLOT(editShipping()));
+       m->addSeparator();
+       m->addAction(tr("&Deduct from voucher..."),this,SLOT(deductVoucher()));
+       m->addSeparator();
+       m->addAction(tr("&Money Log for voucher..."),this,SLOT(moneylogVoucher()));
+       m->addAction(tr("Money Log for &user..."),this,SLOT(moneylogUser()));
+       
+       m=mb->addMenu(tr("C&onfigure"));
+       m->addAction(tr("&Auto-Refresh settings..."),this,SLOT(setRefresh()));
+       m->addAction(tr("&Server Access settings..."),this,SLOT(webSettings()));
+       
+       m=mb->addMenu(tr("&Admin"));
+       m->addAction(tr("Backup &Settings..."),this,SLOT(backupSettings()))
+        ->setEnabled(req->hasRight(req->RBackup));
+       m->addAction(tr("&Backup now..."),this,SLOT(doBackup()))
+        ->setEnabled(req->hasRight(req->RBackup));
+
+       mb->addMenu(MApplication::helpMenu());
+       
+       //tabs
+       setCentralWidget(tab=new QTabWidget);
+       connect(tab,SIGNAL(currentChanged(int)),this,SLOT(tabChanged()));
+       
+       //Event tab
+       tab->addTab(eventtab=new QWidget,tr("Events"));
+       QVBoxLayout*vl;QHBoxLayout*hl;
+       eventtab->setLayout(hl=new QHBoxLayout);
+       hl->addWidget(eventtable=new QTableView,10);
+       eventtable->setModel(eventmodel=new QStandardItemModel(this));
+       eventtable->setSelectionMode(QAbstractItemView::SingleSelection);
+       eventtable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       hl->addSpacing(5);
+       hl->addLayout(vl=new QVBoxLayout,0);
+       QPushButton*p;
+       vl->addWidget(p=new QPushButton(tr("New Event...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(newEvent()));
+       p->setEnabled(req->hasRole("createevent"));
+       vl->addWidget(p=new QPushButton(tr("Details...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editEvent()));
+       p->setEnabled(req->hasRole("geteventdata"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Order Ticket...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(eventOrderTicket()));
+       p->setEnabled(req->hasRole("createorder"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Event Summary...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(eventSummary()));
+       p->setEnabled(req->hasRole("eventsummary"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Cancel Event...")),0);
+       p->setEnabled(req->hasRole("cancelevent"));
+       connect(p,SIGNAL(clicked()),this,SLOT(eventCancel()));
+       vl->addStretch(10);
+       
+       //Shopping Cart Tab
+       tab->addTab(carttab=new QWidget,tr("Shopping Cart"));
+       carttab->setLayout(vl=new QVBoxLayout);
+       vl->addLayout(hl=new QHBoxLayout);
+       QVBoxLayout*vl2;
+       hl->addLayout(vl2=new QVBoxLayout,2);
+       vl2->addWidget(carttable=new QTableView,10);
+       carttable->setModel(cartmodel=new QStandardItemModel(this));
+       carttable->setSelectionMode(QAbstractItemView::SingleSelection);
+       carttable->setItemDelegate(new MCartTableDelegate(this));
+       QHBoxLayout*hl2;
+       vl2->addLayout(hl2=new QHBoxLayout,0);
+       hl2->addStretch(10);
+       hl2->addWidget(p=new QPushButton(tr("Add Ticket")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(cartAddTicket()));
+       hl2->addWidget(p=new QPushButton(tr("Add Voucher")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(cartAddVoucher()));
+       hl2->addWidget(p=new QPushButton(tr("Remove Item")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(cartRemoveItem()));
+       QFrame*frm;
+       hl->addWidget(frm=new QFrame,0);
+       frm->setFrameShape(QFrame::VLine);
+       hl->addLayout(vl2=new QVBoxLayout,1);
+       vl2->addWidget(p=new QPushButton(tr("Customer:")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(setCustomer()));
+       vl2->addWidget(cartcustomer=new QLabel("...\n \n \n "));
+       vl2->addWidget(frm=new QFrame,0);
+       frm->setFrameShape(QFrame::HLine);
+       vl2->addSpacing(10);
+       vl2->addWidget(new QLabel(tr("Shipping Method:")),0);
+       vl2->addWidget(cartship=new QComboBox,0);
+       cartship->setEditable(false);
+       vl2->addWidget(new QLabel(tr("Delivery Address:")),0);
+       vl2->addWidget(cartaddr=new QTextEdit);
+       vl2->addSpacing(10);
+       vl2->addWidget(new QLabel(tr("Comments:")),0);
+       vl2->addWidget(cartcomment=new QTextEdit);
+       vl2->addStretch(10);
+       vl->addWidget(frm=new QFrame,0);
+       frm->setFrameShape(QFrame::HLine);
+       vl->addLayout(hl=new QHBoxLayout,0);
+       hl->addStretch(10);
+       hl->addWidget(p=new QPushButton(tr("Check Order")));
+       p->setEnabled(req->hasRole("checkorder"));
+       connect(p,SIGNAL(clicked()),this,SLOT(cartOrder()));
+       hl->addWidget(p=new QPushButton(tr("Clear")));
+       connect(p,SIGNAL(clicked()),this,SLOT(initCart()));
+       
+       //Order List Tab
+       tab->addTab(ordertab=new QWidget,tr("Order List"));
+       ordertab->setLayout(hl=new QHBoxLayout);
+       hl->addLayout(vl=new QVBoxLayout,10);
+       vl->addWidget(ordermode=new QComboBox,0);
+       ordermode->addItem(tr("-select mode-"),ORDERNONE);
+       ordermode->addItem(tr("All Orders"),ORDERALL);
+       ordermode->addItem(tr("Open Orders"),ORDEROPEN);
+       ordermode->addItem(tr("Open Reservations"),ORDERRESERVE);
+       ordermode->addItem(tr("Outstanding Payments"),ORDERPAY);
+       ordermode->addItem(tr("Outstanding Refunds"),ORDERREFUND);
+       ordermode->addItem(tr("Undelivered Orders"),ORDERUNSENT);
+       //make sure this entry is the last one, since we use count()-1 to select it
+       ordermode->addItem(tr("-search result-"),ORDERNONE);
+       connect(ordermode,SIGNAL(currentIndexChanged(int)),this,SLOT(updateOrders()));
+       vl->addWidget(ordertable=new QTableView);
+       ordertable->setModel(ordermodel=new QStandardItemModel(this));
+       ordertable->setSelectionMode(QAbstractItemView::SingleSelection);
+       ordertable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       connect(ordertable,SIGNAL(doubleClicked(const QModelIndex&)),this,SLOT(orderDetails()));
+       hl->addLayout(vl=new QVBoxLayout,0);
+       vl->addWidget(p=new QPushButton(tr("Update")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(updateOrders()));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Details...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderDetails()));
+       p->setEnabled(req->hasRole("getorder"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Find by Ticket...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderByTicket()));
+       p->setEnabled(req->hasRole("orderbyticket"));
+       vl->addWidget(p=new QPushButton(tr("Find by Event...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderByEvent()));
+       p->setEnabled(req->hasRole("getordersbyevents"));
+       vl->addWidget(p=new QPushButton(tr("Find by Customer...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderByCustomer()));
+       p->setEnabled(req->hasRole("getorderlist"));
+       vl->addWidget(p=new QPushButton(tr("Find by Order ID...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderByOrder()));
+       p->setEnabled(req->hasRole("getorder"));
+       vl->addStretch(10);
+       
+       //Entrance Control Tab
+       tab->addTab(entrancetab=new QWidget,tr("Entrance"));
+       entrancetab->setLayout(vl=new QVBoxLayout);
+       vl->addWidget(entranceevent=new QComboBox,0);
+       entranceevent->setEditable(false);
+       vl->addSpacing(30);
+       vl->addWidget(new QLabel(tr("Enter or scan Ticket-ID:")),0);
+       vl->addWidget(entrancescan=new QLineEdit,0);
+       connect(entrancescan,SIGNAL(editingFinished()),this,SLOT(entranceValidate()));
+       vl->addWidget(entrancelabel=new QLabel("  "),10);
+       entrancelabel->setAutoFillBackground(true);
+       QFont fnt=entrancelabel->font();
+       fnt.setBold(true);fnt.setPointSize(24);
+       entrancelabel->setFont(fnt);
+       entrancelabel->setAlignment(Qt::AlignCenter);
+       
+       //user tab
+       tab->addTab(usertab=new QWidget,tr("Users"));
+       usertab->setLayout(hl=new QHBoxLayout);
+       hl->addWidget(usertable=new QTableView,10);
+       usertable->setModel(usermodel=new QStandardItemModel(this));
+       usertable->setSelectionMode(QAbstractItemView::SingleSelection);
+       usertable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       hl->addSpacing(5);
+       hl->addLayout(vl=new QVBoxLayout,0);
+       vl->addWidget(p=new QPushButton(tr("New User...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(newUser()));
+       p->setEnabled(req->hasRole("adduser"));
+       vl->addWidget(p=new QPushButton(tr("Delete User...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(deleteUser()));
+       p->setEnabled(req->hasRole("deleteuser"));
+       vl->addSpacing(20);
+       vl->addWidget(p=new QPushButton(tr("Description...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editUserDescription()));
+       p->setEnabled(req->hasRole("setuserdescription"));
+       vl->addWidget(p=new QPushButton(tr("Hosts...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editUserHosts()));
+       p->setEnabled(req->hasRole("getuserhosts"));
+       vl->addWidget(p=new QPushButton(tr("Roles...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editUserRoles()));
+       p->setEnabled(req->hasRole("getuseracl"));
+       vl->addWidget(p=new QPushButton(tr("Set Password...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(setUserPassword()));
+       p->setEnabled(req->hasRole("setpasswd"));
+       vl->addStretch(10);
+       
+       //host tab
+       tab->addTab(hosttab=new QWidget,tr("Hosts"));
+       hosttab->setLayout(hl=new QHBoxLayout);
+       hl->addWidget(hosttable=new QTableView,10);
+       hosttable->setModel(hostmodel=new QStandardItemModel(this));
+       hosttable->setSelectionMode(QAbstractItemView::SingleSelection);
+       hosttable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       hl->addSpacing(5);
+       hl->addLayout(vl=new QVBoxLayout,0);
+       vl->addWidget(p=new QPushButton(tr("New Host...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(newHost()));
+       p->setEnabled(req->hasRole("addhost"));
+       vl->addWidget(thishostbutton=p=new QPushButton(tr("Add This Host...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(addThisHost()));
+       p->setEnabled(req->hasRole("addhost"));
+       vl->addWidget(p=new QPushButton(tr("Delete Host...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(deleteHost()));
+       p->setEnabled(req->hasRole("deletehost"));
+       vl->addSpacing(20);
+       vl->addWidget(p=new QPushButton(tr("Generate New Key...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(changeHostKey()));
+       p->setEnabled(req->hasRole("sethostkey"));
+       vl->addWidget(p=new QPushButton(tr("Import...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(importHost()));
+       p->setEnabled(req->hasRole("addhost"));
+       vl->addWidget(p=new QPushButton(tr("Export...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(exportHost()));
+       p->setEnabled(req->hasRole("gethostkey"));
+       vl->addStretch(10);
+       
+       //status bar
+       statusBar()->setSizeGripEnabled(true);
+       
+       //make sure webrequest knows its settings
+       webSettings(false);
+       //fill tables
+       if(req->hasRight(req->RGetAllEvents)){
+               updateEvents();
+       }else{
+               eventtab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(eventtab),false);
+       }
+       if(!req->hasRole("createorder")&&!req->hasRole("createsale")){
+               carttab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(carttab),false);
+       }else{
+               initCart();
+       }
+       updateShipping();
+       if(req->hasRole("getorderlist")){
+               updateOrders();
+       }else{
+               ordertab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(ordertab),false);
+       }
+       if(req->hasRole("getusers")){
+               updateUsers();
+       }else{
+               usertab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(usertab),false);
+       }
+       if(req->hasRole("gethosts")){
+               updateHosts();
+       }else{
+               hosttab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(hosttab),false);
+       }
+}
+
+void MOverview::updateEvents()
+{
+       MTGetAllEvents gae=req->queryGetAllEvents();
+       if(gae.stage()!=gae.Success){
+               qDebug("Error getting all events (%s): %s",gae.errorType().toAscii().data(),gae.errorString().toAscii().data());
+               return;
+       }
+       QList<MOEvent>evl=gae.getevents();
+       eventmodel->clear();
+       eventmodel->insertColumns(0,6);
+       eventmodel->setHorizontalHeaderLabels(QStringList()<<tr("Start Time")<<tr("Title")<<tr("Free")<<tr("Reserved")<<tr("Sold")<<tr("Capacity"));
+       QDateTime now=QDateTime::currentDateTime();
+       for(int i=0,j=0;i<evl.size();i++){
+               QDateTime stime=QDateTime::fromTime_t(evl[i].start());
+               if(stime<now && !showoldevents->isChecked())continue;
+               eventmodel->insertRow(j);
+               eventmodel->setData(eventmodel->index(j,0),evl[i].id().value(),Qt::UserRole);
+               eventmodel->setData(eventmodel->index(j,0),stime.toString(tr("ddd MMMM d yyyy, h:mm ap","time format")));
+               eventmodel->setData(eventmodel->index(j,1),evl[i].title().value());
+               eventmodel->setData(eventmodel->index(j,2),evl[i].capacity()-evl[i].amountSold()-evl[i].amountReserved());
+               eventmodel->setData(eventmodel->index(j,3),evl[i].amountReserved().value());
+               eventmodel->setData(eventmodel->index(j,4),evl[i].amountSold().value());
+               eventmodel->setData(eventmodel->index(j,5),evl[i].capacity().value());
+               j++;
+       }
+       eventtable->resizeColumnsToContents();
+       //in case this was called from changing the check state
+       QSettings().setValue("profiles/"+profilekey+"/showOldEvents",showoldevents->isChecked());
+}
+
+void MOverview::closeEvent(QCloseEvent*ce)
+{
+       //make sure session is deleted
+       req->logout();
+       //actually close window
+       QMainWindow::closeEvent(ce);
+}
+
+MOverview::~MOverview()
+{
+       //free requestor
+       req->deleteLater();
+}
+
+void MOverview::relogin()
+{
+       setEnabled(false);
+       if(!req->relogin())
+               QMessageBox::warning(this,tr("Warning"),tr("I was unable to renew the login at the server."));
+       setEnabled(true);
+}
+
+void MOverview::newEvent()
+{
+       MEventEditor ed(this);
+       ed.exec();
+       updateEvents();
+}
+
+void MOverview::editEvent()
+{
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       MEventEditor ed(this,id);
+       ed.exec();
+       updateEvents();
+}
+
+void MOverview::eventSummary()
+{
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       MEventSummary ed(this,id);
+       ed.exec();
+}
+
+void MOverview::eventCancel()
+{
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       MTGetEvent getev=MTGetEvent::query(id);
+       if(!getev.hasError()){
+               bool ok;
+               MOEvent ev=getev.getevent();
+               QString r=QInputDialog::getText(this,tr("Cancel Event"),tr("Please enter a reason to cancel event \"%1\" or abort:").arg(ev.title()),QLineEdit::Normal,"",&ok);
+               if(!ok)return;
+               MTCancelEvent cev=MTCancelEvent::query(id,r);
+               if(!cev.hasError())
+                       QMessageBox::information(this,tr("Event Cancelled"),tr("The event \"%1\" has been cancelled. Please inform everybody who bought a ticket.").arg(ev.title()));
+               else
+                       QMessageBox::warning(this,tr("Warning"),tr("Unable to cancel event \"%1\": %2.").arg(ev.title()).arg(cev.errorString()));
+       }
+}
+
+void MOverview::updateShipping()
+{
+       cartship->clear();
+       cartship->addItem(tr("(No Shipping)"),-1);
+       MTGetAllShipping sh=MTGetAllShipping::query();
+       QList<MOShipping>ship=sh.getshipping();
+       for(int i=0;i<ship.size();i++)
+               cartship->addItem(ship[i].description(),(int)ship[i].id());
+}
+
+void MOverview::updateUsers()
+{
+       MTGetAllUsers au=req->queryGetAllUsers();
+       if(au.hasError())return;
+       QList<MOUser>usl=au.getusers();
+       usermodel->clear();
+       usermodel->insertColumns(0,2);
+       usermodel->insertRows(0,usl.size());
+       usermodel->setHorizontalHeaderLabels(QStringList()<<tr("Login Name")<<tr("Description"));
+       for(int i=0;i<usl.size();i++){
+               usermodel->setData(usermodel->index(i,0),usl[i].name().value());
+               usermodel->setData(usermodel->index(i,1),usl[i].description().value());
+       }
+       usertable->resizeColumnsToContents();
+}
+
+void MOverview::newUser()
+{
+       //get name
+       QString name;
+       while(1){
+               bool ok;
+               name=QInputDialog::getText(this,tr("New User"),tr("Please enter new user name (only letters, digits, and underscore allowed):"),QLineEdit::Normal,name,&ok);
+               if(!ok)
+                       return;
+               if(QRegExp("[A-Za-z0-9_\\.,:-]+").exactMatch(name))
+                       break;
+               if(QMessageBox::warning(this,tr("Error"),tr("The user name must contain only letters, digits, dots and underscores and must be at least one character long!"),QMessageBox::Retry|QMessageBox::Abort)!=QMessageBox::Retry)
+                       return;
+       }
+       //get password
+       QString pwd=QInputDialog::getText(this,tr("Password"),tr("Please enter an initial password for the user:"),QLineEdit::Password);
+       //send request
+       req->queryCreateUser(name,pwd,"");
+       //update display
+       updateUsers();
+}
+
+void MOverview::deleteUser()
+{
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname & descr
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       //make sure user wants this
+       if(QMessageBox::question(this,tr("Delete User?"),tr("Really delete user '%1'?").arg(name),QMessageBox::Yes|QMessageBox::No)!=QMessageBox::Yes)return;
+       //get replacement
+       bool ok;
+       QStringList rplc;
+       rplc<<tr("(Nobody)","this is a username for no user, the string must contain '(' to distinguish it from the others");
+       for(int i=0;i<usermodel->rowCount();i++)
+               rplc<<usermodel->data(usermodel->index(i,0)).toString();
+       QString rp=QInputDialog::getItem(this,tr("Delete User"),tr("Select which user will inherit this users database objects:"),rplc,0,false,&ok);
+       if(!ok)return;
+       //delete
+       MTDeleteUser ret=req->queryDeleteUser(name,rp);
+       if(ret.hasError())
+               QMessageBox::warning(this,tr("Error"),tr("Cannot delete user: %1").arg(ret.errorString()));
+       updateUsers();
+}
+
+void MOverview::editUserDescription()
+{
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname & descr
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       QString descr=usermodel->data(usermodel->index(sel.row(),1)).toString();
+       //edit descr
+       bool ok;
+       descr=QInputDialog::getText(this,tr("Edit Description"),tr("Descriptionof user %1:").arg(name),QLineEdit::Normal,descr,&ok);
+       if(ok)
+               req->querySetUserDescription(name,descr);
+       //update
+       updateUsers();
+}
+
+void MOverview::editUserRoles()
+{/*TODO
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname & descr
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       //...
+       MOUser usr(req,name);
+       MCheckList acl=usr.getRoles();
+       MCheckDialog cd(this,acl,"Edit ACL of user "+name);
+       if(cd.exec()==QDialog::Accepted)
+               usr.setRoles(cd.getCheckList());*/
+}
+
+void MOverview::editUserHosts()
+{/*TODO
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname & descr
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       //...
+       MUser usr(req,name);
+       MCheckList acl=usr.getHosts();
+       MCheckDialog cd(this,acl,"Edit hosts of user "+name);
+       if(cd.exec()==QDialog::Accepted)
+               usr.setHosts(cd.getCheckList());*/
+}
+
+void MOverview::setMyPassword()
+{
+       MPasswordChange pc(this);
+       if(pc.exec()==QDialog::Accepted){
+               MTChangeMyPassword cmp=MTChangeMyPassword::query(pc.oldPassword(),pc.newPassword());
+               if(cmp.hasError())
+                       QMessageBox::warning(this,tr("Warning"),tr("Error setting password: %1").arg(cmp.errorString()));
+       }
+}
+void MOverview::setUserPassword()
+{/*TODO
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       //get new password
+       MPasswordChange pc(this,name);
+       if(pc.exec()!=QDialog::Accepted)return;
+       QString p=pc.newPassword();
+       if(p==""){
+               QMessageBox::warning(this,tr("Warning"),tr("The password must be non-empty and both lines must match"));
+               return;
+       }
+       //...
+       MUser usr(req,name);
+       usr.changePassword(p);*/
+}
+
+void MOverview::updateHosts()
+{/*TODO
+       bool foundThis=false;
+       QString thisHost=req->hostName();
+       QList<MHost>hsl=req->getAllHosts();
+       hostmodel->clear();
+       hostmodel->insertColumns(0,2);
+       hostmodel->insertRows(0,hsl.size());
+       hostmodel->setHorizontalHeaderLabels(QStringList()<<tr("Host Name")<<tr("Host Key"));
+       for(int i=0;i<hsl.size();i++){
+               hostmodel->setData(hostmodel->index(i,0),hsl[i].hostId());
+               hostmodel->setData(hostmodel->index(i,1),hsl[i].hostKey());
+               if(thisHost==hsl[i].hostId())
+                       foundThis=true;
+       }
+       hosttable->resizeColumnsToContents();
+       thishostbutton->setEnabled(!foundThis && req->hasRole("addhost"));*/
+}
+
+void MOverview::newHost()
+{/*TODO
+       //get Host Name
+       QString hname;
+       do{
+               bool ok;
+               hname=QInputDialog::getText(this,tr("Create New Host"),tr("Please enter a host name:"),QLineEdit::Normal,hname,&ok);
+               if(!ok)return;
+               if(!QRegExp("[A-Za-z][A-Za-z0-9_]*").exactMatch(hname))continue;
+       }while(false);
+       //create it
+       MHost hst(req,hname);
+       int e=hst.newKey();
+       if(e<128){
+               if(QMessageBox::warning(this,tr("Warning"),tr("The key of this new host could only be generated with %n bits entropy. Store anyway?","",e).arg(e),QMessageBox::Yes|QMessageBox::No,QMessageBox::No)!=QMessageBox::Yes)
+                       return;
+       }
+       hst.create();
+       //update
+       updateHosts();*/
+}
+
+void MOverview::addThisHost()
+{/*TODO
+       MHost hst(req,req->hostName(),QSettings().value("hostkey").toString());
+       hst.create();
+       updateHosts();*/
+}
+
+void MOverview::deleteHost()
+{/*TODO
+       //get selection
+       QModelIndex sel=hosttable->currentIndex();
+       if(!sel.isValid())return;
+       //get hname
+       QString name=hostmodel->data(hostmodel->index(sel.row(),0)).toString();
+       //ask
+       if(QMessageBox::question(this,tr("Delete this Host?"),tr("Really delete host '%1'?").arg(name),QMessageBox::Yes|QMessageBox::No)!=QMessageBox::Yes)return;
+       //delete it
+       MHost(req,name).deleteHost();
+       updateHosts();*/
+}
+
+void MOverview::changeHostKey()
+{/*TODO
+       //get selection
+       QModelIndex sel=hosttable->currentIndex();
+       if(!sel.isValid())return;
+       //get hname
+       QString name=hostmodel->data(hostmodel->index(sel.row(),0)).toString();
+       //ask
+       if(QMessageBox::question(this,tr("Change Host Key?"),tr("Really change the key of host '%1'?").arg(name),QMessageBox::Yes|QMessageBox::No)!=QMessageBox::Yes)return;
+       //change it
+       MHost hst(req,name);
+       int e=hst.newKey();
+       if(e<128){
+               if(QMessageBox::warning(this,tr("Warning"),tr("The new key of this host could only be generated with %n bits entropy. Store anyway?","",e).arg(e),QMessageBox::Yes|QMessageBox::No,QMessageBox::No)!=QMessageBox::Yes)
+                       return;
+       }
+       hst.save();
+       //update
+       updateHosts();*/
+}
+
+void MOverview::importHost()
+{/*TODO
+       QStringList fn;
+       QFileDialog fdlg(this,tr("Import Key from File"),QString(),"Magic Smoke Host Key (*.mshk)");
+       fdlg.setDefaultSuffix("mshk");
+       fdlg.setAcceptMode(QFileDialog::AcceptOpen);
+       fdlg.setFileMode(QFileDialog::ExistingFile);
+       if(!fdlg.exec())return;
+       fn=fdlg.selectedFiles();
+       if(fn.size()!=1)return;
+       QFile fd(fn[0]);
+       if(!fd.open(QIODevice::ReadOnly)){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to open file %1 for reading: %2").arg(fn[0]).arg(fd.errorString()));
+               return;
+       }
+       //read content (max: 10k to limit potential damage)
+       QStringList fc=QString::fromAscii(fd.read(10240)).split("\n",QString::SkipEmptyParts);
+       fd.close();
+       //check content
+       if(fc.size()<3){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a host key file."));
+               return;
+       }
+       if(fc[0].trimmed()!="MagicSmokeHostKey"){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a host key file."));
+               return;
+       }
+       QString hname=fc[1].trimmed();
+       if(!QRegExp("[A-Za-z][A-Za-z0-9_]*").exactMatch(hname)){
+               QMessageBox::warning(this,tr("Warning"),tr("This host key file does not contain a valid host name."));
+               return;
+       }
+       QString key=fc[2].trimmed();
+       if(!QRegExp("[0-9a-fA-F]+").exactMatch(key) || key.size()<40){
+               QMessageBox::warning(this,tr("Warning"),tr("This host key file does not contain a valid key."));
+               return;
+       }
+       QString chk=QCryptographicHash::hash(key.toAscii(),QCryptographicHash::Md5).toHex();
+       if(chk!=fc[3].trimmed()){
+               QMessageBox::warning(this,tr("Warning"),tr("The key check sum did not match. Please get a clean copy of the host key file."));
+               return;
+       }
+       //save
+       MHost hst(req,hname,key);
+       hst.create();
+       updateHosts();*/
+}
+
+void MOverview::exportHost()
+{/*TODO
+       //get selection
+       QModelIndex sel=hosttable->currentIndex();
+       if(!sel.isValid())return;
+       //get hname
+       QString name=hostmodel->data(hostmodel->index(sel.row(),0)).toString();
+       QString key=hostmodel->data(hostmodel->index(sel.row(),1)).toString();
+       if(name[0]=='_' || key==""){
+               QMessageBox::warning(this,tr("Warning"),tr("This host cannot be exported."));
+               return;
+       }
+       //save
+       QStringList fn;
+       QFileDialog fdlg(this,tr("Export Key to File"),QString(),"Magic Smoke Host Key (*.mshk)");
+       fdlg.setDefaultSuffix("mshk");
+       fdlg.setAcceptMode(QFileDialog::AcceptSave);
+       fdlg.setFileMode(QFileDialog::AnyFile);
+       if(!fdlg.exec())return;
+       fn=fdlg.selectedFiles();
+       if(fn.size()!=1)return;
+       QFile fd(fn[0]);
+       if(!fd.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to open file %1 for writing: %2").arg(fn[0]).arg(fd.errorString()));
+               return;
+       }
+       QString chk=QCryptographicHash::hash(key.toAscii(),QCryptographicHash::Md5).toHex();
+       QString out="MagicSmokeHostKey\n"+name+"\n"+key+"\n"+chk;
+       fd.write(out.toAscii());
+       fd.close();*/
+}
+
+
+void MOverview::initCart()
+{
+       //clear cart
+       cartmodel->clear();
+       cartmodel->setHorizontalHeaderLabels(QStringList()<<tr("Amount")<<tr("Title")<<tr("Start Time"));
+       //clear customer
+       customer=MCustomer();
+       cartcustomer->setText("");
+       //clear address/comment
+       cartaddr->setPlainText("");
+       cartcomment->setPlainText("");
+       //clear shipping
+       cartship->setCurrentIndex(0);
+}
+
+void MOverview::setCustomer()
+{/*TODO
+       MCustomerListDialog mcl(req,this,true,customer.customerID());
+       if(mcl.exec()!=QDialog::Accepted)return;
+       customer=mcl.getCustomer();
+       cartcustomer->setText(customer.getNameAddress());*/
+}
+
+static const int CART_TICKET=1;
+static const int CART_VOUCHER=2;
+
+static const int CART_IDROLE=Qt::UserRole;//ticket id
+static const int CART_PRICEROLE=Qt::UserRole;//voucher price
+static const int CART_VALUEROLE=Qt::UserRole+1;//voucher value
+static const int CART_TYPEROLE=Qt::UserRole+2;//which is it? ticket or voucher?
+
+void MOverview::cartAddTicket()
+{
+       //create ticket selection dialog
+       QDialog dlg;
+       dlg.setWindowTitle(tr("Select Event to order Ticket"));
+       QTableView*tv;
+       QHBoxLayout*hl;
+       QVBoxLayout*vl;
+       dlg.setLayout(vl=new QVBoxLayout);
+       vl->addWidget(tv=new QTableView,10);
+       tv->setModel(eventmodel);
+       tv->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       tv->resizeColumnsToContents();
+       vl->addSpacing(15);
+       vl->addLayout(hl=new QHBoxLayout,0);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Select")),0);
+       connect(p,SIGNAL(clicked()),&dlg,SLOT(accept()));
+       connect(tv,SIGNAL(doubleClicked(const QModelIndex&)),&dlg,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")),0);
+       connect(p,SIGNAL(clicked()),&dlg,SLOT(reject()));
+       //wait for it
+       if(dlg.exec()==QDialog::Accepted){
+               //get selection
+               QModelIndex idx=tv->currentIndex();
+               if(!idx.isValid())return;
+               int id=eventmodel->data(eventmodel->index(idx.row(),0),Qt::UserRole).toInt();
+               if(id<0)return;
+               //copy to cart
+               int cr=cartmodel->rowCount();
+               cartmodel->insertRows(cr,1);
+               cartmodel->setData(cartmodel->index(cr,0),1);
+               cartmodel->setData(cartmodel->index(cr,0),id,CART_IDROLE);
+               cartmodel->setData(cartmodel->index(cr,0),CART_TICKET,CART_TYPEROLE);
+               cartmodel->setData(cartmodel->index(cr,1),eventmodel->data(eventmodel->index(idx.row(),1)));
+               cartmodel->setData(cartmodel->index(cr,2),eventmodel->data(eventmodel->index(idx.row(),0)));
+               carttable->resizeColumnsToContents();
+       }
+}
+
+void MOverview::eventOrderTicket()
+{
+       //get selected event
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       //activate order tab
+       tab->setCurrentWidget(carttab);
+       //insert event into table
+       int cr=cartmodel->rowCount();
+       cartmodel->insertRows(cr,1);
+       cartmodel->setData(cartmodel->index(cr,0),1);
+       cartmodel->setData(cartmodel->index(cr,0),id,CART_IDROLE);
+       cartmodel->setData(cartmodel->index(cr,0),CART_TICKET,CART_TYPEROLE);
+       cartmodel->setData(cartmodel->index(cr,1),eventmodel->data(eventmodel->index(ilst[0].row(),1)));
+       cartmodel->setData(cartmodel->index(cr,2),eventmodel->data(eventmodel->index(ilst[0].row(),0)));
+       carttable->resizeColumnsToContents();
+}
+
+void MOverview::cartAddVoucher()
+{/*TODO
+       //create voucher selection dialog
+       QDialog dlg;
+       dlg.setWindowTitle(tr("Select Voucher"));
+       QComboBox*cp,*cv;
+       QHBoxLayout*hl;
+       QGridLayout*gl;
+       QStandardItemModel mdl;
+       QRegExpValidator regv(priceRegExp(),this);
+       QList<int>prc=req->getVoucherPrices();
+       mdl.insertRows(0,prc.size());
+       mdl.insertColumns(0,1);
+       for(int i=0;i<prc.size();i++)mdl.setData(mdl.index(i,0),cent2str(prc[i]));
+       dlg.setLayout(gl=new QGridLayout);
+       gl->addWidget(new QLabel(tr("Select voucher price and value:")),0,0,1,2);
+       if(req->hasRole("_anypricevoucher")){
+               gl->addWidget(new QLabel(tr("Price:")),1,0);
+               gl->addWidget(cp=new QComboBox,1,1);
+               cp->setModel(&mdl);
+               cp->setEditable(true);
+               cp->setValidator(&regv);
+       }else cp=0;
+       gl->addWidget(new QLabel(tr("Value:")),2,0);
+       gl->addWidget(cv=new QComboBox,2,1);
+       cv->setModel(&mdl);
+       cv->setEditable(req->hasRole("_anyvoucher"));
+       cv->setValidator(&regv);
+       gl->setRowMinimumHeight(3,15);
+       gl->setColumnStretch(0,0);
+       gl->setColumnStretch(1,1);
+       gl->setRowStretch(3,1);
+       gl->addLayout(hl=new QHBoxLayout,4,0,1,2);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Ok")),0);
+       connect(p,SIGNAL(clicked()),&dlg,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")),0);
+       connect(p,SIGNAL(clicked()),&dlg,SLOT(reject()));
+       //wait for it
+       if(dlg.exec()==QDialog::Accepted){
+               //get selection
+               int price,value;
+               value=str2cent(cv->currentText());
+               if(req->hasRole("_anypricevoucher") && cp)
+                       price=str2cent(cp->currentText());
+               else
+                       price=value;
+               //copy to cart
+               int cr=cartmodel->rowCount();
+               cartmodel->insertRows(cr,1);
+               cartmodel->setData(cartmodel->index(cr,0),1);
+               cartmodel->setData(cartmodel->index(cr,0),price,CART_PRICEROLE);
+               cartmodel->setData(cartmodel->index(cr,0),value,CART_VALUEROLE);
+               cartmodel->setData(cartmodel->index(cr,0),CART_VOUCHER,CART_TYPEROLE);
+               cartmodel->setData(cartmodel->index(cr,1),tr("Voucher (price: %1, value %2)").arg(cent2str(price)).arg(cent2str(value)));
+               carttable->resizeColumnsToContents();
+       }*/
+}
+
+void MOverview::cartRemoveItem()
+{
+       //get selection
+       QModelIndex idx=carttable->currentIndex();
+       if(!idx.isValid())return;
+       //remove row
+       cartmodel->removeRow(idx.row());
+}
+
+void MOverview::cartOrder()
+{
+       //sanity checks
+       if(cartmodel->rowCount()<1){
+               QMessageBox::warning(this,tr("Error"),tr("There is nothing in the order. Ignoring it."));
+               return;
+       }
+       if(!customer.isValid()){
+               QMessageBox::warning(this,tr("Error"),tr("Please chose a customer first!"));
+               return;
+       }
+       ///////////////
+       //create order
+       QDomDocument doc;
+       QDomElement root=doc.createElement("Order");
+       root.setAttribute("customer",customer.id());
+       //is there a delivery address
+       QString s=cartaddr->toPlainText().trimmed();
+       if(s!=""){
+               QDomElement da=doc.createElement("DeliveryAddress");
+               da.appendChild(doc.createTextNode(s));
+               root.appendChild(da);
+       }
+       //is there a comment?
+       s=cartcomment->toPlainText().trimmed();
+       if(s!=""){
+               QDomElement cc=doc.createElement("Comment");
+               cc.appendChild(doc.createTextNode(s));
+               root.appendChild(cc);
+       }
+       //scan tickets & scan vouchers
+       for(int i=0;i<cartmodel->rowCount();i++){
+               QModelIndex idx=cartmodel->index(i,0);
+               int tp=cartmodel->data(idx,CART_TYPEROLE).toInt();
+               if(tp==CART_TICKET){
+                       int amt=cartmodel->data(idx).toInt();
+                       int evid=cartmodel->data(idx,CART_IDROLE).toInt();
+                       for(int j=0;j<amt;j++){
+                               QDomElement tc=doc.createElement("Ticket");
+                               tc.setAttribute("event",evid);
+                               root.appendChild(tc);
+                       }
+               }else
+               if(tp==CART_VOUCHER){
+                       int amt=cartmodel->data(idx).toInt();
+                       int price=cartmodel->data(idx,CART_PRICEROLE).toInt();
+                       int value=cartmodel->data(idx,CART_VALUEROLE).toInt();
+                       for(int j=0;j<amt;j++){
+                               QDomElement tc=doc.createElement("Voucher");
+                               tc.setAttribute("price",price);
+                               tc.setAttribute("value",value);
+                               root.appendChild(tc);
+                       }
+               
+               }
+       }
+       //set shipping info
+       if(cartship->currentIndex()>0){
+               QDomElement si=doc.createElement("Shipping");
+               si.setAttribute("type",cartship->itemData(cartship->currentIndex()).toInt());
+               root.appendChild(si);
+       }
+       //finalize
+       doc.appendChild(root);
+       //send
+       /*TODO
+       if(req->request("checkorder",doc.toByteArray())==false){
+               QMessageBox::warning(this,tr("Error"),tr("The request failed."));
+               return;
+       }
+       if(req->responseStatus()!=MSInterface::Ok){
+               QMessageBox::warning(this,tr("Error"),tr("A problem occurred during the order: %1").arg(qApp->translate("php::",req->responseBody())));
+               return;
+       }
+       //parse result
+       QDomDocument rdoc;
+       rdoc.setContent(req->responseBody());
+       //display order and give user chance to actually order it
+       MOrderWindow *ow=new MOrderWindow(this,req,MOrder(req,rdoc.documentElement()));
+       ow->show();
+       //empty the cart
+       initCart();*/
+}
+
+void MOverview::customerMgmt()
+{/*TODO
+       MCustomerListDialog mcl(req,this);
+       mcl.exec();*/
+}
+
+void MOverview::editShipping()
+{/*TODO
+       MShippingEditor se(req,this);
+       se.exec();
+       updateShipping();*/
+}
+
+void MOverview::tabChanged()
+{/*TODO
+       QWidget*w=tab->currentWidget();
+       if(w==entrancetab){
+               //fill combobox from eventmodel
+               int ci=entranceevent->currentIndex();
+               int cev=-1;
+               if(ci>=0)cev=entranceevent->itemData(ci).toInt();
+               ci=-1;
+               entranceevent->clear();
+               for(int i=0;i<eventmodel->rowCount();i++){
+                       QString ev=eventmodel->data(eventmodel->index(i,0)).toString()+" "+
+                        eventmodel->data(eventmodel->index(i,1)).toString();
+                       int eid=eventmodel->data(eventmodel->index(i,0),Qt::UserRole).toInt();
+                       entranceevent->addItem(ev,eid);
+                       if(eid==cev)ci=i;
+               }
+               if(ci>=0)entranceevent->setCurrentIndex(ci);
+               //set focus on scanner
+               entrancescan->setFocus(Qt::OtherFocusReason);
+               entrancescan->setText("");
+       }*/
+}
+
+void MOverview::entranceValidate()
+{/*TODO
+       //get event ID
+       int ci=entranceevent->currentIndex();
+       if(ci<0)return;
+       int cev=entranceevent->itemData(ci).toInt();
+       //check content
+       QString tid=entrancescan->text().trimmed();
+       entrancescan->setText("");
+       //avoid spurious events
+       if(tid=="")return;
+       //avoid double scans
+       QDateTime now=QDateTime::currentDateTime();
+       if(tid==lastbarcode && lastbcscan.addSecs(20)>=now)
+               return;
+       lastbarcode=tid;
+       lastbcscan=now;
+       //reset display
+       QPalette pal=entrancelabel->palette();
+       QPalette::ColorRole rl=QPalette::Window;
+       pal.setColor(rl,Qt::lightGray);
+       entrancelabel->setPalette(pal);
+       entrancelabel->setText(tr("searching...","entrance control"));
+       //ask the server
+       MTicket tick(req,tid);
+       //decide what to do
+       if(!tick.isValid()){
+               entrancelabel->setText(tr("Ticket \"%1\" Not Valid").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else
+       if(tick.eventID()!=cev){
+               entrancelabel->setText(tr("Ticket \"%1\" is not for this event.").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else
+       if(tick.status()==MTicket::Used){
+               entrancelabel->setText(tr("Ticket \"%1\" has already been used").arg(tid));
+               pal.setColor(rl,Qt::magenta);
+       }else
+       if(tick.status()!=MTicket::Bought){
+               entrancelabel->setText(tr("Ticket \"%1\" has not been bought.").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else
+       if(tick.paymentStatus()==MTicket::PSOk){
+               entrancelabel->setText(tr("Ticket \"%1\" Ok").arg(tid));
+               pal.setColor(rl,Qt::green);
+               tick.markUsed();
+       }else
+       if(tick.paymentStatus()==MTicket::PSNeedRefund){
+               entrancelabel->setText(tr("Ticket \"%1\" Ok; the Order has a refund").arg(tid));
+               pal.setColor(rl,Qt::green);
+               tick.markUsed();
+       }else
+       if(tick.paymentStatus()==MTicket::PSNeedPayment){
+               entrancelabel->setText(tr("Ticket \"%1\" is not paid for!").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else{
+               entrancelabel->setText(tr("Ticket \"%1\" cannot be accepted, please check the order!").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }
+       
+       entrancelabel->setPalette(pal);
+       entrancescan->setFocus(Qt::OtherFocusReason);
+       entrancescan->setText("");*/
+}
+
+//helper: finds out whether an order should be printed.
+static inline bool candoUpdateOrders(int omode,const MOrder&ord)
+{
+       if(omode==ORDERALL)return true;
+       if((omode&ORDERPAY)!=0 && ord.needsPayment())return true;
+       if((omode&ORDERREFUND)!=0 && ord.needsRefund())return true;
+       if((omode&ORDERUNSENT)!=0 && !ord.isSent())return true;
+       if((omode&ORDERRESERVE)!=0 && ord.isReservation())return true;
+       return false;
+}
+
+void MOverview::updateOrders()
+{/*TODO
+       ordermodel->clear();
+       ordermodel->setHorizontalHeaderLabels(QStringList()<<tr("Status")<<tr("Total")<<tr("Paid")<<tr("Customer"));
+       int omode=ordermode->itemData(ordermode->currentIndex()).toInt();
+       if(omode==ORDERNONE)return;
+       QList<MOrder> orders=req->getAllOrders();
+       if(orders.size()==0)return;
+       QList<MCustomer> cust=req->getAllCustomers();
+       int cl=0;
+       for(int i=0;i<orders.size();i++){
+               if(!candoUpdateOrders(omode,orders[i]))continue;
+               ordermodel->insertRow(cl);
+               ordermodel->setHeaderData(cl,Qt::Vertical,orders[i].orderID());
+               ordermodel->setData(ordermodel->index(cl,0),orders[i].orderStatusString());
+               ordermodel->setData(ordermodel->index(cl,0),orders[i].orderID(),Qt::UserRole);
+               ordermodel->setData(ordermodel->index(cl,1),orders[i].totalPriceString());
+               ordermodel->setData(ordermodel->index(cl,2),orders[i].amountPaidString());
+               int cid=orders[i].customerID();
+               //TODO: make this more effective:
+               for(int j=0;j<cust.size();j++)
+                       if(cust[j].customerID()==cid)
+                               ordermodel->setData(ordermodel->index(cl,3),cust[j].name());
+               cl++;
+       }
+       ordertable->resizeColumnsToContents();*/
+}
+
+void MOverview::orderDetails()
+{/*TODO
+       //get selected order
+       int id;
+       QModelIndexList ilst=ordertable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=ordermodel->index(ilst[0].row(),0);
+       id=ordermodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       //open order window
+       MOrderWindow *om=new MOrderWindow(this,req,MOrder(req,id));
+       om->setAttribute(Qt::WA_DeleteOnClose);
+       om->show();*/
+}
+
+void MOverview::orderByTicket()
+{/*TODO
+       //get selected order
+       bool ok;
+       QString tid=QInputDialog::getText(this,tr("Enter Ticket"),tr("Please enter the ID of one of the tickets of the order you seek:"),QLineEdit::Normal,"",&ok);
+       if(!ok || tid=="")return;
+       //request it
+       if(!req->request("orderbyticket",tid.toUtf8())){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to query server."));
+               return;
+       }
+       if(req->responseStatus()!=MSInterface::Ok){
+               QMessageBox::warning(this,tr("Warning"),qApp->translate("php::",req->responseBody()));
+               return;
+       }
+       int id=req->responseBody().trimmed().toInt(&ok);
+       if(!ok || id<0){
+               QMessageBox::warning(this,tr("Warning"),tr("Server returned an invalid order ID."));
+               return;
+       }
+       //open order window
+       MOrderWindow *om=new MOrderWindow(this,req,MOrder(req,id));
+       om->setAttribute(Qt::WA_DeleteOnClose);
+       om->show();*/
+}
+
+void MOverview::orderByEvent()
+{/*TODO
+       //display selection dialog
+       QDialog d(this);
+       d.setWindowTitle(tr("Select Event"));
+       QVBoxLayout*vl;
+       QHBoxLayout*hl;
+       d.setLayout(vl=new QVBoxLayout);
+       QTableView*tv;
+       vl->addWidget(tv=new QTableView,10);
+       tv->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       tv->setModel(eventmodel);
+       tv->resizeColumnsToContents();
+       vl->addLayout(hl=new QHBoxLayout,0);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Ok")),0);
+       connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")),0);
+       connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+       //wait for user
+       if(d.exec()!=QDialog::Accepted)
+               return;
+       //get selection
+       QModelIndexList ilst=tv->selectionModel()->selectedIndexes();
+       if(ilst.size()<1){
+               qDebug("nothing selected");
+               return;
+       }
+       //get events
+       QList<int>eventids;
+       for(int i=0;i<ilst.size();i++){
+               int eid=eventmodel->data(eventmodel->index(ilst[i].row(),0),Qt::UserRole).toInt();
+               if(!eventids.contains(eid))eventids.append(eid);
+       }
+       //request data and display
+       //TODO: unify this part with updateOrders
+       ordermodel->clear();
+       ordermodel->setHorizontalHeaderLabels(QStringList()<<tr("Status")<<tr("Total")<<tr("Paid")<<tr("Customer"));
+       QList<MOrder> orders=req->getOrdersByEvents(eventids);
+       if(orders.size()==0)return;
+       QList<MCustomer> cust=req->getAllCustomers();
+       for(int cl=0;cl<orders.size();cl++){
+               ordermodel->insertRow(cl);
+               ordermodel->setHeaderData(cl,Qt::Vertical,orders[cl].orderID());
+               ordermodel->setData(ordermodel->index(cl,0),orders[cl].orderStatusString());
+               ordermodel->setData(ordermodel->index(cl,0),orders[cl].orderID(),Qt::UserRole);
+               ordermodel->setData(ordermodel->index(cl,1),orders[cl].totalPriceString());
+               ordermodel->setData(ordermodel->index(cl,2),orders[cl].amountPaidString());
+               int cid=orders[cl].customerID();
+               //TODO: make this more effective:
+               for(int j=0;j<cust.size();j++)
+                       if(cust[j].customerID()==cid)
+                               ordermodel->setData(ordermodel->index(cl,3),cust[j].name());
+       }
+       ordermode->setCurrentIndex(ordermode->count()-1);*/
+}
+
+void MOverview::orderByCustomer()
+{/*TODO
+       //display selection dialog
+       MCustomerListDialog mcl(req,this,true);
+       //wait for user
+       if(mcl.exec()!=QDialog::Accepted)
+               return;
+       //get selection
+       MCustomer cst=mcl.getCustomer();
+       if(!cst.isValid()){
+               qDebug("nothing selected");
+               return;
+       }
+       qint64 custid=cst.customerID();
+       //request data and display
+       //TODO: unify this part with updateOrders
+       ordermodel->clear();
+       ordermodel->setHorizontalHeaderLabels(QStringList()<<tr("Status")<<tr("Total")<<tr("Paid")<<tr("Customer"));
+       QList<MOrder> orders=req->getAllOrders();
+       if(orders.size()==0)return;
+       QList<MCustomer> cust=req->getAllCustomers();
+       int cl=0;
+       for(int i=0;i<orders.size();i++){
+               //filter
+               if(orders[i].customerID()!=custid)continue;
+               //put into table
+               ordermodel->insertRow(cl);
+               ordermodel->setHeaderData(cl,Qt::Vertical,orders[i].orderID());
+               ordermodel->setData(ordermodel->index(cl,0),orders[i].orderStatusString());
+               ordermodel->setData(ordermodel->index(cl,0),orders[i].orderID(),Qt::UserRole);
+               ordermodel->setData(ordermodel->index(cl,1),orders[i].totalPriceString());
+               ordermodel->setData(ordermodel->index(cl,2),orders[i].amountPaidString());
+               ordermodel->setData(ordermodel->index(cl,3),cst.name());
+               //count up
+               cl++;
+       }
+       ordermode->setCurrentIndex(ordermode->count()-1);*/
+}
+
+void MOverview::orderByOrder()
+{/*TODO
+       //ask for OrderID
+       bool ok;
+       int oid=QInputDialog::getInteger(this,tr("Enter Order ID"),tr("Please enter the ID of the order you want to display:"),0,0,2147483647,1,&ok);
+       if(!ok)return;
+       //display
+       MOrder ord(req,oid);
+       if(!ord.isValid()){
+               QMessageBox::warning(this,tr("Warning"),tr("This order does not exist."));
+               return;
+       }
+       MOrderWindow *ow=new MOrderWindow(this,req,ord);
+       ow->show();*/
+}
+
+void MOverview::ticketReturn()
+{/*TODO
+       //get ticket
+       bool ok;
+       QString tid=QInputDialog::getText(this,tr("Return Ticket"),tr("Please enter the ticket ID to return:"),QLineEdit::Normal,"",&ok);
+       if(!ok || tid=="")return;
+       MTicket tick(req,tid);
+       if(!tick.isValid()){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a valid ticket."));
+               return;
+       }
+       //check state
+       if(tick.status()!=MTicket::Bought && tick.status()!=MTicket::Reserved){
+               QMessageBox::warning(this,tr("Warning"),tr("This ticket cannot be returned, it has already been used or is in the wrong state."));
+               return;
+       }
+       //submit
+       QString r=tick.ticketReturn();
+       if(r!="")QMessageBox::warning(this,tr("Warning"),trUtf8(r.toUtf8()));*/
+}
+
+void MOverview::voucherReturn()
+{/*TODO
+       //get ticket
+       bool ok;
+       QString tid=QInputDialog::getText(this,tr("Return Voucher"),tr("Please enter the voucher ID to return:"),QLineEdit::Normal,"",&ok);
+       if(!ok || tid=="")return;
+       MVoucher vouc(req,tid);
+       if(!vouc.isValid()){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a valid voucher."));
+               return;
+       }
+       //check state
+       if(vouc.isUsed()){
+               QMessageBox::warning(this,tr("Warning"),tr("This voucher cannot be returned, it has already been used."));
+               return;
+       }
+       //submit
+       QString r=vouc.voucherReturn();
+       if(r!="")QMessageBox::warning(this,tr("Warning"),trUtf8(r.toUtf8()));*/
+}
+
+void MOverview::deductVoucher()
+{/*TODO
+       //get voucher ID and amount
+       QDialog d;
+       d.setWindowTitle(tr("Deduct from Voucher"));
+       QGridLayout *gl;
+       d.setLayout(gl=new QGridLayout);
+       gl->addWidget(new QLabel(tr("Using a voucher to pay outside the system.")),0,0,1,2);
+       
+       QLineEdit*vid;
+       MCentSpinBox*cent;
+       gl->addWidget(new QLabel(tr("Amount to deduct:")),1,0);
+       gl->addWidget(cent=new MCentSpinBox,1,1);
+       gl->addWidget(new QLabel(tr("Voucher ID:")),2,0);
+       gl->addWidget(vid=new QLineEdit,2,1);
+       
+       gl->setRowMinimumHeight(3,15);
+       QHBoxLayout*hl;
+       gl->addLayout(hl=new QHBoxLayout,4,0,1,2);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("OK")));
+       connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")));
+       connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+       if(d.exec()!=QDialog::Accepted)return;
+       if(vid->text().trimmed()=="" || cent->value()<=0)return;
+       //query server
+       QByteArray r=vid->text().trimmed().toAscii()+"\n"+QString::number(cent->value()).toAscii();
+       if(!req->request("usevoucheroutside",r)){
+               QMessageBox::warning(this,tr("Warning"),tr("Request failed."));
+               return;
+       }
+       if(req->responseStatus()!=MSInterface::Ok){
+               QMessageBox::warning(this,tr("Warning"),tr("Request failed."));
+               return;
+       }
+       QStringList sl=QString::fromAscii(req->responseBody().trimmed()).split("\n");
+       int tak=-1,rem=-1;
+       if(sl.size()>0)tak=sl[0].trimmed().toInt();
+       if(sl.size()>1)rem=sl[1].trimmed().toInt();
+       QMessageBox::information(this,tr("Deducted from Voucher"),tr("Value taken from voucher: %1\nValue remaining on voucher: %2").arg(cent2str(tak)).arg(cent2str(rem)));*/
+}
+
+void MOverview::refreshData()
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       if(set.value("refreshEvents",false).toBool() && req->hasRole("geteventlist"))
+               updateEvents();
+       if(set.value("refreshUsers",false).toBool() && req->hasRole("getusers"))
+               updateUsers();
+       if(set.value("refreshHosts",false).toBool() && req->hasRole("gethosts"))
+               updateHosts();
+       if(set.value("refreshShipping",false).toBool() && req->hasRole("getshipping"))
+               updateShipping();
+}
+
+void MOverview::setRefresh()
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       //dialog
+       QDialog d;
+       d.setWindowTitle(tr("Refresh Settings"));
+       QVBoxLayout*vl;
+       QHBoxLayout*hl;
+       d.setLayout(vl=new QVBoxLayout);
+       vl->addLayout(hl=new QHBoxLayout);
+       hl->addWidget(new QLabel(tr("Refresh Rate (minutes):")),1);
+       QSpinBox*rate;
+       hl->addWidget(rate=new QSpinBox,0);
+       rate->setRange(1,999);
+       rate->setValue(set.value("refresh",300).toInt()/60);
+       QCheckBox *rev,*rus,*rho,*rsh;
+       vl->addWidget(rev=new QCheckBox(tr("refresh &event list")));
+       rev->setChecked(set.value("refreshEvents",false).toBool());
+       vl->addWidget(rus=new QCheckBox(tr("refresh &user list")));
+       rus->setChecked(set.value("refreshUsers",false).toBool());
+       vl->addWidget(rho=new QCheckBox(tr("refresh &host list")));
+       rho->setChecked(set.value("refreshHosts",false).toBool());
+       vl->addWidget(rsh=new QCheckBox(tr("refresh &shipping list")));
+       rho->setChecked(set.value("refreshShipping",false).toBool());
+       vl->addSpacing(15);
+       vl->addStretch(10);
+       vl->addLayout(hl=new QHBoxLayout);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("&OK")));
+       connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("&Cancel")));
+       connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+       if(d.exec()!=QDialog::Accepted)return;
+       //write settings
+       set.setValue("refreshEvents",rev->isChecked());
+       set.setValue("refreshUsers",rus->isChecked());
+       set.setValue("refreshHosts",rho->isChecked());
+       set.setValue("refreshShipping",rsh->isChecked());
+       set.setValue("refresh",rate->value()*60);
+       //reset timer
+       rtimer.stop();
+       rtimer.setInterval(rate->value()*60000);
+       rtimer.start();
+}
+
+void MOverview::webSettings(bool showdlg)
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       //get settings
+       MSInterface::LogLevel lvl=MSInterface::LogLevel(set.value("webloglevel", MSInterface::LogOnError).toInt());
+       int timeout=set.value("webtimeout",30).toInt();
+       //dialog
+       if(showdlg){
+               QDialog d;
+               d.setWindowTitle(tr("Server Access Settings"));
+               QGridLayout*gl;
+               QHBoxLayout*hl;
+               d.setLayout(gl=new QGridLayout);
+               gl->addWidget(new QLabel(tr("Request Timeout (seconds):")),0,0);
+               QSpinBox*tmout;
+               gl->addWidget(tmout=new QSpinBox,0,1);
+               tmout->setRange(10,999);
+               tmout->setValue(timeout);
+               QComboBox *log;
+               gl->addWidget(new QLabel(tr("Log Level:")),1,0);
+               gl->addWidget(log=new QComboBox,1,1);
+               log->addItem(tr("Minimal Logging"),MSInterface::LogMinimal);
+               log->addItem(tr("Log Details on Error"),MSInterface::LogOnError);
+               log->addItem(tr("Always Log Details"),MSInterface::LogDetailed);
+               switch(lvl){
+                       case MSInterface::LogMinimal:log->setCurrentIndex(0);break;
+                       case MSInterface::LogOnError:log->setCurrentIndex(1);break;
+                       case MSInterface::LogDetailed:log->setCurrentIndex(2);break;
+               }
+               gl->setRowMinimumHeight(2,15);
+               gl->addLayout(hl=new QHBoxLayout,3,0,1,2);
+               hl->addStretch(10);
+               QPushButton*p;
+               hl->addWidget(p=new QPushButton(tr("&OK")));
+               connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+               hl->addWidget(p=new QPushButton(tr("&Cancel")));
+               connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+               if(d.exec()!=QDialog::Accepted)return;
+               //write settings
+               lvl=MSInterface::LogLevel(log->itemData(log->currentIndex()).toInt());
+               timeout=tmout->value();
+               set.setValue("webloglevel",lvl);
+               set.setValue("webtimeout",timeout);
+       }
+       //reset webrequest
+       req->setLogLevel(lvl);
+       req->setWebTimeout(timeout*1000);
+}
+
+void MOverview::doBackup()
+{
+       baktimer.stop();
+       //sanity check
+       if(!req->hasRight(req->RBackup))return;
+       //get settings
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       QString path=set.value("backupfile",req->dataDir()+"/backup").toString();
+       int gens=set.value("backupgenerations",3).toInt();
+       //get data
+       MTBackup bc;
+       bc=MTBackup::query();
+       if(bc.stage()!=bc.Success){
+               QMessageBox::warning(this,tr("Warning"),tr("Backup failed with error (%2): %1").arg(bc.errorString()).arg(bc.errorType()));
+               return;
+       }
+       if(bc.getbackup().isNull()||bc.getbackup().value().isEmpty()){
+               QMessageBox::warning(this,tr("Warning"),tr("Backup returned empty."));
+               return;
+       }
+       //rotate files
+       QFile(path+"."+QString::number(gens)).remove();
+       for(int i=gens-1;i>=0;i--){
+               if(i)
+                       QFile(path+"."+QString::number(i)).rename(path+"."+QString::number(i+1));
+               else
+                       QFile(path).rename(path+".1");
+       }
+       //store new data
+       QFile fd(path);
+       if(fd.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+               fd.write(bc.getbackup().value().toAscii());
+               fd.close();
+               set.setValue("backuptime",QDateTime::currentDateTime().toTime_t());
+               QMessageBox::information(this,tr("Backup"),tr("The backup was successful."));
+               int tm=set.value("backupinterval",0).toInt()*86400000;
+               if(tm)baktimer.start(tm);
+       }else
+               QMessageBox::warning(this,tr("Warning"),tr("Cannot create backup file."));
+}
+
+void MOverview::backupSettings()
+{
+       //show dialog
+       MBackupDialog d(this,profilekey);
+       d.exec();
+       //reset timer
+       int btm=QSettings().value("profiles/"+profilekey+"/backupinterval",0).toInt()*86400;
+       if(btm){
+               //adjust for last backup time
+               int iv=QDateTime::currentDateTime().toTime_t() - QSettings().value("profiles/"+profilekey+"/backuptime",0).toInt();
+               if(iv>=btm)btm=0;
+               else btm-=iv;
+               //start timer
+               baktimer.start(btm*1000);
+       }
+}
+
+void MOverview::moneylogVoucher()
+{/*TODO
+       QString vid=QInputDialog::getText(this,tr("Voucher ID"),tr("Please enter voucher ID to show log:"));
+       if(vid!="")
+               MMoneyLog(this,req,"voucher\n"+vid).exec();*/
+}
+
+void MOverview::moneylogUser()
+{/*TODO
+       QString vid=QInputDialog::getText(this,tr("User"),tr("Please enter login name of user to show log:"));
+       if(vid!="")
+               MMoneyLog(this,req,"user\n"+vid).exec();*/
+}
+
+
+/**********************************************/
+
+MBackupDialog::MBackupDialog(QWidget*par,QString pk)
+       :QDialog(par),profilekey(pk)
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       QString path=set.value("backupfile",req->dataDir()+"/backup").toString();
+       int gens=set.value("backupgenerations",3).toInt();
+       int tm=set.value("backupinterval",0).toInt();
+       //dialog
+       setWindowTitle(tr("Backup Settings"));
+       QGridLayout*gl;
+       QHBoxLayout*hl;
+       setLayout(gl=new QGridLayout);
+       QPushButton*p;
+       gl->addWidget(new QLabel(tr("Backup File:")),0,0);
+       gl->addWidget(lpath=new QLineEdit(path),0,1);
+       gl->addWidget(p=new QPushButton(tr("...")),0,2);
+       connect(p,SIGNAL(clicked()),this,SLOT(getpath()));
+       
+       gl->addWidget(new QLabel(tr("Generations to keep:")),1,0);
+       gl->addWidget(gener=new QSpinBox,1,1,1,2);
+       gener->setRange(1,16);
+       gener->setValue(gens);
+       
+       gl->addWidget(new QLabel(tr("Automatic Backup:")),2,0);
+       gl->addWidget(autob=new QCheckBox,2,1,1,2);
+       autob->setChecked(tm>0);
+       
+       gl->addWidget(new QLabel(tr("Interval in days:")),3,0);
+       gl->addWidget(interv=new QSpinBox,3,1,1,2);
+       interv->setRange(1,24);
+       interv->setValue(tm>0?tm:1);
+       
+       gl->setRowMinimumHeight(4,15);
+       gl->addLayout(hl=new QHBoxLayout,5,0,1,3);
+       hl->addStretch(10);
+       hl->addWidget(p=new QPushButton(tr("&OK")));
+       connect(p,SIGNAL(clicked()),this,SLOT(accept()));
+       connect(p,SIGNAL(clicked()),this,SLOT(save()));
+       hl->addWidget(p=new QPushButton(tr("&Cancel")));
+       connect(p,SIGNAL(clicked()),this,SLOT(reject()));
+}
+
+void MBackupDialog::getpath()
+{
+       QString path=QFileDialog::getSaveFileName(this,tr("Backup File"),lpath->text());
+       if(path!="")lpath->setText(path);
+}
+
+void MBackupDialog::save()
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       set.setValue("backupfile",lpath->text());
+       set.setValue("backupgenerations",gener->value());
+       set.setValue("backupinterval",autob->isChecked()?interv->value():0);
+}
+/**********************************************/
+
+MPasswordChange::MPasswordChange(QWidget*par,QString user)
+       :QDialog(par)
+{
+       oldpwd=newpwd1=newpwd2=0;
+       if(user=="")
+               setWindowTitle(tr("Change my password"));
+       else
+               setWindowTitle(tr("Reset password of user \"%1\"").arg(user));
+       QGridLayout*gl;
+       setLayout(gl=new QGridLayout);
+       if(user==""){
+               gl->addWidget(new QLabel(tr("Old Password:")),0,0);
+               gl->addWidget(oldpwd=new QLineEdit,0,1);
+               oldpwd->setEchoMode(QLineEdit::Password);
+       }
+       gl->addWidget(new QLabel(tr("New Password:")),1,0);
+       gl->addWidget(newpwd1=new QLineEdit,1,1);
+       newpwd1->setEchoMode(QLineEdit::Password);
+       gl->addWidget(new QLabel(tr("Repeat Password:")),2,0);
+       gl->addWidget(newpwd2=new QLineEdit,2,1);
+       newpwd2->setEchoMode(QLineEdit::Password);
+       
+       QHBoxLayout*hl;
+       gl->addLayout(hl=new QHBoxLayout,3,0,1,2);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Set Password")));
+       connect(p,SIGNAL(clicked()),this,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")));
+       connect(p,SIGNAL(clicked()),this,SLOT(reject()));
+}
+
+QString MPasswordChange::oldPassword()
+{
+       if(oldpwd)return oldpwd->text();
+       return "";
+}
+
+QString MPasswordChange::newPassword()
+{
+       if(newpwd1==0 || newpwd2==0)return "";
+       if(newpwd1->text()!=newpwd2->text())return "";
+       return newpwd1->text();
+}
+
+
+/********************************************************************************/
+
+MCartTableDelegate::MCartTableDelegate(QObject*p)
+       :QItemDelegate(p)
+{
+}
+
+QWidget *MCartTableDelegate::createEditor(QWidget *parent,
+        const QStyleOptionViewItem &/* option */,
+        const QModelIndex & index ) const
+{
+       //base class
+       if(index.column()!=0)return 0;
+       
+       QSpinBox *editor = new QSpinBox(parent);
+       editor->setRange(1,1000);
+       editor->installEventFilter(const_cast<MCartTableDelegate*>(this));
+       return editor;
+}
+
+void MCartTableDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
+{
+       //name field
+       int c=index.column();
+       if(c==0)
+               ((QSpinBox*)editor)->setValue(index.model()->data(index).toInt());
+}
+
+void MCartTableDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
+       const QModelIndex &index) const
+{
+       //name field
+       int c=index.column();
+       if(c==0){
+               int newval=((QSpinBox*)editor)->value();
+               model->setData(index,newval);
+       }
+}
diff --git a/src/mwin/acltabs.h b/src/mwin/acltabs.h
new file mode 100644 (file)
index 0000000..dfd5a43
--- /dev/null
@@ -0,0 +1,235 @@
+//
+// C++ Interface: overview
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2007
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef MAGICSMOKE_OVERVIEW_H
+#define MAGICSMOKE_OVERVIEW_H
+
+#include <QDateTime>
+#include <QDialog>
+#include <QItemDelegate>
+#include <QMainWindow>
+#include <QTimer>
+
+#include "customer.h"
+
+class QAction;
+class QCheckBox;
+class QComboBox;
+class QLabel;
+class QLineEdit;
+class QPushButton;
+class QSpinBox;
+class QStandardItemModel;
+class QTabWidget;
+class QTableView;
+
+class MSInterface;
+
+/**Main Overview Window*/
+class MOverview:public QMainWindow
+{
+       Q_OBJECT
+       public:
+               /**construct the window with web-request/session handler and QSettings-key for current profile*/
+               MOverview(QString);
+               ~MOverview();
+       protected:
+               /**handle closing the window: close the session too*/
+               void closeEvent(QCloseEvent*);
+       private slots:
+               /**try to log in again*/
+               void relogin();
+               
+               /**create a new event*/
+               void newEvent();
+               /**edit existing event*/
+               void editEvent();
+               /**update list of events*/
+               void updateEvents();
+               /**order ticket from event tab*/
+               void eventOrderTicket();
+               /**open event summary*/
+               void eventSummary();
+               /**cancel the event*/
+               void eventCancel();
+               
+               /**update shipping info*/
+               void updateShipping();
+               
+               /**get all orders, update list*/
+               void updateOrders();
+               /**open order detail window*/
+               void orderDetails();
+               
+               /**update list of users*/
+               void updateUsers();
+               /**create new user*/
+               void newUser();
+               /**delete selected user*/
+               void deleteUser();
+               /**set users description*/
+               void editUserDescription();
+               /**set users roles*/
+               void editUserRoles();
+               /**set users hosts*/
+               void editUserHosts();
+               /**set my own password*/
+               void setMyPassword();
+               /**set a users password*/
+               void setUserPassword();
+               
+               /**update list of hosts*/
+               void updateHosts();
+               /**create new host*/
+               void newHost();
+               /**create a database entry for this host*/
+               void addThisHost();
+               /**delete a host*/
+               void deleteHost();
+               /**generate a new key*/
+               void changeHostKey();
+               /**import host from file*/
+               void importHost();
+               /**export host to file*/
+               void exportHost();
+               
+               /**decide what customer to use*/
+               void setCustomer();
+               /**initialize cart tab*/
+               void initCart();
+               /**add a ticket to the cart*/
+               void cartAddTicket();
+               /**add a voucher to the cart*/
+               void cartAddVoucher();
+               /**remove item from the cart*/
+               void cartRemoveItem();
+               /**check the order on the server*/
+               void cartOrder();
+               
+               /**manage customers*/
+               void customerMgmt();
+               
+               /**edit shipping options*/
+               void editShipping();
+               
+               /**generic check which tab is active*/
+               void tabChanged();
+               
+               /**react on entry in Entrance tab*/
+               void entranceValidate();
+               
+               /**return a ticket*/
+               void ticketReturn();
+               /**return a voucher*/
+               void voucherReturn();
+               /**find an order by ticket*/
+               void orderByTicket();
+               /**find/select orders by event*/
+               void orderByEvent();
+               /**find/select orders by customer*/
+               void orderByCustomer();
+               /**find and display order by order ID*/
+               void orderByOrder();
+               /**deduct some money from a voucher (to pay outside the system)*/
+               void deductVoucher();
+               
+               /**money log for voucher*/
+               void moneylogVoucher();
+               /**money log for user*/
+               void moneylogUser();
+               
+               /**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);
+               
+               /**do a backup now*/
+               void doBackup();
+               
+               /**settings for backup*/
+               void backupSettings();
+               
+       private:
+               //the profile associated with this session
+               QString profilekey;
+               //widgets
+               QTabWidget*tab;
+               QWidget*eventtab,*carttab,*usertab,*hosttab,*ordertab,*entrancetab;
+               QTableView*eventtable,*usertable,*hosttable,*carttable,*ordertable;
+               QStandardItemModel*eventmodel,*usermodel,*hostmodel,*cartmodel,*ordermodel;
+               QPushButton*thishostbutton;
+               QLabel*cartcustomer,*entrancelabel;
+               QTextEdit *cartaddr,*cartcomment;
+               QComboBox*ordermode,*cartship,*entranceevent;
+               QLineEdit*entrancescan;
+               //event list
+               QAction*showoldevents;
+               //cart
+               MCustomer customer;
+               //barcode cache
+               QString lastbarcode;
+               QDateTime lastbcscan;
+               //refresh timers
+               QTimer rtimer,baktimer;
+};
+
+/**Helper dialog for changing passwords*/
+class MPasswordChange:public QDialog
+{
+       Q_OBJECT
+       public:
+               /**creates a password change dialog, if user is empty it is presumed to change own password*/
+               MPasswordChange(QWidget*parent,QString user=QString());
+               
+               /**if own password: return old password*/
+               QString oldPassword();
+               /**returns new password, or empty if the two lines don't match*/
+               QString newPassword();
+       private:
+               QLineEdit *oldpwd,*newpwd1,*newpwd2;
+};
+
+/**Helper class for shopping cart: allow editing amount, but nothing else*/
+class MCartTableDelegate:public QItemDelegate
+{
+       public:
+               MCartTableDelegate(QObject *parent = 0);
+               
+               QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
+                                     const QModelIndex &index) const;
+               
+               void setEditorData(QWidget *editor, const QModelIndex &index) const;
+               void setModelData(QWidget *editor, QAbstractItemModel *model,
+                                 const QModelIndex &index) const;
+};
+
+/**Helper class for Backup settings*/
+class MBackupDialog:public QDialog
+{
+       Q_OBJECT
+       public:
+               MBackupDialog(QWidget*,QString);
+               
+       private slots:
+               void getpath();
+               void save();
+       private:
+               QLineEdit*lpath;
+               QSpinBox*interv,*gener;
+               QCheckBox*autob;
+               QString profilekey;
+};
+
+#endif
diff --git a/src/mwin/carttab.cpp b/src/mwin/carttab.cpp
new file mode 100644 (file)
index 0000000..33d9424
--- /dev/null
@@ -0,0 +1,1753 @@
+//
+// C++ Implementation: overview
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2007
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "centbox.h"
+#include "checkdlg.h"
+#include "eventedit.h"
+#include "eventsummary.h"
+#include "main.h"
+#include "misc.h"
+#include "moneylog.h"
+#include "msinterface.h"
+#include "orderwin.h"
+#include "overview.h"
+
+#include <QApplication>
+#include <QBoxLayout>
+#include <QCheckBox>
+#include <QComboBox>
+#include <QCryptographicHash>
+#include <QDomDocument>
+#include <QDomElement>
+#include <QFile>
+#include <QFileDialog>
+#include <QFrame>
+#include <QInputDialog>
+#include <QLabel>
+#include <QMenu>
+#include <QMenuBar>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QSettings>
+#include <QSpinBox>
+#include <QStandardItemModel>
+#include <QStatusBar>
+#include <QTabWidget>
+#include <QTableView>
+#include <QTextEdit>
+
+#define ORDERNONE      0
+#define ORDERALL       0xff
+#define ORDEROPEN      0xf
+#define ORDERPAY       1
+#define ORDERREFUND    2
+#define ORDERUNSENT    4
+#define ORDERRESERVE   8
+
+#define req (MSInterface::instance())
+
+MOverview::MOverview(QString pk)
+{
+       profilekey=pk;
+       setAttribute(Qt::WA_DeleteOnClose);
+       setWindowTitle("MagicSmoke: "+req->currentUser()+"@"+QSettings().value("profiles/"+pk+"/name").toString());
+       rtimer.setInterval(QSettings().value("profiles/"+pk+"/refresh",300).toInt()*1000);
+       rtimer.start();
+       connect(&rtimer,SIGNAL(timeout()),this,SLOT(refreshData()));
+       //check backup timing
+       int btm=QSettings().value("profiles/"+pk+"/backupinterval",0).toInt()*86400;
+       if(btm){
+               //adjust for last backup time
+               int iv=QDateTime::currentDateTime().toTime_t() - QSettings().value("profiles/"+pk+"/backuptime",0).toInt();
+               if(iv>=btm)btm=0;
+               else btm-=iv;
+               //earliest allowed backup is 30s from now
+               if(btm<30)btm=30;
+               //start timer
+               baktimer.start(btm*1000);
+               connect(&baktimer,SIGNAL(timeout()),this,SLOT(doBackup()));
+       }
+       
+       //menu
+       QMenuBar*mb=menuBar();
+       QMenu*m=mb->addMenu(tr("&Session"));
+       m->addAction(tr("&Re-Login"),this,SLOT(relogin()));
+       m->addAction(tr("Change my &Password"),this,SLOT(setMyPassword()))
+        ->setEnabled(req->hasRight(req->RChangeMyPassword));
+       m->addSeparator();
+       m->addAction(tr("&Edit Templates..."),req,SLOT(editTemplates()));
+       m->addAction(tr("&Update Templates Now"),req,SLOT(updateTemplates()));
+       m->addSeparator();
+       m->addAction(tr("&Close Session"),this,SLOT(close()));
+       
+       m=mb->addMenu(tr("&Event"));
+       m->addAction(tr("&Update Event List"),this,SLOT(updateEvents()))
+        ->setEnabled(req->hasRight(req->RGetAllEvents));
+       m->addAction(tr("&Show/Edit details..."),this,SLOT(editEvent()))
+        ->setEnabled(req->hasRight(req->RGetEvent));
+       m->addAction(tr("&New Event..."),this,SLOT(newEvent()))->setEnabled(req->hasRole("createevent"));
+       m->addSeparator();
+       showoldevents=m->addAction(tr("Show &old Events"),this,SLOT(updateEvents()));
+       showoldevents->setEnabled(req->hasRight(req->RGetAllEvents));
+       showoldevents->setCheckable(true);
+       showoldevents->setChecked(QSettings().value("profiles/"+pk+"/showOldEvents",false).toBool());
+       
+       m=mb->addMenu(tr("&Customer"));
+       m->addAction(tr("&Show all customers"),this,SLOT(customerMgmt()));
+       
+       m=mb->addMenu(tr("C&art"));
+       m->addAction(tr("Add &Ticket"),this,SLOT(cartAddTicket()));
+       m->addAction(tr("Add &Voucher"),this,SLOT(cartAddVoucher()));
+       m->addAction(tr("&Remove Item"),this,SLOT(cartRemoveItem()));
+       m->addAction(tr("&Abort Shopping"),this,SLOT(initCart()));
+       m->addSeparator();
+       m->addAction(tr("&Update Shipping Options"),this,SLOT(updateShipping()));
+       
+       m=mb->addMenu(tr("&Misc"));
+       m->addAction(tr("Return &ticket..."),this,SLOT(ticketReturn()));
+       m->addAction(tr("Return &voucher..."),this,SLOT(voucherReturn()));
+       m->addSeparator();
+       m->addAction(tr("Edit &Shipping Options..."),this,SLOT(editShipping()));
+       m->addSeparator();
+       m->addAction(tr("&Deduct from voucher..."),this,SLOT(deductVoucher()));
+       m->addSeparator();
+       m->addAction(tr("&Money Log for voucher..."),this,SLOT(moneylogVoucher()));
+       m->addAction(tr("Money Log for &user..."),this,SLOT(moneylogUser()));
+       
+       m=mb->addMenu(tr("C&onfigure"));
+       m->addAction(tr("&Auto-Refresh settings..."),this,SLOT(setRefresh()));
+       m->addAction(tr("&Server Access settings..."),this,SLOT(webSettings()));
+       
+       m=mb->addMenu(tr("&Admin"));
+       m->addAction(tr("Backup &Settings..."),this,SLOT(backupSettings()))
+        ->setEnabled(req->hasRight(req->RBackup));
+       m->addAction(tr("&Backup now..."),this,SLOT(doBackup()))
+        ->setEnabled(req->hasRight(req->RBackup));
+
+       mb->addMenu(MApplication::helpMenu());
+       
+       //tabs
+       setCentralWidget(tab=new QTabWidget);
+       connect(tab,SIGNAL(currentChanged(int)),this,SLOT(tabChanged()));
+       
+       //Event tab
+       tab->addTab(eventtab=new QWidget,tr("Events"));
+       QVBoxLayout*vl;QHBoxLayout*hl;
+       eventtab->setLayout(hl=new QHBoxLayout);
+       hl->addWidget(eventtable=new QTableView,10);
+       eventtable->setModel(eventmodel=new QStandardItemModel(this));
+       eventtable->setSelectionMode(QAbstractItemView::SingleSelection);
+       eventtable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       hl->addSpacing(5);
+       hl->addLayout(vl=new QVBoxLayout,0);
+       QPushButton*p;
+       vl->addWidget(p=new QPushButton(tr("New Event...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(newEvent()));
+       p->setEnabled(req->hasRole("createevent"));
+       vl->addWidget(p=new QPushButton(tr("Details...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editEvent()));
+       p->setEnabled(req->hasRole("geteventdata"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Order Ticket...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(eventOrderTicket()));
+       p->setEnabled(req->hasRole("createorder"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Event Summary...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(eventSummary()));
+       p->setEnabled(req->hasRole("eventsummary"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Cancel Event...")),0);
+       p->setEnabled(req->hasRole("cancelevent"));
+       connect(p,SIGNAL(clicked()),this,SLOT(eventCancel()));
+       vl->addStretch(10);
+       
+       //Shopping Cart Tab
+       tab->addTab(carttab=new QWidget,tr("Shopping Cart"));
+       carttab->setLayout(vl=new QVBoxLayout);
+       vl->addLayout(hl=new QHBoxLayout);
+       QVBoxLayout*vl2;
+       hl->addLayout(vl2=new QVBoxLayout,2);
+       vl2->addWidget(carttable=new QTableView,10);
+       carttable->setModel(cartmodel=new QStandardItemModel(this));
+       carttable->setSelectionMode(QAbstractItemView::SingleSelection);
+       carttable->setItemDelegate(new MCartTableDelegate(this));
+       QHBoxLayout*hl2;
+       vl2->addLayout(hl2=new QHBoxLayout,0);
+       hl2->addStretch(10);
+       hl2->addWidget(p=new QPushButton(tr("Add Ticket")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(cartAddTicket()));
+       hl2->addWidget(p=new QPushButton(tr("Add Voucher")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(cartAddVoucher()));
+       hl2->addWidget(p=new QPushButton(tr("Remove Item")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(cartRemoveItem()));
+       QFrame*frm;
+       hl->addWidget(frm=new QFrame,0);
+       frm->setFrameShape(QFrame::VLine);
+       hl->addLayout(vl2=new QVBoxLayout,1);
+       vl2->addWidget(p=new QPushButton(tr("Customer:")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(setCustomer()));
+       vl2->addWidget(cartcustomer=new QLabel("...\n \n \n "));
+       vl2->addWidget(frm=new QFrame,0);
+       frm->setFrameShape(QFrame::HLine);
+       vl2->addSpacing(10);
+       vl2->addWidget(new QLabel(tr("Shipping Method:")),0);
+       vl2->addWidget(cartship=new QComboBox,0);
+       cartship->setEditable(false);
+       vl2->addWidget(new QLabel(tr("Delivery Address:")),0);
+       vl2->addWidget(cartaddr=new QTextEdit);
+       vl2->addSpacing(10);
+       vl2->addWidget(new QLabel(tr("Comments:")),0);
+       vl2->addWidget(cartcomment=new QTextEdit);
+       vl2->addStretch(10);
+       vl->addWidget(frm=new QFrame,0);
+       frm->setFrameShape(QFrame::HLine);
+       vl->addLayout(hl=new QHBoxLayout,0);
+       hl->addStretch(10);
+       hl->addWidget(p=new QPushButton(tr("Check Order")));
+       p->setEnabled(req->hasRole("checkorder"));
+       connect(p,SIGNAL(clicked()),this,SLOT(cartOrder()));
+       hl->addWidget(p=new QPushButton(tr("Clear")));
+       connect(p,SIGNAL(clicked()),this,SLOT(initCart()));
+       
+       //Order List Tab
+       tab->addTab(ordertab=new QWidget,tr("Order List"));
+       ordertab->setLayout(hl=new QHBoxLayout);
+       hl->addLayout(vl=new QVBoxLayout,10);
+       vl->addWidget(ordermode=new QComboBox,0);
+       ordermode->addItem(tr("-select mode-"),ORDERNONE);
+       ordermode->addItem(tr("All Orders"),ORDERALL);
+       ordermode->addItem(tr("Open Orders"),ORDEROPEN);
+       ordermode->addItem(tr("Open Reservations"),ORDERRESERVE);
+       ordermode->addItem(tr("Outstanding Payments"),ORDERPAY);
+       ordermode->addItem(tr("Outstanding Refunds"),ORDERREFUND);
+       ordermode->addItem(tr("Undelivered Orders"),ORDERUNSENT);
+       //make sure this entry is the last one, since we use count()-1 to select it
+       ordermode->addItem(tr("-search result-"),ORDERNONE);
+       connect(ordermode,SIGNAL(currentIndexChanged(int)),this,SLOT(updateOrders()));
+       vl->addWidget(ordertable=new QTableView);
+       ordertable->setModel(ordermodel=new QStandardItemModel(this));
+       ordertable->setSelectionMode(QAbstractItemView::SingleSelection);
+       ordertable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       connect(ordertable,SIGNAL(doubleClicked(const QModelIndex&)),this,SLOT(orderDetails()));
+       hl->addLayout(vl=new QVBoxLayout,0);
+       vl->addWidget(p=new QPushButton(tr("Update")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(updateOrders()));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Details...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderDetails()));
+       p->setEnabled(req->hasRole("getorder"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Find by Ticket...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderByTicket()));
+       p->setEnabled(req->hasRole("orderbyticket"));
+       vl->addWidget(p=new QPushButton(tr("Find by Event...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderByEvent()));
+       p->setEnabled(req->hasRole("getordersbyevents"));
+       vl->addWidget(p=new QPushButton(tr("Find by Customer...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderByCustomer()));
+       p->setEnabled(req->hasRole("getorderlist"));
+       vl->addWidget(p=new QPushButton(tr("Find by Order ID...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderByOrder()));
+       p->setEnabled(req->hasRole("getorder"));
+       vl->addStretch(10);
+       
+       //Entrance Control Tab
+       tab->addTab(entrancetab=new QWidget,tr("Entrance"));
+       entrancetab->setLayout(vl=new QVBoxLayout);
+       vl->addWidget(entranceevent=new QComboBox,0);
+       entranceevent->setEditable(false);
+       vl->addSpacing(30);
+       vl->addWidget(new QLabel(tr("Enter or scan Ticket-ID:")),0);
+       vl->addWidget(entrancescan=new QLineEdit,0);
+       connect(entrancescan,SIGNAL(editingFinished()),this,SLOT(entranceValidate()));
+       vl->addWidget(entrancelabel=new QLabel("  "),10);
+       entrancelabel->setAutoFillBackground(true);
+       QFont fnt=entrancelabel->font();
+       fnt.setBold(true);fnt.setPointSize(24);
+       entrancelabel->setFont(fnt);
+       entrancelabel->setAlignment(Qt::AlignCenter);
+       
+       //user tab
+       tab->addTab(usertab=new QWidget,tr("Users"));
+       usertab->setLayout(hl=new QHBoxLayout);
+       hl->addWidget(usertable=new QTableView,10);
+       usertable->setModel(usermodel=new QStandardItemModel(this));
+       usertable->setSelectionMode(QAbstractItemView::SingleSelection);
+       usertable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       hl->addSpacing(5);
+       hl->addLayout(vl=new QVBoxLayout,0);
+       vl->addWidget(p=new QPushButton(tr("New User...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(newUser()));
+       p->setEnabled(req->hasRole("adduser"));
+       vl->addWidget(p=new QPushButton(tr("Delete User...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(deleteUser()));
+       p->setEnabled(req->hasRole("deleteuser"));
+       vl->addSpacing(20);
+       vl->addWidget(p=new QPushButton(tr("Description...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editUserDescription()));
+       p->setEnabled(req->hasRole("setuserdescription"));
+       vl->addWidget(p=new QPushButton(tr("Hosts...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editUserHosts()));
+       p->setEnabled(req->hasRole("getuserhosts"));
+       vl->addWidget(p=new QPushButton(tr("Roles...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editUserRoles()));
+       p->setEnabled(req->hasRole("getuseracl"));
+       vl->addWidget(p=new QPushButton(tr("Set Password...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(setUserPassword()));
+       p->setEnabled(req->hasRole("setpasswd"));
+       vl->addStretch(10);
+       
+       //host tab
+       tab->addTab(hosttab=new QWidget,tr("Hosts"));
+       hosttab->setLayout(hl=new QHBoxLayout);
+       hl->addWidget(hosttable=new QTableView,10);
+       hosttable->setModel(hostmodel=new QStandardItemModel(this));
+       hosttable->setSelectionMode(QAbstractItemView::SingleSelection);
+       hosttable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       hl->addSpacing(5);
+       hl->addLayout(vl=new QVBoxLayout,0);
+       vl->addWidget(p=new QPushButton(tr("New Host...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(newHost()));
+       p->setEnabled(req->hasRole("addhost"));
+       vl->addWidget(thishostbutton=p=new QPushButton(tr("Add This Host...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(addThisHost()));
+       p->setEnabled(req->hasRole("addhost"));
+       vl->addWidget(p=new QPushButton(tr("Delete Host...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(deleteHost()));
+       p->setEnabled(req->hasRole("deletehost"));
+       vl->addSpacing(20);
+       vl->addWidget(p=new QPushButton(tr("Generate New Key...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(changeHostKey()));
+       p->setEnabled(req->hasRole("sethostkey"));
+       vl->addWidget(p=new QPushButton(tr("Import...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(importHost()));
+       p->setEnabled(req->hasRole("addhost"));
+       vl->addWidget(p=new QPushButton(tr("Export...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(exportHost()));
+       p->setEnabled(req->hasRole("gethostkey"));
+       vl->addStretch(10);
+       
+       //status bar
+       statusBar()->setSizeGripEnabled(true);
+       
+       //make sure webrequest knows its settings
+       webSettings(false);
+       //fill tables
+       if(req->hasRight(req->RGetAllEvents)){
+               updateEvents();
+       }else{
+               eventtab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(eventtab),false);
+       }
+       if(!req->hasRole("createorder")&&!req->hasRole("createsale")){
+               carttab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(carttab),false);
+       }else{
+               initCart();
+       }
+       updateShipping();
+       if(req->hasRole("getorderlist")){
+               updateOrders();
+       }else{
+               ordertab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(ordertab),false);
+       }
+       if(req->hasRole("getusers")){
+               updateUsers();
+       }else{
+               usertab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(usertab),false);
+       }
+       if(req->hasRole("gethosts")){
+               updateHosts();
+       }else{
+               hosttab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(hosttab),false);
+       }
+}
+
+void MOverview::updateEvents()
+{
+       MTGetAllEvents gae=req->queryGetAllEvents();
+       if(gae.stage()!=gae.Success){
+               qDebug("Error getting all events (%s): %s",gae.errorType().toAscii().data(),gae.errorString().toAscii().data());
+               return;
+       }
+       QList<MOEvent>evl=gae.getevents();
+       eventmodel->clear();
+       eventmodel->insertColumns(0,6);
+       eventmodel->setHorizontalHeaderLabels(QStringList()<<tr("Start Time")<<tr("Title")<<tr("Free")<<tr("Reserved")<<tr("Sold")<<tr("Capacity"));
+       QDateTime now=QDateTime::currentDateTime();
+       for(int i=0,j=0;i<evl.size();i++){
+               QDateTime stime=QDateTime::fromTime_t(evl[i].start());
+               if(stime<now && !showoldevents->isChecked())continue;
+               eventmodel->insertRow(j);
+               eventmodel->setData(eventmodel->index(j,0),evl[i].id().value(),Qt::UserRole);
+               eventmodel->setData(eventmodel->index(j,0),stime.toString(tr("ddd MMMM d yyyy, h:mm ap","time format")));
+               eventmodel->setData(eventmodel->index(j,1),evl[i].title().value());
+               eventmodel->setData(eventmodel->index(j,2),evl[i].capacity()-evl[i].amountSold()-evl[i].amountReserved());
+               eventmodel->setData(eventmodel->index(j,3),evl[i].amountReserved().value());
+               eventmodel->setData(eventmodel->index(j,4),evl[i].amountSold().value());
+               eventmodel->setData(eventmodel->index(j,5),evl[i].capacity().value());
+               j++;
+       }
+       eventtable->resizeColumnsToContents();
+       //in case this was called from changing the check state
+       QSettings().setValue("profiles/"+profilekey+"/showOldEvents",showoldevents->isChecked());
+}
+
+void MOverview::closeEvent(QCloseEvent*ce)
+{
+       //make sure session is deleted
+       req->logout();
+       //actually close window
+       QMainWindow::closeEvent(ce);
+}
+
+MOverview::~MOverview()
+{
+       //free requestor
+       req->deleteLater();
+}
+
+void MOverview::relogin()
+{
+       setEnabled(false);
+       if(!req->relogin())
+               QMessageBox::warning(this,tr("Warning"),tr("I was unable to renew the login at the server."));
+       setEnabled(true);
+}
+
+void MOverview::newEvent()
+{
+       MEventEditor ed(this);
+       ed.exec();
+       updateEvents();
+}
+
+void MOverview::editEvent()
+{
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       MEventEditor ed(this,id);
+       ed.exec();
+       updateEvents();
+}
+
+void MOverview::eventSummary()
+{
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       MEventSummary ed(this,id);
+       ed.exec();
+}
+
+void MOverview::eventCancel()
+{
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       MTGetEvent getev=MTGetEvent::query(id);
+       if(!getev.hasError()){
+               bool ok;
+               MOEvent ev=getev.getevent();
+               QString r=QInputDialog::getText(this,tr("Cancel Event"),tr("Please enter a reason to cancel event \"%1\" or abort:").arg(ev.title()),QLineEdit::Normal,"",&ok);
+               if(!ok)return;
+               MTCancelEvent cev=MTCancelEvent::query(id,r);
+               if(!cev.hasError())
+                       QMessageBox::information(this,tr("Event Cancelled"),tr("The event \"%1\" has been cancelled. Please inform everybody who bought a ticket.").arg(ev.title()));
+               else
+                       QMessageBox::warning(this,tr("Warning"),tr("Unable to cancel event \"%1\": %2.").arg(ev.title()).arg(cev.errorString()));
+       }
+}
+
+void MOverview::updateShipping()
+{
+       cartship->clear();
+       cartship->addItem(tr("(No Shipping)"),-1);
+       MTGetAllShipping sh=MTGetAllShipping::query();
+       QList<MOShipping>ship=sh.getshipping();
+       for(int i=0;i<ship.size();i++)
+               cartship->addItem(ship[i].description(),(int)ship[i].id());
+}
+
+void MOverview::updateUsers()
+{
+       MTGetAllUsers au=req->queryGetAllUsers();
+       if(au.hasError())return;
+       QList<MOUser>usl=au.getusers();
+       usermodel->clear();
+       usermodel->insertColumns(0,2);
+       usermodel->insertRows(0,usl.size());
+       usermodel->setHorizontalHeaderLabels(QStringList()<<tr("Login Name")<<tr("Description"));
+       for(int i=0;i<usl.size();i++){
+               usermodel->setData(usermodel->index(i,0),usl[i].name().value());
+               usermodel->setData(usermodel->index(i,1),usl[i].description().value());
+       }
+       usertable->resizeColumnsToContents();
+}
+
+void MOverview::newUser()
+{
+       //get name
+       QString name;
+       while(1){
+               bool ok;
+               name=QInputDialog::getText(this,tr("New User"),tr("Please enter new user name (only letters, digits, and underscore allowed):"),QLineEdit::Normal,name,&ok);
+               if(!ok)
+                       return;
+               if(QRegExp("[A-Za-z0-9_\\.,:-]+").exactMatch(name))
+                       break;
+               if(QMessageBox::warning(this,tr("Error"),tr("The user name must contain only letters, digits, dots and underscores and must be at least one character long!"),QMessageBox::Retry|QMessageBox::Abort)!=QMessageBox::Retry)
+                       return;
+       }
+       //get password
+       QString pwd=QInputDialog::getText(this,tr("Password"),tr("Please enter an initial password for the user:"),QLineEdit::Password);
+       //send request
+       req->queryCreateUser(name,pwd,"");
+       //update display
+       updateUsers();
+}
+
+void MOverview::deleteUser()
+{
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname & descr
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       //make sure user wants this
+       if(QMessageBox::question(this,tr("Delete User?"),tr("Really delete user '%1'?").arg(name),QMessageBox::Yes|QMessageBox::No)!=QMessageBox::Yes)return;
+       //get replacement
+       bool ok;
+       QStringList rplc;
+       rplc<<tr("(Nobody)","this is a username for no user, the string must contain '(' to distinguish it from the others");
+       for(int i=0;i<usermodel->rowCount();i++)
+               rplc<<usermodel->data(usermodel->index(i,0)).toString();
+       QString rp=QInputDialog::getItem(this,tr("Delete User"),tr("Select which user will inherit this users database objects:"),rplc,0,false,&ok);
+       if(!ok)return;
+       //delete
+       MTDeleteUser ret=req->queryDeleteUser(name,rp);
+       if(ret.hasError())
+               QMessageBox::warning(this,tr("Error"),tr("Cannot delete user: %1").arg(ret.errorString()));
+       updateUsers();
+}
+
+void MOverview::editUserDescription()
+{
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname & descr
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       QString descr=usermodel->data(usermodel->index(sel.row(),1)).toString();
+       //edit descr
+       bool ok;
+       descr=QInputDialog::getText(this,tr("Edit Description"),tr("Descriptionof user %1:").arg(name),QLineEdit::Normal,descr,&ok);
+       if(ok)
+               req->querySetUserDescription(name,descr);
+       //update
+       updateUsers();
+}
+
+void MOverview::editUserRoles()
+{/*TODO
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname & descr
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       //...
+       MOUser usr(req,name);
+       MCheckList acl=usr.getRoles();
+       MCheckDialog cd(this,acl,"Edit ACL of user "+name);
+       if(cd.exec()==QDialog::Accepted)
+               usr.setRoles(cd.getCheckList());*/
+}
+
+void MOverview::editUserHosts()
+{/*TODO
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname & descr
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       //...
+       MUser usr(req,name);
+       MCheckList acl=usr.getHosts();
+       MCheckDialog cd(this,acl,"Edit hosts of user "+name);
+       if(cd.exec()==QDialog::Accepted)
+               usr.setHosts(cd.getCheckList());*/
+}
+
+void MOverview::setMyPassword()
+{
+       MPasswordChange pc(this);
+       if(pc.exec()==QDialog::Accepted){
+               MTChangeMyPassword cmp=MTChangeMyPassword::query(pc.oldPassword(),pc.newPassword());
+               if(cmp.hasError())
+                       QMessageBox::warning(this,tr("Warning"),tr("Error setting password: %1").arg(cmp.errorString()));
+       }
+}
+void MOverview::setUserPassword()
+{/*TODO
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       //get new password
+       MPasswordChange pc(this,name);
+       if(pc.exec()!=QDialog::Accepted)return;
+       QString p=pc.newPassword();
+       if(p==""){
+               QMessageBox::warning(this,tr("Warning"),tr("The password must be non-empty and both lines must match"));
+               return;
+       }
+       //...
+       MUser usr(req,name);
+       usr.changePassword(p);*/
+}
+
+void MOverview::updateHosts()
+{/*TODO
+       bool foundThis=false;
+       QString thisHost=req->hostName();
+       QList<MHost>hsl=req->getAllHosts();
+       hostmodel->clear();
+       hostmodel->insertColumns(0,2);
+       hostmodel->insertRows(0,hsl.size());
+       hostmodel->setHorizontalHeaderLabels(QStringList()<<tr("Host Name")<<tr("Host Key"));
+       for(int i=0;i<hsl.size();i++){
+               hostmodel->setData(hostmodel->index(i,0),hsl[i].hostId());
+               hostmodel->setData(hostmodel->index(i,1),hsl[i].hostKey());
+               if(thisHost==hsl[i].hostId())
+                       foundThis=true;
+       }
+       hosttable->resizeColumnsToContents();
+       thishostbutton->setEnabled(!foundThis && req->hasRole("addhost"));*/
+}
+
+void MOverview::newHost()
+{/*TODO
+       //get Host Name
+       QString hname;
+       do{
+               bool ok;
+               hname=QInputDialog::getText(this,tr("Create New Host"),tr("Please enter a host name:"),QLineEdit::Normal,hname,&ok);
+               if(!ok)return;
+               if(!QRegExp("[A-Za-z][A-Za-z0-9_]*").exactMatch(hname))continue;
+       }while(false);
+       //create it
+       MHost hst(req,hname);
+       int e=hst.newKey();
+       if(e<128){
+               if(QMessageBox::warning(this,tr("Warning"),tr("The key of this new host could only be generated with %n bits entropy. Store anyway?","",e).arg(e),QMessageBox::Yes|QMessageBox::No,QMessageBox::No)!=QMessageBox::Yes)
+                       return;
+       }
+       hst.create();
+       //update
+       updateHosts();*/
+}
+
+void MOverview::addThisHost()
+{/*TODO
+       MHost hst(req,req->hostName(),QSettings().value("hostkey").toString());
+       hst.create();
+       updateHosts();*/
+}
+
+void MOverview::deleteHost()
+{/*TODO
+       //get selection
+       QModelIndex sel=hosttable->currentIndex();
+       if(!sel.isValid())return;
+       //get hname
+       QString name=hostmodel->data(hostmodel->index(sel.row(),0)).toString();
+       //ask
+       if(QMessageBox::question(this,tr("Delete this Host?"),tr("Really delete host '%1'?").arg(name),QMessageBox::Yes|QMessageBox::No)!=QMessageBox::Yes)return;
+       //delete it
+       MHost(req,name).deleteHost();
+       updateHosts();*/
+}
+
+void MOverview::changeHostKey()
+{/*TODO
+       //get selection
+       QModelIndex sel=hosttable->currentIndex();
+       if(!sel.isValid())return;
+       //get hname
+       QString name=hostmodel->data(hostmodel->index(sel.row(),0)).toString();
+       //ask
+       if(QMessageBox::question(this,tr("Change Host Key?"),tr("Really change the key of host '%1'?").arg(name),QMessageBox::Yes|QMessageBox::No)!=QMessageBox::Yes)return;
+       //change it
+       MHost hst(req,name);
+       int e=hst.newKey();
+       if(e<128){
+               if(QMessageBox::warning(this,tr("Warning"),tr("The new key of this host could only be generated with %n bits entropy. Store anyway?","",e).arg(e),QMessageBox::Yes|QMessageBox::No,QMessageBox::No)!=QMessageBox::Yes)
+                       return;
+       }
+       hst.save();
+       //update
+       updateHosts();*/
+}
+
+void MOverview::importHost()
+{/*TODO
+       QStringList fn;
+       QFileDialog fdlg(this,tr("Import Key from File"),QString(),"Magic Smoke Host Key (*.mshk)");
+       fdlg.setDefaultSuffix("mshk");
+       fdlg.setAcceptMode(QFileDialog::AcceptOpen);
+       fdlg.setFileMode(QFileDialog::ExistingFile);
+       if(!fdlg.exec())return;
+       fn=fdlg.selectedFiles();
+       if(fn.size()!=1)return;
+       QFile fd(fn[0]);
+       if(!fd.open(QIODevice::ReadOnly)){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to open file %1 for reading: %2").arg(fn[0]).arg(fd.errorString()));
+               return;
+       }
+       //read content (max: 10k to limit potential damage)
+       QStringList fc=QString::fromAscii(fd.read(10240)).split("\n",QString::SkipEmptyParts);
+       fd.close();
+       //check content
+       if(fc.size()<3){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a host key file."));
+               return;
+       }
+       if(fc[0].trimmed()!="MagicSmokeHostKey"){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a host key file."));
+               return;
+       }
+       QString hname=fc[1].trimmed();
+       if(!QRegExp("[A-Za-z][A-Za-z0-9_]*").exactMatch(hname)){
+               QMessageBox::warning(this,tr("Warning"),tr("This host key file does not contain a valid host name."));
+               return;
+       }
+       QString key=fc[2].trimmed();
+       if(!QRegExp("[0-9a-fA-F]+").exactMatch(key) || key.size()<40){
+               QMessageBox::warning(this,tr("Warning"),tr("This host key file does not contain a valid key."));
+               return;
+       }
+       QString chk=QCryptographicHash::hash(key.toAscii(),QCryptographicHash::Md5).toHex();
+       if(chk!=fc[3].trimmed()){
+               QMessageBox::warning(this,tr("Warning"),tr("The key check sum did not match. Please get a clean copy of the host key file."));
+               return;
+       }
+       //save
+       MHost hst(req,hname,key);
+       hst.create();
+       updateHosts();*/
+}
+
+void MOverview::exportHost()
+{/*TODO
+       //get selection
+       QModelIndex sel=hosttable->currentIndex();
+       if(!sel.isValid())return;
+       //get hname
+       QString name=hostmodel->data(hostmodel->index(sel.row(),0)).toString();
+       QString key=hostmodel->data(hostmodel->index(sel.row(),1)).toString();
+       if(name[0]=='_' || key==""){
+               QMessageBox::warning(this,tr("Warning"),tr("This host cannot be exported."));
+               return;
+       }
+       //save
+       QStringList fn;
+       QFileDialog fdlg(this,tr("Export Key to File"),QString(),"Magic Smoke Host Key (*.mshk)");
+       fdlg.setDefaultSuffix("mshk");
+       fdlg.setAcceptMode(QFileDialog::AcceptSave);
+       fdlg.setFileMode(QFileDialog::AnyFile);
+       if(!fdlg.exec())return;
+       fn=fdlg.selectedFiles();
+       if(fn.size()!=1)return;
+       QFile fd(fn[0]);
+       if(!fd.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to open file %1 for writing: %2").arg(fn[0]).arg(fd.errorString()));
+               return;
+       }
+       QString chk=QCryptographicHash::hash(key.toAscii(),QCryptographicHash::Md5).toHex();
+       QString out="MagicSmokeHostKey\n"+name+"\n"+key+"\n"+chk;
+       fd.write(out.toAscii());
+       fd.close();*/
+}
+
+
+void MOverview::initCart()
+{
+       //clear cart
+       cartmodel->clear();
+       cartmodel->setHorizontalHeaderLabels(QStringList()<<tr("Amount")<<tr("Title")<<tr("Start Time"));
+       //clear customer
+       customer=MCustomer();
+       cartcustomer->setText("");
+       //clear address/comment
+       cartaddr->setPlainText("");
+       cartcomment->setPlainText("");
+       //clear shipping
+       cartship->setCurrentIndex(0);
+}
+
+void MOverview::setCustomer()
+{/*TODO
+       MCustomerListDialog mcl(req,this,true,customer.customerID());
+       if(mcl.exec()!=QDialog::Accepted)return;
+       customer=mcl.getCustomer();
+       cartcustomer->setText(customer.getNameAddress());*/
+}
+
+static const int CART_TICKET=1;
+static const int CART_VOUCHER=2;
+
+static const int CART_IDROLE=Qt::UserRole;//ticket id
+static const int CART_PRICEROLE=Qt::UserRole;//voucher price
+static const int CART_VALUEROLE=Qt::UserRole+1;//voucher value
+static const int CART_TYPEROLE=Qt::UserRole+2;//which is it? ticket or voucher?
+
+void MOverview::cartAddTicket()
+{
+       //create ticket selection dialog
+       QDialog dlg;
+       dlg.setWindowTitle(tr("Select Event to order Ticket"));
+       QTableView*tv;
+       QHBoxLayout*hl;
+       QVBoxLayout*vl;
+       dlg.setLayout(vl=new QVBoxLayout);
+       vl->addWidget(tv=new QTableView,10);
+       tv->setModel(eventmodel);
+       tv->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       tv->resizeColumnsToContents();
+       vl->addSpacing(15);
+       vl->addLayout(hl=new QHBoxLayout,0);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Select")),0);
+       connect(p,SIGNAL(clicked()),&dlg,SLOT(accept()));
+       connect(tv,SIGNAL(doubleClicked(const QModelIndex&)),&dlg,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")),0);
+       connect(p,SIGNAL(clicked()),&dlg,SLOT(reject()));
+       //wait for it
+       if(dlg.exec()==QDialog::Accepted){
+               //get selection
+               QModelIndex idx=tv->currentIndex();
+               if(!idx.isValid())return;
+               int id=eventmodel->data(eventmodel->index(idx.row(),0),Qt::UserRole).toInt();
+               if(id<0)return;
+               //copy to cart
+               int cr=cartmodel->rowCount();
+               cartmodel->insertRows(cr,1);
+               cartmodel->setData(cartmodel->index(cr,0),1);
+               cartmodel->setData(cartmodel->index(cr,0),id,CART_IDROLE);
+               cartmodel->setData(cartmodel->index(cr,0),CART_TICKET,CART_TYPEROLE);
+               cartmodel->setData(cartmodel->index(cr,1),eventmodel->data(eventmodel->index(idx.row(),1)));
+               cartmodel->setData(cartmodel->index(cr,2),eventmodel->data(eventmodel->index(idx.row(),0)));
+               carttable->resizeColumnsToContents();
+       }
+}
+
+void MOverview::eventOrderTicket()
+{
+       //get selected event
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       //activate order tab
+       tab->setCurrentWidget(carttab);
+       //insert event into table
+       int cr=cartmodel->rowCount();
+       cartmodel->insertRows(cr,1);
+       cartmodel->setData(cartmodel->index(cr,0),1);
+       cartmodel->setData(cartmodel->index(cr,0),id,CART_IDROLE);
+       cartmodel->setData(cartmodel->index(cr,0),CART_TICKET,CART_TYPEROLE);
+       cartmodel->setData(cartmodel->index(cr,1),eventmodel->data(eventmodel->index(ilst[0].row(),1)));
+       cartmodel->setData(cartmodel->index(cr,2),eventmodel->data(eventmodel->index(ilst[0].row(),0)));
+       carttable->resizeColumnsToContents();
+}
+
+void MOverview::cartAddVoucher()
+{/*TODO
+       //create voucher selection dialog
+       QDialog dlg;
+       dlg.setWindowTitle(tr("Select Voucher"));
+       QComboBox*cp,*cv;
+       QHBoxLayout*hl;
+       QGridLayout*gl;
+       QStandardItemModel mdl;
+       QRegExpValidator regv(priceRegExp(),this);
+       QList<int>prc=req->getVoucherPrices();
+       mdl.insertRows(0,prc.size());
+       mdl.insertColumns(0,1);
+       for(int i=0;i<prc.size();i++)mdl.setData(mdl.index(i,0),cent2str(prc[i]));
+       dlg.setLayout(gl=new QGridLayout);
+       gl->addWidget(new QLabel(tr("Select voucher price and value:")),0,0,1,2);
+       if(req->hasRole("_anypricevoucher")){
+               gl->addWidget(new QLabel(tr("Price:")),1,0);
+               gl->addWidget(cp=new QComboBox,1,1);
+               cp->setModel(&mdl);
+               cp->setEditable(true);
+               cp->setValidator(&regv);
+       }else cp=0;
+       gl->addWidget(new QLabel(tr("Value:")),2,0);
+       gl->addWidget(cv=new QComboBox,2,1);
+       cv->setModel(&mdl);
+       cv->setEditable(req->hasRole("_anyvoucher"));
+       cv->setValidator(&regv);
+       gl->setRowMinimumHeight(3,15);
+       gl->setColumnStretch(0,0);
+       gl->setColumnStretch(1,1);
+       gl->setRowStretch(3,1);
+       gl->addLayout(hl=new QHBoxLayout,4,0,1,2);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Ok")),0);
+       connect(p,SIGNAL(clicked()),&dlg,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")),0);
+       connect(p,SIGNAL(clicked()),&dlg,SLOT(reject()));
+       //wait for it
+       if(dlg.exec()==QDialog::Accepted){
+               //get selection
+               int price,value;
+               value=str2cent(cv->currentText());
+               if(req->hasRole("_anypricevoucher") && cp)
+                       price=str2cent(cp->currentText());
+               else
+                       price=value;
+               //copy to cart
+               int cr=cartmodel->rowCount();
+               cartmodel->insertRows(cr,1);
+               cartmodel->setData(cartmodel->index(cr,0),1);
+               cartmodel->setData(cartmodel->index(cr,0),price,CART_PRICEROLE);
+               cartmodel->setData(cartmodel->index(cr,0),value,CART_VALUEROLE);
+               cartmodel->setData(cartmodel->index(cr,0),CART_VOUCHER,CART_TYPEROLE);
+               cartmodel->setData(cartmodel->index(cr,1),tr("Voucher (price: %1, value %2)").arg(cent2str(price)).arg(cent2str(value)));
+               carttable->resizeColumnsToContents();
+       }*/
+}
+
+void MOverview::cartRemoveItem()
+{
+       //get selection
+       QModelIndex idx=carttable->currentIndex();
+       if(!idx.isValid())return;
+       //remove row
+       cartmodel->removeRow(idx.row());
+}
+
+void MOverview::cartOrder()
+{
+       //sanity checks
+       if(cartmodel->rowCount()<1){
+               QMessageBox::warning(this,tr("Error"),tr("There is nothing in the order. Ignoring it."));
+               return;
+       }
+       if(!customer.isValid()){
+               QMessageBox::warning(this,tr("Error"),tr("Please chose a customer first!"));
+               return;
+       }
+       ///////////////
+       //create order
+       QDomDocument doc;
+       QDomElement root=doc.createElement("Order");
+       root.setAttribute("customer",customer.id());
+       //is there a delivery address
+       QString s=cartaddr->toPlainText().trimmed();
+       if(s!=""){
+               QDomElement da=doc.createElement("DeliveryAddress");
+               da.appendChild(doc.createTextNode(s));
+               root.appendChild(da);
+       }
+       //is there a comment?
+       s=cartcomment->toPlainText().trimmed();
+       if(s!=""){
+               QDomElement cc=doc.createElement("Comment");
+               cc.appendChild(doc.createTextNode(s));
+               root.appendChild(cc);
+       }
+       //scan tickets & scan vouchers
+       for(int i=0;i<cartmodel->rowCount();i++){
+               QModelIndex idx=cartmodel->index(i,0);
+               int tp=cartmodel->data(idx,CART_TYPEROLE).toInt();
+               if(tp==CART_TICKET){
+                       int amt=cartmodel->data(idx).toInt();
+                       int evid=cartmodel->data(idx,CART_IDROLE).toInt();
+                       for(int j=0;j<amt;j++){
+                               QDomElement tc=doc.createElement("Ticket");
+                               tc.setAttribute("event",evid);
+                               root.appendChild(tc);
+                       }
+               }else
+               if(tp==CART_VOUCHER){
+                       int amt=cartmodel->data(idx).toInt();
+                       int price=cartmodel->data(idx,CART_PRICEROLE).toInt();
+                       int value=cartmodel->data(idx,CART_VALUEROLE).toInt();
+                       for(int j=0;j<amt;j++){
+                               QDomElement tc=doc.createElement("Voucher");
+                               tc.setAttribute("price",price);
+                               tc.setAttribute("value",value);
+                               root.appendChild(tc);
+                       }
+               
+               }
+       }
+       //set shipping info
+       if(cartship->currentIndex()>0){
+               QDomElement si=doc.createElement("Shipping");
+               si.setAttribute("type",cartship->itemData(cartship->currentIndex()).toInt());
+               root.appendChild(si);
+       }
+       //finalize
+       doc.appendChild(root);
+       //send
+       /*TODO
+       if(req->request("checkorder",doc.toByteArray())==false){
+               QMessageBox::warning(this,tr("Error"),tr("The request failed."));
+               return;
+       }
+       if(req->responseStatus()!=MSInterface::Ok){
+               QMessageBox::warning(this,tr("Error"),tr("A problem occurred during the order: %1").arg(qApp->translate("php::",req->responseBody())));
+               return;
+       }
+       //parse result
+       QDomDocument rdoc;
+       rdoc.setContent(req->responseBody());
+       //display order and give user chance to actually order it
+       MOrderWindow *ow=new MOrderWindow(this,req,MOrder(req,rdoc.documentElement()));
+       ow->show();
+       //empty the cart
+       initCart();*/
+}
+
+void MOverview::customerMgmt()
+{/*TODO
+       MCustomerListDialog mcl(req,this);
+       mcl.exec();*/
+}
+
+void MOverview::editShipping()
+{/*TODO
+       MShippingEditor se(req,this);
+       se.exec();
+       updateShipping();*/
+}
+
+void MOverview::tabChanged()
+{/*TODO
+       QWidget*w=tab->currentWidget();
+       if(w==entrancetab){
+               //fill combobox from eventmodel
+               int ci=entranceevent->currentIndex();
+               int cev=-1;
+               if(ci>=0)cev=entranceevent->itemData(ci).toInt();
+               ci=-1;
+               entranceevent->clear();
+               for(int i=0;i<eventmodel->rowCount();i++){
+                       QString ev=eventmodel->data(eventmodel->index(i,0)).toString()+" "+
+                        eventmodel->data(eventmodel->index(i,1)).toString();
+                       int eid=eventmodel->data(eventmodel->index(i,0),Qt::UserRole).toInt();
+                       entranceevent->addItem(ev,eid);
+                       if(eid==cev)ci=i;
+               }
+               if(ci>=0)entranceevent->setCurrentIndex(ci);
+               //set focus on scanner
+               entrancescan->setFocus(Qt::OtherFocusReason);
+               entrancescan->setText("");
+       }*/
+}
+
+void MOverview::entranceValidate()
+{/*TODO
+       //get event ID
+       int ci=entranceevent->currentIndex();
+       if(ci<0)return;
+       int cev=entranceevent->itemData(ci).toInt();
+       //check content
+       QString tid=entrancescan->text().trimmed();
+       entrancescan->setText("");
+       //avoid spurious events
+       if(tid=="")return;
+       //avoid double scans
+       QDateTime now=QDateTime::currentDateTime();
+       if(tid==lastbarcode && lastbcscan.addSecs(20)>=now)
+               return;
+       lastbarcode=tid;
+       lastbcscan=now;
+       //reset display
+       QPalette pal=entrancelabel->palette();
+       QPalette::ColorRole rl=QPalette::Window;
+       pal.setColor(rl,Qt::lightGray);
+       entrancelabel->setPalette(pal);
+       entrancelabel->setText(tr("searching...","entrance control"));
+       //ask the server
+       MTicket tick(req,tid);
+       //decide what to do
+       if(!tick.isValid()){
+               entrancelabel->setText(tr("Ticket \"%1\" Not Valid").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else
+       if(tick.eventID()!=cev){
+               entrancelabel->setText(tr("Ticket \"%1\" is not for this event.").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else
+       if(tick.status()==MTicket::Used){
+               entrancelabel->setText(tr("Ticket \"%1\" has already been used").arg(tid));
+               pal.setColor(rl,Qt::magenta);
+       }else
+       if(tick.status()!=MTicket::Bought){
+               entrancelabel->setText(tr("Ticket \"%1\" has not been bought.").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else
+       if(tick.paymentStatus()==MTicket::PSOk){
+               entrancelabel->setText(tr("Ticket \"%1\" Ok").arg(tid));
+               pal.setColor(rl,Qt::green);
+               tick.markUsed();
+       }else
+       if(tick.paymentStatus()==MTicket::PSNeedRefund){
+               entrancelabel->setText(tr("Ticket \"%1\" Ok; the Order has a refund").arg(tid));
+               pal.setColor(rl,Qt::green);
+               tick.markUsed();
+       }else
+       if(tick.paymentStatus()==MTicket::PSNeedPayment){
+               entrancelabel->setText(tr("Ticket \"%1\" is not paid for!").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else{
+               entrancelabel->setText(tr("Ticket \"%1\" cannot be accepted, please check the order!").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }
+       
+       entrancelabel->setPalette(pal);
+       entrancescan->setFocus(Qt::OtherFocusReason);
+       entrancescan->setText("");*/
+}
+
+//helper: finds out whether an order should be printed.
+static inline bool candoUpdateOrders(int omode,const MOrder&ord)
+{
+       if(omode==ORDERALL)return true;
+       if((omode&ORDERPAY)!=0 && ord.needsPayment())return true;
+       if((omode&ORDERREFUND)!=0 && ord.needsRefund())return true;
+       if((omode&ORDERUNSENT)!=0 && !ord.isSent())return true;
+       if((omode&ORDERRESERVE)!=0 && ord.isReservation())return true;
+       return false;
+}
+
+void MOverview::updateOrders()
+{/*TODO
+       ordermodel->clear();
+       ordermodel->setHorizontalHeaderLabels(QStringList()<<tr("Status")<<tr("Total")<<tr("Paid")<<tr("Customer"));
+       int omode=ordermode->itemData(ordermode->currentIndex()).toInt();
+       if(omode==ORDERNONE)return;
+       QList<MOrder> orders=req->getAllOrders();
+       if(orders.size()==0)return;
+       QList<MCustomer> cust=req->getAllCustomers();
+       int cl=0;
+       for(int i=0;i<orders.size();i++){
+               if(!candoUpdateOrders(omode,orders[i]))continue;
+               ordermodel->insertRow(cl);
+               ordermodel->setHeaderData(cl,Qt::Vertical,orders[i].orderID());
+               ordermodel->setData(ordermodel->index(cl,0),orders[i].orderStatusString());
+               ordermodel->setData(ordermodel->index(cl,0),orders[i].orderID(),Qt::UserRole);
+               ordermodel->setData(ordermodel->index(cl,1),orders[i].totalPriceString());
+               ordermodel->setData(ordermodel->index(cl,2),orders[i].amountPaidString());
+               int cid=orders[i].customerID();
+               //TODO: make this more effective:
+               for(int j=0;j<cust.size();j++)
+                       if(cust[j].customerID()==cid)
+                               ordermodel->setData(ordermodel->index(cl,3),cust[j].name());
+               cl++;
+       }
+       ordertable->resizeColumnsToContents();*/
+}
+
+void MOverview::orderDetails()
+{/*TODO
+       //get selected order
+       int id;
+       QModelIndexList ilst=ordertable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=ordermodel->index(ilst[0].row(),0);
+       id=ordermodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       //open order window
+       MOrderWindow *om=new MOrderWindow(this,req,MOrder(req,id));
+       om->setAttribute(Qt::WA_DeleteOnClose);
+       om->show();*/
+}
+
+void MOverview::orderByTicket()
+{/*TODO
+       //get selected order
+       bool ok;
+       QString tid=QInputDialog::getText(this,tr("Enter Ticket"),tr("Please enter the ID of one of the tickets of the order you seek:"),QLineEdit::Normal,"",&ok);
+       if(!ok || tid=="")return;
+       //request it
+       if(!req->request("orderbyticket",tid.toUtf8())){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to query server."));
+               return;
+       }
+       if(req->responseStatus()!=MSInterface::Ok){
+               QMessageBox::warning(this,tr("Warning"),qApp->translate("php::",req->responseBody()));
+               return;
+       }
+       int id=req->responseBody().trimmed().toInt(&ok);
+       if(!ok || id<0){
+               QMessageBox::warning(this,tr("Warning"),tr("Server returned an invalid order ID."));
+               return;
+       }
+       //open order window
+       MOrderWindow *om=new MOrderWindow(this,req,MOrder(req,id));
+       om->setAttribute(Qt::WA_DeleteOnClose);
+       om->show();*/
+}
+
+void MOverview::orderByEvent()
+{/*TODO
+       //display selection dialog
+       QDialog d(this);
+       d.setWindowTitle(tr("Select Event"));
+       QVBoxLayout*vl;
+       QHBoxLayout*hl;
+       d.setLayout(vl=new QVBoxLayout);
+       QTableView*tv;
+       vl->addWidget(tv=new QTableView,10);
+       tv->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       tv->setModel(eventmodel);
+       tv->resizeColumnsToContents();
+       vl->addLayout(hl=new QHBoxLayout,0);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Ok")),0);
+       connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")),0);
+       connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+       //wait for user
+       if(d.exec()!=QDialog::Accepted)
+               return;
+       //get selection
+       QModelIndexList ilst=tv->selectionModel()->selectedIndexes();
+       if(ilst.size()<1){
+               qDebug("nothing selected");
+               return;
+       }
+       //get events
+       QList<int>eventids;
+       for(int i=0;i<ilst.size();i++){
+               int eid=eventmodel->data(eventmodel->index(ilst[i].row(),0),Qt::UserRole).toInt();
+               if(!eventids.contains(eid))eventids.append(eid);
+       }
+       //request data and display
+       //TODO: unify this part with updateOrders
+       ordermodel->clear();
+       ordermodel->setHorizontalHeaderLabels(QStringList()<<tr("Status")<<tr("Total")<<tr("Paid")<<tr("Customer"));
+       QList<MOrder> orders=req->getOrdersByEvents(eventids);
+       if(orders.size()==0)return;
+       QList<MCustomer> cust=req->getAllCustomers();
+       for(int cl=0;cl<orders.size();cl++){
+               ordermodel->insertRow(cl);
+               ordermodel->setHeaderData(cl,Qt::Vertical,orders[cl].orderID());
+               ordermodel->setData(ordermodel->index(cl,0),orders[cl].orderStatusString());
+               ordermodel->setData(ordermodel->index(cl,0),orders[cl].orderID(),Qt::UserRole);
+               ordermodel->setData(ordermodel->index(cl,1),orders[cl].totalPriceString());
+               ordermodel->setData(ordermodel->index(cl,2),orders[cl].amountPaidString());
+               int cid=orders[cl].customerID();
+               //TODO: make this more effective:
+               for(int j=0;j<cust.size();j++)
+                       if(cust[j].customerID()==cid)
+                               ordermodel->setData(ordermodel->index(cl,3),cust[j].name());
+       }
+       ordermode->setCurrentIndex(ordermode->count()-1);*/
+}
+
+void MOverview::orderByCustomer()
+{/*TODO
+       //display selection dialog
+       MCustomerListDialog mcl(req,this,true);
+       //wait for user
+       if(mcl.exec()!=QDialog::Accepted)
+               return;
+       //get selection
+       MCustomer cst=mcl.getCustomer();
+       if(!cst.isValid()){
+               qDebug("nothing selected");
+               return;
+       }
+       qint64 custid=cst.customerID();
+       //request data and display
+       //TODO: unify this part with updateOrders
+       ordermodel->clear();
+       ordermodel->setHorizontalHeaderLabels(QStringList()<<tr("Status")<<tr("Total")<<tr("Paid")<<tr("Customer"));
+       QList<MOrder> orders=req->getAllOrders();
+       if(orders.size()==0)return;
+       QList<MCustomer> cust=req->getAllCustomers();
+       int cl=0;
+       for(int i=0;i<orders.size();i++){
+               //filter
+               if(orders[i].customerID()!=custid)continue;
+               //put into table
+               ordermodel->insertRow(cl);
+               ordermodel->setHeaderData(cl,Qt::Vertical,orders[i].orderID());
+               ordermodel->setData(ordermodel->index(cl,0),orders[i].orderStatusString());
+               ordermodel->setData(ordermodel->index(cl,0),orders[i].orderID(),Qt::UserRole);
+               ordermodel->setData(ordermodel->index(cl,1),orders[i].totalPriceString());
+               ordermodel->setData(ordermodel->index(cl,2),orders[i].amountPaidString());
+               ordermodel->setData(ordermodel->index(cl,3),cst.name());
+               //count up
+               cl++;
+       }
+       ordermode->setCurrentIndex(ordermode->count()-1);*/
+}
+
+void MOverview::orderByOrder()
+{/*TODO
+       //ask for OrderID
+       bool ok;
+       int oid=QInputDialog::getInteger(this,tr("Enter Order ID"),tr("Please enter the ID of the order you want to display:"),0,0,2147483647,1,&ok);
+       if(!ok)return;
+       //display
+       MOrder ord(req,oid);
+       if(!ord.isValid()){
+               QMessageBox::warning(this,tr("Warning"),tr("This order does not exist."));
+               return;
+       }
+       MOrderWindow *ow=new MOrderWindow(this,req,ord);
+       ow->show();*/
+}
+
+void MOverview::ticketReturn()
+{/*TODO
+       //get ticket
+       bool ok;
+       QString tid=QInputDialog::getText(this,tr("Return Ticket"),tr("Please enter the ticket ID to return:"),QLineEdit::Normal,"",&ok);
+       if(!ok || tid=="")return;
+       MTicket tick(req,tid);
+       if(!tick.isValid()){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a valid ticket."));
+               return;
+       }
+       //check state
+       if(tick.status()!=MTicket::Bought && tick.status()!=MTicket::Reserved){
+               QMessageBox::warning(this,tr("Warning"),tr("This ticket cannot be returned, it has already been used or is in the wrong state."));
+               return;
+       }
+       //submit
+       QString r=tick.ticketReturn();
+       if(r!="")QMessageBox::warning(this,tr("Warning"),trUtf8(r.toUtf8()));*/
+}
+
+void MOverview::voucherReturn()
+{/*TODO
+       //get ticket
+       bool ok;
+       QString tid=QInputDialog::getText(this,tr("Return Voucher"),tr("Please enter the voucher ID to return:"),QLineEdit::Normal,"",&ok);
+       if(!ok || tid=="")return;
+       MVoucher vouc(req,tid);
+       if(!vouc.isValid()){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a valid voucher."));
+               return;
+       }
+       //check state
+       if(vouc.isUsed()){
+               QMessageBox::warning(this,tr("Warning"),tr("This voucher cannot be returned, it has already been used."));
+               return;
+       }
+       //submit
+       QString r=vouc.voucherReturn();
+       if(r!="")QMessageBox::warning(this,tr("Warning"),trUtf8(r.toUtf8()));*/
+}
+
+void MOverview::deductVoucher()
+{/*TODO
+       //get voucher ID and amount
+       QDialog d;
+       d.setWindowTitle(tr("Deduct from Voucher"));
+       QGridLayout *gl;
+       d.setLayout(gl=new QGridLayout);
+       gl->addWidget(new QLabel(tr("Using a voucher to pay outside the system.")),0,0,1,2);
+       
+       QLineEdit*vid;
+       MCentSpinBox*cent;
+       gl->addWidget(new QLabel(tr("Amount to deduct:")),1,0);
+       gl->addWidget(cent=new MCentSpinBox,1,1);
+       gl->addWidget(new QLabel(tr("Voucher ID:")),2,0);
+       gl->addWidget(vid=new QLineEdit,2,1);
+       
+       gl->setRowMinimumHeight(3,15);
+       QHBoxLayout*hl;
+       gl->addLayout(hl=new QHBoxLayout,4,0,1,2);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("OK")));
+       connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")));
+       connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+       if(d.exec()!=QDialog::Accepted)return;
+       if(vid->text().trimmed()=="" || cent->value()<=0)return;
+       //query server
+       QByteArray r=vid->text().trimmed().toAscii()+"\n"+QString::number(cent->value()).toAscii();
+       if(!req->request("usevoucheroutside",r)){
+               QMessageBox::warning(this,tr("Warning"),tr("Request failed."));
+               return;
+       }
+       if(req->responseStatus()!=MSInterface::Ok){
+               QMessageBox::warning(this,tr("Warning"),tr("Request failed."));
+               return;
+       }
+       QStringList sl=QString::fromAscii(req->responseBody().trimmed()).split("\n");
+       int tak=-1,rem=-1;
+       if(sl.size()>0)tak=sl[0].trimmed().toInt();
+       if(sl.size()>1)rem=sl[1].trimmed().toInt();
+       QMessageBox::information(this,tr("Deducted from Voucher"),tr("Value taken from voucher: %1\nValue remaining on voucher: %2").arg(cent2str(tak)).arg(cent2str(rem)));*/
+}
+
+void MOverview::refreshData()
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       if(set.value("refreshEvents",false).toBool() && req->hasRole("geteventlist"))
+               updateEvents();
+       if(set.value("refreshUsers",false).toBool() && req->hasRole("getusers"))
+               updateUsers();
+       if(set.value("refreshHosts",false).toBool() && req->hasRole("gethosts"))
+               updateHosts();
+       if(set.value("refreshShipping",false).toBool() && req->hasRole("getshipping"))
+               updateShipping();
+}
+
+void MOverview::setRefresh()
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       //dialog
+       QDialog d;
+       d.setWindowTitle(tr("Refresh Settings"));
+       QVBoxLayout*vl;
+       QHBoxLayout*hl;
+       d.setLayout(vl=new QVBoxLayout);
+       vl->addLayout(hl=new QHBoxLayout);
+       hl->addWidget(new QLabel(tr("Refresh Rate (minutes):")),1);
+       QSpinBox*rate;
+       hl->addWidget(rate=new QSpinBox,0);
+       rate->setRange(1,999);
+       rate->setValue(set.value("refresh",300).toInt()/60);
+       QCheckBox *rev,*rus,*rho,*rsh;
+       vl->addWidget(rev=new QCheckBox(tr("refresh &event list")));
+       rev->setChecked(set.value("refreshEvents",false).toBool());
+       vl->addWidget(rus=new QCheckBox(tr("refresh &user list")));
+       rus->setChecked(set.value("refreshUsers",false).toBool());
+       vl->addWidget(rho=new QCheckBox(tr("refresh &host list")));
+       rho->setChecked(set.value("refreshHosts",false).toBool());
+       vl->addWidget(rsh=new QCheckBox(tr("refresh &shipping list")));
+       rho->setChecked(set.value("refreshShipping",false).toBool());
+       vl->addSpacing(15);
+       vl->addStretch(10);
+       vl->addLayout(hl=new QHBoxLayout);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("&OK")));
+       connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("&Cancel")));
+       connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+       if(d.exec()!=QDialog::Accepted)return;
+       //write settings
+       set.setValue("refreshEvents",rev->isChecked());
+       set.setValue("refreshUsers",rus->isChecked());
+       set.setValue("refreshHosts",rho->isChecked());
+       set.setValue("refreshShipping",rsh->isChecked());
+       set.setValue("refresh",rate->value()*60);
+       //reset timer
+       rtimer.stop();
+       rtimer.setInterval(rate->value()*60000);
+       rtimer.start();
+}
+
+void MOverview::webSettings(bool showdlg)
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       //get settings
+       MSInterface::LogLevel lvl=MSInterface::LogLevel(set.value("webloglevel", MSInterface::LogOnError).toInt());
+       int timeout=set.value("webtimeout",30).toInt();
+       //dialog
+       if(showdlg){
+               QDialog d;
+               d.setWindowTitle(tr("Server Access Settings"));
+               QGridLayout*gl;
+               QHBoxLayout*hl;
+               d.setLayout(gl=new QGridLayout);
+               gl->addWidget(new QLabel(tr("Request Timeout (seconds):")),0,0);
+               QSpinBox*tmout;
+               gl->addWidget(tmout=new QSpinBox,0,1);
+               tmout->setRange(10,999);
+               tmout->setValue(timeout);
+               QComboBox *log;
+               gl->addWidget(new QLabel(tr("Log Level:")),1,0);
+               gl->addWidget(log=new QComboBox,1,1);
+               log->addItem(tr("Minimal Logging"),MSInterface::LogMinimal);
+               log->addItem(tr("Log Details on Error"),MSInterface::LogOnError);
+               log->addItem(tr("Always Log Details"),MSInterface::LogDetailed);
+               switch(lvl){
+                       case MSInterface::LogMinimal:log->setCurrentIndex(0);break;
+                       case MSInterface::LogOnError:log->setCurrentIndex(1);break;
+                       case MSInterface::LogDetailed:log->setCurrentIndex(2);break;
+               }
+               gl->setRowMinimumHeight(2,15);
+               gl->addLayout(hl=new QHBoxLayout,3,0,1,2);
+               hl->addStretch(10);
+               QPushButton*p;
+               hl->addWidget(p=new QPushButton(tr("&OK")));
+               connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+               hl->addWidget(p=new QPushButton(tr("&Cancel")));
+               connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+               if(d.exec()!=QDialog::Accepted)return;
+               //write settings
+               lvl=MSInterface::LogLevel(log->itemData(log->currentIndex()).toInt());
+               timeout=tmout->value();
+               set.setValue("webloglevel",lvl);
+               set.setValue("webtimeout",timeout);
+       }
+       //reset webrequest
+       req->setLogLevel(lvl);
+       req->setWebTimeout(timeout*1000);
+}
+
+void MOverview::doBackup()
+{
+       baktimer.stop();
+       //sanity check
+       if(!req->hasRight(req->RBackup))return;
+       //get settings
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       QString path=set.value("backupfile",req->dataDir()+"/backup").toString();
+       int gens=set.value("backupgenerations",3).toInt();
+       //get data
+       MTBackup bc;
+       bc=MTBackup::query();
+       if(bc.stage()!=bc.Success){
+               QMessageBox::warning(this,tr("Warning"),tr("Backup failed with error (%2): %1").arg(bc.errorString()).arg(bc.errorType()));
+               return;
+       }
+       if(bc.getbackup().isNull()||bc.getbackup().value().isEmpty()){
+               QMessageBox::warning(this,tr("Warning"),tr("Backup returned empty."));
+               return;
+       }
+       //rotate files
+       QFile(path+"."+QString::number(gens)).remove();
+       for(int i=gens-1;i>=0;i--){
+               if(i)
+                       QFile(path+"."+QString::number(i)).rename(path+"."+QString::number(i+1));
+               else
+                       QFile(path).rename(path+".1");
+       }
+       //store new data
+       QFile fd(path);
+       if(fd.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+               fd.write(bc.getbackup().value().toAscii());
+               fd.close();
+               set.setValue("backuptime",QDateTime::currentDateTime().toTime_t());
+               QMessageBox::information(this,tr("Backup"),tr("The backup was successful."));
+               int tm=set.value("backupinterval",0).toInt()*86400000;
+               if(tm)baktimer.start(tm);
+       }else
+               QMessageBox::warning(this,tr("Warning"),tr("Cannot create backup file."));
+}
+
+void MOverview::backupSettings()
+{
+       //show dialog
+       MBackupDialog d(this,profilekey);
+       d.exec();
+       //reset timer
+       int btm=QSettings().value("profiles/"+profilekey+"/backupinterval",0).toInt()*86400;
+       if(btm){
+               //adjust for last backup time
+               int iv=QDateTime::currentDateTime().toTime_t() - QSettings().value("profiles/"+profilekey+"/backuptime",0).toInt();
+               if(iv>=btm)btm=0;
+               else btm-=iv;
+               //start timer
+               baktimer.start(btm*1000);
+       }
+}
+
+void MOverview::moneylogVoucher()
+{/*TODO
+       QString vid=QInputDialog::getText(this,tr("Voucher ID"),tr("Please enter voucher ID to show log:"));
+       if(vid!="")
+               MMoneyLog(this,req,"voucher\n"+vid).exec();*/
+}
+
+void MOverview::moneylogUser()
+{/*TODO
+       QString vid=QInputDialog::getText(this,tr("User"),tr("Please enter login name of user to show log:"));
+       if(vid!="")
+               MMoneyLog(this,req,"user\n"+vid).exec();*/
+}
+
+
+/**********************************************/
+
+MBackupDialog::MBackupDialog(QWidget*par,QString pk)
+       :QDialog(par),profilekey(pk)
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       QString path=set.value("backupfile",req->dataDir()+"/backup").toString();
+       int gens=set.value("backupgenerations",3).toInt();
+       int tm=set.value("backupinterval",0).toInt();
+       //dialog
+       setWindowTitle(tr("Backup Settings"));
+       QGridLayout*gl;
+       QHBoxLayout*hl;
+       setLayout(gl=new QGridLayout);
+       QPushButton*p;
+       gl->addWidget(new QLabel(tr("Backup File:")),0,0);
+       gl->addWidget(lpath=new QLineEdit(path),0,1);
+       gl->addWidget(p=new QPushButton(tr("...")),0,2);
+       connect(p,SIGNAL(clicked()),this,SLOT(getpath()));
+       
+       gl->addWidget(new QLabel(tr("Generations to keep:")),1,0);
+       gl->addWidget(gener=new QSpinBox,1,1,1,2);
+       gener->setRange(1,16);
+       gener->setValue(gens);
+       
+       gl->addWidget(new QLabel(tr("Automatic Backup:")),2,0);
+       gl->addWidget(autob=new QCheckBox,2,1,1,2);
+       autob->setChecked(tm>0);
+       
+       gl->addWidget(new QLabel(tr("Interval in days:")),3,0);
+       gl->addWidget(interv=new QSpinBox,3,1,1,2);
+       interv->setRange(1,24);
+       interv->setValue(tm>0?tm:1);
+       
+       gl->setRowMinimumHeight(4,15);
+       gl->addLayout(hl=new QHBoxLayout,5,0,1,3);
+       hl->addStretch(10);
+       hl->addWidget(p=new QPushButton(tr("&OK")));
+       connect(p,SIGNAL(clicked()),this,SLOT(accept()));
+       connect(p,SIGNAL(clicked()),this,SLOT(save()));
+       hl->addWidget(p=new QPushButton(tr("&Cancel")));
+       connect(p,SIGNAL(clicked()),this,SLOT(reject()));
+}
+
+void MBackupDialog::getpath()
+{
+       QString path=QFileDialog::getSaveFileName(this,tr("Backup File"),lpath->text());
+       if(path!="")lpath->setText(path);
+}
+
+void MBackupDialog::save()
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       set.setValue("backupfile",lpath->text());
+       set.setValue("backupgenerations",gener->value());
+       set.setValue("backupinterval",autob->isChecked()?interv->value():0);
+}
+/**********************************************/
+
+MPasswordChange::MPasswordChange(QWidget*par,QString user)
+       :QDialog(par)
+{
+       oldpwd=newpwd1=newpwd2=0;
+       if(user=="")
+               setWindowTitle(tr("Change my password"));
+       else
+               setWindowTitle(tr("Reset password of user \"%1\"").arg(user));
+       QGridLayout*gl;
+       setLayout(gl=new QGridLayout);
+       if(user==""){
+               gl->addWidget(new QLabel(tr("Old Password:")),0,0);
+               gl->addWidget(oldpwd=new QLineEdit,0,1);
+               oldpwd->setEchoMode(QLineEdit::Password);
+       }
+       gl->addWidget(new QLabel(tr("New Password:")),1,0);
+       gl->addWidget(newpwd1=new QLineEdit,1,1);
+       newpwd1->setEchoMode(QLineEdit::Password);
+       gl->addWidget(new QLabel(tr("Repeat Password:")),2,0);
+       gl->addWidget(newpwd2=new QLineEdit,2,1);
+       newpwd2->setEchoMode(QLineEdit::Password);
+       
+       QHBoxLayout*hl;
+       gl->addLayout(hl=new QHBoxLayout,3,0,1,2);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Set Password")));
+       connect(p,SIGNAL(clicked()),this,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")));
+       connect(p,SIGNAL(clicked()),this,SLOT(reject()));
+}
+
+QString MPasswordChange::oldPassword()
+{
+       if(oldpwd)return oldpwd->text();
+       return "";
+}
+
+QString MPasswordChange::newPassword()
+{
+       if(newpwd1==0 || newpwd2==0)return "";
+       if(newpwd1->text()!=newpwd2->text())return "";
+       return newpwd1->text();
+}
+
+
+/********************************************************************************/
+
+MCartTableDelegate::MCartTableDelegate(QObject*p)
+       :QItemDelegate(p)
+{
+}
+
+QWidget *MCartTableDelegate::createEditor(QWidget *parent,
+        const QStyleOptionViewItem &/* option */,
+        const QModelIndex & index ) const
+{
+       //base class
+       if(index.column()!=0)return 0;
+       
+       QSpinBox *editor = new QSpinBox(parent);
+       editor->setRange(1,1000);
+       editor->installEventFilter(const_cast<MCartTableDelegate*>(this));
+       return editor;
+}
+
+void MCartTableDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
+{
+       //name field
+       int c=index.column();
+       if(c==0)
+               ((QSpinBox*)editor)->setValue(index.model()->data(index).toInt());
+}
+
+void MCartTableDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
+       const QModelIndex &index) const
+{
+       //name field
+       int c=index.column();
+       if(c==0){
+               int newval=((QSpinBox*)editor)->value();
+               model->setData(index,newval);
+       }
+}
diff --git a/src/mwin/carttab.h b/src/mwin/carttab.h
new file mode 100644 (file)
index 0000000..dfd5a43
--- /dev/null
@@ -0,0 +1,235 @@
+//
+// C++ Interface: overview
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2007
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef MAGICSMOKE_OVERVIEW_H
+#define MAGICSMOKE_OVERVIEW_H
+
+#include <QDateTime>
+#include <QDialog>
+#include <QItemDelegate>
+#include <QMainWindow>
+#include <QTimer>
+
+#include "customer.h"
+
+class QAction;
+class QCheckBox;
+class QComboBox;
+class QLabel;
+class QLineEdit;
+class QPushButton;
+class QSpinBox;
+class QStandardItemModel;
+class QTabWidget;
+class QTableView;
+
+class MSInterface;
+
+/**Main Overview Window*/
+class MOverview:public QMainWindow
+{
+       Q_OBJECT
+       public:
+               /**construct the window with web-request/session handler and QSettings-key for current profile*/
+               MOverview(QString);
+               ~MOverview();
+       protected:
+               /**handle closing the window: close the session too*/
+               void closeEvent(QCloseEvent*);
+       private slots:
+               /**try to log in again*/
+               void relogin();
+               
+               /**create a new event*/
+               void newEvent();
+               /**edit existing event*/
+               void editEvent();
+               /**update list of events*/
+               void updateEvents();
+               /**order ticket from event tab*/
+               void eventOrderTicket();
+               /**open event summary*/
+               void eventSummary();
+               /**cancel the event*/
+               void eventCancel();
+               
+               /**update shipping info*/
+               void updateShipping();
+               
+               /**get all orders, update list*/
+               void updateOrders();
+               /**open order detail window*/
+               void orderDetails();
+               
+               /**update list of users*/
+               void updateUsers();
+               /**create new user*/
+               void newUser();
+               /**delete selected user*/
+               void deleteUser();
+               /**set users description*/
+               void editUserDescription();
+               /**set users roles*/
+               void editUserRoles();
+               /**set users hosts*/
+               void editUserHosts();
+               /**set my own password*/
+               void setMyPassword();
+               /**set a users password*/
+               void setUserPassword();
+               
+               /**update list of hosts*/
+               void updateHosts();
+               /**create new host*/
+               void newHost();
+               /**create a database entry for this host*/
+               void addThisHost();
+               /**delete a host*/
+               void deleteHost();
+               /**generate a new key*/
+               void changeHostKey();
+               /**import host from file*/
+               void importHost();
+               /**export host to file*/
+               void exportHost();
+               
+               /**decide what customer to use*/
+               void setCustomer();
+               /**initialize cart tab*/
+               void initCart();
+               /**add a ticket to the cart*/
+               void cartAddTicket();
+               /**add a voucher to the cart*/
+               void cartAddVoucher();
+               /**remove item from the cart*/
+               void cartRemoveItem();
+               /**check the order on the server*/
+               void cartOrder();
+               
+               /**manage customers*/
+               void customerMgmt();
+               
+               /**edit shipping options*/
+               void editShipping();
+               
+               /**generic check which tab is active*/
+               void tabChanged();
+               
+               /**react on entry in Entrance tab*/
+               void entranceValidate();
+               
+               /**return a ticket*/
+               void ticketReturn();
+               /**return a voucher*/
+               void voucherReturn();
+               /**find an order by ticket*/
+               void orderByTicket();
+               /**find/select orders by event*/
+               void orderByEvent();
+               /**find/select orders by customer*/
+               void orderByCustomer();
+               /**find and display order by order ID*/
+               void orderByOrder();
+               /**deduct some money from a voucher (to pay outside the system)*/
+               void deductVoucher();
+               
+               /**money log for voucher*/
+               void moneylogVoucher();
+               /**money log for user*/
+               void moneylogUser();
+               
+               /**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);
+               
+               /**do a backup now*/
+               void doBackup();
+               
+               /**settings for backup*/
+               void backupSettings();
+               
+       private:
+               //the profile associated with this session
+               QString profilekey;
+               //widgets
+               QTabWidget*tab;
+               QWidget*eventtab,*carttab,*usertab,*hosttab,*ordertab,*entrancetab;
+               QTableView*eventtable,*usertable,*hosttable,*carttable,*ordertable;
+               QStandardItemModel*eventmodel,*usermodel,*hostmodel,*cartmodel,*ordermodel;
+               QPushButton*thishostbutton;
+               QLabel*cartcustomer,*entrancelabel;
+               QTextEdit *cartaddr,*cartcomment;
+               QComboBox*ordermode,*cartship,*entranceevent;
+               QLineEdit*entrancescan;
+               //event list
+               QAction*showoldevents;
+               //cart
+               MCustomer customer;
+               //barcode cache
+               QString lastbarcode;
+               QDateTime lastbcscan;
+               //refresh timers
+               QTimer rtimer,baktimer;
+};
+
+/**Helper dialog for changing passwords*/
+class MPasswordChange:public QDialog
+{
+       Q_OBJECT
+       public:
+               /**creates a password change dialog, if user is empty it is presumed to change own password*/
+               MPasswordChange(QWidget*parent,QString user=QString());
+               
+               /**if own password: return old password*/
+               QString oldPassword();
+               /**returns new password, or empty if the two lines don't match*/
+               QString newPassword();
+       private:
+               QLineEdit *oldpwd,*newpwd1,*newpwd2;
+};
+
+/**Helper class for shopping cart: allow editing amount, but nothing else*/
+class MCartTableDelegate:public QItemDelegate
+{
+       public:
+               MCartTableDelegate(QObject *parent = 0);
+               
+               QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
+                                     const QModelIndex &index) const;
+               
+               void setEditorData(QWidget *editor, const QModelIndex &index) const;
+               void setModelData(QWidget *editor, QAbstractItemModel *model,
+                                 const QModelIndex &index) const;
+};
+
+/**Helper class for Backup settings*/
+class MBackupDialog:public QDialog
+{
+       Q_OBJECT
+       public:
+               MBackupDialog(QWidget*,QString);
+               
+       private slots:
+               void getpath();
+               void save();
+       private:
+               QLineEdit*lpath;
+               QSpinBox*interv,*gener;
+               QCheckBox*autob;
+               QString profilekey;
+};
+
+#endif
diff --git a/src/mwin/entrancetab.cpp b/src/mwin/entrancetab.cpp
new file mode 100644 (file)
index 0000000..33d9424
--- /dev/null
@@ -0,0 +1,1753 @@
+//
+// C++ Implementation: overview
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2007
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "centbox.h"
+#include "checkdlg.h"
+#include "eventedit.h"
+#include "eventsummary.h"
+#include "main.h"
+#include "misc.h"
+#include "moneylog.h"
+#include "msinterface.h"
+#include "orderwin.h"
+#include "overview.h"
+
+#include <QApplication>
+#include <QBoxLayout>
+#include <QCheckBox>
+#include <QComboBox>
+#include <QCryptographicHash>
+#include <QDomDocument>
+#include <QDomElement>
+#include <QFile>
+#include <QFileDialog>
+#include <QFrame>
+#include <QInputDialog>
+#include <QLabel>
+#include <QMenu>
+#include <QMenuBar>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QSettings>
+#include <QSpinBox>
+#include <QStandardItemModel>
+#include <QStatusBar>
+#include <QTabWidget>
+#include <QTableView>
+#include <QTextEdit>
+
+#define ORDERNONE      0
+#define ORDERALL       0xff
+#define ORDEROPEN      0xf
+#define ORDERPAY       1
+#define ORDERREFUND    2
+#define ORDERUNSENT    4
+#define ORDERRESERVE   8
+
+#define req (MSInterface::instance())
+
+MOverview::MOverview(QString pk)
+{
+       profilekey=pk;
+       setAttribute(Qt::WA_DeleteOnClose);
+       setWindowTitle("MagicSmoke: "+req->currentUser()+"@"+QSettings().value("profiles/"+pk+"/name").toString());
+       rtimer.setInterval(QSettings().value("profiles/"+pk+"/refresh",300).toInt()*1000);
+       rtimer.start();
+       connect(&rtimer,SIGNAL(timeout()),this,SLOT(refreshData()));
+       //check backup timing
+       int btm=QSettings().value("profiles/"+pk+"/backupinterval",0).toInt()*86400;
+       if(btm){
+               //adjust for last backup time
+               int iv=QDateTime::currentDateTime().toTime_t() - QSettings().value("profiles/"+pk+"/backuptime",0).toInt();
+               if(iv>=btm)btm=0;
+               else btm-=iv;
+               //earliest allowed backup is 30s from now
+               if(btm<30)btm=30;
+               //start timer
+               baktimer.start(btm*1000);
+               connect(&baktimer,SIGNAL(timeout()),this,SLOT(doBackup()));
+       }
+       
+       //menu
+       QMenuBar*mb=menuBar();
+       QMenu*m=mb->addMenu(tr("&Session"));
+       m->addAction(tr("&Re-Login"),this,SLOT(relogin()));
+       m->addAction(tr("Change my &Password"),this,SLOT(setMyPassword()))
+        ->setEnabled(req->hasRight(req->RChangeMyPassword));
+       m->addSeparator();
+       m->addAction(tr("&Edit Templates..."),req,SLOT(editTemplates()));
+       m->addAction(tr("&Update Templates Now"),req,SLOT(updateTemplates()));
+       m->addSeparator();
+       m->addAction(tr("&Close Session"),this,SLOT(close()));
+       
+       m=mb->addMenu(tr("&Event"));
+       m->addAction(tr("&Update Event List"),this,SLOT(updateEvents()))
+        ->setEnabled(req->hasRight(req->RGetAllEvents));
+       m->addAction(tr("&Show/Edit details..."),this,SLOT(editEvent()))
+        ->setEnabled(req->hasRight(req->RGetEvent));
+       m->addAction(tr("&New Event..."),this,SLOT(newEvent()))->setEnabled(req->hasRole("createevent"));
+       m->addSeparator();
+       showoldevents=m->addAction(tr("Show &old Events"),this,SLOT(updateEvents()));
+       showoldevents->setEnabled(req->hasRight(req->RGetAllEvents));
+       showoldevents->setCheckable(true);
+       showoldevents->setChecked(QSettings().value("profiles/"+pk+"/showOldEvents",false).toBool());
+       
+       m=mb->addMenu(tr("&Customer"));
+       m->addAction(tr("&Show all customers"),this,SLOT(customerMgmt()));
+       
+       m=mb->addMenu(tr("C&art"));
+       m->addAction(tr("Add &Ticket"),this,SLOT(cartAddTicket()));
+       m->addAction(tr("Add &Voucher"),this,SLOT(cartAddVoucher()));
+       m->addAction(tr("&Remove Item"),this,SLOT(cartRemoveItem()));
+       m->addAction(tr("&Abort Shopping"),this,SLOT(initCart()));
+       m->addSeparator();
+       m->addAction(tr("&Update Shipping Options"),this,SLOT(updateShipping()));
+       
+       m=mb->addMenu(tr("&Misc"));
+       m->addAction(tr("Return &ticket..."),this,SLOT(ticketReturn()));
+       m->addAction(tr("Return &voucher..."),this,SLOT(voucherReturn()));
+       m->addSeparator();
+       m->addAction(tr("Edit &Shipping Options..."),this,SLOT(editShipping()));
+       m->addSeparator();
+       m->addAction(tr("&Deduct from voucher..."),this,SLOT(deductVoucher()));
+       m->addSeparator();
+       m->addAction(tr("&Money Log for voucher..."),this,SLOT(moneylogVoucher()));
+       m->addAction(tr("Money Log for &user..."),this,SLOT(moneylogUser()));
+       
+       m=mb->addMenu(tr("C&onfigure"));
+       m->addAction(tr("&Auto-Refresh settings..."),this,SLOT(setRefresh()));
+       m->addAction(tr("&Server Access settings..."),this,SLOT(webSettings()));
+       
+       m=mb->addMenu(tr("&Admin"));
+       m->addAction(tr("Backup &Settings..."),this,SLOT(backupSettings()))
+        ->setEnabled(req->hasRight(req->RBackup));
+       m->addAction(tr("&Backup now..."),this,SLOT(doBackup()))
+        ->setEnabled(req->hasRight(req->RBackup));
+
+       mb->addMenu(MApplication::helpMenu());
+       
+       //tabs
+       setCentralWidget(tab=new QTabWidget);
+       connect(tab,SIGNAL(currentChanged(int)),this,SLOT(tabChanged()));
+       
+       //Event tab
+       tab->addTab(eventtab=new QWidget,tr("Events"));
+       QVBoxLayout*vl;QHBoxLayout*hl;
+       eventtab->setLayout(hl=new QHBoxLayout);
+       hl->addWidget(eventtable=new QTableView,10);
+       eventtable->setModel(eventmodel=new QStandardItemModel(this));
+       eventtable->setSelectionMode(QAbstractItemView::SingleSelection);
+       eventtable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       hl->addSpacing(5);
+       hl->addLayout(vl=new QVBoxLayout,0);
+       QPushButton*p;
+       vl->addWidget(p=new QPushButton(tr("New Event...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(newEvent()));
+       p->setEnabled(req->hasRole("createevent"));
+       vl->addWidget(p=new QPushButton(tr("Details...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editEvent()));
+       p->setEnabled(req->hasRole("geteventdata"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Order Ticket...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(eventOrderTicket()));
+       p->setEnabled(req->hasRole("createorder"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Event Summary...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(eventSummary()));
+       p->setEnabled(req->hasRole("eventsummary"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Cancel Event...")),0);
+       p->setEnabled(req->hasRole("cancelevent"));
+       connect(p,SIGNAL(clicked()),this,SLOT(eventCancel()));
+       vl->addStretch(10);
+       
+       //Shopping Cart Tab
+       tab->addTab(carttab=new QWidget,tr("Shopping Cart"));
+       carttab->setLayout(vl=new QVBoxLayout);
+       vl->addLayout(hl=new QHBoxLayout);
+       QVBoxLayout*vl2;
+       hl->addLayout(vl2=new QVBoxLayout,2);
+       vl2->addWidget(carttable=new QTableView,10);
+       carttable->setModel(cartmodel=new QStandardItemModel(this));
+       carttable->setSelectionMode(QAbstractItemView::SingleSelection);
+       carttable->setItemDelegate(new MCartTableDelegate(this));
+       QHBoxLayout*hl2;
+       vl2->addLayout(hl2=new QHBoxLayout,0);
+       hl2->addStretch(10);
+       hl2->addWidget(p=new QPushButton(tr("Add Ticket")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(cartAddTicket()));
+       hl2->addWidget(p=new QPushButton(tr("Add Voucher")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(cartAddVoucher()));
+       hl2->addWidget(p=new QPushButton(tr("Remove Item")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(cartRemoveItem()));
+       QFrame*frm;
+       hl->addWidget(frm=new QFrame,0);
+       frm->setFrameShape(QFrame::VLine);
+       hl->addLayout(vl2=new QVBoxLayout,1);
+       vl2->addWidget(p=new QPushButton(tr("Customer:")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(setCustomer()));
+       vl2->addWidget(cartcustomer=new QLabel("...\n \n \n "));
+       vl2->addWidget(frm=new QFrame,0);
+       frm->setFrameShape(QFrame::HLine);
+       vl2->addSpacing(10);
+       vl2->addWidget(new QLabel(tr("Shipping Method:")),0);
+       vl2->addWidget(cartship=new QComboBox,0);
+       cartship->setEditable(false);
+       vl2->addWidget(new QLabel(tr("Delivery Address:")),0);
+       vl2->addWidget(cartaddr=new QTextEdit);
+       vl2->addSpacing(10);
+       vl2->addWidget(new QLabel(tr("Comments:")),0);
+       vl2->addWidget(cartcomment=new QTextEdit);
+       vl2->addStretch(10);
+       vl->addWidget(frm=new QFrame,0);
+       frm->setFrameShape(QFrame::HLine);
+       vl->addLayout(hl=new QHBoxLayout,0);
+       hl->addStretch(10);
+       hl->addWidget(p=new QPushButton(tr("Check Order")));
+       p->setEnabled(req->hasRole("checkorder"));
+       connect(p,SIGNAL(clicked()),this,SLOT(cartOrder()));
+       hl->addWidget(p=new QPushButton(tr("Clear")));
+       connect(p,SIGNAL(clicked()),this,SLOT(initCart()));
+       
+       //Order List Tab
+       tab->addTab(ordertab=new QWidget,tr("Order List"));
+       ordertab->setLayout(hl=new QHBoxLayout);
+       hl->addLayout(vl=new QVBoxLayout,10);
+       vl->addWidget(ordermode=new QComboBox,0);
+       ordermode->addItem(tr("-select mode-"),ORDERNONE);
+       ordermode->addItem(tr("All Orders"),ORDERALL);
+       ordermode->addItem(tr("Open Orders"),ORDEROPEN);
+       ordermode->addItem(tr("Open Reservations"),ORDERRESERVE);
+       ordermode->addItem(tr("Outstanding Payments"),ORDERPAY);
+       ordermode->addItem(tr("Outstanding Refunds"),ORDERREFUND);
+       ordermode->addItem(tr("Undelivered Orders"),ORDERUNSENT);
+       //make sure this entry is the last one, since we use count()-1 to select it
+       ordermode->addItem(tr("-search result-"),ORDERNONE);
+       connect(ordermode,SIGNAL(currentIndexChanged(int)),this,SLOT(updateOrders()));
+       vl->addWidget(ordertable=new QTableView);
+       ordertable->setModel(ordermodel=new QStandardItemModel(this));
+       ordertable->setSelectionMode(QAbstractItemView::SingleSelection);
+       ordertable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       connect(ordertable,SIGNAL(doubleClicked(const QModelIndex&)),this,SLOT(orderDetails()));
+       hl->addLayout(vl=new QVBoxLayout,0);
+       vl->addWidget(p=new QPushButton(tr("Update")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(updateOrders()));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Details...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderDetails()));
+       p->setEnabled(req->hasRole("getorder"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Find by Ticket...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderByTicket()));
+       p->setEnabled(req->hasRole("orderbyticket"));
+       vl->addWidget(p=new QPushButton(tr("Find by Event...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderByEvent()));
+       p->setEnabled(req->hasRole("getordersbyevents"));
+       vl->addWidget(p=new QPushButton(tr("Find by Customer...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderByCustomer()));
+       p->setEnabled(req->hasRole("getorderlist"));
+       vl->addWidget(p=new QPushButton(tr("Find by Order ID...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderByOrder()));
+       p->setEnabled(req->hasRole("getorder"));
+       vl->addStretch(10);
+       
+       //Entrance Control Tab
+       tab->addTab(entrancetab=new QWidget,tr("Entrance"));
+       entrancetab->setLayout(vl=new QVBoxLayout);
+       vl->addWidget(entranceevent=new QComboBox,0);
+       entranceevent->setEditable(false);
+       vl->addSpacing(30);
+       vl->addWidget(new QLabel(tr("Enter or scan Ticket-ID:")),0);
+       vl->addWidget(entrancescan=new QLineEdit,0);
+       connect(entrancescan,SIGNAL(editingFinished()),this,SLOT(entranceValidate()));
+       vl->addWidget(entrancelabel=new QLabel("  "),10);
+       entrancelabel->setAutoFillBackground(true);
+       QFont fnt=entrancelabel->font();
+       fnt.setBold(true);fnt.setPointSize(24);
+       entrancelabel->setFont(fnt);
+       entrancelabel->setAlignment(Qt::AlignCenter);
+       
+       //user tab
+       tab->addTab(usertab=new QWidget,tr("Users"));
+       usertab->setLayout(hl=new QHBoxLayout);
+       hl->addWidget(usertable=new QTableView,10);
+       usertable->setModel(usermodel=new QStandardItemModel(this));
+       usertable->setSelectionMode(QAbstractItemView::SingleSelection);
+       usertable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       hl->addSpacing(5);
+       hl->addLayout(vl=new QVBoxLayout,0);
+       vl->addWidget(p=new QPushButton(tr("New User...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(newUser()));
+       p->setEnabled(req->hasRole("adduser"));
+       vl->addWidget(p=new QPushButton(tr("Delete User...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(deleteUser()));
+       p->setEnabled(req->hasRole("deleteuser"));
+       vl->addSpacing(20);
+       vl->addWidget(p=new QPushButton(tr("Description...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editUserDescription()));
+       p->setEnabled(req->hasRole("setuserdescription"));
+       vl->addWidget(p=new QPushButton(tr("Hosts...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editUserHosts()));
+       p->setEnabled(req->hasRole("getuserhosts"));
+       vl->addWidget(p=new QPushButton(tr("Roles...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editUserRoles()));
+       p->setEnabled(req->hasRole("getuseracl"));
+       vl->addWidget(p=new QPushButton(tr("Set Password...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(setUserPassword()));
+       p->setEnabled(req->hasRole("setpasswd"));
+       vl->addStretch(10);
+       
+       //host tab
+       tab->addTab(hosttab=new QWidget,tr("Hosts"));
+       hosttab->setLayout(hl=new QHBoxLayout);
+       hl->addWidget(hosttable=new QTableView,10);
+       hosttable->setModel(hostmodel=new QStandardItemModel(this));
+       hosttable->setSelectionMode(QAbstractItemView::SingleSelection);
+       hosttable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       hl->addSpacing(5);
+       hl->addLayout(vl=new QVBoxLayout,0);
+       vl->addWidget(p=new QPushButton(tr("New Host...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(newHost()));
+       p->setEnabled(req->hasRole("addhost"));
+       vl->addWidget(thishostbutton=p=new QPushButton(tr("Add This Host...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(addThisHost()));
+       p->setEnabled(req->hasRole("addhost"));
+       vl->addWidget(p=new QPushButton(tr("Delete Host...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(deleteHost()));
+       p->setEnabled(req->hasRole("deletehost"));
+       vl->addSpacing(20);
+       vl->addWidget(p=new QPushButton(tr("Generate New Key...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(changeHostKey()));
+       p->setEnabled(req->hasRole("sethostkey"));
+       vl->addWidget(p=new QPushButton(tr("Import...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(importHost()));
+       p->setEnabled(req->hasRole("addhost"));
+       vl->addWidget(p=new QPushButton(tr("Export...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(exportHost()));
+       p->setEnabled(req->hasRole("gethostkey"));
+       vl->addStretch(10);
+       
+       //status bar
+       statusBar()->setSizeGripEnabled(true);
+       
+       //make sure webrequest knows its settings
+       webSettings(false);
+       //fill tables
+       if(req->hasRight(req->RGetAllEvents)){
+               updateEvents();
+       }else{
+               eventtab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(eventtab),false);
+       }
+       if(!req->hasRole("createorder")&&!req->hasRole("createsale")){
+               carttab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(carttab),false);
+       }else{
+               initCart();
+       }
+       updateShipping();
+       if(req->hasRole("getorderlist")){
+               updateOrders();
+       }else{
+               ordertab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(ordertab),false);
+       }
+       if(req->hasRole("getusers")){
+               updateUsers();
+       }else{
+               usertab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(usertab),false);
+       }
+       if(req->hasRole("gethosts")){
+               updateHosts();
+       }else{
+               hosttab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(hosttab),false);
+       }
+}
+
+void MOverview::updateEvents()
+{
+       MTGetAllEvents gae=req->queryGetAllEvents();
+       if(gae.stage()!=gae.Success){
+               qDebug("Error getting all events (%s): %s",gae.errorType().toAscii().data(),gae.errorString().toAscii().data());
+               return;
+       }
+       QList<MOEvent>evl=gae.getevents();
+       eventmodel->clear();
+       eventmodel->insertColumns(0,6);
+       eventmodel->setHorizontalHeaderLabels(QStringList()<<tr("Start Time")<<tr("Title")<<tr("Free")<<tr("Reserved")<<tr("Sold")<<tr("Capacity"));
+       QDateTime now=QDateTime::currentDateTime();
+       for(int i=0,j=0;i<evl.size();i++){
+               QDateTime stime=QDateTime::fromTime_t(evl[i].start());
+               if(stime<now && !showoldevents->isChecked())continue;
+               eventmodel->insertRow(j);
+               eventmodel->setData(eventmodel->index(j,0),evl[i].id().value(),Qt::UserRole);
+               eventmodel->setData(eventmodel->index(j,0),stime.toString(tr("ddd MMMM d yyyy, h:mm ap","time format")));
+               eventmodel->setData(eventmodel->index(j,1),evl[i].title().value());
+               eventmodel->setData(eventmodel->index(j,2),evl[i].capacity()-evl[i].amountSold()-evl[i].amountReserved());
+               eventmodel->setData(eventmodel->index(j,3),evl[i].amountReserved().value());
+               eventmodel->setData(eventmodel->index(j,4),evl[i].amountSold().value());
+               eventmodel->setData(eventmodel->index(j,5),evl[i].capacity().value());
+               j++;
+       }
+       eventtable->resizeColumnsToContents();
+       //in case this was called from changing the check state
+       QSettings().setValue("profiles/"+profilekey+"/showOldEvents",showoldevents->isChecked());
+}
+
+void MOverview::closeEvent(QCloseEvent*ce)
+{
+       //make sure session is deleted
+       req->logout();
+       //actually close window
+       QMainWindow::closeEvent(ce);
+}
+
+MOverview::~MOverview()
+{
+       //free requestor
+       req->deleteLater();
+}
+
+void MOverview::relogin()
+{
+       setEnabled(false);
+       if(!req->relogin())
+               QMessageBox::warning(this,tr("Warning"),tr("I was unable to renew the login at the server."));
+       setEnabled(true);
+}
+
+void MOverview::newEvent()
+{
+       MEventEditor ed(this);
+       ed.exec();
+       updateEvents();
+}
+
+void MOverview::editEvent()
+{
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       MEventEditor ed(this,id);
+       ed.exec();
+       updateEvents();
+}
+
+void MOverview::eventSummary()
+{
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       MEventSummary ed(this,id);
+       ed.exec();
+}
+
+void MOverview::eventCancel()
+{
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       MTGetEvent getev=MTGetEvent::query(id);
+       if(!getev.hasError()){
+               bool ok;
+               MOEvent ev=getev.getevent();
+               QString r=QInputDialog::getText(this,tr("Cancel Event"),tr("Please enter a reason to cancel event \"%1\" or abort:").arg(ev.title()),QLineEdit::Normal,"",&ok);
+               if(!ok)return;
+               MTCancelEvent cev=MTCancelEvent::query(id,r);
+               if(!cev.hasError())
+                       QMessageBox::information(this,tr("Event Cancelled"),tr("The event \"%1\" has been cancelled. Please inform everybody who bought a ticket.").arg(ev.title()));
+               else
+                       QMessageBox::warning(this,tr("Warning"),tr("Unable to cancel event \"%1\": %2.").arg(ev.title()).arg(cev.errorString()));
+       }
+}
+
+void MOverview::updateShipping()
+{
+       cartship->clear();
+       cartship->addItem(tr("(No Shipping)"),-1);
+       MTGetAllShipping sh=MTGetAllShipping::query();
+       QList<MOShipping>ship=sh.getshipping();
+       for(int i=0;i<ship.size();i++)
+               cartship->addItem(ship[i].description(),(int)ship[i].id());
+}
+
+void MOverview::updateUsers()
+{
+       MTGetAllUsers au=req->queryGetAllUsers();
+       if(au.hasError())return;
+       QList<MOUser>usl=au.getusers();
+       usermodel->clear();
+       usermodel->insertColumns(0,2);
+       usermodel->insertRows(0,usl.size());
+       usermodel->setHorizontalHeaderLabels(QStringList()<<tr("Login Name")<<tr("Description"));
+       for(int i=0;i<usl.size();i++){
+               usermodel->setData(usermodel->index(i,0),usl[i].name().value());
+               usermodel->setData(usermodel->index(i,1),usl[i].description().value());
+       }
+       usertable->resizeColumnsToContents();
+}
+
+void MOverview::newUser()
+{
+       //get name
+       QString name;
+       while(1){
+               bool ok;
+               name=QInputDialog::getText(this,tr("New User"),tr("Please enter new user name (only letters, digits, and underscore allowed):"),QLineEdit::Normal,name,&ok);
+               if(!ok)
+                       return;
+               if(QRegExp("[A-Za-z0-9_\\.,:-]+").exactMatch(name))
+                       break;
+               if(QMessageBox::warning(this,tr("Error"),tr("The user name must contain only letters, digits, dots and underscores and must be at least one character long!"),QMessageBox::Retry|QMessageBox::Abort)!=QMessageBox::Retry)
+                       return;
+       }
+       //get password
+       QString pwd=QInputDialog::getText(this,tr("Password"),tr("Please enter an initial password for the user:"),QLineEdit::Password);
+       //send request
+       req->queryCreateUser(name,pwd,"");
+       //update display
+       updateUsers();
+}
+
+void MOverview::deleteUser()
+{
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname & descr
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       //make sure user wants this
+       if(QMessageBox::question(this,tr("Delete User?"),tr("Really delete user '%1'?").arg(name),QMessageBox::Yes|QMessageBox::No)!=QMessageBox::Yes)return;
+       //get replacement
+       bool ok;
+       QStringList rplc;
+       rplc<<tr("(Nobody)","this is a username for no user, the string must contain '(' to distinguish it from the others");
+       for(int i=0;i<usermodel->rowCount();i++)
+               rplc<<usermodel->data(usermodel->index(i,0)).toString();
+       QString rp=QInputDialog::getItem(this,tr("Delete User"),tr("Select which user will inherit this users database objects:"),rplc,0,false,&ok);
+       if(!ok)return;
+       //delete
+       MTDeleteUser ret=req->queryDeleteUser(name,rp);
+       if(ret.hasError())
+               QMessageBox::warning(this,tr("Error"),tr("Cannot delete user: %1").arg(ret.errorString()));
+       updateUsers();
+}
+
+void MOverview::editUserDescription()
+{
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname & descr
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       QString descr=usermodel->data(usermodel->index(sel.row(),1)).toString();
+       //edit descr
+       bool ok;
+       descr=QInputDialog::getText(this,tr("Edit Description"),tr("Descriptionof user %1:").arg(name),QLineEdit::Normal,descr,&ok);
+       if(ok)
+               req->querySetUserDescription(name,descr);
+       //update
+       updateUsers();
+}
+
+void MOverview::editUserRoles()
+{/*TODO
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname & descr
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       //...
+       MOUser usr(req,name);
+       MCheckList acl=usr.getRoles();
+       MCheckDialog cd(this,acl,"Edit ACL of user "+name);
+       if(cd.exec()==QDialog::Accepted)
+               usr.setRoles(cd.getCheckList());*/
+}
+
+void MOverview::editUserHosts()
+{/*TODO
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname & descr
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       //...
+       MUser usr(req,name);
+       MCheckList acl=usr.getHosts();
+       MCheckDialog cd(this,acl,"Edit hosts of user "+name);
+       if(cd.exec()==QDialog::Accepted)
+               usr.setHosts(cd.getCheckList());*/
+}
+
+void MOverview::setMyPassword()
+{
+       MPasswordChange pc(this);
+       if(pc.exec()==QDialog::Accepted){
+               MTChangeMyPassword cmp=MTChangeMyPassword::query(pc.oldPassword(),pc.newPassword());
+               if(cmp.hasError())
+                       QMessageBox::warning(this,tr("Warning"),tr("Error setting password: %1").arg(cmp.errorString()));
+       }
+}
+void MOverview::setUserPassword()
+{/*TODO
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       //get new password
+       MPasswordChange pc(this,name);
+       if(pc.exec()!=QDialog::Accepted)return;
+       QString p=pc.newPassword();
+       if(p==""){
+               QMessageBox::warning(this,tr("Warning"),tr("The password must be non-empty and both lines must match"));
+               return;
+       }
+       //...
+       MUser usr(req,name);
+       usr.changePassword(p);*/
+}
+
+void MOverview::updateHosts()
+{/*TODO
+       bool foundThis=false;
+       QString thisHost=req->hostName();
+       QList<MHost>hsl=req->getAllHosts();
+       hostmodel->clear();
+       hostmodel->insertColumns(0,2);
+       hostmodel->insertRows(0,hsl.size());
+       hostmodel->setHorizontalHeaderLabels(QStringList()<<tr("Host Name")<<tr("Host Key"));
+       for(int i=0;i<hsl.size();i++){
+               hostmodel->setData(hostmodel->index(i,0),hsl[i].hostId());
+               hostmodel->setData(hostmodel->index(i,1),hsl[i].hostKey());
+               if(thisHost==hsl[i].hostId())
+                       foundThis=true;
+       }
+       hosttable->resizeColumnsToContents();
+       thishostbutton->setEnabled(!foundThis && req->hasRole("addhost"));*/
+}
+
+void MOverview::newHost()
+{/*TODO
+       //get Host Name
+       QString hname;
+       do{
+               bool ok;
+               hname=QInputDialog::getText(this,tr("Create New Host"),tr("Please enter a host name:"),QLineEdit::Normal,hname,&ok);
+               if(!ok)return;
+               if(!QRegExp("[A-Za-z][A-Za-z0-9_]*").exactMatch(hname))continue;
+       }while(false);
+       //create it
+       MHost hst(req,hname);
+       int e=hst.newKey();
+       if(e<128){
+               if(QMessageBox::warning(this,tr("Warning"),tr("The key of this new host could only be generated with %n bits entropy. Store anyway?","",e).arg(e),QMessageBox::Yes|QMessageBox::No,QMessageBox::No)!=QMessageBox::Yes)
+                       return;
+       }
+       hst.create();
+       //update
+       updateHosts();*/
+}
+
+void MOverview::addThisHost()
+{/*TODO
+       MHost hst(req,req->hostName(),QSettings().value("hostkey").toString());
+       hst.create();
+       updateHosts();*/
+}
+
+void MOverview::deleteHost()
+{/*TODO
+       //get selection
+       QModelIndex sel=hosttable->currentIndex();
+       if(!sel.isValid())return;
+       //get hname
+       QString name=hostmodel->data(hostmodel->index(sel.row(),0)).toString();
+       //ask
+       if(QMessageBox::question(this,tr("Delete this Host?"),tr("Really delete host '%1'?").arg(name),QMessageBox::Yes|QMessageBox::No)!=QMessageBox::Yes)return;
+       //delete it
+       MHost(req,name).deleteHost();
+       updateHosts();*/
+}
+
+void MOverview::changeHostKey()
+{/*TODO
+       //get selection
+       QModelIndex sel=hosttable->currentIndex();
+       if(!sel.isValid())return;
+       //get hname
+       QString name=hostmodel->data(hostmodel->index(sel.row(),0)).toString();
+       //ask
+       if(QMessageBox::question(this,tr("Change Host Key?"),tr("Really change the key of host '%1'?").arg(name),QMessageBox::Yes|QMessageBox::No)!=QMessageBox::Yes)return;
+       //change it
+       MHost hst(req,name);
+       int e=hst.newKey();
+       if(e<128){
+               if(QMessageBox::warning(this,tr("Warning"),tr("The new key of this host could only be generated with %n bits entropy. Store anyway?","",e).arg(e),QMessageBox::Yes|QMessageBox::No,QMessageBox::No)!=QMessageBox::Yes)
+                       return;
+       }
+       hst.save();
+       //update
+       updateHosts();*/
+}
+
+void MOverview::importHost()
+{/*TODO
+       QStringList fn;
+       QFileDialog fdlg(this,tr("Import Key from File"),QString(),"Magic Smoke Host Key (*.mshk)");
+       fdlg.setDefaultSuffix("mshk");
+       fdlg.setAcceptMode(QFileDialog::AcceptOpen);
+       fdlg.setFileMode(QFileDialog::ExistingFile);
+       if(!fdlg.exec())return;
+       fn=fdlg.selectedFiles();
+       if(fn.size()!=1)return;
+       QFile fd(fn[0]);
+       if(!fd.open(QIODevice::ReadOnly)){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to open file %1 for reading: %2").arg(fn[0]).arg(fd.errorString()));
+               return;
+       }
+       //read content (max: 10k to limit potential damage)
+       QStringList fc=QString::fromAscii(fd.read(10240)).split("\n",QString::SkipEmptyParts);
+       fd.close();
+       //check content
+       if(fc.size()<3){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a host key file."));
+               return;
+       }
+       if(fc[0].trimmed()!="MagicSmokeHostKey"){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a host key file."));
+               return;
+       }
+       QString hname=fc[1].trimmed();
+       if(!QRegExp("[A-Za-z][A-Za-z0-9_]*").exactMatch(hname)){
+               QMessageBox::warning(this,tr("Warning"),tr("This host key file does not contain a valid host name."));
+               return;
+       }
+       QString key=fc[2].trimmed();
+       if(!QRegExp("[0-9a-fA-F]+").exactMatch(key) || key.size()<40){
+               QMessageBox::warning(this,tr("Warning"),tr("This host key file does not contain a valid key."));
+               return;
+       }
+       QString chk=QCryptographicHash::hash(key.toAscii(),QCryptographicHash::Md5).toHex();
+       if(chk!=fc[3].trimmed()){
+               QMessageBox::warning(this,tr("Warning"),tr("The key check sum did not match. Please get a clean copy of the host key file."));
+               return;
+       }
+       //save
+       MHost hst(req,hname,key);
+       hst.create();
+       updateHosts();*/
+}
+
+void MOverview::exportHost()
+{/*TODO
+       //get selection
+       QModelIndex sel=hosttable->currentIndex();
+       if(!sel.isValid())return;
+       //get hname
+       QString name=hostmodel->data(hostmodel->index(sel.row(),0)).toString();
+       QString key=hostmodel->data(hostmodel->index(sel.row(),1)).toString();
+       if(name[0]=='_' || key==""){
+               QMessageBox::warning(this,tr("Warning"),tr("This host cannot be exported."));
+               return;
+       }
+       //save
+       QStringList fn;
+       QFileDialog fdlg(this,tr("Export Key to File"),QString(),"Magic Smoke Host Key (*.mshk)");
+       fdlg.setDefaultSuffix("mshk");
+       fdlg.setAcceptMode(QFileDialog::AcceptSave);
+       fdlg.setFileMode(QFileDialog::AnyFile);
+       if(!fdlg.exec())return;
+       fn=fdlg.selectedFiles();
+       if(fn.size()!=1)return;
+       QFile fd(fn[0]);
+       if(!fd.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to open file %1 for writing: %2").arg(fn[0]).arg(fd.errorString()));
+               return;
+       }
+       QString chk=QCryptographicHash::hash(key.toAscii(),QCryptographicHash::Md5).toHex();
+       QString out="MagicSmokeHostKey\n"+name+"\n"+key+"\n"+chk;
+       fd.write(out.toAscii());
+       fd.close();*/
+}
+
+
+void MOverview::initCart()
+{
+       //clear cart
+       cartmodel->clear();
+       cartmodel->setHorizontalHeaderLabels(QStringList()<<tr("Amount")<<tr("Title")<<tr("Start Time"));
+       //clear customer
+       customer=MCustomer();
+       cartcustomer->setText("");
+       //clear address/comment
+       cartaddr->setPlainText("");
+       cartcomment->setPlainText("");
+       //clear shipping
+       cartship->setCurrentIndex(0);
+}
+
+void MOverview::setCustomer()
+{/*TODO
+       MCustomerListDialog mcl(req,this,true,customer.customerID());
+       if(mcl.exec()!=QDialog::Accepted)return;
+       customer=mcl.getCustomer();
+       cartcustomer->setText(customer.getNameAddress());*/
+}
+
+static const int CART_TICKET=1;
+static const int CART_VOUCHER=2;
+
+static const int CART_IDROLE=Qt::UserRole;//ticket id
+static const int CART_PRICEROLE=Qt::UserRole;//voucher price
+static const int CART_VALUEROLE=Qt::UserRole+1;//voucher value
+static const int CART_TYPEROLE=Qt::UserRole+2;//which is it? ticket or voucher?
+
+void MOverview::cartAddTicket()
+{
+       //create ticket selection dialog
+       QDialog dlg;
+       dlg.setWindowTitle(tr("Select Event to order Ticket"));
+       QTableView*tv;
+       QHBoxLayout*hl;
+       QVBoxLayout*vl;
+       dlg.setLayout(vl=new QVBoxLayout);
+       vl->addWidget(tv=new QTableView,10);
+       tv->setModel(eventmodel);
+       tv->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       tv->resizeColumnsToContents();
+       vl->addSpacing(15);
+       vl->addLayout(hl=new QHBoxLayout,0);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Select")),0);
+       connect(p,SIGNAL(clicked()),&dlg,SLOT(accept()));
+       connect(tv,SIGNAL(doubleClicked(const QModelIndex&)),&dlg,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")),0);
+       connect(p,SIGNAL(clicked()),&dlg,SLOT(reject()));
+       //wait for it
+       if(dlg.exec()==QDialog::Accepted){
+               //get selection
+               QModelIndex idx=tv->currentIndex();
+               if(!idx.isValid())return;
+               int id=eventmodel->data(eventmodel->index(idx.row(),0),Qt::UserRole).toInt();
+               if(id<0)return;
+               //copy to cart
+               int cr=cartmodel->rowCount();
+               cartmodel->insertRows(cr,1);
+               cartmodel->setData(cartmodel->index(cr,0),1);
+               cartmodel->setData(cartmodel->index(cr,0),id,CART_IDROLE);
+               cartmodel->setData(cartmodel->index(cr,0),CART_TICKET,CART_TYPEROLE);
+               cartmodel->setData(cartmodel->index(cr,1),eventmodel->data(eventmodel->index(idx.row(),1)));
+               cartmodel->setData(cartmodel->index(cr,2),eventmodel->data(eventmodel->index(idx.row(),0)));
+               carttable->resizeColumnsToContents();
+       }
+}
+
+void MOverview::eventOrderTicket()
+{
+       //get selected event
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       //activate order tab
+       tab->setCurrentWidget(carttab);
+       //insert event into table
+       int cr=cartmodel->rowCount();
+       cartmodel->insertRows(cr,1);
+       cartmodel->setData(cartmodel->index(cr,0),1);
+       cartmodel->setData(cartmodel->index(cr,0),id,CART_IDROLE);
+       cartmodel->setData(cartmodel->index(cr,0),CART_TICKET,CART_TYPEROLE);
+       cartmodel->setData(cartmodel->index(cr,1),eventmodel->data(eventmodel->index(ilst[0].row(),1)));
+       cartmodel->setData(cartmodel->index(cr,2),eventmodel->data(eventmodel->index(ilst[0].row(),0)));
+       carttable->resizeColumnsToContents();
+}
+
+void MOverview::cartAddVoucher()
+{/*TODO
+       //create voucher selection dialog
+       QDialog dlg;
+       dlg.setWindowTitle(tr("Select Voucher"));
+       QComboBox*cp,*cv;
+       QHBoxLayout*hl;
+       QGridLayout*gl;
+       QStandardItemModel mdl;
+       QRegExpValidator regv(priceRegExp(),this);
+       QList<int>prc=req->getVoucherPrices();
+       mdl.insertRows(0,prc.size());
+       mdl.insertColumns(0,1);
+       for(int i=0;i<prc.size();i++)mdl.setData(mdl.index(i,0),cent2str(prc[i]));
+       dlg.setLayout(gl=new QGridLayout);
+       gl->addWidget(new QLabel(tr("Select voucher price and value:")),0,0,1,2);
+       if(req->hasRole("_anypricevoucher")){
+               gl->addWidget(new QLabel(tr("Price:")),1,0);
+               gl->addWidget(cp=new QComboBox,1,1);
+               cp->setModel(&mdl);
+               cp->setEditable(true);
+               cp->setValidator(&regv);
+       }else cp=0;
+       gl->addWidget(new QLabel(tr("Value:")),2,0);
+       gl->addWidget(cv=new QComboBox,2,1);
+       cv->setModel(&mdl);
+       cv->setEditable(req->hasRole("_anyvoucher"));
+       cv->setValidator(&regv);
+       gl->setRowMinimumHeight(3,15);
+       gl->setColumnStretch(0,0);
+       gl->setColumnStretch(1,1);
+       gl->setRowStretch(3,1);
+       gl->addLayout(hl=new QHBoxLayout,4,0,1,2);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Ok")),0);
+       connect(p,SIGNAL(clicked()),&dlg,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")),0);
+       connect(p,SIGNAL(clicked()),&dlg,SLOT(reject()));
+       //wait for it
+       if(dlg.exec()==QDialog::Accepted){
+               //get selection
+               int price,value;
+               value=str2cent(cv->currentText());
+               if(req->hasRole("_anypricevoucher") && cp)
+                       price=str2cent(cp->currentText());
+               else
+                       price=value;
+               //copy to cart
+               int cr=cartmodel->rowCount();
+               cartmodel->insertRows(cr,1);
+               cartmodel->setData(cartmodel->index(cr,0),1);
+               cartmodel->setData(cartmodel->index(cr,0),price,CART_PRICEROLE);
+               cartmodel->setData(cartmodel->index(cr,0),value,CART_VALUEROLE);
+               cartmodel->setData(cartmodel->index(cr,0),CART_VOUCHER,CART_TYPEROLE);
+               cartmodel->setData(cartmodel->index(cr,1),tr("Voucher (price: %1, value %2)").arg(cent2str(price)).arg(cent2str(value)));
+               carttable->resizeColumnsToContents();
+       }*/
+}
+
+void MOverview::cartRemoveItem()
+{
+       //get selection
+       QModelIndex idx=carttable->currentIndex();
+       if(!idx.isValid())return;
+       //remove row
+       cartmodel->removeRow(idx.row());
+}
+
+void MOverview::cartOrder()
+{
+       //sanity checks
+       if(cartmodel->rowCount()<1){
+               QMessageBox::warning(this,tr("Error"),tr("There is nothing in the order. Ignoring it."));
+               return;
+       }
+       if(!customer.isValid()){
+               QMessageBox::warning(this,tr("Error"),tr("Please chose a customer first!"));
+               return;
+       }
+       ///////////////
+       //create order
+       QDomDocument doc;
+       QDomElement root=doc.createElement("Order");
+       root.setAttribute("customer",customer.id());
+       //is there a delivery address
+       QString s=cartaddr->toPlainText().trimmed();
+       if(s!=""){
+               QDomElement da=doc.createElement("DeliveryAddress");
+               da.appendChild(doc.createTextNode(s));
+               root.appendChild(da);
+       }
+       //is there a comment?
+       s=cartcomment->toPlainText().trimmed();
+       if(s!=""){
+               QDomElement cc=doc.createElement("Comment");
+               cc.appendChild(doc.createTextNode(s));
+               root.appendChild(cc);
+       }
+       //scan tickets & scan vouchers
+       for(int i=0;i<cartmodel->rowCount();i++){
+               QModelIndex idx=cartmodel->index(i,0);
+               int tp=cartmodel->data(idx,CART_TYPEROLE).toInt();
+               if(tp==CART_TICKET){
+                       int amt=cartmodel->data(idx).toInt();
+                       int evid=cartmodel->data(idx,CART_IDROLE).toInt();
+                       for(int j=0;j<amt;j++){
+                               QDomElement tc=doc.createElement("Ticket");
+                               tc.setAttribute("event",evid);
+                               root.appendChild(tc);
+                       }
+               }else
+               if(tp==CART_VOUCHER){
+                       int amt=cartmodel->data(idx).toInt();
+                       int price=cartmodel->data(idx,CART_PRICEROLE).toInt();
+                       int value=cartmodel->data(idx,CART_VALUEROLE).toInt();
+                       for(int j=0;j<amt;j++){
+                               QDomElement tc=doc.createElement("Voucher");
+                               tc.setAttribute("price",price);
+                               tc.setAttribute("value",value);
+                               root.appendChild(tc);
+                       }
+               
+               }
+       }
+       //set shipping info
+       if(cartship->currentIndex()>0){
+               QDomElement si=doc.createElement("Shipping");
+               si.setAttribute("type",cartship->itemData(cartship->currentIndex()).toInt());
+               root.appendChild(si);
+       }
+       //finalize
+       doc.appendChild(root);
+       //send
+       /*TODO
+       if(req->request("checkorder",doc.toByteArray())==false){
+               QMessageBox::warning(this,tr("Error"),tr("The request failed."));
+               return;
+       }
+       if(req->responseStatus()!=MSInterface::Ok){
+               QMessageBox::warning(this,tr("Error"),tr("A problem occurred during the order: %1").arg(qApp->translate("php::",req->responseBody())));
+               return;
+       }
+       //parse result
+       QDomDocument rdoc;
+       rdoc.setContent(req->responseBody());
+       //display order and give user chance to actually order it
+       MOrderWindow *ow=new MOrderWindow(this,req,MOrder(req,rdoc.documentElement()));
+       ow->show();
+       //empty the cart
+       initCart();*/
+}
+
+void MOverview::customerMgmt()
+{/*TODO
+       MCustomerListDialog mcl(req,this);
+       mcl.exec();*/
+}
+
+void MOverview::editShipping()
+{/*TODO
+       MShippingEditor se(req,this);
+       se.exec();
+       updateShipping();*/
+}
+
+void MOverview::tabChanged()
+{/*TODO
+       QWidget*w=tab->currentWidget();
+       if(w==entrancetab){
+               //fill combobox from eventmodel
+               int ci=entranceevent->currentIndex();
+               int cev=-1;
+               if(ci>=0)cev=entranceevent->itemData(ci).toInt();
+               ci=-1;
+               entranceevent->clear();
+               for(int i=0;i<eventmodel->rowCount();i++){
+                       QString ev=eventmodel->data(eventmodel->index(i,0)).toString()+" "+
+                        eventmodel->data(eventmodel->index(i,1)).toString();
+                       int eid=eventmodel->data(eventmodel->index(i,0),Qt::UserRole).toInt();
+                       entranceevent->addItem(ev,eid);
+                       if(eid==cev)ci=i;
+               }
+               if(ci>=0)entranceevent->setCurrentIndex(ci);
+               //set focus on scanner
+               entrancescan->setFocus(Qt::OtherFocusReason);
+               entrancescan->setText("");
+       }*/
+}
+
+void MOverview::entranceValidate()
+{/*TODO
+       //get event ID
+       int ci=entranceevent->currentIndex();
+       if(ci<0)return;
+       int cev=entranceevent->itemData(ci).toInt();
+       //check content
+       QString tid=entrancescan->text().trimmed();
+       entrancescan->setText("");
+       //avoid spurious events
+       if(tid=="")return;
+       //avoid double scans
+       QDateTime now=QDateTime::currentDateTime();
+       if(tid==lastbarcode && lastbcscan.addSecs(20)>=now)
+               return;
+       lastbarcode=tid;
+       lastbcscan=now;
+       //reset display
+       QPalette pal=entrancelabel->palette();
+       QPalette::ColorRole rl=QPalette::Window;
+       pal.setColor(rl,Qt::lightGray);
+       entrancelabel->setPalette(pal);
+       entrancelabel->setText(tr("searching...","entrance control"));
+       //ask the server
+       MTicket tick(req,tid);
+       //decide what to do
+       if(!tick.isValid()){
+               entrancelabel->setText(tr("Ticket \"%1\" Not Valid").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else
+       if(tick.eventID()!=cev){
+               entrancelabel->setText(tr("Ticket \"%1\" is not for this event.").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else
+       if(tick.status()==MTicket::Used){
+               entrancelabel->setText(tr("Ticket \"%1\" has already been used").arg(tid));
+               pal.setColor(rl,Qt::magenta);
+       }else
+       if(tick.status()!=MTicket::Bought){
+               entrancelabel->setText(tr("Ticket \"%1\" has not been bought.").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else
+       if(tick.paymentStatus()==MTicket::PSOk){
+               entrancelabel->setText(tr("Ticket \"%1\" Ok").arg(tid));
+               pal.setColor(rl,Qt::green);
+               tick.markUsed();
+       }else
+       if(tick.paymentStatus()==MTicket::PSNeedRefund){
+               entrancelabel->setText(tr("Ticket \"%1\" Ok; the Order has a refund").arg(tid));
+               pal.setColor(rl,Qt::green);
+               tick.markUsed();
+       }else
+       if(tick.paymentStatus()==MTicket::PSNeedPayment){
+               entrancelabel->setText(tr("Ticket \"%1\" is not paid for!").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else{
+               entrancelabel->setText(tr("Ticket \"%1\" cannot be accepted, please check the order!").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }
+       
+       entrancelabel->setPalette(pal);
+       entrancescan->setFocus(Qt::OtherFocusReason);
+       entrancescan->setText("");*/
+}
+
+//helper: finds out whether an order should be printed.
+static inline bool candoUpdateOrders(int omode,const MOrder&ord)
+{
+       if(omode==ORDERALL)return true;
+       if((omode&ORDERPAY)!=0 && ord.needsPayment())return true;
+       if((omode&ORDERREFUND)!=0 && ord.needsRefund())return true;
+       if((omode&ORDERUNSENT)!=0 && !ord.isSent())return true;
+       if((omode&ORDERRESERVE)!=0 && ord.isReservation())return true;
+       return false;
+}
+
+void MOverview::updateOrders()
+{/*TODO
+       ordermodel->clear();
+       ordermodel->setHorizontalHeaderLabels(QStringList()<<tr("Status")<<tr("Total")<<tr("Paid")<<tr("Customer"));
+       int omode=ordermode->itemData(ordermode->currentIndex()).toInt();
+       if(omode==ORDERNONE)return;
+       QList<MOrder> orders=req->getAllOrders();
+       if(orders.size()==0)return;
+       QList<MCustomer> cust=req->getAllCustomers();
+       int cl=0;
+       for(int i=0;i<orders.size();i++){
+               if(!candoUpdateOrders(omode,orders[i]))continue;
+               ordermodel->insertRow(cl);
+               ordermodel->setHeaderData(cl,Qt::Vertical,orders[i].orderID());
+               ordermodel->setData(ordermodel->index(cl,0),orders[i].orderStatusString());
+               ordermodel->setData(ordermodel->index(cl,0),orders[i].orderID(),Qt::UserRole);
+               ordermodel->setData(ordermodel->index(cl,1),orders[i].totalPriceString());
+               ordermodel->setData(ordermodel->index(cl,2),orders[i].amountPaidString());
+               int cid=orders[i].customerID();
+               //TODO: make this more effective:
+               for(int j=0;j<cust.size();j++)
+                       if(cust[j].customerID()==cid)
+                               ordermodel->setData(ordermodel->index(cl,3),cust[j].name());
+               cl++;
+       }
+       ordertable->resizeColumnsToContents();*/
+}
+
+void MOverview::orderDetails()
+{/*TODO
+       //get selected order
+       int id;
+       QModelIndexList ilst=ordertable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=ordermodel->index(ilst[0].row(),0);
+       id=ordermodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       //open order window
+       MOrderWindow *om=new MOrderWindow(this,req,MOrder(req,id));
+       om->setAttribute(Qt::WA_DeleteOnClose);
+       om->show();*/
+}
+
+void MOverview::orderByTicket()
+{/*TODO
+       //get selected order
+       bool ok;
+       QString tid=QInputDialog::getText(this,tr("Enter Ticket"),tr("Please enter the ID of one of the tickets of the order you seek:"),QLineEdit::Normal,"",&ok);
+       if(!ok || tid=="")return;
+       //request it
+       if(!req->request("orderbyticket",tid.toUtf8())){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to query server."));
+               return;
+       }
+       if(req->responseStatus()!=MSInterface::Ok){
+               QMessageBox::warning(this,tr("Warning"),qApp->translate("php::",req->responseBody()));
+               return;
+       }
+       int id=req->responseBody().trimmed().toInt(&ok);
+       if(!ok || id<0){
+               QMessageBox::warning(this,tr("Warning"),tr("Server returned an invalid order ID."));
+               return;
+       }
+       //open order window
+       MOrderWindow *om=new MOrderWindow(this,req,MOrder(req,id));
+       om->setAttribute(Qt::WA_DeleteOnClose);
+       om->show();*/
+}
+
+void MOverview::orderByEvent()
+{/*TODO
+       //display selection dialog
+       QDialog d(this);
+       d.setWindowTitle(tr("Select Event"));
+       QVBoxLayout*vl;
+       QHBoxLayout*hl;
+       d.setLayout(vl=new QVBoxLayout);
+       QTableView*tv;
+       vl->addWidget(tv=new QTableView,10);
+       tv->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       tv->setModel(eventmodel);
+       tv->resizeColumnsToContents();
+       vl->addLayout(hl=new QHBoxLayout,0);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Ok")),0);
+       connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")),0);
+       connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+       //wait for user
+       if(d.exec()!=QDialog::Accepted)
+               return;
+       //get selection
+       QModelIndexList ilst=tv->selectionModel()->selectedIndexes();
+       if(ilst.size()<1){
+               qDebug("nothing selected");
+               return;
+       }
+       //get events
+       QList<int>eventids;
+       for(int i=0;i<ilst.size();i++){
+               int eid=eventmodel->data(eventmodel->index(ilst[i].row(),0),Qt::UserRole).toInt();
+               if(!eventids.contains(eid))eventids.append(eid);
+       }
+       //request data and display
+       //TODO: unify this part with updateOrders
+       ordermodel->clear();
+       ordermodel->setHorizontalHeaderLabels(QStringList()<<tr("Status")<<tr("Total")<<tr("Paid")<<tr("Customer"));
+       QList<MOrder> orders=req->getOrdersByEvents(eventids);
+       if(orders.size()==0)return;
+       QList<MCustomer> cust=req->getAllCustomers();
+       for(int cl=0;cl<orders.size();cl++){
+               ordermodel->insertRow(cl);
+               ordermodel->setHeaderData(cl,Qt::Vertical,orders[cl].orderID());
+               ordermodel->setData(ordermodel->index(cl,0),orders[cl].orderStatusString());
+               ordermodel->setData(ordermodel->index(cl,0),orders[cl].orderID(),Qt::UserRole);
+               ordermodel->setData(ordermodel->index(cl,1),orders[cl].totalPriceString());
+               ordermodel->setData(ordermodel->index(cl,2),orders[cl].amountPaidString());
+               int cid=orders[cl].customerID();
+               //TODO: make this more effective:
+               for(int j=0;j<cust.size();j++)
+                       if(cust[j].customerID()==cid)
+                               ordermodel->setData(ordermodel->index(cl,3),cust[j].name());
+       }
+       ordermode->setCurrentIndex(ordermode->count()-1);*/
+}
+
+void MOverview::orderByCustomer()
+{/*TODO
+       //display selection dialog
+       MCustomerListDialog mcl(req,this,true);
+       //wait for user
+       if(mcl.exec()!=QDialog::Accepted)
+               return;
+       //get selection
+       MCustomer cst=mcl.getCustomer();
+       if(!cst.isValid()){
+               qDebug("nothing selected");
+               return;
+       }
+       qint64 custid=cst.customerID();
+       //request data and display
+       //TODO: unify this part with updateOrders
+       ordermodel->clear();
+       ordermodel->setHorizontalHeaderLabels(QStringList()<<tr("Status")<<tr("Total")<<tr("Paid")<<tr("Customer"));
+       QList<MOrder> orders=req->getAllOrders();
+       if(orders.size()==0)return;
+       QList<MCustomer> cust=req->getAllCustomers();
+       int cl=0;
+       for(int i=0;i<orders.size();i++){
+               //filter
+               if(orders[i].customerID()!=custid)continue;
+               //put into table
+               ordermodel->insertRow(cl);
+               ordermodel->setHeaderData(cl,Qt::Vertical,orders[i].orderID());
+               ordermodel->setData(ordermodel->index(cl,0),orders[i].orderStatusString());
+               ordermodel->setData(ordermodel->index(cl,0),orders[i].orderID(),Qt::UserRole);
+               ordermodel->setData(ordermodel->index(cl,1),orders[i].totalPriceString());
+               ordermodel->setData(ordermodel->index(cl,2),orders[i].amountPaidString());
+               ordermodel->setData(ordermodel->index(cl,3),cst.name());
+               //count up
+               cl++;
+       }
+       ordermode->setCurrentIndex(ordermode->count()-1);*/
+}
+
+void MOverview::orderByOrder()
+{/*TODO
+       //ask for OrderID
+       bool ok;
+       int oid=QInputDialog::getInteger(this,tr("Enter Order ID"),tr("Please enter the ID of the order you want to display:"),0,0,2147483647,1,&ok);
+       if(!ok)return;
+       //display
+       MOrder ord(req,oid);
+       if(!ord.isValid()){
+               QMessageBox::warning(this,tr("Warning"),tr("This order does not exist."));
+               return;
+       }
+       MOrderWindow *ow=new MOrderWindow(this,req,ord);
+       ow->show();*/
+}
+
+void MOverview::ticketReturn()
+{/*TODO
+       //get ticket
+       bool ok;
+       QString tid=QInputDialog::getText(this,tr("Return Ticket"),tr("Please enter the ticket ID to return:"),QLineEdit::Normal,"",&ok);
+       if(!ok || tid=="")return;
+       MTicket tick(req,tid);
+       if(!tick.isValid()){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a valid ticket."));
+               return;
+       }
+       //check state
+       if(tick.status()!=MTicket::Bought && tick.status()!=MTicket::Reserved){
+               QMessageBox::warning(this,tr("Warning"),tr("This ticket cannot be returned, it has already been used or is in the wrong state."));
+               return;
+       }
+       //submit
+       QString r=tick.ticketReturn();
+       if(r!="")QMessageBox::warning(this,tr("Warning"),trUtf8(r.toUtf8()));*/
+}
+
+void MOverview::voucherReturn()
+{/*TODO
+       //get ticket
+       bool ok;
+       QString tid=QInputDialog::getText(this,tr("Return Voucher"),tr("Please enter the voucher ID to return:"),QLineEdit::Normal,"",&ok);
+       if(!ok || tid=="")return;
+       MVoucher vouc(req,tid);
+       if(!vouc.isValid()){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a valid voucher."));
+               return;
+       }
+       //check state
+       if(vouc.isUsed()){
+               QMessageBox::warning(this,tr("Warning"),tr("This voucher cannot be returned, it has already been used."));
+               return;
+       }
+       //submit
+       QString r=vouc.voucherReturn();
+       if(r!="")QMessageBox::warning(this,tr("Warning"),trUtf8(r.toUtf8()));*/
+}
+
+void MOverview::deductVoucher()
+{/*TODO
+       //get voucher ID and amount
+       QDialog d;
+       d.setWindowTitle(tr("Deduct from Voucher"));
+       QGridLayout *gl;
+       d.setLayout(gl=new QGridLayout);
+       gl->addWidget(new QLabel(tr("Using a voucher to pay outside the system.")),0,0,1,2);
+       
+       QLineEdit*vid;
+       MCentSpinBox*cent;
+       gl->addWidget(new QLabel(tr("Amount to deduct:")),1,0);
+       gl->addWidget(cent=new MCentSpinBox,1,1);
+       gl->addWidget(new QLabel(tr("Voucher ID:")),2,0);
+       gl->addWidget(vid=new QLineEdit,2,1);
+       
+       gl->setRowMinimumHeight(3,15);
+       QHBoxLayout*hl;
+       gl->addLayout(hl=new QHBoxLayout,4,0,1,2);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("OK")));
+       connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")));
+       connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+       if(d.exec()!=QDialog::Accepted)return;
+       if(vid->text().trimmed()=="" || cent->value()<=0)return;
+       //query server
+       QByteArray r=vid->text().trimmed().toAscii()+"\n"+QString::number(cent->value()).toAscii();
+       if(!req->request("usevoucheroutside",r)){
+               QMessageBox::warning(this,tr("Warning"),tr("Request failed."));
+               return;
+       }
+       if(req->responseStatus()!=MSInterface::Ok){
+               QMessageBox::warning(this,tr("Warning"),tr("Request failed."));
+               return;
+       }
+       QStringList sl=QString::fromAscii(req->responseBody().trimmed()).split("\n");
+       int tak=-1,rem=-1;
+       if(sl.size()>0)tak=sl[0].trimmed().toInt();
+       if(sl.size()>1)rem=sl[1].trimmed().toInt();
+       QMessageBox::information(this,tr("Deducted from Voucher"),tr("Value taken from voucher: %1\nValue remaining on voucher: %2").arg(cent2str(tak)).arg(cent2str(rem)));*/
+}
+
+void MOverview::refreshData()
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       if(set.value("refreshEvents",false).toBool() && req->hasRole("geteventlist"))
+               updateEvents();
+       if(set.value("refreshUsers",false).toBool() && req->hasRole("getusers"))
+               updateUsers();
+       if(set.value("refreshHosts",false).toBool() && req->hasRole("gethosts"))
+               updateHosts();
+       if(set.value("refreshShipping",false).toBool() && req->hasRole("getshipping"))
+               updateShipping();
+}
+
+void MOverview::setRefresh()
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       //dialog
+       QDialog d;
+       d.setWindowTitle(tr("Refresh Settings"));
+       QVBoxLayout*vl;
+       QHBoxLayout*hl;
+       d.setLayout(vl=new QVBoxLayout);
+       vl->addLayout(hl=new QHBoxLayout);
+       hl->addWidget(new QLabel(tr("Refresh Rate (minutes):")),1);
+       QSpinBox*rate;
+       hl->addWidget(rate=new QSpinBox,0);
+       rate->setRange(1,999);
+       rate->setValue(set.value("refresh",300).toInt()/60);
+       QCheckBox *rev,*rus,*rho,*rsh;
+       vl->addWidget(rev=new QCheckBox(tr("refresh &event list")));
+       rev->setChecked(set.value("refreshEvents",false).toBool());
+       vl->addWidget(rus=new QCheckBox(tr("refresh &user list")));
+       rus->setChecked(set.value("refreshUsers",false).toBool());
+       vl->addWidget(rho=new QCheckBox(tr("refresh &host list")));
+       rho->setChecked(set.value("refreshHosts",false).toBool());
+       vl->addWidget(rsh=new QCheckBox(tr("refresh &shipping list")));
+       rho->setChecked(set.value("refreshShipping",false).toBool());
+       vl->addSpacing(15);
+       vl->addStretch(10);
+       vl->addLayout(hl=new QHBoxLayout);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("&OK")));
+       connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("&Cancel")));
+       connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+       if(d.exec()!=QDialog::Accepted)return;
+       //write settings
+       set.setValue("refreshEvents",rev->isChecked());
+       set.setValue("refreshUsers",rus->isChecked());
+       set.setValue("refreshHosts",rho->isChecked());
+       set.setValue("refreshShipping",rsh->isChecked());
+       set.setValue("refresh",rate->value()*60);
+       //reset timer
+       rtimer.stop();
+       rtimer.setInterval(rate->value()*60000);
+       rtimer.start();
+}
+
+void MOverview::webSettings(bool showdlg)
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       //get settings
+       MSInterface::LogLevel lvl=MSInterface::LogLevel(set.value("webloglevel", MSInterface::LogOnError).toInt());
+       int timeout=set.value("webtimeout",30).toInt();
+       //dialog
+       if(showdlg){
+               QDialog d;
+               d.setWindowTitle(tr("Server Access Settings"));
+               QGridLayout*gl;
+               QHBoxLayout*hl;
+               d.setLayout(gl=new QGridLayout);
+               gl->addWidget(new QLabel(tr("Request Timeout (seconds):")),0,0);
+               QSpinBox*tmout;
+               gl->addWidget(tmout=new QSpinBox,0,1);
+               tmout->setRange(10,999);
+               tmout->setValue(timeout);
+               QComboBox *log;
+               gl->addWidget(new QLabel(tr("Log Level:")),1,0);
+               gl->addWidget(log=new QComboBox,1,1);
+               log->addItem(tr("Minimal Logging"),MSInterface::LogMinimal);
+               log->addItem(tr("Log Details on Error"),MSInterface::LogOnError);
+               log->addItem(tr("Always Log Details"),MSInterface::LogDetailed);
+               switch(lvl){
+                       case MSInterface::LogMinimal:log->setCurrentIndex(0);break;
+                       case MSInterface::LogOnError:log->setCurrentIndex(1);break;
+                       case MSInterface::LogDetailed:log->setCurrentIndex(2);break;
+               }
+               gl->setRowMinimumHeight(2,15);
+               gl->addLayout(hl=new QHBoxLayout,3,0,1,2);
+               hl->addStretch(10);
+               QPushButton*p;
+               hl->addWidget(p=new QPushButton(tr("&OK")));
+               connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+               hl->addWidget(p=new QPushButton(tr("&Cancel")));
+               connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+               if(d.exec()!=QDialog::Accepted)return;
+               //write settings
+               lvl=MSInterface::LogLevel(log->itemData(log->currentIndex()).toInt());
+               timeout=tmout->value();
+               set.setValue("webloglevel",lvl);
+               set.setValue("webtimeout",timeout);
+       }
+       //reset webrequest
+       req->setLogLevel(lvl);
+       req->setWebTimeout(timeout*1000);
+}
+
+void MOverview::doBackup()
+{
+       baktimer.stop();
+       //sanity check
+       if(!req->hasRight(req->RBackup))return;
+       //get settings
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       QString path=set.value("backupfile",req->dataDir()+"/backup").toString();
+       int gens=set.value("backupgenerations",3).toInt();
+       //get data
+       MTBackup bc;
+       bc=MTBackup::query();
+       if(bc.stage()!=bc.Success){
+               QMessageBox::warning(this,tr("Warning"),tr("Backup failed with error (%2): %1").arg(bc.errorString()).arg(bc.errorType()));
+               return;
+       }
+       if(bc.getbackup().isNull()||bc.getbackup().value().isEmpty()){
+               QMessageBox::warning(this,tr("Warning"),tr("Backup returned empty."));
+               return;
+       }
+       //rotate files
+       QFile(path+"."+QString::number(gens)).remove();
+       for(int i=gens-1;i>=0;i--){
+               if(i)
+                       QFile(path+"."+QString::number(i)).rename(path+"."+QString::number(i+1));
+               else
+                       QFile(path).rename(path+".1");
+       }
+       //store new data
+       QFile fd(path);
+       if(fd.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+               fd.write(bc.getbackup().value().toAscii());
+               fd.close();
+               set.setValue("backuptime",QDateTime::currentDateTime().toTime_t());
+               QMessageBox::information(this,tr("Backup"),tr("The backup was successful."));
+               int tm=set.value("backupinterval",0).toInt()*86400000;
+               if(tm)baktimer.start(tm);
+       }else
+               QMessageBox::warning(this,tr("Warning"),tr("Cannot create backup file."));
+}
+
+void MOverview::backupSettings()
+{
+       //show dialog
+       MBackupDialog d(this,profilekey);
+       d.exec();
+       //reset timer
+       int btm=QSettings().value("profiles/"+profilekey+"/backupinterval",0).toInt()*86400;
+       if(btm){
+               //adjust for last backup time
+               int iv=QDateTime::currentDateTime().toTime_t() - QSettings().value("profiles/"+profilekey+"/backuptime",0).toInt();
+               if(iv>=btm)btm=0;
+               else btm-=iv;
+               //start timer
+               baktimer.start(btm*1000);
+       }
+}
+
+void MOverview::moneylogVoucher()
+{/*TODO
+       QString vid=QInputDialog::getText(this,tr("Voucher ID"),tr("Please enter voucher ID to show log:"));
+       if(vid!="")
+               MMoneyLog(this,req,"voucher\n"+vid).exec();*/
+}
+
+void MOverview::moneylogUser()
+{/*TODO
+       QString vid=QInputDialog::getText(this,tr("User"),tr("Please enter login name of user to show log:"));
+       if(vid!="")
+               MMoneyLog(this,req,"user\n"+vid).exec();*/
+}
+
+
+/**********************************************/
+
+MBackupDialog::MBackupDialog(QWidget*par,QString pk)
+       :QDialog(par),profilekey(pk)
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       QString path=set.value("backupfile",req->dataDir()+"/backup").toString();
+       int gens=set.value("backupgenerations",3).toInt();
+       int tm=set.value("backupinterval",0).toInt();
+       //dialog
+       setWindowTitle(tr("Backup Settings"));
+       QGridLayout*gl;
+       QHBoxLayout*hl;
+       setLayout(gl=new QGridLayout);
+       QPushButton*p;
+       gl->addWidget(new QLabel(tr("Backup File:")),0,0);
+       gl->addWidget(lpath=new QLineEdit(path),0,1);
+       gl->addWidget(p=new QPushButton(tr("...")),0,2);
+       connect(p,SIGNAL(clicked()),this,SLOT(getpath()));
+       
+       gl->addWidget(new QLabel(tr("Generations to keep:")),1,0);
+       gl->addWidget(gener=new QSpinBox,1,1,1,2);
+       gener->setRange(1,16);
+       gener->setValue(gens);
+       
+       gl->addWidget(new QLabel(tr("Automatic Backup:")),2,0);
+       gl->addWidget(autob=new QCheckBox,2,1,1,2);
+       autob->setChecked(tm>0);
+       
+       gl->addWidget(new QLabel(tr("Interval in days:")),3,0);
+       gl->addWidget(interv=new QSpinBox,3,1,1,2);
+       interv->setRange(1,24);
+       interv->setValue(tm>0?tm:1);
+       
+       gl->setRowMinimumHeight(4,15);
+       gl->addLayout(hl=new QHBoxLayout,5,0,1,3);
+       hl->addStretch(10);
+       hl->addWidget(p=new QPushButton(tr("&OK")));
+       connect(p,SIGNAL(clicked()),this,SLOT(accept()));
+       connect(p,SIGNAL(clicked()),this,SLOT(save()));
+       hl->addWidget(p=new QPushButton(tr("&Cancel")));
+       connect(p,SIGNAL(clicked()),this,SLOT(reject()));
+}
+
+void MBackupDialog::getpath()
+{
+       QString path=QFileDialog::getSaveFileName(this,tr("Backup File"),lpath->text());
+       if(path!="")lpath->setText(path);
+}
+
+void MBackupDialog::save()
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       set.setValue("backupfile",lpath->text());
+       set.setValue("backupgenerations",gener->value());
+       set.setValue("backupinterval",autob->isChecked()?interv->value():0);
+}
+/**********************************************/
+
+MPasswordChange::MPasswordChange(QWidget*par,QString user)
+       :QDialog(par)
+{
+       oldpwd=newpwd1=newpwd2=0;
+       if(user=="")
+               setWindowTitle(tr("Change my password"));
+       else
+               setWindowTitle(tr("Reset password of user \"%1\"").arg(user));
+       QGridLayout*gl;
+       setLayout(gl=new QGridLayout);
+       if(user==""){
+               gl->addWidget(new QLabel(tr("Old Password:")),0,0);
+               gl->addWidget(oldpwd=new QLineEdit,0,1);
+               oldpwd->setEchoMode(QLineEdit::Password);
+       }
+       gl->addWidget(new QLabel(tr("New Password:")),1,0);
+       gl->addWidget(newpwd1=new QLineEdit,1,1);
+       newpwd1->setEchoMode(QLineEdit::Password);
+       gl->addWidget(new QLabel(tr("Repeat Password:")),2,0);
+       gl->addWidget(newpwd2=new QLineEdit,2,1);
+       newpwd2->setEchoMode(QLineEdit::Password);
+       
+       QHBoxLayout*hl;
+       gl->addLayout(hl=new QHBoxLayout,3,0,1,2);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Set Password")));
+       connect(p,SIGNAL(clicked()),this,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")));
+       connect(p,SIGNAL(clicked()),this,SLOT(reject()));
+}
+
+QString MPasswordChange::oldPassword()
+{
+       if(oldpwd)return oldpwd->text();
+       return "";
+}
+
+QString MPasswordChange::newPassword()
+{
+       if(newpwd1==0 || newpwd2==0)return "";
+       if(newpwd1->text()!=newpwd2->text())return "";
+       return newpwd1->text();
+}
+
+
+/********************************************************************************/
+
+MCartTableDelegate::MCartTableDelegate(QObject*p)
+       :QItemDelegate(p)
+{
+}
+
+QWidget *MCartTableDelegate::createEditor(QWidget *parent,
+        const QStyleOptionViewItem &/* option */,
+        const QModelIndex & index ) const
+{
+       //base class
+       if(index.column()!=0)return 0;
+       
+       QSpinBox *editor = new QSpinBox(parent);
+       editor->setRange(1,1000);
+       editor->installEventFilter(const_cast<MCartTableDelegate*>(this));
+       return editor;
+}
+
+void MCartTableDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
+{
+       //name field
+       int c=index.column();
+       if(c==0)
+               ((QSpinBox*)editor)->setValue(index.model()->data(index).toInt());
+}
+
+void MCartTableDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
+       const QModelIndex &index) const
+{
+       //name field
+       int c=index.column();
+       if(c==0){
+               int newval=((QSpinBox*)editor)->value();
+               model->setData(index,newval);
+       }
+}
diff --git a/src/mwin/entrancetab.h b/src/mwin/entrancetab.h
new file mode 100644 (file)
index 0000000..dfd5a43
--- /dev/null
@@ -0,0 +1,235 @@
+//
+// C++ Interface: overview
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2007
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef MAGICSMOKE_OVERVIEW_H
+#define MAGICSMOKE_OVERVIEW_H
+
+#include <QDateTime>
+#include <QDialog>
+#include <QItemDelegate>
+#include <QMainWindow>
+#include <QTimer>
+
+#include "customer.h"
+
+class QAction;
+class QCheckBox;
+class QComboBox;
+class QLabel;
+class QLineEdit;
+class QPushButton;
+class QSpinBox;
+class QStandardItemModel;
+class QTabWidget;
+class QTableView;
+
+class MSInterface;
+
+/**Main Overview Window*/
+class MOverview:public QMainWindow
+{
+       Q_OBJECT
+       public:
+               /**construct the window with web-request/session handler and QSettings-key for current profile*/
+               MOverview(QString);
+               ~MOverview();
+       protected:
+               /**handle closing the window: close the session too*/
+               void closeEvent(QCloseEvent*);
+       private slots:
+               /**try to log in again*/
+               void relogin();
+               
+               /**create a new event*/
+               void newEvent();
+               /**edit existing event*/
+               void editEvent();
+               /**update list of events*/
+               void updateEvents();
+               /**order ticket from event tab*/
+               void eventOrderTicket();
+               /**open event summary*/
+               void eventSummary();
+               /**cancel the event*/
+               void eventCancel();
+               
+               /**update shipping info*/
+               void updateShipping();
+               
+               /**get all orders, update list*/
+               void updateOrders();
+               /**open order detail window*/
+               void orderDetails();
+               
+               /**update list of users*/
+               void updateUsers();
+               /**create new user*/
+               void newUser();
+               /**delete selected user*/
+               void deleteUser();
+               /**set users description*/
+               void editUserDescription();
+               /**set users roles*/
+               void editUserRoles();
+               /**set users hosts*/
+               void editUserHosts();
+               /**set my own password*/
+               void setMyPassword();
+               /**set a users password*/
+               void setUserPassword();
+               
+               /**update list of hosts*/
+               void updateHosts();
+               /**create new host*/
+               void newHost();
+               /**create a database entry for this host*/
+               void addThisHost();
+               /**delete a host*/
+               void deleteHost();
+               /**generate a new key*/
+               void changeHostKey();
+               /**import host from file*/
+               void importHost();
+               /**export host to file*/
+               void exportHost();
+               
+               /**decide what customer to use*/
+               void setCustomer();
+               /**initialize cart tab*/
+               void initCart();
+               /**add a ticket to the cart*/
+               void cartAddTicket();
+               /**add a voucher to the cart*/
+               void cartAddVoucher();
+               /**remove item from the cart*/
+               void cartRemoveItem();
+               /**check the order on the server*/
+               void cartOrder();
+               
+               /**manage customers*/
+               void customerMgmt();
+               
+               /**edit shipping options*/
+               void editShipping();
+               
+               /**generic check which tab is active*/
+               void tabChanged();
+               
+               /**react on entry in Entrance tab*/
+               void entranceValidate();
+               
+               /**return a ticket*/
+               void ticketReturn();
+               /**return a voucher*/
+               void voucherReturn();
+               /**find an order by ticket*/
+               void orderByTicket();
+               /**find/select orders by event*/
+               void orderByEvent();
+               /**find/select orders by customer*/
+               void orderByCustomer();
+               /**find and display order by order ID*/
+               void orderByOrder();
+               /**deduct some money from a voucher (to pay outside the system)*/
+               void deductVoucher();
+               
+               /**money log for voucher*/
+               void moneylogVoucher();
+               /**money log for user*/
+               void moneylogUser();
+               
+               /**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);
+               
+               /**do a backup now*/
+               void doBackup();
+               
+               /**settings for backup*/
+               void backupSettings();
+               
+       private:
+               //the profile associated with this session
+               QString profilekey;
+               //widgets
+               QTabWidget*tab;
+               QWidget*eventtab,*carttab,*usertab,*hosttab,*ordertab,*entrancetab;
+               QTableView*eventtable,*usertable,*hosttable,*carttable,*ordertable;
+               QStandardItemModel*eventmodel,*usermodel,*hostmodel,*cartmodel,*ordermodel;
+               QPushButton*thishostbutton;
+               QLabel*cartcustomer,*entrancelabel;
+               QTextEdit *cartaddr,*cartcomment;
+               QComboBox*ordermode,*cartship,*entranceevent;
+               QLineEdit*entrancescan;
+               //event list
+               QAction*showoldevents;
+               //cart
+               MCustomer customer;
+               //barcode cache
+               QString lastbarcode;
+               QDateTime lastbcscan;
+               //refresh timers
+               QTimer rtimer,baktimer;
+};
+
+/**Helper dialog for changing passwords*/
+class MPasswordChange:public QDialog
+{
+       Q_OBJECT
+       public:
+               /**creates a password change dialog, if user is empty it is presumed to change own password*/
+               MPasswordChange(QWidget*parent,QString user=QString());
+               
+               /**if own password: return old password*/
+               QString oldPassword();
+               /**returns new password, or empty if the two lines don't match*/
+               QString newPassword();
+       private:
+               QLineEdit *oldpwd,*newpwd1,*newpwd2;
+};
+
+/**Helper class for shopping cart: allow editing amount, but nothing else*/
+class MCartTableDelegate:public QItemDelegate
+{
+       public:
+               MCartTableDelegate(QObject *parent = 0);
+               
+               QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
+                                     const QModelIndex &index) const;
+               
+               void setEditorData(QWidget *editor, const QModelIndex &index) const;
+               void setModelData(QWidget *editor, QAbstractItemModel *model,
+                                 const QModelIndex &index) const;
+};
+
+/**Helper class for Backup settings*/
+class MBackupDialog:public QDialog
+{
+       Q_OBJECT
+       public:
+               MBackupDialog(QWidget*,QString);
+               
+       private slots:
+               void getpath();
+               void save();
+       private:
+               QLineEdit*lpath;
+               QSpinBox*interv,*gener;
+               QCheckBox*autob;
+               QString profilekey;
+};
+
+#endif
diff --git a/src/mwin/eventstab.cpp b/src/mwin/eventstab.cpp
new file mode 100644 (file)
index 0000000..5ab6ee3
--- /dev/null
@@ -0,0 +1,213 @@
+//
+// C++ Implementation: event list tab
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2007
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "centbox.h"
+#include "eventedit.h"
+#include "eventsummary.h"
+#include "main.h"
+#include "misc.h"
+#include "msinterface.h"
+
+#include "eventstab.h"
+
+#include <QApplication>
+#include <QBoxLayout>
+#include <QCheckBox>
+#include <QComboBox>
+#include <QFrame>
+#include <QInputDialog>
+#include <QLabel>
+#include <QMenu>
+#include <QMenuBar>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QSettings>
+#include <QSpinBox>
+#include <QStandardItemModel>
+#include <QTableView>
+#include <QTextEdit>
+
+#define req (MSInterface::instance())
+
+MEventsTab::MEventsTab(QString pk)
+{
+       profilekey=pk;
+       showoldevents=0;
+       
+       //Event tab
+       QVBoxLayout*vl;QHBoxLayout*hl;
+       setLayout(hl=new QHBoxLayout);
+       hl->addWidget(eventtable=new QTableView,10);
+       eventtable->setModel(eventmodel=new QStandardItemModel(this));
+       eventtable->setSelectionMode(QAbstractItemView::SingleSelection);
+       eventtable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       hl->addSpacing(5);
+       hl->addLayout(vl=new QVBoxLayout,0);
+       QPushButton*p;
+       vl->addWidget(p=new QPushButton(tr("New Event...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(newEvent()));
+       p->setEnabled(req->hasRole("createevent"));
+       vl->addWidget(p=new QPushButton(tr("Details...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editEvent()));
+       p->setEnabled(req->hasRole("geteventdata"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Order Ticket...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(eventOrderTicket()));
+       p->setEnabled(req->hasRole("createorder"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Event Summary...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(eventSummary()));
+       p->setEnabled(req->hasRole("eventsummary"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Cancel Event...")),0);
+       p->setEnabled(req->hasRole("cancelevent"));
+       connect(p,SIGNAL(clicked()),this,SLOT(eventCancel()));
+       vl->addStretch(10);
+       
+       //fill tables
+       if(req->hasRight(req->RGetAllEvents)){
+               updateEvents();
+       }
+}
+
+QMenu*MEventsTab::menu()
+{
+       //menu
+       QMenu*m=new QMenu(tr("&Event"));
+       m->addAction(tr("&Update Event List"),this,SLOT(updateEvents()))
+        ->setEnabled(req->hasRight(req->RGetAllEvents));
+       m->addAction(tr("&Show/Edit details..."),this,SLOT(editEvent()))
+        ->setEnabled(req->hasRight(req->RGetEvent));
+       m->addAction(tr("&New Event..."),this,SLOT(newEvent()))->setEnabled(req->hasRole("createevent"));
+       m->addSeparator();
+       showoldevents=m->addAction(tr("Show &old Events"),this,SLOT(updateEvents()));
+       showoldevents->setEnabled(req->hasRight(req->RGetAllEvents));
+       showoldevents->setCheckable(true);
+       showoldevents->setChecked(QSettings().value("profiles/"+profilekey+"/showOldEvents",false).toBool());
+       
+       return m;
+}
+
+
+void MEventsTab::updateEvents()
+{
+       MTGetAllEvents gae=req->queryGetAllEvents();
+       if(gae.stage()!=gae.Success){
+               qDebug("Error getting all events (%s): %s",gae.errorType().toAscii().data(),gae.errorString().toAscii().data());
+               return;
+       }
+       QList<MOEvent>evl=gae.getevents();
+       eventmodel->clear();
+       eventmodel->insertColumns(0,6);
+       eventmodel->setHorizontalHeaderLabels(QStringList()<<tr("Start Time")<<tr("Title")<<tr("Free")<<tr("Reserved")<<tr("Sold")<<tr("Capacity"));
+       QDateTime now=QDateTime::currentDateTime();
+       bool showold;
+       if(showoldevents)showold=showoldevents->isChecked();
+       else showold=QSettings().value("profiles/"+profilekey+"/showOldEvents",false).toBool();
+       for(int i=0,j=0;i<evl.size();i++){
+               QDateTime stime=QDateTime::fromTime_t(evl[i].start());
+               if(stime<now && !showold)continue;
+               eventmodel->insertRow(j);
+               eventmodel->setData(eventmodel->index(j,0),evl[i].id().value(),Qt::UserRole);
+               eventmodel->setData(eventmodel->index(j,0),stime.toString(tr("ddd MMMM d yyyy, h:mm ap","time format")));
+               eventmodel->setData(eventmodel->index(j,1),evl[i].title().value());
+               eventmodel->setData(eventmodel->index(j,2),evl[i].capacity()-evl[i].amountSold()-evl[i].amountReserved());
+               eventmodel->setData(eventmodel->index(j,3),evl[i].amountReserved().value());
+               eventmodel->setData(eventmodel->index(j,4),evl[i].amountSold().value());
+               eventmodel->setData(eventmodel->index(j,5),evl[i].capacity().value());
+               j++;
+       }
+       eventtable->resizeColumnsToContents();
+       //in case this was called from changing the check state
+       if(showoldevents)
+               QSettings().setValue("profiles/"+profilekey+"/showOldEvents",showold);
+}
+
+MEventsTab::~MEventsTab()
+{
+}
+
+void MEventsTab::newEvent()
+{
+       MEventEditor ed(this);
+       ed.exec();
+       updateEvents();
+}
+
+void MEventsTab::editEvent()
+{
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       MEventEditor ed(this,id);
+       ed.exec();
+       updateEvents();
+}
+
+void MEventsTab::eventSummary()
+{
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       MEventSummary ed(this,id);
+       ed.exec();
+}
+
+void MEventsTab::eventCancel()
+{
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       MTGetEvent getev=MTGetEvent::query(id);
+       if(!getev.hasError()){
+               bool ok;
+               MOEvent ev=getev.getevent();
+               QString r=QInputDialog::getText(this,tr("Cancel Event"),tr("Please enter a reason to cancel event \"%1\" or abort:").arg(ev.title()),QLineEdit::Normal,"",&ok);
+               if(!ok)return;
+               MTCancelEvent cev=MTCancelEvent::query(id,r);
+               if(!cev.hasError())
+                       QMessageBox::information(this,tr("Event Cancelled"),tr("The event \"%1\" has been cancelled. Please inform everybody who bought a ticket.").arg(ev.title()));
+               else
+                       QMessageBox::warning(this,tr("Warning"),tr("Unable to cancel event \"%1\": %2.").arg(ev.title()).arg(cev.errorString()));
+       }
+}
+
+int MEventsTab::currentEventId()const
+{
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return -1;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       return eventmodel->data(idx,Qt::UserRole).toInt();
+}
+
+QString MEventsTab::currentEventTitle()const
+{
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return "";
+       return eventmodel->data(eventmodel->index(ilst[0].row(),1)).toString();
+}
+
+QString MEventsTab::currentEventStart()const
+{
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return "";
+       return eventmodel->data(eventmodel->index(ilst[0].row(),0)).toString();
+}
diff --git a/src/mwin/eventstab.h b/src/mwin/eventstab.h
new file mode 100644 (file)
index 0000000..e9f1f4c
--- /dev/null
@@ -0,0 +1,86 @@
+//
+// C++ Interface: overview
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2007
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef MAGICSMOKE_EVENTSTAB_H
+#define MAGICSMOKE_EVENTSTAB_H
+
+#include <QDateTime>
+#include <QDialog>
+#include <QItemDelegate>
+#include <QMainWindow>
+#include <QTimer>
+
+class QAction;
+class QCheckBox;
+class QComboBox;
+class QLabel;
+class QLineEdit;
+class QPushButton;
+class QSpinBox;
+class QStandardItemModel;
+class QTabWidget;
+class QTableView;
+
+class MSInterface;
+
+/**Main Overview Window: Event List Tab*/
+class MEventsTab:public QWidget
+{
+       Q_OBJECT
+       public:
+               /**construct the tab with QSettings-key for current profile*/
+               MEventsTab(QString);
+               
+               /**create menu for this tab*/
+               QMenu*menu();
+               
+               /**returns event table model*/
+               QStandardItemModel*eventModel(){return eventmodel;}
+               /**returns the currently selected event (as ID) or -1 if none is selected*/
+               int currentEventId()const;
+               /**returns the currently selected event start time as string*/
+               QString currentEventStart()const;
+               /**returns the currently selected event title*/
+               QString currentEventTitle()const;
+               
+               /**destruct events list tab*/
+               ~MEventsTab();
+       private slots:
+               /**create a new event*/
+               void newEvent();
+               /**edit existing event*/
+               void editEvent();
+               /**open event summary*/
+               void eventSummary();
+               /**cancel the event*/
+               void eventCancel();
+       public slots:
+               /**update list of events*/
+               void updateEvents();
+       
+       signals:
+               /**order ticket from event tab*/
+               void eventOrderTicket();
+               
+       private:
+               //the profile associated with this session
+               QString profilekey;
+               //widgets
+               QTableView*eventtable;
+               QStandardItemModel*eventmodel;
+               //event list
+               QAction*showoldevents;
+               //refresh timers
+               QTimer rtimer;
+};
+
+#endif
index aaf3570..33b2481 100644 (file)
@@ -1,7 +1,9 @@
 HEADERS += \
-       mwin/overview.h
+       mwin/overview.h \
+       mwin/eventstab.h
 
 SOURCES += \
-       mwin/overview.cpp
+       mwin/overview.cpp \
+       mwin/eventstab.cpp
 
 INCLUDEPATH += ./mwin
\ No newline at end of file
diff --git a/src/mwin/orderstab.cpp b/src/mwin/orderstab.cpp
new file mode 100644 (file)
index 0000000..33d9424
--- /dev/null
@@ -0,0 +1,1753 @@
+//
+// C++ Implementation: overview
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2007
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "centbox.h"
+#include "checkdlg.h"
+#include "eventedit.h"
+#include "eventsummary.h"
+#include "main.h"
+#include "misc.h"
+#include "moneylog.h"
+#include "msinterface.h"
+#include "orderwin.h"
+#include "overview.h"
+
+#include <QApplication>
+#include <QBoxLayout>
+#include <QCheckBox>
+#include <QComboBox>
+#include <QCryptographicHash>
+#include <QDomDocument>
+#include <QDomElement>
+#include <QFile>
+#include <QFileDialog>
+#include <QFrame>
+#include <QInputDialog>
+#include <QLabel>
+#include <QMenu>
+#include <QMenuBar>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QSettings>
+#include <QSpinBox>
+#include <QStandardItemModel>
+#include <QStatusBar>
+#include <QTabWidget>
+#include <QTableView>
+#include <QTextEdit>
+
+#define ORDERNONE      0
+#define ORDERALL       0xff
+#define ORDEROPEN      0xf
+#define ORDERPAY       1
+#define ORDERREFUND    2
+#define ORDERUNSENT    4
+#define ORDERRESERVE   8
+
+#define req (MSInterface::instance())
+
+MOverview::MOverview(QString pk)
+{
+       profilekey=pk;
+       setAttribute(Qt::WA_DeleteOnClose);
+       setWindowTitle("MagicSmoke: "+req->currentUser()+"@"+QSettings().value("profiles/"+pk+"/name").toString());
+       rtimer.setInterval(QSettings().value("profiles/"+pk+"/refresh",300).toInt()*1000);
+       rtimer.start();
+       connect(&rtimer,SIGNAL(timeout()),this,SLOT(refreshData()));
+       //check backup timing
+       int btm=QSettings().value("profiles/"+pk+"/backupinterval",0).toInt()*86400;
+       if(btm){
+               //adjust for last backup time
+               int iv=QDateTime::currentDateTime().toTime_t() - QSettings().value("profiles/"+pk+"/backuptime",0).toInt();
+               if(iv>=btm)btm=0;
+               else btm-=iv;
+               //earliest allowed backup is 30s from now
+               if(btm<30)btm=30;
+               //start timer
+               baktimer.start(btm*1000);
+               connect(&baktimer,SIGNAL(timeout()),this,SLOT(doBackup()));
+       }
+       
+       //menu
+       QMenuBar*mb=menuBar();
+       QMenu*m=mb->addMenu(tr("&Session"));
+       m->addAction(tr("&Re-Login"),this,SLOT(relogin()));
+       m->addAction(tr("Change my &Password"),this,SLOT(setMyPassword()))
+        ->setEnabled(req->hasRight(req->RChangeMyPassword));
+       m->addSeparator();
+       m->addAction(tr("&Edit Templates..."),req,SLOT(editTemplates()));
+       m->addAction(tr("&Update Templates Now"),req,SLOT(updateTemplates()));
+       m->addSeparator();
+       m->addAction(tr("&Close Session"),this,SLOT(close()));
+       
+       m=mb->addMenu(tr("&Event"));
+       m->addAction(tr("&Update Event List"),this,SLOT(updateEvents()))
+        ->setEnabled(req->hasRight(req->RGetAllEvents));
+       m->addAction(tr("&Show/Edit details..."),this,SLOT(editEvent()))
+        ->setEnabled(req->hasRight(req->RGetEvent));
+       m->addAction(tr("&New Event..."),this,SLOT(newEvent()))->setEnabled(req->hasRole("createevent"));
+       m->addSeparator();
+       showoldevents=m->addAction(tr("Show &old Events"),this,SLOT(updateEvents()));
+       showoldevents->setEnabled(req->hasRight(req->RGetAllEvents));
+       showoldevents->setCheckable(true);
+       showoldevents->setChecked(QSettings().value("profiles/"+pk+"/showOldEvents",false).toBool());
+       
+       m=mb->addMenu(tr("&Customer"));
+       m->addAction(tr("&Show all customers"),this,SLOT(customerMgmt()));
+       
+       m=mb->addMenu(tr("C&art"));
+       m->addAction(tr("Add &Ticket"),this,SLOT(cartAddTicket()));
+       m->addAction(tr("Add &Voucher"),this,SLOT(cartAddVoucher()));
+       m->addAction(tr("&Remove Item"),this,SLOT(cartRemoveItem()));
+       m->addAction(tr("&Abort Shopping"),this,SLOT(initCart()));
+       m->addSeparator();
+       m->addAction(tr("&Update Shipping Options"),this,SLOT(updateShipping()));
+       
+       m=mb->addMenu(tr("&Misc"));
+       m->addAction(tr("Return &ticket..."),this,SLOT(ticketReturn()));
+       m->addAction(tr("Return &voucher..."),this,SLOT(voucherReturn()));
+       m->addSeparator();
+       m->addAction(tr("Edit &Shipping Options..."),this,SLOT(editShipping()));
+       m->addSeparator();
+       m->addAction(tr("&Deduct from voucher..."),this,SLOT(deductVoucher()));
+       m->addSeparator();
+       m->addAction(tr("&Money Log for voucher..."),this,SLOT(moneylogVoucher()));
+       m->addAction(tr("Money Log for &user..."),this,SLOT(moneylogUser()));
+       
+       m=mb->addMenu(tr("C&onfigure"));
+       m->addAction(tr("&Auto-Refresh settings..."),this,SLOT(setRefresh()));
+       m->addAction(tr("&Server Access settings..."),this,SLOT(webSettings()));
+       
+       m=mb->addMenu(tr("&Admin"));
+       m->addAction(tr("Backup &Settings..."),this,SLOT(backupSettings()))
+        ->setEnabled(req->hasRight(req->RBackup));
+       m->addAction(tr("&Backup now..."),this,SLOT(doBackup()))
+        ->setEnabled(req->hasRight(req->RBackup));
+
+       mb->addMenu(MApplication::helpMenu());
+       
+       //tabs
+       setCentralWidget(tab=new QTabWidget);
+       connect(tab,SIGNAL(currentChanged(int)),this,SLOT(tabChanged()));
+       
+       //Event tab
+       tab->addTab(eventtab=new QWidget,tr("Events"));
+       QVBoxLayout*vl;QHBoxLayout*hl;
+       eventtab->setLayout(hl=new QHBoxLayout);
+       hl->addWidget(eventtable=new QTableView,10);
+       eventtable->setModel(eventmodel=new QStandardItemModel(this));
+       eventtable->setSelectionMode(QAbstractItemView::SingleSelection);
+       eventtable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       hl->addSpacing(5);
+       hl->addLayout(vl=new QVBoxLayout,0);
+       QPushButton*p;
+       vl->addWidget(p=new QPushButton(tr("New Event...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(newEvent()));
+       p->setEnabled(req->hasRole("createevent"));
+       vl->addWidget(p=new QPushButton(tr("Details...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editEvent()));
+       p->setEnabled(req->hasRole("geteventdata"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Order Ticket...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(eventOrderTicket()));
+       p->setEnabled(req->hasRole("createorder"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Event Summary...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(eventSummary()));
+       p->setEnabled(req->hasRole("eventsummary"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Cancel Event...")),0);
+       p->setEnabled(req->hasRole("cancelevent"));
+       connect(p,SIGNAL(clicked()),this,SLOT(eventCancel()));
+       vl->addStretch(10);
+       
+       //Shopping Cart Tab
+       tab->addTab(carttab=new QWidget,tr("Shopping Cart"));
+       carttab->setLayout(vl=new QVBoxLayout);
+       vl->addLayout(hl=new QHBoxLayout);
+       QVBoxLayout*vl2;
+       hl->addLayout(vl2=new QVBoxLayout,2);
+       vl2->addWidget(carttable=new QTableView,10);
+       carttable->setModel(cartmodel=new QStandardItemModel(this));
+       carttable->setSelectionMode(QAbstractItemView::SingleSelection);
+       carttable->setItemDelegate(new MCartTableDelegate(this));
+       QHBoxLayout*hl2;
+       vl2->addLayout(hl2=new QHBoxLayout,0);
+       hl2->addStretch(10);
+       hl2->addWidget(p=new QPushButton(tr("Add Ticket")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(cartAddTicket()));
+       hl2->addWidget(p=new QPushButton(tr("Add Voucher")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(cartAddVoucher()));
+       hl2->addWidget(p=new QPushButton(tr("Remove Item")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(cartRemoveItem()));
+       QFrame*frm;
+       hl->addWidget(frm=new QFrame,0);
+       frm->setFrameShape(QFrame::VLine);
+       hl->addLayout(vl2=new QVBoxLayout,1);
+       vl2->addWidget(p=new QPushButton(tr("Customer:")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(setCustomer()));
+       vl2->addWidget(cartcustomer=new QLabel("...\n \n \n "));
+       vl2->addWidget(frm=new QFrame,0);
+       frm->setFrameShape(QFrame::HLine);
+       vl2->addSpacing(10);
+       vl2->addWidget(new QLabel(tr("Shipping Method:")),0);
+       vl2->addWidget(cartship=new QComboBox,0);
+       cartship->setEditable(false);
+       vl2->addWidget(new QLabel(tr("Delivery Address:")),0);
+       vl2->addWidget(cartaddr=new QTextEdit);
+       vl2->addSpacing(10);
+       vl2->addWidget(new QLabel(tr("Comments:")),0);
+       vl2->addWidget(cartcomment=new QTextEdit);
+       vl2->addStretch(10);
+       vl->addWidget(frm=new QFrame,0);
+       frm->setFrameShape(QFrame::HLine);
+       vl->addLayout(hl=new QHBoxLayout,0);
+       hl->addStretch(10);
+       hl->addWidget(p=new QPushButton(tr("Check Order")));
+       p->setEnabled(req->hasRole("checkorder"));
+       connect(p,SIGNAL(clicked()),this,SLOT(cartOrder()));
+       hl->addWidget(p=new QPushButton(tr("Clear")));
+       connect(p,SIGNAL(clicked()),this,SLOT(initCart()));
+       
+       //Order List Tab
+       tab->addTab(ordertab=new QWidget,tr("Order List"));
+       ordertab->setLayout(hl=new QHBoxLayout);
+       hl->addLayout(vl=new QVBoxLayout,10);
+       vl->addWidget(ordermode=new QComboBox,0);
+       ordermode->addItem(tr("-select mode-"),ORDERNONE);
+       ordermode->addItem(tr("All Orders"),ORDERALL);
+       ordermode->addItem(tr("Open Orders"),ORDEROPEN);
+       ordermode->addItem(tr("Open Reservations"),ORDERRESERVE);
+       ordermode->addItem(tr("Outstanding Payments"),ORDERPAY);
+       ordermode->addItem(tr("Outstanding Refunds"),ORDERREFUND);
+       ordermode->addItem(tr("Undelivered Orders"),ORDERUNSENT);
+       //make sure this entry is the last one, since we use count()-1 to select it
+       ordermode->addItem(tr("-search result-"),ORDERNONE);
+       connect(ordermode,SIGNAL(currentIndexChanged(int)),this,SLOT(updateOrders()));
+       vl->addWidget(ordertable=new QTableView);
+       ordertable->setModel(ordermodel=new QStandardItemModel(this));
+       ordertable->setSelectionMode(QAbstractItemView::SingleSelection);
+       ordertable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       connect(ordertable,SIGNAL(doubleClicked(const QModelIndex&)),this,SLOT(orderDetails()));
+       hl->addLayout(vl=new QVBoxLayout,0);
+       vl->addWidget(p=new QPushButton(tr("Update")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(updateOrders()));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Details...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderDetails()));
+       p->setEnabled(req->hasRole("getorder"));
+       vl->addSpacing(15);
+       vl->addWidget(p=new QPushButton(tr("Find by Ticket...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderByTicket()));
+       p->setEnabled(req->hasRole("orderbyticket"));
+       vl->addWidget(p=new QPushButton(tr("Find by Event...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderByEvent()));
+       p->setEnabled(req->hasRole("getordersbyevents"));
+       vl->addWidget(p=new QPushButton(tr("Find by Customer...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderByCustomer()));
+       p->setEnabled(req->hasRole("getorderlist"));
+       vl->addWidget(p=new QPushButton(tr("Find by Order ID...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(orderByOrder()));
+       p->setEnabled(req->hasRole("getorder"));
+       vl->addStretch(10);
+       
+       //Entrance Control Tab
+       tab->addTab(entrancetab=new QWidget,tr("Entrance"));
+       entrancetab->setLayout(vl=new QVBoxLayout);
+       vl->addWidget(entranceevent=new QComboBox,0);
+       entranceevent->setEditable(false);
+       vl->addSpacing(30);
+       vl->addWidget(new QLabel(tr("Enter or scan Ticket-ID:")),0);
+       vl->addWidget(entrancescan=new QLineEdit,0);
+       connect(entrancescan,SIGNAL(editingFinished()),this,SLOT(entranceValidate()));
+       vl->addWidget(entrancelabel=new QLabel("  "),10);
+       entrancelabel->setAutoFillBackground(true);
+       QFont fnt=entrancelabel->font();
+       fnt.setBold(true);fnt.setPointSize(24);
+       entrancelabel->setFont(fnt);
+       entrancelabel->setAlignment(Qt::AlignCenter);
+       
+       //user tab
+       tab->addTab(usertab=new QWidget,tr("Users"));
+       usertab->setLayout(hl=new QHBoxLayout);
+       hl->addWidget(usertable=new QTableView,10);
+       usertable->setModel(usermodel=new QStandardItemModel(this));
+       usertable->setSelectionMode(QAbstractItemView::SingleSelection);
+       usertable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       hl->addSpacing(5);
+       hl->addLayout(vl=new QVBoxLayout,0);
+       vl->addWidget(p=new QPushButton(tr("New User...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(newUser()));
+       p->setEnabled(req->hasRole("adduser"));
+       vl->addWidget(p=new QPushButton(tr("Delete User...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(deleteUser()));
+       p->setEnabled(req->hasRole("deleteuser"));
+       vl->addSpacing(20);
+       vl->addWidget(p=new QPushButton(tr("Description...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editUserDescription()));
+       p->setEnabled(req->hasRole("setuserdescription"));
+       vl->addWidget(p=new QPushButton(tr("Hosts...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editUserHosts()));
+       p->setEnabled(req->hasRole("getuserhosts"));
+       vl->addWidget(p=new QPushButton(tr("Roles...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(editUserRoles()));
+       p->setEnabled(req->hasRole("getuseracl"));
+       vl->addWidget(p=new QPushButton(tr("Set Password...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(setUserPassword()));
+       p->setEnabled(req->hasRole("setpasswd"));
+       vl->addStretch(10);
+       
+       //host tab
+       tab->addTab(hosttab=new QWidget,tr("Hosts"));
+       hosttab->setLayout(hl=new QHBoxLayout);
+       hl->addWidget(hosttable=new QTableView,10);
+       hosttable->setModel(hostmodel=new QStandardItemModel(this));
+       hosttable->setSelectionMode(QAbstractItemView::SingleSelection);
+       hosttable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       hl->addSpacing(5);
+       hl->addLayout(vl=new QVBoxLayout,0);
+       vl->addWidget(p=new QPushButton(tr("New Host...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(newHost()));
+       p->setEnabled(req->hasRole("addhost"));
+       vl->addWidget(thishostbutton=p=new QPushButton(tr("Add This Host...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(addThisHost()));
+       p->setEnabled(req->hasRole("addhost"));
+       vl->addWidget(p=new QPushButton(tr("Delete Host...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(deleteHost()));
+       p->setEnabled(req->hasRole("deletehost"));
+       vl->addSpacing(20);
+       vl->addWidget(p=new QPushButton(tr("Generate New Key...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(changeHostKey()));
+       p->setEnabled(req->hasRole("sethostkey"));
+       vl->addWidget(p=new QPushButton(tr("Import...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(importHost()));
+       p->setEnabled(req->hasRole("addhost"));
+       vl->addWidget(p=new QPushButton(tr("Export...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(exportHost()));
+       p->setEnabled(req->hasRole("gethostkey"));
+       vl->addStretch(10);
+       
+       //status bar
+       statusBar()->setSizeGripEnabled(true);
+       
+       //make sure webrequest knows its settings
+       webSettings(false);
+       //fill tables
+       if(req->hasRight(req->RGetAllEvents)){
+               updateEvents();
+       }else{
+               eventtab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(eventtab),false);
+       }
+       if(!req->hasRole("createorder")&&!req->hasRole("createsale")){
+               carttab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(carttab),false);
+       }else{
+               initCart();
+       }
+       updateShipping();
+       if(req->hasRole("getorderlist")){
+               updateOrders();
+       }else{
+               ordertab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(ordertab),false);
+       }
+       if(req->hasRole("getusers")){
+               updateUsers();
+       }else{
+               usertab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(usertab),false);
+       }
+       if(req->hasRole("gethosts")){
+               updateHosts();
+       }else{
+               hosttab->setEnabled(false);
+               tab->setTabEnabled(tab->indexOf(hosttab),false);
+       }
+}
+
+void MOverview::updateEvents()
+{
+       MTGetAllEvents gae=req->queryGetAllEvents();
+       if(gae.stage()!=gae.Success){
+               qDebug("Error getting all events (%s): %s",gae.errorType().toAscii().data(),gae.errorString().toAscii().data());
+               return;
+       }
+       QList<MOEvent>evl=gae.getevents();
+       eventmodel->clear();
+       eventmodel->insertColumns(0,6);
+       eventmodel->setHorizontalHeaderLabels(QStringList()<<tr("Start Time")<<tr("Title")<<tr("Free")<<tr("Reserved")<<tr("Sold")<<tr("Capacity"));
+       QDateTime now=QDateTime::currentDateTime();
+       for(int i=0,j=0;i<evl.size();i++){
+               QDateTime stime=QDateTime::fromTime_t(evl[i].start());
+               if(stime<now && !showoldevents->isChecked())continue;
+               eventmodel->insertRow(j);
+               eventmodel->setData(eventmodel->index(j,0),evl[i].id().value(),Qt::UserRole);
+               eventmodel->setData(eventmodel->index(j,0),stime.toString(tr("ddd MMMM d yyyy, h:mm ap","time format")));
+               eventmodel->setData(eventmodel->index(j,1),evl[i].title().value());
+               eventmodel->setData(eventmodel->index(j,2),evl[i].capacity()-evl[i].amountSold()-evl[i].amountReserved());
+               eventmodel->setData(eventmodel->index(j,3),evl[i].amountReserved().value());
+               eventmodel->setData(eventmodel->index(j,4),evl[i].amountSold().value());
+               eventmodel->setData(eventmodel->index(j,5),evl[i].capacity().value());
+               j++;
+       }
+       eventtable->resizeColumnsToContents();
+       //in case this was called from changing the check state
+       QSettings().setValue("profiles/"+profilekey+"/showOldEvents",showoldevents->isChecked());
+}
+
+void MOverview::closeEvent(QCloseEvent*ce)
+{
+       //make sure session is deleted
+       req->logout();
+       //actually close window
+       QMainWindow::closeEvent(ce);
+}
+
+MOverview::~MOverview()
+{
+       //free requestor
+       req->deleteLater();
+}
+
+void MOverview::relogin()
+{
+       setEnabled(false);
+       if(!req->relogin())
+               QMessageBox::warning(this,tr("Warning"),tr("I was unable to renew the login at the server."));
+       setEnabled(true);
+}
+
+void MOverview::newEvent()
+{
+       MEventEditor ed(this);
+       ed.exec();
+       updateEvents();
+}
+
+void MOverview::editEvent()
+{
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       MEventEditor ed(this,id);
+       ed.exec();
+       updateEvents();
+}
+
+void MOverview::eventSummary()
+{
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       MEventSummary ed(this,id);
+       ed.exec();
+}
+
+void MOverview::eventCancel()
+{
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       MTGetEvent getev=MTGetEvent::query(id);
+       if(!getev.hasError()){
+               bool ok;
+               MOEvent ev=getev.getevent();
+               QString r=QInputDialog::getText(this,tr("Cancel Event"),tr("Please enter a reason to cancel event \"%1\" or abort:").arg(ev.title()),QLineEdit::Normal,"",&ok);
+               if(!ok)return;
+               MTCancelEvent cev=MTCancelEvent::query(id,r);
+               if(!cev.hasError())
+                       QMessageBox::information(this,tr("Event Cancelled"),tr("The event \"%1\" has been cancelled. Please inform everybody who bought a ticket.").arg(ev.title()));
+               else
+                       QMessageBox::warning(this,tr("Warning"),tr("Unable to cancel event \"%1\": %2.").arg(ev.title()).arg(cev.errorString()));
+       }
+}
+
+void MOverview::updateShipping()
+{
+       cartship->clear();
+       cartship->addItem(tr("(No Shipping)"),-1);
+       MTGetAllShipping sh=MTGetAllShipping::query();
+       QList<MOShipping>ship=sh.getshipping();
+       for(int i=0;i<ship.size();i++)
+               cartship->addItem(ship[i].description(),(int)ship[i].id());
+}
+
+void MOverview::updateUsers()
+{
+       MTGetAllUsers au=req->queryGetAllUsers();
+       if(au.hasError())return;
+       QList<MOUser>usl=au.getusers();
+       usermodel->clear();
+       usermodel->insertColumns(0,2);
+       usermodel->insertRows(0,usl.size());
+       usermodel->setHorizontalHeaderLabels(QStringList()<<tr("Login Name")<<tr("Description"));
+       for(int i=0;i<usl.size();i++){
+               usermodel->setData(usermodel->index(i,0),usl[i].name().value());
+               usermodel->setData(usermodel->index(i,1),usl[i].description().value());
+       }
+       usertable->resizeColumnsToContents();
+}
+
+void MOverview::newUser()
+{
+       //get name
+       QString name;
+       while(1){
+               bool ok;
+               name=QInputDialog::getText(this,tr("New User"),tr("Please enter new user name (only letters, digits, and underscore allowed):"),QLineEdit::Normal,name,&ok);
+               if(!ok)
+                       return;
+               if(QRegExp("[A-Za-z0-9_\\.,:-]+").exactMatch(name))
+                       break;
+               if(QMessageBox::warning(this,tr("Error"),tr("The user name must contain only letters, digits, dots and underscores and must be at least one character long!"),QMessageBox::Retry|QMessageBox::Abort)!=QMessageBox::Retry)
+                       return;
+       }
+       //get password
+       QString pwd=QInputDialog::getText(this,tr("Password"),tr("Please enter an initial password for the user:"),QLineEdit::Password);
+       //send request
+       req->queryCreateUser(name,pwd,"");
+       //update display
+       updateUsers();
+}
+
+void MOverview::deleteUser()
+{
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname & descr
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       //make sure user wants this
+       if(QMessageBox::question(this,tr("Delete User?"),tr("Really delete user '%1'?").arg(name),QMessageBox::Yes|QMessageBox::No)!=QMessageBox::Yes)return;
+       //get replacement
+       bool ok;
+       QStringList rplc;
+       rplc<<tr("(Nobody)","this is a username for no user, the string must contain '(' to distinguish it from the others");
+       for(int i=0;i<usermodel->rowCount();i++)
+               rplc<<usermodel->data(usermodel->index(i,0)).toString();
+       QString rp=QInputDialog::getItem(this,tr("Delete User"),tr("Select which user will inherit this users database objects:"),rplc,0,false,&ok);
+       if(!ok)return;
+       //delete
+       MTDeleteUser ret=req->queryDeleteUser(name,rp);
+       if(ret.hasError())
+               QMessageBox::warning(this,tr("Error"),tr("Cannot delete user: %1").arg(ret.errorString()));
+       updateUsers();
+}
+
+void MOverview::editUserDescription()
+{
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname & descr
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       QString descr=usermodel->data(usermodel->index(sel.row(),1)).toString();
+       //edit descr
+       bool ok;
+       descr=QInputDialog::getText(this,tr("Edit Description"),tr("Descriptionof user %1:").arg(name),QLineEdit::Normal,descr,&ok);
+       if(ok)
+               req->querySetUserDescription(name,descr);
+       //update
+       updateUsers();
+}
+
+void MOverview::editUserRoles()
+{/*TODO
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname & descr
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       //...
+       MOUser usr(req,name);
+       MCheckList acl=usr.getRoles();
+       MCheckDialog cd(this,acl,"Edit ACL of user "+name);
+       if(cd.exec()==QDialog::Accepted)
+               usr.setRoles(cd.getCheckList());*/
+}
+
+void MOverview::editUserHosts()
+{/*TODO
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname & descr
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       //...
+       MUser usr(req,name);
+       MCheckList acl=usr.getHosts();
+       MCheckDialog cd(this,acl,"Edit hosts of user "+name);
+       if(cd.exec()==QDialog::Accepted)
+               usr.setHosts(cd.getCheckList());*/
+}
+
+void MOverview::setMyPassword()
+{
+       MPasswordChange pc(this);
+       if(pc.exec()==QDialog::Accepted){
+               MTChangeMyPassword cmp=MTChangeMyPassword::query(pc.oldPassword(),pc.newPassword());
+               if(cmp.hasError())
+                       QMessageBox::warning(this,tr("Warning"),tr("Error setting password: %1").arg(cmp.errorString()));
+       }
+}
+void MOverview::setUserPassword()
+{/*TODO
+       //get selection
+       QModelIndex sel=usertable->currentIndex();
+       if(!sel.isValid())return;
+       //get uname
+       QString name=usermodel->data(usermodel->index(sel.row(),0)).toString();
+       //get new password
+       MPasswordChange pc(this,name);
+       if(pc.exec()!=QDialog::Accepted)return;
+       QString p=pc.newPassword();
+       if(p==""){
+               QMessageBox::warning(this,tr("Warning"),tr("The password must be non-empty and both lines must match"));
+               return;
+       }
+       //...
+       MUser usr(req,name);
+       usr.changePassword(p);*/
+}
+
+void MOverview::updateHosts()
+{/*TODO
+       bool foundThis=false;
+       QString thisHost=req->hostName();
+       QList<MHost>hsl=req->getAllHosts();
+       hostmodel->clear();
+       hostmodel->insertColumns(0,2);
+       hostmodel->insertRows(0,hsl.size());
+       hostmodel->setHorizontalHeaderLabels(QStringList()<<tr("Host Name")<<tr("Host Key"));
+       for(int i=0;i<hsl.size();i++){
+               hostmodel->setData(hostmodel->index(i,0),hsl[i].hostId());
+               hostmodel->setData(hostmodel->index(i,1),hsl[i].hostKey());
+               if(thisHost==hsl[i].hostId())
+                       foundThis=true;
+       }
+       hosttable->resizeColumnsToContents();
+       thishostbutton->setEnabled(!foundThis && req->hasRole("addhost"));*/
+}
+
+void MOverview::newHost()
+{/*TODO
+       //get Host Name
+       QString hname;
+       do{
+               bool ok;
+               hname=QInputDialog::getText(this,tr("Create New Host"),tr("Please enter a host name:"),QLineEdit::Normal,hname,&ok);
+               if(!ok)return;
+               if(!QRegExp("[A-Za-z][A-Za-z0-9_]*").exactMatch(hname))continue;
+       }while(false);
+       //create it
+       MHost hst(req,hname);
+       int e=hst.newKey();
+       if(e<128){
+               if(QMessageBox::warning(this,tr("Warning"),tr("The key of this new host could only be generated with %n bits entropy. Store anyway?","",e).arg(e),QMessageBox::Yes|QMessageBox::No,QMessageBox::No)!=QMessageBox::Yes)
+                       return;
+       }
+       hst.create();
+       //update
+       updateHosts();*/
+}
+
+void MOverview::addThisHost()
+{/*TODO
+       MHost hst(req,req->hostName(),QSettings().value("hostkey").toString());
+       hst.create();
+       updateHosts();*/
+}
+
+void MOverview::deleteHost()
+{/*TODO
+       //get selection
+       QModelIndex sel=hosttable->currentIndex();
+       if(!sel.isValid())return;
+       //get hname
+       QString name=hostmodel->data(hostmodel->index(sel.row(),0)).toString();
+       //ask
+       if(QMessageBox::question(this,tr("Delete this Host?"),tr("Really delete host '%1'?").arg(name),QMessageBox::Yes|QMessageBox::No)!=QMessageBox::Yes)return;
+       //delete it
+       MHost(req,name).deleteHost();
+       updateHosts();*/
+}
+
+void MOverview::changeHostKey()
+{/*TODO
+       //get selection
+       QModelIndex sel=hosttable->currentIndex();
+       if(!sel.isValid())return;
+       //get hname
+       QString name=hostmodel->data(hostmodel->index(sel.row(),0)).toString();
+       //ask
+       if(QMessageBox::question(this,tr("Change Host Key?"),tr("Really change the key of host '%1'?").arg(name),QMessageBox::Yes|QMessageBox::No)!=QMessageBox::Yes)return;
+       //change it
+       MHost hst(req,name);
+       int e=hst.newKey();
+       if(e<128){
+               if(QMessageBox::warning(this,tr("Warning"),tr("The new key of this host could only be generated with %n bits entropy. Store anyway?","",e).arg(e),QMessageBox::Yes|QMessageBox::No,QMessageBox::No)!=QMessageBox::Yes)
+                       return;
+       }
+       hst.save();
+       //update
+       updateHosts();*/
+}
+
+void MOverview::importHost()
+{/*TODO
+       QStringList fn;
+       QFileDialog fdlg(this,tr("Import Key from File"),QString(),"Magic Smoke Host Key (*.mshk)");
+       fdlg.setDefaultSuffix("mshk");
+       fdlg.setAcceptMode(QFileDialog::AcceptOpen);
+       fdlg.setFileMode(QFileDialog::ExistingFile);
+       if(!fdlg.exec())return;
+       fn=fdlg.selectedFiles();
+       if(fn.size()!=1)return;
+       QFile fd(fn[0]);
+       if(!fd.open(QIODevice::ReadOnly)){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to open file %1 for reading: %2").arg(fn[0]).arg(fd.errorString()));
+               return;
+       }
+       //read content (max: 10k to limit potential damage)
+       QStringList fc=QString::fromAscii(fd.read(10240)).split("\n",QString::SkipEmptyParts);
+       fd.close();
+       //check content
+       if(fc.size()<3){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a host key file."));
+               return;
+       }
+       if(fc[0].trimmed()!="MagicSmokeHostKey"){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a host key file."));
+               return;
+       }
+       QString hname=fc[1].trimmed();
+       if(!QRegExp("[A-Za-z][A-Za-z0-9_]*").exactMatch(hname)){
+               QMessageBox::warning(this,tr("Warning"),tr("This host key file does not contain a valid host name."));
+               return;
+       }
+       QString key=fc[2].trimmed();
+       if(!QRegExp("[0-9a-fA-F]+").exactMatch(key) || key.size()<40){
+               QMessageBox::warning(this,tr("Warning"),tr("This host key file does not contain a valid key."));
+               return;
+       }
+       QString chk=QCryptographicHash::hash(key.toAscii(),QCryptographicHash::Md5).toHex();
+       if(chk!=fc[3].trimmed()){
+               QMessageBox::warning(this,tr("Warning"),tr("The key check sum did not match. Please get a clean copy of the host key file."));
+               return;
+       }
+       //save
+       MHost hst(req,hname,key);
+       hst.create();
+       updateHosts();*/
+}
+
+void MOverview::exportHost()
+{/*TODO
+       //get selection
+       QModelIndex sel=hosttable->currentIndex();
+       if(!sel.isValid())return;
+       //get hname
+       QString name=hostmodel->data(hostmodel->index(sel.row(),0)).toString();
+       QString key=hostmodel->data(hostmodel->index(sel.row(),1)).toString();
+       if(name[0]=='_' || key==""){
+               QMessageBox::warning(this,tr("Warning"),tr("This host cannot be exported."));
+               return;
+       }
+       //save
+       QStringList fn;
+       QFileDialog fdlg(this,tr("Export Key to File"),QString(),"Magic Smoke Host Key (*.mshk)");
+       fdlg.setDefaultSuffix("mshk");
+       fdlg.setAcceptMode(QFileDialog::AcceptSave);
+       fdlg.setFileMode(QFileDialog::AnyFile);
+       if(!fdlg.exec())return;
+       fn=fdlg.selectedFiles();
+       if(fn.size()!=1)return;
+       QFile fd(fn[0]);
+       if(!fd.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to open file %1 for writing: %2").arg(fn[0]).arg(fd.errorString()));
+               return;
+       }
+       QString chk=QCryptographicHash::hash(key.toAscii(),QCryptographicHash::Md5).toHex();
+       QString out="MagicSmokeHostKey\n"+name+"\n"+key+"\n"+chk;
+       fd.write(out.toAscii());
+       fd.close();*/
+}
+
+
+void MOverview::initCart()
+{
+       //clear cart
+       cartmodel->clear();
+       cartmodel->setHorizontalHeaderLabels(QStringList()<<tr("Amount")<<tr("Title")<<tr("Start Time"));
+       //clear customer
+       customer=MCustomer();
+       cartcustomer->setText("");
+       //clear address/comment
+       cartaddr->setPlainText("");
+       cartcomment->setPlainText("");
+       //clear shipping
+       cartship->setCurrentIndex(0);
+}
+
+void MOverview::setCustomer()
+{/*TODO
+       MCustomerListDialog mcl(req,this,true,customer.customerID());
+       if(mcl.exec()!=QDialog::Accepted)return;
+       customer=mcl.getCustomer();
+       cartcustomer->setText(customer.getNameAddress());*/
+}
+
+static const int CART_TICKET=1;
+static const int CART_VOUCHER=2;
+
+static const int CART_IDROLE=Qt::UserRole;//ticket id
+static const int CART_PRICEROLE=Qt::UserRole;//voucher price
+static const int CART_VALUEROLE=Qt::UserRole+1;//voucher value
+static const int CART_TYPEROLE=Qt::UserRole+2;//which is it? ticket or voucher?
+
+void MOverview::cartAddTicket()
+{
+       //create ticket selection dialog
+       QDialog dlg;
+       dlg.setWindowTitle(tr("Select Event to order Ticket"));
+       QTableView*tv;
+       QHBoxLayout*hl;
+       QVBoxLayout*vl;
+       dlg.setLayout(vl=new QVBoxLayout);
+       vl->addWidget(tv=new QTableView,10);
+       tv->setModel(eventmodel);
+       tv->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       tv->resizeColumnsToContents();
+       vl->addSpacing(15);
+       vl->addLayout(hl=new QHBoxLayout,0);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Select")),0);
+       connect(p,SIGNAL(clicked()),&dlg,SLOT(accept()));
+       connect(tv,SIGNAL(doubleClicked(const QModelIndex&)),&dlg,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")),0);
+       connect(p,SIGNAL(clicked()),&dlg,SLOT(reject()));
+       //wait for it
+       if(dlg.exec()==QDialog::Accepted){
+               //get selection
+               QModelIndex idx=tv->currentIndex();
+               if(!idx.isValid())return;
+               int id=eventmodel->data(eventmodel->index(idx.row(),0),Qt::UserRole).toInt();
+               if(id<0)return;
+               //copy to cart
+               int cr=cartmodel->rowCount();
+               cartmodel->insertRows(cr,1);
+               cartmodel->setData(cartmodel->index(cr,0),1);
+               cartmodel->setData(cartmodel->index(cr,0),id,CART_IDROLE);
+               cartmodel->setData(cartmodel->index(cr,0),CART_TICKET,CART_TYPEROLE);
+               cartmodel->setData(cartmodel->index(cr,1),eventmodel->data(eventmodel->index(idx.row(),1)));
+               cartmodel->setData(cartmodel->index(cr,2),eventmodel->data(eventmodel->index(idx.row(),0)));
+               carttable->resizeColumnsToContents();
+       }
+}
+
+void MOverview::eventOrderTicket()
+{
+       //get selected event
+       int id;
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       //activate order tab
+       tab->setCurrentWidget(carttab);
+       //insert event into table
+       int cr=cartmodel->rowCount();
+       cartmodel->insertRows(cr,1);
+       cartmodel->setData(cartmodel->index(cr,0),1);
+       cartmodel->setData(cartmodel->index(cr,0),id,CART_IDROLE);
+       cartmodel->setData(cartmodel->index(cr,0),CART_TICKET,CART_TYPEROLE);
+       cartmodel->setData(cartmodel->index(cr,1),eventmodel->data(eventmodel->index(ilst[0].row(),1)));
+       cartmodel->setData(cartmodel->index(cr,2),eventmodel->data(eventmodel->index(ilst[0].row(),0)));
+       carttable->resizeColumnsToContents();
+}
+
+void MOverview::cartAddVoucher()
+{/*TODO
+       //create voucher selection dialog
+       QDialog dlg;
+       dlg.setWindowTitle(tr("Select Voucher"));
+       QComboBox*cp,*cv;
+       QHBoxLayout*hl;
+       QGridLayout*gl;
+       QStandardItemModel mdl;
+       QRegExpValidator regv(priceRegExp(),this);
+       QList<int>prc=req->getVoucherPrices();
+       mdl.insertRows(0,prc.size());
+       mdl.insertColumns(0,1);
+       for(int i=0;i<prc.size();i++)mdl.setData(mdl.index(i,0),cent2str(prc[i]));
+       dlg.setLayout(gl=new QGridLayout);
+       gl->addWidget(new QLabel(tr("Select voucher price and value:")),0,0,1,2);
+       if(req->hasRole("_anypricevoucher")){
+               gl->addWidget(new QLabel(tr("Price:")),1,0);
+               gl->addWidget(cp=new QComboBox,1,1);
+               cp->setModel(&mdl);
+               cp->setEditable(true);
+               cp->setValidator(&regv);
+       }else cp=0;
+       gl->addWidget(new QLabel(tr("Value:")),2,0);
+       gl->addWidget(cv=new QComboBox,2,1);
+       cv->setModel(&mdl);
+       cv->setEditable(req->hasRole("_anyvoucher"));
+       cv->setValidator(&regv);
+       gl->setRowMinimumHeight(3,15);
+       gl->setColumnStretch(0,0);
+       gl->setColumnStretch(1,1);
+       gl->setRowStretch(3,1);
+       gl->addLayout(hl=new QHBoxLayout,4,0,1,2);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Ok")),0);
+       connect(p,SIGNAL(clicked()),&dlg,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")),0);
+       connect(p,SIGNAL(clicked()),&dlg,SLOT(reject()));
+       //wait for it
+       if(dlg.exec()==QDialog::Accepted){
+               //get selection
+               int price,value;
+               value=str2cent(cv->currentText());
+               if(req->hasRole("_anypricevoucher") && cp)
+                       price=str2cent(cp->currentText());
+               else
+                       price=value;
+               //copy to cart
+               int cr=cartmodel->rowCount();
+               cartmodel->insertRows(cr,1);
+               cartmodel->setData(cartmodel->index(cr,0),1);
+               cartmodel->setData(cartmodel->index(cr,0),price,CART_PRICEROLE);
+               cartmodel->setData(cartmodel->index(cr,0),value,CART_VALUEROLE);
+               cartmodel->setData(cartmodel->index(cr,0),CART_VOUCHER,CART_TYPEROLE);
+               cartmodel->setData(cartmodel->index(cr,1),tr("Voucher (price: %1, value %2)").arg(cent2str(price)).arg(cent2str(value)));
+               carttable->resizeColumnsToContents();
+       }*/
+}
+
+void MOverview::cartRemoveItem()
+{
+       //get selection
+       QModelIndex idx=carttable->currentIndex();
+       if(!idx.isValid())return;
+       //remove row
+       cartmodel->removeRow(idx.row());
+}
+
+void MOverview::cartOrder()
+{
+       //sanity checks
+       if(cartmodel->rowCount()<1){
+               QMessageBox::warning(this,tr("Error"),tr("There is nothing in the order. Ignoring it."));
+               return;
+       }
+       if(!customer.isValid()){
+               QMessageBox::warning(this,tr("Error"),tr("Please chose a customer first!"));
+               return;
+       }
+       ///////////////
+       //create order
+       QDomDocument doc;
+       QDomElement root=doc.createElement("Order");
+       root.setAttribute("customer",customer.id());
+       //is there a delivery address
+       QString s=cartaddr->toPlainText().trimmed();
+       if(s!=""){
+               QDomElement da=doc.createElement("DeliveryAddress");
+               da.appendChild(doc.createTextNode(s));
+               root.appendChild(da);
+       }
+       //is there a comment?
+       s=cartcomment->toPlainText().trimmed();
+       if(s!=""){
+               QDomElement cc=doc.createElement("Comment");
+               cc.appendChild(doc.createTextNode(s));
+               root.appendChild(cc);
+       }
+       //scan tickets & scan vouchers
+       for(int i=0;i<cartmodel->rowCount();i++){
+               QModelIndex idx=cartmodel->index(i,0);
+               int tp=cartmodel->data(idx,CART_TYPEROLE).toInt();
+               if(tp==CART_TICKET){
+                       int amt=cartmodel->data(idx).toInt();
+                       int evid=cartmodel->data(idx,CART_IDROLE).toInt();
+                       for(int j=0;j<amt;j++){
+                               QDomElement tc=doc.createElement("Ticket");
+                               tc.setAttribute("event",evid);
+                               root.appendChild(tc);
+                       }
+               }else
+               if(tp==CART_VOUCHER){
+                       int amt=cartmodel->data(idx).toInt();
+                       int price=cartmodel->data(idx,CART_PRICEROLE).toInt();
+                       int value=cartmodel->data(idx,CART_VALUEROLE).toInt();
+                       for(int j=0;j<amt;j++){
+                               QDomElement tc=doc.createElement("Voucher");
+                               tc.setAttribute("price",price);
+                               tc.setAttribute("value",value);
+                               root.appendChild(tc);
+                       }
+               
+               }
+       }
+       //set shipping info
+       if(cartship->currentIndex()>0){
+               QDomElement si=doc.createElement("Shipping");
+               si.setAttribute("type",cartship->itemData(cartship->currentIndex()).toInt());
+               root.appendChild(si);
+       }
+       //finalize
+       doc.appendChild(root);
+       //send
+       /*TODO
+       if(req->request("checkorder",doc.toByteArray())==false){
+               QMessageBox::warning(this,tr("Error"),tr("The request failed."));
+               return;
+       }
+       if(req->responseStatus()!=MSInterface::Ok){
+               QMessageBox::warning(this,tr("Error"),tr("A problem occurred during the order: %1").arg(qApp->translate("php::",req->responseBody())));
+               return;
+       }
+       //parse result
+       QDomDocument rdoc;
+       rdoc.setContent(req->responseBody());
+       //display order and give user chance to actually order it
+       MOrderWindow *ow=new MOrderWindow(this,req,MOrder(req,rdoc.documentElement()));
+       ow->show();
+       //empty the cart
+       initCart();*/
+}
+
+void MOverview::customerMgmt()
+{/*TODO
+       MCustomerListDialog mcl(req,this);
+       mcl.exec();*/
+}
+
+void MOverview::editShipping()
+{/*TODO
+       MShippingEditor se(req,this);
+       se.exec();
+       updateShipping();*/
+}
+
+void MOverview::tabChanged()
+{/*TODO
+       QWidget*w=tab->currentWidget();
+       if(w==entrancetab){
+               //fill combobox from eventmodel
+               int ci=entranceevent->currentIndex();
+               int cev=-1;
+               if(ci>=0)cev=entranceevent->itemData(ci).toInt();
+               ci=-1;
+               entranceevent->clear();
+               for(int i=0;i<eventmodel->rowCount();i++){
+                       QString ev=eventmodel->data(eventmodel->index(i,0)).toString()+" "+
+                        eventmodel->data(eventmodel->index(i,1)).toString();
+                       int eid=eventmodel->data(eventmodel->index(i,0),Qt::UserRole).toInt();
+                       entranceevent->addItem(ev,eid);
+                       if(eid==cev)ci=i;
+               }
+               if(ci>=0)entranceevent->setCurrentIndex(ci);
+               //set focus on scanner
+               entrancescan->setFocus(Qt::OtherFocusReason);
+               entrancescan->setText("");
+       }*/
+}
+
+void MOverview::entranceValidate()
+{/*TODO
+       //get event ID
+       int ci=entranceevent->currentIndex();
+       if(ci<0)return;
+       int cev=entranceevent->itemData(ci).toInt();
+       //check content
+       QString tid=entrancescan->text().trimmed();
+       entrancescan->setText("");
+       //avoid spurious events
+       if(tid=="")return;
+       //avoid double scans
+       QDateTime now=QDateTime::currentDateTime();
+       if(tid==lastbarcode && lastbcscan.addSecs(20)>=now)
+               return;
+       lastbarcode=tid;
+       lastbcscan=now;
+       //reset display
+       QPalette pal=entrancelabel->palette();
+       QPalette::ColorRole rl=QPalette::Window;
+       pal.setColor(rl,Qt::lightGray);
+       entrancelabel->setPalette(pal);
+       entrancelabel->setText(tr("searching...","entrance control"));
+       //ask the server
+       MTicket tick(req,tid);
+       //decide what to do
+       if(!tick.isValid()){
+               entrancelabel->setText(tr("Ticket \"%1\" Not Valid").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else
+       if(tick.eventID()!=cev){
+               entrancelabel->setText(tr("Ticket \"%1\" is not for this event.").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else
+       if(tick.status()==MTicket::Used){
+               entrancelabel->setText(tr("Ticket \"%1\" has already been used").arg(tid));
+               pal.setColor(rl,Qt::magenta);
+       }else
+       if(tick.status()!=MTicket::Bought){
+               entrancelabel->setText(tr("Ticket \"%1\" has not been bought.").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else
+       if(tick.paymentStatus()==MTicket::PSOk){
+               entrancelabel->setText(tr("Ticket \"%1\" Ok").arg(tid));
+               pal.setColor(rl,Qt::green);
+               tick.markUsed();
+       }else
+       if(tick.paymentStatus()==MTicket::PSNeedRefund){
+               entrancelabel->setText(tr("Ticket \"%1\" Ok; the Order has a refund").arg(tid));
+               pal.setColor(rl,Qt::green);
+               tick.markUsed();
+       }else
+       if(tick.paymentStatus()==MTicket::PSNeedPayment){
+               entrancelabel->setText(tr("Ticket \"%1\" is not paid for!").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }else{
+               entrancelabel->setText(tr("Ticket \"%1\" cannot be accepted, please check the order!").arg(tid));
+               pal.setColor(rl,Qt::red);
+       }
+       
+       entrancelabel->setPalette(pal);
+       entrancescan->setFocus(Qt::OtherFocusReason);
+       entrancescan->setText("");*/
+}
+
+//helper: finds out whether an order should be printed.
+static inline bool candoUpdateOrders(int omode,const MOrder&ord)
+{
+       if(omode==ORDERALL)return true;
+       if((omode&ORDERPAY)!=0 && ord.needsPayment())return true;
+       if((omode&ORDERREFUND)!=0 && ord.needsRefund())return true;
+       if((omode&ORDERUNSENT)!=0 && !ord.isSent())return true;
+       if((omode&ORDERRESERVE)!=0 && ord.isReservation())return true;
+       return false;
+}
+
+void MOverview::updateOrders()
+{/*TODO
+       ordermodel->clear();
+       ordermodel->setHorizontalHeaderLabels(QStringList()<<tr("Status")<<tr("Total")<<tr("Paid")<<tr("Customer"));
+       int omode=ordermode->itemData(ordermode->currentIndex()).toInt();
+       if(omode==ORDERNONE)return;
+       QList<MOrder> orders=req->getAllOrders();
+       if(orders.size()==0)return;
+       QList<MCustomer> cust=req->getAllCustomers();
+       int cl=0;
+       for(int i=0;i<orders.size();i++){
+               if(!candoUpdateOrders(omode,orders[i]))continue;
+               ordermodel->insertRow(cl);
+               ordermodel->setHeaderData(cl,Qt::Vertical,orders[i].orderID());
+               ordermodel->setData(ordermodel->index(cl,0),orders[i].orderStatusString());
+               ordermodel->setData(ordermodel->index(cl,0),orders[i].orderID(),Qt::UserRole);
+               ordermodel->setData(ordermodel->index(cl,1),orders[i].totalPriceString());
+               ordermodel->setData(ordermodel->index(cl,2),orders[i].amountPaidString());
+               int cid=orders[i].customerID();
+               //TODO: make this more effective:
+               for(int j=0;j<cust.size();j++)
+                       if(cust[j].customerID()==cid)
+                               ordermodel->setData(ordermodel->index(cl,3),cust[j].name());
+               cl++;
+       }
+       ordertable->resizeColumnsToContents();*/
+}
+
+void MOverview::orderDetails()
+{/*TODO
+       //get selected order
+       int id;
+       QModelIndexList ilst=ordertable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=ordermodel->index(ilst[0].row(),0);
+       id=ordermodel->data(idx,Qt::UserRole).toInt();
+       if(id<0)return;
+       //open order window
+       MOrderWindow *om=new MOrderWindow(this,req,MOrder(req,id));
+       om->setAttribute(Qt::WA_DeleteOnClose);
+       om->show();*/
+}
+
+void MOverview::orderByTicket()
+{/*TODO
+       //get selected order
+       bool ok;
+       QString tid=QInputDialog::getText(this,tr("Enter Ticket"),tr("Please enter the ID of one of the tickets of the order you seek:"),QLineEdit::Normal,"",&ok);
+       if(!ok || tid=="")return;
+       //request it
+       if(!req->request("orderbyticket",tid.toUtf8())){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to query server."));
+               return;
+       }
+       if(req->responseStatus()!=MSInterface::Ok){
+               QMessageBox::warning(this,tr("Warning"),qApp->translate("php::",req->responseBody()));
+               return;
+       }
+       int id=req->responseBody().trimmed().toInt(&ok);
+       if(!ok || id<0){
+               QMessageBox::warning(this,tr("Warning"),tr("Server returned an invalid order ID."));
+               return;
+       }
+       //open order window
+       MOrderWindow *om=new MOrderWindow(this,req,MOrder(req,id));
+       om->setAttribute(Qt::WA_DeleteOnClose);
+       om->show();*/
+}
+
+void MOverview::orderByEvent()
+{/*TODO
+       //display selection dialog
+       QDialog d(this);
+       d.setWindowTitle(tr("Select Event"));
+       QVBoxLayout*vl;
+       QHBoxLayout*hl;
+       d.setLayout(vl=new QVBoxLayout);
+       QTableView*tv;
+       vl->addWidget(tv=new QTableView,10);
+       tv->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       tv->setModel(eventmodel);
+       tv->resizeColumnsToContents();
+       vl->addLayout(hl=new QHBoxLayout,0);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Ok")),0);
+       connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")),0);
+       connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+       //wait for user
+       if(d.exec()!=QDialog::Accepted)
+               return;
+       //get selection
+       QModelIndexList ilst=tv->selectionModel()->selectedIndexes();
+       if(ilst.size()<1){
+               qDebug("nothing selected");
+               return;
+       }
+       //get events
+       QList<int>eventids;
+       for(int i=0;i<ilst.size();i++){
+               int eid=eventmodel->data(eventmodel->index(ilst[i].row(),0),Qt::UserRole).toInt();
+               if(!eventids.contains(eid))eventids.append(eid);
+       }
+       //request data and display
+       //TODO: unify this part with updateOrders
+       ordermodel->clear();
+       ordermodel->setHorizontalHeaderLabels(QStringList()<<tr("Status")<<tr("Total")<<tr("Paid")<<tr("Customer"));
+       QList<MOrder> orders=req->getOrdersByEvents(eventids);
+       if(orders.size()==0)return;
+       QList<MCustomer> cust=req->getAllCustomers();
+       for(int cl=0;cl<orders.size();cl++){
+               ordermodel->insertRow(cl);
+               ordermodel->setHeaderData(cl,Qt::Vertical,orders[cl].orderID());
+               ordermodel->setData(ordermodel->index(cl,0),orders[cl].orderStatusString());
+               ordermodel->setData(ordermodel->index(cl,0),orders[cl].orderID(),Qt::UserRole);
+               ordermodel->setData(ordermodel->index(cl,1),orders[cl].totalPriceString());
+               ordermodel->setData(ordermodel->index(cl,2),orders[cl].amountPaidString());
+               int cid=orders[cl].customerID();
+               //TODO: make this more effective:
+               for(int j=0;j<cust.size();j++)
+                       if(cust[j].customerID()==cid)
+                               ordermodel->setData(ordermodel->index(cl,3),cust[j].name());
+       }
+       ordermode->setCurrentIndex(ordermode->count()-1);*/
+}
+
+void MOverview::orderByCustomer()
+{/*TODO
+       //display selection dialog
+       MCustomerListDialog mcl(req,this,true);
+       //wait for user
+       if(mcl.exec()!=QDialog::Accepted)
+               return;
+       //get selection
+       MCustomer cst=mcl.getCustomer();
+       if(!cst.isValid()){
+               qDebug("nothing selected");
+               return;
+       }
+       qint64 custid=cst.customerID();
+       //request data and display
+       //TODO: unify this part with updateOrders
+       ordermodel->clear();
+       ordermodel->setHorizontalHeaderLabels(QStringList()<<tr("Status")<<tr("Total")<<tr("Paid")<<tr("Customer"));
+       QList<MOrder> orders=req->getAllOrders();
+       if(orders.size()==0)return;
+       QList<MCustomer> cust=req->getAllCustomers();
+       int cl=0;
+       for(int i=0;i<orders.size();i++){
+               //filter
+               if(orders[i].customerID()!=custid)continue;
+               //put into table
+               ordermodel->insertRow(cl);
+               ordermodel->setHeaderData(cl,Qt::Vertical,orders[i].orderID());
+               ordermodel->setData(ordermodel->index(cl,0),orders[i].orderStatusString());
+               ordermodel->setData(ordermodel->index(cl,0),orders[i].orderID(),Qt::UserRole);
+               ordermodel->setData(ordermodel->index(cl,1),orders[i].totalPriceString());
+               ordermodel->setData(ordermodel->index(cl,2),orders[i].amountPaidString());
+               ordermodel->setData(ordermodel->index(cl,3),cst.name());
+               //count up
+               cl++;
+       }
+       ordermode->setCurrentIndex(ordermode->count()-1);*/
+}
+
+void MOverview::orderByOrder()
+{/*TODO
+       //ask for OrderID
+       bool ok;
+       int oid=QInputDialog::getInteger(this,tr("Enter Order ID"),tr("Please enter the ID of the order you want to display:"),0,0,2147483647,1,&ok);
+       if(!ok)return;
+       //display
+       MOrder ord(req,oid);
+       if(!ord.isValid()){
+               QMessageBox::warning(this,tr("Warning"),tr("This order does not exist."));
+               return;
+       }
+       MOrderWindow *ow=new MOrderWindow(this,req,ord);
+       ow->show();*/
+}
+
+void MOverview::ticketReturn()
+{/*TODO
+       //get ticket
+       bool ok;
+       QString tid=QInputDialog::getText(this,tr("Return Ticket"),tr("Please enter the ticket ID to return:"),QLineEdit::Normal,"",&ok);
+       if(!ok || tid=="")return;
+       MTicket tick(req,tid);
+       if(!tick.isValid()){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a valid ticket."));
+               return;
+       }
+       //check state
+       if(tick.status()!=MTicket::Bought && tick.status()!=MTicket::Reserved){
+               QMessageBox::warning(this,tr("Warning"),tr("This ticket cannot be returned, it has already been used or is in the wrong state."));
+               return;
+       }
+       //submit
+       QString r=tick.ticketReturn();
+       if(r!="")QMessageBox::warning(this,tr("Warning"),trUtf8(r.toUtf8()));*/
+}
+
+void MOverview::voucherReturn()
+{/*TODO
+       //get ticket
+       bool ok;
+       QString tid=QInputDialog::getText(this,tr("Return Voucher"),tr("Please enter the voucher ID to return:"),QLineEdit::Normal,"",&ok);
+       if(!ok || tid=="")return;
+       MVoucher vouc(req,tid);
+       if(!vouc.isValid()){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a valid voucher."));
+               return;
+       }
+       //check state
+       if(vouc.isUsed()){
+               QMessageBox::warning(this,tr("Warning"),tr("This voucher cannot be returned, it has already been used."));
+               return;
+       }
+       //submit
+       QString r=vouc.voucherReturn();
+       if(r!="")QMessageBox::warning(this,tr("Warning"),trUtf8(r.toUtf8()));*/
+}
+
+void MOverview::deductVoucher()
+{/*TODO
+       //get voucher ID and amount
+       QDialog d;
+       d.setWindowTitle(tr("Deduct from Voucher"));
+       QGridLayout *gl;
+       d.setLayout(gl=new QGridLayout);
+       gl->addWidget(new QLabel(tr("Using a voucher to pay outside the system.")),0,0,1,2);
+       
+       QLineEdit*vid;
+       MCentSpinBox*cent;
+       gl->addWidget(new QLabel(tr("Amount to deduct:")),1,0);
+       gl->addWidget(cent=new MCentSpinBox,1,1);
+       gl->addWidget(new QLabel(tr("Voucher ID:")),2,0);
+       gl->addWidget(vid=new QLineEdit,2,1);
+       
+       gl->setRowMinimumHeight(3,15);
+       QHBoxLayout*hl;
+       gl->addLayout(hl=new QHBoxLayout,4,0,1,2);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("OK")));
+       connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")));
+       connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+       if(d.exec()!=QDialog::Accepted)return;
+       if(vid->text().trimmed()=="" || cent->value()<=0)return;
+       //query server
+       QByteArray r=vid->text().trimmed().toAscii()+"\n"+QString::number(cent->value()).toAscii();
+       if(!req->request("usevoucheroutside",r)){
+               QMessageBox::warning(this,tr("Warning"),tr("Request failed."));
+               return;
+       }
+       if(req->responseStatus()!=MSInterface::Ok){
+               QMessageBox::warning(this,tr("Warning"),tr("Request failed."));
+               return;
+       }
+       QStringList sl=QString::fromAscii(req->responseBody().trimmed()).split("\n");
+       int tak=-1,rem=-1;
+       if(sl.size()>0)tak=sl[0].trimmed().toInt();
+       if(sl.size()>1)rem=sl[1].trimmed().toInt();
+       QMessageBox::information(this,tr("Deducted from Voucher"),tr("Value taken from voucher: %1\nValue remaining on voucher: %2").arg(cent2str(tak)).arg(cent2str(rem)));*/
+}
+
+void MOverview::refreshData()
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       if(set.value("refreshEvents",false).toBool() && req->hasRole("geteventlist"))
+               updateEvents();
+       if(set.value("refreshUsers",false).toBool() && req->hasRole("getusers"))
+               updateUsers();
+       if(set.value("refreshHosts",false).toBool() && req->hasRole("gethosts"))
+               updateHosts();
+       if(set.value("refreshShipping",false).toBool() && req->hasRole("getshipping"))
+               updateShipping();
+}
+
+void MOverview::setRefresh()
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       //dialog
+       QDialog d;
+       d.setWindowTitle(tr("Refresh Settings"));
+       QVBoxLayout*vl;
+       QHBoxLayout*hl;
+       d.setLayout(vl=new QVBoxLayout);
+       vl->addLayout(hl=new QHBoxLayout);
+       hl->addWidget(new QLabel(tr("Refresh Rate (minutes):")),1);
+       QSpinBox*rate;
+       hl->addWidget(rate=new QSpinBox,0);
+       rate->setRange(1,999);
+       rate->setValue(set.value("refresh",300).toInt()/60);
+       QCheckBox *rev,*rus,*rho,*rsh;
+       vl->addWidget(rev=new QCheckBox(tr("refresh &event list")));
+       rev->setChecked(set.value("refreshEvents",false).toBool());
+       vl->addWidget(rus=new QCheckBox(tr("refresh &user list")));
+       rus->setChecked(set.value("refreshUsers",false).toBool());
+       vl->addWidget(rho=new QCheckBox(tr("refresh &host list")));
+       rho->setChecked(set.value("refreshHosts",false).toBool());
+       vl->addWidget(rsh=new QCheckBox(tr("refresh &shipping list")));
+       rho->setChecked(set.value("refreshShipping",false).toBool());
+       vl->addSpacing(15);
+       vl->addStretch(10);
+       vl->addLayout(hl=new QHBoxLayout);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("&OK")));
+       connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("&Cancel")));
+       connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+       if(d.exec()!=QDialog::Accepted)return;
+       //write settings
+       set.setValue("refreshEvents",rev->isChecked());
+       set.setValue("refreshUsers",rus->isChecked());
+       set.setValue("refreshHosts",rho->isChecked());
+       set.setValue("refreshShipping",rsh->isChecked());
+       set.setValue("refresh",rate->value()*60);
+       //reset timer
+       rtimer.stop();
+       rtimer.setInterval(rate->value()*60000);
+       rtimer.start();
+}
+
+void MOverview::webSettings(bool showdlg)
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       //get settings
+       MSInterface::LogLevel lvl=MSInterface::LogLevel(set.value("webloglevel", MSInterface::LogOnError).toInt());
+       int timeout=set.value("webtimeout",30).toInt();
+       //dialog
+       if(showdlg){
+               QDialog d;
+               d.setWindowTitle(tr("Server Access Settings"));
+               QGridLayout*gl;
+               QHBoxLayout*hl;
+               d.setLayout(gl=new QGridLayout);
+               gl->addWidget(new QLabel(tr("Request Timeout (seconds):")),0,0);
+               QSpinBox*tmout;
+               gl->addWidget(tmout=new QSpinBox,0,1);
+               tmout->setRange(10,999);
+               tmout->setValue(timeout);
+               QComboBox *log;
+               gl->addWidget(new QLabel(tr("Log Level:")),1,0);
+               gl->addWidget(log=new QComboBox,1,1);
+               log->addItem(tr("Minimal Logging"),MSInterface::LogMinimal);
+               log->addItem(tr("Log Details on Error"),MSInterface::LogOnError);
+               log->addItem(tr("Always Log Details"),MSInterface::LogDetailed);
+               switch(lvl){
+                       case MSInterface::LogMinimal:log->setCurrentIndex(0);break;
+                       case MSInterface::LogOnError:log->setCurrentIndex(1);break;
+                       case MSInterface::LogDetailed:log->setCurrentIndex(2);break;
+               }
+               gl->setRowMinimumHeight(2,15);
+               gl->addLayout(hl=new QHBoxLayout,3,0,1,2);
+               hl->addStretch(10);
+               QPushButton*p;
+               hl->addWidget(p=new QPushButton(tr("&OK")));
+               connect(p,SIGNAL(clicked()),&d,SLOT(accept()));
+               hl->addWidget(p=new QPushButton(tr("&Cancel")));
+               connect(p,SIGNAL(clicked()),&d,SLOT(reject()));
+               if(d.exec()!=QDialog::Accepted)return;
+               //write settings
+               lvl=MSInterface::LogLevel(log->itemData(log->currentIndex()).toInt());
+               timeout=tmout->value();
+               set.setValue("webloglevel",lvl);
+               set.setValue("webtimeout",timeout);
+       }
+       //reset webrequest
+       req->setLogLevel(lvl);
+       req->setWebTimeout(timeout*1000);
+}
+
+void MOverview::doBackup()
+{
+       baktimer.stop();
+       //sanity check
+       if(!req->hasRight(req->RBackup))return;
+       //get settings
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       QString path=set.value("backupfile",req->dataDir()+"/backup").toString();
+       int gens=set.value("backupgenerations",3).toInt();
+       //get data
+       MTBackup bc;
+       bc=MTBackup::query();
+       if(bc.stage()!=bc.Success){
+               QMessageBox::warning(this,tr("Warning"),tr("Backup failed with error (%2): %1").arg(bc.errorString()).arg(bc.errorType()));
+               return;
+       }
+       if(bc.getbackup().isNull()||bc.getbackup().value().isEmpty()){
+               QMessageBox::warning(this,tr("Warning"),tr("Backup returned empty."));
+               return;
+       }
+       //rotate files
+       QFile(path+"."+QString::number(gens)).remove();
+       for(int i=gens-1;i>=0;i--){
+               if(i)
+                       QFile(path+"."+QString::number(i)).rename(path+"."+QString::number(i+1));
+               else
+                       QFile(path).rename(path+".1");
+       }
+       //store new data
+       QFile fd(path);
+       if(fd.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+               fd.write(bc.getbackup().value().toAscii());
+               fd.close();
+               set.setValue("backuptime",QDateTime::currentDateTime().toTime_t());
+               QMessageBox::information(this,tr("Backup"),tr("The backup was successful."));
+               int tm=set.value("backupinterval",0).toInt()*86400000;
+               if(tm)baktimer.start(tm);
+       }else
+               QMessageBox::warning(this,tr("Warning"),tr("Cannot create backup file."));
+}
+
+void MOverview::backupSettings()
+{
+       //show dialog
+       MBackupDialog d(this,profilekey);
+       d.exec();
+       //reset timer
+       int btm=QSettings().value("profiles/"+profilekey+"/backupinterval",0).toInt()*86400;
+       if(btm){
+               //adjust for last backup time
+               int iv=QDateTime::currentDateTime().toTime_t() - QSettings().value("profiles/"+profilekey+"/backuptime",0).toInt();
+               if(iv>=btm)btm=0;
+               else btm-=iv;
+               //start timer
+               baktimer.start(btm*1000);
+       }
+}
+
+void MOverview::moneylogVoucher()
+{/*TODO
+       QString vid=QInputDialog::getText(this,tr("Voucher ID"),tr("Please enter voucher ID to show log:"));
+       if(vid!="")
+               MMoneyLog(this,req,"voucher\n"+vid).exec();*/
+}
+
+void MOverview::moneylogUser()
+{/*TODO
+       QString vid=QInputDialog::getText(this,tr("User"),tr("Please enter login name of user to show log:"));
+       if(vid!="")
+               MMoneyLog(this,req,"user\n"+vid).exec();*/
+}
+
+
+/**********************************************/
+
+MBackupDialog::MBackupDialog(QWidget*par,QString pk)
+       :QDialog(par),profilekey(pk)
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       QString path=set.value("backupfile",req->dataDir()+"/backup").toString();
+       int gens=set.value("backupgenerations",3).toInt();
+       int tm=set.value("backupinterval",0).toInt();
+       //dialog
+       setWindowTitle(tr("Backup Settings"));
+       QGridLayout*gl;
+       QHBoxLayout*hl;
+       setLayout(gl=new QGridLayout);
+       QPushButton*p;
+       gl->addWidget(new QLabel(tr("Backup File:")),0,0);
+       gl->addWidget(lpath=new QLineEdit(path),0,1);
+       gl->addWidget(p=new QPushButton(tr("...")),0,2);
+       connect(p,SIGNAL(clicked()),this,SLOT(getpath()));
+       
+       gl->addWidget(new QLabel(tr("Generations to keep:")),1,0);
+       gl->addWidget(gener=new QSpinBox,1,1,1,2);
+       gener->setRange(1,16);
+       gener->setValue(gens);
+       
+       gl->addWidget(new QLabel(tr("Automatic Backup:")),2,0);
+       gl->addWidget(autob=new QCheckBox,2,1,1,2);
+       autob->setChecked(tm>0);
+       
+       gl->addWidget(new QLabel(tr("Interval in days:")),3,0);
+       gl->addWidget(interv=new QSpinBox,3,1,1,2);
+       interv->setRange(1,24);
+       interv->setValue(tm>0?tm:1);
+       
+       gl->setRowMinimumHeight(4,15);
+       gl->addLayout(hl=new QHBoxLayout,5,0,1,3);
+       hl->addStretch(10);
+       hl->addWidget(p=new QPushButton(tr("&OK")));
+       connect(p,SIGNAL(clicked()),this,SLOT(accept()));
+       connect(p,SIGNAL(clicked()),this,SLOT(save()));
+       hl->addWidget(p=new QPushButton(tr("&Cancel")));
+       connect(p,SIGNAL(clicked()),this,SLOT(reject()));
+}
+
+void MBackupDialog::getpath()
+{
+       QString path=QFileDialog::getSaveFileName(this,tr("Backup File"),lpath->text());
+       if(path!="")lpath->setText(path);
+}
+
+void MBackupDialog::save()
+{
+       QSettings set;
+       set.beginGroup("profiles/"+profilekey);
+       set.setValue("backupfile",lpath->text());
+       set.setValue("backupgenerations",gener->value());
+       set.setValue("backupinterval",autob->isChecked()?interv->value():0);
+}
+/**********************************************/
+
+MPasswordChange::MPasswordChange(QWidget*par,QString user)
+       :QDialog(par)
+{
+       oldpwd=newpwd1=newpwd2=0;
+       if(user=="")
+               setWindowTitle(tr("Change my password"));
+       else
+               setWindowTitle(tr("Reset password of user \"%1\"").arg(user));
+       QGridLayout*gl;
+       setLayout(gl=new QGridLayout);
+       if(user==""){
+               gl->addWidget(new QLabel(tr("Old Password:")),0,0);
+               gl->addWidget(oldpwd=new QLineEdit,0,1);
+               oldpwd->setEchoMode(QLineEdit::Password);
+       }
+       gl->addWidget(new QLabel(tr("New Password:")),1,0);
+       gl->addWidget(newpwd1=new QLineEdit,1,1);
+       newpwd1->setEchoMode(QLineEdit::Password);
+       gl->addWidget(new QLabel(tr("Repeat Password:")),2,0);
+       gl->addWidget(newpwd2=new QLineEdit,2,1);
+       newpwd2->setEchoMode(QLineEdit::Password);
+       
+       QHBoxLayout*hl;
+       gl->addLayout(hl=new QHBoxLayout,3,0,1,2);
+       hl->addStretch(10);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Set Password")));
+       connect(p,SIGNAL(clicked()),this,SLOT(accept()));
+       hl->addWidget(p=new QPushButton(tr("Cancel")));
+       connect(p,SIGNAL(clicked()),this,SLOT(reject()));
+}
+
+QString MPasswordChange::oldPassword()
+{
+       if(oldpwd)return oldpwd->text();
+       return "";
+}
+
+QString MPasswordChange::newPassword()
+{
+       if(newpwd1==0 || newpwd2==0)return "";
+       if(newpwd1->text()!=newpwd2->text())return "";
+       return newpwd1->text();
+}
+
+
+/********************************************************************************/
+
+MCartTableDelegate::MCartTableDelegate(QObject*p)
+       :QItemDelegate(p)
+{
+}
+
+QWidget *MCartTableDelegate::createEditor(QWidget *parent,
+        const QStyleOptionViewItem &/* option */,
+        const QModelIndex & index ) const
+{
+       //base class
+       if(index.column()!=0)return 0;
+       
+       QSpinBox *editor = new QSpinBox(parent);
+       editor->setRange(1,1000);
+       editor->installEventFilter(const_cast<MCartTableDelegate*>(this));
+       return editor;
+}
+
+void MCartTableDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
+{
+       //name field
+       int c=index.column();
+       if(c==0)
+               ((QSpinBox*)editor)->setValue(index.model()->data(index).toInt());
+}
+
+void MCartTableDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
+       const QModelIndex &index) const
+{
+       //name field
+       int c=index.column();
+       if(c==0){
+               int newval=((QSpinBox*)editor)->value();
+               model->setData(index,newval);
+       }
+}
diff --git a/src/mwin/orderstab.h b/src/mwin/orderstab.h
new file mode 100644 (file)
index 0000000..dfd5a43
--- /dev/null
@@ -0,0 +1,235 @@
+//
+// C++ Interface: overview
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2007
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef MAGICSMOKE_OVERVIEW_H
+#define MAGICSMOKE_OVERVIEW_H
+
+#include <QDateTime>
+#include <QDialog>
+#include <QItemDelegate>
+#include <QMainWindow>
+#include <QTimer>
+
+#include "customer.h"
+
+class QAction;
+class QCheckBox;
+class QComboBox;
+class QLabel;
+class QLineEdit;
+class QPushButton;
+class QSpinBox;
+class QStandardItemModel;
+class QTabWidget;
+class QTableView;
+
+class MSInterface;
+
+/**Main Overview Window*/
+class MOverview:public QMainWindow
+{
+       Q_OBJECT
+       public:
+               /**construct the window with web-request/session handler and QSettings-key for current profile*/
+               MOverview(QString);
+               ~MOverview();
+       protected:
+               /**handle closing the window: close the session too*/
+               void closeEvent(QCloseEvent*);
+       private slots:
+               /**try to log in again*/
+               void relogin();
+               
+               /**create a new event*/
+               void newEvent();
+               /**edit existing event*/
+               void editEvent();
+               /**update list of events*/
+               void updateEvents();
+               /**order ticket from event tab*/
+               void eventOrderTicket();
+               /**open event summary*/
+               void eventSummary();
+               /**cancel the event*/
+               void eventCancel();
+               
+               /**update shipping info*/
+               void updateShipping();
+               
+               /**get all orders, update list*/
+               void updateOrders();
+               /**open order detail window*/
+               void orderDetails();
+               
+               /**update list of users*/
+               void updateUsers();
+               /**create new user*/
+               void newUser();
+               /**delete selected user*/
+               void deleteUser();
+               /**set users description*/
+               void editUserDescription();
+               /**set users roles*/
+               void editUserRoles();
+               /**set users hosts*/
+               void editUserHosts();
+               /**set my own password*/
+               void setMyPassword();
+               /**set a users password*/
+               void setUserPassword();
+               
+               /**update list of hosts*/
+               void updateHosts();
+               /**create new host*/
+               void newHost();
+               /**create a database entry for this host*/
+               void addThisHost();
+               /**delete a host*/
+               void deleteHost();
+               /**generate a new key*/
+               void changeHostKey();
+               /**import host from file*/
+               void importHost();
+               /**export host to file*/
+               void exportHost();
+               
+               /**decide what customer to use*/
+               void setCustomer();
+               /**initialize cart tab*/
+               void initCart();
+               /**add a ticket to the cart*/
+               void cartAddTicket();
+               /**add a voucher to the cart*/
+               void cartAddVoucher();
+               /**remove item from the cart*/
+               void cartRemoveItem();
+               /**check the order on the server*/
+               void cartOrder();
+               
+               /**manage customers*/
+               void customerMgmt();
+               
+               /**edit shipping options*/
+               void editShipping();
+               
+               /**generic check which tab is active*/
+               void tabChanged();
+               
+               /**react on entry in Entrance tab*/
+               void entranceValidate();
+               
+               /**return a ticket*/
+               void ticketReturn();
+               /**return a voucher*/
+               void voucherReturn();
+               /**find an order by ticket*/
+               void orderByTicket();
+               /**find/select orders by event*/
+               void orderByEvent();
+               /**find/select orders by customer*/
+               void orderByCustomer();
+               /**find and display order by order ID*/
+               void orderByOrder();
+               /**deduct some money from a voucher (to pay outside the system)*/
+               void deductVoucher();
+               
+               /**money log for voucher*/
+               void moneylogVoucher();
+               /**money log for user*/
+               void moneylogUser();
+               
+               /**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);
+               
+               /**do a backup now*/
+               void doBackup();
+               
+               /**settings for backup*/
+               void backupSettings();
+               
+       private:
+               //the profile associated with this session
+               QString profilekey;
+               //widgets
+               QTabWidget*tab;
+               QWidget*eventtab,*carttab,*usertab,*hosttab,*ordertab,*entrancetab;
+               QTableView*eventtable,*usertable,*hosttable,*carttable,*ordertable;
+               QStandardItemModel*eventmodel,*usermodel,*hostmodel,*cartmodel,*ordermodel;
+               QPushButton*thishostbutton;
+               QLabel*cartcustomer,*entrancelabel;
+               QTextEdit *cartaddr,*cartcomment;
+               QComboBox*ordermode,*cartship,*entranceevent;
+               QLineEdit*entrancescan;
+               //event list
+               QAction*showoldevents;
+               //cart
+               MCustomer customer;
+               //barcode cache
+               QString lastbarcode;
+               QDateTime lastbcscan;
+               //refresh timers
+               QTimer rtimer,baktimer;
+};
+
+/**Helper dialog for changing passwords*/
+class MPasswordChange:public QDialog
+{
+       Q_OBJECT
+       public:
+               /**creates a password change dialog, if user is empty it is presumed to change own password*/
+               MPasswordChange(QWidget*parent,QString user=QString());
+               
+               /**if own password: return old password*/
+               QString oldPassword();
+               /**returns new password, or empty if the two lines don't match*/
+               QString newPassword();
+       private:
+               QLineEdit *oldpwd,*newpwd1,*newpwd2;
+};
+
+/**Helper class for shopping cart: allow editing amount, but nothing else*/
+class MCartTableDelegate:public QItemDelegate
+{
+       public:
+               MCartTableDelegate(QObject *parent = 0);
+               
+               QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
+                                     const QModelIndex &index) const;
+               
+               void setEditorData(QWidget *editor, const QModelIndex &index) const;
+               void setModelData(QWidget *editor, QAbstractItemModel *model,
+                                 const QModelIndex &index) const;
+};
+
+/**Helper class for Backup settings*/
+class MBackupDialog:public QDialog
+{
+       Q_OBJECT
+       public:
+               MBackupDialog(QWidget*,QString);
+               
+       private slots:
+               void getpath();
+               void save();
+       private:
+               QLineEdit*lpath;
+               QSpinBox*interv,*gener;
+               QCheckBox*autob;
+               QString profilekey;
+};
+
+#endif
index 33d9424..ead5eb5 100644 (file)
@@ -19,7 +19,9 @@
 #include "moneylog.h"
 #include "msinterface.h"
 #include "orderwin.h"
+
 #include "overview.h"
+#include "eventstab.h"
 
 #include <QApplication>
 #include <QBoxLayout>
@@ -89,18 +91,6 @@ MOverview::MOverview(QString pk)
        m->addSeparator();
        m->addAction(tr("&Close Session"),this,SLOT(close()));
        
-       m=mb->addMenu(tr("&Event"));
-       m->addAction(tr("&Update Event List"),this,SLOT(updateEvents()))
-        ->setEnabled(req->hasRight(req->RGetAllEvents));
-       m->addAction(tr("&Show/Edit details..."),this,SLOT(editEvent()))
-        ->setEnabled(req->hasRight(req->RGetEvent));
-       m->addAction(tr("&New Event..."),this,SLOT(newEvent()))->setEnabled(req->hasRole("createevent"));
-       m->addSeparator();
-       showoldevents=m->addAction(tr("Show &old Events"),this,SLOT(updateEvents()));
-       showoldevents->setEnabled(req->hasRight(req->RGetAllEvents));
-       showoldevents->setCheckable(true);
-       showoldevents->setChecked(QSettings().value("profiles/"+pk+"/showOldEvents",false).toBool());
-       
        m=mb->addMenu(tr("&Customer"));
        m->addAction(tr("&Show all customers"),this,SLOT(customerMgmt()));
        
@@ -135,40 +125,18 @@ MOverview::MOverview(QString pk)
 
        mb->addMenu(MApplication::helpMenu());
        
+       //make sure webrequest knows its settings
+       webSettings(false);
+       
        //tabs
        setCentralWidget(tab=new QTabWidget);
        connect(tab,SIGNAL(currentChanged(int)),this,SLOT(tabChanged()));
        
        //Event tab
-       tab->addTab(eventtab=new QWidget,tr("Events"));
+       tab->addTab(eventtab=new MEventsTab(pk),tr("Events"));
+       mb->addMenu(eventtab->menu());
        QVBoxLayout*vl;QHBoxLayout*hl;
-       eventtab->setLayout(hl=new QHBoxLayout);
-       hl->addWidget(eventtable=new QTableView,10);
-       eventtable->setModel(eventmodel=new QStandardItemModel(this));
-       eventtable->setSelectionMode(QAbstractItemView::SingleSelection);
-       eventtable->setEditTriggers(QAbstractItemView::NoEditTriggers);
-       hl->addSpacing(5);
-       hl->addLayout(vl=new QVBoxLayout,0);
        QPushButton*p;
-       vl->addWidget(p=new QPushButton(tr("New Event...")),0);
-       connect(p,SIGNAL(clicked()),this,SLOT(newEvent()));
-       p->setEnabled(req->hasRole("createevent"));
-       vl->addWidget(p=new QPushButton(tr("Details...")),0);
-       connect(p,SIGNAL(clicked()),this,SLOT(editEvent()));
-       p->setEnabled(req->hasRole("geteventdata"));
-       vl->addSpacing(15);
-       vl->addWidget(p=new QPushButton(tr("Order Ticket...")),0);
-       connect(p,SIGNAL(clicked()),this,SLOT(eventOrderTicket()));
-       p->setEnabled(req->hasRole("createorder"));
-       vl->addSpacing(15);
-       vl->addWidget(p=new QPushButton(tr("Event Summary...")),0);
-       connect(p,SIGNAL(clicked()),this,SLOT(eventSummary()));
-       p->setEnabled(req->hasRole("eventsummary"));
-       vl->addSpacing(15);
-       vl->addWidget(p=new QPushButton(tr("Cancel Event...")),0);
-       p->setEnabled(req->hasRole("cancelevent"));
-       connect(p,SIGNAL(clicked()),this,SLOT(eventCancel()));
-       vl->addStretch(10);
        
        //Shopping Cart Tab
        tab->addTab(carttab=new QWidget,tr("Shopping Cart"));
@@ -339,12 +307,8 @@ MOverview::MOverview(QString pk)
        //status bar
        statusBar()->setSizeGripEnabled(true);
        
-       //make sure webrequest knows its settings
-       webSettings(false);
        //fill tables
-       if(req->hasRight(req->RGetAllEvents)){
-               updateEvents();
-       }else{
+       if(!req->hasRight(req->RGetAllEvents)){
                eventtab->setEnabled(false);
                tab->setTabEnabled(tab->indexOf(eventtab),false);
        }
@@ -375,36 +339,6 @@ MOverview::MOverview(QString pk)
        }
 }
 
-void MOverview::updateEvents()
-{
-       MTGetAllEvents gae=req->queryGetAllEvents();
-       if(gae.stage()!=gae.Success){
-               qDebug("Error getting all events (%s): %s",gae.errorType().toAscii().data(),gae.errorString().toAscii().data());
-               return;
-       }
-       QList<MOEvent>evl=gae.getevents();
-       eventmodel->clear();
-       eventmodel->insertColumns(0,6);
-       eventmodel->setHorizontalHeaderLabels(QStringList()<<tr("Start Time")<<tr("Title")<<tr("Free")<<tr("Reserved")<<tr("Sold")<<tr("Capacity"));
-       QDateTime now=QDateTime::currentDateTime();
-       for(int i=0,j=0;i<evl.size();i++){
-               QDateTime stime=QDateTime::fromTime_t(evl[i].start());
-               if(stime<now && !showoldevents->isChecked())continue;
-               eventmodel->insertRow(j);
-               eventmodel->setData(eventmodel->index(j,0),evl[i].id().value(),Qt::UserRole);
-               eventmodel->setData(eventmodel->index(j,0),stime.toString(tr("ddd MMMM d yyyy, h:mm ap","time format")));
-               eventmodel->setData(eventmodel->index(j,1),evl[i].title().value());
-               eventmodel->setData(eventmodel->index(j,2),evl[i].capacity()-evl[i].amountSold()-evl[i].amountReserved());
-               eventmodel->setData(eventmodel->index(j,3),evl[i].amountReserved().value());
-               eventmodel->setData(eventmodel->index(j,4),evl[i].amountSold().value());
-               eventmodel->setData(eventmodel->index(j,5),evl[i].capacity().value());
-               j++;
-       }
-       eventtable->resizeColumnsToContents();
-       //in case this was called from changing the check state
-       QSettings().setValue("profiles/"+profilekey+"/showOldEvents",showoldevents->isChecked());
-}
-
 void MOverview::closeEvent(QCloseEvent*ce)
 {
        //make sure session is deleted
@@ -427,60 +361,6 @@ void MOverview::relogin()
        setEnabled(true);
 }
 
-void MOverview::newEvent()
-{
-       MEventEditor ed(this);
-       ed.exec();
-       updateEvents();
-}
-
-void MOverview::editEvent()
-{
-       int id;
-       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
-       if(ilst.size()<1)return;
-       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
-       id=eventmodel->data(idx,Qt::UserRole).toInt();
-       if(id<0)return;
-       MEventEditor ed(this,id);
-       ed.exec();
-       updateEvents();
-}
-
-void MOverview::eventSummary()
-{
-       int id;
-       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
-       if(ilst.size()<1)return;
-       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
-       id=eventmodel->data(idx,Qt::UserRole).toInt();
-       if(id<0)return;
-       MEventSummary ed(this,id);
-       ed.exec();
-}
-
-void MOverview::eventCancel()
-{
-       int id;
-       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
-       if(ilst.size()<1)return;
-       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
-       id=eventmodel->data(idx,Qt::UserRole).toInt();
-       if(id<0)return;
-       MTGetEvent getev=MTGetEvent::query(id);
-       if(!getev.hasError()){
-               bool ok;
-               MOEvent ev=getev.getevent();
-               QString r=QInputDialog::getText(this,tr("Cancel Event"),tr("Please enter a reason to cancel event \"%1\" or abort:").arg(ev.title()),QLineEdit::Normal,"",&ok);
-               if(!ok)return;
-               MTCancelEvent cev=MTCancelEvent::query(id,r);
-               if(!cev.hasError())
-                       QMessageBox::information(this,tr("Event Cancelled"),tr("The event \"%1\" has been cancelled. Please inform everybody who bought a ticket.").arg(ev.title()));
-               else
-                       QMessageBox::warning(this,tr("Warning"),tr("Unable to cancel event \"%1\": %2.").arg(ev.title()).arg(cev.errorString()));
-       }
-}
-
 void MOverview::updateShipping()
 {
        cartship->clear();
@@ -834,7 +714,8 @@ void MOverview::cartAddTicket()
        QVBoxLayout*vl;
        dlg.setLayout(vl=new QVBoxLayout);
        vl->addWidget(tv=new QTableView,10);
-       tv->setModel(eventmodel);
+       QStandardItemModel*eventmodel;
+       tv->setModel(eventmodel=eventtab->eventModel());
        tv->setEditTriggers(QAbstractItemView::NoEditTriggers);
        tv->resizeColumnsToContents();
        vl->addSpacing(15);
@@ -868,11 +749,7 @@ void MOverview::cartAddTicket()
 void MOverview::eventOrderTicket()
 {
        //get selected event
-       int id;
-       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
-       if(ilst.size()<1)return;
-       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
-       id=eventmodel->data(idx,Qt::UserRole).toInt();
+       int id=eventtab->currentEventId();
        if(id<0)return;
        //activate order tab
        tab->setCurrentWidget(carttab);
@@ -882,8 +759,8 @@ void MOverview::eventOrderTicket()
        cartmodel->setData(cartmodel->index(cr,0),1);
        cartmodel->setData(cartmodel->index(cr,0),id,CART_IDROLE);
        cartmodel->setData(cartmodel->index(cr,0),CART_TICKET,CART_TYPEROLE);
-       cartmodel->setData(cartmodel->index(cr,1),eventmodel->data(eventmodel->index(ilst[0].row(),1)));
-       cartmodel->setData(cartmodel->index(cr,2),eventmodel->data(eventmodel->index(ilst[0].row(),0)));
+       cartmodel->setData(cartmodel->index(cr,1),eventtab->currentEventTitle());
+       cartmodel->setData(cartmodel->index(cr,2),eventtab->currentEventStart());
        carttable->resizeColumnsToContents();
 }
 
@@ -1426,7 +1303,7 @@ void MOverview::refreshData()
        QSettings set;
        set.beginGroup("profiles/"+profilekey);
        if(set.value("refreshEvents",false).toBool() && req->hasRole("geteventlist"))
-               updateEvents();
+               eventtab->updateEvents();
        if(set.value("refreshUsers",false).toBool() && req->hasRole("getusers"))
                updateUsers();
        if(set.value("refreshHosts",false).toBool() && req->hasRole("gethosts"))
index dfd5a43..b52c4a3 100644 (file)
@@ -34,6 +34,8 @@ class QTableView;
 
 class MSInterface;
 
+class MEventsTab;
+
 /**Main Overview Window*/
 class MOverview:public QMainWindow
 {
@@ -49,18 +51,8 @@ class MOverview:public QMainWindow
                /**try to log in again*/
                void relogin();
                
-               /**create a new event*/
-               void newEvent();
-               /**edit existing event*/
-               void editEvent();
-               /**update list of events*/
-               void updateEvents();
                /**order ticket from event tab*/
                void eventOrderTicket();
-               /**open event summary*/
-               void eventSummary();
-               /**cancel the event*/
-               void eventCancel();
                
                /**update shipping info*/
                void updateShipping();
@@ -166,16 +158,15 @@ class MOverview:public QMainWindow
                QString profilekey;
                //widgets
                QTabWidget*tab;
-               QWidget*eventtab,*carttab,*usertab,*hosttab,*ordertab,*entrancetab;
-               QTableView*eventtable,*usertable,*hosttable,*carttable,*ordertable;
-               QStandardItemModel*eventmodel,*usermodel,*hostmodel,*cartmodel,*ordermodel;
+               MEventsTab*eventtab;
+               QWidget*carttab,*usertab,*hosttab,*ordertab,*entrancetab;
+               QTableView*usertable,*hosttable,*carttable,*ordertable;
+               QStandardItemModel*usermodel,*hostmodel,*cartmodel,*ordermodel;
                QPushButton*thishostbutton;
                QLabel*cartcustomer,*entrancelabel;
                QTextEdit *cartaddr,*cartcomment;
                QComboBox*ordermode,*cartship,*entranceevent;
                QLineEdit*entrancescan;
-               //event list
-               QAction*showoldevents;
                //cart
                MCustomer customer;
                //barcode cache