/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2018 Melin Software HB
This program 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 3 of the License, or
(at your option) any later version.
This program 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 this program. If not, see .
Melin Software HB - software@melin.nu - www.melin.nu
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
************************************************************************/
// oEvent.cpp: implementation of the oEvent class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include
#include "oEvent.h"
#include "gdioutput.h"
#include "oDataContainer.h"
#include "csvparser.h"
#include "TabAuto.h"
#include "random.h"
#include "SportIdent.h"
#include "meosdb/sqltypes.h"
#include "meosexception.h"
#include "meos_util.h"
#include "meos.h"
#include
typedef bool (__cdecl* OPENDB_FCN)(void);
typedef int (__cdecl* SYNCHRONIZE_FCN)(oBase *obj);
bool oEvent::connectToServer()
{
if (isThreadReconnecting())
return false;
#ifdef BUILD_DB_DLL
if (msOpenDatabase)
return true;
#endif
#ifdef BUILD_DB_DLL
hMod=LoadLibrary("meosdb.dll");
msOpenDatabase = (SYNCHRONIZE_FCN)GetProcAddress(hMod, "msOpenDatabase");
msConnectToServer = (SYNCHRONIZE_FCN)GetProcAddress(hMod, "msConnectToServer");
msSynchronizeUpdate = (SYNCHRONIZE_FCN)GetProcAddress(hMod, "msSynchronizeUpdate");
msSynchronizeRead = (SYNCHRONIZE_FCN)GetProcAddress(hMod, "msSynchronizeRead");
msSynchronizeList = (SYNCHRONIZELIST_FCN)GetProcAddress(hMod, "msSynchronizeList");
msRemove = (SYNCHRONIZE_FCN)GetProcAddress(hMod, "msRemove");
msMonitor = (SYNCHRONIZE_FCN)GetProcAddress(hMod, "msMonitor");
msDropDatabase = (SYNCHRONIZE_FCN)GetProcAddress(hMod, "msDropDatabase");
msUploadRunnerDB = (SYNCHRONIZE_FCN)GetProcAddress(hMod, "msUploadRunnerDB");
msGetErrorState = (ERRORMESG_FCN)GetProcAddress(hMod, "msGetErrorState");
msResetConnection = (OPENDB_FCN)GetProcAddress(hMod, "msResetConnection");
msReConnect = (OPENDB_FCN)GetProcAddress(hMod, "msReConnect");
if (!msOpenDatabase || !msSynchronizeUpdate || !msSynchronizeRead
|| !msConnectToServer || !msReConnect || !msGetErrorState
|| !msMonitor || !msDropDatabase || !msUploadRunnerDB) {
MessageBox(NULL, "Cannot load MySQL library.", NULL, MB_OK);
// handle the error
FreeLibrary(hMod);
hMod=0;
return false;//SOME_ERROR_CODE;
}
#else/*
msOpenDatabase = (SYNCHRONIZE_FCN)::msOpenDatabase;
msConnectToServer = (SYNCHRONIZE_FCN)::msConnectToServer;
msSynchronizeUpdate = (SYNCHRONIZE_FCN)::msSynchronizeUpdate;
msSynchronizeRead = (SYNCHRONIZE_FCN)::msSynchronizeRead;
msSynchronizeList = (SYNCHRONIZELIST_FCN)::msSynchronizeList;
msRemove = (SYNCHRONIZE_FCN)::msRemove;
msMonitor = (SYNCHRONIZE_FCN)::msMonitor;
msDropDatabase = (SYNCHRONIZE_FCN)::msDropDatabase;
msUploadRunnerDB = (SYNCHRONIZE_FCN)::msUploadRunnerDB;
msGetErrorState = (ERRORMESG_FCN)::msGetErrorState;
msResetConnection = (OPENDB_FCN)::msResetConnection;
msReConnect = (OPENDB_FCN)::msReConnect;*/
#endif
return true;
}
void oEvent::startReconnectDaemon()
{
if (isThreadReconnecting())
return;
char bf[256];
msGetErrorState(bf);
MySQLReconnect msqlr(lang.tl("warning:dbproblem#" + string(bf)));
msqlr.interval=5;
HasDBConnection = false;
HasPendingDBConnection = true;
tabAutoAddMachinge(msqlr);
gdibase.setDBErrorState(false);
gdibase.setWindowTitle(oe->getTitleName());
if (!isReadOnly()) {
// Do not show in kiosk-mode
gdibase.alert("warning:dbproblem#" + string(bf));
}
}
bool oEvent::msSynchronize(oBase *ob)
{
//if (!msSynchronizeRead) return true;
if (!HasDBConnection && !HasPendingDBConnection)
return true;
int ret = msSynchronizeRead(ob);
char err[256];
if (msGetErrorState(err))
gdibase.addInfoBox("sqlerror", gdibase.widen(err), 15000);
if (ret==0) {
verifyConnection();
return false;
}
if (typeid(*ob)==typeid(oTeam)) {
static_cast(ob)->apply(false, 0, false);
}
if (ret==1) {
gdibase.RemoveFirstInfoBox("sqlwarning");
gdibase.addInfoBox("sqlwarning", L"Varning: ändringar i X blev överskrivna#" + ob->getInfo(), 5000);
}
return ret!=0;
}
void oEvent::resetChangeStatus(bool onlyChangable)
{
if (HasDBConnection) {
if (!onlyChangable) {
// The object here has no dependeces that makes it necessary to set/rest
for (list::iterator it=oe->punches.begin();
it!=oe->punches.end(); ++it)
it->resetChangeStatus();
//synchronize changed objects
for (list::iterator it=oe->Cards.begin();
it!=oe->Cards.end(); ++it)
it->resetChangeStatus();
for (list::iterator it=oe->Clubs.begin();
it!=oe->Clubs.end(); ++it)
it->resetChangeStatus();
for (list::iterator it=oe->Controls.begin();
it!=oe->Controls.end(); ++it)
it->resetChangeStatus();
for (list::iterator it=oe->Courses.begin();
it!=oe->Courses.end(); ++it)
it->resetChangeStatus();
for (list::iterator it=oe->Classes.begin();
it!=oe->Classes.end(); ++it)
it->resetChangeStatus();
}
for (list::iterator it=oe->Runners.begin();
it!=oe->Runners.end(); ++it)
it->resetChangeStatus();
for (list::iterator it=oe->Teams.begin();
it!=oe->Teams.end(); ++it)
it->resetChangeStatus();
}
}
void oEvent::storeChangeStatus(bool onlyChangable)
{
if (HasDBConnection) {
if (!onlyChangable) {
// The object here has no dependeces that makes it necessary to set/rest
for (list::iterator it=oe->punches.begin();
it!=oe->punches.end(); ++it)
it->storeChangeStatus();
for (list::iterator it=oe->Cards.begin();
it!=oe->Cards.end(); ++it)
it->storeChangeStatus();
for (list::iterator it=oe->Clubs.begin();
it!=oe->Clubs.end(); ++it)
it->storeChangeStatus();
for (list::iterator it=oe->Controls.begin();
it!=oe->Controls.end(); ++it)
it->storeChangeStatus();
for (list::iterator it=oe->Courses.begin();
it!=oe->Courses.end(); ++it)
it->storeChangeStatus();
for (list::iterator it=oe->Classes.begin();
it!=oe->Classes.end(); ++it)
it->storeChangeStatus();
}
for (list::iterator it=oe->Runners.begin();
it!=oe->Runners.end(); ++it)
it->storeChangeStatus();
for (list::iterator it=oe->Teams.begin();
it!=oe->Teams.end(); ++it)
it->storeChangeStatus();
}
}
bool oEvent::synchronizeList(oListId id, bool preSyncEvent, bool postSyncEvent) {
if (!HasDBConnection)
return true;
if (preSyncEvent) {
msSynchronize(this);
resetSQLChanged(true, false);
}
if ( !msSynchronizeList(this, id) ) {
verifyConnection();
return false;
}
if (id == oLPunchId)
advanceInformationPunches.clear();
if (postSyncEvent) {
reinitializeClasses();
reEvaluateChanged();
resetChangeStatus();
return true;
}
return true;
}
bool oEvent::needReEvaluate() {
return sqlChangedRunners |
sqlChangedClasses |
sqlChangedCourses |
sqlChangedControls |
sqlChangedCards |
sqlChangedTeams;
}
void oEvent::resetSQLChanged(bool resetAllTeamsRunners, bool cleanClasses) {
sqlChangedRunners = false;
sqlChangedClasses = false;
sqlChangedCourses = false;
sqlChangedControls = false;
sqlChangedClubs = false;
sqlChangedCards = false;
sqlChangedPunches = false;
sqlChangedTeams = false;
if (resetAllTeamsRunners) {
for (list::iterator it=oe->Runners.begin();
it!=oe->Runners.end(); ++it) {
it->storeChangeStatus();
it->sqlChanged = false;
}
for (list::iterator it=oe->Teams.begin();
it!=oe->Teams.end(); ++it) {
it->storeChangeStatus();
it->sqlChanged = false;
}
}
if (cleanClasses) {
// This data is used to redraw lists/speaker etc.
for (list::iterator it=oe->Classes.begin();
it!=oe->Classes.end(); ++it) {
it->storeChangeStatus();
it->sqlChangedControlLeg.clear();
it->sqlChangedLegControl.clear();
}
globalModification = false;
}
}
bool BaseIsRemoved(const oBase &ob){return ob.isRemoved();}
//Returns true if data is changed.
bool oEvent::autoSynchronizeLists(bool SyncPunches)
{
if (!HasDBConnection)
return false;
bool changed=false;
string ot;
int mask = getListMask(*this);
if (mask == 0)
return false;
// Reset change data and store update status on objects
// (which might be incorrectly changed during sql update)
resetSQLChanged(true, false);
//Synchronize ourself
if (mask & oLEventId) {
ot=sqlUpdated;
msSynchronize(this);
if (sqlUpdated!=ot) {
changed=true;
gdibase.setWindowTitle(getTitleName());
}
}
//Controls
if (mask & oLControlId) {
int oc = sqlCounterControls;
ot = sqlUpdateControls;
synchronizeList(oLControlId, false, false);
changed |= oc!=sqlCounterControls;
changed |= ot!=sqlUpdateControls;
}
//Courses
if (mask & oLCourseId) {
int oc = sqlCounterCourses;
ot = sqlUpdateCourses;
synchronizeList(oLCourseId, false, false);
changed |= oc!=sqlCounterCourses;
changed |= ot!=sqlUpdateCourses;
}
//Classes
if (mask & oLClassId) {
int oc = sqlCounterClasses;
ot = sqlUpdateClasses;
synchronizeList(oLClassId, false, false);
changed |= oc!=sqlCounterClasses;
changed |= ot!=sqlUpdateClasses;
}
//Clubs
if (mask & oLClubId) {
int oc = sqlCounterClubs;
ot = sqlUpdateClubs;
synchronizeList(oLClubId, false, false);
changed |= oc!=sqlCounterClubs;
changed |= ot!=sqlUpdateClubs;
}
//Cards
if (mask & oLCardId) {
int oc = sqlCounterCards;
ot = sqlUpdateCards;
synchronizeList(oLCardId, false, false);
changed |= oc!=sqlCounterCards;
changed |= ot!=sqlUpdateCards;
}
//Runners
if (mask & oLRunnerId) {
int oc = sqlCounterRunners;
ot = sqlUpdateRunners;
synchronizeList(oLRunnerId, false, false);
changed |= oc!=sqlCounterRunners;
changed |= ot!=sqlUpdateRunners;
}
//Teams
if (mask & oLTeamId) {
int oc = sqlCounterTeams;
ot = sqlUpdateTeams;
synchronizeList(oLTeamId, false, false);
changed |= oc!=sqlCounterTeams;
changed |= ot!=sqlUpdateTeams;
}
if (SyncPunches && (mask & oLPunchId)) {
//Punches
int oc = sqlCounterPunches;
ot = sqlUpdatePunches;
synchronizeList(oLPunchId, false, false);
changed |= oc!=sqlCounterPunches;
changed |= ot!=sqlUpdatePunches;
}
if (changed) {
if (needReEvaluate())
reEvaluateChanged();
reCalculateLeaderTimes(0);
//Restore changed staus on object that might have been changed
//during sql update, due to partial updates
resetChangeStatus();
return true;
}
return false;
}
bool oEvent::connectToMySQL(const string &server, const string &user, const string &pwd, int port)
{
if (isThreadReconnecting())
return false;
if (!connectToServer())
return false;
MySQLServer=server;
MySQLPassword=pwd;
MySQLPort=port;
MySQLUser=user;
//Delete non-server competitions.
list saved;
list::iterator it;
for (it=cinfo.begin(); it!=cinfo.end(); ++it) {
if (it->Server.empty())
saved.push_back(*it);
}
cinfo = saved;
if (!msConnectToServer(this)) {
char bf[256];
msGetErrorState(bf);
MessageBox(NULL, lang.tl(bf).c_str(), L"Error", MB_OK);
return false;
}
for (it=cinfo.begin(); it!=cinfo.end(); ++it) {
if (it->Name.size() > 1 && it->Name[0] == '%')
it->Name = lang.tl(it->Name.substr(1));
}
return true;
}
bool oEvent::uploadSynchronize()
{
if (isThreadReconnecting())
throw std::exception("Internt fel i anslutningen. Starta om MeOS");
wstring newId = makeValidFileName(currentNameId, true);
currentNameId = newId;
for (list::iterator it = cinfo.begin(); it != cinfo.end(); ++it) {
if (it->FullPath == currentNameId && it->Server.length()>0) {
gdioutput::AskAnswer ans = gdibase.askCancel(L"ask:overwrite_server");
if (ans == gdioutput::AnswerCancel)
return false;
else if (ans == gdioutput::AnswerNo) {
int len = currentNameId.length();
wchar_t ex[10];
swprintf_s(ex, L"_%05XZ", (GetTickCount()/97) & 0xFFFFF);
if (len > 0) {
if (len< 7 || currentNameId[len-1] != 'Z')
currentNameId += ex;
else {
wchar_t CurrentNameId[64];
wcscpy_s(CurrentNameId, currentNameId.c_str());
wcscpy_s(CurrentNameId + len - 7, 64 - len + 7, ex);
currentNameId = CurrentNameId;
}
}
}
else {
if (!gdibase.ask(L"ask:overwriteconfirm"))
return false;
}
}
}
HasDBConnection=false;
#ifdef BUILD_DB_DLL
if (!msSynchronizeUpdate)
throw std::exception("Internt fel. Starta om MeOS");
#endif
if ( !msOpenDatabase(this) ){
char bf[256];
msGetErrorState(bf);
string error = string("Kunde inte öppna databasen (X).#") + bf;
throw std::exception(error.c_str());
}
if ( !msSynchronizeUpdate(this) ) {
char bf[256];
msGetErrorState(bf);
string error = string("Kunde inte ladda upp tävlingen (X).#") + bf;
throw std::exception(error.c_str());
}
OpFailStatus stat = (OpFailStatus)msUploadRunnerDB(this);
if (stat == opStatusFail) {
char bf[256];
msGetErrorState(bf);
string error = string("Kunde inte ladda upp löpardatabasen (X).#") + bf;
throw meosException(error);
}
else if (stat == opStatusWarning) {
char bf[256];
msGetErrorState(bf);
gdibase.addInfoBox("", wstring(L"Kunde inte ladda upp löpardatabasen (X).#") + gdibase.widen(bf), 5000);
}
HasDBConnection=true;
// Save local version of database
saveRunnerDatabase(currentNameId.c_str(), false);
return true;
}
//Load a (new) competition from the server.
bool oEvent::readSynchronize(const CompetitionInfo &ci)
{
if (ci.Id<=0)
throw std::exception("help:12290");
if (isThreadReconnecting())
return false;
HasDBConnection=false;
#ifdef BUILD_DB_DLL
if (!msConnectToServer)
return false;
#endif
MySQLServer=ci.Server;
MySQLPassword=ci.ServerPassword;
MySQLPort=ci.ServerPort;
MySQLUser=ci.ServerUser;
//Delete non-server competitions.
list saved;
list::iterator it;
for (it=cinfo.begin(); it!=cinfo.end(); ++it) {
if (it->Server.empty())
saved.push_back(*it);
}
cinfo=saved;
if (!msConnectToServer(this)) {
char bf[256];
msGetErrorState(bf);
throw std::exception(bf);
return false;
}
for (it=cinfo.begin(); it!=cinfo.end(); ++it) {
if (it->Name.size() > 1 && it->Name[0] == '%')
it->Name = lang.tl(it->Name.substr(1));
}
newCompetition(L"");
Id=ci.Id;
currentNameId = ci.FullPath;
wchar_t file[260];
swprintf_s(file, L"%s.dbmeos", currentNameId.c_str());
getUserFile(CurrentFile, file);
if ( !msOpenDatabase(this) ) {
char bf[256];
msGetErrorState(bf);
throw std::exception(bf);
}
updateFreeId();
HasDBConnection=false;
openRunnerDatabase(currentNameId.c_str());
int ret = msSynchronizeRead(this);
if (ret == 0) {
char bf[256];
msGetErrorState(bf);
string err = string("Kunde inte öppna tävlingen (X)#") + bf;
throw std::exception(err.c_str());
}
else if (ret == 1) {
// Warning
char bf[256];
msGetErrorState(bf);
wstring info = L"Databasvarning: X#" + lang.tl(bf);
gdibase.addInfoBox("sqlerror", info, 15000);
}
// Cache database locally
saveRunnerDatabase(currentNameId.c_str(), false);
HasDBConnection=true;
// Setup multirunner links
for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it)
it->createMultiRunner(false,false);
// Remove incorrect references
for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) {
if (it->multiRunner.size() > 0 ) {
vector &pr = it->multiRunner;
for (size_t k=0; ktParentRunner != &*it) {
it->multiRunner.clear();
it->updateChanged();
it->synchronize();
break;
}
}
}
}
// Check duplicates
vector usedInTeam(qFreeRunnerId+1);
bool teamCorrected = false;
for (oTeamList::iterator it = Teams.begin(); it != Teams.end(); ++it) {
if (it->correctionNeeded) {
it->updateChanged();
teamCorrected = true;
}
for (size_t i = 0; i < it->Runners.size(); i++) {
pRunner r = it->Runners[i];
if (r != 0) {
int expectedIndex = -1;
if (it->Class)
expectedIndex = it->Class->getLegRunnerIndex(i);
if (expectedIndex>=0 && expectedIndex != r->getMultiIndex()) {
int baseLeg = it->Class->getLegRunner(i);
it->setRunner(baseLeg, r->getMultiRunner(0), true);
teamCorrected = true;
}
}
}
for (size_t i = 0; i < it->Runners.size(); i++) {
pRunner r = it->Runners[i];
if (r != 0) {
if (usedInTeam[r->Id]) {
it->Runners[i] = 0; // Reset duplicate runners
it->updateChanged();
teamCorrected = true;
if (r->tInTeam == &*it)
r->tInTeam = 0;
}
else
usedInTeam[r->Id] = true;
}
}
}
usedInTeam.clear();
if (teamCorrected) {
for (oTeamList::iterator it = Teams.begin(); it != Teams.end(); ++it) {
it->apply(true, 0, false);
}
}
reEvaluateAll(set(), false);
vector out;
checkChanged(out);
assert(out.empty());
for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) {
if (it->correctionNeeded) {
it->createMultiRunner(true, true);
if (it->tInTeam && it->Class) {
pTeam t = it->tInTeam;
int nr = min(int(it->Class->getNumStages())-1, int(it->multiRunner.size()));
t->setRunner(0, &*it, true);
for (int k=0; ksetRunner(k+1, it->multiRunner[k], true);
t->updateChanged();
t->synchronize();
}
it->synchronizeAll();
}
}
return true;
}
bool oEvent::reConnect(char *errorMsg256)
{
if (HasDBConnection)
return true;
if (isThreadReconnecting()){
strcpy_s(errorMsg256, 256, "Synkroniseringsfel.");
return false;
}
#ifdef BUILD_DB_DLL
if (!msReConnect) {
strcpy_s(errorMsg256, 256, "Inte ansluten mot meosdb.dll");
return false;
}
#endif
if (msReConnect()) {
HasDBConnection = true;
HasPendingDBConnection = false;
//synchronize changed objects
for (list::iterator it=oe->Cards.begin();
it!=oe->Cards.end(); ++it)
if (it->isChanged())
it->synchronize(false);
for (list::iterator it=oe->Clubs.begin();
it!=oe->Clubs.end(); ++it)
if (it->isChanged())
it->synchronize(false);
for (list::iterator it=oe->Controls.begin();
it!=oe->Controls.end(); ++it)
if (it->isChanged())
it->synchronize(false);
for (list::iterator it=oe->Courses.begin();
it!=oe->Courses.end(); ++it)
if (it->isChanged())
it->synchronize(false);
for (list::iterator it=oe->Classes.begin();
it!=oe->Classes.end(); ++it)
if (it->isChanged())
it->synchronize(false);
for (list::iterator it=oe->Runners.begin();
it!=oe->Runners.end(); ++it)
if (it->isChanged())
it->synchronize(false);
for (list::iterator it=oe->Teams.begin();
it!=oe->Teams.end(); ++it)
if (it->isChanged())
it->synchronize(false);
for (list::iterator it=oe->punches.begin();
it!=oe->punches.end(); ++it)
if (it->isChanged())
it->synchronize(false);
autoSynchronizeLists(true);
return true;
}
msGetErrorState(errorMsg256);
return false;
}
//Returns number of changed, non-saved elements.
int oEvent::checkChanged(vector &out) const
{
int changed=0;
wchar_t bf[256];
out.clear();
for (list::iterator it=oe->Cards.begin();
it!=oe->Cards.end(); ++it)
if (it->isChanged()) {
changed++;
swprintf_s(bf, L"Card %d", it->cardNo);
out.push_back(bf);
it->synchronize();
}
for (list::iterator it=oe->Clubs.begin();
it!=oe->Clubs.end(); ++it)
if (it->isChanged()) {
changed++;
swprintf_s(bf, L"Club %ws", it->name.c_str());
out.push_back(bf);
it->synchronize();
}
for (list::iterator it=oe->Controls.begin();
it!=oe->Controls.end(); ++it)
if (it->isChanged()) {
changed++;
swprintf_s(bf, L"Control %d", it->Numbers[0]);
out.push_back(bf);
it->synchronize();
}
for (list::iterator it=oe->Courses.begin();
it!=oe->Courses.end(); ++it)
if (it->isChanged()) {
changed++;
swprintf_s(bf, L"Course %s", it->Name.c_str());
out.push_back(bf);
it->synchronize();
}
for (list::iterator it=oe->Classes.begin();
it!=oe->Classes.end(); ++it)
if (it->isChanged()) {
changed++;
swprintf_s(bf, L"Class %s", it->Name.c_str());
out.push_back(bf);
it->synchronize();
}
for (list::iterator it=oe->Runners.begin();
it!=oe->Runners.end(); ++it)
if (it->isChanged()) {
changed++;
swprintf_s(bf, L"Runner %s", it->getName().c_str());
out.push_back(bf);
it->synchronize();
}
for (list::iterator it=oe->Teams.begin();
it!=oe->Teams.end(); ++it)
if (it->isChanged()) {
changed++;
swprintf_s(bf, L"Team %s", it->getName().c_str());
out.push_back(bf);
it->synchronize();
}
for (list::iterator it=oe->punches.begin();
it!=oe->punches.end(); ++it)
if (it->isChanged()) {
changed++;
swprintf_s(bf, L"Punch SI=%d, %d", it->CardNo, it->Type);
out.push_back(bf);
it->synchronize();
}
return changed;
}
bool oEvent::verifyConnection()
{
if (!HasDBConnection)
return false;
if (isThreadReconnecting())
return false;
#ifdef BUILD_DB_DLL
if (!msMonitor)
return false;
#endif
if (!msMonitor(this)) {
startReconnectDaemon();
return false;
}
return true;
}
const string &oEvent::getServerName() const
{
return serverName;
}
void oEvent::closeDBConnection()
{
bool hadDB=HasDBConnection;
if (isThreadReconnecting()) {
//Don't know what to do?!
}
gdibase.setWaitCursor(true);
if (HasDBConnection) {
autoSynchronizeLists(true);
}
HasDBConnection=false;
#ifdef BUILD_DB_DLL
if (msResetConnection)
msResetConnection();
#else
msResetConnection();
#endif
Id=0;
if (!oe->empty() && hadDB) {
save();
Name+=L" (Lokal kopia från: " + gdibase.widen(serverName) + L")";
wstring cn = currentNameId + L"." + gdibase.widen(serverName) + L".meos";
getUserFile(CurrentFile, cn.c_str());
serverName.clear();
save();
gdibase.setWindowTitle(Name);
}
else serverName.clear();
gdibase.setWaitCursor(false);
}
void oEvent::listConnectedClients(gdioutput &gdi)
{
gdi.addString("", 1, "Anslutna klienter:");
char bf[256];
gdi.fillRight();
gdi.pushX();
int x=gdi.getCX();
for (size_t k=0;k0)
throw std::exception(bf);
throw std::exception("Operationen misslyckades. Orsak okänd.");
}
clear();
}