redesign event overview:
authorKonrad Rosenbaum <Konrad.Rosenbaum@peergroup.com>
Tue, 9 Feb 2016 21:32:17 +0000 (22:32 +0100)
committerKonrad Rosenbaum <Konrad.Rosenbaum@peergroup.com>
Tue, 9 Feb 2016 21:32:17 +0000 (22:32 +0100)
 - remove buttons
 - move all button functions to menu
 - add detail view

src/dialogs/orderwin.cpp
src/mwin/carttab.cpp
src/mwin/carttab.h
src/mwin/eventstab.cpp
src/mwin/eventstab.h
src/mwin/overview.cpp
src/mwin/tabwin.cpp
src/mwin/tabwin.h

index 001f959..0567e10 100644 (file)
@@ -206,7 +206,7 @@ MOrderWindow::MOrderWindow(QWidget*par,const MOOrder&o)
        vl->addWidget(m_table=new MOWTableView,10);
        m_table->setModel(m_model=new QStandardItemModel(this));
        m_table->setEditTriggers(QAbstractItemView::NoEditTriggers);
-    m_table->setSortingEnabled(true);
+       m_table->setSortingEnabled(true);
        updateData();
 }
 
index 17a9259..60307a6 100644 (file)
@@ -28,6 +28,7 @@
 #include <QApplication>
 #include <QBoxLayout>
 #include <QComboBox>
+#include <QDebug>
 #include <QFrame>
 #include <QLabel>
 #include <QMenu>
@@ -290,7 +291,7 @@ void MCartTab::cartAddTicket()
        addTicketForEvent(id);
 }
 
-void MCartTab::addTicketForEvent(qint64 id)
+void MCartTab::addTicketForEvent(qint64 id, qint64 prcid)
 {
        //get event
        MTGetEvent ge=MTGetEvent::query(id);
@@ -316,8 +317,13 @@ void MCartTab::addTicketForEvent(qint64 id)
                d.setLayout(vl=new QVBoxLayout);
                vl->addWidget(new QLabel(tr("Please chose a price category:")));
                vl->addWidget(box=new QComboBox);
-               for(int i=0;i<ep.size();i++)
+               int prcidx=-1;
+               for(int i=0;i<ep.size();i++){
                        box->addItem(ep[i].pricecategory().value().name().value()+": "+cent2str(ep[i].price()));
+                       if(ep[i].pricecategoryid()==prcid)
+                               prcidx=i;
+               }
+               if(prcidx>=0)box->setCurrentIndex(prcidx);
                box->setEditable(false);
                vl->addSpacing(10);
                vl->addStretch(10);
@@ -355,6 +361,15 @@ void MCartTab::eventOrderTicket()
        addTicketForEvent(id);
 }
 
+void MCartTab::eventOrderTicket(qint64 id,qint64 prcid)
+{
+       qDebug()<<"xxxx";
+       //activate order tab
+       emit requestFocus();
+       //insert event into table
+       addTicketForEvent(id,prcid);
+}
+
 void MCartTab::cartAddVoucher()
 {
        //create voucher selection dialog
index 8601908..9a48a7d 100644 (file)
@@ -72,6 +72,8 @@ class MCartTab:public QWidget
        public slots:
                /**order ticket from event tab*/
                void eventOrderTicket();
+               /**order ticket from event tab*/
+               void eventOrderTicket(qint64,qint64);
                
                /**update shipping info*/
                void updateShipping();
@@ -133,7 +135,7 @@ class MCartTab:public QWidget
                void verifyOrderItems(const QList<MOCartItem>&);
                
                /**helper for cartAddTicket and eventOrderTicket: choses a price category and then adds the ticket*/
-               void addTicketForEvent(qint64);
+               void addTicketForEvent(qint64,qint64 prcid=-1);
 };
 
 /**Helper class for shopping cart: allow editing amount, but nothing else*/
index 6d87039..4afafe8 100644 (file)
 #include <QBoxLayout>
 #include <QCheckBox>
 #include <QComboBox>
+#include <QDebug>
+#include <QDesktopServices>
 #include <QFrame>
 #include <QHeaderView>
 #include <QInputDialog>
+#include <QItemSelectionModel>
 #include <QLabel>
 #include <QMenu>
 #include <QMenuBar>
 #include <QPushButton>
 #include <QSettings>
 #include <QSpinBox>
+#include <QSplitter>
 #include <QStandardItemModel>
 #include <QTableView>
-#include <QTextEdit>
+#include <QTextBrowser>
+#include <QUrl>
+#include <QUrlQuery>
 
 MEventsTab::MEventsTab(QString pk)
 {
@@ -52,16 +58,24 @@ MEventsTab::MEventsTab(QString pk)
        
        //Event tab
        QVBoxLayout*vl;QHBoxLayout*hl;
-       setLayout(hl=new QHBoxLayout);
-       hl->addWidget(eventtable=new QTableView,10);
+       setLayout(vl=new QVBoxLayout);
+       QSplitter*split;
+       vl->addWidget(split=new QSplitter);
+       split->addWidget(eventtable=new QTableView);
        eventtable->setModel(eventmodel=new QStandardItemModel(this));
        eventtable->setSelectionMode(QAbstractItemView::SingleSelection);
-        eventtable->setSelectionBehavior(QAbstractItemView::SelectRows);
+       eventtable->setSelectionBehavior(QAbstractItemView::SelectRows);
        eventtable->setEditTriggers(QAbstractItemView::NoEditTriggers);
        eventtable->verticalHeader()->hide();
        eventtable->setSortingEnabled(true);
        eventmodel->setSortRole(SortRole);
-       hl->addSpacing(5);
+       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);
@@ -71,7 +85,7 @@ MEventsTab::MEventsTab(QString pk)
        m->addAction(tr("New Event..."),this,SLOT(newEvent()));
        m->addAction(tr("Clone Current Event..."),this,SLOT(cloneEvent()));
 
-        vl->addWidget(p=new QPushButton(tr("Details...")),0);
+       vl->addWidget(p=new QPushButton(tr("Details...")),0);
        connect(p,SIGNAL(clicked()),this,SLOT(editEvent()));
        p->setEnabled(req->hasRight(req->RGetEvent));
        vl->addSpacing(15);
@@ -87,7 +101,7 @@ MEventsTab::MEventsTab(QString pk)
        p->setEnabled(req->hasRight(req->RCancelEvent));
        connect(p,SIGNAL(clicked()),this,SLOT(eventCancel()));
        vl->addStretch(10);
-       
+*/     
        //fill tables
        if(req->hasRight(req->RGetAllEvents)){
                updateEvents();
@@ -101,7 +115,9 @@ QList<QMenu*>MEventsTab::menu()
        QMenu*m=new QMenu(tr("&View"));
        ret<<m;
        m->addAction(tr("&Update Event List"),this,SLOT(updateEvents()))
-        ->setEnabled(req->hasRight(req->RGetAllEvents));
+               ->setEnabled(req->hasRight(req->RGetAllEvents));
+       m->addAction(tr("Event &Summary..."),this,SLOT(eventSummary()))
+               ->setEnabled(req->hasRight(MInterface::RGetEventSummary));
        m->addSeparator();
        showoldevents=m->addAction(tr("Show &old Events"),this,SLOT(updateEvents()));
        showoldevents->setEnabled(req->hasRight(req->RGetAllEvents));
@@ -109,10 +125,15 @@ QList<QMenu*>MEventsTab::menu()
        showoldevents->setChecked(QSettings().value("profiles/"+profilekey+"/showOldEvents",false).toBool());
 
        m=new QMenu(tr("&Edit"));
+       ret<<m;
        m->addAction(tr("&Show/Edit details..."),this,SLOT(editEvent()))
                ->setEnabled(req->hasRight(req->RGetEvent));
        m->addAction(tr("&New Event..."),this,SLOT(newEvent()))
                ->setEnabled(req->hasRight(req->RCreateEvent));
+       m->addAction(tr("&Clone Current Event..."),this,SLOT(cloneEvent()))
+               ->setEnabled(req->hasRight(req->RCreateEvent));
+       m->addAction(tr("C&ancel Event..."),this,SLOT(eventCancel()))
+               ->setEnabled(req->hasRight(req->MInterface::RCancelEvent));
        m->addSeparator();
        m->addAction(tr("&Edit Price Categories..."),this,SLOT(editPriceCat()));
        
@@ -143,6 +164,8 @@ void MEventsTab::updateEvents()
                now.addDays(-maxage);
        }
        //fill model
+       eventdetail->clear();
+       eventdetail->clearHistory();
        eventmodel->clear();
        eventmodel->insertColumns(0,6);
        eventmodel->setHorizontalHeaderLabels(QStringList()<<tr("Start Time")<<tr("Title")<<tr("Free")<<tr("Reserved")<<tr("Sold")<<tr("Capacity"));
@@ -153,6 +176,7 @@ void MEventsTab::updateEvents()
                //show
                eventmodel->insertRow(j);
                eventmodel->setData(eventmodel->index(j,0),evl[i].id().value(),IdRole);
+               eventmodel->setData(eventmodel->index(j,0),QVariant::fromValue(evl[i]),ObjectRole);
                eventmodel->setData(eventmodel->index(j,0),evl[i].startTimeString());
                eventmodel->setData(eventmodel->index(j,0),evl[i].start().value(),SortRole);
                eventmodel->setData(eventmodel->index(j,1),evl[i].title().value());
@@ -177,6 +201,107 @@ MEventsTab::~MEventsTab()
 {
 }
 
+void MEventsTab::updateDetails()
+{
+       //clear
+       eventdetail->clearHistory();
+       eventdetail->clear();
+       //get selection
+       QModelIndexList ilst=eventtable->selectionModel()->selectedIndexes();
+       if(ilst.size()<1)return;
+       QModelIndex idx=eventmodel->index(ilst[0].row(),0);
+       //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()));
+       }
+}
+
 void MEventsTab::newEvent()
 {
        MEventEditor ed(this);
index 788c05b..3759adc 100644 (file)
@@ -29,6 +29,7 @@ class QSpinBox;
 class QStandardItemModel;
 class QTabWidget;
 class QTableView;
+class QTextBrowser;
 
 class MSInterface;
 
@@ -69,6 +70,9 @@ class MEventsTab:public QWidget
                /**update list of events*/
                void updateEvents();
                
+               /**update details view when selection changes*/
+               void updateDetails();
+               
                ///shows an event selection dialog and returns the selected event
                /// \param eid the ID of the selected event, if the dialog was normally closed
                /// \param ok true if the dialog was closed normally, false if the user aborted
@@ -77,10 +81,15 @@ class MEventsTab:public QWidget
                /// \param eids the list of IDs of the selected events, empty if nothing was selected or the user aborted
                /// \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();
+               /**order ticket from event tab*/
+               void eventOrderTicket(qint64,qint64);
                
        private:
                //the profile associated with this session
@@ -88,6 +97,7 @@ class MEventsTab:public QWidget
                //widgets
                QTableView*eventtable;
                QStandardItemModel*eventmodel;
+               QTextBrowser*eventdetail;
                //event list
                QAction*showoldevents;
                //refresh timers
@@ -95,7 +105,8 @@ class MEventsTab:public QWidget
                //table role definitions
                enum ExtraTableRoles{
                        IdRole=Qt::UserRole,
-                       SortRole
+                       SortRole,
+                       ObjectRole
                };
 };
 
index ceed9c7..41231cd 100644 (file)
@@ -159,6 +159,7 @@ MOverview::MOverview(QString pk,std::function<void(int,QString)>initUpdate)
        carttab=new MCartTab(pk);
        addTab(carttab,tr("Shopping Cart"),carttab->menu());
        connect(eventtab,SIGNAL(eventOrderTicket()),carttab,SLOT(eventOrderTicket()));
+       connect(eventtab,SIGNAL(eventOrderTicket(qint64,qint64)),carttab,SLOT(eventOrderTicket(qint64,qint64)));
        connect(carttab,SIGNAL(getEventId(int&,bool&)), eventtab,SLOT(selectEventId(int&,bool&)), Qt::DirectConnection);
        connect(carttab,SIGNAL(currentEventId()), eventtab,SLOT(currentEventId()), Qt::DirectConnection);
        connect(carttab,SIGNAL(currentEventTitle()), eventtab,SLOT(currentEventTitle()), Qt::DirectConnection);
index b25f14f..bb22acb 100644 (file)
@@ -98,7 +98,7 @@ void MTabWin::addTab(QWidget* tw, QString title, QList<QMenu*> menu)
        int idx=tabw->addTab(tw,title);
        tabmenu.insert(idx,menu);
        QMenuBar*mb=menuBar();
-       for(int i=menu.size()-1;i>=0;i--){
+       for(int i=0;i<menu.size();i++){
                mb->insertMenu(helpseparator,menu[i]);
        }
 }
index 9ad3590..4435e04 100644 (file)
@@ -39,7 +39,7 @@ class MTabWin:public QMainWindow
                ///add a tab
                virtual void addTab(QWidget*tab,QString title,QList<QMenu*>menu=QList<QMenu*>());
                
-               ///add a menu to the left
+               ///add a menu to the left side, where it is visible for all tabs
                virtual QMenu* addMenu(QString);
                
                ///returns a pointer to the help menu