58 connect(
this, &QQmlInPlacePreviewHandler::hotReloadFailure, service,
59 &QQmlPreviewServiceImpl::forwardHotReloadFailure, Qt::DirectConnection);
60 connect(service, &QQmlPreviewServiceImpl::drop,
this, [
this](
const QUrl &url) {
61 if (!m_droppedUrls.contains(url))
62 m_droppedUrls.push_back(url);
65 emit error(QLatin1String(
"You cannot rerun if in-place updates are enabled."));
67 connect(service, &QQmlPreviewServiceImpl::zoom,
this, [
this](qreal zoomFactor) {
69 zoomWindow(currentWindow(), zoomFactor, &position);
89 QMetaObject::invokeMethod(engine, [engine, url, receiver]() {
90 QV4::ExecutionEngine *v4 = engine->handle();
91 const QQmlRefPointer<QV4::ExecutableCompilationUnit> unit = v4->compilationUnitForUrl(url);
95 const std::vector<QObject *> objects =
96 v4->memoryManager->findObjectsForCompilationUnits({ unit->baseCompilationUnit() });
97 QPointer<QObject> found;
98 for (QObject *object : objects) {
99 QQmlData *ddata = QQmlData::get(object);
100 if (ddata && ddata->compilationUnit == unit && ddata->cuObjectIndex == 0) {
101 if (std::exchange(found, object))
107 QMetaObject::invokeMethod(receiver, [receiver, found]() {
108 if (QQuickItem *rootItem = qobject_cast<QQuickItem *>(found)) {
109 receiver->setCurrentRootItem(rootItem);
110 receiver->setCurrentWindow(findCurrentWindow());
114 if (QQuickWindow *window = qobject_cast<QQuickWindow *>(found)) {
115 receiver->setCurrentWindow(window);
116 receiver->setCurrentRootItem(
nullptr);
120 receiver->setCurrentRootItem(
nullptr);
121 receiver->setCurrentWindow(findCurrentWindow());
131 QV4::ExecutionEngine *v4,
132 const QList<QQmlRefPointer<QV4::CompiledData::CompilationUnit>> &droppedUnits)
134 const auto allCUs = v4->compilationUnits();
135 for (
const auto &ecu : allCUs) {
136 const auto &baseCU = ecu->baseCompilationUnit();
137 for (
auto *typeRef : std::as_const(baseCU->resolvedTypes)) {
138 if (typeRef->isSelfReference())
140 const auto &refCU = typeRef->compilationUnit();
143 for (
const auto &oldCU : droppedUnits) {
144 if (refCU == oldCU) {
145 const auto newCU = QQmlMetaType::obtainCompilationUnit(oldCU->finalUrl());
147 typeRef->setCompilationUnit(newCU);
158 const auto componentUpdateIt =
159 std::find_if(inplaceUpdate->pendingComponentUpdates.begin(),
160 inplaceUpdate->pendingComponentUpdates.end(),
162 return engineUpdate.component.get() == component;
165 if (componentUpdateIt == inplaceUpdate->pendingComponentUpdates.end())
168 componentUpdate =
std::move(*componentUpdateIt);
169 inplaceUpdate->pendingComponentUpdates.erase(componentUpdateIt);
171 switch (component->status()) {
172 case QQmlComponent::Null:
173 case QQmlComponent::Loading:
174 Q_UNREACHABLE_RETURN();
175 case QQmlComponent::Ready:
177 case QQmlComponent::Error:
178 inplaceUpdate->emitError(component->errorString());
182 QV4::ExecutionEngine *v4 = component->engine()->handle();
184 std::vector<QObject *> objects;
185 QV4::CompiledData::CompilationUnitDiff diff;
186 if (
const auto oldExecCU = componentUpdate.oldUnit) {
187 const auto newExecCU = QQmlComponentPrivate::get(component)->compilationUnit();
189 objects = v4->memoryManager->findObjectsForCompilationUnits(
190 { oldExecCU->baseCompilationUnit() });
191 diff = QV4::CompiledData::diffCompilationUnits(oldExecCU->unitData(),
192 newExecCU->unitData());
193 if (!QQmlPreview::applyDiff(objects, diff, oldExecCU, newExecCU))
194 inplaceUpdate->emitReloadFailure(
"Could not apply diff");
196 inplaceUpdate->processedComponentUpdates.push_back(
std::move(componentUpdate));
201 if (inplaceUpdate->pendingComponentUpdates.empty()) {
202 updateResolvedTypeReferences(component->engine()->handle(), inplaceUpdate->droppedUnits);
203 for (
const ComponentUpdate &update : inplaceUpdate->processedComponentUpdates)
204 QQmlPreview::refreshBindings(
206 QQmlComponentPrivate::get(update.component.get())->compilationUnit());
212 QV4::ExecutionEngine *v4 = inplaceUpdate->engine->handle();
213 std::vector<QQmlComponent *> components;
214 for (
const QUrl &url : urls) {
217 v4->typeLoader()->removeFromCache(url);
220 QQmlRefPointer<QV4::ExecutableCompilationUnit> oldUnit = v4->compilationUnitForUrl(url);
223 inplaceUpdate->pendingComponentUpdates.push_back({
224 std::make_unique<QQmlComponent>(inplaceUpdate->engine, url),
229 components.push_back(inplaceUpdate->pendingComponentUpdates.back().component.get());
232 for (QQmlComponent *component : components) {
233 switch (component->status()) {
234 case QQmlComponent::Null:
235 case QQmlComponent::Loading:
236 QObject::connect(component, &QQmlComponent::statusChanged, component,
237 [component, inplaceUpdate]() {
238 switch (component->status()) {
239 case QQmlComponent::Ready:
240 case QQmlComponent::Error:
241 updateInplace(component, inplaceUpdate);
248 case QQmlComponent::Ready:
249 case QQmlComponent::Error:
250 updateInplace(component, inplaceUpdate);
256void QQmlInPlacePreviewHandler::load(
const QUrl &url)
261 const QList<QQmlEngine *> seenEngines = engines();
262 const QList<QUrl> urls = std::exchange(m_droppedUrls, {});
264 QList<QQmlRefPointer<QV4::CompiledData::CompilationUnit>> droppedUnits;
265 for (
const QUrl &droppedUrl : urls) {
266 while (
const auto cu = QQmlMetaType::obtainCompilationUnit(droppedUrl)) {
267 droppedUnits.append(cu);
268 QQmlMetaType::deepClearCompositeType(cu);
271 for (QQmlEngine *engine : seenEngines) {
272 std::shared_ptr<InplaceUpdate> inplaceUpdate =
273 std::make_shared<InplaceUpdate>(
this, engine);
274 inplaceUpdate->droppedUnits = droppedUnits;
278 QMetaObject::invokeMethod(engine,
279 [inplaceUpdate, urls]() { updateEngine(inplaceUpdate, urls); });
286 if (seenEngines.size() == 1) {
287 findCurrentRootObject(seenEngines[0], url,
this);