/*************************************************************************** * Copyright (C) 2003-2004 by * * Unai Garro (ugarro@users.sourceforge.net) * * * * Copyright (C) 2003-2006 by * * Jason Kivlighn (jkivlighn@gmail.com) * * * * 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 "conversiontable.h" #include "datablocks/mixednumber.h" #include "widgets/fractioninput.h" #include #include #include class ConversionTableToolTip : public TQToolTip { public: ConversionTableToolTip( ConversionTable *t ) : TQToolTip( t->viewport() ), table( t ) {} void maybeTip( const TQPoint &pos ) { if ( !table ) return ; TQPoint cp = table->viewportToContents( pos ); int row = table->rowAt( cp.y() ); int col = table->columnAt( cp.x() ); if ( row == col ) return ; TQString row_unit = table->verticalHeader() ->label( row ); TQString col_unit = table->horizontalHeader() ->label( col ); TQString text = table->text( row, col ); if ( text.isEmpty() ) text = "X"; //### Is this i18n friendly??? TQRect cr = table->cellGeometry( row, col ); cr.moveTopLeft( table->contentsToViewport( cr.topLeft() ) ); tip( cr, TQString( "1 %1 = %2 %3" ).arg( row_unit ).arg( text ).arg( col_unit ) ); } private: ConversionTable *table; }; ConversionTable::ConversionTable( TQWidget* parent, int maxrows, int maxcols ) : TQTable( maxrows, maxcols, parent, "table" ) { editBoxValue = -1; items.setAutoDelete( true ); widgets.setAutoDelete( true ); ( void ) new ConversionTableToolTip( this ); } ConversionTable::~ConversionTable() {} #include void ConversionTable::unitRemoved( int id ) { int index = *unitIDs.find( id ); kdDebug() << "index:" << index << endl; removeRow( index ); removeColumn( index ); kdDebug() << "done" << endl; } void ConversionTable::unitCreated( const Unit &unit ) { insertColumns( numCols() ); insertRows( numRows() ); unitIDs.append( unit.id ); horizontalHeader() ->setLabel( numRows() - 1, unit.name ); verticalHeader() ->setLabel( numCols() - 1, unit.name ); } TQTableItem* ConversionTable::item( int r, int c ) const { return items.find( indexOf( r, c ) ); } void ConversionTable::setItem( int r, int c, TQTableItem *i ) { items.replace( indexOf( r, c ), i ); i->setRow( r ); // Otherwise the item i->setCol( c ); //doesn't know where it is! updateCell( r, c ); } void ConversionTable::clearCell( int r, int c ) { items.remove( indexOf( r, c ) ); } void ConversionTable::takeItem( TQTableItem *item ) { items.setAutoDelete( false ); items.remove( indexOf( item->row(), item->col() ) ); items.setAutoDelete( true ); } void ConversionTable::insertWidget( int r, int c, TQWidget *w ) { widgets.replace( indexOf( r, c ), w ); } TQWidget* ConversionTable::cellWidget( int r, int c ) const { return widgets.find( indexOf( r, c ) ); } void ConversionTable::clearCellWidget( int r, int c ) { TQWidget * w = widgets.take( indexOf( r, c ) ); if ( w ) w->deleteLater(); } ConversionTableItem::ConversionTableItem( TQTable *t, EditType et ) : TQTableItem( t, et, TQString::null ) { // we do not want this item to be replaced setReplaceable( false ); } void ConversionTableItem::paint( TQPainter *p, const TQColorGroup &cg, const TQRect &cr, bool selected ) { TQColorGroup g( cg ); // Draw in gray all those cells which are not editable if ( row() == col() ) g.setColor( TQColorGroup::Base, gray ); TQTableItem::paint( p, g, cr, selected ); } TQWidget* ConversionTableItem::createEditor() const { FractionInput *editor = new FractionInput( table()->viewport(), MixedNumber::DecimalFormat ); MixedNumber current = MixedNumber::fromString(text()); if ( current.toDouble() > 1e-8 ) editor->setValue( current, 0 ); return editor; } void ConversionTableItem::setContentFromEditor( TQWidget *w ) { // the user changed the value of the combobox, so synchronize the // value of the item (its text), with the value of the combobox if ( w->inherits( "FractionInput" ) ) { FractionInput* editor = ( FractionInput* ) w; if ( editor->isInputValid() && !editor->isEmpty() && editor->value().toDouble() > 1e-6 ) { setText( editor->value().toString(MixedNumber::DecimalFormat) ); emit ratioChanged( row(), col(), editor->value().toDouble() ); // Signal to store } else { setText( TQString::null ); emit ratioRemoved( row(), col() ); } } else TQTableItem::setContentFromEditor( w ); } void ConversionTableItem::setText( const TQString &s ) { TQTableItem::setText( s ); } TQString ConversionTable::text( int r, int c ) const // without this function, the usual (text(r,c)) won't work { if ( item( r, c ) ) return item( r, c ) ->text(); //Note that item(r,c) was reimplemented here for large sparse tables... else return TQString::null; } void ConversionTable::initTable() { for ( int r = 0;r < numRows();r++ ) { this->createNewItem( r, r, 1.0 ); item( r, r ) ->setEnabled( false ); // Diagonal is not editable } } void ConversionTable::createNewItem( int r, int c, double amount ) { ConversionTableItem * ci = new ConversionTableItem( this, TQTableItem::WhenCurrent ); ci->setText( beautify( TDEGlobal::locale() ->formatNumber( amount, 5 ) ) ); setItem( r, c, ci ); // connect signal (forward) to know when it's actually changed connect( ci, TQ_SIGNAL( ratioChanged( int, int, double ) ), this, TQ_SIGNAL( ratioChanged( int, int, double ) ) ); connect( ci, TQ_SIGNAL( ratioRemoved( int, int ) ), this, TQ_SIGNAL( ratioRemoved( int, int ) ) ); connect( ci, TQ_SIGNAL( signalRepaintCell( int, int ) ), this, TQ_SLOT( repaintCell( int, int ) ) ); } void ConversionTable::setUnitIDs( const IDList &idList ) { unitIDs = idList; } void ConversionTable::setRatio( int ingID1, int ingID2, double ratio ) { int indexID1 = unitIDs.findIndex( ingID1 ); int indexID2 = unitIDs.findIndex( ingID2 ); createNewItem( indexID1, indexID2, ratio ); } int ConversionTable::getUnitID( int rc ) { return ( *( unitIDs.at( rc ) ) ); } TQWidget * ConversionTable::beginEdit ( int row, int col, bool replace ) { // If there's no item, create it first. if ( !item( row, col ) ) { createNewItem( row, col, 0 ); } // Then call normal beginEdit return TQTable::beginEdit( row, col, replace ); } void ConversionTableItem::setTextAndSave( const TQString &s ) { setText( s ); // Change text emit signalRepaintCell( row(), col() ); // Indicate to update the cell to the table. Otherwise it's not repainted emit ratioChanged( row(), col(), s.toDouble() ); // Signal to store } void ConversionTable::repaintCell( int r, int c ) { TQTable::updateCell( r, c ); } void ConversionTable::resize( int r, int c ) { setNumRows( r ); setNumCols( c ); initTable(); } void ConversionTable::clear( void ) { items.clear(); widgets.clear(); unitIDs.clear(); resize( 0, 0 ); } //TODO this is incomplete/wrong void ConversionTable::swapRows( int row1, int row2, bool /*swapHeader*/ ) { //if ( swapHeader ) //((TQTableHeader*)verticalHeader())->swapSections( row1, row2, FALSE ); TQPtrVector tmpContents; tmpContents.resize( numCols() ); TQPtrVector tmpWidgets; tmpWidgets.resize( numCols() ); int i; items.setAutoDelete( FALSE ); widgets.setAutoDelete( FALSE ); for ( i = 0; i < numCols(); ++i ) { TQTableItem *i1, *i2; i1 = item( row1, i ); i2 = item( row2, i ); if ( i1 || i2 ) { tmpContents.insert( i, i1 ); items.remove( indexOf( row1, i ) ); items.insert( indexOf( row1, i ), i2 ); items.remove( indexOf( row2, i ) ); items.insert( indexOf( row2, i ), tmpContents[ i ] ); if ( items[ indexOf( row1, i ) ] ) items[ indexOf( row1, i ) ] ->setRow( row1 ); if ( items[ indexOf( row2, i ) ] ) items[ indexOf( row2, i ) ] ->setRow( row2 ); } TQWidget *w1, *w2; w1 = cellWidget( row1, i ); w2 = cellWidget( row2, i ); if ( w1 || w2 ) { tmpWidgets.insert( i, w1 ); widgets.remove( indexOf( row1, i ) ); widgets.insert( indexOf( row1, i ), w2 ); widgets.remove( indexOf( row2, i ) ); widgets.insert( indexOf( row2, i ), tmpWidgets[ i ] ); } } items.setAutoDelete( FALSE ); widgets.setAutoDelete( TRUE ); //updateRowWidgets( row1 ); //updateRowWidgets( row2 ); /* if ( curRow == row1 ) curRow = row2; else if ( curRow == row2 ) curRow = row1; if ( editRow == row1 ) editRow = row2; else if ( editRow == row2 ) editRow = row1;*/ } //TODO this is incomplete/wrong void ConversionTable::swapColumns( int col1, int col2, bool /*swapHeader*/ ) { //if ( swapHeader ) //((TQTableHeader*)horizontalHeader())->swapSections( col1, col2, FALSE ); TQPtrVector tmpContents; tmpContents.resize( numRows() ); TQPtrVector tmpWidgets; tmpWidgets.resize( numRows() ); int i; items.setAutoDelete( FALSE ); widgets.setAutoDelete( FALSE ); for ( i = 0; i < numRows(); ++i ) { TQTableItem *i1, *i2; i1 = item( i, col1 ); i2 = item( i, col2 ); if ( i1 || i2 ) { tmpContents.insert( i, i1 ); items.remove( indexOf( i, col1 ) ); items.insert( indexOf( i, col1 ), i2 ); items.remove( indexOf( i, col2 ) ); items.insert( indexOf( i, col2 ), tmpContents[ i ] ); if ( items[ indexOf( i, col1 ) ] ) items[ indexOf( i, col1 ) ] ->setCol( col1 ); if ( items[ indexOf( i, col2 ) ] ) items[ indexOf( i, col2 ) ] ->setCol( col2 ); } TQWidget *w1, *w2; w1 = cellWidget( i, col1 ); w2 = cellWidget( i, col2 ); if ( w1 || w2 ) { tmpWidgets.insert( i, w1 ); widgets.remove( indexOf( i, col1 ) ); widgets.insert( indexOf( i, col1 ), w2 ); widgets.remove( indexOf( i, col2 ) ); widgets.insert( indexOf( i, col2 ), tmpWidgets[ i ] ); } } items.setAutoDelete( FALSE ); widgets.setAutoDelete( TRUE ); columnWidthChanged( col1 ); columnWidthChanged( col2 ); /* if ( curCol == col1 ) curCol = col2; else if ( curCol == col2 ) curCol = col1; if ( editCol == col1 ) editCol = col2; else if ( editCol == col2 ) editCol = col1;*/ } //TODO this is incomplete/wrong void ConversionTable::swapCells( int row1, int col1, int row2, int col2 ) { items.setAutoDelete( FALSE ); widgets.setAutoDelete( FALSE ); TQTableItem *i1, *i2; i1 = item( row1, col1 ); i2 = item( row2, col2 ); if ( i1 || i2 ) { TQTableItem * tmp = i1; items.remove( indexOf( row1, col1 ) ); items.insert( indexOf( row1, col1 ), i2 ); items.remove( indexOf( row2, col2 ) ); items.insert( indexOf( row2, col2 ), tmp ); if ( items[ indexOf( row1, col1 ) ] ) { items[ indexOf( row1, col1 ) ] ->setRow( row1 ); items[ indexOf( row1, col1 ) ] ->setCol( col1 ); } if ( items[ indexOf( row2, col2 ) ] ) { items[ indexOf( row2, col2 ) ] ->setRow( row2 ); items[ indexOf( row2, col2 ) ] ->setCol( col2 ); } } TQWidget *w1, *w2; w1 = cellWidget( row1, col1 ); w2 = cellWidget( row2, col2 ); if ( w1 || w2 ) { TQWidget * tmp = w1; widgets.remove( indexOf( row1, col1 ) ); widgets.insert( indexOf( row1, col1 ), w2 ); widgets.remove( indexOf( row2, col2 ) ); widgets.insert( indexOf( row2, col2 ), tmp ); } //updateRowWidgets( row1 ); //updateRowWidgets( row2 ); //updateColWidgets( col1 ); //updateColWidgets( col2 ); items.setAutoDelete( FALSE ); widgets.setAutoDelete( TRUE ); } #include "conversiontable.moc"