#ifndef FACT_FactGui #define FACT_FactGui #include "MainWindow.h" #include #include #include #include "CheckBoxDelegate.h" #include "src/Converter.h" #include "src/HeadersFTM.h" #include "src/DimNetwork.h" using namespace std; class FactGui : public MainWindow, public DimNetwork { private: class FunctionEvent : public QEvent { public: boost::function fFunction; FunctionEvent(const boost::function &f) : QEvent((QEvent::Type)QEvent::registerEventType()), fFunction(f) { } bool Exec() { fFunction(*this); return true; } }; DimInfo fDimDNS; map fServices; // ====================================================================== QStandardItem *AddServiceItem(const std::string &server, const std::string &service, bool iscmd) { QListView *servers = iscmd ? fDimCmdServers : fDimSvcServers; QListView *services = iscmd ? fDimCmdCommands : fDimSvcServices; QListView *description = iscmd ? fDimCmdDescription : fDimSvcDescription; QStandardItemModel *m = dynamic_cast(servers->model()); if (!m) { m = new QStandardItemModel(this); servers->setModel(m); services->setModel(m); description->setModel(m); } QList l = m->findItems(server.c_str()); if (l.size()>1) { cout << "hae" << endl; return 0; } QStandardItem *col = l.size()==0 ? NULL : l[0]; if (!col) { col = new QStandardItem(server.c_str()); m->appendRow(col); if (!services->rootIndex().isValid()) { services->setRootIndex(col->index()); servers->setCurrentIndex(col->index()); } } QStandardItem *item = 0; for (int i=0; irowCount(); i++) { QStandardItem *coli = col->child(i); if (coli->text().toStdString()==service) return coli; } item = new QStandardItem(service.c_str()); col->appendRow(item); if (!description->rootIndex().isValid()) { description->setRootIndex(item->index()); services->setCurrentIndex(item->index()); } if (!iscmd) item->setCheckable(true); return item; } void AddDescription(QStandardItem *item, const vector &vec) { if (!item) return; if (vec.size()==0) return; item->setToolTip(vec[0].comment.c_str()); const string str = Description::GetHtmlDescription(vec); QStandardItem *desc = new QStandardItem(str.c_str()); desc->setSelectable(false); item->setChild(0, 0, desc); } // ====================================================================== void handleAddServer(const std::string &server) { const State s = GetState(server, GetCurrentState(server)); handleStateChanged(Time(), server, s); } void handleRemoveServer(const string &server) { handleStateOffline(server); handleRemoveAllServices(server); } void handleRemoveAllServers() { QStandardItemModel *m = 0; if ((m=dynamic_cast(fDimCmdServers->model()))) m->removeRows(0, m->rowCount()); if ((m = dynamic_cast(fDimSvcServers->model()))) m->removeRows(0, m->rowCount()); } void handleAddService(const std::string &server, const std::string &service, const std::string &/*fmt*/, bool iscmd) { QStandardItem *item = AddServiceItem(server, service, iscmd); const vector v = GetDescription(server, service); AddDescription(item, v); } void handleRemoveService(const std::string &server, const std::string &service, bool iscmd) { QListView *servers = iscmd ? fDimCmdServers : fDimSvcServers; QStandardItemModel *m = dynamic_cast(servers->model()); if (!m) return; QList l = m->findItems(server.c_str()); if (l.size()!=1) return; for (int i=0; irowCount(); i++) { QStandardItem *row = l[0]->child(i); if (row->text().toStdString()==service) { l[0]->removeRow(row->index().row()); return; } } } void handleRemoveAllServices(const std::string &server) { QStandardItemModel *m = 0; if ((m=dynamic_cast(fDimCmdServers->model()))) { QList l = m->findItems(server.c_str()); if (l.size()==1) m->removeRow(l[0]->index().row()); } if ((m = dynamic_cast(fDimSvcServers->model()))) { QList l = m->findItems(server.c_str()); if (l.size()==1) m->removeRow(l[0]->index().row()); } } void handleAddDescription(const std::string &server, const std::string &service, const vector &vec) { const bool iscmd = IsCommand(server, service)==true; QStandardItem *item = AddServiceItem(server, service, iscmd); AddDescription(item, vec); } void handleStateChanged(const Time &/*time*/, const std::string &server, const State &s) { // FIXME: Prefix tooltip with time if (server=="FTM_CONTROL") { fStatusFTMLabel->setText(s.name.c_str()); fStatusFTMLabel->setToolTip(s.comment.c_str()); if (s.indexsetIcon(QIcon(":/Resources/icons/gray circle 1.png")); if (s.index==FTM::kDisconnected) // Dim connection / FTM disconnected fStatusFTMLed->setIcon(QIcon(":/Resources/icons/yellow circle 1.png")); if (s.index==FTM::kConnected) // Dim connection / FTM connected fStatusFTMLed->setIcon(QIcon(":/Resources/icons/green circle 1.png")); } if (server=="FAD_CONTROL") { fStatusFADLabel->setText(s.name.c_str()); fStatusFADLabel->setToolTip(s.comment.c_str()); if (s.indexsetIcon(QIcon(":/Resources/icons/gray circle 1.png")); if (s.index==FTM::kDisconnected) // Dim connection / FTM disconnected fStatusFADLed->setIcon(QIcon(":/Resources/icons/yellow circle 1.png")); if (s.index==FTM::kConnected) // Dim connection / FTM connected fStatusFADLed->setIcon(QIcon(":/Resources/icons/green circle 1.png")); } if (server=="DATA_LOGGER") { fStatusLoggerLabel->setText(s.name.c_str()); fStatusLoggerLabel->setToolTip(s.comment.c_str()); if (s.index<-1) // Error fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png")); if (s.index>=0x100) // Error fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/red circle 1.png")); if (s.index<=30) // Waiting fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/yellow circle 1.png")); if (s.index==40) // Logging fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/green circle 1.png")); } if (server=="CHAT") { fStatusChatLabel->setText(s.name.c_str()); if (s.index==FTM::kConnected) // Dim connection / FTM connected fStatusChatLed->setIcon(QIcon(":/Resources/icons/green circle 1.png")); else fStatusChatLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png")); } } void handleStateOffline(const string &server) { handleStateChanged(Time(), server, State(-2, "Offline", "No connection via DIM.")); } void handleWrite(const Time &time, const string &text, int qos) { stringstream out; if (text.substr(0, 6)=="CHAT: ") { out << "["; out << Time::fmt("%H:%M:%S") << time << "] "; out << text.substr(6); fChatText->append(out.str().c_str()); return; } out << "" << time.GetAsStr() << " - " << text << ""; fLogText->append(out.str().c_str()); if (qos>=kWarn) fTextEdit->append(out.str().c_str()); } void handleDimService(const string &txt) { fDimSvcText->append(txt.c_str()); } void handleDimDNS(int version) { ostringstream str; str << "DIM V" << version/100 << 'r' << version%100; if (version==0) fStatusDNSLed->setIcon(QIcon(":/Resources/icons/red circle 1.png")); else fStatusDNSLed->setIcon(QIcon(":/Resources/icons/green circle 1.png")); fStatusDNSLabel->setText(version==0?"Offline":str.str().c_str()); fStatusDNSLabel->setToolTip(version==0?"No connection to DIM DNS.":"Connection to DIM DNS established."); } // ====================================================================== void AddServer(const std::string &s) { DimNetwork::AddServer(s); QApplication::postEvent(this, new FunctionEvent(boost::bind(&FactGui::handleAddServer, this, s))); } void RemoveServer(const std::string &s) { UnsubscribeServer(s); DimNetwork::RemoveServer(s); QApplication::postEvent(this, new FunctionEvent(boost::bind(&FactGui::handleRemoveServer, this, s))); } void RemoveAllServers() { UnsubscribeAllServers(); vector v = GetServerList(); for (vector::iterator i=v.begin(); i &vec) { QApplication::postEvent(this, new FunctionEvent(boost::bind(&FactGui::handleAddDescription, this, server, service, vec))); } void IndicateStateChange(const Time &time, const std::string &server) { const State s = GetState(server, GetCurrentState(server)); QApplication::postEvent(this, new FunctionEvent(boost::bind(&FactGui::handleStateChanged, this, time, server, s))); } int Write(const Time &time, const string &txt, int qos) { QApplication::postEvent(this, new FunctionEvent(boost::bind(&FactGui::handleWrite, this, time, txt, qos))); return 0; } void infoHandler(DimInfo &info) { const string fmt = string("DIS_DNS/SERVER_INFO")==info.getName() ? "C" : info.getFormat(); stringstream dummy; const Converter conv(dummy, fmt, false); const Time tm(info.getTimestamp(), info.getTimestampMillisecs()); stringstream out; out << Time::fmt("%H:%M:%S.%f") << tm << " " << info.getName() << " - "; bool iserr = false; if (!conv) { out << "Compilation of format string '" << fmt << "' failed!"; iserr = true; } else { try { const string dat = conv.GetString(info.getData(), info.getSize()); out << dat; } catch (const runtime_error &e) { out << "Conversion to string failed!
" << e.what() << "
"; iserr = true; } } // srand(hash()(string(info.getName()))); // int bg = rand()&0xffffff; int bg = hash()(string(info.getName())); int r = bg&0x1f0000; int g = bg&0x001f00; int b = bg&0x00001f; bg = ~(b|g|r)&0xffffff; if (iserr) bg = 0xffffff; stringstream bgcol; bgcol << hex << setfill('0') << setw(6) << bg; const string col = iserr ? "red" : "black"; const string str = "
"+out.str()+"
"; QApplication::postEvent(this, new FunctionEvent(boost::bind(&FactGui::handleDimService, this, str))); } void infoHandler() { if (getInfo()==&fDimDNS) { QApplication::postEvent(this, new FunctionEvent(boost::bind(&FactGui::handleDimDNS, this, getInfo()->getInt()))); return; } for (map::iterator i=fServices.begin(); i!=fServices.end(); i++) if (i->second==getInfo()) { infoHandler(*i->second); return; } DimNetwork::infoHandler(); } // ====================================================================== void SubscribeService(const string &service) { if (fServices.find(service)!=fServices.end()) { cout << "ERROR - We are already subscribed to " << service << endl; return; } fServices[service] = new DimStampedInfo(service.c_str(), (void*)NULL, 0, this); } void UnsubscribeService(const string &service) { const map::iterator i=fServices.find(service); if (i==fServices.end()) { cout << "ERROR - We are not subscribed to " << service << endl; return; } delete i->second; fServices.erase(i); } void UnsubscribeServer(const string &server) { for (map::iterator i=fServices.begin(); i!=fServices.end(); i++) if (i->first.substr(0, server.length()+1)==server+'/') { delete i->second; fServices.erase(i); } } void UnsubscribeAllServers() { for (map::iterator i=fServices.begin(); i!=fServices.end(); i++) delete i->second; fServices.clear(); } // ====================================================================== bool event(QEvent *evt) { if (dynamic_cast(evt)) return static_cast(evt)->Exec(); if (dynamic_cast(evt)) { const QStandardItem &item = static_cast(evt)->item; const QStandardItem *par = item.parent(); if (par) { const QString server = par->text(); const QString service = item.text(); const string s = (server+'/'+service).toStdString(); if (item.checkState()==Qt::Checked) SubscribeService(s); else UnsubscribeService(s); } } return MainWindow::event(evt); // unrecognized } void on_fDimCmdSend_clicked(bool) { const QString server = fDimCmdServers->currentIndex().data().toString(); const QString command = fDimCmdCommands->currentIndex().data().toString(); const QString arguments = fDimCmdLineEdit->displayText(); // FIXME: Sending a command exactly when the info Handler changes // the list it might lead to confusion. try { SendDimCommand(server.toStdString(), command.toStdString()+" "+arguments.toStdString()); fTextEdit->append("Command '"+server+'/'+command+"' successfully emitted."); fDimCmdLineEdit->clear(); } catch (const runtime_error &e) { stringstream txt; txt << e.what(); string buffer; while (getline(txt, buffer, '\n')) fTextEdit->append(("
"+buffer+"
").c_str()); } } public: FactGui() : fDimDNS("DIS_DNS/VERSION_NUMBER", 1, int(0), this) { DimClient::sendCommand("CHAT/MSG", "GUI online."); // + MessageDimRX } ~FactGui() { UnsubscribeAllServers(); } }; #endif