1 // Aseprite
2 // Copyright (C) 2001-2018 David Capello
3 //
4 // This program is distributed under the terms of
5 // the End-User License Agreement for Aseprite.
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #include "app/recent_files.h"
12
13 #include "app/ini_file.h"
14 #include "base/fs.h"
15 #include "fmt/format.h"
16
17 #include <cstdio>
18 #include <cstring>
19 #include <set>
20
21 namespace {
22
23 const char* kRecentFilesSection = "RecentFiles";
24 const char* kRecentFoldersSection = "RecentPaths";
25
26 struct compare_path {
27 std::string a;
compare_path__anonf2016b320111::compare_path28 compare_path(const std::string& a) : a(a) { }
operator ()__anonf2016b320111::compare_path29 bool operator()(const std::string& b) const {
30 return base::compare_filenames(a, b) == 0;
31 }
32 };
33
format_filename_var(const int i)34 std::string format_filename_var(const int i) {
35 return fmt::format("Filename{0:02d}", i);
36 }
37
format_folder_var(const int i)38 std::string format_folder_var(const int i) {
39 return fmt::format("Path{0:02d}", i);
40 }
41
42 }
43
44 namespace app {
45
RecentFiles(const int limit)46 RecentFiles::RecentFiles(const int limit)
47 : m_files(limit)
48 , m_paths(limit)
49 {
50 for (int c=m_files.limit()-1; c>=0; c--) {
51 const char* filename = get_config_string(kRecentFilesSection,
52 format_filename_var(c).c_str(),
53 nullptr);
54 if (filename && *filename && base::is_file(filename)) {
55 std::string fn = normalizePath(filename);
56 m_files.addItem(fn, compare_path(fn));
57 }
58 }
59
60 for (int c=m_paths.limit()-1; c>=0; c--) {
61 const char* path = get_config_string(kRecentFoldersSection,
62 format_folder_var(c).c_str(),
63 nullptr);
64 if (path && *path) {
65 std::string p = normalizePath(path);
66 m_paths.addItem(p, compare_path(p));
67 }
68 }
69 }
70
~RecentFiles()71 RecentFiles::~RecentFiles()
72 {
73 // Save recent files
74
75 int c = 0;
76 for (auto const& filename : m_files) {
77 set_config_string(kRecentFilesSection,
78 format_filename_var(c).c_str(),
79 filename.c_str());
80 ++c;
81 }
82 for (; c<m_files.limit(); ++c) {
83 del_config_value(kRecentFilesSection,
84 format_filename_var(c).c_str());
85 }
86
87 // Save recent folders
88
89 c = 0;
90 for (auto const& path : m_paths) {
91 set_config_string(kRecentFoldersSection,
92 format_folder_var(c).c_str(),
93 path.c_str());
94 ++c;
95 }
96 for (; c<m_files.limit(); ++c) {
97 del_config_value(kRecentFoldersSection,
98 format_folder_var(c).c_str());
99 }
100 }
101
addRecentFile(const std::string & filename)102 void RecentFiles::addRecentFile(const std::string& filename)
103 {
104 std::string fn = normalizePath(filename);
105 m_files.addItem(fn, compare_path(fn));
106
107 std::string path = base::get_file_path(fn);
108 m_paths.addItem(path, compare_path(path));
109
110 Changed();
111 }
112
removeRecentFile(const std::string & filename)113 void RecentFiles::removeRecentFile(const std::string& filename)
114 {
115 std::string fn = normalizePath(filename);
116 m_files.removeItem(fn, compare_path(fn));
117
118 std::string dir = base::get_file_path(fn);
119 if (!base::is_directory(dir))
120 removeRecentFolder(dir);
121
122 Changed();
123 }
124
removeRecentFolder(const std::string & dir)125 void RecentFiles::removeRecentFolder(const std::string& dir)
126 {
127 std::string fn = normalizePath(dir);
128 m_paths.removeItem(fn, compare_path(fn));
129
130 Changed();
131 }
132
setLimit(const int n)133 void RecentFiles::setLimit(const int n)
134 {
135 m_files.setLimit(n);
136 m_paths.setLimit(n);
137
138 Changed();
139 }
140
clear()141 void RecentFiles::clear()
142 {
143 m_files.clear();
144 m_paths.clear();
145
146 Changed();
147 }
148
normalizePath(const std::string & filename)149 std::string RecentFiles::normalizePath(const std::string& filename)
150 {
151 return base::normalize_path(filename);
152 }
153
154 } // namespace app
155