forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/13.0'
Change-Id: I77d3656aec10063a90095d5299b85304692d8b32
This commit is contained in:
@@ -1456,6 +1456,21 @@ class Dumper(DumperBase):
|
|||||||
if bp is not None:
|
if bp is not None:
|
||||||
self.reportBreakpointUpdate(bp)
|
self.reportBreakpointUpdate(bp)
|
||||||
|
|
||||||
|
def wantAutoContinue(self, frame):
|
||||||
|
if self.platform_ != 'remote-android':
|
||||||
|
return False
|
||||||
|
funcname = frame.GetFunctionName()
|
||||||
|
if funcname and funcname.startswith('java.'):
|
||||||
|
return True
|
||||||
|
module = frame.GetModule()
|
||||||
|
filespec = module.GetPlatformFileSpec() # Not GetFileSpec
|
||||||
|
filename = filespec.GetFilename()
|
||||||
|
if filename == 'libart.so':
|
||||||
|
return True
|
||||||
|
if funcname == None and not frame.line_entry.file.IsValid() and filename == None:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def handleEvent(self, event):
|
def handleEvent(self, event):
|
||||||
if lldb.SBBreakpoint.EventIsBreakpointEvent(event):
|
if lldb.SBBreakpoint.EventIsBreakpointEvent(event):
|
||||||
self.handleBreakpointEvent(event)
|
self.handleBreakpointEvent(event)
|
||||||
@@ -1490,8 +1505,12 @@ class Dumper(DumperBase):
|
|||||||
if state == lldb.eStateStopped:
|
if state == lldb.eStateStopped:
|
||||||
stoppedThread = self.firstStoppedThread()
|
stoppedThread = self.firstStoppedThread()
|
||||||
if stoppedThread:
|
if stoppedThread:
|
||||||
#self.report("STOPPED THREAD: %s" % stoppedThread)
|
|
||||||
frame = stoppedThread.GetFrameAtIndex(0)
|
frame = stoppedThread.GetFrameAtIndex(0)
|
||||||
|
if self.wantAutoContinue(frame):
|
||||||
|
#self.warn("AUTO CONTINUE")
|
||||||
|
error = self.process.Continue()
|
||||||
|
return
|
||||||
|
|
||||||
#self.report("FRAME: %s" % frame)
|
#self.report("FRAME: %s" % frame)
|
||||||
function = frame.GetFunction()
|
function = frame.GetFunction()
|
||||||
functionName = function.GetName()
|
functionName = function.GetName()
|
||||||
|
@@ -20,7 +20,13 @@ Token_Foreground_Subtle=ff2A2A2A
|
|||||||
Token_Text_Default=ffF8F8F8
|
Token_Text_Default=ffF8F8F8
|
||||||
Token_Text_Muted=ffAEAEAE
|
Token_Text_Muted=ffAEAEAE
|
||||||
Token_Text_Subtle=ff595959
|
Token_Text_Subtle=ff595959
|
||||||
Token_Text_Accent=ff23B26A
|
|
||||||
|
; Token_Text_Accent value from Figma is still too dark. Therefore, it is modified, here.
|
||||||
|
; Text (consisting of thin lines) needs to be substantially brighter than accent colors used for
|
||||||
|
; larger-area elements like the filled button.
|
||||||
|
|
||||||
|
; Token_Text_Accent=ff23B26A
|
||||||
|
Token_Text_Accent=ff30C06A
|
||||||
|
|
||||||
Token_Stroke_Strong=ffeeeeee
|
Token_Stroke_Strong=ffeeeeee
|
||||||
Token_Stroke_Muted=ff727272
|
Token_Stroke_Muted=ff727272
|
||||||
|
@@ -10,7 +10,12 @@ Token_Accent_Muted=ff1f9b5d
|
|||||||
Token_Accent_Subtle=ff1a8550
|
Token_Accent_Subtle=ff1a8550
|
||||||
|
|
||||||
Token_Background_Default=fffcfcfc
|
Token_Background_Default=fffcfcfc
|
||||||
Token_Background_Muted=ffF2F2F2
|
|
||||||
|
; Token_Background_Muted value from Figma is too dark to ensure proper contrast when used as
|
||||||
|
; text bachground. Therefore, it is modified, here.
|
||||||
|
|
||||||
|
;Token_Background_Muted=ffF2F2F2
|
||||||
|
Token_Background_Muted=ffF6F6F6
|
||||||
Token_Background_Subtle=ffe7e7e7
|
Token_Background_Subtle=ffe7e7e7
|
||||||
|
|
||||||
Token_Foreground_Default=ffD8D8D8
|
Token_Foreground_Default=ffD8D8D8
|
||||||
@@ -20,7 +25,7 @@ Token_Foreground_Subtle=ffEFEFEF
|
|||||||
Token_Text_Default=ff393939
|
Token_Text_Default=ff393939
|
||||||
Token_Text_Muted=ff6a6a6a
|
Token_Text_Muted=ff6a6a6a
|
||||||
Token_Text_Subtle=ffbebebe
|
Token_Text_Subtle=ffbebebe
|
||||||
Token_Text_Accent=ff28C878
|
Token_Text_Accent=ff1F9B5D
|
||||||
|
|
||||||
Token_Stroke_Strong=ff464646
|
Token_Stroke_Strong=ff464646
|
||||||
Token_Stroke_Muted=ff727272
|
Token_Stroke_Muted=ff727272
|
||||||
|
@@ -1010,6 +1010,12 @@ QFont StyleHelper::uiFont(UiElement element)
|
|||||||
const qreal qrealPointSize = metrics.pixelSize * pixelsToPointSizeFactor;
|
const qreal qrealPointSize = metrics.pixelSize * pixelsToPointSizeFactor;
|
||||||
font.setPointSizeF(qrealPointSize);
|
font.setPointSizeF(qrealPointSize);
|
||||||
|
|
||||||
|
// Intermediate font weights can produce blurry rendering and are harder to read.
|
||||||
|
// For "non-retina" screens, apply the weight only for some fonts.
|
||||||
|
static const bool isHighDpi = qApp->devicePixelRatio() >= 2;
|
||||||
|
const bool setWeight = isHighDpi || element == UiElementCaptionStrong
|
||||||
|
|| element <= UiElementH4;
|
||||||
|
if (setWeight)
|
||||||
font.setWeight(metrics.weight);
|
font.setWeight(metrics.weight);
|
||||||
|
|
||||||
return font;
|
return font;
|
||||||
|
@@ -813,6 +813,7 @@ void AndroidSettingsWidget::updateUI()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_makeDefaultNdkButton->setEnabled(m_ndkListWidget->count() > 0);
|
||||||
m_makeDefaultNdkButton->setText(isDefaultNdkSelected() ? Tr::tr("Unset Default")
|
m_makeDefaultNdkButton->setText(isDefaultNdkSelected() ? Tr::tr("Unset Default")
|
||||||
: Tr::tr("Make Default"));
|
: Tr::tr("Make Default"));
|
||||||
}
|
}
|
||||||
|
@@ -65,7 +65,11 @@ static void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style,
|
|||||||
|
|
||||||
static llvm::StringRef clearExtraNewline(llvm::StringRef text)
|
static llvm::StringRef clearExtraNewline(llvm::StringRef text)
|
||||||
{
|
{
|
||||||
|
#if LLVM_VERSION_MAJOR >= 16
|
||||||
|
while (text.starts_with("\n\n"))
|
||||||
|
#else
|
||||||
while (text.startswith("\n\n"))
|
while (text.startswith("\n\n"))
|
||||||
|
#endif
|
||||||
text = text.drop_front();
|
text = text.drop_front();
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
@@ -127,7 +127,11 @@ public:
|
|||||||
/// Gets real path of \p Path e.g. collapse all . and .. patterns, resolve
|
/// Gets real path of \p Path e.g. collapse all . and .. patterns, resolve
|
||||||
/// symlinks. For real file system, this uses `llvm::sys::fs::real_path`.
|
/// symlinks. For real file system, this uses `llvm::sys::fs::real_path`.
|
||||||
/// This returns errc::operation_not_permitted if not implemented by subclass.
|
/// This returns errc::operation_not_permitted if not implemented by subclass.
|
||||||
std::error_code getRealPath(const Twine &Path, SmallVectorImpl<char> &Output) const override
|
std::error_code getRealPath(const Twine &Path, SmallVectorImpl<char> &Output)
|
||||||
|
#if LLVM_VERSION_MAJOR < 19
|
||||||
|
const
|
||||||
|
#endif
|
||||||
|
override
|
||||||
{
|
{
|
||||||
Q_UNUSED(Path);
|
Q_UNUSED(Path);
|
||||||
Q_UNUSED(Output);
|
Q_UNUSED(Output);
|
||||||
|
@@ -32,10 +32,28 @@
|
|||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#ifdef QTCREATOR_PCH_H
|
||||||
|
#define CALLBACK WINAPI
|
||||||
|
#endif
|
||||||
|
#include <qt_windows.h>
|
||||||
|
#include <shlobj.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
|
static FilePath windowsDirectory()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
wchar_t str[UNICODE_STRING_MAX_CHARS] = {};
|
||||||
|
if (SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_WINDOWS, nullptr, 0, str)))
|
||||||
|
return FilePath::fromUserInput(QString::fromUtf16(reinterpret_cast<char16_t *>(str)));
|
||||||
|
#endif
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
// Show error with option to open settings.
|
// Show error with option to open settings.
|
||||||
static void showGraphicalShellError(QWidget *parent, const QString &app, const QString &error)
|
static void showGraphicalShellError(QWidget *parent, const QString &app, const QString &error)
|
||||||
{
|
{
|
||||||
@@ -56,13 +74,7 @@ void FileUtils::showInGraphicalShell(QWidget *parent, const FilePath &pathIn)
|
|||||||
const QFileInfo fileInfo = pathIn.toFileInfo();
|
const QFileInfo fileInfo = pathIn.toFileInfo();
|
||||||
// Mac, Windows support folder or file.
|
// Mac, Windows support folder or file.
|
||||||
if (HostOsInfo::isWindowsHost()) {
|
if (HostOsInfo::isWindowsHost()) {
|
||||||
const FilePath explorer = FilePath("explorer.exe").searchInPath();
|
const FilePath explorer = windowsDirectory().pathAppended("explorer.exe");
|
||||||
if (explorer.isEmpty()) {
|
|
||||||
QMessageBox::warning(parent,
|
|
||||||
Tr::tr("Launching Windows Explorer Failed"),
|
|
||||||
Tr::tr("Could not find explorer.exe in path to launch Windows Explorer."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QStringList param;
|
QStringList param;
|
||||||
if (!pathIn.isDir())
|
if (!pathIn.isDir())
|
||||||
param += QLatin1String("/select,");
|
param += QLatin1String("/select,");
|
||||||
|
@@ -47,10 +47,9 @@ const char PROJECT_BASE_ID[] = "Welcome.OpenRecentProject";
|
|||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
constexpr TextFormat projectNameTF {Theme::Token_Text_Accent, StyleHelper::UiElementH6};
|
constexpr TextFormat projectNameTF {Theme::Token_Text_Accent, StyleHelper::UiElementH5};
|
||||||
constexpr TextFormat projectPathTF {Theme::Token_Text_Muted, StyleHelper::UiElementCaptionStrong};
|
constexpr TextFormat projectPathTF {Theme::Token_Text_Muted, StyleHelper::UiElementH6};
|
||||||
constexpr TextFormat sessionNameTF = {projectNameTF.themeColor, projectNameTF.uiElement,
|
constexpr TextFormat sessionNameTF = projectNameTF;
|
||||||
Qt::AlignVCenter | Qt::TextDontClip};
|
|
||||||
constexpr TextFormat sessionProjectNameTF {Theme::Token_Text_Default, projectNameTF.uiElement};
|
constexpr TextFormat sessionProjectNameTF {Theme::Token_Text_Default, projectNameTF.uiElement};
|
||||||
constexpr TextFormat shortcutNumberTF {Theme::Token_Text_Default,
|
constexpr TextFormat shortcutNumberTF {Theme::Token_Text_Default,
|
||||||
StyleHelper::UiElementCaptionStrong,
|
StyleHelper::UiElementCaptionStrong,
|
||||||
@@ -59,7 +58,7 @@ constexpr TextFormat actionTF {Theme::Token_Text_Default, StyleHelper::UiElement
|
|||||||
Qt::AlignCenter | Qt::TextDontClip};
|
Qt::AlignCenter | Qt::TextDontClip};
|
||||||
constexpr TextFormat actionDisabledTF {Theme::Token_Text_Subtle, actionTF.uiElement,
|
constexpr TextFormat actionDisabledTF {Theme::Token_Text_Subtle, actionTF.uiElement,
|
||||||
actionTF.drawTextFlags};
|
actionTF.drawTextFlags};
|
||||||
constexpr int shortcutNumberWidth = 16;
|
constexpr int shortcutNumberWidth = 6;
|
||||||
constexpr int actionSepWidth = 1;
|
constexpr int actionSepWidth = 1;
|
||||||
constexpr int sessionScrollBarGap = HPaddingXs;
|
constexpr int sessionScrollBarGap = HPaddingXs;
|
||||||
|
|
||||||
@@ -318,16 +317,16 @@ public:
|
|||||||
{
|
{
|
||||||
// visible on withIcon() Gap + arrow visible on hover Extra margin right of project item
|
// visible on withIcon() Gap + arrow visible on hover Extra margin right of project item
|
||||||
// | | |
|
// | | |
|
||||||
// +-----------+----------+ +--------+-------+ +----------+----------+
|
// +----------+----------+ +--------+-------+ +----------+----------+
|
||||||
// | | | | | |
|
// | | | | | |
|
||||||
//
|
//
|
||||||
// +------------+--------+---------+------------+---------+-------------+--------+-------+------------+---------------------+ --+
|
// +------------+--------+--------+------------+--------+-------------+--------+-------+------------+---------------------+ --+
|
||||||
// | | | |(VPaddingXs)| |(VPaddingXs) | | | | | |
|
// | | | |(VPaddingXs)| |(VPaddingXs) | | | | | |
|
||||||
// | | | +------------+ +-------------+ | | | | |
|
// | | | +------------+ +-------------+ | | | | |
|
||||||
// |(HPaddingXs)|<number>|(HGapXxs)| <icon> |(HGapXxs)|<sessionName>|(HGapXs)|<arrow>| | | +-- Header
|
// |(HPaddingXs)|<number>|(HGapXs)| <icon> |(HGapXs)|<sessionName>|(HGapXs)|<arrow>| | | +-- Header
|
||||||
// | |(16x16) | +------------+ +-------------+ | | | | |
|
// | |(w:6) | +------------+ +-------------+ | | | | |
|
||||||
// | | | |(VPaddingXs)| |(VPaddingXs) | | | | | |
|
// | | | |(VPaddingXs)| |(VPaddingXs) | | | | | |
|
||||||
// |------------+--------+---------+------------+---------+-------------+--------+-------+ | | --+
|
// |------------+--------+--------+------------+--------+-------------+--------+-------+ | | --+
|
||||||
// | +-- | (VPaddingXxs) | | | |
|
// | +-- | (VPaddingXxs) | | | |
|
||||||
// | | +------------------------------+(HPaddingXs)| | |
|
// | | +------------------------------+(HPaddingXs)| | |
|
||||||
// | | | <projectName> | | | |
|
// | | | <projectName> | | | |
|
||||||
@@ -337,15 +336,15 @@ public:
|
|||||||
// | | | <projectPath> | | | |
|
// | | | <projectPath> | | | |
|
||||||
// | | +------------------------------+ | | +-- Expansion
|
// | | +------------------------------+ | | +-- Expansion
|
||||||
// | +-- | (VPaddingXxs) | | | |
|
// | +-- | (VPaddingXxs) | | | |
|
||||||
// +------------------------------------------------------+------------------------------+------------+ | |
|
// +----------------------------------------------------+------------------------------+------------+ | |
|
||||||
// | (VPaddingXs) | | |
|
// | (VPaddingXs) | | |
|
||||||
// +-----------------------------------------+--------------+-----------------------------------------+ | |
|
// +---------------------------------------+--------------+-----------------------------------------+ | |
|
||||||
// +-- | <cloneButton>|<renameButton>|<deleteButton> | | |
|
// +-- | <cloneButton>|<renameButton>|<deleteButton> | | |
|
||||||
// | +-----------------------------------------+--------------+-----------------------------------------+ | |
|
// | +---------------------------------------+--------------+-----------------------------------------+ | |
|
||||||
// | | (VPaddingXs) | | |
|
// | | (VPaddingXs) | | |
|
||||||
// | +--------------------------------------------------------------------------------------------------+---------------------+ --+
|
// | +------------------------------------------------------------------------------------------------+---------------------+ --+
|
||||||
// | | (VGapL) | +-- Gap between session items
|
// | | (VGapL) | +-- Gap between session items
|
||||||
// | +------------------------------------------------------------------------------------------------------------------------+ --+
|
// | +----------------------------------------------------------------------------------------------------------------------+ --+
|
||||||
// |
|
// |
|
||||||
// \ session action "buttons" and dividers
|
// \ session action "buttons" and dividers
|
||||||
// +-----------------------------------------------+--------+---------+--------+
|
// +-----------------------------------------------+--------+---------+--------+
|
||||||
@@ -381,11 +380,11 @@ public:
|
|||||||
const int y = bgR.y();
|
const int y = bgR.y();
|
||||||
|
|
||||||
const int numberX = x + s(HPaddingXs);
|
const int numberX = x + s(HPaddingXs);
|
||||||
const int iconX = numberX + shortcutNumberWidth + s(HGapXxs);
|
const int iconX = numberX + shortcutNumberWidth + s(HGapXs);
|
||||||
const int arrowX = bgR.right() - s(HPaddingXs) - arrowS.width();
|
const int arrowX = bgR.right() - s(HPaddingXs) - arrowS.width();
|
||||||
const QRect arrowHoverR(arrowX - s(HGapXs) + 1, y,
|
const QRect arrowHoverR(arrowX - s(HGapXs) + 1, y,
|
||||||
s(HGapXs) + arrowS.width() + s(HPaddingXs), hdR.height());
|
s(HGapXs) + arrowS.width() + s(HPaddingXs), hdR.height());
|
||||||
const int textX = withIcon() ? iconX + iconS.width() + s(HGapXxs) : iconX;
|
const int textX = withIcon() ? iconX + iconS.width() + s(HGapXs) : iconX;
|
||||||
|
|
||||||
const int iconY = y + (hdR.height() - iconS.height()) / 2;
|
const int iconY = y + (hdR.height() - iconS.height()) / 2;
|
||||||
const int arrowY = y + (hdR.height() - arrowS.height()) / 2;
|
const int arrowY = y + (hdR.height() - arrowS.height()) / 2;
|
||||||
@@ -627,19 +626,19 @@ public:
|
|||||||
// +--------+-------+ +------+-----+
|
// +--------+-------+ +------+-----+
|
||||||
// | | | |
|
// | | | |
|
||||||
//
|
//
|
||||||
// +------------+--------+---------+------+---------+-------------+------------+------------+
|
// +------------+--------+--------+------+---------+-------------+------------+------------+
|
||||||
// | | | | | | (VPaddingXs)| | |
|
// | | | | | | (VPaddingXs)| | |
|
||||||
// | | | | | +-------------+ | |
|
// | | | | | +-------------+ | |
|
||||||
// | | | | | |<projectName>| | |
|
// | | | | | |<projectName>| | |
|
||||||
// | | | | | +-------------+ | |
|
// | | | | | +-------------+ | |
|
||||||
// |(HPaddingXs)|<number>|(HGapXxs)|<icon>|(HGapXxs)| (VGapXs) |(HPaddingXs)|(HPaddingXs)|
|
// |(HPaddingXs)|<number>|(HGapXs)|<icon>|(HGapXxs)| (VGapXs) |(HPaddingXs)|(HPaddingXs)|
|
||||||
// | |(16x16) | | | +-------------+ | |
|
// | |(w:6) | | | +-------------+ | |
|
||||||
// | | | | | |<projectPath>| | |
|
// | | | | | |<projectPath>| | |
|
||||||
// | | | | | +-------------+ | |
|
// | | | | | +-------------+ | |
|
||||||
// | | | | | | (VPaddingXs)| | |
|
// | | | | | | (VPaddingXs)| | |
|
||||||
// +------------+--------+---------+------+---------+-------------+------------+------------+ --+
|
// +------------+--------+--------+------+---------+-------------+------------+------------+ --+
|
||||||
// | (VGapL) | +-- Gap between project items
|
// | (VGapL) | +-- Gap between project items
|
||||||
// +----------------------------------------------------------------------------------------+ --+
|
// +---------------------------------------------------------------------------------------+ --+
|
||||||
|
|
||||||
const bool hovered = option.widget->isActiveWindow()
|
const bool hovered = option.widget->isActiveWindow()
|
||||||
&& option.state & QStyle::State_MouseOver;
|
&& option.state & QStyle::State_MouseOver;
|
||||||
@@ -651,9 +650,9 @@ public:
|
|||||||
|
|
||||||
const int x = bgR.x();
|
const int x = bgR.x();
|
||||||
const int numberX = x + s(HPaddingXs);
|
const int numberX = x + s(HPaddingXs);
|
||||||
const int iconX = numberX + shortcutNumberWidth + s(HGapXxs);
|
const int iconX = numberX + shortcutNumberWidth + s(HGapXs);
|
||||||
const int iconWidth = iconS.width();
|
const int iconWidth = iconS.width();
|
||||||
const int textX = withIcon() ? iconX + iconWidth + s(HGapXxs) : iconX;
|
const int textX = withIcon() ? iconX + iconWidth + s(HGapXs) : iconX;
|
||||||
const int textWidth = bgR.width() - s(HPaddingXs) - textX;
|
const int textWidth = bgR.width() - s(HPaddingXs) - textX;
|
||||||
|
|
||||||
const int y = bgR.y();
|
const int y = bgR.y();
|
||||||
|
Submodule src/shared/qbs updated: 12bc60c93d...488fbe40e8
@@ -113,10 +113,7 @@ def handleBuildSystemVerifyKits(category, template, kits, displayedPlatforms,
|
|||||||
return
|
return
|
||||||
|
|
||||||
fixedBuildSystems = list(availableBuildSystems)
|
fixedBuildSystems = list(availableBuildSystems)
|
||||||
if template == 'Qt Quick Application':
|
if template == 'Qt Quick 2 Extension Plugin':
|
||||||
fixedBuildSystems.remove('qmake')
|
|
||||||
test.log("Skipped qmake (not supported).")
|
|
||||||
elif template == 'Qt Quick 2 Extension Plugin':
|
|
||||||
fixedBuildSystems.remove('Qbs')
|
fixedBuildSystems.remove('Qbs')
|
||||||
test.log("Skipped Qbs (not supported).")
|
test.log("Skipped Qbs (not supported).")
|
||||||
|
|
||||||
@@ -126,7 +123,7 @@ def handleBuildSystemVerifyKits(category, template, kits, displayedPlatforms,
|
|||||||
clickButton(waitForObject(":Next_QPushButton"))
|
clickButton(waitForObject(":Next_QPushButton"))
|
||||||
if specialHandlingFunc:
|
if specialHandlingFunc:
|
||||||
specialHandlingFunc(displayedPlatforms, *args)
|
specialHandlingFunc(displayedPlatforms, *args)
|
||||||
if not ('Plain C' in template or template == 'Qt Quick Application'):
|
if not ('Plain C' in template):
|
||||||
__createProjectHandleTranslationSelection__()
|
__createProjectHandleTranslationSelection__()
|
||||||
verifyKitCheckboxes(kits, displayedPlatforms)
|
verifyKitCheckboxes(kits, displayedPlatforms)
|
||||||
safeClickButton("Cancel")
|
safeClickButton("Cancel")
|
||||||
|
Reference in New Issue
Block a user