MyGUI  3.2.1
MyGUI_TextIterator.cpp
Go to the documentation of this file.
1 /*
2  * This source file is part of MyGUI. For the latest info, see http://mygui.info/
3  * Distributed under the MIT License
4  * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
5  */
6 
7 #include "MyGUI_Precompiled.h"
8 #include "MyGUI_TextIterator.h"
9 
10 namespace MyGUI
11 {
12 
13  TextIterator::TextIterator() :
14  mPosition(0),
15  mSize(ITEM_NONE),
16  mFirst(true),
17  mHistory(nullptr)
18  {
19  }
20 
21  TextIterator::TextIterator(const UString& _text, VectorChangeInfo* _history) :
22  mText(_text),
23  mCurrent(mText.begin()),
24  mEnd(mText.end()),
25  mSave(mEnd),
26  mPosition(0),
27  mSize(ITEM_NONE),
28  mFirst(true),
29  mHistory(_history)
30  {
31  }
32 
34  {
35  if (mCurrent == mEnd) return false;
36  else if (mFirst)
37  {
38  mFirst = false;
39  return true;
40  }
41 
42  // ставим на следующий символ проскакивая все тэги
43  for (UString::iterator iter = mCurrent; iter != mEnd; ++iter)
44  {
45 
46  if ((*iter) == L'#')
47  {
48 
49  // следующий символ
50  ++ iter;
51  if (iter == mEnd)
52  {
53  mCurrent = mEnd;
54  return false;
55  }
56 
57  // две решетки подряд
58  if ((*iter) == L'#')
59  {
60 
61  // следующий символ
62  mPosition ++;
63  ++iter;
64  if (iter == mEnd)
65  {
66  mCurrent = mEnd;
67  return false;
68  }
69 
70  // указатель на следующий символ
71  mCurrent = iter;
72  return true;
73  }
74 
75  // остальные 5 символов цвета
76  for (size_t pos = 0; pos < 5; pos++)
77  {
78  // следующий символ
79  ++ iter;
80  if (iter == mEnd)
81  {
82  mCurrent = mEnd;
83  return false;
84  }
85  }
86 
87  }
88  else
89  {
90 
91  // обыкновенный символ
92  mPosition ++;
93  ++iter;
94  if (iter == mEnd)
95  {
96  mCurrent = mEnd;
97  return false;
98  }
99 
100  // указатель на следующий символ
101  mCurrent = iter;
102  return true;
103  }
104  }
105 
106  return false;
107  }
108 
109  // возвращает цвет
110  bool TextIterator::getTagColour(UString& _colour) const
111  {
112  if (mCurrent == mEnd) return false;
113 
114  UString::iterator iter = mCurrent;
115 
116  // нам нужен последний цвет
117  bool ret = false;
118  while (getTagColour(_colour, iter))
119  {
120  ret = true;
121  }
122 
123  return ret;
124  }
125 
126  bool TextIterator::setTagColour(const Colour& _colour)
127  {
128  if (mCurrent == mEnd) return false;
129  // очищаем все цвета
130  clearTagColour();
131  // на всякий
132  if (mCurrent == mEnd) return false;
133 
134  const size_t SIZE = 16;
135  wchar_t buff[SIZE];
136 
137 #ifdef __MINGW32__
138  swprintf(buff, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255));
139 #else
140  swprintf(buff, SIZE, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255));
141 #endif
142  // непосредственная вставка
143  UString tmpStr = UString(buff);
144  insert(mCurrent, tmpStr);
145 
146  return true;
147  }
148 
150  {
151  if (mCurrent == mEnd) return false;
152  // очищаем все цвета
153  clearTagColour();
154  // на всякий
155  if (mCurrent == mEnd) return false;
156 
157  // проверяем на цвет хоть чуть чуть
158  if ( (_colour.size() != 7) || (_colour.find(L'#', 1) != _colour.npos) ) return false;
159 
160  // непосредственная вставка
161  insert(mCurrent, _colour);
162 
163  return true;
164  }
165 
166  // возвращает размер строки
167  size_t TextIterator::getSize() const
168  {
169  if (mSize != ITEM_NONE) return mSize;
170  mSize = mPosition;
171 
172  for (UString::iterator iter = mCurrent; iter != mEnd; ++iter)
173  {
174 
175  if ((*iter) == L'#')
176  {
177  // следующий символ
178  ++ iter;
179  if (iter == mEnd) break;
180 
181  // тэг цвета
182  if ((*iter) != L'#')
183  {
184  // остальные 5 символов цвета
185  for (size_t pos = 0; pos < 5; pos++)
186  {
187  ++ iter;
188  if (iter == mEnd)
189  {
190  --iter;
191  break;
192  }
193  }
194  continue;
195  }
196  }
197 
198  // обыкновенный символ
199  mSize ++;
200  }
201 
202  return mSize;
203  }
204 
205  // возвращает текст без тегов
207  {
208  UString ret;
209  ret.reserve(_text.size());
210 
211  UString::const_iterator end = _text.end();
212  for (UString::const_iterator iter = _text.begin(); iter != end; ++iter)
213  {
214 
215  if ((*iter) == L'#')
216  {
217  // следующий символ
218  ++ iter;
219  if (iter == end) break;
220 
221  // тэг цвета
222  if ((*iter) != L'#')
223  {
224  // остальные 5 символов цвета
225  for (size_t pos = 0; pos < 5; pos++)
226  {
227  ++ iter;
228  if (iter == end)
229  {
230  --iter;
231  break;
232  }
233  }
234  continue;
235  }
236  }
237 
238  // обыкновенный символ
239  ret.push_back(*iter);
240  }
241 
242  return ret;
243  }
244 
245  // возвращает цвет
246  bool TextIterator::getTagColour(UString& _colour, UString::iterator& _iter) const
247  {
248  if ( (_iter == mEnd) || ((*_iter) != L'#') ) return false;
249 
250  // следующий символ
251  ++_iter;
252  if ( (_iter == mEnd) || ((*_iter) == L'#') ) return false;
253 
254  // берем цвет
255  wchar_t buff[16] = L"#FFFFFF\0";
256  buff[1] = (wchar_t)(*_iter);
257  for (size_t pos = 2; pos < 7; pos++)
258  {
259  ++_iter;
260  if ( _iter == mEnd ) return false;
261  buff[pos] = (wchar_t)(*_iter);
262  }
263 
264  // ставим на следующий тег или символ
265  ++_iter;
266 
267  // возвращаем цвет
268  _colour = buff;
269  return true;
270  }
271 
273  {
274  for (UString::iterator iter = _text.begin(); iter != _text.end(); ++iter)
275  {
276  if ( ((*iter) == FontCodeType::NEL) ||
277  ((*iter) == FontCodeType::CR) ||
278  ((*iter) == FontCodeType::LF) )
279  {
280  (*iter) = FontCodeType::Space;
281  }
282  }
283  }
284 
286  {
287  if (mCurrent == mEnd) return false;
288  mSave = mCurrent;
289  return true;
290  }
291 
293  {
294  if (mSave == mEnd) return L"";
295  size_t start = mSave - mText.begin();
296  return mText.substr(start, mCurrent - mText.begin() - start);
297  }
298 
300  {
301  if (mSave == mEnd) return false;
302  mCurrent = erase(mSave, mCurrent);
303  mSave = mEnd = mText.end();
304  return true;
305  }
306 
307  void TextIterator::insertText(const UString& _insert, bool _multiLine)
308  {
309  UString text = _insert;
310 
311  // нормализуем
312  normaliseNewLine(text);
313 
314  if (!_multiLine)
315  clearNewLine(text);
316 
317  insert(mCurrent, text);
318  }
319 
320  void TextIterator::setText(const UString& _text, bool _multiLine)
321  {
322  // сначала все очищаем
323  clear();
324 
325  // а теперь вставляем
326  UString text = _text;
327 
328  // нормализуем
329  normaliseNewLine(text);
330 
331  if (!_multiLine)
332  clearNewLine(text);
333 
334  insert(mCurrent, text);
335  }
336 
338  {
339  if (_char == L'#') return L"##";
340  wchar_t buff[16] = L"_\0";
341  buff[0] = (wchar_t)_char;
342  return buff;
343  }
344 
346  {
347  const size_t SIZE = 16;
348  wchar_t buff[SIZE];
349 //FIXME
350 #ifdef __MINGW32__
351  swprintf(buff, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255));
352 #else
353  swprintf(buff, SIZE, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255));
354 #endif
355  return buff;
356  }
357 
359  {
360  // преобразуем в строку с тегами
361  UString text(_text);
362  for (UString::iterator iter = text.begin(); iter != text.end(); ++iter)
363  {
364  // потом переделать через TextIterator чтобы отвязать понятие тег от эдита
365  if (L'#' == (*iter)) iter = text.insert(++iter, L'#');
366  }
367  return text;
368  }
369 
370  void TextIterator::insert(UString::iterator& _start, UString& _insert)
371  {
372  // сбрасываем размер
373  mSize = ITEM_NONE;
374  // записываем в историю
375  if (mHistory) mHistory->push_back(TextCommandInfo(_insert, _start - mText.begin(), TextCommandInfo::COMMAND_INSERT));
376  // запоминаем позицию итератора
377  size_t pos = _start - mText.begin();
378  size_t pos_save = (mSave == mEnd) ? ITEM_NONE : _start - mText.begin();
379  // непосредственно вставляем
380  mText.insert(_start, _insert.begin(), _insert.end());
381  // возвращаем итераторы
382  _start = mText.begin() + pos;
383  mEnd = mText.end();
384  (pos_save == ITEM_NONE) ? mSave = mEnd : mSave = mText.begin() + pos_save;
385  }
386 
387  UString::iterator TextIterator::erase(UString::iterator _start, UString::iterator _end)
388  {
389  // сбрасываем размер
390  mSize = ITEM_NONE;
391  // сохраняем в историю
392  size_t start = _start - mText.begin();
393  if (mHistory) mHistory->push_back(TextCommandInfo(mText.substr(start, _end - _start), start, TextCommandInfo::COMMAND_ERASE));
394  // возвращаем итератор
395  return mText.erase(_start, _end);
396  }
397 
398  void TextIterator::clear()
399  {
400  if (mText.empty()) return;
401 
402  // записываем в историю
403  if (mHistory) mHistory->push_back(TextCommandInfo(mText, 0, TextCommandInfo::COMMAND_ERASE));
404 
405  // все сбрасываем
406  mText.clear();
407  mCurrent = mText.begin();
408  mEnd = mSave = mText.end();
409  mSize = ITEM_NONE;
410  }
411 
412  void TextIterator::cutMaxLength(size_t _max)
413  {
414  if ( (mSize != ITEM_NONE) && (mSize <= _max) ) return;
415  if (mPosition > _max)
416  {
417  // придется считать сначала
418  mSize = mPosition = 0;
419  mCurrent = mText.begin();
420  mEnd = mSave = mText.end();
421  }
422 
423  mSize = mPosition;
424 
425  for (UString::iterator iter = mCurrent; iter != mEnd; ++iter)
426  {
427 
428  if ((*iter) == L'#')
429  {
430  // следующий символ
431  ++ iter;
432  if (iter == mEnd) break;
433 
434  // тэг цвета
435  if ((*iter) != L'#')
436  {
437  // остальные 5 символов цвета
438  for (size_t pos = 0; pos < 5; pos++)
439  {
440  ++ iter;
441  if (iter == mEnd)
442  {
443  -- iter;
444  break;
445  }
446  }
447  continue;
448  }
449  }
450 
451  // проверяем и обрезаем
452  if (mSize == _max)
453  {
454  mPosition = mSize; // сохраняем
455  mCurrent = erase(iter, mEnd);
456  mSave = mEnd = mText.end();
457  mSize = mPosition; // восстанавливаем
458  return;
459  }
460 
461  // увеличиваем
462  mSize ++;
463  }
464  }
465 
467  {
468  // узнаем размер без тегов
469  size_t size = getSize();
470  if (size <= _max) return;
471 
472  // разница
473  size_t diff = size - _max;
474 
475  // последний цвет
476  UString::iterator iter_colour = mEnd;
477 
478  // теперь пройдем от начала и узнаем реальную позицию разницы
479  UString::iterator iter = mText.begin();
480  for (; iter != mEnd; ++iter)
481  {
482  if ((*iter) == L'#')
483  {
484  UString::iterator save = iter;
485 
486  // следующий символ
487  ++ iter;
488  if (iter == mEnd) break;
489 
490  // тэг цвета
491  if ((*iter) != L'#')
492  {
493  // остальные 5 символов цвета
494  for (size_t pos = 0; pos < 5; pos++)
495  {
496  ++ iter;
497  if (iter == mEnd)
498  {
499  -- iter;
500  break;
501  }
502  }
503  // сохраняем цвет
504  iter_colour = save;
505  }
506  continue;
507  }
508  // обычный символ был
509  if (diff == 0) break;
510  -- diff;
511  }
512 
513  UString colour;
514  // если бы цвет, то вставляем назад
515  if (iter_colour != mEnd)
516  {
517  colour.append(iter_colour, iter_colour + size_t(7));
518  }
519 
520  mCurrent = erase(mText.begin(), iter);
521  mEnd = mText.end();
522  mSave = mText.end(); //FIXME
523  mPosition = 0;
524  mSize = _max;
525 
526  if ( ! colour.empty() ) setTagColour(colour);
527 
528  }
529 
531  {
532  if (mCurrent == mEnd) return;
533 
534  UString::iterator iter = mCurrent;
535  UString colour;
536  // нам нужен последний цвет
537  while (getTagColour(colour, iter))
538  {
539  // обязательно обновляем итераторы
540  iter = mCurrent = erase(mCurrent, iter);
541  mEnd = mText.end();
542  }
543  }
544 
546  {
547  return mPosition;
548  }
549 
551  {
552  return mText;
553  }
554 
556  {
557  clear();
558  }
559 
561  {
562  return L"\n";
563  }
564 
565  void TextIterator::normaliseNewLine(UString& _text)
566  {
567  for (size_t index = 0; index < _text.size(); ++index)
568  {
569  Char character = _text[index];
570  if ((character == FontCodeType::CR) &&
571  ((index + 1) < _text.size()) &&
572  (_text[index + 1] == FontCodeType::LF))
573  {
574  _text.erase(index, 1);
575  }
576  }
577  }
578 
579 } // namespace MyGUI