// called whenever global preferences change or a file is // added or removed from gFileHistory (in order to keep // the list of recently opened documents in sync) bool Save() { // don't save preferences without the proper permission if (!HasPermission(Perm_SavePreferences)) return false; /* mark currently shown files as visible */ for (size_t i = 0; i < gWindows.Count(); i++) { UpdateCurrentFileDisplayStateForWin(gWindows.At(i)); } // remove entries which should (no longer) be remembered gFileHistory.Purge(!gGlobalPrefs->rememberStatePerDocument); // update display mode and zoom fields from internal values str::ReplacePtr(&gGlobalPrefs->defaultDisplayMode, conv::FromDisplayMode(gGlobalPrefs->defaultDisplayModeEnum)); conv::FromZoom(&gGlobalPrefs->defaultZoom, gGlobalPrefs->defaultZoomFloat); ScopedMem<WCHAR> path(GetSettingsPath()); CrashIf(!path); if (!path) return false; size_t prevPrefsDataSize; ScopedMem<char> prevPrefsData(file::ReadAll(path, &prevPrefsDataSize)); if (!gGlobalPrefs->rememberStatePerDocument || !gGlobalPrefs->rememberOpenedFiles) { for (DisplayState **ds = gGlobalPrefs->fileStates->IterStart(); ds; ds = gGlobalPrefs->fileStates->IterNext()) { (*ds)->useDefaultState = true; } // prevent unnecessary settings from being written out uint16_t fieldCount = 0; while (++fieldCount <= dimof(gFileStateFields)) { // count the number of fields up to and including useDefaultState if (gFileStateFields[fieldCount - 1].offset == offsetof(FileState, useDefaultState)) break; } // restore the correct fieldCount ASAP after serialization gFileStateInfo.fieldCount = fieldCount; } size_t prefsDataSize; ScopedMem<char> prefsData(SerializeStruct(&gGlobalPrefsInfo, gGlobalPrefs, prevPrefsData, &prefsDataSize)); if (!gGlobalPrefs->rememberStatePerDocument || !gGlobalPrefs->rememberOpenedFiles) gFileStateInfo.fieldCount = dimof(gFileStateFields); CrashIf(!prefsData || 0 == prefsDataSize); if (!prefsData || 0 == prefsDataSize) return false; // only save if anything's changed at all if (prevPrefsDataSize == prefsDataSize && str::Eq(prefsData, prevPrefsData)) return true; FileTransaction trans; bool ok = trans.WriteAll(path, prefsData, prefsDataSize) && trans.Commit(); if (!ok) return false; gGlobalPrefs->lastPrefUpdate = file::GetModificationTime(path); return true; }
/* Caller needs to prefs::CleanUp() */ bool Load() { CrashIf(gGlobalPrefs); ScopedMem<WCHAR> path(GetSettingsPath()); ScopedMem<char> prefsData(file::ReadAll(path, NULL)); gGlobalPrefs = (GlobalPrefs *)DeserializeStruct(&gGlobalPrefsInfo, prefsData); CrashAlwaysIf(!gGlobalPrefs); #ifdef DISABLE_EBOOK_UI if (!file::Exists(path)) gGlobalPrefs->ebookUI.useFixedPageUI = gGlobalPrefs->chmUI.useFixedPageUI = true; #endif #ifdef DISABLE_TABS if (!file::Exists(path)) gGlobalPrefs->useTabs = false; #endif if (!gGlobalPrefs->uiLanguage || !trans::ValidateLangCode(gGlobalPrefs->uiLanguage)) { // guess the ui language on first start str::ReplacePtr(&gGlobalPrefs->uiLanguage, trans::DetectUserLang()); } gGlobalPrefs->lastPrefUpdate = file::GetModificationTime(path); gGlobalPrefs->defaultDisplayModeEnum = conv::ToDisplayMode(gGlobalPrefs->defaultDisplayMode, DM_AUTOMATIC); gGlobalPrefs->defaultZoomFloat = conv::ToZoom(gGlobalPrefs->defaultZoom, ZOOM_ACTUAL_SIZE); CrashIf(!IsValidZoom(gGlobalPrefs->defaultZoomFloat)); int weekDiff = GetWeekCount() - gGlobalPrefs->openCountWeek; gGlobalPrefs->openCountWeek = GetWeekCount(); if (weekDiff > 0) { // "age" openCount statistics (cut in in half after every week) for (DisplayState **ds = gGlobalPrefs->fileStates->IterStart(); ds; ds = gGlobalPrefs->fileStates->IterNext()) { (*ds)->openCount >>= weekDiff; } } // make sure that zoom levels are in the order expected by DisplayModel gGlobalPrefs->zoomLevels->Sort(cmpFloat); while (gGlobalPrefs->zoomLevels->Count() > 0 && gGlobalPrefs->zoomLevels->At(0) < ZOOM_MIN) { gGlobalPrefs->zoomLevels->PopAt(0); } while (gGlobalPrefs->zoomLevels->Count() > 0 && gGlobalPrefs->zoomLevels->Last() > ZOOM_MAX) { gGlobalPrefs->zoomLevels->Pop(); } // TODO: verify that all states have a non-NULL file path? gFileHistory.UpdateStatesSource(gGlobalPrefs->fileStates); SetDefaultEbookFont(gGlobalPrefs->ebookUI.fontName, gGlobalPrefs->ebookUI.fontSize); if (!file::Exists(path)) Save(); return true; }
void SelectTranslation(const WCHAR *exePath=NULL) { LANGID langId = GetUserDefaultUILanguage(); int idx = GetLanguageIndex(langId); if (-1 == idx) { // try a neutral language if the specific sublanguage isn't available langId = MAKELANGID(PRIMARYLANGID(langId), SUBLANG_NEUTRAL); idx = GetLanguageIndex(langId); } if (-1 != idx) { gTranslationIdx = idx; plogf("sp: Detected language %s (%d)", gLanguages[idx / gTranslationsCount], idx); } // try to extract the language used by SumatraPDF ScopedMem<WCHAR> path; if (exePath) { path.Set(path::GetDir(exePath)); path.Set(path::Join(path, PREFS_FILE_NAME)); } if (!file::Exists(path)) { path.Set(GetSpecialFolder(CSIDL_APPDATA)); path.Set(path::Join(path, L"SumatraPDF\\" PREFS_FILE_NAME)); } if (!file::Exists(path)) return; plogf("sp: Found preferences at %S", path); ScopedMem<char> prefsData(file::ReadAll(path, NULL)); SquareTree sqt(prefsData); const char *langCode = sqt.root ? sqt.root->GetValue("UiLanguage") : NULL; if (langCode) { plogf("sp: UiLanguage from preferences: %s", langCode); for (int i = 0; gLanguages[i]; i++) { if (str::Eq(gLanguages[i], langCode)) { gTranslationIdx = i * gTranslationsCount; break; } } } }