1 /*
2 * Copyright (C) 2011 Felix Geyer <debfx@fobos.de>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 or (at your option)
7 * version 3 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "FilePath.h"
19
20 #include <QCoreApplication>
21 #include <QDir>
22 #include <QLibrary>
23
24 #include "config-keepassx.h"
25 #include "core/Global.h"
26
27 FilePath* FilePath::m_instance(nullptr);
28
dataPath(const QString & name)29 QString FilePath::dataPath(const QString& name)
30 {
31 if (name.isEmpty() || name.startsWith('/')) {
32 return m_dataPath + name;
33 }
34 else {
35 return m_dataPath + "/" + name;
36 }
37 }
38
pluginPath(const QString & name)39 QString FilePath::pluginPath(const QString& name)
40 {
41 QStringList pluginPaths;
42
43 QDir buildDir(QCoreApplication::applicationDirPath() + "/autotype");
44 const QStringList buildDirEntryList = buildDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
45 for (const QString& dir : buildDirEntryList) {
46 pluginPaths << QCoreApplication::applicationDirPath() + "/autotype/" + dir;
47 }
48
49 // for TestAutoType
50 pluginPaths << QCoreApplication::applicationDirPath() + "/../src/autotype/test";
51
52 pluginPaths << QCoreApplication::applicationDirPath();
53
54 QString configuredPluginDir = KEEPASSX_PLUGIN_DIR;
55 if (configuredPluginDir != ".") {
56 if (QDir(configuredPluginDir).isAbsolute()) {
57 pluginPaths << configuredPluginDir;
58 }
59 else {
60 QString relativePluginDir = QString("%1/../%2")
61 .arg(QCoreApplication::applicationDirPath(), configuredPluginDir);
62 pluginPaths << QDir(relativePluginDir).canonicalPath();
63
64 QString absolutePluginDir = QString("%1/%2")
65 .arg(KEEPASSX_PREFIX_DIR, configuredPluginDir);
66 pluginPaths << QDir(absolutePluginDir).canonicalPath();
67 }
68 }
69
70 QStringList dirFilter;
71 dirFilter << QString("*%1*").arg(name);
72
73 for (const QString& path : asConst(pluginPaths)) {
74 const QStringList fileCandidates = QDir(path).entryList(dirFilter, QDir::Files);
75
76 for (const QString& file : fileCandidates) {
77 QString filePath = path + "/" + file;
78
79 if (QLibrary::isLibrary(filePath)) {
80 return filePath;
81 }
82 }
83 }
84
85 return QString();
86 }
87
applicationIcon()88 QIcon FilePath::applicationIcon()
89 {
90 return icon("apps", "keepassx");
91 }
92
icon(const QString & category,const QString & name,bool fromTheme)93 QIcon FilePath::icon(const QString& category, const QString& name, bool fromTheme)
94 {
95 QString combinedName = category + "/" + name;
96
97 QIcon icon = m_iconCache.value(combinedName);
98
99 if (!icon.isNull()) {
100 return icon;
101 }
102
103 if (fromTheme) {
104 icon = QIcon::fromTheme(name);
105 }
106
107 if (icon.isNull()) {
108 const QList<int> pngSizes = { 16, 22, 24, 32, 48, 64, 128 };
109 QString filename;
110 for (int size : pngSizes) {
111 filename = QString("%1/icons/application/%2x%2/%3.png").arg(m_dataPath, QString::number(size),
112 combinedName);
113 if (QFile::exists(filename)) {
114 icon.addFile(filename, QSize(size, size));
115 }
116 }
117 filename = QString("%1/icons/application/scalable/%2.svgz").arg(m_dataPath, combinedName);
118 if (QFile::exists(filename)) {
119 icon.addFile(filename);
120 }
121 }
122
123 m_iconCache.insert(combinedName, icon);
124
125 return icon;
126 }
127
onOffIcon(const QString & category,const QString & name)128 QIcon FilePath::onOffIcon(const QString& category, const QString& name)
129 {
130 QString combinedName = category + "/" + name;
131 QString cacheName = "onoff/" + combinedName;
132
133 QIcon icon = m_iconCache.value(cacheName);
134
135 if (!icon.isNull()) {
136 return icon;
137 }
138
139 for (int i = 0; i < 2; i++) {
140 QIcon::State state;
141 QString stateName;
142
143 if (i == 0) {
144 state = QIcon::Off;
145 stateName = "off";
146 }
147 else {
148 state = QIcon::On;
149 stateName = "on";
150 }
151
152 const QList<int> pngSizes = { 16, 22, 24, 32, 48, 64, 128 };
153 QString filename;
154 for (int size : pngSizes) {
155 filename = QString("%1/icons/application/%2x%2/%3-%4.png").arg(m_dataPath, QString::number(size),
156 combinedName, stateName);
157 if (QFile::exists(filename)) {
158 icon.addFile(filename, QSize(size, size), QIcon::Normal, state);
159 }
160 }
161 filename = QString("%1/icons/application/scalable/%2-%3.svgz").arg(m_dataPath, combinedName, stateName);
162 if (QFile::exists(filename)) {
163 icon.addFile(filename, QSize(), QIcon::Normal, state);
164 }
165 }
166
167 m_iconCache.insert(cacheName, icon);
168
169 return icon;
170 }
171
FilePath()172 FilePath::FilePath()
173 {
174 const QString appDirPath = QCoreApplication::applicationDirPath();
175 bool isDataDirAbsolute = QDir::isAbsolutePath(KEEPASSX_DATA_DIR);
176 Q_UNUSED(isDataDirAbsolute);
177
178 if (false) {
179 }
180 #ifdef QT_DEBUG
181 else if (testSetDir(QString(KEEPASSX_SOURCE_DIR) + "/share")) {
182 }
183 #endif
184 #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
185 else if (isDataDirAbsolute && testSetDir(KEEPASSX_DATA_DIR)) {
186 }
187 else if (!isDataDirAbsolute && testSetDir(QString("%1/../%2").arg(appDirPath, KEEPASSX_DATA_DIR))) {
188 }
189 else if (!isDataDirAbsolute && testSetDir(QString("%1/%2").arg(KEEPASSX_PREFIX_DIR, KEEPASSX_DATA_DIR))) {
190 }
191 #endif
192 #ifdef Q_OS_MAC
193 else if (testSetDir(appDirPath + "/../Resources")) {
194 }
195 #endif
196 #ifdef Q_OS_WIN
197 else if (testSetDir(appDirPath + "/share")) {
198 }
199 #endif
200
201 if (m_dataPath.isEmpty()) {
202 qWarning("FilePath::DataPath: can't find data dir");
203 }
204 else {
205 m_dataPath = QDir::cleanPath(m_dataPath);
206 }
207 }
208
testSetDir(const QString & dir)209 bool FilePath::testSetDir(const QString& dir)
210 {
211 if (QFile::exists(dir + "/icons/database/C00_Password.png")) {
212 m_dataPath = dir;
213 return true;
214 }
215 else {
216 return false;
217 }
218 }
219
instance()220 FilePath* FilePath::instance()
221 {
222 if (!m_instance) {
223 m_instance = new FilePath();
224 }
225
226 return m_instance;
227 }
228