forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/4.11'
Change-Id: I3fd1723e8c097bf6df8933c122fcc006ad0af9e7
This commit is contained in:
@ -130,12 +130,71 @@
|
||||
<translation>Анализатор</translation>
|
||||
</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>
|
||||
@ -7116,6 +7175,10 @@ p, li { white-space: pre-wrap; }
|
||||
<source>Recent</source>
|
||||
<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>
|
||||
@ -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>
|
||||
@ -18417,6 +18480,10 @@ will also disable the following plugins:
|
||||
<source>Determines whether the Flickable will give a feeling that the edges of the view are soft, rather than a hard physical boundary.</source>
|
||||
<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>
|
||||
@ -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>
|
||||
@ -38765,6 +38832,10 @@ For more details, see /etc/sysctl.d/10-ptrace.conf
|
||||
<source>Type</source>
|
||||
<translation>Тип</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Change the type of this item.</source>
|
||||
<translation>Меняет тип этого элемента.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>id</source>
|
||||
<translation>идентификатор</translation>
|
||||
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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)
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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\".")
|
||||
|
@ -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:
|
||||
private:
|
||||
RunSettings m_runSettings;
|
||||
CppTools::ClangDiagnosticConfig m_diagnosticConfig;
|
||||
FileInfos m_fileInfos;
|
||||
|
||||
ProjectBuilder *m_projectBuilder = nullptr;
|
||||
Utils::Environment m_environment;
|
||||
Utils::TemporaryDirectory m_temporaryDir;
|
||||
|
||||
private:
|
||||
CppTools::ClangDiagnosticConfig m_diagnosticConfig;
|
||||
FileInfos m_fileInfos;
|
||||
|
||||
CppTools::ProjectInfo m_projectInfoBeforeBuild;
|
||||
CppTools::ProjectInfo m_projectInfo;
|
||||
QString m_targetTriple;
|
||||
|
@ -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) {
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
// Read map
|
||||
m_useGlobalSettings = map.value(SETTINGS_KEY_USE_GLOBAL_SETTINGS).toBool();
|
||||
|
||||
auto toFileName = [](const QString &s) { return Utils::FilePath::fromString(s); };
|
||||
|
||||
const QStringList dirs = m_project->namedSettings(SETTINGS_KEY_SELECTED_DIRS).toStringList();
|
||||
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;
|
||||
}
|
||||
m_runSettings.toMap(map, SETTINGS_PREFIX);
|
||||
|
||||
void ClangToolsProjectSettings::setUseGlobalSettings(bool useGlobalSettings)
|
||||
{
|
||||
m_useGlobalSettings = useGlobalSettings;
|
||||
}
|
||||
|
||||
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()
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
|
@ -44,6 +44,8 @@ public:
|
||||
~ProjectSettingsWidget() override;
|
||||
|
||||
private:
|
||||
void onGlobalCustomChanged(int index);
|
||||
|
||||
void updateButtonStates();
|
||||
void updateButtonStateRemoveSelected();
|
||||
void updateButtonStateRemoveAll();
|
||||
|
@ -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>
|
||||
|
@ -29,21 +29,38 @@
|
||||
|
||||
#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";
|
||||
|
||||
static const char parallelJobsKey[] = "ParallelJobs";
|
||||
static const char buildBeforeAnalysisKey[] = "BuildBeforeAnalysis";
|
||||
|
||||
static const char oldDiagnosticConfigIdKey[] = "diagnosticConfigId";
|
||||
|
||||
namespace ClangTools {
|
||||
namespace Internal {
|
||||
|
||||
RunSettings::RunSettings()
|
||||
: m_parallelJobs(qMax(0, QThread::idealThreadCount() / 2))
|
||||
{
|
||||
}
|
||||
|
||||
void RunSettings::fromMap(const QVariantMap &map, const QString &prefix)
|
||||
{
|
||||
m_diagnosticConfigId = Core::Id::fromSetting(map.value(prefix + diagnosticConfigIdKey));
|
||||
m_parallelJobs = map.value(prefix + parallelJobsKey).toInt();
|
||||
m_buildBeforeAnalysis = map.value(prefix + buildBeforeAnalysisKey).toBool();
|
||||
}
|
||||
|
||||
void RunSettings::toMap(QVariantMap &map, const QString &prefix) const
|
||||
{
|
||||
map.insert(prefix + diagnosticConfigIdKey, m_diagnosticConfigId.toSetting());
|
||||
map.insert(prefix + parallelJobsKey, m_parallelJobs);
|
||||
map.insert(prefix + buildBeforeAnalysisKey, m_buildBeforeAnalysis);
|
||||
}
|
||||
|
||||
ClangToolsSettings::ClangToolsSettings()
|
||||
{
|
||||
readSettings();
|
||||
@ -55,134 +72,69 @@ ClangToolsSettings *ClangToolsSettings::instance()
|
||||
return &instance;
|
||||
}
|
||||
|
||||
int ClangToolsSettings::savedSimultaneousProcesses() const
|
||||
static QVariantMap convertToMapFromVersionBefore410(QSettings *s)
|
||||
{
|
||||
return m_savedSimultaneousProcesses;
|
||||
}
|
||||
const char oldParallelJobsKey[] = "simultaneousProcesses";
|
||||
const char oldBuildBeforeAnalysisKey[] = "buildBeforeAnalysis";
|
||||
|
||||
int ClangToolsSettings::simultaneousProcesses() const
|
||||
{
|
||||
return m_simultaneousProcesses;
|
||||
}
|
||||
QVariantMap map;
|
||||
map.insert(diagnosticConfigIdKey, s->value(oldDiagnosticConfigIdKey));
|
||||
map.insert(parallelJobsKey, s->value(oldParallelJobsKey));
|
||||
map.insert(buildBeforeAnalysisKey, s->value(oldBuildBeforeAnalysisKey));
|
||||
|
||||
void ClangToolsSettings::setSimultaneousProcesses(int processes)
|
||||
{
|
||||
m_simultaneousProcesses = processes;
|
||||
}
|
||||
s->remove(oldDiagnosticConfigIdKey);
|
||||
s->remove(oldParallelJobsKey);
|
||||
s->remove(oldBuildBeforeAnalysisKey);
|
||||
|
||||
bool ClangToolsSettings::savedBuildBeforeAnalysis() const
|
||||
{
|
||||
return m_savedBuildBeforeAnalysis;
|
||||
}
|
||||
|
||||
bool ClangToolsSettings::buildBeforeAnalysis() const
|
||||
{
|
||||
return m_buildBeforeAnalysis;
|
||||
}
|
||||
|
||||
void ClangToolsSettings::setBuildBeforeAnalysis(bool build)
|
||||
{
|
||||
m_buildBeforeAnalysis = build;
|
||||
}
|
||||
|
||||
Core::Id ClangToolsSettings::savedDiagnosticConfigId() const
|
||||
{
|
||||
return m_savedDiagnosticConfigId;
|
||||
}
|
||||
|
||||
Core::Id ClangToolsSettings::diagnosticConfigId() const
|
||||
{
|
||||
return m_diagnosticConfigId;
|
||||
}
|
||||
|
||||
void ClangToolsSettings::setDiagnosticConfigId(Core::Id id)
|
||||
{
|
||||
m_diagnosticConfigId = id;
|
||||
}
|
||||
|
||||
void ClangToolsSettings::updateSavedBuildBeforeAnalysiIfRequired()
|
||||
{
|
||||
if (m_savedBuildBeforeAnalysis == m_buildBeforeAnalysis)
|
||||
return;
|
||||
m_savedBuildBeforeAnalysis = m_buildBeforeAnalysis;
|
||||
emit buildBeforeAnalysisChanged(m_savedBuildBeforeAnalysis);
|
||||
}
|
||||
|
||||
QString ClangToolsSettings::savedClazyStandaloneExecutable() const
|
||||
{
|
||||
return m_savedClazyStandaloneExecutable;
|
||||
}
|
||||
|
||||
QString ClangToolsSettings::savedClangTidyExecutable() const
|
||||
{
|
||||
return m_savedClangTidyExecutable;
|
||||
}
|
||||
|
||||
QString ClangToolsSettings::clazyStandaloneExecutable() const
|
||||
{
|
||||
return m_clazyStandaloneExecutable;
|
||||
}
|
||||
|
||||
void ClangToolsSettings::setClazyStandaloneExecutable(const QString &path)
|
||||
{
|
||||
m_clazyStandaloneExecutable = path;
|
||||
}
|
||||
|
||||
QString ClangToolsSettings::clangTidyExecutable() const
|
||||
{
|
||||
return m_clangTidyExecutable;
|
||||
}
|
||||
|
||||
void ClangToolsSettings::setClangTidyExecutable(const QString &path)
|
||||
{
|
||||
m_clangTidyExecutable = path;
|
||||
return map;
|
||||
}
|
||||
|
||||
void ClangToolsSettings::readSettings()
|
||||
{
|
||||
QSettings *settings = Core::ICore::settings();
|
||||
settings->beginGroup(QLatin1String(Constants::SETTINGS_ID));
|
||||
QSettings *s = Core::ICore::settings();
|
||||
s->beginGroup(Constants::SETTINGS_ID);
|
||||
m_clangTidyExecutable = s->value(clangTidyExecutableKey).toString();
|
||||
m_clazyStandaloneExecutable = s->value(clazyStandaloneExecutableKey).toString();
|
||||
|
||||
const int defaultSimultaneousProcesses = qMax(0, QThread::idealThreadCount() / 2);
|
||||
m_savedSimultaneousProcesses = m_simultaneousProcesses
|
||||
= settings->value(QString(simultaneousProcessesKey),
|
||||
defaultSimultaneousProcesses).toInt();
|
||||
bool write = false;
|
||||
|
||||
m_buildBeforeAnalysis = settings->value(QString(buildBeforeAnalysisKey), true).toBool();
|
||||
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()));
|
||||
}
|
||||
|
||||
m_savedClangTidyExecutable = m_clangTidyExecutable
|
||||
= settings->value(QLatin1String(clangTidyExecutableKey)).toString();
|
||||
m_savedClazyStandaloneExecutable = m_clazyStandaloneExecutable
|
||||
= settings->value(QLatin1String(clazyStandaloneExecutableKey)).toString();
|
||||
// Run settings
|
||||
m_runSettings.fromMap(map);
|
||||
|
||||
m_diagnosticConfigId = Core::Id::fromSetting(settings->value(QString(diagnosticConfigIdKey)));
|
||||
if (!m_diagnosticConfigId.isValid())
|
||||
m_diagnosticConfigId = "Builtin.TidyAndClazy";
|
||||
s->endGroup();
|
||||
|
||||
m_savedDiagnosticConfigId = m_diagnosticConfigId;
|
||||
|
||||
updateSavedBuildBeforeAnalysiIfRequired();
|
||||
|
||||
settings->endGroup();
|
||||
if (write)
|
||||
writeSettings();
|
||||
}
|
||||
|
||||
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());
|
||||
QSettings *s = Core::ICore::settings();
|
||||
s->beginGroup(Constants::SETTINGS_ID);
|
||||
|
||||
m_savedSimultaneousProcesses = m_simultaneousProcesses;
|
||||
m_savedDiagnosticConfigId = m_diagnosticConfigId;
|
||||
m_savedClangTidyExecutable = m_clangTidyExecutable;
|
||||
m_savedClazyStandaloneExecutable = m_clazyStandaloneExecutable;
|
||||
updateSavedBuildBeforeAnalysiIfRequired();
|
||||
s->setValue(clangTidyExecutableKey, m_clangTidyExecutable);
|
||||
s->setValue(clazyStandaloneExecutableKey, m_clazyStandaloneExecutable);
|
||||
|
||||
settings->endGroup();
|
||||
QVariantMap map;
|
||||
m_runSettings.toMap(map);
|
||||
for (QVariantMap::ConstIterator it = map.constBegin(); it != map.constEnd(); ++it)
|
||||
s->setValue(it.key(), it.value());
|
||||
|
||||
s->endGroup();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
@ -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
|
||||
{
|
||||
public:
|
||||
RunSettings();
|
||||
|
||||
void fromMap(const QVariantMap &map, const QString &prefix = QString());
|
||||
void toMap(QVariantMap &map, const QString &prefix = QString()) const;
|
||||
|
||||
Core::Id diagnosticConfigId() const { return m_diagnosticConfigId; }
|
||||
void setDiagnosticConfigId(const Core::Id &id) { m_diagnosticConfigId = id; }
|
||||
|
||||
bool buildBeforeAnalysis() const { return m_buildBeforeAnalysis; }
|
||||
void setBuildBeforeAnalysis(bool yesno) { m_buildBeforeAnalysis = yesno; }
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
class ClangToolsSettings
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static ClangToolsSettings *instance();
|
||||
|
||||
void writeSettings();
|
||||
|
||||
int savedSimultaneousProcesses() const;
|
||||
bool savedBuildBeforeAnalysis() const;
|
||||
Core::Id savedDiagnosticConfigId() const;
|
||||
QString savedClangTidyExecutable() const;
|
||||
QString savedClazyStandaloneExecutable() const;
|
||||
QString clangTidyExecutable() const { return m_clangTidyExecutable; }
|
||||
void setClangTidyExecutable(const QString &path) { m_clangTidyExecutable = path; }
|
||||
|
||||
int simultaneousProcesses() const;
|
||||
void setSimultaneousProcesses(int processes);
|
||||
QString clazyStandaloneExecutable() const { return m_clazyStandaloneExecutable; }
|
||||
void setClazyStandaloneExecutable(const QString &path) { m_clazyStandaloneExecutable = path; }
|
||||
|
||||
bool buildBeforeAnalysis() const;
|
||||
void setBuildBeforeAnalysis(bool build);
|
||||
|
||||
Core::Id diagnosticConfigId() const;
|
||||
void setDiagnosticConfigId(Core::Id id);
|
||||
|
||||
QString clangTidyExecutable() const;
|
||||
void setClangTidyExecutable(const QString &path);
|
||||
|
||||
QString clazyStandaloneExecutable() const;
|
||||
void setClazyStandaloneExecutable(const QString &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
|
||||
|
@ -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));
|
||||
|
||||
|
87
src/plugins/clangtools/runsettingswidget.cpp
Normal file
87
src/plugins/clangtools/runsettingswidget.cpp
Normal file
@ -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
|
58
src/plugins/clangtools/runsettingswidget.h
Normal file
58
src/plugins/clangtools/runsettingswidget.h
Normal file
@ -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
|
93
src/plugins/clangtools/runsettingswidget.ui
Normal file
93
src/plugins/clangtools/runsettingswidget.ui
Normal file
@ -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>
|
@ -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);
|
||||
});
|
||||
m_ui->runSettingsWidget->fromSettings(m_settings->runSettings());
|
||||
}
|
||||
|
||||
CppTools::ClangDiagnosticConfigsSelectionWidget *diagnosticWidget = m_ui->diagnosticWidget;
|
||||
diagnosticWidget->refresh(settings->savedDiagnosticConfigId());
|
||||
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(diagnosticWidget,
|
||||
&CppTools::ClangDiagnosticConfigsSelectionWidget::currentConfigChanged,
|
||||
this, [this](const Core::Id ¤tConfigId) {
|
||||
m_settings->setDiagnosticConfigId(currentConfigId);
|
||||
});
|
||||
|
||||
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;
|
||||
|
@ -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;
|
||||
|
@ -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">
|
||||
@ -112,17 +62,18 @@
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CppTools::ClangDiagnosticConfigsSelectionWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>cpptools/clangdiagnosticconfigsselectionwidget.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Utils::PathChooser</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">utils/pathchooser.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ClangTools::Internal::RunSettingsWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>clangtools/runsettingswidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ private:
|
||||
QAction *m_zoomAction;
|
||||
QAction *m_closeAction;
|
||||
QAction *m_toggleFullScreenAction;
|
||||
Qt::WindowStates m_previousWindowState;
|
||||
bool m_shutdown = false;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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/>
|
||||
|
@ -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";
|
||||
|
@ -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)
|
||||
|
@ -160,7 +160,7 @@ private:
|
||||
ModelNode timelineModelNode() const;
|
||||
|
||||
void emitScrollOffsetChanged();
|
||||
void emitStatusBarFrameMessageChanged(int frame);
|
||||
void emitStatusBarPlayheadFrameChanged(int frame);
|
||||
|
||||
QList<QGraphicsItem *> itemsAt(const QPointF &pos);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
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);
|
||||
qreal newFrame = qBound(timelineRange.first, dialog->frame(), timelineRange.second);
|
||||
if (newFrame != frame)
|
||||
frameNode.variantProperty("frame").setValue(newFrame);
|
||||
|
||||
int userType = value.userType();
|
||||
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());
|
||||
|
@ -63,6 +63,8 @@ public:
|
||||
|
||||
void commitPosition(const QPointF &point) override;
|
||||
|
||||
void itemDoubleClicked() override;
|
||||
|
||||
TimelineKeyframeItem *asTimelineKeyframeItem() override;
|
||||
|
||||
protected:
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user