From 00dab06535278da1cbfb2a11e93c38258aed3655 Mon Sep 17 00:00:00 2001
From: Christian Stenger <christian.stenger@digia.com>
Date: Tue, 30 Oct 2012 12:05:27 +0100
Subject: [PATCH] Squish: Added test for QML outline

Change-Id: I6199cf22da0049319c2eaef6977884ed7f63a4fd
Reviewed-by: Robert Loehning <robert.loehning@digia.com>
---
 tests/system/objects.map                      |   2 +
 tests/system/shared/editor_utils.py           |   1 +
 tests/system/suite_qtquick/suite.conf         |   2 +-
 .../suite_qtquick/tst_qml_outline/test.py     | 114 ++++++++++++++++++
 .../testdata/ListMenu.qml_outline.tsv         |  85 +++++++++++++
 .../testdata/focus.qml_mod1_outline.tsv       |  81 +++++++++++++
 .../testdata/focus.qml_mod2_outline.tsv       |  81 +++++++++++++
 .../testdata/focus.qml_outline.tsv            |  75 ++++++++++++
 8 files changed, 440 insertions(+), 1 deletion(-)
 create mode 100644 tests/system/suite_qtquick/tst_qml_outline/test.py
 create mode 100644 tests/system/suite_qtquick/tst_qml_outline/testdata/ListMenu.qml_outline.tsv
 create mode 100644 tests/system/suite_qtquick/tst_qml_outline/testdata/focus.qml_mod1_outline.tsv
 create mode 100644 tests/system/suite_qtquick/tst_qml_outline/testdata/focus.qml_mod2_outline.tsv
 create mode 100644 tests/system/suite_qtquick/tst_qml_outline/testdata/focus.qml_outline.tsv

diff --git a/tests/system/objects.map b/tests/system/objects.map
index cff13b8456e..2ee61a9e843 100644
--- a/tests/system/objects.map
+++ b/tests/system/objects.map
@@ -91,6 +91,7 @@
 :Qt Creator_CompileOutput_Core::Internal::OutputPaneToggleButton	{occurrence='4' type='Core::Internal::OutputPaneToggleButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
 :Qt Creator_Core::Internal::CommandComboBox	{type='Core::Internal::CommandComboBox' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
 :Qt Creator_Core::Internal::MainWindow	{type='Core::Internal::MainWindow' visible='1' windowTitle?='*Qt Creator'}
+:Qt Creator_Core::Internal::NavComboBox	{type='Core::Internal::NavComboBox' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
 :Qt Creator_CppEditor::Internal::CPPEditorWidget	{type='CppEditor::Internal::CPPEditorWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
 :Qt Creator_FilenameQComboBox	{type='QComboBox' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
 :Qt Creator_Find::Internal::SearchResultTreeView	{type='Find::Internal::SearchResultTreeView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
@@ -101,6 +102,7 @@
 :Qt Creator_QDeclarativeView	{type='QDeclarativeView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
 :Qt Creator_QHelpContentWidget	{type='QHelpContentWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
 :Qt Creator_QTableView	{type='QTableView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
+:Qt Creator_QmlJSEditor::Internal::QmlJSOutlineTreeView	{type='QmlJSEditor::Internal::QmlJSOutlineTreeView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
 :Qt Creator_QmlJSEditor::QmlJSTextEditorWidget	{type='QmlJSEditor::QmlJSTextEditorWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
 :Qt Creator_SearchResult_Core::Internal::OutputPaneToggleButton	{occurrence='2' type='Core::Internal::OutputPaneToggleButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
 :Qt Creator_SystemSettings.Details_Utils::DetailsButton	{occurrence='4' text='Details' type='Utils::DetailsButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'}
diff --git a/tests/system/shared/editor_utils.py b/tests/system/shared/editor_utils.py
index 7200725346d..45d533420ee 100644
--- a/tests/system/shared/editor_utils.py
+++ b/tests/system/shared/editor_utils.py
@@ -294,6 +294,7 @@ def invokeFindUsage(editor, line, typeOperation, n=1):
 
 def openDocument(treeElement):
     try:
+        selectFromCombo(":Qt Creator_Core::Internal::NavComboBox", "Open Documents")
         navigator = waitForObject(":Qt Creator_Utils::NavigationTreeView")
         fileName = waitForObjectItem(navigator, treeElement).text
         doubleClickItem(navigator, treeElement, 5, 5, 0, Qt.LeftButton)
diff --git a/tests/system/suite_qtquick/suite.conf b/tests/system/suite_qtquick/suite.conf
index 7700a40c5aa..b7ff85fa5ae 100644
--- a/tests/system/suite_qtquick/suite.conf
+++ b/tests/system/suite_qtquick/suite.conf
@@ -7,6 +7,6 @@ HOOK_SUB_PROCESSES=false
 IMPLICITAUTSTART=0
 LANGUAGE=Python
 OBJECTMAP=../objects.map
-TEST_CASES=tst_qtquick_creation tst_qtquick_creation2 tst_qtquick_creation3 tst_qtquick_creation4
+TEST_CASES=tst_qml_outline tst_qtquick_creation tst_qtquick_creation2 tst_qtquick_creation3 tst_qtquick_creation4
 VERSION=2
 WRAPPERS=Qt
diff --git a/tests/system/suite_qtquick/tst_qml_outline/test.py b/tests/system/suite_qtquick/tst_qml_outline/test.py
new file mode 100644
index 00000000000..3a15c78183d
--- /dev/null
+++ b/tests/system/suite_qtquick/tst_qml_outline/test.py
@@ -0,0 +1,114 @@
+source("../../shared/qtcreator.py")
+
+qmlEditor = ":Qt Creator_QmlJSEditor::QmlJSTextEditorWidget"
+outline = ":Qt Creator_QmlJSEditor::Internal::QmlJSOutlineTreeView"
+
+def main():
+    sourceExample = os.path.abspath(os.path.join(sdkPath, "Examples", "4.7", "declarative",
+                                                 "keyinteraction", "focus"))
+    proFile = "focus.pro"
+    if not neededFilePresent(os.path.join(sourceExample, proFile)):
+        return
+    templateDir = prepareTemplate(sourceExample)
+    startApplication("qtcreator" + SettingsPath)
+    openQmakeProject(os.path.join(templateDir, proFile))
+    qmlFiles = ["focus.QML.qml.focus\\.qml", "focus.QML.qml.Core.ListMenu\\.qml"]
+    checkOutlineFor(qmlFiles)
+    testModify()
+    invokeMenuItem("File", "Save All")
+    invokeMenuItem("File", "Exit")
+
+def checkOutlineFor(qmlFiles):
+    for qmlFile in qmlFiles:
+        if not openDocument(qmlFile):
+            test.fatal("Failed to open file '%s'" % simpleFileName(qmlFile))
+            continue
+        selectFromCombo(":Qt Creator_Core::Internal::NavComboBox", "Outline")
+        pseudoTree = buildTreeFromOutline()
+        # __writeOutlineFile__(pseudoTree, simpleFileName(qmlFile)+"_outline.tsv")
+        verifyOutline(pseudoTree, simpleFileName(qmlFile) + "_outline.tsv")
+
+def buildTreeFromOutline():
+    global outline
+    model = waitForObject(outline).model()
+    waitFor("model.rowCount() > 0")
+    return processChildren(model, QModelIndex(), 0)
+
+def processChildren(model, startIndex, level):
+    children = []
+    for index in dumpIndices(model, startIndex):
+        annotationData = str(index.data(Qt.UserRole + 3)) # HACK - taken from source
+        children.append((str(index.data()), level, annotationData))
+        if model.hasChildren(index):
+            children.extend(processChildren(model, index, level + 1))
+    return children
+
+def testModify():
+    global qmlEditor, outline
+    if not openDocument("focus.QML.qml.focus\\.qml"):
+        test.fatal("Failed to open file focus.qml")
+        return
+    test.log("Testing whether modifications show up inside outline.")
+    if not placeCursorToLine(qmlEditor, 'color: "#3E606F"'):
+        return
+    test.log("Modification: adding a QML element")
+    typeLines(qmlEditor, ['', '', 'Text {', 'id: addedText', 'text: "Squish QML outline test"',
+                          'color: "darkcyan"', 'font.bold: true', 'anchors.centerIn: parent'])
+    selectFromCombo(":Qt Creator_Core::Internal::NavComboBox", "Outline")
+    snooze(1) # no way to wait for a private signal
+    pseudoTree = buildTreeFromOutline()
+    # __writeOutlineFile__(pseudoTree, "focus.qml_mod1_outline.tsv")
+    verifyOutline(pseudoTree, "focus.qml_mod1_outline.tsv")
+    test.log("Modification: change existing content")
+    performModification('color: "#3E606F"', "<Left>", 7, "Left", "white")
+    performModification('color: "black"', "<Left>", 5, "Left", "#cc00bb")
+    performModification('rotation: 90', None, 2, "Left", "180")
+    snooze(1) # no way to wait for a private signal
+    pseudoTree = buildTreeFromOutline()
+    # __writeOutlineFile__(pseudoTree, "focus.qml_mod2_outline.tsv")
+    verifyOutline(pseudoTree, "focus.qml_mod2_outline.tsv")
+
+def performModification(afterLine, typing, markCount, markDirection, newText):
+    global qmlEditor
+    if not placeCursorToLine(qmlEditor, afterLine):
+        return
+    if typing:
+        type(qmlEditor, typing)
+    markText(qmlEditor, markCount, markDirection)
+    type(qmlEditor, newText)
+
+def markText(editor, charCount, direction):
+    for i in range(charCount):
+        type(editor, "<Shift+%s>" % direction)
+
+# used to create the tsv file(s)
+def __writeOutlineFile__(outlinePseudoTree, filename):
+    f = open(filename, "w+")
+    f.write('"element"\t"nestinglevel"\t"value"\n')
+    for elem in outlinePseudoTree:
+        f.write('"%s"\t"%s"\t"%s"\n' % (elem[0], elem[1], elem[2].replace('"', '\"\"')))
+    f.close()
+
+def retrieveData(record):
+    return (testData.field(record, "element"),
+            __builtin__.int(testData.field(record, "nestinglevel")),
+            testData.field(record, "value"))
+
+def verifyOutline(outlinePseudoTree, datasetFileName):
+    fileName = datasetFileName[:datasetFileName.index("_")]
+    expected = map(retrieveData, testData.dataset(datasetFileName))
+    if len(expected) != len(outlinePseudoTree):
+        test.fail("Mismatch in length of expected and found elements of outline. Skipping "
+                  "verification of nodes.",
+                  "Found %d elements, but expected %d" % (len(outlinePseudoTree), len(expected)))
+        return
+    for counter, (expectedItem, foundItem) in enumerate(zip(expected, outlinePseudoTree)):
+       if expectedItem != foundItem:
+           test.fail("Mismatch in element number %d for '%s'" % (counter + 1, fileName),
+                      "%s != %s" % (str(expectedItem), str(foundItem)))
+           return
+    test.passes("All nodes (%d) inside outline match expected nodes for '%s'."
+                % (len(expected), fileName))
+
+def simpleFileName(navigatorFileName):
+    return ".".join(navigatorFileName.split(".")[-2:]).replace("\\", "")
diff --git a/tests/system/suite_qtquick/tst_qml_outline/testdata/ListMenu.qml_outline.tsv b/tests/system/suite_qtquick/tst_qml_outline/testdata/ListMenu.qml_outline.tsv
new file mode 100644
index 00000000000..3ca25e4b9c9
--- /dev/null
+++ b/tests/system/suite_qtquick/tst_qml_outline/testdata/ListMenu.qml_outline.tsv
@@ -0,0 +1,85 @@
+"element"	"nestinglevel"	"value"
+"FocusScope"	"0"	""
+"clip"	"1"	"true"
+"onActiveFocusChanged"	"1"	""
+"ListView"	"1"	""
+"id"	"2"	"list1"
+"y"	"2"	"activeFocus ? 10 : 40"
+"width"	"2"	"parent.width / 3"
+"height"	"2"	"parent.height - 20"
+"focus"	"2"	"true"
+"KeyNavigation.up"	"2"	"gridMenu"
+"KeyNavigation.left"	"2"	"contextMenu"
+"KeyNavigation.right"	"2"	"list2"
+"model"	"2"	"10"
+"cacheBuffer"	"2"	"200"
+"delegate"	"2"	""
+"ListViewDelegate"	"3"	""
+"y"	"2"	""
+"Behavior"	"3"	""
+"NumberAnimation"	"4"	""
+"duration"	"5"	"600"
+"easing.type"	"5"	"Easing.OutQuint"
+"ListView"	"1"	""
+"id"	"2"	"list2"
+"y"	"2"	"activeFocus ? 10 : 40"
+"x"	"2"	"parseInt(parent.width / 3)"
+"width"	"2"	"parent.width / 3"
+"height"	"2"	"parent.height - 20"
+"KeyNavigation.up"	"2"	"gridMenu"
+"KeyNavigation.left"	"2"	"list1"
+"KeyNavigation.right"	"2"	"list3"
+"model"	"2"	"10"
+"cacheBuffer"	"2"	"200"
+"delegate"	"2"	""
+"ListViewDelegate"	"3"	""
+"y"	"2"	""
+"Behavior"	"3"	""
+"NumberAnimation"	"4"	""
+"duration"	"5"	"600"
+"easing.type"	"5"	"Easing.OutQuint"
+"ListView"	"1"	""
+"id"	"2"	"list3"
+"y"	"2"	"activeFocus ? 10 : 40"
+"x"	"2"	"parseInt(2 * parent.width / 3)"
+"width"	"2"	"parent.width / 3"
+"height"	"2"	"parent.height - 20"
+"KeyNavigation.up"	"2"	"gridMenu"
+"KeyNavigation.left"	"2"	"list2"
+"model"	"2"	"10"
+"cacheBuffer"	"2"	"200"
+"delegate"	"2"	""
+"ListViewDelegate"	"3"	""
+"y"	"2"	""
+"Behavior"	"3"	""
+"NumberAnimation"	"4"	""
+"duration"	"5"	"600"
+"easing.type"	"5"	"Easing.OutQuint"
+"Rectangle"	"1"	""
+"width"	"2"	"parent.width"
+"height"	"2"	"1"
+"color"	"2"	"""#D1DBBD"""
+"Rectangle"	"1"	""
+"y"	"2"	"1"
+"width"	"2"	"parent.width"
+"height"	"2"	"10"
+"gradient"	"2"	""
+"Gradient"	"3"	""
+"GradientStop"	"4"	""
+"position"	"5"	"0.0"
+"color"	"5"	"""#3E606F"""
+"GradientStop"	"4"	""
+"position"	"5"	"1.0"
+"color"	"5"	"""transparent"""
+"Rectangle"	"1"	""
+"y"	"2"	"parent.height - 10"
+"width"	"2"	"parent.width"
+"height"	"2"	"10"
+"gradient"	"2"	""
+"Gradient"	"3"	""
+"GradientStop"	"4"	""
+"position"	"5"	"1.0"
+"color"	"5"	"""#3E606F"""
+"GradientStop"	"4"	""
+"position"	"5"	"0.0"
+"color"	"5"	"""transparent"""
diff --git a/tests/system/suite_qtquick/tst_qml_outline/testdata/focus.qml_mod1_outline.tsv b/tests/system/suite_qtquick/tst_qml_outline/testdata/focus.qml_mod1_outline.tsv
new file mode 100644
index 00000000000..d31ad3d1483
--- /dev/null
+++ b/tests/system/suite_qtquick/tst_qml_outline/testdata/focus.qml_mod1_outline.tsv
@@ -0,0 +1,81 @@
+"element"	"nestinglevel"	"value"
+"Rectangle"	"0"	""
+"id"	"1"	"window"
+"width"	"1"	"800"
+"height"	"1"	"480"
+"color"	"1"	"""#3E606F"""
+"Text"	"1"	""
+"id"	"2"	"addedText"
+"text"	"2"	"""Squish QML outline test"""
+"color"	"2"	"""darkcyan"""
+"font.bold"	"2"	"true"
+"anchors.centerIn"	"2"	"parent"
+"FocusScope"	"1"	""
+"id"	"2"	"mainView"
+"width"	"2"	"parent.width"
+"height"	"2"	"parent.height"
+"focus"	"2"	"true"
+"GridMenu"	"2"	""
+"id"	"3"	"gridMenu"
+"width"	"3"	"parent.width"
+"height"	"3"	"320"
+"focus"	"3"	"true"
+"interactive"	"3"	"parent.activeFocus"
+"ListMenu"	"2"	""
+"id"	"3"	"listMenu"
+"y"	"3"	"320"
+"width"	"3"	"parent.width"
+"height"	"3"	"320"
+"Rectangle"	"2"	""
+"id"	"3"	"shade"
+"anchors.fill"	"3"	"parent"
+"color"	"3"	"""black"""
+"opacity"	"3"	"0"
+"states"	"2"	""
+"State"	"3"	""
+"name"	"4"	"""showListViews"""
+"PropertyChanges"	"4"	""
+"target"	"5"	"gridMenu"
+"y"	"5"	"-160"
+"PropertyChanges"	"4"	""
+"target"	"5"	"listMenu"
+"y"	"5"	"160"
+"transitions"	"2"	""
+"Transition"	"3"	""
+"NumberAnimation"	"4"	""
+"properties"	"5"	"""y"""
+"duration"	"5"	"600"
+"easing.type"	"5"	"Easing.OutQuint"
+"Image"	"1"	""
+"source"	"2"	"""Core/images/arrow.png"""
+"rotation"	"2"	"90"
+"anchors.verticalCenter"	"2"	"parent.verticalCenter"
+"MouseArea"	"2"	""
+"anchors.fill"	"3"	"parent"
+"anchors.margins"	"3"	"-10"
+"onClicked"	"3"	"contextMenu.focus = true"
+"ContextMenu"	"1"	""
+"id"	"2"	"contextMenu"
+"x"	"2"	"-265"
+"width"	"2"	"260"
+"height"	"2"	"parent.height"
+"states"	"1"	""
+"State"	"2"	""
+"name"	"3"	"""contextMenuOpen"""
+"when"	"3"	"!mainView.activeFocus"
+"PropertyChanges"	"3"	""
+"target"	"4"	"contextMenu"
+"x"	"4"	"0"
+"open"	"4"	"true"
+"PropertyChanges"	"3"	""
+"target"	"4"	"mainView"
+"x"	"4"	"130"
+"PropertyChanges"	"3"	""
+"target"	"4"	"shade"
+"opacity"	"4"	"0.25"
+"transitions"	"1"	""
+"Transition"	"2"	""
+"NumberAnimation"	"3"	""
+"properties"	"4"	"""x,opacity"""
+"duration"	"4"	"600"
+"easing.type"	"4"	"Easing.OutQuint"
diff --git a/tests/system/suite_qtquick/tst_qml_outline/testdata/focus.qml_mod2_outline.tsv b/tests/system/suite_qtquick/tst_qml_outline/testdata/focus.qml_mod2_outline.tsv
new file mode 100644
index 00000000000..27026b87170
--- /dev/null
+++ b/tests/system/suite_qtquick/tst_qml_outline/testdata/focus.qml_mod2_outline.tsv
@@ -0,0 +1,81 @@
+"element"	"nestinglevel"	"value"
+"Rectangle"	"0"	""
+"id"	"1"	"window"
+"width"	"1"	"800"
+"height"	"1"	"480"
+"color"	"1"	"""white"""
+"Text"	"1"	""
+"id"	"2"	"addedText"
+"text"	"2"	"""Squish QML outline test"""
+"color"	"2"	"""darkcyan"""
+"font.bold"	"2"	"true"
+"anchors.centerIn"	"2"	"parent"
+"FocusScope"	"1"	""
+"id"	"2"	"mainView"
+"width"	"2"	"parent.width"
+"height"	"2"	"parent.height"
+"focus"	"2"	"true"
+"GridMenu"	"2"	""
+"id"	"3"	"gridMenu"
+"width"	"3"	"parent.width"
+"height"	"3"	"320"
+"focus"	"3"	"true"
+"interactive"	"3"	"parent.activeFocus"
+"ListMenu"	"2"	""
+"id"	"3"	"listMenu"
+"y"	"3"	"320"
+"width"	"3"	"parent.width"
+"height"	"3"	"320"
+"Rectangle"	"2"	""
+"id"	"3"	"shade"
+"anchors.fill"	"3"	"parent"
+"color"	"3"	"""#cc00bb"""
+"opacity"	"3"	"0"
+"states"	"2"	""
+"State"	"3"	""
+"name"	"4"	"""showListViews"""
+"PropertyChanges"	"4"	""
+"target"	"5"	"gridMenu"
+"y"	"5"	"-160"
+"PropertyChanges"	"4"	""
+"target"	"5"	"listMenu"
+"y"	"5"	"160"
+"transitions"	"2"	""
+"Transition"	"3"	""
+"NumberAnimation"	"4"	""
+"properties"	"5"	"""y"""
+"duration"	"5"	"600"
+"easing.type"	"5"	"Easing.OutQuint"
+"Image"	"1"	""
+"source"	"2"	"""Core/images/arrow.png"""
+"rotation"	"2"	"180"
+"anchors.verticalCenter"	"2"	"parent.verticalCenter"
+"MouseArea"	"2"	""
+"anchors.fill"	"3"	"parent"
+"anchors.margins"	"3"	"-10"
+"onClicked"	"3"	"contextMenu.focus = true"
+"ContextMenu"	"1"	""
+"id"	"2"	"contextMenu"
+"x"	"2"	"-265"
+"width"	"2"	"260"
+"height"	"2"	"parent.height"
+"states"	"1"	""
+"State"	"2"	""
+"name"	"3"	"""contextMenuOpen"""
+"when"	"3"	"!mainView.activeFocus"
+"PropertyChanges"	"3"	""
+"target"	"4"	"contextMenu"
+"x"	"4"	"0"
+"open"	"4"	"true"
+"PropertyChanges"	"3"	""
+"target"	"4"	"mainView"
+"x"	"4"	"130"
+"PropertyChanges"	"3"	""
+"target"	"4"	"shade"
+"opacity"	"4"	"0.25"
+"transitions"	"1"	""
+"Transition"	"2"	""
+"NumberAnimation"	"3"	""
+"properties"	"4"	"""x,opacity"""
+"duration"	"4"	"600"
+"easing.type"	"4"	"Easing.OutQuint"
diff --git a/tests/system/suite_qtquick/tst_qml_outline/testdata/focus.qml_outline.tsv b/tests/system/suite_qtquick/tst_qml_outline/testdata/focus.qml_outline.tsv
new file mode 100644
index 00000000000..0f72a543a0c
--- /dev/null
+++ b/tests/system/suite_qtquick/tst_qml_outline/testdata/focus.qml_outline.tsv
@@ -0,0 +1,75 @@
+"element"	"nestinglevel"	"value"
+"Rectangle"	"0"	""
+"id"	"1"	"window"
+"width"	"1"	"800"
+"height"	"1"	"480"
+"color"	"1"	"""#3E606F"""
+"FocusScope"	"1"	""
+"id"	"2"	"mainView"
+"width"	"2"	"parent.width"
+"height"	"2"	"parent.height"
+"focus"	"2"	"true"
+"GridMenu"	"2"	""
+"id"	"3"	"gridMenu"
+"width"	"3"	"parent.width"
+"height"	"3"	"320"
+"focus"	"3"	"true"
+"interactive"	"3"	"parent.activeFocus"
+"ListMenu"	"2"	""
+"id"	"3"	"listMenu"
+"y"	"3"	"320"
+"width"	"3"	"parent.width"
+"height"	"3"	"320"
+"Rectangle"	"2"	""
+"id"	"3"	"shade"
+"anchors.fill"	"3"	"parent"
+"color"	"3"	"""black"""
+"opacity"	"3"	"0"
+"states"	"2"	""
+"State"	"3"	""
+"name"	"4"	"""showListViews"""
+"PropertyChanges"	"4"	""
+"target"	"5"	"gridMenu"
+"y"	"5"	"-160"
+"PropertyChanges"	"4"	""
+"target"	"5"	"listMenu"
+"y"	"5"	"160"
+"transitions"	"2"	""
+"Transition"	"3"	""
+"NumberAnimation"	"4"	""
+"properties"	"5"	"""y"""
+"duration"	"5"	"600"
+"easing.type"	"5"	"Easing.OutQuint"
+"Image"	"1"	""
+"source"	"2"	"""Core/images/arrow.png"""
+"rotation"	"2"	"90"
+"anchors.verticalCenter"	"2"	"parent.verticalCenter"
+"MouseArea"	"2"	""
+"anchors.fill"	"3"	"parent"
+"anchors.margins"	"3"	"-10"
+"onClicked"	"3"	"contextMenu.focus = true"
+"ContextMenu"	"1"	""
+"id"	"2"	"contextMenu"
+"x"	"2"	"-265"
+"width"	"2"	"260"
+"height"	"2"	"parent.height"
+"states"	"1"	""
+"State"	"2"	""
+"name"	"3"	"""contextMenuOpen"""
+"when"	"3"	"!mainView.activeFocus"
+"PropertyChanges"	"3"	""
+"target"	"4"	"contextMenu"
+"x"	"4"	"0"
+"open"	"4"	"true"
+"PropertyChanges"	"3"	""
+"target"	"4"	"mainView"
+"x"	"4"	"130"
+"PropertyChanges"	"3"	""
+"target"	"4"	"shade"
+"opacity"	"4"	"0.25"
+"transitions"	"1"	""
+"Transition"	"2"	""
+"NumberAnimation"	"3"	""
+"properties"	"4"	"""x,opacity"""
+"duration"	"4"	"600"
+"easing.type"	"4"	"Easing.OutQuint"
-- 
GitLab