1 /**
2 * Mandelbulber v2, a 3D fractal generator ,=#MKNmMMKmmßMNWy,
3 * ,B" ]L,,p%%%,,,§;, "K
4 * Copyright (C) 2014-21 Mandelbulber Team §R-==%w["'~5]m%=L.=~5N
5 * ,=mm=§M ]=4 yJKA"/-Nsaj "Bw,==,,
6 * This file is part of Mandelbulber. §R.r= jw",M Km .mM FW ",§=ß., ,TN
7 * ,4R =%["w[N=7]J '"5=],""]]M,w,-; T=]M
8 * Mandelbulber is free software: §R.ß~-Q/M=,=5"v"]=Qf,'§"M= =,M.§ Rz]M"Kw
9 * you can redistribute it and/or §w "xDY.J ' -"m=====WeC=\ ""%""y=%"]"" §
10 * modify it under the terms of the "§M=M =D=4"N #"%==A%p M§ M6 R' #"=~.4M
11 * GNU General Public License as §W =, ][T"]C § § '§ e===~ U !§[Z ]N
12 * published by the 4M",,Jm=,"=e~ § § j]]""N BmM"py=ßM
13 * Free Software Foundation, ]§ T,M=& 'YmMMpM9MMM%=w=,,=MT]M m§;'§,
14 * either version 3 of the License, TWw [.j"5=~N[=§%=%W,T ]R,"=="Y[LFT ]N
15 * or (at your option) TW=,-#"%=;[ =Q:["V"" ],,M.m == ]N
16 * any later version. J§"mr"] ,=,," =="""J]= M"M"]==ß"
17 * §= "=C=4 §"eM "=B:m|4"]#F,§~
18 * Mandelbulber is distributed in "9w=,,]w em%wJ '"~" ,=,,ß"
19 * the hope that it will be useful, . "K= ,=RMMMßM"""
20 * but WITHOUT ANY WARRANTY; .'''
21 * without even the implied warranty
22 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 *
24 * See the GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with Mandelbulber. If not, see <http://www.gnu.org/licenses/>.
27 *
28 * ###########################################################################
29 *
30 * Authors: Krzysztof Marczak (buddhi1980@gmail.com)
31 *
32 * system data - place for system functions and definition of default file paths
33 */
34
35 #include "system.hpp"
36
37 #include <qstylefactory.h>
38
39 #include <clocale>
40
41 #include <QTextStream>
42
43 #include "global_data.hpp"
44 #include "initparameters.hpp"
45 #include "interface.hpp"
46 #include "render_window.hpp"
47 #include "system_data.hpp"
48 #include "system_directories.hpp"
49 #include "write_log.hpp"
50
51 // custom includes
52 #ifndef _WIN32
53 #include <csignal>
54 #include <sys/ioctl.h>
55 #include <unistd.h>
56 #endif
57 #if defined(__APPLE__) || defined(__MACOSX)
58 #include "CoreFoundation/CoreFoundation.h"
59 #endif
60
61 //#define CLSUPPORT
62
63 sSystem systemData;
64 sActualFileNames actualFileNames;
65
InitSystem()66 bool InitSystem()
67 {
68 setlocale(LC_ALL, "");
69 systemData.locale = QLocale::system();
70 systemData.locale.setNumberOptions(QLocale::OmitGroupSeparator);
71 QLocale::setDefault(systemData.locale);
72
73 QTextStream out(stdout);
74 QTextStream outErr(stderr);
75
76 systemData.globalTimer.start();
77
78 QThreadPool::globalInstance()->setExpiryTimeout(1000);
79
80 systemDirectories.homeDir = QDir::toNativeSeparators(QDir::homePath() + QDir::separator());
81 #ifdef _WIN32 /* WINDOWS */
82 systemDirectories.sharedDir = QDir::toNativeSeparators(QDir::currentPath() + QDir::separator());
83 systemDirectories.docDir =
84 QDir::toNativeSeparators(QDir::currentPath() + QDir::separator() + "doc" + QDir::separator());
85 #elif SHARED_DIR_IS_APP_DIR
86 /* used for AppImage, which requires fixed data bundled at same location, as the application */
87 QString sharePath;
88 #if defined(__APPLE__) || defined(__MACOSX)
89 CFURLRef appUrlRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
90 CFStringRef macPath = CFURLCopyFileSystemPath(appUrlRef, kCFURLPOSIXPathStyle);
91 sharePath = QString::fromCFString(macPath);
92 CFRelease(appUrlRef);
93 CFRelease(macPath);
94 #else
95 sharePath = QDir::currentPath();
96 #endif
97 out << "sharePath directory: " << sharePath << endl;
98
99 systemDirectories.sharedDir = QDir::toNativeSeparators(sharePath + QDir::separator());
100 systemDirectories.docDir =
101 QDir::toNativeSeparators(sharePath + QDir::separator() + "doc" + QDir::separator());
102 #else //_WIN32
103 // if SHARED_DIR is not defined under Linux then use path relative to main executable directory
104 #ifndef SHARED_DIR
105 QDir shareDir(QCoreApplication::applicationDirPath());
106 bool success = false;
107 if (shareDir.cdUp())
108 {
109 if (shareDir.cd("share"))
110 {
111 QDir shareMandelbulber = shareDir;
112 if (shareMandelbulber.cd("mandelbulber2"))
113 {
114 systemDirectories.sharedDir =
115 QDir::cleanPath(shareMandelbulber.absolutePath()) + QDir::separator();
116 success = true;
117 }
118 else
119 {
120 outErr << "Error! There is no 'mandelbulber2' directory in "
121 << shareMandelbulber.absolutePath() << "\n";
122 ;
123 }
124
125 QDir shareDocMandelbulber = shareDir;
126 if (shareDocMandelbulber.cd("doc/mandelbulber2"))
127 {
128 systemDirectories.docDir =
129 QDir::cleanPath(shareDocMandelbulber.absolutePath()) + QDir::separator();
130 }
131 else
132 {
133 outErr << "Error! There is no 'doc/mandelbulber2' directory in "
134 << shareDocMandelbulber.absolutePath() << "\n";
135 ;
136 }
137 }
138 else
139 {
140 outErr << "Error! There is no 'share' directory in " << shareDir.absolutePath() << "\n";
141 ;
142 }
143 }
144 else
145 {
146 outErr << "Error: " << QCoreApplication::applicationDirPath() << " has no parent directory!"
147 << "\n";
148 ;
149 }
150
151 // try to use default share dir
152 if (!success)
153 {
154 outErr << "Trying to use /usr/share/mandelbulber2 as program data directory"
155 << "\n";
156 ;
157 if (shareDir.cd("/usr/share/mandelbulber2"))
158 {
159 systemDirectories.sharedDir = QDir::cleanPath(shareDir.absolutePath()) + QDir::separator();
160 }
161 else
162 {
163 outErr << "Error! Directory "
164 << "/usr/share/mandelbulber2"
165 << "doesn't exist!"
166 << "\n";
167 ;
168 }
169
170 if (shareDir.cd("/usr/share/doc/mandelbulber2"))
171 {
172 systemDirectories.docDir = QDir::cleanPath(shareDir.absolutePath()) + QDir::separator();
173 }
174 else
175 {
176 outErr << "Error! Directory "
177 << "/usr/share/doc/mandelbulber2"
178 << "doesn't exist!"
179 << "\n";
180 ;
181 }
182 }
183
184 #else // SHARED_DIR
185 systemDirectories.sharedDir = QDir::toNativeSeparators(QString(SHARED_DIR) + QDir::separator());
186 systemDirectories.docDir = QDir::toNativeSeparators(QString(SHARED_DOC_DIR) + QDir::separator());
187 #endif // else SHARED_DIR
188 #endif // else _WIN32
189
190 // logfile
191 #ifdef _WIN32 /* WINDOWS */
192 systemData.logfileName = systemDirectories.homeDir + "mandelbulber_log.txt";
193 #else
194 systemData.logfileName = systemDirectories.homeDir + ".mandelbulber_log.txt";
195 #endif
196 FILE *logfile = fopen(systemData.logfileName.toLocal8Bit().constData(), "w");
197 if (logfile)
198 {
199 fclose(logfile);
200 }
201
202 out << "Mandelbulber " << MANDELBULBER_VERSION_STRING << "\n";
203 out << "Log file name: " << systemData.logfileName << "\n";
204 ;
205 WriteLogString("Mandelbulber version", QString(MANDELBULBER_VERSION_STRING), 1);
206
207 // detecting number of CPU cores
208 systemData.numberOfThreads = get_cpu_count();
209
210 printf("Detected %d CPUs\n", systemData.numberOfThreads);
211 WriteLogDouble("CPUs detected", systemData.numberOfThreads, 2);
212
213 #ifdef ONETHREAD // for debugging
214 NR_THREADS = 1;
215 #endif
216
217 // data directory location
218 #ifdef _WIN32 /* WINDOWS */
219 systemDirectories.SetDataDirectoryHidden(
220 systemDirectories.homeDir + "mandelbulber" + QDir::separator());
221 systemDirectories.SetDataDirectoryPublic(
222 systemDirectories.homeDir + "mandelbulber" + QDir::separator());
223 #else
224 systemDirectories.SetDataDirectoryHidden(
225 QDir::toNativeSeparators(systemDirectories.homeDir + ".mandelbulber" + QDir::separator()));
226 systemDirectories.SetDataDirectoryPublic(
227 QDir::toNativeSeparators(systemDirectories.homeDir + "mandelbulber" + QDir::separator()));
228 #endif
229 out << "Program data files directory " << systemDirectories.sharedDir << "\n";
230 ;
231 out << "Default data hidden directory: " << systemDirectories.GetDataDirectoryHidden() << "\n";
232 ;
233 WriteLogString("Default data hidden directory", systemDirectories.GetDataDirectoryHidden(), 1);
234 out << "Default data public directory: " << systemDirectories.GetDataDirectoryPublic() << "\n";
235 ;
236 WriteLogString("Default data public directory", systemDirectories.GetDataDirectoryPublic(), 1);
237
238 //*********** temporary set to false ************
239 systemData.noGui = false;
240 systemData.silent = false;
241
242 systemData.lastSettingsFile = QDir::toNativeSeparators(
243 systemDirectories.GetSettingsFolder() + QDir::separator() + QString("settings.fract"));
244 systemData.lastImageFile = QDir::toNativeSeparators(
245 systemDirectories.GetImagesFolder() + QDir::separator() + QString("image.jpg"));
246 systemData.lastImagePaletteFile = QDir::toNativeSeparators(
247 systemDirectories.sharedDir + "textures" + QDir::separator() + QString("colour palette.jpg"));
248 systemData.lastGradientFile = QDir::toNativeSeparators(
249 systemDirectories.GetGradientsFolder() + QDir::separator() + "colors.gradient");
250
251 QLocale systemLocale = QLocale::system();
252 systemData.decimalPoint = systemLocale.decimalPoint();
253 WriteLogString("Decimal point", QString(systemData.decimalPoint), 2);
254
255 systemData.supportedLanguages.insert("en_EN", "English");
256 systemData.supportedLanguages.insert("pl_PL", "Polski");
257 systemData.supportedLanguages.insert("de_DE", "Deutsch");
258 systemData.supportedLanguages.insert("it_IT", "Italiano");
259 systemData.supportedLanguages.insert("nl_NL", "Nederlands");
260 systemData.supportedLanguages.insert("es_ES", "Español");
261
262 // get number of columns of console
263 systemData.terminalWidth = 80;
264 systemData.loggingVerbosity = 3;
265 systemData.settingsLoadedFromCLI = false;
266 systemData.globalStopRequest = false;
267 systemData.isOutputTty = IsOutputTty();
268
269 #ifndef WIN32
270 handle_winch(-1);
271 #endif
272 return true;
273 }
274
275 // SIGWINCH is called when the window is resized.
handle_winch(int sig)276 void handle_winch(int sig)
277 {
278 (void)sig;
279 #ifndef _WIN32
280 signal(SIGWINCH, SIG_IGN);
281 struct winsize w
282 {
283 };
284 ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
285 systemData.terminalWidth = w.ws_col;
286 if (systemData.terminalWidth <= 0) systemData.terminalWidth = 80;
287 if (systemData.terminalWidth >= 150) systemData.terminalWidth = 150;
288 if (!systemData.isOutputTty) systemData.terminalWidth = 80;
289 signal(SIGWINCH, handle_winch);
290 #endif
291 }
292
get_cpu_count()293 int get_cpu_count()
294 {
295 return QThread::idealThreadCount();
296 }
297
CreateDefaultFolders()298 bool CreateDefaultFolders()
299 {
300 // create data directory if not exists
301 bool result = true;
302
303 result &= CreateFolder(systemDirectories.GetDataDirectoryHidden());
304 result &= CreateFolder(systemDirectories.GetDataDirectoryPublic());
305 result &= CreateFolder(systemDirectories.GetImagesFolder());
306 result &= CreateFolder(systemDirectories.GetThumbnailsFolder());
307 result &= CreateFolder(systemDirectories.GetToolbarFolder());
308 result &= CreateFolder(systemDirectories.GetHttpCacheFolder());
309 result &= CreateFolder(systemDirectories.GetCustomWindowStateFolder());
310 result &= CreateFolder(systemDirectories.GetSettingsFolder());
311 result &= CreateFolder(systemDirectories.GetSlicesFolder());
312 result &= CreateFolder(systemDirectories.GetMaterialsFolder());
313 result &= CreateFolder(systemDirectories.GetAnimationFolder());
314 result &= CreateFolder(systemDirectories.GetNetrenderFolder());
315 result &= CreateFolder(systemDirectories.GetGradientsFolder());
316 result &= CreateFolder(systemDirectories.GetOpenCLTempFolder());
317 result &= CreateFolder(systemDirectories.GetOpenCLCustomFormulasFolder());
318 result &= CreateFolder(systemDirectories.GetUndoFolder());
319 result &= PutClangFormatFileToDataDirectoryHidden();
320
321 RetrieveToolbarPresets(false);
322 RetrieveExampleMaterials(false);
323
324 #ifdef CLSUPPORT
325 string oclDir = systemData.dataDirectory + "/custom_ocl_formulas";
326 QString qoclDir = QString::fromStdString(oclDir);
327 if (!QDir(qoclDir).exists())
328 {
329 result &= CreateFolder(oclDir);
330 if (result)
331 {
332 fcopy(systemData.sharedDir + "/exampleOCLformulas/cl_example1.c", oclDir + "/cl_example1.c");
333 fcopy(systemData.sharedDir + "/exampleOCLformulas/cl_example2.c", oclDir + "/cl_example2.c");
334 fcopy(systemData.sharedDir + "/exampleOCLformulas/cl_example3.c", oclDir + +"/cl_example3.c");
335 fcopy(systemData.sharedDir + "/exampleOCLformulas/cl_example1Init.c",
336 oclDir + "/cl_example1Init.c");
337 fcopy(systemData.sharedDir + "/exampleOCLformulas/cl_example2Init.c",
338 oclDir + "/cl_example2Init.c");
339 fcopy(systemData.sharedDir + "/exampleOCLformulas/cl_example3Init.c",
340 oclDir + "/cl_example3Init.c");
341 }
342 }
343 #endif
344
345 actualFileNames.actualFilenameSettings =
346 QString("settings") + QDir::separator() + "default.fract";
347 actualFileNames.actualFilenameSettings =
348 QDir::toNativeSeparators(actualFileNames.actualFilenameSettings);
349
350 actualFileNames.actualFilenameImage = QString("images") + QDir::separator() + "image.jpg";
351 actualFileNames.actualFilenameImage =
352 QDir::toNativeSeparators(actualFileNames.actualFilenameImage);
353
354 actualFileNames.actualFilenamePalette =
355 systemDirectories.sharedDir + "textures" + QDir::separator() + "colour palette.jpg";
356 actualFileNames.actualFilenamePalette =
357 QDir::toNativeSeparators(actualFileNames.actualFilenamePalette);
358
359 ClearNetRenderCache();
360 DeleteOldChache(systemDirectories.GetThumbnailsFolder(), 90);
361 DeleteOldChache(systemDirectories.GetHttpCacheFolder(), 10);
362
363 return result;
364 }
365
CreateFolder(const QString & qName)366 bool CreateFolder(const QString &qName)
367 {
368 if (QDir(qName).exists())
369 {
370 WriteLogString("Directory already exists", qName, 1);
371 return true;
372 }
373 else
374 {
375 if (QDir().mkdir(qName))
376 {
377 WriteLogString("Directory created", qName, 2);
378 return true;
379 }
380 else
381 {
382 WriteLogString("Directory can't be created", qName, 1);
383 qCritical() << "error: directory " << qName << " cannot be created";
384 return false;
385 }
386 }
387 }
388
DeleteAllFilesFromDirectory(const QString & folder,const QString & filterExpression,QRegExp::PatternSyntax pattern)389 void DeleteAllFilesFromDirectory(
390 const QString &folder, const QString &filterExpression, QRegExp::PatternSyntax pattern)
391 {
392 QRegExp rx(filterExpression);
393 rx.setPatternSyntax(pattern);
394
395 if (QDir(folder).exists())
396 {
397 QDirIterator folderIterator(folder);
398 while (folderIterator.hasNext())
399 {
400 folderIterator.next();
401 if (folderIterator.fileName() == "." || folderIterator.fileName() == "..") continue;
402 if (rx.exactMatch(folderIterator.fileName()))
403 {
404 if (QFile::remove(folderIterator.filePath()))
405 {
406 WriteLogString("File deleted", folderIterator.filePath(), 2);
407 }
408 else
409 {
410 WriteLogString("File not deleted", folderIterator.filePath(), 1);
411 }
412 }
413 }
414 }
415 else
416 {
417 WriteLogString("Directory does not exist", folder, 2);
418 }
419 }
420
myMessageOutput(QtMsgType type,const QMessageLogContext & context,const QString & msg)421 void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
422 {
423 QByteArray localMsg = msg.toLocal8Bit();
424 QString text;
425 switch (type)
426 {
427 #if QT_VERSION >= 0x050500
428 case QtInfoMsg:
429 fprintf(stderr, "Info: %s\n", localMsg.constData());
430 text = QString("Info: ") + QString(localMsg.constData());
431 break;
432 #endif
433 case QtDebugMsg:
434 fprintf(stderr, "Debug: %s\n", localMsg.constData());
435 text = QString("Debug: ") + QString(localMsg.constData());
436 break;
437 case QtWarningMsg:
438 fprintf(stderr, "Warning: %s\n(%s:%u, %s)\n\n", localMsg.constData(), context.file,
439 context.line, context.function);
440 text = QString("Warning: ") + QString(localMsg.constData()) + " (" + context.file + ":"
441 + QString::number(context.line) + ", " + context.function;
442 break;
443 case QtCriticalMsg:
444 fprintf(stderr, "Critical: %s\n(%s:%u, %s)\n\n", localMsg.constData(), context.file,
445 context.line, context.function);
446 text = QString("Critical: ") + QString(localMsg.constData()) + " (" + context.file + ":"
447 + QString::number(context.line) + ", " + context.function;
448 break;
449 case QtFatalMsg:
450 fprintf(stderr, "Fatal: %s\n(%s:%u, %s)\n\n", localMsg.constData(), context.file,
451 context.line, context.function);
452 text = QString("Fatal: ") + QString(localMsg.constData()) + " (" + context.file + ":"
453 + QString::number(context.line) + ", " + context.function;
454 abort();
455 break;
456 }
457 WriteLog(text, 1);
458
459 if (type == QtFatalMsg) abort();
460 }
461
UpdateDefaultPaths()462 void UpdateDefaultPaths()
463 {
464 systemData.lastSettingsFile =
465 gPar->Get<QString>("default_settings_path") + QDir::separator() + QString("settings.fract");
466 systemData.lastImageFile =
467 gPar->Get<QString>("default_image_path") + QDir::separator() + QString("image.jpg");
468 gPar->Set("file_background",
469 gPar->Get<QString>("default_textures_path") + QDir::separator() + "background.jpg");
470 gPar->Set(
471 "file_envmap", gPar->Get<QString>("default_textures_path") + QDir::separator() + "envmap.jpg");
472 gPar->Set("file_lightmap",
473 gPar->Get<QString>("default_textures_path") + QDir::separator() + "lightmap.jpg");
474 }
475
UpdateUIStyle()476 void UpdateUIStyle()
477 {
478 // Selecting default Fusion UI style in case if wrong style is selected
479 if (gPar->Get<int>("ui_style_type") < 0
480 || gPar->Get<int>("ui_style_type") >= QStyleFactory::keys().size())
481 {
482 QStringList listOfStyles = QStyleFactory::keys();
483 int indexOfFusion = listOfStyles.indexOf("Fusion");
484 gPar->Set<int>("ui_style_type", indexOfFusion);
485 }
486
487 // set ui style
488 if (gPar->Get<int>("ui_style_type") >= 0
489 && gPar->Get<int>("ui_style_type") < QStyleFactory::keys().size())
490 {
491 QApplication::setStyle(
492 QStyleFactory::create(QStyleFactory::keys().at(gPar->Get<int>("ui_style_type"))));
493 }
494 }
495
UpdateUISkin()496 void UpdateUISkin()
497 {
498 static QPalette defaultPalette; // cache "normal" skin on first call
499 QPalette palette;
500
501 QColor colorBackground1 = palette.color(QPalette::Window);
502 QColor colorBackground2 = palette.color(QPalette::Base);
503 QColor colorText1 = palette.color(QPalette::WindowText);
504 QColor colorText2 = palette.color(QPalette::HighlightedText);
505
506 switch (gPar->Get<int>("ui_skin"))
507 {
508 case 1: // dark skin
509 colorBackground1 = QColor(53, 53, 53);
510 colorBackground2 = QColor(25, 25, 25);
511 colorText1 = Qt::white;
512 colorText2 = Qt::black;
513 break;
514 case 2: // light skin (only roughly inverted dark skin)
515 colorBackground1 = QColor(240, 240, 240);
516 colorBackground2 = QColor(250, 250, 250);
517 colorText1 = Qt::black;
518 colorText2 = Qt::white;
519 break;
520 case 3: // Nasa Font light
521 QFontDatabase::addApplicationFont(":/fonts/fonts/nasalization-rg.ttf");
522 QApplication::setFont(QFont("nasalization"));
523 colorBackground1 = QColor(167, 173, 187);
524 colorBackground2 = QColor(192, 196, 207);
525 colorText1 = Qt::black;
526 colorText2 = Qt::white;
527 break;
528 case 4: // Nasa Font dark
529 QFontDatabase::addApplicationFont(":/fonts/fonts/nasalization-rg.ttf");
530 QApplication::setFont(QFont("nasalization"));
531 colorBackground1 = QColor(52, 61, 70);
532 colorBackground2 = QColor(79, 91, 102);
533 colorText1 = Qt::white;
534 colorText2 = Qt::black;
535 break;
536 case 5: // Nasa Font dark green
537 QFontDatabase::addApplicationFont(":/fonts/fonts/nasalization-rg.ttf");
538 QApplication::setFont(QFont("nasalization"));
539 colorBackground1 = QColor(20, 40, 10);
540 colorBackground2 = QColor(30, 50, 0);
541 colorText1 = Qt::green;
542 colorText2 = Qt::black;
543 break;
544 case 6: // Nasa Font dark blue
545 QFontDatabase::addApplicationFont(":/fonts/fonts/nasalization-rg.ttf");
546 QApplication::setFont(QFont("nasalization"));
547 colorBackground1 = QColor(10, 10, 40);
548 colorBackground2 = QColor(20, 20, 60);
549 colorText1 = QColor(50, 150, 255);
550 colorText2 = Qt::black;
551 break;
552 case 7: // Nasa Font dark brown
553 QFontDatabase::addApplicationFont(":/fonts/fonts/nasalization-rg.ttf");
554 QApplication::setFont(QFont("nasalization"));
555 colorBackground1 = QColor(40, 10, 10);
556 colorBackground2 = QColor(60, 20, 20);
557 colorText1 = QColor(255, 150, 50);
558 colorText2 = Qt::black;
559 break;
560 default: // normal skin
561 palette = defaultPalette;
562 break;
563 }
564 if (gPar->Get<int>("ui_skin") != 0)
565 {
566 palette.setColor(QPalette::Window, colorBackground1);
567 palette.setColor(QPalette::WindowText, colorText1);
568 palette.setColor(QPalette::Base, colorBackground2);
569 palette.setColor(QPalette::AlternateBase, colorBackground1);
570 palette.setColor(QPalette::ToolTipBase, colorBackground2);
571 palette.setColor(QPalette::ToolTipText, colorText1);
572 palette.setColor(QPalette::Text, colorText1);
573 palette.setColor(QPalette::Button, colorBackground1);
574 palette.setColor(QPalette::ButtonText, colorText1);
575 palette.setColor(QPalette::BrightText, Qt::red);
576 palette.setColor(QPalette::Link, QColor(42, 130, 218));
577
578 palette.setColor(QPalette::Highlight, QColor(42, 130, 218));
579 palette.setColor(QPalette::HighlightedText, colorText2);
580 }
581 // set ui skin
582 QApplication::setPalette(palette);
583 }
584
UpdateLanguage()585 void UpdateLanguage()
586 {
587 // Set language from locale
588 WriteLog("Prepare translator", 2);
589 static QTranslator mandelbulberMainTranslator;
590 static QTranslator mandelbulberFractalUiTranslator;
591 static QTranslator qtTranslator;
592
593 QString locale = systemData.locale.name();
594 if (gPar)
595 {
596 if (systemData.supportedLanguages.contains(gPar->Get<QString>("language")))
597 {
598 locale = gPar->Get<QString>("language");
599 }
600 }
601
602 WriteLogString("locale", locale, 2);
603 mandelbulberMainTranslator.load(
604 locale, systemDirectories.sharedDir + QDir::separator() + "language");
605 mandelbulberFractalUiTranslator.load(
606 "formula_" + locale, systemDirectories.sharedDir + QDir::separator() + "language");
607
608 WriteLog("Installing translator", 2);
609 QCoreApplication::installTranslator(&mandelbulberMainTranslator);
610 QCoreApplication::installTranslator(&mandelbulberFractalUiTranslator);
611
612 // try to load qt translator
613 if (qtTranslator.load(
614 QLatin1String("qt_") + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath))
615 || qtTranslator.load(
616 QLatin1String("qtbase_") + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
617 {
618 QCoreApplication::installTranslator(&qtTranslator);
619 }
620 }
621
RetrieveToolbarPresets(bool force)622 void RetrieveToolbarPresets(bool force)
623 {
624 if (QDir(systemDirectories.GetToolbarFolder())
625 .entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries)
626 .count()
627 == 0
628 || force)
629 {
630 // first run of program (or all toolbar items deleted) -> copy toolbar presets to working folder
631 QDirIterator toolbarFiles(systemDirectories.sharedDir + "toolbar");
632 while (toolbarFiles.hasNext())
633 {
634 toolbarFiles.next();
635 if (toolbarFiles.fileName() == "." || toolbarFiles.fileName() == "..") continue;
636 fcopy(toolbarFiles.filePath(),
637 systemDirectories.GetToolbarFolder() + QDir::separator() + toolbarFiles.fileName());
638 }
639 }
640 }
641
RetrieveExampleMaterials(bool force)642 void RetrieveExampleMaterials(bool force)
643 {
644 if (QDir(systemDirectories.GetMaterialsFolder())
645 .entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries)
646 .count()
647 == 0
648 || force)
649 {
650 // first run of program (or all material items deleted) -> copy materials to working folder
651 QDirIterator materialFiles(systemDirectories.sharedDir + "materials");
652 while (materialFiles.hasNext())
653 {
654 materialFiles.next();
655 if (materialFiles.fileName() == "." || materialFiles.fileName() == "..") continue;
656 fcopy(materialFiles.filePath(),
657 systemDirectories.GetMaterialsFolder() + QDir::separator() + materialFiles.fileName());
658 }
659 }
660 }
661
CalcPreferredFontSize(bool noGui)662 void CalcPreferredFontSize(bool noGui)
663 {
664 if (!noGui)
665 {
666 const int fontSize = (int)QApplication::font().pointSizeF();
667 systemData.SetPreferredFontPointSize(fontSize);
668
669 QFontMetrics fm(QApplication::font());
670 const int pixelFontSize = fm.height();
671
672 const int thumbnailSize = (pixelFontSize * 8);
673 systemData.SetPreferredThumbnailSize(thumbnailSize);
674 }
675 else
676 {
677 systemData.SetPreferredFontPointSize(10);
678 systemData.SetPreferredFontSize(10);
679 systemData.SetPreferredThumbnailSize(80);
680 }
681 }
682
IsOutputTty()683 bool IsOutputTty()
684 {
685 #ifdef _WIN32 /* WINDOWS */
686 return false;
687 #else
688 return isatty(fileno(stdout));
689 #endif
690 }
691
ClearNetRenderCache()692 void ClearNetRenderCache()
693 {
694 QDir dir(systemDirectories.GetNetrenderFolder());
695 if (dir.exists())
696 {
697 QDirIterator it(dir);
698 while (it.hasNext())
699 {
700 QFile file(it.next());
701 file.remove();
702 }
703 }
704 }
705
DeleteOldChache(const QString & directoryPath,int maxDays)706 void DeleteOldChache(const QString &directoryPath, int maxDays)
707 {
708 QDir dir(directoryPath);
709 int counter = 0;
710 qint64 totalSize = 0;
711 if (dir.exists())
712 {
713 QDirIterator it(dir);
714 while (it.hasNext())
715 {
716 QFile file(it.next());
717 QFileInfo fileInfo(file);
718 QDateTime dateTime = fileInfo.lastModified();
719 qint64 days = dateTime.daysTo(QDateTime::currentDateTime());
720 if (days > maxDays)
721 {
722 totalSize += file.size();
723 file.remove();
724 counter++;
725 }
726 }
727 }
728 if (counter > 0)
729 {
730 QString message = QString("Removed %1 old files from %2. Saved %3 MB")
731 .arg(counter)
732 .arg(directoryPath)
733 .arg(totalSize / 1024 / 1024);
734 qInfo() << message;
735 WriteLog(message, 2);
736 }
737 }
738
PutClangFormatFileToDataDirectoryHidden()739 bool PutClangFormatFileToDataDirectoryHidden()
740 {
741 QFile file(systemDirectories.GetDataDirectoryHidden() + "/.clang-format");
742 if (file.exists()) return true;
743 if (file.open(QIODevice::WriteOnly))
744 {
745 QTextStream out(&file);
746 out << "---\n"
747 "Language: Cpp\n"
748 "# BasedOnStyle: LLVM\n"
749 "AccessModifierOffset: -2\n"
750 "AlignAfterOpenBracket: false\n"
751 "AlignEscapedNewlinesLeft: true\n"
752 "AlignTrailingComments: true\n"
753 "AlignOperands: true\n"
754 "AllowAllParametersOfDeclarationOnNextLine: true\n"
755 "AllowShortBlocksOnASingleLine: false\n"
756 "AllowShortCaseLabelsOnASingleLine: true\n"
757 "AllowShortIfStatementsOnASingleLine: true\n"
758 "AllowShortLoopsOnASingleLine: false\n"
759 "AllowShortFunctionsOnASingleLine: Inline\n"
760 "AlwaysBreakAfterDefinitionReturnType: false\n"
761 "AlwaysBreakTemplateDeclarations: true\n"
762 "AlwaysBreakBeforeMultilineStrings: true\n"
763 "BreakBeforeBinaryOperators: NonAssignment\n"
764 "BreakBeforeTernaryOperators: true\n"
765 "BreakConstructorInitializersBeforeComma: false\n"
766 "BinPackParameters: true\n"
767 "BinPackArguments: true\n"
768 "ColumnLimit: 100\n"
769 "ConstructorInitializerAllOnOneLineOrOnePerLine: true\n"
770 "ConstructorInitializerIndentWidth: 4\n"
771 "DerivePointerAlignment: false\n"
772 "ExperimentalAutoDetectBinPacking: false\n"
773 "IndentCaseLabels: true\n"
774 "IndentWrappedFunctionNames: false\n"
775 "IndentFunctionDeclarationAfterType: false\n"
776 "MaxEmptyLinesToKeep: 1\n"
777 "KeepEmptyLinesAtTheStartOfBlocks: true\n"
778 "NamespaceIndentation: None\n"
779 "ObjCBlockIndentWidth: 2\n"
780 "ObjCSpaceAfterProperty: false\n"
781 "ObjCSpaceBeforeProtocolList: true\n"
782 "PenaltyBreakBeforeFirstCallParameter: 19\n"
783 "PenaltyBreakComment: 300\n"
784 "PenaltyBreakString: 1000\n"
785 "PenaltyBreakFirstLessLess: 120\n"
786 "PenaltyExcessCharacter: 1000000\n"
787 "PenaltyReturnTypeOnItsOwnLine: 60\n"
788 "PointerAlignment: Right\n"
789 "SpacesBeforeTrailingComments: 1\n"
790 "Cpp11BracedListStyle: true\n"
791 "Standard: Cpp11\n"
792 "IndentWidth: 2\n"
793 "TabWidth: 2\n"
794 "UseTab: Always\n"
795 "BreakBeforeBraces: Allman\n"
796 "SpacesInParentheses: false\n"
797 "SpacesInSquareBrackets: false\n"
798 "SpacesInAngles: false\n"
799 "SpaceInEmptyParentheses: false\n"
800 "SpacesInCStyleCastParentheses: false\n"
801 "SpaceAfterCStyleCast: false\n"
802 "SpacesInContainerLiterals: true\n"
803 "SpaceBeforeAssignmentOperators: true\n"
804 "ContinuationIndentWidth: 2\n"
805 "CommentPragmas: '^ IWYU pragma:'\n"
806 "ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]\n"
807 "SpaceBeforeParens: ControlStatements\n"
808 "DisableFormat: false\n"
809 "SortIncludes: false\n"
810 "...\n";
811 file.close();
812 return true;
813 }
814 return false;
815 }
816