/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*************************************************************************** * cprquerydialog.cc * * Sat Feb 19 17:05:43 CET 2005 * Copyright 2005 Bent Bisballe * deva@aasimon.org ****************************************************************************/ /* * This file is part of MIaV. * * MIaV is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * MIaV is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MIaV; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "cprquerydialog.h" #include #include "messagebox.h" #include "miav_config.h" CPRQueryDialog::CPRQueryDialog(QLabel *lcpr, QLabel *lname, QWidget *parent, const char *name, QStatusBar *status) : QDialog(parent) { setModal(true); setWindowTitle(name); // Load image QPixmap pix_backspace; pix_backspace.load( PIXMAP_BACKSPACE ); lbl_name = lname; lbl_cpr = lcpr; statusbar = status; //Read configuration CPR_HOST = config->readString("cpr_host"); CPR_PORT = config->readInt("cpr_port"); CPR_TIMEOUT = config->readInt("cpr_timeout"); cpr[0] = '\0'; internalCpr[0] = '\0'; cprSocket = new QTcpSocket(this); connect(cprSocket, SIGNAL(readyRead()), SLOT(cprSocket_readyRead())); connect(cprSocket, SIGNAL(connected()), SLOT(cprSocket_connected())); connect(cprSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(cprSocket_error(QAbstractSocket::SocketError))); lbl_cpr->setText("Indtast CPR"); // Setup connection timer timer = new QTimer(this); connect(timer, SIGNAL(timeout()), SLOT(cprSocket_timeout())); // Generate input buttons QGridLayout *gl = new QGridLayout(this); QPushButton *b1 = createButton(this, "1", 1); QPushButton *b2 = createButton(this, "2", 2); QPushButton *b3 = createButton(this, "3", 3); QPushButton *b4 = createButton(this, "4", 4); QPushButton *b5 = createButton(this, "5", 5); QPushButton *b6 = createButton(this, "6", 6); QPushButton *b7 = createButton(this, "7", 7); QPushButton *b8 = createButton(this, "8", 8); QPushButton *b9 = createButton(this, "9", 9); QPushButton *b0 = createButton(this, "0", 0); QPushButton *bbs = createButton(this, "", 10); bbs->setIcon(pix_backspace); QPushButton *bca = createButton(this, "CA", 11); gl->addWidget(b1, 0,0); gl->addWidget(b2, 0,1); gl->addWidget(b3, 0,2); gl->addWidget(b4, 1,0); gl->addWidget(b5, 1,1); gl->addWidget(b6, 1,2); gl->addWidget(b7, 2,0); gl->addWidget(b8, 2,1); gl->addWidget(b9, 2,2); gl->addWidget(b0, 3,1); gl->addWidget(bbs, 3,2); gl->addWidget(bca, 3,0); // Setup signals connect(b1, SIGNAL(clicked()), SLOT(b_1_clicked())); connect(b2, SIGNAL(clicked()), SLOT(b_2_clicked())); connect(b3, SIGNAL(clicked()), SLOT(b_3_clicked())); connect(b4, SIGNAL(clicked()), SLOT(b_4_clicked())); connect(b5, SIGNAL(clicked()), SLOT(b_5_clicked())); connect(b6, SIGNAL(clicked()), SLOT(b_6_clicked())); connect(b7, SIGNAL(clicked()), SLOT(b_7_clicked())); connect(b8, SIGNAL(clicked()), SLOT(b_8_clicked())); connect(b9, SIGNAL(clicked()), SLOT(b_9_clicked())); connect(b0, SIGNAL(clicked()), SLOT(b_0_clicked())); connect(bbs,SIGNAL(clicked()), SLOT(b_b_clicked())); connect(bca,SIGNAL(clicked()), SLOT(b_c_clicked())); this->move(175,150); listen = new CPRListen(config->readInt("cprlisten_port")); listen_timer = new QTimer(this); connect(listen_timer, SIGNAL(timeout()), SLOT(listen_timeout())); listen->run(); listen_timer->start(500); // Check every 500 ms show(); } CPRQueryDialog::~CPRQueryDialog() { // Cleanup after cpr listen listen->stop(); // listen->wait_stop(); delete listen; } void CPRQueryDialog::listen_timeout() { string newcpr; if(listen->cprChanged()) { char newcpr_buf[32]; newcpr = listen->getCpr(); sprintf(newcpr_buf, "%s-%s", newcpr.substr(0,6).c_str(), newcpr.substr(6,4).c_str()); //printf("cprbuf[%s]\n", newcpr_buf); lbl_cpr->setText(newcpr_buf); verifycpr(newcpr_buf); } } /** * createButton: * A genric button-creater */ QPushButton *CPRQueryDialog::createButton(QWidget *parent, const char *text, int value) { char buf[32]; sprintf(buf, "%d", value); QPushButton *q = new QPushButton(this);// buf); // TODO QFont f("Lucida", 48); q->setFixedSize(150, 100); q->setText(text); q->setFont(f); return q; } /** * Event functions for handling buttonclicks. * For button 0-9 the values is sent back. * Backspace and clear are handled via special * signals. * When 10 digits has been input we close the form */ void CPRQueryDialog::b_1_clicked() { insert_digit(1); } void CPRQueryDialog::b_2_clicked() { insert_digit(2); } void CPRQueryDialog::b_3_clicked() { insert_digit(3); } void CPRQueryDialog::b_4_clicked() { insert_digit(4); } void CPRQueryDialog::b_5_clicked() { insert_digit(5); } void CPRQueryDialog::b_6_clicked() { insert_digit(6); } void CPRQueryDialog::b_7_clicked() { insert_digit(7); } void CPRQueryDialog::b_8_clicked() { insert_digit(8); } void CPRQueryDialog::b_9_clicked() { insert_digit(9); } void CPRQueryDialog::b_0_clicked() { insert_digit(0);} void CPRQueryDialog::b_b_clicked() { remove_digit();} void CPRQueryDialog::b_c_clicked() { remove_all();} void CPRQueryDialog::b_clicked(int value) { //printf("%d\n", value); switch(value) { case 10: if (digits>0) digits--; emit bbs_clicked(); break; case 11: digits = 0; emit bca_clicked(); break; default: digits++; emit number_clicked(value); } if (digits == 10){ digits = 0; accept(); } } /** * remove_digit: * Remove one digit from the selected cpr * Used when the user pushes backspace in * the inputwindow */ void CPRQueryDialog::remove_digit() { int temp; temp = strlen(cpr); if (temp == 7) /* Remove two characters due to the hyphen */ strcpy(cpr+temp-2, "\0"); else if ((temp >0) && (temp <=11)) strcpy(cpr+temp-1, "\0"); lbl_cpr->setText(cpr); } /** * remove_all: * Clear the selected cpr */ void CPRQueryDialog::remove_all() { strcpy(cpr, ""); lbl_cpr->setText(cpr); } /** * insert_digit: * Respond to what the user types in the inputWindow */ void CPRQueryDialog::insert_digit(int value) { //printf("insert_digit(%d)\n", value); char temp[3]; //printf("strlen(cpr) = %d cpr: '%s'\n", strlen(cpr), cpr); switch(strlen(cpr)) { case 5: // Automaticaly add a hyphen after the sixth digit sprintf(temp, "%d-", value); strcat(cpr, temp); lbl_cpr->setText(cpr); break; case 10: sprintf(temp, "%d", value); strcat(cpr, temp); lbl_cpr->setText(cpr); verifycpr(cpr); break; default: sprintf(temp, "%d", value); strcat(cpr, temp); lbl_cpr->setText(cpr); break; } } /** * verifycpr: * Test a cpr via test_cpr(). * If cpr is invalid, then ask user what * to do via MessageBox */ void CPRQueryDialog::verifycpr(char *cpr) { strncpy(internalCpr, cpr, 6); strncpy(internalCpr+6, cpr+7, 4); internalCpr[10] = 0; if (!(test_cpr(internalCpr))) { MessageBox ccw(this, CONFIRM_INVALID_CPR_TITLE, CONFIRM_INVALID_CPR, TYPE_YES_NO_CANCEL); switch(ccw.exec()) { case MSG_CANCEL: bedit_clicked(); break; case MSG_NO: bcancel_clicked(); break; case MSG_YES: // Overwrite name from previous cpr. lbl_name->setText(NAME_NOT_AVAILABLE); accept(); break; } } else { cprSocket->connectToHost(CPR_HOST->c_str(), CPR_PORT); timer->start(CPR_TIMEOUT); // accept(); } } /* Clears all data - alerts user if measurements are not stored */ void CPRQueryDialog::bcancel_clicked() { cpr[0]= '\0'; lbl_cpr->setText("Indtast CPR"); lbl_name->setText(""); } /* This is used when the user enters a cpr that is not valid and wishes to edit * the cpr. */ void CPRQueryDialog::bedit_clicked() { cpr[10]= '\0'; lbl_cpr->setText(cpr); lbl_name->setText(""); } /** * test_cpr: * Checks that a cpr i valid via a modulo 11 test */ int CPRQueryDialog::test_cpr(const char *s) { int sum = 0; int ctl; const char *cptr; // Is the string to short to be a cpr? if(strlen(s) != 10) return 0; // Are all characters digits? for(cptr = s; *cptr; cptr++) if(!isdigit(*cptr)) return 0; // Calculate modulo 11 checksum sum += (s[0] - '0') * 4; sum += (s[1] - '0') * 3; sum += (s[2] - '0') * 2; sum += (s[3] - '0') * 7; sum += (s[4] - '0') * 6; sum += (s[5] - '0') * 5; sum += (s[6] - '0') * 4; sum += (s[7] - '0') * 3; sum += (s[8] - '0') * 2; ctl = 11 - (sum % 11); // Is the checksum correct? if(ctl == 11) ctl = 0; return s[9] - '0' == ctl; } /** * cprSocket_error * Called if an error occurres in the corsocket connection. * Writes out the appropriate error message. */ void CPRQueryDialog::cprSocket_error(QAbstractSocket::SocketError err) { QString msg = QString("cprSocket encountered an error: "); timer->stop(); lbl_name->setText(NAME_NOT_AVAILABLE); // Print error message switch(err) { case QAbstractSocket::ConnectionRefusedError: // if the connection was refused msg.append("ErrConnectionRefused"); break; case QAbstractSocket::HostNotFoundError: // if the host was not found msg.append("ErrHostNotFound"); break; default: msg.sprintf("Socket Error %d", (int)err); break; } if(statusbar) statusbar->showMessage(msg, 5000); MessageBox(this, "Fejl", msg.toStdString().c_str(), TYPE_OK, ICON_ERROR).exec(); accept(); } /** * cprSocket_readyRead: * Uses a patients cpr to look up his or hers name * via the departments cpr-server. * This is called by the cprSocket when the socket is ready */ void CPRQueryDialog::cprSocket_readyRead() { QString name; QString firstname; QString lastname; int timeout = 0; if (!cprSocket->canReadLine()) return; QString msg = QString("Recieving name from cpr database..."); if(statusbar) statusbar->showMessage(msg, 5000); timer->stop(); while(cprSocket->canReadLine()) { QString s = cprSocket->readLine(); if (s.startsWith("0001")) { name.append(s.right(s.length()-4)); lastname.append(s.right(s.length()-4)); name = name.left(name.length()-1); if (name.length()) name += QString(", "); } if (s.startsWith("0002")) { name.append(s.right(s.length()-4)); firstname.append(s.right(s.length()-4)); name = name.left(name.length()-1); cprSocket->close(); lbl_name->setText(name); accept(); return; } if (timeout>1000) { lbl_name->setText(NAME_NOT_AVAILABLE); MessageBox(this, NAME_NOT_AVAILABLE_TITLE, NAME_NOT_AVAILABLE, TYPE_OK, ICON_ERROR).exec(); accept(); return; } timeout++; } accept(); } /** * cprSocket_connected: * Writes the selected cpr to the cpr-server * when the cprSocket is connected. */ void CPRQueryDialog::cprSocket_connected() { QString msg = QString("Connected to cpr database, sending cpr number..."); if(statusbar) statusbar->showMessage(msg, 5000); timer->stop(); cprSocket->write(internalCpr, 10); cprSocket->write("\n", 1); } /** * cprSocket_timeout: * Called when the connection has not emitted a signal in CPR_TIMEOUT miliseconds. */ void CPRQueryDialog::cprSocket_timeout() { QString msg = QString("cprSocket timed out doing: "); timer->stop(); lbl_name->setText(NAME_NOT_AVAILABLE); QAbstractSocket::SocketState state = cprSocket->state(); // Print connection status switch(state) { case QAbstractSocket::UnconnectedState: // if there is no connection msg.append("Idle"); break; case QAbstractSocket::HostLookupState: // during a DNS lookup msg.append("HostLookup"); break; case QAbstractSocket::ConnectingState: // during TCP connection establishment msg.append("Connecting"); break; case QAbstractSocket::ConnectedState: // when there is an operational connection msg.append("Connected"); break; case QAbstractSocket::ClosingState: // if the socket is closing down, but is not yet closed. msg.append("Closing"); break; default: msg.sprintf("Unknown state: %d", state); break; } if(statusbar) statusbar->showMessage(msg, 5000); MessageBox(this, "Fejl", msg.toStdString().c_str(), TYPE_OK, ICON_ERROR).exec(); accept(); }