cxMempoolFree(mp);
- note_store_reload();
+ if(note_store_reload()) {
+ fprintf(stderr, "Error: note_store_reload failed\n");
+ exit(1);
+ }
ui_window_default_size(1600, 1200);
window_create();
#include "types.h"
#include "store_sqlite.h"
-#include "../dbutils/dbutils/db.h"
-#include "../dbutils/dbutils/sqlite.h"
-#include "cx/mempool.h"
+#include <dbutils/dbutils/sqlite.h>
+#include <cx/mempool.h>
#define SQL_REPOSITORY_GET_ALL "select * from repositories;"
return usersettings;
}
+DBUConnection* note_store_get_connection() {
+ return connection;
+}
+
void close_note_store() {
dbuConnectionFree(connection);
connection = NULL;
if(settings->host && host && strcmp(settings->host, host)) {
return 0;
}
- if(settings->user && host && strcmp(settings->user, user)) {
+ if(settings->user && user && strcmp(settings->user, user)) {
return 0;
}
if(settings->profile_name && profile && strcmp(settings->profile_name, profile)) {
* Reloads the NoteStore structure. The previous NoteStore* pointer will be
* invalid after this call
*/
-void note_store_reload() {
+int note_store_reload() {
// load notebook/collection structure
CxMempool *mp = cxMempoolCreateSimple(64);
const CxAllocator *a = mp->allocator;
if(!collections) {
fprintf(stderr, "Error: cannot query note store\n");
cxMempoolFree(mp);
- return;
+ return 1;
}
// NoteStore root object
}
current_store = store;
+
+ return 0;
}
NoteStore* note_store_get() {
#include "types.h"
#include <cx/list.h>
#include <cx/mempool.h>
+#include <dbutils/dbutils/db.h>
#ifdef __cplusplus
extern "C" {
CxList* note_store_get_user_settings(const CxAllocator *a, const char *host, const char *user, const char *profile);
+DBUConnection* note_store_get_connection();
+
void close_note_store();
int user_settings_is_valid(
int note_store_create_default(const char *host, const char *user);
-void note_store_reload();
+int note_store_reload();
NoteStore* note_store_get();
#include "../store.h"
+#include <dbutils/dbutils/db.h>
+#include <dbutils/dbutils/sqlite.h>
+
+static int64_t test_root_resource_id;
+static int64_t test_repository_id;
+static bool test_store_initialized = FALSE;
+
CX_TEST(test_init_note_store) {
CX_TEST_DO {
int ret = init_note_store();
// the database
int ret2 = init_note_store();
CX_TEST_ASSERT(ret2 == 0);
+
+ DBUConnection *conn = note_store_get_connection();
+ CX_TEST_ASSERT(conn);
+ }
+}
+
+CX_TEST(test_note_store_create_default) {
+ CX_TEST_DO {
+ DBUConnection *conn = note_store_get_connection();
+ CX_TEST_ASSERT(conn);
+
+ int ret = note_store_create_default("testhost", "testuser");
+ CX_TEST_ASSERT(ret == 0);
+
+ DBUResult *result = dbuSqlExec(conn, NULL,
+ "select r.repository_id, c.resource_id from user_settings u "
+ "inner join repositories r on u.default_repository_id = r.repository_id "
+ "inner join resources c on u.default_collection_id = c.resource_id "
+ "where host = 'testhost' and user = 'testuser';");
+ CX_TEST_ASSERT(result);
+
+ CX_TEST_ASSERT(dbuResultHasData(result));
+ test_repository_id = dbuResultGetInt(result, 0);
+ test_root_resource_id = dbuResultGetInt(result, 1);
+
+ dbuResultNextRow(result);
+ CX_TEST_ASSERT(!dbuResultHasData(result)); // result should only have 1 row
+
+ dbuResultFree(result);
+
+ note_store_set_settings("testhost", "testuser", "default", test_repository_id, test_root_resource_id);
+
+ test_store_initialized = TRUE;
+ }
+}
+
+CX_TEST(test_user_settings_is_valid) {
+ CX_TEST_DO {
+ UserSettings settings1;
+ settings1.host = "testhost";
+ settings1.user = "testuser";
+ settings1.profile_name = "default";
+
+ CX_TEST_ASSERT(user_settings_is_valid(&settings1, "testhost", "testuser", "default"));
+ CX_TEST_ASSERT(user_settings_is_valid(&settings1, "testhost", "testuser", NULL));
+ CX_TEST_ASSERT(user_settings_is_valid(&settings1, "testhost", NULL, "default"));
+ CX_TEST_ASSERT(user_settings_is_valid(&settings1, NULL, "testuser", "default"));
+ CX_TEST_ASSERT(user_settings_is_valid(&settings1, NULL, NULL, NULL));
+
+ UserSettings settings2;
+ settings2.host = NULL;
+ settings2.user = NULL;
+ settings2.profile_name = NULL;
+
+ CX_TEST_ASSERT(user_settings_is_valid(&settings2, "testhost", "testuser", "default"));
+ CX_TEST_ASSERT(user_settings_is_valid(&settings2, "testhost", "testuser", NULL));
+ CX_TEST_ASSERT(user_settings_is_valid(&settings2, "testhost", NULL, "default"));
+ CX_TEST_ASSERT(user_settings_is_valid(&settings2, NULL, "testuser", "default"));
+ CX_TEST_ASSERT(user_settings_is_valid(&settings2, NULL, NULL, NULL));
+
+ // invalid settings
+
+ UserSettings invalid1;
+ invalid1.host = "testhost2";
+ invalid1.user = "root";
+ invalid1.profile_name = "test";
+
+ CX_TEST_ASSERT(!user_settings_is_valid(&invalid1, "testhost", "root", "test"));
+ CX_TEST_ASSERT(!user_settings_is_valid(&invalid1, "testhost2", "testuser", "test"));
+ CX_TEST_ASSERT(!user_settings_is_valid(&invalid1, "testhost2", "root", "default"));
+ }
+}
+
+
+CX_TEST(test_note_store_reload) {
+ CX_TEST_DO {
+ CX_TEST_ASSERT(!note_store_reload());
+ NoteStore *store = note_store_get();
+ CX_TEST_ASSERT(store);
+ CX_TEST_ASSERT(store->mp);
+ CX_TEST_ASSERT(store->root);
+ CX_TEST_ASSERT(store->repositories);
+
+ CX_TEST_ASSERT(store->root->children);
+ CX_TEST_ASSERT(cxListSize(store->root->children) > 0); // there should be some default groups/notebooks
}
}
+
#endif
CX_TEST(test_init_note_store);
+CX_TEST(test_note_store_create_default);
+CX_TEST(test_user_settings_is_valid);
+
+CX_TEST(test_note_store_reload);
+
#ifdef __cplusplus
#include "test-editor.h"
#include "test-store.h"
+#include "../types.h"
+
int main(int argc, char **argv) {
struct stat s;
if(!stat("notetestdata", &s)) {
ui_setappdir("notetestdata");
ui_init(NULL, 0, NULL);
+ register_types();
CxTestSuite *suite = cx_test_suite_new("note");
cx_test_register(suite, test_init_note_store);
+ cx_test_register(suite, test_note_store_create_default);
+ cx_test_register(suite, test_user_settings_is_valid);
+ cx_test_register(suite, test_note_store_reload);
cx_test_register(suite, test_parse_markdown_para);
cx_test_register(suite, test_parse_markdown_formatting_simple);
if(result->optional_getInt) {
return result->optional_getInt(result, field);
} else {
- cxstring s = result->getText(result, 0);
+ cxstring s = result->getText(result, field);
int64_t value = 0;
cx_strtoi64(s, &value, 10);
return value;
@end
void ui_call_mainthread(ui_threadfunc tf, void* td) {
+ if(uic_mainthread_calls_is_buffered()) {
+ uic_add_buffered_mainthread_call(tf, td);
+ return;
+ }
+
UiAppCallback *cb = [[UiAppCallback alloc]initWithCallback:tf userdata:td];
[cb callMainThread];
}
return;
}
- //if(!ui_appname()) {
- // // applications without name cannot load app properties
- // return;
- //}
char *dir = ui_configfile(NULL);
if(!dir) {
#include "threadpool.h"
#include "context.h"
+#include <cx/linked_list.h>
#include <pthread.h>
#include <stdio.h>
static threadpool_job kill_job;
+
+
+static pthread_mutex_t mc_buffer_mutex;
+static CxList *mainthread_call_buffer;
+static volatile int mainthread_call_buffered = 0;
+
+typedef struct UiMainCall {
+ ui_threadfunc func;
+ void *data;
+} UiMainCall;
+
+void uic_init_threads(void) {
+ pthread_mutex_init(&mc_buffer_mutex, NULL);
+ mainthread_call_buffer = cxLinkedListCreate(NULL, sizeof(UiMainCall));
+}
+
+int uic_mainthread_calls_is_buffered(void) {
+ return mainthread_call_buffered;
+}
+
+void uic_add_buffered_mainthread_call(ui_threadfunc func, void *data) {
+ pthread_mutex_lock(&mc_buffer_mutex);
+ UiMainCall call;
+ call.func = func;
+ call.data = data;
+ cxListAdd(mainthread_call_buffer, &call);
+ pthread_mutex_unlock(&mc_buffer_mutex);
+}
+
+
+void ui_buffer_mainthread_calls(UiBool enable_buffering) {
+ mainthread_call_buffered = enable_buffering;
+ if(!enable_buffering) {
+ ui_exec_buffered_mainthread_calls();
+ }
+}
+void ui_exec_buffered_mainthread_calls(void) {
+ pthread_mutex_lock(&mc_buffer_mutex);
+ CxIterator i = cxListIterator(mainthread_call_buffer);
+ cx_foreach(UiMainCall *, call, i) {
+ if(call->func) {
+ call->func(call->data);
+ }
+ }
+ cxListClear(mainthread_call_buffer);
+ pthread_mutex_unlock(&mc_buffer_mutex);
+}
+
+
+
UiThreadpool* threadpool_new(int min, int max) {
UiThreadpool *pool = malloc(sizeof(UiThreadpool));
pool->queue = ui_queue_create();
extern "C" {
#endif
+void uic_init_threads(void);
+int uic_mainthread_calls_is_buffered(void);
+void uic_add_buffered_mainthread_call(ui_threadfunc func, void *data);
+
typedef struct UiQueueElm UiQueueElm;
typedef struct UiQueue UiQueue;
uic_toolbar_init();
ui_image_init();
uic_load_app_properties();
+ uic_init_threads();
#if GTK_MAJOR_VERSION >= 4
scale_factor = 1; // TODO
}
void ui_call_mainthread(ui_threadfunc tf, void* td) {
+ if(uic_mainthread_calls_is_buffered()) {
+ uic_add_buffered_mainthread_call(tf, td);
+ return;
+ }
+
UiJob *job = malloc(sizeof(UiJob));
job->job_func = tf;
job->job_data = td;
}
void ui_call_mainthread(ui_threadfunc tf, void* td) {
+ if(uic_mainthread_calls_is_buffered()) {
+ uic_add_buffered_mainthread_call(tf, td);
+ return;
+ }
+
UiJob *job = malloc(sizeof(UiJob));
memset(job, 0, sizeof(UiJob));
job->job_func = tf;
UIEXPORT void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd);
UIEXPORT void ui_call_mainthread(ui_threadfunc tf, void* td);
+
+UIEXPORT void ui_buffer_mainthread_calls(UiBool enable_buffering);
+UIEXPORT void ui_exec_buffered_mainthread_calls(void);
+
UIEXPORT UiThreadpool* ui_threadpool_create(int nthreads);
UIEXPORT void ui_threadpool_destroy(UiThreadpool* pool);
UIEXPORT void ui_threadpool_job(UiThreadpool* pool, UiObject* obj, ui_threadfunc tf, void* td, ui_callback f, void* fd);