MezzanineEngine 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
texttoken.cpp
1 //© Copyright 2010 - 2012 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 #ifndef _uitexttoken_cpp
41 #define _uitexttoken_cpp
42 
43 #include "UI/texttoken.h"
44 
45 #include "unicode.h"
46 #include "exception.h"
47 
48 namespace Mezzanine
49 {
50  namespace UI
51  {
52  ///////////////////////////////////////////////////////////////////////////////
53  // TextToken Methods
54 
56  {
57  Int32 BytesAdvance = 0;
58  UInt32 CurrRawIndex = 0;
59  UInt32 CurrRenderIndex = 0;
60  while( CurrRawIndex < this->Text.size() && CurrRenderIndex < Index )
61  {
62  if( Unicode::GetIntFromCharacter(BytesAdvance,this->Text.data() + CurrRawIndex) < 0 ) {
63  return -1;
64  }
65  CurrRawIndex += BytesAdvance;
66  ++CurrRenderIndex;
67  }
68 
69  return CurrRawIndex;
70  }
71 
73  { return this->Text; }
74 
76  { return this->Type; }
77 
79  { return this->Text.size(); }
80 
82  { return this->RenderSize; }
83 
85  {
86  return this->InsertCharacters(Index,&UChar,1);
87  }
88 
89  UInt32 TextToken::InsertCharacters(const UInt32 Index, const Char8* Characters, const UInt32 Size)
90  {
91  if( this->RenderSize >= Index )
92  {
93  UInt32 RawIndex = this->ConvertRenderIndexToRawIndex(Index);
94  if( RawIndex < 0 ) {
95  return 0;
96  }
97 
98  UInt32 Ret = 0;
99  // Verify the encoding and count the characters
100  UInt32 BufPos = 0;
101  Int32 BytesAdvance = 0;
102  //Char8 ConversionBuffer[4];
103  while( BufPos < Size )
104  {
105  if( Unicode::GetIntFromCharacter(BytesAdvance,Characters + BufPos) < 0 ) {
106  return 0;
107  }
108  BufPos += static_cast<UInt32>(BytesAdvance);
109  ++Ret;
110  }
111  this->Text.insert(RawIndex,Characters[0],Size);
112  return Ret;
113  }
114  return 0;
115  }
116 
117  UInt32 TextToken::InsertCharacters(const UInt32 Index, const UInt32* Characters, const UInt32 Size)
118  {
119  if( this->RenderSize >= Index )
120  {
121  UInt32 RawIndex = this->ConvertRenderIndexToRawIndex(Index);
122  if( RawIndex < 0 ) {
123  return 0;
124  }
125 
126  Int32 BytesAdvance = 0;
127  UInt32 SourceBufPos = 0;
128  UInt32 ConvBufPos = 0;
129  UInt32 ConvBufSize = Size * 4; // Max size needed
130  Char8* ConversionBuffer = new Char8[ConvBufSize];
131  while( SourceBufPos < Size )
132  {
133  BytesAdvance = Unicode::GetCharacterFromInt(&(ConversionBuffer[ConvBufPos]),ConvBufSize - ConvBufPos,Characters[SourceBufPos]);
134  if( BytesAdvance < 0 ) {
135  return 0;
136  }
137 
138  ConvBufPos += static_cast<UInt32>(BytesAdvance);
139  ++SourceBufPos;
140  }
141 
142  this->Text.insert(RawIndex,ConversionBuffer,ConvBufPos);
143  delete[] ConversionBuffer;
144  return Size;
145  }
146  return 0;
147  }
148 
150  {
151  if( this->RenderSize > Index )
152  {
153  UInt32 RawIndex = this->ConvertRenderIndexToRawIndex(Index);
154  if( RawIndex < 0 ) {
155  return 0;
156  }
157 
158  Int32 BytesAdvance = 0;
159  if( RawIndex < this->Text.size() ) { //possibly redundent check
160  if( Unicode::GetIntFromCharacter(BytesAdvance,(this->Text.data() + RawIndex)) < 0 ) {
161  return 0;
162  }
163  this->Text.erase(RawIndex,BytesAdvance);
164  return 1;
165  }
166  }
167  return 0;
168  }
169 
170  UInt32 TextToken::RemoveCharacters(const UInt32 Index, const UInt32 Length)
171  {
172  if( this->RenderSize > Index )
173  {
174  UInt32 RawIndex = this->ConvertRenderIndexToRawIndex(Index);
175  if( RawIndex < 0 ) {
176  return 0;
177  }
178 
179  // Start another loop to find the length
180  Int32 BytesAdvance = 0;
181  UInt32 CurrRawLength = 0;
182  UInt32 CurrRenderLength = 0;
183  while( RawIndex + CurrRawLength < this->Text.size() && CurrRenderLength < Length )
184  {
185  if( Unicode::GetIntFromCharacter(BytesAdvance,(this->Text.data() + RawIndex) + CurrRawLength) < 0 ) {
186  return 0;
187  }
188  CurrRawLength += static_cast<UInt32>(BytesAdvance);
189  ++CurrRenderLength;
190  }
191 
192  this->Text.erase(RawIndex,CurrRawLength);
193  return CurrRenderLength;
194  }
195  return 0;
196  }
197 
199  {
200  UInt32 PrevSize = this->RenderSize;
201  this->Text.clear();
202  this->RenderSize = 0;
203  return PrevSize;
204  }
205 
206  ///////////////////////////////////////////////////////////////////////////////
207  // TagToken Methods
208 
210  {
211  return this->TagName;
212  }
213 
215  {
216  NameValuePairMap::const_iterator ParamIt = this->Params.find(Param);
217  if( ParamIt != this->Params.end() ) return (*ParamIt).second;
218  else return "";
219  }
220 
221  ///////////////////////////////////////////////////////////////////////////////
222  // RangeTagToken Methods
223 
225  {
226  return this->PartnerTag;
227  }
228 
230  {
231  if( this->PartnerTag == NULL ) {
232  if( this->RenderSize != 0 ) {
233  return this->TextToken::InsertCharacter(Index,UChar);
234  }
235  }
236  return 0;
237  }
238 
239  UInt32 RangeTagToken::InsertCharacters(const UInt32 Index, const Char8* Characters, const UInt32 Size)
240  {
241  if( this->PartnerTag == NULL ) {
242  if( this->RenderSize != 0 ) {
243  return this->TextToken::InsertCharacters(Index,Characters,Size);
244  }
245  }
246  return 0;
247  }
248 
249  UInt32 RangeTagToken::InsertCharacters(const UInt32 Index, const UInt32* Characters, const UInt32 Size)
250  {
251  if( this->PartnerTag == NULL ) {
252  if( this->RenderSize != 0 ) {
253  return this->TextToken::InsertCharacters(Index,Characters,Size);
254  }
255  }
256  return 0;
257  }
258 
260  {
261  if( this->PartnerTag == NULL ) {
262  if( this->RenderSize != 0 ) {
263  return this->TextToken::RemoveCharacter(Index);
264  }
265  }
266  return 0;
267  }
268 
270  {
271  if( this->PartnerTag == NULL ) {
272  if( this->RenderSize != 0 ) {
273  return this->TextToken::RemoveCharacters(Index,Length);
274  }
275  }
276  return 0;
277  }
278 
280  {
281  if( this->PartnerTag == NULL ) {
282  if( this->RenderSize != 0 ) {
283  return this->TextToken::ClearAllCharacters();
284  }
285  }
286  return 0;
287  }
288 
289  ///////////////////////////////////////////////////////////////////////////////
290  // InsertTagToken Methods
291 
293  {
294  // Glyphs can't be inserted into this type of token.
295  return 0;
296  }
297 
298  UInt32 InsertTagToken::InsertCharacters(const UInt32 Index, const Char8* Characters, const UInt32 Size)
299  {
300  // Glyphs can't be inserted into this type of token.
301  return 0;
302  }
303 
304  UInt32 InsertTagToken::InsertCharacters(const UInt32 Index, const UInt32* Characters, const UInt32 Size)
305  {
306  // Glyphs can't be inserted into this type of token.
307  return 0;
308  }
309 
311  {
312  if( this->RenderSize != 0 && Index == 0 ) {
313  this->Text.clear();
314  this->RenderSize = 0;
315  return 1;
316  }
317  return 0;
318  }
319 
321  {
322  if( this->RenderSize != 0 && Index == 0 && Length > 0 ) {
323  this->Text.clear();
324  this->RenderSize = 0;
325  return 1;
326  }
327  return 0;
328  }
329 
331  {
332  if( this->RenderSize != 0 ) {
333  this->Text.clear();
334  this->RenderSize = 0;
335  return 1;
336  }
337  return 0;
338  }
339 
340  ///////////////////////////////////////////////////////////////////////////////
341  // TokenString Methods
342 
344  { }
345 
347  { this->DestroyAllTokens(); }
348 
350  {
351  TokenIndexPair Ret(this->Tokens.begin(),0);
352  UInt32 IndexCount = 0;
353  for( TokenIterator TokIt = this->Tokens.begin() ; TokIt != this->Tokens.end() ; ++TokIt )
354  {
355  if( IndexCount + (*TokIt)->GetRenderCharacterSize() < Index ) {
356  IndexCount += (*TokIt)->GetRenderCharacterSize();
357  continue;
358  }else{
359  Ret.first = TokIt;
360  Ret.second = Index - IndexCount;
361  return Ret;
362  }
363  }
364  // If we get to this point, then the index requested is out of bounds.
365  // Just return the last token and it's max index.
366  Ret.first = --(this->Tokens.end());
367  Ret.second = (*Ret.first)->GetRenderCharacterSize();
368  return Ret;
369  }
370 
371  ///////////////////////////////////////////////////////////////////////////////
372  // Utility
373 
375  {
376  String Ret;
377  for( ConstTokenIterator TokIt = this->Tokens.begin() ; TokIt != this->Tokens.end() ; ++TokIt )
378  {
379  Ret.append( (*TokIt)->GetRawCharacterString() );
380  }
381  return Ret;
382  }
383 
385  { return this->Tokens.begin(); }
386 
388  { return this->Tokens.end(); }
389 
391  { return this->Tokens.begin(); }
392 
394  { return this->Tokens.end(); }
395 
397  { return this->Tokens.rbegin(); }
398 
400  { return this->Tokens.rend(); }
401 
403  { return this->Tokens.rbegin(); }
404 
406  { return this->Tokens.rend(); }
407 
408  ///////////////////////////////////////////////////////////////////////////////
409  // Generating the String
410 
412  { this->Tokens.push_back(ToBePushed); }
413 
414  void TokenString::PushTokens(const TokenContainer& ToBePushed)
415  { this->Tokens.insert(this->Tokens.end(),ToBePushed.begin(),ToBePushed.end()); }
416 
418  {
419  for( TokenIterator TokIt = this->Tokens.begin() ; TokIt != this->Tokens.end() ; ++TokIt )
420  {
421  delete (*TokIt);
422  }
423  this->Tokens.clear();
424  }
425 
426  ///////////////////////////////////////////////////////////////////////////////
427  // Inserting and Removing
428 
430  {
431  TokenIndexPair Result = this->GetTokenIndex(Index);
432  UInt32 Ret = (*Result.first)->InsertCharacter(Result.second,UChar);
433  if( Ret == 0 ) {
434  // If we're here, then we're probably on a token that isn't a text token, or behaving like one.
435  // There are a number of conditions depending on tag types that could cause this, so instead of trying to troubleshoot them, lets just insert a new text token.
436  TextToken* NewToken = new TextToken(&UChar,1);
437  this->Tokens.insert(Result.first,NewToken);
438  Ret = 1;
439  }
440  return Ret;
441  }
442 
443  UInt32 TokenString::InsertCharacters(const UInt32 Index, const Char8* Characters, const UInt32 Size)
444  {
445  TokenIndexPair Result = this->GetTokenIndex(Index);
446  UInt32 Ret = (*Result.first)->InsertCharacters(Result.second,Characters,Size);
447  if( Ret == 0 ) {
448  // If we're here, then we're probably on a token that isn't a text token, or behaving like one.
449  // There are a number of conditions depending on tag types that could cause this, so instead of trying to troubleshoot them, lets just insert a new text token.
450  TextToken* NewToken = new TextToken(Characters,Size);
451  this->Tokens.insert(Result.first,NewToken);
452  Ret = Size;
453  }
454  return Ret;
455  }
456 
457  UInt32 TokenString::InsertCharacters(const UInt32 Index, const UInt32* Characters, const UInt32 Size)
458  {
459  TokenIndexPair Result = this->GetTokenIndex(Index);
460  UInt32 Ret = (*Result.first)->InsertCharacters(Result.second,Characters,Size);
461  if( Ret == 0 ) {
462  // If we're here, then we're probably on a token that isn't a text token, or behaving like one.
463  // There are a number of conditions depending on tag types that could cause this, so instead of trying to troubleshoot them, lets just insert a new text token.
464  TextToken* NewToken = new TextToken(Characters,Size);
465  this->Tokens.insert(Result.first,NewToken);
466  Ret = Size;
467  }
468  return Ret;
469  }
470 
472  {
473  TokenIndexPair Result = this->GetTokenIndex(Index);
474  return (*Result.first)->RemoveCharacter(Result.second);
475  }
476 
478  {
479  TokenIndexPair Result = this->GetTokenIndex(Index);
480  UInt32 Removed = (*Result.first)->RemoveCharacters(Result.second,Length);
481  while( Removed < Length ) {
482  ++(Result.first);
483  if( Result.first == this->Tokens.end() )
484  break;
485 
486  Removed += (*Result.first)->RemoveCharacters(Result.second,Length - Removed);
487  }
488  return Removed;
489  }
490 
492  {
493  UInt32 Ret = 0;
494  for( TokenIterator TokIt = this->Tokens.begin() ; TokIt != this->Tokens.end() ; ++TokIt )
495  {
496  Ret += (*TokIt)->ClearAllCharacters();
497  }
498  return Ret;
499  }
500  }//UI
501 }//Mezzanine
502 
503 #endif