title: How to get an instantiated delegate component from a GridView or ListView in QML
body: <p>My conundrum, phrased generally, is: through some action outside the GridView, I want to figure out the coordinates of a particular delegate item in the GridView based only on a particular model item or index selected before.</p>
  
  <p>I've got a GridView with a number of items in the model.  The GridView's delegate creates a thumbnail view of each item.  When clicked, it brings up a detailed, fullscreen view of the item.  I'd like a nice transition that shows the thumbnail expanding out from its place in the GridView, and when the detailed view is dismissed, shrinking back down into the GridView in place.</p>
  
  <p>The trick is, the detailed view is itself a delegate of a ListView so you can page between detailed views one screen at a time.  This means a solution that simply resizes the GridView's delegate item or something won't work.  Also, since you can page to any item in the ListView, returning to the GridView has to be done based only on information available in the model or the model item's index (e.g. I can't store the coords of the MouseArea used to launch the detailed view or something).</p>
  
  <p>The expansion animation is fairly easy, as the delegate item has a MouseArea for the click handler that knows its own placement, so that can be passed out to the function that starts the animation.  It's the reverse I can't figure out: from the model item/index in the ListView, how do I figure out the coordinates of the related item in the GridView?</p>
  
  <p>I can't find anything in the docs that would seem to let you have access to a delegate item instance from a model item instance or even an index.  The GridView has <code>indexAt()</code> that returns the index based on coordinates.  I think I could make do with the reverse, but it doesn't appear to exist.</p>
  
  <p>Here's a more concrete example.  Apologies for the length; this is the shortest example code I could come up with that accurately describes my problem:</p>
  
  <pre><code>import QtQuick 1.1
  
  Item {
      id: window
      width: 400
      height: 200
  
      state: "summary"
      states: [
          State { name: "summary"; },
          State { name: "details"; }
      ]
      transitions: [
          Transition { from: "summary"; to: "details";
              SequentialAnimation {
                  PropertyAction { target: animationRect; property: "visible"; value: true; }
                  ParallelAnimation {
                      NumberAnimation { target: animationRect; properties: "x,y"; to: 0; duration: 200; }
                      NumberAnimation { target: animationRect; property: "width"; to: 400; duration: 200; }
                      NumberAnimation { target: animationRect; property: "height"; to: 200; duration: 200; }
                  }
                  PropertyAction { target: detailsView; property: "visible"; value: true; }
                  PropertyAction { target: summaryView; property: "visible"; value: false; }
                  PropertyAction { target: animationRect; property: "visible"; value: false; }
              }
          },
          Transition { from: "details"; to: "summary";
              SequentialAnimation {
                  PropertyAction { target: summaryView; property: "visible"; value: true; }
  
                  // How to animate animationRect back down to the correct item?
  
                  PropertyAction { target: detailsView; property: "visible"; value: false; }
              }
          }
      ]
  
      Rectangle {
          id: animationRect
          z: 1
          color: "gray"
          visible: false
  
          function positionOverSummary(summaryRect) {
              x = summaryRect.x; y = summaryRect.y;
              width = summaryRect.width; height = summaryRect.height;
          }
      }
  
      ListModel {
          id: data
          ListElement { summary: "Item 1"; description: "Lorem ipsum..."; }
          ListElement { summary: "Item 2"; description: "Blah blah..."; }
          ListElement { summary: "Item 3"; description: "Hurf burf..."; }
      }
  
      GridView {
          id: summaryView
          anchors.fill: parent
          cellWidth: 100
          cellHeight: 100
  
          model: data
          delegate: Rectangle {
              color: "lightgray"
              width: 95; height: 95;
  
              Text { text: summary; }
              MouseArea {
                  anchors.fill: parent
                  onClicked: {
                      var delegateRect = mapToItem(window, x, y);
                      delegateRect.width = width; delegateRect.height = height;
  
                      animationRect.positionOverSummary(delegateRect);
                      detailsView.positionViewAtIndex(index, ListView.Beginning);
                      window.state = "details";
                  }
              }
          }
      }
  
      ListView {
          id: detailsView
          anchors.fill: parent
          visible: false
          orientation: ListView.Horizontal
          snapMode: ListView.SnapOneItem
  
          model: data
          delegate: Rectangle {
              color: "gray"
              width: 400; height: 200;
  
              Column {
                  Text { text: summary; }
                  Text { text: description; }
              }
              MouseArea {
                  anchors.fill: parent
                  onClicked: {
                      // How do I get the coordinates to where animationRect should return?
  
                      summaryView.positionViewAtIndex(index, GridView.Visible);
                      window.state = "summary";
                  }
              }
          }
      }
  }
  </code></pre>
  
  <p>Any ideas?  It's possible I'm just going about this the wrong way.  If what I'm trying to do specifically is impossible, is there some other way I should be architecting this?  Thanks!</p>
  
  <hr>
  
  <p>Edit: Some ideas I've had (none of which I believe are feasible):</p>
  
  <ul>
  <li><p>Keep a list of all the delegate items created, using <code>Component.onCompleted</code> and <code>Component.onDestruction</code>.  To be useful, it should be a map of model item or index => delegate item.  Trouble is, the <a href="https://doc.qt.io/qt-5/qdeclarativebasictypes.html" rel="nofollow noreferrer">basic types docs</a> (especially <a href="https://doc.qt.io/qt-5/qml-variant.html" rel="nofollow noreferrer">variant</a>) seem to indicate that this kind of map is impossible to create in pure QML.  So it sounds like this would mean creating this map as a C++ class and using that in QML with <code>onCompleted</code>/<code>onDestruction</code> within the delegate component to keep it up to date.  Seems a little dangerous and heavy-handed for something that should be simple.</p></li>
  <li><p><a href="http://lists.qt.nokia.com/pipermail/qt-qml/2011-July/002800.html" rel="nofollow noreferrer">This mailing list post</a> seems to indicate that Flickable's <code>contentItem</code> property can be used to enumerate the delegate items.  Then I found <a href="http://lists.qt.nokia.com/pipermail/qt-qml/2011-July/002802.html" rel="nofollow noreferrer">this post</a> calling that out as bad practice.  I'm still looking into it, but I'm skeptical this will be a legitimate solution.  Seems way too hacky to work reliably.</p></li>
  </ul>
  
  <p>That's all I've got so far.</p>