Kirigami2

pagerouter.cpp
1 /*
2  * SPDX-FileCopyrightText: 2020 Carson Black <[email protected]>
3  *
4  * SPDX-License-Identifier: LGPL-2.0-or-later
5  */
6 
7 #include "pagerouter.h"
8 #include "loggingcategory.h"
9 #include <QJSEngine>
10 #include <QJSValue>
11 #include <QJsonObject>
12 #include <QJsonValue>
13 #include <QQmlProperty>
14 #include <QQuickWindow>
15 #include <QTimer>
16 #include <qqmlpropertymap.h>
17 
18 ParsedRoute *parseRoute(QJSValue value)
19 {
20  if (value.isUndefined()) {
21  return new ParsedRoute{};
22  } else if (value.isString()) {
23  return new ParsedRoute{value.toString(), QVariant()};
24  } else {
25  auto map = value.toVariant().value<QVariantMap>();
26  map.remove(QStringLiteral("route"));
27  map.remove(QStringLiteral("data"));
28  return new ParsedRoute{value.property(QStringLiteral("route")).toString(), //
29  value.property(QStringLiteral("data")).toVariant(),
30  map,
31  false};
32  }
33 }
34 
35 QList<ParsedRoute *> parseRoutes(QJSValue values)
36 {
38  if (values.isArray()) {
39  const auto valuesList = values.toVariant().toList();
40  for (const auto &route : valuesList) {
41  if (route.toString() != QString()) {
42  ret << new ParsedRoute{route.toString(), QVariant(), QVariantMap(), false, nullptr};
43  } else if (route.canConvert<QVariantMap>()) {
44  auto map = route.value<QVariantMap>();
45  auto copy = map;
46  copy.remove(QStringLiteral("route"));
47  copy.remove(QStringLiteral("data"));
48 
49  ret << new ParsedRoute{map.value(QStringLiteral("route")).toString(), map.value(QStringLiteral("data")), copy, false, nullptr};
50  }
51  }
52  } else {
53  ret << parseRoute(values);
54  }
55  return ret;
56 }
57 
58 PageRouter::PageRouter(QQuickItem *parent)
59  : QObject(parent)
60  , m_paramMap(new QQmlPropertyMap)
61  , m_cache()
62  , m_preload()
63 {
64  connect(this, &PageRouter::pageStackChanged, [=]() {
65  connect(m_pageStack, &ColumnView::currentIndexChanged, this, &PageRouter::currentIndexChanged);
66  });
67 }
68 
70 {
71  return QQmlListProperty<PageRoute>(this, nullptr, appendRoute, routeCount, route, clearRoutes);
72 }
73 
74 void PageRouter::appendRoute(QQmlListProperty<PageRoute> *prop, PageRoute *route)
75 {
76  auto router = qobject_cast<PageRouter *>(prop->object);
77  router->m_routes.append(route);
78 }
79 
80 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
81 int PageRouter::routeCount(QQmlListProperty<PageRoute> *prop)
82 #else
83 qsizetype PageRouter::routeCount(QQmlListProperty<PageRoute> *prop)
84 #endif
85 {
86  auto router = qobject_cast<PageRouter *>(prop->object);
87  return router->m_routes.length();
88 }
89 
90 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
91 PageRoute *PageRouter::route(QQmlListProperty<PageRoute> *prop, int index)
92 #else
93 PageRoute *PageRouter::route(QQmlListProperty<PageRoute> *prop, qsizetype index)
94 #endif
95 {
96  auto router = qobject_cast<PageRouter *>(prop->object);
97  return router->m_routes[index];
98 }
99 
100 void PageRouter::clearRoutes(QQmlListProperty<PageRoute> *prop)
101 {
102  auto router = qobject_cast<PageRouter *>(prop->object);
103  router->m_routes.clear();
104 }
105 
106 PageRouter::~PageRouter()
107 {
108 }
109 
110 void PageRouter::classBegin()
111 {
112 }
113 
114 void PageRouter::componentComplete()
115 {
116  if (m_pageStack == nullptr) {
117  qCCritical(KirigamiLog)
118  << "PageRouter should be created with a ColumnView. Not doing so is undefined behaviour, and is likely to result in a crash upon further "
119  "interaction.";
120  } else {
121  Q_EMIT pageStackChanged();
122  m_currentRoutes.clear();
123  push(parseRoute(initialRoute()));
124  }
125 }
126 
127 bool PageRouter::routesContainsKey(const QString &key) const
128 {
129  for (auto route : m_routes) {
130  if (route->name() == key) {
131  return true;
132  }
133  }
134  return false;
135 }
136 
137 QQmlComponent *PageRouter::routesValueForKey(const QString &key) const
138 {
139  for (auto route : m_routes) {
140  if (route->name() == key) {
141  return route->component();
142  }
143  }
144  return nullptr;
145 }
146 
147 bool PageRouter::routesCacheForKey(const QString &key) const
148 {
149  for (auto route : m_routes) {
150  if (route->name() == key) {
151  return route->cache();
152  }
153  }
154  return false;
155 }
156 
157 int PageRouter::routesCostForKey(const QString &key) const
158 {
159  for (auto route : m_routes) {
160  if (route->name() == key) {
161  return route->cost();
162  }
163  }
164  return -1;
165 }
166 
167 // It would be nice if this could surgically update the
168 // param map instead of doing this brute force approach,
169 // but this seems to work well enough, and prematurely
170 // optimising stuff is pretty bad if it isn't found as
171 // a performance bottleneck.
172 void PageRouter::reevaluateParamMapProperties()
173 {
174  QStringList currentKeys;
175 
176  for (auto item : m_currentRoutes) {
177  for (auto key : item->properties.keys()) {
178  currentKeys << key;
179 
180  auto &value = item->properties[key];
181  m_paramMap->insert(key, value);
182  }
183  }
184 
185  for (auto key : m_paramMap->keys()) {
186  if (!currentKeys.contains(key)) {
187  m_paramMap->clear(key);
188  }
189  }
190 }
191 
192 void PageRouter::push(ParsedRoute *route)
193 {
194  Q_ASSERT(route);
195  if (!routesContainsKey(route->name)) {
196  qCCritical(KirigamiLog) << "Route" << route->name << "not defined";
197  return;
198  }
199  if (routesCacheForKey(route->name)) {
200  auto push = [route, this](ParsedRoute *item) {
201  m_currentRoutes << item;
202 
203  for (auto it = route->properties.begin(); it != route->properties.end(); it++) {
204  item->item->setProperty(qUtf8Printable(it.key()), it.value());
205  item->properties[it.key()] = it.value();
206  }
207  reevaluateParamMapProperties();
208 
209  m_pageStack->addItem(item->item);
210  };
211  auto item = m_cache.take(qMakePair(route->name, route->hash()));
212  if (item && item->item) {
213  push(item);
214  return;
215  }
216  item = m_preload.take(qMakePair(route->name, route->hash()));
217  if (item && item->item) {
218  push(item);
219  return;
220  }
221  }
222  auto context = qmlContext(this);
223  auto component = routesValueForKey(route->name);
224  auto createAndPush = [component, context, route, this]() {
225  // We use beginCreate and completeCreate to allow
226  // for a PageRouterAttached to find its parent
227  // on construction time.
228  auto item = component->beginCreate(context);
229  if (item == nullptr) {
230  return;
231  }
232  item->setParent(this);
233  auto qqItem = qobject_cast<QQuickItem *>(item);
234  if (!qqItem) {
235  qCCritical(KirigamiLog) << "Route" << route->name << "is not an item! This is undefined behaviour and will likely crash your application.";
236  }
237  for (auto it = route->properties.begin(); it != route->properties.end(); it++) {
238  qqItem->setProperty(qUtf8Printable(it.key()), it.value());
239  }
240  route->setItem(qqItem);
241  route->cache = routesCacheForKey(route->name);
242  m_currentRoutes << route;
243  reevaluateParamMapProperties();
244 
245  auto attached = qobject_cast<PageRouterAttached *>(qmlAttachedPropertiesObject<PageRouter>(item, true));
246  attached->m_router = this;
247  component->completeCreate();
248  m_pageStack->addItem(qqItem);
249  m_pageStack->setCurrentIndex(m_currentRoutes.length() - 1);
250  };
251 
252  if (component->status() == QQmlComponent::Ready) {
253  createAndPush();
254  } else if (component->status() == QQmlComponent::Loading) {
255  connect(component, &QQmlComponent::statusChanged, [=](QQmlComponent::Status status) {
256  // Loading can only go to Ready or Error.
257  if (status != QQmlComponent::Ready) {
258  qCCritical(KirigamiLog) << "Failed to push route:" << component->errors();
259  }
260  createAndPush();
261  });
262  } else {
263  qCCritical(KirigamiLog) << "Failed to push route:" << component->errors();
264  }
265 }
266 
268 {
269  return m_initialRoute;
270 }
271 
272 void PageRouter::setInitialRoute(QJSValue value)
273 {
274  m_initialRoute = value;
275 }
276 
278 {
279  auto incomingRoutes = parseRoutes(route);
280  QList<ParsedRoute *> resolvedRoutes;
281 
282  if (incomingRoutes.length() <= m_currentRoutes.length()) {
283  resolvedRoutes = m_currentRoutes.mid(0, incomingRoutes.length());
284  } else {
285  resolvedRoutes = m_currentRoutes;
286  resolvedRoutes.reserve(incomingRoutes.length() - m_currentRoutes.length());
287  }
288 
289  for (int i = 0; i < incomingRoutes.length(); i++) {
290  auto incoming = incomingRoutes.at(i);
291  Q_ASSERT(incoming);
292  if (i >= resolvedRoutes.length()) {
293  resolvedRoutes.append(incoming);
294  } else {
295  auto current = resolvedRoutes.value(i);
296  Q_ASSERT(current);
297  auto props = incoming->properties;
298  if (current->name != incoming->name || current->data != incoming->data) {
299  resolvedRoutes.replace(i, incoming);
300  }
301  resolvedRoutes[i]->properties.clear();
302  for (auto it = props.constBegin(); it != props.constEnd(); it++) {
303  resolvedRoutes[i]->properties.insert(it.key(), it.value());
304  }
305  }
306  }
307 
308  for (const auto &route : std::as_const(m_currentRoutes)) {
309  if (!resolvedRoutes.contains(route)) {
310  placeInCache(route);
311  }
312  }
313 
314  m_pageStack->clear();
315  m_currentRoutes.clear();
316  for (auto toPush : std::as_const(resolvedRoutes)) {
317  push(toPush);
318  }
319  reevaluateParamMapProperties();
320  Q_EMIT navigationChanged();
321 }
322 
324 {
325  if (route.isNumber()) {
326  auto index = route.toNumber();
327  m_pageStack->setCurrentIndex(index);
328  } else {
329  auto parsed = parseRoute(route);
330  auto index = 0;
331  for (auto currentRoute : std::as_const(m_currentRoutes)) {
332  if (currentRoute->name == parsed->name && currentRoute->data == parsed->data) {
333  m_pageStack->setCurrentIndex(index);
334  return;
335  }
336  index++;
337  }
338  qCWarning(KirigamiLog) << "Route" << parsed->name << "with data" << parsed->data << "is not on the current stack of routes.";
339  }
340 }
341 
343 {
344  auto parsed = parseRoutes(route);
345  if (parsed.length() > m_currentRoutes.length()) {
346  return false;
347  }
348  for (int i = 0; i < parsed.length(); i++) {
349  if (parsed[i]->name != m_currentRoutes[i]->name) {
350  return false;
351  }
352  if (parsed[i]->data.isValid()) {
353  if (parsed[i]->data != m_currentRoutes[i]->data) {
354  return false;
355  }
356  }
357  }
358  return true;
359 }
360 
362 {
363  push(parseRoute(route));
364  Q_EMIT navigationChanged();
365 }
366 
368 {
369  m_pageStack->pop(m_currentRoutes.last()->item);
370  placeInCache(m_currentRoutes.last());
371  m_currentRoutes.removeLast();
372  reevaluateParamMapProperties();
373  Q_EMIT navigationChanged();
374 }
375 
376 QVariant PageRouter::dataFor(QObject *object)
377 {
378  auto pointer = object;
379  auto qqiPointer = qobject_cast<QQuickItem *>(object);
381  for (auto route : std::as_const(m_cache.items)) {
382  routes[route->item] = route;
383  }
384  for (auto route : std::as_const(m_preload.items)) {
385  routes[route->item] = route;
386  }
387  for (auto route : std::as_const(m_currentRoutes)) {
388  routes[route->item] = route;
389  }
390  while (qqiPointer != nullptr) {
391  const auto keys = routes.keys();
392  for (auto item : keys) {
393  if (item == qqiPointer) {
394  return routes[item]->data;
395  }
396  }
397  qqiPointer = qqiPointer->parentItem();
398  }
399  while (pointer != nullptr) {
400  const auto keys = routes.keys();
401  for (auto item : keys) {
402  if (item == pointer) {
403  return routes[item]->data;
404  }
405  }
406  pointer = pointer->parent();
407  }
408  return QVariant();
409 }
410 
411 bool PageRouter::isActive(QObject *object)
412 {
413  auto pointer = object;
414  while (pointer != nullptr) {
415  auto index = 0;
416  for (auto route : std::as_const(m_currentRoutes)) {
417  if (route->item == pointer) {
418  return m_pageStack->currentIndex() == index;
419  }
420  index++;
421  }
422  pointer = pointer->parent();
423  }
424  qCWarning(KirigamiLog) << "Object" << object << "not in current routes";
425  return false;
426 }
427 
428 PageRouterAttached *PageRouter::qmlAttachedProperties(QObject *object)
429 {
430  auto attached = new PageRouterAttached(object);
431  return attached;
432 }
433 
434 QSet<QObject *> flatParentTree(QObject *object)
435 {
436  // See below comment in Climber::climbObjectParents for why this is here.
437  static const QMetaObject *metaObject = QMetaType::metaObjectForType(QMetaType::type("QQuickItem*"));
438  QSet<QObject *> ret;
439  // Use an inline struct type so that climbItemParents and climbObjectParents
440  // can call each other
441  struct Climber {
442  void climbItemParents(QSet<QObject *> &out, QQuickItem *item)
443  {
444  auto parent = item->parentItem();
445  while (parent != nullptr) {
446  out << parent;
447  climbObjectParents(out, parent);
448  parent = parent->parentItem();
449  }
450  }
451  void climbObjectParents(QSet<QObject *> &out, QObject *object)
452  {
453  auto parent = object->parent();
454  while (parent != nullptr) {
455  out << parent;
456  // We manually call metaObject()->inherits() and
457  // use a reinterpret cast because qobject_cast seems
458  // to have stability issues here due to mutable
459  // pointer mechanics.
460  if (parent->metaObject()->inherits(metaObject)) {
461  climbItemParents(out, reinterpret_cast<QQuickItem *>(parent));
462  }
463  parent = parent->parent();
464  }
465  }
466  };
467  Climber climber;
468  if (qobject_cast<QQuickItem *>(object)) {
469  climber.climbItemParents(ret, qobject_cast<QQuickItem *>(object));
470  }
471  climber.climbObjectParents(ret, object);
472  return ret;
473 }
474 
475 void PageRouter::preload(ParsedRoute *route)
476 {
477  for (auto preloaded : std::as_const(m_preload.items)) {
478  if (preloaded->equals(route)) {
479  delete route;
480  return;
481  }
482  }
483  if (!routesContainsKey(route->name)) {
484  qCCritical(KirigamiLog) << "Route" << route->name << "not defined";
485  delete route;
486  return;
487  }
488  auto context = qmlContext(this);
489  auto component = routesValueForKey(route->name);
490  auto createAndCache = [component, context, route, this]() {
491  auto item = component->beginCreate(context);
492  item->setParent(this);
493  auto qqItem = qobject_cast<QQuickItem *>(item);
494  if (!qqItem) {
495  qCCritical(KirigamiLog) << "Route" << route->name << "is not an item! This is undefined behaviour and will likely crash your application.";
496  }
497  for (auto it = route->properties.begin(); it != route->properties.end(); it++) {
498  qqItem->setProperty(qUtf8Printable(it.key()), it.value());
499  }
500  route->setItem(qqItem);
501  route->cache = routesCacheForKey(route->name);
502  auto attached = qobject_cast<PageRouterAttached *>(qmlAttachedPropertiesObject<PageRouter>(item, true));
503  attached->m_router = this;
504  component->completeCreate();
505  if (!route->cache) {
506  qCCritical(KirigamiLog) << "Route" << route->name << "is being preloaded despite it not having caching enabled.";
507  delete route;
508  return;
509  }
510  auto string = route->name;
511  auto hash = route->hash();
512  m_preload.insert(qMakePair(string, hash), route, routesCostForKey(route->name));
513  };
514 
515  if (component->status() == QQmlComponent::Ready) {
516  createAndCache();
517  } else if (component->status() == QQmlComponent::Loading) {
518  connect(component, &QQmlComponent::statusChanged, [=](QQmlComponent::Status status) {
519  // Loading can only go to Ready or Error.
520  if (status != QQmlComponent::Ready) {
521  qCCritical(KirigamiLog) << "Failed to push route:" << component->errors();
522  }
523  createAndCache();
524  });
525  } else {
526  qCCritical(KirigamiLog) << "Failed to push route:" << component->errors();
527  }
528 }
529 
530 void PageRouter::unpreload(ParsedRoute *route)
531 {
532  ParsedRoute *toDelete = nullptr;
533  for (auto preloaded : std::as_const(m_preload.items)) {
534  if (preloaded->equals(route)) {
535  toDelete = preloaded;
536  }
537  }
538  if (toDelete != nullptr) {
539  m_preload.take(qMakePair(toDelete->name, toDelete->hash()));
540  delete toDelete;
541  }
542  delete route;
543 }
544 
545 void PreloadRouteGroup::handleChange()
546 {
547  if (!(m_parent->m_router)) {
548  qCCritical(KirigamiLog) << "PreloadRouteGroup does not have a parent PageRouter";
549  return;
550  }
551  auto r = m_parent->m_router;
552  auto parsed = parseRoute(m_route);
553  if (m_when) {
554  r->preload(parsed);
555  } else {
556  r->unpreload(parsed);
557  }
558 }
559 
560 PreloadRouteGroup::~PreloadRouteGroup()
561 {
562  if (m_parent->m_router) {
563  m_parent->m_router->unpreload(parseRoute(m_route));
564  }
565 }
566 
567 void PageRouterAttached::findParent()
568 {
569  QQuickItem *parent = qobject_cast<QQuickItem *>(this->parent());
570  while (parent != nullptr) {
571  auto attached = qobject_cast<PageRouterAttached *>(qmlAttachedPropertiesObject<PageRouter>(parent, false));
572  if (attached != nullptr && attached->m_router != nullptr) {
573  m_router = attached->m_router;
574  Q_EMIT routerChanged();
575  Q_EMIT dataChanged();
576  Q_EMIT isCurrentChanged();
577  Q_EMIT navigationChanged();
578  break;
579  }
580  parent = parent->parentItem();
581  }
582 }
583 
585 {
586  if (m_router) {
587  m_router->navigateToRoute(route);
588  } else {
589  qCCritical(KirigamiLog) << "PageRouterAttached does not have a parent PageRouter";
590  return;
591  }
592 }
593 
595 {
596  if (m_router) {
597  return m_router->routeActive(route);
598  } else {
599  qCCritical(KirigamiLog) << "PageRouterAttached does not have a parent PageRouter";
600  return false;
601  }
602 }
603 
605 {
606  if (m_router) {
607  m_router->pushRoute(route);
608  } else {
609  qCCritical(KirigamiLog) << "PageRouterAttached does not have a parent PageRouter";
610  return;
611  }
612 }
613 
615 {
616  if (m_router) {
617  m_router->popRoute();
618  } else {
619  qCCritical(KirigamiLog) << "PageRouterAttached does not have a parent PageRouter";
620  return;
621  }
622 }
623 
624 void PageRouterAttached::bringToView(QJSValue route)
625 {
626  if (m_router) {
627  m_router->bringToView(route);
628  } else {
629  qCCritical(KirigamiLog) << "PageRouterAttached does not have a parent PageRouter";
630  return;
631  }
632 }
633 
635 {
636  if (m_router) {
637  return m_router->dataFor(parent());
638  } else {
639  qCCritical(KirigamiLog) << "PageRouterAttached does not have a parent PageRouter";
640  return QVariant();
641  }
642 }
643 
645 {
646  if (m_router) {
647  return m_router->isActive(parent());
648  } else {
649  qCCritical(KirigamiLog) << "PageRouterAttached does not have a parent PageRouter";
650  return false;
651  }
652 }
653 
655 {
656  if (m_router) {
657  return m_router->routeActive(m_watchedRoute);
658  } else {
659  qCCritical(KirigamiLog) << "PageRouterAttached does not have a parent PageRouter";
660  return false;
661  }
662 }
663 
664 void PageRouterAttached::setWatchedRoute(QJSValue route)
665 {
666  m_watchedRoute = route;
667  Q_EMIT watchedRouteChanged();
668 }
669 
671 {
672  return m_watchedRoute;
673 }
674 
676 {
677  if (m_router) {
678  m_router->pushFromObject(parent(), route);
679  } else {
680  qCCritical(KirigamiLog) << "PageRouterAttached does not have a parent PageRouter";
681  }
682 }
683 
685 {
686  if (m_router) {
687  m_router->pushFromObject(parent(), route, true);
688  } else {
689  qCCritical(KirigamiLog) << "PageRouterAttached does not have a parent PageRouter";
690  }
691 }
692 
694 {
695  if (m_router) {
696  m_router->pushFromObject(parent(), QJSValue());
697  } else {
698  qCCritical(KirigamiLog) << "PageRouterAttached does not have a parent PageRouter";
699  }
700 }
701 
702 void PageRouter::placeInCache(ParsedRoute *route)
703 {
704  Q_ASSERT(route);
705  if (!route->cache) {
706  delete route;
707  return;
708  }
709  auto string = route->name;
710  auto hash = route->hash();
711  m_cache.insert(qMakePair(string, hash), route, routesCostForKey(route->name));
712 }
713 
714 void PageRouter::pushFromObject(QObject *object, QJSValue inputRoute, bool replace)
715 {
716  const auto parsed = parseRoutes(inputRoute);
717  const auto objects = flatParentTree(object);
718 
719  for (const auto &obj : objects) {
720  bool popping = false;
721  for (auto route : std::as_const(m_currentRoutes)) {
722  if (popping) {
723  m_currentRoutes.removeAll(route);
724  reevaluateParamMapProperties();
725  placeInCache(route);
726  continue;
727  }
728  if (route->item == obj) {
729  m_pageStack->pop(route->item);
730  if (replace) {
731  m_currentRoutes.removeAll(route);
732  reevaluateParamMapProperties();
733  m_pageStack->removeItem(route->item);
734  }
735  popping = true;
736  }
737  }
738  if (popping) {
739  if (!inputRoute.isUndefined()) {
740  for (auto route : parsed) {
741  push(route);
742  }
743  }
744  Q_EMIT navigationChanged();
745  return;
746  }
747  }
748  qCWarning(KirigamiLog) << "Object" << object << "not in current routes";
749 }
750 
752 {
753  auto engine = qjsEngine(this);
754  auto ret = engine->newArray(m_currentRoutes.length());
755  for (int i = 0; i < m_currentRoutes.length(); ++i) {
756  auto object = engine->newObject();
757  object.setProperty(QStringLiteral("route"), m_currentRoutes[i]->name);
758  object.setProperty(QStringLiteral("data"), engine->toScriptValue(m_currentRoutes[i]->data));
759  auto keys = m_currentRoutes[i]->properties.keys();
760  for (auto key : keys) {
761  object.setProperty(key, engine->toScriptValue(m_currentRoutes[i]->properties[key]));
762  }
763  ret.setProperty(i, object);
764  }
765  return ret;
766 }
767 
768 PageRouterAttached::PageRouterAttached(QObject *parent)
769  : QObject(parent)
770  , m_preload(new PreloadRouteGroup(this))
771 {
772  findParent();
773  auto item = qobject_cast<QQuickItem *>(parent);
774  if (item != nullptr) {
775  connect(item, &QQuickItem::windowChanged, this, [this]() {
776  findParent();
777  });
778  connect(item, &QQuickItem::parentChanged, this, [this]() {
779  findParent();
780  });
781  }
782 }
Q_INVOKABLE void navigateToRoute(QJSValue route)
Navigate to the given route.
Definition: pagerouter.cpp:277
void clear()
Attached object allowing children of a PageRouter to access its functions without requiring the child...
Definition: pagerouter.h:695
Q_INVOKABLE void popRoute()
Definition: pagerouter.cpp:614
Q_INVOKABLE void popFromHere()
Pop routes after this route on the stack.
Definition: pagerouter.cpp:693
QQuickItem * parentItem() const const
bool isArray() const const
QJSValue initialRoute
The initial route.
Definition: pagerouter.h:357
Q_INVOKABLE void pushRoute(QJSValue route)
Appends a route to the currently navigated route.
Definition: pagerouter.cpp:361
const QMetaObject * metaObjectForType(int type)
int length() const const
QList< QVariant > toList() const const
void reserve(int alloc)
bool watchedRouteActive
Whether the watchedRoute is currently active.
Definition: pagerouter.h:727
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
QString toString() const const
void statusChanged(QQmlComponent::Status status)
Q_INVOKABLE QJSValue currentRoutes() const
Returns a QJSValue corresponding to the current pages on the stack.
Definition: pagerouter.cpp:751
T value() const const
An item managing pages and data of a ColumnView using named routes.
Definition: pagerouter.h:333
const QLatin1String name
int type(const char *typeName)
T value(int i) const const
QQmlComponent component
The page component of this route.
Definition: pagerouter.h:216
Q_INVOKABLE void bringToView(QJSValue route)
Shifts keyboard focus and view to a given index on the PageRouter&#39;s stack.
Definition: pagerouter.cpp:323
QVariant toVariant() const const
KIOCORE_EXPORT CopyJob * copy(const QUrl &src, const QUrl &dest, JobFlags flags=DefaultFlags)
void append(const T &value)
QJSValue property(const QString &name) const const
bool isString() const const
Item representing a route the PageRouter can navigate to.
Definition: pagerouter.h:197
QVariant data
The data for the page this item belongs to.
Definition: pagerouter.h:704
double toNumber() const const
Item holding data about when to preload a route.
Definition: pagerouter.h:150
QList< Key > keys() const const
QQmlListProperty< PageRoute > routes
The named routes a PageRouter can navigate to.
Definition: pagerouter.h:343
bool contains(const T &value) const const
Q_INVOKABLE void pushRoute(QJSValue route)
Definition: pagerouter.cpp:604
bool isNumber() const const
Q_INVOKABLE void pushFromHere(QJSValue route)
Push a route from this route on the stack.
Definition: pagerouter.cpp:675
void insert(int i, const T &value)
bool isUndefined() const const
QList< T > mid(int pos, int length) const const
Q_INVOKABLE bool routeActive(QJSValue route)
Check whether the current route is on the stack.
Definition: pagerouter.cpp:342
Q_INVOKABLE bool routeActive(QJSValue route)
Definition: pagerouter.cpp:594
Q_INVOKABLE void navigateToRoute(QJSValue route)
Definition: pagerouter.cpp:584
bool setProperty(const char *name, const QVariant &value)
void windowChanged(QQuickWindow *window)
QObject * parent() const const
Q_INVOKABLE void replaceFromHere(QJSValue route)
Replaces this route with the given routes on the stack.
Definition: pagerouter.cpp:684
QFuture< void > map(Sequence &sequence, MapFunctor function)
bool isCurrent
Whether the page this item belongs to is the current index of the ColumnView.
Definition: pagerouter.h:710
QString name
The name of this route.
Definition: pagerouter.h:208
bool cache
Whether pages generated by this route should be cached or not.
Definition: pagerouter.h:233
QJSValue watchedRoute
Which route this PageRouterAttached should watch for.
Definition: pagerouter.h:717
Q_INVOKABLE void popRoute()
Pops the last page on the router.
Definition: pagerouter.cpp:367
void replace(int i, const T &value)
int cost
How expensive this route is on memory.
Definition: pagerouter.h:241
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Jan 22 2022 22:34:52 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.