f42b1efcc8a79fe3f1570dd62c60dee21604c13f
[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 <QAbstractButton>
24 #include <QButtonGroup>
25 #include <QDebug>
26 #include <QPropertyAnimation>
27 #include <QRegion>
28 #include <QSignalTransition>
29 #include <QStackedWidget>
30 #include <QStateMachine>
31
32 #include "listitemcontextbuttonbar.h"
33 #include "panelbar.h"
34 #include "panelbase.h"
35 #include "panelcontentstack.h"
36 #include "panelcontextbuttonbar.h"
37 #include "paneltabbar.h"
38
39 #include "tabbedpanel.h"
40
41 const int PANEL_CONTEXT_BUTTON_BAR_LEFT_X = 1;
42 const int PANEL_TAB_BAR_TOP_SPACING = 8;
43
44 TabbedPanel::TabbedPanel(QWidget *parent)
45     : QWidget(parent),
46       m_open(false),
47       m_closeRequestPending(false)
48 {
49     qDebug() << __PRETTY_FUNCTION__;
50
51     const int PANEL_LEFT_X = 0;
52     const int PANEL_TOP_Y = 0;
53
54     resize(PANEL_BAR_TABBED_WIDTH + PANEL_WIDTH, PANEL_HEIGHT);
55     move(PANEL_CLOSED_X, PANEL_TOP_PADDING);
56
57     // --- TABS ---
58     m_panelTabBar = new PanelTabBar(this);
59     m_panelTabBar->move(PANEL_LEFT_X, PANEL_TAB_BAR_TOP_SPACING);
60
61     connect(m_panelTabBar, SIGNAL(currentChanged(int)),
62             this, SLOT(setCurrentIndex(int)));
63
64     connect(m_panelTabBar, SIGNAL(sizeChangeRequested()),
65             this, SLOT(calculateMask()));
66
67     connect(m_panelTabBar, SIGNAL(tabCloseRequested(int)),
68              this, SLOT(closePanel()));
69
70     connect(this, SIGNAL(panelClosed()),
71             m_panelTabBar, SLOT(deselectTabs()));
72
73     // --- BAR ---
74     m_panelBar = new PanelBar(this);
75     m_panelBar->move(PANEL_TAB_BAR_WIDTH, PANEL_TOP_Y);
76
77     // --- GENERIC PANEL CONTEXT BUTTON BAR ---
78     m_panelContextButtonBar = new PanelContextButtonBar(this);
79     m_panelContextButtonBar->move(PANEL_CONTEXT_BUTTON_BAR_LEFT_X, PANEL_HEIGHT);
80
81     connect(m_panelContextButtonBar, SIGNAL(barHidden()),
82             this, SLOT(closePanel()));
83
84     connect(m_panelContextButtonBar, SIGNAL(positionChangeRequested()),
85             this, SLOT(repositionContextButtonBar()));
86
87     // --- LIST ITEM RELATED CONTEXT BUTTONS BAR ---
88     m_itemContextButtonBar = new ListItemContextButtonBar(this);
89
90     connect(this, SIGNAL(listItemSelectionChanged(bool)),
91             m_itemContextButtonBar, SLOT(onListItemSelectionChanged(bool)));
92
93     // --- PANEL CONTENT ---
94     m_panelContentStack = new PanelContentStack(this);
95     m_panelContentStack->move(PANEL_TAB_BAR_WIDTH + PANEL_BAR_WIDTH, PANEL_TOP_Y);
96     m_panelContentStack->stackUnder(m_itemContextButtonBar);
97
98     // --- PANEL ANIMATION ---
99     QStateMachine *panelStateMachine = new QStateMachine(this);
100
101     m_stateClosed = new QState(panelStateMachine);
102     m_stateOpened = new QState(panelStateMachine);
103
104     QPropertyAnimation *panelAnimation = new QPropertyAnimation(this, "pos", this);
105
106     panelStateMachine->setInitialState(m_stateClosed);
107
108     QSignalTransition *panelTransitionOpen = m_stateClosed->addTransition(this,
109                                                                           SIGNAL(toggleState()),
110                                                                           m_stateOpened);
111     panelTransitionOpen->addAnimation(panelAnimation);
112
113     QSignalTransition *panelTransitionClose = m_stateOpened->addTransition(this,
114                                                                            SIGNAL(toggleState()),
115                                                                            m_stateClosed);
116     panelTransitionClose->addAnimation(panelAnimation);
117
118     connect(panelAnimation, SIGNAL(finished()),
119             this, SLOT(stateChanged()));
120
121     QPoint closedPosition(PANEL_CLOSED_X, PANEL_TOP_PADDING);
122     m_stateClosed->assignProperty(this, "pos", closedPosition);
123
124     QPoint openedPosition(PANEL_OPENED_X, PANEL_TOP_PADDING);
125     m_stateOpened->assignProperty(this, "pos", openedPosition);
126
127     panelStateMachine->start();
128 }
129
130 int TabbedPanel::addTab(QWidget *widget, const QIcon& icon)
131 {
132     qDebug() << __PRETTY_FUNCTION__;
133
134     const int APPEND_INDEX = -1;
135
136     return insertTab(APPEND_INDEX, widget, icon);
137 }
138
139 void TabbedPanel::calculateMask()
140 {
141     qDebug() << __PRETTY_FUNCTION__;
142
143     QRect panelTabBarRect = m_panelTabBar->rect();
144     QRect panelContextButtonBarRect = m_panelContextButtonBar->rect();
145     int panelContextButtonBarY = height() - panelContextButtonBarRect.height();
146
147     if (!m_open)
148         panelContextButtonBarY = height();
149
150     QRegion panelTabBarRegion(0, PANEL_TAB_BAR_TOP_SPACING,
151                          panelTabBarRect.width(), panelTabBarRect.height());
152     QRegion panelContextButtonBarRegion(0, panelContextButtonBarY,
153                                       panelContextButtonBarRect.width(),
154                                       panelContextButtonBarRect.height());
155     QRegion panelContentRegion(panelTabBarRect.right() + 1, 0,
156                                PANEL_WIDTH + PANEL_BAR_WIDTH, height());
157     QRegion panelRegion = panelTabBarRegion + panelContentRegion + panelContextButtonBarRegion;
158
159     setMask(panelRegion);
160 }
161
162 void TabbedPanel::closePanel()
163 {
164     qDebug() << __PRETTY_FUNCTION__;
165
166     if (m_open) {
167         m_open = false;
168
169         if (m_panelContextButtonBar->isBarVisible()) {
170             m_closeRequestPending = true;
171             m_panelContextButtonBar->hideContextButtonBar();
172         } else {
173             emit toggleState();
174         }
175     } else if (m_closeRequestPending) {
176         m_closeRequestPending = false;
177         emit toggleState();
178     }
179 }
180
181 int TabbedPanel::insertTab(int index, QWidget *widget, const QIcon& icon)
182 {
183     qDebug() << __PRETTY_FUNCTION__;
184
185     index = m_panelContentStack->insertWidget(index, widget);
186     m_panelTabBar->insertTab(index, icon);
187
188     return index;
189 }
190
191 void TabbedPanel::openPanel(QWidget *widget)
192 {
193     qDebug() << __PRETTY_FUNCTION__;
194
195     if (widget) {
196         m_panelTabBar->selectTab(m_panelContentStack->indexOf(widget));
197     } else if (!m_open) {
198         if (!m_closeRequestPending) {
199             m_open = true;
200             emit toggleState();
201         }
202     }
203 }
204
205 void TabbedPanel::removeTab(int index)
206 {
207     qDebug() << __PRETTY_FUNCTION__;
208
209     if (QWidget *widget = m_panelContentStack->widget(index)) {
210         m_panelContentStack->removeWidget(widget);
211         m_panelTabBar->removeTab(index);
212     }
213 }
214
215 void TabbedPanel::repositionContextButtonBar()
216 {
217     qDebug() << __PRETTY_FUNCTION__;
218
219     m_panelContextButtonBar->move(PANEL_CONTEXT_BUTTON_BAR_LEFT_X, height());
220
221     calculateMask();
222 }
223
224 void TabbedPanel::resizePanel(const QSize &size)
225 {
226     qDebug() << __PRETTY_FUNCTION__;
227
228     resize(PANEL_BAR_TABBED_WIDTH + PANEL_WIDTH,
229            size.height() - PANEL_TOP_PADDING - PANEL_BOTTOM_PADDING);
230
231     if (!m_open)
232         move(size.width() - PANEL_TAB_BAR_WIDTH - PANEL_BAR_WIDTH, PANEL_TOP_PADDING);
233     else
234         move(size.width() - PANEL_TAB_BAR_WIDTH - PANEL_BAR_WIDTH - PANEL_WIDTH, PANEL_TOP_PADDING);
235
236     m_panelBar->resizeBar(size);
237
238     m_panelContextButtonBar->move(PANEL_CONTEXT_BUTTON_BAR_LEFT_X, size.height());
239
240     m_panelContentStack->resizeContentStack(size);
241
242     QPoint closedPosition(size.width() - PANEL_TAB_BAR_WIDTH - PANEL_BAR_WIDTH, PANEL_TOP_PADDING);
243     m_stateClosed->assignProperty(this, "pos", closedPosition);
244
245     QPoint openedPosition(size.width() - PANEL_TAB_BAR_WIDTH - PANEL_BAR_WIDTH - PANEL_WIDTH,
246                           PANEL_TOP_PADDING);
247     m_stateOpened->assignProperty(this, "pos", openedPosition);
248
249     calculateMask();
250 }
251
252 void TabbedPanel::setCurrentIndex(int index)
253 {
254     qDebug() << __PRETTY_FUNCTION__;
255
256     if ((index < m_panelContentStack->count()) && (index >= 0)) {
257         m_panelContentStack->setCurrentIndex(index);
258
259         if (!m_open)
260             openPanel();
261
262         m_panelContextButtonBar->setContextButtons(
263                 static_cast<PanelBase *>(m_panelContentStack->widget(index))->genericPanelButtons());
264
265         QWidget *itemContextButtons = static_cast<PanelBase *>(m_panelContentStack->widget(index))->itemButtons();
266         m_itemContextButtonBar->setContextButtons(itemContextButtons);
267
268         emit currentChanged(index);
269     }
270 }
271
272 void TabbedPanel::setTabsEnabled(const QList<int> &tabIndexes, bool enabled)
273 {
274     qDebug() << __PRETTY_FUNCTION__;
275
276     QButtonGroup *tabs = m_panelTabBar->tabs();
277
278     foreach (int tabIndex, tabIndexes) {
279         QAbstractButton *tabButton = tabs->button(tabIndex);
280
281         if (tabButton) {
282             if (tabButton->isChecked())
283                 closePanel();
284
285             tabButton->setEnabled(enabled);
286         }
287     }
288 }
289
290 void TabbedPanel::stateChanged()
291 {
292     qDebug() << __PRETTY_FUNCTION__;
293
294     calculateMask();
295
296     if (m_open) {
297         m_panelContextButtonBar->showContextButtonBar();
298         emit panelOpened();
299     } else {
300         emit panelClosed();
301     }
302 }