Merge "Merge remote-tracking branch 'origin/6.0'"

This commit is contained in:
The Qt Project
2022-01-14 11:47:06 +00:00
39 changed files with 707 additions and 384 deletions

View File

@@ -25,6 +25,7 @@
#pragma once
#include <utils/optional.h>
#include <utils/smallstringview.h>
#include <type_traits>
@@ -62,7 +63,7 @@ void insertUpdateDelete(SqliteRange &&sqliteRange,
auto endSqliteIterator = sqliteRange.end();
auto currentValueIterator = values.begin();
auto endValueIterator = values.end();
std::optional<std::decay_t<decltype(*currentValueIterator)>> lastValue;
Utils::optional<std::decay_t<decltype(*currentValueIterator)>> lastValue;
while (true) {
bool hasMoreValues = currentValueIterator != endValueIterator;

View File

@@ -41,6 +41,17 @@ public:
}
friend bool operator!=(TimeStamp first, TimeStamp second) { return !(first == second); }
friend bool operator<(TimeStamp first, TimeStamp second) { return first.value < second.value; }
friend TimeStamp operator+(TimeStamp first, TimeStamp second)
{
return first.value + second.value;
}
friend TimeStamp operator-(TimeStamp first, TimeStamp second)
{
return first.value - second.value;
}
bool isValid() const { return value >= 0; }

View File

@@ -408,7 +408,10 @@ QFuture<ResultType> runAsync_internal(QThreadPool *pool,
QFuture<ResultType> future = job->future();
if (pool) {
job->setThreadPool(pool);
pool->start(job);
if (QThread::currentThread() == pool->thread())
pool->start(job);
else
QMetaObject::invokeMethod(pool, [pool, job]() { pool->start(job); }, Qt::QueuedConnection);
} else {
auto thread = new Internal::RunnableThread(job);
if (stackSize)

View File

@@ -138,11 +138,10 @@ void DPasteDotComProtocol::paste(
});
}
bool DPasteDotComProtocol::checkConfiguration(QString *errorMessage)
bool DPasteDotComProtocol::checkConfiguration(QString * /*errorMessage*/)
{
if (!m_hostKnownOk)
m_hostKnownOk = httpStatus(baseUrl(), errorMessage);
return m_hostKnownOk;
// we need a 1s gap between requests, so skip status check to avoid failing
return true;
}
void DPasteDotComProtocol::reportError(const QString &message)

View File

@@ -50,8 +50,6 @@ private:
bool checkConfiguration(QString *errorMessage) override;
static void reportError(const QString &message);
bool m_hostKnownOk = false;
};
} // namespace CodePaster

View File

@@ -1572,7 +1572,9 @@ static const MsvcToolChain *selectMsvcToolChain(const QString &displayedVarsBat,
QTC_CHECK(displayedVarsBat.isEmpty());
const QVersionNumber version = clangClVersion(clangClPath);
if (version.majorVersion() >= 6) {
toolChain = findMsvcToolChain(wordWidth, Abi::WindowsMsvc2019Flavor);
toolChain = findMsvcToolChain(wordWidth, Abi::WindowsMsvc2022Flavor);
if (!toolChain)
toolChain = findMsvcToolChain(wordWidth, Abi::WindowsMsvc2019Flavor);
if (!toolChain)
toolChain = findMsvcToolChain(wordWidth, Abi::WindowsMsvc2017Flavor);
}

View File

@@ -185,7 +185,7 @@ void CMakeGeneratorDialogTreeModel::createNodes(const FilePaths &candidates, QSt
const CheckableFileTreeItem* CMakeGeneratorDialogTreeModel::constNodeForIndex(const QModelIndex &index) const
{
const QStandardItem *parent = static_cast<const QStandardItem*>(index.constInternalPointer());
const QStandardItem *parent = static_cast<const QStandardItem*>(index.internalPointer());
const QStandardItem *item = parent->child(index.row(), index.column());
return static_cast<const CheckableFileTreeItem*>(item);
}

View File

@@ -1050,15 +1050,16 @@ static QString getAssetDefaultDirectory(const QString &assetDir, const QString &
{
QString adjustedDefaultDirectory = defaultDirectory;
Utils::FilePath assetPath = projectFilePath();
if (assetPath.pathAppended("content").exists())
assetPath= assetPath.pathAppended("content");
Utils::FilePath contentPath = projectFilePath();
assetPath = assetPath.pathAppended(assetDir);
if (contentPath.pathAppended("content").exists())
contentPath = contentPath.pathAppended("content");
Utils::FilePath assetPath = contentPath.pathAppended(assetDir);
if (!assetPath.exists()) {
// Create the default asset type directory if it doesn't exist
QDir dir(projectFilePath().toString());
QDir dir(contentPath.toString());
dir.mkpath(assetDir);
}

View File

@@ -25,18 +25,19 @@
#include "asynchronousimagefactory.h"
#include "imagecachecollector.h"
#include "imagecachegenerator.h"
#include "imagecachestorage.h"
#include "timestampprovider.h"
#include "timestampproviderinterface.h"
namespace QmlDesigner {
AsynchronousImageFactory::AsynchronousImageFactory(ImageCacheStorageInterface &storage,
ImageCacheGeneratorInterface &generator,
TimeStampProviderInterface &timeStampProvider)
TimeStampProviderInterface &timeStampProvider,
ImageCacheCollectorInterface &collector)
: m_storage(storage)
, m_generator(generator)
, m_timeStampProvider(timeStampProvider)
, m_collector(collector)
{
m_backgroundThread = std::thread{[this] {
while (isRunning()) {
@@ -45,8 +46,8 @@ AsynchronousImageFactory::AsynchronousImageFactory(ImageCacheStorageInterface &s
entry->extraId,
std::move(entry->auxiliaryData),
m_storage,
m_generator,
m_timeStampProvider);
m_timeStampProvider,
m_collector);
}
waitForEntries();
@@ -107,30 +108,33 @@ void AsynchronousImageFactory::request(Utils::SmallStringView name,
Utils::SmallStringView extraId,
ImageCache::AuxiliaryData auxiliaryData,
ImageCacheStorageInterface &storage,
ImageCacheGeneratorInterface &generator,
TimeStampProviderInterface &timeStampProvider)
TimeStampProviderInterface &timeStampProvider,
ImageCacheCollectorInterface &collector)
{
const auto id = extraId.empty() ? Utils::PathString{name}
: Utils::PathString::join({name, "+", extraId});
const auto currentModifiedTime = timeStampProvider.timeStamp(name);
const auto storageModifiedTime = storage.fetchModifiedImageTime(id);
const auto pause = timeStampProvider.pause();
if (currentModifiedTime == storageModifiedTime && storage.fetchHasImage(id))
if (currentModifiedTime < (storageModifiedTime + pause))
return;
generator.generateImage(name,
extraId,
currentModifiedTime,
ImageCache::CaptureImageWithSmallImageCallback{},
ImageCache::AbortCallback{},
std::move(auxiliaryData));
auto capture = [=](const QImage &image, const QImage &smallImage) {
m_storage.storeImage(id, currentModifiedTime, image, smallImage);
};
collector.start(name,
extraId,
std::move(auxiliaryData),
std::move(capture),
ImageCache::AbortCallback{});
}
void AsynchronousImageFactory::clean()
{
clearEntries();
m_generator.clean();
}
void AsynchronousImageFactory::wait()

View File

@@ -39,15 +39,14 @@ namespace QmlDesigner {
class TimeStampProviderInterface;
class ImageCacheStorageInterface;
class ImageCacheGeneratorInterface;
class ImageCacheCollectorInterface;
class AsynchronousImageFactory
{
public:
AsynchronousImageFactory(ImageCacheStorageInterface &storage,
ImageCacheGeneratorInterface &generator,
TimeStampProviderInterface &timeStampProvider);
TimeStampProviderInterface &timeStampProvider,
ImageCacheCollectorInterface &collector);
~AsynchronousImageFactory();
@@ -83,8 +82,8 @@ private:
Utils::SmallStringView extraId,
ImageCache::AuxiliaryData auxiliaryData,
ImageCacheStorageInterface &storage,
ImageCacheGeneratorInterface &generator,
TimeStampProviderInterface &timeStampProvider);
TimeStampProviderInterface &timeStampProvider,
ImageCacheCollectorInterface &collector);
void wait();
void clearEntries();
void stopThread();
@@ -95,8 +94,8 @@ private:
std::condition_variable m_condition;
std::thread m_backgroundThread;
ImageCacheStorageInterface &m_storage;
ImageCacheGeneratorInterface &m_generator;
TimeStampProviderInterface &m_timeStampProvider;
ImageCacheCollectorInterface &m_collector;
bool m_finishing{false};
};

View File

@@ -60,8 +60,10 @@ QString fileToString(const QString &filename)
} // namespace
ImageCacheCollector::ImageCacheCollector(ImageCacheConnectionManager &connectionManager)
ImageCacheCollector::ImageCacheCollector(ImageCacheConnectionManager &connectionManager,
ImageCacheCollectorNullImageHandling nullImageHandling)
: m_connectionManager{connectionManager}
, nullImageHandling{nullImageHandling}
{}
ImageCacheCollector::~ImageCacheCollector() = default;
@@ -89,7 +91,8 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
model->setRewriterView(&rewriterView);
if (rewriterView.inErrorState() || !rewriterView.rootModelNode().metaInfo().isGraphicalItem()) {
abortCallback(ImageCache::AbortReason::Failed);
if (abortCallback)
abortCallback(ImageCache::AbortReason::Failed);
return;
}
@@ -98,12 +101,14 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
if (stateNode.isValid())
rewriterView.setCurrentStateNode(stateNode);
auto callback = [captureCallback = std::move(captureCallback)](const QImage &image) {
QSize smallImageSize = image.size().scaled(QSize{96, 96}.boundedTo(image.size()),
Qt::KeepAspectRatio);
QImage smallImage = image.isNull() ? QImage{} : image.scaled(smallImageSize);
captureCallback(image, smallImage);
auto callback = [=, captureCallback = std::move(captureCallback)](const QImage &image) {
if (nullImageHandling == ImageCacheCollectorNullImageHandling::CaptureNullImage
|| !image.isNull()) {
QSize smallImageSize = image.size().scaled(QSize{96, 96}.boundedTo(image.size()),
Qt::KeepAspectRatio);
QImage smallImage = image.isNull() ? QImage{} : image.scaled(smallImageSize);
captureCallback(image, smallImage);
}
};
if (!m_target)
@@ -122,29 +127,21 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
model->setNodeInstanceView({});
model->setRewriterView({});
if (!capturedDataArrived)
if (!capturedDataArrived && abortCallback)
abortCallback(ImageCache::AbortReason::Failed);
}
std::pair<QImage, QImage> ImageCacheCollector::createImage(Utils::SmallStringView filePath,
Utils::SmallStringView state,
const ImageCache::AuxiliaryData &auxiliaryData)
std::pair<QImage, QImage> ImageCacheCollector::createImage(Utils::SmallStringView,
Utils::SmallStringView,
const ImageCache::AuxiliaryData &)
{
Q_UNUSED(filePath)
Q_UNUSED(state)
Q_UNUSED(auxiliaryData)
return {};
}
QIcon ImageCacheCollector::createIcon(Utils::SmallStringView filePath,
Utils::SmallStringView state,
const ImageCache::AuxiliaryData &auxiliaryData)
QIcon ImageCacheCollector::createIcon(Utils::SmallStringView,
Utils::SmallStringView,
const ImageCache::AuxiliaryData &)
{
Q_UNUSED(filePath)
Q_UNUSED(state)
Q_UNUSED(auxiliaryData)
return {};
}

View File

@@ -45,10 +45,13 @@ class ImageCacheConnectionManager;
class RewriterView;
class NodeInstanceView;
enum class ImageCacheCollectorNullImageHandling { CaptureNullImage, DontCaptureNullImage };
class ImageCacheCollector final : public ImageCacheCollectorInterface
{
public:
ImageCacheCollector(ImageCacheConnectionManager &connectionManager);
ImageCacheCollector(ImageCacheConnectionManager &connectionManager,
ImageCacheCollectorNullImageHandling nullImageHandling = {});
~ImageCacheCollector();
@@ -72,6 +75,7 @@ public:
private:
ImageCacheConnectionManager &m_connectionManager;
QPointer<ProjectExplorer::Target> m_target;
ImageCacheCollectorNullImageHandling nullImageHandling{};
};
} // namespace QmlDesigner

View File

@@ -33,6 +33,7 @@ class TimeStampProvider : public TimeStampProviderInterface
{
public:
Sqlite::TimeStamp timeStamp(Utils::SmallStringView name) const override;
Sqlite::TimeStamp pause() const override { return 0; }
};
} // namespace QmlDesigner

View File

@@ -36,6 +36,7 @@ class TimeStampProviderInterface
{
public:
virtual Sqlite::TimeStamp timeStamp(Utils::SmallStringView name) const = 0;
virtual Sqlite::TimeStamp pause() const = 0;
protected:
~TimeStampProviderInterface() = default;

View File

@@ -137,7 +137,8 @@ void BaseConnectionManager::callCrashCallback()
{
std::lock_guard<std::mutex> lock{m_callbackMutex};
m_crashCallback();
if (m_crashCallback)
m_crashCallback();
}
} // namespace QmlDesigner

View File

@@ -50,7 +50,7 @@
#include <imagecache/imagecacheconnectionmanager.h>
#include <imagecache/imagecachegenerator.h>
#include <imagecache/imagecachestorage.h>
#include <imagecache/timestampprovider.h>
#include <imagecache/timestampproviderinterface.h>
#include <coreplugin/icore.h>
@@ -70,6 +70,23 @@ QString defaultImagePath()
return qobject_cast<::QmlProjectManager::QmlBuildSystem *>(target->buildSystem());
}
class TimeStampProvider : public TimeStampProviderInterface
{
public:
Sqlite::TimeStamp timeStamp(Utils::SmallStringView) const override
{
auto now = std::chrono::steady_clock::now();
return std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();
}
Sqlite::TimeStamp pause() const override
{
using namespace std::chrono_literals;
return std::chrono::duration_cast<std::chrono::seconds>(1h).count();
}
};
} // namespace
class PreviewImageCacheData
@@ -81,11 +98,11 @@ public:
Sqlite::LockingMode::Normal};
ImageCacheStorage<Sqlite::Database> storage{database};
ImageCacheConnectionManager connectionManager;
ImageCacheCollector collector{connectionManager};
ImageCacheGenerator generator{collector, storage};
ImageCacheCollector collector{connectionManager,
ImageCacheCollectorNullImageHandling::DontCaptureNullImage};
TimeStampProvider timeStampProvider;
AsynchronousExplicitImageCache cache{storage};
AsynchronousImageFactory factory{storage, generator, timeStampProvider};
AsynchronousImageFactory factory{storage, timeStampProvider, collector};
};
class QmlDesignerProjectManagerProjectData
@@ -155,8 +172,10 @@ void QmlDesignerProjectManager::projectAdded(::ProjectExplorer::Project *project
void QmlDesignerProjectManager::aboutToRemoveProject(::ProjectExplorer::Project *)
{
m_imageCacheData->collector.setTarget(m_projectData->activeTarget);
m_projectData.reset();
if (m_projectData) {
m_imageCacheData->collector.setTarget(m_projectData->activeTarget);
m_projectData.reset();
}
}
void QmlDesignerProjectManager::projectRemoved(::ProjectExplorer::Project *) {}

View File

@@ -28,6 +28,8 @@
#include "qdsnewdialog.h"
#include <app/app_version.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/dialogs/restartdialog.h>
#include <coreplugin/editormanager/editormanager.h>
@@ -268,6 +270,24 @@ int ProjectModel::rowCount(const QModelIndex &) const
return ProjectExplorer::ProjectExplorerPlugin::recentProjects().count();
}
QString getQDSVersion(const QString &projectFilePath)
{
const QString defaultReturn = "";
Utils::FileReader reader;
if (!reader.fetch(Utils::FilePath::fromString(projectFilePath)))
return defaultReturn;
const QByteArray data = reader.data();
QRegularExpression regexp(R"x(qdsVersion: "(.*)")x");
QRegularExpressionMatch match = regexp.match(QString::fromUtf8(data));
if (!match.hasMatch())
return defaultReturn;
return ProjectModel::tr("Created with Qt Design Studio version: %1").arg(match.captured(1));
}
QString getMainQmlFile(const QString &projectFilePath)
{
const QString defaultReturn = "content/App.qml";
@@ -293,8 +313,8 @@ QString appQmlFile(const QString &projectFilePath)
static QString fromCamelCase(const QString &s) {
static QRegularExpression regExp1 {"(.)([A-Z][a-z]+)"};
static QRegularExpression regExp2 {"([a-z0-9])([A-Z])"};
const QRegularExpression regExp1 {"(.)([A-Z][a-z]+)"};
const QRegularExpression regExp2 {"([a-z0-9])([A-Z])"};
QString result = s;
result.replace(regExp1, "\\1 \\2");
result.replace(regExp2, "\\1 \\2");
@@ -302,15 +322,49 @@ static QString fromCamelCase(const QString &s) {
return result;
}
static QString resolutionFromConstants(const QString &projectFilePath)
{
const QFileInfo fileInfo(projectFilePath);
const QString fileName = fileInfo.dir().absolutePath()
+ "/" + "imports" + "/" + fileInfo.baseName() + "/Constants.qml";
Utils::FileReader reader;
if (!reader.fetch(Utils::FilePath::fromString(fileName)))
return {};
const QByteArray data = reader.data();
const QRegularExpression regexpWidth(R"x(readonly\s+property\s+int\s+width:\s+(\d*))x");
const QRegularExpression regexpHeight(R"x(readonly\s+property\s+int\s+height:\s+(\d*))x");
int width = -1;
int height = -1;
QRegularExpressionMatch match = regexpHeight.match(QString::fromUtf8(data));
if (match.hasMatch())
height = match.captured(1).toInt();
match = regexpWidth.match(QString::fromUtf8(data));
if (match.hasMatch())
width = match.captured(1).toInt();
if (width > 0 && height > 0)
return ProjectModel::tr("Resolution: %1x%2").arg(width).arg(height);
return {};
}
static QString description(const QString &projectFilePath)
{
const QString created = "Created: " +
QFileInfo(projectFilePath).fileTime(QFileDevice::FileBirthTime).toString();
const QString lastEdited = "Last Edited: " +
QFileInfo(projectFilePath).fileTime(QFileDevice::FileModificationTime).toString();
const QString created = ProjectModel::tr("Created: %1").arg(
QFileInfo(projectFilePath).fileTime(QFileDevice::FileBirthTime).toString());
const QString lastEdited = ProjectModel::tr("Last Edited: %1").arg(
QFileInfo(projectFilePath).fileTime(QFileDevice::FileModificationTime).toString());
return fromCamelCase(QFileInfo(projectFilePath).baseName()) + "\n" + created + "\n" + lastEdited;
return fromCamelCase(QFileInfo(projectFilePath).baseName()) + "\n\n" + created + "\n" + lastEdited
+ "\n" + resolutionFromConstants(projectFilePath)
+ "\n" + getQDSVersion(projectFilePath);
}
static QString tags(const QString &projectFilePath)
@@ -438,6 +492,26 @@ bool StudioWelcomePlugin::initialize(const QStringList &arguments, QString *erro
return true;
}
static bool showSplashScreen()
{
const QString lastQDSVersionEntry = "QML/Designer/lastQDSVersion";
QSettings *settings = Core::ICore::settings();
const QString lastQDSVersion = settings->value(lastQDSVersionEntry).toString();
const QString currentVersion = Core::Constants::IDE_VERSION_DISPLAY;
if (currentVersion != lastQDSVersion) {
settings->setValue(lastQDSVersionEntry, currentVersion);
return true;
}
return Utils::CheckableMessageBox::shouldAskAgain(Core::ICore::settings(),
DO_NOT_SHOW_SPLASHSCREEN_AGAIN_KEY);
}
void StudioWelcomePlugin::extensionsInitialized()
{
Core::ModeManager::activateMode(m_welcomeMode->id());
@@ -445,8 +519,7 @@ void StudioWelcomePlugin::extensionsInitialized()
// Enable QDS new project dialog
Core::ICore::setNewDialogFactory([](QWidget *parent) { return new QdsNewDialog(parent); });
if (Utils::CheckableMessageBox::shouldAskAgain(Core::ICore::settings(),
DO_NOT_SHOW_SPLASHSCREEN_AGAIN_KEY)) {
if (showSplashScreen()) {
connect(Core::ICore::instance(), &Core::ICore::coreOpened, this, [this] {
s_view = new QQuickWidget(Core::ICore::dialogParent());
s_view->setResizeMode(QQuickWidget::SizeRootObjectToView);
@@ -532,6 +605,8 @@ WelcomeMode::WelcomeMode()
setContextHelp("Qt Design Studio Manual");
setContext(Core::Context(Core::Constants::C_WELCOME_MODE));
QFontDatabase::addApplicationFont(":/studiofonts/TitilliumWeb-Regular.ttf");
m_modeWidget = new QQuickWidget;
m_modeWidget->setMinimumSize(1024, 768);
m_modeWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);