diff --git a/src/Cutter.cpp b/src/Cutter.cpp index 9e1e4cd3..4021876e 100644 --- a/src/Cutter.cpp +++ b/src/Cutter.cpp @@ -2311,3 +2311,4 @@ QList CutterCore::getCutterPlugins() { return plugins; } + diff --git a/src/Cutter.pro b/src/Cutter.pro index 8099632b..67efae93 100644 --- a/src/Cutter.pro +++ b/src/Cutter.pro @@ -220,7 +220,9 @@ SOURCES += \ dialogs/HexdumpRangeDialog.cpp \ common/QtResImporter.cpp \ common/CutterSeekable.cpp \ - common/RefreshDeferrer.cpp + common/RefreshDeferrer.cpp \ + dialogs/WelcomeDialog.cpp + HEADERS += \ Cutter.h \ @@ -324,7 +326,8 @@ HEADERS += \ dialogs/HexdumpRangeDialog.h \ common/QtResImporter.h \ common/CutterSeekable.h \ - common/RefreshDeferrer.h + common/RefreshDeferrer.h \ + dialogs/WelcomeDialog.h FORMS += \ dialogs/AboutDialog.ui \ @@ -382,7 +385,8 @@ FORMS += \ widgets/ColorSchemePrefWidget.ui \ widgets/CutterTreeView.ui \ widgets/ComboQuickFilterView.ui \ - dialogs/HexdumpRangeDialog.ui + dialogs/HexdumpRangeDialog.ui \ + dialogs/WelcomeDialog.ui RESOURCES += \ resources.qrc \ diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index e928d87c..c70a224f 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -166,6 +166,11 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc std::exit(1); } + // check if this is the first execution of Cutter in this computer + // Note: the execution after the preferences benn reset, will be considered as first-execution + if (Config()->isFirstExecution()) { + mainWindow->displayWelcomeDialog(); + } mainWindow->displayNewFileDialog(); } else { // filename specified as positional argument InitialOptions options; diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 56a9e929..1bb4c390 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -42,6 +42,7 @@ #include "common/TempConfig.h" // Dialogs +#include "dialogs/WelcomeDialog.h" #include "dialogs/NewFileDialog.h" #include "dialogs/InitialOptionsDialog.h" #include "dialogs/SaveProjectDialog.h" @@ -335,6 +336,19 @@ void MainWindow::openNewFileFailed() mb.exec(); } +/*! + * \brief displays the WelocmeDialog + * + * Upon first execution of Cutter, the WelcomeDialog would be showed to the user. + * The Welcome dialog would be showed after a reset of Cutter's preferences by the user. + */ + +void MainWindow::displayWelcomeDialog() +{ + WelcomeDialog w; + w.exec(); +} + void MainWindow::displayNewFileDialog() { NewFileDialog *n = new NewFileDialog(); diff --git a/src/MainWindow.h b/src/MainWindow.h index c2c962e8..d288facf 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -11,6 +11,7 @@ #include "widgets/HexdumpWidget.h" #include "widgets/PseudocodeWidget.h" #include "dialogs/NewFileDialog.h" +#include "dialogs/WelcomeDialog.h" #include "common/Configuration.h" #include "common/InitialOptions.h" @@ -70,6 +71,7 @@ public: void openNewFile(InitialOptions options = InitialOptions(), bool skipOptionsDialog = false); void displayNewFileDialog(); + void displayWelcomeDialog(); void closeNewFileDialog(); void openProject(const QString &project_name); diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 90a9ba62..d06b81de 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -115,16 +115,41 @@ void Configuration::resetAll() emit fontsUpdated(); } +/*! + * \brief get the current Locale set in Cutter's user configuration + * \return a QLocale object describes user's current locale + */ QLocale Configuration::getCurrLocale() const { return s.value("locale", QLocale().system()).toLocale(); } +/*! + * \brief sets Cutter's locale + * \param l - a QLocale object describes the locate to confugre + */ void Configuration::setLocale(const QLocale &l) { s.setValue("locale", l); } +/*! + * \brief set Cutter's interface language by a given locale name + * \param language - a string represents the name of a locale language + */ +void Configuration::setLocaleByName(const QString &language) +{ + auto allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, + QLocale::AnyCountry); + + for (auto &it : allLocales) { + if (QString::compare(it.nativeLanguageName(), language, Qt::CaseInsensitive) == 0) { + setLocale(it); + break; + } + } +} + bool Configuration::windowColorIsDark() { ColorFlags currentThemeColorFlags = getCurrentTheme()->flag; @@ -422,3 +447,48 @@ void Configuration::setConfig(const QString &key, const QVariant &value) Core()->setConfig(key, value); } + +/*! + * \brief this function will gather and return available translation for Cutter + * \return a list of all available translations + */ +QStringList Configuration::getAvailableTranslations() +{ + QDir dir(QCoreApplication::applicationDirPath() + QDir::separator() + + "translations"); + QStringList fileNames = dir.entryList(QStringList("cutter_*.qm"), QDir::Files, + QDir::Name); + QStringList languages; + QString currLanguageName; + auto allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, + QLocale::AnyCountry); + + for (auto i : fileNames) { + QString localeName = i.mid(sizeof("cutter_") - 1, 2); + for (auto j : allLocales) { + if (j.name().startsWith(localeName)) { + currLanguageName = j.nativeLanguageName(); + currLanguageName = currLanguageName.at(0).toUpper() + + currLanguageName.right(currLanguageName.length() - 1); + languages << currLanguageName; + break; + } + } + } + return languages << "English"; +} + +/*! + * \brief check if this is the first time Cutter's is executed on this computer + * \return true if this is first execution; otherwise returns false. + */ +bool Configuration::isFirstExecution() +{ + // check if a variable named firstExecution existed in the configuration + if (s.contains("firstExecution")) { + return false; + } else { + s.setValue("firstExecution", false); + return true; + } +} diff --git a/src/common/Configuration.h b/src/common/Configuration.h index 22b9c478..4cb95b53 100644 --- a/src/common/Configuration.h +++ b/src/common/Configuration.h @@ -50,6 +50,8 @@ public: // Languages QLocale getCurrLocale() const; void setLocale(const QLocale &l); + void setLocaleByName(const QString &language); + QStringList getAvailableTranslations(); // Fonts const QFont getFont() const; @@ -104,6 +106,8 @@ public: * \brief Set the value of a config var either to r2 or settings, depending on the key. */ void setConfig(const QString &key, const QVariant &value); + bool isFirstExecution(); + signals: void fontsUpdated(); diff --git a/src/dialogs/NewfileDialog.ui b/src/dialogs/NewfileDialog.ui index 45e1bd4e..daf2e938 100755 --- a/src/dialogs/NewfileDialog.ui +++ b/src/dialogs/NewfileDialog.ui @@ -10,6 +10,12 @@ 599 + + + 0 + 0 + + Open File @@ -138,7 +144,6 @@ 0 - Open File @@ -313,13 +318,11 @@ - Open Shellcode - @@ -333,7 +336,6 @@ - @@ -344,7 +346,6 @@ - @@ -352,10 +353,10 @@ Qt::Horizontal - + - 40 - 20 + 0 + 0 @@ -369,10 +370,8 @@ - - > - + Projects @@ -517,7 +516,6 @@ - diff --git a/src/dialogs/WelcomeDialog.cpp b/src/dialogs/WelcomeDialog.cpp new file mode 100644 index 00000000..18b4f593 --- /dev/null +++ b/src/dialogs/WelcomeDialog.cpp @@ -0,0 +1,92 @@ +#include "MainWindow.h" +#include "CutterConfig.h" + +#include "common/Helpers.h" +#include "WelcomeDialog.h" +#include "AboutDialog.h" + +#include "ui_WelcomeDialog.h" + +/*! + * \brief Constructs a WelcomeDialog object + * \param parent + */ +WelcomeDialog::WelcomeDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::WelcomeDialog) +{ + ui->setupUi(this); + ui->logoSvgWidget->load(Config()->getLogoFile()); + ui->versionLabel->setText("" + tr("Version ") + CUTTER_VERSION_FULL + ""); + ui->themeComboBox->setCurrentIndex(Config()->getTheme()); + ui->themeComboBox->setFixedWidth(200); + ui->themeComboBox->view()->setFixedWidth(200); + + QStringList langs = Config()->getAvailableTranslations(); + ui->languageComboBox->addItems(langs); + QString curr = Config()->getCurrLocale().nativeLanguageName(); + curr = curr.at(0).toUpper() + curr.right(curr.length() - 1); + if (!langs.contains(curr)) { + curr = "English"; + } + ui->languageComboBox->setCurrentText(curr); + connect(ui->languageComboBox, + static_cast(&QComboBox::currentIndexChanged), + this, + &WelcomeDialog::onLanguageComboBox_currentIndexChanged); + +} + +/*! + * \brief Destroys the WelcomeDialog + */ +WelcomeDialog::~WelcomeDialog() +{ + delete ui; +} + +/*! + * \brief change Cutter's QT Theme as selected by the user + * \param index - a Slot being called after theme's value changes its index + */ +void WelcomeDialog::on_themeComboBox_currentIndexChanged(int index) +{ + Config()->setTheme(index); + + // make sure that Cutter's logo changes its color according to the selected theme + ui->logoSvgWidget->load(Config()->getLogoFile()); +} + +/*! + * \brief change Cutter's interface language as selected by the user + * \param index - a Slot being called after language combo box value changes its index + */ +void WelcomeDialog::onLanguageComboBox_currentIndexChanged(int index) +{ + QString language = ui->languageComboBox->itemText(index).toLower(); + Config()->setLocaleByName(language); + + QMessageBox mb; + mb.setWindowTitle(tr("Language settings")); + mb.setText(tr("Language will be changed after next application start.")); + mb.setIcon(QMessageBox::Information); + mb.setStandardButtons(QMessageBox::Ok); + mb.exec(); +} + +/*! + * \brief show Cutter's About dialog + */ +void WelcomeDialog::on_checkUpdateButton_clicked() +{ + AboutDialog *a = new AboutDialog(this); + a->open(); +} + +/*! + * \brief accept user preferences, close the window and continue Cutter's execution + */ +void WelcomeDialog::on_continueButton_clicked() +{ + accept(); +} diff --git a/src/dialogs/WelcomeDialog.h b/src/dialogs/WelcomeDialog.h new file mode 100644 index 00000000..95ab73e9 --- /dev/null +++ b/src/dialogs/WelcomeDialog.h @@ -0,0 +1,38 @@ +#ifndef WELCOMEDIALOG_H +#define WELCOMEDIALOG_H + +#include + +namespace Ui { + +/*! + * \class WelcomeDialog + * \brief The WelcomeDialog class will show the user the Welcome windows + * upon first execution of Cutter. + * + * Upon first execution of Cutter, the WelcomeDialog would be showed to the user. + * The Welcome dialog would be showed after a reset of Cutter's preferences by the user. + */ + +class WelcomeDialog; +} + +class WelcomeDialog : public QDialog +{ + Q_OBJECT + +public: + explicit WelcomeDialog(QWidget *parent = 0); + ~WelcomeDialog(); + +private slots: + void on_themeComboBox_currentIndexChanged(int index); + void onLanguageComboBox_currentIndexChanged(int index); + void on_checkUpdateButton_clicked(); + void on_continueButton_clicked(); + +private: + Ui::WelcomeDialog *ui; +}; + +#endif // WELCOMEDIALOG_H diff --git a/src/dialogs/WelcomeDialog.ui b/src/dialogs/WelcomeDialog.ui new file mode 100644 index 00000000..5874bbf6 --- /dev/null +++ b/src/dialogs/WelcomeDialog.ui @@ -0,0 +1,364 @@ + + + WelcomeDialog + + + + 0 + 0 + 717 + 452 + + + + + 0 + 0 + + + + Welcome to Cutter + + + true + + + + QLayout::SetDefaultConstraint + + + + + 0 + + + QLayout::SetFixedSize + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + + 88 + 88 + + + + + 88 + 88 + + + + + + + + true + + + + Monospace + 20 + + + + Cutter + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 11 + + + + Version + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + QLayout::SetFixedSize + + + 0 + + + 9 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + About + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + 0 + + + + 160 + 16 + + + + + Native Theme + + + + + Dark Theme + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + QLayout::SetDefaultConstraint + + + 0 + + + 5 + + + + + + 12 + 75 + true + + + + 2 + + + Community + + + + + + + 1 + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Join thousands of reverse engineers in our community:<br /><span style=" font-weight:600;">Twitter:</span> <a href="https://twitter.com/r2gui"><span style=" text-decoration: underline; color:#2980b9;">@r2gui</span></a><br /><span style=" font-weight:600;">Telegram: </span><a href="https://t.me/r2cutter"><span style=" text-decoration: underline; color:#2980b9;">@r2cutter <br /></span></a><span style=" font-weight:600;">IRC: </span>#cutter on <a href="irc.freenode.net"><span style=" text-decoration: underline; color:#2980b9;">irc.freenode.net</span></a></p></body></html> + + + Qt::RichText + + + true + + + true + + + Qt::TextBrowserInteraction + + + + + + + <html><head/><body><p>Want to help us make Cutter even better?<br/>Visit our <a href="https://github.com/radareorg/cutter"><span style=" text-decoration: underline; color:#2980b9;">Github page</span></a> and report bugs or contribute code.</p></body></html> + + + true + + + 20 + + + true + + + Qt::TextBrowserInteraction + + + + + + + Qt::Horizontal + + + + 10 + 20 + + + + + + + + + 12 + 75 + true + + + + Contributing + + + 20 + + + + + + + Qt::Horizontal + + + + 10 + 20 + + + + + + + + Continue 🢒 + + + true + + + + + + + + + + QSvgWidget + QWidget +
QSvgWidget
+ 1 +
+
+ + +
diff --git a/src/dialogs/preferences/AppearanceOptionsWidget.cpp b/src/dialogs/preferences/AppearanceOptionsWidget.cpp index 76730149..5227965a 100644 --- a/src/dialogs/preferences/AppearanceOptionsWidget.cpp +++ b/src/dialogs/preferences/AppearanceOptionsWidget.cpp @@ -30,34 +30,6 @@ static const QHash kRelevantSchemes = { { "white", LightFlag } }; -QStringList findLanguages() -{ - QDir dir(QCoreApplication::applicationDirPath() + QDir::separator() + - "translations"); - QStringList fileNames = dir.entryList(QStringList("cutter_*.qm"), QDir::Files, - QDir::Name); - QStringList languages; - QString currLanguageName; - auto allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, - QLocale::AnyCountry); - - for (auto i : fileNames) { - QString localeName = i.mid(sizeof("cutter_") - 1, 2); - for (auto j : allLocales) { - if (j.name().startsWith(localeName)) { - currLanguageName = j.nativeLanguageName(); - currLanguageName = currLanguageName.at(0).toUpper() + - currLanguageName.right(currLanguageName.length() - 1); - languages << currLanguageName; - break; - } - } - } - - return languages << "English"; -} - - AppearanceOptionsWidget::AppearanceOptionsWidget(PreferencesDialog *dialog, QWidget *parent) : QDialog(parent), ui(new Ui::AppearanceOptionsWidget) @@ -68,7 +40,7 @@ AppearanceOptionsWidget::AppearanceOptionsWidget(PreferencesDialog *dialog, QWid updateFontFromConfig(); updateThemeFromConfig(false); - QStringList langs = findLanguages(); + QStringList langs = Config()->getAvailableTranslations(); ui->languageComboBox->addItems(langs); QString curr = Config()->getCurrLocale().nativeLanguageName(); @@ -213,15 +185,7 @@ void AppearanceOptionsWidget::on_deleteButton_clicked() void AppearanceOptionsWidget::onLanguageComboBoxCurrentIndexChanged(int index) { QString language = ui->languageComboBox->itemText(index).toLower(); - auto allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, - QLocale::AnyCountry); - - for (auto &it : allLocales) { - if (it.nativeLanguageName().toLower() == language) { - Config()->setLocale(it); - break; - } - } + Config()->setLocaleByName(language); QMessageBox mb; mb.setWindowTitle(tr("Language settings"));