MyGUI  3.2.1
MyGUI_TextIterator.cpp
Go to the documentation of this file.
00001 /*
00002  * This source file is part of MyGUI. For the latest info, see http://mygui.info/
00003  * Distributed under the MIT License
00004  * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
00005  */
00006 
00007 #include "MyGUI_Precompiled.h"
00008 #include "MyGUI_TextIterator.h"
00009 
00010 namespace MyGUI
00011 {
00012 
00013     TextIterator::TextIterator() :
00014         mPosition(0),
00015         mSize(ITEM_NONE),
00016         mFirst(true),
00017         mHistory(nullptr)
00018     {
00019     }
00020 
00021     TextIterator::TextIterator(const UString& _text, VectorChangeInfo* _history) :
00022         mText(_text),
00023         mCurrent(mText.begin()),
00024         mEnd(mText.end()),
00025         mSave(mEnd),
00026         mPosition(0),
00027         mSize(ITEM_NONE),
00028         mFirst(true),
00029         mHistory(_history)
00030     {
00031     }
00032 
00033     bool TextIterator::moveNext()
00034     {
00035         if (mCurrent == mEnd) return false;
00036         else if (mFirst)
00037         {
00038             mFirst = false;
00039             return true;
00040         }
00041 
00042         // ставим на следующий символ проскакивая все тэги
00043         for (UString::iterator iter = mCurrent; iter != mEnd; ++iter)
00044         {
00045 
00046             if ((*iter) == L'#')
00047             {
00048 
00049                 // следующий символ
00050                 ++ iter;
00051                 if (iter == mEnd)
00052                 {
00053                     mCurrent = mEnd;
00054                     return false;
00055                 }
00056 
00057                 // две решетки подряд
00058                 if ((*iter) == L'#')
00059                 {
00060 
00061                     // следующий символ
00062                     mPosition ++;
00063                     ++iter;
00064                     if (iter == mEnd)
00065                     {
00066                         mCurrent = mEnd;
00067                         return false;
00068                     }
00069 
00070                     // указатель на следующий символ
00071                     mCurrent = iter;
00072                     return true;
00073                 }
00074 
00075                 // остальные 5 символов цвета
00076                 for (size_t pos = 0; pos < 5; pos++)
00077                 {
00078                     // следующий символ
00079                     ++ iter;
00080                     if (iter == mEnd)
00081                     {
00082                         mCurrent = mEnd;
00083                         return false;
00084                     }
00085                 }
00086 
00087             }
00088             else
00089             {
00090 
00091                 // обыкновенный символ
00092                 mPosition ++;
00093                 ++iter;
00094                 if (iter == mEnd)
00095                 {
00096                     mCurrent = mEnd;
00097                     return false;
00098                 }
00099 
00100                 // указатель на следующий символ
00101                 mCurrent = iter;
00102                 return true;
00103             }
00104         }
00105 
00106         return false;
00107     }
00108 
00109     // возвращает цвет
00110     bool TextIterator::getTagColour(UString& _colour) const
00111     {
00112         if (mCurrent == mEnd) return false;
00113 
00114         UString::iterator iter = mCurrent;
00115 
00116         // нам нужен последний цвет
00117         bool ret = false;
00118         while (getTagColour(_colour, iter))
00119         {
00120             ret = true;
00121         }
00122 
00123         return ret;
00124     }
00125 
00126     bool TextIterator::setTagColour(const Colour& _colour)
00127     {
00128         if (mCurrent == mEnd) return false;
00129         // очищаем все цвета
00130         clearTagColour();
00131         // на всякий
00132         if (mCurrent == mEnd) return false;
00133 
00134         const size_t SIZE = 16;
00135         wchar_t buff[SIZE];
00136 
00137 #ifdef __MINGW32__
00138         swprintf(buff, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255));
00139 #else
00140         swprintf(buff, SIZE, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255));
00141 #endif
00142         // непосредственная вставка
00143         UString tmpStr = UString(buff);
00144         insert(mCurrent, tmpStr);
00145 
00146         return true;
00147     }
00148 
00149     bool TextIterator::setTagColour(UString _colour)
00150     {
00151         if (mCurrent == mEnd) return false;
00152         // очищаем все цвета
00153         clearTagColour();
00154         // на всякий
00155         if (mCurrent == mEnd) return false;
00156 
00157         // проверяем на цвет хоть чуть чуть
00158         if ( (_colour.size() != 7) || (_colour.find(L'#', 1) != _colour.npos) ) return false;
00159 
00160         // непосредственная вставка
00161         insert(mCurrent, _colour);
00162 
00163         return true;
00164     }
00165 
00166     // возвращает размер строки
00167     size_t TextIterator::getSize() const
00168     {
00169         if (mSize != ITEM_NONE) return mSize;
00170         mSize = mPosition;
00171 
00172         for (UString::iterator iter = mCurrent; iter != mEnd; ++iter)
00173         {
00174 
00175             if ((*iter) == L'#')
00176             {
00177                 // следующий символ
00178                 ++ iter;
00179                 if (iter == mEnd) break;
00180 
00181                 // тэг цвета
00182                 if ((*iter) != L'#')
00183                 {
00184                     // остальные 5 символов цвета
00185                     for (size_t pos = 0; pos < 5; pos++)
00186                     {
00187                         ++ iter;
00188                         if (iter == mEnd)
00189                         {
00190                             --iter;
00191                             break;
00192                         }
00193                     }
00194                     continue;
00195                 }
00196             }
00197 
00198             // обыкновенный символ
00199             mSize ++;
00200         }
00201 
00202         return mSize;
00203     }
00204 
00205     // возвращает текст без тегов
00206     UString TextIterator::getOnlyText(const UString& _text)
00207     {
00208         UString ret;
00209         ret.reserve(_text.size());
00210 
00211         UString::const_iterator end = _text.end();
00212         for (UString::const_iterator iter = _text.begin(); iter != end; ++iter)
00213         {
00214 
00215             if ((*iter) == L'#')
00216             {
00217                 // следующий символ
00218                 ++ iter;
00219                 if (iter == end) break;
00220 
00221                 // тэг цвета
00222                 if ((*iter) != L'#')
00223                 {
00224                     // остальные 5 символов цвета
00225                     for (size_t pos = 0; pos < 5; pos++)
00226                     {
00227                         ++ iter;
00228                         if (iter == end)
00229                         {
00230                             --iter;
00231                             break;
00232                         }
00233                     }
00234                     continue;
00235                 }
00236             }
00237 
00238             // обыкновенный символ
00239             ret.push_back(*iter);
00240         }
00241 
00242         return ret;
00243     }
00244 
00245     // возвращает цвет
00246     bool TextIterator::getTagColour(UString& _colour, UString::iterator& _iter) const
00247     {
00248         if ( (_iter == mEnd) || ((*_iter) != L'#') ) return false;
00249 
00250         // следующий символ
00251         ++_iter;
00252         if ( (_iter == mEnd) || ((*_iter) == L'#') ) return false;
00253 
00254         // берем цвет
00255         wchar_t buff[16] = L"#FFFFFF\0";
00256         buff[1] = (wchar_t)(*_iter);
00257         for (size_t pos = 2; pos < 7; pos++)
00258         {
00259             ++_iter;
00260             if ( _iter == mEnd ) return false;
00261             buff[pos] = (wchar_t)(*_iter);
00262         }
00263 
00264         // ставим на следующий тег или символ
00265         ++_iter;
00266 
00267         // возвращаем цвет
00268         _colour = buff;
00269         return true;
00270     }
00271 
00272     void TextIterator::clearNewLine(UString& _text)
00273     {
00274         for (UString::iterator iter = _text.begin(); iter != _text.end(); ++iter)
00275         {
00276             if ( ((*iter) == FontCodeType::NEL) ||
00277                 ((*iter) == FontCodeType::CR) ||
00278                 ((*iter) == FontCodeType::LF) )
00279             {
00280                 (*iter) = FontCodeType::Space;
00281             }
00282         }
00283     }
00284 
00285     bool TextIterator::saveStartPoint()
00286     {
00287         if (mCurrent == mEnd) return false;
00288         mSave = mCurrent;
00289         return true;
00290     }
00291 
00292     UString TextIterator::getFromStart()
00293     {
00294         if (mSave == mEnd) return L"";
00295         size_t start = mSave - mText.begin();
00296         return mText.substr(start, mCurrent - mText.begin() - start);
00297     }
00298 
00299     bool TextIterator::eraseFromStart()
00300     {
00301         if (mSave == mEnd) return false;
00302         mCurrent = erase(mSave, mCurrent);
00303         mSave = mEnd = mText.end();
00304         return true;
00305     }
00306 
00307     void TextIterator::insertText(const UString& _insert, bool _multiLine)
00308     {
00309         UString text = _insert;
00310 
00311         // нормализуем
00312         normaliseNewLine(text);
00313 
00314         if (!_multiLine)
00315             clearNewLine(text);
00316 
00317         insert(mCurrent, text);
00318     }
00319 
00320     void TextIterator::setText(const UString& _text, bool _multiLine)
00321     {
00322         // сначала все очищаем
00323         clear();
00324 
00325         // а теперь вставляем
00326         UString text = _text;
00327 
00328         // нормализуем
00329         normaliseNewLine(text);
00330 
00331         if (!_multiLine)
00332             clearNewLine(text);
00333 
00334         insert(mCurrent, text);
00335     }
00336 
00337     UString TextIterator::getTextCharInfo(Char _char)
00338     {
00339         if (_char == L'#') return L"##";
00340         wchar_t buff[16] = L"_\0";
00341         buff[0] = (wchar_t)_char;
00342         return buff;
00343     }
00344 
00345     UString TextIterator::convertTagColour(const Colour& _colour)
00346     {
00347         const size_t SIZE = 16;
00348         wchar_t buff[SIZE];
00349 //FIXME
00350 #ifdef __MINGW32__
00351         swprintf(buff, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255));
00352 #else
00353         swprintf(buff, SIZE, L"#%.2X%.2X%.2X\0", (int)(_colour.red * 255), (int)(_colour.green * 255), (int)(_colour.blue * 255));
00354 #endif
00355         return buff;
00356     }
00357 
00358     UString TextIterator::toTagsString(const UString& _text)
00359     {
00360         // преобразуем в строку с тегами
00361         UString text(_text);
00362         for (UString::iterator iter = text.begin(); iter != text.end(); ++iter)
00363         {
00364             // потом переделать через TextIterator чтобы отвязать понятие тег от эдита
00365             if (L'#' == (*iter)) iter = text.insert(++iter, L'#');
00366         }
00367         return text;
00368     }
00369 
00370     void TextIterator::insert(UString::iterator& _start, UString& _insert)
00371     {
00372         // сбрасываем размер
00373         mSize = ITEM_NONE;
00374         // записываем в историю
00375         if (mHistory) mHistory->push_back(TextCommandInfo(_insert, _start - mText.begin(), TextCommandInfo::COMMAND_INSERT));
00376         // запоминаем позицию итератора
00377         size_t pos = _start - mText.begin();
00378         size_t pos_save = (mSave == mEnd) ? ITEM_NONE : _start - mText.begin();
00379         // непосредственно вставляем
00380         mText.insert(_start, _insert.begin(), _insert.end());
00381         // возвращаем итераторы
00382         _start = mText.begin() + pos;
00383         mEnd = mText.end();
00384         (pos_save == ITEM_NONE) ? mSave = mEnd : mSave = mText.begin() + pos_save;
00385     }
00386 
00387     UString::iterator TextIterator::erase(UString::iterator _start, UString::iterator _end)
00388     {
00389         // сбрасываем размер
00390         mSize = ITEM_NONE;
00391         // сохраняем в историю
00392         size_t start = _start - mText.begin();
00393         if (mHistory) mHistory->push_back(TextCommandInfo(mText.substr(start, _end - _start), start, TextCommandInfo::COMMAND_ERASE));
00394         // возвращаем итератор
00395         return mText.erase(_start, _end);
00396     }
00397 
00398     void TextIterator::clear()
00399     {
00400         if (mText.empty()) return;
00401 
00402         // записываем в историю
00403         if (mHistory) mHistory->push_back(TextCommandInfo(mText, 0, TextCommandInfo::COMMAND_ERASE));
00404 
00405         // все сбрасываем
00406         mText.clear();
00407         mCurrent = mText.begin();
00408         mEnd = mSave = mText.end();
00409         mSize = ITEM_NONE;
00410     }
00411 
00412     void TextIterator::cutMaxLength(size_t _max)
00413     {
00414         if ( (mSize != ITEM_NONE) && (mSize <= _max) ) return;
00415         if (mPosition > _max)
00416         {
00417             // придется считать сначала
00418             mSize = mPosition = 0;
00419             mCurrent = mText.begin();
00420             mEnd = mSave = mText.end();
00421         }
00422 
00423         mSize = mPosition;
00424 
00425         for (UString::iterator iter = mCurrent; iter != mEnd; ++iter)
00426         {
00427 
00428             if ((*iter) == L'#')
00429             {
00430                 // следующий символ
00431                 ++ iter;
00432                 if (iter == mEnd) break;
00433 
00434                 // тэг цвета
00435                 if ((*iter) != L'#')
00436                 {
00437                     // остальные 5 символов цвета
00438                     for (size_t pos = 0; pos < 5; pos++)
00439                     {
00440                         ++ iter;
00441                         if (iter == mEnd)
00442                         {
00443                             -- iter;
00444                             break;
00445                         }
00446                     }
00447                     continue;
00448                 }
00449             }
00450 
00451             // проверяем и обрезаем
00452             if (mSize == _max)
00453             {
00454                 mPosition = mSize; // сохраняем
00455                 mCurrent = erase(iter, mEnd);
00456                 mSave = mEnd = mText.end();
00457                 mSize = mPosition; // восстанавливаем
00458                 return;
00459             }
00460 
00461             // увеличиваем
00462             mSize ++;
00463         }
00464     }
00465 
00466     void TextIterator::cutMaxLengthFromBeginning(size_t _max)
00467     {
00468         // узнаем размер без тегов
00469         size_t size = getSize();
00470         if (size <= _max) return;
00471 
00472         // разница
00473         size_t diff = size - _max;
00474 
00475         // последний цвет
00476         UString::iterator iter_colour = mEnd;
00477 
00478         // теперь пройдем от начала и узнаем реальную позицию разницы
00479         UString::iterator iter = mText.begin();
00480         for (; iter != mEnd; ++iter)
00481         {
00482             if ((*iter) == L'#')
00483             {
00484                 UString::iterator save = iter;
00485 
00486                 // следующий символ
00487                 ++ iter;
00488                 if (iter == mEnd) break;
00489 
00490                 // тэг цвета
00491                 if ((*iter) != L'#')
00492                 {
00493                     // остальные 5 символов цвета
00494                     for (size_t pos = 0; pos < 5; pos++)
00495                     {
00496                         ++ iter;
00497                         if (iter == mEnd)
00498                         {
00499                             -- iter;
00500                             break;
00501                         }
00502                     }
00503                     // сохраняем цвет
00504                     iter_colour = save;
00505                 }
00506                 continue;
00507             }
00508             // обычный символ был
00509             if (diff == 0) break;
00510             -- diff;
00511         }
00512 
00513         UString colour;
00514         // если бы цвет, то вставляем назад
00515         if (iter_colour != mEnd)
00516         {
00517             colour.append(iter_colour, iter_colour + size_t(7));
00518         }
00519 
00520         mCurrent = erase(mText.begin(), iter);
00521         mEnd = mText.end();
00522         mSave = mText.end(); //FIXME
00523         mPosition = 0;
00524         mSize = _max;
00525 
00526         if ( ! colour.empty() ) setTagColour(colour);
00527 
00528     }
00529 
00530     void TextIterator::clearTagColour()
00531     {
00532         if (mCurrent == mEnd) return;
00533 
00534         UString::iterator iter = mCurrent;
00535         UString colour;
00536         // нам нужен последний цвет
00537         while (getTagColour(colour, iter))
00538         {
00539             // обязательно обновляем итераторы
00540             iter = mCurrent = erase(mCurrent, iter);
00541             mEnd = mText.end();
00542         }
00543     }
00544 
00545     size_t TextIterator::getPosition() const
00546     {
00547         return mPosition;
00548     }
00549 
00550     const UString& TextIterator::getText() const
00551     {
00552         return mText;
00553     }
00554 
00555     void TextIterator::clearText()
00556     {
00557         clear();
00558     }
00559 
00560     UString TextIterator::getTextNewLine()
00561     {
00562         return L"\n";
00563     }
00564 
00565     void TextIterator::normaliseNewLine(UString& _text)
00566     {
00567         for (size_t index = 0; index < _text.size(); ++index)
00568         {
00569             Char character = _text[index];
00570             if ((character == FontCodeType::CR) &&
00571                 ((index + 1) < _text.size()) &&
00572                 (_text[index + 1] == FontCodeType::LF))
00573             {
00574                 _text.erase(index, 1);
00575             }
00576         }
00577     }
00578 
00579 } // namespace MyGUI