FreeCAD

Форк
0
/
PreferencePackManager.cpp 
588 строк · 23.8 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2021 Chris Hennes <chennes@pioneerlibrarysystem.org>    *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
6
 *   This library is free software; you can redistribute it and/or         *
7
 *   modify it under the terms of the GNU Library General Public           *
8
 *   License as published by the Free Software Foundation; either          *
9
 *   version 2 of the License, or (at your option) any later version.      *
10
 *                                                                         *
11
 *   This library  is distributed in the hope that it will be useful,      *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
 *   GNU Library General Public License for more details.                  *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Library General Public     *
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23

24
#include "PreCompiled.h"
25

26
#ifndef _PreComp_
27
# include <memory>
28
# include <string_view>
29
# include <mutex>
30
#endif
31

32
#include <boost/filesystem.hpp>
33
#include <QDir>
34

35
#include "PreferencePackManager.h"
36
#include "App/Metadata.h"
37
#include "Base/Parameter.h"
38
#include "Base/Interpreter.h"
39
#include "Base/Console.h"
40
#include "DockWindowManager.h"
41
#include "ToolBarManager.h"
42

43
#include <App/Application.h>
44

45
#include <ctime> // For generating a timestamped filename
46

47

48
using namespace Gui;
49
using namespace xercesc;
50
namespace fs = boost::filesystem;
51

52
PreferencePack::PreferencePack(const fs::path& path, const App::Metadata& metadata) :
53
    _path(path), _metadata(metadata)
54
{
55
    if (!fs::exists(_path)) {
56
        throw std::runtime_error{ "Cannot access " + path.string() };
57
    }
58

59
    auto qssPaths = QDir::searchPaths(QString::fromUtf8("qss"));
60
    auto cssPaths = QDir::searchPaths(QString::fromUtf8("css"));
61
    auto overlayPaths = QDir::searchPaths(QString::fromUtf8("overlay"));
62

63
    qssPaths.append(QString::fromStdString(_path.string()));
64
    cssPaths.append(QString::fromStdString(_path.string()));
65
    overlayPaths.append(QString::fromStdString(_path.string() + "/overlay"));
66

67
    QDir::setSearchPaths(QString::fromUtf8("qss"), qssPaths);
68
    QDir::setSearchPaths(QString::fromUtf8("css"), cssPaths);
69
    QDir::setSearchPaths(QString::fromUtf8("overlay"), overlayPaths);
70
}
71

72
std::string PreferencePack::name() const
73
{
74
    return _metadata.name();
75
}
76

77
bool PreferencePack::apply() const
78
{
79
    // Run the pre.FCMacro, if it exists: if it raises an exception, abort the process
80
    auto preMacroPath = _path / "pre.FCMacro";
81
    if (fs::exists(preMacroPath)) {
82
        try {
83
            Base::Interpreter().runFile(preMacroPath.string().c_str(), false);
84
        }
85
        catch (...) {
86
            Base::Console().Message("PreferencePack application aborted by the preferencePack's pre.FCMacro");
87
            return false;
88
        }
89
    }
90

91
    // Back up the old config file
92
    auto savedPreferencePacksDirectory = fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks";
93
    auto backupFile = savedPreferencePacksDirectory / "user.cfg.backup";
94
    try {
95
        fs::remove(backupFile);
96
    }
97
    catch (...) {}
98
    App::GetApplication().GetUserParameter().SaveDocument(backupFile.string().c_str());
99

100
    // Apply the config settings
101
    applyConfigChanges();
102

103
    // Run the Post.FCMacro, if it exists
104
    auto postMacroPath = _path / "post.FCMacro";
105
    if (fs::exists(postMacroPath)) {
106
        try {
107
            Base::Interpreter().runFile(postMacroPath.string().c_str(), false);
108
        }
109
        catch (...) {
110
            Base::Console().Message("PreferencePack application reverted by the preferencePack's post.FCMacro");
111
            App::GetApplication().GetUserParameter().LoadDocument(backupFile.string().c_str());
112
            return false;
113
        }
114
    }
115

116
    return true;
117
}
118

119

120
App::Metadata Gui::PreferencePack::metadata() const
121
{
122
    return _metadata;
123
}
124

125
void PreferencePack::applyConfigChanges() const
126
{
127
    auto configFile = _path / (_metadata.name() + ".cfg");
128
    if (fs::exists(configFile)) {
129
        auto newParameters = ParameterManager::Create();
130
        newParameters->LoadDocument(configFile.string().c_str());
131
        auto baseAppGroup = App::GetApplication().GetUserParameter().GetGroup("BaseApp");
132
        newParameters->GetGroup("BaseApp")->insertTo(baseAppGroup);
133
    }
134
}
135

136
PreferencePackManager::PreferencePackManager()
137
{
138
    auto modPath = fs::path(App::Application::getUserAppDataDir()) / "Mod";
139
    auto savedPath = fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks";
140
    auto resourcePath = fs::path(App::Application::getResourceDir()) / "Gui" / "PreferencePacks";
141
    _preferencePackPaths.push_back(resourcePath);
142
    _preferencePackPaths.push_back(modPath);
143
    _preferencePackPaths.push_back(savedPath);
144
    rescan();
145

146
    // Housekeeping:
147
    DeleteOldBackups();
148
}
149

150
void PreferencePackManager::rescan()
151
{
152
    std::lock_guard<std::mutex> lock(_mutex);
153
    _preferencePacks.clear();
154
    for (const auto& path : _preferencePackPaths) {
155
        if (fs::exists(path) && fs::is_directory(path)) {
156
            FindPreferencePacksInPackage(path);
157
            for (const auto& mod : fs::directory_iterator(path)) {
158
                if (fs::is_directory(mod)) {
159
                    FindPreferencePacksInPackage(mod);
160
                }
161
            }
162
        }
163
    }
164
}
165

166
void Gui::PreferencePackManager::AddPackToMetadata(const std::string &packName) const
167
{
168
    std::lock_guard<std::mutex> lock(_mutex);
169
    auto savedPreferencePacksDirectory =
170
        fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks";
171
    fs::path preferencePackDirectory(savedPreferencePacksDirectory / packName);
172
    if (fs::exists(preferencePackDirectory) && !fs::is_directory(preferencePackDirectory))
173
        throw std::runtime_error("Cannot create " + savedPreferencePacksDirectory.string()
174
                                 + ": file with that name exists already");
175

176
    if (!fs::exists(preferencePackDirectory)) fs::create_directories(preferencePackDirectory);
177

178
    // Create or update the saved user preferencePacks package.xml metadata file
179
    std::unique_ptr<App::Metadata> metadata;
180
    if (fs::exists(savedPreferencePacksDirectory / "package.xml")) {
181
        metadata = std::make_unique<App::Metadata>(savedPreferencePacksDirectory / "package.xml");
182
    }
183
    else {
184
        metadata = std::make_unique<App::Metadata>();
185
        metadata->setName("User-Saved Preference Packs");
186
        std::stringstream str;
187
        str << "Generated automatically -- edits may be lost when saving new preference packs. To "
188
            << "distribute one or more of these packs:\n"
189
            << "    1) copy the entire SavedPreferencePacks directory to a convenient location,\n"
190
            << "    2) rename the directory (usually to the name of the preference pack you are "
191
            << "distributing),\n"
192
            << "    3) delete any subfolders containing packs you don't want to distribute,\n"
193
            << "    4) use git to initialize the directory as a git repository,\n"
194
            << "    5) push it to a remote git host,\n"
195
            << "    6) activate Developer Mode in the Addon Manager,\n"
196
            << "    7) use Developer Tools in the Addon Manager to update the metadata file,\n"
197
            << "    8) add, commit, and push the updated package.xml file,\n"
198
            << "    9) add your remote host to the custom repositories list in the Addon Manager"
199
            << " preferences,\n"
200
            << "   10) use the Addon Manager to install your preference pack locally for testing.";
201
        metadata->setDescription(str.str());
202
        metadata->addLicense(App::Meta::License("All Rights Reserved", fs::path()));
203
    }
204
    for (const auto &item : metadata->content()) {
205
        if (item.first == "preferencepack") {
206
            if (item.second.name() == packName) {
207
                // A pack with this name exists already, bail out
208
                return;
209
            }
210
        }
211
    }
212
    App::Metadata newPreferencePackMetadata;
213
    newPreferencePackMetadata.setName(packName);
214

215
    metadata->addContentItem("preferencepack", newPreferencePackMetadata);
216
    metadata->write(savedPreferencePacksDirectory / "package.xml");
217
}
218

219
void Gui::PreferencePackManager::importConfig(const std::string& packName,
220
    const boost::filesystem::path& path)
221
{
222
    AddPackToMetadata(packName);
223

224
    auto savedPreferencePacksDirectory =
225
        fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks";
226
    auto cfgFilename = savedPreferencePacksDirectory / packName / (packName + ".cfg");
227
    fs::copy_file(path, cfgFilename, fs::copy_option::overwrite_if_exists);
228
    rescan();
229
}
230

231
void Gui::PreferencePackManager::FindPreferencePacksInPackage(const fs::path &mod)
232
{
233
    try {
234
        TryFindPreferencePacksInPackage(mod);
235
    }
236
    catch (const std::exception& e) {
237
        Base::Console().Error("%s\n", e.what());
238
    }
239
    catch (...) {
240
        // Failed to read the metadata, or to create the preferencePack based on it...
241
        auto packageMetadataFile = mod / "package.xml";
242
        Base::Console().Error("Failed to read %s\n", packageMetadataFile.string().c_str());
243
    }
244
}
245

246
void PreferencePackManager::TryFindPreferencePacksInPackage(const boost::filesystem::path& mod)
247
{
248
    auto packageMetadataFile = mod / "package.xml";
249
    static const auto modDirectory = fs::path(App::Application::getUserAppDataDir()) / "Mod" / "SavedPreferencePacks";
250
    static const auto resourcePath = fs::path(App::Application::getResourceDir()) / "Gui" / "PreferencePacks";
251

252
    if (fs::exists(packageMetadataFile) && fs::is_regular_file(packageMetadataFile)) {
253
        App::Metadata metadata(packageMetadataFile);
254
        auto content = metadata.content();
255
        auto basename = mod.filename().string();
256
        if (mod == modDirectory)
257
            basename = "##USER_SAVED##";
258
        else if (mod == resourcePath)
259
            basename = "##BUILT_IN##";
260
        for (const auto& item : content) {
261
            if (item.first == "preferencepack") {
262
                if (isVisible(basename, item.second.name())) {
263
                    PreferencePack newPreferencePack(mod / item.second.name(), item.second);
264
                    _preferencePacks.insert(std::make_pair(newPreferencePack.name(), newPreferencePack));
265
                }
266
            }
267
        }
268
    }
269
}
270

271
std::vector<std::string> PreferencePackManager::preferencePackNames() const
272
{
273
    std::lock_guard<std::mutex> lock(_mutex);
274
    std::vector<std::string> names;
275
    for (const auto& preferencePack : _preferencePacks)
276
        names.push_back(preferencePack.first);
277
    return names;
278
}
279

280
std::map<std::string, PreferencePack> Gui::PreferencePackManager::preferencePacks() const
281
{
282
    return _preferencePacks;
283
}
284

285
bool PreferencePackManager::apply(const std::string& preferencePackName) const
286
{
287
    std::lock_guard<std::mutex> lock(_mutex);
288
    if (auto preferencePack = _preferencePacks.find(preferencePackName); preferencePack != _preferencePacks.end()) {
289
        BackupCurrentConfig();
290
        bool wasApplied = preferencePack->second.apply();
291
        if (wasApplied) {
292
            // If the visibility state of the dock windows was changed we have to manually reload their state
293
            Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance();
294
            pDockMgr->loadState();
295

296
            // Same goes for toolbars:
297
            Gui::ToolBarManager* pToolbarMgr = Gui::ToolBarManager::getInstance();
298
            pToolbarMgr->restoreState();
299

300
            // TODO: Are there other things that have to be manually triggered?
301
        }
302
        return wasApplied;
303
    }
304
    else {
305
        throw std::runtime_error("No such Preference Pack: " + preferencePackName);
306
    }
307
}
308

309
std::string findUnusedName(const std::string &basename, ParameterGrp::handle parent)
310
{
311
    int i = 1;
312
    while (true) {
313
        std::ostringstream nameToTest;
314
        nameToTest << basename << "_" << i;
315
        if (!parent->HasGroup(nameToTest.str().c_str()))
316
            return nameToTest.str();
317
        ++i;
318
    }
319
}
320

321
bool PreferencePackManager::isVisible(const std::string& addonName, const std::string& preferencePackName) const
322
{
323
    if (addonName.empty() || preferencePackName.empty())
324
        return true;
325

326
    auto pref = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General/HiddenPreferencePacks");
327
    auto hiddenPacks = pref->GetGroups();
328
    auto hiddenPack = std::find_if(hiddenPacks.begin(), hiddenPacks.end(), [addonName, preferencePackName](ParameterGrp::handle handle) {
329
        return (handle->GetASCII("addonName", "") == addonName) && (handle->GetASCII("preferencePackName", "") == preferencePackName);
330
        });
331
    if (hiddenPack == hiddenPacks.end())
332
        return true;
333
    else
334
        return false;
335
}
336

337
void PreferencePackManager::toggleVisibility(const std::string& addonName, const std::string& preferencePackName)
338
{
339
    if (preferencePackName.empty())
340
        return;
341
    auto pref = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General/HiddenPreferencePacks");
342
    auto hiddenPacks = pref->GetGroups();
343
    auto hiddenPack = std::find_if(hiddenPacks.begin(), hiddenPacks.end(), [addonName,preferencePackName](ParameterGrp::handle handle) {
344
        return (handle->GetASCII("addonName", "") == addonName) && (handle->GetASCII("preferencePackName", "") == preferencePackName);
345
        });
346
    if (hiddenPack == hiddenPacks.end()) {
347
        auto name = findUnusedName("PreferencePack", pref);
348
        auto group = pref->GetGroup(name.c_str());
349
        group->SetASCII("addonName", addonName.c_str());
350
        group->SetASCII("preferencePackName", preferencePackName.c_str());
351
    }
352
    else {
353
        auto groupName = (*hiddenPack)->GetGroupName();
354
        hiddenPacks.clear(); // To decrement the reference count of the group we are about the remove...
355
        pref->RemoveGrp(groupName);
356
    }
357
    rescan();
358
}
359

360
void Gui::PreferencePackManager::deleteUserPack(const std::string& name)
361
{
362
    if (name.empty())
363
        return;
364
    auto savedPreferencePacksDirectory = fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks";
365
    auto savedPath = savedPreferencePacksDirectory / name;
366
    std::unique_ptr<App::Metadata> metadata;
367
    if (fs::exists(savedPreferencePacksDirectory / "package.xml")) {
368
        metadata = std::make_unique<App::Metadata>(savedPreferencePacksDirectory / "package.xml");
369
    }
370
    else {
371
        throw std::runtime_error("Lost the user-saved preference packs metadata file!");
372
    }
373
    metadata->removeContentItem("preferencepack", name);
374
    metadata->write(savedPreferencePacksDirectory / "package.xml");
375
    if (fs::exists(savedPath))
376
        fs::remove_all(savedPath);
377
    rescan();
378
}
379

380
void copyTemplateParameters(Base::Reference<ParameterGrp> templateGroup, const std::string& path, Base::Reference<ParameterGrp> outputGroup)
381
{
382
    auto userParameterHandle = App::GetApplication().GetParameterGroupByPath(path.c_str());
383

384
    // Ensure that the DockWindowManager has saved its current state:
385
    Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance();
386
    pDockMgr->saveState();
387

388
    // Do the same for ToolBars
389
    Gui::ToolBarManager* pToolbarMgr = Gui::ToolBarManager::getInstance();
390
    pToolbarMgr->saveState();
391

392
    auto boolMap = templateGroup->GetBoolMap();
393
    for (const auto& kv : boolMap) {
394
        auto currentValue = userParameterHandle->GetBool(kv.first.c_str(), kv.second);
395
        outputGroup->SetBool(kv.first.c_str(), currentValue);
396
    }
397

398
    auto intMap = templateGroup->GetIntMap();
399
    for (const auto& kv : intMap) {
400
        auto currentValue = userParameterHandle->GetInt(kv.first.c_str(), kv.second);
401
        outputGroup->SetInt(kv.first.c_str(), currentValue);
402
    }
403

404
    auto uintMap = templateGroup->GetUnsignedMap();
405
    for (const auto& kv : uintMap) {
406
        auto currentValue = userParameterHandle->GetUnsigned(kv.first.c_str(), kv.second);
407
        outputGroup->SetUnsigned(kv.first.c_str(), currentValue);
408
    }
409

410
    auto floatMap = templateGroup->GetFloatMap();
411
    for (const auto& kv : floatMap) {
412
        auto currentValue = userParameterHandle->GetFloat(kv.first.c_str(), kv.second);
413
        outputGroup->SetFloat(kv.first.c_str(), currentValue);
414
    }
415

416
    auto asciiMap = templateGroup->GetASCIIMap();
417
    for (const auto& kv : asciiMap) {
418
        auto currentValue = userParameterHandle->GetASCII(kv.first.c_str(), kv.second.c_str());
419
        outputGroup->SetASCII(kv.first.c_str(), currentValue.c_str());
420
    }
421

422
    // Recurse...
423
    auto templateSubgroups = templateGroup->GetGroups();
424
    for (auto& templateSubgroup : templateSubgroups) {
425
        std::string sgName = templateSubgroup->GetGroupName();
426
        auto outputSubgroupHandle = outputGroup->GetGroup(sgName.c_str());
427
        copyTemplateParameters(templateSubgroup, path + "/" + sgName, outputSubgroupHandle);
428
    }
429
}
430

431
void copyTemplateParameters(/*const*/ ParameterManager& templateParameterManager, ParameterManager& outputParameterManager)
432
{
433
    auto groups = templateParameterManager.GetGroups();
434
    for (auto& group : groups) {
435
        std::string name = group->GetGroupName();
436
        auto groupHandle = outputParameterManager.GetGroup(name.c_str());
437
        copyTemplateParameters(group, "User parameter:" + name, groupHandle);
438
    }
439
}
440

441
void PreferencePackManager::save(const std::string& name, const std::vector<TemplateFile>& templates)
442
{
443
    if (templates.empty())
444
        return;
445

446
    AddPackToMetadata(name);
447

448
    // Create the config file
449
    auto outputParameterManager = ParameterManager::Create();
450
    outputParameterManager->CreateDocument();
451
    for (const auto& t : templates) {
452
        auto templateParameterManager = ParameterManager::Create();
453
        templateParameterManager->LoadDocument(t.path.string().c_str());
454
        copyTemplateParameters(*templateParameterManager, *outputParameterManager);
455
    }
456
    auto savedPreferencePacksDirectory =
457
        fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks";
458
    auto cfgFilename = savedPreferencePacksDirectory / name / (name + ".cfg");
459
    outputParameterManager->SaveDocument(cfgFilename.string().c_str());
460
}
461

462
// Needed until we support only C++20 and above and can use std::string's built-in ends_with()
463
bool fc_ends_with(std::string_view str, std::string_view suffix)
464
{
465
    return str.size() >= suffix.size() && str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
466
}
467

468
std::vector<fs::path> scanForTemplateFolders(const std::string& groupName, const fs::path& entry)
469
{
470
    // From this location, find the folder(s) called "PreferencePackTemplates"
471
    std::vector<fs::path> templateFolders;
472
    if (fs::exists(entry)) {
473
        if (fs::is_directory(entry)) {
474
            if (entry.filename() == "PreferencePackTemplates" ||
475
                entry.filename() == "preference_pack_templates") {
476
                templateFolders.push_back(entry);
477
            }
478
            else {
479
                std::string subgroupName = groupName + "/" + entry.filename().string();
480
                for (const auto& subentry : fs::directory_iterator(entry)) {
481
                    auto contents = scanForTemplateFolders(subgroupName, subentry);
482
                    std::copy(contents.begin(), contents.end(), std::back_inserter(templateFolders));
483
                }
484
            }
485
        }
486
    }
487
    return templateFolders;
488
}
489

490
std::vector<PreferencePackManager::TemplateFile> scanForTemplateFiles(const std::string& groupName, const fs::path& entry)
491
{
492
    auto templateFolders = scanForTemplateFolders(groupName, entry);
493

494
    std::vector<PreferencePackManager::TemplateFile> templateFiles;
495
    for (const auto& templateDir : templateFolders) {
496
        if (!fs::exists(templateDir) || !fs::is_directory(templateDir))
497
            continue;
498
        for (const auto& entry : fs::directory_iterator(templateDir)) {
499
            if (entry.path().extension() == ".cfg") {
500
                auto name = entry.path().filename().stem().string();
501
                std::replace(name.begin(), name.end(), '_', ' ');
502
                // Make sure we don't insert the same thing twice...
503
                if (std::find_if(templateFiles.begin(), templateFiles.end(), [groupName, name](const auto &rhs)->bool {
504
                    return groupName == rhs.group && name == rhs.name;
505
                    } ) != templateFiles.end())
506
                    continue;
507
                templateFiles.push_back({ groupName, name, entry });
508
            }
509
        }
510
    }
511
    return templateFiles;
512
}
513

514
std::vector<PreferencePackManager::TemplateFile> PreferencePackManager::templateFiles(bool rescan)
515
{
516
    std::lock_guard<std::mutex> lock(_mutex);
517
    if (!_templateFiles.empty() && !rescan)
518
        return _templateFiles;
519

520
    // Locate all of the template files available on this system
521
    // Template files end in ".cfg" -- They are located in:
522
    // * $INSTALL_DIR/data/Gui/PreferencePackTemplates/(Appearance|Behavior)/*
523
    // * $DATA_DIR/Mod/**/PreferencePackTemplates/(Appearance|Behavior)/*
524
    // (alternate spellings are provided for packages using CamelCase and snake_case, and both major English dialects)
525

526
    auto resourcePath = fs::path(App::Application::getResourceDir()) / "Gui";
527
    auto modPath = fs::path(App::Application::getUserAppDataDir()) / "Mod";
528

529
    std::string group = "Built-In";
530
    if (fs::exists(resourcePath) && fs::is_directory(resourcePath)) {
531
        const auto localFiles = scanForTemplateFiles(group, resourcePath);
532
        std::copy(localFiles.begin(), localFiles.end(), std::back_inserter(_templateFiles));
533
    }
534

535
    if (fs::exists(modPath) && fs::is_directory(modPath)) {
536
        for (const auto& mod : fs::directory_iterator(modPath)) {
537
            group = mod.path().filename().string();
538
            const auto localFiles = scanForTemplateFiles(group, mod);
539
            std::copy(localFiles.begin(), localFiles.end(), std::back_inserter(_templateFiles));
540
        }
541
    }
542

543
    return _templateFiles;
544
}
545

546
void Gui::PreferencePackManager::BackupCurrentConfig() const
547
{
548
    auto backupDirectory = fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks" / "Backups";
549
    fs::create_directories(backupDirectory);
550

551
    // Create a timestamped filename:
552
    auto time = std::time(nullptr);
553
    std::ostringstream timestampStream;
554
    timestampStream << "user." << time << ".cfg";
555
    auto filename = backupDirectory / timestampStream.str();
556

557
    // Save the current config:
558
    App::GetApplication().GetUserParameter().SaveDocument(filename.string().c_str());
559
}
560

561
void Gui::PreferencePackManager::DeleteOldBackups() const
562
{
563
    constexpr auto oneWeek = 60.0 * 60.0 * 24.0 * 7.0;
564
    const auto now = std::time(nullptr);
565
    auto backupDirectory = fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks" / "Backups";
566
    if (fs::exists(backupDirectory) && fs::is_directory(backupDirectory)) {
567
        for (const auto& backup : fs::directory_iterator(backupDirectory)) {
568
            if (std::difftime(now, fs::last_write_time(backup)) > oneWeek) {
569
                try {
570
                    fs::remove(backup);
571
                }
572
                catch (...) {}
573
            }
574
        }
575
    }
576
}
577

578
std::vector<boost::filesystem::path> Gui::PreferencePackManager::configBackups() const
579
{
580
    std::vector<boost::filesystem::path> results;
581
    auto backupDirectory = fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks" / "Backups";
582
    if (fs::exists(backupDirectory) && fs::is_directory(backupDirectory)) {
583
        for (const auto& backup : fs::directory_iterator(backupDirectory)) {
584
            results.push_back(backup);
585
        }
586
    }
587
    return results;
588
}
589

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.