diff options
author | Eike Ziller <eike.ziller@qt.io> | 2019-09-27 14:22:41 +0200 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2019-09-27 14:22:41 +0200 |
commit | 68d08c162a8d191e7777aefc84f4401b5fb70aeb (patch) | |
tree | 3bfd7a29374b96a4e0a815c39506b9063996c10a | |
parent | 642be639919dbb92d9248dfd635ecbed9a0bb726 (diff) | |
parent | d4c0f9e5103056cb9e7d6a4affbd6000b39e98e5 (diff) | |
download | qt-creator-68d08c162a8d191e7777aefc84f4401b5fb70aeb.tar.gz |
Merge remote-tracking branch 'origin/4.11'
Change-Id: I3fd1723e8c097bf6df8933c122fcc006ad0af9e7
47 files changed, 1423 insertions, 1284 deletions
diff --git a/share/qtcreator/translations/qtcreator_ru.ts b/share/qtcreator/translations/qtcreator_ru.ts index 5bffaae635..16a28c2f65 100644 --- a/share/qtcreator/translations/qtcreator_ru.ts +++ b/share/qtcreator/translations/qtcreator_ru.ts @@ -131,11 +131,70 @@ </message> </context> <context> + <name>AnchorButtons</name> + <message> + <source>Anchor item to the top.</source> + <translation>Привязка элемента к верхнему краю.</translation> + </message> + <message> + <source>Anchor item to the bottom.</source> + <translation>Привязка элемента к нижнему краю.</translation> + </message> + <message> + <source>Anchor item to the left.</source> + <translation>Привязка элемента к левому краю.</translation> + </message> + <message> + <source>Anchor item to the right.</source> + <translation>Привязка элемента к правому краю.</translation> + </message> + <message> + <source>Fill parent item.</source> + <translation>Заполнить родительский элемент.</translation> + </message> + <message> + <source>Anchor item vertically.</source> + <translation>Вертикальная привязка элемента.</translation> + </message> + <message> + <source>Anchor item horizontally.</source> + <translation>Горизонтальная привязка элемента.</translation> + </message> +</context> +<context> <name>AnchorRow</name> <message> <source>Target</source> <translation>Цель</translation> </message> + <message> + <source>Margin</source> + <translation>Внешний отступ</translation> + </message> + <message> + <source>Anchor to the top of the target.</source> + <translation>Привязка к верхнему краю цели.</translation> + </message> + <message> + <source>Anchor to the left of the target.</source> + <translation>Привязка к левому краю цели.</translation> + </message> + <message> + <source>Anchor to the vertical center of the target.</source> + <translation>Привязка к вертикальному центру цели.</translation> + </message> + <message> + <source>Anchor to the horizontal center of the target.</source> + <translation>Привязка к горизонтальному центру цели.</translation> + </message> + <message> + <source>Anchor to the bottom of the target.</source> + <translation>Привязка к нижнему краю цели.</translation> + </message> + <message> + <source>Anchor to the right of the target.</source> + <translation>Привязка к правому краю цели.</translation> + </message> </context> <context> <name>Android::AndroidBuildApkStep</name> @@ -1903,7 +1962,7 @@ Install an SDK of at least API version %1.</source> </message> <message> <source>%1 tests passed.</source> - <translation>%1 тестов прошли успешно.</translation> + <translation>%1 тестов прошло успешно.</translation> </message> <message> <source>No errors detected.</source> @@ -3241,7 +3300,7 @@ Warning: this is an experimental feature and might lead to failing to execute th </message> <message> <source>The kit has a Qt version, but no C++ compiler.</source> - <translation>У комплекта задан профил Qt, но нет компилятора C++.</translation> + <translation>У комплекта задан профиль Qt, но нет компилятора C++.</translation> </message> <message> <source>Name:</source> @@ -4476,7 +4535,7 @@ For example, "Revision: 15" will leave the branch at revision 15.</sou </message> <message> <source>A seed of 0 means no randomization. A value of 1 uses the current time any other value is used as random seed generator.</source> - <translation>0 отключает случайный порядок. Значение 1 использует текущее время, любой другое используется для генерации случайной последовательности.</translation> + <translation>0 отключает случайный порядок. Значение 1 использует текущее время, любое другое используется для генерации случайной последовательности.</translation> </message> <message> <source>Catch or ignore system errors.</source> @@ -7117,6 +7176,10 @@ p, li { white-space: pre-wrap; } <translation>Недавний</translation> </message> <message> + <source>Open Color Dialog</source> + <translation>Открыть выбор цвета</translation> + </message> + <message> <source>Defines the start angle for the conical gradient. The value is in degrees (0-360).</source> <translation>Определяет начальный угол для конического градиента. Значение в градусах от 0 до 360.</translation> </message> @@ -9120,11 +9183,11 @@ Do you want to kill it?</source> </message> <message> <source>Cycle Mode Selector Styles</source> - <translation type="unfinished">Зациклить стили режима выбора</translation> + <translation>Зациклить стили режима выбора</translation> </message> <message> <source>Mode Selector Style</source> - <translation type="unfinished">Стиль режима выбора</translation> + <translation>Стиль режима выбора</translation> </message> <message> <source>Icons and Text</source> @@ -16270,7 +16333,7 @@ You can choose another communication channel here, such as a serial line or cust </message> <message> <source>Creation Time in ms</source> - <translation>Время создания в мс</translation> + <translation>Время создания, мс</translation> </message> <message> <source><empty></source> @@ -17359,7 +17422,7 @@ Rebuilding the project might help.</source> </message> <message> <source>Drag Margin</source> - <translation>Поле перетаскивания</translation> + <translation>Зона перетаскивания</translation> </message> <message> <source>Defines the distance from the screen edge within which drag actions will open the drawer.</source> @@ -18418,6 +18481,10 @@ will also disable the following plugins: <translation>Определяет, будет ли Flickable создавать ощущение, что края у вида мягкие, а не жесткие физические границы.</translation> </message> <message> + <source>Describes whether the user can interact with the Flickable. A user cannot drag or flick a Flickable that is not interactive.</source> + <translation>Определяет, может ли пользователь влиять на Flickable. Пользователь не может перетягивать или сдвигать Flickable, если он не интерактивен.</translation> + </message> + <message> <source>Press delay</source> <translation>Задержка нажатия</translation> </message> @@ -18443,7 +18510,7 @@ will also disable the following plugins: </message> <message> <source>Margins</source> - <translation>Отступы</translation> + <translation>Внешние отступы</translation> </message> <message> <source>Flick direction</source> @@ -20499,7 +20566,7 @@ Commit now?</source> </message> <message> <source>DCommit</source> - <translation type="unfinished">Дельта фиксация (dcommit)</translation> + <translation>Дельта фиксация (dcommit)</translation> </message> <message> <source>Manage Remotes...</source> @@ -23443,7 +23510,7 @@ Error: %5</translation> </message> <message> <source>Margins</source> - <translation>Отступы</translation> + <translation>Внешние отступы</translation> </message> <message> <source>Row span</source> @@ -23954,7 +24021,7 @@ Error: %5</translation> <name>MarginSection</name> <message> <source>Margin</source> - <translation>Поле</translation> + <translation>Внешний отступ</translation> </message> <message> <source>Vertical</source> @@ -23998,7 +24065,7 @@ Error: %5</translation> </message> <message> <source>Margins</source> - <translation>Отступы</translation> + <translation>Внешние отступы</translation> </message> <message> <source>The margins around the item.</source> @@ -25088,7 +25155,7 @@ Error: %5</translation> </message> <message> <source>Drag margin</source> - <translation>Перетаскиваемый край</translation> + <translation>Зона перетаскивания</translation> </message> <message> <source>Flick deceleration</source> @@ -25795,12 +25862,12 @@ Error: %5</translation> </message> <message> <source>Self Samples</source> - <translation type="unfinished">Собственных семплов</translation> + <translation>Собственных семплов</translation> </message> <message> <source>Self in Percent</source> <translatorcomment>х.з. как переводить</translatorcomment> - <translation type="unfinished">Собственное в процентах</translation> + <translation>Собственное в процентах</translation> </message> </context> <context> @@ -26741,7 +26808,7 @@ Error: %5</translation> </message> <message> <source>Build/Deployment canceled</source> - <translation>Сборка/разворачивание отменено</translation> + <translation>Сборка/развёртывание отменено</translation> </message> <message> <source>When executing step "%1"</source> @@ -26754,7 +26821,7 @@ Error: %5</translation> <message> <source>Deployment</source> <comment>Category for deployment issues listed under 'Issues'</comment> - <translation>Разворачивание</translation> + <translation>Развёртывание</translation> </message> <message> <source>Autotests</source> @@ -26763,11 +26830,11 @@ Error: %5</translation> </message> <message> <source>Canceled build/deployment.</source> - <translation>Сборка/разворачивание было отменено.</translation> + <translation>Сборка/развёртывание было отменено.</translation> </message> <message> <source>Error while building/deploying project %1 (kit: %2)</source> - <translation>Ошибка при сборке/разворачивании проекта %1 (комплект: %2)</translation> + <translation>Ошибка при сборке/развёртывании проекта %1 (комплект: %2)</translation> </message> <message> <source>The kit %1 has configuration issues which might be the root cause for this problem.</source> @@ -27022,21 +27089,21 @@ Error: %5</translation> <message> <source>Deploy</source> <extracomment>Display name of the deploy build step list. Used as part of the labels in the project window.</extracomment> - <translation>Разваорачивание</translation> + <translation>Развёртывание</translation> </message> <message> <source>Deploy locally</source> <extracomment>Default DeployConfiguration display name</extracomment> - <translation>Локальное разворачивание</translation> + <translation>Локальное развёртывание</translation> </message> <message> <source>Deploy Configuration</source> <extracomment>Display name of the default deploy configuration</extracomment> - <translation>Конфигурация разворачивания</translation> + <translation>Конфигурация развёртывания</translation> </message> <message> <source>Deploy Settings</source> - <translation>Настройки разворачивания</translation> + <translation>Настройки развёртывания</translation> </message> </context> <context> @@ -27054,7 +27121,7 @@ Error: %5</translation> <name>ProjectExplorer::DeploymentDataView</name> <message> <source>Files to deploy:</source> - <translation>Разворачиваемые файлы:</translation> + <translation>Файлы для развёртывания:</translation> </message> </context> <context> @@ -27360,11 +27427,11 @@ Error: %5</translation> </message> <message> <source>Append Path...</source> - <translation type="unfinished">Добавить после пути...</translation> + <translation>Добавить после пути...</translation> </message> <message> <source>Prepend Path...</source> - <translation type="unfinished">Добавить перед путём...</translation> + <translation>Добавить перед путём...</translation> </message> <message> <source>&Batch Edit...</source> @@ -27987,7 +28054,7 @@ Excluding: %2 </message> <message> <source>Synchronize active kit, build, and deploy configuration between projects.</source> - <translation>Сихронизировать у проектов текущий комплект и конфигурации сборки и разворачивания.</translation> + <translation>Сихронизировать у проектов текущий комплект и конфигурации сборки и развёртывания.</translation> </message> </context> <context> @@ -28492,7 +28559,7 @@ What should Qt Creator do now?</source> </message> <message> <source>Deploy</source> - <translation>Разворачивание</translation> + <translation>Развёртывание</translation> </message> <message> <source>Run</source> @@ -28520,7 +28587,7 @@ What should Qt Creator do now?</source> </message> <message> <source><b>Deploy:</b> %1</source> - <translation><b>Разворачивание:</b> %1</translation> + <translation><b>Развёртывание:</b> %1</translation> </message> <message> <source><b>Run:</b> %1</source> @@ -28544,7 +28611,7 @@ What should Qt Creator do now?</source> </message> <message> <source>Deploy: <b>%1</b><br/></source> - <translation>Разворачивание: <b>%1</b><br/></translation> + <translation>Развёртывание: <b>%1</b><br/></translation> </message> <message> <source>Run: <b>%1</b><br/></source> @@ -28687,11 +28754,11 @@ What should Qt Creator do now?</source> </message> <message> <source>Always build project before deploying it</source> - <translation>Всегда собирать проект перед разворачиванием</translation> + <translation>Всегда собирать проект перед развёртыванием</translation> </message> <message> <source>Always deploy project before running it</source> - <translation>Всегда разворачивать проект перед запуском</translation> + <translation>Всегда развёртывать проект перед запуском</translation> </message> <message> <source>Always ask before stopping applications</source> @@ -29053,7 +29120,7 @@ to project "%2".</source> </message> <message> <source>Deployment</source> - <translation>Разворачивание</translation> + <translation>Развёртывание</translation> </message> <message> <source>Method:</source> @@ -29082,7 +29149,7 @@ to project "%2".</source> </message> <message> <source>Cancel Build && Remove Deploy Configuration</source> - <translation>Отменить сборку и удалить конфигурацию разворачивания</translation> + <translation>Отменить сборку и удалить конфигурацию развёртывания</translation> </message> <message> <source>Do Not Remove</source> @@ -29090,27 +29157,27 @@ to project "%2".</source> </message> <message> <source>Remove Deploy Configuration %1?</source> - <translation>Удаление конфигурации разворачивания %1</translation> + <translation>Удаление конфигурации развёртывания %1</translation> </message> <message> <source>The deploy configuration <b>%1</b> is currently being built.</source> - <translation>В данный момент идёт сборка с использованием конфигурации разворачивания <b>%1</b>.</translation> + <translation>В данный момент идёт сборка с использованием конфигурации развёртывания <b>%1</b>.</translation> </message> <message> <source>Do you want to cancel the build process and remove the Deploy Configuration anyway?</source> - <translation>Остановить процесс сборки и удалить конфигурацию разворачивания?</translation> + <translation>Остановить процесс сборки и удалить конфигурацию развёртывания?</translation> </message> <message> <source>Remove Deploy Configuration?</source> - <translation>Удаление конфигурации разворачивания</translation> + <translation>Удаление конфигурации развёртывания</translation> </message> <message> <source>Do you really want to delete deploy configuration <b>%1</b>?</source> - <translation>Желаете удалить конфигурацию разворачивания <b>%1</b>?</translation> + <translation>Желаете удалить конфигурацию развёртывания <b>%1</b>?</translation> </message> <message> <source>New name for deploy configuration <b>%1</b>:</source> - <translation>Новое название конфигурации разворачивания <b>%1</b>:</translation> + <translation>Новое название конфигурации развёртывания <b>%1</b>:</translation> </message> </context> <context> @@ -30027,7 +30094,7 @@ to project "%2".</source> </message> <message> <source>QML File (Qt Quick 2)</source> - <translation>Файл QML (Qt Quck 2)</translation> + <translation>Файл QML (Qt Quick 2)</translation> </message> <message> <source>Creates a scratch buffer using a temporary file.</source> @@ -31178,7 +31245,7 @@ Please close all running instances of your application before starting a build.< </message> <message> <source>Deploy configurations:</source> - <translation>Конфигурации разворачивания:</translation> + <translation>Конфигурации развёртывания:</translation> </message> <message> <source>Run configurations:</source> @@ -31581,7 +31648,7 @@ Rename %2 to %3 anyway?</source> </message> <message> <source>Run Without Deployment</source> - <translation>Запустить без разворачивания</translation> + <translation>Запустить без развёртывания</translation> </message> <message> <source>New Subproject...</source> @@ -33828,7 +33895,7 @@ Neither the path to the library nor the path to its includes is added to the .pr </message> <message> <source>Qmake has subtle bugs that can be triggered if source and build directory are not at the same level.</source> - <translation>Qmake содержит ошибку, возникающую при нахождении каталогов сборки и исходников на разных уровнях.</translation> + <translation>Qmake содержит ошибку, которая может проявляться, если каталоги сборки и исходников находятся на разных уровнях.</translation> </message> <message> <source>Run qmake on every build</source> @@ -38341,7 +38408,7 @@ Saving failed.</source> <name>Qnx::Internal::QnxDeployQtLibrariesDialog</name> <message> <source>Qt library to deploy:</source> - <translation>Разворачиваемая Qt:</translation> + <translation>Библиотека Qt для развёртывания:</translation> </message> <message> <source>Deploy</source> @@ -38766,6 +38833,10 @@ For more details, see /etc/sysctl.d/10-ptrace.conf <translation>Тип</translation> </message> <message> + <source>Change the type of this item.</source> + <translation>Меняет тип этого элемента.</translation> + </message> + <message> <source>id</source> <translation>идентификатор</translation> </message> @@ -42948,7 +43019,7 @@ Specifies how backspace interacts with indentation. </message> <message> <source>Timeout in ms:</source> - <translation>Таймаут в мс:</translation> + <translation>Таймаут, мс:</translation> </message> <message> <source>Inserts the common prefix of available completion items.</source> @@ -47925,7 +47996,7 @@ What do you want to do?</source> </message> <message> <source>Multi-paradigm language for creating highly dynamic applications.</source> - <translation>Многопарадигмый язый для создания высокодинамичных приложений.</translation> + <translation>Мультипарадигменный язык для создания высокодинамичных приложений.</translation> </message> <message> <source>Run your concepts and prototypes on your final hardware.</source> diff --git a/src/libs/utils/touchbar/touchbar_mac.mm b/src/libs/utils/touchbar/touchbar_mac.mm index ee5a45bf72..dfaf670087 100644 --- a/src/libs/utils/touchbar/touchbar_mac.mm +++ b/src/libs/utils/touchbar/touchbar_mac.mm @@ -177,7 +177,7 @@ static NSImage *iconToTemplateNSImage(const QIcon &icon) { self = [super init]; [self setButtonType:NSButtonTypeMomentaryPushIn]; - self.bezelStyle = NSRoundedBezelStyle; + self.bezelStyle = NSBezelStyleRounded; self.target = self; self.action = @selector(trigger:); _qaction = qaction; @@ -208,7 +208,7 @@ static NSImage *iconToTemplateNSImage(const QIcon &icon) { self = [super init]; [self setButtonType:NSButtonTypeMomentaryPushIn]; - self.bezelStyle = NSRoundedBezelStyle; + self.bezelStyle = NSBezelStyleRounded; self.target = self; self.action = @selector(trigger:); _parent = parent; diff --git a/src/plugins/clangtools/CMakeLists.txt b/src/plugins/clangtools/CMakeLists.txt index 93195bdfb9..f5f2c2a84c 100644 --- a/src/plugins/clangtools/CMakeLists.txt +++ b/src/plugins/clangtools/CMakeLists.txt @@ -14,7 +14,6 @@ add_qtc_plugin(ClangTools clangfixitsrefactoringchanges.cpp clangfixitsrefactoringchanges.h clangselectablefilesdialog.cpp clangselectablefilesdialog.h clangselectablefilesdialog.ui clangtidyclazyrunner.cpp clangtidyclazyrunner.h - clangtidyclazytool.cpp clangtidyclazytool.h clangtool.cpp clangtool.h clangtoolruncontrol.cpp clangtoolruncontrol.h clangtoolrunner.cpp clangtoolrunner.h @@ -29,6 +28,7 @@ add_qtc_plugin(ClangTools clangtoolsprojectsettingswidget.cpp clangtoolsprojectsettingswidget.h clangtoolsprojectsettingswidget.ui clangtoolssettings.cpp clangtoolssettings.h clangtoolsutils.cpp clangtoolsutils.h + runsettingswidget.cpp runsettingswidget.h runsettingswidget.ui settingswidget.cpp settingswidget.h settingswidget.ui ) diff --git a/src/plugins/clangtools/clangselectablefilesdialog.cpp b/src/plugins/clangtools/clangselectablefilesdialog.cpp index c9fce5552f..6541ca46bc 100644 --- a/src/plugins/clangtools/clangselectablefilesdialog.cpp +++ b/src/plugins/clangtools/clangselectablefilesdialog.cpp @@ -266,16 +266,6 @@ private: } }; -enum { GlobalSettings , CustomSettings }; - -static Core::Id diagnosticConfiguration(ClangToolsProjectSettings *settings) -{ - Core::Id id = settings->diagnosticConfig(); - if (id.isValid()) - return id; - return ClangToolsSettings::instance()->savedDiagnosticConfigId(); -} - SelectableFilesDialog::SelectableFilesDialog(const ProjectInfo &projectInfo, const FileInfos &allFileInfos) : QDialog(nullptr) @@ -292,36 +282,7 @@ SelectableFilesDialog::SelectableFilesDialog(const ProjectInfo &projectInfo, m_ui->buttons->setStandardButtons(QDialogButtonBox::Cancel); m_ui->buttons->addButton(m_analyzeButton, QDialogButtonBox::AcceptRole); - CppTools::ClangDiagnosticConfigsSelectionWidget *diagnosticWidget = m_ui->diagnosticWidget; - ClangToolsProjectSettings *settings = ClangToolsProjectSettingsManager::getSettings(m_project); - m_customDiagnosticConfig = diagnosticConfiguration(settings); - - if (settings->useGlobalSettings()) { - m_ui->globalOrCustom->setCurrentIndex(GlobalSettings); - diagnosticWidget->refresh(ClangToolsSettings::instance()->savedDiagnosticConfigId()); - diagnosticWidget->setEnabled(false); - } else { - m_ui->globalOrCustom->setCurrentIndex(CustomSettings); - diagnosticWidget->refresh(m_customDiagnosticConfig); - diagnosticWidget->setEnabled(true); - } - - connect(m_ui->globalOrCustom, - QOverload<int>::of(&QComboBox::currentIndexChanged), - [=](int index){ - diagnosticWidget->setEnabled(index == CustomSettings); - if (index == CustomSettings) - diagnosticWidget->refresh(m_customDiagnosticConfig); - else - diagnosticWidget->refresh(ClangToolsSettings::instance()->savedDiagnosticConfigId()); - }); - connect(diagnosticWidget, - &ClangDiagnosticConfigsSelectionWidget::currentConfigChanged, - [this](const Core::Id ¤tConfigId) { - if (m_ui->globalOrCustom->currentIndex() == CustomSettings) - m_customDiagnosticConfig = currentConfigId; - }); // Restore selection if (settings->selectedDirs().isEmpty() && settings->selectedFiles().isEmpty()) @@ -333,16 +294,6 @@ SelectableFilesDialog::SelectableFilesDialog(const ProjectInfo &projectInfo, connect(m_filesModel.get(), &QAbstractItemModel::dataChanged, [this]() { m_analyzeButton->setEnabled(m_filesModel->hasCheckedFiles()); }); - - connect(CppTools::codeModelSettings().data(), &CppTools::CppCodeModelSettings::changed, - this, [=]() { - if (m_ui->globalOrCustom->currentIndex() == CustomSettings) { - diagnosticWidget->refresh(m_customDiagnosticConfig); - } else { - diagnosticWidget->refresh( - ClangToolsSettings::instance()->savedDiagnosticConfigId()); - } - }); } SelectableFilesDialog::~SelectableFilesDialog() = default; @@ -356,11 +307,6 @@ void SelectableFilesDialog::accept() { ClangToolsProjectSettings *settings = ClangToolsProjectSettingsManager::getSettings(m_project); - // Save diagnostic configuration - settings->setUseGlobalSettings(m_ui->globalOrCustom->currentIndex() == GlobalSettings); - settings->setDiagnosticConfig(m_customDiagnosticConfig); - - // Save file selection QSet<FilePath> checkedDirs; QSet<FilePath> checkedFiles; m_filesModel->minimalSelection(checkedDirs, checkedFiles); diff --git a/src/plugins/clangtools/clangselectablefilesdialog.ui b/src/plugins/clangtools/clangselectablefilesdialog.ui index 267b36364a..834f3fc189 100644 --- a/src/plugins/clangtools/clangselectablefilesdialog.ui +++ b/src/plugins/clangtools/clangselectablefilesdialog.ui @@ -11,66 +11,14 @@ </rect> </property> <property name="windowTitle"> - <string>Analyzer Configuration</string> + <string>Files to Analyze</string> </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QGroupBox" name="groupBox_3"> - <property name="title"> - <string>General</string> + <widget class="QTreeView" name="filesView"> + <property name="headerHidden"> + <bool>true</bool> </property> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QComboBox" name="globalOrCustom"> - <item> - <property name="text"> - <string>Global Settings</string> - </property> - </item> - <item> - <property name="text"> - <string>Custom Settings</string> - </property> - </item> - </widget> - </item> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item> - <widget class="CppTools::ClangDiagnosticConfigsSelectionWidget" name="diagnosticWidget" native="true"/> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="groupBox_2"> - <property name="title"> - <string>Files to Analyze</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <widget class="QTreeView" name="filesView"> - <property name="headerHidden"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> </widget> </item> <item> @@ -85,13 +33,6 @@ </item> </layout> </widget> - <customwidgets> - <customwidget> - <class>CppTools::ClangDiagnosticConfigsSelectionWidget</class> - <extends>QWidget</extends> - <header>cpptools/clangdiagnosticconfigsselectionwidget.h</header> - </customwidget> - </customwidgets> <resources/> <connections> <connection> diff --git a/src/plugins/clangtools/clangtidyclazytool.cpp b/src/plugins/clangtools/clangtidyclazytool.cpp deleted file mode 100644 index 85be64da49..0000000000 --- a/src/plugins/clangtools/clangtidyclazytool.cpp +++ /dev/null @@ -1,569 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "clangtidyclazytool.h" - -#include "clangfixitsrefactoringchanges.h" -#include "clangselectablefilesdialog.h" -#include "clangtoolruncontrol.h" -#include "clangtoolsconstants.h" -#include "clangtoolsdiagnosticmodel.h" -#include "clangtoolslogfilereader.h" -#include "clangtoolsdiagnosticview.h" -#include "clangtoolsprojectsettings.h" -#include "clangtoolssettings.h" - -#include <coreplugin/actionmanager/actioncontainer.h> -#include <coreplugin/actionmanager/actionmanager.h> -#include <coreplugin/icore.h> -#include <coreplugin/messagebox.h> - -#include <cpptools/clangdiagnosticconfigsmodel.h> -#include <cpptools/cppcodemodelsettings.h> -#include <cpptools/cppmodelmanager.h> -#include <cpptools/cpptoolsreuse.h> - -#include <debugger/analyzer/analyzermanager.h> - -#include <projectexplorer/kitinformation.h> -#include <projectexplorer/projectexplorer.h> -#include <projectexplorer/projectexplorericons.h> -#include <projectexplorer/target.h> -#include <projectexplorer/session.h> - -#include <utils/fancylineedit.h> -#include <utils/utilsicons.h> - -#include <QAction> -#include <QFileDialog> -#include <QToolButton> - -using namespace Core; -using namespace CppTools; -using namespace Debugger; -using namespace ProjectExplorer; -using namespace Utils; - -namespace ClangTools { -namespace Internal { - -static ClangTidyClazyTool *s_instance; - -class ApplyFixIts -{ -public: - class RefactoringFileInfo - { - public: - bool isValid() const { return file.isValid(); } - - FixitsRefactoringFile file; - QVector<DiagnosticItem *> diagnosticItems; - bool hasScheduledFixits = false; - }; - - ApplyFixIts(const QVector<DiagnosticItem *> &diagnosticItems) - { - for (DiagnosticItem *diagnosticItem : diagnosticItems) { - const QString &filePath = diagnosticItem->diagnostic().location.filePath; - QTC_ASSERT(!filePath.isEmpty(), continue); - - // Get or create refactoring file - RefactoringFileInfo &fileInfo = m_refactoringFileInfos[filePath]; - if (!fileInfo.isValid()) - fileInfo.file = FixitsRefactoringFile(filePath); - - // Append item - fileInfo.diagnosticItems += diagnosticItem; - if (diagnosticItem->fixItStatus() == FixitStatus::Scheduled) - fileInfo.hasScheduledFixits = true; - } - } - - static void addFixitOperations(DiagnosticItem *diagnosticItem, - const FixitsRefactoringFile &file, bool apply) - { - if (!diagnosticItem->hasNewFixIts()) - return; - - // Did we already created the fixit operations? - ReplacementOperations currentOps = diagnosticItem->fixitOperations(); - if (!currentOps.isEmpty()) { - for (ReplacementOperation *op : currentOps) - op->apply = apply; - return; - } - - // Collect/construct the fixit operations - ReplacementOperations replacements; - - for (const ExplainingStep &step : diagnosticItem->diagnostic().explainingSteps) { - if (!step.isFixIt) - continue; - - const Debugger::DiagnosticLocation start = step.ranges.first(); - const Debugger::DiagnosticLocation end = step.ranges.last(); - const int startPos = file.position(start.filePath, start.line, start.column); - const int endPos = file.position(start.filePath, end.line, end.column); - - auto op = new ReplacementOperation; - op->pos = startPos; - op->length = endPos - startPos; - op->text = step.message; - op->fileName = start.filePath; - op->apply = apply; - - replacements += op; - } - - diagnosticItem->setFixitOperations(replacements); - } - - void apply(ClangToolsDiagnosticModel *model) - { - for (auto it = m_refactoringFileInfos.begin(); it != m_refactoringFileInfos.end(); ++it) { - RefactoringFileInfo &fileInfo = it.value(); - - QVector<DiagnosticItem *> itemsScheduledOrSchedulable; - QVector<DiagnosticItem *> itemsScheduled; - QVector<DiagnosticItem *> itemsSchedulable; - - // Construct refactoring operations - for (DiagnosticItem *diagnosticItem : fileInfo.diagnosticItems) { - const FixitStatus fixItStatus = diagnosticItem->fixItStatus(); - - const bool isScheduled = fixItStatus == FixitStatus::Scheduled; - const bool isSchedulable = fileInfo.hasScheduledFixits - && fixItStatus == FixitStatus::NotScheduled; - - if (isScheduled || isSchedulable) { - addFixitOperations(diagnosticItem, fileInfo.file, isScheduled); - itemsScheduledOrSchedulable += diagnosticItem; - if (isScheduled) - itemsScheduled += diagnosticItem; - else - itemsSchedulable += diagnosticItem; - } - } - - // Collect replacements - ReplacementOperations ops; - for (DiagnosticItem *item : itemsScheduledOrSchedulable) - ops += item->fixitOperations(); - - if (ops.empty()) - continue; - - // Apply file - QVector<DiagnosticItem *> itemsApplied; - QVector<DiagnosticItem *> itemsFailedToApply; - QVector<DiagnosticItem *> itemsInvalidated; - - fileInfo.file.setReplacements(ops); - model->removeWatchedPath(ops.first()->fileName); - if (fileInfo.file.apply()) { - itemsApplied = itemsScheduled; - } else { - itemsFailedToApply = itemsScheduled; - itemsInvalidated = itemsSchedulable; - } - model->addWatchedPath(ops.first()->fileName); - - // Update DiagnosticItem state - for (DiagnosticItem *diagnosticItem : itemsScheduled) - diagnosticItem->setFixItStatus(FixitStatus::Applied); - for (DiagnosticItem *diagnosticItem : itemsFailedToApply) - diagnosticItem->setFixItStatus(FixitStatus::FailedToApply); - for (DiagnosticItem *diagnosticItem : itemsInvalidated) - diagnosticItem->setFixItStatus(FixitStatus::Invalidated); - } - } - -private: - QMap<QString, RefactoringFileInfo> m_refactoringFileInfos; -}; - -ClangTidyClazyTool::ClangTidyClazyTool() - : ClangTool("Clang-Tidy and Clazy") -{ - setObjectName("ClangTidyClazyTool"); - s_instance = this; - - m_diagnosticFilterModel = new DiagnosticFilterModel(this); - m_diagnosticFilterModel->setSourceModel(m_diagnosticModel); - m_diagnosticFilterModel->setDynamicSortFilter(true); - - m_diagnosticView = new DiagnosticView; - initDiagnosticView(); - m_diagnosticView->setModel(m_diagnosticFilterModel); - m_diagnosticView->setSortingEnabled(true); - m_diagnosticView->sortByColumn(Debugger::DetailedErrorView::DiagnosticColumn, - Qt::AscendingOrder); - m_diagnosticView->setObjectName(QLatin1String("ClangTidyClazyIssuesView")); - m_diagnosticView->setWindowTitle(tr("Clang-Tidy and Clazy Diagnostics")); - - foreach (auto * const model, - QList<QAbstractItemModel *>({m_diagnosticModel, m_diagnosticFilterModel})) { - connect(model, &QAbstractItemModel::rowsInserted, - this, &ClangTidyClazyTool::handleStateUpdate); - connect(model, &QAbstractItemModel::rowsRemoved, - this, &ClangTidyClazyTool::handleStateUpdate); - connect(model, &QAbstractItemModel::modelReset, - this, &ClangTidyClazyTool::handleStateUpdate); - connect(model, &QAbstractItemModel::layoutChanged, // For QSortFilterProxyModel::invalidate() - this, &ClangTidyClazyTool::handleStateUpdate); - } - - // Go to previous diagnostic - auto action = new QAction(this); - action->setDisabled(true); - action->setIcon(Utils::Icons::PREV_TOOLBAR.icon()); - action->setToolTip(tr("Go to previous diagnostic.")); - connect(action, &QAction::triggered, m_diagnosticView, &DetailedErrorView::goBack); - m_goBack = action; - - // Go to next diagnostic - action = new QAction(this); - action->setDisabled(true); - action->setIcon(Utils::Icons::NEXT_TOOLBAR.icon()); - action->setToolTip(tr("Go to next diagnostic.")); - connect(action, &QAction::triggered, m_diagnosticView, &DetailedErrorView::goNext); - m_goNext = action; - - // Load diagnostics from file - action = new QAction(this); - action->setIcon(Utils::Icons::OPENFILE_TOOLBAR.icon()); - action->setToolTip(tr("Load Diagnostics from YAML Files exported with \"-export-fixes\".")); - connect(action, &QAction::triggered, this, &ClangTidyClazyTool::loadDiagnosticsFromFiles); - m_loadExported = action; - - // Clear data - action = new QAction(this); - action->setDisabled(true); - action->setIcon(Utils::Icons::CLEAN_TOOLBAR.icon()); - action->setToolTip(tr("Clear")); - connect(action, &QAction::triggered, [this](){ - m_clear->setEnabled(false); - m_diagnosticModel->clear(); - Debugger::showPermanentStatusMessage(QString()); - }); - m_clear = action; - - // Expand/Collapse - action = new QAction(this); - action->setDisabled(true); - action->setCheckable(true); - action->setIcon(Utils::Icons::EXPAND_ALL_TOOLBAR.icon()); - action->setToolTip(tr("Expand All")); - connect(action, &QAction::toggled, [this](bool checked){ - if (checked) { - m_expandCollapse->setToolTip(tr("Collapse All")); - m_diagnosticView->expandAll(); - } else { - m_expandCollapse->setToolTip(tr("Expand All")); - m_diagnosticView->collapseAll(); - } - }); - m_expandCollapse = action; - - // Filter line edit - m_filterLineEdit = new Utils::FancyLineEdit(); - m_filterLineEdit->setFiltering(true); - m_filterLineEdit->setPlaceholderText(tr("Filter Diagnostics")); - m_filterLineEdit->setHistoryCompleter("CppTools.ClangTidyClazyIssueFilter", true); - connect(m_filterLineEdit, &Utils::FancyLineEdit::filterChanged, [this](const QString &filter) { - m_diagnosticFilterModel->setFilterRegExp( - QRegExp(filter, Qt::CaseSensitive, QRegExp::WildcardUnix)); - }); - - // Apply fixits button - m_applyFixitsButton = new QToolButton; - m_applyFixitsButton->setText(tr("Apply Fixits")); - m_applyFixitsButton->setEnabled(false); - connect(m_diagnosticModel, - &ClangToolsDiagnosticModel::fixItsToApplyCountChanged, - [this](int c) { - m_applyFixitsButton->setEnabled(c); - static_cast<DiagnosticView *>(m_diagnosticView.data())->setSelectedFixItsCount(c); - }); - connect(m_applyFixitsButton, &QToolButton::clicked, [this]() { - QVector<DiagnosticItem *> diagnosticItems; - m_diagnosticModel->forItemsAtLevel<2>([&](DiagnosticItem *item){ - diagnosticItems += item; - }); - - ApplyFixIts(diagnosticItems).apply(m_diagnosticModel); - }); - - ActionContainer *menu = ActionManager::actionContainer(Debugger::Constants::M_DEBUG_ANALYZER); - const QString toolTip = tr("Clang-Tidy and Clazy use a customized Clang executable from the " - "Clang project to search for diagnostics."); - - m_perspective.addWindow(m_diagnosticView, Perspective::SplitVertical, nullptr); - - action = new QAction(tr("Clang-Tidy and Clazy..."), this); - action->setToolTip(toolTip); - menu->addAction(ActionManager::registerAction(action, "ClangTidyClazy.Action"), - Debugger::Constants::G_ANALYZER_TOOLS); - QObject::connect(action, &QAction::triggered, this, [this]() { - startTool(ClangTidyClazyTool::FileSelection::AskUser); - }); - QObject::connect(m_startAction, &QAction::triggered, action, &QAction::triggered); - QObject::connect(m_startAction, &QAction::changed, action, [action, this] { - action->setEnabled(m_startAction->isEnabled()); - }); - - QObject::connect(m_startOnCurrentFileAction, &QAction::triggered, this, [this] { - startTool(ClangTidyClazyTool::FileSelection::CurrentFile); - }); - - m_perspective.addToolBarAction(m_startAction); - m_perspective.addToolBarAction(m_startOnCurrentFileAction); - m_perspective.addToolBarAction(m_stopAction); - m_perspective.addToolBarAction(m_loadExported); - m_perspective.addToolBarAction(m_clear); - m_perspective.addToolBarAction(m_goBack); - m_perspective.addToolBarAction(m_goNext); - m_perspective.addToolBarAction(m_expandCollapse); - m_perspective.addToolBarWidget(m_filterLineEdit); - m_perspective.addToolBarWidget(m_applyFixitsButton); - - updateRunActions(); - - connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, - this, &ClangTidyClazyTool::updateRunActions); - -} - -ClangTidyClazyTool *ClangTidyClazyTool::instance() -{ - return s_instance; -} - -static ClangDiagnosticConfig getDiagnosticConfig(Project *project) -{ - ClangToolsProjectSettings *projectSettings = ClangToolsProjectSettingsManager::getSettings( - project); - - Core::Id diagnosticConfigId; - if (projectSettings->useGlobalSettings()) - diagnosticConfigId = ClangToolsSettings::instance()->savedDiagnosticConfigId(); - else - diagnosticConfigId = projectSettings->diagnosticConfig(); - - const ClangDiagnosticConfigsModel configsModel( - CppTools::codeModelSettings()->clangCustomDiagnosticConfigs()); - - QTC_ASSERT(configsModel.hasConfigWithId(diagnosticConfigId), return ClangDiagnosticConfig()); - return configsModel.configWithId(diagnosticConfigId); -} - -void ClangTidyClazyTool::startTool(FileSelection fileSelection) -{ - Project *project = SessionManager::startupProject(); - QTC_ASSERT(project, return); - QTC_ASSERT(project->activeTarget(), return); - - auto runControl = new RunControl(Constants::CLANGTIDYCLAZY_RUN_MODE); - runControl->setDisplayName(tr("Clang-Tidy and Clazy")); - runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR); - runControl->setTarget(project->activeTarget()); - - const FileInfos fileInfos = collectFileInfos(project, fileSelection); - if (fileInfos.empty()) - return; - - const bool preventBuild = fileSelection == FileSelection::CurrentFile; - auto clangTool = new ClangToolRunWorker(runControl, - getDiagnosticConfig(project), - fileInfos, - preventBuild); - - m_stopAction->disconnect(); - connect(m_stopAction, &QAction::triggered, runControl, [runControl] { - runControl->appendMessage(tr("Clang-Tidy and Clazy tool stopped by user."), - NormalMessageFormat); - runControl->initiateStop(); - }); - - connect(runControl, &RunControl::stopped, this, [this, clangTool] { - bool success = clangTool->success(); - setToolBusy(false); - m_running = false; - handleStateUpdate(); - updateRunActions(); - emit finished(success); - }); - - m_perspective.select(); - - m_diagnosticModel->clear(); - - setToolBusy(true); - m_diagnosticFilterModel->setProject(project); - m_running = true; - handleStateUpdate(); - updateRunActions(); - - ProjectExplorerPlugin::startRunControl(runControl); -} - -void ClangTidyClazyTool::updateRunActions() -{ - if (m_toolBusy) { - QString tooltipText = tr("Clang-Tidy and Clazy are still running."); - - m_startAction->setEnabled(false); - m_startAction->setToolTip(tooltipText); - - m_startOnCurrentFileAction->setEnabled(false); - m_startOnCurrentFileAction->setToolTip(tooltipText); - - m_stopAction->setEnabled(true); - m_loadExported->setEnabled(false); - m_clear->setEnabled(false); - } else { - QString toolTipStart = m_startAction->text(); - QString toolTipStartOnCurrentFile = m_startOnCurrentFileAction->text(); - - Project *project = SessionManager::startupProject(); - Target *target = project ? project->activeTarget() : nullptr; - const Core::Id cxx = ProjectExplorer::Constants::CXX_LANGUAGE_ID; - bool canRun = target && project->projectLanguages().contains(cxx) - && ToolChainKitAspect::toolChain(target->kit(), cxx); - if (!canRun) - toolTipStart = toolTipStartOnCurrentFile = tr("This is not a C/C++ project."); - - m_startAction->setEnabled(canRun); - m_startAction->setToolTip(toolTipStart); - - m_startOnCurrentFileAction->setEnabled(canRun); - m_startOnCurrentFileAction->setToolTip(toolTipStartOnCurrentFile); - - m_stopAction->setEnabled(false); - m_loadExported->setEnabled(true); - m_clear->setEnabled(m_diagnosticModel->diagnostics().count()); - } -} - -void ClangTidyClazyTool::loadDiagnosticsFromFiles() -{ - // Ask user for files - const QStringList filePaths - = QFileDialog::getOpenFileNames(Core::ICore::mainWindow(), - tr("Select YAML Files with Diagnostics"), - QDir::homePath(), - tr("YAML Files (*.yml *.yaml);;All Files (*)")); - if (filePaths.isEmpty()) - return; - - // Load files - Diagnostics diagnostics; - QString errors; - for (const QString &filePath : filePaths) { - QString currentError; - diagnostics << readExportedDiagnostics(Utils::FilePath::fromString(filePath), - {}, - ¤tError); - - if (!currentError.isEmpty()) { - if (!errors.isEmpty()) - errors.append("\n"); - errors.append(currentError); - } - } - - // Show errors - if (!errors.isEmpty()) - AsynchronousMessageBox::critical(tr("Error Loading Diagnostics"), errors); - - // Show imported - m_diagnosticModel->clear(); - onNewDiagnosticsAvailable(diagnostics); -} - -void ClangTidyClazyTool::handleStateUpdate() -{ - QTC_ASSERT(m_goBack, return); - QTC_ASSERT(m_goNext, return); - QTC_ASSERT(m_diagnosticModel, return); - QTC_ASSERT(m_diagnosticFilterModel, return); - - const int issuesFound = m_diagnosticModel->diagnostics().count(); - const int issuesVisible = m_diagnosticFilterModel->rowCount(); - m_goBack->setEnabled(issuesVisible > 1); - m_goNext->setEnabled(issuesVisible > 1); - m_clear->setEnabled(issuesFound > 0); - m_expandCollapse->setEnabled(issuesVisible); - - m_loadExported->setEnabled(!m_running); - - QString message; - if (m_running) { - if (issuesFound) - message = tr("Running - %n diagnostics", nullptr, issuesFound); - else - message = tr("Running - No diagnostics"); - } else { - if (issuesFound) - message = tr("Finished - %n diagnostics", nullptr, issuesFound); - else - message = tr("Finished - No diagnostics"); - } - - Debugger::showPermanentStatusMessage(message); -} - -Diagnostics ClangTidyClazyTool::read(OutputFileFormat outputFileFormat, - const QString &logFilePath, - const QString &mainFilePath, - const QSet<Utils::FilePath> &projectFiles, - QString *errorMessage) const -{ - const auto acceptFromFilePath = [projectFiles](const Utils::FilePath &filePath) { - return projectFiles.contains(filePath); - }; - - if (outputFileFormat == OutputFileFormat::Yaml) { - return readExportedDiagnostics(Utils::FilePath::fromString(logFilePath), - acceptFromFilePath, - errorMessage); - } - return readSerializedDiagnostics(Utils::FilePath::fromString(logFilePath), - Utils::FilePath::fromString(mainFilePath), - acceptFromFilePath, - errorMessage); -} - -void ClangTidyClazyTool::onNewDiagnosticsAvailable(const Diagnostics &diagnostics) -{ - ClangTool::onNewDiagnosticsAvailable(diagnostics); - if (!m_diagnosticFilterModel->filterRegExp().pattern().isEmpty()) - m_diagnosticFilterModel->invalidateFilter(); -} - -} // namespace Internal -} // namespace ClangTools - diff --git a/src/plugins/clangtools/clangtidyclazytool.h b/src/plugins/clangtools/clangtidyclazytool.h deleted file mode 100644 index be96438117..0000000000 --- a/src/plugins/clangtools/clangtidyclazytool.h +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include "clangtool.h" - -#include <debugger/debuggermainwindow.h> - -QT_BEGIN_NAMESPACE -class QToolButton; -QT_END_NAMESPACE - -namespace Utils { class FancyLineEdit; } - -namespace ClangTools { -namespace Internal { - -class DiagnosticFilterModel; - -const char ClangTidyClazyPerspectiveId[] = "ClangTidyClazy.Perspective"; - -class ClangTidyClazyTool final : public ClangTool -{ - Q_OBJECT - -public: - ClangTidyClazyTool(); - - static ClangTidyClazyTool *instance(); - - void startTool(FileSelection fileSelection) final; - - Diagnostics read(OutputFileFormat outputFileFormat, - const QString &logFilePath, - const QString &mainFilePath, - const QSet<Utils::FilePath> &projectFiles, - QString *errorMessage) const final; - - void onNewDiagnosticsAvailable(const Diagnostics &diagnostics) override; - -private: - void handleStateUpdate() final; - - void updateRunActions(); - void loadDiagnosticsFromFiles(); - - DiagnosticFilterModel *m_diagnosticFilterModel = nullptr; - - Utils::FancyLineEdit *m_filterLineEdit = nullptr; - QToolButton *m_applyFixitsButton = nullptr; - - QAction *m_goBack = nullptr; - QAction *m_goNext = nullptr; - QAction *m_loadExported = nullptr; - QAction *m_clear = nullptr; - QAction *m_expandCollapse = nullptr; - - Utils::Perspective m_perspective{ClangTidyClazyPerspectiveId, tr("Clang-Tidy and Clazy")}; -}; - -} // namespace Internal -} // namespace ClangTools diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index a2ffb83c7b..da9e022b03 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -25,10 +25,16 @@ #include "clangtool.h" +#include "clangfixitsrefactoringchanges.h" #include "clangselectablefilesdialog.h" +#include "clangtoolruncontrol.h" #include "clangtoolsconstants.h" #include "clangtoolsdiagnostic.h" #include "clangtoolsdiagnosticmodel.h" +#include "clangtoolsdiagnosticview.h" +#include "clangtoolslogfilereader.h" +#include "clangtoolsprojectsettings.h" +#include "clangtoolssettings.h" #include "clangtoolsutils.h" #include <coreplugin/actionmanager/actioncontainer.h> @@ -36,6 +42,7 @@ #include <coreplugin/coreconstants.h> #include <coreplugin/editormanager/editormanager.h> #include <coreplugin/icore.h> +#include <coreplugin/messagebox.h> #include <cpptools/cppmodelmanager.h> @@ -44,19 +51,22 @@ #include <projectexplorer/kitinformation.h> #include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorericons.h> -#include <projectexplorer/target.h> #include <projectexplorer/session.h> +#include <projectexplorer/target.h> #include <utils/algorithm.h> +#include <utils/fancylineedit.h> #include <utils/fancymainwindow.h> #include <utils/utilsicons.h> #include <QAction> +#include <QFileDialog> #include <QLabel> #include <QSortFilterProxyModel> #include <QToolButton> using namespace Core; +using namespace CppTools; using namespace Debugger; using namespace ProjectExplorer; using namespace Utils; @@ -64,6 +74,142 @@ using namespace Utils; namespace ClangTools { namespace Internal { +static ClangTool *s_instance; + +class ApplyFixIts +{ +public: + class RefactoringFileInfo + { + public: + bool isValid() const { return file.isValid(); } + + FixitsRefactoringFile file; + QVector<DiagnosticItem *> diagnosticItems; + bool hasScheduledFixits = false; + }; + + ApplyFixIts(const QVector<DiagnosticItem *> &diagnosticItems) + { + for (DiagnosticItem *diagnosticItem : diagnosticItems) { + const QString &filePath = diagnosticItem->diagnostic().location.filePath; + QTC_ASSERT(!filePath.isEmpty(), continue); + + // Get or create refactoring file + RefactoringFileInfo &fileInfo = m_refactoringFileInfos[filePath]; + if (!fileInfo.isValid()) + fileInfo.file = FixitsRefactoringFile(filePath); + + // Append item + fileInfo.diagnosticItems += diagnosticItem; + if (diagnosticItem->fixItStatus() == FixitStatus::Scheduled) + fileInfo.hasScheduledFixits = true; + } + } + + static void addFixitOperations(DiagnosticItem *diagnosticItem, + const FixitsRefactoringFile &file, bool apply) + { + if (!diagnosticItem->hasNewFixIts()) + return; + + // Did we already created the fixit operations? + ReplacementOperations currentOps = diagnosticItem->fixitOperations(); + if (!currentOps.isEmpty()) { + for (ReplacementOperation *op : currentOps) + op->apply = apply; + return; + } + + // Collect/construct the fixit operations + ReplacementOperations replacements; + + for (const ExplainingStep &step : diagnosticItem->diagnostic().explainingSteps) { + if (!step.isFixIt) + continue; + + const Debugger::DiagnosticLocation start = step.ranges.first(); + const Debugger::DiagnosticLocation end = step.ranges.last(); + const int startPos = file.position(start.filePath, start.line, start.column); + const int endPos = file.position(start.filePath, end.line, end.column); + + auto op = new ReplacementOperation; + op->pos = startPos; + op->length = endPos - startPos; + op->text = step.message; + op->fileName = start.filePath; + op->apply = apply; + + replacements += op; + } + + diagnosticItem->setFixitOperations(replacements); + } + + void apply(ClangToolsDiagnosticModel *model) + { + for (auto it = m_refactoringFileInfos.begin(); it != m_refactoringFileInfos.end(); ++it) { + RefactoringFileInfo &fileInfo = it.value(); + + QVector<DiagnosticItem *> itemsScheduledOrSchedulable; + QVector<DiagnosticItem *> itemsScheduled; + QVector<DiagnosticItem *> itemsSchedulable; + + // Construct refactoring operations + for (DiagnosticItem *diagnosticItem : fileInfo.diagnosticItems) { + const FixitStatus fixItStatus = diagnosticItem->fixItStatus(); + + const bool isScheduled = fixItStatus == FixitStatus::Scheduled; + const bool isSchedulable = fileInfo.hasScheduledFixits + && fixItStatus == FixitStatus::NotScheduled; + + if (isScheduled || isSchedulable) { + addFixitOperations(diagnosticItem, fileInfo.file, isScheduled); + itemsScheduledOrSchedulable += diagnosticItem; + if (isScheduled) + itemsScheduled += diagnosticItem; + else + itemsSchedulable += diagnosticItem; + } + } + + // Collect replacements + ReplacementOperations ops; + for (DiagnosticItem *item : itemsScheduledOrSchedulable) + ops += item->fixitOperations(); + + if (ops.empty()) + continue; + + // Apply file + QVector<DiagnosticItem *> itemsApplied; + QVector<DiagnosticItem *> itemsFailedToApply; + QVector<DiagnosticItem *> itemsInvalidated; + + fileInfo.file.setReplacements(ops); + model->removeWatchedPath(ops.first()->fileName); + if (fileInfo.file.apply()) { + itemsApplied = itemsScheduled; + } else { + itemsFailedToApply = itemsScheduled; + itemsInvalidated = itemsSchedulable; + } + model->addWatchedPath(ops.first()->fileName); + + // Update DiagnosticItem state + for (DiagnosticItem *diagnosticItem : itemsScheduled) + diagnosticItem->setFixItStatus(FixitStatus::Applied); + for (DiagnosticItem *diagnosticItem : itemsFailedToApply) + diagnosticItem->setFixItStatus(FixitStatus::FailedToApply); + for (DiagnosticItem *diagnosticItem : itemsInvalidated) + diagnosticItem->setFixItStatus(FixitStatus::Invalidated); + } + } + +private: + QMap<QString, RefactoringFileInfo> m_refactoringFileInfos; +}; + static FileInfos sortedFileInfos(const QVector<CppTools::ProjectPart::Ptr> &projectParts) { FileInfos fileInfos; @@ -93,9 +239,24 @@ static FileInfos sortedFileInfos(const QVector<CppTools::ProjectPart::Ptr> &proj return fileInfos; } -ClangTool::ClangTool(const QString &name) - : m_name(name) +static RunSettings runSettings(Project *project) +{ + auto *projectSettings = ClangToolsProjectSettingsManager::getSettings(project); + if (projectSettings->useGlobalSettings()) + return ClangToolsSettings::instance()->runSettings(); + return projectSettings->runSettings(); +} + +ClangTool *ClangTool::instance() +{ + return s_instance; +} + +ClangTool::ClangTool() + : m_name("Clang-Tidy and Clazy") { + setObjectName("ClangTidyClazyTool"); + s_instance = this; m_diagnosticModel = new ClangToolsDiagnosticModel(this); const Utils::Icon RUN_FILE_OVERLAY( @@ -120,6 +281,150 @@ ClangTool::ClangTool(const QString &name) m_startOnCurrentFileAction = action; m_stopAction = Debugger::createStopAction(); + + m_diagnosticFilterModel = new DiagnosticFilterModel(this); + m_diagnosticFilterModel->setSourceModel(m_diagnosticModel); + m_diagnosticFilterModel->setDynamicSortFilter(true); + + m_diagnosticView = new DiagnosticView; + initDiagnosticView(); + m_diagnosticView->setModel(m_diagnosticFilterModel); + m_diagnosticView->setSortingEnabled(true); + m_diagnosticView->sortByColumn(Debugger::DetailedErrorView::DiagnosticColumn, + Qt::AscendingOrder); + m_diagnosticView->setObjectName(QLatin1String("ClangTidyClazyIssuesView")); + m_diagnosticView->setWindowTitle(tr("Clang-Tidy and Clazy Diagnostics")); + + foreach (auto * const model, + QList<QAbstractItemModel *>({m_diagnosticModel, m_diagnosticFilterModel})) { + connect(model, &QAbstractItemModel::rowsInserted, + this, &ClangTool::handleStateUpdate); + connect(model, &QAbstractItemModel::rowsRemoved, + this, &ClangTool::handleStateUpdate); + connect(model, &QAbstractItemModel::modelReset, + this, &ClangTool::handleStateUpdate); + connect(model, &QAbstractItemModel::layoutChanged, // For QSortFilterProxyModel::invalidate() + this, &ClangTool::handleStateUpdate); + } + + // Go to previous diagnostic + action = new QAction(this); + action->setDisabled(true); + action->setIcon(Utils::Icons::PREV_TOOLBAR.icon()); + action->setToolTip(tr("Go to previous diagnostic.")); + connect(action, &QAction::triggered, m_diagnosticView, &DetailedErrorView::goBack); + m_goBack = action; + + // Go to next diagnostic + action = new QAction(this); + action->setDisabled(true); + action->setIcon(Utils::Icons::NEXT_TOOLBAR.icon()); + action->setToolTip(tr("Go to next diagnostic.")); + connect(action, &QAction::triggered, m_diagnosticView, &DetailedErrorView::goNext); + m_goNext = action; + + // Load diagnostics from file + action = new QAction(this); + action->setIcon(Utils::Icons::OPENFILE_TOOLBAR.icon()); + action->setToolTip(tr("Load Diagnostics from YAML Files exported with \"-export-fixes\".")); + connect(action, &QAction::triggered, this, &ClangTool::loadDiagnosticsFromFiles); + m_loadExported = action; + + // Clear data + action = new QAction(this); + action->setDisabled(true); + action->setIcon(Utils::Icons::CLEAN_TOOLBAR.icon()); + action->setToolTip(tr("Clear")); + connect(action, &QAction::triggered, [this](){ + m_clear->setEnabled(false); + m_diagnosticModel->clear(); + Debugger::showPermanentStatusMessage(QString()); + }); + m_clear = action; + + // Expand/Collapse + action = new QAction(this); + action->setDisabled(true); + action->setCheckable(true); + action->setIcon(Utils::Icons::EXPAND_ALL_TOOLBAR.icon()); + action->setToolTip(tr("Expand All")); + connect(action, &QAction::toggled, [this](bool checked){ + if (checked) { + m_expandCollapse->setToolTip(tr("Collapse All")); + m_diagnosticView->expandAll(); + } else { + m_expandCollapse->setToolTip(tr("Expand All")); + m_diagnosticView->collapseAll(); + } + }); + m_expandCollapse = action; + + // Filter line edit + m_filterLineEdit = new Utils::FancyLineEdit(); + m_filterLineEdit->setFiltering(true); + m_filterLineEdit->setPlaceholderText(tr("Filter Diagnostics")); + m_filterLineEdit->setHistoryCompleter("CppTools.ClangTidyClazyIssueFilter", true); + connect(m_filterLineEdit, &Utils::FancyLineEdit::filterChanged, [this](const QString &filter) { + m_diagnosticFilterModel->setFilterRegExp( + QRegExp(filter, Qt::CaseSensitive, QRegExp::WildcardUnix)); + }); + + // Apply fixits button + m_applyFixitsButton = new QToolButton; + m_applyFixitsButton->setText(tr("Apply Fixits")); + m_applyFixitsButton->setEnabled(false); + connect(m_diagnosticModel, + &ClangToolsDiagnosticModel::fixItsToApplyCountChanged, + [this](int c) { + m_applyFixitsButton->setEnabled(c); + static_cast<DiagnosticView *>(m_diagnosticView.data())->setSelectedFixItsCount(c); + }); + connect(m_applyFixitsButton, &QToolButton::clicked, [this]() { + QVector<DiagnosticItem *> diagnosticItems; + m_diagnosticModel->forItemsAtLevel<2>([&](DiagnosticItem *item){ + diagnosticItems += item; + }); + + ApplyFixIts(diagnosticItems).apply(m_diagnosticModel); + }); + + ActionContainer *menu = ActionManager::actionContainer(Debugger::Constants::M_DEBUG_ANALYZER); + const QString toolTip = tr("Clang-Tidy and Clazy use a customized Clang executable from the " + "Clang project to search for diagnostics."); + + m_perspective.addWindow(m_diagnosticView, Perspective::SplitVertical, nullptr); + + action = new QAction(tr("Clang-Tidy and Clazy..."), this); + action->setToolTip(toolTip); + menu->addAction(ActionManager::registerAction(action, "ClangTidyClazy.Action"), + Debugger::Constants::G_ANALYZER_TOOLS); + QObject::connect(action, &QAction::triggered, this, [this]() { + startTool(ClangTool::FileSelection::AskUser); + }); + QObject::connect(m_startAction, &QAction::triggered, action, &QAction::triggered); + QObject::connect(m_startAction, &QAction::changed, action, [action, this] { + action->setEnabled(m_startAction->isEnabled()); + }); + + QObject::connect(m_startOnCurrentFileAction, &QAction::triggered, this, [this] { + startTool(ClangTool::FileSelection::CurrentFile); + }); + + m_perspective.addToolBarAction(m_startAction); + m_perspective.addToolBarAction(m_startOnCurrentFileAction); + m_perspective.addToolBarAction(m_stopAction); + m_perspective.addToolBarAction(m_loadExported); + m_perspective.addToolBarAction(m_clear); + m_perspective.addToolBarAction(m_goBack); + m_perspective.addToolBarAction(m_goNext); + m_perspective.addToolBarAction(m_expandCollapse); + m_perspective.addToolBarWidget(m_filterLineEdit); + m_perspective.addToolBarWidget(m_applyFixitsButton); + + updateRunActions(); + + connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, + this, &ClangTool::updateRunActions); } ClangTool::~ClangTool() @@ -127,6 +432,78 @@ ClangTool::~ClangTool() delete m_diagnosticView; } +void ClangTool::selectPerspective() +{ + m_perspective.select(); +} + +void ClangTool::startTool(ClangTool::FileSelection fileSelection) +{ + Project *project = SessionManager::startupProject(); + QTC_ASSERT(project, return); + QTC_ASSERT(project->activeTarget(), return); + + auto runControl = new RunControl(Constants::CLANGTIDYCLAZY_RUN_MODE); + runControl->setDisplayName(tr("Clang-Tidy and Clazy")); + runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR); + runControl->setTarget(project->activeTarget()); + + const FileInfos fileInfos = collectFileInfos(project, fileSelection); + if (fileInfos.empty()) + return; + + const bool preventBuild = fileSelection == FileSelection::CurrentFile; + auto clangTool = new ClangToolRunWorker(runControl, + runSettings(project), + fileInfos, + preventBuild); + + m_stopAction->disconnect(); + connect(m_stopAction, &QAction::triggered, runControl, [runControl] { + runControl->appendMessage(tr("Clang-Tidy and Clazy tool stopped by user."), + NormalMessageFormat); + runControl->initiateStop(); + }); + + connect(runControl, &RunControl::stopped, this, [this, clangTool] { + bool success = clangTool->success(); + setToolBusy(false); + m_running = false; + handleStateUpdate(); + updateRunActions(); + emit finished(success); + }); + + m_perspective.select(); + + m_diagnosticModel->clear(); + + setToolBusy(true); + m_diagnosticFilterModel->setProject(project); + m_running = true; + handleStateUpdate(); + updateRunActions(); + + ProjectExplorerPlugin::startRunControl(runControl); +} + +Diagnostics ClangTool::read(OutputFileFormat outputFileFormat, const QString &logFilePath, const QString &mainFilePath, const QSet<FilePath> &projectFiles, QString *errorMessage) const +{ + const auto acceptFromFilePath = [projectFiles](const Utils::FilePath &filePath) { + return projectFiles.contains(filePath); + }; + + if (outputFileFormat == OutputFileFormat::Yaml) { + return readExportedDiagnostics(Utils::FilePath::fromString(logFilePath), + acceptFromFilePath, + errorMessage); + } + return readSerializedDiagnostics(Utils::FilePath::fromString(logFilePath), + Utils::FilePath::fromString(mainFilePath), + acceptFromFilePath, + errorMessage); +} + FileInfos ClangTool::collectFileInfos(Project *project, FileSelection fileSelection) const { auto projectInfo = CppTools::CppModelManager::instance()->projectInfo(project); @@ -174,6 +551,42 @@ void ClangTool::initDiagnosticView() m_diagnosticView->setAutoScroll(false); } +void ClangTool::loadDiagnosticsFromFiles() +{ + // Ask user for files + const QStringList filePaths + = QFileDialog::getOpenFileNames(Core::ICore::mainWindow(), + tr("Select YAML Files with Diagnostics"), + QDir::homePath(), + tr("YAML Files (*.yml *.yaml);;All Files (*)")); + if (filePaths.isEmpty()) + return; + + // Load files + Diagnostics diagnostics; + QString errors; + for (const QString &filePath : filePaths) { + QString currentError; + diagnostics << readExportedDiagnostics(Utils::FilePath::fromString(filePath), + {}, + ¤tError); + + if (!currentError.isEmpty()) { + if (!errors.isEmpty()) + errors.append("\n"); + errors.append(currentError); + } + } + + // Show errors + if (!errors.isEmpty()) + AsynchronousMessageBox::critical(tr("Error Loading Diagnostics"), errors); + + // Show imported + m_diagnosticModel->clear(); + onNewDiagnosticsAvailable(diagnostics); +} + QSet<Diagnostic> ClangTool::diagnostics() const { return Utils::filtered(m_diagnosticModel->diagnostics(), [](const Diagnostic &diagnostic) { @@ -186,6 +599,78 @@ void ClangTool::onNewDiagnosticsAvailable(const Diagnostics &diagnostics) { QTC_ASSERT(m_diagnosticModel, return); m_diagnosticModel->addDiagnostics(diagnostics); + if (!m_diagnosticFilterModel->filterRegExp().pattern().isEmpty()) + m_diagnosticFilterModel->invalidateFilter(); +} + +void ClangTool::updateRunActions() +{ + if (m_toolBusy) { + QString tooltipText = tr("Clang-Tidy and Clazy are still running."); + + m_startAction->setEnabled(false); + m_startAction->setToolTip(tooltipText); + + m_startOnCurrentFileAction->setEnabled(false); + m_startOnCurrentFileAction->setToolTip(tooltipText); + + m_stopAction->setEnabled(true); + m_loadExported->setEnabled(false); + m_clear->setEnabled(false); + } else { + QString toolTipStart = m_startAction->text(); + QString toolTipStartOnCurrentFile = m_startOnCurrentFileAction->text(); + + Project *project = SessionManager::startupProject(); + Target *target = project ? project->activeTarget() : nullptr; + const Core::Id cxx = ProjectExplorer::Constants::CXX_LANGUAGE_ID; + bool canRun = target && project->projectLanguages().contains(cxx) + && ToolChainKitAspect::toolChain(target->kit(), cxx); + if (!canRun) + toolTipStart = toolTipStartOnCurrentFile = tr("This is not a C/C++ project."); + + m_startAction->setEnabled(canRun); + m_startAction->setToolTip(toolTipStart); + + m_startOnCurrentFileAction->setEnabled(canRun); + m_startOnCurrentFileAction->setToolTip(toolTipStartOnCurrentFile); + + m_stopAction->setEnabled(false); + m_loadExported->setEnabled(true); + m_clear->setEnabled(m_diagnosticModel->diagnostics().count()); + } +} + +void ClangTool::handleStateUpdate() +{ + QTC_ASSERT(m_goBack, return); + QTC_ASSERT(m_goNext, return); + QTC_ASSERT(m_diagnosticModel, return); + QTC_ASSERT(m_diagnosticFilterModel, return); + + const int issuesFound = m_diagnosticModel->diagnostics().count(); + const int issuesVisible = m_diagnosticFilterModel->rowCount(); + m_goBack->setEnabled(issuesVisible > 1); + m_goNext->setEnabled(issuesVisible > 1); + m_clear->setEnabled(issuesFound > 0); + m_expandCollapse->setEnabled(issuesVisible); + + m_loadExported->setEnabled(!m_running); + + QString message; + if (m_running) { + if (issuesFound) + message = tr("Running - %n diagnostics", nullptr, issuesFound); + else + message = tr("Running - No diagnostics"); + } else { + if (issuesFound) + message = tr("Finished - %n diagnostics", nullptr, issuesFound); + else + message = tr("Finished - No diagnostics"); + } + + Debugger::showPermanentStatusMessage(message); } void ClangTool::setToolBusy(bool busy) diff --git a/src/plugins/clangtools/clangtool.h b/src/plugins/clangtools/clangtool.h index c0b1565260..b61ed1ac44 100644 --- a/src/plugins/clangtools/clangtool.h +++ b/src/plugins/clangtools/clangtool.h @@ -29,38 +29,56 @@ #include "clangtoolsdiagnostic.h" #include "clangtoolslogfilereader.h" +#include <debugger/debuggermainwindow.h> + #include <projectexplorer/runconfiguration.h> #include <cpptools/projectinfo.h> -namespace Debugger { class DetailedErrorView; } -namespace Utils { class FilePath; } +QT_BEGIN_NAMESPACE +class QToolButton; +QT_END_NAMESPACE + +namespace Debugger { +class DetailedErrorView; +} +namespace Utils { +class FilePath; +class FancyLineEdit; +} // namespace Utils namespace ClangTools { namespace Internal { class ClangToolsDiagnosticModel; class Diagnostic; +class DiagnosticFilterModel; + +const char ClangTidyClazyPerspectiveId[] = "ClangTidyClazy.Perspective"; class ClangTool : public QObject { Q_OBJECT public: - ClangTool(const QString &name); + static ClangTool *instance(); + + ClangTool(); ~ClangTool() override; + void selectPerspective(); + enum class FileSelection { AllFiles, CurrentFile, AskUser, }; - virtual void startTool(FileSelection fileSelection) = 0; + void startTool(FileSelection fileSelection); - virtual Diagnostics read(OutputFileFormat outputFileFormat, + Diagnostics read(OutputFileFormat outputFileFormat, const QString &logFilePath, const QString &mainFilePath, const QSet<Utils::FilePath> &projectFiles, - QString *errorMessage) const = 0; + QString *errorMessage) const; FileInfos collectFileInfos(ProjectExplorer::Project *project, FileSelection fileSelection) const; @@ -70,7 +88,7 @@ public: const QString &name() const; - virtual void onNewDiagnosticsAvailable(const Diagnostics &diagnostics); + void onNewDiagnosticsAvailable(const Diagnostics &diagnostics); QAction *startAction() const { return m_startAction; } QAction *startOnCurrentFileAction() const { return m_startOnCurrentFileAction; } @@ -78,11 +96,14 @@ public: signals: void finished(bool success); // For testing. -protected: - virtual void handleStateUpdate() = 0; +private: + void updateRunActions(); + void handleStateUpdate(); void setToolBusy(bool busy); + void initDiagnosticView(); + void loadDiagnosticsFromFiles(); ClangToolsDiagnosticModel *m_diagnosticModel = nullptr; QPointer<Debugger::DetailedErrorView> m_diagnosticView; @@ -93,6 +114,19 @@ protected: bool m_running = false; bool m_toolBusy = false; + DiagnosticFilterModel *m_diagnosticFilterModel = nullptr; + + Utils::FancyLineEdit *m_filterLineEdit = nullptr; + QToolButton *m_applyFixitsButton = nullptr; + + QAction *m_goBack = nullptr; + QAction *m_goNext = nullptr; + QAction *m_loadExported = nullptr; + QAction *m_clear = nullptr; + QAction *m_expandCollapse = nullptr; + + Utils::Perspective m_perspective{ClangTidyClazyPerspectiveId, tr("Clang-Tidy and Clazy")}; + private: const QString m_name; }; diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp index dc22e7a39b..2af11aa7ef 100644 --- a/src/plugins/clangtools/clangtoolruncontrol.cpp +++ b/src/plugins/clangtools/clangtoolruncontrol.cpp @@ -26,9 +26,9 @@ #include "clangtoolruncontrol.h" #include "clangtidyclazyrunner.h" -#include "clangtidyclazytool.h" #include "clangtool.h" #include "clangtoolslogfilereader.h" +#include "clangtoolsprojectsettings.h" #include "clangtoolssettings.h" #include "clangtoolsutils.h" @@ -40,7 +40,9 @@ #include <coreplugin/progressmanager/futureprogress.h> #include <coreplugin/progressmanager/progressmanager.h> +#include <cpptools/clangdiagnosticconfigsmodel.h> #include <cpptools/compileroptionsbuilder.h> +#include <cpptools/cppcodemodelsettings.h> #include <cpptools/cppmodelmanager.h> #include <cpptools/cppprojectfile.h> #include <cpptools/cpptoolsreuse.h> @@ -116,7 +118,7 @@ namespace Internal { static ClangTool *tool() { - return ClangTidyClazyTool::instance(); + return ClangTool::instance(); } class ProjectBuilder : public RunWorker @@ -219,19 +221,28 @@ static QDebug operator<<(QDebug debug, const AnalyzeUnits &analyzeUnits) return debug; } +static ClangDiagnosticConfig diagnosticConfig(const Core::Id &diagConfigId) +{ + const ClangDiagnosticConfigsModel configsModel( + CppTools::codeModelSettings()->clangCustomDiagnosticConfigs()); + + QTC_ASSERT(configsModel.hasConfigWithId(diagConfigId), return ClangDiagnosticConfig()); + return configsModel.configWithId(diagConfigId); +} + ClangToolRunWorker::ClangToolRunWorker(RunControl *runControl, - const ClangDiagnosticConfig &diagnosticConfig, + const RunSettings &runSettings, const FileInfos &fileInfos, bool preventBuild) : RunWorker(runControl) - , m_temporaryDir("clangtools-XXXXXX") - , m_diagnosticConfig(diagnosticConfig) + , m_diagnosticConfig(diagnosticConfig(runSettings.diagnosticConfigId())) , m_fileInfos(fileInfos) + , m_temporaryDir("clangtools-XXXXXX") { setId("ClangTidyClazyRunner"); setSupportsReRunning(false); - if (!preventBuild && ClangToolsSettings::instance()->savedBuildBeforeAnalysis()) { + if (!preventBuild && runSettings.buildBeforeAnalysis()) { m_projectBuilder = new ProjectBuilder(runControl); addStartDependency(m_projectBuilder); } @@ -272,11 +283,9 @@ void ClangToolRunWorker::start() TaskHub::clearTasks(Debugger::Constants::ANALYZERTASK_ID); ProjectExplorerPlugin::saveModifiedFiles(); - if (ClangToolsSettings::instance()->savedBuildBeforeAnalysis()) { - if (m_projectBuilder && !m_projectBuilder->success()) { - reportFailure(); - return; - } + if (m_projectBuilder && !m_projectBuilder->success()) { + reportFailure(); + return; } const QString &toolName = tool()->name(); @@ -337,7 +346,7 @@ void ClangToolRunWorker::start() // Start process(es) qCDebug(LOG) << "Environment:" << m_environment; m_runners.clear(); - const int parallelRuns = ClangToolsSettings::instance()->savedSimultaneousProcesses(); + const int parallelRuns = m_runSettings.parallelJobs(); QTC_ASSERT(parallelRuns >= 1, reportFailure(); return); m_success = true; @@ -491,7 +500,7 @@ void ClangToolRunWorker::finalize() TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID); Target *target = runControl()->target(); if (target && !target->activeBuildConfiguration()->buildDirectory().exists() - && !ClangToolsSettings::instance()->savedBuildBeforeAnalysis()) { + && !m_runSettings.buildBeforeAnalysis()) { msg = tr("%1: You might need to build the project to generate or update source " "files. To build automatically, enable \"Build the project before starting " "analysis\".") diff --git a/src/plugins/clangtools/clangtoolruncontrol.h b/src/plugins/clangtools/clangtoolruncontrol.h index 842350a7f4..bfada9e502 100644 --- a/src/plugins/clangtools/clangtoolruncontrol.h +++ b/src/plugins/clangtools/clangtoolruncontrol.h @@ -26,6 +26,7 @@ #pragma once #include "clangfileinfo.h" +#include "clangtoolssettings.h" #include <cpptools/clangdiagnosticconfig.h> #include <cpptools/projectinfo.h> @@ -66,7 +67,7 @@ class ClangToolRunWorker : public ProjectExplorer::RunWorker public: ClangToolRunWorker(ProjectExplorer::RunControl *runControl, - const CppTools::ClangDiagnosticConfig &diagnosticConfig, + const RunSettings &runSettings, const FileInfos &fileInfos, bool preventBuild); @@ -93,15 +94,15 @@ private: void finalize(); -protected: - ProjectBuilder *m_projectBuilder = nullptr; - Utils::Environment m_environment; - Utils::TemporaryDirectory m_temporaryDir; - private: + RunSettings m_runSettings; CppTools::ClangDiagnosticConfig m_diagnosticConfig; FileInfos m_fileInfos; + ProjectBuilder *m_projectBuilder = nullptr; + Utils::Environment m_environment; + Utils::TemporaryDirectory m_temporaryDir; + CppTools::ProjectInfo m_projectInfoBeforeBuild; CppTools::ProjectInfo m_projectInfo; QString m_targetTriple; diff --git a/src/plugins/clangtools/clangtools.pro b/src/plugins/clangtools/clangtools.pro index a089f1edb7..6173e2eec1 100644 --- a/src/plugins/clangtools/clangtools.pro +++ b/src/plugins/clangtools/clangtools.pro @@ -21,7 +21,6 @@ SOURCES += \ clangtoolsdiagnosticview.cpp \ clangtoolsprojectsettingswidget.cpp \ clangtidyclazyrunner.cpp \ - clangtidyclazytool.cpp \ clangtool.cpp \ clangtoolruncontrol.cpp \ clangtoolrunner.cpp \ @@ -32,6 +31,7 @@ SOURCES += \ clangtoolsprojectsettings.cpp \ clangtoolssettings.cpp \ clangtoolsutils.cpp \ + runsettingswidget.cpp \ settingswidget.cpp \ HEADERS += \ @@ -41,7 +41,6 @@ HEADERS += \ clangtoolsdiagnosticview.h \ clangtoolsprojectsettingswidget.h \ clangtidyclazyrunner.h \ - clangtidyclazytool.h \ clangtool.h \ clangtoolruncontrol.h \ clangtoolrunner.h \ @@ -54,11 +53,13 @@ HEADERS += \ clangtoolsprojectsettings.h \ clangtoolssettings.h \ clangtoolsutils.h \ + runsettingswidget.h \ settingswidget.h \ FORMS += \ clangselectablefilesdialog.ui \ clangtoolsprojectsettingswidget.ui \ + runsettingswidget.ui \ settingswidget.ui \ equals(TEST, 1) { diff --git a/src/plugins/clangtools/clangtools.qbs b/src/plugins/clangtools/clangtools.qbs index 32146f87c0..daca2934c1 100644 --- a/src/plugins/clangtools/clangtools.qbs +++ b/src/plugins/clangtools/clangtools.qbs @@ -39,8 +39,6 @@ QtcPlugin { "clangselectablefilesdialog.ui", "clangtidyclazyrunner.cpp", "clangtidyclazyrunner.h", - "clangtidyclazytool.cpp", - "clangtidyclazytool.h", "clangtool.cpp", "clangtool.h", "clangtoolruncontrol.cpp", @@ -68,6 +66,9 @@ QtcPlugin { "clangtoolsutils.h", "clangtoolsplugin.cpp", "clangtoolsplugin.h", + "runsettingswidget.cpp", + "runsettingswidget.h", + "runsettingswidget.ui", "settingswidget.cpp", "settingswidget.h", "settingswidget.ui", diff --git a/src/plugins/clangtools/clangtoolslogfilereader.cpp b/src/plugins/clangtools/clangtoolslogfilereader.cpp index 59ea741c25..1fe490a6bf 100644 --- a/src/plugins/clangtools/clangtoolslogfilereader.cpp +++ b/src/plugins/clangtools/clangtoolslogfilereader.cpp @@ -417,7 +417,7 @@ Diagnostics readExportedDiagnostics(const Utils::FilePath &logFilePath, try { YAML::Node document = YAML::LoadFile(logFilePath.toString().toStdString()); for (const auto &diagNode : document["Diagnostics"]) { - // clazy omits the "DiagnosticMessage" node. + // Since llvm/clang 9.0 the diagnostic items are wrapped in a "DiagnosticMessage" node. const auto msgNode = diagNode["DiagnosticMessage"]; const YAML::Node &node = msgNode ? msgNode : diagNode; diff --git a/src/plugins/clangtools/clangtoolsplugin.cpp b/src/plugins/clangtools/clangtoolsplugin.cpp index fed9cb2150..12031dc589 100644 --- a/src/plugins/clangtools/clangtoolsplugin.cpp +++ b/src/plugins/clangtools/clangtoolsplugin.cpp @@ -25,10 +25,10 @@ #include "clangtoolsplugin.h" +#include "clangtool.h" #include "clangtoolsconstants.h" -#include "clangtoolsprojectsettingswidget.h" -#include "clangtidyclazytool.h" #include "clangtoolsprojectsettings.h" +#include "clangtoolsprojectsettingswidget.h" #include "settingswidget.h" #ifdef WITH_TESTS @@ -88,24 +88,17 @@ public: return m_widget; } - void apply() override - { - ClangToolsSettings::instance()->writeSettings(); - } - - void finish() override - { - delete m_widget; - } + void apply() override { m_widget->apply(); } + void finish() override { delete m_widget; } private: - QPointer<QWidget> m_widget; + QPointer<SettingsWidget> m_widget; }; class ClangToolsPluginPrivate { public: - ClangTidyClazyTool clangTidyClazyTool; + ClangTool clangTool; ClangToolsOptionsPage optionsPage; ClangToolsProjectSettingsManager settingsManager; }; @@ -122,9 +115,8 @@ bool ClangToolsPlugin::initialize(const QStringList &arguments, QString *errorSt d = new ClangToolsPluginPrivate; - ActionManager::registerAction(d->clangTidyClazyTool.startAction(), - Constants::RUN_ON_PROJECT); - ActionManager::registerAction(d->clangTidyClazyTool.startOnCurrentFileAction(), + ActionManager::registerAction(d->clangTool.startAction(), Constants::RUN_ON_PROJECT); + ActionManager::registerAction(d->clangTool.startOnCurrentFileAction(), Constants::RUN_ON_CURRENT_FILE); auto panelFactory = new ProjectPanelFactory(); diff --git a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp index 5d711a8aef..2ed19354f2 100644 --- a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp +++ b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp @@ -25,8 +25,8 @@ #include "clangtoolspreconfiguredsessiontests.h" +#include "clangtool.h" #include "clangtoolsdiagnostic.h" -#include "clangtidyclazytool.h" #include "clangtoolsutils.h" #include <coreplugin/icore.h> @@ -121,13 +121,13 @@ void PreconfiguredSessionTests::testPreconfiguredSession() QVERIFY(switchToProjectAndTarget(project, target)); - ClangTidyClazyTool::instance()->startTool(ClangTidyClazyTool::FileSelection::AllFiles); - QSignalSpy waitUntilAnalyzerFinished(ClangTidyClazyTool::instance(), SIGNAL(finished(bool))); + ClangTool::instance()->startTool(ClangTool::FileSelection::AllFiles); + QSignalSpy waitUntilAnalyzerFinished(ClangTool::instance(), SIGNAL(finished(bool))); QVERIFY(waitUntilAnalyzerFinished.wait(30000)); const QList<QVariant> arguments = waitUntilAnalyzerFinished.takeFirst(); const bool analyzerFinishedSuccessfully = arguments.first().toBool(); QVERIFY(analyzerFinishedSuccessfully); - QCOMPARE(ClangTidyClazyTool::instance()->diagnostics().count(), 0); + QCOMPARE(ClangTool::instance()->diagnostics().count(), 0); } static QList<Project *> validProjects(const QList<Project *> projectsOfSession) diff --git a/src/plugins/clangtools/clangtoolsprojectsettings.cpp b/src/plugins/clangtools/clangtoolsprojectsettings.cpp index 6c2597789d..005897b49c 100644 --- a/src/plugins/clangtools/clangtoolsprojectsettings.cpp +++ b/src/plugins/clangtools/clangtoolsprojectsettings.cpp @@ -34,8 +34,9 @@ namespace ClangTools { namespace Internal { +static const char SETTINGS_KEY_MAIN[] = "ClangTools"; +static const char SETTINGS_PREFIX[] = "ClangTools."; static const char SETTINGS_KEY_USE_GLOBAL_SETTINGS[] = "ClangTools.UseGlobalSettings"; -static const char SETTINGS_KEY_DIAGNOSTIC_CONFIG[] = "ClangTools.DiagnosticConfig"; static const char SETTINGS_KEY_SELECTED_DIRS[] = "ClangTools.SelectedDirs"; static const char SETTINGS_KEY_SELECTED_FILES[] = "ClangTools.SelectedFiles"; static const char SETTINGS_KEY_SUPPRESSED_DIAGS[] = "ClangTools.SuppressedDiagnostics"; @@ -78,22 +79,53 @@ void ClangToolsProjectSettings::removeAllSuppressedDiagnostics() emit suppressedDiagnosticsChanged(); } +static QVariantMap convertToMapFromVersionBefore410(ProjectExplorer::Project *p) +{ + // These keys haven't changed. + const QStringList keys = { + SETTINGS_KEY_SELECTED_DIRS, + SETTINGS_KEY_SELECTED_FILES, + SETTINGS_KEY_SUPPRESSED_DIAGS, + SETTINGS_KEY_USE_GLOBAL_SETTINGS, + "ClangTools.BuildBeforeAnalysis", + }; + + QVariantMap map; + for (const QString &key : keys) + map.insert(key, p->namedSettings(key)); + + map.insert(SETTINGS_PREFIX + QString(diagnosticConfigIdKey), + p->namedSettings("ClangTools.DiagnosticConfig")); + + return map; +} + void ClangToolsProjectSettings::load() { - const QVariant useGlobalVariant = m_project->namedSettings(SETTINGS_KEY_USE_GLOBAL_SETTINGS); - m_useGlobalSettings = useGlobalVariant.isValid() ? useGlobalVariant.toBool() : true; - m_diagnosticConfig = Core::Id::fromSetting( - m_project->namedSettings(SETTINGS_KEY_DIAGNOSTIC_CONFIG)); + // Load map + QVariantMap map = m_project->namedSettings(SETTINGS_KEY_MAIN).toMap(); + + bool write; + if (map.isEmpty()) { + if (!m_project->namedSettings(SETTINGS_KEY_SELECTED_DIRS).isNull()) { + map = convertToMapFromVersionBefore410(m_project); + write = true; + } else { + return; // Use defaults + } + } - auto toFileName = [](const QString &s) { return Utils::FilePath::fromString(s); }; + // Read map + m_useGlobalSettings = map.value(SETTINGS_KEY_USE_GLOBAL_SETTINGS).toBool(); - const QStringList dirs = m_project->namedSettings(SETTINGS_KEY_SELECTED_DIRS).toStringList(); + auto toFileName = [](const QString &s) { return Utils::FilePath::fromString(s); }; + const QStringList dirs = map.value(SETTINGS_KEY_SELECTED_DIRS).toStringList(); m_selectedDirs = Utils::transform<QSet>(dirs, toFileName); - const QStringList files = m_project->namedSettings(SETTINGS_KEY_SELECTED_FILES).toStringList(); + const QStringList files = map.value(SETTINGS_KEY_SELECTED_FILES).toStringList(); m_selectedFiles = Utils::transform<QSet>(files, toFileName); - const QVariantList list = m_project->namedSettings(SETTINGS_KEY_SUPPRESSED_DIAGS).toList(); + const QVariantList list = map.value(SETTINGS_KEY_SUPPRESSED_DIAGS).toList(); foreach (const QVariant &v, list) { const QVariantMap diag = v.toMap(); const QString fp = diag.value(SETTINGS_KEY_SUPPRESSED_DIAGS_FILEPATH).toString(); @@ -113,48 +145,37 @@ void ClangToolsProjectSettings::load() uniquifier); } emit suppressedDiagnosticsChanged(); + + m_runSettings.fromMap(map, SETTINGS_PREFIX); + + if (write) + store(); // Store new settings format } void ClangToolsProjectSettings::store() { - m_project->setNamedSettings(SETTINGS_KEY_USE_GLOBAL_SETTINGS, m_useGlobalSettings); - m_project->setNamedSettings(SETTINGS_KEY_DIAGNOSTIC_CONFIG, m_diagnosticConfig.toSetting()); + QVariantMap map; + map.insert(SETTINGS_KEY_USE_GLOBAL_SETTINGS, m_useGlobalSettings); const QStringList dirs = Utils::transform<QList>(m_selectedDirs, &Utils::FilePath::toString); - m_project->setNamedSettings(SETTINGS_KEY_SELECTED_DIRS, dirs); + map.insert(SETTINGS_KEY_SELECTED_DIRS, dirs); const QStringList files = Utils::transform<QList>(m_selectedFiles, &Utils::FilePath::toString); - m_project->setNamedSettings(SETTINGS_KEY_SELECTED_FILES, files); + map.insert(SETTINGS_KEY_SELECTED_FILES, files); QVariantList list; - foreach (const SuppressedDiagnostic &diag, m_suppressedDiagnostics) { + for (const SuppressedDiagnostic &diag : m_suppressedDiagnostics) { QVariantMap diagMap; diagMap.insert(SETTINGS_KEY_SUPPRESSED_DIAGS_FILEPATH, diag.filePath.toString()); diagMap.insert(SETTINGS_KEY_SUPPRESSED_DIAGS_MESSAGE, diag.description); diagMap.insert(SETTINGS_KEY_SUPPRESSED_DIAGS_UNIQIFIER, diag.uniquifier); list << diagMap; } - m_project->setNamedSettings(SETTINGS_KEY_SUPPRESSED_DIAGS, list); -} + map.insert(SETTINGS_KEY_SUPPRESSED_DIAGS, list); -bool ClangToolsProjectSettings::useGlobalSettings() const -{ - return m_useGlobalSettings; -} - -void ClangToolsProjectSettings::setUseGlobalSettings(bool useGlobalSettings) -{ - m_useGlobalSettings = useGlobalSettings; -} + m_runSettings.toMap(map, SETTINGS_PREFIX); -Core::Id ClangToolsProjectSettings::diagnosticConfig() const -{ - return m_diagnosticConfig; -} - -void ClangToolsProjectSettings::setDiagnosticConfig(const Core::Id &diagnosticConfig) -{ - m_diagnosticConfig = diagnosticConfig; + m_project->setNamedSettings(SETTINGS_KEY_MAIN, map); } ClangToolsProjectSettingsManager::ClangToolsProjectSettingsManager() diff --git a/src/plugins/clangtools/clangtoolsprojectsettings.h b/src/plugins/clangtools/clangtoolsprojectsettings.h index 0a6aa477d3..aaf045f056 100644 --- a/src/plugins/clangtools/clangtoolsprojectsettings.h +++ b/src/plugins/clangtools/clangtoolsprojectsettings.h @@ -25,7 +25,7 @@ #pragma once -#include <QObject> +#include "clangtoolssettings.h" #include <coreplugin/id.h> #include <projectexplorer/project.h> @@ -70,11 +70,11 @@ public: ClangToolsProjectSettings(ProjectExplorer::Project *project); ~ClangToolsProjectSettings() override; - bool useGlobalSettings() const; - void setUseGlobalSettings(bool useGlobalSettings); + bool useGlobalSettings() const { return m_useGlobalSettings; } + void setUseGlobalSettings(bool useGlobalSettings) { m_useGlobalSettings = useGlobalSettings; } - Core::Id diagnosticConfig() const; - void setDiagnosticConfig(const Core::Id &diagnosticConfig); + RunSettings runSettings() const { return m_runSettings; } + void setRunSettings(const RunSettings &settings) { m_runSettings = settings; } QSet<Utils::FilePath> selectedDirs() const { return m_selectedDirs; } void setSelectedDirs(const QSet<Utils::FilePath> &value) { m_selectedDirs = value; } @@ -95,10 +95,14 @@ private: void store(); ProjectExplorer::Project *m_project; + bool m_useGlobalSettings = true; - Core::Id m_diagnosticConfig; + + RunSettings m_runSettings; + QSet<Utils::FilePath> m_selectedDirs; QSet<Utils::FilePath> m_selectedFiles; + SuppressedDiagnosticsList m_suppressedDiagnostics; }; diff --git a/src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp b/src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp index 3e380aa9af..c5b7c53a68 100644 --- a/src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp +++ b/src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp @@ -26,8 +26,12 @@ #include "clangtoolsprojectsettingswidget.h" #include "ui_clangtoolsprojectsettingswidget.h" +#include "clangtool.h" +#include "clangtoolsconstants.h" #include "clangtoolsprojectsettings.h" +#include <coreplugin/icore.h> + #include <utils/qtcassert.h> #include <QAbstractTableModel> @@ -56,12 +60,46 @@ private: SuppressedDiagnosticsList m_diagnostics; }; +enum { UseGlobalSettings, UseCustomSettings }; // Values in sync with m_ui->globalCustomComboBox + ProjectSettingsWidget::ProjectSettingsWidget(ProjectExplorer::Project *project, QWidget *parent) : QWidget(parent), m_ui(new Ui::ProjectSettingsWidget) , m_projectSettings(ClangToolsProjectSettingsManager::getSettings(project)) { m_ui->setupUi(this); + + // Use global/custom settings + const int globalOrCustomIndex = m_projectSettings->useGlobalSettings() ? UseGlobalSettings + : UseCustomSettings; + m_ui->globalCustomComboBox->setCurrentIndex(globalOrCustomIndex); + onGlobalCustomChanged(globalOrCustomIndex); + connect(m_ui->globalCustomComboBox, + QOverload<int>::of(&QComboBox::currentIndexChanged), + this, + &ProjectSettingsWidget::onGlobalCustomChanged); + + // Restore global settings + connect(m_ui->restoreGlobal, &QPushButton::clicked, this, [this]() { + m_ui->runSettingsWidget->fromSettings(ClangToolsSettings::instance()->runSettings()); + }); + + // Links + connect(m_ui->gotoGlobalSettingsLabel, &QLabel::linkActivated, [](const QString &){ + Core::ICore::showOptionsDialog(ClangTools::Constants::SETTINGS_PAGE_ID); + }); + + connect(m_ui->gotoAnalyzerModeLabel, &QLabel::linkActivated, [](const QString &){ + ClangTool::instance()->selectPerspective(); + }); + + // Run options + m_ui->runSettingsWidget->fromSettings(m_projectSettings->runSettings()); + connect(m_ui->runSettingsWidget, &RunSettingsWidget::changed, [this]() { + m_projectSettings->setRunSettings(m_ui->runSettingsWidget->toSettings()); + }); + + // Suppressed diagnostics auto * const model = new SuppressedDiagnosticsModel(this); model->setDiagnostics(m_projectSettings->suppressedDiagnostics()); connect(m_projectSettings, &ClangToolsProjectSettings::suppressedDiagnosticsChanged, @@ -86,6 +124,14 @@ ProjectSettingsWidget::~ProjectSettingsWidget() delete m_ui; } +void ProjectSettingsWidget::onGlobalCustomChanged(int index) +{ + const bool useGlobal = index == UseGlobalSettings; + m_ui->runSettingsWidget->setEnabled(!useGlobal); + m_ui->restoreGlobal->setEnabled(!useGlobal); + m_projectSettings->setUseGlobalSettings(useGlobal); +} + void ProjectSettingsWidget::updateButtonStates() { updateButtonStateRemoveSelected(); diff --git a/src/plugins/clangtools/clangtoolsprojectsettingswidget.h b/src/plugins/clangtools/clangtoolsprojectsettingswidget.h index f9153f75a6..680431cc6e 100644 --- a/src/plugins/clangtools/clangtoolsprojectsettingswidget.h +++ b/src/plugins/clangtools/clangtoolsprojectsettingswidget.h @@ -44,6 +44,8 @@ public: ~ProjectSettingsWidget() override; private: + void onGlobalCustomChanged(int index); + void updateButtonStates(); void updateButtonStateRemoveSelected(); void updateButtonStateRemoveAll(); diff --git a/src/plugins/clangtools/clangtoolsprojectsettingswidget.ui b/src/plugins/clangtools/clangtoolsprojectsettingswidget.ui index c120d3bb95..b8263a450a 100644 --- a/src/plugins/clangtools/clangtoolsprojectsettingswidget.ui +++ b/src/plugins/clangtools/clangtoolsprojectsettingswidget.ui @@ -6,20 +6,41 @@ <rect> <x>0</x> <y>0</y> - <width>400</width> - <height>300</height> + <width>615</width> + <height>399</height> </rect> </property> <property name="windowTitle"> <string/> </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> + <layout class="QVBoxLayout" name="verticalLayout_3"> <item> <layout class="QHBoxLayout" name="horizontalLayout"> <item> - <widget class="QLabel" name="label"> + <widget class="QComboBox" name="globalCustomComboBox"> + <item> + <property name="text"> + <string>Use Global Settings</string> + </property> + </item> + <item> + <property name="text"> + <string>Use Customized Settings</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="QPushButton" name="restoreGlobal"> <property name="text"> - <string>Suppressed diagnostics:</string> + <string>Restore Global Settings</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="gotoGlobalSettingsLabel"> + <property name="text"> + <string><a href="target">Show Global Settings</a></string> </property> </widget> </item> @@ -36,52 +57,79 @@ </property> </spacer> </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_2"> <item> - <widget class="QTreeView" name="diagnosticsView"> - <property name="selectionMode"> - <enum>QAbstractItemView::SingleSelection</enum> + <widget class="QLabel" name="gotoAnalyzerModeLabel"> + <property name="text"> + <string><a href="target">Go to Analyzer</a></string> </property> </widget> </item> - <item> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QPushButton" name="removeSelectedButton"> - <property name="text"> - <string>Remove Selected</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="removeAllButton"> - <property name="text"> - <string>Remove All</string> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> </layout> </item> + <item> + <widget class="ClangTools::Internal::RunSettingsWidget" name="runSettingsWidget" native="true"/> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Suppressed diagnostics</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QTreeView" name="diagnosticsView"> + <property name="selectionMode"> + <enum>QAbstractItemView::SingleSelection</enum> + </property> + </widget> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QPushButton" name="removeSelectedButton"> + <property name="text"> + <string>Remove Selected</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="removeAllButton"> + <property name="text"> + <string>Remove All</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </widget> + </item> </layout> </widget> + <customwidgets> + <customwidget> + <class>ClangTools::Internal::RunSettingsWidget</class> + <extends>QWidget</extends> + <header>clangtools/runsettingswidget.h</header> + <container>1</container> + </customwidget> + </customwidgets> <resources/> <connections/> </ui> diff --git a/src/plugins/clangtools/clangtoolssettings.cpp b/src/plugins/clangtools/clangtoolssettings.cpp index 86f152f660..07b9592a8e 100644 --- a/src/plugins/clangtools/clangtoolssettings.cpp +++ b/src/plugins/clangtools/clangtoolssettings.cpp @@ -29,160 +29,112 @@ #include <coreplugin/icore.h> -#include <utils/hostosinfo.h> -#include <utils/qtcassert.h> - -#include <QFileInfo> #include <QThread> -static const char simultaneousProcessesKey[] = "simultaneousProcesses"; -static const char buildBeforeAnalysisKey[] = "buildBeforeAnalysis"; -static const char diagnosticConfigIdKey[] = "diagnosticConfigId"; -static const char clangTidyExecutableKey[] = "clangTidyExecutable"; -static const char clazyStandaloneExecutableKey[] = "clazyStandaloneExecutable"; +static const char clangTidyExecutableKey[] = "ClangTidyExecutable"; +static const char clazyStandaloneExecutableKey[] = "ClazyStandaloneExecutable"; -namespace ClangTools { -namespace Internal { +static const char parallelJobsKey[] = "ParallelJobs"; +static const char buildBeforeAnalysisKey[] = "BuildBeforeAnalysis"; -ClangToolsSettings::ClangToolsSettings() -{ - readSettings(); -} +static const char oldDiagnosticConfigIdKey[] = "diagnosticConfigId"; -ClangToolsSettings *ClangToolsSettings::instance() -{ - static ClangToolsSettings instance; - return &instance; -} +namespace ClangTools { +namespace Internal { -int ClangToolsSettings::savedSimultaneousProcesses() const +RunSettings::RunSettings() + : m_parallelJobs(qMax(0, QThread::idealThreadCount() / 2)) { - return m_savedSimultaneousProcesses; } -int ClangToolsSettings::simultaneousProcesses() const +void RunSettings::fromMap(const QVariantMap &map, const QString &prefix) { - return m_simultaneousProcesses; + m_diagnosticConfigId = Core::Id::fromSetting(map.value(prefix + diagnosticConfigIdKey)); + m_parallelJobs = map.value(prefix + parallelJobsKey).toInt(); + m_buildBeforeAnalysis = map.value(prefix + buildBeforeAnalysisKey).toBool(); } -void ClangToolsSettings::setSimultaneousProcesses(int processes) +void RunSettings::toMap(QVariantMap &map, const QString &prefix) const { - m_simultaneousProcesses = processes; + map.insert(prefix + diagnosticConfigIdKey, m_diagnosticConfigId.toSetting()); + map.insert(prefix + parallelJobsKey, m_parallelJobs); + map.insert(prefix + buildBeforeAnalysisKey, m_buildBeforeAnalysis); } -bool ClangToolsSettings::savedBuildBeforeAnalysis() const +ClangToolsSettings::ClangToolsSettings() { - return m_savedBuildBeforeAnalysis; + readSettings(); } -bool ClangToolsSettings::buildBeforeAnalysis() const +ClangToolsSettings *ClangToolsSettings::instance() { - return m_buildBeforeAnalysis; + static ClangToolsSettings instance; + return &instance; } -void ClangToolsSettings::setBuildBeforeAnalysis(bool build) +static QVariantMap convertToMapFromVersionBefore410(QSettings *s) { - m_buildBeforeAnalysis = build; -} + const char oldParallelJobsKey[] = "simultaneousProcesses"; + const char oldBuildBeforeAnalysisKey[] = "buildBeforeAnalysis"; -Core::Id ClangToolsSettings::savedDiagnosticConfigId() const -{ - return m_savedDiagnosticConfigId; -} + QVariantMap map; + map.insert(diagnosticConfigIdKey, s->value(oldDiagnosticConfigIdKey)); + map.insert(parallelJobsKey, s->value(oldParallelJobsKey)); + map.insert(buildBeforeAnalysisKey, s->value(oldBuildBeforeAnalysisKey)); -Core::Id ClangToolsSettings::diagnosticConfigId() const -{ - return m_diagnosticConfigId; -} + s->remove(oldDiagnosticConfigIdKey); + s->remove(oldParallelJobsKey); + s->remove(oldBuildBeforeAnalysisKey); -void ClangToolsSettings::setDiagnosticConfigId(Core::Id id) -{ - m_diagnosticConfigId = id; + return map; } -void ClangToolsSettings::updateSavedBuildBeforeAnalysiIfRequired() -{ - if (m_savedBuildBeforeAnalysis == m_buildBeforeAnalysis) - return; - m_savedBuildBeforeAnalysis = m_buildBeforeAnalysis; - emit buildBeforeAnalysisChanged(m_savedBuildBeforeAnalysis); -} - -QString ClangToolsSettings::savedClazyStandaloneExecutable() const +void ClangToolsSettings::readSettings() { - return m_savedClazyStandaloneExecutable; -} + QSettings *s = Core::ICore::settings(); + s->beginGroup(Constants::SETTINGS_ID); + m_clangTidyExecutable = s->value(clangTidyExecutableKey).toString(); + m_clazyStandaloneExecutable = s->value(clazyStandaloneExecutableKey).toString(); -QString ClangToolsSettings::savedClangTidyExecutable() const -{ - return m_savedClangTidyExecutable; -} + bool write = false; -QString ClangToolsSettings::clazyStandaloneExecutable() const -{ - return m_clazyStandaloneExecutable; -} + QVariantMap map; + if (!s->value(oldDiagnosticConfigIdKey).isNull()) { + map = convertToMapFromVersionBefore410(s); + write = true; + } else { + QVariantMap defaults; + defaults.insert(diagnosticConfigIdKey, m_runSettings.diagnosticConfigId().toSetting()); + defaults.insert(parallelJobsKey, m_runSettings.parallelJobs()); + defaults.insert(buildBeforeAnalysisKey, m_runSettings.buildBeforeAnalysis()); + map = defaults; + for (QVariantMap::ConstIterator it = defaults.constBegin(); it != defaults.constEnd(); ++it) + map.insert(it.key(), s->value(it.key(), it.value())); + } -void ClangToolsSettings::setClazyStandaloneExecutable(const QString &path) -{ - m_clazyStandaloneExecutable = path; -} + // Run settings + m_runSettings.fromMap(map); -QString ClangToolsSettings::clangTidyExecutable() const -{ - return m_clangTidyExecutable; -} + s->endGroup(); -void ClangToolsSettings::setClangTidyExecutable(const QString &path) -{ - m_clangTidyExecutable = path; + if (write) + writeSettings(); } -void ClangToolsSettings::readSettings() +void ClangToolsSettings::writeSettings() { - QSettings *settings = Core::ICore::settings(); - settings->beginGroup(QLatin1String(Constants::SETTINGS_ID)); - - const int defaultSimultaneousProcesses = qMax(0, QThread::idealThreadCount() / 2); - m_savedSimultaneousProcesses = m_simultaneousProcesses - = settings->value(QString(simultaneousProcessesKey), - defaultSimultaneousProcesses).toInt(); - - m_buildBeforeAnalysis = settings->value(QString(buildBeforeAnalysisKey), true).toBool(); + QSettings *s = Core::ICore::settings(); + s->beginGroup(Constants::SETTINGS_ID); - m_savedClangTidyExecutable = m_clangTidyExecutable - = settings->value(QLatin1String(clangTidyExecutableKey)).toString(); - m_savedClazyStandaloneExecutable = m_clazyStandaloneExecutable - = settings->value(QLatin1String(clazyStandaloneExecutableKey)).toString(); + s->setValue(clangTidyExecutableKey, m_clangTidyExecutable); + s->setValue(clazyStandaloneExecutableKey, m_clazyStandaloneExecutable); - m_diagnosticConfigId = Core::Id::fromSetting(settings->value(QString(diagnosticConfigIdKey))); - if (!m_diagnosticConfigId.isValid()) - m_diagnosticConfigId = "Builtin.TidyAndClazy"; + QVariantMap map; + m_runSettings.toMap(map); + for (QVariantMap::ConstIterator it = map.constBegin(); it != map.constEnd(); ++it) + s->setValue(it.key(), it.value()); - m_savedDiagnosticConfigId = m_diagnosticConfigId; - - updateSavedBuildBeforeAnalysiIfRequired(); - - settings->endGroup(); -} - -void ClangToolsSettings::writeSettings() -{ - QSettings *settings = Core::ICore::settings(); - settings->beginGroup(QString(Constants::SETTINGS_ID)); - settings->setValue(QString(simultaneousProcessesKey), m_simultaneousProcesses); - settings->setValue(QString(buildBeforeAnalysisKey), m_buildBeforeAnalysis); - settings->setValue(QString(clangTidyExecutableKey), m_clangTidyExecutable); - settings->setValue(QString(clazyStandaloneExecutableKey), m_clazyStandaloneExecutable); - settings->setValue(QString(diagnosticConfigIdKey), m_diagnosticConfigId.toSetting()); - - m_savedSimultaneousProcesses = m_simultaneousProcesses; - m_savedDiagnosticConfigId = m_diagnosticConfigId; - m_savedClangTidyExecutable = m_clangTidyExecutable; - m_savedClazyStandaloneExecutable = m_clazyStandaloneExecutable; - updateSavedBuildBeforeAnalysiIfRequired(); - - settings->endGroup(); + s->endGroup(); } } // namespace Internal diff --git a/src/plugins/clangtools/clangtoolssettings.h b/src/plugins/clangtools/clangtoolssettings.h index 402845d20f..893dbd23f9 100644 --- a/src/plugins/clangtools/clangtoolssettings.h +++ b/src/plugins/clangtools/clangtoolssettings.h @@ -27,61 +27,61 @@ #include <coreplugin/id.h> -#include <QObject> #include <QString> namespace ClangTools { namespace Internal { -// TODO: Remove need for "saved* members -class ClangToolsSettings : public QObject +const char diagnosticConfigIdKey[] = "DiagnosticConfigId"; + +class RunSettings { - Q_OBJECT public: - static ClangToolsSettings *instance(); + RunSettings(); - void writeSettings(); + void fromMap(const QVariantMap &map, const QString &prefix = QString()); + void toMap(QVariantMap &map, const QString &prefix = QString()) const; - int savedSimultaneousProcesses() const; - bool savedBuildBeforeAnalysis() const; - Core::Id savedDiagnosticConfigId() const; - QString savedClangTidyExecutable() const; - QString savedClazyStandaloneExecutable() const; + Core::Id diagnosticConfigId() const { return m_diagnosticConfigId; } + void setDiagnosticConfigId(const Core::Id &id) { m_diagnosticConfigId = id; } - int simultaneousProcesses() const; - void setSimultaneousProcesses(int processes); + bool buildBeforeAnalysis() const { return m_buildBeforeAnalysis; } + void setBuildBeforeAnalysis(bool yesno) { m_buildBeforeAnalysis = yesno; } - bool buildBeforeAnalysis() const; - void setBuildBeforeAnalysis(bool build); + int parallelJobs() const { return m_parallelJobs; } + void setParallelJobs(int jobs) { m_parallelJobs = jobs; } + +private: + Core::Id m_diagnosticConfigId = "Builtin.TidyAndClazy"; // TODO + int m_parallelJobs = -1; + bool m_buildBeforeAnalysis = true; +}; - Core::Id diagnosticConfigId() const; - void setDiagnosticConfigId(Core::Id id); +class ClangToolsSettings +{ +public: + static ClangToolsSettings *instance(); + void writeSettings(); - QString clangTidyExecutable() const; - void setClangTidyExecutable(const QString &path); + QString clangTidyExecutable() const { return m_clangTidyExecutable; } + void setClangTidyExecutable(const QString &path) { m_clangTidyExecutable = path; } - QString clazyStandaloneExecutable() const; - void setClazyStandaloneExecutable(const QString &path); + QString clazyStandaloneExecutable() const { return m_clazyStandaloneExecutable; } + void setClazyStandaloneExecutable(const QString &path) { m_clazyStandaloneExecutable = path; } -signals: - void buildBeforeAnalysisChanged(bool checked) const; + RunSettings runSettings() const { return m_runSettings; } + void setRunSettings(const RunSettings &settings) { m_runSettings = settings; } private: ClangToolsSettings(); void readSettings(); - void updateSavedBuildBeforeAnalysiIfRequired(); - - int m_simultaneousProcesses = -1; - int m_savedSimultaneousProcesses = -1; - bool m_buildBeforeAnalysis = false; - bool m_savedBuildBeforeAnalysis= false; + // Executables QString m_clangTidyExecutable; - QString m_savedClangTidyExecutable; QString m_clazyStandaloneExecutable; - QString m_savedClazyStandaloneExecutable; - Core::Id m_diagnosticConfigId; - Core::Id m_savedDiagnosticConfigId; + + // Run settings + RunSettings m_runSettings; }; } // namespace Internal diff --git a/src/plugins/clangtools/clangtoolsunittests.cpp b/src/plugins/clangtools/clangtoolsunittests.cpp index b8546c58bd..79b7bfcc94 100644 --- a/src/plugins/clangtools/clangtoolsunittests.cpp +++ b/src/plugins/clangtools/clangtoolsunittests.cpp @@ -25,7 +25,7 @@ #include "clangtoolsunittests.h" -#include "clangtidyclazytool.h" +#include "clangtool.h" #include "clangtoolsdiagnostic.h" #include "clangtoolssettings.h" #include "clangtoolsutils.h" @@ -87,7 +87,8 @@ static CppTools::ClangDiagnosticConfig configFor(const QString &tidyChecks, config.setIsReadOnly(true); config.setClangOptions(QStringList{QStringLiteral("-Wno-everything")}); config.setClangTidyMode(CppTools::ClangDiagnosticConfig::TidyMode::ChecksPrefixList); - config.setClangTidyChecks("-*," + tidyChecks); + const QString theTidyChecks = tidyChecks.isEmpty() ? tidyChecks : "-*," + tidyChecks; + config.setClangTidyChecks(theTidyChecks); config.setClazyChecks(clazyChecks); return config; } @@ -108,14 +109,14 @@ void ClangToolsUnitTests::testProject() CppTools::Tests::ProjectOpenerAndCloser projectManager; const CppTools::ProjectInfo projectInfo = projectManager.open(projectFilePath, true); QVERIFY(projectInfo.isValid()); - ClangTool *tool = ClangTidyClazyTool::instance(); + ClangTool *tool = ClangTool::instance(); // Change configs QSharedPointer<CppTools::CppCodeModelSettings> cppToolsSettings = CppTools::codeModelSettings(); ClangToolsSettings *clangToolsSettings = ClangToolsSettings::instance(); const CppTools::ClangDiagnosticConfigs originalConfigs = cppToolsSettings ->clangCustomDiagnosticConfigs(); - const Core::Id originalId = clangToolsSettings->diagnosticConfigId(); + const Core::Id originalId = clangToolsSettings->runSettings().diagnosticConfigId(); CppTools::ClangDiagnosticConfigs modifiedConfigs = originalConfigs; modifiedConfigs.push_back(diagnosticConfig); @@ -123,15 +124,19 @@ void ClangToolsUnitTests::testProject() ExecuteOnDestruction executeOnDestruction([=]() { // Restore configs cppToolsSettings->setClangCustomDiagnosticConfigs(originalConfigs); - clangToolsSettings->setDiagnosticConfigId(originalId); + RunSettings runSettings = clangToolsSettings->runSettings(); + runSettings.setDiagnosticConfigId(originalId); + clangToolsSettings->setRunSettings(runSettings); clangToolsSettings->writeSettings(); }); cppToolsSettings->setClangCustomDiagnosticConfigs(modifiedConfigs); - clangToolsSettings->setDiagnosticConfigId(diagnosticConfig.id()); + RunSettings runSettings = clangToolsSettings->runSettings(); + runSettings.setDiagnosticConfigId(diagnosticConfig.id()); + clangToolsSettings->setRunSettings(runSettings); clangToolsSettings->writeSettings(); - tool->startTool(ClangTidyClazyTool::FileSelection::AllFiles); + tool->startTool(ClangTool::FileSelection::AllFiles); QSignalSpy waiter(tool, SIGNAL(finished(bool))); QVERIFY(waiter.wait(30000)); diff --git a/src/plugins/clangtools/runsettingswidget.cpp b/src/plugins/clangtools/runsettingswidget.cpp new file mode 100644 index 0000000000..1a26d2e7d0 --- /dev/null +++ b/src/plugins/clangtools/runsettingswidget.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "runsettingswidget.h" + +#include "ui_runsettingswidget.h" + +#include "clangtoolssettings.h" +#include "clangtoolsutils.h" + +#include <QThread> + +namespace ClangTools { +namespace Internal { + +RunSettingsWidget::RunSettingsWidget(QWidget *parent) + : QWidget(parent) + , m_ui(new Ui::RunSettingsWidget) +{ + m_ui->setupUi(this); + + connect(m_ui->diagnosticWidget, + &CppTools::ClangDiagnosticConfigsSelectionWidget::currentConfigChanged, + [this](const Core::Id &) { emit changed(); }); + // m_ui->buildBeforeAnalysis is handled in fromSettings() + connect(m_ui->parallelJobsSpinBox, + QOverload<int>::of(&QSpinBox::valueChanged), + [this](int) { emit changed(); }); +} + +RunSettingsWidget::~RunSettingsWidget() +{ + delete m_ui; +} + +void RunSettingsWidget::fromSettings(const RunSettings &s) +{ + m_ui->diagnosticWidget->refresh(s.diagnosticConfigId()); + + disconnect(m_ui->buildBeforeAnalysis, 0, 0, 0); + m_ui->buildBeforeAnalysis->setToolTip(hintAboutBuildBeforeAnalysis()); + m_ui->buildBeforeAnalysis->setCheckState(s.buildBeforeAnalysis() ? Qt::Checked : Qt::Unchecked); + connect(m_ui->buildBeforeAnalysis, &QCheckBox::toggled, [this](bool checked) { + if (!checked) + showHintAboutBuildBeforeAnalysis(); + emit changed(); + }); + + m_ui->parallelJobsSpinBox->setValue(s.parallelJobs()); + m_ui->parallelJobsSpinBox->setMinimum(1); + m_ui->parallelJobsSpinBox->setMaximum(QThread::idealThreadCount()); +} + +RunSettings RunSettingsWidget::toSettings() const +{ + RunSettings s; + s.setDiagnosticConfigId(m_ui->diagnosticWidget->currentConfigId()); + s.setBuildBeforeAnalysis(m_ui->buildBeforeAnalysis->checkState() == Qt::CheckState::Checked); + s.setParallelJobs(m_ui->parallelJobsSpinBox->value()); + + return s; +} + +} // namespace Internal +} // namespace ClangTools diff --git a/src/plugins/clangtools/runsettingswidget.h b/src/plugins/clangtools/runsettingswidget.h new file mode 100644 index 0000000000..c49bc88f75 --- /dev/null +++ b/src/plugins/clangtools/runsettingswidget.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <QWidget> + +namespace ClangTools { +namespace Internal { + +class RunSettings; + +namespace Ui { +class RunSettingsWidget; +} + +class RunSettingsWidget : public QWidget +{ + Q_OBJECT + +public: + explicit RunSettingsWidget(QWidget *parent = nullptr); + ~RunSettingsWidget(); + + void fromSettings(const RunSettings &s); + RunSettings toSettings() const; + +signals: + void changed(); + +private: + Ui::RunSettingsWidget *m_ui; +}; + +} // namespace Internal +} // namespace ClangTools diff --git a/src/plugins/clangtools/runsettingswidget.ui b/src/plugins/clangtools/runsettingswidget.ui new file mode 100644 index 0000000000..e7ad362c84 --- /dev/null +++ b/src/plugins/clangtools/runsettingswidget.ui @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ClangTools::Internal::RunSettingsWidget</class> + <widget class="QWidget" name="ClangTools::Internal::RunSettingsWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>383</width> + <height>125</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Run Options</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="CppTools::ClangDiagnosticConfigsSelectionWidget" name="diagnosticWidget" native="true"/> + </item> + <item> + <widget class="QCheckBox" name="buildBeforeAnalysis"> + <property name="text"> + <string>Build the project before analysis</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="processesLayout"> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Parallel jobs:</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="parallelJobsSpinBox"> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>32</number> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>CppTools::ClangDiagnosticConfigsSelectionWidget</class> + <extends>QWidget</extends> + <header>cpptools/clangdiagnosticconfigsselectionwidget.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/src/plugins/clangtools/settingswidget.cpp b/src/plugins/clangtools/settingswidget.cpp index de5976a04f..110135a779 100644 --- a/src/plugins/clangtools/settingswidget.cpp +++ b/src/plugins/clangtools/settingswidget.cpp @@ -30,17 +30,6 @@ #include "clangtoolsconstants.h" #include "clangtoolsutils.h" -#include <coreplugin/icore.h> - -#include <cpptools/clangdiagnosticconfigswidget.h> -#include <cpptools/cppcodemodelsettings.h> -#include <cpptools/cpptoolsreuse.h> - -#include <QDir> -#include <QThread> - -#include <memory> - namespace ClangTools { namespace Internal { @@ -48,15 +37,13 @@ static void setupPathChooser(Utils::PathChooser *const chooser, const QString &promptDiaglogTitle, const QString &placeHolderText, const QString &pathFromSettings, - const QString &historyCompleterId, - std::function<void(const QString &path)> savePath) + const QString &historyCompleterId) { chooser->setPromptDialogTitle(promptDiaglogTitle); chooser->lineEdit()->setPlaceholderText(placeHolderText); chooser->setPath(pathFromSettings); chooser->setExpectedKind(Utils::PathChooser::ExistingCommand); chooser->setHistoryCompleter(historyCompleterId); - QObject::connect(chooser, &Utils::PathChooser::rawPathChanged, savePath), chooser->setValidationFunction([chooser](Utils::FancyLineEdit *edit, QString *errorMessage) { const QString currentFilePath = chooser->fileName().toString(); Utils::PathChooser pc; @@ -92,8 +79,7 @@ SettingsWidget::SettingsWidget(ClangToolsSettings *settings, QWidget *parent) tr("Clang-Tidy Executable"), placeHolderText, path, - "ClangTools.ClangTidyExecutable.History", - [settings](const QString &path) { settings->setClangTidyExecutable(path); }); + "ClangTools.ClangTidyExecutable.History"); if (qEnvironmentVariable("QTC_USE_CLAZY_STANDALONE_PATH").isEmpty()) { m_ui->clazyStandalonePathChooser->setVisible(false); @@ -107,47 +93,23 @@ SettingsWidget::SettingsWidget(ClangToolsSettings *settings, QWidget *parent) tr("Clazy Executable"), placeHolderText, path, - "ClangTools.ClazyStandaloneExecutable.History", - [settings](const QString &path) { - settings->setClazyStandaloneExecutable(path); - }); + "ClangTools.ClazyStandaloneExecutable.History"); } // // Group box "Run Options" // - m_ui->simultaneousProccessesSpinBox->setValue(settings->savedSimultaneousProcesses()); - m_ui->simultaneousProccessesSpinBox->setMinimum(1); - m_ui->simultaneousProccessesSpinBox->setMaximum(QThread::idealThreadCount()); - connect(m_ui->simultaneousProccessesSpinBox, - QOverload<int>::of(&QSpinBox::valueChanged), - [settings](int count) { settings->setSimultaneousProcesses(count); }); - - QCheckBox *buildBeforeAnalysis = m_ui->buildBeforeAnalysis; - buildBeforeAnalysis->setToolTip(hintAboutBuildBeforeAnalysis()); - buildBeforeAnalysis->setCheckState(settings->savedBuildBeforeAnalysis() - ? Qt::Checked : Qt::Unchecked); - connect(buildBeforeAnalysis, &QCheckBox::toggled, [settings](bool checked) { - if (!checked) - showHintAboutBuildBeforeAnalysis(); - settings->setBuildBeforeAnalysis(checked); - }); - CppTools::ClangDiagnosticConfigsSelectionWidget *diagnosticWidget = m_ui->diagnosticWidget; - diagnosticWidget->refresh(settings->savedDiagnosticConfigId()); + m_ui->runSettingsWidget->fromSettings(m_settings->runSettings()); +} - connect(diagnosticWidget, - &CppTools::ClangDiagnosticConfigsSelectionWidget::currentConfigChanged, - this, [this](const Core::Id ¤tConfigId) { - m_settings->setDiagnosticConfigId(currentConfigId); - }); +void SettingsWidget::apply() +{ + m_settings->setClangTidyExecutable(m_ui->clangTidyPathChooser->rawPath()); + m_settings->setClazyStandaloneExecutable(m_ui->clazyStandalonePathChooser->rawPath()); + m_settings->setRunSettings(m_ui->runSettingsWidget->toSettings()); - connect(CppTools::codeModelSettings().data(), &CppTools::CppCodeModelSettings::changed, - this, [=]() { - // Settings were applied so apply also the current selection if possible. - diagnosticWidget->refresh(m_settings->diagnosticConfigId()); - m_settings->writeSettings(); - }); + m_settings->writeSettings(); } SettingsWidget::~SettingsWidget() = default; diff --git a/src/plugins/clangtools/settingswidget.h b/src/plugins/clangtools/settingswidget.h index 6eeaeb5d98..2002f32eec 100644 --- a/src/plugins/clangtools/settingswidget.h +++ b/src/plugins/clangtools/settingswidget.h @@ -43,6 +43,9 @@ class SettingsWidget : public QWidget public: SettingsWidget(ClangToolsSettings *settings, QWidget *parent = nullptr); ~SettingsWidget() override; + + void apply(); + private: std::unique_ptr<Ui::SettingsWidget> m_ui; ClangToolsSettings *m_settings; diff --git a/src/plugins/clangtools/settingswidget.ui b/src/plugins/clangtools/settingswidget.ui index c73148d0da..6ef3d09297 100644 --- a/src/plugins/clangtools/settingswidget.ui +++ b/src/plugins/clangtools/settingswidget.ui @@ -44,57 +44,7 @@ </widget> </item> <item> - <widget class="QGroupBox" name="groupBox"> - <property name="title"> - <string>Run Options</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <widget class="CppTools::ClangDiagnosticConfigsSelectionWidget" name="diagnosticWidget" native="true"/> - </item> - <item> - <widget class="QCheckBox" name="buildBeforeAnalysis"> - <property name="text"> - <string>Build the project before analysis</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="processesLayout"> - <item> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Simultaneous processes:</string> - </property> - </widget> - </item> - <item> - <widget class="QSpinBox" name="simultaneousProccessesSpinBox"> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>32</number> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - </layout> - </widget> + <widget class="ClangTools::Internal::RunSettingsWidget" name="runSettingsWidget" native="true"/> </item> <item> <spacer name="verticalSpacer"> @@ -113,14 +63,15 @@ </widget> <customwidgets> <customwidget> - <class>CppTools::ClangDiagnosticConfigsSelectionWidget</class> + <class>Utils::PathChooser</class> <extends>QWidget</extends> - <header>cpptools/clangdiagnosticconfigsselectionwidget.h</header> + <header location="global">utils/pathchooser.h</header> + <container>1</container> </customwidget> <customwidget> - <class>Utils::PathChooser</class> + <class>ClangTools::Internal::RunSettingsWidget</class> <extends>QWidget</extends> - <header location="global">utils/pathchooser.h</header> + <header>clangtools/runsettingswidget.h</header> <container>1</container> </customwidget> </customwidgets> diff --git a/src/plugins/coreplugin/windowsupport.cpp b/src/plugins/coreplugin/windowsupport.cpp index 17bab61bcc..26117ba12f 100644 --- a/src/plugins/coreplugin/windowsupport.cpp +++ b/src/plugins/coreplugin/windowsupport.cpp @@ -40,6 +40,7 @@ #include <QEvent> #include <QMenu> #include <QWidget> +#include <QWindowStateChangeEvent> namespace Core { namespace Internal { @@ -111,6 +112,7 @@ bool WindowSupport::eventFilter(QObject *obj, QEvent *event) m_minimizeAction->setEnabled(!minimized); m_zoomAction->setEnabled(!minimized); } + m_previousWindowState = static_cast<QWindowStateChangeEvent *>(event)->oldState(); updateFullScreenAction(); } else if (event->type() == QEvent::WindowActivate) { m_windowList->setActiveWindow(m_window); @@ -126,7 +128,7 @@ bool WindowSupport::eventFilter(QObject *obj, QEvent *event) void WindowSupport::toggleFullScreen() { if (m_window->isFullScreen()) { - m_window->setWindowState(m_window->windowState() & ~Qt::WindowFullScreen); + m_window->setWindowState(m_previousWindowState & ~Qt::WindowFullScreen); } else { m_window->setWindowState(m_window->windowState() | Qt::WindowFullScreen); } diff --git a/src/plugins/coreplugin/windowsupport.h b/src/plugins/coreplugin/windowsupport.h index 5531306fe0..1e640f6edb 100644 --- a/src/plugins/coreplugin/windowsupport.h +++ b/src/plugins/coreplugin/windowsupport.h @@ -80,6 +80,7 @@ private: QAction *m_zoomAction; QAction *m_closeAction; QAction *m_toggleFullScreenAction; + Qt::WindowStates m_previousWindowState; bool m_shutdown = false; }; diff --git a/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp b/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp index 4120aaee21..dbb70ca07a 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp @@ -26,14 +26,25 @@ #include "setframevaluedialog.h" #include "ui_setframevaluedialog.h" +#include <QIntValidator> + namespace QmlDesigner { -SetFrameValueDialog::SetFrameValueDialog(QWidget *parent) +SetFrameValueDialog::SetFrameValueDialog(qreal frame, const QVariant &value, + const QString &propertyName, QWidget *parent) : QDialog(parent) , ui(new Ui::SetFrameValueDialog) { - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); ui->setupUi(this); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setWindowTitle(tr("Edit Keyframe")); + setFixedSize(size()); + + ui->lineEditFrame->setValidator(new QIntValidator(0, 99999, this)); + + ui->lineEditFrame->setText(QString::number(frame)); + ui->lineEditValue->setText(value.toString()); + ui->labelValue->setText(propertyName); } SetFrameValueDialog::~SetFrameValueDialog() @@ -41,15 +52,14 @@ SetFrameValueDialog::~SetFrameValueDialog() delete ui; } -QLineEdit *SetFrameValueDialog::lineEdit() const +qreal SetFrameValueDialog::frame() const { - return ui->lineEdit; + return ui->lineEditFrame->text().toDouble(); } -void SetFrameValueDialog::setPropertName(const QString &name) +QVariant SetFrameValueDialog::value() const { - setWindowTitle(tr("Change %1").arg(name)); - ui->label->setText(name); + return QVariant(ui->lineEditValue->text()); } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.h b/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.h index e7ed226b67..799e3fadc5 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.h +++ b/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.h @@ -40,12 +40,12 @@ class SetFrameValueDialog : public QDialog Q_OBJECT public: - explicit SetFrameValueDialog(QWidget *parent = nullptr); + explicit SetFrameValueDialog(qreal frame, const QVariant &value, const QString &propertyName, + QWidget *parent = nullptr); ~SetFrameValueDialog() override; - QLineEdit *lineEdit() const; - - void setPropertName(const QString &name); + qreal frame() const; + QVariant value() const; private: Ui::SetFrameValueDialog *ui; diff --git a/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.ui b/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.ui index 2fa1241e4a..1fe2468a6b 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.ui +++ b/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>184</width> - <height>79</height> + <height>93</height> </rect> </property> <property name="windowTitle"> @@ -15,16 +15,13 @@ </property> <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0"> - <widget class="QLabel" name="label"> + <widget class="QLabel" name="labelFrame"> <property name="text"> - <string>Value</string> + <string>Frame</string> </property> </widget> </item> - <item row="0" column="1"> - <widget class="QLineEdit" name="lineEdit"/> - </item> - <item row="1" column="0" colspan="2"> + <item row="2" column="0" colspan="2"> <widget class="QDialogButtonBox" name="buttonBox"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -34,6 +31,19 @@ </property> </widget> </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="lineEditFrame"/> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="lineEditValue"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="labelValue"> + <property name="text"> + <string>Value</string> + </property> + </widget> + </item> </layout> </widget> <resources/> diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelineconstants.h b/src/plugins/qmldesigner/components/timelineeditor/timelineconstants.h index c2a8137352..622dc366ed 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelineconstants.h +++ b/src/plugins/qmldesigner/components/timelineeditor/timelineconstants.h @@ -54,7 +54,8 @@ const char timelineInsertKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesigner const char timelineDeleteKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Delete All Keyframes"); -const char timelineStatusBarFrameNumber[] = QT_TRANSLATE_NOOP("QmlDesignerTimeline", "Frame %1"); +const char statusBarPlayheadFrame[] = QT_TRANSLATE_NOOP("QmlDesignerTimeline", "Playhead frame %1"); +const char statusBarKeyframe[] = QT_TRANSLATE_NOOP("QmlDesignerTimeline", "Keyframe %1"); const char C_QMLTIMELINE[] = "QmlDesigner::Timeline"; const char C_SETTINGS[] = "QmlDesigner.Settings"; diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp index 97ebb7e84d..a5f6110812 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp @@ -187,14 +187,14 @@ void TimelineGraphicsScene::setCurrentFrame(int frame) if (timeline.isValid()) { timeline.modelNode().setAuxiliaryData("currentFrame@NodeInstance", frame); - m_currentFrameIndicator->setPosition(frame + timeline.startKeyframe()); + m_currentFrameIndicator->setPosition(frame); } else { m_currentFrameIndicator->setPosition(0); } invalidateCurrentValues(); - emitStatusBarFrameMessageChanged(frame); + emitStatusBarPlayheadFrameChanged(frame); } void TimelineGraphicsScene::setStartFrame(int frame) @@ -318,7 +318,7 @@ void TimelineGraphicsScene::commitCurrentFrame(qreal frame) setCurrenFrame(timeline, qRound(frame)); invalidateCurrentValues(); } - emitStatusBarFrameMessageChanged(int(frame)); + emitStatusBarPlayheadFrameChanged(int(frame)); } QList<TimelineKeyframeItem *> TimelineGraphicsScene::selectedKeyframes() const @@ -700,10 +700,10 @@ void TimelineGraphicsScene::emitScrollOffsetChanged() TimelineMovableAbstractItem::emitScrollOffsetChanged(item); } -void TimelineGraphicsScene::emitStatusBarFrameMessageChanged(int frame) +void TimelineGraphicsScene::emitStatusBarPlayheadFrameChanged(int frame) { emit statusBarMessageChanged( - QString(TimelineConstants::timelineStatusBarFrameNumber).arg(frame)); + tr(TimelineConstants::statusBarPlayheadFrame).arg(frame)); } bool TimelineGraphicsScene::event(QEvent *event) diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.h b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.h index b8f93595c4..d03a6a5824 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.h +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.h @@ -160,7 +160,7 @@ private: ModelNode timelineModelNode() const; void emitScrollOffsetChanged(); - void emitStatusBarFrameMessageChanged(int frame); + void emitStatusBarPlayheadFrameChanged(int frame); QList<QGraphicsItem *> itemsAt(const QPointF &pos); diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.cpp index 4db4567fd6..1d700cf063 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.cpp @@ -46,6 +46,11 @@ void TimelineMovableAbstractItem::itemMoved(const QPointF & /*start*/, const QPo setPositionInteractive(end); } +void TimelineMovableAbstractItem::itemDoubleClicked() +{ + // to be overridden by child classes if needed +} + int TimelineMovableAbstractItem::scrollOffset() const { return timelineScene()->scrollOffset(); diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.h b/src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.h index 0830facfbf..cf71397225 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.h +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.h @@ -57,6 +57,7 @@ public: virtual void setPositionInteractive(const QPointF &point); virtual void commitPosition(const QPointF &point); virtual void itemMoved(const QPointF &start, const QPointF &end); + virtual void itemDoubleClicked(); int xPosScrollOffset(int x) const; diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinemovetool.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinemovetool.cpp index 0e68a63ff4..71c76e5f67 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinemovetool.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinemovetool.cpp @@ -100,6 +100,9 @@ void TimelineMoveTool::mouseMoveEvent(TimelineMovableAbstractItem *item, current->setPosition(sourceFrame + deltaFrame); + scene()->statusBarMessageChanged(tr(TimelineConstants::statusBarKeyframe) + .arg(sourceFrame + deltaFrame)); + for (auto *keyframe : scene()->selectedKeyframes()) { if (keyframe != current) { qreal pos = std::round(current->mapFromSceneToFrame(keyframe->rect().center().x())); @@ -125,29 +128,36 @@ void TimelineMoveTool::mouseReleaseEvent(TimelineMovableAbstractItem *item, double start = current->mapFromFrameToScene(scene()->startFrame()); double end = current->mapFromFrameToScene(scene()->endFrame()); - if (mousePos < start) { - scene()->setCurrentFrame(scene()->startFrame()); - scene()->statusBarMessageChanged(QObject::tr("Frame %1").arg(scene()->startFrame())); - return; - } else if (mousePos > end) { - scene()->setCurrentFrame(scene()->endFrame()); - scene()->statusBarMessageChanged(QObject::tr("Frame %1").arg(scene()->endFrame())); + double limitFrame = -999999.; + if (mousePos < start) + limitFrame = scene()->startFrame(); + else if (mousePos > end) + limitFrame = scene()->endFrame(); + + if (limitFrame > -999999.) { + scene()->setCurrentFrame(limitFrame); + scene()->statusBarMessageChanged( + tr(TimelineConstants::statusBarPlayheadFrame).arg(limitFrame)); return; } } - scene()->timelineView()->executeInTransaction("TimelineMoveTool::mouseReleaseEvent", [this, current](){ + scene()->timelineView()->executeInTransaction("TimelineMoveTool::mouseReleaseEvent", + [this, current]() { current->commitPosition(mapToItem(current, current->rect().center())); if (current->asTimelineKeyframeItem()) { double frame = std::round( current->mapFromSceneToFrame(current->rect().center().x())); - scene()->statusBarMessageChanged(QObject::tr("Frame %1").arg(frame)); + scene()->statusBarMessageChanged( + tr(TimelineConstants::statusBarKeyframe).arg(frame)); - for (auto keyframe : scene()->selectedKeyframes()) + const auto selectedKeyframes = scene()->selectedKeyframes(); + for (auto keyframe : selectedKeyframes) { if (keyframe != current) keyframe->commitPosition(mapToItem(current, keyframe->rect().center())); + } } }); } diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinemovetool.h b/src/plugins/qmldesigner/components/timelineeditor/timelinemovetool.h index 55b9a39417..20b9537af9 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinemovetool.h +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinemovetool.h @@ -27,6 +27,7 @@ #include "timelineabstracttool.h" +#include <QCoreApplication> #include <QPointF> QT_FORWARD_DECLARE_CLASS(QGraphicsRectItem) @@ -37,6 +38,8 @@ class TimelineMovableAbstractItem; class TimelineMoveTool : public TimelineAbstractTool { + Q_DECLARE_TR_FUNCTIONS(TimelineMoveTool) + public: explicit TimelineMoveTool(TimelineGraphicsScene *scene, TimelineToolDelegate *delegate); void mousePressEvent(TimelineMovableAbstractItem *item, diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp index beeca23183..920a8b35ca 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp @@ -106,31 +106,40 @@ static void setEasingCurve(TimelineGraphicsScene *scene, const QList<ModelNode> EasingCurveDialog::runDialog(keys); } -static void editValue(const ModelNode &frame, const QString &propertyName) +// display and handle the edit keyframe dialog +static void editValue(const ModelNode &frameNode, const std::pair<qreal, qreal> &timelineRange, + const QString &propertyName) { - const QVariant value = frame.variantProperty("value").value(); - auto dialog = new SetFrameValueDialog(Core::ICore::dialogParent()); - - dialog->lineEdit()->setText(value.toString()); - dialog->setPropertName(propertyName); + const qreal frame = frameNode.variantProperty("frame").value().toReal(); + const QVariant value = frameNode.variantProperty("value").value(); + auto dialog = new SetFrameValueDialog(frame, value, propertyName, + Core::ICore::dialogParent()); QObject::connect(dialog, &SetFrameValueDialog::rejected, [dialog]() { dialog->deleteLater(); }); - QObject::connect(dialog, &SetFrameValueDialog::accepted, [dialog, frame, value]() { + QObject::connect(dialog, &SetFrameValueDialog::accepted, [dialog, frameNode, frame, value, + timelineRange]() { dialog->deleteLater(); + + qreal newFrame = qBound(timelineRange.first, dialog->frame(), timelineRange.second); + if (newFrame != frame) + frameNode.variantProperty("frame").setValue(newFrame); + int userType = value.userType(); - const QVariant result = dialog->lineEdit()->text(); - - if (result.canConvert(userType)) { - QVariant newValue = result; - newValue.convert(userType); - // canConvert gives true in case if the result is a double but the usertype was interger - // try to fix that with a workaround to convert it to double if convertion resulted in isNull - if (newValue.isNull()) { - newValue = result; - newValue.convert(QMetaType::Double); + QVariant newValue = dialog->value(); + + if (newValue.canConvert(userType)) { + QVariant newValueConverted = newValue; + bool converted = newValueConverted.convert(userType); + + if (!converted) { + // convert() fails for int to double, so we try this combination + newValueConverted = newValue; + converted = newValueConverted.convert(QMetaType::Double); } - frame.variantProperty("value").setValue(result); + + if (converted) + frameNode.variantProperty("value").setValue(newValueConverted); } }); @@ -431,9 +440,12 @@ void TimelinePropertyItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *even setEasingCurve(timelineScene(), {currentFrameNode}); }); - QAction *editValueAction = mainMenu.addAction(tr("Edit Value for Keyframe...")); + QAction *editValueAction = mainMenu.addAction(tr("Edit Keyframe...")); QObject::connect(editValueAction, &QAction::triggered, [this, currentFrameNode]() { - editValue(currentFrameNode, propertyName()); + std::pair<qreal, qreal> timelineRange + = {timelineScene()->currentTimeline().startKeyframe(), + timelineScene()->currentTimeline().endKeyframe()}; + editValue(currentFrameNode, timelineRange, propertyName()); }); const bool hasKeyframe = currentFrameNode.isValid(); @@ -541,6 +553,13 @@ void TimelineKeyframeItem::commitPosition(const QPointF &point) enableUpdates(); } +void TimelineKeyframeItem::itemDoubleClicked() +{ + std::pair<qreal, qreal> timelineRange = {timelineScene()->currentTimeline().startKeyframe(), + timelineScene()->currentTimeline().endKeyframe()}; + editValue(m_frame, timelineRange, propertyItem()->propertyName()); +} + TimelineKeyframeItem *TimelineKeyframeItem::asTimelineKeyframeItem() { return this; @@ -630,9 +649,11 @@ void TimelineKeyframeItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *even setEasingCurve(timelineScene(), keys); }); - QAction *editValueAction = mainMenu.addAction(tr("Edit Value for Keyframe...")); + QAction *editValueAction = mainMenu.addAction(tr("Edit Keyframe...")); QObject::connect(editValueAction, &QAction::triggered, [this]() { - editValue(m_frame, propertyItem()->propertyName()); + std::pair<qreal, qreal> timelineRange = {timelineScene()->currentTimeline().startKeyframe(), + timelineScene()->currentTimeline().endKeyframe()}; + editValue(m_frame, timelineRange, propertyItem()->propertyName()); }); mainMenu.exec(event->screenPos()); diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.h b/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.h index 2b8c00c59b..4544b40302 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.h +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.h @@ -63,6 +63,8 @@ public: void commitPosition(const QPointF &point) override; + void itemDoubleClicked() override; + TimelineKeyframeItem *asTimelineKeyframeItem() override; protected: diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelineselectiontool.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelineselectiontool.cpp index 987ac4935a..c9ab304497 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelineselectiontool.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelineselectiontool.cpp @@ -98,7 +98,6 @@ void TimelineSelectionTool::mouseReleaseEvent(TimelineMovableAbstractItem *item, QGraphicsSceneMouseEvent *event) { Q_UNUSED(item) - Q_UNUSED(event) commitSelection(selectionMode(event)); @@ -108,9 +107,11 @@ void TimelineSelectionTool::mouseReleaseEvent(TimelineMovableAbstractItem *item, void TimelineSelectionTool::mouseDoubleClickEvent(TimelineMovableAbstractItem *item, QGraphicsSceneMouseEvent *event) { - Q_UNUSED(item) Q_UNUSED(event) + if (item) + item->itemDoubleClicked(); + reset(); } diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinetooldelegate.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinetooldelegate.cpp index 51c5a7d088..d84a461999 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinetooldelegate.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinetooldelegate.cpp @@ -92,8 +92,10 @@ void TimelineToolDelegate::mouseReleaseEvent(TimelineMovableAbstractItem *item, void TimelineToolDelegate::mouseDoubleClickEvent(TimelineMovableAbstractItem *item, QGraphicsSceneMouseEvent *event) { - if (m_currentTool) + if (hitCanvas(event)) { + m_currentTool = m_selectTool.get(); m_currentTool->mouseDoubleClickEvent(item, event); + } reset(); } diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp index 522607f615..303c761f3c 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp @@ -405,14 +405,18 @@ void TimelineWidget::contextHelp(const Core::IContext::HelpCallback &callback) c void TimelineWidget::init() { QmlTimeline currentTimeline = m_timelineView->timelineForState(m_timelineView->currentState()); - if (currentTimeline.isValid()) + if (currentTimeline.isValid()) { setTimelineId(currentTimeline.modelNode().id()); - else + m_statusBar->setText(tr(TimelineConstants::statusBarPlayheadFrame) + .arg(getcurrentFrame(currentTimeline))); + } else { setTimelineId({}); + m_statusBar->clear(); + } - invalidateTimelineDuration(graphicsScene()->currentTimeline()); + invalidateTimelineDuration(m_graphicsScene->currentTimeline()); - graphicsScene()->setWidth(m_graphicsView->viewport()->width()); + m_graphicsScene->setWidth(m_graphicsView->viewport()->width()); // setScaleFactor uses QSignalBlocker. m_toolbar->setScaleFactor(0); @@ -442,7 +446,14 @@ void TimelineWidget::invalidateTimelineDuration(const QmlTimeline &timeline) QmlTimeline currentTimeline = graphicsScene()->currentTimeline(); if (currentTimeline.isValid() && currentTimeline == timeline) { graphicsScene()->setTimeline(timeline); - graphicsScene()->setCurrenFrame(timeline, getcurrentFrame(timeline)); + + qreal playHeadFrame = getcurrentFrame(timeline); + if (playHeadFrame < timeline.startKeyframe()) + playHeadFrame = timeline.startKeyframe(); + else if (playHeadFrame > timeline.endKeyframe()) + playHeadFrame = timeline.endKeyframe(); + + graphicsScene()->setCurrentFrame(playHeadFrame); } } } |