diff options
Diffstat (limited to 'kspread/kspread_cluster.cpp')
-rw-r--r-- | kspread/kspread_cluster.cpp | 1449 |
1 files changed, 1449 insertions, 0 deletions
diff --git a/kspread/kspread_cluster.cpp b/kspread/kspread_cluster.cpp new file mode 100644 index 00000000..318ee758 --- /dev/null +++ b/kspread/kspread_cluster.cpp @@ -0,0 +1,1449 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Tomas Mecir <mecirt@gmail.com> + Copyright (C) 2000 Torben Weis <weis@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <stdlib.h> + +#include <kdebug.h> + +#include "kspread_cell.h" +#include "kspread_format.h" + +#include "kspread_cluster.h" + +using namespace KSpread; + +/**************************************************** + * + * Cluster + * + ****************************************************/ + +/* Generate a matrix LEVEL1 with the size LEVEL1*LEVEL1 */ +Cluster::Cluster() + : m_first( 0 ), m_autoDelete( false ), m_biggestX(0), m_biggestY(0) +{ + m_cluster = (Cell***)malloc( KSPREAD_CLUSTER_LEVEL1 * KSPREAD_CLUSTER_LEVEL1 * sizeof( Cell** ) ); + + for( int x = 0; x < KSPREAD_CLUSTER_LEVEL1; ++x ) + for( int y = 0; y < KSPREAD_CLUSTER_LEVEL1; ++y ) + m_cluster[ y * KSPREAD_CLUSTER_LEVEL1 + x ] = 0; +} + +/* Delete the matrix LEVEL1 and all existing LEVEL2 matrizes */ +Cluster::~Cluster() +{ +// Can't we use clear(), to remove double code - Philipp? + for( int x = 0; x < KSPREAD_CLUSTER_LEVEL1; ++x ) + for( int y = 0; y < KSPREAD_CLUSTER_LEVEL1; ++y ) + { + Cell** cl = m_cluster[ y * KSPREAD_CLUSTER_LEVEL1 + x ]; + if ( cl ) + { + free( cl ); + m_cluster[ y * KSPREAD_CLUSTER_LEVEL1 + x ] = 0; + } + } + + if ( m_autoDelete ) + { + Cell* cell = m_first; + while( cell ) + { + Cell* n = cell->nextCell(); + delete cell; + cell = n; + } + } + + free( m_cluster ); +} + +void Cluster::clear() +{ + for( int x = 0; x < KSPREAD_CLUSTER_LEVEL1; ++x ) + for( int y = 0; y < KSPREAD_CLUSTER_LEVEL1; ++y ) + { + Cell** cl = m_cluster[ y * KSPREAD_CLUSTER_LEVEL1 + x ]; + if ( cl ) + { + free( cl ); + m_cluster[ y * KSPREAD_CLUSTER_LEVEL1 + x ] = 0; + } + } + + if ( m_autoDelete ) + { + Cell* cell = m_first; + while( cell ) + { + Cell* n = cell->nextCell(); + delete cell; + cell = n; + } + } + + m_first = 0; + m_biggestX = m_biggestY = 0; +} + +Cell* Cluster::lookup( int x, int y ) const +{ + if ( x >= KSPREAD_CLUSTER_MAX || x < 0 || y >= KSPREAD_CLUSTER_MAX || y < 0 ) + { + kdDebug(36001) << "Cluster::lookup: invalid column or row value (col: " + << x << " | row: " << y << ")" << endl; + return 0; + } + int cx = x / KSPREAD_CLUSTER_LEVEL2; + int cy = y / KSPREAD_CLUSTER_LEVEL2; + int dx = x % KSPREAD_CLUSTER_LEVEL2; + int dy = y % KSPREAD_CLUSTER_LEVEL2; + + Cell** cl = m_cluster[ cy * KSPREAD_CLUSTER_LEVEL1 + cx ]; + if ( !cl ) + return 0; + + return cl[ dy * KSPREAD_CLUSTER_LEVEL2 + dx ]; +} + +/* Paste a cell in LEVEL2 (it's more paste than insert) */ +void Cluster::insert( Cell* cell, int x, int y ) +{ + if ( x >= KSPREAD_CLUSTER_MAX || x < 0 || y >= KSPREAD_CLUSTER_MAX || y < 0 ) + { + kdDebug(36001) << "Cluster::insert: invalid column or row value (col: " + << x << " | row: " << y << ")" << endl; + return; + } + + int cx = x / KSPREAD_CLUSTER_LEVEL2; + int cy = y / KSPREAD_CLUSTER_LEVEL2; + int dx = x % KSPREAD_CLUSTER_LEVEL2; + int dy = y % KSPREAD_CLUSTER_LEVEL2; + + Cell** cl = m_cluster[ cy * KSPREAD_CLUSTER_LEVEL1 + cx ]; + if ( !cl ) + { + cl = (Cell**)malloc( KSPREAD_CLUSTER_LEVEL2 * KSPREAD_CLUSTER_LEVEL2 * sizeof( Cell* ) ); + m_cluster[ cy * KSPREAD_CLUSTER_LEVEL1 + cx ] = cl; + + for( int a = 0; a < KSPREAD_CLUSTER_LEVEL2; ++a ) + for( int b = 0; b < KSPREAD_CLUSTER_LEVEL2; ++b ) + cl[ b * KSPREAD_CLUSTER_LEVEL2 + a ] = 0; + } + + if ( cl[ dy * KSPREAD_CLUSTER_LEVEL2 + dx ] ) + remove( x, y ); + + cl[ dy * KSPREAD_CLUSTER_LEVEL2 + dx ] = cell; + + if ( m_first ) + { + cell->setNextCell( m_first ); + m_first->setPreviousCell( cell ); + } + m_first = cell; + + if (x > m_biggestX) m_biggestX = x; + if (y > m_biggestY) m_biggestY = y; +} + +/* Removes the cell of a matrix, the matrix itself keeps unchanged */ +void Cluster::remove( int x, int y ) +{ + if ( x >= KSPREAD_CLUSTER_MAX || x < 0 || y >= KSPREAD_CLUSTER_MAX || y < 0 ) + { + kdDebug(36001) << "Cluster::remove: invalid column or row value (col: " + << x << " | row: " << y << ")" << endl; + return; + } + + int cx = x / KSPREAD_CLUSTER_LEVEL2; + int cy = y / KSPREAD_CLUSTER_LEVEL2; + int dx = x % KSPREAD_CLUSTER_LEVEL2; + int dy = y % KSPREAD_CLUSTER_LEVEL2; + + Cell** cl = m_cluster[ cy * KSPREAD_CLUSTER_LEVEL1 + cx ]; + if ( !cl ) + return; + + Cell* c = cl[ dy * KSPREAD_CLUSTER_LEVEL2 + dx ]; + if ( !c ) + return; + + cl[ dy * KSPREAD_CLUSTER_LEVEL2 + dx ] = 0; + + if ( m_autoDelete ) + { + if ( m_first == c ) + m_first = c->nextCell(); + if(c->doesMergeCells()) + { + c->mergeCells(c->column(),c->row(),0,0); + } + delete c; + } + else + { + if ( m_first == c ) + m_first = c->nextCell(); + if ( c->previousCell() ) + c->previousCell()->setNextCell( c->nextCell() ); + if ( c->nextCell() ) + c->nextCell()->setPreviousCell( c->previousCell() ); + c->setNextCell( 0 ); + c->setPreviousCell( 0 ); + } +} + +bool Cluster::shiftRow( const TQPoint& marker ) +{ + bool dummy; + return shiftRow( marker, dummy ); +} + +bool Cluster::shiftColumn( const TQPoint& marker ) +{ + bool dummy; + return shiftColumn( marker, dummy ); +} + +void Cluster::unshiftColumn( const TQPoint& marker ) +{ + bool dummy; + unshiftColumn( marker, dummy ); +} + +void Cluster::unshiftRow( const TQPoint& marker ) +{ + bool dummy; + unshiftRow( marker, dummy ); +} + +void Cluster::setAutoDelete( bool b ) +{ + m_autoDelete = b; +} + +bool Cluster::autoDelete() const +{ + return m_autoDelete; +} + +Cell* Cluster::firstCell() const +{ + return m_first; +} + +bool Cluster::shiftRow( const TQPoint& marker, bool& work ) +{ + work = false; + + if ( marker.x() >= KSPREAD_CLUSTER_MAX || marker.x() < 0 || + marker.y() >= KSPREAD_CLUSTER_MAX || marker.y() < 0 ) + { + kdDebug(36001) << "Cluster::shiftRow: invalid column or row value (col: " + << marker.x() << " | row: " << marker.y() << ")" << endl; + return false; + } + + int cx = marker.x() / KSPREAD_CLUSTER_LEVEL2; + int cy = marker.y() / KSPREAD_CLUSTER_LEVEL2; + int dx = marker.x() % KSPREAD_CLUSTER_LEVEL2; + int dy = marker.y() % KSPREAD_CLUSTER_LEVEL2; + + // Is there a cell at the bottom most position ? + // In this case the shift is impossible. + Cell** cl = m_cluster[ cy * KSPREAD_CLUSTER_LEVEL1 + KSPREAD_CLUSTER_LEVEL1 - 1 ]; + if ( cl && cl[ dy * KSPREAD_CLUSTER_LEVEL2 + KSPREAD_CLUSTER_LEVEL2 - 1 ] ) + return false; + + bool a = autoDelete(); + setAutoDelete( false ); + + // Move cells in this row one down. + for( int i = KSPREAD_CLUSTER_LEVEL1 - 1; i >= cx ; --i ) + { + Cell** cl = m_cluster[ cy * KSPREAD_CLUSTER_LEVEL1 + i ]; + if ( cl ) + { + work = true; + int left = 0; + if ( i == cx ) + left = dx; + int right = KSPREAD_CLUSTER_LEVEL2 - 1; + if ( i == KSPREAD_CLUSTER_LEVEL1 - 1 ) + right = KSPREAD_CLUSTER_LEVEL2 - 2; + for( int k = right; k >= left; --k ) + { + Cell* c = cl[ dy * KSPREAD_CLUSTER_LEVEL2 + k ]; + if ( c ) + { + remove( c->column(), c->row() ); + c->move( c->column() + 1, c->row() ); + insert( c, c->column(), c->row() ); + } + } + } + } + + setAutoDelete( a ); + + return true; +} + +bool Cluster::shiftColumn( const TQPoint& marker, bool& work ) +{ + work = false; + + if ( marker.x() >= KSPREAD_CLUSTER_MAX || marker.x() < 0 || + marker.y() >= KSPREAD_CLUSTER_MAX || marker.y() < 0 ) + { + kdDebug(36001) << "Cluster::shiftColumn: invalid column or row value (col: " + << marker.x() << " | row: " << marker.y() << ")" << endl; + return false; + } + + int cx = marker.x() / KSPREAD_CLUSTER_LEVEL2; + int cy = marker.y() / KSPREAD_CLUSTER_LEVEL2; + int dx = marker.x() % KSPREAD_CLUSTER_LEVEL2; + int dy = marker.y() % KSPREAD_CLUSTER_LEVEL2; + + // Is there a cell at the right most position ? + // In this case the shift is impossible. + Cell** cl = m_cluster[ KSPREAD_CLUSTER_LEVEL1 * ( KSPREAD_CLUSTER_LEVEL1 - 1 ) + cx ]; + if ( cl && cl[ KSPREAD_CLUSTER_LEVEL2 * ( KSPREAD_CLUSTER_LEVEL2 - 1 ) + dx ] ) + return false; + + bool a = autoDelete(); + setAutoDelete( false ); + + // Move cells in this column one right. + for( int i = KSPREAD_CLUSTER_LEVEL1 - 1; i >= cy ; --i ) + { + Cell** cl = m_cluster[ i * KSPREAD_CLUSTER_LEVEL1 + cx ]; + if ( cl ) + { + work = true; + + int top = 0; + if ( i == cy ) + top = dy; + int bottom = KSPREAD_CLUSTER_LEVEL2 - 1; + if ( i == KSPREAD_CLUSTER_LEVEL1 - 1 ) + bottom = KSPREAD_CLUSTER_LEVEL2 - 2; + for( int k = bottom; k >= top; --k ) + { + Cell* c = cl[ k * KSPREAD_CLUSTER_LEVEL2 + dx ]; + if ( c ) + { + remove( c->column(), c->row() ); + c->move( c->column(), c->row() + 1 ); + insert( c, c->column(), c->row() ); + } + } + } + } + + setAutoDelete( a ); + + return true; +} + +bool Cluster::insertColumn( int col ) +{ + if ( col >= KSPREAD_CLUSTER_MAX || col < 0 ) + { + kdDebug(36001) << "Cluster::insertColumn: invalid column value (col: " + << col << ")" << endl; + return false; + } + + // Is there a cell at the right most position ? + // In this case the shift is impossible. + for( int t1 = 0; t1 < KSPREAD_CLUSTER_LEVEL1; ++t1 ) + { + Cell** cl = m_cluster[ t1 * KSPREAD_CLUSTER_LEVEL1 + KSPREAD_CLUSTER_LEVEL1 - 1 ]; + if ( cl ) + for( int t2 = 0; t2 < KSPREAD_CLUSTER_LEVEL2; ++t2 ) + if ( cl[ t2 * KSPREAD_CLUSTER_LEVEL2 + KSPREAD_CLUSTER_LEVEL2 - 1 ] ) + return false; + } + + for( int t1 = 0; t1 < KSPREAD_CLUSTER_LEVEL1; ++t1 ) + { + bool work = true; + for( int t2 = 0; work && t2 < KSPREAD_CLUSTER_LEVEL2; ++t2 ) + shiftRow( TQPoint( col, t1 * KSPREAD_CLUSTER_LEVEL2 + t2 ), work ); + } + + return true; +} + +bool Cluster::insertRow( int row ) +{ + if ( row >= KSPREAD_CLUSTER_MAX || row < 0 ) + { + kdDebug(36001) << "Cluster::insertRow: invalid row value (row: " + << row << ")" << endl; + return false; + } + + // Is there a cell at the bottom most position ? + // In this case the shift is impossible. + for( int t1 = 0; t1 < KSPREAD_CLUSTER_LEVEL1; ++t1 ) + { + Cell** cl = m_cluster[ KSPREAD_CLUSTER_LEVEL1 * ( KSPREAD_CLUSTER_LEVEL1 - 1 ) + t1 ]; + if ( cl ) + for( int t2 = 0; t2 < KSPREAD_CLUSTER_LEVEL2; ++t2 ) + if ( cl[ KSPREAD_CLUSTER_LEVEL2 * ( KSPREAD_CLUSTER_LEVEL2 - 1 ) + t2 ] ) + return false; + } + + for( int t1 = 0; t1 < KSPREAD_CLUSTER_LEVEL1; ++t1 ) + { + bool work = true; + for( int t2 = 0; work && t2 < KSPREAD_CLUSTER_LEVEL2; ++t2 ) + shiftColumn( TQPoint( t1 * KSPREAD_CLUSTER_LEVEL2 + t2, row ), work ); + } + + return true; +} + +void Cluster::unshiftColumn( const TQPoint& marker, bool& work ) +{ + work = false; + + if ( marker.x() >= KSPREAD_CLUSTER_MAX || marker.x() < 0 || + marker.y() >= KSPREAD_CLUSTER_MAX || marker.y() < 0 ) + { + kdDebug(36001) << "Cluster::unshiftColumn: invalid column or row value (col: " + << marker.x() << " | row: " << marker.y() << ")" << endl; + return; + } + + int cx = marker.x() / KSPREAD_CLUSTER_LEVEL2; + int cy = marker.y() / KSPREAD_CLUSTER_LEVEL2; + int dx = marker.x() % KSPREAD_CLUSTER_LEVEL2; + int dy = marker.y() % KSPREAD_CLUSTER_LEVEL2; + + bool a = autoDelete(); + setAutoDelete( false ); + + // Move cells in this column one column to the left. + for( int i = cy; i < KSPREAD_CLUSTER_LEVEL1; ++i ) + { + Cell** cl = m_cluster[ i * KSPREAD_CLUSTER_LEVEL1 + cx ]; + if ( cl ) + { + work = true; + + int top = 0; + if ( i == cy ) + top = dy + 1; + int bottom = KSPREAD_CLUSTER_LEVEL2 - 1; + for( int k = top; k <= bottom; ++k ) + { + Cell* c = cl[ k * KSPREAD_CLUSTER_LEVEL2 + dx ]; + if ( c ) + { + remove( c->column(), c->row() ); + c->move( c->column(), c->row() - 1 ); + insert( c, c->column(), c->row() ); + } + } + } + } + + setAutoDelete( a ); +} + +void Cluster::unshiftRow( const TQPoint& marker, bool& work ) +{ + work = false; + + if ( marker.x() >= KSPREAD_CLUSTER_MAX || marker.x() < 0 || + marker.y() >= KSPREAD_CLUSTER_MAX || marker.y() < 0 ) + { + kdDebug(36001) << "Cluster::unshiftRow: invalid column or row value (col: " + << marker.x() << " | row: " << marker.y() << ")" << endl; + return; + } + + int cx = marker.x() / KSPREAD_CLUSTER_LEVEL2; + int cy = marker.y() / KSPREAD_CLUSTER_LEVEL2; + int dx = marker.x() % KSPREAD_CLUSTER_LEVEL2; + int dy = marker.y() % KSPREAD_CLUSTER_LEVEL2; + + bool a = autoDelete(); + setAutoDelete( false ); + + // Move cells in this row one row up. + for( int i = cx; i < KSPREAD_CLUSTER_LEVEL1; ++i ) + { + Cell** cl = m_cluster[ cy * KSPREAD_CLUSTER_LEVEL1 + i ]; + if ( cl ) + { + work = true; + + int left = 0; + if ( i == cx ) + left = dx + 1; + int right = KSPREAD_CLUSTER_LEVEL2 - 1; + for( int k = left; k <= right; ++k ) + { + Cell* c = cl[ dy * KSPREAD_CLUSTER_LEVEL2 + k ]; + if ( c ) + { + remove( c->column(), c->row() ); + c->move( c->column() - 1, c->row() ); + insert( c, c->column(), c->row() ); + } + } + } + } + + setAutoDelete( a ); +} + +void Cluster::removeColumn( int col ) +{ + if ( col >= KSPREAD_CLUSTER_MAX || col < 0 ) + { + kdDebug(36001) << "Cluster::removeColumn: invalid column value (col: " + << col << ")" << endl; + return; + } + + int cx = col / KSPREAD_CLUSTER_LEVEL2; + int dx = col % KSPREAD_CLUSTER_LEVEL2; + + for( int y1 = 0; y1 < KSPREAD_CLUSTER_LEVEL1; ++y1 ) + { + Cell** cl = m_cluster[ y1 * KSPREAD_CLUSTER_LEVEL1 + cx ]; + if ( cl ) + for( int y2 = 0; y2 < KSPREAD_CLUSTER_LEVEL2; ++y2 ) + if ( cl[ y2 * KSPREAD_CLUSTER_LEVEL2 + dx ] ) + remove( col, y1 * KSPREAD_CLUSTER_LEVEL1 + y2 ); + } + + for( int t1 = 0; t1 < KSPREAD_CLUSTER_LEVEL1; ++t1 ) + { + bool work = true; + for( int t2 = 0; work && t2 < KSPREAD_CLUSTER_LEVEL2; ++t2 ) + unshiftRow( TQPoint( col, t1 * KSPREAD_CLUSTER_LEVEL2 + t2 ), work ); + } +} + +void Cluster::removeRow( int row ) +{ + if ( row >= KSPREAD_CLUSTER_MAX || row < 0 ) + { + kdDebug(36001) << "Cluster::removeRow: invalid row value (row: " + << row << ")" << endl; + return; + } + + int cy = row / KSPREAD_CLUSTER_LEVEL2; + int dy = row % KSPREAD_CLUSTER_LEVEL2; + + for( int x1 = 0; x1 < KSPREAD_CLUSTER_LEVEL1; ++x1 ) + { + Cell** cl = m_cluster[ cy * KSPREAD_CLUSTER_LEVEL1 + x1 ]; + if ( cl ) + for( int x2 = 0; x2 < KSPREAD_CLUSTER_LEVEL2; ++x2 ) + if ( cl[ dy * KSPREAD_CLUSTER_LEVEL2 + x2 ] ) + remove( x1 * KSPREAD_CLUSTER_LEVEL2 + x2, row ); + } + + for( int t1 = 0; t1 < KSPREAD_CLUSTER_LEVEL1; ++t1 ) + { + bool work = true; + for( int t2 = 0; work && t2 < KSPREAD_CLUSTER_LEVEL2; ++t2 ) + unshiftColumn( TQPoint( t1 * KSPREAD_CLUSTER_LEVEL2 + t2, row ), work ); + } +} + +void Cluster::clearColumn( int col ) +{ + if ( col >= KSPREAD_CLUSTER_MAX || col < 0 ) + { + kdDebug(36001) << "Cluster::clearColumn: invalid column value (col: " + << col << ")" << endl; + return; + } + + int cx = col / KSPREAD_CLUSTER_LEVEL2; + int dx = col % KSPREAD_CLUSTER_LEVEL2; + + for( int cy = 0; cy < KSPREAD_CLUSTER_LEVEL1; ++cy ) + { + Cell** cl = m_cluster[ cy * KSPREAD_CLUSTER_LEVEL1 + cx ]; + if ( cl ) + for( int dy = 0; dy < KSPREAD_CLUSTER_LEVEL2; ++dy ) + if ( cl[ dy * KSPREAD_CLUSTER_LEVEL2 + dx ] ) + { + int row = cy * KSPREAD_CLUSTER_LEVEL2 + dy ; + remove( col, row ); + } + } +} + +void Cluster::clearRow( int row ) +{ + if ( row >= KSPREAD_CLUSTER_MAX || row < 0 ) + { + kdDebug(36001) << "Cluster::clearRow: invalid row value (row: " + << row << ")" << endl; + return; + } + + int cy = row / KSPREAD_CLUSTER_LEVEL2; + int dy = row % KSPREAD_CLUSTER_LEVEL2; + + for( int cx = 0; cx < KSPREAD_CLUSTER_LEVEL1; ++cx ) + { + Cell** cl = m_cluster[ cy * KSPREAD_CLUSTER_LEVEL2 + cx ]; + if ( cl ) + for( int dx = 0; dx < KSPREAD_CLUSTER_LEVEL2; ++dx ) + if ( cl[ dy * KSPREAD_CLUSTER_LEVEL2 + dx ] ) + { + int column = cx * KSPREAD_CLUSTER_LEVEL2 + dx ; + remove( column, row ); + } + } +} + +Value Cluster::valueRange (int col1, int row1, + int col2, int row2) const +{ + Value empty; + + //swap first/second values if needed + if (col1 > col2) + { + int p = col1; col1 = col2; col2 = p; + } + if (row1 > row2) + { + int p = row1; row1 = col2; row2 = p; + } + if ((row1 < 0) || (col1 < 0) || (row2 > KSPREAD_CLUSTER_MAX) || + (col2 > KSPREAD_CLUSTER_MAX)) + return empty; + + // if we are out of range occupied by cells, we return an empty + // array of the requested size + if ((row1 > m_biggestY) || (col1 > m_biggestX)) + { + int cols = col2 - col1 + 1; + int rows = row2 - row1 + 1; + Value array (cols, rows); + return array; + } + + return makeArray (col1, row1, col2, row2); +} + +Value Cluster::makeArray (int col1, int row1, + int col2, int row2) const +{ + // this generates an array of values + // TODO: make this thing faster by skipping empty regions + int cols = col2 - col1 + 1; + int rows = row2 - row1 + 1; + Value array (cols, rows); + for (int row = row1; row <= row2; ++row) + for (int col = col1; col <= col2; ++col) + { + Cell *cell = lookup (col, row); + if (cell) + { + Value val = cell->value(); + array.setElement (col-col1, row-row1, val); + } + } + + //return the result + return array; +} + +Cell* Cluster::getFirstCellColumn(int col) const +{ + Cell* cell = lookup(col, 1); + + if (cell == NULL) + { + cell = getNextCellDown(col, 1); + } + return cell; +} + +Cell* Cluster::getLastCellColumn(int col) const +{ + Cell* cell = lookup(col, KS_rowMax); + + if (cell == NULL) + { + cell = getNextCellUp(col, KS_rowMax); + } + return cell; +} + +Cell* Cluster::getFirstCellRow(int row) const +{ + Cell* cell = lookup(1, row); + + if (cell == NULL) + { + cell = getNextCellRight(1, row); + } + return cell; +} + +Cell* Cluster::getLastCellRow(int row) const +{ + Cell* cell = lookup(KS_colMax, row); + + if (cell == NULL) + { + cell = getNextCellLeft(KS_colMax, row); + } + return cell; +} + +Cell* Cluster::getNextCellUp(int col, int row) const +{ + int cx = col / KSPREAD_CLUSTER_LEVEL2; + int cy = (row - 1) / KSPREAD_CLUSTER_LEVEL2; + int dx = col % KSPREAD_CLUSTER_LEVEL2; + int dy = (row - 1) % KSPREAD_CLUSTER_LEVEL2; + + while (cy >= 0) + { + if ( m_cluster[ cy * KSPREAD_CLUSTER_LEVEL1 + cx ] != NULL ) + { + while (dy >= 0) + { + + if ( m_cluster[ cy*KSPREAD_CLUSTER_LEVEL1 + cx] + [ dy*KSPREAD_CLUSTER_LEVEL2 + dx] != NULL ) + { + return m_cluster[ cy*KSPREAD_CLUSTER_LEVEL1 + cx ] + [ dy*KSPREAD_CLUSTER_LEVEL2 + dx]; + } + dy--; + } + } + cy--; + dy = KSPREAD_CLUSTER_LEVEL2 - 1; + } + return NULL; +} + +Cell* Cluster::getNextCellDown(int col, int row) const +{ + int cx = col / KSPREAD_CLUSTER_LEVEL2; + int cy = (row + 1) / KSPREAD_CLUSTER_LEVEL2; + int dx = col % KSPREAD_CLUSTER_LEVEL2; + int dy = (row + 1) % KSPREAD_CLUSTER_LEVEL2; + + while (cy < KSPREAD_CLUSTER_LEVEL1) + { + if ( m_cluster[ cy * KSPREAD_CLUSTER_LEVEL1 + cx ] != NULL ) + { + while (dy < KSPREAD_CLUSTER_LEVEL2) + { + + if ( m_cluster[ cy*KSPREAD_CLUSTER_LEVEL1 + cx] + [ dy*KSPREAD_CLUSTER_LEVEL2 + dx] != NULL ) + { + return m_cluster[ cy*KSPREAD_CLUSTER_LEVEL1 + cx ] + [ dy*KSPREAD_CLUSTER_LEVEL2 + dx]; + } + dy++; + } + } + cy++; + dy = 0; + } + return NULL; +} + +Cell* Cluster::getNextCellLeft(int col, int row) const +{ + int cx = (col - 1) / KSPREAD_CLUSTER_LEVEL2; + int cy = row / KSPREAD_CLUSTER_LEVEL2; + int dx = (col - 1) % KSPREAD_CLUSTER_LEVEL2; + int dy = row % KSPREAD_CLUSTER_LEVEL2; + + while (cx >= 0) + { + if ( m_cluster[ cy * KSPREAD_CLUSTER_LEVEL1 + cx ] != NULL ) + { + while (dx >= 0) + { + + if ( m_cluster[ cy*KSPREAD_CLUSTER_LEVEL1 + cx] + [ dy*KSPREAD_CLUSTER_LEVEL2 + dx] != NULL ) + { + return m_cluster[ cy*KSPREAD_CLUSTER_LEVEL1 + cx ] + [ dy*KSPREAD_CLUSTER_LEVEL2 + dx]; + } + dx--; + } + } + cx--; + dx = KSPREAD_CLUSTER_LEVEL2 - 1; + } + return NULL; +} + +Cell* Cluster::getNextCellRight(int col, int row) const +{ + int cx = (col + 1) / KSPREAD_CLUSTER_LEVEL2; + int cy = row / KSPREAD_CLUSTER_LEVEL2; + int dx = (col + 1) % KSPREAD_CLUSTER_LEVEL2; + int dy = row % KSPREAD_CLUSTER_LEVEL2; + + while (cx < KSPREAD_CLUSTER_LEVEL1) + { + if ( m_cluster[ cy * KSPREAD_CLUSTER_LEVEL1 + cx ] != NULL ) + { + while (dx < KSPREAD_CLUSTER_LEVEL2) + { + + if ( m_cluster[ cy*KSPREAD_CLUSTER_LEVEL1 + cx] + [ dy*KSPREAD_CLUSTER_LEVEL2 + dx] != NULL ) + { + return m_cluster[ cy*KSPREAD_CLUSTER_LEVEL1 + cx ] + [ dy*KSPREAD_CLUSTER_LEVEL2 + dx]; + } + dx++; + } + } + cx++; + dx = 0; + } + return NULL; +} + +/**************************************************** + * + * ColumnCluster + * + ****************************************************/ + +ColumnCluster::ColumnCluster() + : m_first( 0 ), m_autoDelete( false ) +{ + m_cluster = (ColumnFormat***)malloc( KSPREAD_CLUSTER_LEVEL1 * sizeof( ColumnFormat** ) ); + + for( int x = 0; x < KSPREAD_CLUSTER_LEVEL1; ++x ) + m_cluster[ x ] = 0; +} + +ColumnCluster::~ColumnCluster() +{ + for( int x = 0; x < KSPREAD_CLUSTER_LEVEL1; ++x ) + { + ColumnFormat** cl = m_cluster[ x ]; + if ( cl ) + { + free( cl ); + m_cluster[ x ] = 0; + } + } + + if ( m_autoDelete ) + { + ColumnFormat* cell = m_first; + while( cell ) + { + ColumnFormat* n = cell->next(); + delete cell; + cell = n; + } + } + + + free( m_cluster ); +} + +ColumnFormat* ColumnCluster::lookup( int col ) +{ + if ( col >= KSPREAD_CLUSTER_MAX || col < 0 ) + { + kdDebug(36001) << "ColumnCluster::lookup: invalid column value (col: " + << col << ")" << endl; + return 0; + } + + int cx = col / KSPREAD_CLUSTER_LEVEL2; + int dx = col % KSPREAD_CLUSTER_LEVEL2; + + ColumnFormat** cl = m_cluster[ cx ]; + if ( !cl ) + return 0; + + return cl[ dx ]; +} + +const ColumnFormat* ColumnCluster::lookup( int col ) const +{ + if ( col >= KSPREAD_CLUSTER_MAX || col < 0 ) + { + kdDebug(36001) << "ColumnCluster::lookup: invalid column value (col: " + << col << ")" << endl; + return 0; + } + + int cx = col / KSPREAD_CLUSTER_LEVEL2; + int dx = col % KSPREAD_CLUSTER_LEVEL2; + + ColumnFormat** cl = m_cluster[ cx ]; + if ( !cl ) + return 0; + + return cl[ dx ]; +} + +void ColumnCluster::clear() +{ + for( int x = 0; x < KSPREAD_CLUSTER_LEVEL1; ++x ) + { + ColumnFormat** cl = m_cluster[ x ]; + if ( cl ) + { + free( cl ); + m_cluster[ x ] = 0; + } + } + + if ( m_autoDelete ) + { + ColumnFormat* cell = m_first; + while( cell ) + { + ColumnFormat* n = cell->next(); + delete cell; + cell = n; + } + } + + m_first = 0; +} + +void ColumnCluster::insertElement( ColumnFormat* lay, int col ) +{ + if ( col >= KSPREAD_CLUSTER_MAX || col < 0 ) + { + kdDebug(36001) << "ColumnCluster::insertElement: invalid column value (col: " + << col << ")" << endl; + return; + } + + int cx = col / KSPREAD_CLUSTER_LEVEL2; + int dx = col % KSPREAD_CLUSTER_LEVEL2; + + ColumnFormat** cl = m_cluster[ cx ]; + if ( !cl ) + { + cl = (ColumnFormat**)malloc( KSPREAD_CLUSTER_LEVEL2 * sizeof( ColumnFormat* ) ); + m_cluster[ cx ] = cl; + + for( int a = 0; a < KSPREAD_CLUSTER_LEVEL2; ++a ) + cl[ a ] = 0; + } + + if ( cl[ dx ] ) + removeElement( col ); + + cl[ dx ] = lay; + + if ( m_first ) + { + lay->setNext( m_first ); + m_first->setPrevious( lay ); + } + m_first = lay; +} + +void ColumnCluster::removeElement( int col ) +{ + if ( col >= KSPREAD_CLUSTER_MAX || col < 0 ) + { + kdDebug(36001) << "ColumnCluster::removeElement: invalid column value (col: " + << col << ")" << endl; + return; + } + + int cx = col / KSPREAD_CLUSTER_LEVEL2; + int dx = col % KSPREAD_CLUSTER_LEVEL2; + + ColumnFormat** cl = m_cluster[ cx ]; + if ( !cl ) + return; + + ColumnFormat* c = cl[ dx ]; + if ( !c ) + return; + + cl[ dx ] = 0; + + if ( m_autoDelete ) + { + if ( m_first == c ) + m_first = c->next(); + delete c; + } + else + { + if ( m_first == c ) + m_first = c->next(); + if ( c->previous() ) + c->previous()->setNext( c->next() ); + if ( c->next() ) + c->next()->setPrevious( c->previous() ); + c->setNext( 0 ); + c->setPrevious( 0 ); + } +} + +bool ColumnCluster::insertColumn( int col ) +{ + if ( col >= KSPREAD_CLUSTER_MAX || col < 0 ) + { + kdDebug(36001) << "ColumnCluster::insertColumn: invalid column value (col: " + << col << ")" << endl; + return false; + } + + int cx = col / KSPREAD_CLUSTER_LEVEL2; + int dx = col % KSPREAD_CLUSTER_LEVEL2; + + // Is there a column layout at the right most position ? + // In this case the shift is impossible. + ColumnFormat** cl = m_cluster[ KSPREAD_CLUSTER_LEVEL1 - 1 ]; + if ( cl && cl[ KSPREAD_CLUSTER_LEVEL2 - 1 ] ) + return false; + + bool a = autoDelete(); + setAutoDelete( false ); + + for( int i = KSPREAD_CLUSTER_LEVEL1 - 1; i >= cx ; --i ) + { + ColumnFormat** cl = m_cluster[ i ]; + if ( cl ) + { + int left = 0; + if ( i == cx ) + left = dx; + int right = KSPREAD_CLUSTER_LEVEL2 - 1; + if ( i == KSPREAD_CLUSTER_LEVEL1 - 1 ) + right = KSPREAD_CLUSTER_LEVEL2 - 2; + for( int k = right; k >= left; --k ) + { + ColumnFormat* c = cl[ k ]; + if ( c ) + { + removeElement( c->column() ); + c->setColumn( c->column() + 1 ); + insertElement( c, c->column() ); + } + } + } + } + + setAutoDelete( a ); + + return true; +} + +bool ColumnCluster::removeColumn( int column ) +{ + if ( column >= KSPREAD_CLUSTER_MAX || column < 0 ) + { + kdDebug(36001) << "ColumnCluster::removeColumn: invalid column value (col: " + << column << ")" << endl; + return false; + } + + int cx = column / KSPREAD_CLUSTER_LEVEL2; + int dx = column % KSPREAD_CLUSTER_LEVEL2; + + removeElement( column ); + + bool a = autoDelete(); + setAutoDelete( false ); + + for( int i = cx; i < KSPREAD_CLUSTER_LEVEL1; ++i ) + { + ColumnFormat** cl = m_cluster[ i ]; + if ( cl ) + { + int left = 0; + if ( i == cx ) + left = dx + 1; + int right = KSPREAD_CLUSTER_LEVEL2 - 1; + for( int k = left; k <= right; ++k ) + { + ColumnFormat* c = cl[ k ]; + if ( c ) + { + removeElement( c->column() ); + c->setColumn( c->column() - 1 ); + insertElement( c, c->column() ); + } + } + } + } + + setAutoDelete( a ); + + return true; +} + +void ColumnCluster::setAutoDelete( bool a ) +{ + m_autoDelete = a; +} + +bool ColumnCluster::autoDelete() const +{ + return m_autoDelete; +} + +ColumnFormat* ColumnCluster::next( int col ) const +{ + if ( col >= KSPREAD_CLUSTER_MAX || col < 0 ) + { + kdDebug(36001) << "ColumnCluster::next: invalid column value (col: " + << col << ")" << endl; + return 0; + } + + int cx = (col + 1) / KSPREAD_CLUSTER_LEVEL2; + int dx = (col + 1) % KSPREAD_CLUSTER_LEVEL2; + + while ( cx < KSPREAD_CLUSTER_LEVEL1 ) + { + if ( m_cluster[ cx ] ) + { + while ( dx < KSPREAD_CLUSTER_LEVEL2 ) + { + + if ( m_cluster[ cx ][ dx ] ) + { + return m_cluster[ cx ][ dx ]; + } + ++dx; + } + } + ++cx; + dx = 0; + } + return 0; +} + +/**************************************************** + * + * RowCluster + * + ****************************************************/ + +RowCluster::RowCluster() + : m_first( 0 ), m_autoDelete( false ) +{ + m_cluster = (RowFormat***)malloc( KSPREAD_CLUSTER_LEVEL1 * sizeof( RowFormat** ) ); + + for( int x = 0; x < KSPREAD_CLUSTER_LEVEL1; ++x ) + m_cluster[ x ] = 0; +} + +RowCluster::~RowCluster() +{ + for( int x = 0; x < KSPREAD_CLUSTER_LEVEL1; ++x ) + { + RowFormat** cl = m_cluster[ x ]; + if ( cl ) + { + free( cl ); + m_cluster[ x ] = 0; + } + } + + if ( m_autoDelete ) + { + RowFormat* cell = m_first; + while( cell ) + { + RowFormat* n = cell->next(); + delete cell; + cell = n; + } + } + + free( m_cluster ); +} + +const RowFormat* RowCluster::lookup( int row ) const +{ + if ( row >= KSPREAD_CLUSTER_MAX || row < 0 ) + { + kdDebug(36001) << "RowCluster::lookup: invalid row value (row: " + << row << ")" << endl; + return 0; + } + + int cx = row / KSPREAD_CLUSTER_LEVEL2; + int dx = row % KSPREAD_CLUSTER_LEVEL2; + + RowFormat** cl = m_cluster[ cx ]; + if ( !cl ) + return 0; + + return cl[ dx ]; +} + +RowFormat* RowCluster::lookup( int row ) +{ + if ( row >= KSPREAD_CLUSTER_MAX || row < 0 ) + { + kdDebug(36001) << "RowCluster::lookup: invalid row value (row: " + << row << ")" << endl; + return 0; + } + + int cx = row / KSPREAD_CLUSTER_LEVEL2; + int dx = row % KSPREAD_CLUSTER_LEVEL2; + + RowFormat** cl = m_cluster[ cx ]; + if ( !cl ) + return 0; + + return cl[ dx ]; +} + +void RowCluster::clear() +{ + for( int x = 0; x < KSPREAD_CLUSTER_LEVEL1; ++x ) + { + RowFormat** cl = m_cluster[ x ]; + if ( cl ) + { + free( cl ); + m_cluster[ x ] = 0; + } + } + + if ( m_autoDelete ) + { + RowFormat* cell = m_first; + while( cell ) + { + RowFormat* n = cell->next(); + delete cell; + cell = n; + } + } + + m_first = 0; +} + +void RowCluster::insertElement( RowFormat* lay, int row ) +{ + if ( row >= KSPREAD_CLUSTER_MAX || row < 0 ) + { + kdDebug(36001) << "RowCluster::insertElement: invalid row value (row: " + << row << ")" << endl; + return; + } + + int cx = row / KSPREAD_CLUSTER_LEVEL2; + int dx = row % KSPREAD_CLUSTER_LEVEL2; + + RowFormat** cl = m_cluster[ cx ]; + if ( !cl ) + { + cl = (RowFormat**)malloc( KSPREAD_CLUSTER_LEVEL2 * sizeof( RowFormat* ) ); + m_cluster[ cx ] = cl; + + for( int a = 0; a < KSPREAD_CLUSTER_LEVEL2; ++a ) + cl[ a ] = 0; + } + + if ( cl[ dx ] ) + removeElement( row ); + + cl[ dx ] = lay; + + if ( m_first ) + { + lay->setNext( m_first ); + m_first->setPrevious( lay ); + } + m_first = lay; +} + +void RowCluster::removeElement( int row ) +{ + if ( row >= KSPREAD_CLUSTER_MAX || row < 0 ) + { + kdDebug(36001) << "RowCluster::removeElement: invalid row value (row: " + << row << ")" << endl; + return; + } + + int cx = row / KSPREAD_CLUSTER_LEVEL2; + int dx = row % KSPREAD_CLUSTER_LEVEL2; + + RowFormat** cl = m_cluster[ cx ]; + if ( !cl ) + return; + + RowFormat* c = cl[ dx ]; + if ( !c ) + return; + + cl[ dx ] = 0; + + if ( m_autoDelete ) + { + if ( m_first == c ) + m_first = c->next(); + delete c; + } + else + { + if ( m_first == c ) + m_first = c->next(); + if ( c->previous() ) + c->previous()->setNext( c->next() ); + if ( c->next() ) + c->next()->setPrevious( c->previous() ); + c->setNext( 0 ); + c->setPrevious( 0 ); + } +} + +bool RowCluster::insertRow( int row ) +{ + if ( row >= KSPREAD_CLUSTER_MAX || row < 0 ) + { + kdDebug(36001) << "RowCluster::insertRow: invalid row value (row: " + << row << ")" << endl; + return false; + } + + int cx = row / KSPREAD_CLUSTER_LEVEL2; + int dx = row % KSPREAD_CLUSTER_LEVEL2; + + // Is there a row layout at the bottom most position ? + // In this case the shift is impossible. + RowFormat** cl = m_cluster[ KSPREAD_CLUSTER_LEVEL1 - 1 ]; + if ( cl && cl[ KSPREAD_CLUSTER_LEVEL2 - 1 ] ) + return false; + + bool a = autoDelete(); + setAutoDelete( false ); + + for( int i = KSPREAD_CLUSTER_LEVEL1 - 1; i >= cx ; --i ) + { + RowFormat** cl = m_cluster[ i ]; + if ( cl ) + { + int left = 0; + if ( i == cx ) + left = dx; + int right = KSPREAD_CLUSTER_LEVEL2 - 1; + if ( i == KSPREAD_CLUSTER_LEVEL1 - 1 ) + right = KSPREAD_CLUSTER_LEVEL2 - 2; + for( int k = right; k >= left; --k ) + { + RowFormat* c = cl[ k ]; + if ( c ) + { + removeElement( c->row() ); + c->setRow( c->row() + 1 ); + insertElement( c, c->row() ); + } + } + } + } + + setAutoDelete( a ); + + return true; +} + +bool RowCluster::removeRow( int row ) +{ + if ( row >= KSPREAD_CLUSTER_MAX || row < 0 ) + { + kdDebug(36001) << "RowCluster::removeRow: invalid row value (row: " + << row << ")" << endl; + return false; + } + + int cx = row / KSPREAD_CLUSTER_LEVEL2; + int dx = row % KSPREAD_CLUSTER_LEVEL2; + + removeElement( row ); + + bool a = autoDelete(); + setAutoDelete( false ); + + for( int i = cx; i < KSPREAD_CLUSTER_LEVEL1; ++i ) + { + RowFormat** cl = m_cluster[ i ]; + if ( cl ) + { + int left = 0; + if ( i == cx ) + left = dx + 1; + int right = KSPREAD_CLUSTER_LEVEL2 - 1; + for( int k = left; k <= right; ++k ) + { + RowFormat* c = cl[ k ]; + if ( c ) + { + removeElement( c->row() ); + c->setRow( c->row() - 1 ); + insertElement( c, c->row() ); + } + } + } + } + + setAutoDelete( a ); + + return true; +} + +void RowCluster::setAutoDelete( bool a ) +{ + m_autoDelete = a; +} + +bool RowCluster::autoDelete() const +{ + return m_autoDelete; +} |