File indexing completed on 2025-01-05 05:23:53
0001 /* 0002 This file is part of the Okteta Kasten module, made within the KDE community. 0003 0004 SPDX-FileCopyrightText: 2008 Friedrich W. H. Kossebau <kossebau@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #include "bytearrayrowscolumntextrenderer.hpp" 0010 0011 // Okteta core 0012 #include <Okteta/ValueCodec> 0013 #include <Okteta/CharCodec> 0014 #include <Okteta/Character> 0015 #include <Okteta/AbstractByteArrayModel> 0016 // Qt 0017 #include <QTextStream> 0018 0019 namespace Kasten { 0020 0021 ByteArrayRowsColumnTextRenderer::ByteArrayRowsColumnTextRenderer(const Okteta::AbstractByteArrayModel* byteArrayModel, 0022 Okteta::Address offset, 0023 const Okteta::CoordRange& coordRange, 0024 int noOfBytesPerLine, int byteSpacingWidth, int noOfGroupedBytes, 0025 int visibleCodings, 0026 Okteta::ValueCoding valueCoding, 0027 const QString& charCodecName, QChar substituteChar, QChar undefinedChar) 0028 : mByteArrayModel(byteArrayModel) 0029 , mCoordRange(coordRange) 0030 , mNoOfBytesPerLine(noOfBytesPerLine) 0031 , mVisibleCodings(visibleCodings) 0032 , mValueCodec(Okteta::ValueCodec::createCodec(valueCoding)) 0033 , mCharCodec(Okteta::CharCodec::createCodec(charCodecName)) 0034 , mSubstituteChar(substituteChar) 0035 , mUndefinedChar(undefinedChar) 0036 , mOffset(offset) 0037 , mLinePositions(new int[mNoOfBytesPerLine]) 0038 { 0039 const int encodingWidth = (mVisibleCodings & 1) ? mValueCodec->encodingWidth() : 1; 0040 setWidths(encodingWidth, byteSpacingWidth, noOfGroupedBytes); 0041 } 0042 0043 ByteArrayRowsColumnTextRenderer::~ByteArrayRowsColumnTextRenderer() 0044 { 0045 delete [] mLinePositions; 0046 delete mCharCodec; 0047 delete mValueCodec; 0048 } 0049 0050 int ByteArrayRowsColumnTextRenderer::noOfSublinesNeeded() const 0051 { 0052 return (mVisibleCodings > 2) ? 2 : 1; 0053 } 0054 0055 void ByteArrayRowsColumnTextRenderer::setWidths(int byteWidth, int byteSpacingWidth, int noOfGroupedBytes) 0056 { 0057 // TODO: remove this hack and make it more general 0058 if (byteSpacingWidth > 0) { 0059 byteSpacingWidth = DefaultTRByteSpacingWidth; 0060 } 0061 0062 int spacingTrigger = noOfGroupedBytes - 1; 0063 if (spacingTrigger < 0) { 0064 spacingTrigger = mNoOfBytesPerLine; // ensures to never trigger the group spacing 0065 0066 } 0067 int N = 0; 0068 int p = 0; 0069 int gs = 0; 0070 int* P = mLinePositions; 0071 for (; P < &mLinePositions[mNoOfBytesPerLine]; ++P, ++p, ++gs) { 0072 *P = N; 0073 N += byteWidth; 0074 0075 // is there a space behind the actual byte (if it is not the last)? 0076 if (gs == spacingTrigger) { 0077 N += TRGroupSpacingWidth; 0078 gs = -1; 0079 } else { 0080 N += byteSpacingWidth; 0081 } 0082 } 0083 0084 N -= (gs == 0) ? TRGroupSpacingWidth : byteSpacingWidth; 0085 0086 mNoOfCharsPerLine = N; 0087 } 0088 0089 void ByteArrayRowsColumnTextRenderer::renderFirstLine(QTextStream* stream, int lineIndex) const 0090 { 0091 mRenderLine = lineIndex; 0092 renderLine(stream, false); 0093 } 0094 0095 void ByteArrayRowsColumnTextRenderer::renderNextLine(QTextStream* stream, bool isSubline) const 0096 { 0097 renderLine(stream, isSubline); 0098 } 0099 0100 void ByteArrayRowsColumnTextRenderer::renderLine(QTextStream* stream, bool isSubline) const 0101 { 0102 const int lineOffset = mOffset; 0103 0104 int p = 0; 0105 int pEnd = mNoOfBytesPerLine; 0106 // correct boundaries 0107 if (mRenderLine == mCoordRange.start().line()) { 0108 p = mCoordRange.start().pos(); 0109 } 0110 if (mRenderLine == mCoordRange.end().line()) { 0111 pEnd = mCoordRange.end().pos() + 1; 0112 } 0113 0114 uint e = 0; 0115 if (isSubline || mVisibleCodings == 2) { 0116 const QChar tabChar = QLatin1Char('\t'); 0117 const QChar returnChar = QLatin1Char('\n'); 0118 0119 // draw individual chars 0120 for (; p < pEnd; ++p, ++mOffset) { 0121 // get next position 0122 const uint t = mLinePositions[p]; 0123 // clear spacing 0124 *stream << whiteSpace(t - e); 0125 0126 // print char 0127 const Okteta::Character byteChar = mCharCodec->decode(mByteArrayModel->byte(mOffset)); 0128 0129 const QChar streamChar = byteChar.isUndefined() ? Okteta::Character(mUndefinedChar) : 0130 (!byteChar.isPrint() 0131 || byteChar == tabChar 0132 || byteChar == returnChar) ? Okteta::Character(mSubstituteChar) : 0133 byteChar; 0134 *stream << streamChar; 0135 0136 e = t + 1; 0137 } 0138 } else { 0139 QString E; 0140 E.resize(mValueCodec->encodingWidth()); 0141 // draw individual chars 0142 for (; p < pEnd; ++p, ++mOffset) { 0143 // get next position 0144 const uint t = mLinePositions[p]; 0145 // clear spacing 0146 *stream << whiteSpace(t - e); 0147 mValueCodec->encode(&E, 0, mByteArrayModel->byte(mOffset)); 0148 *stream << E; 0149 e = t + mValueCodec->encodingWidth(); 0150 } 0151 } 0152 0153 *stream << whiteSpace(mNoOfCharsPerLine - e); 0154 0155 if (isSubline || mVisibleCodings < 3) { 0156 ++mRenderLine; 0157 } else { 0158 mOffset = lineOffset; 0159 } 0160 } 0161 0162 }