appprefs.cc.svn-base

来自「SumatraPDF是一款小型开源的pdf阅读工具。虽然玲珑小巧(只有800多K」· SVN-BASE 代码 · 共 470 行

SVN-BASE
470
字号
/* Copyright Krzysztof Kowalczyk 2006-2007
   License: GPLv2 */

#include "base_util.h"
#include "benc_util.h"
#include "str_util.h"
#include "file_util.h"
#include "dstring.h"

#include "AppPrefs.h"
#include "DisplayState.h"
#include "FileHistory.h"

extern bool CurrLangNameSet(const char* langName);
extern const char* CurrLangNameGet();

#define DEFAULT_WINDOW_X     40
#define DEFAULT_WINDOW_Y     20
#define DEFAULT_WINDOW_DX    640
#define DEFAULT_WINDOW_DY    480

static bool ParseDisplayMode(const char *txt, DisplayMode *resOut)
{
    assert(txt);
    if (!txt) return false;
    return DisplayModeEnumFromName(txt, resOut);
}

#define GLOBAL_PREFS_STR "gp"

#define DICT_NEW(boname) \
    benc_dict* boname = benc_dict_new(); \
    if (!boname) \
        goto Error;

#define DICT_ADD_INT64(doname,name,val) \
    ok = benc_dict_insert_int64(doname,name,(int64_t)val); \
    if (!ok) \
        goto Error;

#define DICT_ADD_STR(doname,name,val) \
        if (val) { \
            ok = benc_dict_insert_str(doname,name,val); \
            if (!ok) \
                goto Error; \
        }

#define DICT_ADD_DICT(doname,name,val) \
        ok = benc_dict_insert2(doname,name,(benc_obj*)val); \
        if (!ok) \
            goto Error;

benc_dict* Prefs_SerializeGlobal(void)
{
    BOOL       ok;
    const char * txt;

    DICT_NEW(prefs);
    DICT_ADD_INT64(prefs, SHOW_TOOLBAR_STR, gGlobalPrefs.m_showToolbar);
    DICT_ADD_INT64(prefs, PDF_ASSOCIATE_DONT_ASK_STR, gGlobalPrefs.m_pdfAssociateDontAskAgain);
    DICT_ADD_INT64(prefs, PDF_ASSOCIATE_ASSOCIATE_STR, gGlobalPrefs.m_pdfAssociateShouldAssociate);

    DICT_ADD_INT64(prefs, BG_COLOR_STR, gGlobalPrefs.m_bgColor);
    DICT_ADD_INT64(prefs, ESC_TO_EXIT_STR, gGlobalPrefs.m_escToExit);
    DICT_ADD_INT64(prefs, PDFS_OPENED_STR, gGlobalPrefs.m_pdfsOpened);
    DICT_ADD_INT64(prefs, ENABLE_AUTO_UPDATE_STR, gGlobalPrefs.m_enableAutoUpdate);

    txt = DisplayModeNameFromEnum(gGlobalPrefs.m_defaultDisplayMode);
    DICT_ADD_STR(prefs, DISPLAY_MODE_STR, txt);

    txt = str_printf("%.4f", gGlobalPrefs.m_defaultZoom);
    if (txt) {
        DICT_ADD_STR(prefs, ZOOM_VIRTUAL_STR, txt);
        free((void*)txt);
    }
    DICT_ADD_INT64(prefs, WINDOW_STATE_STR, gGlobalPrefs.m_windowState);
    if (gGlobalPrefs.m_windowState == WIN_STATE_NORMAL) {
        DICT_ADD_INT64(prefs, WINDOW_X_STR, gGlobalPrefs.m_windowPosX);
        DICT_ADD_INT64(prefs, WINDOW_Y_STR, gGlobalPrefs.m_windowPosY);
        DICT_ADD_INT64(prefs, WINDOW_DX_STR, gGlobalPrefs.m_windowDx);
        DICT_ADD_INT64(prefs, WINDOW_DY_STR, gGlobalPrefs.m_windowDy);
    }
    else {
        DICT_ADD_INT64(prefs, WINDOW_X_STR, gGlobalPrefs.m_tmpWindowPosX);
        DICT_ADD_INT64(prefs, WINDOW_Y_STR, gGlobalPrefs.m_tmpWindowPosY);
        DICT_ADD_INT64(prefs, WINDOW_DX_STR, gGlobalPrefs.m_tmpWindowDx);
        DICT_ADD_INT64(prefs, WINDOW_DY_STR, gGlobalPrefs.m_tmpWindowDy);
    }

    DICT_ADD_STR(prefs, INVERSE_SEARCH_COMMANDLINE, gGlobalPrefs.m_inverseSearchCmdLine);
    DICT_ADD_STR(prefs, VERSION_TO_SKIP_STR, gGlobalPrefs.m_versionToSkip);
    DICT_ADD_STR(prefs, LAST_UPDATE_STR, gGlobalPrefs.m_lastUpdateTime);
    DICT_ADD_STR(prefs, UI_LANGUAGE_STR, CurrLangNameGet());
    return prefs;
Error:
    benc_obj_delete((benc_obj*)prefs);
    return NULL;
}

/* TODO: move to benc_util.c ? */
static BOOL dict_get_str_dup(benc_dict* dict, const char* key, const char** valOut)
{
    const char *str = dict_get_str(dict, key);
    if (!str) return FALSE;
    *valOut = str_dup(str);
    return true;
}

static bool DisplayState_Deserialize(benc_dict* dict, DisplayState *ds)
{
    DisplayState_Init(ds);

    dict_get_str_dup(dict, FILE_STR, &ds->filePath);
    const char* txt = dict_get_str(dict, DISPLAY_MODE_STR);
    if (txt)
        DisplayModeEnumFromName(txt, &ds->displayMode);
    dict_get_bool(dict, VISIBLE_STR, &ds->visible);
    dict_get_int(dict, PAGE_NO_STR, &ds->pageNo);
    dict_get_int(dict, ROTATION_STR, &ds->rotation);
    dict_get_int(dict, SCROLL_X_STR, &ds->scrollX);
    dict_get_int(dict, SCROLL_Y_STR, &ds->scrollY);
    dict_get_int(dict, WINDOW_STATE_STR, &ds->windowState);
    dict_get_int(dict, WINDOW_X_STR, &ds->windowX);
    dict_get_int(dict, WINDOW_Y_STR, &ds->windowY);
    dict_get_int(dict, WINDOW_DX_STR, &ds->windowDx);
    dict_get_int(dict, WINDOW_DY_STR, &ds->windowDy);
    dict_get_bool(dict, SHOW_TOC_STR, &ds->showToc);
    dict_get_double_from_str(dict, ZOOM_VIRTUAL_STR, &ds->zoomVirtual);
    return true;
}

static benc_dict* DisplayState_Serialize(DisplayState *ds)
{
    BOOL  ok;
    const char * txt;
    
    DICT_NEW(prefs);
    DICT_ADD_STR(prefs, FILE_STR, ds->filePath);
    txt = DisplayModeNameFromEnum(ds->displayMode);
    if (txt)
        DICT_ADD_STR(prefs, DISPLAY_MODE_STR, txt);
    DICT_ADD_INT64(prefs, VISIBLE_STR, ds->visible);
    DICT_ADD_INT64(prefs, PAGE_NO_STR, ds->pageNo);
    DICT_ADD_INT64(prefs, ROTATION_STR, ds->rotation);
    DICT_ADD_INT64(prefs, SCROLL_X_STR, ds->scrollX);

   DICT_ADD_INT64(prefs, SCROLL_Y_STR, ds->scrollY);
   DICT_ADD_INT64(prefs, WINDOW_STATE_STR, ds->windowState);
    if (ds->windowState == WIN_STATE_NORMAL) {
        DICT_ADD_INT64(prefs, WINDOW_X_STR, ds->windowX);
        DICT_ADD_INT64(prefs, WINDOW_Y_STR, ds->windowY);
        DICT_ADD_INT64(prefs, WINDOW_DX_STR, ds->windowDx);
        DICT_ADD_INT64(prefs, WINDOW_DY_STR, ds->windowDy);
    } else {
        DICT_ADD_INT64(prefs, WINDOW_X_STR, gGlobalPrefs.m_tmpWindowPosX);
        DICT_ADD_INT64(prefs, WINDOW_Y_STR, gGlobalPrefs.m_tmpWindowPosY);
        DICT_ADD_INT64(prefs, WINDOW_DX_STR, gGlobalPrefs.m_tmpWindowDx);
        DICT_ADD_INT64(prefs, WINDOW_DY_STR, gGlobalPrefs.m_tmpWindowDy);
    }

    DICT_ADD_INT64(prefs, SHOW_TOC_STR, ds->showToc);

    txt = str_printf("%.4f", ds->zoomVirtual);
    if (txt) {
        DICT_ADD_STR(prefs, ZOOM_VIRTUAL_STR, txt);
        free((void*)txt);
    }

    return prefs;
Error:
    benc_obj_delete((benc_obj*)prefs);
    return NULL;
}

static benc_dict* FileHistoryList_Node_Serialize2(FileHistoryList *node)
{
    assert(node);
    if (!node) return NULL;

    return DisplayState_Serialize(&(node->state));
}

benc_array* FileHistoryList_Serialize(FileHistoryList **root)
{
    BOOL ok;
    assert(root);
    if (!root) return NULL;

    benc_array* arr = benc_array_new();
    if (!arr)
        goto Error;

    FileHistoryList *curr = *root;
    while (curr) {
        benc_obj* bobj = (benc_obj*) FileHistoryList_Node_Serialize2(curr);
        if (!bobj)
            goto Error;
        ok = benc_array_append(arr, bobj);
        if (!ok)
            goto Error;
        curr = curr->next;
    }
    return arr;
Error:
    if (arr)
        benc_array_delete(arr);
    return NULL;      
}

const char *Prefs_Serialize(FileHistoryList **root, size_t* lenOut)
{
    BOOL        ok;
    char *      data = NULL;

    DICT_NEW(prefs);

    benc_dict* global = Prefs_SerializeGlobal();
    if (!global)
        goto Error;
    DICT_ADD_DICT(prefs, GLOBAL_PREFS_STR, global);
    benc_array *fileHistory = FileHistoryList_Serialize(root);
    if (!fileHistory)
        goto Error;
    DICT_ADD_DICT(prefs, FILE_HISTORY_STR, fileHistory);

    data = benc_obj_to_data((benc_obj*)prefs, lenOut);
Error:
    benc_obj_delete((benc_obj*)prefs);
    return (const char*)data;
}

static BOOL ParseInt(const char *txt, int *resOut)
{
    assert(txt);
    if (!txt) return FALSE;
    *resOut = atoi(txt);
    return TRUE;
}

static BOOL ParseBool(const char *txt, BOOL *resOut)
{
    assert(txt);
    if (!txt) return FALSE;
    int val = atoi(txt);
    if (val)
        *resOut = TRUE;
    else
        *resOut = FALSE;
    return TRUE;
}

enum PrefsParsingState { PPS_START, PPS_IN_FILE_HISTORY };

/* Return TRUE if 'str' is a comment line in preferences file.
   Comment lines start with '#'. */
static int Prefs_LineIsComment(const char *str)
{
    if (!str)
        return FALSE;
    if ('#' == *str)
        return TRUE;
    return FALSE;
}

static int Prefs_LineIsStructKey(const char *str)
{
    if (strlen(str) <= 3)
        return FALSE;
    if ((' ' == str[0]) && (' ' == str[1]))
        return TRUE;
    return FALSE;
}

static void ParseKeyValue(char *key, char *value, DisplayState *dsOut)
{
    BOOL    fOk;

    assert(key);
    assert(value);
    assert(dsOut);
    if (!key || !value || !dsOut)
        return;

    if (str_eq(FILE_STR, key)) {
        assert(value);
        if (!value) return;
        assert(!dsOut->filePath);
        free((void*)dsOut->filePath);
        dsOut->filePath = str_dup(value);
        return;
    }

    if (str_eq(DISPLAY_MODE_STR, key)) {
        dsOut->displayMode = DM_SINGLE_PAGE;
        fOk = ParseDisplayMode(value, &dsOut->displayMode);
        assert(fOk);
        return;
    }

    if (str_eq(PAGE_NO_STR, key)) {
        fOk = ParseInt(value, &dsOut->pageNo);
        assert(fOk);
        if (!fOk || (dsOut->pageNo < 1))
            dsOut->pageNo = 1;
        return;
    }

    if (str_eq(ZOOM_VIRTUAL_STR, key)) {
        fOk = str_to_double(value, &dsOut->zoomVirtual);
        assert(fOk);
        if (!fOk || !ValidZoomVirtual(dsOut->zoomVirtual))
            dsOut->zoomVirtual = 100.0;
        return;
    }

    if (str_eq(ROTATION_STR, key)) {
        fOk = ParseInt(value, &dsOut->rotation);
        assert(fOk);
        if (!fOk || !validRotation(dsOut->rotation))
            dsOut->rotation = 0;
        return;
    }

    if (str_eq(VISIBLE_STR, key)) {
        dsOut->visible= FALSE;
        fOk = ParseBool(value, &dsOut->visible);
        assert(fOk);
        return;
    }

    if (str_eq(SCROLL_X_STR, key)) {
        dsOut->scrollX = 0;
        fOk = ParseInt(value, &dsOut->scrollX);
        assert(fOk);
        return;
    }

    if (str_eq(SCROLL_Y_STR, key)) {
        dsOut->scrollY = 0;
        fOk = ParseInt(value, &dsOut->scrollY);
        assert(fOk);
        return;
    }

    if (str_eq(WINDOW_X_STR, key)) {
        dsOut->windowX = DEFAULT_WINDOW_X;
        fOk = ParseInt(value, &dsOut->windowX);
        assert(fOk);
        return;
    } 

    if (str_eq(WINDOW_Y_STR, key)) {
        dsOut->windowY = DEFAULT_WINDOW_Y;
        fOk = ParseInt(value, &dsOut->windowY);
        assert(fOk);
        return;
    }

    if (str_eq(WINDOW_DX_STR, key)) {
        dsOut->windowDx = DEFAULT_WINDOW_DX;
        fOk = ParseInt(value, &dsOut->windowDx);
        assert(fOk);
        return;
    }

    if (str_eq(WINDOW_DY_STR, key)) {
        dsOut->windowDy = DEFAULT_WINDOW_DY;
        fOk = ParseInt(value, &dsOut->windowDy);
        assert(fOk);
        return;
    }

    assert(0);
}

void FileHistory_Add(FileHistoryList **fileHistoryRoot, DisplayState *state)
{
    FileHistoryList *   fileHistoryNode = NULL;
    // TODO: add a check if a file exists, to filter out deleted files
    // but only if a file is on a non-network drive (because
    // accessing network drives can be slow and unnecessarily spin
    // the drives. Also, the filePath is utf8, so convert to unicode
    // first.
#if 0
    if (!file_exists(state->filePath)) {
        DBG_OUT("FileHistory_Add() file '%s' doesn't exist anymore\n", state->filePath);
        return;
    }
#endif
    fileHistoryNode = FileHistoryList_Node_Create();
    fileHistoryNode->state = *state;
    FileHistoryList_Node_Append(fileHistoryRoot, fileHistoryNode);
    fileHistoryNode = NULL;
}

static void dict_get_str_helper(benc_dict *d, const char *key, char **val)
{
    const char *txt = dict_get_str(d, key);
    if (txt)
        str_dup_replace(val, txt);
}

bool Prefs_Deserialize(const char *prefsTxt, size_t prefsTxtLen, FileHistoryList **fileHistoryRoot)
{
    benc_obj * bobj;
    benc_str * bstr;
    bobj = benc_obj_from_data(prefsTxt, prefsTxtLen);
    if (!bobj)
        return false;
    benc_dict* prefs = benc_obj_as_dict(bobj);
    if (!prefs)
        goto Error;

    benc_dict* global = benc_obj_as_dict(benc_dict_find2(prefs, GLOBAL_PREFS_STR));
    if (!global)
        goto Error;

    dict_get_bool(global, SHOW_TOOLBAR_STR, &gGlobalPrefs.m_showToolbar);
    dict_get_bool(global, PDF_ASSOCIATE_DONT_ASK_STR, &gGlobalPrefs.m_pdfAssociateDontAskAgain);
    dict_get_bool(global, PDF_ASSOCIATE_ASSOCIATE_STR, &gGlobalPrefs.m_pdfAssociateShouldAssociate);
    dict_get_bool(global, ESC_TO_EXIT_STR, &gGlobalPrefs.m_escToExit);
    dict_get_int(global, BG_COLOR_STR, &gGlobalPrefs.m_bgColor);
    dict_get_int(global, PDFS_OPENED_STR, &gGlobalPrefs.m_pdfsOpened);
    dict_get_bool(global, ENABLE_AUTO_UPDATE_STR, &gGlobalPrefs.m_enableAutoUpdate);

    const char* txt = dict_get_str(global, DISPLAY_MODE_STR);
    if (txt)
        DisplayModeEnumFromName(txt, &gGlobalPrefs.m_defaultDisplayMode);
    dict_get_double_from_str(global, ZOOM_VIRTUAL_STR, &gGlobalPrefs.m_defaultZoom);
    dict_get_int(global, WINDOW_STATE_STR, &gGlobalPrefs.m_windowState);

    dict_get_int(global, WINDOW_X_STR, &gGlobalPrefs.m_windowPosX);
    gGlobalPrefs.m_tmpWindowPosX = gGlobalPrefs.m_windowPosX;
    dict_get_int(global, WINDOW_Y_STR, &gGlobalPrefs.m_windowPosY);
    gGlobalPrefs.m_tmpWindowPosY = gGlobalPrefs.m_windowPosY;
    dict_get_int(global, WINDOW_DX_STR, &gGlobalPrefs.m_windowDx);
    gGlobalPrefs.m_tmpWindowDx = gGlobalPrefs.m_windowDx;
    dict_get_int(global, WINDOW_DY_STR, &gGlobalPrefs.m_windowDy);
    gGlobalPrefs.m_tmpWindowDy = gGlobalPrefs.m_windowDy;

    dict_get_str_helper(global, INVERSE_SEARCH_COMMANDLINE, &gGlobalPrefs.m_inverseSearchCmdLine);
    dict_get_str_helper(global, VERSION_TO_SKIP_STR, &gGlobalPrefs.m_versionToSkip);
    dict_get_str_helper(global, LAST_UPDATE_STR, &gGlobalPrefs.m_lastUpdateTime);

    bstr = benc_obj_as_str(benc_dict_find2(global, UI_LANGUAGE_STR));
    if (bstr)
        CurrLangNameSet(bstr->m_str);

    benc_array* fileHistory = benc_obj_as_array(benc_dict_find2(prefs, FILE_HISTORY_STR));
    if (!fileHistory)
        goto Error;
    size_t dlen = benc_array_len(fileHistory);
    for (size_t i = 0; i < dlen; i++) {
        DisplayState state;
        benc_dict *dict = benc_obj_as_dict(benc_array_get(fileHistory, i));
        assert(dict);
        if (!dict) continue;
        DisplayState_Deserialize(dict, &state);
        if (state.filePath) {
            FileHistory_Add(fileHistoryRoot, &state);
        }
    }
    benc_obj_delete(bobj);
    return true;
Error:
    benc_obj_delete(bobj);
    return false;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?