Logo Search packages:      
Sourcecode: scidavis version File versions  Download package

future_Table.cpp

/***************************************************************************
    File                 : Table.cpp
    Project              : SciDAVis
    Description          : Aspect providing a spreadsheet table with column logic
    --------------------------------------------------------------------
    Copyright            : (C) 2006-2009 Tilman Benkert (thzs*gmx.net)
    Copyright            : (C) 2006-2009 Knut Franke (knut.franke*gmx.de)
    Copyright            : (C) 2006-2007 Ion Vasilief (ion_vasilief*yahoo.fr)
                           (replace * with @ in the email addresses) 

 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *  This program is free software; you can redistribute it and/or modify   *
 *  it under the terms of the GNU General Public License as published by   *
 *  the Free Software Foundation; either version 2 of the License, or      *
 *  (at your option) any later version.                                    *
 *                                                                         *
 *  This program is distributed in the hope that it will be useful,        *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 *  GNU General Public License for more details.                           *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the Free Software           *
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
 *   Boston, MA  02110-1301  USA                                           *
 *                                                                         *
 ***************************************************************************/
#include "table/future_Table.h"
#include "core/Project.h"
#include "lib/ActionManager.h"

#include <QItemSelectionModel>
#include <QTime>
#include <QtGlobal>
#include <QHBoxLayout>
#include <QShortcut>
#include <QApplication>
#include <QContextMenuEvent>
#include <climits> // for RAND_MAX
#include <QMenu>
#include <QItemSelection>
#include <QModelIndex>
#include <QModelIndexList>
#include <QInputDialog>
#include <QMapIterator>
#include <QDialog>
#include <QMenuBar>
#include <QClipboard>
#include <QToolBar>
#include <QtDebug>

#include "core/AbstractScript.h"
#include "core/AspectPrivate.h"
#include "table/TableModel.h"
#include "table/TableView.h"
#include "table/tablecommands.h"
#include "table/future_SortDialog.h"
#include "core/column/Column.h"
#include "core/AbstractFilter.h"
#include "core/datatypes/String2DoubleFilter.h"
#include "core/datatypes/Double2StringFilter.h"
#include "core/datatypes/DateTime2StringFilter.h"
#include "core/datatypes/String2DayOfWeekFilter.h"
#include "core/datatypes/String2MonthFilter.h"
#include "core/datatypes/Double2DateTimeFilter.h"
#include "core/datatypes/Double2MonthFilter.h"
#include "core/datatypes/Double2DayOfWeekFilter.h"
#include "core/datatypes/String2DateTimeFilter.h"
#include "core/datatypes/DateTime2DoubleFilter.h"
#include "core/datatypes/SimpleCopyThroughFilter.h"

#include "ui_DimensionsDialog.h"

#define WAIT_CURSOR QApplication::setOverrideCursor(QCursor(Qt::WaitCursor))
#define RESET_CURSOR QApplication::restoreOverrideCursor()

namespace future
{

bool Table::d_default_comment_visibility = false;
int Table::default_column_width = 120;

// TODO: move all selection related stuff to the primary view ?

#ifndef LEGACY_CODE_0_2_x
Table::Table(AbstractScriptingEngine *engine, int rows, int columns, const QString& name)
      : AbstractPart(name), d_plot_menu(0), scripted(engine)
#else
Table::Table(void *engine, int rows, int columns, const QString& name)
      : AbstractPart(name), d_plot_menu(0)
#endif
{
      d_table_private = new Private(this);

      // set initial number of rows and columns
      QList<Column*> cols;
      for(int i=0; i<columns; i++)
      {
            Column * new_col = new Column(QString::number(i+1), SciDAVis::Numeric);
            new_col->setPlotDesignation(i == 0 ? SciDAVis::X : SciDAVis::Y);
            cols << new_col;
      }
      appendColumns(cols);
      setRowCount(rows);

      d_view = NULL; 
      createActions();
      connectActions();
}

#ifndef LEGACY_CODE_0_2_x
00115 Table::Table()
      : AbstractPart("temp"), scripted(0)
#else
Table::Table()
      : AbstractPart("temp")
#endif
{
      d_view = NULL;
      createActions();
}

Table::~Table()
{
      delete d_view;
}

00131 Column * Table::column(int index) const
{ 
      return d_table_private->column(index); 
}

00136 Column * Table::column(const QString & name) const
{ 
      // TODO for 0.3.0: remove all name concatenation with _ in favor of Column * pointers
      int pos=name.find("_",false);
      QString label=name.right(name.length()-pos-1);
      for (int i=0; i<columnCount(); i++)
      {
            Column *col = d_table_private->column(i);
            if (col->name() == name || col->name() == label)
                  return col;
      }

      return NULL;
}

void Table::setView(TableView * view)
{
      d_view = view;
      addActionsToView();
      d_view->showComments(d_default_comment_visibility);
}

00158 QWidget *Table::view()
{
#ifndef LEGACY_CODE_0_2_x
      if (!d_view)
      {
            d_view = new TableView(this); 
            addActionsToView();
            d_view->showComments(d_default_comment_visibility);
      }
#else
      Q_ASSERT(d_view != NULL);
#endif
      return d_view;
}

00173 void Table::insertColumns(int before, QList<Column*> new_cols)
{
      if( new_cols.size() < 1 || before < 0 || before > columnCount()) return;
      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: insert %2 column(s)").arg(name()).arg(new_cols.size()));
      int pos=before;
      foreach(Column* col, new_cols)
            insertChild(col, pos++);
      // remark: the TableInsertColumnsCmd will be created in completeAspectInsertion()
      endMacro();
      RESET_CURSOR;
}

void Table::removeColumns(int first, int count)
{
      if( count < 1 || first < 0 || first+count > columnCount()) return;
      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: remove %2 column(s)").arg(name()).arg(count));
      QList<Column*> cols;
      for(int i=first; i<(first+count); i++)
            cols.append(d_table_private->column(i));
      // remark:  the TableRemoveColumnsCmd will be created in prepareAspectRemoval()
      foreach(Column* col, cols)
            removeChild(col);
      endMacro();
      RESET_CURSOR;
}

void Table::removeColumn(Column * col)
{
      removeColumns(columnIndex(col), 1);
}

void Table::removeRows(int first, int count)
{
      if( count < 1 || first < 0 || first+count > rowCount()) return;
      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: remove %2 row(s)").arg(name()).arg(count));
      int end = d_table_private->columnCount();
      for(int col=0; col<end; col++)
            d_table_private->column(col)->removeRows(first, count);
      exec(new TableSetNumberOfRowsCmd(d_table_private, d_table_private->rowCount()-count));
      endMacro();
      RESET_CURSOR;
}

void Table::insertRows(int before, int count)
{
      if( count < 1 || before < 0 || before > rowCount()) return;
      WAIT_CURSOR;
      int new_row_count = rowCount() + count;
      beginMacro(QObject::tr("%1: insert %2 row(s)").arg(name()).arg(count));
      int end = d_table_private->columnCount();
      for(int col=0; col<end; col++)
            d_table_private->column(col)->insertRows(before, count);
      setRowCount(new_row_count);
      endMacro();
      RESET_CURSOR;
}

00233 void Table::setRowCount(int new_size)
{
      if( (new_size < 0) || (new_size == d_table_private->rowCount()) ) return;
      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: set the number of rows to %2").arg(name()).arg(new_size));
      if (new_size < d_table_private->rowCount())
      {
            int end = d_table_private->columnCount();
            for(int col=0; col<end; col++)
            {     
                  Column *col_ptr = d_table_private->column(col);
                  if (col_ptr->rowCount() > new_size)
                        col_ptr->removeRows(new_size, col_ptr->rowCount() - new_size);
            }
      }
      exec(new TableSetNumberOfRowsCmd(d_table_private, new_size));
      endMacro();
      RESET_CURSOR;
}

00253 int Table::columnCount() const
{
      return d_table_private->columnCount();
}

00258 int Table::rowCount() const
{
      return d_table_private->rowCount();
}

00263 int Table::columnCount(SciDAVis::PlotDesignation pd) const
{
      int count = 0;
      int cols = columnCount();
      for(int i=0; i<cols; i++)
            if(column(i)->plotDesignation() == pd) count++;
      
      return count;
}

00273 void Table::setColumnCount(int new_size)
{
      int old_size = columnCount();
      if ( old_size == new_size || new_size < 0 )
            return;

      WAIT_CURSOR;
      if (new_size < old_size)
            removeColumns(new_size, old_size-new_size);
      else
      {
            QList<Column*> cols;
            for(int i=0; i<new_size-old_size; i++)
            {
                  Column * new_col = new Column(QString::number(i+1), SciDAVis::Numeric);
                  new_col->setPlotDesignation(SciDAVis::Y);
                  cols << new_col;
            }
            appendColumns(cols);
      }
      RESET_CURSOR;
}
            
int Table::columnIndex(const Column * col) const 
{ 
      return d_table_private->columnIndex(col); 
}

00301 void Table::clear()
{
      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: clear").arg(name()));
      int cols = columnCount();
      for(int i=0; i<cols; i++)
            column(i)->clear();
      endMacro();
      RESET_CURSOR;
}

#ifndef LEGACY_CODE_0_2_x
00313 void Table::clearMasks()
{
      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: clear all masks").arg(name()));
      int cols = columnCount();
      for(int i=0; i<cols; i++)
            column(i)->clearMasks();
      endMacro();
      RESET_CURSOR;
}
#endif

00325 void Table::addColumn()
{
      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: add column").arg(name()));
      setColumnCount(columnCount()+1);
      endMacro();
      RESET_CURSOR;
}

00334 void Table::addColumns()
{
      if (!d_view) return;
      WAIT_CURSOR;
      int count = d_view->selectedColumnCount(false);
      beginMacro(QObject::tr("%1: add %2 column(s)").arg(name()).arg(count));
      setColumnCount(columnCount() + count);
      endMacro();
      RESET_CURSOR;
}

void Table::cutSelection()
{
      if (!d_view) return;
      int first = d_view->firstSelectedRow();
      if( first < 0 ) return;

      WAIT_CURSOR;
      beginMacro(tr("%1: cut selected cell(s)").arg(name()));
      copySelection();
      clearSelectedCells();
      endMacro();
      RESET_CURSOR;
}

void Table::copySelection()
{
      if (!d_view) return;
      int first_col = d_view->firstSelectedColumn(false);
      if(first_col == -1) return;
      int last_col = d_view->lastSelectedColumn(false);
      if(last_col == -2) return;
      int first_row = d_view->firstSelectedRow(false);
      if(first_row == -1)     return;
      int last_row = d_view->lastSelectedRow(false);
      if(last_row == -2) return;
      int cols = last_col - first_col +1;
      int rows = last_row - first_row +1;
      
      WAIT_CURSOR;
      QString output_str;

      for(int r=0; r<rows; r++)
      {
            for(int c=0; c<cols; c++)
            {     
                  Column *col_ptr = column(first_col + c);
                  if(d_view->isCellSelected(first_row + r, first_col + c))
                  {
                        if (d_view->formulaModeActive())
                        {
                              output_str += col_ptr->formula(first_row + r);
                        }
                        else if (col_ptr->dataType() == SciDAVis::TypeDouble)
                        {
                              Double2StringFilter * out_fltr = static_cast<Double2StringFilter *>(col_ptr->outputFilter());
                              output_str += QLocale().toString(col_ptr->valueAt(first_row + r), 
                                          out_fltr->numericFormat(), 16); // copy with max. precision
                        }
                        else
                        {
                              output_str += text(first_row + r, first_col + c);
                        }
                  }
                  if(c < cols-1)
                        output_str += "\t";
            }
            if(r < rows-1)
                  output_str += "\n";
      }
      QApplication::clipboard()->setText(output_str);
      RESET_CURSOR;
}

void Table::pasteIntoSelection()
{
      if (!d_view) return;
      if(columnCount() < 1 || rowCount() < 1) return;

      WAIT_CURSOR;
      beginMacro(tr("%1: paste from clipboard").arg(name()));
      const QMimeData * mime_data = QApplication::clipboard()->mimeData();

      int first_col = d_view->firstSelectedColumn(false);
      int last_col = d_view->lastSelectedColumn(false);
      int first_row = d_view->firstSelectedRow(false);
      int last_row = d_view->lastSelectedRow(false);
      int input_row_count = 0;
      int input_col_count = 0;
      int rows, cols;

      if(mime_data->hasFormat("text/plain"))
      {
            QString input_str = QString(mime_data->data("text/plain")).trimmed();
            QList< QStringList > cell_texts;
            QStringList input_rows(input_str.split("\n"));
            input_row_count = input_rows.count();
            input_col_count = 0;
            for(int i=0; i<input_row_count; i++)
            {
                  cell_texts.append(input_rows.at(i).trimmed().split(QRegExp("\\s+")));
                  if(cell_texts.at(i).count() > input_col_count) input_col_count = cell_texts.at(i).count();
            }

            if( (first_col == -1 || first_row == -1) ||
                  (last_row == first_row && last_col == first_col) )
            // if the is no selection or only one cell selected, the
            // selection will be expanded to the needed size from the current cell
            {
                  int current_row, current_col;
                  d_view->getCurrentCell(&current_row, &current_col);
                  if(current_row == -1) current_row = 0;
                  if(current_col == -1) current_col = 0;
                  d_view->setCellSelected(current_row, current_col);
                  first_col = current_col;
                  first_row = current_row;
                  last_row = first_row + input_row_count -1;
                  last_col = first_col + input_col_count -1;
                  // resize the table if necessary
                  if(last_col >= columnCount())
                  {
                        QList<Column*> cols;
                        for(int i=0; i<last_col+1-columnCount(); i++)
                        {
                              Column * new_col = new Column(QString::number(i+1), SciDAVis::Text);
                              new_col->setPlotDesignation(SciDAVis::Y);
                              cols << new_col;
                        }
                        appendColumns(cols);
                  }
                  if(last_row >= rowCount())
                        appendRows(last_row+1-rowCount());
                  // select the rectangle to be pasted in
                  d_view->setCellsSelected(first_row, first_col, last_row, last_col);
            }

            rows = last_row - first_row + 1;
            cols = last_col - first_col + 1;
            for(int r=0; r<rows && r<input_row_count; r++)
            {
                  for(int c=0; c<cols && c<input_col_count; c++)
                  {
                        if(d_view->isCellSelected(first_row + r, first_col + c) && (c < cell_texts.at(r).count()) )
                        {
                              Column * col_ptr = d_table_private->column(first_col + c);
                              if (d_view->formulaModeActive())
                              {
                                    col_ptr->setFormula(first_row + r, cell_texts.at(r).at(c));  
                              }
                              else
                                    col_ptr->asStringColumn()->setTextAt(first_row+r, cell_texts.at(r).at(c));
                        }
                  }
            }
      }
      endMacro();
      RESET_CURSOR;
}

#ifndef LEGACY_CODE_0_2_x
void Table::maskSelection()
{
      if (!d_view) return;
      int first = d_view->firstSelectedRow();
      int last = d_view->lastSelectedRow();
      if( first < 0 ) return;

      WAIT_CURSOR;
      beginMacro(tr("%1: mask selected cell(s)").arg(name()));
      QList<Column*> list = d_view->selectedColumns();
      foreach(Column * col_ptr, list)
      {
            int col = columnIndex(col_ptr);
            for(int row=first; row<=last; row++)
                  if(d_view->isCellSelected(row, col)) col_ptr->setMasked(row);  
      }
      endMacro();
      RESET_CURSOR;
}

void Table::unmaskSelection()
{
      if (!d_view) return;
      int first = d_view->firstSelectedRow();
      int last = d_view->lastSelectedRow();
      if( first < 0 ) return;

      WAIT_CURSOR;
      beginMacro(tr("%1: unmask selected cell(s)").arg(name()));
      QList<Column*> list = d_view->selectedColumns();
      foreach(Column * col_ptr, list)
      {
            int col = columnIndex(col_ptr);
            for(int row=first; row<=last; row++)
                  if(d_view->isCellSelected(row, col)) col_ptr->setMasked(row, false);  
      }
      endMacro();
      RESET_CURSOR;
}
#endif

void Table::setFormulaForSelection()
{
      if (!d_view) return;
      d_view->showControlFormulaTab();
}

void Table::recalculateSelectedCells()
{
      if (!d_view) return;
#ifdef LEGACY_CODE_0_2_x
      WAIT_CURSOR;
      beginMacro(tr("%1: apply formula to selection").arg(name()));
      emit recalculate();
      endMacro();
      RESET_CURSOR;
#endif
}

void Table::fillSelectedCellsWithRowNumbers()
{
      if (!d_view) return;
      if(d_view->selectedColumnCount() < 1) return;
      int first = d_view->firstSelectedRow();
      int last = d_view->lastSelectedRow();
      if( first < 0 ) return;
      
      WAIT_CURSOR;
      beginMacro(tr("%1: fill cells with row numbers").arg(name()));
      foreach(Column *col_ptr, d_view->selectedColumns()) {
            int col = columnIndex(col_ptr);
            switch (col_ptr->columnMode()) {
                  case SciDAVis::Numeric:
                        {
                              QVector<double> results(last-first+1);
                              for (int row=first; row<=last; row++)
                                    if(d_view->isCellSelected(row, col)) 
                                          results[row-first] = row+1;
                                    else
                                          results[row-first] = col_ptr->valueAt(row);
                              col_ptr->replaceValues(first, results);
                              break;
                        }
                  case SciDAVis::Text:
                        {
                              QStringList results;
                              for (int row=first; row<=last; row++)
                                    if (d_view->isCellSelected(row, col))
                                          results << QString::number(row+1);
                                    else
                                          results << col_ptr->textAt(row);
                              col_ptr->replaceTexts(first, results);
                              break;
                        }
            }
      }
      endMacro();
      RESET_CURSOR;
}

void Table::fillSelectedCellsWithRandomNumbers()
{
      if (!d_view) return;
      if(d_view->selectedColumnCount() < 1) return;
      int first = d_view->firstSelectedRow();
      int last = d_view->lastSelectedRow();
      if( first < 0 ) return;
      
      WAIT_CURSOR;
      beginMacro(tr("%1: fill cells with random values").arg(name()));
      qsrand(QTime::currentTime().msec());
      foreach(Column *col_ptr, d_view->selectedColumns()) {
            int col = columnIndex(col_ptr);
            switch (col_ptr->columnMode()) {
                  case SciDAVis::Numeric:
                        {
                              QVector<double> results(last-first+1);
                              for (int row=first; row<=last; row++)
                                    if (d_view->isCellSelected(row, col))
                                          results[row-first] = double(qrand())/double(RAND_MAX);
                                    else
                                          results[row-first] = col_ptr->valueAt(row);
                              col_ptr->replaceValues(first, results);
                              break;
                        }
                  case SciDAVis::Text:
                        {
                              QStringList results;
                              for (int row=first; row<=last; row++)
                                    if (d_view->isCellSelected(row, col))
                                          results << QString::number(double(qrand())/double(RAND_MAX));
                                    else
                                          results << col_ptr->textAt(row);
                              col_ptr->replaceTexts(first, results);
                              break;
                        }
                  case SciDAVis::DateTime:
                  case SciDAVis::Month:
                  case SciDAVis::Day:
                        {
                              QList<QDateTime> results;
                              QDate earliestDate(1,1,1);
                              QDate latestDate(2999,12,31);
                              QTime midnight(0,0,0,0);
                              for (int row=first; row<=last; row++)
                                    if (d_view->isCellSelected(row, col))
                                          results << QDateTime(
                                                      earliestDate.addDays(((double)qrand())*((double)earliestDate.daysTo(latestDate))/((double)RAND_MAX)),
                                                      midnight.addMSecs(((qint64)qrand())*1000*60*60*24/RAND_MAX));
                                    else
                                          results << col_ptr->dateTimeAt(row);
                              col_ptr->replaceDateTimes(first, results);
                              break;
                        }
            }
      }
      endMacro();
      RESET_CURSOR;
}

00654 void Table::sortTable()
{
      QList<Column*> cols;
      
      for(int i=0; i<columnCount(); i++)
            cols.append(column(i));

      sortDialog(cols);
}

00664 void Table::insertEmptyColumns()
{
      if (!d_view) return;
      int first = d_view->firstSelectedColumn();
      int last = d_view->lastSelectedColumn();
      if( first < 0 ) return;
      int count, current = first;
      QList<Column*> cols;

      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: insert empty column(s)").arg(name()));
      while( current <= last )
      {
            current = first+1;
            while( current <= last && d_view->isColumnSelected(current) ) current++;
            count = current-first;
            for(int i=0; i<count; i++)
            {
                  Column * new_col = new Column(QString::number(i+1), SciDAVis::Numeric);
                  new_col->setPlotDesignation(SciDAVis::Y);
                  cols << new_col;
            }
            insertColumns(first, cols);
            cols.clear();
            current += count;
            last += count;
            while( current <= last && !d_view->isColumnSelected(current) ) current++;
            first = current;
      }
      endMacro();
      RESET_CURSOR;
}

void Table::removeSelectedColumns()
{
      if (!d_view) return;
      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: remove selected column(s)").arg(name()));

      QList< Column* > list = d_view->selectedColumns();
      foreach(Column* ptr, list)
            removeColumn(ptr);

      endMacro();
      RESET_CURSOR;
}

void Table::clearSelectedColumns()
{
      if (!d_view) return;
      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: clear selected column(s)").arg(name()));

      QList< Column* > list = d_view->selectedColumns();
      if (d_view->formulaModeActive())
      {
            foreach(Column* ptr, list)
                  ptr->clearFormulas();
      }
      else
      {
            foreach(Column* ptr, list)
                  ptr->clear();
      }

      endMacro();
      RESET_CURSOR;
}

void Table::setSelectionAs(SciDAVis::PlotDesignation pd)
{
      if (!d_view) return;
      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: set plot designation(s)").arg(name()));

      QList< Column* > list = d_view->selectedColumns();
      foreach(Column* ptr, list)
            ptr->setPlotDesignation(pd);

      endMacro();
      RESET_CURSOR;
}

void Table::setSelectedColumnsAsX()
{
      setSelectionAs(SciDAVis::X);
}

void Table::setSelectedColumnsAsY()
{
      setSelectionAs(SciDAVis::Y);
}

void Table::setSelectedColumnsAsZ()
{
      setSelectionAs(SciDAVis::Z);
}

void Table::setSelectedColumnsAsYError()
{
      setSelectionAs(SciDAVis::yErr);
}

void Table::setSelectedColumnsAsXError()
{
      setSelectionAs(SciDAVis::xErr);
}

void Table::setSelectedColumnsAsNone()
{
      setSelectionAs(SciDAVis::noDesignation);
}

void Table::normalizeColumns(QList< Column* > cols)
{
      if (!d_view) return;

      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: normalize column(s)").arg(name()));
      foreach(Column * col, cols)
      {
            if (col->dataType() == SciDAVis::TypeDouble)
            {
                  double max = 0.0;
                  for (int row=0; row<col->rowCount(); row++)
                  {
                        if (col->valueAt(row) > max)
                              max = col->valueAt(row);
                  }
                  if (max != 0.0) // avoid division by zero
                        for (int row=0; row<col->rowCount(); row++)
                              col->setValueAt(row, col->valueAt(row) / max);
            }
      }
      endMacro();
      RESET_CURSOR;
}

void Table::normalizeSelectedColumns()
{
      normalizeColumns(d_view->selectedColumns());
}

void Table::normalizeSelection()
{
      if (!d_view) return;

      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: normalize selection").arg(name()));
      double max = 0.0;
      for (int col=d_view->firstSelectedColumn(); col<=d_view->lastSelectedColumn(); col++)
            if (column(col)->dataType() == SciDAVis::TypeDouble)
                  for (int row=0; row<rowCount(); row++)
                  {
                        if (d_view->isCellSelected(row, col) && column(col)->valueAt(row) > max)
                              max = column(col)->valueAt(row);
                  }

      if (max != 0.0) // avoid division by zero
      {
            for (int col=d_view->firstSelectedColumn(); col<=d_view->lastSelectedColumn(); col++)
                  if (column(col)->dataType() == SciDAVis::TypeDouble)
                        for (int row=0; row<rowCount(); row++)
                        {
                              if (d_view->isCellSelected(row, col))
                                    column(col)->setValueAt(row, column(col)->valueAt(row) / max);
                        }
      }
      endMacro();
      RESET_CURSOR;
}

void Table::sortSelectedColumns()
{
      if (!d_view) return;
      QList< Column* > cols = d_view->selectedColumns();
      sortDialog(cols);
}

void Table::statisticsOnSelectedColumns()
{
#ifdef LEGACY_CODE_0_2_x
      // TODO: this is only an ugly hack for 0.2.0
      emit requestColumnStatistics();
#endif
}

void Table::statisticsOnSelectedRows()
{
#ifdef LEGACY_CODE_0_2_x
      // TODO: this is only an ugly hack for 0.2.0
      emit requestRowStatistics();
#endif
}

00859 void Table::insertEmptyRows()
{
      if (!d_view) return;
      int first = d_view->firstSelectedRow();
      int last = d_view->lastSelectedRow();
      int count, current = first;

      if( first < 0 ) return;

      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: insert empty rows(s)").arg(name()));
      while( current <= last )
      {
            current = first+1;
            while( current <= last && d_view->isRowSelected(current) ) current++;
            count = current-first;
            insertRows(first, count);
            current += count;
            last += count;
            while( current <= last && !d_view->isRowSelected(current) ) current++;
            first = current;
      }
      endMacro();
      RESET_CURSOR;
}

void Table::removeSelectedRows()
{
      if (!d_view) return;

      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: remove selected rows(s)").arg(name()));
      foreach(Interval<int> i, d_view->selectedRows().intervals())
            removeRows(i.start(), i.size());
      endMacro();
      RESET_CURSOR;
}

void Table::clearSelectedRows()
{
      if (!d_view) return;
      int first = d_view->firstSelectedRow();
      int last = d_view->lastSelectedRow();
      if( first < 0 ) return;

      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: clear selected rows(s)").arg(name()));
      QList<Column*> list = d_view->selectedColumns();
      foreach(Column * col_ptr, list)
      {
            if (d_view->formulaModeActive())
                  foreach(Interval<int> i, d_view->selectedRows().intervals())
                        col_ptr->setFormula(i, "");
            else
                  foreach(Interval<int> i, d_view->selectedRows().intervals())
                        if (i.end() == col_ptr->rowCount()-1)
                              col_ptr->removeRows(i.start(), i.size());
                        else {
                              QStringList empties;
                              for (int j=0; j<i.size(); j++)
                                    empties << QString();
                              col_ptr->asStringColumn()->replaceTexts(i.start(), empties);
                        }
      }
      endMacro();
      RESET_CURSOR;
}

void Table::editTypeAndFormatOfSelectedColumns()
{
      if (!d_view) return;
      d_view->showControlTypeTab();
}

void Table::editDescriptionOfCurrentColumn()
{
      if (!d_view) return;
      d_view->showControlDescriptionTab();
}

00939 void Table::addRows()
{
      if (!d_view) return;
      WAIT_CURSOR;
      int count = d_view->selectedRowCount(false);
      beginMacro(QObject::tr("%1: add %2 rows(s)").arg(name()).arg(count));
      exec(new TableSetNumberOfRowsCmd(d_table_private, rowCount() + count));
      endMacro();
      RESET_CURSOR;
}

void Table::clearSelectedCells()
{
      if (!d_view) return;
      int first = d_view->firstSelectedRow();
      int last = d_view->lastSelectedRow();
      if( first < 0 ) return;

      WAIT_CURSOR;
      beginMacro(tr("%1: clear selected cell(s)").arg(name()));
      QList<Column*> list = d_view->selectedColumns();
      foreach(Column * col_ptr, list)
      {
            if (d_view->formulaModeActive())
            {
                  int col = columnIndex(col_ptr);
                  for(int row=last; row>=first; row--)
                        if(d_view->isCellSelected(row, col))
                        {
                              col_ptr->setFormula(row, "");  
                        }
            }
            else
            {
                  int col = columnIndex(col_ptr);
                  for(int row=last; row>=first; row--)
                        if(d_view->isCellSelected(row, col))
                        {
                              if(row == (col_ptr->rowCount()-1) )
                                    col_ptr->removeRows(row,1);
                              else if(row < col_ptr->rowCount())
                                    col_ptr->asStringColumn()->setTextAt(row, "");
                        }
            }
      }
      endMacro();
      RESET_CURSOR;
}

00988 bool Table::fillProjectMenu(QMenu * menu)
{
      menu->setTitle(tr("&Table"));

      QMenu * submenu = new QMenu(tr("S&et Column(s) As"));
      submenu->addAction(action_set_as_x);
      submenu->addAction(action_set_as_y);
      submenu->addAction(action_set_as_z);
      submenu->addSeparator();
      submenu->addAction(action_set_as_xerr);
      submenu->addAction(action_set_as_yerr);
      submenu->addSeparator();
      submenu->addAction(action_set_as_none);
      menu->addMenu(submenu);
      menu->addSeparator();

      submenu = new QMenu(tr("Fi&ll Selection with"));
      submenu->addAction(action_fill_row_numbers);
      submenu->addAction(action_fill_random);
      menu->addMenu(submenu);
      menu->addSeparator();

      connect(menu, SIGNAL(aboutToShow()), this, SLOT(adjustActionNames()));
      menu->addAction(action_toggle_comments);
      menu->addAction(action_toggle_tabbar);
      menu->addAction(action_formula_mode);
      menu->addAction(action_edit_description);
      menu->addAction(action_type_format);
      menu->addSeparator();
      menu->addAction(action_clear_table);
#ifndef LEGACY_CODE_0_2_x
      menu->addAction(action_clear_masks);
#endif
      menu->addAction(action_sort_table);
      menu->addSeparator();
      menu->addAction(action_set_formula);
      menu->addAction(action_recalculate);
      menu->addSeparator();
      menu->addAction(action_add_column);
      menu->addAction(action_dimensions_dialog);
      menu->addSeparator();
      menu->addAction(action_go_to_cell);

      return true;

      // TODO:
      // Convert to Matrix
      // Export 
}
            
01038 bool Table::fillProjectToolBar(QToolBar * bar)
{
      bar->addAction(action_dimensions_dialog);
      bar->addAction(action_add_column);
      bar->addAction(action_statistics_columns);
      bar->addAction(action_statistics_rows);

      return true;
}

01048 QMenu *Table::createContextMenu() const
{
      QMenu *menu = AbstractPart::createContextMenu();
      Q_ASSERT(menu);
      menu->addSeparator();
      
      // TODO
      // Export to ASCII
      // Print --> maybe should go to AbstractPart::createContextMenu()
      // ----
      // Rename --> AbstractAspect::createContextMenu(); maybe call this "Properties" and include changing comment/caption spec
      // Duplicate --> AbstractPart::createContextMenu()
      // Hide/Show --> Do we need hiding of views (in addition to minimizing)? How do we avoid confusion with hiding of Aspects?
      // Activate ?
      // Resize --> AbstractPart::createContextMenu()
      
      return menu;
}
            

void Table::createActions()
{
      QIcon * icon_temp;

      // selection related actions
      action_cut_selection = new QAction(QIcon(QPixmap(":/cut.xpm")), tr("Cu&t"), this);
      actionManager()->addAction(action_cut_selection, "cut_selection");

      action_copy_selection = new QAction(QIcon(QPixmap(":/copy.xpm")), tr("&Copy"), this);
      actionManager()->addAction(action_copy_selection, "copy_selection");

      action_paste_into_selection = new QAction(QIcon(QPixmap(":/paste.xpm")), tr("Past&e"), this);
      actionManager()->addAction(action_paste_into_selection, "paste_into_selection"); 

#ifndef LEGACY_CODE_0_2_x
      action_mask_selection = new QAction(QIcon(QPixmap(":/mask.xpm")), tr("&Mask","mask selection"), this);
      actionManager()->addAction(action_mask_selection, "mask_selection"); 

      action_unmask_selection = new QAction(QIcon(QPixmap(":/unmask.xpm")), tr("&Unmask","unmask selection"), this);
      actionManager()->addAction(action_unmask_selection, "unmask_selection"); 
#endif

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/fx.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/fx.png"));
      action_set_formula = new QAction(*icon_temp, tr("Assign &Formula"), this);
      action_set_formula->setShortcut(tr("Alt+Q"));
      actionManager()->addAction(action_set_formula, "set_formula"); 
      delete icon_temp;

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/clear.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/clear.png"));
      action_clear_selection = new QAction(*icon_temp, tr("Clea&r","clear selection"), this);
      actionManager()->addAction(action_clear_selection, "clear_selection"); 
      delete icon_temp;

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/recalculate.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/recalculate.png"));
      action_recalculate = new QAction(*icon_temp, tr("Recalculate"), this);
      action_recalculate->setShortcut(tr("Ctrl+Return"));
      actionManager()->addAction(action_recalculate, "recalculate"); 
      delete icon_temp;

      action_fill_row_numbers = new QAction(QIcon(QPixmap(":/rowNumbers.xpm")), tr("Row Numbers"), this);
      actionManager()->addAction(action_fill_row_numbers, "fill_row_numbers"); 

      action_fill_random = new QAction(QIcon(QPixmap(":/randomNumbers.xpm")), tr("Random Values"), this);
      actionManager()->addAction(action_fill_random, "fill_random"); 
      
      //table related actions
      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/table_header.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/table_header.png"));
      action_toggle_comments = new QAction(*icon_temp, QString("Show/Hide comments"), this); // show/hide column comments
      actionManager()->addAction(action_toggle_comments, "toggle_comments"); 
      delete icon_temp;

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/table_options.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/table_options.png"));
      action_toggle_tabbar = new QAction(*icon_temp, QString("Show/Hide Controls"), this); // show/hide control tabs
      action_toggle_tabbar->setShortcut(tr("F12"));
      actionManager()->addAction(action_toggle_tabbar, "toggle_tabbar"); 
      delete icon_temp;

      action_formula_mode = new QAction(tr("Formula Edit Mode"), this);
      action_formula_mode->setCheckable(true);
      actionManager()->addAction(action_formula_mode, "formula_mode"); 

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/select_all.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/select_all.png"));
      action_select_all = new QAction(*icon_temp, tr("Select All"), this);
      actionManager()->addAction(action_select_all, "select_all"); 
      delete icon_temp;

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/add_column.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/add_column.png"));
      action_add_column = new QAction(*icon_temp, tr("&Add Column"), this);
      action_add_column->setToolTip(tr("append a new column to the table"));
      actionManager()->addAction(action_add_column, "add_column"); 
      delete icon_temp;

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/clear_table.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/clear_table.png"));
      action_clear_table = new QAction(*icon_temp, tr("Clear Table"), this);
      actionManager()->addAction(action_clear_table, "clear_table"); 
      delete icon_temp;

#ifndef LEGACY_CODE_0_2_x
      action_clear_masks = new QAction(QIcon(QPixmap(":/unmask.xpm")), tr("Clear Masks"), this);
      actionManager()->addAction(action_clear_masks, "clear_masks"); 
#endif

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/sort.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/sort.png"));
      action_sort_table = new QAction(*icon_temp, tr("&Sort Table"), this);
      actionManager()->addAction(action_sort_table, "sort_table"); 
      delete icon_temp;

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/go_to_cell.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/go_to_cell.png"));
      action_go_to_cell = new QAction(*icon_temp, tr("&Go to Cell"), this);
      action_go_to_cell->setShortcut(tr("Ctrl+Alt+G"));
      actionManager()->addAction(action_go_to_cell, "go_to_cell"); 
      delete icon_temp;

      action_dimensions_dialog = new QAction(QIcon(QPixmap(":/resize.xpm")), tr("&Dimensions", "table size"), this);
      action_dimensions_dialog->setToolTip(tr("change the table size"));
      actionManager()->addAction(action_dimensions_dialog, "dimensions_dialog"); 

      // column related actions
      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/insert_column.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/insert_column.png"));
      action_insert_columns = new QAction(*icon_temp, tr("&Insert Empty Columns"), this);
      actionManager()->addAction(action_insert_columns, "insert_columns"); 
      delete icon_temp;

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/remove_column.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/remove_column.png"));
      action_remove_columns = new QAction(*icon_temp, tr("Remo&ve Columns"), this);
      actionManager()->addAction(action_remove_columns, "remove_columns"); 
      delete icon_temp;

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/clear_column.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/clear_column.png"));
      action_clear_columns = new QAction(*icon_temp, tr("Clea&r Columns"), this);
      actionManager()->addAction(action_clear_columns, "clear_columns"); 
      delete icon_temp;

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/add_columns.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/add_columns.png"));
      action_add_columns = new QAction(*icon_temp, tr("&Add Columns"), this);
      actionManager()->addAction(action_add_columns, "add_columns"); 
      delete icon_temp;

      action_set_as_x = new QAction(QIcon(QPixmap()), tr("X","plot designation"), this);
      actionManager()->addAction(action_set_as_x, "set_as_x"); 

      action_set_as_y = new QAction(QIcon(QPixmap()), tr("Y","plot designation"), this);
      actionManager()->addAction(action_set_as_y, "set_as_y"); 

      action_set_as_z = new QAction(QIcon(QPixmap()), tr("Z","plot designation"), this);
      actionManager()->addAction(action_set_as_z, "set_as_z"); 

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/x_error.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/x_error.png"));
      action_set_as_xerr = new QAction(*icon_temp, tr("X Error","plot designation"), this);
      actionManager()->addAction(action_set_as_xerr, "set_as_xerr"); 
      delete icon_temp;

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/y_error.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/y_error.png"));
      action_set_as_yerr = new QAction(*icon_temp, tr("Y Error","plot designation"), this);
      actionManager()->addAction(action_set_as_yerr, "set_as_yerr"); 
      delete icon_temp;

      action_set_as_none = new QAction(QIcon(QPixmap()), tr("None","plot designation"), this);
      actionManager()->addAction(action_set_as_none, "set_as_none"); 

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/normalize.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/normalize.png"));
      action_normalize_columns = new QAction(*icon_temp, tr("&Normalize Columns"), this);
      actionManager()->addAction(action_normalize_columns, "normalize_columns"); 
      delete icon_temp;

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/normalize.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/normalize.png"));
      action_normalize_selection = new QAction(*icon_temp, tr("&Normalize Selection"), this);
      actionManager()->addAction(action_normalize_selection, "normalize_selection"); 
      delete icon_temp;

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/sort.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/sort.png"));
      action_sort_columns = new QAction(*icon_temp, tr("&Sort Columns"), this);
      actionManager()->addAction(action_sort_columns, "sort_columns"); 
      delete icon_temp;

      action_statistics_columns = new QAction(QIcon(QPixmap(":/col_stat.xpm")), tr("Column Statisti&cs"), this);
      action_statistics_columns->setToolTip(tr("statistics on columns"));
      actionManager()->addAction(action_statistics_columns, "statistics_columns"); 

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/column_format_type.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/column_format_type.png"));
      action_type_format = new QAction(*icon_temp, tr("Change &Type && Format"), this);
      action_type_format->setShortcut(tr("Ctrl+Alt+O"));
      actionManager()->addAction(action_type_format, "type_format"); 
      delete icon_temp;

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/column_description.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/column_description.png"));
      action_edit_description = new QAction(*icon_temp, tr("Edit Column &Description"), this);
      actionManager()->addAction(action_edit_description, "edit_description"); 
      delete icon_temp;

      // row related actions
      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/insert_row.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/insert_row.png"));
      action_insert_rows = new QAction(*icon_temp ,tr("&Insert Empty Rows"), this);
      actionManager()->addAction(action_insert_rows, "insert_rows"); 
      delete icon_temp;

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/remove_row.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/remove_row.png"));
      action_remove_rows = new QAction(*icon_temp, tr("Remo&ve Rows"), this);
      actionManager()->addAction(action_remove_rows, "remove_rows"); 
      delete icon_temp;

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/clear_row.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/clear_row.png"));
      action_clear_rows = new QAction(*icon_temp, tr("Clea&r Rows"), this);
      actionManager()->addAction(action_clear_rows, "clear_rows"); 
      delete icon_temp;

      icon_temp = new QIcon();
      icon_temp->addPixmap(QPixmap(":/16x16/add_rows.png"));
      icon_temp->addPixmap(QPixmap(":/32x32/add_rows.png"));
      action_add_rows = new QAction(*icon_temp, tr("&Add Rows"), this);
      actionManager()->addAction(action_add_rows, "add_rows"); 
      delete icon_temp;

      action_statistics_rows = new QAction(QIcon(QPixmap(":/stat_rows.xpm")), tr("Row Statisti&cs"), this);
      action_statistics_rows->setToolTip(tr("statistics on rows"));
      actionManager()->addAction(action_statistics_rows, "statistics_rows"); 
}

void Table::connectActions()
{
      connect(action_cut_selection, SIGNAL(triggered()), this, SLOT(cutSelection()));
      connect(action_copy_selection, SIGNAL(triggered()), this, SLOT(copySelection()));
      connect(action_paste_into_selection, SIGNAL(triggered()), this, SLOT(pasteIntoSelection()));
#ifndef LEGACY_CODE_0_2_x
      connect(action_mask_selection, SIGNAL(triggered()), this, SLOT(maskSelection()));
      connect(action_unmask_selection, SIGNAL(triggered()), this, SLOT(unmaskSelection()));
#endif
      connect(action_set_formula, SIGNAL(triggered()), this, SLOT(setFormulaForSelection()));
      connect(action_clear_selection, SIGNAL(triggered()), this, SLOT(clearSelectedCells()));
      connect(action_recalculate, SIGNAL(triggered()), this, SLOT(recalculateSelectedCells()));
      connect(action_fill_row_numbers, SIGNAL(triggered()), this, SLOT(fillSelectedCellsWithRowNumbers()));
      connect(action_fill_random, SIGNAL(triggered()), this, SLOT(fillSelectedCellsWithRandomNumbers()));
      connect(action_select_all, SIGNAL(triggered()), this, SLOT(selectAll()));
      connect(action_add_column, SIGNAL(triggered()), this, SLOT(addColumn()));
      connect(action_clear_table, SIGNAL(triggered()), this, SLOT(clear()));
#ifndef LEGACY_CODE_0_2_x
      connect(action_clear_masks, SIGNAL(triggered()), this, SLOT(clearMasks()));
#endif
      connect(action_sort_table, SIGNAL(triggered()), this, SLOT(sortTable()));
      connect(action_go_to_cell, SIGNAL(triggered()), this, SLOT(goToCell()));
      connect(action_dimensions_dialog, SIGNAL(triggered()), this, SLOT(dimensionsDialog()));
      connect(action_insert_columns, SIGNAL(triggered()), this, SLOT(insertEmptyColumns()));
      connect(action_remove_columns, SIGNAL(triggered()), this, SLOT(removeSelectedColumns()));
      connect(action_clear_columns, SIGNAL(triggered()), this, SLOT(clearSelectedColumns()));
      connect(action_add_columns, SIGNAL(triggered()), this, SLOT(addColumns()));
      connect(action_set_as_x, SIGNAL(triggered()), this, SLOT(setSelectedColumnsAsX()));
      connect(action_set_as_y, SIGNAL(triggered()), this, SLOT(setSelectedColumnsAsY()));
      connect(action_set_as_z, SIGNAL(triggered()), this, SLOT(setSelectedColumnsAsZ()));
      connect(action_set_as_xerr, SIGNAL(triggered()), this, SLOT(setSelectedColumnsAsXError()));
      connect(action_set_as_yerr, SIGNAL(triggered()), this, SLOT(setSelectedColumnsAsYError()));
      connect(action_set_as_none, SIGNAL(triggered()), this, SLOT(setSelectedColumnsAsNone()));
      connect(action_normalize_columns, SIGNAL(triggered()), this, SLOT(normalizeSelectedColumns()));
      connect(action_normalize_selection, SIGNAL(triggered()), this, SLOT(normalizeSelection()));
      connect(action_sort_columns, SIGNAL(triggered()), this, SLOT(sortSelectedColumns()));
      connect(action_statistics_columns, SIGNAL(triggered()), this, SLOT(statisticsOnSelectedColumns()));
      connect(action_type_format, SIGNAL(triggered()), this, SLOT(editTypeAndFormatOfSelectedColumns()));
      connect(action_edit_description, SIGNAL(triggered()), this, SLOT(editDescriptionOfCurrentColumn()));
      connect(action_insert_rows, SIGNAL(triggered()), this, SLOT(insertEmptyRows()));
      connect(action_remove_rows, SIGNAL(triggered()), this, SLOT(removeSelectedRows()));
      connect(action_clear_rows, SIGNAL(triggered()), this, SLOT(clearSelectedRows()));
      connect(action_add_rows, SIGNAL(triggered()), this, SLOT(addRows()));
      connect(action_statistics_rows, SIGNAL(triggered()), this, SLOT(statisticsOnSelectedRows()));
}

void Table::addActionsToView()
{
      connect(action_toggle_comments, SIGNAL(triggered()), d_view, SLOT(toggleComments()));
      connect(action_toggle_tabbar, SIGNAL(triggered()), d_view, SLOT(toggleControlTabBar()));
      connect(action_formula_mode, SIGNAL(toggled(bool)), d_view, SLOT(activateFormulaMode(bool)));

      d_view->addAction(action_cut_selection);
      d_view->addAction(action_copy_selection);
      d_view->addAction(action_paste_into_selection);
#ifndef LEGACY_CODE_0_2_x
      d_view->addAction(action_mask_selection);
      d_view->addAction(action_unmask_selection);
#endif
      d_view->addAction(action_set_formula);
      d_view->addAction(action_clear_selection);
      d_view->addAction(action_recalculate);
      d_view->addAction(action_fill_row_numbers);
      d_view->addAction(action_fill_random);
      d_view->addAction(action_toggle_comments);
      d_view->addAction(action_toggle_tabbar);
      d_view->addAction(action_formula_mode);
      d_view->addAction(action_select_all);
      d_view->addAction(action_add_column);
      d_view->addAction(action_clear_table);
#ifndef LEGACY_CODE_0_2_x
      d_view->addAction(action_clear_masks);
#endif
      d_view->addAction(action_sort_table);
      d_view->addAction(action_go_to_cell);
      d_view->addAction(action_dimensions_dialog);
      d_view->addAction(action_insert_columns);
      d_view->addAction(action_remove_columns);
      d_view->addAction(action_clear_columns);
      d_view->addAction(action_add_columns);
      d_view->addAction(action_set_as_x);
      d_view->addAction(action_set_as_y);
      d_view->addAction(action_set_as_z);
      d_view->addAction(action_set_as_xerr);
      d_view->addAction(action_set_as_yerr);
      d_view->addAction(action_set_as_none);
      d_view->addAction(action_normalize_columns);
      d_view->addAction(action_normalize_selection);
      d_view->addAction(action_sort_columns);
      d_view->addAction(action_statistics_columns);
      d_view->addAction(action_type_format);
      d_view->addAction(action_edit_description);
      d_view->addAction(action_insert_rows);
      d_view->addAction(action_remove_rows);
      d_view->addAction(action_clear_rows);
      d_view->addAction(action_add_rows);
      d_view->addAction(action_statistics_rows);
}

01413 void Table::showTableViewContextMenu(const QPoint& pos)
{
      if (!d_view) return;
      QMenu context_menu;
      
// TODO: Does undo/redo really be belong into a context menu?
//    context_menu.addAction(undoAction(&context_menu));
//    context_menu.addAction(redoAction(&context_menu));

      if(d_plot_menu)
      {
            context_menu.addMenu(d_plot_menu);
            context_menu.addSeparator();
      }

      createSelectionMenu(&context_menu);
      context_menu.addSeparator();
      createTableMenu(&context_menu);
      context_menu.addSeparator();

      context_menu.exec(pos);
}

01436 void Table::showTableViewColumnContextMenu(const QPoint& pos)
{
      if (!d_view) return;
      QMenu context_menu;
      
// TODO: Does undo/redo really be belong into a context menu?
//    context_menu.addAction(undoAction(&context_menu));
//    context_menu.addAction(redoAction(&context_menu));

      if(d_plot_menu)
      {
            context_menu.addMenu(d_plot_menu);
            context_menu.addSeparator();
      }

      createColumnMenu(&context_menu);
      context_menu.addSeparator();

      context_menu.exec(pos);
}

01457 void Table::showTableViewRowContextMenu(const QPoint& pos)
{
      if (!d_view) return;
      QMenu context_menu;
      
// TODO: Does undo/redo really be belong into a context menu?
//    context_menu.addAction(undoAction(&context_menu));
//    context_menu.addAction(redoAction(&context_menu));

      createRowMenu(&context_menu);

      context_menu.exec(pos);
}

01471 QMenu * Table::createSelectionMenu(QMenu * append_to)
{
      QMenu * menu = append_to;
      if(!menu)
            menu = new QMenu();

      QMenu * submenu = new QMenu(tr("Fi&ll Selection with"));
      submenu->addAction(action_fill_row_numbers);
      submenu->addAction(action_fill_random);
      menu->addMenu(submenu);
      menu->addSeparator();

      menu->addAction(action_cut_selection);
      menu->addAction(action_copy_selection);
      menu->addAction(action_paste_into_selection);
      menu->addAction(action_clear_selection);
      menu->addSeparator();
#ifndef LEGACY_CODE_0_2_x
      menu->addAction(action_mask_selection);
      menu->addAction(action_unmask_selection);
      menu->addSeparator();
#endif
      menu->addAction(action_normalize_selection);
      menu->addSeparator();
      menu->addAction(action_set_formula);
      menu->addAction(action_recalculate);
      menu->addSeparator();

      return menu;
}


01503 QMenu * Table::createColumnMenu(QMenu * append_to)
{
      QMenu * menu = append_to;
      if(!menu)
            menu = new QMenu();

      QMenu * submenu = new QMenu(tr("S&et Column(s) As"));
      submenu->addAction(action_set_as_x);
      submenu->addAction(action_set_as_y);
      submenu->addAction(action_set_as_z);
      submenu->addSeparator();
      submenu->addAction(action_set_as_xerr);
      submenu->addAction(action_set_as_yerr);
      submenu->addSeparator();
      submenu->addAction(action_set_as_none);
      menu->addMenu(submenu);
      menu->addSeparator();

      submenu = new QMenu(tr("Fi&ll Selection with"));
      submenu->addAction(action_fill_row_numbers);
      submenu->addAction(action_fill_random);
      menu->addMenu(submenu);
      menu->addSeparator();

      menu->addAction(action_insert_columns);
      menu->addAction(action_remove_columns);
      menu->addAction(action_clear_columns);
      menu->addAction(action_add_columns);
      menu->addSeparator();
      
      menu->addAction(action_normalize_columns);
      menu->addAction(action_sort_columns);
      menu->addSeparator();

      menu->addAction(action_edit_description);
      menu->addAction(action_type_format);
      connect(menu, SIGNAL(aboutToShow()), this, SLOT(adjustActionNames()));
      menu->addAction(action_toggle_comments);
      menu->addSeparator();

      menu->addAction(action_statistics_columns);

      return menu;
}

01548 QMenu * Table::createTableMenu(QMenu * append_to) 
{
      QMenu * menu = append_to;
      if(!menu)
            menu = new QMenu();

      connect(menu, SIGNAL(aboutToShow()), this, SLOT(adjustActionNames()));
      menu->addAction(action_toggle_comments);
      menu->addAction(action_toggle_tabbar);
      menu->addAction(action_formula_mode);
      menu->addSeparator();
      menu->addAction(action_select_all);
      menu->addAction(action_clear_table);
#ifndef LEGACY_CODE_0_2_x
      menu->addAction(action_clear_masks);
      menu->addAction(action_sort_table);
#endif
      menu->addSeparator();
      menu->addAction(action_add_column);
      menu->addSeparator();
      menu->addAction(action_go_to_cell);

      return menu;
}

01573 QMenu * Table::createRowMenu(QMenu * append_to) 
{
      QMenu * menu = append_to;
      if(!menu)
            menu = new QMenu();

      menu->addAction(action_insert_rows);
      menu->addAction(action_remove_rows);
      menu->addAction(action_clear_rows);
      menu->addAction(action_add_rows);
      menu->addSeparator();
      QMenu *submenu = new QMenu(tr("Fi&ll Selection with"));
      submenu->addAction(action_fill_row_numbers);
      submenu->addAction(action_fill_random);
      menu->addMenu(submenu);
      menu->addSeparator();
      menu->addAction(action_statistics_rows);

      return menu;
}

void Table::goToCell()
{
      if (!d_view) return;
      bool ok;

      int col = QInputDialog::getInteger(0, tr("Go to Cell"), tr("Enter column"),
                  1, 1, columnCount(), 1, &ok);
      if ( !ok ) return;

      int row = QInputDialog::getInteger(0, tr("Go to Cell"), tr("Enter row"),
                  1, 1, rowCount(), 1, &ok);
      if ( !ok ) return;

      d_view->goToCell(row-1, col-1);
}

void Table::dimensionsDialog()
{
      Ui::DimensionsDialog ui;
      QDialog dialog;
      ui.setupUi(&dialog);
      dialog.setWindowTitle(tr("Set Table Dimensions"));
      ui.columnsSpinBox->setValue(columnCount());
      ui.rowsSpinBox->setValue(rowCount());
      connect(ui.buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
      connect(ui.buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));

      if (dialog.exec())
      {
            setColumnCount(ui.columnsSpinBox->value());
            setRowCount(ui.rowsSpinBox->value());
      }
}

void Table::moveColumn(int from, int to)
{
      beginMacro(tr("%1: move column %2 from position %3 to %4.").arg(name()).arg(d_table_private->column(from)->name()).arg(from+1).arg(to+1));
      moveChild(from, to);
      exec(new TableMoveColumnCmd(d_table_private, from, to));    
      endMacro();
}

void Table::copy(Table * other)
{
      WAIT_CURSOR;
      beginMacro(QObject::tr("%1: copy %2").arg(name()).arg(other->name()));
      
      removeColumns(0, columnCount());
      QList<Column *> columns;
      for (int i=0; i<other->columnCount(); i++)
      {
            Column * src_col = other->column(i);
            Column * new_col = new Column(src_col->name(), src_col->columnMode());
            new_col->copy(src_col);
            new_col->setPlotDesignation(src_col->plotDesignation());
            QList< Interval<int> > masks = src_col->maskedIntervals();
            foreach(Interval<int> iv, masks)
                  new_col->setMasked(iv);
            QList< Interval<int> > formulas = src_col->formulaIntervals();
            foreach(Interval<int> iv, formulas)
                  new_col->setFormula(iv, src_col->formula(iv.start()));
            columns.append(new_col);
      }
      appendColumns(columns);
      setCaptionSpec(other->captionSpec());
      setComment(other->comment());
      for (int i=0; i<columnCount(); i++)
            setColumnWidth(i, other->columnWidth(i));
      if (d_view) d_view->rereadSectionSizes();

      endMacro();
      RESET_CURSOR;
}

01668 int Table::colX(int col)
{
      for(int i=col-1; i>=0; i--)
      {
            if (column(i)->plotDesignation() == SciDAVis::X)
                  return i;
      }
      int cols = columnCount();
      for(int i=col+1; i<cols; i++)
      {
            if (column(i)->plotDesignation() == SciDAVis::X)
                  return i;
      }
      return -1;
}

01684 int Table::colY(int col)
{
      int cols = columnCount();
      // look to the right first
      for(int i=col+1; i<cols; i++)
      {
            if (column(i)->plotDesignation() == SciDAVis::Y)
                  return i;
      }
      for(int i=col-1; i>=0; i--)
      {
            if (column(i)->plotDesignation() == SciDAVis::Y)
                  return i;
      }
      return -1;
}

01701 void Table::setPlotMenu(QMenu * menu)
{
      d_plot_menu = menu;
}

01706 void Table::sortDialog(QList<Column*> cols)
{
      if(cols.isEmpty()) return;

      SortDialog *sortd = new future::SortDialog();
      sortd->setAttribute(Qt::WA_DeleteOnClose);
      connect(sortd, SIGNAL(sort(Column*,QList<Column*>,bool)), this, SLOT(sortColumns(Column*,QList<Column*>,bool)));
      sortd->setColumnsList(cols);
      sortd->exec();
}


01718 void Table::sortColumns(Column *leading, QList<Column*> cols, bool ascending)
{
      if(cols.isEmpty()) return;

      // the normal QPair comparison does not work properly with descending sorting
      // thefore we use our own compare functions
      class CompareFunctions{ 
            public:
                  static bool doubleLess(const QPair<double, int>& a, const QPair<double, int>& b)
                  {
                        return a.first < b.first;
                  }
                  static bool doubleGreater(const QPair<double, int>& a, const QPair<double, int>& b)
                  {
                        return a.first > b.first;
                  }
                  static bool QStringLess(const QPair<QString, int>& a, const QPair<QString, int>& b)
                  {
                        return a < b;
                  }
                  static bool QStringGreater(const QPair<QString, int>& a, const QPair<QString, int>& b)
                  {
                        return a > b;
                  }
                  static bool QDateTimeLess(const QPair<QDateTime, int>& a, const QPair<QDateTime, int>& b)
                  {
                        return a < b;
                  }
                  static bool QDateTimeGreater(const QPair<QDateTime, int>& a, const QPair<QDateTime, int>& b)
                  {
                        return a > b;
                  }
      };

      WAIT_CURSOR;
      beginMacro(tr("%1: sort column(s)").arg(name()));

      if(leading == 0) // sort separately
      {
            for(int i=0; i<cols.size(); i++)
            {
                  Column* col = cols.at(i);

                  if(col->dataType() == SciDAVis::TypeDouble)
                  {
                        int rows = col->rowCount();
                        QList< QPair<double, int> > map;

                        for(int j=0; j<rows; j++)
                              map.append(QPair<double, int>(col->valueAt(j), j));
      
                        if(ascending)
                              qStableSort(map.begin(), map.end(), CompareFunctions::doubleLess);
                        else
                              qStableSort(map.begin(), map.end(), CompareFunctions::doubleGreater);

                        QListIterator< QPair<double, int> > it(map);
                        Column *temp_col = new Column("temp", col->columnMode());
                        
                        int k=0;
                        // put the values in the right order into temp_col
                        while(it.hasNext())
                        {
                              temp_col->copy(col, it.peekNext().second, k, 1);
                              temp_col->setMasked(col->isMasked(it.next().second));
                              k++;
                        }
                        // copy the sorted column
                        col->copy(temp_col, 0, 0, rows);
                        delete temp_col;
                  }
                  else if(col->dataType() == SciDAVis::TypeQString)
                  {
                        int rows = col->rowCount();
                        QList< QPair<QString, int> > map;

                        for(int j=0; j<rows; j++)
                              map.append(QPair<QString, int>(col->textAt(j), j));
      
                        if(ascending)
                              qStableSort(map.begin(), map.end(), CompareFunctions::QStringLess);
                        else
                              qStableSort(map.begin(), map.end(), CompareFunctions::QStringGreater);

                        QListIterator< QPair<QString, int> > it(map);
                        Column *temp_col = new Column("temp", col->columnMode());
                        
                        int k=0;
                        // put the values in the right order into temp_col
                        while(it.hasNext())
                        {
                              temp_col->copy(col, it.peekNext().second, k, 1);
                              temp_col->setMasked(col->isMasked(it.next().second));
                              k++;
                        }
                        // copy the sorted column
                        col->copy(temp_col, 0, 0, rows);
                        delete temp_col;
                  }
                  else if(col->dataType() == SciDAVis::TypeQDateTime)
                  {
                        int rows = col->rowCount();
                        QList< QPair<QDateTime, int> > map;

                        for(int j=0; j<rows; j++)
                              map.append(QPair<QDateTime, int>(col->dateTimeAt(j), j));
      
                        if(ascending)
                              qStableSort(map.begin(), map.end(), CompareFunctions::QDateTimeLess);
                        else
                              qStableSort(map.begin(), map.end(), CompareFunctions::QDateTimeGreater);

                        QListIterator< QPair<QDateTime, int> > it(map);
                        Column *temp_col = new Column("temp", col->columnMode());
                        
                        int k=0;
                        // put the values in the right order into temp_col
                        while(it.hasNext())
                        {
                              temp_col->copy(col, it.peekNext().second, k, 1);
                              temp_col->setMasked(col->isMasked(it.next().second));
                              k++;
                        }
                        // copy the sorted column
                        col->copy(temp_col, 0, 0, rows);
                        delete temp_col;
                  }
            }
            
      }
      else // sort with leading column
      {
            if(leading->dataType() == SciDAVis::TypeDouble)
            {
                  QList< QPair<double, int> > map;
                  int rows = leading->rowCount();

                  for(int i=0; i<rows; i++)
                        map.append(QPair<double, int>(leading->valueAt(i), i));

                  if(ascending)
                        qStableSort(map.begin(), map.end(), CompareFunctions::doubleLess);
                  else
                        qStableSort(map.begin(), map.end(), CompareFunctions::doubleGreater);
                  QListIterator< QPair<double, int> > it(map);

                  for(int i=0; i<cols.size(); i++) 
                  {
                        Column *temp_col = new Column("temp", cols.at(i)->columnMode());
                        it.toFront();
                        int j=0;
                        // put the values in the right order into temp_col
                        while(it.hasNext())
                        {
                              temp_col->copy(cols.at(i), it.peekNext().second, j, 1);
                              temp_col->setMasked(cols.at(i)->isMasked(it.next().second));
                              j++;
                        }
                        // copy the sorted column
                        cols.at(i)->copy(temp_col, 0, 0, rows);
                        delete temp_col;
                  }
            }
            else if(leading->dataType() == SciDAVis::TypeQString)
            {
                  QList< QPair<QString, int> > map;
                  int rows = leading->rowCount();

                  for(int i=0; i<rows; i++)
                        map.append(QPair<QString, int>(leading->textAt(i), i));

                  if(ascending)
                        qStableSort(map.begin(), map.end(), CompareFunctions::QStringLess);
                  else
                        qStableSort(map.begin(), map.end(), CompareFunctions::QStringGreater);
                  QListIterator< QPair<QString, int> > it(map);

                  for(int i=0; i<cols.size(); i++) 
                  {
                        Column *temp_col = new Column("temp", cols.at(i)->columnMode());
                        it.toFront();
                        int j=0;
                        // put the values in the right order into temp_col
                        while(it.hasNext())
                        {
                              temp_col->copy(cols.at(i), it.peekNext().second, j, 1);
                              temp_col->setMasked(cols.at(i)->isMasked(it.next().second));
                              j++;
                        }
                        // copy the sorted column
                        cols.at(i)->copy(temp_col, 0, 0, rows);
                        delete temp_col;
                  }
            }
            else if(leading->dataType() == SciDAVis::TypeQDateTime)
            {
                  QList< QPair<QDateTime, int> > map;
                  int rows = leading->rowCount();

                  for(int i=0; i<rows; i++)
                        map.append(QPair<QDateTime, int>(leading->dateTimeAt(i), i));

                  if(ascending)
                        qStableSort(map.begin(), map.end(), CompareFunctions::QDateTimeLess);
                  else
                        qStableSort(map.begin(), map.end(), CompareFunctions::QDateTimeGreater);
                  QListIterator< QPair<QDateTime, int> > it(map);

                  for(int i=0; i<cols.size(); i++) 
                  {
                        Column *temp_col = new Column("temp", cols.at(i)->columnMode());
                        it.toFront();
                        int j=0;
                        // put the values in the right order into temp_col
                        while(it.hasNext())
                        {
                              temp_col->copy(cols.at(i), it.peekNext().second, j, 1);
                              temp_col->setMasked(cols.at(i)->isMasked(it.next().second));
                              j++;
                        }
                        // copy the sorted column
                        cols.at(i)->copy(temp_col, 0, 0, rows);
                        delete temp_col;
                  }
            }
      }
      endMacro();
      RESET_CURSOR;
} // end of sortColumns()


01949 QIcon Table::icon() const
{
      QIcon ico;
      ico.addPixmap(QPixmap(":/16x16/table.png"));
      ico.addPixmap(QPixmap(":/24x24/table.png"));
      ico.addPixmap(QPixmap(":/32x32/table.png"));
      return ico;
}

01958 QString Table::text(int row, int col)
{
      Column * col_ptr = column(col);
      if(!col_ptr)
            return QString();
      if(col_ptr->isInvalid(row))
            return QString();

      AbstractSimpleFilter * out_fltr = col_ptr->outputFilter();
      out_fltr->input(0, col_ptr);
      return out_fltr->output(0)->textAt(row);
}

void Table::selectAll()
{
      if (!d_view) return;
      d_view->selectAll();
}

void Table::handleModeChange(const AbstractColumn * col)
{
      int index = columnIndex(static_cast<const Column *>(col));
      if(index != -1)
            d_table_private->updateHorizontalHeader(index, index);
}

void Table::handleDescriptionChange(const AbstractAspect * aspect)
{
      int index = columnIndex(static_cast<const Column *>(aspect));
      if(index != -1)
            d_table_private->updateHorizontalHeader(index, index);
}

void Table::handlePlotDesignationChange(const AbstractColumn * col)
{
      int index = columnIndex(static_cast<const Column *>(col));
      if(index != -1)
            d_table_private->updateHorizontalHeader(index, columnCount()-1);
}

void Table::handleDataChange(const AbstractColumn * col)
{
      int index = columnIndex(static_cast<const Column *>(col));
      if(index != -1)
      {
            if (col->rowCount() > rowCount())
                  setRowCount(col->rowCount());
            emit dataChanged(0, index, col->rowCount()-1, index); 
      }
}

void Table::handleRowsAboutToBeInserted(const AbstractColumn * col, int before, int count)
{
      int new_size = col->rowCount() + count; 
      if(before <= col->rowCount() && new_size > rowCount())
            setRowCount(new_size);
}

void Table::handleRowsInserted(const AbstractColumn * col, int before, int count)
{
      Q_UNUSED(count);
      int index = columnIndex(static_cast<const Column *>(col));
      if(index != -1 && before <= col->rowCount())
            emit dataChanged(before, index, col->rowCount()-1, index);
}


void Table::handleRowsAboutToBeRemoved(const AbstractColumn * col, int first, int count)
{
      Q_UNUSED(col);
      Q_UNUSED(first);
      Q_UNUSED(count);
}

void Table::handleRowsRemoved(const AbstractColumn * col, int first, int count)
{
      Q_UNUSED(count);
      int index = columnIndex(static_cast<const Column *>(col));
      if(index != -1)
            emit dataChanged(first, index, col->rowCount()-1, index);
}

02040 void Table::connectColumn(const Column* col)
{
      connect(col, SIGNAL(aspectDescriptionChanged(const AbstractAspect *)), this, 
                  SLOT(handleDescriptionChange(const AbstractAspect *)));
      connect(col, SIGNAL(plotDesignationChanged(const AbstractColumn *)), this, 
                  SLOT(handlePlotDesignationChange(const AbstractColumn *)));
      connect(col, SIGNAL(modeChanged(const AbstractColumn *)), this, 
                  SLOT(handleDataChange(const AbstractColumn *)));
      connect(col, SIGNAL(dataChanged(const AbstractColumn *)), this, 
                  SLOT(handleDataChange(const AbstractColumn *)));
      connect(col, SIGNAL(modeChanged(const AbstractColumn *)), this, 
                  SLOT(handleModeChange(const AbstractColumn *)));
      connect(col, SIGNAL(rowsAboutToBeInserted(const AbstractColumn *, int, int)), this, 
                  SLOT(handleRowsAboutToBeInserted(const AbstractColumn *,int,int)));
      connect(col, SIGNAL(rowsInserted(const AbstractColumn *, int, int)), this, 
                  SLOT(handleRowsInserted(const AbstractColumn *,int,int))); 
      connect(col, SIGNAL(rowsAboutToBeRemoved(const AbstractColumn *, int, int)), this, 
                  SLOT(handleRowsAboutToBeRemoved(const AbstractColumn *,int,int))); 
      connect(col, SIGNAL(rowsRemoved(const AbstractColumn *, int, int)), this, 
                  SLOT(handleRowsRemoved(const AbstractColumn *,int,int))); 
      connect(col, SIGNAL(maskingChanged(const AbstractColumn *)), this, 
                  SLOT(handleDataChange(const AbstractColumn *))); 
}

02064 void Table::disconnectColumn(const Column* col)
{
      disconnect(col, 0, this, 0);
}

QVariant Table::headerData(int section, Qt::Orientation orientation,int role) const
{
      return d_table_private->headerData(section, orientation, role);
}

02074 void Table::completeAspectInsertion(AbstractAspect * aspect, int index)
{
      Column * column = qobject_cast<Column *>(aspect);
      if (!column) return;
      QList<Column*> cols;
      cols.append(column);
      exec(new TableInsertColumnsCmd(d_table_private, index, cols));
}

02083 void Table::prepareAspectRemoval(AbstractAspect * aspect)
{
      Column * column = qobject_cast<Column *>(aspect);
      if (!column) return;
      int first = columnIndex(column);
      QList<Column*> cols;
      cols.append(column);
      exec(new TableRemoveColumnsCmd(d_table_private, first, 1, cols));
}

02093 void Table::save(QXmlStreamWriter * writer) const
{
      int cols = columnCount();
      int rows = rowCount();
      writer->writeStartElement("table");
      writeBasicAttributes(writer);
      writer->writeAttribute("columns", QString::number(cols));
      writer->writeAttribute("rows", QString::number(rows));
      writeCommentElement(writer);

      for (int col=0; col<cols; col++)
            column(col)->save(writer);
      for (int col=0; col<cols; col++)
      {
            writer->writeStartElement("column_width");
            writer->writeAttribute("column", QString::number(col));
            writer->writeCharacters(QString::number(columnWidth(col)));
            writer->writeEndElement();
      }
      writer->writeEndElement(); // "table"
}

02115 bool Table::load(XmlStreamReader * reader)
{
      if(reader->isStartElement() && reader->name() == "table") 
      {
            setColumnCount(0);
            setRowCount(0);
            setComment("");

            if (!readBasicAttributes(reader)) return false;

            // read dimensions
            bool ok1, ok2;
            int rows, cols;
            rows = reader->readAttributeInt("rows", &ok1);
            cols = reader->readAttributeInt("columns", &ok2);
            if(!ok1 || !ok2) 
            {
                  reader->raiseError(tr("invalid row or column count"));
                  return false;
            }

            setRowCount(rows);
            // read child elements
            while (!reader->atEnd()) 
            {
                  reader->readNext();

                  if (reader->isEndElement()) break;

                  if (reader->isStartElement()) 
                  {
                        if (reader->name() == "comment")
                        {
                              if (!readCommentElement(reader)) return false;
                        }
                        else if(reader->name() == "column")
                        {
                              Column * column = new Column(tr("Column %1").arg(1), SciDAVis::Text);
                              if (!column->load(reader))
                              {
                                    setColumnCount(0);
                                    return false;
                              }
                              QList<Column *> columns;
                              columns.append(column);
                              appendColumns(columns);
                        }
                        else if(reader->name() == "column_width")
                        {
                              if (!readColumnWidthElement(reader)) return false;
                        }
                        else // unknown element
                        {
                              reader->raiseWarning(tr("unknown element '%1'").arg(reader->name().toString()));
                              if (!reader->skipToEndElement()) return false;
                        }
                  } 
            }
            if (cols != columnCount())
                  reader->raiseWarning(tr("columns attribute and number of read columns do not match"));
      }
      else // no table element
            reader->raiseError(tr("no table element found"));

      return !reader->hasError();
}

void Table::adjustActionNames()
{
      if (!d_view) return;

      QString action_name;
      if(d_view->areCommentsShown()) 
            action_name = tr("Hide Comments");
      else
            action_name = tr("Show Comments");
      action_toggle_comments->setText(action_name);

      if(d_view->isControlTabBarVisible()) 
            action_name = tr("Hide Controls");
      else
            action_name = tr("Show Controls");
      action_toggle_tabbar->setText(action_name);
}

bool Table::readColumnWidthElement(XmlStreamReader * reader)
{
      Q_ASSERT(reader->isStartElement() && reader->name() == "column_width");
      bool ok;
      int col = reader->readAttributeInt("column", &ok);
      if(!ok)
      {
            reader->raiseError(tr("invalid or missing column index"));
            return false;
      }
      QString str = reader->readElementText();
      int value = str.toInt(&ok);
      if(!ok)
      {
            reader->raiseError(tr("invalid column width"));
            return false;
      }
      if (d_view)
            d_view->setColumnWidth(col, value);
      else
            setColumnWidth(col, value);
      return true;
}

02224 void Table::setColumnWidth(int col, int width) 
{ 
      d_table_private->setColumnWidth(col, width); 
}

int Table::columnWidth(int col) const 
{ 
      return d_table_private->columnWidth(col); 
}


/* ========================= static methods ======================= */
ActionManager * Table::action_manager = 0;

ActionManager * Table::actionManager()
{
      if (!action_manager)
            initActionManager();
      
      return action_manager;
}

void Table::initActionManager()
{
      if (!action_manager)
            action_manager = new ActionManager();

      action_manager->setTitle(tr("Table"));
      volatile Table * action_creator = new Table(); // initialize the action texts
      delete action_creator;
}

/* ========================== Table::Private ====================== */

02258 Column * Table::Private::column(int index) const            
{ 
      return d_columns.value(index); 
}

02263 void Table::Private::replaceColumns(int first, QList<Column*> new_cols)
{
      if( (first < 0) || (first + new_cols.size() > d_column_count) )
            return;

      int count = new_cols.size();
      emit d_owner->columnsAboutToBeReplaced(first, new_cols.count());
      for(int i=0; i<count; i++)
      {
            int rows = new_cols.at(i)->rowCount();
            if(rows > d_row_count)
                  setRowCount(rows); 

            if(d_columns.at(first+i))
                  d_columns.at(first+i)->notifyReplacement(new_cols.at(i));

            d_columns[first+i] = new_cols.at(i);
            d_owner->connectColumn(new_cols.at(i));
      }
      updateHorizontalHeader(first, first+count-1);
      emit d_owner->columnsReplaced(first, new_cols.count());
      emit d_owner->dataChanged(0, first, d_row_count-1, first+count-1);
}

02287 void Table::Private::insertColumns(int before, QList<Column*> cols)
{
      int count = cols.count();

      if( (count < 1) || (before > d_column_count) )
            return;

      Q_ASSERT(before >= 0);

      int i, rows;
      for(i=0; i<count; i++)
      {
            rows = cols.at(i)->rowCount();
            if(rows > d_row_count)
                  setRowCount(rows); 
      }

      emit d_owner->columnsAboutToBeInserted(before, cols);
      for(int i=count-1; i>=0; i--)
      {
            d_columns.insert(before, cols.at(i));
            d_owner->connectColumn(cols.at(i));
            d_column_widths.insert(before, Table::defaultColumnWidth());
      }
      d_column_count += count;
      updateHorizontalHeader(before, before+count-1);
      emit d_owner->columnsInserted(before, cols.count());
}

02316 void Table::Private::removeColumns(int first, int count)
{
      if( (count < 1) || (first >= d_column_count) )
            return;

      Q_ASSERT(first >= 0);

      Q_ASSERT(first+count <= d_column_count);

      emit d_owner->columnsAboutToBeRemoved(first, count);
      for(int i=count-1; i>=0; i--)
      {
            d_owner->disconnectColumn(d_columns.at(first));
            d_columns.removeAt(first);
            d_column_widths.removeAt(first);
      }
      d_column_count -= count;
      emit d_owner->columnsRemoved(first, count);
      updateHorizontalHeader(first, d_column_count-1);
}

02337 void Table::Private::appendColumns(QList<Column*> cols)
{
      insertColumns(d_column_count, cols);
}

02342 void Table::Private::moveColumn(int from, int to)
{
      if( from < 0 || from >= d_column_count) return;
      if( to < 0 || to >= d_column_count) return;
      
      d_columns.move(from, to);
      d_owner->connectColumn(d_columns.at(to));
      d_column_widths.move(from, to);
      updateHorizontalHeader(qMin(from, to), qMax(from, to));
      emit d_owner->dataChanged(0, from, d_row_count-1, from);
      emit d_owner->dataChanged(0, to, d_row_count-1, to);
      if (d_owner->d_view) d_owner->d_view->rereadSectionSizes();
}

02356 void Table::Private::setRowCount(int rows)
{
      int diff = rows - d_row_count;
      int old_row_count = d_row_count;
      if(diff == 0) 
            return;

      if(diff > 0)
      {
            emit d_owner->rowsAboutToBeInserted(d_row_count, diff);
            d_row_count = rows;
            updateVerticalHeader(d_row_count - diff);
            emit d_owner->rowsInserted(old_row_count, diff);
      }
      else
      {
            emit d_owner->rowsAboutToBeRemoved(rows, -diff);
            d_row_count = rows;
            emit d_owner->rowsRemoved(rows, -diff);
      }
}

02378 QString Table::Private::columnHeader(int col)
{
      return headerData(col, Qt::Horizontal, Qt::DisplayRole).toString();
}

02383 int Table::Private::numColsWithPD(SciDAVis::PlotDesignation pd)
{
      int count = 0;
      
      for (int i=0; i<d_column_count; i++)
            if(d_columns.at(i)->plotDesignation() == pd)
                  count++;
      
      return count;
}

02394 void Table::Private::updateVerticalHeader(int start_row)
{
      int current_size = d_vertical_header_data.size(), i;
      for(i=start_row; i<current_size; i++)
            d_vertical_header_data.replace(i, QString::number(i+1));
      for(; i<d_row_count; i++)
            d_vertical_header_data << QString::number(i+1);
      emit d_owner->headerDataChanged(Qt::Vertical, start_row, d_row_count -1);     
}

02404 void Table::Private::updateHorizontalHeader(int start_col, int end_col)
{
      if (start_col > end_col) return;

      while(d_horizontal_header_data.size() < d_column_count)
            d_horizontal_header_data << QString();

      if(numColsWithPD(SciDAVis::X)>1)
      {
            int x_cols = 0;
            for (int i=0; i<d_column_count; i++)
            {
                  if (d_columns.at(i)->plotDesignation() == SciDAVis::X)
                        composeColumnHeader(i, d_columns.at(i)->name()+"[X" + QString::number(++x_cols) +"]");
                  else if (d_columns.at(i)->plotDesignation() == SciDAVis::Y)
                  {
                        if(x_cols>0)
                              composeColumnHeader(i, d_columns.at(i)->name()+"[Y"+ QString::number(x_cols) +"]");
                        else
                              composeColumnHeader(i, d_columns.at(i)->name()+"[Y]");
                  }
                  else if (d_columns.at(i)->plotDesignation() == SciDAVis::Z)
                  {
                        if(x_cols>0)
                              composeColumnHeader(i, d_columns.at(i)->name()+"[Z"+ QString::number(x_cols) +"]");
                        else
                              composeColumnHeader(i, d_columns.at(i)->name()+"[Z]");
                  }
                  else if (d_columns.at(i)->plotDesignation() == SciDAVis::xErr)
                  {
                        if(x_cols>0)
                              composeColumnHeader(i, d_columns.at(i)->name()+"[xEr"+ QString::number(x_cols) +"]");
                        else
                              composeColumnHeader(i, d_columns.at(i)->name()+"[xEr]");
                  }
                  else if (d_columns.at(i)->plotDesignation() == SciDAVis::yErr)
                  {
                        if(x_cols>0)
                              composeColumnHeader(i, d_columns.at(i)->name()+"[yEr"+ QString::number(x_cols) +"]");
                        else
                              composeColumnHeader(i, d_columns.at(i)->name()+"[yEr]");
                  }
                  else
                        composeColumnHeader(i, d_columns.at(i)->name());
            }
      }
      else
      {
            for (int i=0; i<d_column_count; i++)
            {
                  if (d_columns.at(i)->plotDesignation() == SciDAVis::X)
                        composeColumnHeader(i, d_columns.at(i)->name()+"[X]");
                  else if(d_columns.at(i)->plotDesignation() == SciDAVis::Y)
                        composeColumnHeader(i, d_columns.at(i)->name()+"[Y]");
                  else if(d_columns.at(i)->plotDesignation() == SciDAVis::Z)
                        composeColumnHeader(i, d_columns.at(i)->name()+"[Z]");
                  else if(d_columns.at(i)->plotDesignation() == SciDAVis::xErr)
                        composeColumnHeader(i, d_columns.at(i)->name()+"[xEr]");
                  else if(d_columns.at(i)->plotDesignation() == SciDAVis::yErr)
                        composeColumnHeader(i, d_columns.at(i)->name()+"[yEr]");
                  else
                        composeColumnHeader(i, d_columns.at(i)->name());
            }
      }
      emit d_owner->headerDataChanged(Qt::Horizontal, start_col, end_col);    
}

02471 void Table::Private::composeColumnHeader(int col, const QString& label)
{
      if (col >= d_horizontal_header_data.size())
            d_horizontal_header_data << label;
      else
            d_horizontal_header_data.replace(col, label);
}

QVariant Table::Private::headerData(int section, Qt::Orientation orientation, int role) const
{
      switch(orientation) {
            case Qt::Horizontal:
                  switch(role) {
                        case Qt::DisplayRole:
                        case Qt::ToolTipRole:
                        case Qt::EditRole:
                              return d_horizontal_header_data.at(section);
                        case Qt::DecorationRole:
                              return d_columns.at(section)->icon();
                        case TableModel::CommentRole:
                              return d_columns.at(section)->comment();
                  }
            case Qt::Vertical:
                  switch(role) {
                        case Qt::DisplayRole:
                        case Qt::ToolTipRole:
                              return d_vertical_header_data.at(section);
                  }
      }
      return QVariant();
}

} // namespace

Generated by  Doxygen 1.6.0   Back to index