YATISH
Yet Another TIme SHeet
/home/nicolas/sources/yatish/yatishDBsqlite.cpp
Go to the documentation of this file.
1 /***************************************************************
2  * Name: yatishDBsqlite.cpp
3  * Purpose: Code for the sqlite controller
4  * Author: Nicolas PĂ©renne (nicolas.perenne@eif-services.eu)
5  * Created: 2020-03-09
6  * Copyright: EIF-services (https://www.eif-services.eu)
7  * License: GPLv3
8  **************************************************************/
9 
10 #include "wx_pch.h"
11 #include "yatishDBsqlite.h"
12 
18  filter = wxEmptyString;
19  limitRow = false; rowLimit = 100;
20  wxASSERT_MSG (masterDB == nullptr, "There can be only one instance of yatishDBsqlite.");
21 #ifdef NDEBUG
22  wxString databasePath = wxStandardPaths::Get().GetUserLocalDataDir() + wxFILE_SEP_PATH + "yatish.sqlite";
23  databasePath.Replace ("\\", "\\\\" ); // need to escape (Windows) anti-slashes
24 #else
25  wxString databasePath = "yatish.sqlite";
26 #endif
27  masterDB = GetDatabase ("[SQLite]\ndatabase=" + databasePath);
28  if (!masterDB) {
29  wxMessageBox (_("You are probably using Yatish for the first time...\n"
30  "Please ignore error messages and read\n"
31  "\"Getting started\" in the User guide (F1)"),
32  _("Startup procedure completed?"), wxOK);
33  return;
34  }
35  try {
36  if (masterDB->GetTypeName() != "SQLITE")
37  throw ( wxDatabaseException (-4, _("Master DB must be SQLite") ) );
38  if ( !TablesOk (masterDB) )
39  throw ( wxDatabaseException (-5, _("Yatish tables not found (SQLite)") ) );
40  masterDB->RunQuery ("PRAGMA foreign_keys = ON;");
41  }
42  catch (wxDatabaseException& e) {
43  wxLogError ( "[%d] %s", e.GetErrorCode(), e.GetErrorMessage() );
44  masterDB->Close();
45  delete masterDB;
46  masterDB = nullptr;
47  }
48 }
49 
51  if (!masterDB) return;
52  StopTimeslot(); // in case yatish is closed before stop button is pressed
53  masterDB->Close();
54  delete masterDB;
55 }
56 
63 bool yatishDBsqlite::FillChoice (wxChoice * choices, tableID tid) {
64  if (!masterDB) return false;
65  wxArrayLong * ids;
66  wxString sql ("SELECT id,name FROM yatish_");
67  switch (tid) {
68  case client_tid:
69  sql += "client WHERE sync <> 'D' ORDER BY name;";
70  ids = &clientIDs;
71  break;
72  case project_tid:
73  sql += "project WHERE sync <> 'D' ORDER BY name;";
74  ids = &projectIDs;
75  break;
76  case task_tid:
77  sql += "task WHERE sync <> 'D' ORDER BY name;";
78  ids = &taskIDs;
79  break;
80  case tool_tid:
81  sql += "tool WHERE sync <> 'D' ORDER BY name;";
82  ids = &toolIDs;
83  break;
84  default:
85  return false;
86  }
87  ids->Empty();
88  choices->Clear();
89  try {
90  wxDatabaseResultSet * results = masterDB->RunQueryWithResults (sql);
91  while ( results->Next() ) {
92  ids->Add ( results->GetResultLong (1) );
93  choices->Append ( results->GetResultString (2) );
94  }
95  masterDB->CloseResultSet (results);
96  }
97  CATCH (false)
98  ids->Shrink();
99  return true;
100 }
101 
110  if (!masterDB) return wxNOT_FOUND;
111  wxArrayLong * ids;
112  tableID refering_tid;
113  switch (tid) {
114  case client_tid:
115  ids = &clientIDs;
116  refering_tid = project_tid;
117  break;
118  case project_tid:
119  ids = &projectIDs;
120  refering_tid = activity_tid;
121  break;
122  case task_tid:
123  ids = &taskIDs;
124  refering_tid = activity_tid;
125  break;
126  case tool_tid:
127  ids = &toolIDs;
128  refering_tid = activity_tid;
129  break;
130  default:
131  return wxNOT_FOUND;
132  }
133  long refered_id;
134  try {
135  wxString sql;
136  sql.Printf ("SELECT %s_id FROM yatish_%s WHERE id = %ld;",
137  tableName[tid], tableName[refering_tid], id);
138  refered_id = masterDB->GetSingleResultLong (sql, 1);
139  }
140  CATCH (wxNOT_FOUND)
141  return ids->Index (refered_id);
142 }
143 
149 bool yatishDBsqlite::StartTimeslot (int project, int task, int tool) {
150  if (!masterDB) return false;
151  int projectID = projectIDs[project],
152  taskID = taskIDs[task],
153  toolID = toolIDs[tool];
154  wxString sql;
155  sql.Printf ("SELECT id FROM yatish_activity"
156  " WHERE project_id = %d AND task_id = %d AND tool_id = %d;",
157  projectID, taskID, toolID);
158  try {
159  wxDatabaseResultSet * results = masterDB->RunQueryWithResults (sql);
160  if ( !results->Next() ) {
161  wxString sql2;
162  sql2.Printf ("INSERT INTO yatish_activity (project_id,task_id,tool_id,sync)"
163  " VALUES (%d,%d,%d,'I');",
164  projectID, taskID, toolID);
165  masterDB->CloseResultSet (results);
166  masterDB->RunQuery (sql2);
167  results = masterDB->RunQueryWithResults (sql);
168  results->Next();
169  }
170  long activityID = results->GetResultLong (1);
171  masterDB->CloseResultSet (results);
172  sql.Printf ("INSERT INTO yatish_timeslot (start,activity_id,sync)"
173  " VALUES (datetime('now'),%ld,'I');", activityID); // datetime('now'): SQLite specific (UTC)
174  masterDB->RunQuery (sql);
175  results = masterDB->RunQueryWithResults ("SELECT id FROM yatish_timeslot WHERE stop IS NULL;");
176  results->Next(); // there should be one and only one...
177  currentTimeslotID = results->GetResultLong (1);
178  masterDB->CloseResultSet (results);
179  }
180  CATCH (false)
181  return true;
182 }
183 
188  if (!masterDB) return false;
189  try {
190  wxString sql;
191  sql.Printf ("UPDATE yatish_timeslot SET stop=datetime('now')"
192  " WHERE id = %ld AND stop IS NULL;", currentTimeslotID);
193  masterDB->RunQuery (sql);
194  }
195  CATCH (false)
196  return true;
197 }
198 
203  if (!masterDB) return -1;
204  int n;
205  try {
206  wxString sql ("SELECT id,COUNT(*) FROM yatish_timeslot WHERE stop IS NULL;");
207  currentTimeslotID = masterDB->GetSingleResultLong (sql, 1);
208  n = masterDB->GetSingleResultInt (sql, 2);
209  }
210  CATCH (-1)
211  return n;
212 }
213 
220 bool yatishDBsqlite::FillList (wxListCtrl * lst, tableID tid) {
221  if (!masterDB) return false;
222  int colmin, colmax = lst->GetColumnCount();
223  wxString sql ("SELECT ");
224  switch (tid) {
225  case client_tid:
226  if (colmax != 1) return false;
227  sql += "id,name FROM yatish_client WHERE sync <> 'D';";
228  break;
229  case project_tid:
230  if (colmax != 2) return false;
231  sql += "p.id,p.name,c.name FROM yatish_project AS p"
232  " INNER JOIN yatish_client AS c ON p.client_id = c.id"
233  " WHERE p.sync <> 'D'";
234  sql += filter;
235  sql += ";";
236  break;
237  case task_tid:
238  if (colmax != 1) return false;
239  sql += "id,name FROM yatish_task WHERE sync <> 'D';";
240  break;
241  case tool_tid:
242  if (colmax != 1) return false;
243  sql += "id,name FROM yatish_tool WHERE sync <> 'D';";
244  break;
245  case activity_tid:
246  if (colmax != 4) return false;
247  sql += "a.id,p.name,c.name,tk.name,tl.name"
248  " FROM (((yatish_activity AS a"
249  " INNER JOIN yatish_project AS p ON a.project_id = p.id)"
250  " INNER JOIN yatish_client AS c ON p.client_id = c.id)"
251  " INNER JOIN yatish_task AS tk ON a.task_id = tk.id)"
252  " INNER JOIN yatish_tool AS tl ON a.tool_id = tl.id"
253  " WHERE a.sync <> 'D'";
254  sql += filter;
255  sql += ";";
256  break;
257  case timeslot_tid:
258  if (colmax != 6) return false;
259  sql.Printf ("SELECT t.id,t.start,t.stop,p.name,c.name,tk.name,tl.name"
260  " FROM ((((yatish_timeslot AS t"
261  " INNER JOIN yatish_activity AS a ON t.activity_id = a.id)"
262  " INNER JOIN yatish_project AS p ON a.project_id = p.id)"
263  " INNER JOIN yatish_client AS c ON p.client_id = c.id)"
264  " INNER JOIN yatish_task AS tk ON a.task_id = tk.id)"
265  " INNER JOIN yatish_tool AS tl ON a.tool_id = tl.id"
266  " WHERE t.sync <> 'D' AND t.start BETWEEN '%s' AND '%s'"
267  , firstDay, lastDay);
268  sql += filter;
269  if (limitRow)
270  sql += wxString::Format (" ORDER BY t.id DESC LIMIT %d;", rowLimit);
271  else
272  sql += " ORDER BY t.id DESC;";
273  break;
274  default:
275  return false;
276  }
277  // { for timeslot_tid only...
278  wxTimeSpan span;
279  slotCount = 0;
280  totalSpan = wxTimeSpan::Hours (0);
281  // }
282  try {
283  wxDatabaseResultSet * results = masterDB->RunQueryWithResults (sql);
284  long row = 0,
285  row_index; // appears to be necessary...
286  while ( results->Next() ) {
287  if (tid == timeslot_tid) {
288  wxDateTime start = results->GetResultDate (2), stop = results->GetResultDate (3);
289  start.MakeFromUTC();
290  // update first item of the row
291  row_index = lst->InsertItem ( row++, start.FormatISODate() );
292  if ( stop.IsValid() ) {
293  stop.MakeFromUTC();
294  span = stop - start;
295  slotCount++; totalSpan += span;
296  // update second item of the row
297  lst->SetItem ( row_index, 1, span.Format ("%H:%M:%S") );
298  }
299  colmin = 2;
300  } else {
301  // update first item of the row
302  row_index = lst->InsertItem ( row++, results->GetResultString (2) );
303  colmin = 1;
304  }
305  // update remaining items
306  for (int col = colmin; col < colmax; col++)
307  // +1 because wxDatabase indexes are 1-based, and +1 to skip the id
308  lst->SetItem ( row_index, col, results->GetResultString (col + 2) );
309  // store the SQL id of the row (which is not the row index)
310  lst->SetItemData ( row_index, results->GetResultLong (1) );
311  }
312  masterDB->CloseResultSet (results);
313  }
314  CATCH (false)
315  return true;
316 }
317 
322 void yatishDBsqlite::AddToFilter (tableID tid, int choice) {
323  wxString sqlAnd;
324  switch (tid) {
325  case client_tid:
326  sqlAnd.Printf (" AND c.id = %ld", clientIDs[choice]);
327  break;
328  case project_tid:
329  sqlAnd.Printf (" AND p.id = %ld", projectIDs[choice]);
330  break;
331  case task_tid:
332  sqlAnd.Printf (" AND tk.id = %ld", taskIDs[choice]);
333  break;
334  case tool_tid:
335  sqlAnd.Printf (" AND tl.id = %ld", toolIDs[choice]);
336  break;
337  default:
338  return;
339  }
340  filter += sqlAnd;
341 }
342 
349  if (!slotCount) return wxEmptyString;
350  unsigned long totalSeconds = totalSpan.GetSeconds().ToLong();
351  double totalDays, averageHours;
352  totalDays = totalSeconds / 3600.; // hours still...
353  averageHours = totalDays / slotCount;
354  totalDays /= 7.; // ...nowadays!
355  return wxString::Format(_("SUM: %.1f days | AVG: %.1f hours (x%ld)"),
356  totalDays, averageHours, slotCount);
357 }
358 
363 void yatishDBsqlite::SetFirstDay (const wxDateTime& dt) {
364  firstDay = dt.ToUTC().FormatISOCombined();
365 }
366 
371 void yatishDBsqlite::SetLastDay (const wxDateTime& dt) {
372  lastDay = dt.ToUTC().FormatISOCombined();
373 }
374 
379 wxDateTime yatishDBsqlite::First () {
380  wxDateTime dt = wxDateTime::Now();
381  if (!masterDB) return dt;
382  wxString ans;
383  try {
384  wxString sql ("SELECT MIN(start) FROM ((((yatish_timeslot AS t"
385  " INNER JOIN yatish_activity AS a ON t.activity_id = a.id)"
386  " INNER JOIN yatish_project AS p ON a.project_id = p.id)"
387  " INNER JOIN yatish_client AS c ON p.client_id = c.id)"
388  " INNER JOIN yatish_task AS tk ON a.task_id = tk.id)"
389  " INNER JOIN yatish_tool AS tl ON a.tool_id = tl.id"
390  " WHERE t.sync <> 'D'");
391  sql += filter;
392  sql += ";";
393  ans = masterDB->GetSingleResultString (sql, 1);
394  }
395  CATCH (dt)
396  dt.ParseISOCombined (ans, ' ');
397  return dt.MakeFromUTC();
398 }
399 
404 wxDateTime yatishDBsqlite::Last () {
405  wxDateTime dt = wxDateTime::Now();
406  if (!masterDB) return dt;
407  wxString ans;
408  try {
409  wxString sql ("SELECT MAX(start) FROM ((((yatish_timeslot AS t"
410  " INNER JOIN yatish_activity AS a ON t.activity_id = a.id)"
411  " INNER JOIN yatish_project AS p ON a.project_id = p.id)"
412  " INNER JOIN yatish_client AS c ON p.client_id = c.id)"
413  " INNER JOIN yatish_task AS tk ON a.task_id = tk.id)"
414  " INNER JOIN yatish_tool AS tl ON a.tool_id = tl.id"
415  " WHERE t.sync <> 'D'");
416  sql += filter;
417  sql += ";";
418  ans = masterDB->GetSingleResultString (sql, 1);
419  }
420  CATCH (dt)
421  dt.ParseISOCombined (ans, ' ');
422  return dt.MakeFromUTC();
423 }
424 
429  long id = wxNOT_FOUND;
430  if (!masterDB) return id;
431  try {
432  wxString sql ("SELECT activity_id FROM yatish_timeslot ORDER BY start DESC LIMIT 1;");
433  wxDatabaseResultSet * results = masterDB->RunQueryWithResults (sql);
434  if ( results->Next() ) id = results->GetResultLong (1);
435  masterDB->CloseResultSet (results);
436  }
437  CATCH (id)
438  return id;
439 }
440 
445 long yatishDBsqlite::Activity (long id) {
446  long rid = wxNOT_FOUND;
447  if (!masterDB) return rid;
448  try {
449  wxString sql = wxString::Format("SELECT activity_id FROM yatish_timeslot WHERE id=%ld;", id);
450  rid = masterDB->GetSingleResultLong (sql, 1);
451  }
452  CATCH (rid)
453  return rid;
454 }
455 
462 bool yatishDBsqlite::Delete (tableID tid, long id) {
463  if (!masterDB) return false;
464  if ( tid != timeslot_tid &&
465  wxMessageBox ( _("Owing to foreign key constraints\nin the Yatish database,"
466  "\nrecords refering to this item\nwill also be deleted."),
467  _("Confirm deletion"),
468  wxICON_EXCLAMATION|wxOK|wxCANCEL|wxCANCEL_DEFAULT )
469  == wxCANCEL ) return false;
470  wxString sql, status;
471  try {
472  sql.Printf ("SELECT sync FROM yatish_%s WHERE id = %ld;", tableName[tid], id);
473  status = masterDB->GetSingleResultString(sql, 1);
474  }
475  CATCH (false)
476  if (status == 'I')
477  sql.Printf ("DELETE FROM yatish_%s WHERE id = %ld;", tableName[tid], id);
478  else
479  sql.Printf ("UPDATE yatish_%s SET sync='D' WHERE id = %ld;", tableName[tid], id);
480  try {
481  masterDB->RunQuery (sql);
482  }
483  CATCH (false)
484  return true;
485 }
486 
492 wxString yatishDBsqlite::ReadName (tableID tid, long id) {
493  if (!masterDB) return "";
494  try {
495  wxString sql;
496  sql.Printf ("SELECT name FROM yatish_%s WHERE id = %ld;", tableName[tid], id);
497  return masterDB->GetSingleResultString (sql, 1);
498  }
499  CATCH ("")
500 }
501 
520 bool yatishDBsqlite::ReadDates (long id, wxDateTime& dt1, wxDateTime& dt2) {
521  if (!masterDB) return false;
522  try {
523  wxString sql;
524  sql.Printf ("SELECT start,stop FROM yatish_timeslot WHERE id = %ld;", id);
525  wxDatabaseResultSet * results = masterDB->RunQueryWithResults (sql);
526  if ( !results->Next() ) {
527  masterDB->CloseResultSet (results);
528  return false;
529  }
530  dt1 = results->GetResultDate (1); dt2 = results->GetResultDate (2);
531  masterDB->CloseResultSet (results);
532  }
533  CATCH (false)
534  dt1.MakeFromUTC();
535  if ( !dt2.IsValid() ) return false;
536  dt2.MakeFromUTC();
537  return true;
538 }
539 
546 bool yatishDBsqlite::RecordName (tableID tid, long id, const wxString& str) {
547  if (!masterDB) return false;
548  if (tid == project_tid || tid == activity_tid || tid == timeslot_tid) return false;
549  try {
550  wxString sql, tbl = tableName[tid], sync;
551  if (id == wxNOT_FOUND)
552  sql.Printf ("INSERT INTO yatish_%s (name,sync) VALUES ('%s','I');", tbl, str);
553  else {
554  sql.Printf ("SELECT sync FROM yatish_%s WHERE id = %ld", tbl, id);
555  sync = masterDB->GetSingleResultString (sql, 1);
556  if (sync == 'I') // don't switch to 'U' state before it is synchronized
557  sql.Printf ("UPDATE yatish_%s SET name='%s'"
558  " WHERE id = %ld;", tbl, str, id);
559  else
560  sql.Printf ("UPDATE yatish_%s SET name='%s',sync='U'"
561  "WHERE id = %ld;", tbl, str, id);
562  }
563  masterDB->RunQuery (sql);
564  }
565  CATCH (false)
566  return true;
567 }
568 
575 bool yatishDBsqlite::RecordProject (long id, const wxString& str, int client_choice) {
576  if (!masterDB) return false;
577  try {
578  wxString sql, sync;
579  int clientID = clientIDs[client_choice];
580  if (id == wxNOT_FOUND)
581  sql.Printf ("INSERT INTO yatish_project (name,client_id,sync) VALUES ('%s',%d,'I');",
582  str, clientID);
583  else {
584  sql.Printf ("SELECT sync FROM yatish_project WHERE id = %ld", id);
585  sync = masterDB->GetSingleResultString (sql, 1);
586  if (sync == 'I') // don't switch to 'U' state before it is synchronized
587  sql.Printf ("UPDATE yatish_project SET name='%s',client_id=%d"
588  " WHERE id = %ld;", str, clientID, id);
589  else
590  sql.Printf ("UPDATE yatish_project SET name='%s',client_id=%d,sync='U'"
591  " WHERE id = %ld;", str, clientID, id);
592  }
593  masterDB->RunQuery (sql);
594  }
595  CATCH (false)
596  return true;
597 }
598 
604 bool yatishDBsqlite::RecordActivity (long id, int project, int task, int tool) {
605  if (!masterDB) return false;
606  try {
607  wxString sql, sync;
608  int projectID = projectIDs[project],
609  taskID = taskIDs[task],
610  toolID = toolIDs[tool];
611  if (id == wxNOT_FOUND)
612  sql.Printf ("INSERT INTO yatish_activity (project_id,task_id,tool_id,sync)"
613  " VALUES (%d,%d,%d,'I');", projectID, taskID, toolID);
614  else {
615  sql.Printf ("SELECT sync FROM yatish_activity WHERE id = %ld", id);
616  sync = masterDB->GetSingleResultString (sql, 1);
617  if (sync == 'I') // don't switch to 'U' state before it is synchronized
618  sql.Printf ("UPDATE yatish_activity SET project_id=%d,task_id=%d,tool_id=%d"
619  " WHERE id = %ld;", projectID, taskID, toolID, id);
620  else
621  sql.Printf ("UPDATE yatish_activity SET project_id=%d,task_id=%d,tool_id=%d,sync='U'"
622  " WHERE id = %ld;", projectID, taskID, toolID, id);
623  }
624  masterDB->RunQuery (sql);
625  }
626  CATCH (false)
627  return true;
628 }
629 
639  const wxDateTime& dt1, const wxDateTime& dt2,
640  int project, int task, int tool) {
641  if (!masterDB) return false;
642  wxString start = dt1.ToUTC().FormatISOCombined(' ');
643  wxString stop = dt2.ToUTC().FormatISOCombined(' ');
644  int projectID = projectIDs[project],
645  taskID = taskIDs[task],
646  toolID = toolIDs[tool];
647  wxString sql, sync;
648  sql.Printf ("SELECT id FROM yatish_activity"
649  " WHERE project_id = %d AND task_id = %d AND tool_id = %d;",
650  projectID, taskID, toolID);
651  try {
652  wxDatabaseResultSet * results = masterDB->RunQueryWithResults (sql);
653  if ( !results->Next() ) {
654  wxString sql2;
655  sql2.Printf ("INSERT INTO yatish_activity (project_id,task_id,tool_id,sync)"
656  " VALUES (%d,%d,%d,'I');",
657  projectID, taskID, toolID);
658  masterDB->CloseResultSet (results);
659  masterDB->RunQuery (sql2);
660  results = masterDB->RunQueryWithResults (sql);
661  results->Next();
662  }
663  long activityID = results->GetResultLong (1);
664  masterDB->CloseResultSet (results);
665  if (id == wxNOT_FOUND)
666  sql.Printf ("INSERT INTO yatish_timeslot (start,stop,activity_id,sync)"
667  " VALUES ('%s','%s',%ld,'I');", start, stop, activityID);
668  else {
669  sql.Printf ("SELECT sync FROM yatish_timeslot WHERE id = %ld", id);
670  sync = masterDB->GetSingleResultString (sql, 1);
671  if (sync == 'I') // don't switch to 'U' state before it is synchronized
672  sql.Printf ("UPDATE yatish_timeslot SET start='%s',stop='%s',activity_id=%ld"
673  " WHERE id = %ld;", start, stop, activityID, id);
674  else
675  sql.Printf ("UPDATE yatish_timeslot SET start='%s',stop='%s',activity_id=%ld,sync='U'"
676  " WHERE id = %ld;", start, stop, activityID, id);
677  }
678  masterDB->RunQuery (sql);
679  }
680  CATCH (false)
681  return true;
682 }
bool StopTimeslot()
Stops current timeslot.
long Activity(long)
Reads the activity_id in a record of yatish_timeslot.
wxDateTime First()
Obtains the minimum time in column start from currently selected rows of table yatish_timeslot.
int RunningTimeslots()
Determines the number n of unfinished timeslots.
wxString firstDay
wxString lastDay
void SetLastDay(const wxDateTime &)
Sets private member lastDay (for future SQL queries).
wxArrayLong clientIDs
long LastActivity()
Reads the last activity_id in yatish_timeslot.
wxDatabase * GetDatabase(const wxString &)
Sets up a (configuration) flux using its argument then calls wxDatabase::GetDatabase().
Definition: yatishDB.cpp:47
bool ReadDates(long, wxDateTime &, wxDateTime &)
Reads the start and stop fields of a yatish_timeslot record.
static wxDatabase * masterDB
Definition: yatishDB.h:53
bool RecordActivity(long, int, int, int)
Modifies or creates a record in the yatish_activity table.
void AddToFilter(tableID, int)
Add a condition to the WHERE clause of FillList().
yatishDBsqlite()
Mainly connects to the yatish.sqlite database.
wxString FilteredTotal()
Writes the total and average durations of currently viewed timeslots.
bool StartTimeslot(int, int, int)
Starts a new row in the timeslot table.
wxArrayLong toolIDs
void SetFirstDay(const wxDateTime &)
Sets private member firstDay (for future SQL queries).
bool Delete(tableID, long)
Marks a local record for deletion.
bool RecordTimeslot(long, const wxDateTime &, const wxDateTime &, int, int, int)
Modifies or creates a record in the yatish_timeslot table.
tableID
Definition: yatishDB.h:20
int ChoiceSelector(tableID, long)
Finds the proper index for selection in a wxChoice.
bool TablesOk(wxDatabase *)
Returns false if any of the yatish table is missings.
Definition: yatishDB.cpp:82
#define CATCH(returnValue)
Definition: yatishDB.h:29
bool RecordProject(long, const wxString &, int)
Modifies or creates a record in the yatish_project table.
bool FillList(wxListCtrl *, tableID)
Fills a wxListCtrl.
bool RecordName(tableID, long, const wxString &)
Modifies or creates a record with only one field (called name).
wxArrayLong taskIDs
wxArrayLong projectIDs
wxDateTime Last()
Obtains the maximum time in column start from currently selected rows of table yatish_timeslot.
wxTimeSpan totalSpan
bool FillChoice(wxChoice *, tableID)
Fills a wxChoice.
wxString ReadName(tableID, long)
Reads a wxString from the name column.
static const char * tableName[]
Must be defined in the same order as enum tableID.
Definition: yatishDB.h:51