├── .gitignore ├── Components ├── config_files.h ├── config_gconf.h ├── configcollection.cpp ├── configcollection.h ├── configcollection_p.h ├── magickonfug.cpp ├── magickonfug.h └── magickonfug.ui ├── INSTALL ├── Icons ├── SuperPanda.png ├── configure.png ├── exit.png ├── help.png └── information.png ├── Interfaces ├── configfileeditor.cpp ├── configfileeditor.h ├── exelauncher.cpp └── exelauncher.h ├── LICENSE ├── README.md ├── SuperPanda.pro ├── Translations ├── SuperPanda_fr_FR.ts ├── SuperPanda_zh_CN.ts └── SuperPanda_zh_TW.ts ├── Utils ├── bootutils.cpp ├── bootutils.h ├── dialogutils.cpp ├── dialogutils.h ├── diskutils.cpp ├── diskutils.h ├── environment.cpp ├── environment.h ├── environmentmodel.cpp ├── environmentmodel.h ├── fileutils.cpp ├── fileutils.h ├── gsettingseditor.cpp ├── gsettingseditor.h ├── hostosinfo.cpp ├── hostosinfo.h ├── osspecificaspects.h ├── qtcassert.cpp ├── qtcassert.h ├── savefile.cpp ├── savefile.h ├── screenutils.cpp ├── screenutils.h ├── swaputils.cpp └── swaputils.h ├── Widgets ├── environmentdialog.cpp ├── environmentdialog.h ├── environmentwidget.cpp ├── environmentwidget.h ├── headerviewstretcher.cpp ├── headerviewstretcher.h ├── itemviews.cpp └── itemviews.h ├── aboutwindow.cpp ├── aboutwindow.h ├── aboutwindow.ui ├── doc └── Component - MagicKonfug.md ├── global.cpp ├── global.h ├── icons.qrc ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── translation.pri └── translations.qrc /.gitignore: -------------------------------------------------------------------------------- 1 | *.bak 2 | SuperPanda 3 | *.o 4 | moc* 5 | ui*.h 6 | *.pro.user 7 | *.qm 8 | Makefile 9 | -------------------------------------------------------------------------------- /Components/config_files.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_FILES_H 2 | #define CONFIG_FILES_H 3 | 4 | #define SPANDA_CONFIG_FILE_GRUB_DEFAULT "/etc/default/grub" 5 | #define SPANDA_CONFIG_FILE_KEYBD_DEFAULT "/etc/default/keyboard" 6 | #define SPANDA_CONFIG_FILE_MOUNT_ROOT "/etc/fstab" 7 | #define SPANDA_CONFIG_FILE_SYSTEMD_SYSTEM "/etc/systemd/system.conf" 8 | #define SPANDA_CONFIG_FILE_SYSTEMD_USER "/etc/systemd/user.conf" 9 | #define SPANDA_CONFIG_FILE_UDEV_DISK "/etc/udev/rules.d/95-superpanda.rules" 10 | #define SPANDA_CONFIG_FILE_MODCONF_IWLWIFI "/etc/modprobe.d/iwlwifi.conf" 11 | #define SPANDA_CONFIG_FILE_ENVIRONMENT_SYS "/etc/environment" 12 | #define SPANDA_CONFIG_FILE_ENVIRONMENT_USER "~/.xsessionrc" 13 | #define SPANDA_CONFIG_FILE_XSESSION_USER "~/.xsession" 14 | #define SPANDA_CONFIG_FILE_AUTOSTART_SCREEN_USER "~/.config/autostart/" \ 15 | "spanda-screen-config.desktop" 16 | 17 | #define SPANDA_CONFIG_FILE_SWAPFILE_ROOT "/swapfile" 18 | 19 | #endif // CONFIG_FILES_H 20 | -------------------------------------------------------------------------------- /Components/config_gconf.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_GCONF_H 2 | #define CONFIG_GCONF_H 3 | 4 | #define SPANDA_CONFIG_GCONF_SCHEMA_GNOME_IFACE "org.gnome.desktop.interface" 5 | #define SPANDA_CONFIG_GCONF_SCHEMA_DDE_GNOME \ 6 | "com.deepin.wrap.gnome.desktop.interface" 7 | #define SPANDA_CONFIG_GCONF_KEY_GNOME_SCALING "scaling-factor" 8 | #define SPANDA_CONFIG_GCONF_KEY_GNOME_TEXTSCALING "text-scaling-factor" 9 | 10 | #endif // CONFIG_GCONF_H 11 | -------------------------------------------------------------------------------- /Components/configcollection.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIGCOLLECTION_H 2 | #define CONFIGCOLLECTION_H 3 | 4 | #include 5 | #include "../Utils/environment.h" 6 | 7 | 8 | class ConfigCollectionPrivate; 9 | 10 | class ConfigCollection : public QObject 11 | { 12 | Q_OBJECT 13 | Q_DECLARE_PRIVATE(ConfigCollection) 14 | protected: 15 | ConfigCollectionPrivate* d_ptr; 16 | 17 | public: 18 | enum ConfigEntryKey 19 | { 20 | CONFIG_SERVICE_TIMEOUT = 1, 21 | CONFIG_SHUTDOWN_TIMEOUT = 2, 22 | CONFIG_CPU_INTEL_TURBO = 3, 23 | CONFIG_KEYBD_COMPOSE = 4, 24 | CONFIG_DISK_PHYSICS = 5, 25 | CONFIG_BOOT_TIMEOUT = 6, 26 | CONFIG_BOOT_RESOLUTION = 7, 27 | CONFIG_WIFI_INTEL_80211n = 8, 28 | CONFIG_DISP_SCALE_GNOME_WINDOW = 11, 29 | CONFIG_DISP_SCALE_GNOME_TEXT = 12, 30 | CONFIG_DISP_RESOLUTION = 13, 31 | CONFIG_DISK_SWAP = 14, 32 | CONFIG_ACPI_OS = 15, 33 | CONFIG_DISP_GAMMA = 16 34 | }; 35 | 36 | explicit ConfigCollection(); 37 | void loadConfig(); 38 | bool applyConfig(); 39 | 40 | QVariant getValue(ConfigEntryKey key); 41 | QVariant getDefaultValue(ConfigEntryKey key); 42 | bool setValue(ConfigEntryKey key, QVariant value); 43 | void resetValue(ConfigEntryKey key); 44 | bool isModified(ConfigEntryKey key); 45 | QList modifiedEntryList(); 46 | 47 | bool setEnvironment(QList changes, 48 | bool systemScope = false); 49 | 50 | signals: 51 | void configApplied(bool successful); 52 | void promptNeedReboot(); 53 | }; 54 | 55 | #endif // CONFIGCOLLECTION_H 56 | -------------------------------------------------------------------------------- /Components/configcollection_p.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIGCOLLECTION_P_H 2 | #define CONFIGCOLLECTION_P_H 3 | 4 | #include 5 | #include 6 | #include "../Interfaces/configfileeditor.h" 7 | #include "../Interfaces/exelauncher.h" 8 | #include "../Utils/gsettingseditor.h" 9 | #include "../Utils/bootutils.h" 10 | #include "../Utils/swaputils.h" 11 | 12 | 13 | class ConfigCollection; 14 | 15 | class ConfigCollectionPrivate : public QObject 16 | { 17 | Q_OBJECT 18 | Q_DECLARE_PUBLIC(ConfigCollection) 19 | protected: 20 | ConfigCollection* q_ptr; 21 | 22 | public: 23 | QMap configList; 24 | QMap configModified; 25 | BootUtils bootConfig; 26 | SwapUtils swapConfig; 27 | ConfigFileEditor configFile; 28 | ExeLauncher exeFile; 29 | bool needResetScreen; 30 | bool needResetSwapFile; 31 | bool needUpdatingBoot; 32 | static const int MaxConfigEntry = 16; 33 | 34 | ConfigCollectionPrivate(ConfigCollection* parent); 35 | void doUpdating(); 36 | static QString getEnvironmentVariable(QString key); 37 | static bool testConfigFileError(ConfigFileEditor::FileErrorCode errCode, 38 | const QString& fileName, 39 | const bool aborted = true); 40 | 41 | protected slots: 42 | void onUpdatingBootFinished(); 43 | void onFinishedMakingSwapfile(); 44 | void onFinishedRemovingSwapfile(); 45 | void onFinishedTurnOnSwap(); 46 | }; 47 | 48 | #endif // CONFIGCOLLECTION_P_H 49 | -------------------------------------------------------------------------------- /Components/magickonfug.h: -------------------------------------------------------------------------------- 1 | #ifndef MagicKonfug_H 2 | #define MagicKonfug_H 3 | 4 | #include 5 | #include "configcollection.h" 6 | #include "Utils/environment.h" 7 | 8 | 9 | class QAbstractButton; 10 | class EnvironmentWidget; 11 | 12 | namespace Ui { 13 | class MagicKonfug; 14 | } 15 | 16 | class MagicKonfug : public QMainWindow 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | explicit MagicKonfug(QWidget *parent = 0); 22 | ~MagicKonfug(); 23 | 24 | protected: 25 | void changeEvent(QEvent* event); 26 | void closeEvent(QCloseEvent* event); 27 | void showEvent(QShowEvent* event); 28 | 29 | private: 30 | enum class EnvEditMode 31 | { 32 | NotEditting = 0, 33 | SystemScope = 1, 34 | UserScope = 2, 35 | Disabled = 255 36 | }; 37 | 38 | Ui::MagicKonfug *ui; 39 | EnvironmentWidget* envEditor; 40 | ConfigCollection configEditor; 41 | EnvEditMode currentEnvEditMode; 42 | QList envVarChanges; 43 | int lastPageGroupIndex; 44 | static const int pageGroupCount = 6; 45 | bool configPageMoidified[pageGroupCount]; 46 | bool systemScopeEnvEdit; 47 | 48 | void loadConfig(); 49 | bool applyConfig(int configIndex); 50 | void setConfigModified(int configIndex, bool modified = true); 51 | void setConfigPageModified(int pageIndex, bool modified = true); 52 | void setWidgetDisabled(QWidget* widget); 53 | void showEnvEditor(bool systemScope = false); 54 | void showStatusPage(bool pageVisible, QString text = QString()); 55 | static void destroyWidget(QWidget* widget);static int composeKeyStringToIndex(const QString& str); 56 | static QString composeKeyIndexToString(int index); 57 | static int bootResolutionStringToIndex(const QString& str); 58 | static QString bootResolutionIndexToString(int index); 59 | 60 | private slots: 61 | void onConfigEditorApplied(bool successful); 62 | void onConfigEditorPromptReboot(); 63 | void onEnvEditorClosing(); 64 | 65 | void on_listWidget_clicked(const QModelIndex &index); 66 | void on_buttonAbout_clicked(); 67 | void on_buttonExit_clicked(); 68 | void on_buttonBox_clicked(QAbstractButton *button); 69 | void on_groupPage_currentChanged(int arg1); 70 | void on_textTimeoutSrvStart_valueChanged(int arg1); 71 | void on_textTimeoutShutdown_valueChanged(int arg1); 72 | void on_checkTurboFreq_toggled(bool checked); 73 | void on_comboKeySequence_currentIndexChanged(int index); 74 | void on_comboDiskType_currentIndexChanged(const QString &arg1); 75 | void on_textTimeoutBoot_valueChanged(int arg1); 76 | void on_comboBootResolution_currentIndexChanged(int index); 77 | void on_checkIWiFi80211n_toggled(bool checked); 78 | void on_buttonEditSysEnv_clicked(); 79 | void on_buttonEditUserEnv_clicked(); 80 | void on_textWindowScaling_valueChanged(int arg1); 81 | void on_textWindowTextScaling_valueChanged(double arg1); 82 | void on_radioDefaultResolution_clicked(); 83 | void on_radioCustomizedResolution_clicked(); 84 | void on_textScreenWidth_valueChanged(int arg1); 85 | void on_textScreenHeight_valueChanged(int arg1); 86 | void on_radioDisableSwap_clicked(); 87 | void on_radioEnableSwap_clicked(); 88 | void on_textSwapSize_valueChanged(int arg1); 89 | void on_comboACPIos_currentIndexChanged(int index); 90 | void on_textGammaRed_valueChanged(double arg1); 91 | void on_textGammaGreen_valueChanged(double arg1); 92 | void on_textGammaBlue_valueChanged(double arg1); 93 | }; 94 | 95 | #endif // MagicKonfug_H 96 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | How To Build And Install 2 | ======================== 3 | 4 | Build 5 | ----- 6 | 7 | There are 2 ways to build from source: 8 | 9 | * Using QtCreator: 10 | 11 | 1. Download and install the latest version of QtCreator; 12 | 13 | 2. Open "SuperPanda.pro" with QtCreator; 14 | 15 | 3. Compile the project. 16 | 17 | * Using qmake: 18 | 19 | 1. Download and install qmake. There might be other dependencies needed for qmake. For example, under Ubuntu you can: 20 | 21 | sudo apt-get install g++ 22 | sudo apt-get install qt5-default 23 | 24 | 2. Switch to the source directory and run qmake: 25 | 26 | cd SuperPanda/ 27 | qmake 28 | 29 | 3. Actually build the project: 30 | 31 | make 32 | 33 | 34 | Install 35 | ------- 36 | 37 | The built executable "SuperPanda" can be launched directly (either from terminal or file manager), without further configuration of environmental variables. 38 | -------------------------------------------------------------------------------- /Icons/SuperPanda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwpwjwtz/SuperPanda/3061c7a74f26f9bcf8893c04a886b8910a4e3b39/Icons/SuperPanda.png -------------------------------------------------------------------------------- /Icons/configure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwpwjwtz/SuperPanda/3061c7a74f26f9bcf8893c04a886b8910a4e3b39/Icons/configure.png -------------------------------------------------------------------------------- /Icons/exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwpwjwtz/SuperPanda/3061c7a74f26f9bcf8893c04a886b8910a4e3b39/Icons/exit.png -------------------------------------------------------------------------------- /Icons/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwpwjwtz/SuperPanda/3061c7a74f26f9bcf8893c04a886b8910a4e3b39/Icons/help.png -------------------------------------------------------------------------------- /Icons/information.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwpwjwtz/SuperPanda/3061c7a74f26f9bcf8893c04a886b8910a4e3b39/Icons/information.png -------------------------------------------------------------------------------- /Interfaces/configfileeditor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "configfileeditor.h" 4 | 5 | #define SPANDA_IFACE_CONFEDIT_BUFFER_LEN 1024 6 | #define SPANDA_IFACE_CONFEDIT_BACKUP_MAX 5 7 | 8 | 9 | ConfigFileEditor::ConfigFileEditor() 10 | { 11 | 12 | } 13 | 14 | bool ConfigFileEditor::fileExists(const QString& fileName) 15 | { 16 | QFile file(expandFileName(fileName)); 17 | return file.exists(); 18 | } 19 | 20 | qint64 ConfigFileEditor::fileSize(const QString& fileName) 21 | { 22 | QFile file(expandFileName(fileName)); 23 | if (file.exists()) 24 | return file.size(); 25 | else 26 | return 0; 27 | } 28 | 29 | ConfigFileEditor::FileErrorCode 30 | ConfigFileEditor::exists(const QString& fileName, 31 | const QString& search, 32 | bool& exist) 33 | { 34 | exist = false; 35 | 36 | QFile file(expandFileName(fileName)); 37 | if (!file.exists()) 38 | return FileNotFound; 39 | if (!file.open(QFile::ReadOnly)) 40 | return NoPermission; 41 | 42 | QByteArray searchBytes(search.toUtf8()); 43 | QByteArray buffer; 44 | while (!file.atEnd()) 45 | { 46 | buffer.append(file.read(SPANDA_IFACE_CONFEDIT_BUFFER_LEN)); 47 | if (buffer.contains(searchBytes)) 48 | { 49 | exist = true; 50 | break; 51 | } 52 | else 53 | buffer.remove(0, buffer.length() - searchBytes.length()); 54 | } 55 | return FileOk; 56 | } 57 | 58 | ConfigFileEditor::FileErrorCode 59 | ConfigFileEditor::findLine(const QString& fileName, 60 | const QString& search, 61 | QString& matchedLine) 62 | { 63 | matchedLine.clear(); 64 | 65 | QFile file(expandFileName(fileName)); 66 | if (!file.exists()) 67 | return FileNotFound; 68 | if (!file.open(QFile::ReadOnly)) 69 | return NoPermission; 70 | 71 | QByteArray searchBytes(search.toUtf8()); 72 | QByteArray buffer; 73 | bool found = false; 74 | while (!file.atEnd()) 75 | { 76 | buffer = file.readLine(); 77 | if (buffer.contains(searchBytes)) 78 | { 79 | found = true; 80 | break; 81 | } 82 | } 83 | if (found) 84 | matchedLine = buffer; 85 | return FileOk; 86 | } 87 | 88 | ConfigFileEditor::FileErrorCode 89 | ConfigFileEditor::replace(const QString& fileName, 90 | const QString& search, 91 | const QString& replace) 92 | { 93 | QFile file(expandFileName(fileName)); 94 | if (!file.exists()) 95 | return FileNotFound; 96 | if (!file.open(QFile::ReadOnly)) 97 | return NoPermission; 98 | 99 | int pos = -1; 100 | QByteArray searchBytes(search.toUtf8()); 101 | QByteArray buffer, readBuffer; 102 | while (!file.atEnd()) 103 | { 104 | readBuffer = file.read(SPANDA_IFACE_CONFEDIT_BUFFER_LEN); 105 | buffer.append(readBuffer); 106 | if (buffer.contains(searchBytes)) 107 | { 108 | pos = file.pos() - buffer.length() + buffer.indexOf(searchBytes); 109 | break; 110 | } 111 | else 112 | buffer.remove(0, buffer.length() - searchBytes.length()); 113 | } 114 | 115 | if (pos >= 0) 116 | { 117 | // Create a temporary file of the content to be modified 118 | QTemporaryFile tempFile; 119 | if (!tempFile.open()) 120 | return NoPermission; 121 | file.seek(0); 122 | tempFile.write(file.readAll()); 123 | file.close(); 124 | 125 | // Modify the searched content with replacing content 126 | file.open(QFile::ReadWrite); 127 | if (!file.isWritable()) 128 | return NoPermission; 129 | file.resize(pos); 130 | file.seek(pos); 131 | file.write(replace.toUtf8()); 132 | 133 | // Write the rest part of file according to 134 | // the content of the temp file 135 | tempFile.seek(pos + search.length()); 136 | file.write(tempFile.readAll()); 137 | } 138 | file.close(); 139 | return FileOk; 140 | } 141 | 142 | ConfigFileEditor::FileErrorCode 143 | ConfigFileEditor::replaceLine(const QString& fileName, 144 | const QString& search, 145 | const QString& replace, 146 | bool appendIfNotFound) 147 | { 148 | QString oldConfigLine; 149 | FileErrorCode errCode = findLine(fileName, search, oldConfigLine); 150 | if (oldConfigLine.isEmpty()) 151 | { 152 | if (appendIfNotFound) 153 | errCode = ConfigFileEditor::append(fileName, replace); 154 | } 155 | else 156 | errCode = ConfigFileEditor::replace(fileName, oldConfigLine, replace); 157 | return errCode; 158 | } 159 | 160 | ConfigFileEditor::FileErrorCode 161 | ConfigFileEditor::regexpReplaceLine(const QString& fileName, 162 | const QString& search, 163 | const QString& regExp, 164 | const QString& replace) 165 | { 166 | QString oldConfigLine, newConfigLine; 167 | findLine(fileName, search, oldConfigLine); 168 | if (oldConfigLine.isEmpty()) 169 | newConfigLine = search; 170 | else 171 | newConfigLine = oldConfigLine; 172 | newConfigLine.replace(QRegExp(regExp), replace); 173 | return ConfigFileEditor::replace(fileName, oldConfigLine, newConfigLine); 174 | } 175 | 176 | ConfigFileEditor::FileErrorCode 177 | ConfigFileEditor::regexpWriteLine(const QString& fileName, 178 | const QString& search, 179 | const QString& regExp, 180 | QString replace, 181 | bool replaceIfExists) 182 | { 183 | bool existed; 184 | FileErrorCode errCode = exists(fileName, search, existed); 185 | if (existed) 186 | { 187 | if (replaceIfExists) 188 | errCode = regexpReplaceLine(fileName, search, regExp, replace); 189 | } 190 | else 191 | errCode = append(fileName, replace.prepend("\n")); 192 | return errCode; 193 | } 194 | 195 | ConfigFileEditor::FileErrorCode ConfigFileEditor::backupFile(const QString &origin, 196 | QString &destination) 197 | { 198 | QFile file(expandFileName(origin)); 199 | QString destName; 200 | int backupCount = 1; 201 | 202 | if (!file.exists()) 203 | return FileNotFound; 204 | 205 | if (destName.isEmpty()) 206 | { 207 | while (backupCount <= SPANDA_IFACE_CONFEDIT_BACKUP_MAX) 208 | { 209 | destName = QString(origin) 210 | .append(".bak.") 211 | .append(QString::number(backupCount)); 212 | file.setFileName(destName); 213 | if (file.exists()) 214 | backupCount++; 215 | else 216 | break; 217 | } 218 | if (file.exists()) 219 | { 220 | // Shift backup file number 221 | // i.e. delete 1, 2=>1, 3=>2, ..., MAX=>MAX-1 222 | // Then we can use MAX for the number of new backup file 223 | if (!QFile::remove(QString(origin) 224 | .append(".bak.") 225 | .append(QString::number(1)))) 226 | return NoPermission; 227 | 228 | for (int i=2; i<=SPANDA_IFACE_CONFEDIT_BACKUP_MAX; i++) 229 | { 230 | file.setFileName(QString(origin) 231 | .append(".bak.") 232 | .append(QString::number(i))); 233 | if (!file.exists()) 234 | continue; 235 | if (!file.rename(QString(origin) 236 | .append(".bak.") 237 | .append(QString::number(i - 1)))) 238 | return NoPermission; 239 | } 240 | } 241 | } 242 | 243 | file.setFileName(origin); 244 | if (!QFile::copy(origin, destName)) 245 | return NoPermission; 246 | else 247 | { 248 | destination = destName; 249 | return FileOk; 250 | } 251 | } 252 | 253 | ConfigFileEditor::FileErrorCode 254 | ConfigFileEditor::deleteFile(const QString &fileName) 255 | { 256 | QFile file(expandFileName(fileName)); 257 | if (!file.exists()) 258 | return FileNotFound; 259 | if (file.remove()) 260 | return FileOk; 261 | else 262 | return NoPermission; 263 | } 264 | 265 | ConfigFileEditor::FileErrorCode 266 | ConfigFileEditor::append(const QString &fileName, const QString &content) 267 | { 268 | QFile file(expandFileName(fileName)); 269 | if (!file.open(QFile::Append)) 270 | return NoPermission; 271 | 272 | file.write(content.toUtf8()); 273 | file.close(); 274 | return FileOk; 275 | } 276 | 277 | QString ConfigFileEditor::expandFileName(const QString &fileName) 278 | { 279 | QString fullName(fileName); 280 | if (fullName.indexOf("$HOME") >= 0) 281 | fullName.replace("$HOME", QDir::homePath()); 282 | if (fullName.indexOf('~') == 0) 283 | fullName.replace(0, 1, QDir::homePath()); 284 | return fullName; 285 | } 286 | -------------------------------------------------------------------------------- /Interfaces/configfileeditor.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIGFILEEDITOR_H 2 | #define CONFIGFILEEDITOR_H 3 | 4 | #include 5 | 6 | 7 | class ConfigFileEditor 8 | { 9 | public: 10 | enum FileErrorCode 11 | { 12 | FileOk = 0, 13 | FileNotFound = 1, 14 | NoPermission = 2, 15 | CannotBackup = 3, 16 | UnknownError = 255 17 | }; 18 | 19 | ConfigFileEditor(); 20 | 21 | static bool fileExists(const QString& fileName); 22 | static qint64 fileSize(const QString& fileName); 23 | static FileErrorCode backupFile(const QString& origin, 24 | QString& destination); 25 | static FileErrorCode deleteFile(const QString& fileName); 26 | 27 | static FileErrorCode exists(const QString& fileName, 28 | const QString& search, 29 | bool& exist); 30 | static FileErrorCode findLine(const QString& fileName, 31 | const QString& search, 32 | QString& matchedLine); 33 | static FileErrorCode replace(const QString& fileName, 34 | const QString& search, 35 | const QString& replace); 36 | static FileErrorCode replaceLine(const QString& fileName, 37 | const QString& search, 38 | const QString& replace, 39 | bool appendIfNotFound = true); 40 | static FileErrorCode regexpReplaceLine(const QString& fileName, 41 | const QString& search, 42 | const QString& expression, 43 | const QString& replace); 44 | static FileErrorCode regexpWriteLine(const QString& fileName, 45 | const QString& search, 46 | const QString& regExp, 47 | QString replace, 48 | bool replaceIfExists = true); 49 | static FileErrorCode append(const QString& fileName, 50 | const QString& content); 51 | 52 | private: 53 | static QString expandFileName(const QString& fileName); 54 | }; 55 | 56 | #endif // CONFIGFILEEDITOR_H 57 | -------------------------------------------------------------------------------- /Interfaces/exelauncher.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "exelauncher.h" 3 | 4 | #define SPANDA_EXEC_SHELL_DEFAULT "/bin/bash" 5 | #define SPANDA_EXEC_SHELL_ARG_EXEC "-c" 6 | 7 | ExeLauncher::ExeLauncher() 8 | { 9 | connect(&process, 10 | SIGNAL(error(QProcess::ProcessError)), 11 | this, 12 | SLOT(onProcessError(QProcess::ProcessError))); 13 | connect(&process, 14 | SIGNAL(finished(int)), 15 | this, 16 | SLOT(onProcessFinished(int))); 17 | } 18 | 19 | ExeLauncher::ExecErrorCode 20 | ExeLauncher::runFile(const QString& filePath, 21 | const QList& arguments, 22 | bool synchronous) 23 | { 24 | // Save command information 25 | command = filePath; 26 | command.append(' ').append(arguments.join(' ')); 27 | execPath = filePath; 28 | 29 | ExecErrorCode errCode = ExecOk; 30 | process.start(filePath, arguments); 31 | if (synchronous) 32 | { 33 | process.waitForStarted(); 34 | process.waitForFinished(); 35 | } 36 | return errCode; 37 | } 38 | 39 | ExeLauncher::ExecErrorCode 40 | ExeLauncher::runCommand(const QString& command, 41 | bool synchronous) 42 | { 43 | QStringList args(command); 44 | args.push_front(SPANDA_EXEC_SHELL_ARG_EXEC); 45 | return runFile(SPANDA_EXEC_SHELL_DEFAULT, args, synchronous); 46 | } 47 | 48 | QString ExeLauncher::getCommand() 49 | { 50 | return command; 51 | } 52 | 53 | QString ExeLauncher::getExeFilePath() 54 | { 55 | return execPath; 56 | } 57 | 58 | QByteArray ExeLauncher::getOutput() 59 | { 60 | return output; 61 | } 62 | 63 | int ExeLauncher::getExitCode() 64 | { 65 | return process.exitCode(); 66 | } 67 | 68 | ExeLauncher::ExecErrorCode ExeLauncher::getErrCode() 69 | { 70 | if (process.exitStatus() == QProcess::CrashExit) 71 | return Crashed; 72 | switch (process.exitCode()) 73 | { 74 | case 0: 75 | return ExecOk; 76 | case 1: 77 | return NoPermission; 78 | case 126: 79 | return NoPermission; 80 | case 127: 81 | return FileNotFound; 82 | default: 83 | return UnknownError; 84 | } 85 | } 86 | 87 | bool ExeLauncher::fileExecutable(const QString &filePath) 88 | { 89 | QFileInfo fileInfo(filePath); 90 | return fileInfo.exists() && fileInfo.isExecutable(); 91 | } 92 | 93 | void ExeLauncher::onProcessError(QProcess::ProcessError errCode) 94 | { 95 | output.clear(); 96 | switch (errCode) 97 | { 98 | case QProcess::Crashed: 99 | emit finished(Crashed); 100 | break; 101 | case QProcess::FailedToStart: 102 | emit finished(NoPermission); 103 | break; 104 | default: 105 | emit finished(UnknownError); 106 | } 107 | } 108 | 109 | void ExeLauncher::onProcessFinished(int exitCode) 110 | { 111 | Q_UNUSED(exitCode) 112 | output = process.readAllStandardOutput(); 113 | ExecErrorCode errCode = getErrCode(); 114 | if (errCode != ExecOk) 115 | output.append(process.readAllStandardError()); 116 | emit finished(errCode); 117 | } 118 | -------------------------------------------------------------------------------- /Interfaces/exelauncher.h: -------------------------------------------------------------------------------- 1 | #ifndef EXELAUNCHER_H 2 | #define EXELAUNCHER_H 3 | 4 | #include 5 | #include 6 | 7 | 8 | class ExeLauncher : public QObject 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | enum ExecErrorCode 14 | { 15 | ExecOk = 0, 16 | FileNotFound = 1, 17 | NoPermission = 2, 18 | Crashed = 3, 19 | UnknownError = 255 20 | }; 21 | 22 | ExeLauncher(); 23 | 24 | ExecErrorCode runFile(const QString& filePath, 25 | const QList& arguments, 26 | bool synchronous = false); 27 | ExecErrorCode runCommand(const QString& command, 28 | bool synchronous = false); 29 | QString getCommand(); 30 | QString getExeFilePath(); 31 | QByteArray getOutput(); 32 | int getExitCode(); 33 | ExecErrorCode getErrCode(); 34 | static bool fileExecutable(const QString& filePath); 35 | 36 | signals: 37 | void finished(ExeLauncher::ExecErrorCode errCode); 38 | 39 | private: 40 | QString execPath; 41 | QString command; 42 | QProcess process; 43 | QByteArray output; 44 | 45 | private slots: 46 | void onProcessError(QProcess::ProcessError errCode); 47 | void onProcessFinished(int exitCode); 48 | }; 49 | 50 | #endif // EXELAUNCHER_H 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SuperPanda 2 | 3 | This is a simple tool for tuning Linux system. Enjoy the Konfug! 4 | 5 | The [SuperPanda icon](./Icons/SuperPanda.png) is adapted from the [original work](https://thenounproject.com/elena.rimeikaite/collection/panda/?i=433972) created by Elena Rimeikaite from the Noun Project, and is licensed under Creative Commons Attribution 3.0 (CC BY 3.0). 6 | 7 | The rest part of this project is licensed under GNU GPLv3. The licence text can be found in file [LICENSE](./LICENSE). 8 | 9 | Part of the code in this project is ported from [Qt Creator Project](https://code.qt.io/cgit/qt-creator/). We thank its authors for their excellent works in making software more OPEN and FREE! 10 | 11 | 12 | ## How To Build And Install 13 | 14 | See file [INSTALL](./INSTALL). 15 | 16 | 17 | ## Document 18 | 19 | Technical details can be found in markdown files under [doc](./doc) directory. -------------------------------------------------------------------------------- /SuperPanda.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2018-06-13T20:48:02 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = SuperPanda 12 | TEMPLATE = app 13 | 14 | VER_MAJ = 1 15 | VER_MIN = 1 16 | VER_PAT = 0 17 | VERSION = 1.1.0 18 | 19 | # The following define makes your compiler emit warnings if you use 20 | # any feature of Qt which as been marked as deprecated (the exact warnings 21 | # depend on your compiler). Please consult the documentation of the 22 | # deprecated API in order to know how to port your code away from it. 23 | DEFINES += QT_DEPRECATED_WARNINGS APP_VERSION=\\\"$$VERSION\\\" 24 | 25 | # You can also make your code fail to compile if you use deprecated APIs. 26 | # In order to do so, uncomment the following line. 27 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 28 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 29 | 30 | 31 | SOURCES +=\ 32 | main.cpp \ 33 | Interfaces/configfileeditor.cpp \ 34 | Components/magickonfug.cpp \ 35 | Interfaces/exelauncher.cpp \ 36 | Utils/diskutils.cpp \ 37 | Utils/bootutils.cpp \ 38 | Utils/dialogutils.cpp \ 39 | mainwindow.cpp \ 40 | global.cpp \ 41 | aboutwindow.cpp \ 42 | Utils/environment.cpp \ 43 | Utils/environmentmodel.cpp \ 44 | Utils/hostosinfo.cpp \ 45 | Utils/qtcassert.cpp \ 46 | Utils/fileutils.cpp \ 47 | Utils/savefile.cpp \ 48 | Widgets/headerviewstretcher.cpp \ 49 | Widgets/itemviews.cpp \ 50 | Widgets/environmentdialog.cpp \ 51 | Widgets/environmentwidget.cpp \ 52 | Utils/gsettingseditor.cpp \ 53 | Components/configcollection.cpp \ 54 | Utils/screenutils.cpp \ 55 | Utils/swaputils.cpp 56 | 57 | HEADERS += \ 58 | Interfaces/configfileeditor.h \ 59 | Components/magickonfug.h \ 60 | Interfaces/exelauncher.h \ 61 | Utils/diskutils.h \ 62 | Utils/bootutils.h \ 63 | Utils/dialogutils.h \ 64 | mainwindow.h \ 65 | global.h \ 66 | aboutwindow.h \ 67 | Utils/environment.h \ 68 | Utils/environmentmodel.h \ 69 | Utils/hostosinfo.h \ 70 | Utils/fileutils.h \ 71 | Utils/qtcassert.h \ 72 | Utils/osspecificaspects.h \ 73 | Utils/savefile.h \ 74 | Widgets/headerviewstretcher.h \ 75 | Widgets/itemviews.h \ 76 | Widgets/environmentdialog.h \ 77 | Widgets/environmentwidget.h \ 78 | Utils/gsettingseditor.h \ 79 | Components/configcollection.h \ 80 | Components/configcollection_p.h \ 81 | Components/config_files.h \ 82 | Components/config_gconf.h \ 83 | Utils/screenutils.h \ 84 | Utils/swaputils.h 85 | 86 | FORMS += \ 87 | Components/magickonfug.ui \ 88 | mainwindow.ui \ 89 | aboutwindow.ui 90 | 91 | RESOURCES += \ 92 | icons.qrc \ 93 | translations.qrc \ 94 | 95 | TRANSLATIONS += \ 96 | Translations/SuperPanda_fr_FR.ts \ 97 | Translations/SuperPanda_zh_CN.ts \ 98 | Translations/SuperPanda_zh_TW.ts 99 | 100 | include(translation.pri) 101 | 102 | 103 | target.path = $${PREFIX}/bin/ 104 | 105 | INSTALLS += target 106 | -------------------------------------------------------------------------------- /Translations/SuperPanda_zh_CN.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AboutWindow 6 | 7 | 8 | <html><head/><body><p><span style=" font-size:20pt;">Super Panda</span></p></body></html> 9 | <html><head/><body><p><span style=" font-size:20pt;">超级熊猫</span></p></body></html> 10 | 11 | 12 | 13 | 14 | About 15 | 关于 16 | 17 | 18 | 19 | Author 20 | 作者 21 | 22 | 23 | Ver 24 | 版本 25 | 26 | 27 | 28 | Ver: %1 29 | 版本: %1 30 | 31 | 32 | 33 | Super Panda - Toolkit for tweaking Linux system 34 | 35 | This program is a free software. 36 | 37 | You can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 38 | 39 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. 40 | 41 | 超级熊猫 - Linux专属优化大师 42 | 43 | 本程序是自由软件。 44 | 45 | 你可以按照自由软件基金会出版的GNU通用公共许可证(GPL)条款来修改和重新发布本程序;GPL许可证的版本可以是第三版,或者(根据你的选择)更高的版本。 46 | 47 | 发布这一程序的目的是希望它能有用,但作者对此不做任何保证。作者也不保证本程序的经济价值,或特定场景下的适用性。请参见GNU通用公共许可证(GPL)的文本以便详细了解相关条款。 48 | 49 | 50 | 51 | <p>Project Home: <a href="https://github.com/zwpwjwtz/SuperPanda">Github</a><p align="center">Feel free to report bugs and give suggestions!</p> 52 | <p>项目主页:<a href="https://github.com/zwpwjwtz/SuperPanda">Github</a><p align="center">欢迎报告软件错误、反馈意见/建议!</p> 53 | 54 | 55 | 56 | DialogUtils 57 | 58 | 59 | 60 | Missing file 61 | 缺少文件 62 | 63 | 64 | 65 | Cannot continue due to a missing file: 66 | %1 67 | 操作无法继续进行,因为缺少以下文件: 68 | %1 69 | 70 | 71 | 72 | File %1 does not exists. We will try to create it if possible. 73 | 文件 %1 不存在。我们将试图创建它。 74 | 75 | 76 | 77 | 78 | Permission denied 79 | 权限不足 80 | 81 | 82 | 83 | Cannot continue due to denied access to 84 | %1 85 | 操作无法继续进行,因为我们无权访问以下文件: 86 | %1 87 | 88 | 89 | 90 | Cannot execute %1. 91 | Please make sure that you have the right permission to do it. 92 | 无法执行 %1。 93 | 请确保您有足够的权限。 94 | 95 | 96 | 97 | EnvironmentWidget 98 | 99 | 100 | Ed&it 101 | 编辑(&E) 102 | 103 | 104 | 105 | &Add 106 | 添加(&A) 107 | 108 | 109 | 110 | &Reset 111 | 还原(&R) 112 | 113 | 114 | 115 | &Unset 116 | 删除(&U) 117 | 118 | 119 | 120 | &Batch Edit... 121 | 批量编辑(&B) 122 | 123 | 124 | 125 | Unset <a href="%1"><b>%1</b></a> 126 | 删除 <a href="%1"><b>%1</b></a> 127 | 128 | 129 | 130 | Set <a href="%1"><b>%1</b></a> to <b>%2</b> 131 | 设置 <a href="%1"><b>%1</b></a> 为 <b>%2</b> 132 | 133 | 134 | 135 | Use <b>%1</b> 136 | %1 is "System Environment" or some such. 137 | 修改 <b>%1</b> 138 | 139 | 140 | 141 | Use <b>%1</b> and 142 | Yup, word puzzle. The Set/Unset phrases above are appended to this. %1 is "System Environment" or some such. 143 | 修改 <b>%1</b> 并且 144 | 145 | 146 | 147 | MagicKonfug 148 | 149 | 150 | SuperPanda - MagiKonfu 151 | 超级熊猫魔法设置 152 | 153 | 154 | 155 | Startup 156 | 启动 157 | 158 | 159 | 160 | Hardware 161 | 硬件 162 | 163 | 164 | 165 | Service 166 | 服务 167 | 168 | 169 | 170 | Application 171 | 应用程序 172 | 173 | 174 | 175 | Input/Output 176 | 输入/输出 177 | 178 | 179 | 180 | Disk 181 | 磁盘 182 | 183 | 184 | 185 | Boot Menu 186 | 开机菜单 187 | 188 | 189 | 190 | 191 | 192 | sec. 193 | 194 | 195 | 196 | 197 | Timeout: 198 | 等待时间: 199 | 200 | 201 | 202 | Resolution: 203 | 分辨率: 204 | 205 | 206 | 207 | Default 208 | 默认 209 | 210 | 211 | 212 | 640x480 213 | 640x480 214 | 215 | 216 | 217 | 800x600 218 | 800x600 219 | 220 | 221 | 222 | 1024x768 223 | 1024x768 224 | 225 | 226 | 227 | CPU 228 | CPU 229 | 230 | 231 | Enable Turbo Frequency for Inel® processors 232 | 为 Inel® 处理器开启动态频率调节功能 233 | 234 | 235 | 236 | Enable Turbo Frequency for Intel® processors 237 | 为 Inel® 处理器开启动态频率调节功能 238 | 239 | 240 | 241 | WiFi 242 | WiFi 243 | 244 | 245 | 246 | Enable 802.11n for Intel® Wireless LAN adapters 247 | 在 Inel® 无线网卡上启用 802.11n 模式 248 | 249 | 250 | 251 | Set timeout for services: 252 | 设置系统服务的等待时间: 253 | 254 | 255 | 256 | Start/stop: 257 | 启动/停止: 258 | 259 | 260 | 261 | Shutdown: 262 | 关机: 263 | 264 | 265 | 266 | Edit environment variables: 267 | 编辑环境变量: 268 | 269 | 270 | 271 | For the whole system 272 | 应用到整个系统 273 | 274 | 275 | 276 | For this user only 277 | 仅针对当前用户 278 | 279 | 280 | 281 | Keyboard 282 | 键盘 283 | 284 | 285 | 286 | Compose Key 287 | 合成键 288 | 289 | 290 | 291 | Set compose key for inputing special characters: 292 | 设置合成键以便输入特殊字符: 293 | 294 | 295 | 296 | (Disabled) 297 | (禁用) 298 | 299 | 300 | 301 | Right Alt Key 302 | 右Alt 303 | 304 | 305 | 306 | Left Win Key 307 | 左Win 308 | 309 | 310 | 311 | Right Win Key 312 | 右Win 313 | 314 | 315 | 316 | Left Ctrl Key 317 | 左Ctrl 318 | 319 | 320 | 321 | Right Ctrl Key 322 | 右Ctrl 323 | 324 | 325 | 326 | Caps Lock Key 327 | Caps Lock 328 | 329 | 330 | 331 | Menu Key 332 | 菜单键 333 | 334 | 335 | 336 | Display 337 | 显示 338 | 339 | 340 | 341 | Screen scaling 342 | 屏幕缩放 343 | 344 | 345 | 346 | Set screen scaling factors: 347 | 设置屏幕缩放比例: 348 | 349 | 350 | 351 | Window: 352 | 窗口: 353 | 354 | 355 | 356 | Window text: 357 | 窗口文本: 358 | 359 | 360 | 361 | Hard disk (HDD) 362 | 机械硬盘(HDD) 363 | 364 | 365 | 366 | Solid state disk (SSD) 367 | 固态硬盘(SSD) 368 | 369 | 370 | 371 | Optimize system disk according to its type: 372 | 选择系统盘属性以便进行优化: 373 | 374 | 375 | 376 | Welcome to the Magic Konfug world! 377 | 欢迎来到超级熊猫的魔法世界! 378 | 379 | 380 | 381 | This tool helps you tune your system. Just explore it and hope you can get the excellent Konfug! 382 | 本工具将帮助您调整系统的各项参数。祝您早日成为 Linux 高手! 383 | 384 | 385 | 386 | Magic Konfu is a part of SuperPanda, a toolkit designed for customizing Linux system without annoying command lines. 387 | 388 | See About page of SuperPanda for more details. 389 | “超级熊猫魔法设置”是“超级熊猫”软件的一部分,它可以帮助您调整 Linux 系统的各项参数,而无需使用命令行。 390 | 391 | 请查看 SuperPanda 的“关于”页面以了解更多信息。 392 | 393 | 394 | 395 | Not supported on your system. 396 | 抱歉,您的系统不支持此功能。 397 | 398 | 399 | 400 | Environment Variable Editor 401 | 环境变量编辑器 402 | 403 | 404 | 405 | System Environment 406 | 系统环境变量 407 | 408 | 409 | 410 | User Environment 411 | 用户环境变量 412 | 413 | 414 | 415 | Processing configuration, please wait... 416 | 正在应用配置,请稍后…… 417 | 418 | 419 | 420 | Configuration(s) applied 421 | 您的更改已保存 422 | 423 | 424 | 425 | Finish applying configuration. You may need to reboot to have them take effect. 426 | 已保存配置。您可能需要重启电脑以使更改生效。 427 | 428 | 429 | 430 | MainWindow 431 | 432 | 433 | Super Panda 434 | 超级熊猫 435 | 436 | 437 | 438 | About SuperPanda 439 | 关于超级熊猫 440 | 441 | 442 | 443 | SuperPanda 444 | MagiKonfug 445 | 超级熊猫 446 | 魔法设置 447 | 448 | 449 | 450 | Utils::EnvironmentDialog 451 | 452 | 453 | Enter one environment variable per line. 454 | To set or change a variable, use VARIABLE=VALUE. 455 | Existing variables can be referenced in a VALUE with ${OTHER}. 456 | To clear a variable, put its name on a line with nothing else on it. 457 | 请输入环境变量,每行一个。 458 | 如要添加或修改环境变量,请遵循“变量名=变量值”的语法。 459 | 您可以使用 ${变量名} 的方式来引用已经存在的变量。 460 | 若要删除一个变量,只需将它的值清空即可。 461 | 462 | 463 | 464 | Edit Environment 465 | 编辑环境变量 466 | 467 | 468 | 469 | Utils::EnvironmentModel 470 | 471 | 472 | <UNSET> 473 | <已删除> 474 | 475 | 476 | 477 | Variable 478 | 变量 479 | 480 | 481 | 482 | Value 483 | 484 | 485 | 486 | 487 | 488 | <VARIABLE> 489 | Name when inserting a new variable 490 | <变量名> 491 | 492 | 493 | 494 | <VALUE> 495 | Value when inserting a new variable 496 | <值> 497 | 498 | 499 | 500 | Utils::FileUtils 501 | 502 | 503 | Refusing to remove root directory. 504 | 无法删除根目录。 505 | 506 | 507 | 508 | Refusing to remove your home directory. 509 | 无法删除当前用户的主目录。 510 | 511 | 512 | 513 | Failed to remove directory "%1". 514 | 无法删除目录“%1”。 515 | 516 | 517 | 518 | Failed to remove file "%1". 519 | 无法删除文件“%1”。 520 | 521 | 522 | 523 | Failed to create directory "%1". 524 | 无法创建目录“%1”。 525 | 526 | 527 | 528 | Could not copy file "%1" to "%2". 529 | 无法复制文件“%1”到“%2”。 530 | 531 | 532 | 533 | Cannot open %1 for reading: %2 534 | 无法打开并读取文件 %1:%2 535 | 536 | 537 | 538 | Cannot read %1: %2 539 | 无法读取 %1:%2 540 | 541 | 542 | 543 | 544 | File Error 545 | 文件错误 546 | 547 | 548 | 549 | Cannot write file %1: %2 550 | 无法写入文件%1:%2 551 | 552 | 553 | 554 | Cannot write file %1. Disk full? 555 | 无法写入文件%1,磁盘可能已满。 556 | 557 | 558 | 559 | %1: Is a reserved filename on Windows. Cannot save. 560 | %1 是 Windows 下的保留文件名,无法保存到该文件。 561 | 562 | 563 | 564 | Cannot overwrite file %1: %2 565 | 无法覆盖文件 %1:%2 566 | 567 | 568 | 569 | Cannot create file %1: %2 570 | 无法创建文件%1:%2 571 | 572 | 573 | 574 | Cannot create temporary file in %1: %2 575 | 无法在 %1 下创建临时文件:%2 576 | 577 | 578 | 579 | Utils::HostOsInfo 580 | 581 | 582 | Cannot create OpenGL context. 583 | 无法创建 OpenGL 上下文。 584 | 585 | 586 | 587 | -------------------------------------------------------------------------------- /Utils/bootutils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bootutils.h" 3 | #include "dialogutils.h" 4 | #include "../Interfaces/configfileeditor.h" 5 | 6 | #define SPANDA_MGCKF_EXEC_GRUB_UPDATE "/usr/sbin/grub2-mkconfig" 7 | #define SPANDA_MGCKF_EXEC_GRUB_UPDATE2 "/usr/sbin/grub-mkconfig" 8 | 9 | #define SPANDA_MGCKF_FILE_GRUB_CONFIG "/boot/grub2/grub.cfg" 10 | #define SPANDA_MGCKF_FILE_GRUB_CONFIG2 "/boot/grub/grub.cfg" 11 | 12 | 13 | BootUtils::BootUtils() 14 | { 15 | connect(&exeFile, 16 | SIGNAL(finished(ExeLauncher::ExecErrorCode)), 17 | this, 18 | SLOT(onExeFinished(ExeLauncher::ExecErrorCode))); 19 | } 20 | 21 | bool BootUtils::updateBootMenu(QString configFilePath) 22 | { 23 | // Update grub config file using grub-mkconfig 24 | 25 | QList tempStringList; 26 | tempStringList.append("-o"); 27 | 28 | if (configFilePath.isEmpty()) 29 | { 30 | if (ConfigFileEditor::fileExists(SPANDA_MGCKF_FILE_GRUB_CONFIG)) 31 | tempStringList.append(SPANDA_MGCKF_FILE_GRUB_CONFIG); 32 | else 33 | tempStringList.append(SPANDA_MGCKF_FILE_GRUB_CONFIG2); 34 | } 35 | else 36 | { 37 | if (!ConfigFileEditor::fileExists(configFilePath)) 38 | return false; 39 | } 40 | 41 | QString fileName; 42 | if (exeFile.fileExecutable(SPANDA_MGCKF_EXEC_GRUB_UPDATE)) 43 | fileName = SPANDA_MGCKF_EXEC_GRUB_UPDATE; 44 | else 45 | fileName = SPANDA_MGCKF_EXEC_GRUB_UPDATE2; 46 | 47 | return (exeFile.runFile(fileName, tempStringList) == ExeLauncher::ExecOk); 48 | } 49 | 50 | void BootUtils::onExeFinished(ExeLauncher::ExecErrorCode errCode) 51 | { 52 | switch (errCode) 53 | { 54 | case ExeLauncher::ExecOk: 55 | emit commandFinished(true); 56 | return; 57 | case ExeLauncher::FileNotFound: 58 | DialogUtils::warnMissingFile(exeFile.getExeFilePath(), true); 59 | break; 60 | case ExeLauncher::NoPermission: 61 | DialogUtils::warnExecPermission(exeFile.getExeFilePath()); 62 | break; 63 | case ExeLauncher::Crashed: 64 | case ExeLauncher::UnknownError: 65 | default: 66 | QMessageBox::critical(nullptr, "Unknown error occured", 67 | QString("Magic Panda encountered an exception " 68 | "when trying to execute program \n%1\n" 69 | "Exit code: %2\n") 70 | .arg(exeFile.getCommand()) 71 | .arg(exeFile.getExitCode())); 72 | } 73 | emit commandFinished(false); 74 | } 75 | -------------------------------------------------------------------------------- /Utils/bootutils.h: -------------------------------------------------------------------------------- 1 | #ifndef BOOTUTILS_H 2 | #define BOOTUTILS_H 3 | 4 | #include 5 | #include "../Interfaces/exelauncher.h" 6 | 7 | 8 | class BootUtils : public QObject 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | BootUtils(); 14 | 15 | bool updateBootMenu(QString configFilePath = ""); 16 | 17 | signals: 18 | void commandFinished(bool successful); 19 | 20 | private: 21 | ExeLauncher exeFile; 22 | 23 | private slots: 24 | void onExeFinished(ExeLauncher::ExecErrorCode errCode); 25 | }; 26 | 27 | #endif // BOOTUTILS_H 28 | -------------------------------------------------------------------------------- /Utils/dialogutils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "dialogutils.h" 3 | 4 | 5 | DialogUtils::DialogUtils() 6 | { 7 | 8 | } 9 | 10 | void DialogUtils::warnMissingFile(QString fileName, bool aborted) 11 | { 12 | if (aborted) 13 | { 14 | QMessageBox::critical(nullptr, tr("Missing file"), 15 | QString( 16 | tr("Cannot continue due to a missing file: " 17 | "\n%1") 18 | ).arg(fileName)); 19 | } 20 | else 21 | { 22 | QMessageBox::warning(nullptr, tr("Missing file"), 23 | QString( 24 | tr("File %1 does not exists. We will try to " 25 | "create it if possible.") 26 | ).arg(fileName)); 27 | } 28 | } 29 | 30 | void DialogUtils::warnPermission(QString objectName) 31 | { 32 | QMessageBox::critical(nullptr, tr("Permission denied"), 33 | QString( 34 | tr("Cannot continue due to denied access to " 35 | "\n%1") 36 | ).arg(objectName)); 37 | } 38 | 39 | void DialogUtils::warnExecPermission(QString objectName) 40 | { 41 | QMessageBox::critical(nullptr, tr("Permission denied"), 42 | QString( 43 | tr("Cannot execute %1.\n" 44 | "Please make sure that you have the " 45 | "right permission to do it.") 46 | ).arg(objectName)); 47 | } 48 | 49 | void DialogUtils::warnInsufficientSpace(QString path, qint64 requiredSpace) 50 | { 51 | requiredSpace /= 1024 * 1024; // Use MiB as readable unit 52 | QMessageBox::critical(nullptr, tr("Insufficient Space"), 53 | QString(tr("One or more operation failed due to " 54 | "insufficient space of directory %1.\n" 55 | "Please make sure that it has at least " 56 | "%2 MB free space.")) 57 | .arg(path) 58 | .arg(QString::number(requiredSpace))); 59 | } 60 | -------------------------------------------------------------------------------- /Utils/dialogutils.h: -------------------------------------------------------------------------------- 1 | #ifndef DIALOGUTILS_H 2 | #define DIALOGUTILS_H 3 | 4 | #include 5 | 6 | 7 | class DialogUtils 8 | { 9 | Q_DECLARE_TR_FUNCTIONS(DialogUtils) 10 | 11 | public: 12 | DialogUtils(); 13 | 14 | static void warnMissingFile(QString fileName, bool aborted = false); 15 | static void warnPermission(QString objectName); 16 | static void warnExecPermission(QString objectName); 17 | static void warnInsufficientSpace(QString path, qint64 requiredSpace); 18 | }; 19 | 20 | #endif // DIALOGUTILS_H 21 | -------------------------------------------------------------------------------- /Utils/diskutils.cpp: -------------------------------------------------------------------------------- 1 | #include "diskutils.h" 2 | #include "../Interfaces/exelauncher.h" 3 | 4 | 5 | DiskUtils::DiskUtils() 6 | { 7 | 8 | } 9 | 10 | QString DiskUtils::getUUIDByBlock(QString blockName) 11 | { 12 | ExeLauncher exe; 13 | exe.runCommand(QString("blkid | grep \"^%1\"").arg(blockName), true); 14 | 15 | QString result; 16 | QList output(exe.getOutput().split(' ')); 17 | if (output.count() > 2) 18 | { 19 | // Use the third field as UUID of the specified block device 20 | // Assuming field format: UUID="XXX" 21 | result = output[2]; 22 | result = result.mid(6, result.length() - 7); 23 | } 24 | return result; 25 | } 26 | 27 | qint64 DiskUtils::getFreeSpace(QString path) 28 | { 29 | ExeLauncher exe; 30 | exe.runCommand(QString("df -B 1 %1").arg(path), true); 31 | 32 | qint64 result = 0; 33 | QList output(exe.getOutput().split('\n')); 34 | if (output.count() > 2) 35 | { 36 | // The second line should contain space info of given device 37 | // Assuming the fields follow the style: 38 | // /dev/sda2 1000000000 200000000 800000000 20% /home 39 | QList fieldList = QString::fromUtf8(output[1]) 40 | .split(' ', QString::SkipEmptyParts); 41 | if (fieldList.count() > 4) 42 | result = fieldList[3].toLongLong(); 43 | } 44 | return result; 45 | } 46 | -------------------------------------------------------------------------------- /Utils/diskutils.h: -------------------------------------------------------------------------------- 1 | #ifndef DISKUTILS_H 2 | #define DISKUTILS_H 3 | 4 | #include 5 | 6 | class DiskUtils 7 | { 8 | public: 9 | DiskUtils(); 10 | 11 | static QString getUUIDByBlock(QString blockName); 12 | static qint64 getFreeSpace(QString path); 13 | }; 14 | 15 | #endif // DISKUTILS_H 16 | -------------------------------------------------------------------------------- /Utils/environment.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include "fileutils.h" 29 | #include "hostosinfo.h" 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | QT_FORWARD_DECLARE_CLASS(QDebug) 37 | QT_FORWARD_DECLARE_CLASS(QProcessEnvironment) 38 | 39 | namespace Utils { 40 | class Environment; 41 | 42 | class EnvironmentItem 43 | { 44 | public: 45 | enum Operation { Set, Unset, Prepend, Append }; 46 | 47 | EnvironmentItem(const QString &n, const QString &v, Operation op = Set) 48 | : name(n), value(v), operation(op) 49 | {} 50 | 51 | void apply(Environment *e) const { apply(e, operation); } 52 | 53 | QString name; 54 | QString value; 55 | Operation operation; 56 | 57 | bool operator==(const EnvironmentItem &other) const 58 | { 59 | return operation == other.operation && name == other.name && value == other.value; 60 | } 61 | 62 | bool operator!=(const EnvironmentItem &other) const 63 | { 64 | return !(*this == other); 65 | } 66 | 67 | static void sort(QList *list); 68 | static QList fromStringList(const QStringList &list); 69 | static QStringList toStringList(const QList &list); 70 | static QList itemsFromVariantList(const QVariantList &list); 71 | static QVariantList toVariantList(const QList &list); 72 | static EnvironmentItem itemFromVariantList(const QVariantList &list); 73 | static QVariantList toVariantList(const EnvironmentItem &item); 74 | 75 | private: 76 | void apply(Environment *e, Operation op) const; 77 | }; 78 | 79 | QDebug operator<<(QDebug debug, const EnvironmentItem &i); 80 | 81 | class Environment 82 | { 83 | public: 84 | using const_iterator = QMap::const_iterator; 85 | 86 | explicit Environment(OsType osType = HostOsInfo::hostOs()) : m_osType(osType) {} 87 | explicit Environment(const QStringList &env, OsType osType = HostOsInfo::hostOs()); 88 | static Environment systemEnvironment(); 89 | static void setupEnglishOutput(Environment *environment); 90 | static void setupEnglishOutput(QProcessEnvironment *environment); 91 | static void setupEnglishOutput(QStringList *environment); 92 | 93 | QStringList toStringList() const; 94 | QProcessEnvironment toProcessEnvironment() const; 95 | QString value(const QString &key) const; 96 | void set(const QString &key, const QString &value); 97 | void unset(const QString &key); 98 | void modify(const QList &list); 99 | /// Return the Environment changes necessary to modify this into the other environment. 100 | QList diff(const Environment &other, bool checkAppendPrepend = false) const; 101 | bool hasKey(const QString &key) const; 102 | OsType osType() const; 103 | 104 | QString userName() const; 105 | 106 | void appendOrSet(const QString &key, const QString &value, const QString &sep = QString()); 107 | void prependOrSet(const QString &key, const QString &value, const QString &sep = QString()); 108 | 109 | void appendOrSetPath(const QString &value); 110 | void prependOrSetPath(const QString &value); 111 | 112 | void prependOrSetLibrarySearchPath(const QString &value); 113 | void prependOrSetLibrarySearchPaths(const QStringList &values); 114 | 115 | void clear(); 116 | int size() const; 117 | 118 | QString key(Environment::const_iterator it) const; 119 | QString value(Environment::const_iterator it) const; 120 | 121 | Environment::const_iterator constBegin() const; 122 | Environment::const_iterator constEnd() const; 123 | Environment::const_iterator constFind(const QString &name) const; 124 | 125 | using PathFilter = std::function; 126 | FileName searchInPath(const QString &executable, 127 | const FileNameList &additionalDirs = FileNameList(), 128 | const PathFilter &func = PathFilter()) const; 129 | 130 | FileNameList path() const; 131 | QStringList appendExeExtensions(const QString &executable) const; 132 | 133 | bool isSameExecutable(const QString &exe1, const QString &exe2) const; 134 | 135 | QString expandVariables(const QString &input) const; 136 | QStringList expandVariables(const QStringList &input) const; 137 | 138 | bool operator!=(const Environment &other) const; 139 | bool operator==(const Environment &other) const; 140 | 141 | static void modifySystemEnvironment(const QList &list); // use with care!!! 142 | 143 | private: 144 | FileName searchInDirectory(const QStringList &execs, const FileName &directory, 145 | QSet &alreadyChecked) const; 146 | QMap m_values; 147 | OsType m_osType; 148 | }; 149 | 150 | } // namespace Utils 151 | -------------------------------------------------------------------------------- /Utils/environmentmodel.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #include "environmentmodel.h" 27 | 28 | #include "environment.h" 29 | #include "hostosinfo.h" 30 | 31 | #include 32 | #include 33 | 34 | namespace Utils { 35 | namespace Internal { 36 | 37 | class EnvironmentModelPrivate 38 | { 39 | public: 40 | void updateResultEnvironment() 41 | { 42 | m_resultEnvironment = m_baseEnvironment; 43 | m_resultEnvironment.modify(m_items); 44 | // Add removed variables again and mark them as "" so 45 | // that the user can actually see those removals: 46 | foreach (const EnvironmentItem &item, m_items) { 47 | if (item.operation == EnvironmentItem::Unset) 48 | m_resultEnvironment.set(item.name, EnvironmentModel::tr("")); 49 | } 50 | } 51 | 52 | int findInChanges(const QString &name) const 53 | { 54 | for (int i=0; i name) 66 | return i; 67 | return m_resultEnvironment.size(); 68 | } 69 | 70 | int findInResult(const QString &name) const 71 | { 72 | Environment::const_iterator it; 73 | int i = 0; 74 | for (it = m_resultEnvironment.constBegin(); it != m_resultEnvironment.constEnd(); ++it, ++i) 75 | if (m_resultEnvironment.key(it) == name) 76 | return i; 77 | return -1; 78 | } 79 | 80 | Environment m_baseEnvironment; 81 | Environment m_resultEnvironment; 82 | QList m_items; 83 | }; 84 | 85 | } // namespace Internal 86 | 87 | EnvironmentModel::EnvironmentModel(QObject *parent) : 88 | QAbstractTableModel(parent), 89 | d(new Internal::EnvironmentModelPrivate) 90 | { } 91 | 92 | EnvironmentModel::~EnvironmentModel() 93 | { 94 | delete d; 95 | } 96 | 97 | QString EnvironmentModel::indexToVariable(const QModelIndex &index) const 98 | { 99 | return d->m_resultEnvironment.key(d->m_resultEnvironment.constBegin() + index.row()); 100 | } 101 | 102 | void EnvironmentModel::setBaseEnvironment(const Environment &env) 103 | { 104 | if (d->m_baseEnvironment == env) 105 | return; 106 | beginResetModel(); 107 | d->m_baseEnvironment = env; 108 | d->updateResultEnvironment(); 109 | endResetModel(); 110 | } 111 | 112 | int EnvironmentModel::rowCount(const QModelIndex &parent) const 113 | { 114 | if (parent.isValid()) 115 | return 0; 116 | 117 | return d->m_resultEnvironment.size(); 118 | } 119 | int EnvironmentModel::columnCount(const QModelIndex &parent) const 120 | { 121 | if (parent.isValid()) 122 | return 0; 123 | 124 | return 2; 125 | } 126 | 127 | bool EnvironmentModel::changes(const QString &name) const 128 | { 129 | return d->findInChanges(name) >= 0; 130 | } 131 | 132 | Environment EnvironmentModel::baseEnvironment() const 133 | { 134 | return d->m_baseEnvironment; 135 | } 136 | 137 | QVariant EnvironmentModel::data(const QModelIndex &index, int role) const 138 | { 139 | if (!index.isValid()) 140 | return QVariant(); 141 | 142 | if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole) { 143 | if (index.column() == 0) { 144 | return d->m_resultEnvironment.key(d->m_resultEnvironment.constBegin() + index.row()); 145 | } else if (index.column() == 1) { 146 | // Do not return "" when editing a previously unset variable: 147 | if (role == Qt::EditRole) { 148 | int pos = d->findInChanges(indexToVariable(index)); 149 | if (pos >= 0) 150 | return d->m_items.at(pos).value; 151 | } 152 | QString value = d->m_resultEnvironment.value(d->m_resultEnvironment.constBegin() + index.row()); 153 | if (role == Qt::ToolTipRole && value.length() > 80) { 154 | // Use html to enable text wrapping 155 | value = value.toHtmlEscaped(); 156 | value.prepend(QLatin1String("")); 157 | value.append(QLatin1String("")); 158 | } 159 | return value; 160 | } 161 | } 162 | if (role == Qt::FontRole) { 163 | // check whether this environment variable exists in d->m_items 164 | if (changes(d->m_resultEnvironment.key(d->m_resultEnvironment.constBegin() + index.row()))) { 165 | QFont f; 166 | f.setBold(true); 167 | return QVariant(f); 168 | } 169 | return QFont(); 170 | } 171 | return QVariant(); 172 | } 173 | 174 | Qt::ItemFlags EnvironmentModel::flags(const QModelIndex &index) const 175 | { 176 | Q_UNUSED(index) 177 | return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled; 178 | } 179 | 180 | QVariant EnvironmentModel::headerData(int section, Qt::Orientation orientation, int role) const 181 | { 182 | if (orientation == Qt::Vertical || role != Qt::DisplayRole) 183 | return QVariant(); 184 | return section == 0 ? tr("Variable") : tr("Value"); 185 | } 186 | 187 | /// ***************** 188 | /// Utility functions 189 | /// ***************** 190 | QModelIndex EnvironmentModel::variableToIndex(const QString &name) const 191 | { 192 | int row = d->findInResult(name); 193 | if (row == -1) 194 | return QModelIndex(); 195 | return index(row, 0); 196 | } 197 | 198 | bool EnvironmentModel::setData(const QModelIndex &index, const QVariant &value, int role) 199 | { 200 | if (!index.isValid() || role != Qt::EditRole) 201 | return false; 202 | 203 | // ignore changes to already set values: 204 | if (data(index, role) == value) 205 | return true; 206 | 207 | const QString oldName = data(this->index(index.row(), 0, QModelIndex())).toString(); 208 | const QString oldValue = data(this->index(index.row(), 1, QModelIndex()), Qt::EditRole).toString(); 209 | int changesPos = d->findInChanges(oldName); 210 | 211 | if (index.column() == 0) { 212 | //fail if a variable with the same name already exists 213 | const QString &newName = HostOsInfo::isWindowsHost() 214 | ? value.toString().toUpper() : value.toString(); 215 | if (newName.isEmpty() || newName.contains('=')) 216 | return false; 217 | // Does the new name exist already? 218 | if (d->m_resultEnvironment.hasKey(newName) || newName.isEmpty()) 219 | return false; 220 | 221 | EnvironmentItem newVariable(newName, oldValue); 222 | 223 | if (changesPos != -1) 224 | resetVariable(oldName); // restore the original base variable again 225 | 226 | QModelIndex newIndex = addVariable(newVariable); // add the new variable 227 | emit focusIndex(newIndex.sibling(newIndex.row(), 1)); // hint to focus on the value 228 | return true; 229 | } else if (index.column() == 1) { 230 | // We are changing an existing value: 231 | const QString stringValue = value.toString(); 232 | if (changesPos != -1) { 233 | // We have already changed this value 234 | if (d->m_baseEnvironment.hasKey(oldName) && stringValue == d->m_baseEnvironment.value(oldName)) { 235 | // ... and now went back to the base value 236 | d->m_items.removeAt(changesPos); 237 | } else { 238 | // ... and changed it again 239 | d->m_items[changesPos].value = stringValue; 240 | d->m_items[changesPos].operation = EnvironmentItem::Set; 241 | } 242 | } else { 243 | // Add a new change item: 244 | d->m_items.append(EnvironmentItem(oldName, stringValue)); 245 | } 246 | d->updateResultEnvironment(); 247 | emit dataChanged(index, index); 248 | emit userChangesChanged(); 249 | return true; 250 | } 251 | return false; 252 | } 253 | 254 | QModelIndex EnvironmentModel::addVariable() 255 | { 256 | //: Name when inserting a new variable 257 | return addVariable(EnvironmentItem(tr(""), 258 | //: Value when inserting a new variable 259 | tr(""))); 260 | } 261 | 262 | QModelIndex EnvironmentModel::addVariable(const EnvironmentItem &item) 263 | { 264 | 265 | // Return existing index if the name is already in the result set: 266 | int pos = d->findInResult(item.name); 267 | if (pos >= 0 && pos < d->m_resultEnvironment.size()) 268 | return index(pos, 0, QModelIndex()); 269 | 270 | int insertPos = d->findInResultInsertPosition(item.name); 271 | int changePos = d->findInChanges(item.name); 272 | if (d->m_baseEnvironment.hasKey(item.name)) { 273 | // We previously unset this! 274 | Q_ASSERT(changePos >= 0); 275 | // Do not insert a line here as we listed the variable as before! 276 | Q_ASSERT(d->m_items.at(changePos).name == item.name); 277 | Q_ASSERT(d->m_items.at(changePos).operation == EnvironmentItem::Unset); 278 | Q_ASSERT(d->m_items.at(changePos).value.isEmpty()); 279 | d->m_items[changePos] = item; 280 | emit dataChanged(index(insertPos, 0, QModelIndex()), index(insertPos, 1, QModelIndex())); 281 | } else { 282 | // We add something that is not in the base environment 283 | // Insert a new line! 284 | beginInsertRows(QModelIndex(), insertPos, insertPos); 285 | Q_ASSERT(changePos < 0); 286 | d->m_items.append(item); 287 | d->updateResultEnvironment(); 288 | endInsertRows(); 289 | } 290 | emit userChangesChanged(); 291 | return index(insertPos, 0, QModelIndex()); 292 | } 293 | 294 | void EnvironmentModel::resetVariable(const QString &name) 295 | { 296 | int rowInChanges = d->findInChanges(name); 297 | if (rowInChanges < 0) 298 | return; 299 | 300 | int rowInResult = d->findInResult(name); 301 | if (rowInResult < 0) 302 | return; 303 | 304 | if (d->m_baseEnvironment.hasKey(name)) { 305 | d->m_items.removeAt(rowInChanges); 306 | d->updateResultEnvironment(); 307 | emit dataChanged(index(rowInResult, 0, QModelIndex()), index(rowInResult, 1, QModelIndex())); 308 | emit userChangesChanged(); 309 | } else { 310 | // Remove the line completely! 311 | beginRemoveRows(QModelIndex(), rowInResult, rowInResult); 312 | d->m_items.removeAt(rowInChanges); 313 | d->updateResultEnvironment(); 314 | endRemoveRows(); 315 | emit userChangesChanged(); 316 | } 317 | } 318 | 319 | void EnvironmentModel::unsetVariable(const QString &name) 320 | { 321 | // This does not change the number of rows as we will display a 322 | // in place of the original variable! 323 | int row = d->findInResult(name); 324 | if (row < 0) 325 | return; 326 | 327 | // look in d->m_items for the variable 328 | int pos = d->findInChanges(name); 329 | if (pos != -1) { 330 | d->m_items[pos].operation = EnvironmentItem::Unset; 331 | d->m_items[pos].value.clear(); 332 | d->updateResultEnvironment(); 333 | emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex())); 334 | emit userChangesChanged(); 335 | return; 336 | } 337 | d->m_items.append(EnvironmentItem(name, QString(), EnvironmentItem::Unset)); 338 | d->updateResultEnvironment(); 339 | emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex())); 340 | emit userChangesChanged(); 341 | } 342 | 343 | bool EnvironmentModel::canUnset(const QString &name) 344 | { 345 | int pos = d->findInChanges(name); 346 | if (pos != -1) 347 | return d->m_items.at(pos).operation == EnvironmentItem::Unset; 348 | else 349 | return false; 350 | } 351 | 352 | bool EnvironmentModel::canReset(const QString &name) 353 | { 354 | return d->m_baseEnvironment.hasKey(name); 355 | } 356 | 357 | QList EnvironmentModel::userChanges() const 358 | { 359 | return d->m_items; 360 | } 361 | 362 | void EnvironmentModel::setUserChanges(const QList &list) 363 | { 364 | QList filtered; 365 | for (int i=0; i 5 | 6 | 7 | class GSettingsEditor 8 | { 9 | public: 10 | GSettingsEditor(); 11 | 12 | static bool existKey(QString schema, QString key); 13 | static QVariant getValue(QString schema, QString key); 14 | static bool setValue(QString schema, QString key, const QVariant& value); 15 | static bool resetValue(QString schema, QString key); 16 | }; 17 | 18 | #endif // GSETTINGSEDITOR_H 19 | -------------------------------------------------------------------------------- /Utils/hostosinfo.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #include "hostosinfo.h" 27 | 28 | #include 29 | 30 | #if !defined(QT_NO_OPENGL) && defined(QT_GUI_LIB) 31 | #include 32 | #endif 33 | 34 | #ifdef Q_OS_WIN 35 | #undef _WIN32_WINNT 36 | #define _WIN32_WINNT 0x0501 /* WinXP, needed for GetNativeSystemInfo() */ 37 | #include 38 | #endif 39 | 40 | using namespace Utils; 41 | 42 | Qt::CaseSensitivity HostOsInfo::m_overrideFileNameCaseSensitivity = Qt::CaseSensitive; 43 | bool HostOsInfo::m_useOverrideFileNameCaseSensitivity = false; 44 | 45 | #ifdef Q_OS_WIN 46 | static WORD hostProcessorArchitecture() 47 | { 48 | SYSTEM_INFO info; 49 | GetNativeSystemInfo(&info); 50 | return info.wProcessorArchitecture; 51 | } 52 | #endif 53 | 54 | HostOsInfo::HostArchitecture HostOsInfo::hostArchitecture() 55 | { 56 | #ifdef Q_OS_WIN 57 | static const WORD processorArchitecture = hostProcessorArchitecture(); 58 | switch (processorArchitecture) { 59 | case PROCESSOR_ARCHITECTURE_AMD64: 60 | return HostOsInfo::HostArchitectureAMD64; 61 | case PROCESSOR_ARCHITECTURE_INTEL: 62 | return HostOsInfo::HostArchitectureX86; 63 | case PROCESSOR_ARCHITECTURE_IA64: 64 | return HostOsInfo::HostArchitectureItanium; 65 | case PROCESSOR_ARCHITECTURE_ARM: 66 | return HostOsInfo::HostArchitectureArm; 67 | default: 68 | return HostOsInfo::HostArchitectureUnknown; 69 | } 70 | #else 71 | return HostOsInfo::HostArchitectureUnknown; 72 | #endif 73 | } 74 | 75 | void HostOsInfo::setOverrideFileNameCaseSensitivity(Qt::CaseSensitivity sensitivity) 76 | { 77 | m_useOverrideFileNameCaseSensitivity = true; 78 | m_overrideFileNameCaseSensitivity = sensitivity; 79 | } 80 | 81 | void HostOsInfo::unsetOverrideFileNameCaseSensitivity() 82 | { 83 | m_useOverrideFileNameCaseSensitivity = false; 84 | } 85 | 86 | bool HostOsInfo::canCreateOpenGLContext(QString *errorMessage) 87 | { 88 | #if defined(QT_NO_OPENGL) || !defined(QT_GUI_LIB) 89 | Q_UNUSED(errorMessage) 90 | return false; 91 | #else 92 | static const bool canCreate = QOpenGLContext().create(); 93 | if (!canCreate) 94 | *errorMessage = QCoreApplication::translate("Utils::HostOsInfo", 95 | "Cannot create OpenGL context."); 96 | return canCreate; 97 | #endif 98 | } 99 | -------------------------------------------------------------------------------- /Utils/hostosinfo.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include "osspecificaspects.h" 29 | 30 | #include 31 | 32 | #ifdef Q_OS_WIN 33 | #define QTC_HOST_EXE_SUFFIX QTC_WIN_EXE_SUFFIX 34 | #else 35 | #define QTC_HOST_EXE_SUFFIX "" 36 | #endif // Q_OS_WIN 37 | 38 | namespace Utils { 39 | 40 | class HostOsInfo 41 | { 42 | public: 43 | static constexpr OsType hostOs() 44 | { 45 | #if defined(Q_OS_WIN) 46 | return OsTypeWindows; 47 | #elif defined(Q_OS_LINUX) 48 | return OsTypeLinux; 49 | #elif defined(Q_OS_MAC) 50 | return OsTypeMac; 51 | #elif defined(Q_OS_UNIX) 52 | return OsTypeOtherUnix; 53 | #else 54 | return OsTypeOther; 55 | #endif 56 | } 57 | 58 | enum HostArchitecture { HostArchitectureX86, HostArchitectureAMD64, HostArchitectureItanium, 59 | HostArchitectureArm, HostArchitectureUnknown }; 60 | static HostArchitecture hostArchitecture(); 61 | 62 | static constexpr bool isWindowsHost() { return hostOs() == OsTypeWindows; } 63 | static constexpr bool isLinuxHost() { return hostOs() == OsTypeLinux; } 64 | static constexpr bool isMacHost() { return hostOs() == OsTypeMac; } 65 | static constexpr bool isAnyUnixHost() 66 | { 67 | #ifdef Q_OS_UNIX 68 | return true; 69 | #else 70 | return false; 71 | #endif 72 | } 73 | 74 | static QString withExecutableSuffix(const QString &executable) 75 | { 76 | return OsSpecificAspects::withExecutableSuffix(hostOs(), executable); 77 | } 78 | 79 | static void setOverrideFileNameCaseSensitivity(Qt::CaseSensitivity sensitivity); 80 | static void unsetOverrideFileNameCaseSensitivity(); 81 | 82 | static Qt::CaseSensitivity fileNameCaseSensitivity() 83 | { 84 | return m_useOverrideFileNameCaseSensitivity 85 | ? m_overrideFileNameCaseSensitivity 86 | : OsSpecificAspects::fileNameCaseSensitivity(hostOs()); 87 | } 88 | 89 | static QChar pathListSeparator() 90 | { 91 | return OsSpecificAspects::pathListSeparator(hostOs()); 92 | } 93 | 94 | static Qt::KeyboardModifier controlModifier() 95 | { 96 | return OsSpecificAspects::controlModifier(hostOs()); 97 | } 98 | 99 | static bool canCreateOpenGLContext(QString *errorMessage); 100 | 101 | private: 102 | static Qt::CaseSensitivity m_overrideFileNameCaseSensitivity; 103 | static bool m_useOverrideFileNameCaseSensitivity; 104 | }; 105 | 106 | } // namespace Utils 107 | -------------------------------------------------------------------------------- /Utils/osspecificaspects.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include 29 | 30 | #include 31 | 32 | #define QTC_WIN_EXE_SUFFIX ".exe" 33 | 34 | namespace Utils { 35 | 36 | // Add more as needed. 37 | enum OsType { OsTypeWindows, OsTypeLinux, OsTypeMac, OsTypeOtherUnix, OsTypeOther }; 38 | 39 | namespace OsSpecificAspects { 40 | 41 | inline QString withExecutableSuffix(OsType osType, const QString &executable) 42 | { 43 | QString finalName = executable; 44 | if (osType == OsTypeWindows) 45 | finalName += QLatin1String(QTC_WIN_EXE_SUFFIX); 46 | return finalName; 47 | } 48 | 49 | inline Qt::CaseSensitivity fileNameCaseSensitivity(OsType osType) 50 | { 51 | return osType == OsTypeWindows || osType == OsTypeMac ? Qt::CaseInsensitive : Qt::CaseSensitive; 52 | } 53 | 54 | inline QChar pathListSeparator(OsType osType) 55 | { 56 | return QLatin1Char(osType == OsTypeWindows ? ';' : ':'); 57 | } 58 | 59 | inline Qt::KeyboardModifier controlModifier(OsType osType) 60 | { 61 | return osType == OsTypeMac ? Qt::MetaModifier : Qt::ControlModifier; 62 | } 63 | 64 | inline QString pathWithNativeSeparators(OsType osType, const QString &pathName) 65 | { 66 | if (osType == OsTypeWindows) { 67 | const int pos = pathName.indexOf('/'); 68 | if (pos >= 0) { 69 | QString n = pathName; 70 | std::replace(std::begin(n) + pos, std::end(n), '/', '\\'); 71 | return n; 72 | } 73 | } 74 | return pathName; 75 | } 76 | 77 | } // namespace OsSpecificAspects 78 | } // namespace Utils 79 | -------------------------------------------------------------------------------- /Utils/qtcassert.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #include "qtcassert.h" 27 | 28 | #include 29 | 30 | namespace Utils { 31 | 32 | void writeAssertLocation(const char *msg) 33 | { 34 | static bool goBoom = qEnvironmentVariableIsSet("QTC_FATAL_ASSERTS"); 35 | if (goBoom) 36 | qFatal("SOFT ASSERT made fatal: %s", msg); 37 | else 38 | qDebug("SOFT ASSERT: %s", msg); 39 | } 40 | 41 | } // namespace Utils 42 | -------------------------------------------------------------------------------- /Utils/qtcassert.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #pragma once 27 | 28 | namespace Utils { void writeAssertLocation(const char *msg); } 29 | 30 | #define QTC_ASSERT_STRINGIFY_HELPER(x) #x 31 | #define QTC_ASSERT_STRINGIFY(x) QTC_ASSERT_STRINGIFY_HELPER(x) 32 | #define QTC_ASSERT_STRING(cond) ::Utils::writeAssertLocation(\ 33 | "\"" cond"\" in file " __FILE__ ", line " QTC_ASSERT_STRINGIFY(__LINE__)) 34 | 35 | // The 'do {...} while (0)' idiom is not used for the main block here to be 36 | // able to use 'break' and 'continue' as 'actions'. 37 | 38 | #define QTC_ASSERT(cond, action) if (cond) {} else { QTC_ASSERT_STRING(#cond); action; } do {} while (0) 39 | #define QTC_CHECK(cond) if (cond) {} else { QTC_ASSERT_STRING(#cond); } do {} while (0) 40 | #define QTC_GUARD(cond) ((cond) ? true : (QTC_ASSERT_STRING(#cond), false)) 41 | -------------------------------------------------------------------------------- /Utils/savefile.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #include "savefile.h" 27 | #include "qtcassert.h" 28 | #include "fileutils.h" 29 | #ifdef Q_OS_WIN 30 | # include 31 | # include 32 | #else 33 | # include 34 | # include 35 | #endif 36 | 37 | namespace Utils { 38 | 39 | QFile::Permissions SaveFile::m_umask = nullptr; 40 | 41 | SaveFile::SaveFile(const QString &filename) : 42 | m_finalFileName(filename) 43 | { 44 | } 45 | 46 | SaveFile::~SaveFile() 47 | { 48 | QTC_ASSERT(m_finalized, rollback()); 49 | } 50 | 51 | bool SaveFile::open(OpenMode flags) 52 | { 53 | QTC_ASSERT(!m_finalFileName.isEmpty(), return false); 54 | 55 | QFile ofi(m_finalFileName); 56 | // Check whether the existing file is writable 57 | if (ofi.exists() && !ofi.open(QIODevice::ReadWrite)) { 58 | setErrorString(ofi.errorString()); 59 | return false; 60 | } 61 | 62 | m_tempFile.reset(new QTemporaryFile(m_finalFileName)); 63 | m_tempFile->setAutoRemove(false); 64 | if (!m_tempFile->open()) 65 | return false; 66 | setFileName(m_tempFile->fileName()); 67 | 68 | if (!QFile::open(flags)) 69 | return false; 70 | 71 | m_finalized = false; // needs clean up in the end 72 | if (ofi.exists()) { 73 | setPermissions(ofi.permissions()); // Ignore errors 74 | } else { 75 | Permissions permAll = QFile::ReadOwner 76 | | QFile::ReadGroup 77 | | QFile::ReadOther 78 | | QFile::WriteOwner 79 | | QFile::WriteGroup 80 | | QFile::WriteOther; 81 | 82 | // set permissions with respect to the current umask 83 | setPermissions(permAll & ~m_umask); 84 | } 85 | 86 | return true; 87 | } 88 | 89 | void SaveFile::rollback() 90 | { 91 | close(); 92 | if (m_tempFile) 93 | m_tempFile->remove(); 94 | m_finalized = true; 95 | } 96 | 97 | bool SaveFile::commit() 98 | { 99 | QTC_ASSERT(!m_finalized && m_tempFile, return false;); 100 | m_finalized = true; 101 | 102 | if (!flush()) { 103 | close(); 104 | m_tempFile->remove(); 105 | return false; 106 | } 107 | #ifdef Q_OS_WIN 108 | FlushFileBuffers(reinterpret_cast(_get_osfhandle(handle()))); 109 | #elif _POSIX_SYNCHRONIZED_IO > 0 110 | fdatasync(handle()); 111 | #else 112 | fsync(handle()); 113 | #endif 114 | close(); 115 | m_tempFile->close(); 116 | if (error() != NoError) { 117 | m_tempFile->remove(); 118 | return false; 119 | } 120 | 121 | QString finalFileName 122 | = FileUtils::resolveSymlinks(FileName::fromString(m_finalFileName)).toString(); 123 | 124 | #ifdef Q_OS_WIN 125 | // Release the file lock 126 | m_tempFile.reset(); 127 | bool result = ReplaceFile(finalFileName.toStdWString().data(), 128 | fileName().toStdWString().data(), 129 | nullptr, REPLACEFILE_IGNORE_MERGE_ERRORS, nullptr, nullptr); 130 | if (!result) { 131 | const DWORD replaceErrorCode = GetLastError(); 132 | QString errorStr; 133 | if (!QFile::exists(finalFileName)) { 134 | // Replace failed because finalFileName does not exist, try rename. 135 | if (!(result = rename(finalFileName))) 136 | errorStr = errorString(); 137 | } else { 138 | wchar_t messageBuffer[256]; 139 | FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 140 | nullptr, replaceErrorCode, 141 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 142 | messageBuffer, sizeof(messageBuffer), nullptr); 143 | errorStr = QString::fromWCharArray(messageBuffer); 144 | } 145 | if (!result) { 146 | remove(); 147 | setErrorString(errorStr); 148 | } 149 | } 150 | 151 | return result; 152 | #else 153 | const QString backupName = finalFileName + '~'; 154 | 155 | // Back up current file. 156 | // If it's opened by another application, the lock follows the move. 157 | if (QFile::exists(finalFileName)) { 158 | // Kill old backup. Might be useful if creator crashed before removing backup. 159 | QFile::remove(backupName); 160 | QFile finalFile(finalFileName); 161 | if (!finalFile.rename(backupName)) { 162 | m_tempFile->remove(); 163 | setErrorString(finalFile.errorString()); 164 | return false; 165 | } 166 | } 167 | 168 | bool result = true; 169 | if (!m_tempFile->rename(finalFileName)) { 170 | // The case when someone else was able to create finalFileName after we've renamed it. 171 | // Higher level call may try to save this file again but here we do nothing and 172 | // return false while keeping the error string from last rename call. 173 | const QString &renameError = m_tempFile->errorString(); 174 | m_tempFile->remove(); 175 | setErrorString(renameError); 176 | result = false; 177 | } 178 | 179 | QFile::remove(backupName); 180 | 181 | return result; 182 | #endif 183 | } 184 | 185 | void SaveFile::initializeUmask() 186 | { 187 | #ifdef Q_OS_WIN 188 | m_umask = QFile::WriteGroup | QFile::WriteOther; 189 | #else 190 | // Get the current process' file creation mask (umask) 191 | // umask() is not thread safe so this has to be done by single threaded 192 | // application initialization 193 | mode_t mask = umask(0); // get current umask 194 | umask(mask); // set it back 195 | 196 | m_umask = ((mask & S_IRUSR) ? QFile::ReadOwner : QFlags(0)) 197 | | ((mask & S_IWUSR) ? QFile::WriteOwner : QFlags(0)) 198 | | ((mask & S_IXUSR) ? QFile::ExeOwner : QFlags(0)) 199 | | ((mask & S_IRGRP) ? QFile::ReadGroup : QFlags(0)) 200 | | ((mask & S_IWGRP) ? QFile::WriteGroup : QFlags(0)) 201 | | ((mask & S_IXGRP) ? QFile::ExeGroup : QFlags(0)) 202 | | ((mask & S_IROTH) ? QFile::ReadOther : QFlags(0)) 203 | | ((mask & S_IWOTH) ? QFile::WriteOther : QFlags(0)) 204 | | ((mask & S_IXOTH) ? QFile::ExeOther : QFlags(0)); 205 | #endif 206 | } 207 | 208 | } // namespace Utils 209 | -------------------------------------------------------------------------------- /Utils/savefile.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include 29 | 30 | #include 31 | 32 | namespace Utils { 33 | 34 | class SaveFile : public QFile 35 | { 36 | Q_OBJECT 37 | 38 | public: 39 | explicit SaveFile(const QString &filename); 40 | ~SaveFile() override; 41 | 42 | bool open(OpenMode flags = QIODevice::WriteOnly) override; 43 | 44 | void rollback(); 45 | bool commit(); 46 | 47 | static void initializeUmask(); 48 | 49 | private: 50 | const QString m_finalFileName; 51 | std::unique_ptr m_tempFile; 52 | bool m_finalized = true; 53 | static QFile::Permissions m_umask; 54 | }; 55 | 56 | } // namespace Utils 57 | -------------------------------------------------------------------------------- /Utils/screenutils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "screenutils.h" 3 | 4 | #define SPANDA_SCREEN_EXEC_CVT "cvt" 5 | #define SPANDA_SCREEN_EXEC_XRANDR "xrandr" 6 | #define SPANDA_SCREEN_EXEC_XRANDR_LISTMONITOR "--listmonitors" 7 | #define SPANDA_SCREEN_EXEC_XRANDR_NEWMODE "--newmode" 8 | #define SPANDA_SCREEN_EXEC_XRANDR_ADDMODE "--addmode" 9 | #define SPANDA_SCREEN_EXEC_XRANDR_OUTPUT "--output" 10 | #define SPANDA_SCREEN_EXEC_XRANDR_MODE "--mode" 11 | #define SPANDA_SCREEN_EXEC_XGAMMA "xgamma" 12 | #define SPANDA_SCREEN_EXEC_XGAMMA_SCREEN "-s" 13 | #define SPANDA_SCREEN_EXEC_XGAMMA_RED "-rgamma" 14 | #define SPANDA_SCREEN_EXEC_XGAMMA_GREEN "-ggamma" 15 | #define SPANDA_SCREEN_EXEC_XGAMMA_BLUE "-bgamma" 16 | 17 | 18 | ScreenUtils::ScreenUtils() 19 | { 20 | } 21 | 22 | QList ScreenUtils::getMonitors() 23 | { 24 | QProcess exe; 25 | exe.start(QString("%1 %2") 26 | .arg(SPANDA_SCREEN_EXEC_XRANDR) 27 | .arg(SPANDA_SCREEN_EXEC_XRANDR_LISTMONITOR)); 28 | exe.waitForFinished(); 29 | 30 | // Assuming the first line is the total number of monitors 31 | // and the following lines give the details 32 | QList output = exe.readAllStandardOutput().split('\n'); 33 | int monitorCount = output[0].mid(output[0].indexOf(": ") + 2).toInt(); 34 | QList monitorList; 35 | QList tempLine; 36 | for (int i=0; i= output.count()) 39 | break; 40 | 41 | tempLine = output[i + 1].split(' '); 42 | if (tempLine.count() > 0) 43 | monitorList.push_back(QString::fromUtf8(tempLine.last())); 44 | } 45 | 46 | return monitorList; 47 | } 48 | 49 | QString ScreenUtils::currentMonitor() 50 | { 51 | QList monitorList(getMonitors()); 52 | if (monitorList.count() > 0) 53 | return monitorList[0]; 54 | else 55 | return ""; 56 | } 57 | 58 | QSize ScreenUtils::currentResolution(QString monitor) 59 | { 60 | QProcess exe; 61 | exe.start(QString("%1 %2") 62 | .arg(SPANDA_SCREEN_EXEC_XRANDR) 63 | .arg(SPANDA_SCREEN_EXEC_XRANDR_LISTMONITOR)); 64 | exe.waitForFinished(); 65 | 66 | // Same output as getMonitors() 67 | QList output = exe.readAllStandardOutput().split('\n'); 68 | int monitorCount = output[0].mid(output[0].indexOf(": ") + 2).toInt(); 69 | QList tempLine; 70 | QSize resolution; 71 | for (int i=0; i= output.count()) 74 | break; 75 | 76 | // Assuming each line follows the style below: 77 | // 0: +*eDP1 1024/270x768/160+0+0 eDP1 78 | // No. Width Height Monitor 79 | tempLine = QString::fromUtf8(output[i + 1]) 80 | .split(' ', QString::SkipEmptyParts); 81 | if (tempLine.count() >= 4) 82 | { 83 | if (!monitor.isEmpty() && tempLine[3] != monitor) 84 | continue; 85 | tempLine = tempLine[2].split('x'); 86 | resolution.setWidth(tempLine[0].left(tempLine[0].indexOf('/')) 87 | .toInt()); 88 | resolution.setHeight(tempLine[1].left(tempLine[0].indexOf('/')) 89 | .toInt()); 90 | break; 91 | } 92 | } 93 | return resolution; 94 | } 95 | 96 | QList ScreenUtils::currentGamma(QString monitor) 97 | { 98 | QProcess exe; 99 | if (monitor.isEmpty()) 100 | exe.start(SPANDA_SCREEN_EXEC_XGAMMA); 101 | else 102 | exe.start(QString("%1 %2 %3") 103 | .arg(SPANDA_SCREEN_EXEC_XGAMMA) 104 | .arg(SPANDA_SCREEN_EXEC_XGAMMA_SCREEN) 105 | .arg(monitor)); 106 | exe.waitForFinished(); 107 | 108 | // Assuming the first line of the output looks like this: 109 | // -> Red 0.950, Green 0.900, Blue 0.850 110 | // Note: The output of xgamma command is redirected to STDERROR! 111 | QList output = exe.readAllStandardError().split('\n'); 112 | QList gammaComponent; 113 | QList tempLine; 114 | int i, p; 115 | if (output.count() > 0) 116 | { 117 | tempLine = output[0].replace("-> ", "").split(','); 118 | for (i=0; i 0) 132 | refreshRateString = QString::number(refreshRate); 133 | 134 | QProcess exe; 135 | exe.start(QString("%1 %2 %3 %4") 136 | .arg(SPANDA_SCREEN_EXEC_CVT) 137 | .arg(QString::number(resolution.width())) 138 | .arg(QString::number(resolution.height())) 139 | .arg(refreshRateString)); 140 | exe.waitForFinished(); 141 | 142 | QList output = exe.readAll().split('\n'); 143 | if (output.count() < 2) 144 | return ""; 145 | else 146 | return QString::fromUtf8(output[1].replace("Modeline ", "")); 147 | } 148 | 149 | QString ScreenUtils::getModeName(QString modeLine) 150 | { 151 | return modeLine.left(modeLine.indexOf(' ')); 152 | } 153 | 154 | bool ScreenUtils::setMode(QString monitor, 155 | QSize resolution, 156 | int refreshRate) 157 | { 158 | QString modeLine = getModeLine(resolution, refreshRate); 159 | QString modeName = modeLine.left(modeLine.indexOf(' ')); 160 | if (modeName.isEmpty()) 161 | return false; 162 | 163 | // Create a new mode 164 | QProcess exe; 165 | exe.start(QString("%1 %2 %3") 166 | .arg(SPANDA_SCREEN_EXEC_XRANDR) 167 | .arg(SPANDA_SCREEN_EXEC_XRANDR_NEWMODE) 168 | .arg(modeLine)); 169 | exe.waitForFinished(); 170 | 171 | // Bind the mode to the given monitor 172 | if (!getMonitors().contains(monitor)) 173 | return false; 174 | exe.start(QString("%1 %2 %3 %4") 175 | .arg(SPANDA_SCREEN_EXEC_XRANDR) 176 | .arg(SPANDA_SCREEN_EXEC_XRANDR_ADDMODE) 177 | .arg(monitor) 178 | .arg(modeName)); 179 | exe.waitForFinished(); 180 | if (exe.exitCode() != 0) 181 | return false; 182 | 183 | // Apply the mode 184 | exe.start(QString("%1 %2 %3 %4 %5") 185 | .arg(SPANDA_SCREEN_EXEC_XRANDR) 186 | .arg(SPANDA_SCREEN_EXEC_XRANDR_OUTPUT) 187 | .arg(monitor) 188 | .arg(SPANDA_SCREEN_EXEC_XRANDR_MODE) 189 | .arg(modeName)); 190 | exe.waitForFinished(); 191 | return (exe.exitCode() == 0); 192 | } 193 | 194 | bool ScreenUtils::setGamma(QString monitor, 195 | double red, double green, double blue) 196 | { 197 | QList args; 198 | if (!monitor.isEmpty()) 199 | { 200 | args.push_back(SPANDA_SCREEN_EXEC_XGAMMA_SCREEN); 201 | args.push_back(monitor); 202 | } 203 | args.push_back(SPANDA_SCREEN_EXEC_XGAMMA_RED); 204 | args.push_back(QString::number(red)); 205 | args.push_back(SPANDA_SCREEN_EXEC_XGAMMA_GREEN); 206 | args.push_back(QString::number(green)); 207 | args.push_back(SPANDA_SCREEN_EXEC_XGAMMA_BLUE); 208 | args.push_back(QString::number(blue)); 209 | 210 | QProcess exe; 211 | exe.start(SPANDA_SCREEN_EXEC_XGAMMA, args); 212 | exe.waitForFinished(); 213 | return (exe.exitCode() == 0); 214 | } 215 | -------------------------------------------------------------------------------- /Utils/screenutils.h: -------------------------------------------------------------------------------- 1 | #ifndef SCREENUTILS_H 2 | #define SCREENUTILS_H 3 | 4 | #include 5 | 6 | 7 | class ScreenUtils 8 | { 9 | public: 10 | ScreenUtils(); 11 | 12 | static QList getMonitors(); 13 | static QString currentMonitor(); 14 | static QSize currentResolution(QString monitor = ""); 15 | static QList currentGamma(QString monitor = ""); 16 | 17 | static QString getModeLine(QSize resolution, int refreshRate = 0); 18 | static QString getModeName(QString modeLine); 19 | static bool setMode(QString monitor, 20 | QSize resolution, 21 | int refreshRate = 0); 22 | static bool setGamma(QString monitor, 23 | double red, double green, double blue); 24 | }; 25 | 26 | #endif // SCREENUTILS_H 27 | -------------------------------------------------------------------------------- /Utils/swaputils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "swaputils.h" 5 | #include "dialogutils.h" 6 | 7 | #define SPANDA_SWAPUTILS_FILE_TYPE_SWAPFILE "swap file" 8 | 9 | #define SPANDA_SWAPUTILS_OP_NONE 0 10 | #define SPANDA_SWAPUTILS_OP_PRE_MAKE_SWAPFILE 1 11 | #define SPANDA_SWAPUTILS_OP_MAKE_SWAPFILE 2 12 | #define SPANDA_SWAPUTILS_OP_PRE_REMOVE_SWAPFILE 3 13 | #define SPANDA_SWAPUTILS_OP_REMOVE_SWAPFILE 4 14 | #define SPANDA_SWAPUTILS_OP_SETUP_SWAP 5 15 | #define SPANDA_SWAPUTILS_OP_TURNON_SWAP 6 16 | #define SPANDA_SWAPUTILS_OP_TURNOFF_SWAP 7 17 | 18 | 19 | SwapUtils::SwapUtils() 20 | { 21 | deviceSize = 0; 22 | currentOperation = SPANDA_SWAPUTILS_OP_NONE; 23 | connect(&exe, 24 | SIGNAL(finished(ExeLauncher::ExecErrorCode)), 25 | this, 26 | SLOT(onExeFinished(ExeLauncher::ExecErrorCode))); 27 | } 28 | 29 | bool SwapUtils::isSwapFile(QString fileName) 30 | { 31 | ExeLauncher exe; 32 | exe.runCommand(QString("file %1").arg(fileName), true); 33 | return exe.getOutput().contains(SPANDA_SWAPUTILS_FILE_TYPE_SWAPFILE); 34 | } 35 | 36 | bool SwapUtils::makeSwapFile(QString fileName, qint64 size) 37 | { 38 | QFileInfo swapfile(fileName); 39 | if (swapfile.exists()) 40 | { 41 | // Check if the file belongs to root 42 | if (swapfile.ownerId() != 0) 43 | return false; 44 | 45 | // Check if it is not a swap file 46 | if (!isSwapFile(fileName)) 47 | return false; 48 | 49 | turnOffSwap(fileName); 50 | 51 | // NOTE: the following assignment may fail if the callback 52 | // triggered by exe.runCommand() called in turnOffSwap() 53 | // comes before the returning of turnOffSwap() 54 | currentOperation = SPANDA_SWAPUTILS_OP_PRE_MAKE_SWAPFILE; 55 | deviceSize = size; 56 | } 57 | else 58 | createSwapFile(fileName, size); 59 | return true; 60 | } 61 | 62 | bool SwapUtils::removeSwapFile(QString fileName) 63 | { 64 | QFile swapfile(fileName); 65 | if (swapfile.exists()) 66 | { 67 | if (!isSwapFile(fileName)) 68 | return false; 69 | } 70 | 71 | currentDevice = fileName; 72 | currentOperation = SPANDA_SWAPUTILS_OP_PRE_REMOVE_SWAPFILE; 73 | exe.runCommand(QString("swapoff %1").arg(fileName)); 74 | return true; 75 | } 76 | 77 | bool SwapUtils::turnOnSwap(QString device) 78 | { 79 | currentDevice = device; 80 | currentOperation = SPANDA_SWAPUTILS_OP_TURNON_SWAP; 81 | exe.runCommand(QString("swapon %1").arg(device)); 82 | return true; 83 | } 84 | 85 | bool SwapUtils::turnOffSwap(QString device) 86 | { 87 | currentDevice = device; 88 | currentOperation = SPANDA_SWAPUTILS_OP_TURNOFF_SWAP; 89 | exe.runCommand(QString("swapoff %1").arg(device)); 90 | return true; 91 | } 92 | 93 | bool SwapUtils::createSwapFile(QString fileName, qint64 size) 94 | { 95 | currentDevice = fileName; 96 | currentOperation = SPANDA_SWAPUTILS_OP_MAKE_SWAPFILE; 97 | exe.runCommand(QString("dd if=/dev/zero of=%1 bs=1M count=%2") 98 | .arg(fileName) 99 | .arg(QString::number(size / 1024 / 1024))); 100 | return true; 101 | } 102 | 103 | bool SwapUtils::setupSwapFile(QString fileName) 104 | { 105 | // Initialize the swap filesystem 106 | currentDevice = fileName; 107 | currentOperation = SPANDA_SWAPUTILS_OP_SETUP_SWAP; 108 | exe.runCommand(QString("chmod 600 %1").arg(fileName), true); 109 | exe.runCommand(QString("mkswap %1").arg(fileName), true); 110 | return true; 111 | } 112 | 113 | void SwapUtils::onExeFinished(ExeLauncher::ExecErrorCode errCode) 114 | { 115 | switch (errCode) 116 | { 117 | case ExeLauncher::ExecOk: 118 | { 119 | switch (currentOperation) 120 | { 121 | case SPANDA_SWAPUTILS_OP_PRE_MAKE_SWAPFILE: 122 | createSwapFile(currentDevice, deviceSize); 123 | break; 124 | case SPANDA_SWAPUTILS_OP_MAKE_SWAPFILE: 125 | if (setupSwapFile(currentDevice)) 126 | emit finishedMakingSwapfile(); 127 | else 128 | emit operationFailed(); 129 | break; 130 | case SPANDA_SWAPUTILS_OP_PRE_REMOVE_SWAPFILE: 131 | currentOperation = SPANDA_SWAPUTILS_OP_REMOVE_SWAPFILE; 132 | if (exe.runCommand(QString("rm -f %1").arg(currentDevice), true) 133 | == ExeLauncher::ExecOk) 134 | emit finishedRemovingSwapfile(); 135 | else 136 | emit operationFailed(); 137 | break; 138 | case SPANDA_SWAPUTILS_OP_TURNON_SWAP: 139 | emit finishedTurnOnSwap(); 140 | break; 141 | case SPANDA_SWAPUTILS_OP_TURNOFF_SWAP: 142 | emit finishedTurnOffSwap(); 143 | break; 144 | default:; 145 | } 146 | break; 147 | } 148 | case ExeLauncher::FileNotFound: 149 | DialogUtils::warnMissingFile(exe.getExeFilePath(), true); 150 | break; 151 | case ExeLauncher::NoPermission: 152 | DialogUtils::warnExecPermission(exe.getExeFilePath()); 153 | break; 154 | case ExeLauncher::Crashed: 155 | case ExeLauncher::UnknownError: 156 | default: 157 | emit operationFailed(); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /Utils/swaputils.h: -------------------------------------------------------------------------------- 1 | #ifndef SWAPUTILS_H 2 | #define SWAPUTILS_H 3 | 4 | #include "../Interfaces/exelauncher.h" 5 | 6 | 7 | class SwapUtils : public QObject 8 | { 9 | Q_OBJECT 10 | public: 11 | SwapUtils(); 12 | 13 | static bool isSwapFile(QString fileName); 14 | bool makeSwapFile(QString fileName, qint64 size); 15 | bool removeSwapFile(QString fileName); 16 | 17 | bool turnOnSwap(QString device); 18 | bool turnOffSwap(QString device); 19 | 20 | signals: 21 | void finishedMakingSwapfile(); 22 | void finishedRemovingSwapfile(); 23 | void finishedTurnOnSwap(); 24 | void finishedTurnOffSwap(); 25 | void operationFailed(); 26 | 27 | private: 28 | ExeLauncher exe; 29 | QString currentDevice; 30 | int deviceSize; 31 | int currentOperation; 32 | 33 | bool createSwapFile(QString fileName, qint64 size); 34 | bool setupSwapFile(QString fileName); 35 | 36 | private slots: 37 | void onExeFinished(ExeLauncher::ExecErrorCode errCode); 38 | }; 39 | 40 | #endif // SWAPUTILS_H 41 | -------------------------------------------------------------------------------- /Widgets/environmentdialog.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #include "environmentdialog.h" 27 | 28 | #include "../Utils/environment.h" 29 | #include "../Utils/hostosinfo.h" 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | namespace Utils { 37 | 38 | namespace Internal { 39 | 40 | static QList cleanUp( 41 | const QList &items) 42 | { 43 | QList uniqueItems; 44 | QSet uniqueSet; 45 | for (int i = items.count() - 1; i >= 0; i--) { 46 | EnvironmentItem item = items.at(i); 47 | if (HostOsInfo::isWindowsHost()) 48 | item.name = item.name.toUpper(); 49 | const QString &itemName = item.name; 50 | QString emptyName = itemName; 51 | emptyName.remove(QLatin1Char(' ')); 52 | if (!emptyName.isEmpty() && !uniqueSet.contains(itemName)) { 53 | uniqueItems.prepend(item); 54 | uniqueSet.insert(itemName); 55 | } 56 | } 57 | return uniqueItems; 58 | } 59 | 60 | class EnvironmentItemsWidget : public QWidget 61 | { 62 | Q_OBJECT 63 | public: 64 | explicit EnvironmentItemsWidget(QWidget *parent = nullptr); 65 | 66 | void setEnvironmentItems(const QList &items); 67 | QList environmentItems() const; 68 | 69 | void setPlaceholderText(const QString &text); 70 | 71 | private: 72 | QPlainTextEdit *m_editor; 73 | }; 74 | 75 | EnvironmentItemsWidget::EnvironmentItemsWidget(QWidget *parent) : 76 | QWidget(parent) 77 | { 78 | m_editor = new QPlainTextEdit(this); 79 | auto layout = new QVBoxLayout(this); 80 | layout->setMargin(0); 81 | layout->addWidget(m_editor); 82 | } 83 | 84 | void EnvironmentItemsWidget::setEnvironmentItems(const QList &items) 85 | { 86 | QList sortedItems = items; 87 | EnvironmentItem::sort(&sortedItems); 88 | const QStringList list = EnvironmentItem::toStringList(sortedItems); 89 | m_editor->document()->setPlainText(list.join(QLatin1Char('\n'))); 90 | } 91 | 92 | QList EnvironmentItemsWidget::environmentItems() const 93 | { 94 | const QStringList list = m_editor->document()->toPlainText().split(QLatin1String("\n")); 95 | QList items = EnvironmentItem::fromStringList(list); 96 | return cleanUp(items); 97 | } 98 | 99 | void EnvironmentItemsWidget::setPlaceholderText(const QString &text) 100 | { 101 | m_editor->setPlaceholderText(text); 102 | } 103 | 104 | class EnvironmentDialogPrivate 105 | { 106 | public: 107 | EnvironmentItemsWidget *m_editor; 108 | }; 109 | 110 | } // namespace Internal 111 | 112 | EnvironmentDialog::EnvironmentDialog(QWidget *parent) : 113 | QDialog(parent), d(new Internal::EnvironmentDialogPrivate) 114 | { 115 | setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); 116 | resize(640, 480); 117 | d->m_editor = new Internal::EnvironmentItemsWidget(this); 118 | auto box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this); 119 | connect(box, &QDialogButtonBox::accepted, this, &QDialog::accept); 120 | connect(box, &QDialogButtonBox::rejected, this, &QDialog::reject); 121 | 122 | auto helpLabel = new QLabel(this); 123 | helpLabel->setText(tr("Enter one environment variable per line.\n" 124 | "To set or change a variable, use VARIABLE=VALUE.\n" 125 | "Existing variables can be referenced in a VALUE with ${OTHER}.\n" 126 | "To clear a variable, put its name on a line with nothing else on it.")); 127 | 128 | auto layout = new QVBoxLayout(this); 129 | layout->addWidget(d->m_editor); 130 | layout->addWidget(helpLabel); 131 | 132 | layout->addWidget(box); 133 | 134 | setWindowTitle(tr("Edit Environment")); 135 | } 136 | 137 | EnvironmentDialog::~EnvironmentDialog() 138 | { 139 | delete d; 140 | } 141 | 142 | void EnvironmentDialog::setEnvironmentItems(const QList &items) 143 | { 144 | d->m_editor->setEnvironmentItems(items); 145 | } 146 | 147 | QList EnvironmentDialog::environmentItems() const 148 | { 149 | return d->m_editor->environmentItems(); 150 | } 151 | 152 | void EnvironmentDialog::setPlaceholderText(const QString &text) 153 | { 154 | d->m_editor->setPlaceholderText(text); 155 | } 156 | 157 | QList EnvironmentDialog::getEnvironmentItems(bool *ok, 158 | QWidget *parent, 159 | const QList &initial, 160 | const QString &placeholderText, 161 | Polisher polisher) 162 | { 163 | EnvironmentDialog dlg(parent); 164 | if (polisher) 165 | polisher(&dlg); 166 | dlg.setEnvironmentItems(initial); 167 | dlg.setPlaceholderText(placeholderText); 168 | bool result = dlg.exec() == QDialog::Accepted; 169 | if (ok) 170 | *ok = result; 171 | if (result) 172 | return dlg.environmentItems(); 173 | return QList(); 174 | } 175 | 176 | } // namespace Utils 177 | 178 | #include "environmentdialog.moc" 179 | -------------------------------------------------------------------------------- /Widgets/environmentdialog.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include "../Utils/environment.h" 29 | 30 | #include 31 | 32 | namespace Utils { 33 | 34 | namespace Internal { class EnvironmentDialogPrivate; } 35 | 36 | class EnvironmentDialog : public QDialog 37 | { 38 | Q_OBJECT 39 | public: 40 | explicit EnvironmentDialog(QWidget *parent = nullptr); 41 | ~EnvironmentDialog() override; 42 | 43 | void setEnvironmentItems(const QList &items); 44 | QList environmentItems() const; 45 | 46 | void setPlaceholderText(const QString &text); 47 | 48 | using Polisher = std::function; 49 | static QList getEnvironmentItems(bool *ok, 50 | QWidget *parent = nullptr, 51 | const QList &initial = QList(), 52 | const QString &placeholderText = QString(), 53 | Polisher polish = Polisher()); 54 | 55 | private: 56 | Internal::EnvironmentDialogPrivate *d; 57 | }; 58 | 59 | } // namespace Utils 60 | -------------------------------------------------------------------------------- /Widgets/environmentwidget.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #include "environmentwidget.h" 27 | 28 | //#include 29 | #include "../Utils/environment.h" 30 | #include "../Utils/environmentmodel.h" 31 | #include "../Widgets/environmentdialog.h" 32 | #include "../Widgets/headerviewstretcher.h" 33 | #include "../Widgets/itemviews.h" 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | 48 | class EnvironmentValidator : public QValidator 49 | { 50 | Q_OBJECT 51 | public: 52 | EnvironmentValidator(QWidget *parent, Utils::EnvironmentModel *model, QTreeView *view, 53 | const QModelIndex &index) : 54 | QValidator(parent), m_model(model), m_view(view), m_index(index) 55 | { 56 | } 57 | 58 | QValidator::State validate(QString &in, int &pos) const override 59 | { 60 | Q_UNUSED(pos) 61 | QModelIndex idx = m_model->variableToIndex(in); 62 | if (idx.isValid() && idx != m_index) 63 | return QValidator::Intermediate; 64 | return QValidator::Acceptable; 65 | } 66 | 67 | void fixup(QString &input) const override 68 | { 69 | Q_UNUSED(input) 70 | // do nothing 71 | } 72 | private: 73 | Utils::EnvironmentModel *m_model; 74 | QTreeView *m_view; 75 | QModelIndex m_index; 76 | }; 77 | 78 | class EnvironmentDelegate : public QStyledItemDelegate 79 | { 80 | public: 81 | EnvironmentDelegate(Utils::EnvironmentModel *model, 82 | QTreeView *view) 83 | : QStyledItemDelegate(view), m_model(model), m_view(view) 84 | {} 85 | 86 | QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override 87 | { 88 | QWidget *w = QStyledItemDelegate::createEditor(parent, option, index); 89 | if (index.column() != 0) 90 | return w; 91 | 92 | if (auto edit = qobject_cast(w)) 93 | edit->setValidator(new EnvironmentValidator(edit, m_model, m_view, index)); 94 | return w; 95 | } 96 | private: 97 | Utils::EnvironmentModel *m_model; 98 | QTreeView *m_view; 99 | }; 100 | 101 | 102 | //// 103 | // EnvironmentWidget::EnvironmentWidget 104 | //// 105 | 106 | class EnvironmentWidgetPrivate 107 | { 108 | public: 109 | Utils::EnvironmentModel *m_model; 110 | 111 | QString m_baseEnvironmentText; 112 | QLabel *m_summaryText; 113 | QTreeView *m_environmentView; 114 | QPushButton *m_editButton; 115 | QPushButton *m_addButton; 116 | QPushButton *m_resetButton; 117 | QPushButton *m_unsetButton; 118 | QPushButton *m_batchEditButton; 119 | }; 120 | 121 | EnvironmentWidget::EnvironmentWidget(QWidget *parent, QWidget *additionalDetailsWidget) 122 | : QWidget(parent), d(new EnvironmentWidgetPrivate) 123 | { 124 | d->m_model = new Utils::EnvironmentModel(); 125 | connect(d->m_model, &Utils::EnvironmentModel::userChangesChanged, 126 | this, &EnvironmentWidget::userChangesChanged); 127 | connect(d->m_model, &QAbstractItemModel::modelReset, 128 | this, &EnvironmentWidget::invalidateCurrentIndex); 129 | 130 | connect(d->m_model, &Utils::EnvironmentModel::focusIndex, 131 | this, &EnvironmentWidget::focusIndex); 132 | 133 | auto vbox = new QVBoxLayout(this); 134 | vbox->setContentsMargins(0, 0, 0, 0); 135 | 136 | if (additionalDetailsWidget) 137 | vbox->addWidget(additionalDetailsWidget); 138 | 139 | d->m_summaryText = new QLabel(this); 140 | d->m_summaryText->setWordWrap(true); 141 | vbox->addWidget(d->m_summaryText); 142 | 143 | auto horizontalLayout = new QHBoxLayout(); 144 | horizontalLayout->setMargin(0); 145 | auto tree = new Utils::TreeView(this); 146 | connect(tree, &QAbstractItemView::activated, 147 | tree, [tree](const QModelIndex &idx) { tree->edit(idx); }); 148 | d->m_environmentView = tree; 149 | d->m_environmentView->setModel(d->m_model); 150 | d->m_environmentView->setItemDelegate(new EnvironmentDelegate(d->m_model, d->m_environmentView)); 151 | d->m_environmentView->setMinimumHeight(400); 152 | d->m_environmentView->setRootIsDecorated(false); 153 | d->m_environmentView->setUniformRowHeights(true); 154 | new Utils::HeaderViewStretcher(d->m_environmentView->header(), 1); 155 | d->m_environmentView->setSelectionMode(QAbstractItemView::SingleSelection); 156 | d->m_environmentView->setSelectionBehavior(QAbstractItemView::SelectItems); 157 | d->m_environmentView->setFrameShape(QFrame::NoFrame); 158 | 159 | auto buttonLayout = new QVBoxLayout(); 160 | 161 | d->m_editButton = new QPushButton(this); 162 | d->m_editButton->setText(tr("Ed&it")); 163 | buttonLayout->addWidget(d->m_editButton); 164 | 165 | d->m_addButton = new QPushButton(this); 166 | d->m_addButton->setText(tr("&Add")); 167 | buttonLayout->addWidget(d->m_addButton); 168 | 169 | d->m_resetButton = new QPushButton(this); 170 | d->m_resetButton->setEnabled(false); 171 | d->m_resetButton->setText(tr("&Reset")); 172 | buttonLayout->addWidget(d->m_resetButton); 173 | 174 | d->m_unsetButton = new QPushButton(this); 175 | d->m_unsetButton->setEnabled(false); 176 | d->m_unsetButton->setText(tr("&Unset")); 177 | buttonLayout->addWidget(d->m_unsetButton); 178 | 179 | d->m_batchEditButton = new QPushButton(this); 180 | d->m_batchEditButton->setText(tr("&Batch Edit...")); 181 | buttonLayout->addWidget(d->m_batchEditButton); 182 | 183 | buttonLayout->addStretch(); 184 | 185 | horizontalLayout->addWidget(tree); 186 | horizontalLayout->addLayout(buttonLayout); 187 | vbox->addLayout(horizontalLayout); 188 | 189 | connect(d->m_model, &QAbstractItemModel::dataChanged, 190 | this, &EnvironmentWidget::updateButtons); 191 | 192 | connect(d->m_editButton, &QAbstractButton::clicked, 193 | this, &EnvironmentWidget::editEnvironmentButtonClicked); 194 | connect(d->m_addButton, &QAbstractButton::clicked, 195 | this, &EnvironmentWidget::addEnvironmentButtonClicked); 196 | connect(d->m_resetButton, &QAbstractButton::clicked, 197 | this, &EnvironmentWidget::removeEnvironmentButtonClicked); 198 | connect(d->m_unsetButton, &QAbstractButton::clicked, 199 | this, &EnvironmentWidget::unsetEnvironmentButtonClicked); 200 | connect(d->m_batchEditButton, &QAbstractButton::clicked, 201 | this, &EnvironmentWidget::batchEditEnvironmentButtonClicked); 202 | connect(d->m_environmentView->selectionModel(), &QItemSelectionModel::currentChanged, 203 | this, &EnvironmentWidget::environmentCurrentIndexChanged); 204 | 205 | connect(d->m_model, &Utils::EnvironmentModel::userChangesChanged, 206 | this, &EnvironmentWidget::updateSummaryText); 207 | } 208 | 209 | EnvironmentWidget::~EnvironmentWidget() 210 | { 211 | delete d->m_model; 212 | d->m_model = nullptr; 213 | } 214 | 215 | void EnvironmentWidget::focusIndex(const QModelIndex &index) 216 | { 217 | d->m_environmentView->setCurrentIndex(index); 218 | d->m_environmentView->setFocus(); 219 | // When the current item changes as a result of the call above, 220 | // QAbstractItemView::currentChanged() is called. That calls scrollTo(current), 221 | // using the default EnsureVisible scroll hint, whereas we want PositionAtTop, 222 | // because it ensures that the user doesn't have to scroll down when they've 223 | // added a new environment variable and want to edit its value; they'll be able 224 | // to see its value as they're typing it. 225 | // This only helps to a certain degree - variables whose names start with letters 226 | // later in the alphabet cause them fall within the "end" of the view's range, 227 | // making it impossible to position them at the top of the view. 228 | d->m_environmentView->scrollTo(index, QAbstractItemView::PositionAtTop); 229 | } 230 | 231 | void EnvironmentWidget::setBaseEnvironment(const Utils::Environment &env) 232 | { 233 | d->m_model->setBaseEnvironment(env); 234 | } 235 | 236 | void EnvironmentWidget::setBaseEnvironmentText(const QString &text) 237 | { 238 | d->m_baseEnvironmentText = text; 239 | updateSummaryText(); 240 | } 241 | 242 | QList EnvironmentWidget::userChanges() const 243 | { 244 | return d->m_model->userChanges(); 245 | } 246 | 247 | void EnvironmentWidget::setUserChanges(const QList &list) 248 | { 249 | d->m_model->setUserChanges(list); 250 | updateSummaryText(); 251 | } 252 | 253 | void EnvironmentWidget::closeEvent(QCloseEvent *event) 254 | { 255 | Q_UNUSED(event) 256 | emit closing(); 257 | } 258 | 259 | void EnvironmentWidget::updateSummaryText() 260 | { 261 | QList list = d->m_model->userChanges(); 262 | Utils::EnvironmentItem::sort(&list); 263 | 264 | QString text; 265 | foreach (const Utils::EnvironmentItem &item, list) { 266 | if (item.name != Utils::EnvironmentModel::tr("")) { 267 | text.append(QLatin1String("
")); 268 | if (item.operation == Utils::EnvironmentItem::Unset) 269 | text.append(tr("Unset %1").arg(item.name.toHtmlEscaped())); 270 | else 271 | text.append(tr("Set %1 to %2").arg(item.name.toHtmlEscaped(), item.value.toHtmlEscaped())); 272 | } 273 | } 274 | 275 | if (text.isEmpty()) { 276 | //: %1 is "System Environment" or some such. 277 | text.prepend(tr("Use %1").arg(d->m_baseEnvironmentText)); 278 | } else { 279 | //: Yup, word puzzle. The Set/Unset phrases above are appended to this. 280 | //: %1 is "System Environment" or some such. 281 | text.prepend(tr("Use %1 and").arg(d->m_baseEnvironmentText)); 282 | } 283 | 284 | d->m_summaryText->setText(text); 285 | } 286 | 287 | void EnvironmentWidget::updateButtons() 288 | { 289 | environmentCurrentIndexChanged(d->m_environmentView->currentIndex()); 290 | } 291 | 292 | void EnvironmentWidget::editEnvironmentButtonClicked() 293 | { 294 | d->m_environmentView->edit(d->m_environmentView->currentIndex()); 295 | } 296 | 297 | void EnvironmentWidget::addEnvironmentButtonClicked() 298 | { 299 | QModelIndex index = d->m_model->addVariable(); 300 | d->m_environmentView->setCurrentIndex(index); 301 | d->m_environmentView->edit(index); 302 | } 303 | 304 | void EnvironmentWidget::removeEnvironmentButtonClicked() 305 | { 306 | const QString &name = d->m_model->indexToVariable(d->m_environmentView->currentIndex()); 307 | d->m_model->resetVariable(name); 308 | } 309 | 310 | // unset in Merged Environment Mode means, unset if it comes from the base environment 311 | // or remove when it is just a change we added 312 | void EnvironmentWidget::unsetEnvironmentButtonClicked() 313 | { 314 | const QString &name = d->m_model->indexToVariable(d->m_environmentView->currentIndex()); 315 | if (!d->m_model->canReset(name)) 316 | d->m_model->resetVariable(name); 317 | else 318 | d->m_model->unsetVariable(name); 319 | } 320 | 321 | void EnvironmentWidget::batchEditEnvironmentButtonClicked() 322 | { 323 | const QList changes = d->m_model->userChanges(); 324 | 325 | bool ok; 326 | const QList newChanges = Utils::EnvironmentDialog::getEnvironmentItems(&ok, this, changes); 327 | if (!ok) 328 | return; 329 | 330 | d->m_model->setUserChanges(newChanges); 331 | } 332 | 333 | void EnvironmentWidget::environmentCurrentIndexChanged(const QModelIndex ¤t) 334 | { 335 | if (current.isValid()) { 336 | d->m_editButton->setEnabled(true); 337 | const QString &name = d->m_model->indexToVariable(current); 338 | bool modified = d->m_model->canReset(name) && d->m_model->changes(name); 339 | bool unset = d->m_model->canUnset(name); 340 | d->m_resetButton->setEnabled(modified || unset); 341 | d->m_unsetButton->setEnabled(!unset); 342 | } else { 343 | d->m_editButton->setEnabled(false); 344 | d->m_resetButton->setEnabled(false); 345 | d->m_unsetButton->setEnabled(false); 346 | } 347 | } 348 | 349 | void EnvironmentWidget::invalidateCurrentIndex() 350 | { 351 | environmentCurrentIndexChanged(QModelIndex()); 352 | } 353 | 354 | #include "environmentwidget.moc" 355 | -------------------------------------------------------------------------------- /Widgets/environmentwidget.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include 29 | 30 | #include 31 | 32 | QT_FORWARD_DECLARE_CLASS(QModelIndex) 33 | 34 | namespace Utils { 35 | class Environment; 36 | class EnvironmentItem; 37 | } // namespace Utils 38 | 39 | class EnvironmentWidgetPrivate; 40 | 41 | class EnvironmentWidget : public QWidget 42 | { 43 | Q_OBJECT 44 | 45 | public: 46 | explicit EnvironmentWidget(QWidget *parent, QWidget *additionalDetailsWidget = nullptr); 47 | ~EnvironmentWidget() override; 48 | 49 | void setBaseEnvironmentText(const QString &text); 50 | void setBaseEnvironment(const Utils::Environment &env); 51 | 52 | QList userChanges() const; 53 | void setUserChanges(const QList &list); 54 | 55 | signals: 56 | void userChangesChanged(); 57 | void closing(); 58 | 59 | protected: 60 | void closeEvent(QCloseEvent* event); 61 | 62 | private: 63 | void editEnvironmentButtonClicked(); 64 | void addEnvironmentButtonClicked(); 65 | void removeEnvironmentButtonClicked(); 66 | void unsetEnvironmentButtonClicked(); 67 | void batchEditEnvironmentButtonClicked(); 68 | void environmentCurrentIndexChanged(const QModelIndex ¤t); 69 | void invalidateCurrentIndex(); 70 | void updateSummaryText(); 71 | void focusIndex(const QModelIndex &index); 72 | void updateButtons(); 73 | 74 | const std::unique_ptr d; 75 | }; 76 | -------------------------------------------------------------------------------- /Widgets/headerviewstretcher.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #include "headerviewstretcher.h" 27 | #include 28 | #include 29 | 30 | using namespace Utils; 31 | 32 | /*! 33 | \class Utils::HeaderViewStretcher 34 | 35 | \brief The HeaderViewStretcher class fixes QHeaderView to resize all 36 | columns to contents, except one 37 | stretching column. 38 | 39 | As opposed to standard QTreeWidget, all columns are 40 | still interactively resizable. 41 | */ 42 | 43 | HeaderViewStretcher::HeaderViewStretcher(QHeaderView *headerView, int columnToStretch) 44 | : QObject(headerView), m_columnToStretch(columnToStretch) 45 | { 46 | headerView->installEventFilter(this); 47 | stretch(); 48 | } 49 | 50 | void HeaderViewStretcher::stretch() 51 | { 52 | QHideEvent fake; 53 | HeaderViewStretcher::eventFilter(parent(), &fake); 54 | } 55 | 56 | bool HeaderViewStretcher::eventFilter(QObject *obj, QEvent *ev) 57 | { 58 | if (obj == parent()) { 59 | if (ev->type() == QEvent::Show) { 60 | auto hv = qobject_cast(obj); 61 | for (int i = 0; i < hv->count(); ++i) 62 | hv->setSectionResizeMode(i, QHeaderView::Interactive); 63 | } else if (ev->type() == QEvent::Hide) { 64 | auto hv = qobject_cast(obj); 65 | for (int i = 0; i < hv->count(); ++i) 66 | hv->setSectionResizeMode(i, i == m_columnToStretch 67 | ? QHeaderView::Stretch : QHeaderView::ResizeToContents); 68 | } else if (ev->type() == QEvent::Resize) { 69 | auto hv = qobject_cast(obj); 70 | if (hv->sectionResizeMode(m_columnToStretch) == QHeaderView::Interactive) { 71 | auto re = static_cast(ev); 72 | int diff = re->size().width() - re->oldSize().width() ; 73 | hv->resizeSection(m_columnToStretch, qMax(32, hv->sectionSize(m_columnToStretch) + diff)); 74 | } 75 | } 76 | } 77 | return false; 78 | } 79 | -------------------------------------------------------------------------------- /Widgets/headerviewstretcher.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #pragma once 27 | 28 | #include 29 | 30 | QT_BEGIN_NAMESPACE 31 | class QHeaderView; 32 | QT_END_NAMESPACE 33 | 34 | namespace Utils { 35 | 36 | class HeaderViewStretcher : public QObject 37 | { 38 | const int m_columnToStretch; 39 | public: 40 | explicit HeaderViewStretcher(QHeaderView *headerView, int columnToStretch); 41 | 42 | void stretch(); 43 | bool eventFilter(QObject *obj, QEvent *ev) override; 44 | }; 45 | 46 | } // namespace Utils 47 | -------------------------------------------------------------------------------- /Widgets/itemviews.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #include "itemviews.h" 27 | 28 | /*! 29 | \class Utils::TreeView 30 | 31 | \brief The TreeView adds setActivationMode to QTreeView 32 | to allow for single click/double click behavior on 33 | platforms where the default is different. Use with care. 34 | 35 | Also adds sane keyboard navigation for mac. 36 | */ 37 | 38 | /*! 39 | \class Utils::TreeWidget 40 | 41 | \brief The TreeWidget adds setActivationMode to QTreeWidget 42 | to allow for single click/double click behavior on 43 | platforms where the default is different. Use with care. 44 | 45 | Also adds sane keyboard navigation for mac. 46 | */ 47 | 48 | /*! 49 | \class Utils::ListView 50 | 51 | \brief The ListView adds setActivationMode to QListView 52 | to allow for single click/double click behavior on 53 | platforms where the default is different. Use with care. 54 | 55 | Also adds sane keyboard navigation for mac. 56 | */ 57 | 58 | /*! 59 | \class Utils::ListWidget 60 | 61 | \brief The ListWidget adds setActivationMode to QListWidget 62 | to allow for single click/double click behavior on 63 | platforms where the default is different. Use with care. 64 | 65 | Also adds sane keyboard navigation for mac. 66 | */ 67 | -------------------------------------------------------------------------------- /Widgets/itemviews.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of Qt Creator. 7 | ** 8 | ** Commercial License Usage 9 | ** Licensees holding valid commercial Qt licenses may use this file in 10 | ** accordance with the commercial license agreement provided with the 11 | ** Software or, alternatively, in accordance with the terms contained in 12 | ** a written agreement between you and The Qt Company. For licensing terms 13 | ** and conditions see https://www.qt.io/terms-conditions. For further 14 | ** information use the contact form at https://www.qt.io/contact-us. 15 | ** 16 | ** GNU General Public License Usage 17 | ** Alternatively, this file may be used under the terms of the GNU 18 | ** General Public License version 3 as published by the Free Software 19 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 | ** included in the packaging of this file. Please review the following 21 | ** information to ensure the GNU General Public License requirements will 22 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 | ** 24 | ****************************************************************************/ 25 | 26 | #pragma once 27 | 28 | static const char activationModeC[] = "ActivationMode"; 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | 37 | 38 | namespace Utils { 39 | 40 | enum ActivationMode { 41 | DoubleClickActivation = 0, 42 | SingleClickActivation = 1, 43 | PlatformDefaultActivation = 2 44 | }; 45 | 46 | template 47 | class View : public BaseT 48 | { 49 | public: 50 | View(QWidget *parent = nullptr) 51 | : BaseT(parent) 52 | {} 53 | void setActivationMode(ActivationMode mode) 54 | { 55 | if (mode == PlatformDefaultActivation) 56 | BaseT::setProperty(activationModeC, QVariant()); 57 | else 58 | BaseT::setProperty(activationModeC, QVariant(bool(mode))); 59 | } 60 | 61 | ActivationMode activationMode() const 62 | { 63 | QVariant v = BaseT::property(activationModeC); 64 | if (!v.isValid()) 65 | return PlatformDefaultActivation; 66 | return v.toBool() ? SingleClickActivation : DoubleClickActivation; 67 | } 68 | 69 | void keyPressEvent(QKeyEvent *event) override 70 | { 71 | // Note: This always eats the event 72 | // whereas QAbstractItemView never eats it 73 | if ((event->key() == Qt::Key_Return 74 | || event->key() == Qt::Key_Enter) 75 | && event->modifiers() == 0 76 | && BaseT::currentIndex().isValid() 77 | && BaseT::state() != QAbstractItemView::EditingState) { 78 | emit BaseT::activated(BaseT::currentIndex()); 79 | return; 80 | } 81 | BaseT::keyPressEvent(event); 82 | } 83 | 84 | }; 85 | 86 | class TreeView : public View 87 | { 88 | Q_OBJECT 89 | public: 90 | TreeView(QWidget *parent = nullptr) 91 | : View(parent) 92 | {} 93 | }; 94 | 95 | class TreeWidget : public View 96 | { 97 | Q_OBJECT 98 | public: 99 | TreeWidget(QWidget *parent = nullptr) 100 | : View(parent) 101 | {} 102 | }; 103 | 104 | class ListView : public View 105 | { 106 | Q_OBJECT 107 | public: 108 | ListView(QWidget *parent = nullptr) 109 | : View(parent) 110 | {} 111 | }; 112 | 113 | class ListWidget : public View 114 | { 115 | Q_OBJECT 116 | public: 117 | ListWidget(QWidget *parent = nullptr) 118 | : View(parent) 119 | {} 120 | }; 121 | 122 | } // Utils 123 | -------------------------------------------------------------------------------- /aboutwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "aboutwindow.h" 2 | #include "ui_aboutwindow.h" 3 | 4 | 5 | AboutWindow::AboutWindow(QWidget *parent) : 6 | QDialog(parent), 7 | ui(new Ui::AboutWindow) 8 | { 9 | ui->setupUi(this); 10 | setFixedSize(width(), height()); 11 | } 12 | 13 | AboutWindow::~AboutWindow() 14 | { 15 | delete ui; 16 | } 17 | 18 | void AboutWindow::changeEvent(QEvent* event) 19 | { 20 | if (event->type() == QEvent::LanguageChange) 21 | ui->retranslateUi(this); 22 | 23 | ui->labelVersion->setText(QString(tr("Ver: %1")).arg(APP_VERSION)); 24 | ui->textAbout->setText(tr("Super Panda - Toolkit for tweaking Linux system\n\n" 25 | "This program is a free software.\n\n" 26 | "You can redistribute it and/or modify it under the terms of " 27 | "the GNU Library General Public License as published by " 28 | "the Free Software Foundation; either version 3 of the License, " 29 | "or (at your option) any later version.\n\n" 30 | "This program is distributed in the hope that it will be useful, but WITHOUT " 31 | "ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or " 32 | "FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License " 33 | "for more details.\n")); 34 | ui->labelContact->setText(tr("

Project Home: Github" 35 | "

Feel free to report bugs and give suggestions!

")); 36 | } 37 | -------------------------------------------------------------------------------- /aboutwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef AboutWindow_H 2 | #define AboutWindow_H 3 | 4 | #include 5 | 6 | 7 | namespace Ui { 8 | class AboutWindow; 9 | } 10 | 11 | class AboutWindow : public QDialog 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | explicit AboutWindow(QWidget *parent = 0); 17 | ~AboutWindow(); 18 | 19 | protected: 20 | void changeEvent(QEvent* event); 21 | 22 | private: 23 | Ui::AboutWindow *ui; 24 | }; 25 | 26 | #endif // AboutWindow_H 27 | -------------------------------------------------------------------------------- /aboutwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | AboutWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | About 15 | 16 | 17 | 18 | 19 | 20 20 | 260 21 | 361 22 | 32 23 | 24 | 25 | 26 | Qt::Horizontal 27 | 28 | 29 | QDialogButtonBox::Close 30 | 31 | 32 | 33 | 34 | 35 | 10 36 | 0 37 | 50 38 | 50 39 | 40 | 41 | 42 | 43 | 44 | 45 | :/Icons/Icons/SuperPanda.png 46 | 47 | 48 | true 49 | 50 | 51 | 52 | 53 | 54 | 60 55 | 0 56 | 231 57 | 51 58 | 59 | 60 | 61 | <html><head/><body><p><span style=" font-size:20pt;">Super Panda</span></p></body></html> 62 | 63 | 64 | 65 | 66 | 67 | 10 68 | 60 69 | 381 70 | 191 71 | 72 | 73 | 74 | 0 75 | 76 | 77 | 78 | About 79 | 80 | 81 | 82 | 83 | -5 84 | -5 85 | 381 86 | 171 87 | 88 | 89 | 90 | 91 | 92 | 93 | Author 94 | 95 | 96 | 97 | 98 | 10 99 | 0 100 | 351 101 | 151 102 | 103 | 104 | 105 | Qt::RichText 106 | 107 | 108 | true 109 | 110 | 111 | true 112 | 113 | 114 | Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 290 123 | 20 124 | 101 125 | 31 126 | 127 | 128 | 129 | 130 | 131 | 132 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | buttonBox 142 | accepted() 143 | AboutWindow 144 | accept() 145 | 146 | 147 | 248 148 | 254 149 | 150 | 151 | 157 152 | 274 153 | 154 | 155 | 156 | 157 | buttonBox 158 | rejected() 159 | AboutWindow 160 | reject() 161 | 162 | 163 | 316 164 | 260 165 | 166 | 167 | 286 168 | 274 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /doc/Component - MagicKonfug.md: -------------------------------------------------------------------------------- 1 | # SuperPanda - MagicKunfug 2 | 3 | The component "MagicKunfug" helps tweaking system parameters, by modifying configuration files via standard file IO functions, or binary configuration via command line interface. The idea of the design is to utilize file/command as native APIs for system configuration, contrary to that of Windows(R) system which largely depends on application binary interfaces (ABI), as ABIs in Linux world seem impossible to be conciliated due to the incompatibility among vast variation of standard libraries. As a consequence, MagicKunfug requires nothing other than a Qt shared library of minimum build version, with basic or optional command line tools for extended functions to work. 4 | 5 | This document is devoted to elucidate the technical details of each tweaking functions built in MagicKunfug. 6 | 7 | 8 | ## Cheat sheet 9 | 10 | ### Configuration files 11 | 12 | All file IDs are defined in [config_files.h](./Component/config_files.h). 13 | 14 | |No.|File ID|File Type|File Scope|Default Path| 15 | |---|---|---|---|---| 16 | |1|SPANDA_CONFIG_FILE_GRUB_DEFAULT|Text|System|/etc/default/grub| 17 | |2|SPANDA_CONFIG_FILE_KEYBD_DEFAULT|Text|System|/etc/default/keyboard| 18 | |3|SPANDA_CONFIG_FILE_MOUNT_ROOT|Text|System|/etc/fstab| 19 | |4|SPANDA_CONFIG_FILE_SYSTEMD_SYSTEM|Text|System|/etc/systemd/system.conf| 20 | |5|SPANDA_CONFIG_FILE_SYSTEMD_USER|Text|System|/etc/systemd/user.conf| 21 | |6|SPANDA_CONFIG_FILE_UDEV_DISK|Text|System|/etc/udev/rules.d/95-superpanda.rules| 22 | |7|SPANDA_CONFIG_FILE_MODCONF_IWLWIFI|Text|System|/etc/modprobe.d/iwlwifi.conf| 23 | |8|SPANDA_CONFIG_FILE_ENVIRONMENT_SYS|Text|System|/etc/environment| 24 | |9|SPANDA_CONFIG_FILE_ENVIRONMENT_USER|Text|User|~/.xsessionrc| 25 | |10|SPANDA_CONFIG_FILE_XSESSION_USER|Text|User|~/.xsession| 26 | |11|SPANDA_CONFIG_FILE_AUTOSTART_SCREEN_USER|Text|User|~/.config/autostart/spanda-screen-config.desktop| 27 | |12|SPANDA_CONFIG_FILE_SWAPFILE_ROOT|Binary|System|/swapfile| 28 | 29 | 30 | ### Configurations 31 | 32 | All config IDs are defined in [configcollection.h](./Component/configcollection.h). 33 | 34 | |No.|Name|Category|Config ID|Config File No.|Value Type|Default Value| 35 | |---|---|---|---|---|---|---| 36 | |1|Service timeout|Service|CONFIG_SERVICE_TIMEOUT|4,5|Int|10| 37 | |2|System shutdown timeout|Service|CONFIG_SHUTDOWN_TIMEOUT|4|Int|30| 38 | |3|Intel CPU Turbo|CPU|CONFIG_CPU_INTEL_TURBO|1|Bool|false| 39 | |4|Keboard Compose Key|Keyboard|CONFIG_KEYBD_COMPOSE|2|String|""| 40 | |5|Disk physics|Disk|CONFIG_DISK_PHYSICS|3,6|Int|0| 41 | |6|Boot screen timeout|Boot|CONFIG_BOOT_TIMEOUT|1|Int|10| 42 | |7|Boot screen resolution|Boot|CONFIG_BOOT_RESOLUTION|1|String|""| 43 | |8|Intel Wifi 802.11n|Network|CONFIG_WIFI_INTEL_80211n|7|Bool|true| 44 | |11|Gnome desktop scaling - Window|Screen|CONFIG_DISP_SCALE_GNOME_WINDOW|(Gsettings)|Int|1| 45 | |12|Gnome desktop scaling - Text|Screen|CONFIG_DISP_SCALE_GNOME_TEXT|(Gsettings)|Double|1.0| 46 | |13|Screen resolution|Screen|CONFIG_DISP_RESOLUTION|10,11|{Int,Int}|{0,0}| 47 | |14|System swap file|Swap|CONFIG_DISK_SWAP|3,12|Int|0| 48 | |15|ACPI OS reporting|ACPI|CONFIG_ACPI_OS|1|String|0| 49 | |16|Screen gamma|Screen|CONFIG_DISP_GAMMA|10,11|String|"1,1,1"| 50 | 51 | 52 | ## Implementation 53 | 54 | ### Hardware 55 | 56 | #### ACPI 57 | 58 | ##### ACPI OS reporting 59 | 60 | Report OS type and version to BIOS during boot. The OS type string is passed as kernel boot parameter with following possible values: 61 | 62 | |Value|Kernel boot parameter|Description| 63 | |---|---|---| 64 | |0|""|Use default setting| 65 | |1|"acpi_osi=!"|Disable reporting| 66 | |2|"acpi_osi=Linux"|Linux| 67 | |3|"acpi_osi=Windows"|Windows(R)| 68 | 69 | More details can be found on [ArchWiki](https://wiki.archlinux.org/index.php/Talk:ASUS_E403SA). 70 | 71 | 72 | #### CPU 73 | 74 | ##### Intel CPU Turbo 75 | 76 | Enabled/disable dynamic frequency/power management ("Turbo") on Intel(R) CPUs. The setting is passed as kernel boot parameter with following possible values: 77 | 78 | |Value|Kernel boot parameter|Description| 79 | |---|---|---| 80 | |False|""|Use default setting| 81 | |True|"intel_pstate=enable"|Enable CPU Turbo| 82 | 83 | 84 | #### Disk 85 | 86 | ##### Disk physics 87 | 88 | Enable/disable optimization for solid state drive (SSD). A series of parameters concerning disk IO is set, either in UDEV config file or in system mount config file (fstab), with following possible values: 89 | 90 | Value=0: Using traditional hard disk drive (HDD), with config line 91 | 92 | ``` 93 | ACTION=="add|change", KERNEL==\"%1\", ATTR{queue/rotational} 94 | ``` 95 | 96 | and fstab config parameters without "discard, noatime" for root partition. 97 | 98 | 99 | Value=1: Using SSD for root partition, with UDEV config line 100 | 101 | ``` 102 | "ACTION=="add|change", "KERNEL=="%1", "ATTR{queue/rotational}=="0", "ATTR{queue/scheduler}="deadline" 103 | ``` 104 | and fstab config parameters with "discard,noatime" for root partition. 105 | 106 | 107 | #### Keyboard 108 | 109 | ##### Keboard Compose Key 110 | 111 | Set compose key for inputing non-ASCII characters, i.e. "€", "é" or "ĺ". The parameter is set in system config file of keyboard, with following possible values: 112 | 113 | |Value|Description| 114 | |---|---| 115 | |""|Use default setting| 116 | |"XKBOPTIONS=ralt"|Use right Alt key| 117 | |"XKBOPTIONS=lwin"|Use left Win/Super key| 118 | |"XKBOPTIONS=rwin"|Use right Win/Super key| 119 | |"XKBOPTIONS=lctrl"|Use left Ctrl key| 120 | |"XKBOPTIONS=rctrl"|Use right Ctrl key| 121 | |"XKBOPTIONS=caps"|Use Caps Lock key| 122 | |"XKBOPTIONS=menu"|Use Menu key| 123 | 124 | 125 | #### Network 126 | 127 | ##### Intel Wifi 802.11n 128 | 129 | Enable/disable 802.11n support (if any) on Intel(R) wireless wetwork adapters. This may help improve the stability of wireless connection when connecting to 802.11b/g network. The parameter is set in config file of IWLWIFI module, with following possible values: 130 | 131 | |Value|Module config parameter|Description| 132 | |---|---|---| 133 | |True|"11n_disable=0"|Enable 802.11n support| 134 | |False|"11n_disable=1"|Disable 802.11n support| 135 | 136 | 137 | #### Screen 138 | 139 | ##### Gnome desktop scaling 140 | 141 | Set desktop scaling factors for desktop environment (which is generally required by HiDPI display) via GSettings CUI interface. The config entries concerning screen scalings are: 142 | 143 | |Schema|Key|Type|Default value| 144 | |---|---|---|---| 145 | |org.gnome.desktop.interface|scaling-factor|Int|1| 146 | |org.gnome.desktop.interface|text-scaling-factor|Double|1.0| 147 | |com.deepin.wrap.gnome.desktop.interface|scaling-factor|1| 148 | |com.deepin.wrap.gnome.desktop.interface|text-scaling-factor|1.0| 149 | 150 | Note: the schema "com.deepin.wrap.gnome.desktop.interface" is a wrapper for standard gnome desktop settings. 151 | 152 | ##### Screen resolution 153 | 154 | Adjust screen resolution via xrandr command. The commands for adjusting are stored in an auto-starting bash script which is launched after user's login to X desktop environment. The following commands are used: 155 | 156 | ``` 157 | xrandr --newmode MODE_LINE 158 | xrandr --addmode MONITOR MODE_NAME 159 | xrandr --output MONITOR --mode MODE_NAME 160 | ``` 161 | 162 | where "MODE_LINE", "MONITOR" and "MODE_NAME" are complete config string of display mode, monitor ID and name of the display mode, respectively, detected via "cvt" command and "xrandr" command. 163 | 164 | ##### Screen gamma 165 | 166 | Adjust screen gamma via xrandr command. The commands for adjusting are stored in an auto-starting bash script which is launched after user's login to X desktop environment. The following commands are used: 167 | 168 | ``` 169 | xgamma -rgamma RED -ggamma GREEN -bgamma BLUE 170 | ``` 171 | 172 | where "RED", "GREEN" and "BLUE" are float values corresponding to red, green and blue component of gamma. The default values are all "1.0". 173 | 174 | 175 | ### System Management 176 | 177 | #### Boot 178 | 179 | ##### Boot screen timeout 180 | 181 | Set timeout for GRUB OS selection screen. Following line in GRUB config file is modified: 182 | 183 | ``` 184 | GRUB_TIMEOUT=SECOND 185 | ``` 186 | 187 | where "SECOND" is the timeout value in second. Any leading hastags in this line will be removed. 188 | 189 | ##### Boot screen resolution 190 | 191 | Set resolution for GRUB OS selection screen. Following line in GRUB config file is modified: 192 | 193 | ``` 194 | GRUB_GFXMODE=WIDTHxHEIGHT 195 | ``` 196 | 197 | where "WIDTH" and "HEIGHT" are width and height of the boot screen, respectively. Any leading hastags in this line will be removed. 198 | 199 | Currently, only "640x480", "800x600" and "1024x768" are available as they are the most commonly supported modes. 200 | 201 | 202 | #### Service 203 | 204 | ##### Service timeout 205 | 206 | Set timeout for system service. The following line in systemd config file (system-scope and user-scope config) is modified: 207 | 208 | ``` 209 | DefaultTimeoutStartSec=SECOND 210 | ``` 211 | 212 | where "SECOND" is the timeout value in second. Any leading hastags in this line will be removed. 213 | 214 | ##### System shutdown timeout 215 | 216 | Set timeout for system shutdown. This is specially useful when the shutdown process is stucked by hardware failure or driver error. The following line in systemd config file (system-scope and user-scope config) is modified: 217 | 218 | ``` 219 | ShutdownWatchdogSec=SECOND 220 | ``` 221 | 222 | where "SECOND" is the timeout value in second. Any leading hastags in this line will be removed. 223 | 224 | 225 | #### Swap 226 | 227 | ##### System swap file 228 | 229 | Create/destroy swap file for system, and enable/disable them. The swap file is created in root partition, with size (in MiB) specified by user. Then a mount entry is added to system mount config file (fstab) in order to enable it during boot. The following line in fstab is modified: 230 | 231 | ``` 232 | /swapfile none swap defaults 0 0 233 | ``` 234 | 235 | "dd", "mkswap", "swapon" and "swapoff" command are needed to manipulate the swap file. 236 | 237 | 238 | ### Application 239 | 240 | #### Environment variables 241 | 242 | The environment variables (or simply "environments") are pre-defined key-value pairs that tells applications specified information during their execution. Environment variables are defined either as system-scope or user-scope configuration, stored separately in config files, each with following format: 243 | 244 | ``` 245 | KEY=VALUE 246 | ``` 247 | 248 | where "KEY" and "VALUE" are variable name and variable value in string,respectively. -------------------------------------------------------------------------------- /global.cpp: -------------------------------------------------------------------------------- 1 | #include "global.h" 2 | #include 3 | 4 | 5 | // Global object definitions 6 | MagicKonfug* windowMgckf = nullptr; 7 | AboutWindow* windowAbout = nullptr; 8 | QTranslator appTranslator; 9 | 10 | const char* spanda_language_string[4] = 11 | { 12 | "en_US", 13 | "fr_FR", 14 | "zh_CN", 15 | "zh_TW" 16 | }; 17 | -------------------------------------------------------------------------------- /global.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | #include 5 | 6 | 7 | // Global object declarations 8 | class MagicKonfug; 9 | class AboutWindow; 10 | 11 | extern MagicKonfug* windowMgckf; 12 | extern AboutWindow* windowAbout; 13 | extern QTranslator appTranslator; 14 | 15 | extern const char* spanda_language_string[4]; 16 | 17 | #endif // COMMON_H 18 | -------------------------------------------------------------------------------- /icons.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | Icons/exit.png 4 | Icons/information.png 5 | Icons/help.png 6 | Icons/configure.png 7 | Icons/SuperPanda.png 8 | 9 | 10 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "global.h" 2 | #include "mainwindow.h" 3 | #include 4 | #include 5 | 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | // Enable scaling for HiDPI device 10 | if (qgetenv("QT_SCALE_FACTOR").isEmpty() && 11 | qgetenv("QT_SCREEN_SCALE_FACTORS").isEmpty()) 12 | { 13 | qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1"); 14 | #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) 15 | QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 16 | #endif 17 | } 18 | 19 | QApplication a(argc, argv); 20 | 21 | appTranslator.load(QString(":/Translations/SuperPanda_") 22 | .append(QLocale::system().name())); 23 | a.installTranslator(&appTranslator); 24 | 25 | MainWindow w; 26 | w.show(); 27 | 28 | return a.exec(); 29 | } 30 | -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mainwindow.h" 4 | #include "ui_mainwindow.h" 5 | #include "global.h" 6 | #include "aboutwindow.h" 7 | #include "Components/magickonfug.h" 8 | 9 | 10 | MainWindow::MainWindow(QWidget *parent) : 11 | QMainWindow(parent), 12 | ui(new Ui::MainWindow) 13 | { 14 | ui->setupUi(this); 15 | 16 | move((QApplication::desktop()->width() - width()) / 2, 17 | (QApplication::desktop()->height() - height()) / 2); 18 | } 19 | 20 | MainWindow::~MainWindow() 21 | { 22 | delete ui; 23 | } 24 | 25 | void MainWindow::changeEvent(QEvent* event) 26 | { 27 | if (event->type() == QEvent::LanguageChange) 28 | ui->retranslateUi(this); 29 | } 30 | 31 | void MainWindow::on_toolButton_2_clicked() 32 | { 33 | if (!windowMgckf) 34 | windowMgckf = new MagicKonfug; 35 | windowMgckf->show(); 36 | } 37 | 38 | void MainWindow::on_comboBox_currentIndexChanged(int index) 39 | { 40 | appTranslator.load(QString(":/Translations/SuperPanda_") 41 | .append(spanda_language_string[index])); 42 | } 43 | 44 | void MainWindow::on_pushButton_clicked() 45 | { 46 | if (!windowAbout) 47 | windowAbout = new AboutWindow; 48 | windowAbout->show(); 49 | } 50 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class MainWindow; 8 | } 9 | 10 | class MainWindow : public QMainWindow 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit MainWindow(QWidget *parent = 0); 16 | ~MainWindow(); 17 | 18 | protected: 19 | void changeEvent(QEvent* event); 20 | 21 | private slots: 22 | void on_toolButton_2_clicked(); 23 | void on_comboBox_currentIndexChanged(int index); 24 | 25 | void on_pushButton_clicked(); 26 | 27 | private: 28 | Ui::MainWindow *ui; 29 | }; 30 | 31 | #endif // MAINWINDOW_H 32 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Super Panda 15 | 16 | 17 | 18 | :/Icons/Icons/SuperPanda.png:/Icons/Icons/SuperPanda.png 19 | 20 | 21 | 22 | 23 | 0 24 | 25 | 26 | 0 27 | 28 | 29 | 0 30 | 31 | 32 | 0 33 | 34 | 35 | 0 36 | 37 | 38 | 39 | 40 | 41 | 0 42 | 43 | 44 | 0 45 | 46 | 47 | 0 48 | 49 | 50 | 0 51 | 52 | 53 | 0 54 | 55 | 56 | 57 | 58 | 59 | English 60 | 61 | 62 | 63 | 64 | Français 65 | 66 | 67 | 68 | 69 | 简体中文 70 | 71 | 72 | 73 | 74 | 正體中文 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | Qt::Horizontal 83 | 84 | 85 | 86 | 40 87 | 20 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | About SuperPanda 96 | 97 | 98 | 99 | 100 | 101 | 102 | :/Icons/Icons/help.png:/Icons/Icons/help.png 103 | 104 | 105 | true 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | SuperPanda 119 | MagiKonfug 120 | 121 | 122 | 123 | :/Icons/Icons/configure.png:/Icons/Icons/configure.png 124 | 125 | 126 | Qt::ToolButtonTextUnderIcon 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /translation.pri: -------------------------------------------------------------------------------- 1 | isEmpty(QMAKE_LRELEASE) { 2 | win32:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]\lrelease.exe 3 | else:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease 4 | } 5 | 6 | updateqm.input = TRANSLATIONS 7 | updateqm.output = ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.qm 8 | updateqm.commands = $$QMAKE_LRELEASE ${QMAKE_FILE_IN} -qm ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.qm 9 | updateqm.CONFIG += no_link 10 | 11 | QMAKE_EXTRA_COMPILERS += updateqm 12 | 13 | PRE_TARGETDEPS += compiler_updateqm_make_all -------------------------------------------------------------------------------- /translations.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | Translations/SuperPanda_zh_TW.qm 4 | Translations/SuperPanda_zh_CN.qm 5 | Translations/SuperPanda_fr_FR.qm 6 | 7 | 8 | --------------------------------------------------------------------------------