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