1 /***************************************************************************
2 *                                                                         *
3 *   This program is free software; you can redistribute it and/or modify  *
4 *   it under the terms of the GNU General Public License as published by  *
5 *   the Free Software Foundation; either version 3 of the License, or     *
6 *   (at your option) any later version.                                   *
7 *                                                                         *
8 ***************************************************************************/
9 
10 #include "TabFrame.h"
11 
12 #include "FlowLayout.h"
13 #include "TabButton.h"
14 #include "WulforUtil.h"
15 #include "ArenaWidgetManager.h"
16 #include "DebugHelper.h"
17 #include "GlobalTimer.h"
18 
19 #if QT_VERSION >= 0x050000
20 #include <QtWidgets>
21 #else
22 #include <QtGui>
23 #endif
24 
25 #include <QPushButton>
26 #include <QWheelEvent>
27 #include <functional>
28 
TabFrame(QWidget * parent)29 TabFrame::TabFrame(QWidget *parent) :
30     QFrame(parent)
31 {
32     DEBUG_BLOCK
33 
34     setAcceptDrops(true);
35 
36     fr_layout = new FlowLayout(this);
37     fr_layout->setContentsMargins(0, 0, 0, 0);
38 
39     setMinimumHeight(20);
40     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
41 
42     shortcuts << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_1), this))
43               << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_2), this))
44               << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_3), this))
45               << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_4), this))
46               << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_5), this))
47               << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_6), this))
48               << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_7), this))
49               << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_8), this))
50               << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_9), this))
51               << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_0), this));
52 
53     for (const auto &s : shortcuts){
54         s->setContext(Qt::ApplicationShortcut);
55 
56         connect(s, SIGNAL(activated()), this, SLOT(slotShorcuts()));
57     }
58 
59     connect(GlobalTimer::getInstance(), SIGNAL(second()), this, SLOT(redraw()));
60 }
61 
62 
~TabFrame()63 TabFrame::~TabFrame(){
64     DEBUG_BLOCK
65 
66     auto it = tbtn_map.begin();
67 
68     for  (; it != tbtn_map.end(); ++it){
69         TabButton *btn = const_cast<TabButton*>(it.key());
70 
71         btn->deleteLater();
72     }
73 }
74 
resizeEvent(QResizeEvent * e)75 void TabFrame::resizeEvent(QResizeEvent *e){
76     e->accept();
77 
78     QFrame::updateGeometry();
79 }
80 
eventFilter(QObject * obj,QEvent * e)81 bool TabFrame::eventFilter(QObject *obj, QEvent *e){
82     TabButton *btn = qobject_cast<TabButton*>(obj);
83     QWheelEvent *w_e = reinterpret_cast<QWheelEvent*>(e);
84 
85     if (btn && (e->type() == QEvent::Wheel) && w_e){
86         int numDegrees = (w_e->delta() < 0)? (-1*w_e->delta()/8) : (w_e->delta()/8);
87         int numSteps = numDegrees/15;
88         std::function<void()> f = [this]() { this->nextTab(); };
89 
90         if (w_e->delta() < 0)
91             f = [this]() { this->prevTab(); };
92 
93         for (int i = 0; i < numSteps; i++)
94             f();
95 
96         return true;
97     }
98 
99     return QFrame::eventFilter(obj, e);
100 }
101 
sizeHint() const102 QSize TabFrame::sizeHint() const {
103     QSize s(fr_layout->sizeHint().width() , fr_layout->heightForWidth(width()));
104     return s;
105 }
106 
minimumSizeHint() const107 QSize TabFrame::minimumSizeHint() const{
108     return sizeHint();
109 }
110 
removeWidget(ArenaWidget * awgt)111 void TabFrame::removeWidget(ArenaWidget *awgt){
112     DEBUG_BLOCK
113 
114     if (!awgt_map.contains(awgt))
115         return;
116 
117     TabButton *btn = const_cast<TabButton*>(awgt_map.value(awgt));
118 
119     fr_layout->removeWidget(btn);
120     tbtn_map.remove(btn);
121     awgt_map.remove(awgt);
122 
123     btn->deleteLater();
124 
125     historyPurge(awgt);
126     historyPop();
127 
128      if (awgt->toolButton())
129         awgt->toolButton()->setChecked(false);
130 }
131 
insertWidget(ArenaWidget * awgt)132 void TabFrame::insertWidget(ArenaWidget *awgt){
133     DEBUG_BLOCK
134 
135     if (awgt_map.contains(awgt) || (awgt && (awgt->state() & ArenaWidget::Hidden)) || !awgt)
136         return;
137 
138     TabButton *btn = new TabButton();
139     btn->setText(awgt->getArenaShortTitle().left(32));
140     btn->setToolTip(WulforUtil::getInstance()->compactToolTipText(awgt->getArenaTitle(), 60, "\n"));
141     btn->setWidgetIcon(awgt->getPixmap());
142     btn->setContextMenuPolicy(Qt::CustomContextMenu);
143     btn->installEventFilter(this);
144 
145     fr_layout->addWidget(btn);
146 
147     awgt_map.insert(awgt, btn);
148     tbtn_map.insert(btn, awgt);
149 
150     if (awgt->toolButton())
151         awgt->toolButton()->setChecked(true);
152 
153     connect(btn, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotContextMenu()));
154     connect(btn, SIGNAL(clicked()), this, SLOT(buttonClicked()));
155     connect(btn, SIGNAL(closeRequest()), this, SLOT(closeRequsted()));
156     connect(btn, SIGNAL(dropped(TabButton*)), this, SLOT(slotDropped(TabButton*)));
157 }
158 
hasWidget(ArenaWidget * awgt) const159 bool TabFrame::hasWidget(ArenaWidget *awgt) const{
160     DEBUG_BLOCK
161 
162     return awgt_map.contains(awgt);
163 }
164 
mapped(ArenaWidget * awgt)165 void TabFrame::mapped(ArenaWidget *awgt){
166     DEBUG_BLOCK
167 
168     if (!awgt_map.contains(awgt))
169         return;
170 
171     TabButton *btn = const_cast<TabButton*>(awgt_map.value(awgt));
172 
173     btn->setChecked(true);
174     btn->setFocus();
175 
176     historyPush(awgt);
177 }
178 
updated(ArenaWidget * awgt)179 void TabFrame::updated ( ArenaWidget* awgt ) {
180     DEBUG_BLOCK
181 
182     if (awgt->state() & ArenaWidget::Hidden){
183         removeWidget(awgt);
184     }
185     else if (!awgt_map.contains(awgt)){
186         insertWidget(awgt);
187     }
188 }
189 
redraw()190 void TabFrame::redraw() {
191     DEBUG_BLOCK
192 
193     auto it = tbtn_map.begin();
194 
195     for  (; it != tbtn_map.end(); ++it){
196         TabButton *btn = const_cast<TabButton*>(it.key());
197         ArenaWidget *awgt = const_cast<ArenaWidget*>(it.value());
198 
199         btn->setText(awgt->getArenaShortTitle().left(32));
200         btn->setToolTip(WulforUtil::getInstance()->compactToolTipText(awgt->getArenaTitle(), 60, "\n"));
201         btn->setWidgetIcon(awgt->getPixmap());
202 
203         if (awgt->state() & ArenaWidget::Hidden)
204             continue;
205         else
206             btn->resetGeometry();
207     }
208 }
209 
historyPush(ArenaWidget * awgt)210 void TabFrame::historyPush(ArenaWidget *awgt){
211     DEBUG_BLOCK
212 
213     historyPurge(awgt);
214 
215     history.push_back(awgt);
216 }
217 
historyPurge(ArenaWidget * awgt)218 void TabFrame::historyPurge(ArenaWidget *awgt){
219     DEBUG_BLOCK
220 
221     if (history.contains(awgt))
222         history.removeAt(history.indexOf(awgt));
223 }
224 
historyPop()225 void TabFrame::historyPop(){
226     DEBUG_BLOCK
227 
228     if (history.isEmpty() && fr_layout->count() > 0){
229         QLayoutItem *item = fr_layout->itemAt(0);
230 
231         if (!item)
232             return;
233 
234         TabButton *btn = qobject_cast<TabButton*>(item->widget());
235 
236         if (btn)
237             ArenaWidgetManager::getInstance()->activate(tbtn_map[btn]);
238 
239         return;
240     }
241     else if (history.isEmpty()){
242         ArenaWidgetManager::getInstance()->activate(NULL);
243 
244         return;
245     }
246 
247     ArenaWidget *awgt = history.takeLast();
248 
249     ArenaWidgetManager::getInstance()->activate(awgt);
250 }
251 
buttonClicked()252 void TabFrame::buttonClicked(){
253     DEBUG_BLOCK
254 
255     TabButton *btn = qobject_cast<TabButton*>(sender());
256 
257     if (!(btn && tbtn_map.contains(btn)))
258         return;
259 
260     btn->setFocus();
261 
262     ArenaWidgetManager::getInstance()->activate(tbtn_map[btn]);
263 }
264 
closeRequsted()265 void TabFrame::closeRequsted() {
266     DEBUG_BLOCK
267 
268     TabButton *btn = qobject_cast<TabButton*>(sender());
269 
270     if (!(btn && tbtn_map.contains(btn)))
271         return;
272 
273     ArenaWidget *awgt = const_cast<ArenaWidget*>(tbtn_map[btn]);
274     ArenaWidgetManager::getInstance()->rem(awgt);
275 }
276 
nextTab()277 void TabFrame::nextTab(){
278     DEBUG_BLOCK
279 
280     TabButton *next = NULL;
281 
282     for (int i = 0; i < fr_layout->count(); i++){
283         TabButton *t = qobject_cast<TabButton*>(fr_layout->itemAt(i)->widget());
284 
285         if (t && t->isChecked()){
286             if (i == (fr_layout->count()-1)){
287                 next = qobject_cast<TabButton*>(fr_layout->itemAt(0)->widget());
288                 break;
289             }
290 
291             next = qobject_cast<TabButton*>(fr_layout->itemAt(i+1)->widget());
292             break;
293         }
294     }
295 
296     if (!next)
297         return;
298 
299     ArenaWidgetManager::getInstance()->activate(tbtn_map[next]);
300 }
301 
prevTab()302 void TabFrame::prevTab(){
303     DEBUG_BLOCK
304 
305     TabButton *next = NULL;
306 
307     for (int i = 0; i < fr_layout->count(); i++){
308         TabButton *t = qobject_cast<TabButton*>(fr_layout->itemAt(i)->widget());
309 
310         if (t && t->isChecked()){
311             if (!i){
312                 next = qobject_cast<TabButton*>(fr_layout->itemAt(fr_layout->count()-1)->widget());
313                 break;
314             }
315 
316             next = qobject_cast<TabButton*>(fr_layout->itemAt(i-1)->widget());
317             break;
318         }
319     }
320 
321     if (!next)
322         return;
323 
324    ArenaWidgetManager::getInstance()->activate(tbtn_map[next]);
325 }
326 
slotShorcuts()327 void TabFrame::slotShorcuts(){
328     DEBUG_BLOCK
329 
330     QShortcut *sh = qobject_cast<QShortcut*>(sender());
331 
332     if (!sh)
333         return;
334 
335     int index = shortcuts.indexOf(sh);
336 
337     if (index >= 0 && fr_layout->count() >= (index + 1)){
338         TabButton *next = qobject_cast<TabButton*>(fr_layout->itemAt(index)->widget());
339 
340         if (!next)
341             return;
342 
343         ArenaWidgetManager::getInstance()->activate(tbtn_map[next]);
344     }
345 }
346 
slotContextMenu()347 void TabFrame::slotContextMenu() {
348     DEBUG_BLOCK
349 
350     TabButton *btn = qobject_cast<TabButton*>(sender());
351 
352     if (!(btn && tbtn_map.contains(btn)))
353         return;
354 
355     ArenaWidget *awgt = const_cast<ArenaWidget*>(tbtn_map[btn]);
356 
357     if (awgt) {
358         QMenu *widget_menu = awgt->getMenu();
359         if (widget_menu) {
360             widget_menu->exec(btn->mapToGlobal(btn->rect().bottomLeft()));
361         } else {
362             widget_menu = new QMenu(this);
363             widget_menu->addAction(WulforUtil::getInstance()->getPixmap(WulforUtil::eiEDITDELETE), tr("Close"));
364 
365             if (widget_menu->exec(QCursor::pos()))
366                 ArenaWidgetManager::getInstance()->rem(awgt);
367 
368             delete widget_menu;
369         }
370     }
371 }
372 
slotDropped(TabButton * dropped)373 void TabFrame::slotDropped(TabButton *dropped){
374     DEBUG_BLOCK
375 
376     TabButton *on = qobject_cast<TabButton*>(sender());
377 
378     if (!(on && dropped && on != dropped))
379         return;
380 
381     fr_layout->place(on, dropped);
382 }
383 
moveLeft()384 void TabFrame::moveLeft(){
385     DEBUG_BLOCK
386 
387     for (int i = 0; i < fr_layout->count(); i++){
388         QLayoutItem *item = const_cast<QLayoutItem*>(fr_layout->itemAt(i));
389         TabButton *t = qobject_cast<TabButton*>(item->widget());
390 
391         if (t && t->isChecked()){
392             fr_layout->moveLeft(item);
393 
394             break;
395         }
396     }
397 }
398 
moveRight()399 void TabFrame::moveRight(){
400     DEBUG_BLOCK
401 
402     for (int i = 0; i < fr_layout->count(); i++){
403         QLayoutItem *item = const_cast<QLayoutItem*>(fr_layout->itemAt(i));
404         TabButton *t = qobject_cast<TabButton*>(item->widget());
405 
406         if (t && t->isChecked()){
407             fr_layout->moveRight(item);
408 
409             break;
410         }
411     }
412 }
413 
toggled(ArenaWidget * awgt)414 void TabFrame::toggled ( ArenaWidget* awgt ) {
415     DEBUG_BLOCK
416 
417     if (!awgt)
418         return;
419 
420     if (!(awgt->state() & ArenaWidget::Singleton))
421         return;
422 
423     if (awgt->state() & ArenaWidget::Hidden)
424         ArenaWidgetManager::getInstance()->activate(awgt);
425     else
426         ArenaWidgetManager::getInstance()->rem(awgt);
427 }
428 
429