source: trunk/FACT++/gui/FactGui.h@ 10427

Last change on this file since 10427 was 10415, checked in by tbretz, 14 years ago
Removed obsolete second and thrid button.
File size: 17.8 KB
Line 
1#ifndef FACT_FactGui
2#define FACT_FactGui
3
4#include "MainWindow.h"
5
6#include <iomanip>
7
8#include <boost/bind.hpp>
9
10#include <QtGui/QStandardItemModel>
11
12#include "CheckBoxDelegate.h"
13
14#include "src/Converter.h"
15#include "src/HeadersFTM.h"
16#include "src/DimNetwork.h"
17
18using namespace std;
19
20class FactGui : public MainWindow, public DimNetwork
21{
22private:
23 class FunctionEvent : public QEvent
24 {
25 public:
26 boost::function<void(const QEvent &)> fFunction;
27
28 FunctionEvent(const boost::function<void(const QEvent &)> &f)
29 : QEvent((QEvent::Type)QEvent::registerEventType()),
30 fFunction(f) { }
31
32 bool Exec() { fFunction(*this); return true; }
33 };
34
35 DimInfo fDimDNS;
36 map<string, DimInfo*> fServices;
37
38 // ======================================================================
39
40 QStandardItem *AddServiceItem(const std::string &server, const std::string &service, bool iscmd)
41 {
42 QListView *servers = iscmd ? fDimCmdServers : fDimSvcServers;
43 QListView *services = iscmd ? fDimCmdCommands : fDimSvcServices;
44 QListView *description = iscmd ? fDimCmdDescription : fDimSvcDescription;
45
46 QStandardItemModel *m = dynamic_cast<QStandardItemModel*>(servers->model());
47 if (!m)
48 {
49 m = new QStandardItemModel(this);
50 servers->setModel(m);
51 services->setModel(m);
52 description->setModel(m);
53 }
54
55 QList<QStandardItem*> l = m->findItems(server.c_str());
56
57 if (l.size()>1)
58 {
59 cout << "hae" << endl;
60 return 0;
61 }
62
63 QStandardItem *col = l.size()==0 ? NULL : l[0];
64
65 if (!col)
66 {
67 col = new QStandardItem(server.c_str());
68 m->appendRow(col);
69
70 if (!services->rootIndex().isValid())
71 {
72 services->setRootIndex(col->index());
73 servers->setCurrentIndex(col->index());
74 }
75 }
76
77 QStandardItem *item = 0;
78 for (int i=0; i<col->rowCount(); i++)
79 {
80 QStandardItem *coli = col->child(i);
81 if (coli->text().toStdString()==service)
82 return coli;
83 }
84
85 item = new QStandardItem(service.c_str());
86 col->appendRow(item);
87
88 if (!description->rootIndex().isValid())
89 {
90 description->setRootIndex(item->index());
91 services->setCurrentIndex(item->index());
92 }
93
94 if (!iscmd)
95 item->setCheckable(true);
96
97 return item;
98 }
99
100 void AddDescription(QStandardItem *item, const vector<Description> &vec)
101 {
102 if (!item)
103 return;
104 if (vec.size()==0)
105 return;
106
107 item->setToolTip(vec[0].comment.c_str());
108
109 const string str = Description::GetHtmlDescription(vec);
110
111 QStandardItem *desc = new QStandardItem(str.c_str());
112 desc->setSelectable(false);
113 item->setChild(0, 0, desc);
114 }
115
116 // ======================================================================
117
118 void handleAddServer(const std::string &server)
119 {
120 const State s = GetState(server, GetCurrentState(server));
121 handleStateChanged(Time(), server, s);
122 }
123
124 void handleRemoveServer(const string &server)
125 {
126 handleStateOffline(server);
127 handleRemoveAllServices(server);
128 }
129
130 void handleRemoveAllServers()
131 {
132 QStandardItemModel *m = 0;
133 if ((m=dynamic_cast<QStandardItemModel*>(fDimCmdServers->model())))
134 m->removeRows(0, m->rowCount());
135
136 if ((m = dynamic_cast<QStandardItemModel*>(fDimSvcServers->model())))
137 m->removeRows(0, m->rowCount());
138 }
139
140 void handleAddService(const std::string &server, const std::string &service, const std::string &/*fmt*/, bool iscmd)
141 {
142 QStandardItem *item = AddServiceItem(server, service, iscmd);
143 const vector<Description> v = GetDescription(server, service);
144 AddDescription(item, v);
145 }
146
147 void handleRemoveService(const std::string &server, const std::string &service, bool iscmd)
148 {
149 QListView *servers = iscmd ? fDimCmdServers : fDimSvcServers;
150
151 QStandardItemModel *m = dynamic_cast<QStandardItemModel*>(servers->model());
152 if (!m)
153 return;
154
155 QList<QStandardItem*> l = m->findItems(server.c_str());
156 if (l.size()!=1)
157 return;
158
159 for (int i=0; i<l[0]->rowCount(); i++)
160 {
161 QStandardItem *row = l[0]->child(i);
162 if (row->text().toStdString()==service)
163 {
164 l[0]->removeRow(row->index().row());
165 return;
166 }
167 }
168 }
169
170 void handleRemoveAllServices(const std::string &server)
171 {
172 QStandardItemModel *m = 0;
173 if ((m=dynamic_cast<QStandardItemModel*>(fDimCmdServers->model())))
174 {
175 QList<QStandardItem*> l = m->findItems(server.c_str());
176 if (l.size()==1)
177 m->removeRow(l[0]->index().row());
178 }
179
180 if ((m = dynamic_cast<QStandardItemModel*>(fDimSvcServers->model())))
181 {
182 QList<QStandardItem*> l = m->findItems(server.c_str());
183 if (l.size()==1)
184 m->removeRow(l[0]->index().row());
185 }
186 }
187
188 void handleAddDescription(const std::string &server, const std::string &service, const vector<Description> &vec)
189 {
190 const bool iscmd = IsCommand(server, service)==true;
191
192 QStandardItem *item = AddServiceItem(server, service, iscmd);
193 AddDescription(item, vec);
194 }
195
196 void handleStateChanged(const Time &/*time*/, const std::string &server,
197 const State &s)
198 {
199 // FIXME: Prefix tooltip with time
200 if (server=="FTM_CONTROL")
201 {
202 fStatusFTMLabel->setText(s.name.c_str());
203 fStatusFTMLabel->setToolTip(s.comment.c_str());
204
205 if (s.index<FTM::kDisconnected) // No Dim connection
206 fStatusFTMLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
207 if (s.index==FTM::kDisconnected) // Dim connection / FTM disconnected
208 fStatusFTMLed->setIcon(QIcon(":/Resources/icons/yellow circle 1.png"));
209 if (s.index==FTM::kConnected) // Dim connection / FTM connected
210 fStatusFTMLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
211 }
212
213 if (server=="FAD_CONTROL")
214 {
215 fStatusFADLabel->setText(s.name.c_str());
216 fStatusFADLabel->setToolTip(s.comment.c_str());
217
218 if (s.index<FTM::kDisconnected) // No Dim connection
219 fStatusFADLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
220 if (s.index==FTM::kDisconnected) // Dim connection / FTM disconnected
221 fStatusFADLed->setIcon(QIcon(":/Resources/icons/yellow circle 1.png"));
222 if (s.index==FTM::kConnected) // Dim connection / FTM connected
223 fStatusFADLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
224 }
225
226 if (server=="DATA_LOGGER")
227 {
228 fStatusLoggerLabel->setText(s.name.c_str());
229 fStatusLoggerLabel->setToolTip(s.comment.c_str());
230
231 if (s.index<-1) // Error
232 fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
233 if (s.index>=0x100) // Error
234 fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/red circle 1.png"));
235 if (s.index<=30) // Waiting
236 fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/yellow circle 1.png"));
237 if (s.index==40) // Logging
238 fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
239 }
240
241 if (server=="CHAT")
242 {
243 fStatusChatLabel->setText(s.name.c_str());
244
245 if (s.index==FTM::kConnected) // Dim connection / FTM connected
246 fStatusChatLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
247 else
248 fStatusChatLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
249 }
250 }
251
252 void handleStateOffline(const string &server)
253 {
254 handleStateChanged(Time(), server, State(-2, "Offline", "No connection via DIM."));
255 }
256
257 void handleWrite(const Time &time, const string &text, int qos)
258 {
259 stringstream out;
260
261 if (text.substr(0, 6)=="CHAT: ")
262 {
263 out << "<font size='-1' color='navy'>[<B>";
264 out << Time::fmt("%H:%M:%S") << time << "</B>]</FONT> ";
265 out << text.substr(6);
266 fChatText->append(out.str().c_str());
267 return;
268 }
269
270
271 out << "<font color='";
272
273 switch (qos)
274 {
275 case kMessage: out << "black"; break;
276 case kInfo: out << "green"; break;
277 case kWarn: out << "#FF6600"; break;
278 case kError: out << "maroon"; break;
279 case kFatal: out << "maroon"; break;
280 case kDebug: out << "navy"; break;
281 default: out << "navy"; break;
282 }
283 out << "'>" << time.GetAsStr() << " - " << text << "</font>";
284
285 fLogText->append(out.str().c_str());
286
287 if (qos>=kWarn)
288 fTextEdit->append(out.str().c_str());
289 }
290
291 void handleDimService(const string &txt)
292 {
293 fDimSvcText->append(txt.c_str());
294 }
295
296 void handleDimDNS(int version)
297 {
298 ostringstream str;
299 str << "DIM V" << version/100 << 'r' << version%100;
300
301 if (version==0)
302 fStatusDNSLed->setIcon(QIcon(":/Resources/icons/red circle 1.png"));
303 else
304 fStatusDNSLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
305
306 fStatusDNSLabel->setText(version==0?"Offline":str.str().c_str());
307 fStatusDNSLabel->setToolTip(version==0?"No connection to DIM DNS.":"Connection to DIM DNS established.");
308 }
309
310 // ======================================================================
311
312 void AddServer(const std::string &s)
313 {
314 DimNetwork::AddServer(s);
315
316 QApplication::postEvent(this,
317 new FunctionEvent(boost::bind(&FactGui::handleAddServer, this, s)));
318 }
319
320 void RemoveServer(const std::string &s)
321 {
322 UnsubscribeServer(s);
323
324 DimNetwork::RemoveServer(s);
325
326 QApplication::postEvent(this,
327 new FunctionEvent(boost::bind(&FactGui::handleRemoveServer, this, s)));
328 }
329
330 void RemoveAllServers()
331 {
332 UnsubscribeAllServers();
333
334 vector<string> v = GetServerList();
335 for (vector<string>::iterator i=v.begin(); i<v.end(); i++)
336 QApplication::postEvent(this,
337 new FunctionEvent(boost::bind(&FactGui::handleStateOffline, this, *i)));
338
339 DimNetwork::RemoveAllServers();
340
341 QApplication::postEvent(this,
342 new FunctionEvent(boost::bind(&FactGui::handleRemoveAllServers, this)));
343 }
344
345 void AddService(const std::string &server, const std::string &service, const std::string &fmt, bool iscmd)
346 {
347 QApplication::postEvent(this,
348 new FunctionEvent(boost::bind(&FactGui::handleAddService, this, server, service, fmt, iscmd)));
349 }
350
351 void RemoveService(const std::string &server, const std::string &service, bool iscmd)
352 {
353 if (fServices.find(server+'/'+service)!=fServices.end())
354 UnsubscribeService(server+'/'+service);
355
356 QApplication::postEvent(this,
357 new FunctionEvent(boost::bind(&FactGui::handleRemoveService, this, server, service, iscmd)));
358 }
359
360 void RemoveAllServices(const std::string &server)
361 {
362 UnsubscribeServer(server);
363
364 QApplication::postEvent(this,
365 new FunctionEvent(boost::bind(&FactGui::handleRemoveAllServices, this, server)));
366 }
367
368 void AddDescription(const std::string &server, const std::string &service, const vector<Description> &vec)
369 {
370 QApplication::postEvent(this,
371 new FunctionEvent(boost::bind(&FactGui::handleAddDescription, this, server, service, vec)));
372 }
373
374
375 void IndicateStateChange(const Time &time, const std::string &server)
376 {
377 const State s = GetState(server, GetCurrentState(server));
378
379 QApplication::postEvent(this,
380 new FunctionEvent(boost::bind(&FactGui::handleStateChanged, this, time, server, s)));
381 }
382
383 int Write(const Time &time, const string &txt, int qos)
384 {
385 QApplication::postEvent(this,
386 new FunctionEvent(boost::bind(&FactGui::handleWrite, this, time, txt, qos)));
387
388 return 0;
389 }
390
391 void infoHandler(DimInfo &info)
392 {
393 const string fmt = string("DIS_DNS/SERVER_INFO")==info.getName() ? "C" : info.getFormat();
394
395 stringstream dummy;
396 const Converter conv(dummy, fmt, false);
397
398 const Time tm(info.getTimestamp(), info.getTimestampMillisecs());
399
400 stringstream out;
401 out << Time::fmt("%H:%M:%S.%f") << tm << " <B>" << info.getName() << "</B> - ";
402
403 bool iserr = false;
404 if (!conv)
405 {
406 out << "Compilation of format string '" << fmt << "' failed!";
407 iserr = true;
408 }
409 else
410 {
411 try
412 {
413 const string dat = conv.GetString(info.getData(), info.getSize());
414 out << dat;
415 }
416 catch (const runtime_error &e)
417 {
418 out << "Conversion to string failed!<pre>" << e.what() << "</pre>";
419 iserr = true;
420 }
421 }
422
423 // srand(hash<string>()(string(info.getName())));
424 // int bg = rand()&0xffffff;
425
426 int bg = hash<string>()(string(info.getName()));
427
428 int r = bg&0x1f0000;
429 int g = bg&0x001f00;
430 int b = bg&0x00001f;
431
432 bg = ~(b|g|r)&0xffffff;
433
434 if (iserr)
435 bg = 0xffffff;
436
437 stringstream bgcol;
438 bgcol << hex << setfill('0') << setw(6) << bg;
439
440 const string col = iserr ? "red" : "black";
441 const string str = "<table width='100%' bgcolor=#"+bgcol.str()+"><tr><td><font color='"+col+"'>"+out.str()+"</font></td></tr></table>";
442
443 QApplication::postEvent(this,
444 new FunctionEvent(boost::bind(&FactGui::handleDimService, this, str)));
445 }
446
447 void infoHandler()
448 {
449 if (getInfo()==&fDimDNS)
450 {
451 QApplication::postEvent(this,
452 new FunctionEvent(boost::bind(&FactGui::handleDimDNS, this, getInfo()->getInt())));
453 return;
454 }
455
456 for (map<string,DimInfo*>::iterator i=fServices.begin(); i!=fServices.end(); i++)
457 if (i->second==getInfo())
458 {
459 infoHandler(*i->second);
460 return;
461 }
462
463 DimNetwork::infoHandler();
464 }
465
466 // ======================================================================
467
468
469 void SubscribeService(const string &service)
470 {
471 if (fServices.find(service)!=fServices.end())
472 {
473 cout << "ERROR - We are already subscribed to " << service << endl;
474 return;
475 }
476
477 fServices[service] = new DimStampedInfo(service.c_str(), (void*)NULL, 0, this);
478 }
479
480 void UnsubscribeService(const string &service)
481 {
482 const map<string,DimInfo*>::iterator i=fServices.find(service);
483
484 if (i==fServices.end())
485 {
486 cout << "ERROR - We are not subscribed to " << service << endl;
487 return;
488 }
489
490 delete i->second;
491
492 fServices.erase(i);
493 }
494
495 void UnsubscribeServer(const string &server)
496 {
497 for (map<string,DimInfo*>::iterator i=fServices.begin();
498 i!=fServices.end(); i++)
499 if (i->first.substr(0, server.length()+1)==server+'/')
500 {
501 delete i->second;
502 fServices.erase(i);
503 }
504 }
505
506 void UnsubscribeAllServers()
507 {
508 for (map<string,DimInfo*>::iterator i=fServices.begin();
509 i!=fServices.end(); i++)
510 delete i->second;
511
512 fServices.clear();
513 }
514
515 // ======================================================================
516
517 bool event(QEvent *evt)
518 {
519 if (dynamic_cast<FunctionEvent*>(evt))
520 return static_cast<FunctionEvent*>(evt)->Exec();
521
522 if (dynamic_cast<CheckBoxEvent*>(evt))
523 {
524 const QStandardItem &item = static_cast<CheckBoxEvent*>(evt)->item;
525 const QStandardItem *par = item.parent();
526 if (par)
527 {
528 const QString server = par->text();
529 const QString service = item.text();
530
531 const string s = (server+'/'+service).toStdString();
532
533 if (item.checkState()==Qt::Checked)
534 SubscribeService(s);
535 else
536 UnsubscribeService(s);
537 }
538 }
539
540 return MainWindow::event(evt); // unrecognized
541 }
542
543 void on_fDimCmdSend_clicked(bool)
544 {
545 const QString server = fDimCmdServers->currentIndex().data().toString();
546 const QString command = fDimCmdCommands->currentIndex().data().toString();
547 const QString arguments = fDimCmdLineEdit->displayText();
548
549 // FIXME: Sending a command exactly when the info Handler changes
550 // the list it might lead to confusion.
551 try
552 {
553 SendDimCommand(server.toStdString(), command.toStdString()+" "+arguments.toStdString());
554 fTextEdit->append("<font color='green'>Command '"+server+'/'+command+"' successfully emitted.</font>");
555 fDimCmdLineEdit->clear();
556 }
557 catch (const runtime_error &e)
558 {
559 stringstream txt;
560 txt << e.what();
561
562 string buffer;
563 while (getline(txt, buffer, '\n'))
564 fTextEdit->append(("<font color='red'><pre>"+buffer+"</pre></font>").c_str());
565 }
566 }
567
568public:
569 FactGui() : fDimDNS("DIS_DNS/VERSION_NUMBER", 1, int(0), this)
570 {
571 DimClient::sendCommand("CHAT/MSG", "GUI online.");
572 // + MessageDimRX
573 }
574 ~FactGui()
575 {
576 UnsubscribeAllServers();
577 }
578};
579
580#endif
Note: See TracBrowser for help on using the repository browser.