1 #include "Configuration.h"
2 #include <QJsonObject>
3 #include <QJsonArray>
4 #include <QDir>
5 #include <QFontDatabase>
6 #include <QFile>
7 #include <QApplication>
8
9 #ifdef CUTTER_ENABLE_KSYNTAXHIGHLIGHTING
10 #include <KSyntaxHighlighting/repository.h>
11 #include <KSyntaxHighlighting/theme.h>
12 #include <KSyntaxHighlighting/definition.h>
13 #endif
14
15 #include "common/ColorThemeWorker.h"
16 #include "common/SyntaxHighlighter.h"
17 #include "common/ResourcePaths.h"
18
19 /* Map with names of themes associated with its color palette
20 * (Dark or Light), so for dark interface themes will be shown only Dark color themes
21 * and for light - only light ones.
22 */
23 const QHash<QString, ColorFlags> Configuration::relevantThemes = {
24 { "ayu", DarkFlag },
25 { "consonance", DarkFlag },
26 { "darkda", DarkFlag },
27 { "onedark", DarkFlag },
28 { "solarized", DarkFlag },
29 { "zenburn", DarkFlag },
30 { "cutter", LightFlag },
31 { "dark", LightFlag },
32 { "matrix", LightFlag },
33 { "tango", LightFlag },
34 { "white", LightFlag }
35 };
36 static const QString DEFAULT_LIGHT_COLOR_THEME = "cutter";
37 static const QString DEFAULT_DARK_COLOR_THEME = "ayu";
38
39
40 const QHash<QString, QHash<ColorFlags, QColor>> Configuration::cutterOptionColors = {
41 { "gui.cflow", { { DarkFlag, QColor(0xff, 0xff, 0xff) },
42 { LightFlag, QColor(0x00, 0x00, 0x00) }} },
43 { "gui.dataoffset", { { DarkFlag, QColor(0xff, 0xff, 0xff) },
44 { LightFlag, QColor(0x00, 0x00, 0x00) }} },
45 { "gui.imports", { { DarkFlag, QColor(0x32, 0x8c, 0xff) },
46 { LightFlag, QColor(0x32, 0x8c, 0xff) }} },
47 { "gui.item_invalid", { { DarkFlag, QColor(0x9b, 0x9b, 0x9b) },
48 { LightFlag, QColor(0x9b, 0x9b, 0x9b) }} },
49 { "gui.main", { { DarkFlag, QColor(0x00, 0x80, 0x00) },
50 { LightFlag, QColor(0x00, 0x80, 0x00) }} },
51 { "gui.item_unsafe", { { DarkFlag, QColor(0xff, 0x81, 0x7b) },
52 { LightFlag, QColor(0xff, 0x81, 0x7b) }} },
53 { "gui.navbar.seek", { { DarkFlag, QColor(0xe9, 0x56, 0x56) },
54 { LightFlag, QColor(0xff, 0x00, 0x00) }} },
55 { "gui.navbar.pc", { { DarkFlag, QColor(0x42, 0xee, 0xf4) },
56 { LightFlag, QColor(0x42, 0xee, 0xf4) }} },
57 { "gui.navbar.code", { { DarkFlag, QColor(0x82, 0xc8, 0x6f) },
58 { LightFlag, QColor(0x68, 0xe5, 0x45) }} },
59 { "gui.navbar.str", { { DarkFlag, QColor(0x6f, 0x86, 0xd8) },
60 { LightFlag, QColor(0x45, 0x68, 0xe5) }} },
61 { "gui.navbar.sym", { { DarkFlag, QColor(0xdd, 0xa3, 0x68) },
62 { LightFlag, QColor(0xe5, 0x96, 0x45) }} },
63 { "gui.navbar.empty", { { DarkFlag, QColor(0x64, 0x64, 0x64) },
64 { LightFlag, QColor(0xdc, 0xec, 0xf5) }} },
65 { "gui.breakpoint_background", { { DarkFlag, QColor(0x8c, 0x4c, 0x4c) },
66 { LightFlag, QColor(0xe9, 0x8f, 0x8f) }} },
67 { "gui.overview.node", { { DarkFlag, QColor(0x64, 0x64, 0x64) },
68 { LightFlag, QColor(0xf5, 0xfa, 0xff) }} },
69 { "gui.tooltip.background", { { DarkFlag, QColor(0x2a, 0x2c, 0x2e) },
70 { LightFlag, QColor(0xfa, 0xfc, 0xfe) }} },
71 { "gui.tooltip.foreground", { { DarkFlag, QColor(0xfa, 0xfc, 0xfe) },
72 { LightFlag, QColor(0x2a, 0x2c, 0x2e) }} },
73 { "gui.border", { { DarkFlag, QColor(0x64, 0x64, 0x64) },
74 { LightFlag, QColor(0x91, 0xc8, 0xfa) }} },
75 { "gui.background", { { DarkFlag, QColor(0x25, 0x28, 0x2b) },
76 { LightFlag, QColor(0xff, 0xff, 0xff) }} },
77 { "gui.alt_background", { { DarkFlag, QColor(0x1c, 0x1f, 0x24) },
78 { LightFlag, QColor(0xf5, 0xfa, 0xff) }} },
79 { "gui.disass_selected", { { DarkFlag, QColor(0x1f, 0x22, 0x28) },
80 { LightFlag, QColor(0xff, 0xff, 0xff) }} },
81 { "lineHighlight", { { DarkFlag, QColor(0x15, 0x1d, 0x1d, 0x96) },
82 { LightFlag, QColor(0xd2, 0xd2, 0xff, 0x96) }} },
83 { "wordHighlight", { { DarkFlag, QColor(0x34, 0x3a, 0x47, 0xff) },
84 { LightFlag, QColor(0xb3, 0x77, 0xd6, 0x3c) }} },
85 { "highlightPC", { { DarkFlag, QColor(0x57, 0x1a, 0x07) },
86 { LightFlag, QColor(0xd6, 0xff, 0xd2) }} },
87 { "gui.overview.fill", { { DarkFlag, QColor(0xff, 0xff, 0xff, 0x28) },
88 { LightFlag, QColor(0xaf, 0xd9, 0xea, 0x41) }} },
89 { "gui.overview.border", { { DarkFlag, QColor(0x63, 0xda, 0xe8, 0x32) },
90 { LightFlag, QColor(0x63, 0xda, 0xe8, 0x32) }} },
91 { "gui.navbar.err", { { DarkFlag, QColor(0x03, 0xaa, 0xf5) },
92 { LightFlag, QColor(0x03, 0xaa, 0xf5) }} }
93 };
94
95 Configuration *Configuration::mPtr = nullptr;
96
97 /**
98 * @brief All asm.* options saved as settings. Values are the default values.
99 */
100 static const QHash<QString, QVariant> asmOptions = {
101 { "asm.esil", false },
102 { "asm.pseudo", false },
103 { "asm.offset", true },
104 { "asm.xrefs", false },
105 { "asm.indent", false },
106 { "asm.describe", false },
107 { "asm.slow", true },
108 { "asm.lines", true },
109 { "asm.lines.fcn", true },
110 { "asm.flags.offset", false },
111 { "asm.emu", false },
112 { "emu.str", false},
113 { "asm.cmt.right", true },
114 { "asm.cmt.col", 35 },
115 { "asm.var.summary", false },
116 { "asm.bytes", false },
117 { "asm.size", false },
118 { "asm.bytes.space", false },
119 { "asm.lbytes", true },
120 { "asm.nbytes", 10 },
121 { "asm.syntax", "intel" },
122 { "asm.ucase", false },
123 { "asm.bb.line", false },
124 { "asm.capitalize", false },
125 { "asm.var.sub", true },
126 { "asm.sub.varonly", true },
127 { "asm.tabs", 8 },
128 { "asm.tabs.off", 5 },
129 { "asm.marks", false },
130 { "asm.refptr", false },
131 { "asm.flags.real", true },
132 { "asm.reloff", false },
133 { "asm.reloff.flags", false },
134 { "esil.breakoninvalid",true },
135 { "graph.offset", false}
136 };
137
138
Configuration()139 Configuration::Configuration() : QObject(), nativePalette(qApp->palette())
140 {
141 mPtr = this;
142 if (!s.isWritable()) {
143 QMessageBox::critical(nullptr,
144 tr("Critical!"),
145 tr("!!! Settings are not writable! Make sure you have a write access to \"%1\"")
146 .arg(s.fileName())
147 );
148 }
149 #ifdef CUTTER_ENABLE_KSYNTAXHIGHLIGHTING
150 kSyntaxHighlightingRepository = nullptr;
151 #endif
152 }
153
instance()154 Configuration *Configuration::instance()
155 {
156 if (!mPtr)
157 mPtr = new Configuration();
158 return mPtr;
159 }
160
loadInitial()161 void Configuration::loadInitial()
162 {
163 setInterfaceTheme(getInterfaceTheme());
164 setColorTheme(getColorTheme());
165 applySavedAsmOptions();
166
167 #ifdef CUTTER_ENABLE_KSYNTAXHIGHLIGHTING
168 kSyntaxHighlightingRepository = new KSyntaxHighlighting::Repository();
169 #endif
170 }
171
getDirProjects()172 QString Configuration::getDirProjects()
173 {
174 auto projectsDir = s.value("dir.projects").toString();
175 if (projectsDir.isEmpty()) {
176 projectsDir = Core()->getConfig("dir.projects");
177 setDirProjects(projectsDir);
178 }
179
180 return QDir::toNativeSeparators(projectsDir);
181 }
182
setDirProjects(const QString & dir)183 void Configuration::setDirProjects(const QString &dir)
184 {
185 s.setValue("dir.projects", QDir::toNativeSeparators(dir));
186 }
187
getRecentFolder()188 QString Configuration::getRecentFolder()
189 {
190 QString recentFolder = s.value("dir.recentFolder", QDir::homePath()).toString();
191
192 return QDir::toNativeSeparators(recentFolder);
193 }
194
setRecentFolder(const QString & dir)195 void Configuration::setRecentFolder(const QString &dir)
196 {
197 s.setValue("dir.recentFolder", QDir::toNativeSeparators(dir));
198 }
199
200 /**
201 * @brief Configuration::setFilesTabLastClicked
202 * Set the new file dialog last clicked tab
203 * @param lastClicked
204 */
setNewFileLastClicked(int lastClicked)205 void Configuration::setNewFileLastClicked(int lastClicked)
206 {
207 s.setValue("newFileLastClicked", lastClicked);
208 }
209
getNewFileLastClicked()210 int Configuration::getNewFileLastClicked()
211 {
212 return s.value("newFileLastClicked").toInt();
213 }
214
resetAll()215 void Configuration::resetAll()
216 {
217 // Don't reset all r2 vars, that currently breaks a bunch of stuff.
218 // settingsFile.remove()+loadInitials() should reset all settings configurable using Cutter GUI.
219 //Core()->cmdRaw("e-");
220
221 Core()->setSettings();
222 // Delete the file so no extra configuration is in it.
223 QFile settingsFile(s.fileName());
224 settingsFile.remove();
225 s.clear();
226
227 loadInitial();
228 emit fontsUpdated();
229 }
230
getAutoUpdateEnabled() const231 bool Configuration::getAutoUpdateEnabled() const
232 {
233 return s.value("autoUpdateEnabled", false).toBool();
234 }
235
setAutoUpdateEnabled(bool au)236 void Configuration::setAutoUpdateEnabled(bool au)
237 {
238 s.setValue("autoUpdateEnabled", au);
239 }
240
241 /**
242 * @brief get the current Locale set in Cutter's user configuration
243 * @return a QLocale object describes user's current locale
244 */
getCurrLocale() const245 QLocale Configuration::getCurrLocale() const
246 {
247 return s.value("locale", QLocale().system()).toLocale();
248 }
249
250 /**
251 * @brief sets Cutter's locale
252 * @param l - a QLocale object describes the locate to configure
253 */
setLocale(const QLocale & l)254 void Configuration::setLocale(const QLocale &l)
255 {
256 s.setValue("locale", l);
257 }
258
259 /**
260 * @brief set Cutter's interface language by a given locale name
261 * @param language - a string represents the name of a locale language
262 * @return true on success
263 */
setLocaleByName(const QString & language)264 bool Configuration::setLocaleByName(const QString &language)
265 {
266 const auto &allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript,
267 QLocale::AnyCountry);
268
269 for (auto &it : allLocales) {
270 if (QString::compare(it.nativeLanguageName(), language, Qt::CaseInsensitive) == 0) {
271 setLocale(it);
272 return true;
273 }
274 }
275 return false;
276 }
277
windowColorIsDark()278 bool Configuration::windowColorIsDark()
279 {
280 ColorFlags currentThemeColorFlags = getCurrentTheme()->flag;
281 if (currentThemeColorFlags == ColorFlags::LightFlag) {
282 return false;
283 } else if (currentThemeColorFlags == ColorFlags::DarkFlag) {
284 return true;
285 }
286 return nativeWindowIsDark();
287 }
288
nativeWindowIsDark()289 bool Configuration::nativeWindowIsDark()
290 {
291 const QPalette &palette = qApp->palette();
292 auto windowColor = palette.color(QPalette::Window).toRgb();
293 return (windowColor.red() + windowColor.green() + windowColor.blue()) < 382;
294 }
295
loadNativeStylesheet()296 void Configuration::loadNativeStylesheet()
297 {
298 /* Load Qt Theme */
299 QFile f(":native/native.qss");
300 if (!f.exists()) {
301 qWarning() << "Can't find Native theme stylesheet.";
302 } else {
303 f.open(QFile::ReadOnly | QFile::Text);
304 QTextStream ts(&f);
305 QString stylesheet = ts.readAll();
306 qApp->setStyleSheet(stylesheet);
307 }
308
309 qApp->setPalette(nativePalette);
310 /* Some widgets does not change its palette when QApplication changes one
311 * so this loop force all widgets do this, but all widgets take palette from
312 * QApplication::palette() when they are created so line above is necessary too.
313 */
314 for (auto widget : qApp->allWidgets()) {
315 widget->setPalette(nativePalette);
316 }
317 }
318
319 /**
320 * @brief Loads the Light theme of Cutter and modify special theme colors
321 */
loadLightStylesheet()322 void Configuration::loadLightStylesheet()
323 {
324 /* Load Qt Theme */
325 QFile f(":lightstyle/light.qss");
326 if (!f.exists()) {
327 qWarning() << "Can't find Light theme stylesheet.";
328 } else {
329 f.open(QFile::ReadOnly | QFile::Text);
330 QTextStream ts(&f);
331 QString stylesheet = ts.readAll();
332
333 QPalette p = qApp->palette();
334 p.setColor(QPalette::Text, Qt::black);
335 qApp->setPalette(p);
336
337 qApp->setStyleSheet(stylesheet);
338 }
339 }
340
loadDarkStylesheet()341 void Configuration::loadDarkStylesheet()
342 {
343 /* Load Qt Theme */
344 QFile f(":qdarkstyle/style.qss");
345 if (!f.exists()) {
346 qWarning() << "Can't find Dark theme stylesheet.";
347 } else {
348 f.open(QFile::ReadOnly | QFile::Text);
349 QTextStream ts(&f);
350 QString stylesheet = ts.readAll();
351 #ifdef Q_OS_MACX
352 // see https://github.com/ColinDuquesnoy/QDarkStyleSheet/issues/22#issuecomment-96179529
353 stylesheet += "QDockWidget::title"
354 "{"
355 " background-color: #31363b;"
356 " text-align: center;"
357 " height: 12px;"
358 "}";
359 #endif
360 QPalette p = qApp->palette();
361 p.setColor(QPalette::Text, Qt::white);
362 qApp->setPalette(p);
363 qApp->setStyleSheet(stylesheet);
364 }
365 }
366
loadMidnightStylesheet()367 void Configuration::loadMidnightStylesheet()
368 {
369 /* Load Qt Theme */
370 QFile f(":midnight/style.css");
371 if (!f.exists()) {
372 qWarning() << "Can't find Midnight theme stylesheet.";
373 } else {
374 f.open(QFile::ReadOnly | QFile::Text);
375 QTextStream ts(&f);
376 QString stylesheet = ts.readAll();
377
378 QPalette p = qApp->palette();
379 p.setColor(QPalette::Text, Qt::white);
380 qApp->setPalette(p);
381
382 qApp->setStyleSheet(stylesheet);
383 }
384 }
385
getBaseFont() const386 const QFont Configuration::getBaseFont() const
387 {
388 QFont font = s.value("font", QFont("Inconsolata", 11)).value<QFont>();
389 return font;
390 }
391
getFont() const392 const QFont Configuration::getFont() const
393 {
394 QFont font = getBaseFont();
395 font.setPointSizeF(font.pointSizeF() * getZoomFactor());
396 return font;
397 }
398
setFont(const QFont & font)399 void Configuration::setFont(const QFont &font)
400 {
401 s.setValue("font", font);
402 emit fontsUpdated();
403 }
404
refreshFont()405 void Configuration::refreshFont()
406 {
407 emit fontsUpdated();
408 }
409
getZoomFactor() const410 qreal Configuration::getZoomFactor() const {
411 qreal fontZoom = s.value("zoomFactor", 1.0).value<qreal>();
412 return qMax(fontZoom, 0.1);
413 }
414
setZoomFactor(qreal zoom)415 void Configuration::setZoomFactor(qreal zoom) {
416 s.setValue("zoomFactor", qMax(zoom, 0.1));
417 emit fontsUpdated();
418 }
419
getLastThemeOf(const CutterInterfaceTheme & currInterfaceTheme) const420 QString Configuration::getLastThemeOf(const CutterInterfaceTheme &currInterfaceTheme) const
421 {
422 return s.value("lastThemeOf." + currInterfaceTheme.name,
423 Config()->getColorTheme()).toString();
424 }
425
setInterfaceTheme(int theme)426 void Configuration::setInterfaceTheme(int theme)
427 {
428 if (theme >= cutterInterfaceThemesList().size() ||
429 theme < 0) {
430 theme = 0;
431 }
432 s.setValue("ColorPalette", theme);
433
434 CutterInterfaceTheme interfaceTheme = cutterInterfaceThemesList()[theme];
435
436 if (interfaceTheme.name == "Native") {
437 loadNativeStylesheet();
438 } else if (interfaceTheme.name == "Dark") {
439 loadDarkStylesheet();
440 } else if (interfaceTheme.name == "Midnight") {
441 loadMidnightStylesheet();
442 } else if (interfaceTheme.name == "Light") {
443 loadLightStylesheet();
444 } else {
445 loadNativeStylesheet();
446 }
447
448 for (auto it = cutterOptionColors.cbegin(); it != cutterOptionColors.cend(); it++) {
449 setColor(it.key(), it.value()[interfaceTheme.flag]);
450 }
451
452 adjustColorThemeDarkness();
453
454 emit interfaceThemeChanged();
455 emit colorsUpdated();
456 #ifdef CUTTER_ENABLE_KSYNTAXHIGHLIGHTING
457 emit kSyntaxHighlightingThemeChanged();
458 #endif
459 }
460
getCurrentTheme()461 const CutterInterfaceTheme *Configuration::getCurrentTheme()
462 {
463 int i = getInterfaceTheme();
464 if (i < 0 || i >= cutterInterfaceThemesList().size()) {
465 i = 0;
466 setInterfaceTheme(i);
467 }
468 return &cutterInterfaceThemesList()[i];
469 }
470
471 #ifdef CUTTER_ENABLE_KSYNTAXHIGHLIGHTING
getKSyntaxHighlightingRepository()472 KSyntaxHighlighting::Repository *Configuration::getKSyntaxHighlightingRepository()
473 {
474 return kSyntaxHighlightingRepository;
475 }
476
getKSyntaxHighlightingTheme()477 KSyntaxHighlighting::Theme Configuration::getKSyntaxHighlightingTheme()
478 {
479 auto repo = getKSyntaxHighlightingRepository();
480 if (!repo) {
481 return KSyntaxHighlighting::Theme();
482 }
483 return repo->defaultTheme(
484 getCurrentTheme()->flag & DarkFlag
485 ? KSyntaxHighlighting::Repository::DefaultTheme::DarkTheme
486 : KSyntaxHighlighting::Repository::DefaultTheme::LightTheme);
487 }
488 #endif
489
createSyntaxHighlighter(QTextDocument * document)490 QSyntaxHighlighter *Configuration::createSyntaxHighlighter(QTextDocument *document)
491 {
492 #ifdef CUTTER_ENABLE_KSYNTAXHIGHLIGHTING
493 auto syntaxHighlighter = new SyntaxHighlighter(document);
494 auto repo = getKSyntaxHighlightingRepository();
495 if (repo) {
496 syntaxHighlighter->setDefinition(repo->definitionForName("C"));
497 }
498 return syntaxHighlighter;
499 #else
500 return new FallbackSyntaxHighlighter(document);
501 #endif
502 }
503
getLogoFile()504 QString Configuration::getLogoFile()
505 {
506 return windowColorIsDark()
507 ? QString(":/img/cutter_white_plain.svg")
508 : QString(":/img/cutter_plain.svg");
509 }
510
511 /**
512 * @brief Configuration::setColor sets the local Cutter configuration color
513 * @param name Color Name
514 * @param color The color you want to set
515 */
setColor(const QString & name,const QColor & color)516 void Configuration::setColor(const QString &name, const QColor &color)
517 {
518 s.setValue("colors." + name, color);
519 }
520
setLastThemeOf(const CutterInterfaceTheme & currInterfaceTheme,const QString & theme)521 void Configuration::setLastThemeOf(const CutterInterfaceTheme &currInterfaceTheme, const QString &theme)
522 {
523 s.setValue("lastThemeOf." + currInterfaceTheme.name, theme);
524 }
525
getColor(const QString & name) const526 const QColor Configuration::getColor(const QString &name) const
527 {
528 if (s.contains("colors." + name)) {
529 return s.value("colors." + name).value<QColor>();
530 } else {
531 return s.value("colors.other").value<QColor>();
532 }
533 }
534
setColorTheme(const QString & theme)535 void Configuration::setColorTheme(const QString &theme)
536 {
537 if (theme == "default") {
538 Core()->cmdRaw("ecd");
539 s.setValue("theme", "default");
540 } else {
541 Core()->cmdRaw(QStringLiteral("eco %1").arg(theme));
542 s.setValue("theme", theme);
543 }
544
545 QJsonObject colorTheme = ThemeWorker().getTheme(theme).object();
546 for (auto it = colorTheme.constBegin(); it != colorTheme.constEnd(); it++) {
547 QJsonArray rgb = it.value().toArray();
548 if (rgb.size() != 4) {
549 continue;
550 }
551 setColor(it.key(), QColor(rgb[0].toInt(), rgb[1].toInt(), rgb[2].toInt(), rgb[3].toInt()));
552 }
553
554 emit colorsUpdated();
555 }
556
adjustColorThemeDarkness()557 void Configuration::adjustColorThemeDarkness()
558 {
559 bool windowIsDark = windowColorIsDark();
560 int windowDarkness = windowIsDark ? DarkFlag : LightFlag;
561 int currentColorThemeDarkness = colorThemeDarkness(getColorTheme());
562
563 if ((currentColorThemeDarkness & windowDarkness) == 0) {
564 setColorTheme(windowIsDark ? DEFAULT_DARK_COLOR_THEME : DEFAULT_LIGHT_COLOR_THEME);
565 }
566 }
567
colorThemeDarkness(const QString & colorTheme) const568 int Configuration::colorThemeDarkness(const QString &colorTheme) const
569 {
570 auto flags = relevantThemes.find(colorTheme);
571 if (flags != relevantThemes.end()) {
572 return static_cast<int>(*flags);
573 }
574 return DarkFlag | LightFlag;
575 }
576
resetToDefaultAsmOptions()577 void Configuration::resetToDefaultAsmOptions()
578 {
579 for (auto it = asmOptions.cbegin(); it != asmOptions.cend(); it++) {
580 setConfig(it.key(), it.value());
581 }
582 }
583
applySavedAsmOptions()584 void Configuration::applySavedAsmOptions()
585 {
586 for (auto it = asmOptions.cbegin(); it != asmOptions.cend(); it++) {
587 Core()->setConfig(it.key(), s.value(it.key(), it.value()));
588 }
589 }
590
cutterInterfaceThemesList()591 const QList<CutterInterfaceTheme>& Configuration::cutterInterfaceThemesList()
592 {
593 static const QList<CutterInterfaceTheme> list = {
594 { "Native", Configuration::nativeWindowIsDark() ? DarkFlag : LightFlag },
595 { "Dark", DarkFlag },
596 { "Midnight", DarkFlag },
597 { "Light", LightFlag }
598 };
599 return list;
600 }
601
getConfigVar(const QString & key)602 QVariant Configuration::getConfigVar(const QString &key)
603 {
604 QHash<QString, QVariant>::const_iterator it = asmOptions.find(key);
605 if (it != asmOptions.end()) {
606 switch (it.value().type()) {
607 case QVariant::Type::Bool:
608 return Core()->getConfigb(key);
609 case QVariant::Type::Int:
610 return Core()->getConfigi(key);
611 default:
612 return Core()->getConfig(key);
613 }
614 }
615 return QVariant();
616 }
617
618
getConfigBool(const QString & key)619 bool Configuration::getConfigBool(const QString &key)
620 {
621 return getConfigVar(key).toBool();
622 }
623
getConfigInt(const QString & key)624 int Configuration::getConfigInt(const QString &key)
625 {
626 return getConfigVar(key).toInt();
627 }
628
getConfigString(const QString & key)629 QString Configuration::getConfigString(const QString &key)
630 {
631 return getConfigVar(key).toString();
632 }
633
634 /**
635 * @brief Configuration::setConfig
636 * Set radare2 configuration value (e.g. "asm.lines")
637 * @param key
638 * @param value
639 */
setConfig(const QString & key,const QVariant & value)640 void Configuration::setConfig(const QString &key, const QVariant &value)
641 {
642 if (asmOptions.contains(key)) {
643 s.setValue(key, value);
644 }
645
646 Core()->setConfig(key, value);
647 }
648
649 /**
650 * @brief this function will gather and return available translation for Cutter
651 * @return a list of all available translations
652 */
getAvailableTranslations()653 QStringList Configuration::getAvailableTranslations()
654 {
655 const auto &trDirs = Cutter::getTranslationsDirectories();
656
657 QSet<QString> fileNamesSet;
658 for (const auto &trDir : trDirs) {
659 QDir dir(trDir);
660 if (!dir.exists()) {
661 continue;
662 }
663 const QStringList &currTrFileNames = dir.entryList(QStringList("cutter_*.qm"), QDir::Files,
664 QDir::Name);
665 for (const auto &trFile : currTrFileNames) {
666 fileNamesSet << trFile;
667 }
668 }
669
670 QStringList fileNames = fileNamesSet.values();
671 std::sort(fileNames.begin(), fileNames.end());
672 QStringList languages;
673 QString currLanguageName;
674 auto allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript,
675 QLocale::AnyCountry);
676
677 for (auto i : fileNames) {
678 QString localeName = i.mid(sizeof("cutter_") - 1, 2);
679 for (auto j : allLocales) {
680 if (j.name().startsWith(localeName)) {
681 currLanguageName = j.nativeLanguageName();
682 currLanguageName = currLanguageName.at(0).toUpper() +
683 currLanguageName.right(currLanguageName.length() - 1);
684 languages << currLanguageName;
685 break;
686 }
687 }
688 }
689 return languages << QLatin1String("English");
690 }
691
692 /**
693 * @brief check if this is the first time Cutter's is executed on this computer
694 * @return true if this is first execution; otherwise returns false.
695 */
isFirstExecution()696 bool Configuration::isFirstExecution()
697 {
698 // check if a variable named firstExecution existed in the configuration
699 if (s.contains("firstExecution")) {
700 return false;
701 } else {
702 s.setValue("firstExecution", false);
703 return true;
704 }
705 }
706
getSelectedDecompiler()707 QString Configuration::getSelectedDecompiler()
708 {
709 return s.value("selectedDecompiler").toString();
710 }
711
setSelectedDecompiler(const QString & id)712 void Configuration::setSelectedDecompiler(const QString &id)
713 {
714 s.setValue("selectedDecompiler", id);
715 }
716
getDecompilerAutoRefreshEnabled()717 bool Configuration::getDecompilerAutoRefreshEnabled()
718 {
719 return s.value("decompilerAutoRefresh", true).toBool();
720 }
721
setDecompilerAutoRefreshEnabled(bool enabled)722 void Configuration::setDecompilerAutoRefreshEnabled(bool enabled)
723 {
724 s.setValue("decompilerAutoRefresh", enabled);
725 }
726
enableDecompilerAnnotationHighlighter(bool useDecompilerHighlighter)727 void Configuration::enableDecompilerAnnotationHighlighter(bool useDecompilerHighlighter)
728 {
729 s.setValue("decompilerAnnotationHighlighter", useDecompilerHighlighter);
730 emit colorsUpdated();
731 }
732
isDecompilerAnnotationHighlighterEnabled()733 bool Configuration::isDecompilerAnnotationHighlighterEnabled()
734 {
735 return s.value("decompilerAnnotationHighlighter", true).value<bool>();
736 }
737
getBitmapTransparentState()738 bool Configuration::getBitmapTransparentState()
739 {
740 return s.value("bitmapGraphExportTransparency", false).value<bool>();
741 }
742
getBitmapExportScaleFactor()743 double Configuration::getBitmapExportScaleFactor()
744 {
745 return s.value("bitmapGraphExportScale", 1.0).value<double>();
746 }
747
setBitmapTransparentState(bool inputValueGraph)748 void Configuration::setBitmapTransparentState(bool inputValueGraph)
749 {
750 s.setValue("bitmapGraphExportTransparency", inputValueGraph);
751 }
752
setBitmapExportScaleFactor(double inputValueGraph)753 void Configuration::setBitmapExportScaleFactor(double inputValueGraph)
754 {
755 s.setValue("bitmapGraphExportScale", inputValueGraph);
756 }
757
setGraphSpacing(QPoint blockSpacing,QPoint edgeSpacing)758 void Configuration::setGraphSpacing(QPoint blockSpacing, QPoint edgeSpacing)
759 {
760 s.setValue("graph.blockSpacing", blockSpacing);
761 s.setValue("graph.edgeSpacing", edgeSpacing);
762 }
763
getGraphBlockSpacing()764 QPoint Configuration::getGraphBlockSpacing()
765 {
766 return s.value("graph.blockSpacing", QPoint(20, 40)).value<QPoint>();
767 }
768
getGraphEdgeSpacing()769 QPoint Configuration::getGraphEdgeSpacing()
770 {
771 return s.value("graph.edgeSpacing", QPoint(10, 10)).value<QPoint>();
772 }
773
setOutputRedirectionEnabled(bool enabled)774 void Configuration::setOutputRedirectionEnabled(bool enabled)
775 {
776 this->outputRedirectEnabled = enabled;
777 }
778
getOutputRedirectionEnabled() const779 bool Configuration::getOutputRedirectionEnabled() const
780 {
781 return outputRedirectEnabled;
782 }
783
getGraphBlockEntryOffset()784 bool Configuration::getGraphBlockEntryOffset()
785 {
786 return s.value("graphBlockEntryOffset", true).value<bool>();
787 }
788
setGraphBlockEntryOffset(bool enabled)789 void Configuration::setGraphBlockEntryOffset(bool enabled)
790 {
791 s.setValue("graphBlockEntryOffset", enabled);
792 }