From c41c204f421c4c1bc453932d2d5552227d794201 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Fri, 25 Nov 2011 09:28:31 +0100 Subject: Replace newline with symbol to avoid new row generation in office import. --- server/src/admin_export.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/src/admin_export.cc b/server/src/admin_export.cc index 3ec77d1..e125699 100644 --- a/server/src/admin_export.cc +++ b/server/src/admin_export.cc @@ -47,8 +47,10 @@ static std::string escape(std::string &str) std::string::iterator i = str.begin(); while(i != str.end()) { if(*i == '\"') out += "''"; + else if(*i == '\n') out += "\342\220\244"; // N/L controlcharacter pictogram + else if(*i == '\r') { } else out += *i; - i++; + i++; } out += "\""; return out; -- cgit v1.2.3 From dd1fb6e16ff777d3e098076d1015c6c565b51bb7 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Fri, 25 Nov 2011 11:59:37 +0100 Subject: Reuse environment (macrolist) instead of creating a new one. Add 'to' and 'from' times to export, both unixtimestamps. --- server/src/admin_connection.cc | 7 ++++++- server/src/admin_export.cc | 44 +++++++++++++++++++++++------------------- server/src/admin_export.h | 4 +++- server/src/fieldnamescanner.cc | 6 +++--- server/src/fieldnamescanner.h | 4 +++- 5 files changed, 39 insertions(+), 26 deletions(-) diff --git a/server/src/admin_connection.cc b/server/src/admin_connection.cc index 0fe5380..6ad7642 100644 --- a/server/src/admin_connection.cc +++ b/server/src/admin_connection.cc @@ -118,8 +118,13 @@ bool AdminConnection::handle(const char *data, size_t size) } if(uri == "/export" && args.find("template") != args.end()) { + time_t from = 0; + if(args.find("from") != args.end()) from = atoi(args["from"].c_str()); + + time_t to = time(NULL); + if(args.find("to") != args.end()) to = atoi(args["to"].c_str()); bool ok; - std::string res = admin_export(env, args["template"], &ok); + std::string res = admin_export(env, args["template"], &ok, from, to); if(!ok) reply = admin_header(uri) + res + admin_rc("footer"); else { reply = res; diff --git a/server/src/admin_export.cc b/server/src/admin_export.cc index e125699..0aa290c 100644 --- a/server/src/admin_export.cc +++ b/server/src/admin_export.cc @@ -61,34 +61,22 @@ public: File(fieldnames_t &f, pqxx::work &w) : work(w), fieldnames(f) { - // name += ".csf"; - // fp = fopen(name.c_str(), "w"); - pos["id"] = 0; pos["patientid"] = 1; pos["time"] = 2; pos["template"] = 3; - //printf("%s\n", n.c_str()); - size_t idx = 4; fieldnames_t::iterator i = f.begin(); while(i != f.end()) { - //printf("%s ", i->c_str()); pos[*i] = idx; idx++; i++; } - // printf("\n"); output_header(); } - ~File() - { - // if(fp) fclose(fp); - } - void output_header() { beginrow(); @@ -146,7 +134,8 @@ private: }; -static std::string do_export(std::string templ, bool *ok) +static std::string do_export(Environment &env, std::string templ, bool *ok, + time_t from, time_t to) { if(Conf::database_backend != "pgsql") { *ok = false; @@ -184,7 +173,7 @@ static std::string do_export(std::string templ, bool *ok) } } - templates_t t = scanfieldnames(filter); + templates_t t = scanfieldnames(env, filter); /* templates_t::iterator ti = t.begin(); while(ti != t.end()) { @@ -200,10 +189,24 @@ static std::string do_export(std::string templ, bool *ok) File file(t[templ], work); + std::string tostr; + std::string fromstr; { - pqxx::result result = - work.exec("SELECT * FROM commits WHERE template='"+templ+"'" - " AND status='committed' ORDER BY patientid, timestamp;"); + char buf[32]; + sprintf(buf, "%d", (int)from); + fromstr = buf; + sprintf(buf, "%d", (int)to); + tostr = buf; + } + + { + std::string q = "SELECT * FROM commits WHERE template='"+templ+"'" + " AND status='committed' AND timestamp>=" +fromstr+ + " AND timestamp<="+tostr+" ORDER BY patientid, timestamp;"; + + DEBUG(export, "QUERY: %s\n", q.c_str()); + + pqxx::result result = work.exec(q); pqxx::result::const_iterator ri = result.begin(); for(unsigned int r = 0; r < result.size(); r++) { pqxx::result::tuple tuple = result.at(r); @@ -212,7 +215,7 @@ static std::string do_export(std::string templ, bool *ok) std::string version = tuple.at(2).c_str(); std::string timestamp = tuple.at(3).c_str(); std::string uid = tuple.at(4).c_str(); - std::string status = tuple.at(5).c_str(); + // std::string status = tuple.at(5).c_str(); file.beginrow(); file.addcell("id", uid); @@ -255,10 +258,11 @@ static std::string do_export(std::string templ, bool *ok) #endif/* WITHOUT_DB */ -std::string admin_export(Environment &env, std::string templ, bool *ok) +std::string admin_export(Environment &env, std::string templ, bool *ok, + time_t from, time_t to) { #ifndef WITHOUT_DB - return do_export(templ, ok); + return do_export(env, templ, ok, from, to); #else return "No database available"; #endif/* WITHOUT_DB */ diff --git a/server/src/admin_export.h b/server/src/admin_export.h index 69c7a36..804d373 100644 --- a/server/src/admin_export.h +++ b/server/src/admin_export.h @@ -29,9 +29,11 @@ #define __PRACRO_ADMIN_EXPORT_H__ #include +#include #include "environment.h" -std::string admin_export(Environment &env, std::string templ, bool *ok); +std::string admin_export(Environment &env, std::string templ, bool *ok, + time_t from, time_t to); #endif/*__PRACRO_ADMIN_EXPORT_H__*/ diff --git a/server/src/fieldnamescanner.cc b/server/src/fieldnamescanner.cc index 5418bb4..ba3b61f 100644 --- a/server/src/fieldnamescanner.cc +++ b/server/src/fieldnamescanner.cc @@ -58,12 +58,12 @@ fieldnames_t getFields(Widget &widget) return fieldnames; } -templates_t scanfieldnames(std::set &filter) +templates_t scanfieldnames(Environment &env, std::set &filter) { templates_t templates; // TemplateList templatelist(Conf::xml_basedir + "/templates"); - MacroList macrolist(Conf::xml_basedir + "/macros"); + // MacroList macrolist(Conf::xml_basedir + "/macros"); // Iterate templates: std::vector templatefiles = getTemplates(); @@ -83,7 +83,7 @@ templates_t scanfieldnames(std::set &filter) if(ms->isHeader == false) { std::string macro = ms->name; DEBUG(scanner, "Name '%s'\n", macro.c_str()); - std::string macrofile = macrolist.getLatestVersion(macro); + std::string macrofile = env.macrolist.getLatestVersion(macro); DEBUG(scanner, "File '%s'\n", macrofile.c_str()); // Iterate fields: diff --git a/server/src/fieldnamescanner.h b/server/src/fieldnamescanner.h index c766ba1..6201db7 100644 --- a/server/src/fieldnamescanner.h +++ b/server/src/fieldnamescanner.h @@ -33,12 +33,14 @@ #include #include +#include "environment.h" + typedef std::string fieldname_t; typedef std::vector< fieldname_t > fieldnames_t; typedef std::string template_name_t; typedef std::map< template_name_t, fieldnames_t > templates_t; -templates_t scanfieldnames(std::set &filter); +templates_t scanfieldnames(Environment &env, std::set &filter); #endif/*__PRACRO_FIELDNAMESCANNER_H__*/ -- cgit v1.2.3 From 2a89f766b3c4917001de03a06bfbecb1ce25675f Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Mon, 28 Nov 2011 15:03:17 +0100 Subject: Use one-thread-per-connection and fix up Session locking. --- server/src/admin_connection.cc | 12 +++++++++--- server/src/client_connection.cc | 15 ++++++++++----- server/src/client_connection.h | 7 ++++++- server/src/httpd.cc | 9 +++++++-- server/src/session.cc | 23 +++++++++++++++-------- server/src/session.h | 12 ++++++------ 6 files changed, 53 insertions(+), 25 deletions(-) diff --git a/server/src/admin_connection.cc b/server/src/admin_connection.cc index 6ad7642..60c09d0 100644 --- a/server/src/admin_connection.cc +++ b/server/src/admin_connection.cc @@ -36,7 +36,11 @@ static std::string admin_sessionunlock(Environment &env, std::string id) { - Session *session = env.sessions.session(id); + // NOTE: Returned session is returned in locked state! + Session *session = NULL; + SessionAutounlock l(&session); + + session = env.sessions.lockedSession(id); if(session) { if(session->isReadonly()) { env.sessions.deleteSession(id); @@ -56,8 +60,10 @@ static std::string admin_listactivesessions(Environment &env) std::vector act = env.sessions.activeSessions(); std::vector::iterator i = act.begin(); while(i != act.end()) { - Session *s = env.sessions.session(*i); - SessionAutolock lock(*s); + // NOTE: Returned session is returned in locked state! + Session *s = NULL; + SessionAutounlock l(&s); + s = env.sessions.lockedSession(*i); str += "Session " + *i + ": "+s->templ+" on "+s->patientid+" "+ std::string(s->idle()?"[idle]":"[active]")+"\n"; i++; diff --git a/server/src/client_connection.cc b/server/src/client_connection.cc index fe55efc..075dc46 100644 --- a/server/src/client_connection.cc +++ b/server/src/client_connection.cc @@ -44,7 +44,7 @@ static std::string error_box(std::string message) static bool did_commit = false; #endif -ClientConnection::ClientConnection(Environment &e, headers_t &headers, +ClientConnection::ClientConnection(Environment &e, headers_t headers, headers_t args, std::string uri) : env(e), parser(&transaction) { @@ -154,17 +154,22 @@ bool ClientConnection::handle(const char *data, size_t size) } Session *session = NULL; + SessionAutounlock l(&session); + try { if(sessionid == "") { // Create new session - session = env.sessions.newSession(patientid, templ); + // NOTE: New session is returned in locked state! + session = env.sessions.newLockedSession(patientid, templ); } else { // Attach to old session - session = env.sessions.session(sessionid); + // NOTE: Returned session is returned in locked state! + session = env.sessions.lockedSession(sessionid); // Session didn't exist - create a new one anyway. if(session == NULL) { - session = env.sessions.newSession(patientid, templ); + // NOTE: New session is returned in locked state! + session = env.sessions.newLockedSession(patientid, templ); } } } catch(Sessions::SessionAlreadyActive &e) { @@ -201,7 +206,7 @@ bool ClientConnection::handle(const char *data, size_t size) parser_complete = true; { - SessionAutolock lock(*session); + //SessionAutolock lock(session); response = handleTransaction(request, transaction, env, *session); } diff --git a/server/src/client_connection.h b/server/src/client_connection.h index b811b7f..e64dcad 100644 --- a/server/src/client_connection.h +++ b/server/src/client_connection.h @@ -40,7 +40,12 @@ class Session; class ClientConnection : public Connection { public: - ClientConnection(Environment &e, headers_t &headers, + /** + * URI: course/template/macro + * Params: petientid, sessionid and statechange (commit, nocommit or discard) + * Headers are currently not used. + */ + ClientConnection(Environment &e, headers_t headers, headers_t args, std::string uri); ~ClientConnection(); diff --git a/server/src/httpd.cc b/server/src/httpd.cc index f7ad7f4..1c0575a 100644 --- a/server/src/httpd.cc +++ b/server/src/httpd.cc @@ -68,6 +68,11 @@ static int request_handler(void *cls, unsigned int *data_size, void **con_cls) { + DEBUG(httpd, "request_handler: cls(%p) con(%p) url(%s) method(%s)" + " version(%s) *con_cls(%p)\n", + cls, con, url, method, version, *con_cls); + DEBUG(httpd, "request_handler: *data_size(%u) data:[%s]\n", *data_size, data); + int ret = MHD_YES; Httpd *httpd = (Httpd*)cls; @@ -176,7 +181,7 @@ Httpd::~Httpd() void Httpd::listen(unsigned short int port, unsigned int cn_limit, unsigned int cn_timeout) { - int flags = MHD_USE_DEBUG | MHD_USE_SELECT_INTERNALLY; + int flags = MHD_USE_DEBUG | MHD_USE_THREAD_PER_CONNECTION; d = MHD_start_daemon(flags, port, NULL, NULL, request_handler, this, @@ -196,7 +201,7 @@ void Httpd::listen_ssl(unsigned short int port, std::string key, std::string cert, unsigned int cn_limit, unsigned int cn_timeout) { - int flags = MHD_USE_DEBUG | MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL; + int flags = MHD_USE_DEBUG | MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL; d_ssl = MHD_start_daemon(flags, port, NULL, NULL, request_handler, this, diff --git a/server/src/session.cc b/server/src/session.cc index 8071d45..fcd138a 100644 --- a/server/src/session.cc +++ b/server/src/session.cc @@ -195,7 +195,7 @@ static bool fexists(const std::string &f) return ret; } -Session *Sessions::newSession(std::string patientid, std::string templ) +Session *Sessions::newLockedSession(std::string patientid, std::string templ) throw(SessionAlreadyActive) { MutexAutolock lock(mutex); @@ -209,6 +209,7 @@ Session *Sessions::newSession(std::string patientid, std::string templ) DEBUG(session, "Patient/template matched session is already active."); throw SessionAlreadyActive(session->id()); } + session->lock(); return session; } @@ -224,27 +225,33 @@ Session *Sessions::newSession(std::string patientid, std::string templ) DEBUG(session, "Looked up session by id is already active."); throw SessionAlreadyActive(session->id()); } + session->lock(); return session; } } Session *session = new Session(env, "", patientid, templ); sessions[session->id()] = session; + session->lock(); return session; } -Session *Sessions::session(std::string sessionid) +Session *Sessions::lockedSession(std::string sessionid) { MutexAutolock lock(mutex); - if(sessions.find(sessionid) != sessions.end()) - return sessions[sessionid]; + if(sessions.find(sessionid) != sessions.end()) { + Session *s = sessions[sessionid]; + s->lock(); + return s; + } std::string filename = getSessionFilename(Conf::session_path, sessionid); if(fexists(filename)) { SessionSerialiser ser(env, Conf::session_path); Session *s = ser.load(sessionid); sessions[s->id()] = s; + s->lock(); return s; } @@ -311,15 +318,15 @@ std::vector Sessions::activeSessions() return act; } -SessionAutolock::SessionAutolock(Session &s) +SessionAutounlock::SessionAutounlock(Session **s) : session(s) { - session.lock(); + // session->lock(); } -SessionAutolock::~SessionAutolock() +SessionAutounlock::~SessionAutounlock() { - session.unlock(); + if(*session) (*session)->unlock(); } #ifdef TEST_SESSION diff --git a/server/src/session.h b/server/src/session.h index b5c31d7..4d1ed12 100644 --- a/server/src/session.h +++ b/server/src/session.h @@ -95,14 +95,14 @@ public: * Create a new session, with a unique id. Insert it into the session list, * and return its pointer. */ - Session *newSession(std::string patientid, std::string templ) + Session *newLockedSession(std::string patientid, std::string templ) throw(SessionAlreadyActive); /** * Lookup session in session list. Returns the session or NULL if no session * exists with that sessionid. */ - Session *session(std::string sessionid); + Session *lockedSession(std::string sessionid); /** * Remove session from the session list and return its pointer. It is up to @@ -136,13 +136,13 @@ private: Mutex mutex; }; -class SessionAutolock { +class SessionAutounlock { public: - SessionAutolock(Session &session); - ~SessionAutolock(); + SessionAutounlock(Session **session); + ~SessionAutounlock(); private: - Session &session; + Session **session; }; #endif/*__PRACRO_SESSION_H__*/ -- cgit v1.2.3 From cc3e4ba1e4c93ab2198453e04039e57387a79e60 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Tue, 29 Nov 2011 12:19:19 +0100 Subject: remove old debug code. --- client/widgets/window.cc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/client/widgets/window.cc b/client/widgets/window.cc index a305171..b491d44 100644 --- a/client/widgets/window.cc +++ b/client/widgets/window.cc @@ -30,14 +30,9 @@ #include #include -//#define DEBUG(fmt...) printf(fmt) -#define DEBUG(ftm...) - Window::Window(QDomNode &node, MacroWindow *macrowindow) : Widget(node, macrowindow) { - DEBUG("window\n"); - widget = new QWidget(NULL); widget->setWindowFlags(Qt::WindowContextHelpButtonHint | @@ -65,8 +60,6 @@ Window::Window(QDomNode &node, MacroWindow *macrowindow) Window::~Window() { - DEBUG("~window\n"); - //delete widget; } -- cgit v1.2.3 From 4c2626ad56b871cf3b12cdfa786e632b3f29a71e Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Wed, 30 Nov 2011 09:43:09 +0100 Subject: Make sure we don't 'bounce' around when animating to the same height. --- client/collapser.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/client/collapser.cc b/client/collapser.cc index 599397f..a802396 100644 --- a/client/collapser.cc +++ b/client/collapser.cc @@ -110,8 +110,14 @@ void Collapser::anim() placeholder.setWeight(x); - int height = (int)((1 - y) * placeholder.fromHeight() + - y * placeholder.toHeight()); + // Make sure we don't 'bounce' around when animating to the same height. + int height; + if(placeholder.fromHeight() == placeholder.toHeight()) { + height = placeholder.fromHeight(); + } else { + height = (int)((1 - y) * placeholder.fromHeight() + + y * placeholder.toHeight()); + } setFixedHeight(height); -- cgit v1.2.3 From 29c58328af0d9ec8fa77253451e8d4801b372db3 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Wed, 30 Nov 2011 10:54:29 +0100 Subject: Since from to to heights are the same this is a noop, but it seems more correct this way. --- client/collapser.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/collapser.cc b/client/collapser.cc index a802396..2057a0e 100644 --- a/client/collapser.cc +++ b/client/collapser.cc @@ -32,8 +32,8 @@ #include "debug.h" -#define ANIM_TIME 300 // ms -#define ANIM_INTERVAL 5 // ms +#define ANIM_TIME 100 // ms +#define ANIM_INTERVAL 50 // ms Collapser::Collapser(QWidget *current, QScrollArea *scroll) { @@ -113,7 +113,7 @@ void Collapser::anim() // Make sure we don't 'bounce' around when animating to the same height. int height; if(placeholder.fromHeight() == placeholder.toHeight()) { - height = placeholder.fromHeight(); + height = placeholder.toHeight(); } else { height = (int)((1 - y) * placeholder.fromHeight() + y * placeholder.toHeight()); -- cgit v1.2.3 From 094a66765fcb111ede1c1fbd1b540183ff4c130f Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Wed, 30 Nov 2011 10:56:29 +0100 Subject: Make sure the drawer button is focused before the macro is deleted. Otherwise something random will gain focus making the scroll area jump to this random position. --- client/macrowindow.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/macrowindow.cc b/client/macrowindow.cc index 44f2797..2e0f52a 100644 --- a/client/macrowindow.cc +++ b/client/macrowindow.cc @@ -189,11 +189,13 @@ bool MacroWindow::doCommit() void MacroWindow::commit() { doCommit(); + drawer->setFocus(); } void MacroWindow::cancel() { collapseWrapper(); + drawer->setFocus(); } void MacroWindow::expandWrapper() @@ -271,9 +273,9 @@ void MacroWindow::clear() lua->clear(); if(mainwidget) { - delete mainwidget; - mainwidget = NULL; drawer->setFocus(); + mainwidget->deleteLater(); + mainwidget = NULL; } } -- cgit v1.2.3 From 8c4c801cb524611cc12d04955b469dc66fb8e7c8 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Thu, 1 Dec 2011 07:10:58 +0100 Subject: Add test course. --- server/xml/courses/test.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/server/xml/courses/test.xml b/server/xml/courses/test.xml index 4594409..9dabdb9 100644 --- a/server/xml/courses/test.xml +++ b/server/xml/courses/test.xml @@ -1,5 +1,4 @@