49dd1b6bdbadf9ba869d8ad443845e6c5dd083e9
[situare] / src / ui / tabbedpanel.cpp
1 /*
2     Situare - A location system for Facebook
3     Copyright (C) 2010  Ixonos Plc. Authors:
4
5         Kaj Wallin - kaj.wallin@ixonos.com
6         Pekka Nissinen - pekka.nissinen@ixonos.com
7
8     Situare is free software; you can redistribute it and/or
9     modify it under the terms of the GNU General Public License
10     version 2 as published by the Free Software Foundation.
11
12     Situare is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with Situare; if not, write to the Free Software
19     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
20     USA.
21 */
22
23 #include <QDebug>
24 #include <QPropertyAnimation>
25 #include <QSignalTransition>
26 #include <QStackedWidget>
27 #include <QStateMachine>
28
29 #include "panelbar.h"
30 #include "panelbase.h"
31 #include "panelcontentstack.h"
32 #include "panelcontextbuttonbar.h"
33 #include "paneltabbar.h"
34
35 #include "tabbedpanel.h"
36
37 const int PANEL_CONTEXT_BUTTON_BAR_LEFT_X = 1;
38
39 TabbedPanel::TabbedPanel(QWidget *parent)
40     : QWidget(parent),
41       m_open(false),
42       m_closeRequestPending(false)
43 {
44     qDebug() << __PRETTY_FUNCTION__;
45
46     const int PANEL_LEFT_X = 0;
47     const int PANEL_TOP_Y = 0;
48     const int PANEL_TAB_BAR_TOP_SPACING = 8;
49
50     resize(PANEL_BAR_TABBED_WIDTH + PANEL_WIDTH, PANEL_HEIGHT);
51     move(PANEL_CLOSED_X, PANEL_TOP_PADDING);
52
53     // --- TABS ---
54     m_panelTabBar = new PanelTabBar(this);
55     m_panelTabBar->move(PANEL_LEFT_X, PANEL_TAB_BAR_TOP_SPACING);
56
57     connect(m_panelTabBar, SIGNAL(currentChanged(int)),
58             this, SLOT(setCurrentIndex(int)));
59
60     connect(m_panelTabBar, SIGNAL(tabCloseRequested(int)),
61              this, SLOT(closePanel()));
62
63     connect(this, SIGNAL(panelClosed()),
64             m_panelTabBar, SLOT(deselectTabs()));
65
66     // --- BAR ---
67     m_panelBar = new PanelBar(this);
68     m_panelBar->move(PANEL_TAB_WIDTH, PANEL_TOP_Y);
69
70     // --- CONTEXT BUTTON BAR ---
71     m_panelContextButtonBar = new PanelContextButtonBar(this);
72     m_panelContextButtonBar->move(PANEL_CONTEXT_BUTTON_BAR_LEFT_X, PANEL_HEIGHT);
73
74     connect(m_panelContextButtonBar, SIGNAL(barHidden()),
75             this, SLOT(closePanel()));
76
77     connect(m_panelContextButtonBar, SIGNAL(positionChangeRequested()),
78             this, SLOT(repositionContextButtonBar()));
79
80     // --- PANEL CONTENT ---
81     m_panelContentStack = new PanelContentStack(this);
82     m_panelContentStack->move(PANEL_TAB_WIDTH + PANEL_BAR_WIDTH, PANEL_TOP_Y);
83
84     // --- PANEL ANIMATION ---
85     QStateMachine *panelStateMachine = new QStateMachine(this);
86
87     m_stateClosed = new QState(panelStateMachine);
88     m_stateOpened = new QState(panelStateMachine);
89
90     QPropertyAnimation *panelAnimation = new QPropertyAnimation(this, "pos", this);
91
92     panelStateMachine->setInitialState(m_stateClosed);
93
94     QSignalTransition *panelTransitionOpen = m_stateClosed->addTransition(this,
95                                                                           SIGNAL(toggleState()),
96                                                                           m_stateOpened);
97     panelTransitionOpen->addAnimation(panelAnimation);
98
99     QSignalTransition *panelTransitionClose = m_stateOpened->addTransition(this,
100                                                                            SIGNAL(toggleState()),
101                                                                            m_stateClosed);
102     panelTransitionClose->addAnimation(panelAnimation);
103
104     connect(panelAnimation, SIGNAL(finished()),
105             this, SLOT(stateChanged()));
106
107     QPoint closedPosition(PANEL_CLOSED_X, PANEL_TOP_PADDING);
108     m_stateClosed->assignProperty(this, "pos", closedPosition);
109
110     QPoint openedPosition(PANEL_OPENED_X, PANEL_TOP_PADDING);
111     m_stateOpened->assignProperty(this, "pos", openedPosition);
112
113     panelStateMachine->start();
114 }
115
116 int TabbedPanel::addTab(QWidget *widget, const QIcon& icon)
117 {
118     qDebug() << __PRETTY_FUNCTION__;
119
120     const int APPEND_INDEX = -1;
121
122     return insertTab(APPEND_INDEX, widget, icon);
123 }
124
125 void TabbedPanel::closePanel()
126 {
127     qDebug() << __PRETTY_FUNCTION__;
128
129     if (m_open) {
130         m_open = false;
131
132         if (m_panelContextButtonBar->isBarVisible()) {
133             m_closeRequestPending = true;
134             m_panelContextButtonBar->hideContextButtonBar();
135         } else {
136             emit toggleState();
137         }
138     } else if (m_closeRequestPending) {
139         m_closeRequestPending = false;
140         emit toggleState();
141     }
142 }
143
144 int TabbedPanel::insertTab(int index, QWidget *widget, const QIcon& icon)
145 {
146     qDebug() << __PRETTY_FUNCTION__;
147
148     index = m_panelContentStack->insertWidget(index, widget);
149     m_panelTabBar->insertTab(index, icon);
150
151     return index;
152 }
153
154 void TabbedPanel::openPanel(QWidget *widget)
155 {
156     qDebug() << __PRETTY_FUNCTION__;
157
158     if (widget) {
159         m_panelTabBar->selectTab(m_panelContentStack->indexOf(widget));
160     } else if (!m_open) {
161         if (!m_closeRequestPending) {
162             m_open = true;
163             emit toggleState();
164         }
165     }
166 }
167
168 void TabbedPanel::removeTab(int index)
169 {
170     qDebug() << __PRETTY_FUNCTION__;
171
172     if (QWidget *widget = m_panelContentStack->widget(index)) {
173         m_panelContentStack->removeWidget(widget);
174         m_panelTabBar->removeTab(index);
175     }
176 }
177
178 void TabbedPanel::repositionContextButtonBar()
179 {
180     qDebug() << __PRETTY_FUNCTION__;
181
182     m_panelContextButtonBar->move(PANEL_CONTEXT_BUTTON_BAR_LEFT_X, height());
183 }
184
185 void TabbedPanel::resizePanel(const QSize &size)
186 {
187     qDebug() << __PRETTY_FUNCTION__;
188
189     resize(PANEL_BAR_TABBED_WIDTH + PANEL_WIDTH,
190            size.height() - PANEL_TOP_PADDING - PANEL_BOTTOM_PADDING);
191
192     if (!m_open)
193         move(size.width() - PANEL_TAB_WIDTH - PANEL_BAR_WIDTH, PANEL_TOP_PADDING);
194     else
195         move(size.width() - PANEL_TAB_WIDTH - PANEL_BAR_WIDTH - PANEL_WIDTH, PANEL_TOP_PADDING);
196
197     m_panelBar->resizeBar(size);
198
199     m_panelContextButtonBar->move(PANEL_CONTEXT_BUTTON_BAR_LEFT_X, size.height());
200
201     m_panelContentStack->resizeContentStack(size);
202
203     QPoint closedPosition(size.width() - PANEL_TAB_WIDTH - PANEL_BAR_WIDTH, PANEL_TOP_PADDING);
204     m_stateClosed->assignProperty(this, "pos", closedPosition);
205
206     QPoint openedPosition(size.width() - PANEL_TAB_WIDTH - PANEL_BAR_WIDTH - PANEL_WIDTH,
207                           PANEL_TOP_PADDING);
208     m_stateOpened->assignProperty(this, "pos", openedPosition);
209 }
210
211 void TabbedPanel::setCurrentIndex(int index)
212 {
213     qDebug() << __PRETTY_FUNCTION__;
214
215     if ((index < m_panelContentStack->count()) && (index >= 0)) {
216         m_panelContentStack->setCurrentIndex(index);
217
218         if (!m_open)
219             openPanel();
220
221         m_panelContextButtonBar->setContextButtons(
222                 static_cast<PanelBase *>(m_panelContentStack->widget(index))->contextButtons());
223
224         emit currentChanged(index);
225     }
226 }
227
228 void TabbedPanel::stateChanged()
229 {
230     qDebug() << __PRETTY_FUNCTION__;
231
232     if (m_open) {
233         m_panelContextButtonBar->showContextButtonBar();
234         emit panelOpened();
235     } else {
236         emit panelClosed();
237     }
238 }