ATLAS Offline Software
Loading...
Searching...
No Matches
VP1TabManager.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
6// //
7// Implementation of class VP1TabManager //
8// //
9// Author: Thomas Kittelmann <Thomas.Kittelmann@cern.ch> //
10// //
11// Initial version: April 2007 //
12// //
14
18
20#include "VP1Base/VP1TabBar.h"
21#include "VP1Base/IVP1System.h"
24#include "VP1Base/VP1QtUtils.h"
27#include "VP1Base/VP1Msg.h"
28
29#include <QEvent>
30#include <QPoint>
31#include <QSet>
32#include <QFileInfo>
33#include <QMap>
34#include <QTimer>
35#include <QBuffer>
36#include <QByteArray>
37#include <QMessageBox>
38#include <QMenu>
39#include <QKeyEvent>
40#include <QMainWindow>
41#include <QApplication>
42#include <QInputDialog>
43
44#include <map>
45#include <set>
46#include <cassert>
47#include <iostream>//fixme
48
49
50
51//_______________________________________________________________________
53public:
54 //Constructor, tabwidget & channel manager:
61
65
66 //Convenience:
67 QMainWindow * channel2tab(IVP1ChannelWidget*cw);
68 QMainWindow * name2tab(const QString& tabname);//Returns 0 if not found
69
70 //The actual bookkeeping maps:
71 std::map<QString,QMainWindow *> name_2_tab;
72 std::map<IVP1ChannelWidget*,VP1DockWidget*> channelwidget_2_dockwidget;
73 std::map<QMainWindow*,std::set<IVP1ChannelWidget*> > tab_2_channelwidgets;
74
75 //For sanity checking input, and providing appropriate warnings.
76 //Fixme: Check also max number of chars.
77 bool checkTabnameNotEmpty(const QString& tabname) const;
78 bool checkTabnameExists(const QString& tabname) const;
79 bool checkTabnameNotExists(const QString& tabname) const;
80
81 bool checkChannelNameExists(const QString& channelbasename, const bool& isuniquename, const bool& checkfornonexistance = false) const;
82
84 QSet<IVP1ChannelWidget*> lastvisible;
85 QSet<IVP1ChannelWidget*> lastsoonvisible;
86
88 //Fullscreen of individual channels:
91 //Fullscreen of tabs:
94 QMainWindow* fullscreen_tab;
95 std::set<VP1DockWidget*> fullscreen_floatingdocks;
96
97 QMap<QString,QStringList> serializeTabAndChannelConfigInfo() const;
98 void serializeTabAndChannelConfigInfo(QMap<QString,QMultiMap<QString,ChanState> >& tab2channels,
99 QMap<QString,QByteArray>&tab2arrangements) const;
100
101 QMainWindow* previousTab();
102 QMainWindow* nextTab();
104
105 QStringList channelsInTab(QMainWindow* tab);
106 QStringList channelsInTab(const QString&);
107
109};
110
111//_______________________________________________________________________
113 : QObject(parent), m_d(new Imp(this,tw,cm)) {
114
115 m_d->dontEmitVisibilityChanges=false;
116 tw->setTabReorderingEnabled(true);
117 connect(tw->getVP1TabBar(),SIGNAL(contextMenu( int, const QPoint& )),
118 this,SLOT(raiseTabBarContextMenu(int,const QPoint &)));
119
120 connect(tw,SIGNAL(currentChanged(int)),this,SLOT(currentVisibleChanged()));
121}
122
123
124
125//_______________________________________________________________________
127 while (m_d->tabwidget->count()>0) {
128 removeTab( m_d->tabwidget->tabText(0) );
129 }
130 delete m_d;
131}
132
133
134//___________________________________________________________________________________
136 VP1Msg::messageVerbose("VP1TabManager::launchStereoEditorCurrentTab()");
138 if (channel ) {
139 channel->launchStereoEditor();
140 }
141}
142
143
144
146//void VP1TabManager::setAntiAliasingCurrentTab(bool aa)
147//{
148// VP1Msg::messageVerbose("VP1TabManager::setAntiAliasingCurrentTab()");
149//
150// if (dynamic_cast<IVP13DStandardChannelWidget*>(selectedChannelWidget()) ) {
151// IVP13DStandardChannelWidget* channel = dynamic_cast<IVP13DStandardChannelWidget*>(selectedChannelWidget());
152// channel->setAntiAliasing(aa);
153// }
154//}
155
156
157//___________________________________________________________________________________
158bool VP1TabManager::Imp::checkTabnameExists(const QString& tabname) const {
159 if (!checkTabnameNotEmpty(tabname))
160 return false;
161 if (name_2_tab.find(tabname)==name_2_tab.end()) {
162 QMessageBox::critical(0, "Error - Tab "+tabname+" does not exists",
163 "Tab <i>"+tabname+"</i> does not exists.",QMessageBox::Ok,QMessageBox::Ok);
164 return false;
165 }
166 return true;
167}
168
169//___________________________________________________________________________________
170bool VP1TabManager::Imp::checkTabnameNotExists(const QString& tabname) const {
171 if (!checkTabnameNotEmpty(tabname))
172 return false;
173 if (name_2_tab.find(tabname)!=name_2_tab.end()) {
174 QMessageBox::critical(0, "Error - Tab "+tabname+" already exists",
175 "Tab <i>"+tabname+"</i> already exists.",QMessageBox::Ok,QMessageBox::Ok);
176 return false;
177 }
178 return true;
179}
180
181//___________________________________________________________________________________
182bool VP1TabManager::Imp::checkTabnameNotEmpty(const QString& tabname) const {
183 if (tabname.isEmpty()) {
184 QMessageBox::critical(0, "Error - Empty tab name provided",
185 "Empty tab name provided.",QMessageBox::Ok,QMessageBox::Ok);
186 return false;
187 }
188 return true;
189}
190
191//___________________________________________________________________________________
192bool VP1TabManager::Imp::checkChannelNameExists(const QString& channelname, const bool& isuniquename, const bool& checkfornonexistance) const {
193 if (channelname.isEmpty()) {
194 QMessageBox::critical(0, "Error - Empty channel name provided",
195 "Empty channel name provided.",QMessageBox::Ok,QMessageBox::Ok);
196 return false;
197 }
198 if ( checkfornonexistance == ( isuniquename ? channelmanager->uniqueNameExists(channelname)
199 : channelmanager->baseNameExists(channelname) ) ) {
200 QString tmp = ( checkfornonexistance ? "already":"does not" );
201 QMessageBox::critical(0, "Error - Channel "+channelname+" "+tmp+" exists",
202 "Channel <i>"+channelname+"</i> "+tmp+" exists.",QMessageBox::Ok,QMessageBox::Ok);
203 return false;
204 }
205 return true;
206}
207
208//_______________________________________________________________________
209QStringList VP1TabManager::Imp::channelsInTab(QMainWindow* tab)
210{
211 assert(tab_2_channelwidgets.find(tab)!=tab_2_channelwidgets.end());
212 if (tab_2_channelwidgets.find(tab)==tab_2_channelwidgets.end())
213 return QStringList();
214 std::set<IVP1ChannelWidget*>::const_iterator it, itE = tab_2_channelwidgets[tab].end();
215
216 QStringList l;
217 for (it = tab_2_channelwidgets[tab].begin();it!=itE;++it) {
218 l << (*it)->unique_name();
219 }
220
221 return l;
222}
223
224//_______________________________________________________________________
225QStringList VP1TabManager::Imp::channelsInTab(const QString& tabname)
226{
227 //Get list of (unique) names of channels in this tab:
228 assert(name_2_tab.find(tabname)!=name_2_tab.end());
229 if (name_2_tab.find(tabname)==name_2_tab.end())
230 return QStringList();
231 return channelsInTab(name_2_tab[tabname]);
232}
233
234
235//_______________________________________________________________________
236void VP1TabManager::addNewTab(const QString& tabname,const int& index)
237{
238 if (!m_d->checkTabnameNotExists(tabname)) return;
239 bool save = m_d->dontEmitVisibilityChanges;
240 m_d->dontEmitVisibilityChanges=true;
241
242 QMainWindow * t = new QMainWindow();
243 t->setDockNestingEnabled(true);
244 if (index==-1)
245 m_d->tabwidget->addTab(t,tabname);
246 else
247 m_d->tabwidget->insertTab(index,t,tabname);
248 //NB: Do not call: t->setParent(m_d->tabwidget);
249 m_d->name_2_tab[tabname]=t;
250 m_d->tab_2_channelwidgets[t] = std::set<IVP1ChannelWidget*>();
252 m_d->dontEmitVisibilityChanges=save;
254}
255
256//___________________________________________________________________________________
258{
259 if (!(m_d->fullscreen_dockwidget||m_d->fullscreen_tab))
260 return;
261
262 bool save = m_d->dontEmitVisibilityChanges;
263 m_d->dontEmitVisibilityChanges=true;
264 qApp->removeEventFilter(this);
265 QWidget * focuswidget = qApp->focusWidget();
266
267 if (m_d->fullscreen_dockwidget) {
268 assert(m_d->fullscreen_dockwidget&&m_d->fullscreen_channelwidget);
269 m_d->fullscreen_dockwidget->ensureCWHasParent();
270 m_d->fullscreen_channelwidget->showNormal();//fixme? Do inside dockwidget?
271 m_d->fullscreen_dockwidget=0;
272 m_d->fullscreen_channelwidget=0;
273 } else {
274 assert(m_d->fullscreen_tab);
275 QWidget * dummywidget=m_d->tabwidget->widget(m_d->fullscreen_tabindex);
276 m_d->tabwidget->removeTab(m_d->fullscreen_tabindex);
277 m_d->tabwidget->insertTab(m_d->fullscreen_tabindex, m_d->fullscreen_tab, m_d->fullscreen_tabname );
278 delete dummywidget;
279 m_d->tabwidget->setCurrentIndex(m_d->fullscreen_tabindex);
280 //Make dockwidgets in the tab floatable again
281 assert(m_d->tab_2_channelwidgets.find(m_d->fullscreen_tab)!=m_d->tab_2_channelwidgets.end());
282 std::set<IVP1ChannelWidget*>::const_iterator it = m_d->tab_2_channelwidgets[m_d->fullscreen_tab].begin();
283 std::set<IVP1ChannelWidget*>::const_iterator itE = m_d->tab_2_channelwidgets[m_d->fullscreen_tab].end();
284 for (;it!=itE;++it) {
285 assert(m_d->channelwidget_2_dockwidget.find(*it)!=m_d->channelwidget_2_dockwidget.end());
286 VP1DockWidget * dock = m_d->channelwidget_2_dockwidget[*it];
287 dock->setFeatures(VP1DockWidget::DockWidgetMovable|VP1DockWidget::DockWidgetFloatable);
288 if (m_d->fullscreen_floatingdocks.find(dock)!=m_d->fullscreen_floatingdocks.end())
289 dock->setFloating(true);
290 }
291 m_d->fullscreen_tabname = "";
292 m_d->fullscreen_tabindex = -1;
293 m_d->fullscreen_tab = 0;
294 m_d->fullscreen_floatingdocks.clear();
295 }
296 if (focuswidget&&!focuswidget->hasFocus())
297 focuswidget->setFocus(Qt::OtherFocusReason);
298 m_d->dontEmitVisibilityChanges=save;
300}
301
302//___________________________________________________________________________________
303bool VP1TabManager::eventFilter ( QObject *, QEvent * event ) {
304
305 //When in fullscreen mode we monitor all events in the application
306 //to look for ESC (leave fullscreen) and to prevent any toplevel
307 //widgets from getting closed by e.g. the user pressing ALT+F4.
308
309 if (event->type()==QEvent::Close) {
310 event->ignore();
311 return true;
312 }
313
314 if (event->type()!=QEvent::KeyPress)
315 return false;
316
317 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
318 assert(keyEvent);
319 if (keyEvent->key()!=Qt::Key_Escape)
320 return false;
321
323
324 //Eat the event:
325 return true;
326}
327
328//___________________________________________________________________________________
330
331 VP1Msg::messageDebug("VP1TabManager::setSelectedDockWidget()");
332
333 if ( m_d->selecteddockwidget == dw )
334 return;
335
336 if (m_d->selecteddockwidget)
337 m_d->selecteddockwidget->setUnselected();
338
339 m_d->selecteddockwidget=dw;
340 if (dw)
341 dw->setSelected();
342
343 selectedChannelChanged( dw ? dw->channelWidget() : 0 );
344}
345
346//___________________________________________________________________________________
348{
349 if (!cw) {
351 return;
352 }
353 assert(m_d->channelwidget_2_dockwidget.find(cw)!=m_d->channelwidget_2_dockwidget.end());
354 setSelectedDockWidget(m_d->channelwidget_2_dockwidget[cw]);
355}
356
357//___________________________________________________________________________________
360
361 assert(m_d->channelwidget_2_dockwidget.find(cw)!=m_d->channelwidget_2_dockwidget.end());
362 VP1DockWidget* dock = m_d->channelwidget_2_dockwidget[cw];
363 bool save = m_d->dontEmitVisibilityChanges;
364 m_d->dontEmitVisibilityChanges=true;
365 m_d->fullscreen_dockwidget=dock;
366 m_d->fullscreen_channelwidget=cw;
367 cw->hide();
368 dock->ensureCWHasNoParent();
369 cw->showFullScreen();
370 qApp->installEventFilter(this);
371 m_d->dontEmitVisibilityChanges=save;
373
374
375}
376
377//___________________________________________________________________________________
379{
380 if(!m_d->selecteddockwidget)
381 return;
382 showChannelFullScreen(m_d->selecteddockwidget->channelWidget());
383}
384
385//___________________________________________________________________________________
387{
388 if(!m_d->selecteddockwidget)
389 return "";
390 else
391 return m_d->selecteddockwidget->channelWidget()->unique_name();
392}
393
394//___________________________________________________________________________________
395void VP1TabManager::showTabFullScreen(const QString& tabname)
396{
397 int index = 0;
398 for (; index < m_d->tabwidget->count(); ++index) {
399 if (m_d->tabwidget->tabText(index)==tabname)
400 break;
401 }
402 if (index >= m_d->tabwidget->count())
403 return;
405 //Test that we are not already fs:
406 assert(m_d->fullscreen_tabname.isEmpty());
407 assert(m_d->fullscreen_tabindex==-1);
408 assert(!m_d->fullscreen_tab);
409 assert(m_d->fullscreen_floatingdocks.empty());
410
411 bool save = m_d->dontEmitVisibilityChanges;
412 m_d->dontEmitVisibilityChanges=true;
413
414 //Set tab info:
415 m_d->fullscreen_tabindex = index;
416 m_d->fullscreen_tabname = m_d->tabwidget->tabText(m_d->fullscreen_tabindex);
417 assert(m_d->name_2_tab.find(m_d->fullscreen_tabname)!=m_d->name_2_tab.end());
418 m_d->fullscreen_tab = m_d->name_2_tab[m_d->fullscreen_tabname];
419 //Dock all dockwidgets in the tab that are currently floating, and make them unfloatable:
420 assert(m_d->tab_2_channelwidgets.find(m_d->fullscreen_tab)!=m_d->tab_2_channelwidgets.end());
421 std::set<IVP1ChannelWidget*>::const_iterator it = m_d->tab_2_channelwidgets[m_d->fullscreen_tab].begin();
422 std::set<IVP1ChannelWidget*>::const_iterator itE = m_d->tab_2_channelwidgets[m_d->fullscreen_tab].end();
423 for (;it!=itE;++it) {
424 assert(m_d->channelwidget_2_dockwidget.find(*it)!=m_d->channelwidget_2_dockwidget.end());
425 VP1DockWidget * dock = m_d->channelwidget_2_dockwidget[*it];
426 if (dock->isFloating()) {
427 m_d->fullscreen_floatingdocks.insert(dock);
428 dock->setFloating(false);
429 }
430 dock->setFeatures(VP1DockWidget::DockWidgetMovable);
431 }
432
433 //Remove tab, put a dummy in its place, and go fullscreen:
434 m_d->tabwidget->removeTab(m_d->fullscreen_tabindex);
435 m_d->fullscreen_tab->hide();
436 m_d->fullscreen_tab->setParent(0);
437 m_d->tabwidget->insertTab ( m_d->fullscreen_tabindex, new QWidget(), m_d->fullscreen_tabname );
438 m_d->fullscreen_tab->showFullScreen();
439 //Needs an extra update apparently, to get selection frame properly enlarged
440 it = m_d->tab_2_channelwidgets[m_d->fullscreen_tab].begin();
441 itE = m_d->tab_2_channelwidgets[m_d->fullscreen_tab].end();
442 for (;it!=itE;++it) {
443 assert(m_d->channelwidget_2_dockwidget.find(*it)!=m_d->channelwidget_2_dockwidget.end());
444 VP1DockWidget * dock = m_d->channelwidget_2_dockwidget[*it];
445 dock->update();
446 }
447
448 qApp->installEventFilter(this);
449 m_d->dontEmitVisibilityChanges=save;
451
452}
453
454//___________________________________________________________________________________
456{
457 if (m_d->tabwidget->count()==0)
458 return;
459 showTabFullScreen(m_d->tabwidget->tabText(m_d->tabwidget->currentIndex()));
460}
461
462
463
464//___________________________________________________________________________________
466 return m_d->selecteddockwidget ? m_d->selecteddockwidget->channelWidget() : 0;
467}
468
469//_______________________________________________________________________
470IVP1ChannelWidget * VP1TabManager::addChannelToTab(const QString& channelbasename,const QString& tabname) {
471
472 #if defined BUILDVP1LIGHT
473 bool checkDisallowMultipleChannels = VP1QtUtils::expertSettingIsOn("general","ExpertSettings/VP1_DISALLOW_MULTIPLE_CHANNELS");
474 #else
475 bool checkDisallowMultipleChannels = VP1QtUtils::environmentVariableIsOn("VP1_DISALLOW_MULTIPLE_CHANNELS");
476 #endif
477
478 if (m_d->channelwidget_2_dockwidget.size()&&checkDisallowMultipleChannels) {
479 QMessageBox::critical(0, "Error - Not allowed to open channel",
480 "The possibility to launch multiple channels has been disabled by the environment variable VP1_DISALLOW_MULTIPLE_CHANNELS."
481 " This was likely set since some badly written 3D drivers have been known to cause crashes when showing multiple 3D views."
482 "\n In order to launch a new channel you must thus first remove the already active channel."
483 "\n To disable this behaviour don't set VP1_DISALLOW_MULTIPLE_CHANNELS, or set it to \"0'.",QMessageBox::Ok,QMessageBox::Ok);
484 return 0;
485 }
486
487 if (!m_d->checkTabnameExists(tabname)) return 0;
488 if (!m_d->checkChannelNameExists(channelbasename, false)) return 0;
489
490 //Then we get the channel:
491 QString err;
492 IVP1ChannelWidget * cw = m_d->channelmanager->getChannel( channelbasename,err );
493 if (!err.isEmpty()) {
494 QMessageBox::critical(0, "Error - could not get channel: "+channelbasename,
495 "Could not get channel: "+channelbasename
496 +"\n\nReason: "+err,QMessageBox::Ok,QMessageBox::Ok);
497
498 return 0;
499 }
500 assert(cw);
501 bool save = m_d->dontEmitVisibilityChanges;
502 m_d->dontEmitVisibilityChanges=true;
503 cw->setUpdatesEnabled(false);
504
505 //Everything went well - go ahead and add the channel to the tab.
506 VP1DockWidget *dock = new VP1DockWidget(cw,this);
507 connect(dock,SIGNAL(topLevelChanged(bool)),this,SLOT(currentVisibleChanged()));
508 connect(dock,SIGNAL(wasSelected(VP1DockWidget*)),this,SLOT(setSelectedDockWidget(VP1DockWidget*)));
509
510 QMainWindow * tab = m_d->name_2_tab[tabname];
511 tab->addDockWidget(Qt::TopDockWidgetArea, dock);
512
513 assert(m_d->channelwidget_2_dockwidget.find(cw)==m_d->channelwidget_2_dockwidget.end());
514 m_d->channelwidget_2_dockwidget[cw]=dock;
515 assert(m_d->tab_2_channelwidgets.find(tab)!=m_d->tab_2_channelwidgets.end());
516 m_d->tab_2_channelwidgets[tab].insert(cw);
517 cw->setUpdatesEnabled(true);
518 m_d->dontEmitVisibilityChanges=save;
520 return cw;
521}
522
523//_______________________________________________________________________
524void VP1TabManager::renameTab( const QString& tabname, const QString& newtabname ) {
525 if (!m_d->checkTabnameExists(tabname)) return;
526 if (!m_d->checkTabnameNotExists(newtabname)) return;
527
528 QMainWindow * tab = m_d->name_2_tab[tabname];
529
530 m_d->name_2_tab.erase(m_d->name_2_tab.find(tabname));
531 m_d->name_2_tab[newtabname]=tab;
532 int tabindex = m_d->tabwidget->indexOf(tab);
533 assert(tabindex!=-1);
534 m_d->tabwidget->setTabText ( tabindex, newtabname );
536}
537
538//_______________________________________________________________________
540 QStringList l;
541 for (int i = 0; i < m_d->tabwidget->count(); ++i) {
542 l<<m_d->tabwidget->tabText(i);
543 }
544 return l;
545}
546
547
548//_______________________________________________________________________
549void VP1TabManager::removeTab( const QString& tabname ) {
550
551 if (!m_d->checkTabnameExists(tabname)) return;
552
553 bool save = m_d->dontEmitVisibilityChanges;
554 m_d->dontEmitVisibilityChanges=true;
555
556 assert(m_d->name_2_tab.find(tabname)!=m_d->name_2_tab.end());
557 QMainWindow * tab = m_d->name_2_tab[tabname];
558 assert(tab);
559 assert(m_d->tab_2_channelwidgets.find(tab)!=m_d->tab_2_channelwidgets.end());
560
561 //First, we turn off updates on all channel widgets in the tab (this
562 //prevents some crashes due to poorly written channels):
563 std::set<IVP1ChannelWidget*>::const_iterator it = m_d->tab_2_channelwidgets[tab].begin();
564 std::set<IVP1ChannelWidget*>::const_iterator itE = m_d->tab_2_channelwidgets[tab].end();
565 for (;it!=itE;++it) {
566 (*it)->setUpdatesEnabled(false);//Fixme: do this on detach/reattach also?
567 (*it)->hide();
568 }
569
570 while(m_d->tab_2_channelwidgets[tab].size()>0) {
571 IVP1ChannelWidget * channelwidget = *(m_d->tab_2_channelwidgets[tab].begin());
572 removeChannel(channelwidget->unique_name());
573 }
574
575 //Remove the tab from the tabwidget (this does not actually delete the tab)
576 m_d->name_2_tab.erase(m_d->name_2_tab.find(tabname));
577 int i = m_d->tabwidget->indexOf(tab);
578 assert(i!=-1);
579 m_d->tabwidget->removeTab(i);
580
581 delete tab;
582
584 m_d->dontEmitVisibilityChanges=save;
586}
587
588
589//_______________________________________________________________________
591{
592 VP1Msg::messageDebug("VP1TabManager::removeAllTabs()");
593 for(const QString& tab : tabList() ) {
594 removeTab(tab);
595 }
596}
597
598
599//___________________________________________________________________________________
600void VP1TabManager::removeChannel(const QString& channeluniquename) {
601
602 VP1Msg::messageDebug("VP1TabManager::removeChannel()");
603
604 if (!m_d->checkChannelNameExists(channeluniquename, true)) return;
605
606 IVP1ChannelWidget* cw = m_d->channelmanager->uniqueName2Channel(channeluniquename);
607 assert(cw);
608
609 //Unselect if selected:
610 if (m_d->selecteddockwidget&&cw==m_d->selecteddockwidget->channelWidget())
612
613 QString bn = cw->name();
614 cw->setUpdatesEnabled(false);
615
616 assert(m_d->channelwidget_2_dockwidget.find(cw)!=m_d->channelwidget_2_dockwidget.end());
617 VP1DockWidget * dw = m_d->channelwidget_2_dockwidget[cw];
618
619 //Update maps:
620 assert(m_d->channelwidget_2_dockwidget.find(cw)!=m_d->channelwidget_2_dockwidget.end());
621 m_d->channelwidget_2_dockwidget.erase(m_d->channelwidget_2_dockwidget.find(cw));
622
623 //And remove dock from tab.
624 QMainWindow * tab = m_d->channel2tab(cw);
625 assert(tab);
626
627// int itab = m_d->tabwidget->indexOf(tab);
628// assert(itab!=-1);
629// QString tabname = m_d->tabwidget->tabText(itab);
630 // m_d->tabwidget->removeTab(itab);
631 tab->setUpdatesEnabled(false);
632 tab->removeDockWidget(dw);
633
634
635 //Update map:
636 assert(m_d->tab_2_channelwidgets[tab].find(cw)!=m_d->tab_2_channelwidgets[tab].end());
637 m_d->tab_2_channelwidgets[tab].erase(m_d->tab_2_channelwidgets[tab].find(cw));
638
639 //delete channel
640 cw->hide();
642 [[maybe_unused]] //To avoid compile warning in opt mode.
643 bool ok=m_d->channelmanager->deleteChannel(cw->unique_name());
644 assert(ok);
645
646 //delete dock widget
647 delete dw;
648
649 tab->setUpdatesEnabled(true);
650 // m_d->tabwidget->insertTab(itab,tab,tabname);
651
652 if (m_d->selecteddockwidget==dw) {
653 m_d->selecteddockwidget=0;
655 }
656
658}
659
660//___________________________________________________________________________________
662 std::map<QMainWindow*,std::set<IVP1ChannelWidget*> >::iterator it = tab_2_channelwidgets.begin();
663 std::map<QMainWindow*,std::set<IVP1ChannelWidget*> >::iterator itE = tab_2_channelwidgets.end();
664 for (;it!=itE;++it) {
665 if (it->second.find(cw)!=it->second.end())
666 return it->first;
667 }
668 return 0;
669}
670
671
672//___________________________________________________________________________________
673QMainWindow * VP1TabManager::Imp::name2tab(const QString& tabname)
674{
675 if (name_2_tab.find(tabname)==name_2_tab.end())
676 return 0;
677 return name_2_tab[tabname];
678}
679
680//Fixme: check for empty input strings in all methods where applicable!
681
682//___________________________________________________________________________________
683void VP1TabManager::moveChannelToTab(const QString& channeluniquename,const QString& tabname) {
684
685 if (!m_d->checkTabnameExists(tabname)) return;
686 if (!m_d->checkChannelNameExists(channeluniquename, true)) return;
687
688 QMainWindow * tab_new = m_d->name_2_tab[tabname];
689 assert(tab_new);
690 IVP1ChannelWidget* cw = m_d->channelmanager->uniqueName2Channel(channeluniquename);
691 assert(cw);
692
693 assert(m_d->channelwidget_2_dockwidget.find(cw)!=m_d->channelwidget_2_dockwidget.end());
694
695 VP1DockWidget* dw = m_d->channelwidget_2_dockwidget[cw];
696 assert(dw);
697 QMainWindow * tab_old = m_d->channel2tab(cw);
698 assert(tab_old);
699
700 if (tab_old==tab_new)//Fixme: Make warning here instead, and ensure that the interface does not allow this.
701 return;
702
703 tab_old->removeDockWidget(dw);
704 dw->setParent(tab_new);
705 tab_new->addDockWidget(Qt::TopDockWidgetArea, dw);
706 dw->show();
707
708 //Update tab_2_channelwidgets:
709 assert(m_d->tab_2_channelwidgets.find(tab_old)!=m_d->tab_2_channelwidgets.end());
710 assert(m_d->tab_2_channelwidgets.find(tab_new)!=m_d->tab_2_channelwidgets.end());
711 assert(m_d->tab_2_channelwidgets[tab_old].find(cw)!=m_d->tab_2_channelwidgets[tab_old].end());
712 assert(m_d->tab_2_channelwidgets[tab_new].find(cw)==m_d->tab_2_channelwidgets[tab_new].end());//dies!
713 m_d->tab_2_channelwidgets[tab_old].erase(m_d->tab_2_channelwidgets[tab_old].find(cw));
714 m_d->tab_2_channelwidgets[tab_new].insert(cw);
715
716}
717
718//___________________________________________________________________________________
719void VP1TabManager::cloneChannelToTab(const QString& channeluniquename,const QString& tabname) {
720 if (!m_d->checkTabnameExists(tabname)) return;
721 if (!m_d->checkChannelNameExists(channeluniquename, true)) return;
722 IVP1ChannelWidget* cw = m_d->channelmanager->uniqueName2Channel(channeluniquename);
723 assert(cw);
724 IVP1ChannelWidget * newcw = addChannelToTab(cw->name(),tabname);
725 if (newcw) {
726 ChanState state;
727 serializeChannelState(cw,state);
728 unserializeChannelState(newcw,state);
729 }
730}
731
732//___________________________________________________________________________________
733void VP1TabManager::cloneTab(const QString& oldtabname,const QString& newtabname)
734{
735 if (!m_d->checkTabnameExists(oldtabname)) return;
736 if (!m_d->checkTabnameNotExists(newtabname)) return;
737
738 addNewTab(newtabname);
739
740 assert(m_d->name_2_tab.find(newtabname)!=m_d->name_2_tab.end());
741
742 QMainWindow * oldtab = m_d->name_2_tab[oldtabname];
743
744 assert(m_d->tab_2_channelwidgets.find(oldtab)!=m_d->tab_2_channelwidgets.end());
745 std::set<IVP1ChannelWidget*>::const_iterator it = m_d->tab_2_channelwidgets[oldtab].begin();
746 std::set<IVP1ChannelWidget*>::const_iterator itE = m_d->tab_2_channelwidgets[oldtab].end();
747
748 for (;it!=itE;++it) {
749 IVP1ChannelWidget * newcw = addChannelToTab((*it)->name(),newtabname);
750 if (newcw) {
751 ChanState state;
752 serializeChannelState(*it,state);
753 unserializeChannelState(newcw,state);
754 }
755 }
756
757 QMainWindow * newtab = m_d->name_2_tab[newtabname];
758 QByteArray state = oldtab->saveState();
759 if (!newtab->restoreState(state))
760 QMessageBox::warning(0, "Warning - Problems cloning channel arrangement",
761 "Problems cloning channel arrangement.",QMessageBox::Ok,QMessageBox::Ok);
762}
763
764
765
766//___________________________________________________________________________________
767void VP1TabManager::saveConfigurationToFile(const QString& filename,const bool& askonoverride) {
768 if (filename.isEmpty()) {
769 QMessageBox::critical(0, "Error - Empty file name provided",
770 "Empty file name provided.",QMessageBox::Ok,QMessageBox::Ok);
771 return;
772 }
773 //If file exists, ask to overwrite.
774 QFileInfo fi(filename);
775 if (fi.exists()) {
776 if (!fi.isWritable()) {
777 QMessageBox::critical(0, "Error - could not save to file "+filename,
778 "Could not save to file: <i>"+filename+"</i>"
779 +"<br/><br/>Reason: File exists already and is write protected",QMessageBox::Ok,QMessageBox::Ok);
780 return;
781 }
782 if (askonoverride) {
783 int ret = QMessageBox::question(0, "File already exists: "+filename,
784 "The file <i>"+filename+"</i> already exists.\n"
785 "Override this file?",
786 QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel);
787 if (ret==QMessageBox::Cancel)
788 return;
789 }
790 }
791
792 QFile file(filename);
793 if (!file.open(QIODevice::WriteOnly)) {
794 QMessageBox::critical(0, "Error - problems writing to file "+filename,
795 "Problems writing to file: <i>"+filename+"</i>",QMessageBox::Ok,QMessageBox::Ok);
796 return;
797 }
798
799 //Serialise :
800 QMap<QString,QMultiMap<QString,ChanState> > tab2channels;
801 QMap<QString,QByteArray> tab2arrangements;
802 m_d->serializeTabAndChannelConfigInfo(tab2channels, tab2arrangements);
803
804 //Put into bytearray:
805 QByteArray byteArray;
806 QBuffer buffer(&byteArray);
807 buffer.open(QIODevice::WriteOnly);
808 QDataStream out(&buffer);
809 out<<QString("This is an automatically generated config file for VP1. [cfg version 003]" );
810 out<<m_d->channelmanager->serializePluginInfo();
811 out<<tab2channels;
812 out<<tab2arrangements;
813 out<<tabList();//For tab *order*
814 out<<QString("This is the end of the automatically generated config file for VP1." );
815 buffer.close();
816
817 QDataStream outfile(&file);
818 outfile<<qCompress(byteArray).toBase64();
819
820
821}
822
823//___________________________________________________________________________________
824void VP1TabManager::loadConfigurationFromFile(const QString& filename,const QMap<QString,QString>& availableplugins) {
825 if (filename.isEmpty()) {
826 QMessageBox::critical(0, "Error - Empty file name provided",
827 "Empty file name provided.",QMessageBox::Ok,QMessageBox::Ok);
828 return;
829 }
830 QFileInfo fi(filename);
831 if (!fi.exists()) {
832 QMessageBox::critical(0, "Error - file does not exists: "+filename,
833 "File does not exists: <i>"+filename+"</i>",QMessageBox::Ok,QMessageBox::Ok);
834 return;
835 }
836 if (!fi.isReadable()) {
837 QMessageBox::critical(0, "Error - file is not readable: "+filename,
838 "File is not readable: <i>"+filename+"</i>",QMessageBox::Ok,QMessageBox::Ok);
839 return;
840 }
841 //open file
842 QFile file(filename);
843 if (!file.open(QIODevice::ReadOnly)) {
844 QMessageBox::critical(0, "Error - problems opening file "+filename,
845 "Problems opening file: <i>"+filename+"</i>",QMessageBox::Ok,QMessageBox::Ok);
846 return;
847 }
848
849 //Read:
850 QString head,foot;
851 QStringList pluginfiles;
852 QMap<QString,QMultiMap<QString,ChanState> > tab2channels;
853 QMap<QString,QByteArray> tab2arrangements;
854 QStringList tabs_orded;
855
856 QByteArray byteArray64;
857 QDataStream infile(&file);
858 infile >> byteArray64;
859
860 QByteArray byteArray = qUncompress(QByteArray::fromBase64(byteArray64));
861
862 QBuffer buffer(&byteArray);
863 buffer.open(QIODevice::ReadOnly);
864 QDataStream in(&buffer);
865 in >> head;
866 in >> pluginfiles;
867 in >> tab2channels;
868 in >> tab2arrangements;
869 in >> tabs_orded;
870 in >> foot;
871 buffer.close();
872
873 if (head!="This is an automatically generated config file for VP1. [cfg version 003]"
874 ||foot!="This is the end of the automatically generated config file for VP1."
875 ||tab2channels.count()!=tab2arrangements.count()) {
876 QMessageBox::critical(0, "Error - file not in correct format: "+filename,
877 "File not in correct format: <i>"+filename+"</i>",QMessageBox::Ok,QMessageBox::Ok);
878 return;
879 }
880
881 QStringList pf_withproblem;
882 QStringList errormessage;
883
884#ifdef __APPLE__
885 QString sharedlibsuffix_correct = ".dylib";
886 QString sharedlibsuffix_wrong = ".so";
887#else
888 QString sharedlibsuffix_correct = ".so";
889 QString sharedlibsuffix_wrong = ".dylib";
890#endif
891
892 for(QString pf : pluginfiles) {
893 if (pf.endsWith(sharedlibsuffix_wrong)) {
894 pf.replace(sharedlibsuffix_wrong, sharedlibsuffix_correct);
895 }
896
897 if (!availableplugins.contains(pf)) {
898 pf_withproblem<<pf;
899 errormessage<<"Could not locate " + pf;
900 continue;
901 }
902 QString pfabsolute = availableplugins[pf];
903 QString err;
904 if (m_d->channelmanager->channelsInPluginFile(pfabsolute).empty())
905 err = m_d->channelmanager->loadPluginFile(pfabsolute);
906 if (!err.isEmpty()) {
907 pf_withproblem<<pfabsolute;
908 errormessage<<err;
909 }
910 }
911
912 if (!pf_withproblem.empty()) {
913 assert(pf_withproblem.count()==errormessage.count());
914 QString tmp;
915 for (int i = 0; i<pf_withproblem.count();++i) {
916 tmp += pf_withproblem.value(i)+": "+errormessage.value(i)+"\n";
917 }
918 QMessageBox::warning(0, "Warning - could not load all plugins",
919 "Some or more plugins did not load properly:\n\n"+tmp,QMessageBox::Ok,QMessageBox::Ok);
920 }
921
922 QString channelsFailureMsg;
923 QString tabArrangementFailureMsg;
924
925 QString lastaddedtab;
926
927 for (const QString& newtabname_infile : tabs_orded) {
928 //Check format:
929 if (!tab2channels.contains(newtabname_infile)||!tab2arrangements.contains(newtabname_infile)) {
930 QMessageBox::critical(0, "Error - file not in correct format: "+filename,
931 "File not in correct format: <i>"+filename+"</i>",QMessageBox::Ok,QMessageBox::Ok);
932 return;
933 }
934
935 //We are about to add a new tab. If there is already one with
936 //that name we remove it if it is empty:
937 QMainWindow * existingtab = m_d->name2tab(newtabname_infile);
938 if (existingtab) {
939 if (m_d->tab_2_channelwidgets.find(existingtab)==m_d->tab_2_channelwidgets.end()
940 ||m_d->tab_2_channelwidgets[existingtab].empty())
941 removeTab(newtabname_infile);
942 }
943
944 //Special case: If there are presently no loaded channels, and
945 //only one existing tab named 'My Tab', then we remove that one
946 if (m_d->channelwidget_2_dockwidget.empty()
947 &&m_d->name_2_tab.size()==1
948 &&m_d->name_2_tab.begin()->first=="My Tab")
949 removeTab("My Tab");
950
951 QString newtabname = suggestNewTabName(newtabname_infile);
952 addNewTab(newtabname);
953 if (!m_d->checkTabnameExists(newtabname))
954 return;
955 lastaddedtab=newtabname;
956
957 QMapIterator<QString,ChanState> it( tab2channels.value(newtabname_infile) );
958
959 while (it.hasNext()) {
960 it.next();
961 //it.key(): Channel base name.
962 //it.value(): Channel state info.
963 if (!m_d->channelmanager->baseNameExists(it.key())) {
964 channelsFailureMsg += it.key()+" (tab "+newtabname+")"+"\n";
965 } else {
966 IVP1ChannelWidget * cw = addChannelToTab( it.key(), newtabname );
967 if (cw)
968 unserializeChannelState(cw,it.value());
969 else
970 channelsFailureMsg += it.key()+" (tab "+newtabname+")"+"\n";
971 }
972 }
973
974 //Setup layout state:
975 assert(m_d->name_2_tab.find(newtabname)!=m_d->name_2_tab.end());
976 QMainWindow * tab = m_d->name_2_tab.find(newtabname)->second;
977 QByteArray state = tab2arrangements.value(newtabname_infile);
978
979 if (!state.isEmpty()) {
980 if (!tab->restoreState(state,0/*version*/)) {
981 tabArrangementFailureMsg += newtabname+"\n";
982 }
983 }
984 }
985 if (!channelsFailureMsg.isEmpty()) {
986 QMessageBox::warning(0, "Warning - could not start all channels",
987 "Some or more channels were not available to start:\n\n"
988 +channelsFailureMsg,QMessageBox::Ok,QMessageBox::Ok);
989 }
990 if (!tabArrangementFailureMsg.isEmpty()) {
991 QMessageBox::warning(0, "Warning - could not arrange channels in all tabs",
992 "The arrangement of channels could not be properly determined withing the following tabs:\n\n"
993 +tabArrangementFailureMsg,QMessageBox::Ok,QMessageBox::Ok);
994 }
995 if (!lastaddedtab.isEmpty())
996 showTab(lastaddedtab);
997}
998
999//___________________________________________________________________________________
1000void VP1TabManager::Imp::serializeTabAndChannelConfigInfo(QMap<QString,QMultiMap<QString,ChanState> >& tab2channels,
1001 QMap<QString,QByteArray>& tab2arrangements) const {
1002
1003 tab2channels.clear();
1004 tab2arrangements.clear();
1005 for (int i = 0; i< tabwidget->count();++i) {
1006 QString tabname = tabwidget->tabText(i);
1007 assert(name_2_tab.find(tabname)!=name_2_tab.end());
1008 QMainWindow * tab = name_2_tab.find(tabname)->second;
1009 QMultiMap<QString,ChanState> channelsinfo;
1010 std::map<QMainWindow*,std::set<IVP1ChannelWidget*> >::const_iterator itcws=tab_2_channelwidgets.find(tab);
1011 assert(itcws!=tab_2_channelwidgets.end());
1012 std::set<IVP1ChannelWidget*>::const_iterator it = itcws->second.begin();
1013 std::set<IVP1ChannelWidget*>::const_iterator itE = itcws->second.end();
1014 for (;it!=itE;++it) {
1015 ChanState chanstate;
1016 tabmanager->serializeChannelState(*it,chanstate);
1017 channelsinfo.insert((*it)->name(),chanstate);
1018 }
1019 tab2channels.insert(tabname,channelsinfo);
1020
1021
1022 tab2arrangements.insert(tabname,tab->saveState(0/*version*/));
1023 }
1024}
1025
1026//___________________________________________________________________________________
1027QString VP1TabManager::suggestNewTabName(const QString& oldtabname) const {
1028 QString newtabname=oldtabname;
1029 int i = 1;
1030 while (m_d->name_2_tab.find(newtabname)!=m_d->name_2_tab.end())
1031 newtabname=oldtabname+" "+QString::number(++i);
1032 return newtabname;
1033}
1034
1035//___________________________________________________________________________________
1037 if (m_d->tabwidget->count()==0)
1038 return "";
1039 return m_d->tabwidget->tabText(m_d->tabwidget->currentIndex());
1040}
1041
1042//___________________________________________________________________________________
1044 return m_d->tabwidget->count();
1045}
1046
1047//___________________________________________________________________________________
1049 if (tabwidget->count()<=1)
1050 return 0;
1051 std::cout<<"currentindex:"<<tabwidget->currentIndex()<<std::endl;
1052 std::cout<<"nextindex:"<<(tabwidget->currentIndex() + 1) % tabwidget->count()<<std::endl;
1053 std::cout<<"ntabs:"<<tab_2_channelwidgets.size()<<std::endl;
1054 QMainWindow*nexttab=static_cast<QMainWindow*>(tabwidget->widget((tabwidget->currentIndex() + 1) % tabwidget->count()));
1055 assert(nexttab);
1056 assert(tab_2_channelwidgets.find(nexttab)!=tab_2_channelwidgets.end());
1057// if (tab_2_channelwidgets.find(nexttab)==tab_2_channelwidgets.end())
1058// return fullscreen_tab;
1059// else
1060 return nexttab;
1061}
1062
1063//___________________________________________________________________________________
1065 if (tabwidget->count()<=1)
1066 return 0;
1067 int newindex = tabwidget->currentIndex() - 1;
1068 if (newindex<0)
1069 newindex += tabwidget->count();
1070 QMainWindow*prevtab = static_cast<QMainWindow*>(tabwidget->widget(newindex % tabwidget->count()));
1071 if (tab_2_channelwidgets.find(prevtab)==tab_2_channelwidgets.end())
1072 return fullscreen_tab;
1073 else
1074 return prevtab;
1075}
1076
1077//___________________________________________________________________________________
1078bool VP1TabManager::showTab(const QString& tabname){
1079 int itarget(-1);
1080 for (int i = 0; i < m_d->tabwidget->count(); ++i) {
1081 if (m_d->tabwidget->tabText(i)==tabname) {
1082 itarget = i;
1083 break;
1084 }
1085 }
1086 if (itarget<0)
1087 return false;
1088 if (itarget==m_d->tabwidget->currentIndex())
1089 return true;
1090
1091 bool save = m_d->dontEmitVisibilityChanges;
1092 m_d->dontEmitVisibilityChanges=true;
1093
1094 bool fullscreentab = (m_d->fullscreen_tab!=0);
1095 if (m_d->fullscreen_channelwidget||m_d->fullscreen_tab)
1097
1098 m_d->tabwidget->setCurrentIndex(itarget);
1099 if (fullscreentab)
1101 m_d->dontEmitVisibilityChanges=save;
1103 return true;
1104}
1105
1106
1107//___________________________________________________________________________________
1109 if (m_d->tabwidget->count()<=1)
1110 return;
1111 assert(!m_d->fullscreen_channelwidget);
1112 if (m_d->fullscreen_tab) {
1113 bool save = m_d->dontEmitVisibilityChanges;
1114 m_d->dontEmitVisibilityChanges=true;
1116 showNextTab();
1118 m_d->dontEmitVisibilityChanges=save;
1119 }
1120 m_d->tabwidget->setCurrentIndex((m_d->tabwidget->currentIndex() + 1) % m_d->tabwidget->count());
1121}
1122
1123//___________________________________________________________________________________
1125 assert(!m_d->fullscreen_channelwidget);
1126 assert(!m_d->fullscreen_tab);//Fixme: as above.
1127 if (m_d->tabwidget->count()<=1)
1128 return;
1129 int newindex = m_d->tabwidget->currentIndex() - 1;
1130 if (newindex<0)
1131 newindex += m_d->tabwidget->count();
1132 m_d->tabwidget->setCurrentIndex( newindex % m_d->tabwidget->count());
1133}
1134
1135//___________________________________________________________________________________
1136void VP1TabManager::raiseTabBarContextMenu(int i,const QPoint & p) {
1137
1138 QString tabname = m_d->tabwidget->tabText(i);
1139
1140 QMenu menu(m_d->tabwidget);
1141
1142 //Construct menu:
1143 // menu.addAction("Tab: "+tabname)->setEnabled(false);
1144 // menu.addSeparator ();
1145 QAction* pFullScreenAction = menu.addAction("Show &full Screen");
1146 menu.addSeparator();
1147 QAction* pRenameAction = menu.addAction("Re&name tab");
1148 QAction* pDeleteAction = menu.addAction("&Remove tab");
1149 menu.addSeparator ();
1150 QAction* pInsertNewAction = menu.addAction("&Insert new tab");
1151 QAction* pCloneAction = menu.addAction("&Clone tab");
1152 menu.addSeparator ();
1153 QAction* pAddChannelAction = menu.addAction("&Add channel");
1154 QAction* pRemoveChannelAction = menu.addAction("R&emove channel");
1155
1156 QMenu menu_addchan(m_d->tabwidget);
1157 QStringList chnls = m_d->channelmanager->availableChannelList();
1158 if (chnls.empty()) {
1159 menu_addchan.addAction("No channels available")->setEnabled(false);
1160 } else {
1161 for (const QString& chnl : chnls) {
1162 QString iconloc = m_d->channelmanager->getIconLocation(chnl, true);
1163 QAction* pChnlAct;
1164 if (iconloc.isEmpty())
1165 pChnlAct = menu_addchan.addAction(chnl);
1166 else
1167 pChnlAct = menu_addchan.addAction(QIcon(iconloc),chnl);
1168 pChnlAct->setData("ADDCHAN");
1169 }
1170 }
1171 pAddChannelAction->setMenu(&menu_addchan);
1172 QStringList chnls_rem = m_d->channelsInTab(tabname);
1173 if (chnls_rem.empty())
1174 pFullScreenAction->setEnabled(false);
1175 QMenu menu_remchan(m_d->tabwidget);
1176 if (chnls_rem.empty()) {
1177 menu_remchan.addAction("No channels in tab")->setEnabled(false);
1178 } else {
1179 for (const QString& chnl : chnls_rem) {
1180 QString iconloc = m_d->channelmanager->getIconLocation(chnl, false);
1181 QAction* pChnlAct;
1182 if (iconloc.isEmpty())
1183 pChnlAct = menu_remchan.addAction(chnl);
1184 else
1185 pChnlAct = menu_remchan.addAction(QIcon(iconloc),chnl);
1186 pChnlAct->setData("REMCHAN");
1187 }
1188 }
1189 pRemoveChannelAction->setMenu(&menu_remchan);
1190
1191
1192 //Execute
1193 QAction * selAct = menu.exec(p);
1194 //
1195 if (!selAct)
1196 return;
1197 if (selAct==pFullScreenAction) {
1198 showTabFullScreen(tabname);
1199 return;
1200 }
1201 if (selAct==pRenameAction) {
1202 bool ok;
1203 QString text = QInputDialog::getText( 0, "Rename tab '"+tabname+"'","Rename tab '"+tabname+"' to:",
1204 QLineEdit::Normal, tabname, &ok );
1205 if (!ok||text==tabname)
1206 return;
1207 renameTab(tabname,text);
1208 return;
1209 }
1210 if (selAct==pDeleteAction) {
1211 removeTab( tabname );
1212 return;
1213 }
1214 if (selAct==pInsertNewAction) {
1215 bool ok;
1216 QString newtabname = QInputDialog::getText( 0, "New Tab Name","New tab name:",
1217 QLineEdit::Normal, suggestNewTabName("My Tab"), &ok );
1218 if (!ok||newtabname.isEmpty())
1219 return;
1220 addNewTab(newtabname,i+1);
1221 return;
1222 }
1223 if (selAct==pCloneAction) {
1224 bool ok;
1225 QString newtabname = QInputDialog::getText( 0, "Cloning '"+tabname+"'.","Cloning '"+tabname+"'. Name of new tab:",
1226 QLineEdit::Normal, suggestNewTabName(tabname), &ok );
1227 if (!ok||newtabname.isEmpty())
1228 return;
1229 cloneTab(tabname,newtabname);
1230 return;
1231 }
1232 if (selAct==pAddChannelAction) {
1233 return;
1234 }
1235 //Only option left is channels...
1236 if (selAct->data()=="ADDCHAN") {
1237 addChannelToTab( selAct->text(), tabname );
1238 return;
1239 }
1240 if (selAct->data()=="REMCHAN") {
1241 removeChannel( selAct->text() );
1242 return;
1243 }
1244 std::cout<<"ERROR in VP1TabManager::raiseTabBarContextMenu!!!!!"<<std::endl;
1245}
1246
1247//___________________________________________________________________________________
1249 if (m_d->dontEmitVisibilityChanges)
1250 return;
1251
1252 QSet<IVP1ChannelWidget*> visible;
1253 QSet<IVP1ChannelWidget*> soonvisible;
1254 double soonbonus(0.0);
1255
1259
1260 if (m_d->fullscreen_dockwidget) {
1261 //Thats an easy one:
1262 visible << m_d->fullscreen_dockwidget->channelWidget();
1263 } else if (m_d->fullscreen_tab) {
1264 //Add all channel widgets from this tab:
1265 assert(m_d->tab_2_channelwidgets.find(m_d->fullscreen_tab)!=m_d->tab_2_channelwidgets.end());
1266 std::set<IVP1ChannelWidget*>::iterator it,itE;
1267 itE = m_d->tab_2_channelwidgets[m_d->fullscreen_tab].end();
1268 for (it = m_d->tab_2_channelwidgets[m_d->fullscreen_tab].begin();it!=itE;++it) {
1269 visible << *it;
1270 }
1271 std::cout<<"fullscreen tab:"<<m_d->fullscreen_tab<<std::endl;
1272 } else {
1273 //Go through the tabs, if it is the current tab we add all dock
1274 //widgets, otherwise we add those that are floating:
1275 QWidget * currentTab = m_d->tabwidget->currentWidget();
1276 std::map<QMainWindow*,std::set<IVP1ChannelWidget*> >::iterator tabIt,tabItE = m_d->tab_2_channelwidgets.end();
1277 std::set<IVP1ChannelWidget*>::iterator it,itE;
1278 for (tabIt=m_d->tab_2_channelwidgets.begin();tabIt!=tabItE;++tabIt) {
1279 //Loop over channels;
1280 it = tabIt->second.begin();
1281 itE = tabIt->second.end();
1282 for (;it!=itE;++it) {
1283 if (currentTab==tabIt->first) {
1284 //Add all:
1285 visible << *it;
1286 } else {
1287 if (!m_d->fullscreen_tab) {
1288 //Add only if floating and not a fullscreen tab:
1289 assert(m_d->channelwidget_2_dockwidget.find(*it)!=m_d->channelwidget_2_dockwidget.end());
1290 if (m_d->channelwidget_2_dockwidget[*it]->isFloating())
1291 visible << *it;
1292 }
1293 }
1294 }
1295 }
1296 }
1297
1301
1302 if (m_d->fullscreen_dockwidget) {
1303 assert(!m_d->tabcruisemode);
1304 //Soon visible: All floating channels (not this one) and all channels in the present tab.
1305 soonbonus = 2000;//We are afterall quite sure here what will soon be visible.
1306 QWidget * currentTab = m_d->tabwidget->currentWidget();
1307 std::map<QMainWindow*,std::set<IVP1ChannelWidget*> >::iterator tabIt, tabItE = m_d->tab_2_channelwidgets.end();
1308 std::set<IVP1ChannelWidget*>::iterator it,itE;
1309 for (tabIt=m_d->tab_2_channelwidgets.begin();tabIt!=tabItE;++tabIt) {
1310 //Loop over channels;
1311 itE = tabIt->second.end();
1312 for (it=tabIt->second.begin();it!=itE;++it) {
1313 if (currentTab==tabIt->first) {
1314 //Add all except the fullscreen'ed one:
1315 if (*it!=m_d->fullscreen_dockwidget->channelWidget())
1316 soonvisible << *it;
1317 } else {
1318 //Add only if floating:
1319 assert(m_d->channelwidget_2_dockwidget.find(*it)!=m_d->channelwidget_2_dockwidget.end());
1320 if (m_d->channelwidget_2_dockwidget[*it]->isFloating())
1321 soonvisible << *it;
1322 }
1323 }
1324 }
1325 } else if (m_d->fullscreen_tab) {
1326 if (m_d->tabcruisemode&&m_d->tab_2_channelwidgets.size()>1) {
1327 //Everything in the next tab.
1328 soonbonus = 10000;//Very important that the stuff in the next tab gets a high priority!
1329 QMainWindow * nexttab = m_d->nextTab();
1330 assert(nexttab);
1331 std::cout<<"fullscreen tab:"<<m_d->fullscreen_tab<<std::endl;
1332 std::cout<<"nexttab:"<<nexttab<<std::endl;
1333 assert(m_d->tab_2_channelwidgets.find(nexttab)!=m_d->tab_2_channelwidgets.end());
1334 std::set<IVP1ChannelWidget*>::iterator it,itE=m_d->tab_2_channelwidgets[nexttab].end();
1335 for(it=m_d->tab_2_channelwidgets[nexttab].begin();it!=itE;++it){
1336 soonvisible << *it;
1337 }
1338 } else {
1339 //All floating channels not in the present tab
1340 soonbonus = 1000;//We are rather sure here what will soon be visible.
1341 QWidget * currentTab = m_d->tabwidget->currentWidget();
1342 std::map<QMainWindow*,std::set<IVP1ChannelWidget*> >::iterator tabIt, tabItE = m_d->tab_2_channelwidgets.end();
1343 std::set<IVP1ChannelWidget*>::iterator it,itE;
1344 for (tabIt=m_d->tab_2_channelwidgets.begin();tabIt!=tabItE;++tabIt) {
1345 //Loop over channels;
1346 itE = tabIt->second.end();
1347 for (it=tabIt->second.begin();it!=itE;++it) {
1348 if (m_d->fullscreen_tab!=tabIt->first&&currentTab!=tabIt->first) {
1349 //Add only if floating:
1350 assert(m_d->channelwidget_2_dockwidget.find(*it)!=m_d->channelwidget_2_dockwidget.end());
1351 if (m_d->channelwidget_2_dockwidget[*it]->isFloating())
1352 soonvisible << *it;
1353 }
1354 }
1355 }
1356 }
1357 } else {
1358 //Add everything non-floating from the next tab.
1359 soonbonus = 200;//A weak guess (fixme: Stronger if tab cruise mode).
1360 if (m_d->tabwidget->count()>=2) {
1361 int nexttabindex = (m_d->tabwidget->currentIndex() + 1) % m_d->tabwidget->count();
1362 QMainWindow* tab = static_cast<QMainWindow*>(m_d->tabwidget->widget(nexttabindex));
1363 assert(tab);
1364 assert(m_d->tab_2_channelwidgets.find(tab)!=m_d->tab_2_channelwidgets.end());
1365 std::set<IVP1ChannelWidget*>::iterator it,itE=m_d->tab_2_channelwidgets[tab].end();
1366 for (it=m_d->tab_2_channelwidgets[tab].begin();it!=itE;++it) {
1367 assert(m_d->channelwidget_2_dockwidget.find(*it)!=m_d->channelwidget_2_dockwidget.end());
1368 if (!m_d->channelwidget_2_dockwidget[*it]->isFloating())
1369 soonvisible << *it;
1370 }
1371 }
1372 }
1373
1374
1375 assert(soonbonus>0.0);
1376
1377#ifndef NDEBUG
1378 //There should be no intersection between visible and soon visible!
1379 QSet<IVP1ChannelWidget*> tmp = visible;
1380 tmp.intersect(soonvisible);
1381 assert(tmp.empty());
1382#endif
1383
1384 if (visible!=m_d->lastvisible||soonvisible!=m_d->lastsoonvisible) {
1385 m_d->lastvisible=visible;
1386 m_d->lastsoonvisible=soonvisible;
1387 visibleChannelsChanged(visible,soonvisible,soonbonus);
1388
1389 //To ensure that we dont show controllers for channels that are
1390 //not visible:
1391 if (m_d->selecteddockwidget) {
1392 if (!visible.contains(m_d->selecteddockwidget->channelWidget()))
1394 }
1395
1396 //To make sure we automatically select a channel if it is the only
1397 //one visible:
1398 if (visible.count()==1&&(!m_d->selecteddockwidget||*(visible.begin())!=m_d->selecteddockwidget->channelWidget())) {
1399 assert(m_d->channelwidget_2_dockwidget.find(*(visible.begin()))!=m_d->channelwidget_2_dockwidget.end());
1400 setSelectedDockWidget(m_d->channelwidget_2_dockwidget[*(visible.begin())]);
1401 }
1402 }
1403}
1404
1405//___________________________________________________________________________________
1407{
1408 QMainWindow * tab = m_d->channel2tab(cw);
1409 if (!tab)
1410 return "VP1TabManager::channelToTab ERROR: Unknown CW";
1411
1412 std::map<QString,QMainWindow *>::const_iterator it, itE = m_d->name_2_tab.end();
1413 for ( it = m_d->name_2_tab.begin(); it!=itE; ++it ) {
1414 if (it->second == tab)
1415 return it->first;
1416 }
1417 return "";
1418}
1419
1420//___________________________________________________________________________________
1421bool VP1TabManager::hasTab(const QString& tabname) const
1422{
1423 return m_d->name_2_tab.find(tabname)!=m_d->name_2_tab.end();
1424}
1425
1426//___________________________________________________________________________________
1428
1429 std::set<IVP1ChannelWidget*>::const_iterator it2,it2E;
1430
1431 std::map<QMainWindow*,std::set<IVP1ChannelWidget*> >::const_iterator
1432 it = m_d->tab_2_channelwidgets.begin(), itE=m_d->tab_2_channelwidgets.end();
1433 for (;it!=itE;++it) {
1434 it2=it->second.begin();
1435 it2E=it->second.end();
1436 for (;it2!=it2E;++it2) {
1437 if ((*it2)->name()==basename) {
1438 //Figure out the tabname:
1439 std::map<QString,QMainWindow *>::const_iterator it3,it3E;
1440 it3=m_d->name_2_tab.begin();it3E=m_d->name_2_tab.end();
1441 for (;it3!=it3E;++it3) {
1442 if (it3->second==it->first)
1443 return showTab(it3->first);
1444 }
1445 //Something is wrong.
1446 return false;
1447 }
1448 }
1449 }
1450 return false;
1451}
1452
1453
1454//___________________________________________________________________________________
1455QList<IVP1ChannelWidget*> VP1TabManager::allChannels() const
1456{
1457 QList<IVP1ChannelWidget*> l;
1458 std::map<IVP1ChannelWidget*,VP1DockWidget*>::iterator it, itE(m_d->channelwidget_2_dockwidget.end());
1459 for(it=m_d->channelwidget_2_dockwidget.begin();it!=itE;++it) {
1460 l <<it->first;
1461 }
1462 return l;
1463}
1464
1465
1466//___________________________________________________________________________________
1467const QSet<IVP1ChannelWidget*>& VP1TabManager::visibleChannels() const
1468{
1469 return m_d->lastvisible;
1470}
1471//___________________________________________________________________________________
1472const QSet<IVP1ChannelWidget*>& VP1TabManager::soonVisibleChannels() const
1473{
1474 return m_d->lastsoonvisible;
1475}
1476
1477
1478//___________________________________________________________________________________
1480{
1481 return m_d->lastvisible.contains(cw);
1482}
1483
1484//___________________________________________________________________________________
1486 if (m_d->tabcruisemode==b)
1487 return;
1488 bool save = m_d->dontEmitVisibilityChanges;
1489 m_d->dontEmitVisibilityChanges = true;
1490 m_d->tabcruisemode = b;
1491// if (m_d->tabcruisemode) {
1492// assert(!fullscreen_dockwidget);//We cant be in FS single-channel mode.
1493// if (fullscreen_tab) {
1494// //Dock all floating (in other tabs) immediately (fixme: only when they need to be shown!.
1495// } else {
1496// //normal mode
1497// }
1498// } else {
1499// }
1500 //Soonvisible might have changed - so emit changes:
1501 m_d->dontEmitVisibilityChanges=save;
1503}
1504
1505
1506
1507
1508//___________________________________________________________________________________
1510{
1511 m_d->channelWithPendingRemoval = chnlun;
1512 QTimer::singleShot(0, this, SLOT(executePendingChannelRemoval()));
1513}
1514
1515//___________________________________________________________________________________
1517{
1518 if (m_d->channelWithPendingRemoval.isEmpty())
1519 return;
1520 removeChannel(m_d->channelWithPendingRemoval);
1521 m_d->channelWithPendingRemoval="";
1522}
1523
1524//___________________________________________________________________________________
1526{
1527 QMultiMap<QString,QByteArray> sysstate;
1528 std::set<IVP1System*>::const_iterator it, itE = cw->systems().end();
1529 for (it=cw->systems().begin();it!=itE;++it) {
1530 unsigned nVP1Serialise = VP1Serialise::numberOfInstantiations();
1531 sysstate.insert((*it)->name(),(*it)->saveState());
1532 if (nVP1Serialise==VP1Serialise::numberOfInstantiations())
1533 VP1Msg::messageDebug("VP1TabManager WARNING: System "+(*it)->name()
1534 +" did not use VP1Serialise in implementation of saveState()");
1535 }
1536
1537 state.first = cw->saveState();
1538 state.second = sysstate;
1539}
1540
1541//___________________________________________________________________________________
1543{
1544 if(!state.first.isEmpty())
1545 cw->restoreFromState(state.first);
1546
1547 QList<QString> storedSystems = state.second.keys();
1548
1549 std::set<IVP1System*>::const_iterator itsys, itsysE = cw->systems().end();
1550 for (itsys=cw->systems().begin();itsys!=itsysE;++itsys) {
1551 QString name = (*itsys)->name();
1552 //Look for the first entry with this system name in the list. If it is there - use it and remove it:
1553 QMultiMap<QString,QByteArray>::iterator it_state = state.second.find(name);
1554 if (it_state != state.second.end()) {
1555 storedSystems.removeAll(name);
1556// //Lets make sure that we advance it_state to the LAST of the elements with the same key:
1557// QMultiMap<QString,QByteArray>::iterator it_state_tmp = it_state;
1558// while ( it_state_tmp != state.second.end() && it_state_tmp.key() == (*itsys)->name() ) {
1559// it_state=it_state_tmp;
1560// ++it_state_tmp;
1561// }
1562 //Fixme ^^^: The above has not been tested on any channel which
1563 //actually has multiple similar systems. So might be buggy.
1564
1565 //Use it and remove it from array:
1566 if (!it_state.value().isEmpty()) {
1567 unsigned nVP1Deserialise = VP1Deserialise::numberOfInstantiations();
1568 (*itsys)->restoreFromState(it_state.value());
1569 if (nVP1Deserialise==VP1Deserialise::numberOfInstantiations())
1570 VP1Msg::messageDebug("VP1TabManager WARNING: System "+(*itsys)->name()
1571 +" did not use VP1Deserialise in implementation of restoreFromState()");
1572 }
1573 //state.second.erase(it_state);
1574 } else {
1575 std::cout<<"VP1TabManager::unserializeChannelState Warning: Did not find state data for system "<<name.toStdString()<<std::endl;
1576 }
1577 }
1578 for (const QString& name : storedSystems)
1579 std::cout<<"VP1TabManager::unserializeChannelState Warning: Did not use stored configuration for system "<<name.toStdString()<<std::endl;
1580}
virtual void restoreFromState(QByteArray)
const QString unique_name() const
const QString & name() const
const std::set< IVP1System * > & systems()
virtual QByteArray saveState()
static unsigned numberOfInstantiations()
IVP1ChannelWidget * channelWidget() const
void ensureCWHasNoParent()
static void messageVerbose(const QString &)
Definition VP1Msg.cxx:84
static void messageDebug(const QString &)
Definition VP1Msg.cxx:39
static bool environmentVariableIsOn(const QString &name)
static bool expertSettingIsOn(const QString &type, const QString &name)
static unsigned numberOfInstantiations()
std::map< QString, QMainWindow * > name_2_tab
bool checkTabnameExists(const QString &tabname) const
QMap< QString, QStringList > serializeTabAndChannelConfigInfo() const
QMainWindow * previousTab()
bool checkChannelNameExists(const QString &channelbasename, const bool &isuniquename, const bool &checkfornonexistance=false) const
QMainWindow * fullscreen_tab
bool checkTabnameNotExists(const QString &tabname) const
QMainWindow * nextTab()
QStringList channelsInTab(QMainWindow *tab)
std::map< QMainWindow *, std::set< IVP1ChannelWidget * > > tab_2_channelwidgets
Imp(VP1TabManager *tm, VP1TabWidget *tw, VP1ChannelManager *cm)
VP1DockWidget * selecteddockwidget
VP1ChannelManager * channelmanager
QMainWindow * name2tab(const QString &tabname)
QSet< IVP1ChannelWidget * > lastvisible
std::map< IVP1ChannelWidget *, VP1DockWidget * > channelwidget_2_dockwidget
QString channelWithPendingRemoval
QMainWindow * channel2tab(IVP1ChannelWidget *cw)
VP1TabWidget * tabwidget
VP1DockWidget * fullscreen_dockwidget
QSet< IVP1ChannelWidget * > lastsoonvisible
bool checkTabnameNotEmpty(const QString &tabname) const
std::set< VP1DockWidget * > fullscreen_floatingdocks
IVP1ChannelWidget * fullscreen_channelwidget
VP1TabManager * tabmanager
VP1TabManager(QObject *parent, VP1TabWidget *, VP1ChannelManager *)
QStringList tabList()
void renameTab(const QString &tabname, const QString &newtabname)
void showCurrentTabFullScreen()
QList< IVP1ChannelWidget * > allChannels() const
bool showTab(const QString &)
void currentVisibleChanged()
QPair< QByteArray, QMultiMap< QString, QByteArray > > ChanState
int nTabs() const
void setSelectedDockWidget(VP1DockWidget *dw=0)
bool isVisible(IVP1ChannelWidget *) const
void serializeChannelState(IVP1ChannelWidget *, ChanState &state)
IVP1ChannelWidget * addChannelToTab(const QString &channelbasename, const QString &tabname)
void unserializeChannelState(IVP1ChannelWidget *cw, ChanState tate)
void loadConfigurationFromFile(const QString &filename, const QMap< QString, QString > &availableplugins)
void setSelectedChannelWidget(IVP1ChannelWidget *cw=0)
void selectedChannelChanged(IVP1ChannelWidget *)
QString suggestNewTabName(const QString &oldtabname) const
void dropOutOfFullScreen()
void cloneChannelToTab(const QString &channeluniquename, const QString &tabname)
void raiseTabBarContextMenu(int, const QPoint &)
void tabListChanged(QStringList)
void removeTab(const QString &tabname)
void setTabCruiseMode(const bool &)
bool showFirstChannelWithGivenBasename(const QString &basename)
void launchStereoEditorCurrentTab()
void moveChannelToTab(const QString &channeluniquename, const QString &tabname)
QString channelToTab(IVP1ChannelWidget *)
const QSet< IVP1ChannelWidget * > & visibleChannels() const
IVP1ChannelWidget * selectedChannelWidget() const
bool eventFilter(QObject *, QEvent *)
QString currentTab() const
void cloneTab(const QString &oldtabname, const QString &newtabname)
void removeChannel(const QString &channeluniquename)
void visibleChannelsChanged(const QSet< IVP1ChannelWidget * > &vis, const QSet< IVP1ChannelWidget * > &soonvis, const double &soonvisbonus)
void executePendingChannelRemoval()
bool hasTab(const QString &) const
QString currentChannelUniqueName() const
void saveConfigurationToFile(const QString &filename, const bool &askonoverride=true)
void showChannelFullScreen(IVP1ChannelWidget *)
const QSet< IVP1ChannelWidget * > & soonVisibleChannels() const
void removeChannelAfterQueueEmpties(const QString &)
void addNewTab(const QString &, const int &index=-1)
void showCurrentChannelFullScreen()
void showTabFullScreen(const QString &tabname)
void setTabReorderingEnabled(bool enable)
VP1TabBar * getVP1TabBar()
make the sidebar many part of the config
Definition hcg.cxx:552
std::string head(std::string s, const std::string &pattern)
head of a string
Definition index.py:1
TFile * file
std::string basename(std::string name)
Definition utils.cxx:207