improve app_conf, fix issue #898

This commit is contained in:
lixianjing 2024-09-17 09:19:20 +08:00
parent 060e08884b
commit a5889f0a10
6 changed files with 255 additions and 33 deletions

View File

@ -1,5 +1,8 @@
# 最新动态
2024/09/17
* app_conf初始化时不拷贝默认配置到用户配置而是优先读取用户配置再读取默认配置。
2024/09/14
* edit控件得到焦点时才响应鼠标滚轮事件(感谢雨欣提供补丁)

View File

@ -24,6 +24,8 @@ AWTK 提供了 [app_conf](https://github.com/zlgopen/awtk/blob/master/docs/manua
* Flash(TODO)
> 为了方便软件升级时,保留用户配置,先从用户配置读取,如果配置不存在,再读取默认配置。
## 2. 初始化(任意选一种格式即可)
[app_conf](https://github.com/zlgopen/awtk/blob/master/docs/manual/app_conf_t.md) 作为可选组件,需要开发者自己初始化。
@ -467,7 +469,7 @@ app_conf_on_changed(app_conf_changed, NULL);
3.8 恢复出厂设置
用默认配置文件替换当前配置文件,并重新加载。
删除用户配置文件,并重新加载。
```c
/**
@ -615,7 +617,7 @@ ret_t application_exit() {
ENSURE(app_conf_init_json("demo") == RET_OK);
```
> 在初始化时,如果配置文件不存在,则将缺省配置拷贝到配置文件
> 优先读取用户配置,如果没有读到,再读取默认配置
## 9. 注意事项

View File

@ -23,34 +23,13 @@
#include "tkc/mem.h"
#include "tkc/path.h"
#include "tkc/utils.h"
#include "conf_io/conf_obj.h"
#include "conf_io/object_app_conf.inc"
#include "conf_io/app_conf_init.h"
#include "tkc/data_reader_factory.h"
#include "tkc/data_writer_factory.h"
static bool_t app_conf_file_exist(const char* url) {
bool_t exist = FALSE;
data_reader_t* reader = data_reader_factory_create_reader(data_reader_factory(), url);
if (reader != NULL) {
if (data_reader_get_size(reader) > 0) {
exist = TRUE;
}
data_reader_destroy(reader);
}
return exist;
}
static ret_t app_conf_prepare_default(const char* url, const char* default_url) {
ret_t ret = RET_OK;
if (!app_conf_file_exist(url)) {
ret = data_url_copy(url, default_url);
}
return ret;
}
static ret_t app_conf_get_url(char url[MAX_PATH + 1], const char* app_name, const char* extname) {
char path[MAX_PATH + 1];
char app_dir[MAX_PATH + 1];
@ -77,7 +56,10 @@ static ret_t app_conf_get_url(char url[MAX_PATH + 1], const char* app_name, cons
}
ret_t app_conf_init(conf_load_t load, const char* app_name, const char* extname) {
ret_t ret = RET_FAIL;
tk_object_t* obj = NULL;
tk_object_t* default_obj = NULL;
tk_object_t* user_obj = NULL;
char path[MAX_PATH + 1];
#ifdef APP_CONF_URL
const char* app_conf_name = APP_CONF_URL;
@ -88,24 +70,35 @@ ret_t app_conf_init(conf_load_t load, const char* app_name, const char* extname)
log_info("app conf: %s\n", app_conf_name);
tk_snprintf(path, MAX_PATH, "asset://data/%s.%s", app_name, extname);
app_conf_prepare_default(app_conf_name, path);
obj = load(app_conf_name, TRUE);
return_value_if_fail(obj != NULL, RET_FAIL);
log_info("load default conf: %s\n", path);
default_obj = load(path, TRUE);
goto_error_if_fail(default_obj != NULL);
log_info("load user conf: %s\n", app_conf_name);
user_obj = load(app_conf_name, TRUE);
goto_error_if_fail(user_obj != NULL);
obj = object_app_conf_create(user_obj, default_obj);
goto_error_if_fail(obj != NULL);
app_conf_set_instance(obj);
app_conf_set_str(CONF_OBJ_PROP_DEFAULT_URL, path);
TK_OBJECT_UNREF(obj);
return RET_OK;
error:
TK_OBJECT_UNREF(obj);
TK_OBJECT_UNREF(user_obj);
TK_OBJECT_UNREF(default_obj);
return ret;
}
ret_t app_conf_reset(void) {
const char* url = app_conf_get_str(CONF_OBJ_PROP_URL, NULL);
const char* default_url = app_conf_get_str(CONF_OBJ_PROP_DEFAULT_URL, NULL);
return_value_if_fail(url != NULL && default_url != NULL, RET_BAD_PARAMS);
return_value_if_fail(data_url_copy(url, default_url) == RET_OK, RET_BAD_PARAMS);
return_value_if_fail(url != NULL, RET_BAD_PARAMS);
data_writer_write_all(url, "\0", 1);
return_value_if_fail(app_conf_reload() == RET_OK, RET_BAD_PARAMS);
return RET_OK;

View File

@ -0,0 +1,78 @@
/**
* File: object_app_conf.h
* Author: AWTK Develop Team
* Brief: object app conf
*
* Copyright (c) 2020 - 2024 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* 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
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2024-09-17 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_OBJECT_APP_CONF_H
#define TK_OBJECT_APP_CONF_H
#include "tkc/object.h"
#include "tkc/mutex_nest.h"
BEGIN_C_DECLS
/**
* @class object_app_conf_t
* @parent tk_object_t
*
* *
* *
* *
*
*/
typedef struct _object_app_conf_t {
tk_object_t object;
/*private*/
tk_object_t* user_obj;
tk_object_t* default_obj;
} object_app_conf_t;
/**
* @method object_app_conf_create
*
*
*
* @annotation ["constructor"]
*
* @param {tk_object_t*} user_obj
* @param {tk_object_t*} default_obj
*
* @return {tk_object_t*} object对象
*
*/
tk_object_t* object_app_conf_create(tk_object_t* user_obj, tk_object_t* default_obj);
/**
* @method object_app_conf_cast
* object_app_conf对象
* @annotation ["cast"]
* @param {tk_object_t*} obj object_app_conf对象
*
* @return {object_app_conf_t*} object_app_conf对象
*/
object_app_conf_t* object_app_conf_cast(tk_object_t* obj);
#define OBJECT_APP_CONF(obj) object_app_conf_cast(obj)
#define OBJECT_APP_CONF_TYPE "object_app_conf"
END_C_DECLS
#endif /*TK_OBJECT_APP_CONF_H*/

View File

@ -0,0 +1,140 @@
/**
* File: object_app_conf.h
* Author: AWTK Develop Team
* Brief: object app conf
*
* Copyright (c) 2020 - 2024 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* 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
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2024-09-17 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "tkc/mem.h"
#include "tkc/value.h"
#include "tkc/utils.h"
#include "object_app_conf.h"
static ret_t object_app_conf_on_destroy(tk_object_t* obj) {
object_app_conf_t* o = OBJECT_APP_CONF(obj);
return_value_if_fail(o != NULL && o->user_obj != NULL, RET_BAD_PARAMS);
emitter_off_by_ctx(EMITTER(o->user_obj), o);
TK_OBJECT_UNREF(o->user_obj);
TK_OBJECT_UNREF(o->default_obj);
return RET_OK;
}
static int32_t object_app_conf_compare(tk_object_t* obj, tk_object_t* other) {
object_app_conf_t* o = OBJECT_APP_CONF(obj);
return_value_if_fail(o != NULL && o->user_obj != NULL, -1);
return tk_object_compare(o->user_obj, other);
}
static ret_t object_app_conf_remove_prop(tk_object_t* obj, const char* name) {
object_app_conf_t* o = OBJECT_APP_CONF(obj);
return_value_if_fail(o != NULL, RET_BAD_PARAMS);
return tk_object_remove_prop(o->user_obj, name);
}
static ret_t object_app_conf_set_prop(tk_object_t* obj, const char* name, const value_t* v) {
object_app_conf_t* o = OBJECT_APP_CONF(obj);
return_value_if_fail(o != NULL, RET_BAD_PARAMS);
return tk_object_set_prop(o->user_obj, name, v);
}
static ret_t object_app_conf_get_prop(tk_object_t* obj, const char* name, value_t* v) {
ret_t ret = RET_NOT_FOUND;
object_app_conf_t* o = OBJECT_APP_CONF(obj);
return_value_if_fail(o != NULL, RET_BAD_PARAMS);
ret = tk_object_get_prop(o->user_obj, name, v);
if (ret != RET_OK) {
ret = tk_object_get_prop(o->default_obj, name, v);
}
return ret;
}
static ret_t object_app_conf_foreach_prop(tk_object_t* obj, tk_visit_t on_prop, void* ctx) {
ret_t ret = RET_OK;
object_app_conf_t* o = OBJECT_APP_CONF(obj);
return_value_if_fail(o != NULL, RET_BAD_PARAMS);
ret = tk_object_foreach_prop(o->user_obj, on_prop, ctx);
if (ret != RET_STOP) {
ret = tk_object_foreach_prop(o->default_obj, on_prop, ctx);
}
return ret;
}
static bool_t object_app_conf_can_exec(tk_object_t* obj, const char* name, const char* args) {
object_app_conf_t* o = OBJECT_APP_CONF(obj);
return_value_if_fail(o != NULL, RET_BAD_PARAMS);
return tk_object_can_exec(o->user_obj, name, args);
}
static ret_t object_app_conf_exec(tk_object_t* obj, const char* name, const char* args) {
object_app_conf_t* o = OBJECT_APP_CONF(obj);
return_value_if_fail(o != NULL, RET_BAD_PARAMS);
return tk_object_exec(o->user_obj, name, args);
}
static const object_vtable_t s_object_app_conf_vtable = {.type = OBJECT_APP_CONF_TYPE,
.desc = OBJECT_APP_CONF_TYPE,
.size = sizeof(object_app_conf_t),
.is_collection = FALSE,
.on_destroy = object_app_conf_on_destroy,
.exec = object_app_conf_exec,
.can_exec = object_app_conf_can_exec,
.compare = object_app_conf_compare,
.get_prop = object_app_conf_get_prop,
.set_prop = object_app_conf_set_prop,
.remove_prop = object_app_conf_remove_prop,
.foreach_prop = object_app_conf_foreach_prop};
static ret_t object_app_conf_forward_events(void* ctx, event_t* e) {
object_app_conf_t* o = OBJECT_APP_CONF(ctx);
return_value_if_fail(o != NULL, RET_BAD_PARAMS);
emitter_dispatch_simple_event(EMITTER(o), e->type);
return RET_OK;
}
tk_object_t* object_app_conf_create(tk_object_t* user_obj, tk_object_t* default_obj) {
tk_object_t* o = NULL;
object_app_conf_t* wrapper = NULL;
return_value_if_fail(user_obj != NULL, NULL);
o = tk_object_create(&s_object_app_conf_vtable);
return_value_if_fail(o != NULL, NULL);
wrapper = OBJECT_APP_CONF(o);
return_value_if_fail(wrapper != NULL, NULL);
wrapper->user_obj = tk_object_ref(user_obj);
wrapper->default_obj = tk_object_ref(default_obj);
emitter_on(EMITTER(user_obj), EVT_ITEMS_CHANGED, object_app_conf_forward_events, o);
emitter_on(EMITTER(user_obj), EVT_PROPS_CHANGED, object_app_conf_forward_events, o);
return o;
}
object_app_conf_t* object_app_conf_cast(tk_object_t* obj) {
return_value_if_fail(obj != NULL && obj->vt == &s_object_app_conf_vtable, NULL);
return (object_app_conf_t*)(obj);
}

View File

@ -111,6 +111,12 @@ TEST(AppConf, reset) {
ASSERT_STREQ(app_conf_get_str("name", NULL), "test");
ASSERT_EQ(app_conf_get_int("age", 0), 100);
ASSERT_EQ(app_conf_set_str("name", "awtk"), RET_OK);
ASSERT_EQ(app_conf_set_int("age", 200), RET_OK);
ASSERT_STREQ(app_conf_get_str("name", NULL), "awtk");
ASSERT_EQ(app_conf_get_int("age", 0), 200);
ASSERT_EQ(app_conf_deinit(), RET_OK);
}