//survived all tests
return true;
}
+
+QUrl MSInterface::parentUrl() const
+{
+ QUrl parent=url();
+ parent.setFragment(QString());
+ parent.setQuery(QString());
+ QString path=parent.path();
+ if(path==QString() || path.endsWith('/'))return parent;
+ parent.setPath(path.left(path.lastIndexOf('/')+1));
+}
///return all flags of the current user
QStringList allFlags()const{return userflags;}
+
+ ///return the parent directory of the base URL
+ QUrl parentUrl()const;
///return application main data directory
static QString appDataDir();
#include "centbox.h"
#include "eventedit.h"
#include "eventsummary.h"
+#include "eventview.h"
#include "main.h"
#include "misc.h"
#include "msinterface.h"
#include <QTextBrowser>
#include <QUrl>
#include <QUrlQuery>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+#include <QEventLoop>
+
+
MEventsTab::MEventsTab(QString pk)
{
setObjectName("eventstab");
//Event tab
- QVBoxLayout*vl;QHBoxLayout*hl;
+ QVBoxLayout*vl;
setLayout(vl=new QVBoxLayout);
QSplitter*split;
vl->addWidget(split=new QSplitter);
eventtable->setSortingEnabled(true);
eventmodel->setSortRole(SortRole);
connect(eventtable->selectionModel(),SIGNAL(selectionChanged(QItemSelection,QItemSelection)),this,SLOT(updateDetails()));
- split->addWidget(eventdetail=new QTextBrowser);
- eventdetail->setReadOnly(true);
- connect(eventdetail,SIGNAL(anchorClicked(QUrl)),this,SLOT(eventOrderTicketUrl(QUrl)));
- eventdetail->setOpenExternalLinks(false);
- eventdetail->setOpenLinks(false);
-/* hl->addSpacing(5);
- hl->addLayout(vl=new QVBoxLayout,0);
- QPushButton*p;
- vl->addWidget(p=new QPushButton(tr("New Event")),0);
- p->setEnabled(req->hasRight(req->RCreateEvent));
- QMenu*m;
- p->setMenu(m=new QMenu);
- m->addAction(tr("New Event..."),this,SLOT(newEvent()));
- m->addAction(tr("Clone Current Event..."),this,SLOT(cloneEvent()));
+ split->addWidget(eventdetail=new MEventView);
+ connect(eventdetail,SIGNAL(eventOrderTicket(qint64,qint64)),this,SIGNAL(eventOrderTicket(qint64,qint64)));
+ connect(eventdetail,SIGNAL(eventOrderTicket()),this,SIGNAL(eventOrderTicket()));
- vl->addWidget(p=new QPushButton(tr("Details...")),0);
- connect(p,SIGNAL(clicked()),this,SLOT(editEvent()));
- p->setEnabled(req->hasRight(req->RGetEvent));
- vl->addSpacing(15);
- vl->addWidget(p=new QPushButton(tr("Order Ticket...")),0);
- connect(p,SIGNAL(clicked()),this,SIGNAL(eventOrderTicket()));
- p->setEnabled(req->hasRight(req->RCreateOrder)||req->hasRight(req->RCreateReservation));
- vl->addSpacing(15);
- vl->addWidget(p=new QPushButton(tr("Event Summary...")),0);
- connect(p,SIGNAL(clicked()),this,SLOT(eventSummary()));
- p->setEnabled(req->hasRight(req->RGetEventSummary));
- vl->addSpacing(15);
- vl->addWidget(p=new QPushButton(tr("Cancel Event...")),0);
- p->setEnabled(req->hasRight(req->RCancelEvent));
- connect(p,SIGNAL(clicked()),this,SLOT(eventCancel()));
- vl->addStretch(10);
-*/
//fill tables
if(req->hasRight(req->RGetAllEvents)){
updateEvents();
void MEventsTab::updateDetails()
{
//clear
- eventdetail->clearHistory();
- eventdetail->clear();
+ eventdetail->clearEvent();
//get selection
QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
if(ilst.size()<1)return;
//get event
MOEvent event=eventmodel->data(idx,ObjectRole).value<MOEvent>();
if(!event.isValid())return;
- //generate HTML
- QString detail="<h1>"+htmlize(event.title())+"</h1>\n";
- detail+=tr("Artist: %1").arg(htmlize(event.artist().value().name()))+"<p>\n";
- detail+=tr("Starttime: %1").arg(htmlize(event.startTimeString()))+"<br>\n";
- detail+=tr("Endtime: %1").arg(htmlize(event.startTimeString()))+"<p>\n";
- detail+=tr("Room: %1").arg(htmlize(event.room()))+"<br>\n";
- detail+=tr("Seats: %1 max. (%2 sold out; %3 reserved; %4 free)").arg(event.capacity()).arg(event.amountSold()).arg(event.amountReserved()).arg(event.amountFree())+"<p>\n";
-
- const QString bgsold=tr("<div style=\"background-color:#ff8080\">Sold Out!</div>","Colored display for sold out tickets");
- const QString bgavail=tr("<table border=1 style=\"border-style:groove; background-color:#00ff00\"><tr><td><div style=\"background-color:#80ff80\"><a href=\"%1\">Order Tickets...</a></div></td></tr></table>","Colored display for ordering tickets");
- const QString bghide=tr("<div style=\"background-color:#c0c0c0\">Unable to sell.</div>","Colored display for tickets unavailable to this user");
-
- const bool showevent=req->checkFlags(event.flags());
- if(showevent)
- detail+=event.amountFree()>0?bgavail.arg(QString("order:?ev=%1").arg(event.id())):bgsold;
- else
- detail+=bghide;
- detail+="<h2>"+tr("Prices")+"</h2>\n";
- detail+="<table frame=1 border=1>"
- "<thead><tr><th>"+tr("Category")+"</th><th>"+tr("Price")+"</th><th>"+tr("Available")+"</th><th>"+tr("Max. Seats")+"</th><th>"+tr("Order")+"</th></tr></thead>\n";
- QList<MOEventPrice>prices=event.price();
- qSort(prices.begin(),prices.end(),[](const MOEventPrice&p1,const MOEventPrice&p2){return p1.prio()<p2.prio();});
- for(MOEventPrice ctg:prices){
- detail+="<tr><td>"+ctg.pricecategory().value().name();
- detail+="</td><td>"+cent2str(ctg.price().value());
- const int avail=ctg.maxavailable()-ctg.amountticketsblock();
- detail+="</td><td>"+QString::number(avail);
- detail+="</td><td>"+QString::number(ctg.maxavailable());
- if(showevent && req->checkFlags(ctg.flags()))
- detail+="</td><td>"+
- (avail>0?
- bgavail.arg(QString("order:?ev=%1&pr=%2").arg(event.id()).arg(ctg.pricecategoryid()))
- :bgsold);
- else
- detail+="</td><td>"+bghide;
- detail+="</td></tr>";
- }
- detail+="</table><p>\n";
-
- detail+="<h2>"+tr("Description")+"</h2>\n"+event.description()+"<p>\n";
- detail+="<h2>"+tr("Comment")+"</h2>\n"+htmlize(event.comment());
- //set value
- eventdetail->setHtml(detail);
-}
-
-void MEventsTab::eventOrderTicketUrl(const QUrl &url)
-{
- //check whether it is order URL
- if(url.scheme()=="order"){
- QUrlQuery query(url);
- if(query.hasQueryItem("ev")){
- bool b=false;
- qint64 evid=query.queryItemValue("ev").toLongLong(&b);
- if(!b || evid<0){
- qDebug()<<"ordering tickets for current event (invalid EvID)...";
- emit eventOrderTicket();
- return;
- }
- qint64 prid=-1;
- if(query.hasQueryItem("pr")){
- prid=query.queryItemValue("pr").toLongLong(&b);
- if(!b)prid=-1;
- }
- qDebug()<<"ordering tickets for event"<<evid<<"price ID"<<prid;
- emit eventOrderTicket(evid,prid);
- }else{
- qDebug()<<"ordering tickets for current event (no EvID)...";
- emit eventOrderTicket();
- }
- return;
- }
- QUrl target=url;
- //Other URLs happen only in the comment or description sections
- if(url.isRelative()){
- //a relative link can only occur in comment or description, so it is relative to the
- //server URL (the index.php used for displaying this on the web page is parallel to machine.php,
- //so we can safely use it as base for resolving the relative URL)
- target=req->url().resolved(url);
- qDebug()<<"Relative URL"<<url<<"aligned to"<<req->url();
- qDebug()<<" ...opening"<<target;
- }
- if(QDesktopServices::openUrl(target))
- qDebug()<<"Opened URL"<<target;
- else{
- qDebug()<<"WARNING: unknown URL type in"<<url;
- QMessageBox::warning(this,tr("Warning"),tr("Unable to open URL %1").arg(url.toString()));
- }
+ eventdetail->setEvent(event);
}
void MEventsTab::newEvent()
class QStandardItemModel;
class QTabWidget;
class QTableView;
-class QTextBrowser;
+class MEventView;
class MSInterface;
/// \param multi true if multiple IDs can be selected, false if only one can be selec ted
void selectEventIds(QList<int>&eids,bool multi=true)const;
- ///order ticket from URL click
- void eventOrderTicketUrl(const QUrl&);
-
signals:
/**order ticket from event tab*/
void eventOrderTicket();
//widgets
QTableView*eventtable;
QStandardItemModel*eventmodel;
- QTextBrowser*eventdetail;
+ MEventView*eventdetail;
//event list
QAction*showoldevents;
//refresh timers
--- /dev/null
+//
+// C++ Implementation: event list tab
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2007-2013
+//
+// Copyright: See README/COPYING.GPL files that come with this distribution
+//
+//
+
+#include "eventview.h"
+#include "misc.h"
+#include "msinterface.h"
+
+#include <MOEvent>
+#include <MOEventPrice>
+
+#include <QEventLoop>
+#include <QUrl>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+#include <QTimer>
+#include <QUrlQuery>
+#include <QMessageBox>
+#include <QDesktopServices>
+
+
+MEventView::MEventView ( QWidget* parent ) : QTextBrowser ( parent )
+{
+ setReadOnly(true);
+ connect(this,SIGNAL(anchorClicked(QUrl)),this,SLOT(handleClick(QUrl)));
+ setOpenExternalLinks(false);
+ setOpenLinks(false);
+ qDebug()<<"Setting path"<<req->parentUrl()<<"for URL"<<req->url();
+ setSearchPaths(QStringList()<<req->parentUrl().toString());
+ resetPattern();
+}
+
+
+QVariant MEventView::loadResource ( int type, const QUrl& name )
+{
+ Q_UNUSED(type);
+ qDebug()<<"Loading Resource"<<name;
+ if(name.isRelative()||name.scheme()=="http"||name.scheme()=="https"){
+ QUrl url(name);
+ if(name.isRelative())url=req->url().resolved(name);
+ QNetworkAccessManager nam;
+ connect(&nam,SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),req,SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
+ QNetworkReply*rpl= nam.get(QNetworkRequest(url));
+ qDebug()<<"Trying to GET"<<url;
+ QEventLoop loop;
+ connect(rpl,SIGNAL(finished()),&loop,SLOT(quit()));
+ QTimer::singleShot(15000,&loop,SLOT(quit()));
+ loop.exec();
+ QByteArray data=rpl->readAll();
+ qDebug()<<"...got"<<data.size()<<"bytes";
+ return data;
+ }else
+ return QTextBrowser::loadResource ( type, name );
+}
+
+void MEventView::clearEvent()
+{
+ clearHistory();
+ clear();
+}
+
+void MEventView::setEvent ( MOEvent event )
+{
+ clearEvent();
+
+ //generate HTML
+ QString detail="<h1>"+htmlize(event.title())+"</h1>\n";
+ detail+=tr("Artist: %1").arg(htmlize(event.artist().value().name()))+"<p>\n";
+ detail+=tr("Starttime: %1").arg(htmlize(event.startTimeString()))+"<br>\n";
+ detail+=tr("Endtime: %1").arg(htmlize(event.endTimeString()))+"<p>\n";
+ detail+=tr("Room: %1").arg(htmlize(event.room()))+"<br>\n";
+ detail+=tr("Seats: %1 max. (%2 sold out; %3 reserved; %4 free)").arg(event.capacity()).arg(event.amountSold()).arg(event.amountReserved()).arg(event.amountFree())+"<p>\n";
+
+ const QString bgsold=tr("<div style=\"background-color:#ff8080\">Sold Out!</div>","Colored display for sold out tickets");
+ const QString bgavail=tr("<table border=1 style=\"border-style:groove; background-color:#00ff00\"><tr><td><div style=\"background-color:#80ff80\"><a href=\"%1\">Order Tickets...</a></div></td></tr></table>","Colored display for ordering tickets");
+ const QString bghide=tr("<div style=\"background-color:#c0c0c0\">Unable to sell.</div>","Colored display for tickets unavailable to this user");
+
+ const bool showevent=req->checkFlags(event.flags());
+ if(showevent)
+ detail+=event.amountFree()>0?bgavail.arg(QString("order:?ev=%1").arg(event.id())):bgsold;
+ else
+ detail+=bghide;
+ detail+="<h2>"+tr("Prices")+"</h2>\n";
+ detail+="<table frame=1 border=1>"
+ "<thead><tr><th>"+tr("Category")+"</th><th>"+tr("Price")+"</th><th>"+tr("Available")+"</th><th>"+tr("Max. Seats")+"</th><th>"+tr("Order")+"</th></tr></thead>\n";
+ QList<MOEventPrice>prices=event.price();
+ qSort(prices.begin(),prices.end(),[](const MOEventPrice&p1,const MOEventPrice&p2){return p1.prio()<p2.prio();});
+ for(MOEventPrice ctg:prices){
+ detail+="<tr><td>"+ctg.pricecategory().value().name();
+ detail+="</td><td>"+cent2str(ctg.price().value());
+ const int avail=ctg.maxavailable()-ctg.amountticketsblock();
+ detail+="</td><td>"+QString::number(avail);
+ detail+="</td><td>"+QString::number(ctg.maxavailable());
+ if(showevent && req->checkFlags(ctg.flags()))
+ detail+="</td><td>"+
+ (avail>0?
+ bgavail.arg(QString("order:?ev=%1&pr=%2").arg(event.id()).arg(ctg.pricecategoryid()))
+ :bgsold);
+ else
+ detail+="</td><td>"+bghide;
+ detail+="</td></tr>";
+ }
+ detail+="</table><p>\n";
+
+ detail+="<h2>"+tr("Description")+"</h2>\n"+event.description()+"<p>\n";
+ detail+="<h2>"+tr("Comment")+"</h2>\n";
+ QString comment=event.comment();
+ if(!comment.trimmed().startsWith("<html>"))comment=htmlize(comment);
+ detail+=comment;
+ //set value
+ setHtml(detail);
+}
+
+void MEventView::handleClick(const QUrl &url)
+{
+ //check whether it is order URL
+ if(url.scheme()=="order"){
+ QUrlQuery query(url);
+ if(query.hasQueryItem("ev")){
+ bool b=false;
+ qint64 evid=query.queryItemValue("ev").toLongLong(&b);
+ if(!b || evid<0){
+ qDebug()<<"ordering tickets for current event (invalid EvID)...";
+ emit eventOrderTicket();
+ return;
+ }
+ qint64 prid=-1;
+ if(query.hasQueryItem("pr")){
+ prid=query.queryItemValue("pr").toLongLong(&b);
+ if(!b)prid=-1;
+ }
+ qDebug()<<"ordering tickets for event"<<evid<<"price ID"<<prid;
+ emit eventOrderTicket(evid,prid);
+ }else{
+ qDebug()<<"ordering tickets for current event (no EvID)...";
+ emit eventOrderTicket();
+ }
+ return;
+ }
+ QUrl target=url;
+ //Other URLs happen only in the comment or description sections
+ if(url.isRelative()){
+ //a relative link can only occur in comment or description, so it is relative to the
+ //server URL (the index.php used for displaying this on the web page is parallel to machine.php,
+ //so we can safely use it as base for resolving the relative URL)
+ target=req->url().resolved(url);
+ qDebug()<<"Relative URL"<<url<<"aligned to"<<req->url();
+ qDebug()<<" ...opening"<<target;
+ }
+ if(QDesktopServices::openUrl(target))
+ qDebug()<<"Opened URL"<<target;
+ else{
+ qDebug()<<"WARNING: unknown URL type in"<<url;
+ QMessageBox::warning(this,tr("Warning"),tr("Unable to open URL %1").arg(url.toString()));
+ }
+}
+
+void MEventView::setPattern ( QString p )
+{
+ mPattern=p;
+}
+
+void MEventView::resetPattern()
+{
+ mPattern=tr(
+ "<h1>{event.name|html}</h1>\n"
+ "Artist: {event.artist|html}<p>\n"
+ "Starttime: {event.startTimeString}<br>\n"
+ "Endtime: {event.endTimeString}<p>\n"
+ "Room: {event.room|html}<br>\n"
+ "Seats: {event.capacity} max. ({event.amountSold} sold out; {event.amountReserved} reserved; {event.amountFree} free)<p>\n"
+ "{% if(event.haveAccess) %}\n"
+
+ "{% endif %}"
+ );
+}
--- /dev/null
+//
+// C++ Interface: event view`
+//
+// Description: widget for displaying event details
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2016
+//
+// Copyright: See README/COPYING.GPL files that come with this distribution
+//
+//
+
+#ifndef MAGICSMOKE_EVENTVIEW_H
+#define MAGICSMOKE_EVENTVIEW_H
+
+#include <QTextBrowser>
+
+#include <MOEvent>
+
+///Event Viewer
+class MEventView:public QTextBrowser
+{
+ Q_OBJECT
+public:
+ explicit MEventView ( QWidget* parent = 0 );
+ QVariant loadResource(int type, const QUrl & name)override;
+
+public slots:
+ void setEvent(MOEvent);
+ void clearEvent();
+ void setPattern(QString);
+ void resetPattern();
+private slots:
+ void handleClick(const QUrl&);
+signals:
+ /**order ticket from event tab*/
+ void eventOrderTicket();
+ /**order ticket from event tab*/
+ void eventOrderTicket(qint64,qint64);
+private:
+ QString mPattern;
+};
+
+
+#endif
widgets/centbox.h \
widgets/listview.h \
widgets/treeview.h \
- widgets/barcodeline.h
+ widgets/barcodeline.h \
+ widgets/eventview.h
SOURCES += \
widgets/centbox.cpp \
widgets/listview.cpp \
widgets/treeview.cpp \
- widgets/barcodeline.cpp
+ widgets/barcodeline.cpp \
+ widgets/eventview.cpp
INCLUDEPATH += ./widgets