Thu, 22 Feb 2024 22:25:53 +0100
implement listview (GTK)
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2017 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <errno.h> #include "properties.h" #include <cx/string.h> #include <cx/buffer.h> #include "ucx_properties.h" static CxMap *application_properties; static CxMap *language; #ifndef UI_COCOA static char *locales_dir; static char *pixmaps_dir; #endif char* ui_getappdir() { if(ui_appname() == NULL) { return NULL; } return ui_configfile(NULL); } char* ui_configfile(char *name) { const char *appname = ui_appname(); if(!appname) { return NULL; } CxBuffer buf; cxBufferInit(&buf, NULL, 128, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); // add base dir char *homeenv = getenv("HOME"); if(homeenv == NULL) { cxBufferDestroy(&buf); return NULL; } cxstring home = cx_str(homeenv); cxBufferWrite(home.ptr, 1, home.length, &buf); if(home.ptr[home.length-1] != '/') { cxBufferPut(&buf, '/'); } #ifdef UI_COCOA // on OS X the app dir is $HOME/Library/Application Support/$APPNAME/ ucx_buffer_puts(buf, "Library/Application Support/"); #else // app dir is $HOME/.$APPNAME/ cxBufferPut(&buf, '.'); #endif cxBufferPutString(&buf, appname); cxBufferPut(&buf, '/'); // add file name if(name) { cxBufferPutString(&buf, name); } cxBufferPut(&buf, 0); return buf.space; } static int ui_mkdir(char *path) { #ifdef _WIN32 return mkdir(path); #else return mkdir(path, S_IRWXU); #endif } void uic_load_app_properties() { application_properties = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 128); if(!ui_appname()) { // applications without name cannot load app properties return; } char *dir = ui_configfile(NULL); if(!dir) { return; } if(ui_mkdir(dir)) { if(errno != EEXIST) { fprintf(stderr, "Ui Error: Cannot create directory %s\n", dir); free(dir); return; } } free(dir); char *path = ui_configfile("application.properties"); if(!path) { return; } FILE *file = fopen(path, "r"); if(!file) { free(path); return; } if(ucx_properties_load(application_properties, file)) { fprintf(stderr, "Ui Error: Cannot load application properties.\n"); } fclose(file); free(path); } void uic_store_app_properties() { char *path = ui_configfile("application.properties"); if(!path) { return; } FILE *file = fopen(path, "w"); if(!file) { fprintf(stderr, "Ui Error: Cannot open properties file: %s\n", path); free(path); return; } if(ucx_properties_store(application_properties, file)) { fprintf(stderr, "Ui Error: Cannot store application properties.\n"); } fclose(file); free(path); } char* ui_get_property(char *name) { return cxMapGet(application_properties, name); } void ui_set_property(char *name, char *value) { cxMapPut(application_properties, name, value); } void ui_set_default_property(char *name, char *value) { char *v = cxMapGet(application_properties, name); if(!v) { cxMapPut(application_properties, name, value); } } static char* uic_concat_path(const char *base, const char *p, const char *ext) { size_t baselen = strlen(base); CxBuffer *buf = cxBufferCreate(NULL, 32, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); if(baselen > 0) { cxBufferWrite(base, 1, baselen, buf); if(base[baselen - 1] != '/') { cxBufferPut(buf, '/'); } } cxBufferWrite(p, 1, strlen(p), buf); if(ext) { cxBufferWrite(ext, 1, strlen(ext), buf); } char *str = buf->space; free(buf); return str; } #ifndef UI_COCOA void ui_locales_dir(char *path) { locales_dir = path; } void ui_pixmaps_dir(char *path) { pixmaps_dir = path; } char* uic_get_image_path(const char *imgfilename) { if(pixmaps_dir) { return uic_concat_path(pixmaps_dir, imgfilename, NULL); } else { return NULL; } } void ui_load_lang(char *locale) { if(!locale) { locale = "en_EN"; } char *path = uic_concat_path(locales_dir, locale, ".properties"); uic_load_language_file(path); free(path); } void ui_load_lang_def(char *locale, char *default_locale) { char tmp[6]; if(!locale) { char *lang = getenv("LANG"); if(lang && strlen(lang) >= 5) { memcpy(tmp, lang, 5); tmp[5] = '\0'; locale = tmp; } else { locale = default_locale; } } char *path = uic_concat_path(locales_dir, locale, ".properties"); if(uic_load_language_file(path)) { if(default_locale) { ui_load_lang_def(default_locale, NULL); } else { // cannot find any language file fprintf(stderr, "Ui Error: Cannot load language.\n"); free(path); exit(-1); } } free(path); } #endif int uic_load_language_file(const char *path) { CxMap *lang = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 256); FILE *file = fopen(path, "r"); if(!file) { return 1; } if(ucx_properties_load(lang, file)) { fprintf(stderr, "Ui Error: Cannot parse language file: %s.\n", path); } fclose(file); cxMapRehash(lang); language = lang; return 0; } char* uistr(char *name) { char *value = uistr_n(name); return value ? value : "missing string"; } char* uistr_n(char *name) { if(!language) { return NULL; } return cxMapGet(language, name); }