/****************************************************************************
**  SCALASCA    http://www.scalasca.org/                                   **
*****************************************************************************
**  Copyright (c) 1998-2012                                                **
**  Forschungszentrum Juelich GmbH, Juelich Supercomputing Centre          **
**                                                                         **
**  See the file COPYRIGHT in the package base directory for details       **
****************************************************************************/


#include <QToolButton>
#include <QScrollBar>

#include "TabWidget.h"
#include "SystemTopologyWidget.h"
#include "PrecisionWidget.h"
#include "Statistics.h"
#include "SystemBoxPlot.h"

#include "Metric.h"
#include "Cartesian.h"

#include <cassert>
#include <qdebug.h>

TabWidget::TabWidget(TabWidgetType type, ColorWidget* colorWidget, ValueWidget* valueWidget, PrecisionWidget* precisionWidget): QTabWidget() {
   
   //general initializations
   valueModus = ABSOLUTE;
   cube = NULL;
   metricTabWidget = NULL;
   callTabWidget = NULL;
   systemTabWidget = NULL;
   splitterWidget = NULL;
   
   this->type = type;
   this->colorWidget = colorWidget;
   this->valueWidget = valueWidget;
   this->precisionWidget = precisionWidget;
   
   //tree-specific initializations
   treeFont = font();
   spacing = 2;
   
   //topology-specific initializations
   currentSysTopWidget = NULL;
   whiteForZero = true;
   lineType = BLACK_LINES;
   antialiasing = false;
   showUnusedTopologyPlanes = true;
   systemBoxWidget = NULL;
   systemBoxPlotIndex = -1;
#ifdef _AIX
   selectionSyntax = FRAME_SELECTION;
#else
   selectionSyntax = BACKGROUND_SELECTION;
#endif
}

TabWidget::~TabWidget(){}


/**************** get methods ******************/

//return the current value modus, see constants.h for the ValueModus type
//
ValueModus TabWidget::getValueModus(){ return valueModus; }

//get different widgets

ColorWidget* TabWidget::getColorWidget(){ return colorWidget; }
PrecisionWidget* TabWidget::getPrecisionWidget(){ return precisionWidget; }
ValueWidget* TabWidget::getValueWidget(){ return valueWidget; }
QSplitter* TabWidget::getSplitterWidget(){ return splitterWidget; }

//return the metric tree if any
//
TreeWidget* TabWidget::getMetricTree(){
   if (metricTabWidget==NULL) return NULL;
   else if (metricTabWidget->count()==0) return NULL;
   else {
      assert(metricTabWidget->widget(0)!=NULL);
      return ((TreeWidget*)(((ScrollArea*)(metricTabWidget->widget(0)))->component()));
   }
}

//return the call tree if any
//
TreeWidget* TabWidget::getCallTree(){
   if (callTabWidget==NULL) return NULL;
   else if (callTabWidget->count()==0) return NULL;
   else {
      assert(callTabWidget->widget(0)!=NULL);
      return ((TreeWidget*)(((ScrollArea*)(callTabWidget->widget(0)))->component()));
   }
}

//return the system tree if any
//
TreeWidget* TabWidget::getSystemTree(){
   if (systemTabWidget==NULL) return NULL;
   else if (systemTabWidget->count()==0) return NULL;
   else {
      assert(systemTabWidget->widget(0)!=NULL);
      return ((TreeWidget*)(((ScrollArea*)(systemTabWidget->widget(0)))->component()));
   }
}

//return the ith external metric item
//

TreeWidgetItem* TabWidget::getExternalMetricItem(int i){
   return externalMetricItems[i];
}

//return the name if the ith external metric item
//
std::string TabWidget::getExternalMetricName(int i){
   return externalMetricNames[i];
}

//return the current tab element of the call tab
//(call tree of flat call profile)
//
TreeWidget* TabWidget::getCurrentCallTree(){
   if (callTabWidget==NULL) return NULL;
   else if (callTabWidget->count()==0) return NULL;
   else {
      QWidget* widget = callTabWidget->widget(callTabWidget->currentIndex());
      assert(widget!=NULL);
      return ((TreeWidget*)(((ScrollArea*)widget)->component()));
   }
}

//get the different tabs

TabWidget* TabWidget::getMetricTabWidget(){ return metricTabWidget;}
TabWidget* TabWidget::getCallTabWidget()  { return callTabWidget;  }
TabWidget* TabWidget::getSystemTabWidget(){ return systemTabWidget;}


//return if unused topology planes should be displayed
//
bool TabWidget::getShowUnusedTopologyPlanes(){ return showUnusedTopologyPlanes; }

//return if lines in topology display should be antialiased
//
bool TabWidget::getAntialiasing(){ return antialiasing; }

//return the line style for topologies
//(black, gray, white or no lines, see constants.h for the LineType type)
//
LineType TabWidget::getLineType(){ return lineType;}

//tell how zero values in topologies are colored
//(white or minimal color)
//
bool TabWidget::getWhiteForZero(){ return whiteForZero; }

//return the current method for marking selected tree items
//(by blue background or by framing, see constants.h for the SelectionSyntax type)
//
SelectionSyntax TabWidget::getSelectionSyntax(){
   return selectionSyntax;
}


/******************* set methods ***************/

//set the value modus, see constants.h for the ValueModus type
//
void TabWidget::setValueModus(ValueModus valueModus){
   this->valueModus = valueModus;
   if (count()==0) return;
   ((TreeWidget*)(((ScrollArea*)(widget(0)))->component()))->computeReferenceValues();
   if (type==CALLTAB)
      ((TreeWidget*)(((ScrollArea*)(widget(1)))->component()))->computeReferenceValues();
   updateValueWidget();
}

//set the different tab widgets;
//they are needed to determine the different trees

void TabWidget::setMetricTabWidget(TabWidget* widget){ metricTabWidget = widget; }
void TabWidget::setCallTabWidget  (TabWidget* widget){ callTabWidget = widget; }
void TabWidget::setSystemTabWidget(TabWidget* widget){ systemTabWidget = widget; }

//set the splitter widget the tab is in
//
void TabWidget::setSplitterWidget(QSplitter* splitter){ splitterWidget = splitter; }

//set font and line spacing for the tree displays
//in this tab
//
void TabWidget::setTreeDisplay(QFont font, int spacing){
   treeFont = font;
   this->spacing = spacing;
   if (count()>0){
      TreeWidget* treeWidget = ((TreeWidget*)(((ScrollArea*)widget(0))->component()));
      treeWidget->setFont(treeFont);
      treeWidget->setSpacing(spacing);
      treeWidget->updateSizes();
      if (type==CALLTAB){
         treeWidget = ((TreeWidget*)(((ScrollArea*)widget(1))->component()));
         treeWidget->setFont(treeFont);
         treeWidget->setSpacing(spacing);
         treeWidget->updateSizes();
      }
   }
}

//set how zero values in topologies should be colored
//(white or minimal color)
//
void TabWidget::setWhiteForZero(bool whiteForZero){ this->whiteForZero = whiteForZero; }

//set how selected tree items should be marked
//(by blue background or by framing, see constants.h for the SelectionSyntax type)
//
void TabWidget::setSelectionSyntax(SelectionSyntax selectionSyntax){
   this->selectionSyntax = selectionSyntax;
   displayItems();
}


/**************** initialization and clean-up ***************/

//initialize according to the type and the cube database
//
void TabWidget::initialize(cube::Cube* cube, QString fileName,
                           cubeparser::Driver* driver, Statistics* statistics){
   
   this->cube = cube;
   
   TreeWidget * treeWidget;
   
   if (type==METRICTAB) {
      //metric tabs have a metric tree
      ScrollArea*  scrollArea = new ScrollArea(this,ScrollAreaTreeWidget);
      treeWidget = new TreeWidget(scrollArea,METRICTREE,fileName,driver,statistics);
      connect(treeWidget,SIGNAL(setMessage(QString)),this,SIGNAL(setMessage(QString)));
      treeWidget->setFont(treeFont);
      treeWidget->setSpacing(spacing);
      treeWidget->setTabWidget(this);
      treeWidget->initialize(cube);
      scrollArea->setMainWidget(treeWidget);
      addTab(scrollArea,"Metric tree");
      
   } else if (type==CALLTAB) {
      //call tabs have a call tree and a flat call profile
      ScrollArea*  scrollArea = new ScrollArea(this,ScrollAreaTreeWidget);
      treeWidget = new TreeWidget(scrollArea,CALLTREE,fileName,driver,statistics);
      connect(treeWidget,SIGNAL(setMessage(QString)),this,SIGNAL(setMessage(QString)));
      treeWidget->setFont(treeFont);
      treeWidget->setSpacing(spacing);
      treeWidget->setTabWidget(this);
      treeWidget->initialize(cube);
      scrollArea->setMainWidget(treeWidget);
      addTab(scrollArea,"Call tree");
      
      scrollArea = new ScrollArea(this,ScrollAreaTreeWidget);
      treeWidget = new TreeWidget(scrollArea,CALLFLAT);
      connect(treeWidget,SIGNAL(setMessage(QString)),this,SIGNAL(setMessage(QString)));
      treeWidget->setFont(treeFont);
      treeWidget->setSpacing(spacing);
      treeWidget->setTabWidget(this);
      treeWidget->initialize(cube);
      scrollArea->setMainWidget(treeWidget);
      addTab(scrollArea,"Flat view");
   } else if (type==SYSTEMTAB){
      //system tabs have a system tree, topologies and box plot
      {
         ScrollArea*  scrollArea = new ScrollArea(this,ScrollAreaTreeWidget);
         treeWidget = new TreeWidget(scrollArea,SYSTEMTREE);
         connect(treeWidget,SIGNAL(setMessage(QString)),this,SIGNAL(setMessage(QString)));
         treeWidget->setFont(treeFont);
         treeWidget->setSpacing(spacing);
         treeWidget->setTabWidget(this);
         treeWidget->initialize(cube);
         scrollArea->setMainWidget(treeWidget);
         addTab(scrollArea,"System tree");
      }
      { // box plot tab
	ScrollArea* scrollArea = new ScrollArea( this, ScrollAreaBoxPlot );
	systemBoxWidget = new SystemBoxPlot( scrollArea, treeWidget );
	scrollArea->setMainWidget( systemBoxWidget );
	scrollArea->setWidgetResizable( true );
	scrollArea->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
	scrollArea->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
	    
         systemBoxPlotIndex = addTab(scrollArea, "Box Plot");
      }
      {
         SystemTopologyWidget* systemTopologyWidget;
         ScrollArea* scrollArea;
         unsigned numTopologies = cube->get_cartv().size();
         
         for (unsigned i=0; i<numTopologies; i++){
            topDimOrders.push_back(0);
            
            QString name = (cube->get_cartv()).at(i)->get_name().c_str();
            if (name == "")
            {
               name.append("Topology ");
               name.append(QString::number(i));
            }
            SystemTopologyContainer *container = new SystemTopologyContainer();
	    
            scrollArea = new ScrollArea(this, ScrollAreaTopologyWidget);
            systemTopologyWidget = new SystemTopologyWidget(scrollArea,i);
            scrollArea->setMainWidget(systemTopologyWidget);
            
            systemTopologyWidget->setScrollArea(scrollArea);
            systemTopologyWidget->setLineType(lineType);
            systemTopologyWidget->setSystemTreeWidget(treeWidget);
            systemTopologyWidget->initialize(cube);
	    
	    
	    
            container->setComponent(systemTopologyWidget);
            container->addWidget(scrollArea);

            QWidget *dimBar = systemTopologyWidget->getDimensionSelectionBar();
            if (dimBar != 0) {
               container->addWidget(dimBar);
            }

            addTab(container, name);
         }
      } // SYSTEMTAB
   }
   connect(this,SIGNAL(currentChanged(int)),this,SLOT(onCurrentChanged(int)));
}

/**
  returns the index of the selected system topology
  @param tabIndex index of the tab
*/
int TabWidget::topologyIndex(int tabIndex) {
   int idx = tabIndex - 1; // don't count system tree (always 1st tab)
   if (tabIndex > systemBoxPlotIndex) idx--; // don't count SystemBoxPlot tab
   return idx;
}

//initialize the topology tool bar
//
void TabWidget::initializeTopologyToolBar(QToolBar* topologyToolBar){
   
   assert(type==SYSTEMTAB);
   this->topologyToolBar = topologyToolBar;
   setButtonsToIcon();
   
   leftAct  = topologyToolBar->addAction(QIcon(":/images/left_small.png"),QString("left"));
   rightAct = topologyToolBar->addAction(QIcon(":/images/right_small.png"),QString("right"));
   upAct    = topologyToolBar->addAction(QIcon(":/images/up_small.png"),QString("up"));
   downAct  = topologyToolBar->addAction(QIcon(":/images/down_small.png"),QString("down"));
   dist1Act = topologyToolBar->addAction(QIcon(":/images/distance1_small.png"),QString("dist+"));
   dist2Act = topologyToolBar->addAction(QIcon(":/images/distance2_small.png"),QString("dist-"));
   zoom1Act = topologyToolBar->addAction(QIcon(":/images/zoomin_small.png"),QString("zoom+"));
   zoom2Act = topologyToolBar->addAction(QIcon(":/images/zoomout_small.png"),QString("zoom-"));
   resetAct = topologyToolBar->addAction(QIcon(":/images/reset_small.png"),QString("reset"));
   scaleAct = topologyToolBar->addAction(QIcon(":/images/scale_small.png"),QString("scale"));
   userAct  = topologyToolBar->addAction(QIcon(":/images/user_small.png"),QString("min/max"));
   
   leftAct->setWhatsThis("Moves the whole topology to the left.");
   rightAct->setWhatsThis("Moves the whole topology to the right.");
   upAct->setWhatsThis("Moves the whole topology upwards.");
   downAct->setWhatsThis("Moves the whole topology downwards.");
   dist1Act->setWhatsThis("Increase the distance between the planes of the topology.");
   dist2Act->setWhatsThis("Decrease the distance between the planes of the topology.");
   zoom1Act->setWhatsThis("Enlarge the topology.");
   zoom2Act->setWhatsThis("Scale down the topology.");
   resetAct->setWhatsThis("Reset the display. It scales the topology such that it fits into the visible rectangle, and transforms it into a default position.");
   scaleAct->setWhatsThis("It scales the topology such that it fits into the visible rectangle, without transformations.");
   userAct->setWhatsThis(" Similarly to the functions offered in the context menu of trees, you can activate and deactivate the application of user-defined minimal and maximal values for the color extremes, i.e., the values corresponding to the left and right end of the color legend. If the you activate user-defined values for the color extremes, you are asked to define two values that should correspond to the minimal and to the maximal colors. All values outside of this interval will get the color gray. Note that canceling any of the input windows causes no changes in the coloring method.  If user-defined min/max values are activated, the selected value information widget displays a \"(u)\" for \"user-defined\" behind the minimal and maximal color values.");
   
   xLabel = new QLabel("x-rot:");
   topologyToolBar->addWidget(xLabel);
   
   xSpin = new QSpinBox();
   xSpin->setMinimum(0);
   xSpin->setMaximum(359);
   xSpin->setSingleStep(1);
   xSpin->setValue(300);
   topologyToolBar->addWidget(xSpin);
   
   yLabel = new QLabel("y-rot:");
   topologyToolBar->addWidget(yLabel);
   
   ySpin = new QSpinBox();
   ySpin->setMinimum(0);
   ySpin->setMaximum(359);
   ySpin->setSingleStep(1);
   ySpin->setValue(30);
   topologyToolBar->addWidget(ySpin);
   
   xLabel->setWhatsThis("Rotate the topology cube about the x-axis with the defined angle.");
   xSpin->setWhatsThis("Rotate the topology cube about the x-axis with the defined angle.");
   yLabel->setWhatsThis("Rotate the topology cube about the y-axis with the defined angle.");
   ySpin->setWhatsThis("Rotate the topology cube about the y-axis with the defined angle.");
   
   comboBox = new QComboBox();
   comboBox->setToolTip("Dimension order for topology display");
   
   comboBox->setIconSize(QSize(25,25));
   
   comboBox->addItem(QIcon(":images/zxy_small.png"),QString(""));
   comboBox->addItem(QIcon(":images/yxz_small.png"),QString(""));
   comboBox->addItem(QIcon(":images/zyx_small.png"),QString(""));
   comboBox->addItem(QIcon(":images/xyz_small.png"),QString(""));
   comboBox->addItem(QIcon(":images/yzx_small.png"),QString(""));
   comboBox->addItem(QIcon(":images/xzy_small.png"),QString(""));
   
   comboBox->setWhatsThis("The topologies may have two or three dimensions. Here you can define the order of dimensions in the display.");
   
   //comboBox has setting for 3D topologies
   comboBoxState = 3;
   topologyToolBar->addWidget(comboBox);
   connect(comboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(onDimensionOrder(int)));
   
   QToolButton* leftButton  = (QToolButton*)(topologyToolBar->widgetForAction(leftAct));
   QToolButton* rightButton = (QToolButton*)(topologyToolBar->widgetForAction(rightAct));
   QToolButton* upButton    = (QToolButton*)(topologyToolBar->widgetForAction(upAct));
   QToolButton* downButton  = (QToolButton*)(topologyToolBar->widgetForAction(downAct));
   QToolButton* dist1Button = (QToolButton*)(topologyToolBar->widgetForAction(dist1Act));
   QToolButton* dist2Button = (QToolButton*)(topologyToolBar->widgetForAction(dist2Act));
   QToolButton* zoom1Button = (QToolButton*)(topologyToolBar->widgetForAction(zoom1Act));
   QToolButton* zoom2Button = (QToolButton*)(topologyToolBar->widgetForAction(zoom2Act));
   QToolButton* resetButton = (QToolButton*)(topologyToolBar->widgetForAction(resetAct));
   QToolButton* scaleButton = (QToolButton*)(topologyToolBar->widgetForAction(scaleAct));
   QToolButton* userButton  = (QToolButton*)(topologyToolBar->widgetForAction(userAct));
   
   leftButton ->setAutoRaise(false);
   rightButton->setAutoRaise(false);
   upButton   ->setAutoRaise(false);
   downButton ->setAutoRaise(false);
   dist1Button->setAutoRaise(false);
   dist2Button->setAutoRaise(false);
   zoom1Button->setAutoRaise(false);
   zoom2Button->setAutoRaise(false);
   resetButton->setAutoRaise(false);
   scaleButton->setAutoRaise(false);
   userButton ->setAutoRaise(false);
   
   leftAct ->setToolTip("Move left");
   rightAct->setToolTip("Move right");
   upAct   ->setToolTip("Move up");
   downAct ->setToolTip("Move down");
   dist1Act->setToolTip("Increase plane distance");
   dist2Act->setToolTip("Decrease plane distance");
   zoom1Act->setToolTip("Zoom in");
   zoom2Act->setToolTip("Zoom out");
   resetAct->setToolTip("Reset");
   scaleAct->setToolTip("Scale into window");
   userAct ->setToolTip("Set minimum/maximum values for coloring");
   
   leftButton ->setAutoRepeat(true);
   rightButton->setAutoRepeat(true);
   upButton   ->setAutoRepeat(true);
   downButton ->setAutoRepeat(true);
   dist1Button->setAutoRepeat(true);
   dist2Button->setAutoRepeat(true);
   zoom1Button->setAutoRepeat(true);
   zoom2Button->setAutoRepeat(true);
   
   connect(leftButton, SIGNAL(pressed()),this,SLOT(moveLeft()));
   connect(rightButton,SIGNAL(pressed()),this,SLOT(moveRight()));
   connect(upButton,   SIGNAL(pressed()),this,SLOT(moveUp()));
   connect(downButton, SIGNAL(pressed()),this,SLOT(moveDown()));
   connect(dist1Button,SIGNAL(pressed()),this,SLOT(increasePlaneDistance()));
   connect(dist2Button,SIGNAL(pressed()),this,SLOT(decreasePlaneDistance()));
   connect(zoom1Button,SIGNAL(pressed()),this,SLOT(zoomIn()));
   connect(zoom2Button,SIGNAL(pressed()),this,SLOT(zoomOut()));
   connect(resetButton,SIGNAL(pressed()),this,SLOT(reset()));
   connect(scaleButton,SIGNAL(pressed()),this,SLOT(scale()));
   connect(userButton, SIGNAL(pressed()),this,SLOT(minMaxValues()));
   
   disableTopologyButtons();
   
}


//called when files are closed;
//clear the tab, no data is shown
//
void TabWidget::cleanUp(){
   topDimOrders.clear();
   disconnect(this,SIGNAL(currentChanged(int)),this,SLOT(onCurrentChanged(int)));
   if (currentSysTopWidget!=NULL){
      disconnect(xSpin,SIGNAL(valueChanged(int)),currentSysTopWidget,SLOT(setXAngleFromExtern(int)));
      disconnect(ySpin,SIGNAL(valueChanged(int)),currentSysTopWidget,SLOT(setYAngleFromExtern(int)));
      disconnect(currentSysTopWidget,SIGNAL(xAngleChanged(int)),xSpin,SLOT(setValue(int)));
      disconnect(currentSysTopWidget,SIGNAL(yAngleChanged(int)),ySpin,SLOT(setValue(int)));
      currentSysTopWidget = NULL;
   }
   //disable topology tool bar
   if (type==SYSTEMTAB) disableTopologyButtons();
   //remove tab elements
   while (count()>0){
      QWidget* child = widget(0);
      removeTab(0);
      delete child;
   }
}


//clean up external values;
//called when external files are closed
//
void TabWidget::clearExternalValues(){
   for (int i=0; i<(int)(externalMetricItems.size()); i++){
      delete externalMetricItems[i];
   }
   externalMetricItems.clear();
   externalMetricNames.clear();
}


/************** value computations ******************/


//(re-)compute the values for the current tab element;
//in case of system tabs, compute the values for the system tree,
//since the topologies use the tree values
//
void TabWidget::computeValues(){
   if (count()>0){
      int index = (type==SYSTEMTAB ? 0 : currentIndex());
      ((TreeWidget*)(((ScrollArea*)(widget(index)))->component()))->computeValues();
      displayItems();
   }
}

//compute the needed external values from the "cubeExternal"
//database for the external percentage value modus
//
void TabWidget::computeExternalValues(cube::Cube* cubeExternal){
   assert(type==METRICTAB);
   
   clearExternalValues();
   
   const std::vector<cube::Metric*>& metricVec = cubeExternal->get_metv();
   const std::vector<cube::Cnode*>&  callVec   = cubeExternal->get_cnodev();
   const std::vector<cube::Thread*>& threadVec = cubeExternal->get_thrdv();
   
   //build the tree of the external metric items
   for (int i=0; i<(int)metricVec.size(); i++){
      //take the next metric item
      cube::Metric* metric = metricVec[i];
      cube::Metric* metricParent = metric->get_parent();
      TreeWidgetItem* itemParent = NULL;
      //search for the (already created) parent item
      if (metricParent!=NULL){
         for (int j=0; j<(int)externalMetricItems.size(); j++){
            if (((cube::Metric*)((TreeWidgetItem*)(externalMetricItems[j]->cubeObject)))==metricParent){
               itemParent = externalMetricItems[j];
               break;
            }
         }
         assert(itemParent!=NULL);
      }
      //create a new item for the current metric with the found parent
      TreeWidgetItem* item = new TreeWidgetItem(itemParent);
      item->cubeObject = metric;
      externalMetricItems.push_back(item);
      //we store the metric names because we delete the cube object
      //after computing the external values
      externalMetricNames.push_back(metric->get_uniq_name());
      
      //compute external metric values
      double totalValue = 0.0;
      for (int j = 0; j < (int)callVec.size(); j++){
         for (int k = 0; k < (int)threadVec.size(); k++){
            totalValue += cube->get_sev(metric,
                                        callVec[j],
                                        threadVec[k]);
         }
      }
      item->totalValue = totalValue;
      item->ownValue   = totalValue;
      if (itemParent!=NULL)
         itemParent->ownValue -= totalValue;
   }
   //clean up the cube object references such that the cube
   //object can be deleted
   for (int i=0; i<(int)(externalMetricItems.size()); i++)
      externalMetricItems[i]->cubeObject = NULL;
}


/***************** display **********************/

//display the current tab element
//
void TabWidget::displayItems(){
   if (count()>0){
      if (type==METRICTAB || type==CALLTAB){
         ((TreeWidget*)(((ScrollArea*)widget(currentIndex()))->component()))->displayItems();
      } else {
         assert(type==SYSTEMTAB);
         ((TreeWidget*)(((ScrollArea*)(widget(0)))->component()))->displayItems();
         if (currentSysTopWidget) {
            currentSysTopWidget->displayItems();
         }
         if (systemBoxWidget && currentIndex() == systemBoxPlotIndex) {
            systemBoxWidget->updateValues();
         }
#if 0
         if (currentIndex()==0) {
            ((TreeWidget*)(((ScrollArea*)(widget(0)))->component()))->displayItems();
         } else {
            currentSysTopWidget->displayItems();
         }
#endif
      }
   }
}

/** signal currentChanged() is emitted when the visible tab element has changed;
  that signal gets connected to this slot;
  parameter: index is the new index of the current tab element
*/
void TabWidget::onCurrentChanged(int index){
   if (type==CALLTAB) {
      
      //for call tabs:
      //(re-)compute values of the current tab element
      
      ((TreeWidget*)(((ScrollArea*)(widget(index)))->component()))->computeValues();
      ((TreeWidget*)(((ScrollArea*)(widget(index)))->component()))->computeMaxValues();
      
   } else if (type==SYSTEMTAB){
      
      //if previous tab element was topology:
      //disconnect signals from/to the previously visible topology tab element
      if (currentSysTopWidget!=NULL){
         disconnect(xSpin,SIGNAL(valueChanged(int)),currentSysTopWidget,SLOT(setXAngleFromExtern(int)));
         disconnect(ySpin,SIGNAL(valueChanged(int)),currentSysTopWidget,SLOT(setYAngleFromExtern(int)));
         disconnect(currentSysTopWidget,SIGNAL(xAngleChanged(int)),xSpin,SLOT(setValue(int)));
         disconnect(currentSysTopWidget,SIGNAL(yAngleChanged(int)),ySpin,SLOT(setValue(int)));
         
         currentSysTopWidget = NULL;
      }
      
      //if current tab element is topology:
      //connect signals from/to the current topology tab element
      if (index > 0 && index != systemBoxPlotIndex) {
         currentSysTopWidget = ((SystemTopologyWidget*)(((ScrollArea*)widget(index))->component()));
         
         //update values of spins before connected not to emit signals unnecessarily
         xSpin->setValue(currentSysTopWidget->getXAngle());
         ySpin ->setValue(currentSysTopWidget->getYAngle());
         
         connect(xSpin,SIGNAL(valueChanged(int)),currentSysTopWidget,SLOT(setXAngleFromExtern(int)));
         connect(ySpin,SIGNAL(valueChanged(int)),currentSysTopWidget,SLOT(setYAngleFromExtern(int)));
         connect(currentSysTopWidget,SIGNAL(xAngleChanged(int)),xSpin,SLOT(setValue(int)));
         connect(currentSysTopWidget,SIGNAL(yAngleChanged(int)),ySpin,SLOT(setValue(int)));
         
      } else if (index == systemBoxPlotIndex) {
         displayItems();
      }

      if (index == 0 || index == systemBoxPlotIndex) {
         //if the current tab elelement is not a topology, then disable the topology tool bar
         disableTopologyButtons();
       }
      else { //update and enable the topology tool bar
         int idx = topologyIndex(index);
         disconnect(comboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(onDimensionOrder(int)));
         if (comboBoxState == 2 &&
            ( (cube->get_cart(idx)->get_dimv().size() >= 3) ||
              (cube->get_cart(idx)->get_dimv().size() == 1) )) {
            comboBox->clear();
            comboBox->addItem(QIcon(":images/zxy_small.png"),QString(""));
            comboBox->addItem(QIcon(":images/yxz_small.png"),QString(""));
            comboBox->addItem(QIcon(":images/zyx_small.png"),QString(""));
            comboBox->addItem(QIcon(":images/xyz_small.png"),QString(""));
            comboBox->addItem(QIcon(":images/yzx_small.png"),QString(""));
            comboBox->addItem(QIcon(":images/xzy_small.png"),QString(""));
            comboBoxState = 3;
         } else if (comboBoxState == 3 && cube->get_cart(idx)->get_dimv().size()==2){
            comboBox->clear();
            comboBox->addItem(QIcon(":images/yx_small.png"),QString(""));
            comboBox->addItem(QIcon(":images/xy_small.png"),QString(""));
            comboBoxState = 2;
         }
         enableTopologyButtons();
         comboBox->setCurrentIndex(topDimOrders[topologyIndex(index)]);
         connect(comboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(onDimensionOrder(int)));
         
         //update the colors, because since the last display the values
         //of the system tree could have changed
         currentSysTopWidget->updateColors();

         /* Scale the topopoly to fit into the window. This is automatically done if resizeEvent is
            emitted, but TabWidget::resizeEvent does only handle the currently displayed tab. After the
            tab has changed, the size may not be correct.
            */
         currentSysTopWidget->reset(false);
      } // topology
   } // SYSTEMTAB
   
   //if current tab element is a tree:
   //ensure that the selected item is visible if the current
   //tab item is a tree
   if (index==0 || type==CALLTAB){
      TreeWidget* treeWidget = ((TreeWidget*)(((ScrollArea*)(widget(index)))->component()));
      if (treeWidget->selectedItems().size()>0){
         treeWidget->ensureVisible(treeWidget->selectedItems().at(0));
      }
      ((ScrollArea*)(widget(index)))->horizontalScrollBar()->setValue(0);
      // redraw system tree and call tab trees
      displayItems();
   }

   //repaint value widget
   updateValueWidget();
}


//update the value widgets below the tab
//
void TabWidget::updateValueWidget(){
   if (count()>0){
      int index = currentIndex();
      //if current tab element is a tree
      if (index==0 || type==CALLTAB){
         ((TreeWidget*)(((ScrollArea*)(widget(index)))->component()))->updateValueWidget();
      } else if (type==SYSTEMTAB){
         //else it is a topology
         if (index != systemBoxPlotIndex) {
            assert(currentSysTopWidget!=NULL);
            currentSysTopWidget->updateValueWidget();
         } else if (index == this->systemBoxPlotIndex) { // box plot
            systemBoxWidget->updateValueWidget();
         }
      }
   }
}

/************* topology tool bar ***************/


//set the button style of the topology tool bar;
//this slot is connected to actions in the menu Display/Toolbar

void TabWidget::setButtonsToText(){
   topologyToolBar->setToolButtonStyle(Qt::ToolButtonTextOnly);
}

void TabWidget::setButtonsToIcon(){
   topologyToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
}


//set the dimension order for topologies
//according to the corresponding combo box in the topology tool bar
//this slot is connected to the change of current index in the combo box
//
void TabWidget::onDimensionOrder(int index){
   assert(type==SYSTEMTAB);
   
   if (comboBoxState==3){
      //comboBox for 3D topologies
      if (index==0) setDimOrder(0,1,2);
      else if (index==1) setDimOrder(0,2,1);
      else if (index==2) setDimOrder(1,0,2);
      else if (index==3) setDimOrder(1,2,0);
      else if (index==4) setDimOrder(2,0,1);
      else if (index==5) setDimOrder(2,1,0);
   } else {
      //comboBox for 2D topologies
      if (index==0) setDimOrder(0,1,2);
      else if (index==1) setDimOrder(0,2,1);
   }
   
   //store the order for the current tab item
   //in order to restore it when returning from another tab item
   topDimOrders[topologyIndex(currentIndex())] = index;
}


//slots connected to the actions in the topology tool bar

void TabWidget::moveDown(){
   assert(currentIndex()>0);
   ((SystemTopologyWidget*)(((ScrollArea*)widget(currentIndex()))->component()))->moveDown();
}
void TabWidget::moveUp(){
   assert(currentIndex()>0);
   ((SystemTopologyWidget*)(((ScrollArea*)widget(currentIndex()))->component()))->moveUp();
}
void TabWidget::moveRight(){
   assert(currentIndex()>0);
   ((SystemTopologyWidget*)(((ScrollArea*)widget(currentIndex()))->component()))->moveRight();
}
void TabWidget::moveLeft(){
   assert(currentIndex()>0);
   ((SystemTopologyWidget*)(((ScrollArea*)widget(currentIndex()))->component()))->moveLeft();
}
void TabWidget::increasePlaneDistance(){
   assert(currentIndex()>0);
   ((SystemTopologyWidget*)(((ScrollArea*)widget(currentIndex()))->component()))->increasePlaneDistance();
}
void TabWidget::decreasePlaneDistance(){
   assert(currentIndex()>0);
   ((SystemTopologyWidget*)(((ScrollArea*)widget(currentIndex()))->component()))->decreasePlaneDistance();
}
void TabWidget::zoomIn(){
   assert(currentIndex()>0);
   ((SystemTopologyWidget*)(((ScrollArea*)widget(currentIndex()))->component()))->zoomIn();
}
void TabWidget::zoomOut(){
   assert(currentIndex()>0);
   ((SystemTopologyWidget*)(((ScrollArea*)widget(currentIndex()))->component()))->zoomOut();
}
void TabWidget::reset(){
   assert(currentIndex()>0);
   ((SystemTopologyWidget*)(((ScrollArea*)widget(currentIndex()))->component()))->reset(true);
}
void TabWidget::scale(){
   assert(currentIndex()>0);
   ((SystemTopologyWidget*)(((ScrollArea*)widget(currentIndex()))->component()))->rescalePlane(false);
}
void TabWidget::minMaxValues(){
   assert(currentIndex()>0);
   ((SystemTopologyWidget*)(((ScrollArea*)widget(currentIndex()))->component()))->minMaxValues();
}

//set the dimension order for topologies according to the combo box of the topology tool bar
//
void TabWidget::setDimOrder(unsigned dim0, unsigned dim1, unsigned dim2){
   assert(type==SYSTEMTAB);
   assert(currentIndex()>0);
   ((SystemTopologyWidget*)(((ScrollArea*)widget(currentIndex()))->component()))->setDimOrder(dim0,dim1,dim2);
}

//the topology tool bar's actions are enabled only if in the tab widget
//the current element is a topology display (SystemTabWidget)

void TabWidget::enableTopologyButtons(){
   assert(type==SYSTEMTAB);
   leftAct->setEnabled(true);
   rightAct->setEnabled(true);
   upAct->setEnabled(true);
   downAct->setEnabled(true);
   dist1Act->setEnabled(true);
   dist2Act->setEnabled(true);
   zoom1Act->setEnabled(true);
   zoom2Act->setEnabled(true);
   resetAct->setEnabled(true);
   scaleAct->setEnabled(true);
   userAct->setEnabled(true);
   comboBox->setEnabled(true);
   xLabel->setEnabled(true);
   yLabel->setEnabled(true);
   xSpin->setEnabled(true);
   ySpin->setEnabled(true);
}

void TabWidget::disableTopologyButtons(){
   assert(type==SYSTEMTAB);
   leftAct->setEnabled(false);
   rightAct->setEnabled(false);
   upAct->setEnabled(false);
   downAct->setEnabled(false);
   dist1Act->setEnabled(false);
   dist2Act->setEnabled(false);
   zoom1Act->setEnabled(false);
   zoom2Act->setEnabled(false);
   resetAct->setEnabled(false);
   scaleAct->setEnabled(false);
   userAct->setEnabled(false);
   comboBox->setEnabled(false);
   xLabel->setEnabled(false);
   yLabel->setEnabled(false);
   xSpin->setEnabled(false);
   ySpin->setEnabled(false);
}

//defines if zero values in topologies should be represented by the
//color white or by the minimal color;
//this slot is connected to the actions in the menu
//Display/Coloring/Topology coloring

void TabWidget::whiteOff(){
   assert(type==SYSTEMTAB);
   whiteForZero = false;
   if (currentSysTopWidget!=NULL) {
      currentSysTopWidget->updateColors();
      displayItems();
   }
}
void TabWidget::whiteOn(){
   assert(type==SYSTEMTAB);
   whiteForZero = true;
   if (currentSysTopWidget!=NULL) {
      currentSysTopWidget->updateColors();
      displayItems();
   }
}

//set line coloring in topology widgets;
//connected to the actions in the menu Display/Coloring/Topology line coloring

void TabWidget::blackLines(){
   assert(type==SYSTEMTAB);
   lineType = BLACK_LINES;
   for (int i=1; i<count(); i++)
      if (i != systemBoxPlotIndex)
         ((SystemTopologyWidget*)(((ScrollArea*)widget(i))->component()))->setLineType(BLACK_LINES);
}
void TabWidget::grayLines(){
   assert(type==SYSTEMTAB);
   lineType = GRAY_LINES;
   for (int i=1; i<count(); i++)
      if (i != systemBoxPlotIndex)
         ((SystemTopologyWidget*)(((ScrollArea*)widget(i))->component()))->setLineType(GRAY_LINES);
}
void TabWidget::whiteLines(){
   assert(type==SYSTEMTAB);
   lineType = WHITE_LINES;
   for (int i=1; i<count(); i++)
      if (i != systemBoxPlotIndex)
         ((SystemTopologyWidget*)(((ScrollArea*)widget(i))->component()))->setLineType(WHITE_LINES);
}
void TabWidget::noLines(){
   assert(type==SYSTEMTAB);
   lineType = NO_LINES;
   for (int i=1; i<count(); i++)
      if (i != systemBoxPlotIndex)
         ((SystemTopologyWidget*)(((ScrollArea*)widget(i))->component()))->setLineType(NO_LINES);
}



//define if lines in topologies should be drawn with antialiasing
//
void TabWidget::setAntialiasing(bool value){
   antialiasing = value;
   if (currentIndex()>0)
      ((SystemTopologyWidget*)(((ScrollArea*)widget(currentIndex()))->component()))->repaint();
}

//toggle modus if lines in topologies should be drawn with antialiasing
void TabWidget::toggleAntialiasing(){
   assert(type==SYSTEMTAB);
   antialiasing = !antialiasing;
   if (currentIndex()>0)
      ((SystemTopologyWidget*)(((ScrollArea*)widget(currentIndex()))->component()))->repaint();
}

//change the modus if unused topology planes should be displayed
void TabWidget::toggleUnused(){
   assert(type==SYSTEMTAB);
   showUnusedTopologyPlanes = !showUnusedTopologyPlanes;
   
   for (int i=1; i<count(); i++)
      if (i != systemBoxPlotIndex)
         ((SystemTopologyWidget*)(((ScrollArea*)widget(i))->component()))->toggleUnused();
}



/***************** settings ***********************/


//save tab settings
//
void TabWidget::saveSettings(QSettings& settings){
   assert(count()>0);
   
   QString groupName;
   if (type==METRICTAB) groupName = "metrictab";
   else if (type==CALLTAB) groupName = "calltab";
   else if (type==SYSTEMTAB) groupName = "systemtab";
   else {assert(false);}
   settings.beginGroup(groupName);
   
   //for system tabs:
   //save the topology dimension orders for all topologies
   if (type==SYSTEMTAB) {
      for (int i=1; i<count(); i++) {
         if (i != systemBoxPlotIndex) {
            QString name = "topologyDimension";
            name.append(QString::number(i));
            settings.setValue(name,topDimOrders[topologyIndex(i)]);
         }
      }
   }
   
   //recursively save settings for the tab elements;
   //first the tree at index 0
   ((TreeWidget*)(((ScrollArea*)(widget(0)))->component()))->saveSettings(settings);
   //for call tabs also the flat call profile
   if (type==CALLTAB)
      ((TreeWidget*)(((ScrollArea*)(widget(1)))->component()))->saveSettings(settings);
   else if (type==SYSTEMTAB && count()>1){
      //and for system tabs all topologies
      for (int i=1; i<count(); i++) {
         if (i != systemBoxPlotIndex) {
            ((SystemTopologyWidget*)(((ScrollArea*)widget(i))->component()))->saveSettings(settings);
         }
      }
   }
   
   //miscellaneous
   settings.setValue("currentIndex",currentIndex());
   settings.setValue("selectionSyntax",selectionSyntax);
   settings.setValue("whiteForZero",whiteForZero);
   if (type==SYSTEMTAB) settings.setValue("lineType",lineType);
   
   settings.endGroup();
}

//load tab settings
//
bool TabWidget::loadSettings(QSettings& settings){
   assert(count()>0);
   
   bool result = true;
   
   
   QString groupName;
   if (type==METRICTAB) groupName = "metrictab";
   else if (type==CALLTAB) groupName = "calltab";
   else if (type==SYSTEMTAB) groupName = "systemtab";
   else {assert(false);}
   settings.beginGroup(groupName);
   
   //recursively load settings for all tab elements:
   //first the tree at index 0
   
   result = ((TreeWidget*)(((ScrollArea*)(widget(0)))->component()))->loadSettings(settings);
   //for call tabs also the flat call profile
   
   if (result && type==CALLTAB)
      result = ((TreeWidget*)(((ScrollArea*)(widget(1)))->component()))->loadSettings(settings);
   else if (result && type==SYSTEMTAB && count()>1){
      //and for system tabs for all topologies
      for (int i=1; result && i<count(); i++){
         if (i != systemBoxPlotIndex) {
            setCurrentIndex(i);
            QString name = "topologyDimension";
            name.append(QString::number(i));
            onDimensionOrder(settings.value(name,0).toInt());
            result = 	((SystemTopologyWidget*)(((ScrollArea*)widget(i))->component()))->loadSettings(settings);
            //restore also topology dimension order
         }
      }
   }
   
   //miscellaneous
   
   setCurrentIndex(settings.value("currentIndex",0).toInt());
   
   selectionSyntax = (SelectionSyntax)(settings.value("selectionSyntax",0).toInt());
   whiteForZero = settings.value("whiteForZero",true).toBool();
   if (currentSysTopWidget!=NULL) {
      currentSysTopWidget->updateColors();
   }
   
   if (type==SYSTEMTAB){
      LineType lineType;
      lineType = (LineType)(settings.value("lineType",0).toInt());
      if (lineType==BLACK_LINES) blackLines();
      else if (lineType==GRAY_LINES) grayLines();
      else if (lineType==WHITE_LINES) whiteLines();
      else noLines();
   }
   
   settings.endGroup();
   
   updateValueWidget();
   displayItems();
   
   return result;
}



/************ miscellaneous **************/

//return the list of external metric items
int TabWidget::numExternalMetricItems(){
   return externalMetricItems.size();
}

//return the minimal width necessary to display all informations
int TabWidget::getOptimalWidth(){
    ScrollArea * as_scroll_area = dynamic_cast<ScrollArea*>(widget( currentIndex() ) );
   int w = 0;
    if ( as_scroll_area != NULL)
	w = ( ( ScrollArea* )( widget( currentIndex() ) ) )->getOptimalWidth();
    else
	w = ( ( SystemTopologyContainer* )( widget( currentIndex() ) ) )->getOptimalWidth();
  
   w += width() - ((ScrollArea*)(widget(currentIndex())))->width();
   if ( w < minimumWidth()) w = minimumWidth();
   return w;
}

/**
  enables box plot tab, if system tab is not first tab
  */
void TabWidget::enableSystemBoxPlot(bool first) {
   if ((systemBoxWidget) && (type==SYSTEMTAB)) {
      setTabEnabled(systemBoxPlotIndex, !first);
   }
}

/**
  if window is resized, the current system topology widget will also be resized
  if the drawing has been resized manually to show more details, it will not be resized automatically
  */
void TabWidget::resizeEvent ( QResizeEvent * event ) {
   QTabWidget::resizeEvent(event);

   if ((currentSysTopWidget!=NULL) && (currentIndex() > 0) && (currentIndex() != systemBoxPlotIndex)) { // system topology tab
      currentSysTopWidget->reset(false); // only rescale
   }
}



