improved desktop UI
[mardrone] / mardrone / imports / com / nokia / meego / PageStack.js
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the Qt Components project.
8 **
9 ** $QT_BEGIN_LICENSE:BSD$
10 ** You may use this file under the terms of the BSD license as follows:
11 **
12 ** "Redistribution and use in source and binary forms, with or without
13 ** modification, are permitted provided that the following conditions are
14 ** met:
15 **   * Redistributions of source code must retain the above copyright
16 **     notice, this list of conditions and the following disclaimer.
17 **   * Redistributions in binary form must reproduce the above copyright
18 **     notice, this list of conditions and the following disclaimer in
19 **     the documentation and/or other materials provided with the
20 **     distribution.
21 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
22 **     the names of its contributors may be used to endorse or promote
23 **     products derived from this software without specific prior written
24 **     permission.
25 **
26 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 // Page stack. Items are page containers.
42 var pageStack = [];
43
44 // Page component cache map. Key is page url, value is page component.
45 var componentCache = {};
46
47 // Returns the page stack depth.
48 function getDepth() {
49     return pageStack.length;
50 }
51
52 // Pushes a page on the stack.
53 function push(page, properties, replace, immediate) {
54     // page order sanity check
55     if ((!replace && page == currentPage) ||
56             (replace && pageStack.length > 1 && page == pageStack[pageStack.length - 2].page)) {
57         throw new Error("Cannot navigate so that the resulting page stack has two consecutive entries of the same page instance.");
58     }
59
60     // figure out if more than one page is being pushed
61     var pages;
62     if (page instanceof Array) {
63         pages = page;
64         page = pages.pop();
65         if (page.createObject === undefined && page.parent === undefined && typeof page != "string") {
66             properties = properties || page.properties;
67             page = page.page;
68         }
69     }
70
71     // get the current container
72     var oldContainer = pageStack[pageStack.length - 1];
73
74     // pop the old container off the stack if this is a replace
75     if (oldContainer && replace) {
76         pageStack.pop();
77     }
78
79     // push any extra defined pages onto the stack
80     if (pages) {
81         var i;
82         for (i = 0; i < pages.length; i++) {
83             var tPage = pages[i];
84             var tProps;
85             if (tPage.createObject === undefined && tPage.parent === undefined && typeof tPage != "string") {
86                 tProps = tPage.properties;
87                 tPage = tPage.page;
88             }
89             pageStack.push(initPage(tPage, tProps));
90         }
91     }
92
93     // initialize the page
94     var container = initPage(page, properties);
95
96     // push the page container onto the stack
97     pageStack.push(container);
98
99     depth = pageStack.length;
100     currentPage = container.page;
101
102     // perform page transition
103     immediate = immediate || !oldContainer;
104     if (oldContainer) {
105         oldContainer.pushExit(replace, immediate);
106     }
107     container.pushEnter(replace, immediate);
108
109     // sync tool bar
110     var tools = container.page.tools || null;
111     if (toolBar) {
112         toolBar.setTools(tools, immediate ? "set" : replace ? "replace" : "push");
113     }
114
115     return container.page;
116 }
117
118 // Initializes a page and its container.
119 function initPage(page, properties) {
120     var container = containerComponent.createObject(root);
121
122     var pageComp;
123     if (page.createObject) {
124         // page defined as component
125         pageComp = page;
126     } else if (typeof page == "string") {
127         // page defined as string (a url)
128         pageComp = componentCache[page];
129         if (!pageComp) {
130             pageComp = componentCache[page] = Qt.createComponent(page);
131         }
132     }
133     if (pageComp) {
134         if (pageComp.status == Component.Error) {
135             throw new Error("Error while loading page: " + pageComp.errorString());
136         } else {
137             // instantiate page from component
138             page = pageComp.createObject(container, properties || {});
139         }
140     } else {
141         // copy properties to the page
142         for (var prop in properties) {
143             if (properties.hasOwnProperty(prop)) {
144                 page[prop] = properties[prop];
145             }
146         }
147     }
148
149     container.page = page;
150     container.owner = page.parent;
151
152     // the page has to be reparented if
153     if (page.parent != container) {
154         page.parent = container;
155     }
156
157     if (page.pageStack !== undefined) {
158         page.pageStack = root;
159     }
160
161     return container;
162 }
163
164 // Pops a page off the stack.
165 function pop(page, immediate) {
166     // make sure there are enough pages in the stack to pop
167     if (pageStack.length > 1) {
168         // pop the current container off the stack and get the next container
169         var oldContainer = pageStack.pop();
170         var container = pageStack[pageStack.length - 1];
171         if (page !== undefined) {
172             // an unwind target has been specified - pop until we find it
173             while (page != container.page && pageStack.length > 1) {
174                 container.cleanup();
175                 pageStack.pop();
176                 container = pageStack[pageStack.length - 1];
177             }
178         }
179
180         depth = pageStack.length;
181         currentPage = container.page;
182
183         // perform page transition
184         oldContainer.popExit(immediate);
185         container.popEnter(immediate);
186
187         // sync tool bar
188         var tools = container.page.tools || null;
189         if (toolBar) {
190             toolBar.setTools(tools, immediate ? "set" : "pop");
191         }
192
193         return oldContainer.page;
194     } else {
195         return null;
196     }
197 }
198
199 // Clears the page stack.
200 function clear() {
201     var container;
202     while (container = pageStack.pop()) {
203         container.cleanup();
204     }
205     depth = 0;
206     currentPage = null;
207 }
208
209 // Iterates through all pages in the stack (top to bottom) to find a page.
210 function find(func) {
211     for (var i = pageStack.length - 1; i >= 0; i--) {
212         var page = pageStack[i].page;
213         if (func(page)) {
214             return page;
215         }
216     }
217     return null;
218 }
219