MyGUI  3.2.0
MyGUI_TextIterator.cpp
Go to the documentation of this file.
1 
6 /*
7  This file is part of MyGUI.
8 
9  MyGUI is free software: you can redistribute it and/or modify
10  it under the terms of the GNU Lesser General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  (at your option) any later version.
13 
14  MyGUI is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public License
20  along with MyGUI. If not, see <http://www.gnu.org/licenses/>.
21 */
22 #include "MyGUI_Precompiled.h"
23 #include "MyGUI_TextIterator.h"
24 
25 namespace MyGUI
26 {
27 
28  TextIterator::TextIterator() :
29  mPosition(0),
30  mSize(ITEM_NONE),
31  mFirst(true),
32  mHistory(nullptr)
33  {
34  }
35 
36  TextIterator::TextIterator(const UString& _text, VectorChangeInfo* _history) :
37  mText(_text),
38  mCurrent(mText.begin()),
39  mEnd(mText.end()),
40  mSave(mEnd),
41  mPosition(0),
42  mSize(ITEM_NONE),
43  mFirst(true),
44  mHistory(_history)
45  {
46  }
47 
49  {
50  if (mCurrent == mEnd) return false;
51  else if (mFirst)
52  {
53  mFirst = false;
54  return true;
55  }
56 
57  // ставим на следующий символ проскакивая все тэги
58  for (UString::iterator iter = mCurrent; iter != mEnd; ++iter)
59  {
60 
61  if ((*iter) == L'#')
62  {
63 
64  // следующий символ
65  ++ iter;
66  if (iter == mEnd)
67  {
68  mCurrent = mEnd;
69  return false;
70  }
71 
72  // две решетки подряд
73  if ((*iter) == L'#')
74  {
75 
76  // следующий символ
77  mPosition ++;
78  ++iter;
79  if (iter == mEnd)
80  {
81  mCurrent = mEnd;
82  return false;
83  }
84 
85  // указатель на следующий символ
86  mCurrent = iter;
87  return true;
88  }
89 
90  // остальные 5 символов цвета
91  for (size_t pos = 0; pos < 5; pos++)
92  {
93  // следующий символ
94  ++ iter;
95  if (iter == mEnd)
96  {
97  mCurrent = mEnd;
98  return false;
99  }
100  }
101 
102  }
103  else
104  {
105 
106  // обыкновенный символ
107  mPosition ++;
108  ++iter;
109  if (iter == mEnd)
110  {
111  mCurrent = mEnd;
112  return false;
113  }
114 
115  // указатель на следующий символ
116  mCurrent = iter;
117  return true;
118  }
119  }
120 
121  return false;
122  }
123 
124  // возвращает цвет
125  bool TextIterator::getTagColour(UString& _colour) const
126  {
127  if (mCurrent == mEnd) return false;
128 
129  UString::iterator iter = mCurrent;
130 
131  // нам нужен последний цвет
132  bool ret = false;
133  while (getTagColour(_colour, iter))
134  {
135  ret = true;
136  }
137 
138  return ret;
139  }
140 
141  bool TextIterator::setTagColour(const Colour& _colour)
142  {
143  if (mCurrent == mEnd) return false;
144  // очищаем все цвета
145  clearTagColour();
146  // на всякий
147  if (mCurrent == mEnd) return false;
148 
149  const size_t SIZE = 16;
150  wchar_t buff[SIZE];
151 
152 #ifdef __MINGW32__
153  swprintf(buff, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255));
154 #else
155  swprintf(buff, SIZE, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255));
156 #endif
157  // непосредственная вставка
158  UString tmpStr = UString(buff);
159  insert(mCurrent, tmpStr);
160 
161  return true;
162  }
163 
165  {
166  if (mCurrent == mEnd) return false;
167  // очищаем все цвета
168  clearTagColour();
169  // на всякий
170  if (mCurrent == mEnd) return false;
171 
172  // проверяем на цвет хоть чуть чуть
173  if ( (_colour.size() != 7) || (_colour.find(L'#', 1) != _colour.npos) ) return false;
174 
175  // непосредственная вставка
176  insert(mCurrent, _colour);
177 
178  return true;
179  }
180 
181  // возвращает размер строки
182  size_t TextIterator::getSize() const
183  {
184  if (mSize != ITEM_NONE) return mSize;
185  mSize = mPosition;
186 
187  for (UString::iterator iter = mCurrent; iter != mEnd; ++iter)
188  {
189 
190  if ((*iter) == L'#')
191  {
192  // следующий символ
193  ++ iter;
194  if (iter == mEnd) break;
195 
196  // тэг цвета
197  if ((*iter) != L'#')
198  {
199  // остальные 5 символов цвета
200  for (size_t pos = 0; pos < 5; pos++)
201  {
202  ++ iter;
203  if (iter == mEnd)
204  {
205  --iter;
206  break;
207  }
208  }
209  continue;
210  }
211  }
212 
213  // обыкновенный символ
214  mSize ++;
215  }
216 
217  return mSize;
218  }
219 
220  // возвращает текст без тегов
222  {
223  UString ret;
224  ret.reserve(_text.size());
225 
226  UString::const_iterator end = _text.end();
227  for (UString::const_iterator iter = _text.begin(); iter != end; ++iter)
228  {
229 
230  if ((*iter) == L'#')
231  {
232  // следующий символ
233  ++ iter;
234  if (iter == end) break;
235 
236  // тэг цвета
237  if ((*iter) != L'#')
238  {
239  // остальные 5 символов цвета
240  for (size_t pos = 0; pos < 5; pos++)
241  {
242  ++ iter;
243  if (iter == end)
244  {
245  --iter;
246  break;
247  }
248  }
249  continue;
250  }
251  }
252 
253  // обыкновенный символ
254  ret.push_back(*iter);
255  }
256 
257  return ret;
258  }
259 
260  // возвращает цвет
261  bool TextIterator::getTagColour(UString& _colour, UString::iterator& _iter) const
262  {
263  if ( (_iter == mEnd) || ((*_iter) != L'#') ) return false;
264 
265  // следующий символ
266  ++_iter;
267  if ( (_iter == mEnd) || ((*_iter) == L'#') ) return false;
268 
269  // берем цвет
270  wchar_t buff[16] = L"#FFFFFF\0";
271  buff[1] = (wchar_t)(*_iter);
272  for (size_t pos = 2; pos < 7; pos++)
273  {
274  ++_iter;
275  if ( _iter == mEnd ) return false;
276  buff[pos] = (wchar_t)(*_iter);
277  }
278 
279  // ставим на следующий тег или символ
280  ++_iter;
281 
282  // возвращаем цвет
283  _colour = buff;
284  return true;
285  }
286 
288  {
289  for (UString::iterator iter = _text.begin(); iter != _text.end(); ++iter)
290  {
291  if ( ((*iter) == FontCodeType::NEL) ||
292  ((*iter) == FontCodeType::CR) ||
293  ((*iter) == FontCodeType::LF) )
294  {
295  (*iter) = FontCodeType::Space;
296  }
297  }
298  }
299 
301  {
302  if (mCurrent == mEnd) return false;
303  mSave = mCurrent;
304  return true;
305  }
306 
308  {
309  if (mSave == mEnd) return L"";
310  size_t start = mSave - mText.begin();
311  return mText.substr(start, mCurrent - mText.begin() - start);
312  }
313 
315  {
316  if (mSave == mEnd) return false;
317  mCurrent = erase(mSave, mCurrent);
318  mSave = mEnd = mText.end();
319  return true;
320  }
321 
322  void TextIterator::insertText(const UString& _insert, bool _multiLine)
323  {
324  UString text = _insert;
325  if (!_multiLine) clearNewLine(text);
326  insert(mCurrent, text);
327  }
328 
329  void TextIterator::setText(const UString& _text, bool _multiLine)
330  {
331  // сначала все очищаем
332  clear();
333  // а теперь вставляем
334  UString text = _text;
335  if (!_multiLine) clearNewLine(text);
336  insert(mCurrent, text);
337  }
338 
340  {
341  if (_char == L'#') return L"##";
342  wchar_t buff[16] = L"_\0";
343  buff[0] = (wchar_t)_char;
344  return buff;
345  }
346 
348  {
349  const size_t SIZE = 16;
350  wchar_t buff[SIZE];
351 //FIXME
352 #ifdef __MINGW32__
353  swprintf(buff, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255));
354 #else
355  swprintf(buff, SIZE, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255));
356 #endif
357  return buff;
358  }
359 
361  {
362  // преобразуем в строку с тегами
363  UString text(_text);
364  for (UString::iterator iter = text.begin(); iter != text.end(); ++iter)
365  {
366  // потом переделать через TextIterator чтобы отвязать понятие тег от эдита
367  if (L'#' == (*iter)) iter = text.insert(++iter, L'#');
368  }
369  return text;
370  }
371 
372  void TextIterator::insert(UString::iterator& _start, UString& _insert)
373  {
374  // сбрасываем размер
375  mSize = ITEM_NONE;
376  // записываем в историю
377  if (mHistory) mHistory->push_back(TextCommandInfo(_insert, _start - mText.begin(), TextCommandInfo::COMMAND_INSERT));
378  // запоминаем позицию итератора
379  size_t pos = _start - mText.begin();
380  size_t pos_save = (mSave == mEnd) ? ITEM_NONE : _start - mText.begin();
381  // непосредственно вставляем
382  mText.insert(_start, _insert.begin(), _insert.end());
383  // возвращаем итераторы
384  _start = mText.begin() + pos;
385  mEnd = mText.end();
386  (pos_save == ITEM_NONE) ? mSave = mEnd : mSave = mText.begin() + pos_save;
387  }
388 
389  UString::iterator TextIterator::erase(UString::iterator _start, UString::iterator _end)
390  {
391  // сбрасываем размер
392  mSize = ITEM_NONE;
393  // сохраняем в историю
394  size_t start = _start - mText.begin();
395  if (mHistory) mHistory->push_back(TextCommandInfo(mText.substr(start, _end - _start), start, TextCommandInfo::COMMAND_ERASE));
396  // возвращаем итератор
397  return mText.erase(_start, _end);
398  }
399 
400  void TextIterator::clear()
401  {
402  if (mText.empty()) return;
403 
404  // записываем в историю
405  if (mHistory) mHistory->push_back(TextCommandInfo(mText, 0, TextCommandInfo::COMMAND_ERASE));
406 
407  // все сбрасываем
408  mText.clear();
409  mCurrent = mText.begin();
410  mEnd = mSave = mText.end();
411  mSize = ITEM_NONE;
412  }
413 
414  void TextIterator::cutMaxLength(size_t _max)
415  {
416  if ( (mSize != ITEM_NONE) && (mSize <= _max) ) return;
417  if (mPosition > _max)
418  {
419  // придется считать сначала
420  mSize = mPosition = 0;
421  mCurrent = mText.begin();
422  mEnd = mSave = mText.end();
423  }
424 
425  mSize = mPosition;
426 
427  for (UString::iterator iter = mCurrent; iter != mEnd; ++iter)
428  {
429 
430  if ((*iter) == L'#')
431  {
432  // следующий символ
433  ++ iter;
434  if (iter == mEnd) break;
435 
436  // тэг цвета
437  if ((*iter) != L'#')
438  {
439  // остальные 5 символов цвета
440  for (size_t pos = 0; pos < 5; pos++)
441  {
442  ++ iter;
443  if (iter == mEnd)
444  {
445  -- iter;
446  break;
447  }
448  }
449  continue;
450  }
451  }
452 
453  // проверяем и обрезаем
454  if (mSize == _max)
455  {
456  mPosition = mSize; // сохраняем
457  mCurrent = erase(iter, mEnd);
458  mSave = mEnd = mText.end();
459  mSize = mPosition; // восстанавливаем
460  return;
461  }
462 
463  // увеличиваем
464  mSize ++;
465  }
466  }
467 
469  {
470  // узнаем размер без тегов
471  size_t size = getSize();
472  if (size <= _max) return;
473 
474  // разница
475  size_t diff = size - _max;
476 
477  // последний цвет
478  UString::iterator iter_colour = mEnd;
479 
480  // теперь пройдем от начала и узнаем реальную позицию разницы
481  UString::iterator iter = mText.begin();
482  for (; iter != mEnd; ++iter)
483  {
484  if ((*iter) == L'#')
485  {
486  UString::iterator save = iter;
487 
488  // следующий символ
489  ++ iter;
490  if (iter == mEnd) break;
491 
492  // тэг цвета
493  if ((*iter) != L'#')
494  {
495  // остальные 5 символов цвета
496  for (size_t pos = 0; pos < 5; pos++)
497  {
498  ++ iter;
499  if (iter == mEnd)
500  {
501  -- iter;
502  break;
503  }
504  }
505  // сохраняем цвет
506  iter_colour = save;
507  }
508  continue;
509  }
510  // обычный символ был
511  if (diff == 0) break;
512  -- diff;
513  }
514 
515  UString colour;
516  // если бы цвет, то вставляем назад
517  if (iter_colour != mEnd)
518  {
519  colour.append(iter_colour, iter_colour + size_t(7));
520  }
521 
522  mCurrent = erase(mText.begin(), iter);
523  mEnd = mText.end();
524  mSave = mText.end(); //FIXME
525  mPosition = 0;
526  mSize = _max;
527 
528  if ( ! colour.empty() ) setTagColour(colour);
529 
530  }
531 
533  {
534  if (mCurrent == mEnd) return;
535 
536  UString::iterator iter = mCurrent;
537  UString colour;
538  // нам нужен последний цвет
539  while (getTagColour(colour, iter))
540  {
541  // обязательно обновляем итераторы
542  iter = mCurrent = erase(mCurrent, iter);
543  mEnd = mText.end();
544  }
545  }
546 
548  {
549  return mPosition;
550  }
551 
553  {
554  return mText;
555  }
556 
558  {
559  clear();
560  }
561 
563  {
564  return L"\n";
565  }
566 
567 } // namespace MyGUI
size_t getPosition() const
static UString getTextCharInfo(Char _char)
void clearNewLine(UString &_text)
const UString & getText() const
UString & append(const UString &str)
appends str on to the end of the current string
void cutMaxLength(size_t _max)
std::vector< TextCommandInfo > VectorChangeInfo
static UString getOnlyText(const UString &_text)
iterator erase(iterator loc)
removes the code point pointed to by loc, returning an iterator to the next character ...
bool getTagColour(UString &_colour) const
size_type find(const UString &str, size_type index=0) const
returns the index of the first occurrence of str within the current string, starting at index; return...
const size_t ITEM_NONE
Definition: MyGUI_Macros.h:32
static const size_type npos
the usual constant representing: not found, no limit, etc
const forward iterator for UString
#define nullptr
void push_back(unicode_char val)
appends val to the end of the string
void clear()
deletes all of the elements in the string
iterator begin()
returns an iterator to the first element of the string
_fwd_iterator iterator
iterator
void insertText(const UString &_insert, bool _multiLine)
UString substr(size_type index, size_type num=npos) const
returns a substring of the current string, starting at index, and num characters long.
static UString toTagsString(const UString &_text)
unsigned int Char
Definition: MyGUI_Types.h:66
void reserve(size_type size)
sets the capacity of the string to at least size code points
forward iterator for UString
void setText(const UString &_text, bool _multiLine)
bool setTagColour(const Colour &_colour)
static UString getTextNewLine()
A UTF-16 string with implicit conversion to/from std::string and std::wstring.
void cutMaxLengthFromBeginning(size_t _max)
iterator insert(iterator i, const code_point &ch)
inserts ch before the code point denoted by i
iterator end()
returns an iterator just past the end of the string
size_type size() const
Returns the number of code points in the current string.
static UString convertTagColour(const Colour &_colour)
bool empty() const
returns true if the string has no elements, false otherwise