From 10f9c8724ee64dd3a12d6fec8b901cc9c3c0617f Mon Sep 17 00:00:00 2001 From: konrad Date: Sat, 26 Dec 2009 15:58:53 +0000 Subject: [PATCH] refactored directory structure of sources git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@353 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33 --- src/README | 39 + src/arrowdiag.png | Bin 224 -> 0 bytes src/arrowdown.png | Bin 206 -> 0 bytes src/arrowright.png | Bin 210 -> 0 bytes src/code39.cpp | 111 --- src/code39.h | 19 - src/configdialog.cpp | 548 ------------- src/configdialog.h | 77 -- src/crypto/crypto.pri | 9 + src/crypto/hmac.cpp | 102 +++ src/crypto/hmac.h | 50 ++ src/crypto/keygen.cpp | 235 ++++++ src/crypto/keygen.h | 66 ++ src/debug.cpp | 58 -- src/debug.h | 18 - src/dialogs/configdialog.cpp | 548 +++++++++++++ src/dialogs/configdialog.h | 77 ++ src/dialogs/dialogs.pri | 15 + src/dialogs/eventedit.cpp | 207 +++++ src/dialogs/eventedit.h | 51 ++ src/dialogs/eventsummary.cpp | 382 +++++++++ src/dialogs/eventsummary.h | 69 ++ src/dialogs/moneylog.cpp | 54 ++ src/dialogs/moneylog.h | 27 + src/dialogs/orderwin.cpp | 1099 +++++++++++++++++++++++++ src/dialogs/orderwin.h | 187 +++++ src/domquery.cpp | 145 ---- src/domquery.h | 91 --- src/eventedit.cpp | 207 ----- src/eventedit.h | 51 -- src/eventsummary.cpp | 382 --------- src/eventsummary.h | 69 -- src/files.qrc | 9 - src/hmac.cpp | 102 --- src/hmac.h | 50 -- src/host.cpp | 59 -- src/host.h | 52 -- src/icon.ico | Bin 9662 -> 0 bytes src/icon.png | Bin 5093 -> 0 bytes src/icon.xcf | Bin 12716 -> 0 bytes src/iface/iface.pri | 10 + src/iface/msinterface.cpp | 191 +++++ src/iface/msinterface.h | 84 ++ src/iface/sslexception.cpp | 108 +++ src/iface/sslexception.h | 58 ++ src/images/arrowdiag.png | Bin 0 -> 224 bytes src/images/arrowdown.png | Bin 0 -> 206 bytes src/images/arrowright.png | Bin 0 -> 210 bytes src/images/files.qrc | 9 + src/images/icon.ico | Bin 0 -> 9662 bytes src/images/icon.png | Bin 0 -> 5093 bytes src/images/icon.xcf | Bin 0 -> 12716 bytes src/keygen.cpp | 235 ------ src/keygen.h | 66 -- src/labeldlg.cpp | 317 -------- src/labeldlg.h | 70 -- src/misc.cpp | 114 --- src/misc.h | 43 - src/misc/code39.cpp | 111 +++ src/misc/code39.h | 19 + src/misc/debug.cpp | 58 ++ src/misc/debug.h | 18 + src/misc/domquery.cpp | 145 ++++ src/misc/domquery.h | 91 +++ src/misc/misc.cpp | 114 +++ src/misc/misc.h | 43 + src/misc/misc.pri | 12 + src/moneylog.cpp | 54 -- src/moneylog.h | 27 - src/msinterface.cpp | 191 ----- src/msinterface.h | 84 -- src/mwin/mwin.pri | 7 + src/mwin/overview.cpp | 1753 ++++++++++++++++++++++++++++++++++++++++ src/mwin/overview.h | 235 ++++++ src/odtrender.cpp | 569 ------------- src/odtrender.h | 98 --- src/office.cpp | 175 ---- src/office.h | 47 -- src/orderwin.cpp | 1099 ------------------------- src/orderwin.h | 187 ----- src/overview.cpp | 1753 ---------------------------------------- src/overview.h | 235 ------ src/smoke.pro | 57 +-- src/sslexception.cpp | 108 --- src/sslexception.h | 58 -- src/templatedlg.cpp | 228 ------ src/templatedlg.h | 64 -- src/templates.cpp | 362 --------- src/templates.h | 143 ---- src/templates/labeldlg.cpp | 317 ++++++++ src/templates/labeldlg.h | 70 ++ src/templates/odtrender.cpp | 569 +++++++++++++ src/templates/odtrender.h | 98 +++ src/templates/office.cpp | 175 ++++ src/templates/office.h | 47 ++ src/templates/templatedlg.cpp | 228 ++++++ src/templates/templatedlg.h | 64 ++ src/templates/templates.cpp | 362 +++++++++ src/templates/templates.h | 143 ++++ src/templates/templates.pri | 17 + src/templates/ticketrender.cpp | 561 +++++++++++++ src/templates/ticketrender.h | 80 ++ src/ticketrender.cpp | 561 ------------- src/ticketrender.h | 80 -- src/user.cpp | 257 ------ src/user.h | 119 --- src/win.rc | 2 +- woc/processor.cpp | 2 +- woc/woc.pro | 6 +- 109 files changed, 9031 insertions(+), 9442 deletions(-) create mode 100644 src/README delete mode 100644 src/arrowdiag.png delete mode 100644 src/arrowdown.png delete mode 100644 src/arrowright.png delete mode 100644 src/code39.cpp delete mode 100644 src/code39.h delete mode 100644 src/configdialog.cpp delete mode 100644 src/configdialog.h create mode 100644 src/crypto/crypto.pri create mode 100644 src/crypto/hmac.cpp create mode 100644 src/crypto/hmac.h create mode 100644 src/crypto/keygen.cpp create mode 100644 src/crypto/keygen.h delete mode 100644 src/debug.cpp delete mode 100644 src/debug.h create mode 100644 src/dialogs/configdialog.cpp create mode 100644 src/dialogs/configdialog.h create mode 100644 src/dialogs/dialogs.pri create mode 100644 src/dialogs/eventedit.cpp create mode 100644 src/dialogs/eventedit.h create mode 100644 src/dialogs/eventsummary.cpp create mode 100644 src/dialogs/eventsummary.h create mode 100644 src/dialogs/moneylog.cpp create mode 100644 src/dialogs/moneylog.h create mode 100644 src/dialogs/orderwin.cpp create mode 100644 src/dialogs/orderwin.h delete mode 100644 src/domquery.cpp delete mode 100644 src/domquery.h delete mode 100644 src/eventedit.cpp delete mode 100644 src/eventedit.h delete mode 100644 src/eventsummary.cpp delete mode 100644 src/eventsummary.h delete mode 100644 src/files.qrc delete mode 100644 src/hmac.cpp delete mode 100644 src/hmac.h delete mode 100644 src/host.cpp delete mode 100644 src/host.h delete mode 100644 src/icon.ico delete mode 100644 src/icon.png delete mode 100644 src/icon.xcf create mode 100644 src/iface/iface.pri create mode 100644 src/iface/msinterface.cpp create mode 100644 src/iface/msinterface.h create mode 100644 src/iface/sslexception.cpp create mode 100644 src/iface/sslexception.h create mode 100644 src/images/arrowdiag.png create mode 100644 src/images/arrowdown.png create mode 100644 src/images/arrowright.png create mode 100644 src/images/files.qrc create mode 100644 src/images/icon.ico create mode 100644 src/images/icon.png create mode 100644 src/images/icon.xcf delete mode 100644 src/keygen.cpp delete mode 100644 src/keygen.h delete mode 100644 src/labeldlg.cpp delete mode 100644 src/labeldlg.h delete mode 100644 src/misc.cpp delete mode 100644 src/misc.h create mode 100644 src/misc/code39.cpp create mode 100644 src/misc/code39.h create mode 100644 src/misc/debug.cpp create mode 100644 src/misc/debug.h create mode 100644 src/misc/domquery.cpp create mode 100644 src/misc/domquery.h create mode 100644 src/misc/misc.cpp create mode 100644 src/misc/misc.h create mode 100644 src/misc/misc.pri delete mode 100644 src/moneylog.cpp delete mode 100644 src/moneylog.h delete mode 100644 src/msinterface.cpp delete mode 100644 src/msinterface.h create mode 100644 src/mwin/mwin.pri create mode 100644 src/mwin/overview.cpp create mode 100644 src/mwin/overview.h delete mode 100644 src/odtrender.cpp delete mode 100644 src/odtrender.h delete mode 100644 src/office.cpp delete mode 100644 src/office.h delete mode 100644 src/orderwin.cpp delete mode 100644 src/orderwin.h delete mode 100644 src/overview.cpp delete mode 100644 src/overview.h delete mode 100644 src/sslexception.cpp delete mode 100644 src/sslexception.h delete mode 100644 src/templatedlg.cpp delete mode 100644 src/templatedlg.h delete mode 100644 src/templates.cpp delete mode 100644 src/templates.h create mode 100644 src/templates/labeldlg.cpp create mode 100644 src/templates/labeldlg.h create mode 100644 src/templates/odtrender.cpp create mode 100644 src/templates/odtrender.h create mode 100644 src/templates/office.cpp create mode 100644 src/templates/office.h create mode 100644 src/templates/templatedlg.cpp create mode 100644 src/templates/templatedlg.h create mode 100644 src/templates/templates.cpp create mode 100644 src/templates/templates.h create mode 100644 src/templates/templates.pri create mode 100644 src/templates/ticketrender.cpp create mode 100644 src/templates/ticketrender.h delete mode 100644 src/ticketrender.cpp delete mode 100644 src/ticketrender.h delete mode 100644 src/user.cpp delete mode 100644 src/user.h diff --git a/src/README b/src/README new file mode 100644 index 0000000..473d435 --- /dev/null +++ b/src/README @@ -0,0 +1,39 @@ +README for src Directory +========================= + +The following (sub-)directories exist: + +. + main build directory, contains main widget and some global classes + +wbase + Web object base classes. + +wob + generated web objects - auto created by woc from ../wob/magicsmoke.wolf + +iface + MagicSmoke web interface classes (derived from wbase/*) + +widgets + some simple helper widgets + +templates + template handling and renderers + printing + +misc + miscellaneous helper functions and classes + (eg. code-39 barcodes, crash-handling, xml escaping) + +images + image files, icons + +crypto + cryptographic functions and helpers (key generator) + +dialogs + dialogs for sub-tasks, like displaying events/orders/etc.pp. + +mwin + main overview window and its sub-widgets (tabs) diff --git a/src/arrowdiag.png b/src/arrowdiag.png deleted file mode 100644 index 8844a7f1a4781d28a1897eef2908d762a221901e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;TYyi9>;M1%fy~fDm+OEOV@Z%- zFoVOh8)+a;lDE4HLkFv@2av;A;1OBOz`!jG!i)^F=12eq*-JcqUDxPv<(Ka|uf7B*ZQ|+T7{YNqIiVmS!Q#My9}SH^ z8JT}Gv;E`e`6Ms##@^t{|AZg^n-BhDXZ|hE#-=bSk%5^ZdLQq~nF;$21NAd_y85}S Ib4q9e06Vxpp#T5? diff --git a/src/arrowdown.png b/src/arrowdown.png deleted file mode 100644 index 683c465cea3449012360934c3b8cb835f206c424..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;TYyi9>;M1%fy~fDm+OEOV@Z%- zFoVOh8)+a;lDE4HLkFv@2av;A;1OBOz`!jG!i)^F=12eq*-JcqUDQ2Tq8=H^K)}k^GXLfS6>2@R`PUl4B@z*oZ!Ip&0gY(eS^S% oW`QJo2B$N;3P(;bIPvf>?CxSel@RdwFHkjur>mdKI;Vst09HISvH$=8 diff --git a/src/arrowright.png b/src/arrowright.png deleted file mode 100644 index 8a62bf75f78dd52d84586f9f1d1e8db84f275c70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;TYyi9>;M1%fy~fDm+OEOV@Z%- zFoVOh8)+a;lDE4HLkFv@2av;A;1OBOz`!jG!i)^F=12eq*-JcqUDxPv<(Ka|uf7B*t>)?C7{YNqIiZ1(kB!ZajqM*0 qvGe?~m-z9&@g%!~pxp)?pvhhBY%Z^IR!j%#VDNPHb6Mw<&;$SvaWxYF diff --git a/src/code39.cpp b/src/code39.cpp deleted file mode 100644 index 8d151a9..0000000 --- a/src/code39.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// -// C++ Implementation: code39 -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2007 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "code39.h" - -#include -#include - -//order of characters for checksum calculation and list of allowed chars -static const QString c39mod="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%"; - -//init pixel map -static QMap initmap() -{ - QMapmap; - // 0=black 1=white pixel - map.insert('*',"0111010001000101"); - map.insert('-',"0111010100010001"); - map.insert('$',"0111011101110101"); - map.insert('%',"0101110111011101"); - map.insert(' ',"0111000101000101"); - map.insert('.',"0001110101000101"); - map.insert('/',"0111011101011101"); - map.insert('+',"0111010111011101"); - map.insert('0',"0101110001000101"); - map.insert('1',"0001011101010001"); - map.insert('2',"0100011101010001"); - map.insert('3',"0001000111010101"); - map.insert('4',"0101110001010001"); - map.insert('5',"0001011100010101"); - map.insert('6',"0100011100010101"); - map.insert('7',"0101110100010001"); - map.insert('8',"0001011101000101"); - map.insert('9',"0100011101000101"); - map.insert('A',"0001010111010001"); - map.insert('B',"0100010111010001"); - map.insert('C',"0001000101110101"); - map.insert('D',"0101000111010001"); - map.insert('E',"0001010001110101"); - map.insert('F',"0100010001110101"); - map.insert('G',"0101011100010001"); - map.insert('H',"0001010111000101"); - map.insert('I',"0100010111000101"); - map.insert('J',"0101000111000101"); - map.insert('K',"0001010101110001"); - map.insert('L',"0100010101110001"); - map.insert('M',"0001000101011101"); - map.insert('N',"0101000101110001"); - map.insert('O',"0001010001011101"); - map.insert('P',"0100010001011101"); - map.insert('Q',"0101010001110001"); - map.insert('R',"0001010100011101"); - map.insert('S',"0100010100011101"); - map.insert('T',"0101000100011101"); - map.insert('U',"0001110101010001"); - map.insert('V',"0111000101010001"); - map.insert('W',"0001110001010101"); - map.insert('X',"0111010001010001"); - map.insert('Y',"0001110100010101"); - map.insert('Z',"0111000100010101"); - return map; -} -//map characters on pixel codes -static const QMapc39map=initmap(); - -//calculate checksum -static char code39mod(QString str) -{ - int sum=0; - for(int i=0;i %c",str.toAscii().data(),code39mod(str)); - //define xpm - char *xpm[4]; - QByteArray xpmsz=QString().sprintf("%i 1 2 1",rstr.size()).toAscii(); - xpm[0]=xpmsz.data(); - xpm[1]="0\tg #000000"; - xpm[2]="1\tg #FFFFFF"; - QByteArray xpmc=rstr.toAscii(); - xpm[3]=xpmc.data(); - //create pixmap - return QImage(xpm); -} diff --git a/src/code39.h b/src/code39.h deleted file mode 100644 index 549a738..0000000 --- a/src/code39.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// C++ Interface: code39 -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2007 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include -#include - -/**Takes a string and converts it into a code-39 bar code. -Code-39 allows letters (case-insensitive), digits, spaces and the special chars "-.$/+%". -The bar code pixmap will be 1 pixel high and 16 pixels wide for each character (plus start/stop character and checksum character) - it needs to be scaled up to fit the intended size.*/ -QImage code39(QString); diff --git a/src/configdialog.cpp b/src/configdialog.cpp deleted file mode 100644 index 4dc2116..0000000 --- a/src/configdialog.cpp +++ /dev/null @@ -1,548 +0,0 @@ -// -// C++ Implementation: mainwindow -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2007 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "keygen.h" -#include "main.h" -#include "configdialog.h" -#include "office.h" -#include "listview.h" -#include "sslexception.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MConfigDialog::MConfigDialog() -{ - setWindowTitle(tr("Magic Smoke Configuration")); - - oldrow=-1; - sslexcept=0; - //main layout - QHBoxLayout*hl; - QVBoxLayout*vl; - setLayout(hl=new QHBoxLayout); - //create Menu Bar - QMenuBar*mb; - hl->setMenuBar(mb=new QMenuBar); - QMenu*m=mb->addMenu(tr("&Profile")); - m->addAction(tr("&New Profile..."),this,SLOT(newProfile())); - m->addAction(tr("&Delete Profile"),this,SLOT(deleteProfile())); - m->addAction(tr("&Rename Profile"),this,SLOT(renameProfile())); - m->addAction(tr("C&lone Profile"),this,SLOT(cloneProfile())); - m->addAction(tr("&Make Default Profile"),this,SLOT(defaultProfile())); - m->addSeparator(); - m->addAction(tr("&Export Host Key..."),this,SLOT(exportKey())); - m->addAction(tr("&Import Host Key..."),this,SLOT(importKey())); - m->addAction(tr("&Generate Host Key..."),this,SLOT(generateKey())); - m->addSeparator(); - m->addAction(tr("&Close Window"),this,SLOT(close())); - m=mb->addMenu(tr("&Settings")); - m->addAction(tr("&Language..."),this,SLOT(changeLang())); - m->addAction(tr("&OpenOffice.org Settings..."),this,SLOT(openOfficeCfg())); - m->addAction(tr("Set &Default Label Font..."),this,SLOT(setDefaultFont())); - mb->addMenu(MApplication::helpMenu()); - - //create list view - hl->addWidget(profiles=new MListView); - profilemodel=new QStandardItemModel(this); - profiles->setModel(profilemodel); - profiles->setEditTriggers(QListView::NoEditTriggers); - connect(profiles,SIGNAL(clicked(const QModelIndex&)),this,SLOT(loadProfile())); - connect(profiles,SIGNAL(activated(const QModelIndex&)),this,SLOT(loadProfile())); - //create tabs - QTabWidget*tab; - QWidget*w; - hl->addWidget(tab=new QTabWidget,10); - tab->addTab(w=new QWidget,tr("Connection")); - QGridLayout*gl; - w->setLayout(gl=new QGridLayout); - QLabel*lab; - int lctr=0; - gl->addWidget(lab=new QLabel(tr("Server URL:")),++lctr,0); - lab->setAlignment(Qt::AlignRight); - gl->addLayout(hl=new QHBoxLayout,lctr,1); - hl->addWidget(new QLabel("https://"),0); - hl->addWidget(serverurl=new QLineEdit,1); - gl->addWidget(useproxy=new QCheckBox(tr("Proxy:")),++lctr,0); - gl->addLayout(hl=new QHBoxLayout,lctr,1); - hl->addWidget(proxyname=new QLineEdit,1); - hl->addWidget(new QLabel(":"),0); - hl->addWidget(proxyport=new QSpinBox,0); - proxyport->setRange(1,65535); - connect(useproxy,SIGNAL(toggled(bool)),proxyname,SLOT(setEnabled(bool))); - connect(useproxy,SIGNAL(toggled(bool)),proxyport,SLOT(setEnabled(bool))); - gl->addWidget(lab=new QLabel(tr("Proxy Username:")),++lctr,0); - lab->setAlignment(Qt::AlignRight); - gl->addWidget(proxyuser=new QLineEdit,lctr,1); - gl->addWidget(lab=new QLabel(tr("Proxy Password:")),++lctr,0); - lab->setAlignment(Qt::AlignRight); - gl->addWidget(proxypass=new QLineEdit,lctr,1); - proxypass->setEchoMode(QLineEdit::Password); - connect(useproxy,SIGNAL(toggled(bool)),proxyuser,SLOT(setEnabled(bool))); - connect(useproxy,SIGNAL(toggled(bool)),proxypass,SLOT(setEnabled(bool))); - - tab->addTab(w=new QWidget,tr("Authentication")); - w->setLayout(gl=new QGridLayout); - lctr=0; - gl->addWidget(lab=new QLabel(tr("Hostname:")),++lctr,0); - lab->setAlignment(Qt::AlignRight); - gl->addWidget(hostname=new QLineEdit,lctr,1); - gl->addWidget(lab=new QLabel(tr("Hostkey:")),++lctr,0); - lab->setAlignment(Qt::AlignRight); - gl->addWidget(hostkey=new QLineEdit,lctr,1); - gl->addWidget(lab=new QLabel(tr("Default Username:")),++lctr,0); - lab->setAlignment(Qt::AlignRight); - gl->addWidget(username=new QLineEdit,lctr,1); - gl->setRowStretch(++lctr,10); - gl->addLayout(hl=new QHBoxLayout,++lctr,0,1,2); - - tab->addTab(w=new QWidget,tr("SSL Exceptions")); - w->setLayout(vl=new QVBoxLayout); - vl->addWidget(new QLabel(tr("List of non-fatal SSL exceptions:")),0); - vl->addWidget(ssltable=new QTableView,10); - ssltable->setModel(sslmodel=new QStandardItemModel(this)); - ssltable->setEditTriggers(QListView::NoEditTriggers); - vl->addSpacing(10); - vl->addLayout(hl=new QHBoxLayout,0); - hl->addStretch(10); - QPushButton*pb; - hl->addWidget(pb=new QPushButton(tr("Clear"))); - connect(pb,SIGNAL(clicked()),this,SLOT(clearSslExceptions())); - hl->addWidget(pb=new QPushButton(tr("Probe Server"))); - connect(pb,SIGNAL(clicked()),this,SLOT(serverProbe())); - - initProfiles(); - loadProfile(); -} - -MConfigDialog::~MConfigDialog() -{ - saveProfile(); -} - -void MConfigDialog::initProfiles(QString selIdx) -{ - oldrow=-1; - QSettings set; - int defpro=set.value("defaultprofile",0).toInt(); - set.beginGroup("profiles"); - QStringList prf=set.childGroups(); - profilemodel->clear(); - if(profilemodel->columnCount()<1) - profilemodel->insertColumn(0); - profilemodel->insertRows(0,prf.size()); - int newrow=0; - for(int i=0;iindex(i,0); - profilemodel->setData(idx,set.value(prf[i]+"/name").toString()); - profilemodel->setData(idx,prf[i],Qt::UserRole); - if(i==defpro){ - QFont f=profiles->font(); - f.setBold(true); - profilemodel->setData(idx,f,Qt::FontRole); - } - if(prf[i]==selIdx)newrow=i; - } - profiles->setCurrentIndex(profilemodel->index(newrow,0)); -} - -void MConfigDialog::loadProfile() -{ - //save old - saveProfile(); - if(sslexcept)delete sslexcept; - sslexcept=0; - //get new - QModelIndex idx=profiles->currentIndex(); - if(!idx.isValid())return; - oldrow=idx.row(); - QString key=profilemodel->data(idx,Qt::UserRole).toString(); - QSettings set; - set.beginGroup("profiles/"+key); - hostname->setText(set.value("hostname").toString()); - hostkey->setText(set.value("hostkey").toString()); - serverurl->setText(set.value("serverurl","my.host.com/path/machine.php").toString()); - useproxy->setChecked(set.value("useproxy",false).toBool()); - proxyname->setText(set.value("proxyname","proxy").toString()); - proxyport->setValue(set.value("proxyport",74).toInt()); - proxyuser->setText(set.value("proxyuser").toString()); - proxypass->setText(set.value("proxypass").toString()); - proxyname->setEnabled(useproxy->isChecked()); - proxyport->setEnabled(useproxy->isChecked()); - proxyuser->setEnabled(useproxy->isChecked()); - proxypass->setEnabled(useproxy->isChecked()); - username->setText(set.value("username").toString()); - sslexcept=new MSslExceptions(::dataDir+"/profile."+key+"/sslexceptions.xml"); - sslFillModel(); -} - -void MConfigDialog::saveProfile() -{ - if(oldrow<0 || oldrow>=profilemodel->rowCount())return; - QString key=profilemodel->data(profilemodel->index(oldrow,0),Qt::UserRole).toString(); - QSettings set; - set.beginGroup("profiles/"+key); - set.setValue("hostname",hostname->text()); - set.setValue("hostkey",hostkey->text()); - set.setValue("serverurl",serverurl->text()); - set.setValue("useproxy",useproxy->isChecked()); - set.setValue("proxyname",proxyname->text()); - set.setValue("proxyport",proxyport->value()); - set.setValue("proxyuser",proxyuser->text()); - set.setValue("proxypass",proxypass->text()); - set.setValue("username",username->text()); - if(sslexcept)sslexcept->savesslexcept(); -} - -void MConfigDialog::newProfile() -{ - saveProfile(); - //scan for existing ones... - QSettings set; - set.beginGroup("profiles"); - QStringList prf=set.childGroups(); - QStringList prn; - for(int i=0;icurrentIndex(); - if(!idx.isValid())return; - QString key=profilemodel->data(idx,Qt::UserRole).toString(); - QSettings set; - set.beginGroup("profiles"); - set.remove(key); - set.sync(); - oldrow=-1; - initProfiles(); - loadProfile(); -} - -void MConfigDialog::renameProfile() -{ - //get old name - QModelIndex idx=profiles->currentIndex(); - if(!idx.isValid())return; - QString key=profilemodel->data(idx,Qt::UserRole).toString(); - QString pname=profilemodel->data(idx).toString(); - //query - bool ok; - QString npname=QInputDialog::getText(this,tr("Rename Profile"),tr("Please enter a profile name. It must be non-empty and must not be used yet:"),QLineEdit::Normal,pname,&ok); - if(!ok)return; - //check - if(npname==pname)return; - for(int i=0;irowCount();i++){ - QString pn=profilemodel->data(profilemodel->index(i,0)).toString(); - if(pn==npname){ - QMessageBox::warning(this,tr("Warning"),tr("This profile name is already in use.")); - return; - } - } - //set - QSettings().setValue("profiles/"+key+"/name",npname); - profilemodel->setData(idx,npname); -} - -void MConfigDialog::cloneProfile() -{ - saveProfile(); - //get current - QModelIndex idx=profiles->currentIndex(); - if(!idx.isValid())return; - QString key=profilemodel->data(idx,Qt::UserRole).toString(); - //scan for existing ones... - QSettings set; - set.beginGroup("profiles"); - QStringList prf=set.childGroups(); - QStringList prn; - for(int i=0;icurrentIndex(); - if(!idx.isValid())return; - QString key=profilemodel->data(idx,Qt::UserRole).toString(); - QSettings().setValue("defaultprofile",key); - initProfiles(key); - loadProfile(); -} - - -void MConfigDialog::changeLang() -{ - choseLanguage(); -} - -void MConfigDialog::exportKey() -{ - QSettings st; - QModelIndex idx=profiles->currentIndex(); - if(!idx.isValid())return; - QString pkey=profilemodel->data(idx,Qt::UserRole).toString(); - st.beginGroup("profiles/"+pkey); - QString host=st.value("hostname").toString().trimmed(); - QString key=st.value("hostkey").toString().trimmed(); - saveKey(host,key); -} - -void MConfigDialog::generateKey() -{ - //ask nicely - if(hostkey->text()!="") - if(QMessageBox::question(this,tr("Generate Hostkey"), tr("Do you really want to generate a new host key for this profile? This may disable all accounts from this host."), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) - return; - //actually create new key - QString name; - MKeyGen mkg(this); - QString k=mkg.getKey(); - if(k=="") - if(mkg.exec()!=QDialog::Accepted) - return; - hostkey->setText(mkg.getKey()); -} - -void MConfigDialog::saveKey(QString host,QString key) -{ - 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"+host+"\n"+key+"\n"+chk; - fd.write(out.toAscii()); - fd.close(); -} - -void MConfigDialog::importKey() -{ - QModelIndex idx=profiles->currentIndex(); - if(!idx.isValid())return; - QString profkey=profilemodel->data(idx,Qt::UserRole).toString(); - - if(QMessageBox::warning(this,tr("Warning"),tr("Importing a key overwrites the host key that is currently used by this profile. This may disable your accounts. Do you still want to continue?"),QMessageBox::Yes|QMessageBox::Abort,QMessageBox::Abort)!=QMessageBox::Yes) - return; - 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 - QSettings set; - set.beginGroup("profiles/"+profkey); - set.setValue("hostkey",key); - set.setValue("hostname",hname); -} - -void MConfigDialog::openOfficeCfg() -{ - MOfficeConfig c(this); - c.exec(); -} - -void MConfigDialog::setDefaultFont() -{ - QStringList fonts=QFontDatabase().families(); - QString df=QInputDialog::getItem(this,tr("Chose Default Font"),tr("Please chose a default font:"),fonts,fonts.indexOf(QSettings().value("defaultfont","").toString()),false); - if(df.isEmpty())return; - QSettings().setValue("defaultfont",df); -} - -void MConfigDialog::serverProbe() -{ - //sanity check - if(!sslexcept)return; - sslexcept->clearRecorded(); - //set up mini-environment - QEventLoop loop; - QNetworkAccessManager man; - connect(&man,SIGNAL(finished(QNetworkReply*)),&loop,SLOT(quit())); - QTimer::singleShot(30000,&loop,SLOT(quit())); - connect(&man,SIGNAL(sslErrors(QNetworkReply*,const QList&)), this,SLOT(sslErrors(QNetworkReply*,const QList&))); - if(useproxy->isChecked()) - man.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy,proxyname->text(),proxyport->value(),proxyuser->text(),proxypass->text())); - //query server - QNetworkRequest rq(QUrl("https://"+serverurl->text())); - QNetworkReply *rp=man.get(rq); - //wait for result - setEnabled(false); - loop.exec(); - setEnabled(true); - //probe result - if(rp->error()==QNetworkReply::NoError){ - QMessageBox::information(this,tr("Server Probe"),tr("The request finished without errors.")); - }else{ - QMessageBox::warning(this,tr("Server Probe"),tr("The request finished with an error: %1").arg(rp->errorString())); - } - delete rp; -} - -void MConfigDialog::sslErrors(QNetworkReply*rp,const QList&errs) -{ - if(!sslexcept)return; - //check/record/clear - if(sslexcept->checksslexcept(errs))rp->ignoreSslErrors(); - //convert to string - QString err=tr("SSL Errors encountered:\n"); - for(int i=0;iignoreSslErrors(); - sslexcept->acceptRecorded(); - } - sslFillModel(); -} - -void MConfigDialog::clearSslExceptions() -{ - if(sslexcept)sslexcept->clear(); - sslmodel->clear(); -} - -void MConfigDialog::sslFillModel() -{ - sslmodel->clear(); - if(!sslexcept)return; - sslmodel->insertColumns(0,3); - sslmodel->setHorizontalHeaderLabels(QStringList()< >lst=sslexcept->nonFatalExceptions(); - sslmodel->insertRows(0,lst.size()); - for(int i=0;isetData(sslmodel->index(i,0),lst[i].first.subjectInfo(QSslCertificate::CommonName)); - sslmodel->setData(sslmodel->index(i,1),QString::fromAscii(lst[i].first.digest(QCryptographicHash::Sha1).toHex())); - sslmodel->setData(sslmodel->index(i,2),QSslError((QSslError::SslError)lst[i].second).errorString()); - } -} diff --git a/src/configdialog.h b/src/configdialog.h deleted file mode 100644 index 279653a..0000000 --- a/src/configdialog.h +++ /dev/null @@ -1,77 +0,0 @@ -// -// C++ Interface: mainwindow -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2007 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_CONFIGDIALOG_H -#define MAGICSMOKE_CONFIGDIALOG_H - -#include -#include -#include - -class QCheckBox; -class QLineEdit; -class QListView; -class QNetworkReply; -class QSpinBox; -class QStandardItemModel; -class QTableView; - -class MSslExceptions; - -/**login and profile configuration window*/ -class MConfigDialog:public QDialog -{ - Q_OBJECT - public: - MConfigDialog(); - ~MConfigDialog(); - - private: - QCheckBox*useproxy; - QLineEdit*hostname,*hostkey,*serverurl,*proxyname,*username,*proxyuser,*proxypass; - QSpinBox*proxyport; - QListView*profiles; - QStandardItemModel*profilemodel,*sslmodel; - QTableView*ssltable; - - MSslExceptions*sslexcept; - - int oldrow; - - //helper for exportKey and generateKey - void saveKey(QString hostname,QString hostkey); - - private slots: - //handling of login/profile screen - void initProfiles(QString idx=QString()); - void loadProfile(); - void saveProfile(); - void newProfile(); - void deleteProfile(); - void renameProfile(); - void cloneProfile(); - void defaultProfile(); - //settings - void changeLang(); - void exportKey(); - void importKey(); - void generateKey(); - void openOfficeCfg(); - void setDefaultFont(); - //ssl server probe - void serverProbe(); - void sslErrors(QNetworkReply*,const QList&); - void clearSslExceptions(); - void sslFillModel(); -}; - -#endif diff --git a/src/crypto/crypto.pri b/src/crypto/crypto.pri new file mode 100644 index 0000000..2958656 --- /dev/null +++ b/src/crypto/crypto.pri @@ -0,0 +1,9 @@ +HEADERS += \ + crypto/keygen.h \ + crypto/hmac.h + +SOURCES += \ + crypto/keygen.cpp \ + crypto/hmac.cpp + +INCLUDEPATH += ./crypto \ No newline at end of file diff --git a/src/crypto/hmac.cpp b/src/crypto/hmac.cpp new file mode 100644 index 0000000..d6b8138 --- /dev/null +++ b/src/crypto/hmac.cpp @@ -0,0 +1,102 @@ +// +// C++ Implementation: hmac +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2007 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "hmac.h" +#include + +SMHmac::SMHmac(QCryptographicHash::Algorithm algo,const QByteArray&key) + :subhashin(algo),subhashout(algo),state(Collecting) +{ + //calculate key schedules + QByteArray k2=key; + int hlen=blockWidth(algo); + if(k2.size()>hlen){ + //hash the key if it is too long + k2=QCryptographicHash::hash(k2,algo); + }else + if(k2.size(), (C) 2007 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef SMOKE_HMAC_H +#define SMOKE_HMAC_H + +#include + +/**Calculate a cryptographic HMAC (used by authentication algorithm)*/ +class SMHmac +{ + public: + /**constructs an object that calculates HMACs*/ + SMHmac(QCryptographicHash::Algorithm algo,const QByteArray&key); + /**adds length bytes of data to the hash-stream*/ + void addData(const char * data, int length ); + /**adds data to the hash-stream*/ + void addData(const QByteArray & data ); + /**reset the hash to the state immediately after construction*/ + void reset(); + /**finalize the hash and return the result*/ + QByteArray result(); + + /**returns the length of the results of given algorithm in bytes; this should have been implemented by QCryptographicHash! performs a test calculation if the algo is unknown*/ + static int resultWidth(QCryptographicHash::Algorithm); + /**returns the length of the blocks used internally in the given algorithm in bytes; this should have been implemented by QCryptographicHash! returns -1 if in doubt*/ + static int blockWidth(QCryptographicHash::Algorithm); + /**complete HMAC calculation in a can*/ + static QByteArray hmac(const QByteArray&data,const QByteArray&key,QCryptographicHash::Algorithm method); + private: + //the two key schedules + QByteArray keyA,keyB; + //remember where we are + enum State {Collecting,Finished}; + mutable State state; + //inner hash function + QCryptographicHash subhashin,subhashout; +}; + + +#endif diff --git a/src/crypto/keygen.cpp b/src/crypto/keygen.cpp new file mode 100644 index 0000000..5158db0 --- /dev/null +++ b/src/crypto/keygen.cpp @@ -0,0 +1,235 @@ +// +// C++ Implementation: keygen +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2007 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "keygen.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hmac.h" + +//enable linux to read /dev/random +#ifdef __linux__ +#include +#include +#endif + +//amount of random bits needed: +#define RANDNEED 160 + +static QPointerefilter; + +MKeyGen::MKeyGen(QWidget*parentw) + :QDialog(parentw) +{ + setWindowTitle(tr("Magic Smoke Key Generator")); + + //pre-init random buffer + randstat=-1; + connect(efilter,SIGNAL(moreBits()),this,SLOT(updateProps())); + //make sure all mouse events arrive + setMouseTracking(true); + QVBoxLayout*vl; + setLayout(vl=new QVBoxLayout); + QLabel*lab; + //main explanation + vl->addWidget(lab=new QLabel(tr("

Key Generation

\nI am currently collecting random bits in order to generate a host key for this installation. Please use mouse and keyboard to generate more random. Alternatively you can load a key from an external medium.

\nAt least %1 Bits of random are required.").arg(RANDNEED)),0); + lab->setWordWrap(true); + lab->setMouseTracking(true); + //buffer display + int e=efilter->entropy(); + vl->addWidget(randlab=new QLabel(tr("Current random buffer: %n Bits","",e)),0); + randlab->setMouseTracking(true); + randlab->setFrameShape(QFrame::Box); + randlab->setAutoFillBackground(true); + + vl->addStretch(1); + + //buttons + QHBoxLayout*hl; + vl->addLayout(hl=new QHBoxLayout,0); + hl->addStretch(1); + hl->addWidget(okbtn=new QPushButton(tr("&OK")),0); + connect(okbtn,SIGNAL(clicked()),this,SLOT(accept())); + hl->addWidget(ccbtn=new QPushButton(tr("&Cancel")),0); + connect(ccbtn,SIGNAL(clicked()),this,SLOT(reject())); + + //make sure widgets look right + updateProps(); + + //make window really big + showMaximized(); +} + +MKeyGen::~MKeyGen() +{ +} + +void MKeyGen::updateProps() +{ + int e=efilter->entropy(); + randlab->setText(tr("Current random buffer: %n Bits","",e)); + if(efilter->entropy()palette(); + pal.setColor(QPalette::Window,QColor("#ff8080")); + randlab->setPalette(pal); + //set button + okbtn->setEnabled(false); + }else{ + //check whether we need to set it + if(randstat==1)return; + randstat=1; + //set label color + QPalette pal=randlab->palette(); + pal.setColor(QPalette::Window,QColor("#80ff80")); + randlab->setPalette(pal); + //set button + okbtn->setEnabled(true); + } +} + +QString MKeyGen::getKey() +{ + if(efilter->entropy()getRandom(40).toHex(); +} + + +EFilter::EFilter() +{ + efilter=this; + randctr=0; + //preload seed + QSettings set; + randbuf.append(set.value("randomseed").toByteArray()); + randent=randbuf.size(); + if(randent>=RANDNEED)set.setValue("randomseed",getRandom(RANDNEED)); + //if Linux: try to pre-load some random +#ifdef __linux__ + int fd=::open("/dev/random",O_RDONLY|O_NONBLOCK); + if(fd>=0){ + char buf[RANDNEED/8]; + int rd=::read(fd,buf,sizeof(buf)); + if(rd>0){ + randbuf.append(QByteArray(buf,rd)); + randent+=rd*8; + } + ::close(fd); + } +#endif +} + +EFilter::~EFilter() +{ + QSettings set; + set.setValue("randomseed",getRandom(RANDNEED)); +} + +EFilter* EFilter::instance() +{ + return efilter; +} + +QByteArray EFilter::getRandom(int bytes) +{ + QByteArray ret; + while(ret.size()type()){ + case QEvent::KeyPress:case QEvent::KeyRelease: + { + QKeyEvent*ke=(QKeyEvent*)e; + addBit(ke->key()+(int)ke->modifiers()); + break; + } + case QEvent::MouseButtonPress:case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + { + QMouseEvent*me=(QMouseEvent*)e; + addBit((int)me->buttons()+me->x()+me->y()); + break; + } + default: + //ignore + break; + } + return false; +} + +void EFilter::addBit(int b) +{ + //add bit to buffer + randbuf.append((b>>24)&0xff); + randbuf.append((b>>16)&0xff); + randbuf.append((b>>8)&0xff); + randbuf.append(b&0xff); + randent++; + //add time info as another bit + QTime ct=QTime::currentTime(); + if(ct.msec()!=0){ //don't use it if platform has no msecs + int t=ct.msec()+ct.second()+ct.minute(); + randbuf.append((t>>24)&0xff); + randbuf.append((t>>16)&0xff); + randbuf.append((t>>8)&0xff); + randbuf.append(t&0xff); + randent++; + } + //pack buffer if necessary (>10kB) + if(randbuf.size()>=10240){ + randbuf=getRandom(80); + if(randent>320)randent=320; + } + //update display + emit moreBits(); +} + +QByteArray getRandom(int num) +{ + if(efilter.isNull())return QByteArray(); + return efilter->getRandom(num); +} + +int getEntropy() +{ + if(efilter.isNull())return 0; + return efilter->entropy(); +} diff --git a/src/crypto/keygen.h b/src/crypto/keygen.h new file mode 100644 index 0000000..f8d05fa --- /dev/null +++ b/src/crypto/keygen.h @@ -0,0 +1,66 @@ +// +// C++ Interface: keygen +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2007 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_KEYGEN_H +#define MAGICSMOKE_KEYGEN_H + +#include +#include + +class QLabel; +class QPushButton; + +class MKeyGen:public QDialog +{ + Q_OBJECT + public: + MKeyGen(QWidget*parent=0); + ~MKeyGen(); + + QString getKey(); + + private: + QLabel*randlab; + int randstat; + + QPushButton *okbtn,*ccbtn; + + private slots: + void updateProps(); +}; + +class EFilter:public QObject +{ + Q_OBJECT + public: + EFilter(); + ~EFilter(); + + static EFilter*instance(); + + int entropy(); + QByteArray getRandom(int); + signals: + void moreBits(); + protected: + bool eventFilter(QObject*,QEvent*); + private: + QByteArray randbuf,randlast; + int randent,randctr; + void addBit(int); +}; + +//shortcut: +QByteArray getRandom(int); +int getEntropy(); + +#endif diff --git a/src/debug.cpp b/src/debug.cpp deleted file mode 100644 index bb52125..0000000 --- a/src/debug.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// -// C++ Implementation: debug -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "debug.h" -#include "main.h" - -#include -#include -#include -#include - -static QFile*mylogFile=0; - -static void mymsghandler(QtMsgType, const char *msg) -{ - if(mylogFile){ - mylogFile->write(msg,strlen(msg)); - mylogFile->write("\n",1); - mylogFile->flush(); - } -#ifdef Q_OS_UNIX - fprintf(stderr,"%s\n",msg); -#endif -} - -void initDebug() -{ - //create new log file - QDir(dataDir).mkpath("debuglog"); - mylogFile=new QFile(dataDir+"/debuglog/log-"+QDateTime::currentDateTime().toString("yyyy-MM-dd_hh.mm.ss.zzz")+".txt"); - //...open it - if(mylogFile->open(QIODevice::WriteOnly|QIODevice::Append|QIODevice::Text)){ - //install as default log - qInstallMsgHandler(mymsghandler); - }else{ - //hmm, failed to open, well hope that stderr is working... - delete mylogFile; - mylogFile=0; - qDebug("Failed to install debuglog."); - } - //delete old logs (older than 30 days) - QStringList fll=QDir(dataDir+"/debuglog").entryList(QDir::Files); - QDateTime old=QDateTime::currentDateTime().addDays(-30); - for(int i=0;i, (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_DEBUG_H -#define MAGICSMOKE_DEBUG_H - -void initDebug(); - -#endif diff --git a/src/dialogs/configdialog.cpp b/src/dialogs/configdialog.cpp new file mode 100644 index 0000000..4dc2116 --- /dev/null +++ b/src/dialogs/configdialog.cpp @@ -0,0 +1,548 @@ +// +// C++ Implementation: mainwindow +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2007 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "keygen.h" +#include "main.h" +#include "configdialog.h" +#include "office.h" +#include "listview.h" +#include "sslexception.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MConfigDialog::MConfigDialog() +{ + setWindowTitle(tr("Magic Smoke Configuration")); + + oldrow=-1; + sslexcept=0; + //main layout + QHBoxLayout*hl; + QVBoxLayout*vl; + setLayout(hl=new QHBoxLayout); + //create Menu Bar + QMenuBar*mb; + hl->setMenuBar(mb=new QMenuBar); + QMenu*m=mb->addMenu(tr("&Profile")); + m->addAction(tr("&New Profile..."),this,SLOT(newProfile())); + m->addAction(tr("&Delete Profile"),this,SLOT(deleteProfile())); + m->addAction(tr("&Rename Profile"),this,SLOT(renameProfile())); + m->addAction(tr("C&lone Profile"),this,SLOT(cloneProfile())); + m->addAction(tr("&Make Default Profile"),this,SLOT(defaultProfile())); + m->addSeparator(); + m->addAction(tr("&Export Host Key..."),this,SLOT(exportKey())); + m->addAction(tr("&Import Host Key..."),this,SLOT(importKey())); + m->addAction(tr("&Generate Host Key..."),this,SLOT(generateKey())); + m->addSeparator(); + m->addAction(tr("&Close Window"),this,SLOT(close())); + m=mb->addMenu(tr("&Settings")); + m->addAction(tr("&Language..."),this,SLOT(changeLang())); + m->addAction(tr("&OpenOffice.org Settings..."),this,SLOT(openOfficeCfg())); + m->addAction(tr("Set &Default Label Font..."),this,SLOT(setDefaultFont())); + mb->addMenu(MApplication::helpMenu()); + + //create list view + hl->addWidget(profiles=new MListView); + profilemodel=new QStandardItemModel(this); + profiles->setModel(profilemodel); + profiles->setEditTriggers(QListView::NoEditTriggers); + connect(profiles,SIGNAL(clicked(const QModelIndex&)),this,SLOT(loadProfile())); + connect(profiles,SIGNAL(activated(const QModelIndex&)),this,SLOT(loadProfile())); + //create tabs + QTabWidget*tab; + QWidget*w; + hl->addWidget(tab=new QTabWidget,10); + tab->addTab(w=new QWidget,tr("Connection")); + QGridLayout*gl; + w->setLayout(gl=new QGridLayout); + QLabel*lab; + int lctr=0; + gl->addWidget(lab=new QLabel(tr("Server URL:")),++lctr,0); + lab->setAlignment(Qt::AlignRight); + gl->addLayout(hl=new QHBoxLayout,lctr,1); + hl->addWidget(new QLabel("https://"),0); + hl->addWidget(serverurl=new QLineEdit,1); + gl->addWidget(useproxy=new QCheckBox(tr("Proxy:")),++lctr,0); + gl->addLayout(hl=new QHBoxLayout,lctr,1); + hl->addWidget(proxyname=new QLineEdit,1); + hl->addWidget(new QLabel(":"),0); + hl->addWidget(proxyport=new QSpinBox,0); + proxyport->setRange(1,65535); + connect(useproxy,SIGNAL(toggled(bool)),proxyname,SLOT(setEnabled(bool))); + connect(useproxy,SIGNAL(toggled(bool)),proxyport,SLOT(setEnabled(bool))); + gl->addWidget(lab=new QLabel(tr("Proxy Username:")),++lctr,0); + lab->setAlignment(Qt::AlignRight); + gl->addWidget(proxyuser=new QLineEdit,lctr,1); + gl->addWidget(lab=new QLabel(tr("Proxy Password:")),++lctr,0); + lab->setAlignment(Qt::AlignRight); + gl->addWidget(proxypass=new QLineEdit,lctr,1); + proxypass->setEchoMode(QLineEdit::Password); + connect(useproxy,SIGNAL(toggled(bool)),proxyuser,SLOT(setEnabled(bool))); + connect(useproxy,SIGNAL(toggled(bool)),proxypass,SLOT(setEnabled(bool))); + + tab->addTab(w=new QWidget,tr("Authentication")); + w->setLayout(gl=new QGridLayout); + lctr=0; + gl->addWidget(lab=new QLabel(tr("Hostname:")),++lctr,0); + lab->setAlignment(Qt::AlignRight); + gl->addWidget(hostname=new QLineEdit,lctr,1); + gl->addWidget(lab=new QLabel(tr("Hostkey:")),++lctr,0); + lab->setAlignment(Qt::AlignRight); + gl->addWidget(hostkey=new QLineEdit,lctr,1); + gl->addWidget(lab=new QLabel(tr("Default Username:")),++lctr,0); + lab->setAlignment(Qt::AlignRight); + gl->addWidget(username=new QLineEdit,lctr,1); + gl->setRowStretch(++lctr,10); + gl->addLayout(hl=new QHBoxLayout,++lctr,0,1,2); + + tab->addTab(w=new QWidget,tr("SSL Exceptions")); + w->setLayout(vl=new QVBoxLayout); + vl->addWidget(new QLabel(tr("List of non-fatal SSL exceptions:")),0); + vl->addWidget(ssltable=new QTableView,10); + ssltable->setModel(sslmodel=new QStandardItemModel(this)); + ssltable->setEditTriggers(QListView::NoEditTriggers); + vl->addSpacing(10); + vl->addLayout(hl=new QHBoxLayout,0); + hl->addStretch(10); + QPushButton*pb; + hl->addWidget(pb=new QPushButton(tr("Clear"))); + connect(pb,SIGNAL(clicked()),this,SLOT(clearSslExceptions())); + hl->addWidget(pb=new QPushButton(tr("Probe Server"))); + connect(pb,SIGNAL(clicked()),this,SLOT(serverProbe())); + + initProfiles(); + loadProfile(); +} + +MConfigDialog::~MConfigDialog() +{ + saveProfile(); +} + +void MConfigDialog::initProfiles(QString selIdx) +{ + oldrow=-1; + QSettings set; + int defpro=set.value("defaultprofile",0).toInt(); + set.beginGroup("profiles"); + QStringList prf=set.childGroups(); + profilemodel->clear(); + if(profilemodel->columnCount()<1) + profilemodel->insertColumn(0); + profilemodel->insertRows(0,prf.size()); + int newrow=0; + for(int i=0;iindex(i,0); + profilemodel->setData(idx,set.value(prf[i]+"/name").toString()); + profilemodel->setData(idx,prf[i],Qt::UserRole); + if(i==defpro){ + QFont f=profiles->font(); + f.setBold(true); + profilemodel->setData(idx,f,Qt::FontRole); + } + if(prf[i]==selIdx)newrow=i; + } + profiles->setCurrentIndex(profilemodel->index(newrow,0)); +} + +void MConfigDialog::loadProfile() +{ + //save old + saveProfile(); + if(sslexcept)delete sslexcept; + sslexcept=0; + //get new + QModelIndex idx=profiles->currentIndex(); + if(!idx.isValid())return; + oldrow=idx.row(); + QString key=profilemodel->data(idx,Qt::UserRole).toString(); + QSettings set; + set.beginGroup("profiles/"+key); + hostname->setText(set.value("hostname").toString()); + hostkey->setText(set.value("hostkey").toString()); + serverurl->setText(set.value("serverurl","my.host.com/path/machine.php").toString()); + useproxy->setChecked(set.value("useproxy",false).toBool()); + proxyname->setText(set.value("proxyname","proxy").toString()); + proxyport->setValue(set.value("proxyport",74).toInt()); + proxyuser->setText(set.value("proxyuser").toString()); + proxypass->setText(set.value("proxypass").toString()); + proxyname->setEnabled(useproxy->isChecked()); + proxyport->setEnabled(useproxy->isChecked()); + proxyuser->setEnabled(useproxy->isChecked()); + proxypass->setEnabled(useproxy->isChecked()); + username->setText(set.value("username").toString()); + sslexcept=new MSslExceptions(::dataDir+"/profile."+key+"/sslexceptions.xml"); + sslFillModel(); +} + +void MConfigDialog::saveProfile() +{ + if(oldrow<0 || oldrow>=profilemodel->rowCount())return; + QString key=profilemodel->data(profilemodel->index(oldrow,0),Qt::UserRole).toString(); + QSettings set; + set.beginGroup("profiles/"+key); + set.setValue("hostname",hostname->text()); + set.setValue("hostkey",hostkey->text()); + set.setValue("serverurl",serverurl->text()); + set.setValue("useproxy",useproxy->isChecked()); + set.setValue("proxyname",proxyname->text()); + set.setValue("proxyport",proxyport->value()); + set.setValue("proxyuser",proxyuser->text()); + set.setValue("proxypass",proxypass->text()); + set.setValue("username",username->text()); + if(sslexcept)sslexcept->savesslexcept(); +} + +void MConfigDialog::newProfile() +{ + saveProfile(); + //scan for existing ones... + QSettings set; + set.beginGroup("profiles"); + QStringList prf=set.childGroups(); + QStringList prn; + for(int i=0;icurrentIndex(); + if(!idx.isValid())return; + QString key=profilemodel->data(idx,Qt::UserRole).toString(); + QSettings set; + set.beginGroup("profiles"); + set.remove(key); + set.sync(); + oldrow=-1; + initProfiles(); + loadProfile(); +} + +void MConfigDialog::renameProfile() +{ + //get old name + QModelIndex idx=profiles->currentIndex(); + if(!idx.isValid())return; + QString key=profilemodel->data(idx,Qt::UserRole).toString(); + QString pname=profilemodel->data(idx).toString(); + //query + bool ok; + QString npname=QInputDialog::getText(this,tr("Rename Profile"),tr("Please enter a profile name. It must be non-empty and must not be used yet:"),QLineEdit::Normal,pname,&ok); + if(!ok)return; + //check + if(npname==pname)return; + for(int i=0;irowCount();i++){ + QString pn=profilemodel->data(profilemodel->index(i,0)).toString(); + if(pn==npname){ + QMessageBox::warning(this,tr("Warning"),tr("This profile name is already in use.")); + return; + } + } + //set + QSettings().setValue("profiles/"+key+"/name",npname); + profilemodel->setData(idx,npname); +} + +void MConfigDialog::cloneProfile() +{ + saveProfile(); + //get current + QModelIndex idx=profiles->currentIndex(); + if(!idx.isValid())return; + QString key=profilemodel->data(idx,Qt::UserRole).toString(); + //scan for existing ones... + QSettings set; + set.beginGroup("profiles"); + QStringList prf=set.childGroups(); + QStringList prn; + for(int i=0;icurrentIndex(); + if(!idx.isValid())return; + QString key=profilemodel->data(idx,Qt::UserRole).toString(); + QSettings().setValue("defaultprofile",key); + initProfiles(key); + loadProfile(); +} + + +void MConfigDialog::changeLang() +{ + choseLanguage(); +} + +void MConfigDialog::exportKey() +{ + QSettings st; + QModelIndex idx=profiles->currentIndex(); + if(!idx.isValid())return; + QString pkey=profilemodel->data(idx,Qt::UserRole).toString(); + st.beginGroup("profiles/"+pkey); + QString host=st.value("hostname").toString().trimmed(); + QString key=st.value("hostkey").toString().trimmed(); + saveKey(host,key); +} + +void MConfigDialog::generateKey() +{ + //ask nicely + if(hostkey->text()!="") + if(QMessageBox::question(this,tr("Generate Hostkey"), tr("Do you really want to generate a new host key for this profile? This may disable all accounts from this host."), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) + return; + //actually create new key + QString name; + MKeyGen mkg(this); + QString k=mkg.getKey(); + if(k=="") + if(mkg.exec()!=QDialog::Accepted) + return; + hostkey->setText(mkg.getKey()); +} + +void MConfigDialog::saveKey(QString host,QString key) +{ + 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"+host+"\n"+key+"\n"+chk; + fd.write(out.toAscii()); + fd.close(); +} + +void MConfigDialog::importKey() +{ + QModelIndex idx=profiles->currentIndex(); + if(!idx.isValid())return; + QString profkey=profilemodel->data(idx,Qt::UserRole).toString(); + + if(QMessageBox::warning(this,tr("Warning"),tr("Importing a key overwrites the host key that is currently used by this profile. This may disable your accounts. Do you still want to continue?"),QMessageBox::Yes|QMessageBox::Abort,QMessageBox::Abort)!=QMessageBox::Yes) + return; + 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 + QSettings set; + set.beginGroup("profiles/"+profkey); + set.setValue("hostkey",key); + set.setValue("hostname",hname); +} + +void MConfigDialog::openOfficeCfg() +{ + MOfficeConfig c(this); + c.exec(); +} + +void MConfigDialog::setDefaultFont() +{ + QStringList fonts=QFontDatabase().families(); + QString df=QInputDialog::getItem(this,tr("Chose Default Font"),tr("Please chose a default font:"),fonts,fonts.indexOf(QSettings().value("defaultfont","").toString()),false); + if(df.isEmpty())return; + QSettings().setValue("defaultfont",df); +} + +void MConfigDialog::serverProbe() +{ + //sanity check + if(!sslexcept)return; + sslexcept->clearRecorded(); + //set up mini-environment + QEventLoop loop; + QNetworkAccessManager man; + connect(&man,SIGNAL(finished(QNetworkReply*)),&loop,SLOT(quit())); + QTimer::singleShot(30000,&loop,SLOT(quit())); + connect(&man,SIGNAL(sslErrors(QNetworkReply*,const QList&)), this,SLOT(sslErrors(QNetworkReply*,const QList&))); + if(useproxy->isChecked()) + man.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy,proxyname->text(),proxyport->value(),proxyuser->text(),proxypass->text())); + //query server + QNetworkRequest rq(QUrl("https://"+serverurl->text())); + QNetworkReply *rp=man.get(rq); + //wait for result + setEnabled(false); + loop.exec(); + setEnabled(true); + //probe result + if(rp->error()==QNetworkReply::NoError){ + QMessageBox::information(this,tr("Server Probe"),tr("The request finished without errors.")); + }else{ + QMessageBox::warning(this,tr("Server Probe"),tr("The request finished with an error: %1").arg(rp->errorString())); + } + delete rp; +} + +void MConfigDialog::sslErrors(QNetworkReply*rp,const QList&errs) +{ + if(!sslexcept)return; + //check/record/clear + if(sslexcept->checksslexcept(errs))rp->ignoreSslErrors(); + //convert to string + QString err=tr("SSL Errors encountered:\n"); + for(int i=0;iignoreSslErrors(); + sslexcept->acceptRecorded(); + } + sslFillModel(); +} + +void MConfigDialog::clearSslExceptions() +{ + if(sslexcept)sslexcept->clear(); + sslmodel->clear(); +} + +void MConfigDialog::sslFillModel() +{ + sslmodel->clear(); + if(!sslexcept)return; + sslmodel->insertColumns(0,3); + sslmodel->setHorizontalHeaderLabels(QStringList()< >lst=sslexcept->nonFatalExceptions(); + sslmodel->insertRows(0,lst.size()); + for(int i=0;isetData(sslmodel->index(i,0),lst[i].first.subjectInfo(QSslCertificate::CommonName)); + sslmodel->setData(sslmodel->index(i,1),QString::fromAscii(lst[i].first.digest(QCryptographicHash::Sha1).toHex())); + sslmodel->setData(sslmodel->index(i,2),QSslError((QSslError::SslError)lst[i].second).errorString()); + } +} diff --git a/src/dialogs/configdialog.h b/src/dialogs/configdialog.h new file mode 100644 index 0000000..279653a --- /dev/null +++ b/src/dialogs/configdialog.h @@ -0,0 +1,77 @@ +// +// C++ Interface: mainwindow +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2007 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_CONFIGDIALOG_H +#define MAGICSMOKE_CONFIGDIALOG_H + +#include +#include +#include + +class QCheckBox; +class QLineEdit; +class QListView; +class QNetworkReply; +class QSpinBox; +class QStandardItemModel; +class QTableView; + +class MSslExceptions; + +/**login and profile configuration window*/ +class MConfigDialog:public QDialog +{ + Q_OBJECT + public: + MConfigDialog(); + ~MConfigDialog(); + + private: + QCheckBox*useproxy; + QLineEdit*hostname,*hostkey,*serverurl,*proxyname,*username,*proxyuser,*proxypass; + QSpinBox*proxyport; + QListView*profiles; + QStandardItemModel*profilemodel,*sslmodel; + QTableView*ssltable; + + MSslExceptions*sslexcept; + + int oldrow; + + //helper for exportKey and generateKey + void saveKey(QString hostname,QString hostkey); + + private slots: + //handling of login/profile screen + void initProfiles(QString idx=QString()); + void loadProfile(); + void saveProfile(); + void newProfile(); + void deleteProfile(); + void renameProfile(); + void cloneProfile(); + void defaultProfile(); + //settings + void changeLang(); + void exportKey(); + void importKey(); + void generateKey(); + void openOfficeCfg(); + void setDefaultFont(); + //ssl server probe + void serverProbe(); + void sslErrors(QNetworkReply*,const QList&); + void clearSslExceptions(); + void sslFillModel(); +}; + +#endif diff --git a/src/dialogs/dialogs.pri b/src/dialogs/dialogs.pri new file mode 100644 index 0000000..825a0f7 --- /dev/null +++ b/src/dialogs/dialogs.pri @@ -0,0 +1,15 @@ +HEADERS += \ + dialogs/configdialog.h \ + dialogs/eventedit.h \ + dialogs/eventsummary.h \ + dialogs/orderwin.h \ + dialogs/moneylog.h + +SOURCES += \ + dialogs/configdialog.cpp \ + dialogs/eventedit.cpp \ + dialogs/eventsummary.cpp \ + dialogs/orderwin.cpp \ + dialogs/moneylog.cpp + +INCLUDEPATH += ./dialogs \ No newline at end of file diff --git a/src/dialogs/eventedit.cpp b/src/dialogs/eventedit.cpp new file mode 100644 index 0000000..2b73b75 --- /dev/null +++ b/src/dialogs/eventedit.cpp @@ -0,0 +1,207 @@ +// +// C++ Implementation: eventedit +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2007 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "eventedit.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define req (MSInterface::instance()) + +MEventEditor::MEventEditor(QWidget*w,qint64 id) + :QDialog(w) +{ + MTGetEvent ge=MTGetEvent::query(id); + if(ge.stage()!=ge.Success){ + QMessageBox::warning(this,tr("Warning"),tr("Unable to load event from server.")); + //make myself disappear immediately + QTimer::singleShot(1,this,SLOT(reject())); + //no point in setting up widgets + return; + } + event=ge.getevent().value(); + setWindowTitle(tr("Event Editor")); + + QGridLayout*gl; + QVBoxLayout*vl; + QHBoxLayout*hl; + QPushButton*p; + int lctr=0; + QLabel*lab; + + setLayout(vl=new QVBoxLayout); + vl->addLayout(gl=new QGridLayout); + + gl->addWidget(lab=new QLabel(tr("ID:")),lctr,0); + lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + gl->addWidget(eventid=new QLabel,lctr,1); + eventid->setText(QString::number(event.id())); + + gl->addWidget(lab=new QLabel(tr("Title:")),++lctr,0); + lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + gl->addWidget(title=new QLineEdit,lctr,1); + title->setText(event.title()); + + gl->addWidget(lab=new QLabel(tr("Artist:")),++lctr,0); + lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + gl->addWidget(artist=new QLineEdit,lctr,1); + artist->setText(event.artist().value().name()); + + gl->addWidget(lab=new QLabel(tr("Description:")),++lctr,0); + lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + gl->addWidget(description=new QTextEdit,lctr,1); + description->setPlainText(event.description()); + + gl->addWidget(lab=new QLabel(tr("Start Time:")),++lctr,0); + lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + gl->addWidget(starttime=new QDateTimeEdit,lctr,1); + starttime->setDisplayFormat(tr("ddd MMMM d yyyy, h:mm ap","time format")); + starttime->setCalendarPopup(true); + starttime->setDateTime(QDateTime::fromTime_t(event.start())); + connect(starttime,SIGNAL(dateTimeChanged(const QDateTime&)),this,SLOT(startTimeChanged(const QDateTime&))); + + gl->addWidget(lab=new QLabel(tr("End Time:")),++lctr,0); + lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + gl->addWidget(endtime=new QDateTimeEdit,lctr,1); + endtime->setDisplayFormat(tr("ddd MMMM d yyyy, h:mm ap","time format")); + endtime->setCalendarPopup(true); + endtime->setDateTime(QDateTime::fromTime_t(event.end())); + connect(endtime,SIGNAL(dateTimeChanged(const QDateTime&)),this,SLOT(endTimeChanged(const QDateTime&))); + + gl->addWidget(lab=new QLabel(tr("Room/Place:")),++lctr,0); + lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + gl->addLayout(hl=new QHBoxLayout,lctr,1); + hl->addWidget(room=new QLineEdit,10); + room->setReadOnly(true); + room->setText(event.room()); + hl->addWidget(p=new QPushButton("..."),0); + connect(p,SIGNAL(clicked()),this,SLOT(selectRoom())); + + gl->addWidget(lab=new QLabel(tr("Capacity:")),++lctr,0); + lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + gl->addWidget(capacity=new QSpinBox,lctr,1); + capacity->setRange(0,1000000000);//it is unlikely that any show will attract more people! + capacity->setValue(event.capacity()); + + gl->addWidget(lab=new QLabel(tr("Default Price:")),++lctr,0); + lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + gl->addWidget(price=new QLineEdit,lctr,1); + price->setValidator(new QRegExpValidator(event.priceRegExp(),this)); + price->setText(event.priceString()); + + gl->addWidget(cancelcheck=new QCheckBox(tr("Event Cancelled:")),++lctr,0); + cancelcheck->setChecked(event.iscancelled()); + cancelcheck->setEnabled(false); + gl->addWidget(cancelreason=new QLineEdit,lctr,1); + cancelreason->setEnabled(event.iscancelled()); + cancelreason->setText(event.cancelreason()); + connect(cancelcheck,SIGNAL(toggled(bool)),cancelreason,SLOT(setEnabled(bool))); + + vl->addStretch(); + + vl->addLayout(hl=new QHBoxLayout,0); + hl->addStretch(); + hl->addWidget(p=new QPushButton(tr("Save"))); +// connect(p,SIGNAL(clicked()),this,SLOT(accept())); + connect(p,SIGNAL(clicked()),this,SLOT(writeBack())); + hl->addWidget(p=new QPushButton(tr("Cancel"))); + connect(p,SIGNAL(clicked()),this,SLOT(reject())); +} + +void MEventEditor::writeBack() +{ + //copy contents to event + event.settitle(title->text()); + event.setstart(starttime->dateTime().toTime_t()); + event.setend(endtime->dateTime().toTime_t()); +// event.setartist(artist->text()); + event.setroom(room->text()); + event.setdefaultprice(price->text()); + event.setiscancelled(cancelcheck->isChecked()); + event.setcancelreason(cancelreason->text()); + event.setdescription(description->toPlainText()); + event.setcapacity(capacity->value()); + //send to server + /*TODO + event.makeValid(); + QString r=event.save(); + if(r!=""){ + QMessageBox::warning(this,tr("Warning"),tr("Problem while uploading event: %s").arg(r)); + }else + accept();*/ +} + +void MEventEditor::selectRoom() +{ + QListrlst=req->queryGetAllRooms().getrooms(); + QDialog d; + d.setWindowTitle(tr("Select a Room")); + QVBoxLayout*vl; + d.setLayout(vl=new QVBoxLayout); + QListWidget*rlstw; + vl->addWidget(rlstw=new QListWidget,10); + for(int i=0;iaddItem(rlst[i].id()); + QHBoxLayout*hl; + vl->addLayout(hl=new QHBoxLayout,0); + hl->addStretch(10); + QPushButton*p; + hl->addWidget(p=new QPushButton(tr("New...","new room")),0); + connect(p,SIGNAL(clicked()),this,SLOT(newRoom())); + connect(p,SIGNAL(clicked()),&d,SLOT(reject())); + hl->addWidget(p=new QPushButton(tr("Select","select room")),0); + connect(p,SIGNAL(clicked()),&d,SLOT(accept())); + hl->addWidget(p=new QPushButton(tr("Cancel")),0); + connect(p,SIGNAL(clicked()),&d,SLOT(reject())); + if(d.exec()==QDialog::Rejected)return; + //get selection + QListwlst=rlstw->selectedItems(); + if(wlst.size()<1)return; + room->setText(wlst[0]->text()); +} + +void MEventEditor::newRoom() +{/*TODO + QString rid=QInputDialog::getText(this,tr("New Room"),tr("Name of new room:")); + if(rid!=""){ + MRoom rm(req,rid); + rm.makeValid(); + rm.save(); + room->setText(rid); + }*/ +} + +void MEventEditor::startTimeChanged(const QDateTime&st) +{ + QDateTime et=endtime->dateTime(); + if(etsetDateTime(st); +} + +void MEventEditor::endTimeChanged(const QDateTime&et) +{ + QDateTime st=starttime->dateTime(); + if(st>et)starttime->setDateTime(et); +} diff --git a/src/dialogs/eventedit.h b/src/dialogs/eventedit.h new file mode 100644 index 0000000..bd183a7 --- /dev/null +++ b/src/dialogs/eventedit.h @@ -0,0 +1,51 @@ +// +// C++ Interface: eventedit +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2007 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef SMOKE_EVENT_EDIT_H +#define SMOKE_EVENT_EDIT_H + +#include + +#include "event.h" + +class QCheckBox; +class QDateTime; +class QDateTimeEdit; +class QLabel; +class QLineEdit; +class QSpinBox; +class QTextEdit; + +class MEventEditor:public QDialog +{ + Q_OBJECT + public: + MEventEditor(QWidget*,qint64 id=-1); + private slots: + void writeBack(); + void selectRoom(); + void newRoom(); + + void startTimeChanged(const QDateTime&); + void endTimeChanged(const QDateTime&); + private: + MEvent event; + QDateTimeEdit*starttime,*endtime; + QLineEdit*title,*artist,*room,*price,*cancelreason; + QTextEdit*description; + QCheckBox*cancelcheck; + QSpinBox*capacity; + QLabel*eventid; +}; + + +#endif diff --git a/src/dialogs/eventsummary.cpp b/src/dialogs/eventsummary.cpp new file mode 100644 index 0000000..70caf5a --- /dev/null +++ b/src/dialogs/eventsummary.cpp @@ -0,0 +1,382 @@ +// +// C++ Implementation: eventsummary +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "eventsummary.h" +#include "misc.h" +#include "odtrender.h" +#include "msinterface.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define req (MSInterface::instance()) + +MEventSummary::MEventSummary(QWidget*par,qint64 eid) + :QDialog(par),event(eid) +{ + nreserved=ncancelled=ntotaltickets=ntotalmoney=0; + //get event data + getSummaryData(); + //layout/tabs + setWindowTitle(tr("Summary for Event %1").arg(event.title())); + QVBoxLayout*vl; + setLayout(vl=new QVBoxLayout); + QTabWidget*tab; + vl->addWidget(tab=new QTabWidget); + QWidget*w; + tab->addTab(w=new QWidget,tr("Summary")); + QGridLayout*gl; + w->setLayout(gl=new QGridLayout); + int rc=0; + gl->addWidget(new QLabel(tr("Title:")),rc,0); + gl->addWidget(new QLabel(event.title()),rc,1); + gl->addWidget(new QLabel(tr("Artist:")),++rc,0); + gl->addWidget(new QLabel(event.artist().value().name()),rc,1); + gl->addWidget(new QLabel(tr("Start:")),++rc,0); + gl->addWidget(new QLabel(event.startTimeString()),rc,1); + gl->addWidget(new QLabel(tr("Capacity:")),++rc,0); + gl->addWidget(new QLabel(QString::number(event.capacity())),rc,1); + gl->addWidget(new QLabel(tr("Tickets currently reserved:")),++rc,0); + gl->addWidget(new QLabel(QString::number(nreserved)),rc,1); + gl->addWidget(new QLabel(tr("Tickets currently cancelled:")),++rc,0); + gl->addWidget(new QLabel(QString::number(ncancelled)),rc,1); + gl->addWidget(new QLabel(tr("Tickets currently usable:")),++rc,0); + gl->addWidget(new QLabel(QString::number(ntotaltickets)),rc,1); + gl->addWidget(new QLabel(tr("Total Income:")),++rc,0); + gl->addWidget(new QLabel(cent2str(ntotalmoney)),rc,1); + + QTableView*table; + QStandardItemModel*model; + tab->addTab(table=new QTableView,tr("Tickets")); + table->setEditTriggers(QAbstractItemView::NoEditTriggers); + table->setModel(model=new QStandardItemModel(this)); + model->insertColumns(0,4); + model->insertRows(0,tickets.size()); + model->setHorizontalHeaderLabels(QStringList()<setData(model->index(i,0),cent2str(tc.price)); + model->setData(model->index(i,1),tc.bought); + model->setData(model->index(i,2),tc.used); + model->setData(model->index(i,3),tc.unused); + } + table->resizeColumnsToContents(); + + QTextBrowser *tb; + tab->addTab(tb=new QTextBrowser,tr("Comments")); + QString cmt; + for(int i=0;i"; + else cmt+="


"; + cmt+=""+tr("Order: "); + cmt+=QString::number(c.orderid); + cmt+="
"+tr("Customer: ")+htmlize(c.custname); + cmt+="

"+htmlize(c.comment); + } + tb->setHtml(cmt); + + QHBoxLayout*hl; + vl->addSpacing(15); + vl->addLayout(hl=new QHBoxLayout,0); + hl->addStretch(10); + QPushButton*p; + hl->addWidget(p=new QPushButton(tr("Print")),0); + connect(p,SIGNAL(clicked()),this,SLOT(print())); + hl->addWidget(p=new QPushButton(tr("Save as...")),0); + connect(p,SIGNAL(clicked()),this,SLOT(saveas())); + hl->addSpacing(15); + hl->addWidget(p=new QPushButton(tr("Close")),0); + connect(p,SIGNAL(clicked()),this,SLOT(accept())); +} + +MEventSummary::~MEventSummary(){} + +void MEventSummary::getOrderData() +{ + if(orderids.size()==orders.size())return; + for(int i=0;irequest("eventsummary",QString::number(event.eventId()).toAscii()))return; + if(req->responseStatus()!=MWebRequest::Ok)return; + QDomDocument doc; + if(!doc.setContent(req->responseBody()))return; + QDomElement sum=doc.documentElement(); + nreserved=sum.attribute("reserved","0").toInt(); + ncancelled=sum.attribute("cancelled","0").toInt(); + ntotaltickets=sum.attribute("totaltickets","0").toInt(); + ntotalmoney=sum.attribute("totalmoney","0").toInt(); + QDomNodeList nl=sum.elementsByTagName("Tickets"); + for(int i=0;igetTemplate("eventsummary"); + if(!tf.isValid()){ + QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (eventsummary). Giving up.")); + return; + } + MOdtSignalRenderer rend(tf); + connect(&rend,SIGNAL(getVariable(QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getVariable(QString,MOdtRenderer::VarType&,QVariant&))); + connect(&rend,SIGNAL(getLoopIterations(QString,int&)),this,SLOT(getLoopIterations(QString,int&))); + connect(&rend,SIGNAL(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&))); + rend.renderToPrinter();*/ +} + +void MEventSummary::saveas() +{/*TODO: + MTemplate tf=req->getTemplate("eventsummary"); + if(!tf.isValid()){ + QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (eventsummary). Giving up.")); + return; + } + QFileDialog fd(this); + fd.setAcceptMode(QFileDialog::AcceptSave); + fd.setFileMode(QFileDialog::AnyFile); + fd.setConfirmOverwrite(true); + fd.setFilter(tr("Open Document File (*.%1)").arg(tf.targetExtension())); + fd.setDefaultSuffix(tf.targetExtension()); + QString fname; + if(fd.exec()){ + QStringList fn=fd.selectedFiles(); + if(fn.size()<1)return; + fname=fn[0]; + } + MOdtSignalRenderer rend(tf); + connect(&rend,SIGNAL(getVariable(QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getVariable(QString,MOdtRenderer::VarType&,QVariant&))); + connect(&rend,SIGNAL(getLoopIterations(QString,int&)),this,SLOT(getLoopIterations(QString,int&))); + connect(&rend,SIGNAL(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&))); + rend.renderToFile(fname);*/ +} + +void MEventSummary::getVariable(QString varname,MOdtRenderer::VarType&av,QVariant&value) +{ + if(varname=="TITLE") + value=event.title().value(); + else + if(varname=="ARTIST") + value=event.artist().value().name().value(); + else + if(varname=="ROOM") + value=event.room().value(); + else + if(varname=="START"){ + value=event.start().value(); + av=MOdtRenderer::DateTimeVar; + }else + if(varname=="CAPACITY"){ + value=event.capacity().value(); + av=MOdtRenderer::IntVar; + }else + if(varname=="RESERVED"){ + value=nreserved; + av=MOdtRenderer::IntVar; + }else + if(varname=="BOUGHT"){ + value=ntotaltickets; + av=MOdtRenderer::IntVar; + }else + if(varname=="USED"){ + int nused=0; + for(int i=0;i=tickets.size())return; + + if(varname=="PRICE"){ + value=tickets[iteration].price; + av=MOdtRenderer::MoneyVar; + }else + if(varname=="BOUGHT"){ + value=tickets[iteration].bought; + av=MOdtRenderer::IntVar; + }else + if(varname=="USED"){ + value=tickets[iteration].used; + av=MOdtRenderer::IntVar; + }else + if(varname=="UNUSED"){ + value=tickets[iteration].unused; + av=MOdtRenderer::IntVar; + } + }else + if(loopname=="COMMENTS"){ + if(iteration<0 || iteration>=comments.size())return; + + if(varname=="ORDERID")value=QString::number(comments[iteration].orderid);else + if(varname=="CUSTOMERID")value=QString::number(comments[iteration].custid);else + if(varname=="CUSTOMER")value=comments[iteration].custname;else + if(varname=="TEXT")value=comments[iteration].comment; + }else + if(loopname=="ORDERS"){ + if(iteration<0 || iteration>=orderids.size())return; + //make sure data is here + getOrderData(); + //get order id + int oid=orderids[iteration]; + + if(varname=="ORDERID"){ + value=QString::number(oid); + return; + } + + //paranoia check + if(!orders.contains(oid))return; + + if(varname=="CUSTOMERID")value=QString::number(orders[oid].orderid());else + if(varname=="CUSTOMER")value=orders[oid].customer().name().value();else + if(varname=="FULLPRICE"){ + value=orders[oid].totalprice().value(); + av=MOdtRenderer::MoneyVar; + }/*TODO: else + if(varname=="SHIPPING")value=orders[oid].shipping().description();else + if(varname=="SHIPPINGCOST"){ + value=orders[oid].shipping().price(); + av=MOdtRenderer::MoneyVar; + }else{ + QListticks=orders[oid].tickets(); + QListeticks; + int first,last; + first=last=event.startTime(); + int eid=event.eventId(); + for(int i=0;i, (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_EVENTSUMMARY_H +#define MAGICSMOKE_EVENTSUMMARY_H + +#include +#include + +#include "order.h" +#include "odtrender.h" + +class QTableView; +class QStandardItemModel; +class QLabel; + +/**shows a summary for the event*/ +class MEventSummary:public QDialog +{ + Q_OBJECT + public: + /**creates a new summary dialog, requests data from server*/ + MEventSummary(QWidget*parent,qint64 eventid); + /**deletes MEventSummary*/ + ~MEventSummary(); + + private slots: + /**internal: print summary*/ + void print(); + /**internal: save summary to file*/ + void saveas(); + + //used for ODT rendering: + void getVariable(QString,MOdtRenderer::VarType&,QVariant&); + void getLoopIterations(QString,int&); + void getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&); + + private: + int eventid; + MEvent event; + int nreserved,ncancelled,ntotaltickets,ntotalmoney; + struct Tickets{ + int price,bought,used,unused; + }; + QListtickets; + struct Comment{ + int custid,orderid; + QString custname,comment; + }; + QListcomments; + QListorderids; + QMaporders; + + //get summary + void getSummaryData(); + //helper: get order details + void getOrderData(); +}; + +#endif diff --git a/src/dialogs/moneylog.cpp b/src/dialogs/moneylog.cpp new file mode 100644 index 0000000..98846a5 --- /dev/null +++ b/src/dialogs/moneylog.cpp @@ -0,0 +1,54 @@ +// +// C++ Implementation: moneylog +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "moneylog.h" +#include "msinterface.h" +#include "misc.h" + +#include +#include +#include + +MMoneyLog::MMoneyLog(QWidget*pa,QString q) + :QDialog(pa) +{ + //set title + QStringList sl=q.split("\n"); + sl[0][0]=sl[0][0].toUpper(); + setWindowTitle(tr("Money Log of %1 %2").arg(sl[0]).arg(sl[1])); + + //layout + QVBoxLayout*vl; + QHBoxLayout*hl; + QTextEdit*text; + QPushButton*p; + setLayout(vl=new QVBoxLayout); + vl->addWidget(text=new QTextEdit,10); + text->setReadOnly(true); + vl->addSpacing(15); + vl->addLayout(hl=new QHBoxLayout,0); + hl->addStretch(10); + hl->addWidget(p=new QPushButton(tr("Close"))); + connect(p,SIGNAL(clicked()),this,SLOT(accept())); + + //query + /*TODO + if(req->request("moneylog",q.toAscii())){ + if(req->responseStatus()==MWebRequest::Ok){ + text->setPlainText(QString::fromUtf8(req->responseBody())); + }else{ + text->setHtml("

Error

"+htmlize(QString::fromUtf8(req->responseBody()))); + } + }else{ + text->setHtml("

Low Level Error

Request failed."); + }*/ +} \ No newline at end of file diff --git a/src/dialogs/moneylog.h b/src/dialogs/moneylog.h new file mode 100644 index 0000000..fbdc415 --- /dev/null +++ b/src/dialogs/moneylog.h @@ -0,0 +1,27 @@ +// +// C++ Interface: moneylog +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_MONEYLOG_H +#define MAGICSMOKE_MONEYLOG_H + +#include + + +class MMoneyLog:public QDialog +{ + Q_OBJECT + public: + MMoneyLog(QWidget*,QString); +}; + + +#endif diff --git a/src/dialogs/orderwin.cpp b/src/dialogs/orderwin.cpp new file mode 100644 index 0000000..f6481a3 --- /dev/null +++ b/src/dialogs/orderwin.cpp @@ -0,0 +1,1099 @@ +// +// C++ Implementation: orderwin +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "centbox.h" +#include "event.h" +#include "labeldlg.h" +#include "misc.h" +#include "moneylog.h" +#include "odtrender.h" +#include "orderwin.h" +#include "ticketrender.h" +#include "msinterface.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define req (MSInterface::instance()) + +MOrderWindow::MOrderWindow(QWidget*par,const MOrder&o) + :QMainWindow(par),m_order(o) +{ + setWindowTitle(tr("Order Details")); + setAttribute(Qt::WA_DeleteOnClose); + m_changed=false; + + QMenuBar*mb=menuBar(); + QMenu *m=mb->addMenu(tr("&Order")); + m->addAction(tr("&Order..."),this,SLOT(createOrder())) + ->setEnabled((req->hasRole("createorder")&&o.canOrder()) || + (req->hasRole("reservationtoorder")&&o.isReservation())); + m->addAction(tr("&Sell..."),this,SLOT(createSale())) + ->setEnabled((req->hasRole("createsale")&&o.canSell()) || + (req->hasRole("reservationtosale")&&o.isReservation())); + m->addAction(tr("Ma&ke Reservation..."),this,SLOT(createReservation())) + ->setEnabled(req->hasRole("createreservedorder")&&o.canReserve()); + m->addAction(tr("&Prune and recheck..."),this,SLOT(recheckOrder())) + ->setEnabled(o.orderid()<0); + m->addSeparator(); + m->addAction(tr("C&ancel Order..."),this,SLOT(cancelOrder())) + //FIXME + ->setEnabled(req->hasRole("cancelorder")/*&&o.isStored()*/); + m->addAction(tr("&Mark Order as Shipped..."),this,SLOT(shipOrder())) + ->setEnabled(req->hasRole("ordershipped")); + m->addSeparator(); + m->addAction(tr("Ch&ange Item-Price..."),this,SLOT(changeItem())) + ->setEnabled(req->hasRole("changeticketprice")); + m->addAction(tr("&Return Item..."),this,SLOT(itemReturn())) + ->setEnabled(req->hasRole("ticketreturn")); + m->addAction(tr("Change Commen&t..."),this,SLOT(changeComment())) + ->setEnabled(req->hasRole("setordercomment")); + m->addAction(tr("Change Sh&ipping Method..."),this,SLOT(changeShipping())) + ->setEnabled(req->hasRole("changeordershipping")); + m->addSeparator(); + m->addAction(tr("MoneyLog for Order..."),this,SLOT(moneyLogOrder())) + ->setEnabled(req->hasRole("moneylog")); + m->addAction(tr("MoneyLog for selected Voucher..."),this,SLOT(moneyLogVoucher())) + ->setEnabled(req->hasRole("moneylog")); + m->addSeparator(); + m->addAction(tr("&Close"),this,SLOT(close())); + + m=mb->addMenu(tr("&Payment")); + //FIXME: m->setEnabled(o.isStored()); + m->addAction(tr("Receive &Payment..."),this,SLOT(payment())) + ->setEnabled(req->hasRole("orderpay")); + m->addAction(tr("&Refund..."),this,SLOT(refund())) + ->setEnabled(req->hasRole("orderrefund")); + m->addAction(tr("Pay with &Voucher..."),this,SLOT(payvoucher())) + ->setEnabled(req->hasRole("usevoucher")); + + m=mb->addMenu(tr("P&rinting")); + //FIXME: m->setEnabled(o.isStored()); + m->addAction(tr("Print &Bill..."),this,SLOT(printBill())); + m->addAction(tr("Save Bill &as file..."),this,SLOT(saveBill())); + m->addSeparator(); + m->addAction(tr("Print &Tickets..."),this,SLOT(printTickets())); + m->addAction(tr("Print V&ouchers..."),this,SLOT(printVouchers())); + m->addAction(tr("Print &Current Item..."),this,SLOT(printCurrentItem())); + m->addAction(tr("&View Items..."),this,SLOT(itemView())); + + QWidget*w; + setCentralWidget(w=new QWidget); + QVBoxLayout *vl; + w->setLayout(vl=new QVBoxLayout); + + QGridLayout*gl; + vl->addLayout(gl=new QGridLayout,0); + int rw=0; + QLabel*lab; + gl->addWidget(new QLabel(tr("Order ID:")),rw,0); + gl->addWidget(m_orderid=new QLabel(QString::number(m_order.orderid())),rw,1); + gl->addWidget(new QLabel(tr("Order Date:")),++rw,0); + gl->addWidget(m_orderdate=new QLabel(m_order.orderDateTimeStr()),rw,1); + gl->addWidget(new QLabel(tr("Shipping Date:")),++rw,0); + gl->addWidget(m_sentdate=new QLabel(m_order.sentDateTimeStr()),rw,1); + gl->addWidget(new QLabel(tr("Customer:")),++rw,0); + gl->addWidget(new QLabel(m_order.customer().address()),rw,1); + gl->addWidget(new QLabel(tr("Delivery Address:")),++rw,0); + //FIXME:gl->addWidget(lab=new QLabel(m_order.deliveryAddress()),rw,1); + //lab->setWordWrap(true); + gl->addWidget(new QLabel(tr("Sold by:")),++rw,0); + gl->addWidget(new QLabel(m_order.seller()),rw,1); + gl->addWidget(new QLabel(tr("Total Price:")),++rw,0); + gl->addWidget(m_total=new QLabel(m_order.totalPriceString()),rw,1); + gl->addWidget(new QLabel(tr("Already Paid:")),++rw,0); + gl->addWidget(m_paid=new QLabel(m_order.amountPaidString()),rw,1); + gl->addWidget(new QLabel(tr("Order State:")),++rw,0); + gl->addWidget(m_state=new QLabel(m_order.orderStatusString()),rw,1); + gl->addWidget(new QLabel(tr("Shipping Method:")),++rw,0); + //FIXME: + gl->addWidget(m_shipmeth=new QLabel(/*m_order.shipping().description()*/"ship?"),rw,1); + gl->addWidget(new QLabel(tr("Shipping Costs:")),++rw,0); + gl->addWidget(m_shipprice=new QLabel(/*m_order.shipping().priceString()*/),rw,1); + gl->addWidget(new QLabel(tr("Order Comment:")),++rw,0); + //FIXME: + gl->addWidget(m_comment=lab=new QLabel(/*m_order.comment()*/"comment?"),rw,1); + lab->setWordWrap(true); + gl->setColumnStretch(0,0); + gl->setColumnStretch(1,10); + + QSize sz=size(); + + vl->addSpacing(10); + vl->addWidget(m_table=new QTableView,10); + m_table->setModel(m_model=new QStandardItemModel(this)); + m_table->setEditTriggers(QAbstractItemView::NoEditTriggers); + updateTable(); + //make sure everything is visible + QSize vsz=m_table->maximumViewportSize(); + vsz.setWidth(vsz.width()+40); + if(sz.width()dataDir(); +} + +static const int ITEM_TICKET=1; +static const int ITEM_VOUCHER=2; + +void MOrderWindow::updateTable() +{/*TODO: + QList tickets=m_order.tickets(); + QList events; + if(tickets.size()>0) + events=req->getAllEvents(); + QList vouchers=m_order.vouchers(); + m_model->clear(); + m_model->setHorizontalHeaderLabels(QStringList()<insertRows(0,tickets.size()+vouchers.size()); + for(int i=0;isetData(m_model->index(i,0),tickets[i].ticketID()); + m_model->setData(m_model->index(i,0),ITEM_TICKET,Qt::UserRole); + m_model->setData(m_model->index(i,3),tickets[i].statusString()); + m_model->setData(m_model->index(i,4),tickets[i].priceString()); + //find event + MEvent ev;int eid=tickets[i].eventID(); + for(int j=0;jsetData(m_model->index(i,1),ev.title()); + m_model->setData(m_model->index(i,2),ev.startTimeString()); + } + int off=tickets.size(); + for(int i=0;isetData(m_model->index(i+off,0),ITEM_VOUCHER,Qt::UserRole); + m_model->setData(m_model->index(i+off,0),vouchers[i].voucherID()); + m_model->setData(m_model->index(i+off,1),tr("Voucher (current value: %1)").arg(vouchers[i].valueString())); + m_model->setData(m_model->index(i+off,3),vouchers[i].statusString()); + m_model->setData(m_model->index(i+off,4),vouchers[i].priceString()); + } + m_table->resizeColumnsToContents();*/ +} + +void MOrderWindow::setChanged() +{ + m_changed=true; +} + +bool MOrderWindow::isChanged()const +{ + return m_changed; +} + +void MOrderWindow::itemView() +{ + QListtickets=m_order.tickets(); + QListvouchers=m_order.vouchers(); + if(tickets.size()<1 && vouchers.size()<1)return; + MOrderItemView tv(this,tickets,vouchers); + tv.exec(); +} + +void MOrderWindow::printCurrentItem() +{ + //get current ticketid/voucherid + QModelIndexList lst=m_table->selectionModel()->selectedIndexes(); + if(lst.size()<1)return; + QModelIndex idx=m_model->index(lst[0].row(),0); + QString id=m_model->data(idx).toString(); + if(id=="")return; + int type=m_model->data(idx,Qt::UserRole).toInt(); + //find ticket/voucher + if(type==ITEM_TICKET){ + QListticks; + QListtickets=m_order.tickets(); + for(int i=0;ivouchs; + QListvouchers=m_order.vouchers(); + for(int i=0;i ticketsin) +{/*TODO + //reduce ticket list to usable ones + QList tickets; + for(int i=0;igetTemplate("ticket"); + if(!tf.isValid()){ + QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (ticket.xtt). Giving up.")); + return; + } + //get printer settings + QPrinter printer; + restorePrinter(printer,"ticket"); + QPrintDialog pd(&printer,this); + if(pd.exec()!=QDialog::Accepted)return; + storePrinter(printer,"ticket"); + //label arrangement + MTicketRenderer render(tf); + MLabelDialog ld(this,&printer,tickets.size(),render.labelSize(printer)); + if(ld.exec()!=QDialog::Accepted) + return; + //print + QPainter painter(&printer); + for(int i=0;i vouchersin) +{/*TODO + //reduce voucher list to usable ones + QListvouchers; + for(int i=0;i0 && vouchersin[i].xmlState()=="") + vouchers.append(vouchersin[i]); + } + //sanity check + if(vouchers.size()<1){ + QMessageBox::warning(this,tr("Warning"),tr("There are no vouchers left to print.")); + return; + } + //get template + MTemplate tf=req->getTemplate("voucher"); + if(!tf.isValid()){ + QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (voucher.xtt). Giving up.")); + return; + } + //get printer settings + QPrinter printer; + restorePrinter(printer,"voucher"); + QPrintDialog pd(&printer,this); + if(pd.exec()!=QDialog::Accepted)return; + storePrinter(printer,"voucher"); + //label arrangement + MVoucherRenderer render(tf); + MLabelDialog ld(this,&printer,vouchers.size(),render.labelSize(printer)); + if(ld.exec()!=QDialog::Accepted) + return; + //print + QPainter painter(&printer); + for(int i=0;isettingsGroup()+"/"+key); + if(!set.contains("name"))return; + prn.setPrinterName(set.value("name").toString()); + prn.setPrinterSelectionOption(set.value("soption","").toString()); + prn.setPaperSize(QPrinter::PageSize(set.value("paper",QPrinter::Custom).toInt())); + prn.setPaperSize(set.value("papersize").toSizeF(),QPrinter::Point); + qreal ml,mr,mt,mb; + ml=set.value("marginLeft").toDouble(); + mr=set.value("marginRight").toDouble(); + mb=set.value("marginBottom").toDouble(); + mt=set.value("marginTop").toDouble(); + prn.setPageMargins(ml,mr,mb,mt,QPrinter::Point); + prn.setDuplex(QPrinter::DuplexMode(set.value("duplex",QPrinter::DuplexAuto).toInt())); + prn.setOrientation((set.value("orientation","portrait").toString()=="portrait")?QPrinter::Portrait:QPrinter::Landscape); + prn.setResolution(set.value("resolution").toInt()); +#endif +} + +void MOrderWindow::storePrinter(QPrinter&prn,QString key) +{ + QSettings set; + set.beginGroup(req->settingsGroup()+"/"+key); + set.setValue("name",prn.printerName()); +#if !defined(Q_OS_WIN32) && !defined(Q_OS_WINCE) + set.setValue("soption",prn.printerSelectionOption()); +#endif + qreal ml,mr,mt,mb; + prn.getPageMargins(&ml,&mr,&mb,&mt,QPrinter::Point); + set.setValue("marginLeft",ml); + set.setValue("marginRight",mr); + set.setValue("marginBottom",mb); + set.setValue("marginTop",mt); + set.setValue("duplex",(int)prn.duplex()); + set.setValue("orientation",prn.orientation()==QPrinter::Portrait?"portrait":"landscape"); + set.setValue("paper",(int)prn.paperSize()); + set.setValue("papersize",prn.paperSize(QPrinter::Point)); + set.setValue("resolution",prn.resolution()); +} + +void MOrderWindow::printBill() +{/*TODO + //get template + MTemplate tf=req->getTemplate("bill"); + if(!tf.isValid()){ + QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (bill). Giving up.")); + return; + } + //mark order as shipped? + if(m_order.orderStatus()==MOrder::Placed) + if(QMessageBox::question(this,tr("Mark as shipped?"),tr("Mark this order as shipped now?"),QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes)==QMessageBox::Yes){ + m_order.shipOrder(); + m_state->setText(m_order.orderStatusString()); + m_sentdate->setText(m_order.sentDateTimeStr()); + } + //print bill + initPrintBuffer(); + MOdtSignalRenderer rend(tf); + connect(&rend,SIGNAL(getVariable(QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getVariable(QString,MOdtRenderer::VarType&,QVariant&))); + connect(&rend,SIGNAL(getLoopIterations(QString,int&)),this,SLOT(getLoopIterations(QString,int&))); + connect(&rend,SIGNAL(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&))); + rend.renderToPrinter(); + donePrintBuffer();*/ +} + +void MOrderWindow::saveBill() +{/*TODO + //get template + MTemplate tf=req->getTemplate("bill"); + if(!tf.isValid()){ + QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (bill). Giving up.")); + return; + } + //get target file name + QFileDialog fd(this); + fd.setAcceptMode(QFileDialog::AcceptSave); + fd.setFileMode(QFileDialog::AnyFile); + fd.setConfirmOverwrite(true); + fd.setFilter(tr("Open Document File (*.%1)").arg(tf.targetExtension())); + fd.setDefaultSuffix(tf.targetExtension()); + QString fname; + if(fd.exec()){ + QStringList fn=fd.selectedFiles(); + if(fn.size()<1)return; + fname=fn[0]; + } + //mark order as shipped? + if(m_order.orderStatus()==MOrder::Placed) + if(QMessageBox::question(this,tr("Mark as shipped?"),tr("Mark this order as shipped now?"),QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes)==QMessageBox::Yes){ + m_order.shipOrder(); + m_state->setText(m_order.orderStatusString()); + m_sentdate->setText(m_order.sentDateTimeStr()); + } + //render bill + initPrintBuffer(); + MOdtSignalRenderer rend(tf); + connect(&rend,SIGNAL(getVariable(QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getVariable(QString,MOdtRenderer::VarType&,QVariant&))); + connect(&rend,SIGNAL(getLoopIterations(QString,int&)),this,SLOT(getLoopIterations(QString,int&))); + connect(&rend,SIGNAL(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&))); + rend.renderToFile(fname); + donePrintBuffer();*/ +} + +void MOrderWindow::getVariable(QString vn,MOdtRenderer::VarType& av,QVariant&value) +{/*TODO + if(vn=="ORDERDATE"){ + value=m_order.orderDateTime().toTime_t(); + av=MOdtRenderer::DateVar; + }else + if(vn=="ORDERDATETIME"){ + value=m_order.orderDateTime().toTime_t(); + av=MOdtRenderer::DateTimeVar; + }else + if(vn=="SENTDATE"){ + value=m_order.sentDateTime().toTime_t(); + av=MOdtRenderer::DateVar; + }else + if(vn=="SENTDATETIME"){ + value=m_order.sentDateTime().toTime_t(); + av=MOdtRenderer::DateTimeVar; + }else + if(vn=="CUSTOMERID")value=QString::number(m_order.customerID());else + if(vn=="ORDERID")value=QString::number(m_order.orderID());else + if(vn=="ADDRESS")value=m_order.customer().address();else + if(vn=="FULLADDRESS")value=m_order.customer().getNameAddress();else + if(vn=="NAME")value=m_order.customer().name();else + if(vn=="DELIVERYADDRESS")value=m_order.deliveryAddress();else + if(vn=="FINALADDRESS"){ + QString v=m_order.deliveryAddress(); + if(v.trimmed()=="")v=m_order.customer().getNameAddress(); + value=v; + }else + if(vn=="TOTALPRICE"){ + value=m_order.totalPrice(); + av=MOdtRenderer::MoneyVar; + }else + if(vn=="AMOUNTPAID"){ + value=m_order.amountPaid(); + av=MOdtRenderer::MoneyVar; + }else + if(vn=="SELLER")value=m_order.seller();else + if(vn=="COMMENT")value=m_order.comment();else + if(vn=="AMOUNTTOPAY"){ + value=m_order.amountToPay(); + av=MOdtRenderer::MoneyVar; + }else + if(vn=="AMOUNTTOREFUND"){ + value=m_order.amountToRefund(); + av=MOdtRenderer::MoneyVar; + }else + if(vn=="TICKETS"){ + value=printBuffer.tickets.size(); + av=MOdtRenderer::IntVar; + }else + if(vn=="ACCTICKETS"){ + value=printBuffer.tickinfo.size(); + av=MOdtRenderer::IntVar; + }else + if(vn=="VOUCHERS"){ + value=printBuffer.vouchers.size(); + av=MOdtRenderer::IntVar; + }else + if(vn=="ADDRESSLINES"){ + value=m_order.customer().address().split("\n").size(); + av=MOdtRenderer::IntVar; + }else + if(vn=="SHIPPING")value=m_order.shipping().description();else + if(vn=="SHIPPINGPRICE"){ + value=m_order.shipping().price(); + av=MOdtRenderer::MoneyVar; + }*/ +} + +void MOrderWindow::getLoopIterations(QString loopname,int&iterations) +{ + if(loopname=="TICKETS")iterations=printBuffer.tickets.size(); + if(loopname=="ACCTICKETS")iterations=printBuffer.tickinfo.size(); + if(loopname=="VOUCHERS")iterations=printBuffer.vouchers.size(); + if(loopname=="ADDRESSLINES")iterations=m_order.customer().address().split("\n").size(); +} +void MOrderWindow::getLoopVariable(QString loopname,int it,QString vn,MOdtRenderer::VarType& av,QVariant&value) +{ + if(loopname=="TICKETS"){ + QList &tickets=printBuffer.tickets; + if(it<0 || it>=tickets.size())return; + + if(vn=="PRICE"){ + value=tickets[it].price().value(); + av=MOdtRenderer::MoneyVar; + }else + if(vn=="ID")value=tickets[it].ticketid().value();else + if(vn=="TITLE")value=tickets[it].event().title().value();else + if(vn=="ARTIST")value=tickets[it].event().artist().value().name().value();else + if(vn=="DATE"){ + value=tickets[it].event().start().value(); + av=MOdtRenderer::DateVar; + }else + if(vn=="STARTTIME"){ + value=tickets[it].event().start().value(); + av=MOdtRenderer::DateTimeVar; + }else + if(vn=="ENDTIME"){ + value=tickets[it].event().end().value(); + av=MOdtRenderer::DateTimeVar; + }else + if(vn=="ROOM")value=tickets[it].event().room().value(); + }else if(loopname=="ACCTICKETS"){ + QList &tickets=printBuffer.tickinfo; + if(it<0 || it>=tickets.size())return; + + if(vn=="PRICE"){ + value=tickets[it].proto.price().value(); + av=MOdtRenderer::MoneyVar; + }else + if(vn=="FULLPRICE"){ + value=tickets[it].proto.price().value()*tickets[it].amount; + av=MOdtRenderer::MoneyVar; + }else + if(vn=="TITLE")value=tickets[it].proto.event().title().value();else + if(vn=="ARTIST")value=tickets[it].proto.event().artist().value().name().value();else + if(vn=="DATE"){ + value=tickets[it].proto.event().start().value(); + av=MOdtRenderer::DateVar; + }else + if(vn=="STARTTIME"){ + value=tickets[it].proto.event().start().value(); + av=MOdtRenderer::DateTimeVar; + }else + if(vn=="ENDTIME"){ + value=tickets[it].proto.event().end().value(); + av=MOdtRenderer::DateTimeVar; + }else + if(vn=="ROOM")value=tickets[it].proto.event().room().value();else + if(vn=="AMOUNT"){ + value=tickets[it].amount; + av=MOdtRenderer::IntVar; + } + }else if(loopname=="VOUCHERS"){ + if(it<0 || it>=printBuffer.vouchers.size())return; + + if(vn=="PRICE"){ + value=printBuffer.vouchers[it].price().value(); + av=MOdtRenderer::MoneyVar; + }else + if(vn=="VALUE"){ + value=printBuffer.vouchers[it].value().value(); + av=MOdtRenderer::MoneyVar; + }else + if(vn=="ID")value=printBuffer.vouchers[it].voucherid().value(); + }else if(loopname=="ADDRESSLINES"){ + QStringList lst=m_order.customer().address().split("\n"); + if(it<0 || it>=lst.size())return; + value=lst[it]; + }else + return /*empty handed*/; +} + +void MOrderWindow::donePrintBuffer() +{ + printBuffer.tickets.clear(); + printBuffer.vouchers.clear(); + printBuffer.tickinfo.clear(); +} + +static inline bool compare(const MTicket&a,const MTicket&b) +{ + if(a.eventid()!=b.eventid())return false; + if(a.price()!=b.price())return false; + return true; +} + +void MOrderWindow::initPrintBuffer() +{/*TODO: + //clear + donePrintBuffer(); + //get tickets (only valid ones) + QListtlst=m_order.tickets(); + for(int i=0;ivlst=m_order.vouchers(); + for(int i=0;irequest("orderpay",rq)){ + QMessageBox::warning(this,tr("Warning"),tr("Unable to submit payment request.")); + return; + } + if(req->responseStatus()!=MWebRequest::Ok){ + QMessageBox::warning(this,tr("Warning"),tr("Error while trying to pay: %1").arg(qApp->translate("php::",req->responseBody()))); + return; + } + m_order.setAmountPaid(req->responseBody().trimmed().toInt()); + m_paid->setText(m_order.amountPaidString());*/ +} + +void MOrderWindow::payvoucher() +{/*TODO + if(!m_order.isValid())return; + //get voucher + bool ok; + QString vid=QInputDialog::getText(this,tr("Enter Voucher"),tr("Please enter the ID of the voucher you want to use:"),QLineEdit::Normal,"",&ok); + if(!ok)return; + if(vid=="")return; + MVoucher vou(req,vid); + if(!vou.isValid()){ + QMessageBox::warning(this,tr("Warning"),tr("This voucher is not valid.")); + return; + } + //submit + QByteArray rq=vid.toAscii()+"\n"+QByteArray::number(m_order.orderID()); + if(!req->request("usevoucher",rq)){ + QMessageBox::warning(this,tr("Warning"),tr("Unable to submit payment request.")); + return; + } + if(req->responseStatus()!=MWebRequest::Ok){ + QMessageBox::warning(this,tr("Warning"),tr("Error while trying to pay: %1").arg(qApp->translate("php::",req->responseBody()))); + return; + } + QStringList sl=QString::fromAscii(req->responseBody().trimmed()).split("\n"); + if(sl.size()>1){ + m_order.setAmountPaid(sl[1].toInt()); + m_paid->setText(m_order.amountPaidString()); + } + if(sl.size()>0){ + QMessageBox::information(this,tr("Voucher Info"),tr("Remaining value of this voucher: %1").arg(cent2str(sl[0].toInt()))); + }*/ +} + +void MOrderWindow::refund() +{/*TODO + if(!m_order.isValid())return; + //get value + bool ok; + int pay=MCentDialog::getCents(this,tr("Enter Refund"),tr("Please enter the amount that will be refunded:"),m_order.amountToRefund(),m_order.amountToRefund(),&ok); + if(!ok)return; + if(pay<=0)return; + //submit + QByteArray rq=QByteArray::number(m_order.orderID())+" "+QByteArray::number(pay); + if(!req->request("orderrefund",rq)){ + QMessageBox::warning(this,tr("Warning"),tr("Unable to submit refund request.")); + return; + } + if(req->responseStatus()!=MWebRequest::Ok){ + QMessageBox::warning(this,tr("Warning"),tr("Error whily trying to refund: %1").arg(qApp->translate("php::",req->responseBody()))); + return; + } + m_order.setAmountPaid(req->responseBody().trimmed().toInt()); + m_paid->setText(m_order.amountPaidString());*/ +} + +void MOrderWindow::changeItem() +{/*TODO + if(!m_order.isValid())return; + //get ticket selection + QModelIndexList lst=m_table->selectionModel()->selectedIndexes(); + if(lst.size()<1)return; + QModelIndex idx=m_model->index(lst[0].row(),0); + QString id=m_model->data(idx).toString(); + if(id=="")return; + int type=m_model->data(idx,Qt::UserRole).toInt(); + if(type==ITEM_TICKET){ + //find ticket + QListtickets=m_order.tickets(); + MTicket tick; + for(int i=0;isetText(m_order.totalPriceString()); + updateTable();*/ +} + +void MOrderWindow::itemReturn() +{/*TODO + if(!m_order.isValid())return; + //get ticket selection + QModelIndexList lst=m_table->selectionModel()->selectedIndexes(); + if(lst.size()<1)return; + QModelIndex idx=m_model->index(lst[0].row(),0); + QString id=m_model->data(idx).toString(); + if(id=="")return; + int type=m_model->data(idx,Qt::UserRole).toInt(); + if(type==ITEM_TICKET){ + //find ticket + QListtickets=m_order.tickets(); + MTicket tick; + for(int i=0;isetText(m_order.totalPriceString()); + updateTable(); + if(r!="")QMessageBox::warning(this,tr("Warning"),trUtf8(r.toUtf8())); + }else + if(type==ITEM_VOUCHER){ + //find ticket + QListvouchers=m_order.vouchers(); + MVoucher vou; + for(int i=0;isetText(m_order.totalPriceString()); + updateTable(); + if(r!="")QMessageBox::warning(this,tr("Warning"),trUtf8(r.toUtf8())); + }else + QMessageBox::warning(this,tr("Warning"),tr("Cannot return this item type."));*/ +} + +void MOrderWindow::cancelOrder() +{/*TODO + if(QMessageBox::question(this,tr("Cancel Order?"),tr("Cancel this order now?"),QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes)!=QMessageBox::Yes)return; + if(m_order.orderStatus()!=MOrder::Placed && m_order.orderStatus()!=MOrder::Reserved){ + QMessageBox::warning(this,tr("Warning"),tr("Cannot cancel this order: it is in the wrong state.")); + return; + } + if(!m_order.cancelOrder()){ + QMessageBox::warning(this,tr("Warning"),tr("Failed to cancel this order.")); + }else + m_state->setText(m_order.orderStatusString());*/ +} + +void MOrderWindow::createOrder(Create mode) +{/*TODO + MOrder ord; + //handle reservation changes specially + if(m_order.orderStatus()==MOrder::Reserved){ + bool ok=false; + ord=m_order; + switch(mode){ + case CreateOrder:ok=ord.reservationToOrder();break; + case CreateSale:ok=ord.reservationToSale();break; + default:ok=false; + } + if(!ok)return; + }else{ + //handle case of new order + switch(mode){ + case CreateSale:ord=m_order.createSale();break; + case CreateOrder:ord=m_order.createOrder();break; + case CreateReservation:ord=m_order.createReservation();break; + } + if(!ord.isValid())return; + } + //display final order + MOrderWindow *ow=new MOrderWindow(parentWidget(),req,ord); + ow->show(); + //undisplay self + close();*/ +} + +void MOrderWindow::createSale() +{ + createOrder(CreateSale); +} + +void MOrderWindow::createReservation() +{ + createOrder(CreateReservation); +} + +void MOrderWindow::recheckOrder() +{/*TODO + //prune + m_order.pruneInvalid(); + //now check + MOrder ord; + ord=m_order.createOrder("checkorder"); + if(!ord.isValid())return; + //display final order + MOrderWindow *ow=new MOrderWindow(parentWidget(),req,ord); + ow->show(); + //undisplay self + close();*/ +} + +void MOrderWindow::shipOrder() +{/*TODO + if(QMessageBox::question(this,tr("Mark as shipped?"),tr("Mark this order as shipped now?"),QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes)==QMessageBox::Yes){ + QDateTime tm=QDateTime::currentDateTime(); + if(req->hasRole("_explicitshipdate")){ + QDialog d; + d.setWindowTitle(tr("Set shipping time")); + QHBoxLayout*hl; + QVBoxLayout*vl; + QPushButton*p; + QDateTimeEdit*dte; + d.setLayout(vl=new QVBoxLayout); + vl->addWidget(new QLabel(tr("Enter the shipping time:"))); + vl->addWidget(dte=new QDateTimeEdit(tm)); + vl->addSpacing(10); + vl->addStretch(10); + vl->addLayout(hl=new QHBoxLayout); + hl->addStretch(10); + 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; + tm=dte->dateTime(); + } + m_order.shipOrder(tm); + m_state->setText(m_order.orderStatusString()); + m_sentdate->setText(m_order.sentDateTimeStr()); + }*/ +} + +void MOrderWindow::changeComment() +{/*TODO + //create editor dialog + QString cmt=m_order.comment(); + QDialog d; + d.setWindowTitle(tr("Set comment: order %1").arg(m_order.orderID())); + QVBoxLayout*vl; + d.setLayout(vl=new QVBoxLayout); + QTextEdit*te; + vl->addWidget(te=new QTextEdit,1); + te->setPlainText(cmt); + vl->addSpacing(15); + QHBoxLayout*hl; + vl->addLayout(hl=new QHBoxLayout,0); + hl->addStretch(10); + QPushButton*p; + hl->addWidget(p=new QPushButton(tr("&Save"))); + connect(p,SIGNAL(clicked()),&d,SLOT(accept())); + hl->addWidget(p=new QPushButton(tr("&Cancel"))); + connect(p,SIGNAL(clicked()),&d,SLOT(reject())); + //get status + if(d.exec()!=QDialog::Accepted)return; + //send to server + m_order.sendComment(cmt=te->toPlainText()); + //reset display + m_comment->setText(cmt);*/ +} + +void MOrderWindow::changeShipping() +{/*TODO + //create editor dialog + MShippingChange d(this,req,m_order.shipping()); + //get status + if(d.exec()!=QDialog::Accepted)return; + //send to server + m_order.sendShipping(d.selection()); + //reset display + m_shipmeth->setText(m_order.shipping().description()); + m_shipprice->setText(m_order.shipping().priceString()); + m_total->setText(m_order.totalPriceString());*/ +} + +void MOrderWindow::moneyLogOrder() +{ + if(m_order.orderid()<0)return; + MMoneyLog ml(this,"order\n"+QString::number(m_order.orderid())); + ml.exec(); +} + +void MOrderWindow::moneyLogVoucher() +{ + if(m_order.orderid()<0)return; + //get selection + if(!m_order.isValid())return; + //get ticket selection + QModelIndexList lst=m_table->selectionModel()->selectedIndexes(); + if(lst.size()<1)return; + QModelIndex idx=m_model->index(lst[0].row(),0); + QString id=m_model->data(idx).toString(); + if(id=="")return; + int type=m_model->data(idx,Qt::UserRole).toInt(); + if(type==ITEM_VOUCHER){ + MMoneyLog ml(this,"voucher\n"+id); + ml.exec(); + }else + QMessageBox::warning(this,tr("Warning"),tr("This is not a voucher, cannot show the money log.")); +} + + +/*************************************************************************************/ + +MOrderItemView::MOrderItemView(QWidget*w,QListt,QListv) + :QDialog(w),tickets(t),vouchers(v) +{ + setWindowTitle(tr("Preview Tickets")); + + QVBoxLayout*vl; + setLayout(vl=new QVBoxLayout); + QComboBox *cb; + vl->addWidget(cb=new QComboBox,0); + cb->setEditable(false); + for(int i=0;iaddItem(tr("Ticket: ")+tickets[i].ticketid()); + for(int i=0;iaddItem(tr("Voucher: ")+vouchers[i].voucherid()); + vl->addWidget(disp=new QLabel,10); + //get the templates + /*TODO + trender=new MTicketRenderer(req->getTemplate("ticket")); + vrender=new MVoucherRenderer(req->getTemplate("voucher")); + */ + changeItem(0); + connect(cb,SIGNAL(currentIndexChanged(int)),this,SLOT(changeItem(int))); +} + +MOrderItemView::~MOrderItemView() +{ + //FIXME + //delete trender; + //delete vrender; +} + +void MOrderItemView::changeItem(int idx) +{/*TODO + //ticket or voucher? + if(idxlabelSize(*disp); + QPixmap tick(sz.toSize()); + tick.fill(); + if(!trender->render(tickets[idx],tick)) + qDebug("unable to render"); + disp->setPixmap(tick); + }else{ + QSizeF sz=vrender->labelSize(*disp); + QPixmap tick(sz.toSize()); + tick.fill(); + if(!vrender->render(vouchers[idx-tickets.size()],tick)) + qDebug("unable to render"); + disp->setPixmap(tick); + }*/ +} + + +/*************************************************************************************/ + +MShippingChange::MShippingChange(QWidget*pa,MOShipping s) + :QDialog(pa) +{ + all=req->queryGetAllShipping().getshipping(); + setWindowTitle(tr("Change Shipping Method")); + + int cid=-1; + //FIXME: + //if(s.isValid())cid=s.id(); + + QGridLayout*gl; + setLayout(gl=new QGridLayout); + gl->addWidget(new QLabel(tr("Method:")),0,0); + gl->addWidget(opt=new QComboBox,0,1); + gl->addWidget(new QLabel(tr("Price:")),1,0); + gl->addWidget(prc=new MCentSpinBox,1,1); + gl->setRowMinimumHeight(2,15); + gl->setRowStretch(2,1); + QHBoxLayout*hl; + 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()),this,SLOT(accept())); + hl->addWidget(p=new QPushButton(tr("Cancel"))); + connect(p,SIGNAL(clicked()),this,SLOT(reject())); + + prc->setRange(0,1000000000);//hmm, even in Yen this should be big enough + prc->setValue(s.cost()); + prc->setEnabled(req->hasRole("orderchangeshipping")); + + opt->addItem(tr("(None)","shipping method")); + int scid=0; + for(int i=0;iaddItem(all[i].description()); + if(all[i].id().value()==cid) + scid=i+1; + } + opt->setCurrentIndex(scid); + connect(opt,SIGNAL(currentIndexChanged(int)),this,SLOT(changeItem(int))); +} + +MOShipping MShippingChange::selection()const +{ + int cid=opt->currentIndex(); + if(cid==0)return MOShipping(); + MOShipping cp=all[cid-1]; + cp.setcost(price()); + return cp; +} + +int MShippingChange::price()const +{ + return prc->value(); +} + +void MShippingChange::changeItem(int cid) +{ + if(cid==0)prc->setValue(0); + else prc->setValue(all[cid-1].cost()); +} diff --git a/src/dialogs/orderwin.h b/src/dialogs/orderwin.h new file mode 100644 index 0000000..dd902ed --- /dev/null +++ b/src/dialogs/orderwin.h @@ -0,0 +1,187 @@ +// +// C++ Interface: orderwin +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_ORDERWIN_H +#define MAGICSMOKE_ORDERWIN_H + +#include +#include "order.h" +#include "odtrender.h" +#include "MOShipping.h" + +class QLabel; +class QTableView; +class QStandardItemModel; + +/**displays an order and allows the user to execute several commands on it*/ +class MOrderWindow:public QMainWindow +{ + Q_OBJECT + public: + /**creates the order window*/ + MOrderWindow(QWidget*,const MOrder&); + + /**returns whether the order has been changed by this window*/ + bool isChanged()const; + + private: + /**helper enum for create* methods*/ + enum Create{CreateOrder,CreateSale,CreateReservation}; + + private slots: + /**internal: mark order as changed*/ + void setChanged(); + + /**internal: updates the ticket table*/ + void updateTable(); + + /**internal: show the tickets as graphics*/ + void itemView(); + /**internal: print the currently selected ticket*/ + void printCurrentItem(); + /**internal: print all tickets*/ + void printTickets(); + /**internal helper: print list of tickets*/ + void printTickets(QList); + /**internal: print all vouchers*/ + void printVouchers(); + /**internal helper: print list of vouchers*/ + void printVouchers(QList); + + /**print a bill*/ + void printBill(); + /**save the bill as file*/ + void saveBill(); + /**callback for bill generator: variables; see MOdtSignalRenderer for details*/ + void getVariable(QString,MOdtRenderer::VarType&,QVariant&); + /**callback for bill generator: loops; see MOdtSignalRenderer for details*/ + void getLoopIterations(QString loopname,int&iterations); + /**callback for bill generator: loop variables; see MOdtSignalRenderer for details*/ + void getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&); + + /**received payment*/ + void payment(); + /**generate a refund*/ + void refund(); + /**pay with a voucher*/ + void payvoucher(); + + /**change a ticket/voucher price*/ + void changeItem(); + /**return a ticket/voucher*/ + void itemReturn(); + + /**change the comment on the order*/ + void changeComment(); + + /**change the shipping option*/ + void changeShipping(); + + /**cancel the order*/ + void cancelOrder(); + /**mark as shipped*/ + void shipOrder(); + + /**create a new order*/ + void createOrder(Create mode=CreateOrder); + + /**create a sale*/ + void createSale(); + + /**create a new reservation*/ + void createReservation(); + + /**prune and recheck the order*/ + void recheckOrder(); + + /**money log for the order*/ + void moneyLogOrder(); + /**money log for a voucher*/ + void moneyLogVoucher(); + + private: + MOrder m_order; + bool m_changed; + QLabel *m_orderid,*m_orderdate,*m_sentdate,*m_state,*m_paid,*m_total,*m_comment, + *m_shipmeth,*m_shipprice; + QTableView *m_table; + QStandardItemModel *m_model; + + //printing buffer + struct TickInfo{ + TickInfo(const MTicket&t):proto(t){amount=1;} + TickInfo(const TickInfo&t):proto(t.proto){amount=t.amount;} + TickInfo(){amount=0;} + MTicket proto; + int amount; + }; + struct PrintBuffer{ + QList tickets; + QList vouchers; + QList tickinfo; + }printBuffer; + void initPrintBuffer(); + void donePrintBuffer(); + + //helper: fetches printer settings from registry + void restorePrinter(QPrinter&,QString); + //helper: stores printer settings in registry + void storePrinter(QPrinter&,QString); +}; + +class MTicketRenderer; +class MVoucherRenderer; + +/**helper class: displays tickets and vouchers*/ +class MOrderItemView:public QDialog +{ + Q_OBJECT + public: + MOrderItemView(QWidget*,QList,QList); + ~MOrderItemView(); + + private slots: + void changeItem(int); + private: + QList tickets; + QList vouchers; + QLabel*disp; + MTicketRenderer*trender; + MVoucherRenderer*vrender; +}; + +class MCentSpinBox; +class QComboBox; + +/**helper class: allows to change the shipping option*/ +class MShippingChange:public QDialog +{ + Q_OBJECT + public: + /**creates the dialog*/ + MShippingChange(QWidget*,MOShipping); + + /**returns the selected shipping option, including corrected price*/ + MOShipping selection()const; + /**returns the entered price in cent*/ + int price()const; + + private slots: + /**internal: updates price when new option is selected*/ + void changeItem(int); + private: + QList all; + QComboBox*opt; + MCentSpinBox*prc; +}; + +#endif diff --git a/src/domquery.cpp b/src/domquery.cpp deleted file mode 100644 index 056fc2d..0000000 --- a/src/domquery.cpp +++ /dev/null @@ -1,145 +0,0 @@ -// -// C++ Implementation: domquery -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2009 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "domquery.h" - - -MDomQuery::MDomQuery(const QDomDocument&start,QString path) -{ - construct(start.documentElement(),path); -} - -MDomQuery::MDomQuery(const QDomElement&start,QString path) -{ - construct(start,path); -} - -void MDomQuery::construct(const QDomElement&start,QString path) -{ - //split query - QStringList ql=path.split("/",QString::SkipEmptyParts); - //determine start mode and initialize list - MDomNodeList ndlst; - if(path.startsWith("//")){ - QDomDocument doc=start.ownerDocument(); - if(ql.size()<1){ - qDebug("MDomQuery: // query must not be empty!"); - return; - } - if(ql[0]=="*" || ql[0]=="@*"){ - qDebug("MDomQuery: // query must not start with wildcard * or @*."); - return; - } - if(ql[0].startsWith("@")){ - qDebug("MDomQuery: cannot start with attributes in a // query."); - return; - }else{ - ndlst=doc.elementsByTagName(ql[0]); - ql.removeFirst(); - } - }else - if(path.startsWith("/")){ - QDomElement root=start.ownerDocument().documentElement(); - if(ql.size()<1){ - //hmm, guess what the user really wanted (assume "/ *" ) - m_result<0){ - MDomNodeList lst2; - //parse pattern - if(ql[0].startsWith("@")){ - //attribute handling... - if(ql.size()>1){ - qDebug("MDomQuery: cannot sub-parse attributes."); - return; - } - if(ql[0]=="@*"){ - //get all attributes of all current elements - for(int i=0;i, (C) 2009 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_DOMQUERY_H -#define MAGICSMOKE_DOMQUERY_H - - -#include -#include -#include - -/**Helper class: more flexible version of QDomNodeList*/ -class MDomNodeList:public QList -{ - public: - MDomNodeList(){} - MDomNodeList(const MDomNodeList&l):QList(l){} - MDomNodeList(const QList&l):QList(l){} - MDomNodeList(const QDomNodeList&l){for(int i=0;i -mousereturn all child elements of the current element that are called "mouse" -\@mousereturn all attribute nodes of the current element that are called "mouse" -*returns all child elements of the current element -\@*returns all attributes of the current element -/*returns the root element of the document irrespective of name -/mousereturns the root element of the document if it has the tag name "mouse" or an empty list -/*/mousereturns all elements directly below the root element that are called "mouse" -//mousereturns all elements in the document that are called "mouse" -mouse/\@trap/doorsyntax error, attributes cannot have children - -*/ -class MDomQuery -{ - public: - /**creates the query object and executes the query*/ - MDomQuery(const QDomElement&start,QString path); - - /**creates the query object and executes the query; this is equivalent to calling the query with the document element as starting point*/ - MDomQuery(const QDomDocument&start,QString path); - - /**returns the search result as a single string, if there were multiple matches, they are separated by spaces*/ - QString toString()const; - /**returns the search result as a list of strings, one string element per match*/ - QStringList toStringList()const; - /**returns the result as a list of DOM nodes*/ - MDomNodeList toNodeList()const{return m_result;} - - /**cast to QString: see toString()*/ - operator QString()const{return toString();} - /**cast to QStringList: see toStringList()*/ - operator QStringList()const{return toStringList();} - /**cast to DOM node list: see toNodeList()*/ - operator MDomNodeList()const{return m_result;} - private: - MDomNodeList m_result; - - //helper for constructor - void construct(const QDomElement&start,QString path); -}; - -#endif diff --git a/src/eventedit.cpp b/src/eventedit.cpp deleted file mode 100644 index 2b73b75..0000000 --- a/src/eventedit.cpp +++ /dev/null @@ -1,207 +0,0 @@ -// -// C++ Implementation: eventedit -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2007 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "eventedit.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define req (MSInterface::instance()) - -MEventEditor::MEventEditor(QWidget*w,qint64 id) - :QDialog(w) -{ - MTGetEvent ge=MTGetEvent::query(id); - if(ge.stage()!=ge.Success){ - QMessageBox::warning(this,tr("Warning"),tr("Unable to load event from server.")); - //make myself disappear immediately - QTimer::singleShot(1,this,SLOT(reject())); - //no point in setting up widgets - return; - } - event=ge.getevent().value(); - setWindowTitle(tr("Event Editor")); - - QGridLayout*gl; - QVBoxLayout*vl; - QHBoxLayout*hl; - QPushButton*p; - int lctr=0; - QLabel*lab; - - setLayout(vl=new QVBoxLayout); - vl->addLayout(gl=new QGridLayout); - - gl->addWidget(lab=new QLabel(tr("ID:")),lctr,0); - lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); - gl->addWidget(eventid=new QLabel,lctr,1); - eventid->setText(QString::number(event.id())); - - gl->addWidget(lab=new QLabel(tr("Title:")),++lctr,0); - lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); - gl->addWidget(title=new QLineEdit,lctr,1); - title->setText(event.title()); - - gl->addWidget(lab=new QLabel(tr("Artist:")),++lctr,0); - lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); - gl->addWidget(artist=new QLineEdit,lctr,1); - artist->setText(event.artist().value().name()); - - gl->addWidget(lab=new QLabel(tr("Description:")),++lctr,0); - lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); - gl->addWidget(description=new QTextEdit,lctr,1); - description->setPlainText(event.description()); - - gl->addWidget(lab=new QLabel(tr("Start Time:")),++lctr,0); - lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); - gl->addWidget(starttime=new QDateTimeEdit,lctr,1); - starttime->setDisplayFormat(tr("ddd MMMM d yyyy, h:mm ap","time format")); - starttime->setCalendarPopup(true); - starttime->setDateTime(QDateTime::fromTime_t(event.start())); - connect(starttime,SIGNAL(dateTimeChanged(const QDateTime&)),this,SLOT(startTimeChanged(const QDateTime&))); - - gl->addWidget(lab=new QLabel(tr("End Time:")),++lctr,0); - lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); - gl->addWidget(endtime=new QDateTimeEdit,lctr,1); - endtime->setDisplayFormat(tr("ddd MMMM d yyyy, h:mm ap","time format")); - endtime->setCalendarPopup(true); - endtime->setDateTime(QDateTime::fromTime_t(event.end())); - connect(endtime,SIGNAL(dateTimeChanged(const QDateTime&)),this,SLOT(endTimeChanged(const QDateTime&))); - - gl->addWidget(lab=new QLabel(tr("Room/Place:")),++lctr,0); - lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); - gl->addLayout(hl=new QHBoxLayout,lctr,1); - hl->addWidget(room=new QLineEdit,10); - room->setReadOnly(true); - room->setText(event.room()); - hl->addWidget(p=new QPushButton("..."),0); - connect(p,SIGNAL(clicked()),this,SLOT(selectRoom())); - - gl->addWidget(lab=new QLabel(tr("Capacity:")),++lctr,0); - lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); - gl->addWidget(capacity=new QSpinBox,lctr,1); - capacity->setRange(0,1000000000);//it is unlikely that any show will attract more people! - capacity->setValue(event.capacity()); - - gl->addWidget(lab=new QLabel(tr("Default Price:")),++lctr,0); - lab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); - gl->addWidget(price=new QLineEdit,lctr,1); - price->setValidator(new QRegExpValidator(event.priceRegExp(),this)); - price->setText(event.priceString()); - - gl->addWidget(cancelcheck=new QCheckBox(tr("Event Cancelled:")),++lctr,0); - cancelcheck->setChecked(event.iscancelled()); - cancelcheck->setEnabled(false); - gl->addWidget(cancelreason=new QLineEdit,lctr,1); - cancelreason->setEnabled(event.iscancelled()); - cancelreason->setText(event.cancelreason()); - connect(cancelcheck,SIGNAL(toggled(bool)),cancelreason,SLOT(setEnabled(bool))); - - vl->addStretch(); - - vl->addLayout(hl=new QHBoxLayout,0); - hl->addStretch(); - hl->addWidget(p=new QPushButton(tr("Save"))); -// connect(p,SIGNAL(clicked()),this,SLOT(accept())); - connect(p,SIGNAL(clicked()),this,SLOT(writeBack())); - hl->addWidget(p=new QPushButton(tr("Cancel"))); - connect(p,SIGNAL(clicked()),this,SLOT(reject())); -} - -void MEventEditor::writeBack() -{ - //copy contents to event - event.settitle(title->text()); - event.setstart(starttime->dateTime().toTime_t()); - event.setend(endtime->dateTime().toTime_t()); -// event.setartist(artist->text()); - event.setroom(room->text()); - event.setdefaultprice(price->text()); - event.setiscancelled(cancelcheck->isChecked()); - event.setcancelreason(cancelreason->text()); - event.setdescription(description->toPlainText()); - event.setcapacity(capacity->value()); - //send to server - /*TODO - event.makeValid(); - QString r=event.save(); - if(r!=""){ - QMessageBox::warning(this,tr("Warning"),tr("Problem while uploading event: %s").arg(r)); - }else - accept();*/ -} - -void MEventEditor::selectRoom() -{ - QListrlst=req->queryGetAllRooms().getrooms(); - QDialog d; - d.setWindowTitle(tr("Select a Room")); - QVBoxLayout*vl; - d.setLayout(vl=new QVBoxLayout); - QListWidget*rlstw; - vl->addWidget(rlstw=new QListWidget,10); - for(int i=0;iaddItem(rlst[i].id()); - QHBoxLayout*hl; - vl->addLayout(hl=new QHBoxLayout,0); - hl->addStretch(10); - QPushButton*p; - hl->addWidget(p=new QPushButton(tr("New...","new room")),0); - connect(p,SIGNAL(clicked()),this,SLOT(newRoom())); - connect(p,SIGNAL(clicked()),&d,SLOT(reject())); - hl->addWidget(p=new QPushButton(tr("Select","select room")),0); - connect(p,SIGNAL(clicked()),&d,SLOT(accept())); - hl->addWidget(p=new QPushButton(tr("Cancel")),0); - connect(p,SIGNAL(clicked()),&d,SLOT(reject())); - if(d.exec()==QDialog::Rejected)return; - //get selection - QListwlst=rlstw->selectedItems(); - if(wlst.size()<1)return; - room->setText(wlst[0]->text()); -} - -void MEventEditor::newRoom() -{/*TODO - QString rid=QInputDialog::getText(this,tr("New Room"),tr("Name of new room:")); - if(rid!=""){ - MRoom rm(req,rid); - rm.makeValid(); - rm.save(); - room->setText(rid); - }*/ -} - -void MEventEditor::startTimeChanged(const QDateTime&st) -{ - QDateTime et=endtime->dateTime(); - if(etsetDateTime(st); -} - -void MEventEditor::endTimeChanged(const QDateTime&et) -{ - QDateTime st=starttime->dateTime(); - if(st>et)starttime->setDateTime(et); -} diff --git a/src/eventedit.h b/src/eventedit.h deleted file mode 100644 index bd183a7..0000000 --- a/src/eventedit.h +++ /dev/null @@ -1,51 +0,0 @@ -// -// C++ Interface: eventedit -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2007 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef SMOKE_EVENT_EDIT_H -#define SMOKE_EVENT_EDIT_H - -#include - -#include "event.h" - -class QCheckBox; -class QDateTime; -class QDateTimeEdit; -class QLabel; -class QLineEdit; -class QSpinBox; -class QTextEdit; - -class MEventEditor:public QDialog -{ - Q_OBJECT - public: - MEventEditor(QWidget*,qint64 id=-1); - private slots: - void writeBack(); - void selectRoom(); - void newRoom(); - - void startTimeChanged(const QDateTime&); - void endTimeChanged(const QDateTime&); - private: - MEvent event; - QDateTimeEdit*starttime,*endtime; - QLineEdit*title,*artist,*room,*price,*cancelreason; - QTextEdit*description; - QCheckBox*cancelcheck; - QSpinBox*capacity; - QLabel*eventid; -}; - - -#endif diff --git a/src/eventsummary.cpp b/src/eventsummary.cpp deleted file mode 100644 index 70caf5a..0000000 --- a/src/eventsummary.cpp +++ /dev/null @@ -1,382 +0,0 @@ -// -// C++ Implementation: eventsummary -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "eventsummary.h" -#include "misc.h" -#include "odtrender.h" -#include "msinterface.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define req (MSInterface::instance()) - -MEventSummary::MEventSummary(QWidget*par,qint64 eid) - :QDialog(par),event(eid) -{ - nreserved=ncancelled=ntotaltickets=ntotalmoney=0; - //get event data - getSummaryData(); - //layout/tabs - setWindowTitle(tr("Summary for Event %1").arg(event.title())); - QVBoxLayout*vl; - setLayout(vl=new QVBoxLayout); - QTabWidget*tab; - vl->addWidget(tab=new QTabWidget); - QWidget*w; - tab->addTab(w=new QWidget,tr("Summary")); - QGridLayout*gl; - w->setLayout(gl=new QGridLayout); - int rc=0; - gl->addWidget(new QLabel(tr("Title:")),rc,0); - gl->addWidget(new QLabel(event.title()),rc,1); - gl->addWidget(new QLabel(tr("Artist:")),++rc,0); - gl->addWidget(new QLabel(event.artist().value().name()),rc,1); - gl->addWidget(new QLabel(tr("Start:")),++rc,0); - gl->addWidget(new QLabel(event.startTimeString()),rc,1); - gl->addWidget(new QLabel(tr("Capacity:")),++rc,0); - gl->addWidget(new QLabel(QString::number(event.capacity())),rc,1); - gl->addWidget(new QLabel(tr("Tickets currently reserved:")),++rc,0); - gl->addWidget(new QLabel(QString::number(nreserved)),rc,1); - gl->addWidget(new QLabel(tr("Tickets currently cancelled:")),++rc,0); - gl->addWidget(new QLabel(QString::number(ncancelled)),rc,1); - gl->addWidget(new QLabel(tr("Tickets currently usable:")),++rc,0); - gl->addWidget(new QLabel(QString::number(ntotaltickets)),rc,1); - gl->addWidget(new QLabel(tr("Total Income:")),++rc,0); - gl->addWidget(new QLabel(cent2str(ntotalmoney)),rc,1); - - QTableView*table; - QStandardItemModel*model; - tab->addTab(table=new QTableView,tr("Tickets")); - table->setEditTriggers(QAbstractItemView::NoEditTriggers); - table->setModel(model=new QStandardItemModel(this)); - model->insertColumns(0,4); - model->insertRows(0,tickets.size()); - model->setHorizontalHeaderLabels(QStringList()<setData(model->index(i,0),cent2str(tc.price)); - model->setData(model->index(i,1),tc.bought); - model->setData(model->index(i,2),tc.used); - model->setData(model->index(i,3),tc.unused); - } - table->resizeColumnsToContents(); - - QTextBrowser *tb; - tab->addTab(tb=new QTextBrowser,tr("Comments")); - QString cmt; - for(int i=0;i"; - else cmt+="
"; - cmt+=""+tr("Order: "); - cmt+=QString::number(c.orderid); - cmt+="
"+tr("Customer: ")+htmlize(c.custname); - cmt+="

"+htmlize(c.comment); - } - tb->setHtml(cmt); - - QHBoxLayout*hl; - vl->addSpacing(15); - vl->addLayout(hl=new QHBoxLayout,0); - hl->addStretch(10); - QPushButton*p; - hl->addWidget(p=new QPushButton(tr("Print")),0); - connect(p,SIGNAL(clicked()),this,SLOT(print())); - hl->addWidget(p=new QPushButton(tr("Save as...")),0); - connect(p,SIGNAL(clicked()),this,SLOT(saveas())); - hl->addSpacing(15); - hl->addWidget(p=new QPushButton(tr("Close")),0); - connect(p,SIGNAL(clicked()),this,SLOT(accept())); -} - -MEventSummary::~MEventSummary(){} - -void MEventSummary::getOrderData() -{ - if(orderids.size()==orders.size())return; - for(int i=0;irequest("eventsummary",QString::number(event.eventId()).toAscii()))return; - if(req->responseStatus()!=MWebRequest::Ok)return; - QDomDocument doc; - if(!doc.setContent(req->responseBody()))return; - QDomElement sum=doc.documentElement(); - nreserved=sum.attribute("reserved","0").toInt(); - ncancelled=sum.attribute("cancelled","0").toInt(); - ntotaltickets=sum.attribute("totaltickets","0").toInt(); - ntotalmoney=sum.attribute("totalmoney","0").toInt(); - QDomNodeList nl=sum.elementsByTagName("Tickets"); - for(int i=0;igetTemplate("eventsummary"); - if(!tf.isValid()){ - QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (eventsummary). Giving up.")); - return; - } - MOdtSignalRenderer rend(tf); - connect(&rend,SIGNAL(getVariable(QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getVariable(QString,MOdtRenderer::VarType&,QVariant&))); - connect(&rend,SIGNAL(getLoopIterations(QString,int&)),this,SLOT(getLoopIterations(QString,int&))); - connect(&rend,SIGNAL(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&))); - rend.renderToPrinter();*/ -} - -void MEventSummary::saveas() -{/*TODO: - MTemplate tf=req->getTemplate("eventsummary"); - if(!tf.isValid()){ - QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (eventsummary). Giving up.")); - return; - } - QFileDialog fd(this); - fd.setAcceptMode(QFileDialog::AcceptSave); - fd.setFileMode(QFileDialog::AnyFile); - fd.setConfirmOverwrite(true); - fd.setFilter(tr("Open Document File (*.%1)").arg(tf.targetExtension())); - fd.setDefaultSuffix(tf.targetExtension()); - QString fname; - if(fd.exec()){ - QStringList fn=fd.selectedFiles(); - if(fn.size()<1)return; - fname=fn[0]; - } - MOdtSignalRenderer rend(tf); - connect(&rend,SIGNAL(getVariable(QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getVariable(QString,MOdtRenderer::VarType&,QVariant&))); - connect(&rend,SIGNAL(getLoopIterations(QString,int&)),this,SLOT(getLoopIterations(QString,int&))); - connect(&rend,SIGNAL(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&))); - rend.renderToFile(fname);*/ -} - -void MEventSummary::getVariable(QString varname,MOdtRenderer::VarType&av,QVariant&value) -{ - if(varname=="TITLE") - value=event.title().value(); - else - if(varname=="ARTIST") - value=event.artist().value().name().value(); - else - if(varname=="ROOM") - value=event.room().value(); - else - if(varname=="START"){ - value=event.start().value(); - av=MOdtRenderer::DateTimeVar; - }else - if(varname=="CAPACITY"){ - value=event.capacity().value(); - av=MOdtRenderer::IntVar; - }else - if(varname=="RESERVED"){ - value=nreserved; - av=MOdtRenderer::IntVar; - }else - if(varname=="BOUGHT"){ - value=ntotaltickets; - av=MOdtRenderer::IntVar; - }else - if(varname=="USED"){ - int nused=0; - for(int i=0;i=tickets.size())return; - - if(varname=="PRICE"){ - value=tickets[iteration].price; - av=MOdtRenderer::MoneyVar; - }else - if(varname=="BOUGHT"){ - value=tickets[iteration].bought; - av=MOdtRenderer::IntVar; - }else - if(varname=="USED"){ - value=tickets[iteration].used; - av=MOdtRenderer::IntVar; - }else - if(varname=="UNUSED"){ - value=tickets[iteration].unused; - av=MOdtRenderer::IntVar; - } - }else - if(loopname=="COMMENTS"){ - if(iteration<0 || iteration>=comments.size())return; - - if(varname=="ORDERID")value=QString::number(comments[iteration].orderid);else - if(varname=="CUSTOMERID")value=QString::number(comments[iteration].custid);else - if(varname=="CUSTOMER")value=comments[iteration].custname;else - if(varname=="TEXT")value=comments[iteration].comment; - }else - if(loopname=="ORDERS"){ - if(iteration<0 || iteration>=orderids.size())return; - //make sure data is here - getOrderData(); - //get order id - int oid=orderids[iteration]; - - if(varname=="ORDERID"){ - value=QString::number(oid); - return; - } - - //paranoia check - if(!orders.contains(oid))return; - - if(varname=="CUSTOMERID")value=QString::number(orders[oid].orderid());else - if(varname=="CUSTOMER")value=orders[oid].customer().name().value();else - if(varname=="FULLPRICE"){ - value=orders[oid].totalprice().value(); - av=MOdtRenderer::MoneyVar; - }/*TODO: else - if(varname=="SHIPPING")value=orders[oid].shipping().description();else - if(varname=="SHIPPINGCOST"){ - value=orders[oid].shipping().price(); - av=MOdtRenderer::MoneyVar; - }else{ - QListticks=orders[oid].tickets(); - QListeticks; - int first,last; - first=last=event.startTime(); - int eid=event.eventId(); - for(int i=0;i, (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_EVENTSUMMARY_H -#define MAGICSMOKE_EVENTSUMMARY_H - -#include -#include - -#include "order.h" -#include "odtrender.h" - -class QTableView; -class QStandardItemModel; -class QLabel; - -/**shows a summary for the event*/ -class MEventSummary:public QDialog -{ - Q_OBJECT - public: - /**creates a new summary dialog, requests data from server*/ - MEventSummary(QWidget*parent,qint64 eventid); - /**deletes MEventSummary*/ - ~MEventSummary(); - - private slots: - /**internal: print summary*/ - void print(); - /**internal: save summary to file*/ - void saveas(); - - //used for ODT rendering: - void getVariable(QString,MOdtRenderer::VarType&,QVariant&); - void getLoopIterations(QString,int&); - void getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&); - - private: - int eventid; - MEvent event; - int nreserved,ncancelled,ntotaltickets,ntotalmoney; - struct Tickets{ - int price,bought,used,unused; - }; - QListtickets; - struct Comment{ - int custid,orderid; - QString custname,comment; - }; - QListcomments; - QListorderids; - QMaporders; - - //get summary - void getSummaryData(); - //helper: get order details - void getOrderData(); -}; - -#endif diff --git a/src/files.qrc b/src/files.qrc deleted file mode 100644 index 4462340..0000000 --- a/src/files.qrc +++ /dev/null @@ -1,9 +0,0 @@ - - - - icon.png - arrowright.png - arrowdown.png - arrowdiag.png - - diff --git a/src/hmac.cpp b/src/hmac.cpp deleted file mode 100644 index d6b8138..0000000 --- a/src/hmac.cpp +++ /dev/null @@ -1,102 +0,0 @@ -// -// C++ Implementation: hmac -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2007 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "hmac.h" -#include - -SMHmac::SMHmac(QCryptographicHash::Algorithm algo,const QByteArray&key) - :subhashin(algo),subhashout(algo),state(Collecting) -{ - //calculate key schedules - QByteArray k2=key; - int hlen=blockWidth(algo); - if(k2.size()>hlen){ - //hash the key if it is too long - k2=QCryptographicHash::hash(k2,algo); - }else - if(k2.size(), (C) 2007 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef SMOKE_HMAC_H -#define SMOKE_HMAC_H - -#include - -/**Calculate a cryptographic HMAC (used by authentication algorithm)*/ -class SMHmac -{ - public: - /**constructs an object that calculates HMACs*/ - SMHmac(QCryptographicHash::Algorithm algo,const QByteArray&key); - /**adds length bytes of data to the hash-stream*/ - void addData(const char * data, int length ); - /**adds data to the hash-stream*/ - void addData(const QByteArray & data ); - /**reset the hash to the state immediately after construction*/ - void reset(); - /**finalize the hash and return the result*/ - QByteArray result(); - - /**returns the length of the results of given algorithm in bytes; this should have been implemented by QCryptographicHash! performs a test calculation if the algo is unknown*/ - static int resultWidth(QCryptographicHash::Algorithm); - /**returns the length of the blocks used internally in the given algorithm in bytes; this should have been implemented by QCryptographicHash! returns -1 if in doubt*/ - static int blockWidth(QCryptographicHash::Algorithm); - /**complete HMAC calculation in a can*/ - static QByteArray hmac(const QByteArray&data,const QByteArray&key,QCryptographicHash::Algorithm method); - private: - //the two key schedules - QByteArray keyA,keyB; - //remember where we are - enum State {Collecting,Finished}; - mutable State state; - //inner hash function - QCryptographicHash subhashin,subhashout; -}; - - -#endif diff --git a/src/host.cpp b/src/host.cpp deleted file mode 100644 index 601357a..0000000 --- a/src/host.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// -// C++ Implementation: host -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2007 -// -// Copyright: See COPYING file that comes with this distribution -// -// - -#include "host.h" -#include "keygen.h" -#include "msinterface.h" - -#include -#include - -#define req (MSInterface::instance()) - -MHost::MHost(QString n,QString k) -{ - setname(n); - setkey(k); -} - - -int MHost::newKey() -{ - int r=getEntropy(); - setkey(QString(getRandom(40).toHex())); - if(r<(40*8))return r; - else return 40*8; -} - -bool MHost::create() -{ - //do not attempt to save invalid or incomplete data - if(!isValid())return false; - MTSetHost ch=req->querySetHost(name(),key()); - //check success - return ch.stage()==ch.Success; -} - -bool MHost::save() -{ - //do not attempt to save invalid or incomplete data - if(!isValid())return false; - MTSetHost ch=req->querySetHost(name(),key()); - //check success - return ch.stage()==ch.Success; -} - -void MHost::deleteHost() -{ - if(!isValid())return; - req->queryDeleteHost(name()); -} diff --git a/src/host.h b/src/host.h deleted file mode 100644 index 9d3fc8e..0000000 --- a/src/host.h +++ /dev/null @@ -1,52 +0,0 @@ -// -// C++ Interface: host -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2007 -// -// Copyright: See COPYING file that comes with this distribution -// -// - -#ifndef MAGICSMOKE_HOST_H -#define MAGICSMOKE_HOST_H - -#include -#include - -/**this class wraps MOHost and adds some convenience methods*/ -class MHost:public MOHost -{ - public: - /**create invalid host*/ - MHost():MOHost(){} - /**create host by name*/ - MHost(QString,QString k=QString()); - /**copy host*/ - MHost(const MHost&h):MOHost(h){} - - /**returns host name*/ - QString hostId(){return name();} - - /**returns host key (fetches it from DB if not known yet)*/ - QString hostKey(){return key();} - - /**checks host name*/ - bool isValid(){return name().value()!="";} - - /**creates new host key for this host; returns number of entropy bits*/ - int newKey(); - - /**creates host in database; returns true on success*/ - bool create(); - - /**updates host key in database; returns true on success*/ - bool save(); - - /**deletes host from database*/ - void deleteHost(); -}; - -#endif diff --git a/src/icon.ico b/src/icon.ico deleted file mode 100644 index 773f47f191881a434d3a500539579fe9fc456ddb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9662 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 V@2(i%w>$pb{}=TC?f)4M{4e>FM&$qi diff --git a/src/icon.png b/src/icon.png deleted file mode 100644 index a5b3bbf74b2456e291c14d9c74e7620e662bb033..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5093 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

$RNE(9RrU>Q8# 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 YJ>ADx7Ot, (C) 2009 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "msinterface.h" +#include "main.h" +#include "sslexception.h" + +#include +#include +#include +#include +#include +#include + +MSInterface::MSInterface(QString pid) + :MInterface() +{ + profileid=pid; + QSettings set; + set.beginGroup("profiles/"+pid); + setUrl("https://"+set.value("serverurl","my.host.com/path/machine.php").toString()); + bool useproxy=set.value("useproxy",false).toBool(); + if(useproxy) + setProxy( + set.value("proxyname","proxy").toString(), + set.value("proxyport",74).toInt(), + set.value("proxyuser").toString(), + set.value("proxypass").toString() + ); + m_host=set.value("hostname").toString(); + m_hostkey=set.value("hostkey").toString(); + sslexcept=new MSslExceptions(dataDir()+"/sslexceptions.xml"); +} + +MSInterface::~MSInterface() +{ + logout(); + if(sslexcept)delete sslexcept; + sslexcept=0; +} + +bool MSInterface::login(QString username,QString passwd) +{ + m_uname=username;m_passwd=passwd; + MTLogin lg=MTLogin::query(username,passwd,m_host,m_hostkey); + if(lg.stage()==lg.Error) + QMessageBox::warning(0,tr("Warning"),tr("Login failed: %1").arg(tr(lg.errorString().toAscii()))); + else + setSessionId(lg.getsessionid()); + if(lg.stage()!=lg.Success)return false; + //get rights + MTGetMyRights mrt=MTGetMyRights::query(); + QStringList rsl=mrt.getright(); + for(int i=0;icommVersion()){ + QMessageBox::warning(0,tr("Error"),tr("This client is too old for the server, please upgrade.")); + return false; + } + //we are ok + return true; +} + +void MSInterface::logout() +{ + if(m_sessid!="")queryLogout(); + m_sessid=""; +} +bool MSInterface::relogin() +{ + logout(); + return login(m_uname,m_passwd); +} + +QMap MSInterface::headers(QString s)const +{ + QMap ret=WInterface::headers(s); + ret.insert("Wob-SessionId",m_sessid); + return ret; +} + +QString MSInterface::dataDir()const +{ + QString dd="profile."+profileid; + QDir dir(::dataDir); + if(!dir.exists(dd)) + if(!dir.mkpath(dd)) + qDebug("Warning: oh dir! Can't create my data directory!"); + return ::dataDir+"/"+dd; +} + +QString MSInterface::settingsGroup()const +{ + return "profsettings/"+profileid; +} + +QString MSInterface::repoPart() +{ + QStringList l=svnRepositoryUrl().split("/smoke/"); + if(l.size()>1)return l[1]; + else return svnRepositoryUrl(); +} + +bool MSInterface::hasRight(Right r)const +{ + if(userroles.contains("_admin"))return true; + return userrights.contains(r); +} + +void MSInterface::initialize() +{ + //retrieve translation file + if(servertranslation.size()==0){ //can be called only once, make sure it is so + QString lang=QSettings().value("lang","--").toString(); + if(lang=="--"){ + qDebug("MSInterface: no local language is set, so not retrieving any from server."); + goto script; + } + MTGetLanguage gl=MTGetLanguage::query(lang,"qm"); + if(gl.hasError()){ + qDebug("MSInterface: error while retrieving language %s from server: (%s) %s", + lang.toAscii().data(), + gl.errorType().toAscii().data(), + gl.errorString().toAscii().data()); + goto script; + } + servertranslation=gl.getfile().value(); + QTranslator *trn=new QTranslator(this); + trn->load((const uchar*)servertranslation.data(),servertranslation.size()); + qApp->installTranslator(trn); + qDebug("MSInterface: successfully loaded server language %s",lang.toAscii().data()); + } + //TODO: retrieve scripts + script: ; +} + +void MSInterface::sslErrors(const QList&errs) +{ + //get source of error + QHttp*src=qobject_cast(sender()); + if(!src)return; + //check against known exceptions + if(sslexcept->checksslexcept(errs)){ + src->ignoreSslErrors(); + return; + } + //message box + if(!didsslerror){ + QMessageBox::warning(0,tr("Connection Error"),tr("There were problems while authenticating the server. Aborting. Check your configuration.")); + } +} diff --git a/src/iface/msinterface.h b/src/iface/msinterface.h new file mode 100644 index 0000000..f4532a2 --- /dev/null +++ b/src/iface/msinterface.h @@ -0,0 +1,84 @@ +// +// C++ Interface: msinterface +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2009 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_MSINTERFACE_H +#define MAGICSMOKE_MSINTERFACE_H + +#include "MInterface.h" + +class MSslExceptions; + +/**the MagicSmoke specific interface class - enhances the basic interface by some functionality needed in the MagicSmoke context*/ +class MSInterface:public MInterface +{ + Q_OBJECT + public: + /**creates the interface object, expects the profile ID as parameter*/ + MSInterface(QString); + /**deletes the interface*/ + ~MSInterface(); + + /**returns the singleton instance of the interface*/ + static MSInterface* instance(){return qobject_cast(MInterface::instance());} + + /**returns the name of the current user*/ + QString currentUser()const{return m_uname;} + + /**returns whether the user is part of this role*/ + bool hasRole(QString)const{return false;} + + /**returns whether the user has a particular right*/ + bool hasRight(Right)const; + + /**returns the directory where to store data retrieved from the server*/ + QString dataDir()const; + /**returns the group in which to find settings in QSettings*/ + QString settingsGroup()const; + + /**checks the server for compatibility*/ + bool checkServer(); + + /**returns the current session ID*/ + QString sessionId()const{return m_sessid;} + + /**returns the branch/trunk part of the repository*/ + static QString repoPart(); + + /**returns default headers, ie. session ID*/ + virtual QMap headers(QString)const; + + /**initializes the interface, ie. retrieves language and scripts*/ + void initialize(); + + public slots: + /**logs into the server, returns true on success*/ + bool login(QString username,QString passwd); + /**logs out of the server*/ + void logout(); + /**refreshes the login*/ + bool relogin(); + /**sets the session id to be transmitted*/ + void setSessionId(QString sid){m_sessid=sid;} + /**handles SSL errors*/ + virtual void sslErrors(const QList&); + + private: + QString profileid,m_sessid,m_uname,m_passwd,m_host,m_hostkey; + mutable QListuserrights; + mutable QStringList userroles; + QByteArray servertranslation; + MSslExceptions*sslexcept; + bool didsslerror; +}; + + +#endif diff --git a/src/iface/sslexception.cpp b/src/iface/sslexception.cpp new file mode 100644 index 0000000..c060d0a --- /dev/null +++ b/src/iface/sslexception.cpp @@ -0,0 +1,108 @@ +// +// C++ Implementation: sslexception +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2009 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "sslexception.h" + +#include +#include +#include +#include +#include + +MSslExceptions::MSslExceptions(QString p) +{ + path=p; + //load... + QFile fd(p); + if(fd.open(QIODevice::ReadOnly)){ + QDomDocument doc; + if(!doc.setContent(&fd))return; + fd.close(); + QDomElement root=doc.documentElement(); + QDomNodeList nl=root.elementsByTagName("SSL-Exception"); + for(int i=0;i(c,e)); + } + } +} + +void MSslExceptions::savesslexcept() +{ + QDomDocument doc; + QDomElement root=doc.createElement("SSL-Exceptions"); + for(int i=0;i&errs) +{ + //stage 1: record unknown exceptions + for(int i=0;ip(errs[i].certificate(),errs[i].error()); + bool known=false; + for(int j=0;jp(errs[i].certificate(),errs[i].error()); + bool known=false; + for(int j=0;j, (C) 2009 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_SSLEXCEPTION_H +#define MAGICSMOKE_SSLEXCEPTION_H + +#include +#include +#include +#include +#include +#include +#include + +class QWidget; + +/**Helper class: stores and compares SSL-Exceptions*/ +class MSslExceptions +{ + public: + /**create instance from file in path*/ + MSslExceptions(QString path); + + /**saves the exceptions to config file for next session*/ + void savesslexcept(); + /**checks errors against the exception list, records all exceptions*/ + bool checksslexcept(const QList&); + + /**returns the current list of acceptable exceptions*/ + QList > nonFatalExceptions()const{return sslexcept;} + + /**returns the list of collected exceptions*/ + QList > collectedExceptions()const{return sslrecord;} + + /**clears the internal lists of exceptions*/ + void clear(); + + /**clears the list of recorded exceptions*/ + void clearRecorded(){sslrecord.clear();} + + /**accepts the recorded exceptions*/ + void acceptRecorded(); + + private: + QList > sslexcept,sslrecord; + QString path; +}; + +#endif diff --git a/src/images/arrowdiag.png b/src/images/arrowdiag.png new file mode 100644 index 0000000000000000000000000000000000000000..8844a7f1a4781d28a1897eef2908d762a221901e GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;TYyi9>;M1%fy~fDm+OEOV@Z%- zFoVOh8)+a;lDE4HLkFv@2av;A;1OBOz`!jG!i)^F=12eq*-JcqUDxPv<(Ka|uf7B*ZQ|+T7{YNqIiVmS!Q#My9}SH^ z8JT}Gv;E`e`6Ms##@^t{|AZg^n-BhDXZ|hE#-=bSk%5^ZdLQq~nF;$21NAd_y85}S Ib4q9e06Vxpp#T5? literal 0 HcmV?d00001 diff --git a/src/images/arrowdown.png b/src/images/arrowdown.png new file mode 100644 index 0000000000000000000000000000000000000000..683c465cea3449012360934c3b8cb835f206c424 GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;TYyi9>;M1%fy~fDm+OEOV@Z%- zFoVOh8)+a;lDE4HLkFv@2av;A;1OBOz`!jG!i)^F=12eq*-JcqUDQ2Tq8=H^K)}k^GXLfS6>2@R`PUl4B@z*oZ!Ip&0gY(eS^S% oW`QJo2B$N;3P(;bIPvf>?CxSel@RdwFHkjur>mdKI;Vst09HISvH$=8 literal 0 HcmV?d00001 diff --git a/src/images/arrowright.png b/src/images/arrowright.png new file mode 100644 index 0000000000000000000000000000000000000000..8a62bf75f78dd52d84586f9f1d1e8db84f275c70 GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;TYyi9>;M1%fy~fDm+OEOV@Z%- zFoVOh8)+a;lDE4HLkFv@2av;A;1OBOz`!jG!i)^F=12eq*-JcqUDxPv<(Ka|uf7B*t>)?C7{YNqIiZ1(kB!ZajqM*0 qvGe?~m-z9&@g%!~pxp)?pvhhBY%Z^IR!j%#VDNPHb6Mw<&;$SvaWxYF literal 0 HcmV?d00001 diff --git a/src/images/files.qrc b/src/images/files.qrc new file mode 100644 index 0000000..4462340 --- /dev/null +++ b/src/images/files.qrc @@ -0,0 +1,9 @@ + + + + icon.png + arrowright.png + arrowdown.png + arrowdiag.png + + diff --git a/src/images/icon.ico b/src/images/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..773f47f191881a434d3a500539579fe9fc456ddb GIT binary patch literal 9662 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 V@2(i%w>$pb{}=TC?f)4M{4e>FM&$qi literal 0 HcmV?d00001 diff --git a/src/images/icon.png b/src/images/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a5b3bbf74b2456e291c14d9c74e7620e662bb033 GIT binary patch literal 5093 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

$RNE(9RrU>Q8# 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 YJ>ADx7Ot, (C) 2007 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "keygen.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hmac.h" - -//enable linux to read /dev/random -#ifdef __linux__ -#include -#include -#endif - -//amount of random bits needed: -#define RANDNEED 160 - -static QPointerefilter; - -MKeyGen::MKeyGen(QWidget*parentw) - :QDialog(parentw) -{ - setWindowTitle(tr("Magic Smoke Key Generator")); - - //pre-init random buffer - randstat=-1; - connect(efilter,SIGNAL(moreBits()),this,SLOT(updateProps())); - //make sure all mouse events arrive - setMouseTracking(true); - QVBoxLayout*vl; - setLayout(vl=new QVBoxLayout); - QLabel*lab; - //main explanation - vl->addWidget(lab=new QLabel(tr("

Key Generation

\nI am currently collecting random bits in order to generate a host key for this installation. Please use mouse and keyboard to generate more random. Alternatively you can load a key from an external medium.

\nAt least %1 Bits of random are required.").arg(RANDNEED)),0); - lab->setWordWrap(true); - lab->setMouseTracking(true); - //buffer display - int e=efilter->entropy(); - vl->addWidget(randlab=new QLabel(tr("Current random buffer: %n Bits","",e)),0); - randlab->setMouseTracking(true); - randlab->setFrameShape(QFrame::Box); - randlab->setAutoFillBackground(true); - - vl->addStretch(1); - - //buttons - QHBoxLayout*hl; - vl->addLayout(hl=new QHBoxLayout,0); - hl->addStretch(1); - hl->addWidget(okbtn=new QPushButton(tr("&OK")),0); - connect(okbtn,SIGNAL(clicked()),this,SLOT(accept())); - hl->addWidget(ccbtn=new QPushButton(tr("&Cancel")),0); - connect(ccbtn,SIGNAL(clicked()),this,SLOT(reject())); - - //make sure widgets look right - updateProps(); - - //make window really big - showMaximized(); -} - -MKeyGen::~MKeyGen() -{ -} - -void MKeyGen::updateProps() -{ - int e=efilter->entropy(); - randlab->setText(tr("Current random buffer: %n Bits","",e)); - if(efilter->entropy()palette(); - pal.setColor(QPalette::Window,QColor("#ff8080")); - randlab->setPalette(pal); - //set button - okbtn->setEnabled(false); - }else{ - //check whether we need to set it - if(randstat==1)return; - randstat=1; - //set label color - QPalette pal=randlab->palette(); - pal.setColor(QPalette::Window,QColor("#80ff80")); - randlab->setPalette(pal); - //set button - okbtn->setEnabled(true); - } -} - -QString MKeyGen::getKey() -{ - if(efilter->entropy()getRandom(40).toHex(); -} - - -EFilter::EFilter() -{ - efilter=this; - randctr=0; - //preload seed - QSettings set; - randbuf.append(set.value("randomseed").toByteArray()); - randent=randbuf.size(); - if(randent>=RANDNEED)set.setValue("randomseed",getRandom(RANDNEED)); - //if Linux: try to pre-load some random -#ifdef __linux__ - int fd=::open("/dev/random",O_RDONLY|O_NONBLOCK); - if(fd>=0){ - char buf[RANDNEED/8]; - int rd=::read(fd,buf,sizeof(buf)); - if(rd>0){ - randbuf.append(QByteArray(buf,rd)); - randent+=rd*8; - } - ::close(fd); - } -#endif -} - -EFilter::~EFilter() -{ - QSettings set; - set.setValue("randomseed",getRandom(RANDNEED)); -} - -EFilter* EFilter::instance() -{ - return efilter; -} - -QByteArray EFilter::getRandom(int bytes) -{ - QByteArray ret; - while(ret.size()type()){ - case QEvent::KeyPress:case QEvent::KeyRelease: - { - QKeyEvent*ke=(QKeyEvent*)e; - addBit(ke->key()+(int)ke->modifiers()); - break; - } - case QEvent::MouseButtonPress:case QEvent::MouseButtonRelease: - case QEvent::MouseMove: - { - QMouseEvent*me=(QMouseEvent*)e; - addBit((int)me->buttons()+me->x()+me->y()); - break; - } - default: - //ignore - break; - } - return false; -} - -void EFilter::addBit(int b) -{ - //add bit to buffer - randbuf.append((b>>24)&0xff); - randbuf.append((b>>16)&0xff); - randbuf.append((b>>8)&0xff); - randbuf.append(b&0xff); - randent++; - //add time info as another bit - QTime ct=QTime::currentTime(); - if(ct.msec()!=0){ //don't use it if platform has no msecs - int t=ct.msec()+ct.second()+ct.minute(); - randbuf.append((t>>24)&0xff); - randbuf.append((t>>16)&0xff); - randbuf.append((t>>8)&0xff); - randbuf.append(t&0xff); - randent++; - } - //pack buffer if necessary (>10kB) - if(randbuf.size()>=10240){ - randbuf=getRandom(80); - if(randent>320)randent=320; - } - //update display - emit moreBits(); -} - -QByteArray getRandom(int num) -{ - if(efilter.isNull())return QByteArray(); - return efilter->getRandom(num); -} - -int getEntropy() -{ - if(efilter.isNull())return 0; - return efilter->entropy(); -} diff --git a/src/keygen.h b/src/keygen.h deleted file mode 100644 index f8d05fa..0000000 --- a/src/keygen.h +++ /dev/null @@ -1,66 +0,0 @@ -// -// C++ Interface: keygen -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2007 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_KEYGEN_H -#define MAGICSMOKE_KEYGEN_H - -#include -#include - -class QLabel; -class QPushButton; - -class MKeyGen:public QDialog -{ - Q_OBJECT - public: - MKeyGen(QWidget*parent=0); - ~MKeyGen(); - - QString getKey(); - - private: - QLabel*randlab; - int randstat; - - QPushButton *okbtn,*ccbtn; - - private slots: - void updateProps(); -}; - -class EFilter:public QObject -{ - Q_OBJECT - public: - EFilter(); - ~EFilter(); - - static EFilter*instance(); - - int entropy(); - QByteArray getRandom(int); - signals: - void moreBits(); - protected: - bool eventFilter(QObject*,QEvent*); - private: - QByteArray randbuf,randlast; - int randent,randctr; - void addBit(int); -}; - -//shortcut: -QByteArray getRandom(int); -int getEntropy(); - -#endif diff --git a/src/labeldlg.cpp b/src/labeldlg.cpp deleted file mode 100644 index 5eb12ab..0000000 --- a/src/labeldlg.cpp +++ /dev/null @@ -1,317 +0,0 @@ -// -// C++ Implementation: labeldlg -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "labeldlg.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ROWS 20 -#define COLS 20 - -MLabelDialog::MLabelDialog(QWidget*par,QPrinter* pn,int nl,QSizeF ls) - :QDialog(par) -{ - printer=pn; - numlabels=nl; - labelsize=ls; - maxrows=ROWS; - maxcols=COLS; - - setWindowTitle(tr("Label Printing Setup")); - - //get settings - QSettings set; - set.beginGroup("printer/"+printer->printerName()); - double ox=set.value("offsetx",0.0).toDouble(); - double oy=set.value("offsety",0.0).toDouble(); - double lsx=set.value("sizex",0.0).toDouble(); - double lsy=set.value("sizey",0.0).toDouble(); - QString mtrc=set.value("metric",tr("mm","defaultmetric: mm, in, cm")).toString(); - if(lsx==0.0 || lsy==0.0){ - //convert ticket template size - double dx=printer->logicalDpiX(); - double dy=printer->logicalDpiY(); - if(mtrc=="in"){ - lsx=ls.width()/dx; - lsy=ls.height()/dy; - }else - if(mtrc=="cm"){ - lsx=ls.width()/dx*2.54; - lsy=ls.height()/dy*2.54; - }else{//mm - lsx=ls.width()/dx*25.4; - lsy=ls.height()/dy*25.4; - } - } - - //display - - QVBoxLayout*vl; - QGridLayout*gl; - setLayout(vl=new QVBoxLayout); - vl->addLayout(gl=new QGridLayout,0); - - int ln=0; - gl->addWidget(new QLabel(tr("Label offset:")),ln,0); - gl->addWidget(offx=new QLineEdit(QString::number(ox)),ln,1); - offx->setValidator(new QDoubleValidator(0.0,1000.0,2,this)); - gl->addWidget(new QLabel("x"),ln,2); - gl->addWidget(offy=new QLineEdit(QString::number(oy)),ln,3); - offy->setValidator(new QDoubleValidator(0.0,1000.0,2,this)); - gl->addWidget(new QLabel(tr("Label size:")),++ln,0); - gl->addWidget(sizex=new QLineEdit(QString::number(lsx)),ln,1); - sizex->setValidator(new QDoubleValidator(0.0,1000.0,2,this)); - gl->addWidget(new QLabel("x"),ln,2); - gl->addWidget(sizey=new QLineEdit(QString::number(lsy)),ln,3); - sizey->setValidator(new QDoubleValidator(0.0,1000.0,2,this)); - gl->addWidget(new QLabel(tr("Unit:")),++ln,0); - gl->addWidget(metric=new QComboBox,ln,1,1,3); - metric->addItem(tr("Millimeter"),"mm"); - metric->addItem(tr("Centimeter"),"cm"); - metric->addItem(tr("Inch"),"in"); - gl->addWidget(warning=new QLabel(""),++ln,0,1,4); - QPalette pal=warning->palette(); - pal.setColor(QPalette::WindowText,Qt::red); - warning->setPalette(pal); - gl->setColumnStretch(++ln,10); - - vl->addSpacing(10); - vl->addWidget(new QLabel(tr("Page usage:")),0); - vl->addWidget(page=new QComboBox,0); - for(int i=0;iaddItem(tr("Page %1").arg(i+1),i); - oldpage=0; - - QScrollArea *sa; - QWidget*w=new QWidget; - vl->addWidget(sa=new QScrollArea,10); - w->setLayout(gl=new QGridLayout); - QToolButton*t; - gl->addWidget(t=new QToolButton,0,0); - t->setIcon(QIcon(":/arrowdiag.png")); - connect(t,SIGNAL(clicked()),this,SLOT(toggleAll())); - QSignalMapper *cmap=new QSignalMapper(this); - connect(cmap,SIGNAL(mapped(int)),this,SLOT(toggleColumn(int))); - for(int i=1;i<=COLS;i++){ - gl->addWidget(t=new QToolButton,0,i); - t->setIcon(QIcon(":/arrowdown.png")); - connect(t,SIGNAL(clicked()),cmap,SLOT(map())); - cmap->setMapping(t,i-1); - } - QSignalMapper *rmap=new QSignalMapper(this); - connect(rmap,SIGNAL(mapped(int)),this,SLOT(toggleRow(int))); - for(int i=1;i<=ROWS;i++){ - gl->addWidget(t=new QToolButton,i,0); - t->setIcon(QIcon(":/arrowright.png")); - connect(t,SIGNAL(clicked()),rmap,SLOT(map())); - rmap->setMapping(t,i-1); - for(int j=1;j<=COLS;j++){ - QCheckBox*b; - gl->addWidget(b=new QCheckBox,i,j); - checks.append(b); - connect(b,SIGNAL(clicked()),this,SLOT(savePage())); - } - } - sa->setWidget(w); - connect(page,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePage())); - connect(sizex,SIGNAL(textChanged(const QString&)),this,SLOT(updatePage())); - connect(sizey,SIGNAL(textChanged(const QString&)),this,SLOT(updatePage())); - connect(metric,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePage())); - - vl->addSpacing(15); - QHBoxLayout*hl; - vl->addLayout(hl=new QHBoxLayout); - hl->addStretch(10); - QPushButton*p; - hl->addWidget(p=new QPushButton(tr("Ok")),0); - connect(p,SIGNAL(clicked()),this,SLOT(accept())); - connect(p,SIGNAL(clicked()),this,SLOT(saveSettings())); - p->setDefault(true); - hl->addWidget(p=new QPushButton(tr("Cancel")),0); - connect(p,SIGNAL(clicked()),this,SLOT(reject())); - - //initialize - QListtpl; - for(int i=0;i<(ROWS*COLS);i++)tpl.append(true); - for(int i=0;i=0;r--) - for(int c=0;ctext().toDouble(); - double py=offy->text().toDouble(); - //add rows/cols - px+=col*sizex->text().toDouble(); - py+=row*sizey->text().toDouble(); - //correct to DPI - QString mtrc=metric->itemData(metric->currentIndex()).toString(); - if(mtrc=="in"){ - px*=printer->logicalDpiX(); - py*=printer->logicalDpiY(); - }else - if(mtrc=="cm"){ - px*=printer->logicalDpiX()/2.54; - py*=printer->logicalDpiY()/2.54; - }else{ - px*=printer->logicalDpiX()/25.4; - py*=printer->logicalDpiY()/25.4; - } - //return - return QPointF(px,py); -} - -bool MLabelDialog::labelNeedsPageTurn(int n) -{ - //find it - int pg,row=0,col=0; - pg=findLabel(n,row,col); - //page 0 needs no turn - if(pg<=0)return false; - //scan that page (all rows below label) - for(int r=maxrows-1;r>row;r--) - for(int c=0;csetChecked(checked[oldpage][i]); - } -} - -void MLabelDialog::toggleColumn(int c) -{ - for(int r=0;rsetChecked(checked[oldpage][i]); - } -} - -void MLabelDialog::toggleAll() -{ - for(int i=0;i<(ROWS*COLS);i++){ - checked[oldpage][i]^=true; - checks[i]->setChecked(checked[oldpage][i]); - } -} - -void MLabelDialog::savePage() -{ - for(int i=0;i<(ROWS*COLS);i++) - checked[oldpage][i]=checks[i]->isChecked(); -} - -void MLabelDialog::updatePage() -{ - //find how many rows/cols fit on the page - double lx=sizex->text().toDouble(); - double ly=sizey->text().toDouble(); - QRect pr=printer->pageRect(); - QString mtrc=metric->itemData(metric->currentIndex()).toString(); - if(mtrc=="in"){ - lx*=printer->logicalDpiX(); - ly*=printer->logicalDpiY(); - }else - if(mtrc=="cm"){ - lx*=printer->logicalDpiX()/2.54; - ly*=printer->logicalDpiY()/2.54; - }else{ - lx*=printer->logicalDpiX()/25.4; - ly*=printer->logicalDpiY()/25.4; - } - - bool dowarn=false; - if(ly>0.0){ - maxrows=pr.height()/ly; - if(maxrows>ROWS)maxrows=ROWS; - if(maxrows<1){ - maxrows=1; - dowarn=true; - } - }else maxrows=ROWS; - if(lx>0.0){ - maxcols=pr.width()/lx; - if(maxcols>COLS)maxcols=COLS; - if(maxcols<1){ - maxcols=1; - dowarn=true; - } - }else maxcols=COLS; - //update - oldpage=page->itemData(page->currentIndex()).toInt(); - for(int r=0;rsetChecked(b && checked[oldpage][i]); - checks[i]->setEnabled(b); - } - if(dowarn) - warning->setText(tr("Warning: the label may not fit on the page!")); - else - warning->setText(""); -} - -void MLabelDialog::saveSettings() -{ - QSettings set; - set.beginGroup("printer/"+printer->printerName()); - set.setValue("offsetx",offx->text().toDouble()); - set.setValue("offsety",offy->text().toDouble()); - set.setValue("sizex",sizex->text().toDouble()); - set.setValue("sizey",sizey->text().toDouble()); - set.setValue("metric",metric->itemData(metric->currentIndex()).toString()); -} diff --git a/src/labeldlg.h b/src/labeldlg.h deleted file mode 100644 index 2b22aae..0000000 --- a/src/labeldlg.h +++ /dev/null @@ -1,70 +0,0 @@ -// -// C++ Interface: labeldlg -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_LABELDLG_H -#define MAGICSMOKE_LABELDLG_H - -#include -#include -#include - -class QPaintDevice; -class QCheckBox; -class QComboBox; -class QLineEdit; -class QPrinter; -class QLabel; - -class MLabelDialog:public QDialog -{ - Q_OBJECT - public: - /**creates a label dialog*/ - MLabelDialog(QWidget*parent,QPrinter*printer,int numlabels,QSizeF labelsize); - /**deletes the label dialog and stores its current settings*/ - ~MLabelDialog(); - - /**returns the offset of label number n; relative to the coordinate system of the given paint device; starts at the bottom left of the page*/ - QPointF labelOffset(int n); - /**returns whether this label is on a new page*/ - bool labelNeedsPageTurn(int n); - - private slots: - /**internal: toggle Row button clicked*/ - void toggleRow(int); - /**internal: toggle Column button clicked*/ - void toggleColumn(int); - /**internal: toggle all button clicked*/ - void toggleAll(); - - /**internal: display correct page*/ - void updatePage(); - /**helper: save current/old page*/ - void savePage(); - /**internal: save settings for next time*/ - void saveSettings(); - - private: - QLineEdit *offx,*offy,*sizex,*sizey; - QLabel *warning; - QSizeF labelsize; - QComboBox *metric,*page; - QListchecks; - QList >checked; - QPrinter* printer; - int numlabels,oldpage,maxrows,maxcols; - - /**internal helper: find coordinates of label n; returns page id; returns -1 on failure*/ - int findLabel(int n,int&row,int&col); -}; - -#endif diff --git a/src/misc.cpp b/src/misc.cpp deleted file mode 100644 index 5e5fb79..0000000 --- a/src/misc.cpp +++ /dev/null @@ -1,114 +0,0 @@ -// -// C++ Implementation: misc -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "misc.h" - -#include -#include - -QString htmlize(QString str) -{ - QString out; - for(int i=0;i')out+=">";else - if(c=='&')out+="&";else - if(c=='\n')out+="
\n";else - if(c.isSpace()||(c.unicode()>=32&&c.unicode()<=0x7f))out+=c; - else out+="&#"+QString::number(ci)+";"; - } - return out; -} - -QString xmlize(QString str,QString newline) -{ - QString out; - for(int i=0;i')out+=">";else - if(c=='&')out+="&";else - if(c=='\n')out+=newline;else - if(c.isSpace()||(c.unicode()>=32&&c.unicode()<=0x7f))out+=c; - else out+="&#"+QString::number(ci)+";"; - } - return out; -} -QString cent2str(int c,bool localize) -{ - QString ret; - if(localize)ret=QCoreApplication::translate("misc","%1.%2","price with decimal dot"); - else ret="%1.%2"; - return ret.arg(c/100).arg(c%100,2,10,QChar('0')); -} - -int str2cent(QString s,bool localize) -{ - //convert local decimal dot by international decimal dot - if(localize)s=s.replace(QCoreApplication::translate("misc",".","decimal dot in price"),"."); - //calculate price - //pp->price part euro/dollar/...; pc->price part cent; pm=multiplier for cent; md->mode - int pp=0,pc=0,pm=10,md=0; - for(int i=0;i before the dot - pp*=10; - pp+=c.digitValue(); - }else{//mode==1 -> after the dot - pc+=c.digitValue()*pm; - if(pm==1)break; - pm=1; - } - }else - if(c=='.')md=1;//reached the dot, switch mode - //ignore everything else - } - //return result - return pp*100+pc; -} - -QRegExp priceRegExp(bool localize) -{ - if(localize) - return QRegExp(QCoreApplication::translate("misc","[0-9]+\\.[0-9]{2}","regexp for price")); - else - return QRegExp("[0-9]+\\.[0-9]{2}"); -} - -QString unix2date(int tm,bool localize) -{ - QString format; - if(localize)format=QCoreApplication::translate("misc","yyyy-MM-dd","localized date format"); - else format="yyyy-MM-dd"; - return QDateTime::fromTime_t(tm).toString(format); -} - -QString unix2time(int tm,bool localize) -{ - QString format; - if(localize)format=QCoreApplication::translate("misc","hh:mm","localized time format"); - else format="hh:mm"; - return QDateTime::fromTime_t(tm).toString(format); -} - -QString unix2dateTime(int tm,bool localize) -{ - QString format; - if(localize)format=QCoreApplication::translate("misc","yyyy-MM-dd hh:mm","localized date + time format"); - else format="yyyy-MM-dd hh:mm"; - return QDateTime::fromTime_t(tm).toString(format); -} - diff --git a/src/misc.h b/src/misc.h deleted file mode 100644 index 6d9766f..0000000 --- a/src/misc.h +++ /dev/null @@ -1,43 +0,0 @@ -// -// C++ Interface: misc -// -// Description: miscellaneous helper functions -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_MISC_H -#define MAGICSMOKE_MISC_H - -#include -#include - -/**converts special HTML characters into harmless &-codes, so the text can be included*/ -QString htmlize(QString str); - -/**converts special XML characters into harmless &-codes, so the text can be included*/ -QString xmlize(QString str,QString newline="\n"); - -/**converts a cent value into a (localized) string*/ -QString cent2str(int cent,bool localize=true); - -/**converts a (localized) string back into a cent value (must not contain spaces or extra dots)*/ -int str2cent(QString s,bool fromlocal=true); - -/**converts a unix timestamp into a date*/ -QString unix2date(int,bool localize=true); - -/**converts a unix timestamp into a time (ommitting the date)*/ -QString unix2time(int,bool localize=true); - -/**converts a unix timestamp into a date-time-string*/ -QString unix2dateTime(int,bool localize=true); - -/**return a (localized) regular expression that validates prices*/ -QRegExp priceRegExp(bool localize=true); - -#endif diff --git a/src/misc/code39.cpp b/src/misc/code39.cpp new file mode 100644 index 0000000..8d151a9 --- /dev/null +++ b/src/misc/code39.cpp @@ -0,0 +1,111 @@ +// +// C++ Implementation: code39 +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2007 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "code39.h" + +#include +#include + +//order of characters for checksum calculation and list of allowed chars +static const QString c39mod="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%"; + +//init pixel map +static QMap initmap() +{ + QMapmap; + // 0=black 1=white pixel + map.insert('*',"0111010001000101"); + map.insert('-',"0111010100010001"); + map.insert('$',"0111011101110101"); + map.insert('%',"0101110111011101"); + map.insert(' ',"0111000101000101"); + map.insert('.',"0001110101000101"); + map.insert('/',"0111011101011101"); + map.insert('+',"0111010111011101"); + map.insert('0',"0101110001000101"); + map.insert('1',"0001011101010001"); + map.insert('2',"0100011101010001"); + map.insert('3',"0001000111010101"); + map.insert('4',"0101110001010001"); + map.insert('5',"0001011100010101"); + map.insert('6',"0100011100010101"); + map.insert('7',"0101110100010001"); + map.insert('8',"0001011101000101"); + map.insert('9',"0100011101000101"); + map.insert('A',"0001010111010001"); + map.insert('B',"0100010111010001"); + map.insert('C',"0001000101110101"); + map.insert('D',"0101000111010001"); + map.insert('E',"0001010001110101"); + map.insert('F',"0100010001110101"); + map.insert('G',"0101011100010001"); + map.insert('H',"0001010111000101"); + map.insert('I',"0100010111000101"); + map.insert('J',"0101000111000101"); + map.insert('K',"0001010101110001"); + map.insert('L',"0100010101110001"); + map.insert('M',"0001000101011101"); + map.insert('N',"0101000101110001"); + map.insert('O',"0001010001011101"); + map.insert('P',"0100010001011101"); + map.insert('Q',"0101010001110001"); + map.insert('R',"0001010100011101"); + map.insert('S',"0100010100011101"); + map.insert('T',"0101000100011101"); + map.insert('U',"0001110101010001"); + map.insert('V',"0111000101010001"); + map.insert('W',"0001110001010101"); + map.insert('X',"0111010001010001"); + map.insert('Y',"0001110100010101"); + map.insert('Z',"0111000100010101"); + return map; +} +//map characters on pixel codes +static const QMapc39map=initmap(); + +//calculate checksum +static char code39mod(QString str) +{ + int sum=0; + for(int i=0;i %c",str.toAscii().data(),code39mod(str)); + //define xpm + char *xpm[4]; + QByteArray xpmsz=QString().sprintf("%i 1 2 1",rstr.size()).toAscii(); + xpm[0]=xpmsz.data(); + xpm[1]="0\tg #000000"; + xpm[2]="1\tg #FFFFFF"; + QByteArray xpmc=rstr.toAscii(); + xpm[3]=xpmc.data(); + //create pixmap + return QImage(xpm); +} diff --git a/src/misc/code39.h b/src/misc/code39.h new file mode 100644 index 0000000..549a738 --- /dev/null +++ b/src/misc/code39.h @@ -0,0 +1,19 @@ +// +// C++ Interface: code39 +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2007 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include +#include + +/**Takes a string and converts it into a code-39 bar code. +Code-39 allows letters (case-insensitive), digits, spaces and the special chars "-.$/+%". +The bar code pixmap will be 1 pixel high and 16 pixels wide for each character (plus start/stop character and checksum character) - it needs to be scaled up to fit the intended size.*/ +QImage code39(QString); diff --git a/src/misc/debug.cpp b/src/misc/debug.cpp new file mode 100644 index 0000000..bb52125 --- /dev/null +++ b/src/misc/debug.cpp @@ -0,0 +1,58 @@ +// +// C++ Implementation: debug +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "debug.h" +#include "main.h" + +#include +#include +#include +#include + +static QFile*mylogFile=0; + +static void mymsghandler(QtMsgType, const char *msg) +{ + if(mylogFile){ + mylogFile->write(msg,strlen(msg)); + mylogFile->write("\n",1); + mylogFile->flush(); + } +#ifdef Q_OS_UNIX + fprintf(stderr,"%s\n",msg); +#endif +} + +void initDebug() +{ + //create new log file + QDir(dataDir).mkpath("debuglog"); + mylogFile=new QFile(dataDir+"/debuglog/log-"+QDateTime::currentDateTime().toString("yyyy-MM-dd_hh.mm.ss.zzz")+".txt"); + //...open it + if(mylogFile->open(QIODevice::WriteOnly|QIODevice::Append|QIODevice::Text)){ + //install as default log + qInstallMsgHandler(mymsghandler); + }else{ + //hmm, failed to open, well hope that stderr is working... + delete mylogFile; + mylogFile=0; + qDebug("Failed to install debuglog."); + } + //delete old logs (older than 30 days) + QStringList fll=QDir(dataDir+"/debuglog").entryList(QDir::Files); + QDateTime old=QDateTime::currentDateTime().addDays(-30); + for(int i=0;i, (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_DEBUG_H +#define MAGICSMOKE_DEBUG_H + +void initDebug(); + +#endif diff --git a/src/misc/domquery.cpp b/src/misc/domquery.cpp new file mode 100644 index 0000000..056fc2d --- /dev/null +++ b/src/misc/domquery.cpp @@ -0,0 +1,145 @@ +// +// C++ Implementation: domquery +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2009 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "domquery.h" + + +MDomQuery::MDomQuery(const QDomDocument&start,QString path) +{ + construct(start.documentElement(),path); +} + +MDomQuery::MDomQuery(const QDomElement&start,QString path) +{ + construct(start,path); +} + +void MDomQuery::construct(const QDomElement&start,QString path) +{ + //split query + QStringList ql=path.split("/",QString::SkipEmptyParts); + //determine start mode and initialize list + MDomNodeList ndlst; + if(path.startsWith("//")){ + QDomDocument doc=start.ownerDocument(); + if(ql.size()<1){ + qDebug("MDomQuery: // query must not be empty!"); + return; + } + if(ql[0]=="*" || ql[0]=="@*"){ + qDebug("MDomQuery: // query must not start with wildcard * or @*."); + return; + } + if(ql[0].startsWith("@")){ + qDebug("MDomQuery: cannot start with attributes in a // query."); + return; + }else{ + ndlst=doc.elementsByTagName(ql[0]); + ql.removeFirst(); + } + }else + if(path.startsWith("/")){ + QDomElement root=start.ownerDocument().documentElement(); + if(ql.size()<1){ + //hmm, guess what the user really wanted (assume "/ *" ) + m_result<0){ + MDomNodeList lst2; + //parse pattern + if(ql[0].startsWith("@")){ + //attribute handling... + if(ql.size()>1){ + qDebug("MDomQuery: cannot sub-parse attributes."); + return; + } + if(ql[0]=="@*"){ + //get all attributes of all current elements + for(int i=0;i, (C) 2009 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_DOMQUERY_H +#define MAGICSMOKE_DOMQUERY_H + + +#include +#include +#include + +/**Helper class: more flexible version of QDomNodeList*/ +class MDomNodeList:public QList +{ + public: + MDomNodeList(){} + MDomNodeList(const MDomNodeList&l):QList(l){} + MDomNodeList(const QList&l):QList(l){} + MDomNodeList(const QDomNodeList&l){for(int i=0;i +mousereturn all child elements of the current element that are called "mouse" +\@mousereturn all attribute nodes of the current element that are called "mouse" +*returns all child elements of the current element +\@*returns all attributes of the current element +/*returns the root element of the document irrespective of name +/mousereturns the root element of the document if it has the tag name "mouse" or an empty list +/*/mousereturns all elements directly below the root element that are called "mouse" +//mousereturns all elements in the document that are called "mouse" +mouse/\@trap/doorsyntax error, attributes cannot have children + +*/ +class MDomQuery +{ + public: + /**creates the query object and executes the query*/ + MDomQuery(const QDomElement&start,QString path); + + /**creates the query object and executes the query; this is equivalent to calling the query with the document element as starting point*/ + MDomQuery(const QDomDocument&start,QString path); + + /**returns the search result as a single string, if there were multiple matches, they are separated by spaces*/ + QString toString()const; + /**returns the search result as a list of strings, one string element per match*/ + QStringList toStringList()const; + /**returns the result as a list of DOM nodes*/ + MDomNodeList toNodeList()const{return m_result;} + + /**cast to QString: see toString()*/ + operator QString()const{return toString();} + /**cast to QStringList: see toStringList()*/ + operator QStringList()const{return toStringList();} + /**cast to DOM node list: see toNodeList()*/ + operator MDomNodeList()const{return m_result;} + private: + MDomNodeList m_result; + + //helper for constructor + void construct(const QDomElement&start,QString path); +}; + +#endif diff --git a/src/misc/misc.cpp b/src/misc/misc.cpp new file mode 100644 index 0000000..5e5fb79 --- /dev/null +++ b/src/misc/misc.cpp @@ -0,0 +1,114 @@ +// +// C++ Implementation: misc +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "misc.h" + +#include +#include + +QString htmlize(QString str) +{ + QString out; + for(int i=0;i')out+=">";else + if(c=='&')out+="&";else + if(c=='\n')out+="
\n";else + if(c.isSpace()||(c.unicode()>=32&&c.unicode()<=0x7f))out+=c; + else out+="&#"+QString::number(ci)+";"; + } + return out; +} + +QString xmlize(QString str,QString newline) +{ + QString out; + for(int i=0;i')out+=">";else + if(c=='&')out+="&";else + if(c=='\n')out+=newline;else + if(c.isSpace()||(c.unicode()>=32&&c.unicode()<=0x7f))out+=c; + else out+="&#"+QString::number(ci)+";"; + } + return out; +} +QString cent2str(int c,bool localize) +{ + QString ret; + if(localize)ret=QCoreApplication::translate("misc","%1.%2","price with decimal dot"); + else ret="%1.%2"; + return ret.arg(c/100).arg(c%100,2,10,QChar('0')); +} + +int str2cent(QString s,bool localize) +{ + //convert local decimal dot by international decimal dot + if(localize)s=s.replace(QCoreApplication::translate("misc",".","decimal dot in price"),"."); + //calculate price + //pp->price part euro/dollar/...; pc->price part cent; pm=multiplier for cent; md->mode + int pp=0,pc=0,pm=10,md=0; + for(int i=0;i before the dot + pp*=10; + pp+=c.digitValue(); + }else{//mode==1 -> after the dot + pc+=c.digitValue()*pm; + if(pm==1)break; + pm=1; + } + }else + if(c=='.')md=1;//reached the dot, switch mode + //ignore everything else + } + //return result + return pp*100+pc; +} + +QRegExp priceRegExp(bool localize) +{ + if(localize) + return QRegExp(QCoreApplication::translate("misc","[0-9]+\\.[0-9]{2}","regexp for price")); + else + return QRegExp("[0-9]+\\.[0-9]{2}"); +} + +QString unix2date(int tm,bool localize) +{ + QString format; + if(localize)format=QCoreApplication::translate("misc","yyyy-MM-dd","localized date format"); + else format="yyyy-MM-dd"; + return QDateTime::fromTime_t(tm).toString(format); +} + +QString unix2time(int tm,bool localize) +{ + QString format; + if(localize)format=QCoreApplication::translate("misc","hh:mm","localized time format"); + else format="hh:mm"; + return QDateTime::fromTime_t(tm).toString(format); +} + +QString unix2dateTime(int tm,bool localize) +{ + QString format; + if(localize)format=QCoreApplication::translate("misc","yyyy-MM-dd hh:mm","localized date + time format"); + else format="yyyy-MM-dd hh:mm"; + return QDateTime::fromTime_t(tm).toString(format); +} + diff --git a/src/misc/misc.h b/src/misc/misc.h new file mode 100644 index 0000000..6d9766f --- /dev/null +++ b/src/misc/misc.h @@ -0,0 +1,43 @@ +// +// C++ Interface: misc +// +// Description: miscellaneous helper functions +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_MISC_H +#define MAGICSMOKE_MISC_H + +#include +#include + +/**converts special HTML characters into harmless &-codes, so the text can be included*/ +QString htmlize(QString str); + +/**converts special XML characters into harmless &-codes, so the text can be included*/ +QString xmlize(QString str,QString newline="\n"); + +/**converts a cent value into a (localized) string*/ +QString cent2str(int cent,bool localize=true); + +/**converts a (localized) string back into a cent value (must not contain spaces or extra dots)*/ +int str2cent(QString s,bool fromlocal=true); + +/**converts a unix timestamp into a date*/ +QString unix2date(int,bool localize=true); + +/**converts a unix timestamp into a time (ommitting the date)*/ +QString unix2time(int,bool localize=true); + +/**converts a unix timestamp into a date-time-string*/ +QString unix2dateTime(int,bool localize=true); + +/**return a (localized) regular expression that validates prices*/ +QRegExp priceRegExp(bool localize=true); + +#endif diff --git a/src/misc/misc.pri b/src/misc/misc.pri new file mode 100644 index 0000000..0f4e172 --- /dev/null +++ b/src/misc/misc.pri @@ -0,0 +1,12 @@ +HEADERS += \ + misc/debug.h \ + misc/misc.h \ + misc/domquery.h + +SOURCES += \ + misc/code39.cpp \ + misc/debug.cpp \ + misc/misc.cpp \ + misc/domquery.cpp + +INCLUDEPATH += ./misc \ No newline at end of file diff --git a/src/moneylog.cpp b/src/moneylog.cpp deleted file mode 100644 index 98846a5..0000000 --- a/src/moneylog.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// -// C++ Implementation: moneylog -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "moneylog.h" -#include "msinterface.h" -#include "misc.h" - -#include -#include -#include - -MMoneyLog::MMoneyLog(QWidget*pa,QString q) - :QDialog(pa) -{ - //set title - QStringList sl=q.split("\n"); - sl[0][0]=sl[0][0].toUpper(); - setWindowTitle(tr("Money Log of %1 %2").arg(sl[0]).arg(sl[1])); - - //layout - QVBoxLayout*vl; - QHBoxLayout*hl; - QTextEdit*text; - QPushButton*p; - setLayout(vl=new QVBoxLayout); - vl->addWidget(text=new QTextEdit,10); - text->setReadOnly(true); - vl->addSpacing(15); - vl->addLayout(hl=new QHBoxLayout,0); - hl->addStretch(10); - hl->addWidget(p=new QPushButton(tr("Close"))); - connect(p,SIGNAL(clicked()),this,SLOT(accept())); - - //query - /*TODO - if(req->request("moneylog",q.toAscii())){ - if(req->responseStatus()==MWebRequest::Ok){ - text->setPlainText(QString::fromUtf8(req->responseBody())); - }else{ - text->setHtml("

Error

"+htmlize(QString::fromUtf8(req->responseBody()))); - } - }else{ - text->setHtml("

Low Level Error

Request failed."); - }*/ -} \ No newline at end of file diff --git a/src/moneylog.h b/src/moneylog.h deleted file mode 100644 index fbdc415..0000000 --- a/src/moneylog.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// C++ Interface: moneylog -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_MONEYLOG_H -#define MAGICSMOKE_MONEYLOG_H - -#include - - -class MMoneyLog:public QDialog -{ - Q_OBJECT - public: - MMoneyLog(QWidget*,QString); -}; - - -#endif diff --git a/src/msinterface.cpp b/src/msinterface.cpp deleted file mode 100644 index 1a7afe6..0000000 --- a/src/msinterface.cpp +++ /dev/null @@ -1,191 +0,0 @@ -// -// C++ Implementation: msinterface -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2009 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "msinterface.h" -#include "main.h" -#include "sslexception.h" - -#include -#include -#include -#include -#include -#include - -MSInterface::MSInterface(QString pid) - :MInterface() -{ - profileid=pid; - QSettings set; - set.beginGroup("profiles/"+pid); - setUrl("https://"+set.value("serverurl","my.host.com/path/machine.php").toString()); - bool useproxy=set.value("useproxy",false).toBool(); - if(useproxy) - setProxy( - set.value("proxyname","proxy").toString(), - set.value("proxyport",74).toInt(), - set.value("proxyuser").toString(), - set.value("proxypass").toString() - ); - m_host=set.value("hostname").toString(); - m_hostkey=set.value("hostkey").toString(); - sslexcept=new MSslExceptions(dataDir()+"/sslexceptions.xml"); -} - -MSInterface::~MSInterface() -{ - logout(); - if(sslexcept)delete sslexcept; - sslexcept=0; -} - -bool MSInterface::login(QString username,QString passwd) -{ - m_uname=username;m_passwd=passwd; - MTLogin lg=MTLogin::query(username,passwd,m_host,m_hostkey); - if(lg.stage()==lg.Error) - QMessageBox::warning(0,tr("Warning"),tr("Login failed: %1").arg(tr(lg.errorString().toAscii()))); - else - setSessionId(lg.getsessionid()); - if(lg.stage()!=lg.Success)return false; - //get rights - MTGetMyRights mrt=MTGetMyRights::query(); - QStringList rsl=mrt.getright(); - for(int i=0;icommVersion()){ - QMessageBox::warning(0,tr("Error"),tr("This client is too old for the server, please upgrade.")); - return false; - } - //we are ok - return true; -} - -void MSInterface::logout() -{ - if(m_sessid!="")queryLogout(); - m_sessid=""; -} -bool MSInterface::relogin() -{ - logout(); - return login(m_uname,m_passwd); -} - -QMap MSInterface::headers(QString s)const -{ - QMap ret=WInterface::headers(s); - ret.insert("Wob-SessionId",m_sessid); - return ret; -} - -QString MSInterface::dataDir()const -{ - QString dd="profile."+profileid; - QDir dir(::dataDir); - if(!dir.exists(dd)) - if(!dir.mkpath(dd)) - qDebug("Warning: oh dir! Can't create my data directory!"); - return ::dataDir+"/"+dd; -} - -QString MSInterface::settingsGroup()const -{ - return "profsettings/"+profileid; -} - -QString MSInterface::repoPart() -{ - QStringList l=svnRepositoryUrl().split("/smoke/"); - if(l.size()>1)return l[1]; - else return svnRepositoryUrl(); -} - -bool MSInterface::hasRight(Right r)const -{ - if(userroles.contains("_admin"))return true; - return userrights.contains(r); -} - -void MSInterface::initialize() -{ - //retrieve translation file - if(servertranslation.size()==0){ //can be called only once, make sure it is so - QString lang=QSettings().value("lang","--").toString(); - if(lang=="--"){ - qDebug("MSInterface: no local language is set, so not retrieving any from server."); - goto script; - } - MTGetLanguage gl=MTGetLanguage::query(lang,"qm"); - if(gl.hasError()){ - qDebug("MSInterface: error while retrieving language %s from server: (%s) %s", - lang.toAscii().data(), - gl.errorType().toAscii().data(), - gl.errorString().toAscii().data()); - goto script; - } - servertranslation=gl.getfile().value(); - QTranslator *trn=new QTranslator(this); - trn->load((const uchar*)servertranslation.data(),servertranslation.size()); - qApp->installTranslator(trn); - qDebug("MSInterface: successfully loaded server language %s",lang.toAscii().data()); - } - //TODO: retrieve scripts - script: ; -} - -void MSInterface::sslErrors(const QList&errs) -{ - //get source of error - QHttp*src=qobject_cast(sender()); - if(!src)return; - //check against known exceptions - if(sslexcept->checksslexcept(errs)){ - src->ignoreSslErrors(); - return; - } - //message box - if(!didsslerror){ - QMessageBox::warning(0,tr("Connection Error"),tr("There were problems while authenticating the server. Aborting. Check your configuration.")); - } -} diff --git a/src/msinterface.h b/src/msinterface.h deleted file mode 100644 index f4532a2..0000000 --- a/src/msinterface.h +++ /dev/null @@ -1,84 +0,0 @@ -// -// C++ Interface: msinterface -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2009 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_MSINTERFACE_H -#define MAGICSMOKE_MSINTERFACE_H - -#include "MInterface.h" - -class MSslExceptions; - -/**the MagicSmoke specific interface class - enhances the basic interface by some functionality needed in the MagicSmoke context*/ -class MSInterface:public MInterface -{ - Q_OBJECT - public: - /**creates the interface object, expects the profile ID as parameter*/ - MSInterface(QString); - /**deletes the interface*/ - ~MSInterface(); - - /**returns the singleton instance of the interface*/ - static MSInterface* instance(){return qobject_cast(MInterface::instance());} - - /**returns the name of the current user*/ - QString currentUser()const{return m_uname;} - - /**returns whether the user is part of this role*/ - bool hasRole(QString)const{return false;} - - /**returns whether the user has a particular right*/ - bool hasRight(Right)const; - - /**returns the directory where to store data retrieved from the server*/ - QString dataDir()const; - /**returns the group in which to find settings in QSettings*/ - QString settingsGroup()const; - - /**checks the server for compatibility*/ - bool checkServer(); - - /**returns the current session ID*/ - QString sessionId()const{return m_sessid;} - - /**returns the branch/trunk part of the repository*/ - static QString repoPart(); - - /**returns default headers, ie. session ID*/ - virtual QMap headers(QString)const; - - /**initializes the interface, ie. retrieves language and scripts*/ - void initialize(); - - public slots: - /**logs into the server, returns true on success*/ - bool login(QString username,QString passwd); - /**logs out of the server*/ - void logout(); - /**refreshes the login*/ - bool relogin(); - /**sets the session id to be transmitted*/ - void setSessionId(QString sid){m_sessid=sid;} - /**handles SSL errors*/ - virtual void sslErrors(const QList&); - - private: - QString profileid,m_sessid,m_uname,m_passwd,m_host,m_hostkey; - mutable QListuserrights; - mutable QStringList userroles; - QByteArray servertranslation; - MSslExceptions*sslexcept; - bool didsslerror; -}; - - -#endif diff --git a/src/mwin/mwin.pri b/src/mwin/mwin.pri new file mode 100644 index 0000000..aaf3570 --- /dev/null +++ b/src/mwin/mwin.pri @@ -0,0 +1,7 @@ +HEADERS += \ + mwin/overview.h + +SOURCES += \ + mwin/overview.cpp + +INCLUDEPATH += ./mwin \ No newline at end of file diff --git a/src/mwin/overview.cpp b/src/mwin/overview.cpp new file mode 100644 index 0000000..33d9424 --- /dev/null +++ b/src/mwin/overview.cpp @@ -0,0 +1,1753 @@ +// +// C++ Implementation: overview +// +// Description: +// +// +// Author: Konrad Rosenbaum , (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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + } + QListevl=gae.getevents(); + eventmodel->clear(); + eventmodel->insertColumns(0,6); + eventmodel->setHorizontalHeaderLabels(QStringList()<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(); + QListship=sh.getshipping(); + for(int i=0;iaddItem(ship[i].description(),(int)ship[i].id()); +} + +void MOverview::updateUsers() +{ + MTGetAllUsers au=req->queryGetAllUsers(); + if(au.hasError())return; + QListusl=au.getusers(); + usermodel->clear(); + usermodel->insertColumns(0,2); + usermodel->insertRows(0,usl.size()); + usermodel->setHorizontalHeaderLabels(QStringList()<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<rowCount();i++) + rplc<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(); + QListhsl=req->getAllHosts(); + hostmodel->clear(); + hostmodel->insertColumns(0,2); + hostmodel->insertRows(0,hsl.size()); + hostmodel->setHorizontalHeaderLabels(QStringList()<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()<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); + QListprc=req->getVoucherPrices(); + mdl.insertRows(0,prc.size()); + mdl.insertColumns(0,1); + for(int i=0;iaddWidget(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(®v); + }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(®v); + 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;irowCount();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;jdata(idx).toInt(); + int price=cartmodel->data(idx,CART_PRICEROLE).toInt(); + int value=cartmodel->data(idx,CART_VALUEROLE).toInt(); + for(int j=0;jcurrentIndex()>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;irowCount();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()<itemData(ordermode->currentIndex()).toInt(); + if(omode==ORDERNONE)return; + QList orders=req->getAllOrders(); + if(orders.size()==0)return; + QList cust=req->getAllCustomers(); + int cl=0; + for(int i=0;iinsertRow(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;jsetData(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 + QListeventids; + for(int i=0;idata(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()< orders=req->getOrdersByEvents(eventids); + if(orders.size()==0)return; + QList cust=req->getAllCustomers(); + for(int cl=0;clinsertRow(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;jsetData(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()< orders=req->getAllOrders(); + if(orders.size()==0)return; + QList cust=req->getAllCustomers(); + int cl=0; + for(int i=0;iinsertRow(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(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/overview.h b/src/mwin/overview.h new file mode 100644 index 0000000..dfd5a43 --- /dev/null +++ b/src/mwin/overview.h @@ -0,0 +1,235 @@ +// +// C++ Interface: overview +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2007 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_OVERVIEW_H +#define MAGICSMOKE_OVERVIEW_H + +#include +#include +#include +#include +#include + +#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/odtrender.cpp b/src/odtrender.cpp deleted file mode 100644 index 38831aa..0000000 --- a/src/odtrender.cpp +++ /dev/null @@ -1,569 +0,0 @@ -// -// C++ Implementation: odtrender -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "misc.h" -#include "odtrender.h" -#include "office.h" - -#include -#include -#include -#include -#include - -#include "../zip/qunzip.h" -#include "../zip/qzip.h" - - -class MOdtRendererPrivate -{ - protected: - friend class MOdtRenderer; - - //methods that the parent uses - MOdtRendererPrivate(QString file,MOdtRenderer*p); - ~MOdtRendererPrivate(); - - bool renderToFile(QFile&); - - //data the parent uses - QString extension; - - private: - //methods that the parent does not call - void render(QIODevice*); - - QString render(QString); - - QString renderLine(QString,QString,int); - - QString getVariable(QString varname); - QString getLoopVariable(QString loopname,int iteration,QString varname); - - qint64 intToken(QString,QString,int); - void setLocalVar(QString,qint64); - void setLocalVarError(QString); - - //data the parent does not access - MOdtRenderer*parent; - QUnZip temp; - QFile tfile; - QString newline; - bool inif,iftrue; - - struct LocalVar{ - MOdtRenderer::VarType type; - QVariant value; - }; - QMaplocalvars; -}; - -MOdtRenderer::MOdtRenderer(MTemplate file) -{ - d=new MOdtRendererPrivate(file.cacheFileName(),this); - d->extension=file.targetExtension(); -} - -MOdtRendererPrivate::MOdtRendererPrivate(QString file,MOdtRenderer*p) - :tfile(file) -{ - parent=p; - newline=" "; - inif=iftrue=true; - //open ZIP - if(tfile.open(QIODevice::ReadOnly))temp.open(&tfile); - //TODO: make sure this is a valid ZIP file, preferably with some ODT content -} - -MOdtRenderer::~MOdtRenderer() -{ - delete d; - d=0; -} -MOdtRendererPrivate::~MOdtRendererPrivate() -{ - temp.close(); - tfile.close(); -} - -void MOdtRenderer::renderToFile(QString file) -{ - QFile f(file); - if(f.open(QIODevice::ReadWrite)){ - renderToFile(f); - f.close(); - } -} - -void MOdtRenderer::renderToFile(QFile &file) -{ - if(d->renderToFile(file)) - if(QSettings().value("doOpenODFs",false).toBool()) - openOfficeFile(file.fileName()); -} -bool MOdtRendererPrivate::renderToFile(QFile &file) -{ - if(!file.isWritable()) - if(!file.open(QIODevice::ReadWrite))return false; - file.seek(0); - file.resize(0); - render(&file); - return true; -} - -void MOdtRenderer::renderToPrinter() -{ - //generate temporary file - QTemporaryFile tfile; - tfile.setAutoRemove(false);//we don't want it to be auto-deleted on close() - tfile.setFileTemplate(QDir::tempPath()+"/msmoke_XXXXXX."+d->extension); - tfile.open(); - QString tname=tfile.fileName(); - //render - d->renderToFile(tfile); - tfile.close(); - //call ooffice and print - printOfficeFile(tname); - //remove temporary file - QFile(tname).remove(); -} - -void MOdtRendererPrivate::render(QIODevice*out) -{ - //sanity check - if(!temp.isOpen())return; - if(!out->isWritable())return; - //rewind input - if(!temp.gotoFirstFile())return; - //create output - QZip ozip; - ozip.open(out); - //copy contents - do{ - QString cname; - QDateTime tstamp; - temp.getCurrentFileInfo(cname,&tstamp); - if(cname=="content.xml"){ - //get content - QBuffer buffer; - buffer.open(QBuffer::ReadWrite); - temp.getCurrentFile(buffer); - //render - QByteArray cont=render(QString::fromUtf8(buffer.data())).toUtf8(); - //write - buffer.close(); - buffer.setData(cont); - buffer.open(QBuffer::ReadWrite); - buffer.seek(0); - ozip.storeFile(cname,buffer,tstamp); - }else{ - //copy unchanged - QBuffer buffer; - buffer.open(QBuffer::ReadWrite); - int meth; - unsigned long crc,usz; - temp.getCurrentFileRaw(buffer,meth,crc,usz); - buffer.seek(0); - ozip.storeFileRaw(cname,buffer,tstamp,meth,crc,usz); - } - }while(temp.gotoNextFile()); - ozip.close(); -} - -QString MOdtRendererPrivate::render(QString s) -{ - //buffer for the whole file - QStringList fbuf=s.split("\n"); - //buffer for loops - QStringList lbuf; - QString lname; - //buffer for return value - QString ret; - //go through all lines - bool isloop=false; - for(int i=0;igetLoopIterations(lname); - //render the loop... - for(int j=0;j")iftrue=op1>op2;else - if(stl[1]=="=" || stl[1]=="==")iftrue=op1==op2;else - if(stl[1]=="<=")iftrue=op1<=op2;else - if(stl[1]==">=")iftrue=op1>=op2;else - if(stl[1]=="<>" || stl[1]=="!=")iftrue=op1!=op2; - else { - qDebug("??????????IfError: unknown operator"); - return ""; - } - qDebug("???????????????? If(%lli %s %lli) evaluates to: %s",op1,stl[1].toAscii().data(),op2,iftrue?"true":"false"); - return ""; - }else - if(line.trimmed()=="#ELSE"){ - iftrue=!iftrue; - return ""; - }else - if(line.trimmed()=="#ENDIF"){ - inif=false; - return ""; - } - //check if state - if(inif && !iftrue)return ""; - //check for other statements - if(line.trimmed().startsWith("#SETNEWLINE:")){ - //set a new newline translation - newline=line.trimmed().mid(12).trimmed(); - if(newline=="")newline=" "; - return ""; - }else - if(line.trimmed().startsWith("#CALC:")){ - //do a calculation - //get full statement - QString stmt=line.trimmed().mid(6).trimmed(); - qDebug("????????????????Calculation: %s",stmt.toAscii().data()); - //split out var name - int p=stmt.indexOf(':'); - if(p<1)return ""; - QString var=stmt.left(p).trimmed(); - //get list of statement tokens - QStringList stl=stmt.mid(p+1).trimmed().split(" "); - //go through - qint64 res=intToken(stl[0],loop,lpos); -// qDebug("??????????CalcInit: %lli",res); - for(int i=1;i=stl.size()){ - setLocalVarError(var); - qDebug("??????????CalcError: missing last operand"); - return ""; - } - qint64 op2=intToken(stl[i+1],loop,lpos); -// qDebug("??????????Calc: operator '%s' operand '%s' -> '%lli'",stl[i].toAscii().data(),stl[i+1].toAscii().data(),op2); - if(stl[i]=="+")res+=op2;else - if(stl[i]=="-")res-=op2;else - if(stl[i]=="*")res*=op2;else - if(stl[i]=="/"){ - if(op2!=0)res/=op2; - else{ - qDebug("??????????CalcError: division operand %s is zero",stl[i+1].toAscii().data()); - return ""; - } - }else - if(stl[i]=="%"){ - if(op2!=0)res%=op2; - else{ - qDebug("??????????CalcError: modulo operand %s is zero",stl[i+1].toAscii().data()); - return ""; - } - }else { - setLocalVarError(var); - qDebug("??????????CalcError: unknown operator %s",stl[i].toAscii().data()); - return ""; - } - } - qDebug("????????????????CalcResult: %s <= %lli",var.toAscii().data(),res); - setLocalVar(var,res); - return ""; - } - //scan characters - for(int i=0;i2){ - //this was a mistake, reset - ret+="@"; - ret+=vname+"@"; - }else - if(vl.size()==2){ - //this is a loop variable, - //check that it is the right loop - //or any loop at all... - if(loop!="" && (loop==vl[0] || ("$"+loop)==vl[0])){ - //get value - ret+=xmlize(getLoopVariable(vl[0],lpos,vl[1]).trimmed(),newline); - } - }else - //this is a normal variable, get valie - ret+=xmlize(getVariable(vname).trimmed(),newline); - } - //reset mode - isvar=false; - vname=""; - }else - //continuation of var? - if(vc.contains(line[i])){ - //valid var-name-letter, add - vname+=line[i]; - }else{//not a valid var-name-letter - //reset - isvar=false; - ret+="@"; - ret+=vname; - vname=""; - } - }else{//not inside variable name - //is this the start of a var? - if(line[i]=='@'){ - isvar=true; - vname=""; - }else{ - ret+=line[i]; - } - } - } - //anything left over? - if(isvar){ - //reset - ret+="@"+vname; - } - //return transformed line - return ret + "\n"; -} - -static inline QString formatVar(QVariant r,MOdtRenderer::VarType tp,bool loc,int offset) -{ - switch(tp){ - case MOdtRenderer::StringVar: - return r.toString(); - case MOdtRenderer::IntVar: - return QString::number(r.toInt()+offset); - case MOdtRenderer::MoneyVar: - return cent2str(r.toInt()+offset,loc); - case MOdtRenderer::DateVar: - return unix2date(r.toInt()+offset,loc); - case MOdtRenderer::TimeVar: - return unix2time(r.toInt()+offset,loc); - case MOdtRenderer::DateTimeVar: - return unix2dateTime(r.toInt()+offset,loc); - } - return ""; -} - -QString MOdtRendererPrivate::getVariable(QString varname) -{ - //split out calculation - int offset=0; - int p=varname.indexOf('+'); - if(p>0){ - offset=varname.mid(p+1).toInt(); - varname=varname.left(p); - } - p=varname.indexOf('-'); - if(p>0){ - offset=varname.mid(p).toInt(); - varname=varname.left(p); - } - //split out $-sign - bool localize=true; - if(varname[0]=='$'){ - localize=false; - varname=varname.mid(1); - } - //get variable - MOdtRenderer::VarType tp=MOdtRenderer::StringVar; - QVariant r; - if(varname=="TODAY"){ - r=QDateTime::currentDateTime().toTime_t(); - tp=MOdtRenderer::DateVar; - }else if(varname=="NOW"){ - r=QDateTime::currentDateTime().toTime_t(); - tp=MOdtRenderer::TimeVar; - }else if(varname[0]=='#'){ - if(localvars.contains(varname.mid(1))){ - r=localvars[varname.mid(1)].value; - tp=localvars[varname.mid(1)].type; - } - }else{ - r=parent->getVariable(varname,tp); - } - return formatVar(r,tp,localize,offset); -} - -QString MOdtRendererPrivate::getLoopVariable(QString loopname,int iteration,QString varname) -{ - //split out calculation - int offset=0; - int p=varname.indexOf('+'); - if(p>0){ - offset=varname.mid(p+1).toInt(); - varname=varname.left(p); - } - p=varname.indexOf('-'); - if(p>0){ - offset=varname.mid(p).toInt(); - varname=varname.left(p); - } - //split out $-sign - bool localize=true; - if(loopname[0]=='$'){ - localize=false; - loopname=loopname.mid(1); - } - qDebug("!!!!!!!!!!getting loop var '%s' : '%s' localized=%s offset=%i",loopname.toAscii().data(),varname.toAscii().data(),(localize?"yes":"no"),offset); - //get variable - MOdtRenderer::VarType tp=MOdtRenderer::StringVar; - QVariant r; - if(varname=="ITERATION"){ - r=iteration; - tp=MOdtRenderer::IntVar; - }else - r=parent->getLoopVariable(loopname,iteration,varname,tp); - return formatVar(r,tp,localize,offset); -} - -qint64 MOdtRendererPrivate::intToken(QString vname,QString loop,int lpos) -{ - //check for literals - bool islit; - qint64 lit=vname.toLongLong(&islit); - if(islit)return lit; - //split the variable - QStringList vnl=vname.split(":"); - if(vnl.size()<2){ - //local var? - if(vnl[0][0]=='#'){ - if(localvars.contains(vnl[0].mid(1))) - return localvars[vnl[0].mid(1)].value.toLongLong(); - return 0; - } - //special var? - if(vname=="TODAY" || vname=="NOW") - return QDateTime::currentDateTime().toTime_t(); - //get from parent - MOdtRenderer::VarType tp; - return parent->getVariable(vnl[0],tp).toLongLong(); - }else{ - //correct loop? - if(vnl[0]!=loop)return 0; - //iteration? - if(vnl[1]=="ITERATION")return lpos; - //get from parent - MOdtRenderer::VarType tp; - return parent->getLoopVariable(loop,lpos,vnl[1],tp).toLongLong(); - } -} - -void MOdtRendererPrivate::setLocalVar(QString vn,qint64 va) -{ - //split vname/type - QStringList vnl=vn.split("/"); - MOdtRenderer::VarType tp=MOdtRenderer::IntVar; - if(vnl.size()>1){ - if(vnl[1]=="MONEY")tp=MOdtRenderer::MoneyVar;else - if(vnl[1]=="DATE")tp=MOdtRenderer::DateVar;else - if(vnl[1]=="TIME")tp=MOdtRenderer::TimeVar;else - if(vnl[1]=="DATETIME")tp=MOdtRenderer::DateTimeVar; - } - //store - LocalVar lv; - lv.type=tp; - lv.value=va; - localvars.insert(vnl[0],lv); -} - -void MOdtRendererPrivate::setLocalVarError(QString vn) -{ - QStringList vnl=vn.split("/"); - LocalVar lv; - lv.type=MOdtRenderer::StringVar; - lv.value="error"; - localvars.insert(vnl[0],lv); -} - -/********************************************************************/ - -MOdtSignalRenderer::MOdtSignalRenderer(MTemplate file) - :MOdtRenderer(file) -{ -} - -MOdtSignalRenderer::~MOdtSignalRenderer(){} - -QVariant MOdtSignalRenderer::getVariable(QString varname,MOdtRenderer::VarType&av) -{ - QVariant ret; - av=MOdtRenderer::StringVar; - emit getVariable(varname,av,ret); - return ret; -} - -int MOdtSignalRenderer::getLoopIterations(QString loopname) -{ - int ret=0; - emit getLoopIterations(loopname,ret); - return ret; -} - -QVariant MOdtSignalRenderer::getLoopVariable(QString loopname,int iteration,QString varname,MOdtRenderer::VarType&av) -{ - QVariant ret="notfound"; - av=MOdtRenderer::StringVar; - emit getLoopVariable(loopname,iteration,varname,av,ret); - return ret; -} diff --git a/src/odtrender.h b/src/odtrender.h deleted file mode 100644 index bae9fef..0000000 --- a/src/odtrender.h +++ /dev/null @@ -1,98 +0,0 @@ -// -// C++ Interface: odtrender -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_ODTRENDER_H -#define MAGICSMOKE_ODTRENDER_H - -#include -#include - -#include "templates.h" - -class MOdtRendererPrivate; -class QFile; - -/**abstract base class for all ODT rendering classes*/ -class MOdtRenderer -{ - public: - /**instantiates a renderer loaded from template file*/ - MOdtRenderer(MTemplate file); - /**deletes the renderer*/ - virtual ~MOdtRenderer(); - - /**starts the internal rendering routine and outputs to file*/ - virtual void renderToFile(QString file); - - /**starts the internal rendering routine and outputs to file*/ - virtual void renderToFile(QFile& file); - - /**starts the internal rendering routine and outputs to printer (calls OpenOffice to print)*/ - virtual void renderToPrinter(); - - /**variable type*/ - enum VarType{ - /**default: uninterpreted string*/ - StringVar, - /**simple integer value*/ - IntVar, - /**money value*/ - MoneyVar, - /**unix timestamp: format as date*/ - DateVar, - /**unix timestamp: format as time*/ - TimeVar, - /**unix timestamp: format as date+time*/ - DateTimeVar - }; - - protected: - friend class MOdtRendererPrivate; - /**implement this to return the value of a variable during rendering; should return empty string if the variable does not exist*/ - virtual QVariant getVariable(QString varname,VarType&)=0; - - /**implement this to return the amount of iterations for a defined loop; should return 0 if the loop does not exist*/ - virtual int getLoopIterations(QString loopname)=0; - - /**implement this to return a specific instance of a loop internal variable; should return empty string if the request is not valid*/ - virtual QVariant getLoopVariable(QString loopname,int iteration,QString varname,VarType&)=0; - private: - MOdtRendererPrivate*d; -}; - -/**generic class that implements MOdtRenderer by calling signals; the signals must be connected using a direct or blocking connection; if any of them is not used it will behave as if the variable/loop did not exist*/ -class MOdtSignalRenderer:public QObject,public MOdtRenderer -{ - Q_OBJECT - public: - /**instantiates a renderer loaded from template file*/ - MOdtSignalRenderer(MTemplate file); - /**deletes the renderer*/ - ~MOdtSignalRenderer(); - - signals: - /**connect this to return the value of a variable during rendering; should return empty string if the variable does not exist*/ - void getVariable(QString varname,MOdtRenderer::VarType&,QVariant&value); - - /**connect this to return the amount of iterations for a defined loop; should return 0 if the loop does not exist*/ - void getLoopIterations(QString loopname,int&iterations); - - /**connect this to return a specific instance of a loop internal variable; should return empty string if the request is not valid*/ - void getLoopVariable(QString loopname,int iteration,QString varname,MOdtRenderer::VarType&,QVariant&value); - - protected: - QVariant getVariable(QString varname,MOdtRenderer::VarType&); - int getLoopIterations(QString loopname); - QVariant getLoopVariable(QString loopname,int iteration,QString varname,MOdtRenderer::VarType&); -}; - -#endif diff --git a/src/office.cpp b/src/office.cpp deleted file mode 100644 index dfc9c94..0000000 --- a/src/office.cpp +++ /dev/null @@ -1,175 +0,0 @@ -// -// C++ Implementation: office -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "office.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static QString getofficepath() -{ - return QSettings().value("officePath","soffice").toString(); -} - -void openOfficeFile(QString fname) -{ - //calculate parameters - QStringList r; - if(QSettings().value("officeViewOnly",false).toBool())r<<"-view"; - r<addWidget(new QLabel(QCoreApplication::translate("office","Please chose a printer:")),0); - QComboBox*printer; - vl->addWidget(printer=new QComboBox,0); - printer->setEditable(false); - printer->addItem(QCoreApplication::translate("office","(Default Printer)")); - QListaprn=QPrinterInfo::availablePrinters(); - int cprn=0; - QString cp=QSettings().value("officePrinter","").toString(); - for(int i=0;iaddItem(s); - if(cp==prn)cprn=i+1; - } - printer->setCurrentIndex(cprn); - vl->addSpacing(10); - vl->addStretch(1); - QHBoxLayout*hl; - vl->addLayout(hl=new QHBoxLayout,0); - hl->addStretch(10); - QPushButton*p; - hl->addWidget(p=new QPushButton(QCoreApplication::translate("office","Ok"))); - QObject::connect(p,SIGNAL(clicked()),&d,SLOT(accept())); - d.exec(); - if(printer->currentIndex()==0)prn=""; - else prn=printer->currentText(); -} - -void printOfficeFile(QString fname) -{ - //calculate parameters - QStringList r; - QString p=QSettings().value("officePrinter","").toString(); - if(QSettings().value("officePrinterConfirm",false).toBool())confirmPrinter(p); - if(p=="")r<<"-p"; - else r<<"-pt"<addWidget(gb=new QGroupBox(tr("OpenOffice.org"))); - gb->setLayout(hl=new QHBoxLayout); - hl->addWidget(new QLabel(tr("Path to Executable:"))); - hl->addWidget(oopath=new QLineEdit(set.value("officePath","soffice").toString()),1); - hl->addWidget(p=new QPushButton(tr("...","select OpenOffice path button"))); - connect(p,SIGNAL(clicked()),this,SLOT(selectpath())); - - vl->addWidget(gb=new QGroupBox(tr("Printing ODF"))); - gb->setLayout(vl2=new QVBoxLayout); - vl2->addLayout(hl=new QHBoxLayout); - hl->addWidget(new QLabel(tr("Printer:"))); - hl->addWidget(printer=new QComboBox,1); - printer->setEditable(false); - printer->addItem(tr("(Default Printer)")); - QListaprn=QPrinterInfo::availablePrinters(); - int cprn=0; - QString cp=set.value("officePrinter","").toString(); - for(int i=0;iaddItem(s); - if(cp==s)cprn=i+1; - } - printer->setCurrentIndex(cprn); - vl2->addWidget(askprint=new QCheckBox(tr("Always confirm printer when printing ODF"))); - askprint->setChecked(set.value("officePrinterConfirm",false).toBool()); - vl2->addWidget(saveprint=new QCheckBox(tr("Save printed files"))); - saveprint->setChecked(set.value("officePrinterSave",false).toBool()); - - vl->addWidget(gb=new QGroupBox(tr("Opening ODF"))); - gb->setLayout(vl2=new QVBoxLayout); - vl2->addWidget(viewonly=new QCheckBox(tr("Always open as Read-Only"))); - viewonly->setChecked(set.value("officeViewOnly",false).toBool()); - vl2->addWidget(doopen=new QCheckBox(tr("Automatically open all newly created files"))); - doopen->setChecked(set.value("doOpenODFs",false).toBool()); - - vl->addSpacing(15); - vl->addLayout(hl=new QHBoxLayout); - hl->addStretch(1); - hl->addWidget(p=new QPushButton(tr("OK"))); - connect(p,SIGNAL(clicked()),this,SLOT(accept())); - connect(p,SIGNAL(clicked()),this,SLOT(savedata())); - hl->addWidget(p=new QPushButton(tr("Cancel"))); - connect(p,SIGNAL(clicked()),this,SLOT(reject())); -} - -void MOfficeConfig::savedata() -{ - QSettings set; - int cprn=printer->currentIndex(); - if(cprn==0)set.setValue("officePrinter",""); - else set.setValue("officePrinter",printer->currentText()); - - set.setValue("officePath",oopath->text()); - set.setValue("officeViewOnly",viewonly->isChecked()); - set.setValue("doOpenODFs",doopen->isChecked()); - set.setValue("officePrinterConfirm",askprint->isChecked()); - set.setValue("officePrinterSave",saveprint->isChecked()); -} - -void MOfficeConfig::selectpath() -{ - QString np=QFileDialog::getOpenFileName(this,tr("Select OpenOffice.org executable"),QFileInfo(oopath->text()).dir().absolutePath()); - if(np!="")oopath->setText(np); -} diff --git a/src/office.h b/src/office.h deleted file mode 100644 index 75bc0ff..0000000 --- a/src/office.h +++ /dev/null @@ -1,47 +0,0 @@ -// -// C++ Interface: office -// -// Description: Wrapper and Config Dialog around OpenOffice.org -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_OFFICE_H -#define MAGICSMOKE_OFFICE_H - -#include - -/**calls OpenOffice.org to open an ODF file*/ -void openOfficeFile(QString fname); - -/**calls OpenOffice.org to print an ODF file*/ -void printOfficeFile(QString fname); - -#include - -class QComboBox; -class QCheckBox; -class QLineEdit; - -/**configuration dialog for OpenOffice access*/ -class MOfficeConfig:public QDialog -{ - Q_OBJECT - public: - MOfficeConfig(QWidget*); - - private slots: - void savedata(); - void selectpath(); - private: - QComboBox*printer; - QCheckBox*viewonly,*doopen,*askprint,*saveprint; - QLineEdit*oopath; -}; - - -#endif diff --git a/src/orderwin.cpp b/src/orderwin.cpp deleted file mode 100644 index f6481a3..0000000 --- a/src/orderwin.cpp +++ /dev/null @@ -1,1099 +0,0 @@ -// -// C++ Implementation: orderwin -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "centbox.h" -#include "event.h" -#include "labeldlg.h" -#include "misc.h" -#include "moneylog.h" -#include "odtrender.h" -#include "orderwin.h" -#include "ticketrender.h" -#include "msinterface.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define req (MSInterface::instance()) - -MOrderWindow::MOrderWindow(QWidget*par,const MOrder&o) - :QMainWindow(par),m_order(o) -{ - setWindowTitle(tr("Order Details")); - setAttribute(Qt::WA_DeleteOnClose); - m_changed=false; - - QMenuBar*mb=menuBar(); - QMenu *m=mb->addMenu(tr("&Order")); - m->addAction(tr("&Order..."),this,SLOT(createOrder())) - ->setEnabled((req->hasRole("createorder")&&o.canOrder()) || - (req->hasRole("reservationtoorder")&&o.isReservation())); - m->addAction(tr("&Sell..."),this,SLOT(createSale())) - ->setEnabled((req->hasRole("createsale")&&o.canSell()) || - (req->hasRole("reservationtosale")&&o.isReservation())); - m->addAction(tr("Ma&ke Reservation..."),this,SLOT(createReservation())) - ->setEnabled(req->hasRole("createreservedorder")&&o.canReserve()); - m->addAction(tr("&Prune and recheck..."),this,SLOT(recheckOrder())) - ->setEnabled(o.orderid()<0); - m->addSeparator(); - m->addAction(tr("C&ancel Order..."),this,SLOT(cancelOrder())) - //FIXME - ->setEnabled(req->hasRole("cancelorder")/*&&o.isStored()*/); - m->addAction(tr("&Mark Order as Shipped..."),this,SLOT(shipOrder())) - ->setEnabled(req->hasRole("ordershipped")); - m->addSeparator(); - m->addAction(tr("Ch&ange Item-Price..."),this,SLOT(changeItem())) - ->setEnabled(req->hasRole("changeticketprice")); - m->addAction(tr("&Return Item..."),this,SLOT(itemReturn())) - ->setEnabled(req->hasRole("ticketreturn")); - m->addAction(tr("Change Commen&t..."),this,SLOT(changeComment())) - ->setEnabled(req->hasRole("setordercomment")); - m->addAction(tr("Change Sh&ipping Method..."),this,SLOT(changeShipping())) - ->setEnabled(req->hasRole("changeordershipping")); - m->addSeparator(); - m->addAction(tr("MoneyLog for Order..."),this,SLOT(moneyLogOrder())) - ->setEnabled(req->hasRole("moneylog")); - m->addAction(tr("MoneyLog for selected Voucher..."),this,SLOT(moneyLogVoucher())) - ->setEnabled(req->hasRole("moneylog")); - m->addSeparator(); - m->addAction(tr("&Close"),this,SLOT(close())); - - m=mb->addMenu(tr("&Payment")); - //FIXME: m->setEnabled(o.isStored()); - m->addAction(tr("Receive &Payment..."),this,SLOT(payment())) - ->setEnabled(req->hasRole("orderpay")); - m->addAction(tr("&Refund..."),this,SLOT(refund())) - ->setEnabled(req->hasRole("orderrefund")); - m->addAction(tr("Pay with &Voucher..."),this,SLOT(payvoucher())) - ->setEnabled(req->hasRole("usevoucher")); - - m=mb->addMenu(tr("P&rinting")); - //FIXME: m->setEnabled(o.isStored()); - m->addAction(tr("Print &Bill..."),this,SLOT(printBill())); - m->addAction(tr("Save Bill &as file..."),this,SLOT(saveBill())); - m->addSeparator(); - m->addAction(tr("Print &Tickets..."),this,SLOT(printTickets())); - m->addAction(tr("Print V&ouchers..."),this,SLOT(printVouchers())); - m->addAction(tr("Print &Current Item..."),this,SLOT(printCurrentItem())); - m->addAction(tr("&View Items..."),this,SLOT(itemView())); - - QWidget*w; - setCentralWidget(w=new QWidget); - QVBoxLayout *vl; - w->setLayout(vl=new QVBoxLayout); - - QGridLayout*gl; - vl->addLayout(gl=new QGridLayout,0); - int rw=0; - QLabel*lab; - gl->addWidget(new QLabel(tr("Order ID:")),rw,0); - gl->addWidget(m_orderid=new QLabel(QString::number(m_order.orderid())),rw,1); - gl->addWidget(new QLabel(tr("Order Date:")),++rw,0); - gl->addWidget(m_orderdate=new QLabel(m_order.orderDateTimeStr()),rw,1); - gl->addWidget(new QLabel(tr("Shipping Date:")),++rw,0); - gl->addWidget(m_sentdate=new QLabel(m_order.sentDateTimeStr()),rw,1); - gl->addWidget(new QLabel(tr("Customer:")),++rw,0); - gl->addWidget(new QLabel(m_order.customer().address()),rw,1); - gl->addWidget(new QLabel(tr("Delivery Address:")),++rw,0); - //FIXME:gl->addWidget(lab=new QLabel(m_order.deliveryAddress()),rw,1); - //lab->setWordWrap(true); - gl->addWidget(new QLabel(tr("Sold by:")),++rw,0); - gl->addWidget(new QLabel(m_order.seller()),rw,1); - gl->addWidget(new QLabel(tr("Total Price:")),++rw,0); - gl->addWidget(m_total=new QLabel(m_order.totalPriceString()),rw,1); - gl->addWidget(new QLabel(tr("Already Paid:")),++rw,0); - gl->addWidget(m_paid=new QLabel(m_order.amountPaidString()),rw,1); - gl->addWidget(new QLabel(tr("Order State:")),++rw,0); - gl->addWidget(m_state=new QLabel(m_order.orderStatusString()),rw,1); - gl->addWidget(new QLabel(tr("Shipping Method:")),++rw,0); - //FIXME: - gl->addWidget(m_shipmeth=new QLabel(/*m_order.shipping().description()*/"ship?"),rw,1); - gl->addWidget(new QLabel(tr("Shipping Costs:")),++rw,0); - gl->addWidget(m_shipprice=new QLabel(/*m_order.shipping().priceString()*/),rw,1); - gl->addWidget(new QLabel(tr("Order Comment:")),++rw,0); - //FIXME: - gl->addWidget(m_comment=lab=new QLabel(/*m_order.comment()*/"comment?"),rw,1); - lab->setWordWrap(true); - gl->setColumnStretch(0,0); - gl->setColumnStretch(1,10); - - QSize sz=size(); - - vl->addSpacing(10); - vl->addWidget(m_table=new QTableView,10); - m_table->setModel(m_model=new QStandardItemModel(this)); - m_table->setEditTriggers(QAbstractItemView::NoEditTriggers); - updateTable(); - //make sure everything is visible - QSize vsz=m_table->maximumViewportSize(); - vsz.setWidth(vsz.width()+40); - if(sz.width()dataDir(); -} - -static const int ITEM_TICKET=1; -static const int ITEM_VOUCHER=2; - -void MOrderWindow::updateTable() -{/*TODO: - QList tickets=m_order.tickets(); - QList events; - if(tickets.size()>0) - events=req->getAllEvents(); - QList vouchers=m_order.vouchers(); - m_model->clear(); - m_model->setHorizontalHeaderLabels(QStringList()<insertRows(0,tickets.size()+vouchers.size()); - for(int i=0;isetData(m_model->index(i,0),tickets[i].ticketID()); - m_model->setData(m_model->index(i,0),ITEM_TICKET,Qt::UserRole); - m_model->setData(m_model->index(i,3),tickets[i].statusString()); - m_model->setData(m_model->index(i,4),tickets[i].priceString()); - //find event - MEvent ev;int eid=tickets[i].eventID(); - for(int j=0;jsetData(m_model->index(i,1),ev.title()); - m_model->setData(m_model->index(i,2),ev.startTimeString()); - } - int off=tickets.size(); - for(int i=0;isetData(m_model->index(i+off,0),ITEM_VOUCHER,Qt::UserRole); - m_model->setData(m_model->index(i+off,0),vouchers[i].voucherID()); - m_model->setData(m_model->index(i+off,1),tr("Voucher (current value: %1)").arg(vouchers[i].valueString())); - m_model->setData(m_model->index(i+off,3),vouchers[i].statusString()); - m_model->setData(m_model->index(i+off,4),vouchers[i].priceString()); - } - m_table->resizeColumnsToContents();*/ -} - -void MOrderWindow::setChanged() -{ - m_changed=true; -} - -bool MOrderWindow::isChanged()const -{ - return m_changed; -} - -void MOrderWindow::itemView() -{ - QListtickets=m_order.tickets(); - QListvouchers=m_order.vouchers(); - if(tickets.size()<1 && vouchers.size()<1)return; - MOrderItemView tv(this,tickets,vouchers); - tv.exec(); -} - -void MOrderWindow::printCurrentItem() -{ - //get current ticketid/voucherid - QModelIndexList lst=m_table->selectionModel()->selectedIndexes(); - if(lst.size()<1)return; - QModelIndex idx=m_model->index(lst[0].row(),0); - QString id=m_model->data(idx).toString(); - if(id=="")return; - int type=m_model->data(idx,Qt::UserRole).toInt(); - //find ticket/voucher - if(type==ITEM_TICKET){ - QListticks; - QListtickets=m_order.tickets(); - for(int i=0;ivouchs; - QListvouchers=m_order.vouchers(); - for(int i=0;i ticketsin) -{/*TODO - //reduce ticket list to usable ones - QList tickets; - for(int i=0;igetTemplate("ticket"); - if(!tf.isValid()){ - QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (ticket.xtt). Giving up.")); - return; - } - //get printer settings - QPrinter printer; - restorePrinter(printer,"ticket"); - QPrintDialog pd(&printer,this); - if(pd.exec()!=QDialog::Accepted)return; - storePrinter(printer,"ticket"); - //label arrangement - MTicketRenderer render(tf); - MLabelDialog ld(this,&printer,tickets.size(),render.labelSize(printer)); - if(ld.exec()!=QDialog::Accepted) - return; - //print - QPainter painter(&printer); - for(int i=0;i vouchersin) -{/*TODO - //reduce voucher list to usable ones - QListvouchers; - for(int i=0;i0 && vouchersin[i].xmlState()=="") - vouchers.append(vouchersin[i]); - } - //sanity check - if(vouchers.size()<1){ - QMessageBox::warning(this,tr("Warning"),tr("There are no vouchers left to print.")); - return; - } - //get template - MTemplate tf=req->getTemplate("voucher"); - if(!tf.isValid()){ - QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (voucher.xtt). Giving up.")); - return; - } - //get printer settings - QPrinter printer; - restorePrinter(printer,"voucher"); - QPrintDialog pd(&printer,this); - if(pd.exec()!=QDialog::Accepted)return; - storePrinter(printer,"voucher"); - //label arrangement - MVoucherRenderer render(tf); - MLabelDialog ld(this,&printer,vouchers.size(),render.labelSize(printer)); - if(ld.exec()!=QDialog::Accepted) - return; - //print - QPainter painter(&printer); - for(int i=0;isettingsGroup()+"/"+key); - if(!set.contains("name"))return; - prn.setPrinterName(set.value("name").toString()); - prn.setPrinterSelectionOption(set.value("soption","").toString()); - prn.setPaperSize(QPrinter::PageSize(set.value("paper",QPrinter::Custom).toInt())); - prn.setPaperSize(set.value("papersize").toSizeF(),QPrinter::Point); - qreal ml,mr,mt,mb; - ml=set.value("marginLeft").toDouble(); - mr=set.value("marginRight").toDouble(); - mb=set.value("marginBottom").toDouble(); - mt=set.value("marginTop").toDouble(); - prn.setPageMargins(ml,mr,mb,mt,QPrinter::Point); - prn.setDuplex(QPrinter::DuplexMode(set.value("duplex",QPrinter::DuplexAuto).toInt())); - prn.setOrientation((set.value("orientation","portrait").toString()=="portrait")?QPrinter::Portrait:QPrinter::Landscape); - prn.setResolution(set.value("resolution").toInt()); -#endif -} - -void MOrderWindow::storePrinter(QPrinter&prn,QString key) -{ - QSettings set; - set.beginGroup(req->settingsGroup()+"/"+key); - set.setValue("name",prn.printerName()); -#if !defined(Q_OS_WIN32) && !defined(Q_OS_WINCE) - set.setValue("soption",prn.printerSelectionOption()); -#endif - qreal ml,mr,mt,mb; - prn.getPageMargins(&ml,&mr,&mb,&mt,QPrinter::Point); - set.setValue("marginLeft",ml); - set.setValue("marginRight",mr); - set.setValue("marginBottom",mb); - set.setValue("marginTop",mt); - set.setValue("duplex",(int)prn.duplex()); - set.setValue("orientation",prn.orientation()==QPrinter::Portrait?"portrait":"landscape"); - set.setValue("paper",(int)prn.paperSize()); - set.setValue("papersize",prn.paperSize(QPrinter::Point)); - set.setValue("resolution",prn.resolution()); -} - -void MOrderWindow::printBill() -{/*TODO - //get template - MTemplate tf=req->getTemplate("bill"); - if(!tf.isValid()){ - QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (bill). Giving up.")); - return; - } - //mark order as shipped? - if(m_order.orderStatus()==MOrder::Placed) - if(QMessageBox::question(this,tr("Mark as shipped?"),tr("Mark this order as shipped now?"),QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes)==QMessageBox::Yes){ - m_order.shipOrder(); - m_state->setText(m_order.orderStatusString()); - m_sentdate->setText(m_order.sentDateTimeStr()); - } - //print bill - initPrintBuffer(); - MOdtSignalRenderer rend(tf); - connect(&rend,SIGNAL(getVariable(QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getVariable(QString,MOdtRenderer::VarType&,QVariant&))); - connect(&rend,SIGNAL(getLoopIterations(QString,int&)),this,SLOT(getLoopIterations(QString,int&))); - connect(&rend,SIGNAL(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&))); - rend.renderToPrinter(); - donePrintBuffer();*/ -} - -void MOrderWindow::saveBill() -{/*TODO - //get template - MTemplate tf=req->getTemplate("bill"); - if(!tf.isValid()){ - QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (bill). Giving up.")); - return; - } - //get target file name - QFileDialog fd(this); - fd.setAcceptMode(QFileDialog::AcceptSave); - fd.setFileMode(QFileDialog::AnyFile); - fd.setConfirmOverwrite(true); - fd.setFilter(tr("Open Document File (*.%1)").arg(tf.targetExtension())); - fd.setDefaultSuffix(tf.targetExtension()); - QString fname; - if(fd.exec()){ - QStringList fn=fd.selectedFiles(); - if(fn.size()<1)return; - fname=fn[0]; - } - //mark order as shipped? - if(m_order.orderStatus()==MOrder::Placed) - if(QMessageBox::question(this,tr("Mark as shipped?"),tr("Mark this order as shipped now?"),QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes)==QMessageBox::Yes){ - m_order.shipOrder(); - m_state->setText(m_order.orderStatusString()); - m_sentdate->setText(m_order.sentDateTimeStr()); - } - //render bill - initPrintBuffer(); - MOdtSignalRenderer rend(tf); - connect(&rend,SIGNAL(getVariable(QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getVariable(QString,MOdtRenderer::VarType&,QVariant&))); - connect(&rend,SIGNAL(getLoopIterations(QString,int&)),this,SLOT(getLoopIterations(QString,int&))); - connect(&rend,SIGNAL(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&)),this,SLOT(getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&))); - rend.renderToFile(fname); - donePrintBuffer();*/ -} - -void MOrderWindow::getVariable(QString vn,MOdtRenderer::VarType& av,QVariant&value) -{/*TODO - if(vn=="ORDERDATE"){ - value=m_order.orderDateTime().toTime_t(); - av=MOdtRenderer::DateVar; - }else - if(vn=="ORDERDATETIME"){ - value=m_order.orderDateTime().toTime_t(); - av=MOdtRenderer::DateTimeVar; - }else - if(vn=="SENTDATE"){ - value=m_order.sentDateTime().toTime_t(); - av=MOdtRenderer::DateVar; - }else - if(vn=="SENTDATETIME"){ - value=m_order.sentDateTime().toTime_t(); - av=MOdtRenderer::DateTimeVar; - }else - if(vn=="CUSTOMERID")value=QString::number(m_order.customerID());else - if(vn=="ORDERID")value=QString::number(m_order.orderID());else - if(vn=="ADDRESS")value=m_order.customer().address();else - if(vn=="FULLADDRESS")value=m_order.customer().getNameAddress();else - if(vn=="NAME")value=m_order.customer().name();else - if(vn=="DELIVERYADDRESS")value=m_order.deliveryAddress();else - if(vn=="FINALADDRESS"){ - QString v=m_order.deliveryAddress(); - if(v.trimmed()=="")v=m_order.customer().getNameAddress(); - value=v; - }else - if(vn=="TOTALPRICE"){ - value=m_order.totalPrice(); - av=MOdtRenderer::MoneyVar; - }else - if(vn=="AMOUNTPAID"){ - value=m_order.amountPaid(); - av=MOdtRenderer::MoneyVar; - }else - if(vn=="SELLER")value=m_order.seller();else - if(vn=="COMMENT")value=m_order.comment();else - if(vn=="AMOUNTTOPAY"){ - value=m_order.amountToPay(); - av=MOdtRenderer::MoneyVar; - }else - if(vn=="AMOUNTTOREFUND"){ - value=m_order.amountToRefund(); - av=MOdtRenderer::MoneyVar; - }else - if(vn=="TICKETS"){ - value=printBuffer.tickets.size(); - av=MOdtRenderer::IntVar; - }else - if(vn=="ACCTICKETS"){ - value=printBuffer.tickinfo.size(); - av=MOdtRenderer::IntVar; - }else - if(vn=="VOUCHERS"){ - value=printBuffer.vouchers.size(); - av=MOdtRenderer::IntVar; - }else - if(vn=="ADDRESSLINES"){ - value=m_order.customer().address().split("\n").size(); - av=MOdtRenderer::IntVar; - }else - if(vn=="SHIPPING")value=m_order.shipping().description();else - if(vn=="SHIPPINGPRICE"){ - value=m_order.shipping().price(); - av=MOdtRenderer::MoneyVar; - }*/ -} - -void MOrderWindow::getLoopIterations(QString loopname,int&iterations) -{ - if(loopname=="TICKETS")iterations=printBuffer.tickets.size(); - if(loopname=="ACCTICKETS")iterations=printBuffer.tickinfo.size(); - if(loopname=="VOUCHERS")iterations=printBuffer.vouchers.size(); - if(loopname=="ADDRESSLINES")iterations=m_order.customer().address().split("\n").size(); -} -void MOrderWindow::getLoopVariable(QString loopname,int it,QString vn,MOdtRenderer::VarType& av,QVariant&value) -{ - if(loopname=="TICKETS"){ - QList &tickets=printBuffer.tickets; - if(it<0 || it>=tickets.size())return; - - if(vn=="PRICE"){ - value=tickets[it].price().value(); - av=MOdtRenderer::MoneyVar; - }else - if(vn=="ID")value=tickets[it].ticketid().value();else - if(vn=="TITLE")value=tickets[it].event().title().value();else - if(vn=="ARTIST")value=tickets[it].event().artist().value().name().value();else - if(vn=="DATE"){ - value=tickets[it].event().start().value(); - av=MOdtRenderer::DateVar; - }else - if(vn=="STARTTIME"){ - value=tickets[it].event().start().value(); - av=MOdtRenderer::DateTimeVar; - }else - if(vn=="ENDTIME"){ - value=tickets[it].event().end().value(); - av=MOdtRenderer::DateTimeVar; - }else - if(vn=="ROOM")value=tickets[it].event().room().value(); - }else if(loopname=="ACCTICKETS"){ - QList &tickets=printBuffer.tickinfo; - if(it<0 || it>=tickets.size())return; - - if(vn=="PRICE"){ - value=tickets[it].proto.price().value(); - av=MOdtRenderer::MoneyVar; - }else - if(vn=="FULLPRICE"){ - value=tickets[it].proto.price().value()*tickets[it].amount; - av=MOdtRenderer::MoneyVar; - }else - if(vn=="TITLE")value=tickets[it].proto.event().title().value();else - if(vn=="ARTIST")value=tickets[it].proto.event().artist().value().name().value();else - if(vn=="DATE"){ - value=tickets[it].proto.event().start().value(); - av=MOdtRenderer::DateVar; - }else - if(vn=="STARTTIME"){ - value=tickets[it].proto.event().start().value(); - av=MOdtRenderer::DateTimeVar; - }else - if(vn=="ENDTIME"){ - value=tickets[it].proto.event().end().value(); - av=MOdtRenderer::DateTimeVar; - }else - if(vn=="ROOM")value=tickets[it].proto.event().room().value();else - if(vn=="AMOUNT"){ - value=tickets[it].amount; - av=MOdtRenderer::IntVar; - } - }else if(loopname=="VOUCHERS"){ - if(it<0 || it>=printBuffer.vouchers.size())return; - - if(vn=="PRICE"){ - value=printBuffer.vouchers[it].price().value(); - av=MOdtRenderer::MoneyVar; - }else - if(vn=="VALUE"){ - value=printBuffer.vouchers[it].value().value(); - av=MOdtRenderer::MoneyVar; - }else - if(vn=="ID")value=printBuffer.vouchers[it].voucherid().value(); - }else if(loopname=="ADDRESSLINES"){ - QStringList lst=m_order.customer().address().split("\n"); - if(it<0 || it>=lst.size())return; - value=lst[it]; - }else - return /*empty handed*/; -} - -void MOrderWindow::donePrintBuffer() -{ - printBuffer.tickets.clear(); - printBuffer.vouchers.clear(); - printBuffer.tickinfo.clear(); -} - -static inline bool compare(const MTicket&a,const MTicket&b) -{ - if(a.eventid()!=b.eventid())return false; - if(a.price()!=b.price())return false; - return true; -} - -void MOrderWindow::initPrintBuffer() -{/*TODO: - //clear - donePrintBuffer(); - //get tickets (only valid ones) - QListtlst=m_order.tickets(); - for(int i=0;ivlst=m_order.vouchers(); - for(int i=0;irequest("orderpay",rq)){ - QMessageBox::warning(this,tr("Warning"),tr("Unable to submit payment request.")); - return; - } - if(req->responseStatus()!=MWebRequest::Ok){ - QMessageBox::warning(this,tr("Warning"),tr("Error while trying to pay: %1").arg(qApp->translate("php::",req->responseBody()))); - return; - } - m_order.setAmountPaid(req->responseBody().trimmed().toInt()); - m_paid->setText(m_order.amountPaidString());*/ -} - -void MOrderWindow::payvoucher() -{/*TODO - if(!m_order.isValid())return; - //get voucher - bool ok; - QString vid=QInputDialog::getText(this,tr("Enter Voucher"),tr("Please enter the ID of the voucher you want to use:"),QLineEdit::Normal,"",&ok); - if(!ok)return; - if(vid=="")return; - MVoucher vou(req,vid); - if(!vou.isValid()){ - QMessageBox::warning(this,tr("Warning"),tr("This voucher is not valid.")); - return; - } - //submit - QByteArray rq=vid.toAscii()+"\n"+QByteArray::number(m_order.orderID()); - if(!req->request("usevoucher",rq)){ - QMessageBox::warning(this,tr("Warning"),tr("Unable to submit payment request.")); - return; - } - if(req->responseStatus()!=MWebRequest::Ok){ - QMessageBox::warning(this,tr("Warning"),tr("Error while trying to pay: %1").arg(qApp->translate("php::",req->responseBody()))); - return; - } - QStringList sl=QString::fromAscii(req->responseBody().trimmed()).split("\n"); - if(sl.size()>1){ - m_order.setAmountPaid(sl[1].toInt()); - m_paid->setText(m_order.amountPaidString()); - } - if(sl.size()>0){ - QMessageBox::information(this,tr("Voucher Info"),tr("Remaining value of this voucher: %1").arg(cent2str(sl[0].toInt()))); - }*/ -} - -void MOrderWindow::refund() -{/*TODO - if(!m_order.isValid())return; - //get value - bool ok; - int pay=MCentDialog::getCents(this,tr("Enter Refund"),tr("Please enter the amount that will be refunded:"),m_order.amountToRefund(),m_order.amountToRefund(),&ok); - if(!ok)return; - if(pay<=0)return; - //submit - QByteArray rq=QByteArray::number(m_order.orderID())+" "+QByteArray::number(pay); - if(!req->request("orderrefund",rq)){ - QMessageBox::warning(this,tr("Warning"),tr("Unable to submit refund request.")); - return; - } - if(req->responseStatus()!=MWebRequest::Ok){ - QMessageBox::warning(this,tr("Warning"),tr("Error whily trying to refund: %1").arg(qApp->translate("php::",req->responseBody()))); - return; - } - m_order.setAmountPaid(req->responseBody().trimmed().toInt()); - m_paid->setText(m_order.amountPaidString());*/ -} - -void MOrderWindow::changeItem() -{/*TODO - if(!m_order.isValid())return; - //get ticket selection - QModelIndexList lst=m_table->selectionModel()->selectedIndexes(); - if(lst.size()<1)return; - QModelIndex idx=m_model->index(lst[0].row(),0); - QString id=m_model->data(idx).toString(); - if(id=="")return; - int type=m_model->data(idx,Qt::UserRole).toInt(); - if(type==ITEM_TICKET){ - //find ticket - QListtickets=m_order.tickets(); - MTicket tick; - for(int i=0;isetText(m_order.totalPriceString()); - updateTable();*/ -} - -void MOrderWindow::itemReturn() -{/*TODO - if(!m_order.isValid())return; - //get ticket selection - QModelIndexList lst=m_table->selectionModel()->selectedIndexes(); - if(lst.size()<1)return; - QModelIndex idx=m_model->index(lst[0].row(),0); - QString id=m_model->data(idx).toString(); - if(id=="")return; - int type=m_model->data(idx,Qt::UserRole).toInt(); - if(type==ITEM_TICKET){ - //find ticket - QListtickets=m_order.tickets(); - MTicket tick; - for(int i=0;isetText(m_order.totalPriceString()); - updateTable(); - if(r!="")QMessageBox::warning(this,tr("Warning"),trUtf8(r.toUtf8())); - }else - if(type==ITEM_VOUCHER){ - //find ticket - QListvouchers=m_order.vouchers(); - MVoucher vou; - for(int i=0;isetText(m_order.totalPriceString()); - updateTable(); - if(r!="")QMessageBox::warning(this,tr("Warning"),trUtf8(r.toUtf8())); - }else - QMessageBox::warning(this,tr("Warning"),tr("Cannot return this item type."));*/ -} - -void MOrderWindow::cancelOrder() -{/*TODO - if(QMessageBox::question(this,tr("Cancel Order?"),tr("Cancel this order now?"),QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes)!=QMessageBox::Yes)return; - if(m_order.orderStatus()!=MOrder::Placed && m_order.orderStatus()!=MOrder::Reserved){ - QMessageBox::warning(this,tr("Warning"),tr("Cannot cancel this order: it is in the wrong state.")); - return; - } - if(!m_order.cancelOrder()){ - QMessageBox::warning(this,tr("Warning"),tr("Failed to cancel this order.")); - }else - m_state->setText(m_order.orderStatusString());*/ -} - -void MOrderWindow::createOrder(Create mode) -{/*TODO - MOrder ord; - //handle reservation changes specially - if(m_order.orderStatus()==MOrder::Reserved){ - bool ok=false; - ord=m_order; - switch(mode){ - case CreateOrder:ok=ord.reservationToOrder();break; - case CreateSale:ok=ord.reservationToSale();break; - default:ok=false; - } - if(!ok)return; - }else{ - //handle case of new order - switch(mode){ - case CreateSale:ord=m_order.createSale();break; - case CreateOrder:ord=m_order.createOrder();break; - case CreateReservation:ord=m_order.createReservation();break; - } - if(!ord.isValid())return; - } - //display final order - MOrderWindow *ow=new MOrderWindow(parentWidget(),req,ord); - ow->show(); - //undisplay self - close();*/ -} - -void MOrderWindow::createSale() -{ - createOrder(CreateSale); -} - -void MOrderWindow::createReservation() -{ - createOrder(CreateReservation); -} - -void MOrderWindow::recheckOrder() -{/*TODO - //prune - m_order.pruneInvalid(); - //now check - MOrder ord; - ord=m_order.createOrder("checkorder"); - if(!ord.isValid())return; - //display final order - MOrderWindow *ow=new MOrderWindow(parentWidget(),req,ord); - ow->show(); - //undisplay self - close();*/ -} - -void MOrderWindow::shipOrder() -{/*TODO - if(QMessageBox::question(this,tr("Mark as shipped?"),tr("Mark this order as shipped now?"),QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes)==QMessageBox::Yes){ - QDateTime tm=QDateTime::currentDateTime(); - if(req->hasRole("_explicitshipdate")){ - QDialog d; - d.setWindowTitle(tr("Set shipping time")); - QHBoxLayout*hl; - QVBoxLayout*vl; - QPushButton*p; - QDateTimeEdit*dte; - d.setLayout(vl=new QVBoxLayout); - vl->addWidget(new QLabel(tr("Enter the shipping time:"))); - vl->addWidget(dte=new QDateTimeEdit(tm)); - vl->addSpacing(10); - vl->addStretch(10); - vl->addLayout(hl=new QHBoxLayout); - hl->addStretch(10); - 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; - tm=dte->dateTime(); - } - m_order.shipOrder(tm); - m_state->setText(m_order.orderStatusString()); - m_sentdate->setText(m_order.sentDateTimeStr()); - }*/ -} - -void MOrderWindow::changeComment() -{/*TODO - //create editor dialog - QString cmt=m_order.comment(); - QDialog d; - d.setWindowTitle(tr("Set comment: order %1").arg(m_order.orderID())); - QVBoxLayout*vl; - d.setLayout(vl=new QVBoxLayout); - QTextEdit*te; - vl->addWidget(te=new QTextEdit,1); - te->setPlainText(cmt); - vl->addSpacing(15); - QHBoxLayout*hl; - vl->addLayout(hl=new QHBoxLayout,0); - hl->addStretch(10); - QPushButton*p; - hl->addWidget(p=new QPushButton(tr("&Save"))); - connect(p,SIGNAL(clicked()),&d,SLOT(accept())); - hl->addWidget(p=new QPushButton(tr("&Cancel"))); - connect(p,SIGNAL(clicked()),&d,SLOT(reject())); - //get status - if(d.exec()!=QDialog::Accepted)return; - //send to server - m_order.sendComment(cmt=te->toPlainText()); - //reset display - m_comment->setText(cmt);*/ -} - -void MOrderWindow::changeShipping() -{/*TODO - //create editor dialog - MShippingChange d(this,req,m_order.shipping()); - //get status - if(d.exec()!=QDialog::Accepted)return; - //send to server - m_order.sendShipping(d.selection()); - //reset display - m_shipmeth->setText(m_order.shipping().description()); - m_shipprice->setText(m_order.shipping().priceString()); - m_total->setText(m_order.totalPriceString());*/ -} - -void MOrderWindow::moneyLogOrder() -{ - if(m_order.orderid()<0)return; - MMoneyLog ml(this,"order\n"+QString::number(m_order.orderid())); - ml.exec(); -} - -void MOrderWindow::moneyLogVoucher() -{ - if(m_order.orderid()<0)return; - //get selection - if(!m_order.isValid())return; - //get ticket selection - QModelIndexList lst=m_table->selectionModel()->selectedIndexes(); - if(lst.size()<1)return; - QModelIndex idx=m_model->index(lst[0].row(),0); - QString id=m_model->data(idx).toString(); - if(id=="")return; - int type=m_model->data(idx,Qt::UserRole).toInt(); - if(type==ITEM_VOUCHER){ - MMoneyLog ml(this,"voucher\n"+id); - ml.exec(); - }else - QMessageBox::warning(this,tr("Warning"),tr("This is not a voucher, cannot show the money log.")); -} - - -/*************************************************************************************/ - -MOrderItemView::MOrderItemView(QWidget*w,QListt,QListv) - :QDialog(w),tickets(t),vouchers(v) -{ - setWindowTitle(tr("Preview Tickets")); - - QVBoxLayout*vl; - setLayout(vl=new QVBoxLayout); - QComboBox *cb; - vl->addWidget(cb=new QComboBox,0); - cb->setEditable(false); - for(int i=0;iaddItem(tr("Ticket: ")+tickets[i].ticketid()); - for(int i=0;iaddItem(tr("Voucher: ")+vouchers[i].voucherid()); - vl->addWidget(disp=new QLabel,10); - //get the templates - /*TODO - trender=new MTicketRenderer(req->getTemplate("ticket")); - vrender=new MVoucherRenderer(req->getTemplate("voucher")); - */ - changeItem(0); - connect(cb,SIGNAL(currentIndexChanged(int)),this,SLOT(changeItem(int))); -} - -MOrderItemView::~MOrderItemView() -{ - //FIXME - //delete trender; - //delete vrender; -} - -void MOrderItemView::changeItem(int idx) -{/*TODO - //ticket or voucher? - if(idxlabelSize(*disp); - QPixmap tick(sz.toSize()); - tick.fill(); - if(!trender->render(tickets[idx],tick)) - qDebug("unable to render"); - disp->setPixmap(tick); - }else{ - QSizeF sz=vrender->labelSize(*disp); - QPixmap tick(sz.toSize()); - tick.fill(); - if(!vrender->render(vouchers[idx-tickets.size()],tick)) - qDebug("unable to render"); - disp->setPixmap(tick); - }*/ -} - - -/*************************************************************************************/ - -MShippingChange::MShippingChange(QWidget*pa,MOShipping s) - :QDialog(pa) -{ - all=req->queryGetAllShipping().getshipping(); - setWindowTitle(tr("Change Shipping Method")); - - int cid=-1; - //FIXME: - //if(s.isValid())cid=s.id(); - - QGridLayout*gl; - setLayout(gl=new QGridLayout); - gl->addWidget(new QLabel(tr("Method:")),0,0); - gl->addWidget(opt=new QComboBox,0,1); - gl->addWidget(new QLabel(tr("Price:")),1,0); - gl->addWidget(prc=new MCentSpinBox,1,1); - gl->setRowMinimumHeight(2,15); - gl->setRowStretch(2,1); - QHBoxLayout*hl; - 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()),this,SLOT(accept())); - hl->addWidget(p=new QPushButton(tr("Cancel"))); - connect(p,SIGNAL(clicked()),this,SLOT(reject())); - - prc->setRange(0,1000000000);//hmm, even in Yen this should be big enough - prc->setValue(s.cost()); - prc->setEnabled(req->hasRole("orderchangeshipping")); - - opt->addItem(tr("(None)","shipping method")); - int scid=0; - for(int i=0;iaddItem(all[i].description()); - if(all[i].id().value()==cid) - scid=i+1; - } - opt->setCurrentIndex(scid); - connect(opt,SIGNAL(currentIndexChanged(int)),this,SLOT(changeItem(int))); -} - -MOShipping MShippingChange::selection()const -{ - int cid=opt->currentIndex(); - if(cid==0)return MOShipping(); - MOShipping cp=all[cid-1]; - cp.setcost(price()); - return cp; -} - -int MShippingChange::price()const -{ - return prc->value(); -} - -void MShippingChange::changeItem(int cid) -{ - if(cid==0)prc->setValue(0); - else prc->setValue(all[cid-1].cost()); -} diff --git a/src/orderwin.h b/src/orderwin.h deleted file mode 100644 index dd902ed..0000000 --- a/src/orderwin.h +++ /dev/null @@ -1,187 +0,0 @@ -// -// C++ Interface: orderwin -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_ORDERWIN_H -#define MAGICSMOKE_ORDERWIN_H - -#include -#include "order.h" -#include "odtrender.h" -#include "MOShipping.h" - -class QLabel; -class QTableView; -class QStandardItemModel; - -/**displays an order and allows the user to execute several commands on it*/ -class MOrderWindow:public QMainWindow -{ - Q_OBJECT - public: - /**creates the order window*/ - MOrderWindow(QWidget*,const MOrder&); - - /**returns whether the order has been changed by this window*/ - bool isChanged()const; - - private: - /**helper enum for create* methods*/ - enum Create{CreateOrder,CreateSale,CreateReservation}; - - private slots: - /**internal: mark order as changed*/ - void setChanged(); - - /**internal: updates the ticket table*/ - void updateTable(); - - /**internal: show the tickets as graphics*/ - void itemView(); - /**internal: print the currently selected ticket*/ - void printCurrentItem(); - /**internal: print all tickets*/ - void printTickets(); - /**internal helper: print list of tickets*/ - void printTickets(QList); - /**internal: print all vouchers*/ - void printVouchers(); - /**internal helper: print list of vouchers*/ - void printVouchers(QList); - - /**print a bill*/ - void printBill(); - /**save the bill as file*/ - void saveBill(); - /**callback for bill generator: variables; see MOdtSignalRenderer for details*/ - void getVariable(QString,MOdtRenderer::VarType&,QVariant&); - /**callback for bill generator: loops; see MOdtSignalRenderer for details*/ - void getLoopIterations(QString loopname,int&iterations); - /**callback for bill generator: loop variables; see MOdtSignalRenderer for details*/ - void getLoopVariable(QString,int,QString,MOdtRenderer::VarType&,QVariant&); - - /**received payment*/ - void payment(); - /**generate a refund*/ - void refund(); - /**pay with a voucher*/ - void payvoucher(); - - /**change a ticket/voucher price*/ - void changeItem(); - /**return a ticket/voucher*/ - void itemReturn(); - - /**change the comment on the order*/ - void changeComment(); - - /**change the shipping option*/ - void changeShipping(); - - /**cancel the order*/ - void cancelOrder(); - /**mark as shipped*/ - void shipOrder(); - - /**create a new order*/ - void createOrder(Create mode=CreateOrder); - - /**create a sale*/ - void createSale(); - - /**create a new reservation*/ - void createReservation(); - - /**prune and recheck the order*/ - void recheckOrder(); - - /**money log for the order*/ - void moneyLogOrder(); - /**money log for a voucher*/ - void moneyLogVoucher(); - - private: - MOrder m_order; - bool m_changed; - QLabel *m_orderid,*m_orderdate,*m_sentdate,*m_state,*m_paid,*m_total,*m_comment, - *m_shipmeth,*m_shipprice; - QTableView *m_table; - QStandardItemModel *m_model; - - //printing buffer - struct TickInfo{ - TickInfo(const MTicket&t):proto(t){amount=1;} - TickInfo(const TickInfo&t):proto(t.proto){amount=t.amount;} - TickInfo(){amount=0;} - MTicket proto; - int amount; - }; - struct PrintBuffer{ - QList tickets; - QList vouchers; - QList tickinfo; - }printBuffer; - void initPrintBuffer(); - void donePrintBuffer(); - - //helper: fetches printer settings from registry - void restorePrinter(QPrinter&,QString); - //helper: stores printer settings in registry - void storePrinter(QPrinter&,QString); -}; - -class MTicketRenderer; -class MVoucherRenderer; - -/**helper class: displays tickets and vouchers*/ -class MOrderItemView:public QDialog -{ - Q_OBJECT - public: - MOrderItemView(QWidget*,QList,QList); - ~MOrderItemView(); - - private slots: - void changeItem(int); - private: - QList tickets; - QList vouchers; - QLabel*disp; - MTicketRenderer*trender; - MVoucherRenderer*vrender; -}; - -class MCentSpinBox; -class QComboBox; - -/**helper class: allows to change the shipping option*/ -class MShippingChange:public QDialog -{ - Q_OBJECT - public: - /**creates the dialog*/ - MShippingChange(QWidget*,MOShipping); - - /**returns the selected shipping option, including corrected price*/ - MOShipping selection()const; - /**returns the entered price in cent*/ - int price()const; - - private slots: - /**internal: updates price when new option is selected*/ - void changeItem(int); - private: - QList all; - QComboBox*opt; - MCentSpinBox*prc; -}; - -#endif diff --git a/src/overview.cpp b/src/overview.cpp deleted file mode 100644 index 33d9424..0000000 --- a/src/overview.cpp +++ /dev/null @@ -1,1753 +0,0 @@ -// -// C++ Implementation: overview -// -// Description: -// -// -// Author: Konrad Rosenbaum , (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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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; - } - QListevl=gae.getevents(); - eventmodel->clear(); - eventmodel->insertColumns(0,6); - eventmodel->setHorizontalHeaderLabels(QStringList()<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(); - QListship=sh.getshipping(); - for(int i=0;iaddItem(ship[i].description(),(int)ship[i].id()); -} - -void MOverview::updateUsers() -{ - MTGetAllUsers au=req->queryGetAllUsers(); - if(au.hasError())return; - QListusl=au.getusers(); - usermodel->clear(); - usermodel->insertColumns(0,2); - usermodel->insertRows(0,usl.size()); - usermodel->setHorizontalHeaderLabels(QStringList()<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<rowCount();i++) - rplc<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(); - QListhsl=req->getAllHosts(); - hostmodel->clear(); - hostmodel->insertColumns(0,2); - hostmodel->insertRows(0,hsl.size()); - hostmodel->setHorizontalHeaderLabels(QStringList()<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()<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); - QListprc=req->getVoucherPrices(); - mdl.insertRows(0,prc.size()); - mdl.insertColumns(0,1); - for(int i=0;iaddWidget(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(®v); - }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(®v); - 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;irowCount();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;jdata(idx).toInt(); - int price=cartmodel->data(idx,CART_PRICEROLE).toInt(); - int value=cartmodel->data(idx,CART_VALUEROLE).toInt(); - for(int j=0;jcurrentIndex()>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;irowCount();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()<itemData(ordermode->currentIndex()).toInt(); - if(omode==ORDERNONE)return; - QList orders=req->getAllOrders(); - if(orders.size()==0)return; - QList cust=req->getAllCustomers(); - int cl=0; - for(int i=0;iinsertRow(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;jsetData(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 - QListeventids; - for(int i=0;idata(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()< orders=req->getOrdersByEvents(eventids); - if(orders.size()==0)return; - QList cust=req->getAllCustomers(); - for(int cl=0;clinsertRow(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;jsetData(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()< orders=req->getAllOrders(); - if(orders.size()==0)return; - QList cust=req->getAllCustomers(); - int cl=0; - for(int i=0;iinsertRow(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(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/overview.h b/src/overview.h deleted file mode 100644 index dfd5a43..0000000 --- a/src/overview.h +++ /dev/null @@ -1,235 +0,0 @@ -// -// C++ Interface: overview -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2007 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_OVERVIEW_H -#define MAGICSMOKE_OVERVIEW_H - -#include -#include -#include -#include -#include - -#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/smoke.pro b/src/smoke.pro index fab326a..ccdba23 100644 --- a/src/smoke.pro +++ b/src/smoke.pro @@ -22,64 +22,21 @@ RCC_DIR = .ctmp SOURCES = \ main.cpp \ - debug.cpp \ - misc.cpp \ - keygen.cpp \ login.cpp \ - configdialog.cpp \ - hmac.cpp \ - code39.cpp \ - overview.cpp \ - eventedit.cpp \ event.cpp \ - user.cpp \ - host.cpp \ order.cpp \ shipping.cpp \ - customer.cpp \ - eventsummary.cpp \ - odtrender.cpp \ - ticketrender.cpp \ - orderwin.cpp \ - labeldlg.cpp \ - templates.cpp \ - templatedlg.cpp \ - office.cpp \ - moneylog.cpp \ - domquery.cpp \ - msinterface.cpp \ - sslexception.cpp + customer.cpp HEADERS = \ main.h \ - keygen.h \ - debug.h \ login.h \ - configdialog.h \ - hmac.h \ - overview.h \ - eventedit.h \ event.h \ - user.h \ - host.h \ order.h \ shipping.h \ - customer.h \ - eventsummary.h \ - odtrender.h \ - ticketrender.h \ - orderwin.h \ - labeldlg.h \ - misc.h \ - templates.h \ - templatedlg.h \ - office.h \ - moneylog.h \ - domquery.h \ - msinterface.h \ - sslexception.h + customer.h -RESOURCES += files.qrc +RESOURCES += images/files.qrc TRANSLATIONS = \ smoke_de.ts \ @@ -90,4 +47,12 @@ TRANSLATIONS = \ include(../zip/zip.pri) include(widgets/widgets.pri) include(wbase/wbase.pri) +include(templates/templates.pri) +include(iface/iface.pri) +include(misc/misc.pri) +include(crypto/crypto.pri) +include(dialogs/dialogs.pri) +include(mwin/mwin.pri) + +#build generated stuff last include(wob/wob.pri) diff --git a/src/sslexception.cpp b/src/sslexception.cpp deleted file mode 100644 index c060d0a..0000000 --- a/src/sslexception.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// -// C++ Implementation: sslexception -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2009 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "sslexception.h" - -#include -#include -#include -#include -#include - -MSslExceptions::MSslExceptions(QString p) -{ - path=p; - //load... - QFile fd(p); - if(fd.open(QIODevice::ReadOnly)){ - QDomDocument doc; - if(!doc.setContent(&fd))return; - fd.close(); - QDomElement root=doc.documentElement(); - QDomNodeList nl=root.elementsByTagName("SSL-Exception"); - for(int i=0;i(c,e)); - } - } -} - -void MSslExceptions::savesslexcept() -{ - QDomDocument doc; - QDomElement root=doc.createElement("SSL-Exceptions"); - for(int i=0;i&errs) -{ - //stage 1: record unknown exceptions - for(int i=0;ip(errs[i].certificate(),errs[i].error()); - bool known=false; - for(int j=0;jp(errs[i].certificate(),errs[i].error()); - bool known=false; - for(int j=0;j, (C) 2009 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_SSLEXCEPTION_H -#define MAGICSMOKE_SSLEXCEPTION_H - -#include -#include -#include -#include -#include -#include -#include - -class QWidget; - -/**Helper class: stores and compares SSL-Exceptions*/ -class MSslExceptions -{ - public: - /**create instance from file in path*/ - MSslExceptions(QString path); - - /**saves the exceptions to config file for next session*/ - void savesslexcept(); - /**checks errors against the exception list, records all exceptions*/ - bool checksslexcept(const QList&); - - /**returns the current list of acceptable exceptions*/ - QList > nonFatalExceptions()const{return sslexcept;} - - /**returns the list of collected exceptions*/ - QList > collectedExceptions()const{return sslrecord;} - - /**clears the internal lists of exceptions*/ - void clear(); - - /**clears the list of recorded exceptions*/ - void clearRecorded(){sslrecord.clear();} - - /**accepts the recorded exceptions*/ - void acceptRecorded(); - - private: - QList > sslexcept,sslrecord; - QString path; -}; - -#endif diff --git a/src/templatedlg.cpp b/src/templatedlg.cpp deleted file mode 100644 index 641b834..0000000 --- a/src/templatedlg.cpp +++ /dev/null @@ -1,228 +0,0 @@ -// -// C++ Implementation: templatedlg -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "templatedlg.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MTemplateChoice::MTemplateChoice(const QString&cd,const QString&tname,const QStringList&choices,const QString&sg) - :sgroup(sg),cachedir(cd) -{ - setWindowTitle(tr("Chose Template")); - QVBoxLayout *vl; - setLayout(vl=new QVBoxLayout); - vl->addWidget(new QLabel(tr("Please chose a variant of template %1:").arg(tname))); - vl->addWidget(box=new QComboBox); - box->setEditable(false); - QSettings set; - set.beginGroup(sg); - for(int i=0;i1)v=vs[1]; - else v=tr("(default)","default template pseudo-variant"); - d=set.value(choices[i]+"/description").toString(); - box->addItem(v+": "+d,choices[i]); - } - vl->addStretch(1); - QHBoxLayout *hl; - vl->addLayout(hl=new QHBoxLayout); - hl->addStretch(1); - QPushButton*p; - hl->addWidget(p=new QPushButton(tr("Ok"))); - p->setDefault(true); - connect(p,SIGNAL(clicked()),this,SLOT(accept())); -} - -MTemplate MTemplateChoice::choice()const -{ - QString fn=box->itemData(box->currentIndex()).toString(); - QSettings set; - set.beginGroup(sgroup+"/"+fn); - return MTemplate(cachedir+"/"+fn, set.value("checksum").toString(), set.value("description").toString()); -} - - - -/**************************************************************/ - -MTemplateEditor::MTemplateEditor(MTemplateStore*s) -{ - store=s; - nochange=false; - - setWindowTitle(tr("Edit Template Directory")); - - QHBoxLayout*hl; - QVBoxLayout*vl,*vl2; - - setLayout(vl=new QVBoxLayout); - vl->addLayout(hl=new QHBoxLayout,1); - hl->addWidget(tree=new QTreeView,1); - tree->setModel(model=new QStandardItemModel(this)); - connect(model,SIGNAL(itemChanged(QStandardItem*)),this,SLOT(changeDescr(QStandardItem*))); - QPushButton*p; - hl->addLayout(vl2=new QVBoxLayout); - vl2->addWidget(p=new QPushButton(tr("Update Now"))); - connect(p,SIGNAL(clicked()),this,SLOT(forceUpdate())); - vl2->addWidget(p=new QPushButton(tr("Add Variant"))); - connect(p,SIGNAL(clicked()),this,SLOT(addItem())); - vl2->addWidget(p=new QPushButton(tr("Delete Variant"))); - connect(p,SIGNAL(clicked()),this,SLOT(deleteItem())); - vl2->addStretch(1); - - vl->addSpacing(15); - vl->addLayout(hl=new QHBoxLayout); - hl->addStretch(1); - hl->addWidget(p=new QPushButton(tr("Close"))); - connect(p,SIGNAL(clicked()),this,SLOT(accept())); - - updateView(); -} - -static const int BASEROLE=Qt::UserRole; -static const int NAMEROLE=Qt::UserRole+1; - -void MTemplateEditor::updateView() -{ - //basic cleanup - nochange=true; - model->clear(); - model->insertColumns(0,3); - model->setHorizontalHeaderLabels(QStringList()<all=store->allTemplates(); - QMap >hier; - for(int i=0;i()); - hier[b].append(all[i]); - } - //create hierarchy - qSort(base); - model->insertRows(0,base.size()); - for(int i=0;iindex(i,0); - model->setData(idx,base[i]); - model->setData(idx,base[i],BASEROLE); - model->setData(idx,"",NAMEROLE); - model->itemFromIndex(idx)->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); - model->setData(model->index(i,1),""); - model->itemFromIndex(model->index(i,1))->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); - model->setData(model->index(i,2),""); - model->itemFromIndex(model->index(i,1))->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); - if(!hier.contains(base[i]))continue; - if(hier[base[i]].size()<1)continue; - QListsub=hier[base[i]]; - model->insertRows(0,sub.size(),idx); - model->insertColumns(0,3,idx); - for(int j=0;jindex(j,0,idx); - model->setData(idx2,sub[j].fileName()+" ("+sub[j].variantID()+")"); - model->setData(idx2,base[i],BASEROLE); - model->setData(idx2,sub[j].completeFileName(),NAMEROLE); - model->itemFromIndex(idx2)->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); - model->setData(model->index(j,1,idx),sub[j].description()); - model->setData(model->index(j,2,idx),sub[j].checksum()); - model->itemFromIndex(model->index(j,2,idx))->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); - } - } - //expand all - tree->expandAll(); - nochange=false; -} -void MTemplateEditor::deleteItem() -{ - //get selection - QModelIndex idx=tree->currentIndex(); - if(!idx.isValid())return; - QModelIndex bidx=model->index(idx.row(),0,idx.parent()); - QString fn=model->data(bidx,NAMEROLE).toString(); - if(fn=="")return; - //delete - if(store->deleteTemplate(fn)) - model->removeRow(idx.row(),idx.parent()); - else - QMessageBox::warning(this,tr("Warning"),tr("Unable to delete this template.")); -} - -void MTemplateEditor::addItem() -{ - //get selection - QModelIndex idx=tree->currentIndex(); - if(!idx.isValid())return; - QModelIndex pidx=idx.parent(); - QModelIndex bidx=model->index(idx.row(),0,pidx); - QString base=model->data(bidx,BASEROLE).toString(); - if(base=="")return; - //query file name - QString fn=QFileDialog::getOpenFileName(this,tr("Select Template File")); - if(fn=="")return; - //check extension - QString ext=QFileInfo(fn).completeSuffix(); - if(!MTemplate::legalSuffixes(base).contains(ext)){ - QMessageBox::warning(this,tr("Warning"),tr("Files with this extension (%1) are not legal for this template.").arg(ext)); - return; - } - //get new variant name - QStringList lst; - for(int i=0;irowCount(pidx);i++){ - QStringList f=model->data(model->index(i,0,pidx),NAMEROLE).toString().split(","); - if(f.size()>1) - lst<setTemplate(base+"."+ext+","+nvar,fn)) - forceUpdate(); - else - QMessageBox::warning(this,tr("Warning"),tr("Unable to upload file.")); -} - -void MTemplateEditor::changeDescr(QStandardItem*item) -{ - if(nochange)return; - if(!item)return; - //sanity check - if(item->column()!=1)return; - //get full name & data - QModelIndex idx=item->index(); - QString dsc=model->data(idx).toString(); - QModelIndex bidx=model->index(item->row(),0,idx.parent()); - QString fn=model->data(bidx,NAMEROLE).toString(); - if(fn=="")return; - //send to server - if(!store->setTemplateDescription(fn,dsc)) - QMessageBox::warning(this,tr("Warning"),tr("Unable to send new description to server.")); -} - -void MTemplateEditor::forceUpdate() -{ - store->updateTemplates(true); - updateView(); -} diff --git a/src/templatedlg.h b/src/templatedlg.h deleted file mode 100644 index b4e7fcb..0000000 --- a/src/templatedlg.h +++ /dev/null @@ -1,64 +0,0 @@ -// -// C++ Interface: templatedlg -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_TEMPLATEDLG_H -#define MAGICSMOKE_TEMPLATEDLG_H - -#include -#include - -#include "templates.h" - -class QComboBox; -class QStandardItem; -class QStandardItemModel; -class QStringList; -class QTreeView; - -/**gives the user a choice of template variants; used by MTemplateStore only!*/ -class MTemplateChoice:public QDialog -{ - Q_OBJECT - public: - MTemplateChoice(const QString&,const QString&,const QStringList&,const QString&); - - MTemplate choice()const; - private: - //selection box - QComboBox*box; - //settings group where to find data - QString sgroup,cachedir; -}; - -/**lets the user add and remove templates and variants to/from the database; used by MWebRequest!*/ -class MTemplateEditor:public QDialog -{ - Q_OBJECT - public: - MTemplateEditor(MTemplateStore*); - - private slots: - void updateView(); - void deleteItem(); - void addItem(); - void changeDescr(QStandardItem*); - void forceUpdate(); - private: - MTemplateStore*store; - QTreeView*tree; - QStandardItemModel*model; - bool nochange; -}; - - - -#endif diff --git a/src/templates.cpp b/src/templates.cpp deleted file mode 100644 index 3642310..0000000 --- a/src/templates.cpp +++ /dev/null @@ -1,362 +0,0 @@ -// -// C++ Implementation: templates -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -/***************************** - * Settings hierarchy for templates: - * - * /templates/$PROFILEID -> template settings for this profile - * .../$TEMPLATENAME -> the settings for a template, uses the complete name (eg. bill.odtt,2) - * ....../checksum -> key that stores the checksum (calculated by server!!) - * ....../description -> key that stores the description (as received from server) - * - * - * Template buffer on disk: - * - * req->dataDir()/templates -> directory for template files; - * each file is stored with complete name, no meta-info - ***************************/ - -#include "main.h" -#include "templatedlg.h" -#include "templates.h" -#include "msinterface.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define req (MSInterface::instance()) - -MTemplateStore::MTemplateStore(QString p) -{ - profileid=p; -} - -MTemplate MTemplateStore::getTemplate(QString f) -{ - //syntax check - f=f.toLower(); - QRegExp fregexp("[a-z0-9_]+"); - if(!fregexp.exactMatch(f))return MTemplate(); - //update directory (no force) - updateTemplates(false); - //find files matching the pattern - //basics - QString dname=req->dataDir()+"/templates/"; - QSettings set; - set.beginGroup("templates/"+profileid); - //get directory - QStringList dir=set.childGroups(); - QStringList tdir; - for(int i=0;idataDir()+"/templates/"; - QSettings set; - set.beginGroup("templates/"+profileid); - //make sure directory exists - QDir(req->dataDir()).mkpath("templates"); - //do we need an update yet? - QDateTime last=QDateTime::fromTime_t(set.value("lastupdate",0).toInt()+300); - if(last>=QDateTime::currentDateTime() && !force)return; - - //get local info - QStringList files=set.childGroups(); - QMap fmap; - for(int i=0;irequest("gettemplatelist",""))return; - if(req->responseStatus()!=MWebRequest::Ok)return; - //remember update time - set.setValue("lastupdate",QDateTime::currentDateTime().toTime_t()); - //parse info - QDomDocument doc; - if(!doc.setContent(req->responseBody()))return; - //scan and create new list - QDomNodeList nl=doc.elementsByTagName("Template"); - QMapnfmap; - for(int i=0;irequest("gettemplate",fn.toUtf8()))return false; - if(req->responseStatus()!=MWebRequest::Ok)return false; - //store - QFile f(dname+"/"+fn); - if(!f.open(QIODevice::WriteOnly|QIODevice::Truncate))return false; - f.write(req->responseBody()); - return true; - */return false; -} - -bool MTemplateStore::setTemplate(QString n,QString f) -{/*TODO - //very rough sanity check - QRegExp fregexp("[a-z0-9_\\.,]+"); - if(!fregexp.exactMatch(n))return false; - //get content - QFile fl(f); - if(!fl.open(QIODevice::ReadOnly)) - return false; - QByteArray ba=fl.readAll(); - fl.close(); - //send to server - if(!req->request("settemplate",n.toUtf8()+"\n"+ba)) - return false; - if(req->responseStatus()!=MWebRequest::Ok) - return false; - //delete it from cache, so it is retrieved again; force retrieval - //TODO: the server returns the hash (since dec08), use it and update the cache without retrieval - QSettings set; - set.remove("templates/"+profileid+"/"+n); - set.setValue("templates/"+profileid+"/lastupdate",0); - QFile(req->dataDir()+"/templates/"+n).remove(); - //return success - return true;*/return false; -} - -bool MTemplateStore::deleteTemplate(QString n) -{/*TODO - //very rough sanity check - QRegExp fregexp("[a-z0-9_\\.,]+"); - if(!fregexp.exactMatch(n))return false; - //send to server - if(!req->request("deletetemplate",n.toUtf8())) - return false; - if(req->responseStatus()!=MWebRequest::Ok) - return false; - //delete it from cache - QSettings set; - set.remove("templates/"+profileid+"/"+n); - QFile(req->dataDir()+"/templates/"+n).remove(); - return true;*/return false; -} - -bool MTemplateStore::setTemplateDescription(QString n,QString d) -{/*TODO - //very rough sanity check - QRegExp fregexp("[a-z0-9_\\.,]+"); - if(!fregexp.exactMatch(n))return false; - //check that we have a real change - QSettings set; - set.beginGroup("templates/"+profileid+"/"+n); - QString o=set.value("description").toString(); - qDebug("setting %s '%s' -> '%s'",n.toAscii().data(),o.toAscii().data(),d.toAscii().data()); - if(o==d)return true; - //send to server - if(!req->request("settemplatedescription",n.toUtf8()+"\n"+d.toUtf8())) - return false; - if(req->responseStatus()!=MWebRequest::Ok) - return false; - //update internal description - set.setValue("description",d); - //return success - return true;*/return false; -} - -QList MTemplateStore::allTemplates() -{ - updateTemplates(false); - QString dname=req->dataDir()+"/templates/"; - QSettings set; - set.beginGroup("templates/"+profileid); - QStringList names=set.childGroups(); - QList ret; - for(int i=0;i1)return lst[1]; - return ""; -} - -QString MTemplate::checksum()const{return m_checksum;} - -bool MTemplate::isValid()const{return m_fname!="";} - -QString MTemplate::targetExtension()const -{ - QString x=extension(); - //ODF file? - if(QRegExp("od.t").exactMatch(x))return x.left(3); - //all else: not storable - return ""; -} - -bool MTemplate::isOdf()const{return (type()&OdfTemplate)!=0;} - -bool MTemplate::isLabel()const{return type()==LabelTemplate;} -MTemplate::Type MTemplate::type()const -{ - QString x=extension(); - //ODF file? - if(x=="odtt")return OdtTemplate; - if(x=="odst")return OdsTemplate; - if(x=="odpt")return OdpTemplate; - if(x=="odgt")return OdgTemplate; - if(x=="odbt")return OdbTemplate; - //label? - if(x=="xtt")return LabelTemplate; - //hmm, unknown one - return UnknownTemplate; -} - -QString MTemplate::description()const{return m_descr;} - - -static QStringList tempBaseNames; -//static -QStringList MTemplate::legalBaseNames() -{ - if(tempBaseNames.size()==0){ - tempBaseNames<<"ticket"<<"voucher"<<"bill"<<"eventsummary"; - } - return tempBaseNames; -} - -//static -MTemplate::Types MTemplate::legalTypes(QString bn) -{ - if(bn=="ticket" || bn=="voucher") - return LabelTemplate; - if(bn=="bill" || bn=="eventsummary") - return OdfTemplate; - return UnknownTemplate; -} - -//static -QStringList MTemplate::legalSuffixes(QString bn) -{ - if(bn=="ticket" || bn=="voucher") - return QStringList()<<"xtt"; - if(bn=="bill" || bn=="eventsummary") - return QStringList()<<"odtt"<<"odst"<<"odpt"<<"odgt"<<"odbt"; - return QStringList(); -} diff --git a/src/templates.h b/src/templates.h deleted file mode 100644 index 08e5aa4..0000000 --- a/src/templates.h +++ /dev/null @@ -1,143 +0,0 @@ -// -// C++ Interface: templates -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_TEMPLATES_H -#define MAGICSMOKE_TEMPLATES_H - -#include - -/**this class wraps a single template*/ -class MTemplate -{ - public: - /**creates an invalid template*/ - MTemplate(); - - /**returns the name/path of the cache file, if it exists*/ - QString cacheFileName()const; - - /**returns the file name of the template (eg. mytemplate.odtt)*/ - QString fileName()const; - - /**returns the complete encoded name of the template (eg. mytemplate.odtt,v1)*/ - QString completeFileName()const; - - /**returns the base name of the template (eg. mytemplate for mytemplate.odtt)*/ - QString baseName()const; - - /**returns the extension of the template (eg. odtt for mytemplate.odtt)*/ - QString extension()const; - - /**returns the variant ID of the template (warning: it has no meaning outside the template storage system*/ - QString variantID()const; - - /**returns the checksum (calculated by the server)*/ - QString checksum()const; - - /**returns the description*/ - QString description()const; - - /**returns whether this is a valid template*/ - bool isValid()const; - - /**returns the extension of the target document if it is saved (empty if the template cannot be saved)*/ - QString targetExtension()const; - - /**returns whether this is an ODF template*/ - bool isOdf()const; - - /**returns whether this is a label template*/ - bool isLabel()const; - - /**template type; currently only ODF and Labels are known*/ - enum Type{ - /**uninitialized or unknown label type*/ - UnknownTemplate=0, - /**ODF Text template*/ - OdtTemplate=1, - /**ODF SpreadSheet template*/ - OdsTemplate=2, - /**ODF Presentation*/ - OdpTemplate=4, - /**ODF Drawing*/ - OdgTemplate=8, - /**ODF DataBase*/ - OdbTemplate=0x10, - /**ODF template*/ - OdfTemplate=0xff, - /**Label template*/ - LabelTemplate=0x100 - }; - Q_DECLARE_FLAGS(Types,Type) - - /**returns the template type*/ - Type type()const; - - /**returns the currently known (by the client) template base names*/ - static QStringList legalBaseNames(); - - /**returns the legal file types (as understood by the client) for a template base name; returns UnknownTemplate if none is legal*/ - static Types legalTypes(QString); - - /**returns the legal template file suffixes (as understood by the client) for a template base name; returns empty if none is legal*/ - static QStringList legalSuffixes(QString); - - protected: - friend class MTemplateStore; - friend class MTemplateChoice; - /**creates a template wrapper from a cache file name; this constructor is used internally in the storage system*/ - MTemplate(QString fn,QString chk,QString dsc); - private: - QString m_fname,m_checksum,m_descr; -}; -Q_DECLARE_OPERATORS_FOR_FLAGS(MTemplate::Types) - -/**this class implements the storage end of the template subsystem, its only instance exists in the webrequest*/ -class MTemplateStore -{ - protected: - //FIXME friend class MWebRequest; - friend class MTemplateEditor; - /**instantiates the template subsystem*/ - MTemplateStore(QString); - - /**stores a specific template*/ - bool setTemplate(QString templatename,QString localfile); - - /**stores a new description for a template*/ - bool setTemplateDescription(QString templatename,QString description); - - /**deletes a template (requires full name), used by MTemplateEditor*/ - bool deleteTemplate(QString); - - /**updates the template directory, does not do anything if force==false and the last update was less than 5min ago*/ - void updateTemplates(bool force); - - /**returns all templates (for MTemplateEditor)*/ - QList allTemplates(); - - private: - /**unused, just here to remove it from accessability*/ - MTemplateStore(){} - - /**helper for updateTemplates: retrieves a single file from the server*/ - bool retrieveFile(QString,QString); - - public: - /**returns a specific template, opens a template choice dialog if necessary*/ - MTemplate getTemplate(QString); - - private: - QString profileid; -}; - -#endif diff --git a/src/templates/labeldlg.cpp b/src/templates/labeldlg.cpp new file mode 100644 index 0000000..5eb12ab --- /dev/null +++ b/src/templates/labeldlg.cpp @@ -0,0 +1,317 @@ +// +// C++ Implementation: labeldlg +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "labeldlg.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ROWS 20 +#define COLS 20 + +MLabelDialog::MLabelDialog(QWidget*par,QPrinter* pn,int nl,QSizeF ls) + :QDialog(par) +{ + printer=pn; + numlabels=nl; + labelsize=ls; + maxrows=ROWS; + maxcols=COLS; + + setWindowTitle(tr("Label Printing Setup")); + + //get settings + QSettings set; + set.beginGroup("printer/"+printer->printerName()); + double ox=set.value("offsetx",0.0).toDouble(); + double oy=set.value("offsety",0.0).toDouble(); + double lsx=set.value("sizex",0.0).toDouble(); + double lsy=set.value("sizey",0.0).toDouble(); + QString mtrc=set.value("metric",tr("mm","defaultmetric: mm, in, cm")).toString(); + if(lsx==0.0 || lsy==0.0){ + //convert ticket template size + double dx=printer->logicalDpiX(); + double dy=printer->logicalDpiY(); + if(mtrc=="in"){ + lsx=ls.width()/dx; + lsy=ls.height()/dy; + }else + if(mtrc=="cm"){ + lsx=ls.width()/dx*2.54; + lsy=ls.height()/dy*2.54; + }else{//mm + lsx=ls.width()/dx*25.4; + lsy=ls.height()/dy*25.4; + } + } + + //display + + QVBoxLayout*vl; + QGridLayout*gl; + setLayout(vl=new QVBoxLayout); + vl->addLayout(gl=new QGridLayout,0); + + int ln=0; + gl->addWidget(new QLabel(tr("Label offset:")),ln,0); + gl->addWidget(offx=new QLineEdit(QString::number(ox)),ln,1); + offx->setValidator(new QDoubleValidator(0.0,1000.0,2,this)); + gl->addWidget(new QLabel("x"),ln,2); + gl->addWidget(offy=new QLineEdit(QString::number(oy)),ln,3); + offy->setValidator(new QDoubleValidator(0.0,1000.0,2,this)); + gl->addWidget(new QLabel(tr("Label size:")),++ln,0); + gl->addWidget(sizex=new QLineEdit(QString::number(lsx)),ln,1); + sizex->setValidator(new QDoubleValidator(0.0,1000.0,2,this)); + gl->addWidget(new QLabel("x"),ln,2); + gl->addWidget(sizey=new QLineEdit(QString::number(lsy)),ln,3); + sizey->setValidator(new QDoubleValidator(0.0,1000.0,2,this)); + gl->addWidget(new QLabel(tr("Unit:")),++ln,0); + gl->addWidget(metric=new QComboBox,ln,1,1,3); + metric->addItem(tr("Millimeter"),"mm"); + metric->addItem(tr("Centimeter"),"cm"); + metric->addItem(tr("Inch"),"in"); + gl->addWidget(warning=new QLabel(""),++ln,0,1,4); + QPalette pal=warning->palette(); + pal.setColor(QPalette::WindowText,Qt::red); + warning->setPalette(pal); + gl->setColumnStretch(++ln,10); + + vl->addSpacing(10); + vl->addWidget(new QLabel(tr("Page usage:")),0); + vl->addWidget(page=new QComboBox,0); + for(int i=0;iaddItem(tr("Page %1").arg(i+1),i); + oldpage=0; + + QScrollArea *sa; + QWidget*w=new QWidget; + vl->addWidget(sa=new QScrollArea,10); + w->setLayout(gl=new QGridLayout); + QToolButton*t; + gl->addWidget(t=new QToolButton,0,0); + t->setIcon(QIcon(":/arrowdiag.png")); + connect(t,SIGNAL(clicked()),this,SLOT(toggleAll())); + QSignalMapper *cmap=new QSignalMapper(this); + connect(cmap,SIGNAL(mapped(int)),this,SLOT(toggleColumn(int))); + for(int i=1;i<=COLS;i++){ + gl->addWidget(t=new QToolButton,0,i); + t->setIcon(QIcon(":/arrowdown.png")); + connect(t,SIGNAL(clicked()),cmap,SLOT(map())); + cmap->setMapping(t,i-1); + } + QSignalMapper *rmap=new QSignalMapper(this); + connect(rmap,SIGNAL(mapped(int)),this,SLOT(toggleRow(int))); + for(int i=1;i<=ROWS;i++){ + gl->addWidget(t=new QToolButton,i,0); + t->setIcon(QIcon(":/arrowright.png")); + connect(t,SIGNAL(clicked()),rmap,SLOT(map())); + rmap->setMapping(t,i-1); + for(int j=1;j<=COLS;j++){ + QCheckBox*b; + gl->addWidget(b=new QCheckBox,i,j); + checks.append(b); + connect(b,SIGNAL(clicked()),this,SLOT(savePage())); + } + } + sa->setWidget(w); + connect(page,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePage())); + connect(sizex,SIGNAL(textChanged(const QString&)),this,SLOT(updatePage())); + connect(sizey,SIGNAL(textChanged(const QString&)),this,SLOT(updatePage())); + connect(metric,SIGNAL(currentIndexChanged(int)),this,SLOT(updatePage())); + + vl->addSpacing(15); + QHBoxLayout*hl; + vl->addLayout(hl=new QHBoxLayout); + hl->addStretch(10); + QPushButton*p; + hl->addWidget(p=new QPushButton(tr("Ok")),0); + connect(p,SIGNAL(clicked()),this,SLOT(accept())); + connect(p,SIGNAL(clicked()),this,SLOT(saveSettings())); + p->setDefault(true); + hl->addWidget(p=new QPushButton(tr("Cancel")),0); + connect(p,SIGNAL(clicked()),this,SLOT(reject())); + + //initialize + QListtpl; + for(int i=0;i<(ROWS*COLS);i++)tpl.append(true); + for(int i=0;i=0;r--) + for(int c=0;ctext().toDouble(); + double py=offy->text().toDouble(); + //add rows/cols + px+=col*sizex->text().toDouble(); + py+=row*sizey->text().toDouble(); + //correct to DPI + QString mtrc=metric->itemData(metric->currentIndex()).toString(); + if(mtrc=="in"){ + px*=printer->logicalDpiX(); + py*=printer->logicalDpiY(); + }else + if(mtrc=="cm"){ + px*=printer->logicalDpiX()/2.54; + py*=printer->logicalDpiY()/2.54; + }else{ + px*=printer->logicalDpiX()/25.4; + py*=printer->logicalDpiY()/25.4; + } + //return + return QPointF(px,py); +} + +bool MLabelDialog::labelNeedsPageTurn(int n) +{ + //find it + int pg,row=0,col=0; + pg=findLabel(n,row,col); + //page 0 needs no turn + if(pg<=0)return false; + //scan that page (all rows below label) + for(int r=maxrows-1;r>row;r--) + for(int c=0;csetChecked(checked[oldpage][i]); + } +} + +void MLabelDialog::toggleColumn(int c) +{ + for(int r=0;rsetChecked(checked[oldpage][i]); + } +} + +void MLabelDialog::toggleAll() +{ + for(int i=0;i<(ROWS*COLS);i++){ + checked[oldpage][i]^=true; + checks[i]->setChecked(checked[oldpage][i]); + } +} + +void MLabelDialog::savePage() +{ + for(int i=0;i<(ROWS*COLS);i++) + checked[oldpage][i]=checks[i]->isChecked(); +} + +void MLabelDialog::updatePage() +{ + //find how many rows/cols fit on the page + double lx=sizex->text().toDouble(); + double ly=sizey->text().toDouble(); + QRect pr=printer->pageRect(); + QString mtrc=metric->itemData(metric->currentIndex()).toString(); + if(mtrc=="in"){ + lx*=printer->logicalDpiX(); + ly*=printer->logicalDpiY(); + }else + if(mtrc=="cm"){ + lx*=printer->logicalDpiX()/2.54; + ly*=printer->logicalDpiY()/2.54; + }else{ + lx*=printer->logicalDpiX()/25.4; + ly*=printer->logicalDpiY()/25.4; + } + + bool dowarn=false; + if(ly>0.0){ + maxrows=pr.height()/ly; + if(maxrows>ROWS)maxrows=ROWS; + if(maxrows<1){ + maxrows=1; + dowarn=true; + } + }else maxrows=ROWS; + if(lx>0.0){ + maxcols=pr.width()/lx; + if(maxcols>COLS)maxcols=COLS; + if(maxcols<1){ + maxcols=1; + dowarn=true; + } + }else maxcols=COLS; + //update + oldpage=page->itemData(page->currentIndex()).toInt(); + for(int r=0;rsetChecked(b && checked[oldpage][i]); + checks[i]->setEnabled(b); + } + if(dowarn) + warning->setText(tr("Warning: the label may not fit on the page!")); + else + warning->setText(""); +} + +void MLabelDialog::saveSettings() +{ + QSettings set; + set.beginGroup("printer/"+printer->printerName()); + set.setValue("offsetx",offx->text().toDouble()); + set.setValue("offsety",offy->text().toDouble()); + set.setValue("sizex",sizex->text().toDouble()); + set.setValue("sizey",sizey->text().toDouble()); + set.setValue("metric",metric->itemData(metric->currentIndex()).toString()); +} diff --git a/src/templates/labeldlg.h b/src/templates/labeldlg.h new file mode 100644 index 0000000..2b22aae --- /dev/null +++ b/src/templates/labeldlg.h @@ -0,0 +1,70 @@ +// +// C++ Interface: labeldlg +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_LABELDLG_H +#define MAGICSMOKE_LABELDLG_H + +#include +#include +#include + +class QPaintDevice; +class QCheckBox; +class QComboBox; +class QLineEdit; +class QPrinter; +class QLabel; + +class MLabelDialog:public QDialog +{ + Q_OBJECT + public: + /**creates a label dialog*/ + MLabelDialog(QWidget*parent,QPrinter*printer,int numlabels,QSizeF labelsize); + /**deletes the label dialog and stores its current settings*/ + ~MLabelDialog(); + + /**returns the offset of label number n; relative to the coordinate system of the given paint device; starts at the bottom left of the page*/ + QPointF labelOffset(int n); + /**returns whether this label is on a new page*/ + bool labelNeedsPageTurn(int n); + + private slots: + /**internal: toggle Row button clicked*/ + void toggleRow(int); + /**internal: toggle Column button clicked*/ + void toggleColumn(int); + /**internal: toggle all button clicked*/ + void toggleAll(); + + /**internal: display correct page*/ + void updatePage(); + /**helper: save current/old page*/ + void savePage(); + /**internal: save settings for next time*/ + void saveSettings(); + + private: + QLineEdit *offx,*offy,*sizex,*sizey; + QLabel *warning; + QSizeF labelsize; + QComboBox *metric,*page; + QListchecks; + QList >checked; + QPrinter* printer; + int numlabels,oldpage,maxrows,maxcols; + + /**internal helper: find coordinates of label n; returns page id; returns -1 on failure*/ + int findLabel(int n,int&row,int&col); +}; + +#endif diff --git a/src/templates/odtrender.cpp b/src/templates/odtrender.cpp new file mode 100644 index 0000000..38831aa --- /dev/null +++ b/src/templates/odtrender.cpp @@ -0,0 +1,569 @@ +// +// C++ Implementation: odtrender +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "misc.h" +#include "odtrender.h" +#include "office.h" + +#include +#include +#include +#include +#include + +#include "../zip/qunzip.h" +#include "../zip/qzip.h" + + +class MOdtRendererPrivate +{ + protected: + friend class MOdtRenderer; + + //methods that the parent uses + MOdtRendererPrivate(QString file,MOdtRenderer*p); + ~MOdtRendererPrivate(); + + bool renderToFile(QFile&); + + //data the parent uses + QString extension; + + private: + //methods that the parent does not call + void render(QIODevice*); + + QString render(QString); + + QString renderLine(QString,QString,int); + + QString getVariable(QString varname); + QString getLoopVariable(QString loopname,int iteration,QString varname); + + qint64 intToken(QString,QString,int); + void setLocalVar(QString,qint64); + void setLocalVarError(QString); + + //data the parent does not access + MOdtRenderer*parent; + QUnZip temp; + QFile tfile; + QString newline; + bool inif,iftrue; + + struct LocalVar{ + MOdtRenderer::VarType type; + QVariant value; + }; + QMaplocalvars; +}; + +MOdtRenderer::MOdtRenderer(MTemplate file) +{ + d=new MOdtRendererPrivate(file.cacheFileName(),this); + d->extension=file.targetExtension(); +} + +MOdtRendererPrivate::MOdtRendererPrivate(QString file,MOdtRenderer*p) + :tfile(file) +{ + parent=p; + newline=" "; + inif=iftrue=true; + //open ZIP + if(tfile.open(QIODevice::ReadOnly))temp.open(&tfile); + //TODO: make sure this is a valid ZIP file, preferably with some ODT content +} + +MOdtRenderer::~MOdtRenderer() +{ + delete d; + d=0; +} +MOdtRendererPrivate::~MOdtRendererPrivate() +{ + temp.close(); + tfile.close(); +} + +void MOdtRenderer::renderToFile(QString file) +{ + QFile f(file); + if(f.open(QIODevice::ReadWrite)){ + renderToFile(f); + f.close(); + } +} + +void MOdtRenderer::renderToFile(QFile &file) +{ + if(d->renderToFile(file)) + if(QSettings().value("doOpenODFs",false).toBool()) + openOfficeFile(file.fileName()); +} +bool MOdtRendererPrivate::renderToFile(QFile &file) +{ + if(!file.isWritable()) + if(!file.open(QIODevice::ReadWrite))return false; + file.seek(0); + file.resize(0); + render(&file); + return true; +} + +void MOdtRenderer::renderToPrinter() +{ + //generate temporary file + QTemporaryFile tfile; + tfile.setAutoRemove(false);//we don't want it to be auto-deleted on close() + tfile.setFileTemplate(QDir::tempPath()+"/msmoke_XXXXXX."+d->extension); + tfile.open(); + QString tname=tfile.fileName(); + //render + d->renderToFile(tfile); + tfile.close(); + //call ooffice and print + printOfficeFile(tname); + //remove temporary file + QFile(tname).remove(); +} + +void MOdtRendererPrivate::render(QIODevice*out) +{ + //sanity check + if(!temp.isOpen())return; + if(!out->isWritable())return; + //rewind input + if(!temp.gotoFirstFile())return; + //create output + QZip ozip; + ozip.open(out); + //copy contents + do{ + QString cname; + QDateTime tstamp; + temp.getCurrentFileInfo(cname,&tstamp); + if(cname=="content.xml"){ + //get content + QBuffer buffer; + buffer.open(QBuffer::ReadWrite); + temp.getCurrentFile(buffer); + //render + QByteArray cont=render(QString::fromUtf8(buffer.data())).toUtf8(); + //write + buffer.close(); + buffer.setData(cont); + buffer.open(QBuffer::ReadWrite); + buffer.seek(0); + ozip.storeFile(cname,buffer,tstamp); + }else{ + //copy unchanged + QBuffer buffer; + buffer.open(QBuffer::ReadWrite); + int meth; + unsigned long crc,usz; + temp.getCurrentFileRaw(buffer,meth,crc,usz); + buffer.seek(0); + ozip.storeFileRaw(cname,buffer,tstamp,meth,crc,usz); + } + }while(temp.gotoNextFile()); + ozip.close(); +} + +QString MOdtRendererPrivate::render(QString s) +{ + //buffer for the whole file + QStringList fbuf=s.split("\n"); + //buffer for loops + QStringList lbuf; + QString lname; + //buffer for return value + QString ret; + //go through all lines + bool isloop=false; + for(int i=0;igetLoopIterations(lname); + //render the loop... + for(int j=0;j")iftrue=op1>op2;else + if(stl[1]=="=" || stl[1]=="==")iftrue=op1==op2;else + if(stl[1]=="<=")iftrue=op1<=op2;else + if(stl[1]==">=")iftrue=op1>=op2;else + if(stl[1]=="<>" || stl[1]=="!=")iftrue=op1!=op2; + else { + qDebug("??????????IfError: unknown operator"); + return ""; + } + qDebug("???????????????? If(%lli %s %lli) evaluates to: %s",op1,stl[1].toAscii().data(),op2,iftrue?"true":"false"); + return ""; + }else + if(line.trimmed()=="#ELSE"){ + iftrue=!iftrue; + return ""; + }else + if(line.trimmed()=="#ENDIF"){ + inif=false; + return ""; + } + //check if state + if(inif && !iftrue)return ""; + //check for other statements + if(line.trimmed().startsWith("#SETNEWLINE:")){ + //set a new newline translation + newline=line.trimmed().mid(12).trimmed(); + if(newline=="")newline=" "; + return ""; + }else + if(line.trimmed().startsWith("#CALC:")){ + //do a calculation + //get full statement + QString stmt=line.trimmed().mid(6).trimmed(); + qDebug("????????????????Calculation: %s",stmt.toAscii().data()); + //split out var name + int p=stmt.indexOf(':'); + if(p<1)return ""; + QString var=stmt.left(p).trimmed(); + //get list of statement tokens + QStringList stl=stmt.mid(p+1).trimmed().split(" "); + //go through + qint64 res=intToken(stl[0],loop,lpos); +// qDebug("??????????CalcInit: %lli",res); + for(int i=1;i=stl.size()){ + setLocalVarError(var); + qDebug("??????????CalcError: missing last operand"); + return ""; + } + qint64 op2=intToken(stl[i+1],loop,lpos); +// qDebug("??????????Calc: operator '%s' operand '%s' -> '%lli'",stl[i].toAscii().data(),stl[i+1].toAscii().data(),op2); + if(stl[i]=="+")res+=op2;else + if(stl[i]=="-")res-=op2;else + if(stl[i]=="*")res*=op2;else + if(stl[i]=="/"){ + if(op2!=0)res/=op2; + else{ + qDebug("??????????CalcError: division operand %s is zero",stl[i+1].toAscii().data()); + return ""; + } + }else + if(stl[i]=="%"){ + if(op2!=0)res%=op2; + else{ + qDebug("??????????CalcError: modulo operand %s is zero",stl[i+1].toAscii().data()); + return ""; + } + }else { + setLocalVarError(var); + qDebug("??????????CalcError: unknown operator %s",stl[i].toAscii().data()); + return ""; + } + } + qDebug("????????????????CalcResult: %s <= %lli",var.toAscii().data(),res); + setLocalVar(var,res); + return ""; + } + //scan characters + for(int i=0;i2){ + //this was a mistake, reset + ret+="@"; + ret+=vname+"@"; + }else + if(vl.size()==2){ + //this is a loop variable, + //check that it is the right loop + //or any loop at all... + if(loop!="" && (loop==vl[0] || ("$"+loop)==vl[0])){ + //get value + ret+=xmlize(getLoopVariable(vl[0],lpos,vl[1]).trimmed(),newline); + } + }else + //this is a normal variable, get valie + ret+=xmlize(getVariable(vname).trimmed(),newline); + } + //reset mode + isvar=false; + vname=""; + }else + //continuation of var? + if(vc.contains(line[i])){ + //valid var-name-letter, add + vname+=line[i]; + }else{//not a valid var-name-letter + //reset + isvar=false; + ret+="@"; + ret+=vname; + vname=""; + } + }else{//not inside variable name + //is this the start of a var? + if(line[i]=='@'){ + isvar=true; + vname=""; + }else{ + ret+=line[i]; + } + } + } + //anything left over? + if(isvar){ + //reset + ret+="@"+vname; + } + //return transformed line + return ret + "\n"; +} + +static inline QString formatVar(QVariant r,MOdtRenderer::VarType tp,bool loc,int offset) +{ + switch(tp){ + case MOdtRenderer::StringVar: + return r.toString(); + case MOdtRenderer::IntVar: + return QString::number(r.toInt()+offset); + case MOdtRenderer::MoneyVar: + return cent2str(r.toInt()+offset,loc); + case MOdtRenderer::DateVar: + return unix2date(r.toInt()+offset,loc); + case MOdtRenderer::TimeVar: + return unix2time(r.toInt()+offset,loc); + case MOdtRenderer::DateTimeVar: + return unix2dateTime(r.toInt()+offset,loc); + } + return ""; +} + +QString MOdtRendererPrivate::getVariable(QString varname) +{ + //split out calculation + int offset=0; + int p=varname.indexOf('+'); + if(p>0){ + offset=varname.mid(p+1).toInt(); + varname=varname.left(p); + } + p=varname.indexOf('-'); + if(p>0){ + offset=varname.mid(p).toInt(); + varname=varname.left(p); + } + //split out $-sign + bool localize=true; + if(varname[0]=='$'){ + localize=false; + varname=varname.mid(1); + } + //get variable + MOdtRenderer::VarType tp=MOdtRenderer::StringVar; + QVariant r; + if(varname=="TODAY"){ + r=QDateTime::currentDateTime().toTime_t(); + tp=MOdtRenderer::DateVar; + }else if(varname=="NOW"){ + r=QDateTime::currentDateTime().toTime_t(); + tp=MOdtRenderer::TimeVar; + }else if(varname[0]=='#'){ + if(localvars.contains(varname.mid(1))){ + r=localvars[varname.mid(1)].value; + tp=localvars[varname.mid(1)].type; + } + }else{ + r=parent->getVariable(varname,tp); + } + return formatVar(r,tp,localize,offset); +} + +QString MOdtRendererPrivate::getLoopVariable(QString loopname,int iteration,QString varname) +{ + //split out calculation + int offset=0; + int p=varname.indexOf('+'); + if(p>0){ + offset=varname.mid(p+1).toInt(); + varname=varname.left(p); + } + p=varname.indexOf('-'); + if(p>0){ + offset=varname.mid(p).toInt(); + varname=varname.left(p); + } + //split out $-sign + bool localize=true; + if(loopname[0]=='$'){ + localize=false; + loopname=loopname.mid(1); + } + qDebug("!!!!!!!!!!getting loop var '%s' : '%s' localized=%s offset=%i",loopname.toAscii().data(),varname.toAscii().data(),(localize?"yes":"no"),offset); + //get variable + MOdtRenderer::VarType tp=MOdtRenderer::StringVar; + QVariant r; + if(varname=="ITERATION"){ + r=iteration; + tp=MOdtRenderer::IntVar; + }else + r=parent->getLoopVariable(loopname,iteration,varname,tp); + return formatVar(r,tp,localize,offset); +} + +qint64 MOdtRendererPrivate::intToken(QString vname,QString loop,int lpos) +{ + //check for literals + bool islit; + qint64 lit=vname.toLongLong(&islit); + if(islit)return lit; + //split the variable + QStringList vnl=vname.split(":"); + if(vnl.size()<2){ + //local var? + if(vnl[0][0]=='#'){ + if(localvars.contains(vnl[0].mid(1))) + return localvars[vnl[0].mid(1)].value.toLongLong(); + return 0; + } + //special var? + if(vname=="TODAY" || vname=="NOW") + return QDateTime::currentDateTime().toTime_t(); + //get from parent + MOdtRenderer::VarType tp; + return parent->getVariable(vnl[0],tp).toLongLong(); + }else{ + //correct loop? + if(vnl[0]!=loop)return 0; + //iteration? + if(vnl[1]=="ITERATION")return lpos; + //get from parent + MOdtRenderer::VarType tp; + return parent->getLoopVariable(loop,lpos,vnl[1],tp).toLongLong(); + } +} + +void MOdtRendererPrivate::setLocalVar(QString vn,qint64 va) +{ + //split vname/type + QStringList vnl=vn.split("/"); + MOdtRenderer::VarType tp=MOdtRenderer::IntVar; + if(vnl.size()>1){ + if(vnl[1]=="MONEY")tp=MOdtRenderer::MoneyVar;else + if(vnl[1]=="DATE")tp=MOdtRenderer::DateVar;else + if(vnl[1]=="TIME")tp=MOdtRenderer::TimeVar;else + if(vnl[1]=="DATETIME")tp=MOdtRenderer::DateTimeVar; + } + //store + LocalVar lv; + lv.type=tp; + lv.value=va; + localvars.insert(vnl[0],lv); +} + +void MOdtRendererPrivate::setLocalVarError(QString vn) +{ + QStringList vnl=vn.split("/"); + LocalVar lv; + lv.type=MOdtRenderer::StringVar; + lv.value="error"; + localvars.insert(vnl[0],lv); +} + +/********************************************************************/ + +MOdtSignalRenderer::MOdtSignalRenderer(MTemplate file) + :MOdtRenderer(file) +{ +} + +MOdtSignalRenderer::~MOdtSignalRenderer(){} + +QVariant MOdtSignalRenderer::getVariable(QString varname,MOdtRenderer::VarType&av) +{ + QVariant ret; + av=MOdtRenderer::StringVar; + emit getVariable(varname,av,ret); + return ret; +} + +int MOdtSignalRenderer::getLoopIterations(QString loopname) +{ + int ret=0; + emit getLoopIterations(loopname,ret); + return ret; +} + +QVariant MOdtSignalRenderer::getLoopVariable(QString loopname,int iteration,QString varname,MOdtRenderer::VarType&av) +{ + QVariant ret="notfound"; + av=MOdtRenderer::StringVar; + emit getLoopVariable(loopname,iteration,varname,av,ret); + return ret; +} diff --git a/src/templates/odtrender.h b/src/templates/odtrender.h new file mode 100644 index 0000000..bae9fef --- /dev/null +++ b/src/templates/odtrender.h @@ -0,0 +1,98 @@ +// +// C++ Interface: odtrender +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_ODTRENDER_H +#define MAGICSMOKE_ODTRENDER_H + +#include +#include + +#include "templates.h" + +class MOdtRendererPrivate; +class QFile; + +/**abstract base class for all ODT rendering classes*/ +class MOdtRenderer +{ + public: + /**instantiates a renderer loaded from template file*/ + MOdtRenderer(MTemplate file); + /**deletes the renderer*/ + virtual ~MOdtRenderer(); + + /**starts the internal rendering routine and outputs to file*/ + virtual void renderToFile(QString file); + + /**starts the internal rendering routine and outputs to file*/ + virtual void renderToFile(QFile& file); + + /**starts the internal rendering routine and outputs to printer (calls OpenOffice to print)*/ + virtual void renderToPrinter(); + + /**variable type*/ + enum VarType{ + /**default: uninterpreted string*/ + StringVar, + /**simple integer value*/ + IntVar, + /**money value*/ + MoneyVar, + /**unix timestamp: format as date*/ + DateVar, + /**unix timestamp: format as time*/ + TimeVar, + /**unix timestamp: format as date+time*/ + DateTimeVar + }; + + protected: + friend class MOdtRendererPrivate; + /**implement this to return the value of a variable during rendering; should return empty string if the variable does not exist*/ + virtual QVariant getVariable(QString varname,VarType&)=0; + + /**implement this to return the amount of iterations for a defined loop; should return 0 if the loop does not exist*/ + virtual int getLoopIterations(QString loopname)=0; + + /**implement this to return a specific instance of a loop internal variable; should return empty string if the request is not valid*/ + virtual QVariant getLoopVariable(QString loopname,int iteration,QString varname,VarType&)=0; + private: + MOdtRendererPrivate*d; +}; + +/**generic class that implements MOdtRenderer by calling signals; the signals must be connected using a direct or blocking connection; if any of them is not used it will behave as if the variable/loop did not exist*/ +class MOdtSignalRenderer:public QObject,public MOdtRenderer +{ + Q_OBJECT + public: + /**instantiates a renderer loaded from template file*/ + MOdtSignalRenderer(MTemplate file); + /**deletes the renderer*/ + ~MOdtSignalRenderer(); + + signals: + /**connect this to return the value of a variable during rendering; should return empty string if the variable does not exist*/ + void getVariable(QString varname,MOdtRenderer::VarType&,QVariant&value); + + /**connect this to return the amount of iterations for a defined loop; should return 0 if the loop does not exist*/ + void getLoopIterations(QString loopname,int&iterations); + + /**connect this to return a specific instance of a loop internal variable; should return empty string if the request is not valid*/ + void getLoopVariable(QString loopname,int iteration,QString varname,MOdtRenderer::VarType&,QVariant&value); + + protected: + QVariant getVariable(QString varname,MOdtRenderer::VarType&); + int getLoopIterations(QString loopname); + QVariant getLoopVariable(QString loopname,int iteration,QString varname,MOdtRenderer::VarType&); +}; + +#endif diff --git a/src/templates/office.cpp b/src/templates/office.cpp new file mode 100644 index 0000000..dfc9c94 --- /dev/null +++ b/src/templates/office.cpp @@ -0,0 +1,175 @@ +// +// C++ Implementation: office +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "office.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static QString getofficepath() +{ + return QSettings().value("officePath","soffice").toString(); +} + +void openOfficeFile(QString fname) +{ + //calculate parameters + QStringList r; + if(QSettings().value("officeViewOnly",false).toBool())r<<"-view"; + r<addWidget(new QLabel(QCoreApplication::translate("office","Please chose a printer:")),0); + QComboBox*printer; + vl->addWidget(printer=new QComboBox,0); + printer->setEditable(false); + printer->addItem(QCoreApplication::translate("office","(Default Printer)")); + QListaprn=QPrinterInfo::availablePrinters(); + int cprn=0; + QString cp=QSettings().value("officePrinter","").toString(); + for(int i=0;iaddItem(s); + if(cp==prn)cprn=i+1; + } + printer->setCurrentIndex(cprn); + vl->addSpacing(10); + vl->addStretch(1); + QHBoxLayout*hl; + vl->addLayout(hl=new QHBoxLayout,0); + hl->addStretch(10); + QPushButton*p; + hl->addWidget(p=new QPushButton(QCoreApplication::translate("office","Ok"))); + QObject::connect(p,SIGNAL(clicked()),&d,SLOT(accept())); + d.exec(); + if(printer->currentIndex()==0)prn=""; + else prn=printer->currentText(); +} + +void printOfficeFile(QString fname) +{ + //calculate parameters + QStringList r; + QString p=QSettings().value("officePrinter","").toString(); + if(QSettings().value("officePrinterConfirm",false).toBool())confirmPrinter(p); + if(p=="")r<<"-p"; + else r<<"-pt"<addWidget(gb=new QGroupBox(tr("OpenOffice.org"))); + gb->setLayout(hl=new QHBoxLayout); + hl->addWidget(new QLabel(tr("Path to Executable:"))); + hl->addWidget(oopath=new QLineEdit(set.value("officePath","soffice").toString()),1); + hl->addWidget(p=new QPushButton(tr("...","select OpenOffice path button"))); + connect(p,SIGNAL(clicked()),this,SLOT(selectpath())); + + vl->addWidget(gb=new QGroupBox(tr("Printing ODF"))); + gb->setLayout(vl2=new QVBoxLayout); + vl2->addLayout(hl=new QHBoxLayout); + hl->addWidget(new QLabel(tr("Printer:"))); + hl->addWidget(printer=new QComboBox,1); + printer->setEditable(false); + printer->addItem(tr("(Default Printer)")); + QListaprn=QPrinterInfo::availablePrinters(); + int cprn=0; + QString cp=set.value("officePrinter","").toString(); + for(int i=0;iaddItem(s); + if(cp==s)cprn=i+1; + } + printer->setCurrentIndex(cprn); + vl2->addWidget(askprint=new QCheckBox(tr("Always confirm printer when printing ODF"))); + askprint->setChecked(set.value("officePrinterConfirm",false).toBool()); + vl2->addWidget(saveprint=new QCheckBox(tr("Save printed files"))); + saveprint->setChecked(set.value("officePrinterSave",false).toBool()); + + vl->addWidget(gb=new QGroupBox(tr("Opening ODF"))); + gb->setLayout(vl2=new QVBoxLayout); + vl2->addWidget(viewonly=new QCheckBox(tr("Always open as Read-Only"))); + viewonly->setChecked(set.value("officeViewOnly",false).toBool()); + vl2->addWidget(doopen=new QCheckBox(tr("Automatically open all newly created files"))); + doopen->setChecked(set.value("doOpenODFs",false).toBool()); + + vl->addSpacing(15); + vl->addLayout(hl=new QHBoxLayout); + hl->addStretch(1); + hl->addWidget(p=new QPushButton(tr("OK"))); + connect(p,SIGNAL(clicked()),this,SLOT(accept())); + connect(p,SIGNAL(clicked()),this,SLOT(savedata())); + hl->addWidget(p=new QPushButton(tr("Cancel"))); + connect(p,SIGNAL(clicked()),this,SLOT(reject())); +} + +void MOfficeConfig::savedata() +{ + QSettings set; + int cprn=printer->currentIndex(); + if(cprn==0)set.setValue("officePrinter",""); + else set.setValue("officePrinter",printer->currentText()); + + set.setValue("officePath",oopath->text()); + set.setValue("officeViewOnly",viewonly->isChecked()); + set.setValue("doOpenODFs",doopen->isChecked()); + set.setValue("officePrinterConfirm",askprint->isChecked()); + set.setValue("officePrinterSave",saveprint->isChecked()); +} + +void MOfficeConfig::selectpath() +{ + QString np=QFileDialog::getOpenFileName(this,tr("Select OpenOffice.org executable"),QFileInfo(oopath->text()).dir().absolutePath()); + if(np!="")oopath->setText(np); +} diff --git a/src/templates/office.h b/src/templates/office.h new file mode 100644 index 0000000..75bc0ff --- /dev/null +++ b/src/templates/office.h @@ -0,0 +1,47 @@ +// +// C++ Interface: office +// +// Description: Wrapper and Config Dialog around OpenOffice.org +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_OFFICE_H +#define MAGICSMOKE_OFFICE_H + +#include + +/**calls OpenOffice.org to open an ODF file*/ +void openOfficeFile(QString fname); + +/**calls OpenOffice.org to print an ODF file*/ +void printOfficeFile(QString fname); + +#include + +class QComboBox; +class QCheckBox; +class QLineEdit; + +/**configuration dialog for OpenOffice access*/ +class MOfficeConfig:public QDialog +{ + Q_OBJECT + public: + MOfficeConfig(QWidget*); + + private slots: + void savedata(); + void selectpath(); + private: + QComboBox*printer; + QCheckBox*viewonly,*doopen,*askprint,*saveprint; + QLineEdit*oopath; +}; + + +#endif diff --git a/src/templates/templatedlg.cpp b/src/templates/templatedlg.cpp new file mode 100644 index 0000000..641b834 --- /dev/null +++ b/src/templates/templatedlg.cpp @@ -0,0 +1,228 @@ +// +// C++ Implementation: templatedlg +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "templatedlg.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MTemplateChoice::MTemplateChoice(const QString&cd,const QString&tname,const QStringList&choices,const QString&sg) + :sgroup(sg),cachedir(cd) +{ + setWindowTitle(tr("Chose Template")); + QVBoxLayout *vl; + setLayout(vl=new QVBoxLayout); + vl->addWidget(new QLabel(tr("Please chose a variant of template %1:").arg(tname))); + vl->addWidget(box=new QComboBox); + box->setEditable(false); + QSettings set; + set.beginGroup(sg); + for(int i=0;i1)v=vs[1]; + else v=tr("(default)","default template pseudo-variant"); + d=set.value(choices[i]+"/description").toString(); + box->addItem(v+": "+d,choices[i]); + } + vl->addStretch(1); + QHBoxLayout *hl; + vl->addLayout(hl=new QHBoxLayout); + hl->addStretch(1); + QPushButton*p; + hl->addWidget(p=new QPushButton(tr("Ok"))); + p->setDefault(true); + connect(p,SIGNAL(clicked()),this,SLOT(accept())); +} + +MTemplate MTemplateChoice::choice()const +{ + QString fn=box->itemData(box->currentIndex()).toString(); + QSettings set; + set.beginGroup(sgroup+"/"+fn); + return MTemplate(cachedir+"/"+fn, set.value("checksum").toString(), set.value("description").toString()); +} + + + +/**************************************************************/ + +MTemplateEditor::MTemplateEditor(MTemplateStore*s) +{ + store=s; + nochange=false; + + setWindowTitle(tr("Edit Template Directory")); + + QHBoxLayout*hl; + QVBoxLayout*vl,*vl2; + + setLayout(vl=new QVBoxLayout); + vl->addLayout(hl=new QHBoxLayout,1); + hl->addWidget(tree=new QTreeView,1); + tree->setModel(model=new QStandardItemModel(this)); + connect(model,SIGNAL(itemChanged(QStandardItem*)),this,SLOT(changeDescr(QStandardItem*))); + QPushButton*p; + hl->addLayout(vl2=new QVBoxLayout); + vl2->addWidget(p=new QPushButton(tr("Update Now"))); + connect(p,SIGNAL(clicked()),this,SLOT(forceUpdate())); + vl2->addWidget(p=new QPushButton(tr("Add Variant"))); + connect(p,SIGNAL(clicked()),this,SLOT(addItem())); + vl2->addWidget(p=new QPushButton(tr("Delete Variant"))); + connect(p,SIGNAL(clicked()),this,SLOT(deleteItem())); + vl2->addStretch(1); + + vl->addSpacing(15); + vl->addLayout(hl=new QHBoxLayout); + hl->addStretch(1); + hl->addWidget(p=new QPushButton(tr("Close"))); + connect(p,SIGNAL(clicked()),this,SLOT(accept())); + + updateView(); +} + +static const int BASEROLE=Qt::UserRole; +static const int NAMEROLE=Qt::UserRole+1; + +void MTemplateEditor::updateView() +{ + //basic cleanup + nochange=true; + model->clear(); + model->insertColumns(0,3); + model->setHorizontalHeaderLabels(QStringList()<all=store->allTemplates(); + QMap >hier; + for(int i=0;i()); + hier[b].append(all[i]); + } + //create hierarchy + qSort(base); + model->insertRows(0,base.size()); + for(int i=0;iindex(i,0); + model->setData(idx,base[i]); + model->setData(idx,base[i],BASEROLE); + model->setData(idx,"",NAMEROLE); + model->itemFromIndex(idx)->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); + model->setData(model->index(i,1),""); + model->itemFromIndex(model->index(i,1))->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); + model->setData(model->index(i,2),""); + model->itemFromIndex(model->index(i,1))->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); + if(!hier.contains(base[i]))continue; + if(hier[base[i]].size()<1)continue; + QListsub=hier[base[i]]; + model->insertRows(0,sub.size(),idx); + model->insertColumns(0,3,idx); + for(int j=0;jindex(j,0,idx); + model->setData(idx2,sub[j].fileName()+" ("+sub[j].variantID()+")"); + model->setData(idx2,base[i],BASEROLE); + model->setData(idx2,sub[j].completeFileName(),NAMEROLE); + model->itemFromIndex(idx2)->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); + model->setData(model->index(j,1,idx),sub[j].description()); + model->setData(model->index(j,2,idx),sub[j].checksum()); + model->itemFromIndex(model->index(j,2,idx))->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); + } + } + //expand all + tree->expandAll(); + nochange=false; +} +void MTemplateEditor::deleteItem() +{ + //get selection + QModelIndex idx=tree->currentIndex(); + if(!idx.isValid())return; + QModelIndex bidx=model->index(idx.row(),0,idx.parent()); + QString fn=model->data(bidx,NAMEROLE).toString(); + if(fn=="")return; + //delete + if(store->deleteTemplate(fn)) + model->removeRow(idx.row(),idx.parent()); + else + QMessageBox::warning(this,tr("Warning"),tr("Unable to delete this template.")); +} + +void MTemplateEditor::addItem() +{ + //get selection + QModelIndex idx=tree->currentIndex(); + if(!idx.isValid())return; + QModelIndex pidx=idx.parent(); + QModelIndex bidx=model->index(idx.row(),0,pidx); + QString base=model->data(bidx,BASEROLE).toString(); + if(base=="")return; + //query file name + QString fn=QFileDialog::getOpenFileName(this,tr("Select Template File")); + if(fn=="")return; + //check extension + QString ext=QFileInfo(fn).completeSuffix(); + if(!MTemplate::legalSuffixes(base).contains(ext)){ + QMessageBox::warning(this,tr("Warning"),tr("Files with this extension (%1) are not legal for this template.").arg(ext)); + return; + } + //get new variant name + QStringList lst; + for(int i=0;irowCount(pidx);i++){ + QStringList f=model->data(model->index(i,0,pidx),NAMEROLE).toString().split(","); + if(f.size()>1) + lst<setTemplate(base+"."+ext+","+nvar,fn)) + forceUpdate(); + else + QMessageBox::warning(this,tr("Warning"),tr("Unable to upload file.")); +} + +void MTemplateEditor::changeDescr(QStandardItem*item) +{ + if(nochange)return; + if(!item)return; + //sanity check + if(item->column()!=1)return; + //get full name & data + QModelIndex idx=item->index(); + QString dsc=model->data(idx).toString(); + QModelIndex bidx=model->index(item->row(),0,idx.parent()); + QString fn=model->data(bidx,NAMEROLE).toString(); + if(fn=="")return; + //send to server + if(!store->setTemplateDescription(fn,dsc)) + QMessageBox::warning(this,tr("Warning"),tr("Unable to send new description to server.")); +} + +void MTemplateEditor::forceUpdate() +{ + store->updateTemplates(true); + updateView(); +} diff --git a/src/templates/templatedlg.h b/src/templates/templatedlg.h new file mode 100644 index 0000000..b4e7fcb --- /dev/null +++ b/src/templates/templatedlg.h @@ -0,0 +1,64 @@ +// +// C++ Interface: templatedlg +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_TEMPLATEDLG_H +#define MAGICSMOKE_TEMPLATEDLG_H + +#include +#include + +#include "templates.h" + +class QComboBox; +class QStandardItem; +class QStandardItemModel; +class QStringList; +class QTreeView; + +/**gives the user a choice of template variants; used by MTemplateStore only!*/ +class MTemplateChoice:public QDialog +{ + Q_OBJECT + public: + MTemplateChoice(const QString&,const QString&,const QStringList&,const QString&); + + MTemplate choice()const; + private: + //selection box + QComboBox*box; + //settings group where to find data + QString sgroup,cachedir; +}; + +/**lets the user add and remove templates and variants to/from the database; used by MWebRequest!*/ +class MTemplateEditor:public QDialog +{ + Q_OBJECT + public: + MTemplateEditor(MTemplateStore*); + + private slots: + void updateView(); + void deleteItem(); + void addItem(); + void changeDescr(QStandardItem*); + void forceUpdate(); + private: + MTemplateStore*store; + QTreeView*tree; + QStandardItemModel*model; + bool nochange; +}; + + + +#endif diff --git a/src/templates/templates.cpp b/src/templates/templates.cpp new file mode 100644 index 0000000..3642310 --- /dev/null +++ b/src/templates/templates.cpp @@ -0,0 +1,362 @@ +// +// C++ Implementation: templates +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +/***************************** + * Settings hierarchy for templates: + * + * /templates/$PROFILEID -> template settings for this profile + * .../$TEMPLATENAME -> the settings for a template, uses the complete name (eg. bill.odtt,2) + * ....../checksum -> key that stores the checksum (calculated by server!!) + * ....../description -> key that stores the description (as received from server) + * + * + * Template buffer on disk: + * + * req->dataDir()/templates -> directory for template files; + * each file is stored with complete name, no meta-info + ***************************/ + +#include "main.h" +#include "templatedlg.h" +#include "templates.h" +#include "msinterface.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define req (MSInterface::instance()) + +MTemplateStore::MTemplateStore(QString p) +{ + profileid=p; +} + +MTemplate MTemplateStore::getTemplate(QString f) +{ + //syntax check + f=f.toLower(); + QRegExp fregexp("[a-z0-9_]+"); + if(!fregexp.exactMatch(f))return MTemplate(); + //update directory (no force) + updateTemplates(false); + //find files matching the pattern + //basics + QString dname=req->dataDir()+"/templates/"; + QSettings set; + set.beginGroup("templates/"+profileid); + //get directory + QStringList dir=set.childGroups(); + QStringList tdir; + for(int i=0;idataDir()+"/templates/"; + QSettings set; + set.beginGroup("templates/"+profileid); + //make sure directory exists + QDir(req->dataDir()).mkpath("templates"); + //do we need an update yet? + QDateTime last=QDateTime::fromTime_t(set.value("lastupdate",0).toInt()+300); + if(last>=QDateTime::currentDateTime() && !force)return; + + //get local info + QStringList files=set.childGroups(); + QMap fmap; + for(int i=0;irequest("gettemplatelist",""))return; + if(req->responseStatus()!=MWebRequest::Ok)return; + //remember update time + set.setValue("lastupdate",QDateTime::currentDateTime().toTime_t()); + //parse info + QDomDocument doc; + if(!doc.setContent(req->responseBody()))return; + //scan and create new list + QDomNodeList nl=doc.elementsByTagName("Template"); + QMapnfmap; + for(int i=0;irequest("gettemplate",fn.toUtf8()))return false; + if(req->responseStatus()!=MWebRequest::Ok)return false; + //store + QFile f(dname+"/"+fn); + if(!f.open(QIODevice::WriteOnly|QIODevice::Truncate))return false; + f.write(req->responseBody()); + return true; + */return false; +} + +bool MTemplateStore::setTemplate(QString n,QString f) +{/*TODO + //very rough sanity check + QRegExp fregexp("[a-z0-9_\\.,]+"); + if(!fregexp.exactMatch(n))return false; + //get content + QFile fl(f); + if(!fl.open(QIODevice::ReadOnly)) + return false; + QByteArray ba=fl.readAll(); + fl.close(); + //send to server + if(!req->request("settemplate",n.toUtf8()+"\n"+ba)) + return false; + if(req->responseStatus()!=MWebRequest::Ok) + return false; + //delete it from cache, so it is retrieved again; force retrieval + //TODO: the server returns the hash (since dec08), use it and update the cache without retrieval + QSettings set; + set.remove("templates/"+profileid+"/"+n); + set.setValue("templates/"+profileid+"/lastupdate",0); + QFile(req->dataDir()+"/templates/"+n).remove(); + //return success + return true;*/return false; +} + +bool MTemplateStore::deleteTemplate(QString n) +{/*TODO + //very rough sanity check + QRegExp fregexp("[a-z0-9_\\.,]+"); + if(!fregexp.exactMatch(n))return false; + //send to server + if(!req->request("deletetemplate",n.toUtf8())) + return false; + if(req->responseStatus()!=MWebRequest::Ok) + return false; + //delete it from cache + QSettings set; + set.remove("templates/"+profileid+"/"+n); + QFile(req->dataDir()+"/templates/"+n).remove(); + return true;*/return false; +} + +bool MTemplateStore::setTemplateDescription(QString n,QString d) +{/*TODO + //very rough sanity check + QRegExp fregexp("[a-z0-9_\\.,]+"); + if(!fregexp.exactMatch(n))return false; + //check that we have a real change + QSettings set; + set.beginGroup("templates/"+profileid+"/"+n); + QString o=set.value("description").toString(); + qDebug("setting %s '%s' -> '%s'",n.toAscii().data(),o.toAscii().data(),d.toAscii().data()); + if(o==d)return true; + //send to server + if(!req->request("settemplatedescription",n.toUtf8()+"\n"+d.toUtf8())) + return false; + if(req->responseStatus()!=MWebRequest::Ok) + return false; + //update internal description + set.setValue("description",d); + //return success + return true;*/return false; +} + +QList MTemplateStore::allTemplates() +{ + updateTemplates(false); + QString dname=req->dataDir()+"/templates/"; + QSettings set; + set.beginGroup("templates/"+profileid); + QStringList names=set.childGroups(); + QList ret; + for(int i=0;i1)return lst[1]; + return ""; +} + +QString MTemplate::checksum()const{return m_checksum;} + +bool MTemplate::isValid()const{return m_fname!="";} + +QString MTemplate::targetExtension()const +{ + QString x=extension(); + //ODF file? + if(QRegExp("od.t").exactMatch(x))return x.left(3); + //all else: not storable + return ""; +} + +bool MTemplate::isOdf()const{return (type()&OdfTemplate)!=0;} + +bool MTemplate::isLabel()const{return type()==LabelTemplate;} +MTemplate::Type MTemplate::type()const +{ + QString x=extension(); + //ODF file? + if(x=="odtt")return OdtTemplate; + if(x=="odst")return OdsTemplate; + if(x=="odpt")return OdpTemplate; + if(x=="odgt")return OdgTemplate; + if(x=="odbt")return OdbTemplate; + //label? + if(x=="xtt")return LabelTemplate; + //hmm, unknown one + return UnknownTemplate; +} + +QString MTemplate::description()const{return m_descr;} + + +static QStringList tempBaseNames; +//static +QStringList MTemplate::legalBaseNames() +{ + if(tempBaseNames.size()==0){ + tempBaseNames<<"ticket"<<"voucher"<<"bill"<<"eventsummary"; + } + return tempBaseNames; +} + +//static +MTemplate::Types MTemplate::legalTypes(QString bn) +{ + if(bn=="ticket" || bn=="voucher") + return LabelTemplate; + if(bn=="bill" || bn=="eventsummary") + return OdfTemplate; + return UnknownTemplate; +} + +//static +QStringList MTemplate::legalSuffixes(QString bn) +{ + if(bn=="ticket" || bn=="voucher") + return QStringList()<<"xtt"; + if(bn=="bill" || bn=="eventsummary") + return QStringList()<<"odtt"<<"odst"<<"odpt"<<"odgt"<<"odbt"; + return QStringList(); +} diff --git a/src/templates/templates.h b/src/templates/templates.h new file mode 100644 index 0000000..08e5aa4 --- /dev/null +++ b/src/templates/templates.h @@ -0,0 +1,143 @@ +// +// C++ Interface: templates +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_TEMPLATES_H +#define MAGICSMOKE_TEMPLATES_H + +#include + +/**this class wraps a single template*/ +class MTemplate +{ + public: + /**creates an invalid template*/ + MTemplate(); + + /**returns the name/path of the cache file, if it exists*/ + QString cacheFileName()const; + + /**returns the file name of the template (eg. mytemplate.odtt)*/ + QString fileName()const; + + /**returns the complete encoded name of the template (eg. mytemplate.odtt,v1)*/ + QString completeFileName()const; + + /**returns the base name of the template (eg. mytemplate for mytemplate.odtt)*/ + QString baseName()const; + + /**returns the extension of the template (eg. odtt for mytemplate.odtt)*/ + QString extension()const; + + /**returns the variant ID of the template (warning: it has no meaning outside the template storage system*/ + QString variantID()const; + + /**returns the checksum (calculated by the server)*/ + QString checksum()const; + + /**returns the description*/ + QString description()const; + + /**returns whether this is a valid template*/ + bool isValid()const; + + /**returns the extension of the target document if it is saved (empty if the template cannot be saved)*/ + QString targetExtension()const; + + /**returns whether this is an ODF template*/ + bool isOdf()const; + + /**returns whether this is a label template*/ + bool isLabel()const; + + /**template type; currently only ODF and Labels are known*/ + enum Type{ + /**uninitialized or unknown label type*/ + UnknownTemplate=0, + /**ODF Text template*/ + OdtTemplate=1, + /**ODF SpreadSheet template*/ + OdsTemplate=2, + /**ODF Presentation*/ + OdpTemplate=4, + /**ODF Drawing*/ + OdgTemplate=8, + /**ODF DataBase*/ + OdbTemplate=0x10, + /**ODF template*/ + OdfTemplate=0xff, + /**Label template*/ + LabelTemplate=0x100 + }; + Q_DECLARE_FLAGS(Types,Type) + + /**returns the template type*/ + Type type()const; + + /**returns the currently known (by the client) template base names*/ + static QStringList legalBaseNames(); + + /**returns the legal file types (as understood by the client) for a template base name; returns UnknownTemplate if none is legal*/ + static Types legalTypes(QString); + + /**returns the legal template file suffixes (as understood by the client) for a template base name; returns empty if none is legal*/ + static QStringList legalSuffixes(QString); + + protected: + friend class MTemplateStore; + friend class MTemplateChoice; + /**creates a template wrapper from a cache file name; this constructor is used internally in the storage system*/ + MTemplate(QString fn,QString chk,QString dsc); + private: + QString m_fname,m_checksum,m_descr; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(MTemplate::Types) + +/**this class implements the storage end of the template subsystem, its only instance exists in the webrequest*/ +class MTemplateStore +{ + protected: + //FIXME friend class MWebRequest; + friend class MTemplateEditor; + /**instantiates the template subsystem*/ + MTemplateStore(QString); + + /**stores a specific template*/ + bool setTemplate(QString templatename,QString localfile); + + /**stores a new description for a template*/ + bool setTemplateDescription(QString templatename,QString description); + + /**deletes a template (requires full name), used by MTemplateEditor*/ + bool deleteTemplate(QString); + + /**updates the template directory, does not do anything if force==false and the last update was less than 5min ago*/ + void updateTemplates(bool force); + + /**returns all templates (for MTemplateEditor)*/ + QList allTemplates(); + + private: + /**unused, just here to remove it from accessability*/ + MTemplateStore(){} + + /**helper for updateTemplates: retrieves a single file from the server*/ + bool retrieveFile(QString,QString); + + public: + /**returns a specific template, opens a template choice dialog if necessary*/ + MTemplate getTemplate(QString); + + private: + QString profileid; +}; + +#endif diff --git a/src/templates/templates.pri b/src/templates/templates.pri new file mode 100644 index 0000000..9085cb3 --- /dev/null +++ b/src/templates/templates.pri @@ -0,0 +1,17 @@ +HEADERS += \ + templates/odtrender.h \ + templates/ticketrender.h \ + templates/office.h \ + templates/labeldlg.h \ + templates/templates.h \ + templates/templatedlg.h + +SOURCES += \ + templates/odtrender.cpp \ + templates/ticketrender.cpp \ + templates/office.cpp \ + templates/labeldlg.cpp \ + templates/templates.cpp \ + templates/templatedlg.cpp + +INCLUDEPATH += ./templates \ No newline at end of file diff --git a/src/templates/ticketrender.cpp b/src/templates/ticketrender.cpp new file mode 100644 index 0000000..8e5b9d4 --- /dev/null +++ b/src/templates/ticketrender.cpp @@ -0,0 +1,561 @@ +// +// C++ Implementation: odtrender +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "ticketrender.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../zip/qunzip.h" +#include "../zip/qzip.h" +#include "code39.h" +#include "order.h" + + +class MLabelRendererPrivate +{ + protected: + friend class MLabelRenderer; + + MLabelRendererPrivate(QString file,MLabelRenderer*p); + ~MLabelRendererPrivate(); + + //part of the constructor + void prepare(QUnZip&); + + //called by MLabelRenderer + bool render(const MLabel&,QPaintDevice&,QPainter*,QPointF); + + //called by MLabelRenderer + QSizeF labelSize(const QPaintDevice&); + + private: + MLabelRenderer*parent; + //internal font-IDs + QList fdb; + QMapfdbl; + QMapgetfontdb; + //image cache: + QMap idb; + //XML template cache (template.xml) + QDomDocument txml; + //contains the unit of measurement + QString unit; + //contains the size of the Label in "unit" + QSizeF tsize; + //after constructor: contains whether this object is correctly initialized + bool canrender; + + //does the actual rendering work + void render(QDomElement&,const MLabel&,QPaintDevice&,QPainter*,QPointF); + + //renders a single line + QString renderLine(const MLabel&,QString); + + //parses element to extract offset + QPointF getoffset(QDomElement&,bool); + + //parses element to extract size + QSizeF getsize(QDomElement&,bool); + + //converts a point to "natural" coordinates + QPointF tonatural(const QPaintDevice&,QPointF); + + //converts a size to "natural" coordinates + QSizeF tonatural(const QPaintDevice&,QSizeF); + + //returns a system font name + QString getfont(QString); +}; + +MLabelRenderer::MLabelRenderer(MTemplate file) +{ + d=new MLabelRendererPrivate(file.cacheFileName(),this); +} + +MLabelRendererPrivate::MLabelRendererPrivate(QString file,MLabelRenderer*p) +{ + parent=p; + canrender=false; + //open ZIP + QUnZip temp; + QFile tfile(file); + if(tfile.open(QIODevice::ReadOnly))temp.open(&tfile); + else return; + prepare(temp); + temp.close(); + tfile.close(); + qDebug("Label Renderer initialized: %s",canrender?"ready!":"error, can't render."); +} + +void MLabelRendererPrivate::prepare(QUnZip&temp) +{ + //make sure this is a valid ZIP file + if(!temp.locateFile("template.xml")){ + qDebug("Label renderer: can't find template.xml"); + canrender=false; + return; + } + //load XML + QBuffer buffer; + buffer.open(QBuffer::ReadWrite); + temp.getCurrentFile(buffer); + if(!txml.setContent(buffer.data())){ + qDebug("Label renderer: can't parse template.xml - XML fault."); + canrender=false; + return; + } + //assume we can render now + canrender=true; + //parse document element + QDomElement doc=txml.documentElement(); + unit=doc.attribute("unit","mm"); + if(unit!="mm"&&unit!="in"){ + qDebug("Label renderer: illegal unit in template.xml."); + canrender=false; + return; + } + tsize=getsize(doc,true); + if(!canrender)return; + //check for fonts + QDomNodeList nl=txml.elementsByTagName("LoadFont"); + QStringList fndb; + for(int i=0;irender(ticket,pdev,painter,offset); +} + +bool MLabelRendererPrivate::render(const MLabel&ticket,QPaintDevice&pdev,QPainter*painter,QPointF offset) +{ + //sanity check + if(!canrender){ + qDebug("Label Renderer: render called, but can't render."); + return false; + } + //actually render + QDomElement el=txml.documentElement(); + render(el,ticket,pdev,painter,offset); + //return result (canrender may be changed by renderer + return canrender; +} + +QPointF MLabelRendererPrivate::getoffset(QDomElement&el,bool isfatal) +{ + QStringList off=el.attribute("offset").split(" "); + if(off.size()!=2){ + if(isfatal){ + qDebug("Label renderer error: Illegal offset in %s at line %i column %i.",el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); + canrender=false; + } + return QPointF(); + } + QPointF ret; + bool b; + ret.setX(off[0].toDouble(&b)); + if(!b){ + if(isfatal){ + qDebug("Label renderer error: Illegal offset in %s at line %i column %i.",el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); + canrender=false; + } + return QPointF(); + } + ret.setY(off[1].toDouble(&b)); + if(!b){ + if(isfatal){ + qDebug("Label renderer error: Illegal offset in %s at line %i column %i.",el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); + canrender=false; + } + return QPointF(); + } + return ret; +} + +QSizeF MLabelRendererPrivate::getsize(QDomElement&el,bool isfatal) +{ + QStringList lst=el.attribute("size").split(" "); + if(lst.size()!=2){ + if(isfatal){ + qDebug("Label renderer error: Illegal size (%i items) in %s at line %i column %i.",lst.size(),el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); + canrender=false; + } + return QSizeF(); + } + QSizeF ret; + bool b; + ret.setWidth(lst[0].toDouble(&b)); + if(!b){ + if(isfatal){ + qDebug("Label renderer error: Illegal size (invalid width) in %s at line %i column %i.",el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); + canrender=false; + } + return QSizeF(); + } + ret.setHeight(lst[1].toDouble(&b)); + if(!b){ + if(isfatal){ + qDebug("Label renderer error: Illegal size (invalid height) in %s at line %i column %i.",el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); + canrender=false; + } + return QSizeF(); + } + return ret; +} + +QPointF MLabelRendererPrivate::tonatural(const QPaintDevice&dev,QPointF p) +{ + double fac; + if(unit=="mm")fac=25.4; + else fac=1.0; + p.setX(p.x()*dev.logicalDpiX()/fac); + p.setY(p.y()*dev.logicalDpiY()/fac); + return p; +} + +QSizeF MLabelRendererPrivate::tonatural(const QPaintDevice&dev,QSizeF s) +{ + double fac; + if(unit=="mm")fac=25.4; + else fac=1.0; + s.setWidth(s.width()*dev.logicalDpiX()/fac); + s.setHeight(s.height()*dev.logicalDpiY()/fac); + return s; +} + +void MLabelRendererPrivate::render(QDomElement&sup, const MLabel&tick, QPaintDevice&pdev, QPainter*painter, QPointF noff) +{ + //initialize painter + QPainter *paint; + if(painter) + paint=painter; + else + paint=new QPainter(&pdev); + QSizeF nsize=tonatural(pdev,tsize); + paint->setClipRect(QRectF(noff,nsize)); + //parse file + QDomNodeList nl=sup.childNodes(); + for(int i=0;idrawImage(QRectF(tonatural(pdev,off)+noff,tonatural(pdev,sz)),idb[fname]); + }else + if(enm=="Text"){ + //get attributes + QPointF off=getoffset(el,true); + if(!canrender){ + return; + } + QSizeF sz=getsize(el,true); + if(!canrender){ + return; + } + //get text + QString text=renderLine(tick,el.text().trimmed()); + //get font; TODO: introduce weight and italic settings + QString font=getfont(el.attribute("font","%")); + int size=el.attribute("fontsize","10").toInt(); + if(size<1)size=10; + paint->setFont(QFont(font,size)); + //get alignment + int flag=0; + QString al=el.attribute("align","left"); + if(al=="left")flag=Qt::AlignLeft;else + if(al=="right")flag=Qt::AlignRight; + else flag=Qt::AlignHCenter; + al=el.attribute("valign","top"); + if(al=="top")flag|=Qt::AlignTop;else + if(al=="bottom")flag|=Qt::AlignBottom; + else flag|=Qt::AlignVCenter; + //render + paint->drawText(QRectF(tonatural(pdev,off)+noff,tonatural(pdev,sz)),flag,text); + qDebug("test %s",text.toLatin1().data()); + }else + if(enm=="Barcode"){ + //get attributes + QPointF off=getoffset(el,true); + if(!canrender){ + return; + } + QSizeF sz=getsize(el,true); + if(!canrender){ + return; + } + QString cd=tick.getVariable("BARCODE"); + //paint + //TODO: find a way to switch off antialiasing + QRectF rect(tonatural(pdev,off)+noff,tonatural(pdev,sz)); + paint->drawImage(rect,code39(cd)); + }else{ + qDebug("Label renderer error: unknown element %s in label template at line %i column %i.",enm.toAscii().data(),el.lineNumber(),el.columnNumber()); + canrender=false; + return; + } + } + if(!painter) + delete paint; +} + +QString MLabelRendererPrivate::getfont(QString fnt) +{ + QString dfont=QSettings().value("defaultfont","Helvetica").toString(); + //did we already answer this? + if(getfontdb.contains(fnt))return getfontdb[fnt]; + if(fnt=="%")return dfont; + //is it a file name? + if(fnt.size())if(fnt[0]=='@'){ + QString font; + QString fnt2=fnt.mid(1); + if(fdbl.contains(fnt2))if(fdbl[fnt2].size()) + font=fdbl[fnt2][0]; + if(font.isEmpty()){ + qDebug("Label renderer warning: font file %s did not contain font families, using %s instead.",fnt.toAscii().data(),dfont.toAscii().data()); + font=dfont; + } + getfontdb.insert(fnt,font); + } + if(!getfontdb.contains(fnt)){ + QStringList fonts=QFontDatabase().families(); + if(!fonts.contains(fnt)){ + qDebug("Label renderer warning: font %s not found, searching a close match...",fnt.toAscii().data()); + QString font; + for(int i=0;ilabelSize(dev); +} + +QSizeF MLabelRendererPrivate::labelSize(const QPaintDevice&dev) +{ + return tonatural(dev,tsize); +} + +MLabel::MLabel(){} +MLabel::~MLabel(){} + +class MTicketLabel:public MLabel +{ + public: + MTicketLabel(const MTicket&t):tick(t){} + QString getVariable(QString var)const; + private: + MTicket tick; +}; + +QString MTicketLabel::getVariable(QString var)const +{ + if(var=="TICKETID"||var=="BARCODE")return tick.ticketid(); + if(var=="PRICE")return tick.priceString(); + if(var=="DATETIME")return tick.event().startTimeString(); + if(var=="ROOM")return tick.event().room(); + if(var=="TITLE")return tick.event().title(); + if(var=="ARTIST")return tick.event().artist().value().name(); + return ""; +} + +MTicketRenderer::MTicketRenderer(MTemplate f):MLabelRenderer(f){} +bool MTicketRenderer::render(const MTicket&label,QPaintDevice&pdev,QPainter*painter,QPointF offset) +{ + return MLabelRenderer::render(MTicketLabel(label),pdev,painter,offset); +} + +class MVoucherLabel:public MLabel +{ + public: + MVoucherLabel(const MVoucher&t):vouc(t){} + QString getVariable(QString var)const; + private: + MVoucher vouc; +}; + +QString MVoucherLabel::getVariable(QString var)const +{ + if(var=="VOUCHERID"||var=="BARCODE")return vouc.voucherid(); + if(var=="PRICE")return vouc.priceString(); + if(var=="VALUE")return vouc.valueString(); + return ""; +} + +MVoucherRenderer::MVoucherRenderer(MTemplate f):MLabelRenderer(f){} +bool MVoucherRenderer::render(const MVoucher&label,QPaintDevice&pdev,QPainter*painter,QPointF offset) +{ + return MLabelRenderer::render(MVoucherLabel(label),pdev,painter,offset); +} diff --git a/src/templates/ticketrender.h b/src/templates/ticketrender.h new file mode 100644 index 0000000..46cb400 --- /dev/null +++ b/src/templates/ticketrender.h @@ -0,0 +1,80 @@ +// +// C++ Interface: odtrender +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2008 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef MAGICSMOKE_TICKETRENDER_H +#define MAGICSMOKE_TICKETRENDER_H + +#include +#include +#include + +#include "templates.h" + +class MLabelRendererPrivate; +class MTicket; +class MVoucher; +class QPaintDevice; +class QPainter; + +/**base class that describes labels*/ +class MLabel +{ + public: + /**constructs the label*/ + MLabel(); + /**deconstructs the label*/ + virtual ~MLabel(); + + /**abstract: overwrite this to return data for a label*/ + virtual QString getVariable(QString)const=0; +}; + +/**base class for all label rendering classes*/ +class MLabelRenderer +{ + public: + /**instantiates a renderer loaded from template file*/ + MLabelRenderer(MTemplate file); + /**deletes the renderer*/ + virtual ~MLabelRenderer(); + + /**renders the ticket; returns whether the rendering was successful*/ + virtual bool render(const MLabel&label,QPaintDevice&pdev,QPainter*painter=0,QPointF offset=QPointF()); + + /**returns the size of the ticket in the coordinates of the specified paint device (used for preview)*/ + virtual QSizeF labelSize(const QPaintDevice&); + + protected: + friend class MLabelRendererPrivate; + + private: + MLabelRendererPrivate*d; +}; + +/**convenience class: renders vouchers directly*/ +class MVoucherRenderer:public MLabelRenderer +{ + public: + MVoucherRenderer(MTemplate f); + bool render(const MVoucher&label,QPaintDevice&pdev,QPainter*painter=0,QPointF offset=QPointF()); +}; + +/**convenience class: renders vouchers directly*/ +class MTicketRenderer:public MLabelRenderer +{ + public: + MTicketRenderer(MTemplate f); + bool render(const MTicket&label,QPaintDevice&pdev,QPainter*painter=0,QPointF offset=QPointF()); +}; + + +#endif diff --git a/src/ticketrender.cpp b/src/ticketrender.cpp deleted file mode 100644 index 8e5b9d4..0000000 --- a/src/ticketrender.cpp +++ /dev/null @@ -1,561 +0,0 @@ -// -// C++ Implementation: odtrender -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#include "ticketrender.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../zip/qunzip.h" -#include "../zip/qzip.h" -#include "code39.h" -#include "order.h" - - -class MLabelRendererPrivate -{ - protected: - friend class MLabelRenderer; - - MLabelRendererPrivate(QString file,MLabelRenderer*p); - ~MLabelRendererPrivate(); - - //part of the constructor - void prepare(QUnZip&); - - //called by MLabelRenderer - bool render(const MLabel&,QPaintDevice&,QPainter*,QPointF); - - //called by MLabelRenderer - QSizeF labelSize(const QPaintDevice&); - - private: - MLabelRenderer*parent; - //internal font-IDs - QList fdb; - QMapfdbl; - QMapgetfontdb; - //image cache: - QMap idb; - //XML template cache (template.xml) - QDomDocument txml; - //contains the unit of measurement - QString unit; - //contains the size of the Label in "unit" - QSizeF tsize; - //after constructor: contains whether this object is correctly initialized - bool canrender; - - //does the actual rendering work - void render(QDomElement&,const MLabel&,QPaintDevice&,QPainter*,QPointF); - - //renders a single line - QString renderLine(const MLabel&,QString); - - //parses element to extract offset - QPointF getoffset(QDomElement&,bool); - - //parses element to extract size - QSizeF getsize(QDomElement&,bool); - - //converts a point to "natural" coordinates - QPointF tonatural(const QPaintDevice&,QPointF); - - //converts a size to "natural" coordinates - QSizeF tonatural(const QPaintDevice&,QSizeF); - - //returns a system font name - QString getfont(QString); -}; - -MLabelRenderer::MLabelRenderer(MTemplate file) -{ - d=new MLabelRendererPrivate(file.cacheFileName(),this); -} - -MLabelRendererPrivate::MLabelRendererPrivate(QString file,MLabelRenderer*p) -{ - parent=p; - canrender=false; - //open ZIP - QUnZip temp; - QFile tfile(file); - if(tfile.open(QIODevice::ReadOnly))temp.open(&tfile); - else return; - prepare(temp); - temp.close(); - tfile.close(); - qDebug("Label Renderer initialized: %s",canrender?"ready!":"error, can't render."); -} - -void MLabelRendererPrivate::prepare(QUnZip&temp) -{ - //make sure this is a valid ZIP file - if(!temp.locateFile("template.xml")){ - qDebug("Label renderer: can't find template.xml"); - canrender=false; - return; - } - //load XML - QBuffer buffer; - buffer.open(QBuffer::ReadWrite); - temp.getCurrentFile(buffer); - if(!txml.setContent(buffer.data())){ - qDebug("Label renderer: can't parse template.xml - XML fault."); - canrender=false; - return; - } - //assume we can render now - canrender=true; - //parse document element - QDomElement doc=txml.documentElement(); - unit=doc.attribute("unit","mm"); - if(unit!="mm"&&unit!="in"){ - qDebug("Label renderer: illegal unit in template.xml."); - canrender=false; - return; - } - tsize=getsize(doc,true); - if(!canrender)return; - //check for fonts - QDomNodeList nl=txml.elementsByTagName("LoadFont"); - QStringList fndb; - for(int i=0;irender(ticket,pdev,painter,offset); -} - -bool MLabelRendererPrivate::render(const MLabel&ticket,QPaintDevice&pdev,QPainter*painter,QPointF offset) -{ - //sanity check - if(!canrender){ - qDebug("Label Renderer: render called, but can't render."); - return false; - } - //actually render - QDomElement el=txml.documentElement(); - render(el,ticket,pdev,painter,offset); - //return result (canrender may be changed by renderer - return canrender; -} - -QPointF MLabelRendererPrivate::getoffset(QDomElement&el,bool isfatal) -{ - QStringList off=el.attribute("offset").split(" "); - if(off.size()!=2){ - if(isfatal){ - qDebug("Label renderer error: Illegal offset in %s at line %i column %i.",el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); - canrender=false; - } - return QPointF(); - } - QPointF ret; - bool b; - ret.setX(off[0].toDouble(&b)); - if(!b){ - if(isfatal){ - qDebug("Label renderer error: Illegal offset in %s at line %i column %i.",el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); - canrender=false; - } - return QPointF(); - } - ret.setY(off[1].toDouble(&b)); - if(!b){ - if(isfatal){ - qDebug("Label renderer error: Illegal offset in %s at line %i column %i.",el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); - canrender=false; - } - return QPointF(); - } - return ret; -} - -QSizeF MLabelRendererPrivate::getsize(QDomElement&el,bool isfatal) -{ - QStringList lst=el.attribute("size").split(" "); - if(lst.size()!=2){ - if(isfatal){ - qDebug("Label renderer error: Illegal size (%i items) in %s at line %i column %i.",lst.size(),el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); - canrender=false; - } - return QSizeF(); - } - QSizeF ret; - bool b; - ret.setWidth(lst[0].toDouble(&b)); - if(!b){ - if(isfatal){ - qDebug("Label renderer error: Illegal size (invalid width) in %s at line %i column %i.",el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); - canrender=false; - } - return QSizeF(); - } - ret.setHeight(lst[1].toDouble(&b)); - if(!b){ - if(isfatal){ - qDebug("Label renderer error: Illegal size (invalid height) in %s at line %i column %i.",el.tagName().toAscii().data(),el.lineNumber(),el.columnNumber()); - canrender=false; - } - return QSizeF(); - } - return ret; -} - -QPointF MLabelRendererPrivate::tonatural(const QPaintDevice&dev,QPointF p) -{ - double fac; - if(unit=="mm")fac=25.4; - else fac=1.0; - p.setX(p.x()*dev.logicalDpiX()/fac); - p.setY(p.y()*dev.logicalDpiY()/fac); - return p; -} - -QSizeF MLabelRendererPrivate::tonatural(const QPaintDevice&dev,QSizeF s) -{ - double fac; - if(unit=="mm")fac=25.4; - else fac=1.0; - s.setWidth(s.width()*dev.logicalDpiX()/fac); - s.setHeight(s.height()*dev.logicalDpiY()/fac); - return s; -} - -void MLabelRendererPrivate::render(QDomElement&sup, const MLabel&tick, QPaintDevice&pdev, QPainter*painter, QPointF noff) -{ - //initialize painter - QPainter *paint; - if(painter) - paint=painter; - else - paint=new QPainter(&pdev); - QSizeF nsize=tonatural(pdev,tsize); - paint->setClipRect(QRectF(noff,nsize)); - //parse file - QDomNodeList nl=sup.childNodes(); - for(int i=0;idrawImage(QRectF(tonatural(pdev,off)+noff,tonatural(pdev,sz)),idb[fname]); - }else - if(enm=="Text"){ - //get attributes - QPointF off=getoffset(el,true); - if(!canrender){ - return; - } - QSizeF sz=getsize(el,true); - if(!canrender){ - return; - } - //get text - QString text=renderLine(tick,el.text().trimmed()); - //get font; TODO: introduce weight and italic settings - QString font=getfont(el.attribute("font","%")); - int size=el.attribute("fontsize","10").toInt(); - if(size<1)size=10; - paint->setFont(QFont(font,size)); - //get alignment - int flag=0; - QString al=el.attribute("align","left"); - if(al=="left")flag=Qt::AlignLeft;else - if(al=="right")flag=Qt::AlignRight; - else flag=Qt::AlignHCenter; - al=el.attribute("valign","top"); - if(al=="top")flag|=Qt::AlignTop;else - if(al=="bottom")flag|=Qt::AlignBottom; - else flag|=Qt::AlignVCenter; - //render - paint->drawText(QRectF(tonatural(pdev,off)+noff,tonatural(pdev,sz)),flag,text); - qDebug("test %s",text.toLatin1().data()); - }else - if(enm=="Barcode"){ - //get attributes - QPointF off=getoffset(el,true); - if(!canrender){ - return; - } - QSizeF sz=getsize(el,true); - if(!canrender){ - return; - } - QString cd=tick.getVariable("BARCODE"); - //paint - //TODO: find a way to switch off antialiasing - QRectF rect(tonatural(pdev,off)+noff,tonatural(pdev,sz)); - paint->drawImage(rect,code39(cd)); - }else{ - qDebug("Label renderer error: unknown element %s in label template at line %i column %i.",enm.toAscii().data(),el.lineNumber(),el.columnNumber()); - canrender=false; - return; - } - } - if(!painter) - delete paint; -} - -QString MLabelRendererPrivate::getfont(QString fnt) -{ - QString dfont=QSettings().value("defaultfont","Helvetica").toString(); - //did we already answer this? - if(getfontdb.contains(fnt))return getfontdb[fnt]; - if(fnt=="%")return dfont; - //is it a file name? - if(fnt.size())if(fnt[0]=='@'){ - QString font; - QString fnt2=fnt.mid(1); - if(fdbl.contains(fnt2))if(fdbl[fnt2].size()) - font=fdbl[fnt2][0]; - if(font.isEmpty()){ - qDebug("Label renderer warning: font file %s did not contain font families, using %s instead.",fnt.toAscii().data(),dfont.toAscii().data()); - font=dfont; - } - getfontdb.insert(fnt,font); - } - if(!getfontdb.contains(fnt)){ - QStringList fonts=QFontDatabase().families(); - if(!fonts.contains(fnt)){ - qDebug("Label renderer warning: font %s not found, searching a close match...",fnt.toAscii().data()); - QString font; - for(int i=0;ilabelSize(dev); -} - -QSizeF MLabelRendererPrivate::labelSize(const QPaintDevice&dev) -{ - return tonatural(dev,tsize); -} - -MLabel::MLabel(){} -MLabel::~MLabel(){} - -class MTicketLabel:public MLabel -{ - public: - MTicketLabel(const MTicket&t):tick(t){} - QString getVariable(QString var)const; - private: - MTicket tick; -}; - -QString MTicketLabel::getVariable(QString var)const -{ - if(var=="TICKETID"||var=="BARCODE")return tick.ticketid(); - if(var=="PRICE")return tick.priceString(); - if(var=="DATETIME")return tick.event().startTimeString(); - if(var=="ROOM")return tick.event().room(); - if(var=="TITLE")return tick.event().title(); - if(var=="ARTIST")return tick.event().artist().value().name(); - return ""; -} - -MTicketRenderer::MTicketRenderer(MTemplate f):MLabelRenderer(f){} -bool MTicketRenderer::render(const MTicket&label,QPaintDevice&pdev,QPainter*painter,QPointF offset) -{ - return MLabelRenderer::render(MTicketLabel(label),pdev,painter,offset); -} - -class MVoucherLabel:public MLabel -{ - public: - MVoucherLabel(const MVoucher&t):vouc(t){} - QString getVariable(QString var)const; - private: - MVoucher vouc; -}; - -QString MVoucherLabel::getVariable(QString var)const -{ - if(var=="VOUCHERID"||var=="BARCODE")return vouc.voucherid(); - if(var=="PRICE")return vouc.priceString(); - if(var=="VALUE")return vouc.valueString(); - return ""; -} - -MVoucherRenderer::MVoucherRenderer(MTemplate f):MLabelRenderer(f){} -bool MVoucherRenderer::render(const MVoucher&label,QPaintDevice&pdev,QPainter*painter,QPointF offset) -{ - return MLabelRenderer::render(MVoucherLabel(label),pdev,painter,offset); -} diff --git a/src/ticketrender.h b/src/ticketrender.h deleted file mode 100644 index 46cb400..0000000 --- a/src/ticketrender.h +++ /dev/null @@ -1,80 +0,0 @@ -// -// C++ Interface: odtrender -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2008 -// -// Copyright: See README/COPYING files that come with this distribution -// -// - -#ifndef MAGICSMOKE_TICKETRENDER_H -#define MAGICSMOKE_TICKETRENDER_H - -#include -#include -#include - -#include "templates.h" - -class MLabelRendererPrivate; -class MTicket; -class MVoucher; -class QPaintDevice; -class QPainter; - -/**base class that describes labels*/ -class MLabel -{ - public: - /**constructs the label*/ - MLabel(); - /**deconstructs the label*/ - virtual ~MLabel(); - - /**abstract: overwrite this to return data for a label*/ - virtual QString getVariable(QString)const=0; -}; - -/**base class for all label rendering classes*/ -class MLabelRenderer -{ - public: - /**instantiates a renderer loaded from template file*/ - MLabelRenderer(MTemplate file); - /**deletes the renderer*/ - virtual ~MLabelRenderer(); - - /**renders the ticket; returns whether the rendering was successful*/ - virtual bool render(const MLabel&label,QPaintDevice&pdev,QPainter*painter=0,QPointF offset=QPointF()); - - /**returns the size of the ticket in the coordinates of the specified paint device (used for preview)*/ - virtual QSizeF labelSize(const QPaintDevice&); - - protected: - friend class MLabelRendererPrivate; - - private: - MLabelRendererPrivate*d; -}; - -/**convenience class: renders vouchers directly*/ -class MVoucherRenderer:public MLabelRenderer -{ - public: - MVoucherRenderer(MTemplate f); - bool render(const MVoucher&label,QPaintDevice&pdev,QPainter*painter=0,QPointF offset=QPointF()); -}; - -/**convenience class: renders vouchers directly*/ -class MTicketRenderer:public MLabelRenderer -{ - public: - MTicketRenderer(MTemplate f); - bool render(const MTicket&label,QPaintDevice&pdev,QPainter*painter=0,QPointF offset=QPointF()); -}; - - -#endif diff --git a/src/user.cpp b/src/user.cpp deleted file mode 100644 index 4c7b18b..0000000 --- a/src/user.cpp +++ /dev/null @@ -1,257 +0,0 @@ -// -// C++ Implementation: user -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2007 -// -// Copyright: See COPYING file that comes with this distribution -// -// - -#include "user.h" -#include "msinterface.h" - -#include -#include -#include - -#define req (MSInterface::instance()) - -bool MUser::isValid() -{ - return QRegExp("[A-Za-z0-9_\\.,:-]+").exactMatch(name().value()); -} - -bool MUser::create(QString pwd) -{ - //do not attempt to save invalid or incomplete data - if(!isValid())return false; - //call - MTCreateUser cu=req->queryCreateUser(name(),pwd,""); - //check success - if(cu.stage()==cu.Success){ - operator=(cu.getuser().value()); - return true; - }else{ - return false; - } -} - -bool MUser::changePassword(QString pwd) -{ - //do not attempt to save invalid or incomplete data - if(!isValid())return false; - //call - MTChangePassword cp=req->queryChangePassword(name(),pwd); - //check success - if(cp.stage()==cp.Success){ - return true; - }else{ - return false; - } -} - -QString MUser::deleteUser(QString replace) -{ - if(!isValid())return QCoreApplication::translate("MUser","User not valid: cannot delete."); - MTDeleteUser du=req->queryDeleteUser(name(),replace); - if(du.stage()!=du.Success) - return " "+QCoreApplication::translate("php::",du.errorString().toAscii()); - else - return QString(); -} - -bool MUser::setDescription(QString d) -{ - //do not attempt to save invalid or incomplete data - if(!isValid())return false; - //call - MTSetUserDescription sud=req->querySetUserDescription(name(),d); - //check success - if(sud.stage()==sud.Success){ - setdescription(d); - return true; - }else{ - return false; - } -} - -MCheckList MUser::getRoles() -{ - //call - MTGetUserRoles gr=req->queryGetUserRoles(name()); - //check success - MCheckList ret; - //TODO: also get roles we don't have and do something about rights - if(gr.stage()==gr.Success){ - QListlr=gr.getroles(); - for(int i=0;ilr; - for(int i=0;iquerySetUserRoles(name(),lr); - if(sur.stage()==sur.Success)return true; - else*/ return false; -} - -MCheckList MUser::getHosts() -{/*TODO - //call - MTGetUserHosts gh=req->queryGetUserHosts(name()); - //check success - MCheckList ret; - if(gh.stage()==gh.Success){ - QList hl=gh.gethosts(); - for(int i=0;i hal; - for(int i=0;iquerySetUserHosts(name(),hal); - if(suh.stage()==suh.Success)return true; - else*/ return false; -} - -/********************************************************/ - -MAcl::MAcl() -{ - m_set=false; -} - -MAcl::MAcl(const MAcl&a) - :MCheckItem() -{ - m_role=a.m_role; - m_set=a.m_set; -} - -MAcl::MAcl(QString r,bool s) -{ - m_role=r; - m_set=s; -} - -QString MAcl::role()const -{ - return m_role; -} - -QString MAcl::key()const -{ - return m_role; -} - -QString MAcl::description()const -{ - return QCoreApplication::translate("TransactionNames::",m_role.toAscii().data()); -} - -QString MAcl::label()const -{ - QString d=description(); - if(d==m_role)return m_role; - else return m_role+": "+d; -} - -bool MAcl::isSet()const -{ - return m_set; -} - -void MAcl::set(bool b) -{ - m_set=b; -} - -MCheckItem* MAcl::copy()const -{ - return new MAcl(*this); -} - -/**************************************************/ - -MUserHost::MUserHost() -{ - m_set=false; -} - -MUserHost::MUserHost(const MUserHost&h) - :MCheckItem() -{ - m_host=h.m_host; - m_set=h.m_set; -} - -MUserHost::MUserHost(QString h,bool s) -{ - m_host=h; - m_set=s; -} - -/*TODO -MUserHost::MUserHost(const MOHostAcl&a) -{ - m_host=a.hostname(); - m_set=a.isset(); -}*/ - -QString MUserHost::host()const -{ - return m_host; -} - -QString MUserHost::key()const -{ - return m_host; -} - -QString MUserHost::label()const -{ - QString d=QCoreApplication::translate("SpecialHost",m_host.toAscii().data()); - if(d!=m_host)return m_host+": "+d; - else return m_host; -} - -bool MUserHost::isSet()const -{ - return m_set; -} - -void MUserHost::set(bool b) -{ - m_set=b; -} - -MCheckItem* MUserHost::copy()const -{ - return new MUserHost(*this); -} diff --git a/src/user.h b/src/user.h deleted file mode 100644 index e49f125..0000000 --- a/src/user.h +++ /dev/null @@ -1,119 +0,0 @@ -// -// C++ Interface: user -// -// Description: -// -// -// Author: Konrad Rosenbaum , (C) 2007 -// -// Copyright: See COPYING file that comes with this distribution -// -// - -#ifndef MAGICSMOKE_USER_H -#define MAGICSMOKE_USER_H - -#include - -#include "checkdlg.h" - -#include "MOUser.h" - -class MUser:public MOUser -{ - public: - /**create invalid user*/ - MUser():MOUser(){} - /**create user by name*/ - MUser(QString i){setname(i);} - /**copy user*/ - MUser(const MUser&u):MOUser(u){} - - /**copy user*/ - MUser& operator=(const MOUser&u){MOUser::operator=(u);return *this;} - - /**checks user name*/ - bool isValid(); - - /**creates user in database with an initial password; returns true on success*/ - bool create(QString pwd); - - /**deletes user from database; optionally: replace it by another existing user; returns an empty string on success or an error message on failure (may be a single space if no message was sent)*/ - QString deleteUser(QString replace=QString()); - - /**sets new description, both locally and on server*/ - bool setDescription(QString); - - /**returns roles of this user (queries server); returns empty list if call fails, returns filled list if call succeeds, the bool will contain whether the user has the role*/ - MCheckList getRoles(); - - /**sends the updated roles to the server; returns true on success*/ - bool setRoles(const MCheckList&); - - /**returns hosts that a user may connect from*/ - MCheckList getHosts(); - - /**send the updated host list of the user to the server; returns true on success*/ - bool setHosts(const MCheckList&); - - /**change the password of this user; returns whether successful*/ - bool changePassword(QString); -}; - -/**overwrites MCheckItem to represent an ACL item for the user*/ -class MAcl:public MCheckItem -{ - public: - MAcl(); - MAcl(const MAcl&); - MAcl(QString,bool); - - /**returns the role this ACL represents*/ - virtual QString role()const; - /**returns the role this ACL represents*/ - virtual QString key()const; - /**attempts to translate the role using the currently active language, this should yield a description of the role if successful or the role name if it fails*/ - virtual QString description()const; - /**returns a usable label (role name + description) for the MCheckDialog */ - virtual QString label()const; - /**returns whether the role is set for this user*/ - virtual bool isSet()const; - /**changes the role setting (used by MCheckDialog)*/ - virtual void set(bool); - - protected: - virtual MCheckItem* copy()const; - private: - QString m_role; - bool m_set; -}; - -// class MOHostAcl; -/**overwrites MCheckItem to represent a host item for the user*/ -class MUserHost:public MCheckItem -{ - public: - MUserHost(); - MUserHost(const MUserHost&); - MUserHost(QString,bool); - //MUserHost(const MOHostAcl&); - - /**returns the host this item represents*/ - virtual QString host()const; - /**returns the host this item represents*/ - virtual QString key()const; - /**returns a usable label (host name + opt. description for special hosts) for the MCheckDialog */ - virtual QString label()const; - /**returns whether the host is allowed for this user*/ - virtual bool isSet()const; - /**changes the host setting (used by MCheckDialog)*/ - virtual void set(bool); - - protected: - virtual MCheckItem* copy()const; - private: - QString m_host; - bool m_set; -}; - -#endif diff --git a/src/win.rc b/src/win.rc index 1bc463a..5b80ef0 100644 --- a/src/win.rc +++ b/src/win.rc @@ -1 +1 @@ -IDI_ICON1 ICON DISCARDABLE "icon.ico" +IDI_ICON1 ICON DISCARDABLE "images\icon.ico" diff --git a/woc/processor.cpp b/woc/processor.cpp index 8533779..9c68500 100644 --- a/woc/processor.cpp +++ b/woc/processor.cpp @@ -16,7 +16,7 @@ #include "qtout.h" #include "htmlout.h" -#include "../src/domquery.h" +#include "domquery.h" #include #include diff --git a/woc/woc.pro b/woc/woc.pro index 7e6a7ad..c74e054 100644 --- a/woc/woc.pro +++ b/woc/woc.pro @@ -16,10 +16,12 @@ SOURCES+= \ qtout.cpp \ phpout.cpp \ htmlout.cpp \ - ../src/domquery.cpp + ../src/misc/domquery.cpp HEADERS+= \ processor.h \ phpout.h \ qtout.h \ htmlout.h \ - ../src/domquery.h \ No newline at end of file + ../src/misc/domquery.h + +INCLUDEPATH += ../src/misc \ No newline at end of file -- 1.7.2.5