• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdeutils
  • Sitemap
  • Contact Us
 

okteta

abstractbytearraycolumnrenderer.cpp

Go to the documentation of this file.
00001 /*
00002     This file is part of the Okteta Gui library, part of the KDE project.
00003 
00004     Copyright 2003,2007,2008 Friedrich W. H. Kossebau <kossebau@kde.org>
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Lesser General Public
00008     License as published by the Free Software Foundation; either
00009     version 2.1 of the License, or (at your option) version 3, or any
00010     later version accepted by the membership of KDE e.V. (or its
00011     successor approved by the membership of KDE e.V.), which shall
00012     act as a proxy defined in Section 6 of version 3 of the license.
00013 
00014     This library is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017     Lesser General Public License for more details.
00018 
00019     You should have received a copy of the GNU Lesser General Public
00020     License along with this library. If not, see <http://www.gnu.org/licenses/>.
00021 */
00022 
00023 #include "abstractbytearraycolumnrenderer.h"
00024 
00025 // lib
00026 #include "kdatacursor.h"
00027 #include "bytearraytablelayout.h"
00028 #include "kdataranges.h"
00029 #include "helper.h"
00030 // ColumnsView
00031 #include <columnsview.h>
00032 // Okteta core
00033 #include <kbookmarkable.h>
00034 #include <kcharcodec.h>
00035 // KDE
00036 #include <KColorScheme>
00037 // Qt
00038 #include <QtGui/QPainter>
00039 
00040 
00041 namespace KHEUI
00042 {
00043 
00044 static const unsigned int StartsBefore = 1;
00045 static const unsigned int EndsLater = 2;
00046 static const char EmptyByte = ' ';
00047 
00048 static const KPixelX DefaultCursorWidth = 2;
00049 static const KPixelX DefaultByteSpacingWidth = 3;
00050 static const KPixelX DefaultGroupSpacingWidth = 9;
00051 static const int DefaultNoOfGroupedBytes = 4;
00052 
00053 AbstractByteArrayColumnRenderer::AbstractByteArrayColumnRenderer( ColumnsView *columnsView,
00054     KHECore::KAbstractByteArrayModel *byteArrayModel, ByteArrayTableLayout *layout, KDataRanges *ranges )
00055  : ColumnRenderer( columnsView ),
00056    mByteArrayModel( byteArrayModel ),
00057    mLayout( layout ),
00058    mRanges( ranges ),
00059    mBookmarks( qobject_cast<KHECore::Bookmarkable*>(byteArrayModel) ),
00060    mDigitWidth( 0 ),
00061    mDigitBaseLine( 0 ),
00062    mByteWidth( 0 ),
00063    mByteSpacingWidth( DefaultByteSpacingWidth ),
00064    mGroupSpacingWidth( DefaultGroupSpacingWidth ),
00065    mNoOfGroupedBytes( DefaultNoOfGroupedBytes ),
00066    mLinePosLeftPixelX( 0 ),
00067    mLinePosRightPixelX( 0 ),
00068    mLastLinePos( 0 ),
00069    mByteTypeColored( true )
00070 {
00071 }
00072 
00073 
00074 void AbstractByteArrayColumnRenderer::set( KHECore::KAbstractByteArrayModel *byteArrayModel )
00075 {
00076     mByteArrayModel = byteArrayModel;
00077     mBookmarks = qobject_cast<KHECore::Bookmarkable*>(byteArrayModel );
00078 }
00079 
00080 
00081 void AbstractByteArrayColumnRenderer::resetXBuffer()
00082 {
00083     delete [] mLinePosLeftPixelX;
00084     delete [] mLinePosRightPixelX;
00085 
00086     mLastLinePos = mLayout->noOfBytesPerLine()-1;
00087     mLinePosLeftPixelX =  new KPixelX[mLastLinePos+1];
00088     mLinePosRightPixelX = new KPixelX[mLastLinePos+1];
00089 
00090     if( mLinePosLeftPixelX )
00091         recalcX();
00092 }
00093 
00094 
00095 void AbstractByteArrayColumnRenderer::setMetrics( KPixelX digitWidth, KPixelY DBL )
00096 {
00097     mDigitBaseLine = DBL;
00098     setDigitWidth( digitWidth );
00099 }
00100 
00101 
00102 bool AbstractByteArrayColumnRenderer::setDigitWidth( KPixelX digitWidth )
00103 {
00104     // no changes?
00105     if( mDigitWidth == digitWidth )
00106         return false;
00107 
00108     mDigitWidth = digitWidth;
00109     // recalculate depend sizes
00110     recalcByteWidth();
00111 
00112     if( mLinePosLeftPixelX )
00113         recalcX();
00114     return true;
00115 }
00116 
00117 
00118 bool AbstractByteArrayColumnRenderer::setSpacing( KPixelX byteSpacingWidth, int NoGB, KPixelX groupSpacingWidth )
00119 {
00120     // no changes?
00121     if( mByteSpacingWidth == byteSpacingWidth && mNoOfGroupedBytes == NoGB && mGroupSpacingWidth == groupSpacingWidth )
00122         return false;
00123 
00124     mByteSpacingWidth = byteSpacingWidth;
00125     mNoOfGroupedBytes = NoGB;
00126     mGroupSpacingWidth = groupSpacingWidth;
00127 
00128     // recalculate depend sizes
00129     if( mLinePosLeftPixelX )
00130         recalcX();
00131 
00132     return true;
00133 }
00134 
00135 
00136 bool AbstractByteArrayColumnRenderer::setByteSpacingWidth( KPixelX byteSpacingWidth )
00137 {
00138     // no changes?
00139     if( mByteSpacingWidth == byteSpacingWidth )
00140         return false;
00141 
00142     mByteSpacingWidth = byteSpacingWidth;
00143 
00144     // recalculate depend sizes
00145     if( mLinePosLeftPixelX )
00146         recalcX();
00147 
00148     return true;
00149 }
00150 
00151 
00152 bool AbstractByteArrayColumnRenderer::setNoOfGroupedBytes( int NoGB )
00153 {
00154     // no changes?
00155     if( mNoOfGroupedBytes == NoGB )
00156         return false;
00157 
00158     mNoOfGroupedBytes = NoGB;
00159 
00160     if( mLinePosLeftPixelX )
00161         recalcX();
00162     return true;
00163 }
00164 
00165 
00166 bool AbstractByteArrayColumnRenderer::setGroupSpacingWidth( KPixelX groupSpacingWidth )
00167 {
00168     // no changes?
00169     if( mGroupSpacingWidth == groupSpacingWidth )
00170         return false;
00171 
00172     mGroupSpacingWidth = groupSpacingWidth;
00173 
00174     // recalculate depend sizes
00175     if( mLinePosLeftPixelX )
00176         recalcX();
00177 
00178     return true;
00179 }
00180 
00181 
00182 void AbstractByteArrayColumnRenderer::recalcByteWidth()
00183 {
00184     setByteWidth( mDigitWidth );
00185 }
00186 
00187 
00188 void AbstractByteArrayColumnRenderer::recalcX()
00189 {
00190     mSpacingTrigger = noOfGroupedBytes() > 0 ? noOfGroupedBytes()-1 : mLastLinePos+1; // last ensures to never trigger the spacing
00191 
00192     KPixelX newWidth = 0;
00193     int groupedBytes = 0;
00194     KPixelX *PX = mLinePosLeftPixelX;
00195     KPixelX *PRX = mLinePosRightPixelX;
00196     int p = 0;
00197     for( ; p<=mLastLinePos; ++PX, ++PRX, ++p, ++groupedBytes )
00198     {
00199         *PX = newWidth;
00200         newWidth += mByteWidth;
00201         *PRX = newWidth-1;
00202 
00203         // is there a space behind the actual byte (if it is not the last)?
00204         if( groupedBytes == mSpacingTrigger )
00205         {
00206             newWidth += mGroupSpacingWidth;
00207             groupedBytes = -1;
00208         }
00209         else
00210         newWidth += mByteSpacingWidth;
00211     }
00212     setWidth( mLinePosRightPixelX[mLastLinePos]+1 );
00213 }
00214 
00215 
00216 // TODO: why are inlined functions not available as symbols when defined before their use
00217 //TODO: works not precisly for the byte rects but includes spacing and left and right
00218 /*inline*/ int AbstractByteArrayColumnRenderer::linePositionOfX( KPixelX PX ) const
00219 {
00220     if( !mLinePosLeftPixelX )
00221         return NoByteFound;
00222 
00223     // translate
00224     PX -= x();
00225     // search backwards for the first byte that is equalleft to x
00226     for( int p=mLastLinePos; p>=0; --p )
00227         if( mLinePosLeftPixelX[p] <= PX )
00228             return p;
00229 
00230     return 0; //NoByteFound;
00231 }
00232 
00233 
00234 int AbstractByteArrayColumnRenderer::magneticLinePositionOfX( KPixelX PX ) const
00235 {
00236     if( !mLinePosLeftPixelX )
00237         return NoByteFound;
00238 
00239     // translate
00240     PX -= x();
00241     // search backwards for the first byte that is equalleft to x
00242     for( int p=mLastLinePos; p>=0; --p )
00243         if( mLinePosLeftPixelX[p] <= PX )
00244         {
00245             // are we close to the right?
00246             if( mLinePosRightPixelX[p]-PX < mDigitWidth/2 ) // TODO: perhaps cache also the middle xpos's
00247                 ++p;
00248             return p;
00249         }
00250 
00251     return 0; //NoByteFound;
00252 }
00253 
00254 
00255 KHE::KSection AbstractByteArrayColumnRenderer::linePositionsOfX( KPixelX PX, KPixelX PW ) const
00256 {
00257     if( !mLinePosLeftPixelX )
00258         return KHE::KSection();
00259 
00260     // translate
00261     PX -= x();
00262     const int PRX = PX + PW - 1;
00263 
00264     KHE::KSection positions;
00265     // search backwards for the first byte that is equalleft to x
00266     for( int p=mLastLinePos; p>=0; --p )
00267         if( mLinePosLeftPixelX[p] <= PRX )
00268         {
00269             positions.setEnd( p );
00270             for( ; p>=0; --p )
00271                 if( mLinePosLeftPixelX[p] <= PX )
00272                 {
00273                     positions.setStart( p );
00274                     break;
00275                 }
00276             break;
00277         }
00278 
00279     return positions;
00280 }
00281 
00282 
00283 KPixelX AbstractByteArrayColumnRenderer::xOfLinePosition( int linePosition ) const
00284 { return x() + (mLinePosLeftPixelX?mLinePosLeftPixelX[linePosition]:0); }
00285 
00286 KPixelX AbstractByteArrayColumnRenderer::rightXOfLinePosition( int linePosition ) const
00287 { return x() + (mLinePosRightPixelX?mLinePosRightPixelX[linePosition]:0); }
00288 
00289 
00290 int AbstractByteArrayColumnRenderer::linePositionOfColumnX( KPixelX PX ) const
00291 {
00292     if( !mLinePosLeftPixelX )
00293         return NoByteFound;
00294 
00295     // search backwards for the first byte that is equalleft to x
00296     for( int p=mLastLinePos; p>=0; --p )
00297         if( mLinePosLeftPixelX[p] <= PX )
00298             return p;
00299 
00300     return 0; //NoByteFound;
00301 }
00302 
00303 
00304 KHE::KSection AbstractByteArrayColumnRenderer::linePositionsOfColumnXs( KPixelX PX, KPixelX PW ) const
00305 {
00306     if( !mLinePosLeftPixelX )
00307         return KHE::KSection();
00308 
00309     const int PRX = PX + PW - 1;
00310 
00311     KHE::KSection positions;
00312     // search backwards for the first byte that is equalleft to x
00313     for( int p=mLastLinePos; p>=0; --p )
00314         if( mLinePosLeftPixelX[p] <= PRX )
00315         {
00316             positions.setEnd( p );
00317             for( ; p>=0; --p )
00318                 if( mLinePosLeftPixelX[p] <= PX )
00319                 {
00320                     positions.setStart( p );
00321                     break;
00322                 }
00323             break;
00324         }
00325 
00326     return positions;
00327 }
00328 
00329 
00330 KPixelX AbstractByteArrayColumnRenderer::columnXOfLinePosition( int linePosition ) const
00331 { return mLinePosLeftPixelX ? mLinePosLeftPixelX[linePosition] : 0; }
00332 KPixelX AbstractByteArrayColumnRenderer::columnRightXOfLinePosition( int linePosition ) const
00333 { return mLinePosRightPixelX ? mLinePosRightPixelX[linePosition] : 0; }
00334 
00335 
00336 KPixelXs AbstractByteArrayColumnRenderer::xsOfLinePositionsInclSpaces( const KHE::KSection &linePositions ) const
00337 {
00338     const int x = (linePositions.start()>0) ? rightXOfLinePosition( linePositions.nextBeforeStart() ) + 1 :
00339                                               xOfLinePosition( linePositions.start() );
00340     const int rightX = (linePositions.end()<mLastLinePos) ? xOfLinePosition( linePositions.nextBehindEnd() ) - 1 :
00341                                                             rightXOfLinePosition( linePositions.end() );
00342     return KPixelXs( x, rightX );
00343 }
00344 
00345 
00346 KPixelXs AbstractByteArrayColumnRenderer::columnXsOfLinePositionsInclSpaces( const KHE::KSection &linePositions ) const
00347 {
00348     const int x = (linePositions.start()>0) ? columnRightXOfLinePosition( linePositions.nextBeforeStart() ) + 1 :
00349                                               columnXOfLinePosition( linePositions.start() );
00350     const int rightX = (linePositions.end()<mLastLinePos) ? columnXOfLinePosition( linePositions.nextBehindEnd() ) - 1 :
00351                                                             columnRightXOfLinePosition( linePositions.end() );
00352     return KPixelXs( x, rightX  );
00353 }
00354 
00355 
00356 void AbstractByteArrayColumnRenderer::prepareRendering( const KPixelXs &_Xs )
00357 {
00358     KPixelXs Xs( _Xs );
00359     restrictToXSpan( &Xs );
00360     // translate
00361     Xs.moveBy( -x() );
00362 
00363     // store the values
00364     mRenderX = Xs.start();
00365     mRenderWidth = Xs.width();
00366 
00367     // get line linePositions to paint
00368     mRenderLinePositions = linePositionsOfColumnXs( mRenderX, mRenderWidth );
00369 }
00370 
00371 
00372 void AbstractByteArrayColumnRenderer::renderFirstLine( QPainter *painter, const KPixelXs &Xs, int firstLineIndex )
00373 {
00374     prepareRendering( Xs );
00375 
00376     mRenderLine = firstLineIndex;
00377 
00378     renderLinePositions( painter, mRenderLine++, mRenderLinePositions );
00379 }
00380 
00381 
00382 void AbstractByteArrayColumnRenderer::renderNextLine( QPainter *painter )
00383 {
00384     renderLinePositions( painter, mRenderLine++, mRenderLinePositions );
00385 }
00386 
00387 
00388 void AbstractByteArrayColumnRenderer::renderLinePositions( QPainter *painter, int lineIndex, const KHE::KSection &_linePositions )
00389 {
00390     // clear background
00391     const unsigned int blankFlag =
00392         (_linePositions.start()!=0?StartsBefore:0) | (_linePositions.end()!=mLastLinePos?EndsLater:0);
00393     const QWidget *viewport = columnsView()->viewport();
00394     const QBrush &backgroundBrush = viewport->palette().brush( viewport->backgroundRole() );
00395 
00396     renderRange( painter, backgroundBrush, _linePositions, blankFlag );
00397 
00398     // Go through the lines TODO: handle first and last line more effeciently
00399     // check for leading and trailing spaces
00400     KHE::KSection linePositions( mLayout->firstLinePosition(Coord( _linePositions.start(), lineIndex )),
00401                                  mLayout->lastLinePosition( Coord( _linePositions.end(),   lineIndex )) );
00402 
00403     // no bytes to paint?
00404     if( !mLayout->hasContent(lineIndex) )
00405         return;
00406 
00407     // check for leading and trailing spaces
00408     KHE::KSection byteIndizes =
00409         KHE::KSection::fromWidth( mLayout->indexAtCoord(Coord( linePositions.start(), lineIndex )), linePositions.width() );
00410 
00411     unsigned int selectionFlag = 0;
00412     unsigned int markingFlag = 0;
00413     KHE::KSection selection;
00414     KHE::KSection markedSection;
00415     bool hasMarking = mRanges->hasMarking();
00416     bool hasSelection = mRanges->hasSelection();
00417 
00418 //kDebug() << QString("painting linePositions (painter%1-%2L%3): ").arg(linePositions.start()).arg(linePositions.end()).arg(lineIndex)
00419 //         <<linePositions.start()<<"-"<<linePositions.start()
00420 //         <<" for byteIndizes "<<byteIndizes.start()<<"-"<<byteIndizes.start()<<endl;
00421     while( linePositions.isValid() )
00422     {
00423         KHE::KSection positionsPart( linePositions );  // set of linePositions to paint next
00424         KHE::KSection byteIndizesPart( byteIndizes );      // set of indizes to paint next
00425         // falls markedSection nicht mehr gebuffert und noch zu erwarten
00426         if( hasMarking && markedSection.endsBefore(byteIndizesPart.start()) )
00427         {
00428             // erhebe nächste Markierung im Bereich
00429             hasMarking = isMarked( byteIndizesPart, &markedSection, &markingFlag );
00430         }
00431         // falls selection nicht mehr gebuffert und noch zu erwarten
00432         if( hasSelection && selection.endsBefore(byteIndizesPart.start()) )
00433         {
00434             // erhebe nächste selection im Bereich
00435             hasSelection = isSelected( byteIndizesPart, &selection, &selectionFlag );
00436         }
00437 
00438         if( markedSection.start() == byteIndizesPart.start() )
00439         {
00440             byteIndizesPart.setEnd( markedSection.end() );
00441             positionsPart.setEndByWidth( markedSection.width() );
00442             if( positionsPart.end() == mLayout->lastLinePosition(lineIndex) )   markingFlag &= ~EndsLater;
00443             if( positionsPart.start() == mLayout->firstLinePosition(lineIndex)) markingFlag &= ~StartsBefore;
00444             renderMarking( painter, positionsPart, byteIndizesPart.start(), markingFlag );
00445         }
00446         else if( selection.includes(byteIndizesPart.start()) )
00447         {
00448             if( selection.startsBehind(byteIndizesPart.start()) )
00449                 selectionFlag |= StartsBefore;
00450             bool MarkingBeforeEnd = hasMarking && markedSection.start() <= selection.end();
00451 
00452             byteIndizesPart.setEnd( MarkingBeforeEnd ? markedSection.nextBeforeStart() : selection.end() );
00453             positionsPart.setEndByWidth( byteIndizesPart.width() );
00454 
00455             if( MarkingBeforeEnd )
00456                 selectionFlag |= EndsLater;
00457             if( positionsPart.end() == mLayout->lastLinePosition(lineIndex) )    selectionFlag &= ~EndsLater;
00458             if( positionsPart.start() == mLayout->firstLinePosition(lineIndex) ) selectionFlag &= ~StartsBefore;
00459 
00460             renderSelection( painter, positionsPart, byteIndizesPart.start(), selectionFlag );
00461         }
00462         else
00463         {
00464             // calc end of plain text
00465             if( hasMarking )
00466                 byteIndizesPart.setEnd( markedSection.nextBeforeStart() );
00467             if( hasSelection )
00468                 byteIndizesPart.restrictEndTo( selection.nextBeforeStart() );
00469 
00470             positionsPart.setEndByWidth( byteIndizesPart.width() );
00471             renderPlain( painter, positionsPart, byteIndizesPart.start() );
00472         }
00473         byteIndizes.setStartNextBehind( byteIndizesPart );
00474         linePositions.setStartNextBehind( positionsPart );
00475     }
00476 }
00477 
00478 
00479 void AbstractByteArrayColumnRenderer::renderPlain( QPainter *painter, const KHE::KSection &linePositions, int byteIndex )
00480 {
00481     bool hasBookmarks = ( mBookmarks != 0 );
00482     KHECore::KBookmarkList bookmarkList;
00483     KHECore::KBookmarkList::ConstIterator bit;
00484     if( hasBookmarks )
00485     {
00486         bookmarkList = mBookmarks->bookmarkList();
00487         bit = bookmarkList.nextFrom(byteIndex);
00488         hasBookmarks = ( bit != bookmarkList.constEnd() );
00489     }
00490 
00491     const QPalette &palette = columnsView()->viewport()->palette();
00492     KColorScheme colorScheme( palette.currentColorGroup(), KColorScheme::View );
00493 
00494     // paint all the bytes affected
00495     for( int linePosition=linePositions.start(); linePosition<=linePositions.end(); ++linePosition,++byteIndex )
00496     {
00497         const KPixelX x = columnXOfLinePosition( linePosition );
00498 
00499         // draw the byte
00500         painter->translate( x, 0 );
00501 
00502         if( hasBookmarks && (byteIndex == bit->offset()) )
00503         {
00504             renderBookmark( painter, colorScheme.background(KColorScheme::LinkBackground) );
00505             ++bit;
00506             hasBookmarks = (bit != bookmarkList.constEnd());//TODO )&& ( bit->offset() <= LastIndex );
00507         }
00508 
00509         const char byte = mByteArrayModel->datum( byteIndex );
00510         const KHECore::KChar byteChar = mCharCodec->decode( byte );
00511 
00512         const KColorScheme::ForegroundRole foregroundRole =
00513             mByteTypeColored ? foregroundRoleForChar(byteChar): KColorScheme::NormalText;
00514         const QBrush brush = colorScheme.foreground( foregroundRole );
00515         const QColor &charColor = brush.color();// palette.text().color();//colorForChar(byteChar)
00516         renderByteText( painter, byte, byteChar, charColor );
00517 
00518         painter->translate( -x, 0 );
00519     }
00520 }
00521 
00522 
00523 void AbstractByteArrayColumnRenderer::renderSelection( QPainter *painter, const KHE::KSection &linePositions, int byteIndex, int flag )
00524 {
00525     bool hasBookmarks = ( mBookmarks != 0 );
00526     KHECore::KBookmarkList bookmarkList;
00527     KHECore::KBookmarkList::ConstIterator bit;
00528     if( hasBookmarks )
00529     {
00530         bookmarkList = mBookmarks->bookmarkList();
00531         bit = bookmarkList.nextFrom(byteIndex);
00532         hasBookmarks = ( bit != bookmarkList.constEnd() );
00533     }
00534 
00535     const QPalette &palette = columnsView()->viewport()->palette();
00536     KColorScheme colorScheme( palette.currentColorGroup(), KColorScheme::Selection );
00537 
00538     renderRange( painter, colorScheme.background(), linePositions, flag );
00539 
00540     // paint all the bytes affected
00541     for( int linePosition=linePositions.start(); linePosition<=linePositions.end(); ++linePosition,++byteIndex )
00542     {
00543         const KPixelX x = columnXOfLinePosition( linePosition );
00544 
00545         // draw the byte
00546         painter->translate( x, 0 );
00547 
00548         if( hasBookmarks && (byteIndex == bit->offset()) )
00549         {
00550             renderBookmark( painter, colorScheme.background(KColorScheme::LinkBackground) );
00551             ++bit;
00552             hasBookmarks = (bit != bookmarkList.constEnd());//TODO )&& ( bit->offset() <= LastIndex );
00553         }
00554 
00555         const char byte = mByteArrayModel->datum( byteIndex );
00556         const KHECore::KChar byteChar = mCharCodec->decode( byte );
00557 
00558         const KColorScheme::ForegroundRole foregroundRole =
00559             mByteTypeColored ? foregroundRoleForChar(byteChar): KColorScheme::NormalText;
00560         const QBrush brush = colorScheme.foreground( foregroundRole );
00561         const QColor &charColor = brush.color();
00562         renderByteText( painter, byte, byteChar, charColor );
00563 
00564         painter->translate( -x, 0 );
00565     }
00566 }
00567 
00568 
00569 void AbstractByteArrayColumnRenderer::renderMarking( QPainter *painter, const KHE::KSection &linePositions, int byteIndex, int flag )
00570 {
00571     const QPalette &palette = columnsView()->viewport()->palette();
00572 
00573     renderRange( painter, palette.text(), linePositions, flag );
00574 
00575     const QColor &baseColor = palette.base().color();
00576     // paint all the bytes affected
00577     for( int p=linePositions.start(); p<=linePositions.end(); ++p,++byteIndex )
00578     {
00579         const KPixelX x = columnXOfLinePosition( p );
00580 
00581         // draw the byte
00582         painter->translate( x, 0 );
00583         const char byte = mByteArrayModel->datum( byteIndex );
00584         const KHECore::KChar byteChar = mCharCodec->decode( byte );
00585         renderByteText( painter, byte, byteChar, baseColor );
00586 
00587         painter->translate( -x, 0 );
00588     }
00589 }
00590 
00591 
00592 void AbstractByteArrayColumnRenderer::renderBookmark( QPainter *painter, const QBrush &brush )
00593 {
00594     // TODO: think about how bookmarks should really be rendered
00595     painter->fillRect( 1,1, mByteWidth-2,lineHeight()-2, brush );
00596 }
00597 
00598 
00599 void AbstractByteArrayColumnRenderer::renderRange( QPainter *painter, const QBrush &brush, const KHE::KSection &linePositions, int flag )
00600 {
00601     const KPixelX rangeX =
00602         ( flag & StartsBefore ) ? columnRightXOfLinePosition( linePositions.nextBeforeStart() ) + 1 :
00603                                   columnXOfLinePosition( linePositions.start() );
00604     const KPixelX rangeW =
00605         ( (flag & EndsLater) ? columnXOfLinePosition( linePositions.nextBehindEnd() ) :
00606                                columnRightXOfLinePosition( linePositions.end() ) + 1  )
00607         - rangeX;
00608 
00609     painter->fillRect( rangeX,0, rangeW,lineHeight(), brush );
00610 }
00611 
00612 
00613 void AbstractByteArrayColumnRenderer::renderByte( QPainter *painter, int byteIndex )
00614 {
00615     const char byte = ( byteIndex > -1 ) ? mByteArrayModel->datum( byteIndex ) : EmptyByte;
00616     const KHECore::KChar byteChar = mCharCodec->decode( byte );
00617 
00618     const QWidget *viewport = columnsView()->viewport();
00619     const QPalette &palette = viewport->palette();
00620 
00621     KColorScheme::ColorSet colorSet = KColorScheme::View;
00622     if( byteIndex > -1 )
00623     {
00624         if( mRanges->selectionIncludes(byteIndex) )
00625             colorSet = KColorScheme::Selection;
00626 //    else if( mRanges->markingIncludes(byteIndex) )
00627 //    {
00628 //      charColor = palette.base().color();
00629 //      brush = palette.text();
00630 //    }
00631     }
00632     KColorScheme colorScheme( palette.currentColorGroup(), colorSet );
00633 
00634     const QBrush backgroundBrush = colorScheme.background();
00635     painter->fillRect( 0,0, mByteWidth,lineHeight(), backgroundBrush );
00636 
00637     if( mBookmarks && mBookmarks->bookmarkList().contains(byteIndex) )
00638         renderBookmark( painter, colorScheme.background(KColorScheme::LinkBackground) );
00639 
00640     if( byteIndex > -1 )
00641     {
00642         const KColorScheme::ForegroundRole foregroundRole =
00643             mByteTypeColored ? foregroundRoleForChar(byteChar): KColorScheme::NormalText;
00644         const QBrush brush = colorScheme.foreground( foregroundRole );
00645         const QColor &charColor = brush.color();
00646 
00647         renderByteText( painter, byte, byteChar, charColor );
00648     }
00649 }
00650 
00651 // TODO: think about making framestyle a enum of a class ByteArrayColumnCursor
00652 void AbstractByteArrayColumnRenderer::renderFramedByte( QPainter *painter, int byteIndex, FrameStyle frameStyle )
00653 {
00654     renderByte( painter, byteIndex );
00655 
00656     const char byte = ( byteIndex > -1 ) ? mByteArrayModel->datum( byteIndex ) : EmptyByte;
00657     const KHECore::KChar byteChar = mCharCodec->decode( byte );
00658 
00659     const QPalette &palette = columnsView()->viewport()->palette();
00660     KColorScheme colorScheme( palette.currentColorGroup(), KColorScheme::View );
00661     const KColorScheme::ForegroundRole foregroundRole =
00662         mByteTypeColored ? foregroundRoleForChar(byteChar): KColorScheme::NormalText;
00663     const QBrush brush = colorScheme.foreground( foregroundRole );
00664     const QColor &charColor = brush.color();
00665     painter->setPen( charColor );
00666     if( frameStyle == Frame )
00667         painter->drawRect( 0,0, mByteWidth-1,lineHeight()-1 );
00668     else if( frameStyle == Left )
00669         painter->drawLine( 0,0, 0,lineHeight()-1 );
00670     else
00671         painter->drawLine( mByteWidth-1,0, mByteWidth-1,lineHeight()-1 );
00672 }
00673 
00674 
00675 void AbstractByteArrayColumnRenderer::renderCursor( QPainter *painter, int byteIndex )
00676 {
00677     const char byte = ( byteIndex > -1 ) ? mByteArrayModel->datum( byteIndex ) : EmptyByte;
00678     const KHECore::KChar byteChar = mCharCodec->decode( byte );
00679 
00680     const QPalette &palette = columnsView()->viewport()->palette();
00681     KColorScheme colorScheme( palette.currentColorGroup(), KColorScheme::View );
00682     const KColorScheme::ForegroundRole foregroundRole =
00683         mByteTypeColored ? foregroundRoleForChar(byteChar): KColorScheme::NormalText;
00684     const QBrush brush = colorScheme.foreground( foregroundRole );
00685     painter->fillRect( 0,0, mByteWidth,lineHeight(), brush );
00686 }
00687 
00688 
00689 bool AbstractByteArrayColumnRenderer::isSelected( const KHE::KSection &section, KHE::KSection *_selection,
00690                                                   unsigned int *_flag ) const
00691 {
00692     const KHE::KSection *overlappingSelectedSection = mRanges->firstOverlappingSelection( section );
00693     if( !overlappingSelectedSection )
00694         return false;
00695 
00696     KHE::KSection selection = *overlappingSelectedSection;
00697     unsigned int flag = 0;
00698 
00699     // does selection start before asked range?
00700     if( selection.startsBefore(section) )
00701     {
00702         selection.setStart( section.start() );
00703         flag |= StartsBefore;
00704     }
00705 
00706     // does selection go on behind asked range?
00707     if( selection.endsBehind(section) )
00708     {
00709         selection.setEnd( section.end() );
00710         flag |= EndsLater;
00711     }
00712 
00713     *_selection = selection;
00714     *_flag = flag;
00715     return true;
00716 }
00717 
00718 
00719 bool AbstractByteArrayColumnRenderer::isMarked( const KHE::KSection &section, KHE::KSection *_markedSection,
00720                                                 unsigned int *_flag ) const
00721 {
00722     const KHE::KSection *overlappingMarkedSection = mRanges->overlappingMarking( section );
00723     if( !overlappingMarkedSection )
00724