QGIS API Documentation  3.21.0-Master (5b68dc587e)
qgstextdocument.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstextdocument.cpp
3  -----------------
4  begin : May 2020
5  copyright : (C) Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgstextdocument.h"
17 #include "qgis.h"
18 #include "qgsstringutils.h"
19 #include "qgstextblock.h"
20 #include "qgstextfragment.h"
21 #include <QTextDocument>
22 #include <QTextBlock>
23 
25 
27 
29 {
30  mBlocks.append( block );
31 }
32 
34 {
35  mBlocks.append( QgsTextBlock( fragment ) );
36 }
37 
39 {
40  QgsTextDocument document;
41  document.reserve( lines.size() );
42  for ( const QString &line : lines )
43  document.append( QgsTextBlock( QgsTextFragment( line ) ) );
44  return document;
45 }
46 
47 QgsTextDocument QgsTextDocument::fromHtml( const QStringList &lines )
48 {
49  QgsTextDocument document;
50 
51  document.reserve( lines.size() );
52  for ( const QString &line : lines )
53  {
54  // QTextDocument is a very heavy way of parsing HTML + css (it's heavily geared toward an editable text document,
55  // and includes a LOT of calculations we don't need, when all we're after is a HTML + CSS style parser).
56  // TODO - try to find an alternative library we can use here
57  QTextDocument sourceDoc;
58  sourceDoc.setHtml( line );
59 
60  QTextBlock sourceBlock = sourceDoc.firstBlock();
61  while ( true )
62  {
63  auto it = sourceBlock.begin();
64  QgsTextBlock block;
65  while ( !it.atEnd() )
66  {
67  const QTextFragment fragment = it.fragment();
68  if ( fragment.isValid() )
69  {
70  block.append( QgsTextFragment( fragment ) );
71  }
72  it++;
73  }
74  if ( !block.empty() )
75  document.append( block );
76 
77  sourceBlock = sourceBlock.next();
78  if ( !sourceBlock.isValid() )
79  break;
80  }
81  }
82  return document;
83 }
84 
86 {
87  mBlocks.append( block );
88 }
89 
91 {
92  mBlocks.push_back( block );
93 }
94 
95 void QgsTextDocument::reserve( int count )
96 {
97  mBlocks.reserve( count );
98 }
99 
100 const QgsTextBlock &QgsTextDocument::at( int i ) const
101 {
102  return mBlocks.at( i );
103 }
104 
106 {
107  return mBlocks[i];
108 }
109 
111 {
112  return mBlocks.size();
113 }
114 
115 QStringList QgsTextDocument::toPlainText() const
116 {
117  QStringList textLines;
118  textLines.reserve( mBlocks.size() );
119  for ( const QgsTextBlock &block : mBlocks )
120  {
121  QString line;
122  for ( const QgsTextFragment &fragment : block )
123  {
124  line.append( fragment.text() );
125  }
126  textLines << line;
127  }
128  return textLines;
129 }
130 
131 void QgsTextDocument::splitLines( const QString &wrapCharacter, int autoWrapLength, bool useMaxLineLengthWhenAutoWrapping )
132 {
133  const QVector< QgsTextBlock > prevBlocks = mBlocks;
134  mBlocks.clear();
135  mBlocks.reserve( prevBlocks.size() );
136  for ( const QgsTextBlock &block : prevBlocks )
137  {
138  QgsTextBlock destinationBlock;
139  for ( const QgsTextFragment &fragment : block )
140  {
141  QStringList thisParts;
142  if ( !wrapCharacter.isEmpty() && wrapCharacter != QLatin1String( "\n" ) )
143  {
144  //wrap on both the wrapchr and new line characters
145  const QStringList lines = fragment.text().split( wrapCharacter );
146  for ( const QString &line : lines )
147  {
148  thisParts.append( line.split( '\n' ) );
149  }
150  }
151  else
152  {
153  thisParts = fragment.text().split( '\n' );
154  }
155 
156  // apply auto wrapping to each manually created line
157  if ( autoWrapLength != 0 )
158  {
159  QStringList autoWrappedLines;
160  autoWrappedLines.reserve( thisParts.count() );
161  for ( const QString &line : std::as_const( thisParts ) )
162  {
163  autoWrappedLines.append( QgsStringUtils::wordWrap( line, autoWrapLength, useMaxLineLengthWhenAutoWrapping ).split( '\n' ) );
164  }
165  thisParts = autoWrappedLines;
166  }
167 
168  if ( thisParts.empty() )
169  continue;
170  else if ( thisParts.size() == 1 )
171  destinationBlock.append( fragment );
172  else
173  {
174  if ( !thisParts.at( 0 ).isEmpty() )
175  destinationBlock.append( QgsTextFragment( thisParts.at( 0 ), fragment.characterFormat() ) );
176 
177  append( destinationBlock );
178  destinationBlock.clear();
179  for ( int i = 1 ; i < thisParts.size() - 1; ++i )
180  {
181  append( QgsTextBlock( QgsTextFragment( thisParts.at( i ), fragment.characterFormat() ) ) );
182  }
183  destinationBlock.append( QgsTextFragment( thisParts.at( thisParts.size() - 1 ), fragment.characterFormat() ) );
184  }
185  }
186  append( destinationBlock );
187  }
188 }
189 
191 {
192  for ( QgsTextBlock &block : mBlocks )
193  {
194  block.applyCapitalization( capitalization );
195  }
196 }
197 
199 QVector< QgsTextBlock >::const_iterator QgsTextDocument::begin() const
200 {
201  return mBlocks.begin();
202 }
203 
204 QVector< QgsTextBlock >::const_iterator QgsTextDocument::end() const
205 {
206  return mBlocks.end();
207 }
Capitalization
Capitalization options.
static QString wordWrap(const QString &string, int length, bool useMaxLineLength=true, const QString &customDelimiter=QString())
Automatically wraps a string by inserting new line characters at appropriate locations in the string.
Represents a block of text consisting of one or more QgsTextFragment objects.
Definition: qgstextblock.h:36
void clear()
Clears the block, removing all its contents.
void append(const QgsTextFragment &fragment)
Appends a fragment to the block.
bool empty() const
Returns true if the block is empty.
Represents a document consisting of one or more QgsTextBlock objects.
void splitLines(const QString &wrapCharacter, int autoWrapLength=0, bool useMaxLineLengthWhenAutoWrapping=true)
Splits lines of text in the document to separate lines, using a specified wrap character (wrapCharact...
QgsTextBlock & operator[](int index)
Returns the block at the specified index.
void applyCapitalization(QgsStringUtils::Capitalization capitalization)
Applies a capitalization style to the document's text.
const QgsTextBlock & at(int index) const
Returns the block at the specified index.
void reserve(int count)
Reserves the specified count of blocks for optimised block appending.
QStringList toPlainText() const
Returns a list of plain text lines of text representing the document.
int size() const
Returns the number of blocks in the document.
static QgsTextDocument fromHtml(const QStringList &lines)
Constructor for QgsTextDocument consisting of a set of HTML formatted lines.
static QgsTextDocument fromPlainText(const QStringList &lines)
Constructor for QgsTextDocument consisting of a set of plain text lines.
void append(const QgsTextBlock &block)
Appends a block to the document.
Stores a fragment of text along with formatting overrides to be used when rendering the fragment.