/*************************************************************************** ksmatrix.cpp ------------------- begin : 01-January-2000 copyright : (C) 2000 by Kamil Dobkowski email : kamildobk@poczta.onet.pl ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include"ksmatrix.h" #include"widgets/qsdata.h" #include"widgets/qsconsole.h" #include"formula/mpformula.h" #include"ksworkbook.h" #include"ksglobalmatrixlist.h" #include #include #include /** * Reference points to QSData::channel ! */ //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// KSMatrix *KSMatrix::create( EType elementType ) { switch( elementType ) { case EUChar: return new KSMatrixImpl(EUChar); case EUShort: return new KSMatrixImpl(EUShort); case EShort: return new KSMatrixImpl(EShort); case ELong: return new KSMatrixImpl(ELong); case EFloat: return new KSMatrixImpl(EFloat); case EDouble: return new KSMatrixImpl(EDouble); } return NULL; } //-------------------------------------------------------------// // // Flexible, but too much complicated // Drop line_offset and pixel_offset and make some template specializations with '<<' instead of '*' ( used in DDE with Octave ) // KSMatrix::KSMatrix( EType elementType ) :QSMatrix() { m_type = elementType; m_rows = 0; m_cols = 0; m_ptr = NULL; m_lo = 0; m_po = 0; m_delete = true; } //-------------------------------------------------------------// EType KSMatrix::detectType() { double max = 0.0; double min = 0.0; EType type = EUChar; for( int r=0; rval?val:min; } } if ( type == ELong && min >= 0x0 && max <= 0xffff ) type = EUShort; return type; } //-------------------------------------------------------------// KSMatrix::~KSMatrix() { if ( m_delete ) delete m_ptr; } //-------------------------------------------------------------// bool KSMatrix::isEditable() const { return true; } //-------------------------------------------------------------/ EType KSMatrix::type() const { return m_type; } //-------------------------------------------------------------// KSMatrix *KSMatrix::convertType( EType newType ) { KSMatrix *result = KSMatrix::create( newType ); result->setName( name() ); result->setDataObject( dataObject(), channel() ); result->setRawData( new char[m_rows*m_cols*result->elementSize()], m_rows, m_cols, true ); for ( int crow=0; crowsetValue( crow, ccol, value(crow,ccol) ); return result; } //-------------------------------------------------------------// bool KSMatrix::resize( int rows, int cols ) { if ( rows <= 0 || cols <= 0 ) { setRawData( NULL, 0, 0 ); } else { KSMatrix *new_data = KSMatrix::create( m_type ); new_data->setRawData( new char[rows*cols*new_data->elementSize()], rows, cols, false ); for ( int crow=0; crowrows(); crow++ ) for ( int ccol=0; ccolcols(); ccol++ ) if ( crowsetValue( crow, ccol, value(crow,ccol) ); else new_data->setValue( crow, ccol, 0.0 ); setRawData( new_data->ptr(), new_data->rows(), new_data->cols(), true ); delete new_data; } return true; } //-------------------------------------------------------------// bool KSMatrix::transpose() { int temp; temp = m_rows; m_rows = m_cols; m_cols = temp; temp = m_lo; m_lo = m_po; m_po = temp; return true; } //-------------------------------------------------------------// void KSMatrix::setRawData( void *ptr, int rows, int cols, bool deleteData, int lineOffset, int pixelOffset ) { if ( m_delete ) delete m_ptr; m_ptr = (char *)ptr; m_rows = rows; m_cols = cols; m_delete = deleteData; m_po = pixelOffset ? pixelOffset : elementSize(); m_lo = lineOffset ? lineOffset : m_po*cols; } //-------------------------------------------------------------// void KSMatrix::setMatrix( QSMatrix *matrix ) { setRawData( new char[matrix->rows()*matrix->cols()*elementSize()], matrix->rows(), matrix->cols(), true ); for ( int crow=0; crowvalue(crow,ccol) ); } //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// KSMatrixString::KSMatrixString() { m_rows = 0; m_cols = 0; m_transposed = false; m_string_table = NULL; } //-------------------------------------------------------------// KSMatrixString::~KSMatrixString() { delete[] m_string_table; } //-------------------------------------------------------------// bool KSMatrixString::isEditable() const { return true; } //-------------------------------------------------------------// bool KSMatrixString::isString() const { return true; } //-------------------------------------------------------------// void KSMatrixString::setValue( int row, int col, double value ) { setString( row, col, QString::number(value,'g',9) ); } //-------------------------------------------------------------// double KSMatrixString::value( int row, int col ) { return string(row,col).toDouble(); } //-------------------------------------------------------------// int KSMatrixString::cols() const { return m_transposed ? m_rows : m_cols; } //-------------------------------------------------------------// int KSMatrixString::rows() const { return m_transposed ? m_cols : m_rows; } //-------------------------------------------------------------// void KSMatrixString::setString( int row, int col, const QString& string ) { if ( m_transposed ) m_string_table[ col*m_cols+row ] = string; else m_string_table[ row*m_cols+col ] = string; } //-------------------------------------------------------------// QString KSMatrixString::string( int row, int col ) { return m_transposed ? m_string_table[col*m_cols+row] : m_string_table[row*m_cols+col]; } //-------------------------------------------------------------// bool KSMatrixString::resize( int new_rows, int new_cols ) { QString *new_string_table = new QString[new_rows*new_cols]; for( int curr_row=0; curr_rowrows(); m_cols = matrix->cols(); m_transposed = false; m_string_table = new QString[m_rows*m_cols]; for ( int crow=0; crowstring(crow,ccol) ); } //-------------------------------------------------------------// void KSMatrixString::loadStateFromStream( QDataStream& stream, QSObjectFactory *factory ) { QSMatrix::loadStateFromStream( stream, factory ); int new_rows; stream >> new_rows; int new_cols; stream >> new_cols; resize( new_rows, new_cols ); for( int row=0; row> element; setString( row, col, element ); } } //-------------------------------------------------------------// void KSMatrixString::saveStateToStream( QDataStream& stream, QSObjectFactory *factory ) { QSMatrix::saveStateToStream( stream, factory ); stream << (int )rows(); stream << (int )cols(); for( int row=0; rowsetValue( m_start_col+col*m_ref_col_step, m_start_row+row*m_ref_row_step, value ); else m_ref_matrix->setValue( m_start_row+row*m_ref_row_step, m_start_col+col*m_ref_col_step, value ); m_in_loop = false; } } //-------------------------------------------------------------// double KSMatrixRef::value( int row, int col ) { double result; if ( !m_in_loop ) { m_in_loop = true; if ( m_transposition ) result = m_ref_matrix->value( m_start_col+col*m_ref_col_step, m_start_row+row*m_ref_row_step ); else result = m_ref_matrix->value( m_start_row+row*m_ref_row_step, m_start_col+col*m_ref_col_step ); m_in_loop = false; } else { result = sqrt(-1.0); } return result; } //-------------------------------------------------------------// void KSMatrixRef::setString( int row, int col, const QString& string ) { if ( !m_in_loop ) { m_in_loop = true; if ( m_transposition ) m_ref_matrix->setString( m_start_col+col*m_ref_col_step, m_start_row+row*m_ref_row_step, string ); else m_ref_matrix->setString( m_start_row+row*m_ref_row_step, m_start_col+col*m_ref_col_step, string ); m_in_loop = false; } } //-------------------------------------------------------------// QString KSMatrixRef::string( int row, int col ) { QString result; if ( !m_in_loop ) { m_in_loop = true; if ( m_transposition ) result = m_ref_matrix->string( m_start_col+col*m_ref_col_step, m_start_row+row*m_ref_row_step ); else result = m_ref_matrix->string( m_start_row+row*m_ref_row_step, m_start_col+col*m_ref_col_step ); m_in_loop = false; } return result; } //-------------------------------------------------------------// void KSMatrixRef::reconnect( QSData *dataObject, int channel ) { if ( m_in_loop ) QSConsole::write( "Kmatplot: Circular reference !" ); else if ( m_ref_object && m_ref_object == dataObject && (m_ref_channel == channel || channel == -1) ) // our referenced object changed { m_in_loop = true; dataChanging(); reconnect(); dataChanged(); m_in_loop = false; } } //-------------------------------------------------------------// void KSMatrixRef::reconnect() { m_ref_matrix = m_ref_object->matrix( m_ref_channel ); int ref_rows = m_ref_matrix ? m_ref_matrix->rows() : 0; int ref_cols = m_ref_matrix ? m_ref_matrix->cols() : 0; m_start_row = ( m_ref_row_from == -1 ) ? ref_rows-1 : m_ref_row_from; m_start_col = ( m_ref_col_from == -1 ) ? ref_cols-1 : m_ref_col_from; int end_row = ( m_ref_row_to == -1 ) ? ref_rows-1 : m_ref_row_to; int end_col = ( m_ref_col_to == -1 ) ? ref_cols-1 : m_ref_col_to; if ( m_ref_row_step > 0 ) { m_start_row = QMAX( m_start_row, 0 ); end_row = QMIN( end_row, ref_rows-1 ); m_rows = ( end_row - m_start_row ) / m_ref_row_step + 1; } else { m_start_row = QMIN( m_start_row, ref_rows-1 ); end_row = QMAX( end_row, 0 ); m_rows = ( end_row - m_start_row ) / m_ref_row_step + 1; } if ( m_ref_col_step > 0 ) { m_start_col = QMAX( m_start_col, 0 ); end_col = QMIN( end_col, ref_cols-1 ); m_cols = ( end_col - m_start_col ) / m_ref_col_step + 1; } else { m_start_col = QMIN( m_start_col, ref_cols-1 ); end_col = QMAX( end_col, 0 ); m_cols = ( end_col - m_start_col ) / m_ref_col_step + 1; } m_rows = QMAX( m_rows, 0 ); m_cols = QMAX( m_cols, 0 ); if ( m_transposition ) { int temp = m_cols; m_cols = m_rows; m_rows = temp; } if ( m_rows*m_cols == 0 ) m_rows = m_cols = 0; m_ref_editable = m_ref_matrix ? m_ref_matrix->isEditable() : false; m_ref_string = m_ref_matrix ? m_ref_matrix->isString() : false; } //-------------------------------------------------------------// void KSMatrixRef::break_connection( QSData *dataObject ) { if ( m_in_loop ) QSConsole::write( "Kmatplot: Circular reference !" ); else if ( m_ref_object && m_ref_object == dataObject ) { m_in_loop = true; dataChanging(); m_rows = 0; m_cols = 0; m_start_row = 0; m_start_col = 0; m_ref_matrix = NULL; m_ref_object = NULL; m_ref_channel = 0; m_in_loop = false; m_ref_editable = false; m_ref_string = false; dataChanged(); m_in_loop = false; } } //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// KSMatrixWorksheetCellRange::KSMatrixWorksheetCellRange( KSWorkbook *workbook ) : KSMatrixRef() { m_workbook = workbook; } //-------------------------------------------------------------// KSMatrixWorksheetCellRange::~KSMatrixWorksheetCellRange() { // unregister KSSheet *curr_sheet = dynamic_cast(refObject()); if ( curr_sheet ) curr_sheet->cellRangeRemove( this ); } //-------------------------------------------------------------// void KSMatrixWorksheetCellRange::setWorksheet( int index ) { KSSheet *sheet = m_workbook->sheets()->child(index); if ( sheet != refObject() ) { KSSheet *curr_sheet = dynamic_cast(refObject()); KSSheet *new_sheet = m_workbook->sheets()->child(index); if ( curr_sheet ) curr_sheet->cellRangeRemove( this ); setRefObject( new_sheet, 0, rowFrom(), rowStep(), rowTo(), colFrom(), colStep(), colTo(), transposition() ); if ( new_sheet ) new_sheet->cellRangeAdd( this ); } } //-------------------------------------------------------------// int KSMatrixWorksheetCellRange::worksheet() const { return m_workbook->sheets()->childIndex(refObject()); } //-------------------------------------------------------------// void KSMatrixWorksheetCellRange::setColumn( int column ) { setRefObject( refObject(), 0, 0, 1, -1, column, 1, column, transposition() ); } //-------------------------------------------------------------// void KSMatrixWorksheetCellRange::setRowFrom( int row ) { setRefObject( refObject(), 0, row, rowStep(), rowTo(), colFrom(), colStep(), colTo(), transposition() ); } //-------------------------------------------------------------// void KSMatrixWorksheetCellRange::setColFrom( int col ) { setRefObject( refObject(), 0, rowFrom(), rowStep(), rowTo(), col, colStep(), colTo(), transposition() ); } //-------------------------------------------------------------// void KSMatrixWorksheetCellRange::setRowStep( int step ) { setRefObject( refObject(), 0, rowFrom(), step, rowTo(), colFrom(), colStep(), colTo(), transposition() ); } //-------------------------------------------------------------// void KSMatrixWorksheetCellRange::setColStep( int step ) { setRefObject( refObject(), 0, rowFrom(), rowStep(), rowTo(), colFrom(), step, colTo(), transposition() ); } //-------------------------------------------------------------// void KSMatrixWorksheetCellRange::setRowTo( int row ) { setRefObject( refObject(), 0, rowFrom(), rowStep(), row, colFrom(), colStep(), colTo(), transposition() ); } //-------------------------------------------------------------// void KSMatrixWorksheetCellRange::setColTo( int col ) { setRefObject( refObject(), 0, rowFrom(), rowStep(), rowTo(), colFrom(), colStep(), col, transposition() ); } //-------------------------------------------------------------// void KSMatrixWorksheetCellRange::setTransposition( bool enabled ) { setRefObject( refObject(), 0, rowFrom(), rowStep(), rowTo(), colFrom(), colStep(), colTo(), enabled ); } //-------------------------------------------------------------// void KSMatrixWorksheetCellRange::loadStateFromStream( QDataStream& stream, QSObjectFactory *factory ) { KSMatrixRef::loadStateFromStream( stream, factory ); } //-------------------------------------------------------------// void KSMatrixWorksheetCellRange::saveStateToStream( QDataStream& stream, QSObjectFactory *factory ) { KSMatrixRef::saveStateToStream( stream, factory ); } //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// KSMatrixFormula::KSMatrixFormula() :QSMatrix() { m_formula = "0:1:10"; m_rows = 0; m_cols = 0; m_data = NULL; m_row_offset = 0; m_col_offset = 0; m_transposition = false; } //-------------------------------------------------------------// KSMatrixFormula::~KSMatrixFormula() { delete m_data; } //-------------------------------------------------------------// void KSMatrixFormula::setFormula( const QString& formula ) { m_formula = formula; } //-------------------------------------------------------------// bool KSMatrixFormula::init( MPError& error, MPFactoryList *locals ) { delete m_data; m_rows = 0; m_cols = 0; m_data = NULL; m_row_offset = 0; m_col_offset = 0; MPFormula f; MPSymbol *s = f.parse( m_formula, error, locals ); if ( s ) { m_cols = s->cols(); m_rows = s->rows(); m_row_offset = m_cols; m_col_offset = 1; m_data = new double[m_rows*m_cols]; for( int row=0; rowvalue(row,col); if ( m_transposition ) { transpose(); m_transposition = true; } delete s; return true; } return false; } //-------------------------------------------------------------// double KSMatrixFormula::value( int row, int col ) { return *(m_data + m_row_offset*row + m_col_offset*col); } //-------------------------------------------------------------// bool KSMatrixFormula::transpose() { int temp; temp = m_rows; m_rows = m_cols; m_cols = temp; temp = m_row_offset; m_row_offset = m_col_offset; m_col_offset = temp; m_transposition = !m_transposition; return true; } //-------------------------------------------------------------// void KSMatrixFormula::setTransposition( bool enabled ) { if ( enabled != m_transposition ) { transpose(); } } //-------------------------------------------------------------------------// //-------------------------------------------------------------------------// //-------------------------------------------------------------------------// //-------------------------------------------------------------------------// //-------------------------------------------------------------------------// MPSymQSMatrix::MPSymQSMatrix( QSMatrix *matrix, MPSymbolList *args, int columnFrom, int columnTo, const char *id ) : MPSymbol( args, columnFrom, columnTo, id ) { m_matrix = matrix; m_range = QRect(0,0,-1,-1); } //-------------------------------------------------------------------------// MPSymQSMatrix::MPSymQSMatrix( QSMatrix *matrix, const QRect& range, MPSymbolList *args, int columnFrom, int columnTo, const char *id ) : MPSymbol( args, columnFrom, columnTo, id ) { m_matrix = matrix; m_range = range; } //-------------------------------------------------------------------------// MPSymQSMatrix::~MPSymQSMatrix() { } //-------------------------------------------------------------------------// void MPSymQSMatrix::checkArgs( MPError& ) { m_matrix_row_max = m_matrix->rows()-1; m_matrix_col_max = m_matrix->cols()-1; if ( m_range.isEmpty() ) { m_rows = m_matrix->rows(); m_cols = m_matrix->cols(); } else { m_rows = m_range.height(); m_cols = m_range.width(); } } //-------------------------------------------------------------------------// double MPSymQSMatrix::value( int row, int col ) { return m_matrix->value( QMIN(row+m_range.top(), m_matrix_row_max ), QMIN(col+m_range.left(), m_matrix_col_max ) ); } //-------------------------------------------------------------------------//