• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

C:/CVUT/diplomka/Automata_editor/sources/stringProcessor.cpp

Go to the documentation of this file.
00001 #include "constants.h"
00002 
00003 #include "stringProcessor.h"
00004 #include "editor.h"
00005 #include "labelSyntaxChecker.h"
00006 
00007 #include <QMap>
00008 #include <QList>
00009 #include <QPair>
00010 #include <QString>
00011 #include <QFont>
00012 #include <QFontMetrics>
00013 #include <QRectF>
00014 #include <QPainter>
00015 #include <QRegExp>
00016 #include <QtDebug>
00017 
00018 #ifdef TESTING_STRING_PROCESSOR
00019 #   define DBGLOG_SP(x) DBGLOG_("STRINGPROCESSOR", x)
00020 #else
00021 #   define DBGLOG_SP(x)
00022 #endif
00023 
00024 #if 0
00025 #   define DBGLOG_SP_DRAW(x) DBGLOG_("SP_DRAW", x)
00026 #else
00027 #   define DBGLOG_SP_DRAW(x)
00028 #endif
00029 
00030 //<-- StringProcessor ---------------------------------------------------
00031 
00032 // static members
00033 StringProcessor::TString2CharMap    StringProcessor::string2CharMap;
00034 
00035 StringProcessor::TString2KwTypeMap  StringProcessor::string2KwTypeMap;
00036 
00037 const QRegExp StringProcessor::keywordRegex("((\\\\\\w+)\\s*)");
00038 const QRegExp StringProcessor::specCharacterRegex("(\\\\|\\{|\\})");
00039 const QRegExp StringProcessor::whitespaceRegex("\\s");
00040 const QRegExp StringProcessor::escapedCharacterRegex
00041 (
00042     "(\\\\\\$|\\\\\\%|\\\\\\#|\\\\\\&|\\\\\\~|\\\\\\_|\\\\\\^|\\\\\\{|\\\\\\}|\\\\\\\\)"
00043 );
00044 
00045 #ifdef USE_UNKNOWN_CONVENTION
00046         const QChar StringProcessor::unknownCharacter = UNKNOWN_CHARACTER;
00047         const QString StringProcessor::unknownString = UNKNOWN_STRING;
00048 #endif
00049 
00050 const QStringList StringProcessor::fontFamilyList = 
00051     QStringList() << "Arial" << "Symbol";
00052 
00053 void StringProcessor::initialize()
00054 {
00055     // initialize just once
00056     if (string2CharMap.contains("\\alpha")) 
00057         return;
00058 
00059     // Greek symbols
00060     addToMaps("\\alpha",         TCharPair('a',     eSymbolFont));
00061     addToMaps("\\beta",          TCharPair('b',     eSymbolFont));
00062     addToMaps("\\gamma",         TCharPair('g',     eSymbolFont));
00063     addToMaps("\\delta",         TCharPair('d',     eSymbolFont));
00064     addToMaps("\\varepsilon",    TCharPair('e',     eSymbolFont));
00065     addToMaps("\\epsilon",       TCharPair(0xCE,    eSymbolFont));
00066     addToMaps("\\zeta",          TCharPair('z',     eSymbolFont));
00067     addToMaps("\\eta",           TCharPair('h',     eSymbolFont));
00068     addToMaps("\\theta",         TCharPair('q',     eSymbolFont));
00069     addToMaps("\\vartheta",      TCharPair(0x4A,    eSymbolFont));
00070     addToMaps("\\iota",          TCharPair('i',     eSymbolFont));
00071     addToMaps("\\kappa",         TCharPair('k',     eSymbolFont));
00072     addToMaps("\\lambda",        TCharPair('l',     eSymbolFont));
00073     addToMaps("\\mu",            TCharPair('m',     eSymbolFont));
00074     addToMaps("\\nu",            TCharPair('n',     eSymbolFont));
00075     addToMaps("\\xi",            TCharPair('x',     eSymbolFont));
00076     addToMaps("\\omicron",       TCharPair('o',     eSymbolFont));
00077     addToMaps("\\pi",            TCharPair('p',     eSymbolFont));
00078     addToMaps("\\varpi",         TCharPair(0x76,    eSymbolFont));
00079     addToMaps("\\rho",           TCharPair('r',     eSymbolFont));
00080     addToMaps("\\varsigma",      TCharPair(0x56,    eSymbolFont));
00081     addToMaps("\\sigma",         TCharPair('s',     eSymbolFont));
00082     addToMaps("\\tau",           TCharPair('t',     eSymbolFont));
00083     addToMaps("\\upsilon",       TCharPair('u',     eSymbolFont));
00084     addToMaps("\\varphi",        TCharPair('j',     eSymbolFont));
00085     addToMaps("\\phi",           TCharPair(0x66,    eSymbolFont));
00086     addToMaps("\\chi",           TCharPair('c',     eSymbolFont));
00087     addToMaps("\\psi",           TCharPair('y',     eSymbolFont));
00088     addToMaps("\\omega",         TCharPair('w',     eSymbolFont));
00089 
00090     addToMaps("\\Alpha",         TCharPair('A',     eSymbolFont));
00091     addToMaps("\\Beta",          TCharPair('B',     eSymbolFont));
00092     addToMaps("\\Gamma",         TCharPair('G',     eSymbolFont));
00093     addToMaps("\\Delta",         TCharPair('D',     eSymbolFont));
00094     addToMaps("\\Epsilon",       TCharPair('E',     eSymbolFont));
00095     addToMaps("\\Zeta",          TCharPair('Z',     eSymbolFont));
00096     addToMaps("\\Eta",           TCharPair('H',     eSymbolFont));
00097     addToMaps("\\Theta",         TCharPair('Q',     eSymbolFont));    
00098     addToMaps("\\Iota",          TCharPair('I',     eSymbolFont));
00099     addToMaps("\\Kappa",         TCharPair('K',     eSymbolFont));
00100     addToMaps("\\Lambda",        TCharPair('L',     eSymbolFont));
00101     addToMaps("\\Mu",            TCharPair('M',     eSymbolFont));
00102     addToMaps("\\Nu",            TCharPair('N',     eSymbolFont));
00103     addToMaps("\\Xi",            TCharPair('X',     eSymbolFont));
00104     addToMaps("\\Omicron",       TCharPair('O',     eSymbolFont));    
00105     addToMaps("\\Pi",            TCharPair('P',     eSymbolFont));
00106     addToMaps("\\Rho",           TCharPair('R',     eSymbolFont));
00107     addToMaps("\\Sigma",         TCharPair('S',     eSymbolFont));
00108     addToMaps("\\Tau",           TCharPair('T',     eSymbolFont));
00109     addToMaps("\\Upsilon",       TCharPair(0xA1,    eSymbolFont));
00110     addToMaps("\\Phi",           TCharPair(0x46,    eSymbolFont));
00111     addToMaps("\\Chi",           TCharPair('C',     eSymbolFont));
00112     addToMaps("\\Psi",           TCharPair('Y',     eSymbolFont));
00113     addToMaps("\\Omega",         TCharPair('W',     eSymbolFont));
00114 
00115     // special symbols
00116     addToMaps("\\{",             TCharPair('{',     eNormalFont));
00117     addToMaps("\\}",             TCharPair('}',     eNormalFont));
00118     addToMaps("\\\\",            TCharPair('\\',    eNormalFont));
00119     //"(\\\\\\$|\\\\\\%|\\\\\\#|\\\\\\&|\\\\\\~|\\\\\\_|\\\\\\^|\\\\\\\\)"
00120     addToMaps("\\$",             TCharPair('$',     eNormalFont));
00121     addToMaps("\\%",             TCharPair('%',     eNormalFont));
00122     addToMaps("\\#",             TCharPair('#',     eNormalFont));
00123     addToMaps("\\&",             TCharPair('&',     eNormalFont));
00124     addToMaps("\\~",             TCharPair('~',     eNormalFont));
00125     addToMaps("\\_",             TCharPair('_',     eNormalFont));
00126     addToMaps("\\^",             TCharPair('^',     eNormalFont));
00127     addToMaps("\\\\",            TCharPair('\\',    eNormalFont));
00128     
00129     addToMaps("\\vdash",         TCharPair(0x0370,  eNormalFont)); // used code for Greek HETA, possible to use 0x2C75 for half H
00130 
00131     // font size changers
00132     string2KwTypeMap["\\scriptstyle"]           =   eFontSize;
00133     string2KwTypeMap["\\textstyle"]             =   eFontSize;
00134     string2KwTypeMap["\\scriptscriptstyle"]     =   eFontSize;
00135     
00136     //modifiers
00137     string2KwTypeMap["\\bar"]                   =   eModifier;
00138     string2KwTypeMap["\\underline"]             =   eModifier;
00139     string2KwTypeMap["\\overline"]              =   eModifier;    
00140 
00141 #if defined(TESTING_STRING_PROCESSOR) || defined(STRING_PROCESSOR_TEST)
00142     DBGLOG_SP(string2CharMap);
00143 #endif
00144 }
00145 
00146 void StringProcessor::addToMaps(const QString &str, const TCharPair &charPair)
00147 {
00148     string2CharMap[str] = charPair;    
00149     string2KwTypeMap[str] = eString2Char;
00150 }
00151 
00152 StringProcessor::CharacterInfo::CharacterInfo(EChangeType type, int idx, const QString &ch,
00153                                               EFontSize size, EModifier mod)
00154 : changeType(type), textIdx(idx), character(ch), fontSize(size), modifier(mod)
00155 {
00156     DBGLOG_SP("creating" << (CharacterInfo) (*this));
00157 }
00158 
00159 bool StringProcessor::isSpecialSymbol(const QString &symb)
00160 {
00161     if (keywordRegex.indexIn(symb) == 0)
00162     {
00163         DBGLOG_SP(DBGPAR(symb));
00164         return true;
00165     }
00166     return false;
00167 }
00168 
00169 QString StringProcessor::getSymbolPrintInfo(const QString &symb, QString &fontFamily)
00170 {
00171     initialize();
00172     
00173     if (string2CharMap.contains(symb))
00174     {
00175         const int fontIdx = string2CharMap[symb].second;
00176         Q_ASSERT(fontIdx < fontFamilyList.count());
00177         Q_UNUSED(fontIdx);
00178         fontFamily = fontFamilyList[fontIdx];
00179         return string2CharMap[symb].first;
00180     }
00181     
00182     fontFamily = fontFamilyList[eNormalFont];
00183     return symb;
00184 }
00185 
00186 bool StringProcessor::parseFontSize(const QString &symb, EFontSize &fontSize)
00187 {
00188     if (symb == "\\textstyle")
00189     {
00190         fontSize = eTextStyle;
00191         return true;
00192     }
00193     if (symb == "\\displaystyle")
00194     {
00195         fontSize = eDisplayStyle;
00196         return true;
00197     }
00198     if (symb == "\\scriptstyle")
00199     {
00200         fontSize = eScriptStyle;
00201         return true;
00202     }
00203     if (symb == "\\scriptscriptstyle")
00204     {
00205         fontSize = eScriptScriptStyle;
00206         return true;
00207     }
00208     return false;
00209 }
00210 
00211 bool StringProcessor::parseModifier(const QString &symb, EModifier &modifier)
00212 {   // hold consistent with string2KwTypeMap !!
00213     if (symb == "\\bar")
00214     {
00215         modifier = eBar;
00216         return true;
00217     }
00218     if (symb == "\\underline")
00219     {
00220         modifier = eUnderline;
00221         return true;
00222     }
00223     if (symb == "\\overline")
00224     {
00225         modifier = eOverline;
00226         return true;
00227     }
00228     return false;
00229 }
00230 
00231 StringProcessor::TCharacterList StringProcessor::computeCharacterListInBlock
00232     (const QString &input, int &startIdx, EFontSize fs, EModifier m)
00233 {
00234     TCharacterList result;
00235     
00236     QString::ConstIterator inputIt = input.begin();
00237     if (QString(*inputIt) == "{")
00238     {
00239         QString newInput;
00240         inputIt++;
00241         ++startIdx; // drop '{'
00242         int b_count = 1;
00243         while(b_count != 0)
00244         {
00245             if (inputIt == input.end())
00246             {
00247                 throw StringProcessorBraceMatchException(); // TODO: check if ok
00248                 break;
00249             }
00250             
00251             if      ((*inputIt) == '{') b_count++;
00252             else if ((*inputIt) == '}') b_count--;
00253             
00254             newInput += *inputIt;
00255             ++inputIt;
00256         }
00257         newInput.resize(newInput.length()-1); // drop '}'
00258         
00259         result = computeCharacterList(newInput, startIdx, fs, m);
00260         ++startIdx; // drop '}'
00261     }
00262     else
00263     {
00264         result << computeCharacterList(input, startIdx, fs, m, true);
00265     }
00266     
00267     return result;
00268 }
00269 
00270 StringProcessor::TCharacterList StringProcessor::computeCharacterList(const QString &input)
00271 {
00272     int idx = 0;
00273     DBGLOG_SP(DBGPAR(input));
00274     TCharacterList result = computeCharacterList(input, idx, eTextStyle, eNoModifier);
00275     return result;
00276 }
00277 
00278 StringProcessor::TCharacterList StringProcessor::computeCharacterList
00279     (const QString &input, int &startIdx, EFontSize fs, EModifier m, bool readOneCharacter)
00280 {
00281     EFontSize fontSize = fs;
00282     EModifier modifier = m;
00283     
00284     int absPos;
00285     TCharacterList result;
00286     
00287     int idx = -1, pos = 0;
00288     while((idx = specCharacterRegex.indexIn(input, pos)) != -1)
00289     {
00290         for(; pos<idx; ++pos)
00291         {
00292             QChar ch = input[pos];
00293             if (!whitespaceRegex.exactMatch(ch))
00294             {
00295                 result << CharacterInfo(eNoChange, startIdx+pos, QString(ch), fontSize, modifier);
00296                 if (readOneCharacter) { startIdx += ++pos; return result; }
00297             }
00298         }
00299         
00300         QString subInput = input.mid(pos);
00301         
00302         QString specCharacter = specCharacterRegex.cap(1);        
00303         if (specCharacter == "{")
00304         {
00305             Q_ASSERT(!readOneCharacter); // shouldn't occure!
00306             absPos = startIdx + pos;
00307             result << computeCharacterListInBlock(subInput, absPos, fontSize, modifier);
00308             pos = absPos - startIdx;
00309             continue;
00310         }
00311         else if (specCharacter == "}")
00312         {
00313             throw StringProcessorBraceMatchException();
00314             continue;
00315         }
00316         
00317         // keyword
00318         if (keywordRegex.indexIn(subInput) == 0)
00319         {
00320             QString matchedString = keywordRegex.cap(1);
00321             QString keyword = keywordRegex.cap(2);
00322             
00323             if (!string2KwTypeMap.contains(keyword))
00324             {
00325 #ifdef USE_UNKNOWN_CONVENTION
00326                 RELLOG(keyword << "is unknown keyword, used " << unknownString <<
00327                        " instead, please contact developer");
00328                 result << CharacterInfo(eNoChange, startIdx+pos, unknownString, fontSize, eNoModifier);
00329 #else
00330                 DBGLOG(DBGPAR(subInput.mid(keyword.length(),2)));
00331                 if (subInput.mid(keyword.length(),2) == "{}")
00332                         keyword += "{}";
00333                 RELLOG(keyword << "is unknown keyword, used unmodified, please contact developer");
00334                 result << CharacterInfo(eNoChange, startIdx+pos, keyword, fontSize, eNoModifier);
00335 #endif
00336                 pos += matchedString.length();
00337                 if (readOneCharacter){ startIdx += pos; return result; }
00338                 continue;
00339             }
00340                       
00341             EModifier newMod = modifier;
00342             switch(string2KwTypeMap[keyword])
00343             {
00344                 case eString2Char:
00345                     result << CharacterInfo(eStringToChar, startIdx+pos,
00346                                             keyword,
00347                                             fontSize, modifier);
00348                     pos += matchedString.length();
00349                     if (readOneCharacter){ startIdx += pos; return result; }
00350                     break;
00351                 case eFontSize:
00352                     if (!parseFontSize(keyword, fontSize))
00353                     {
00354                         Q_ASSERT(0); // shouldn't occure!
00355                     }
00356                     pos += matchedString.length();
00357                     if (readOneCharacter){ startIdx += pos; return result; }
00358                     break;
00359                 case eModifier:
00360                     if (!parseModifier(keyword, newMod))
00361                     {
00362                         Q_ASSERT(0); // shouldn't occure!
00363                     }
00364                     pos += matchedString.length();
00365                     
00366                     absPos = startIdx + pos;
00367                     subInput = input.mid(pos);
00368                     result << computeCharacterListInBlock(subInput, absPos, fontSize, newMod);
00369                     pos = absPos - startIdx;
00370                     if (readOneCharacter) { startIdx += pos; return result; }
00371                     break;
00372                 default: 
00373                     Q_ASSERT(0); break;
00374             }
00375             
00376             continue;            
00377         }
00378         
00379         // can be only character!
00380         if (escapedCharacterRegex.indexIn(subInput) == 0)
00381         {
00382             // print character! -> stored in string2CharMap
00383             QString character = escapedCharacterRegex.cap(1);
00384             
00385             if (string2KwTypeMap.contains(character))
00386             {
00387                 Q_ASSERT(string2KwTypeMap[character] == eString2Char);
00388                 result << CharacterInfo(eStringToChar, startIdx+pos,
00389                                         character,
00390                                         fontSize, modifier);
00391                 pos += character.length();
00392                 if (readOneCharacter) { startIdx += pos; return result; }
00393                 continue;
00394             }
00395         }
00396         
00397 #ifdef USE_UNKNOWN_CONVENTION
00398         RELLOG(subInput.mid(0,2) << "is unknown sequence, used " << unknownCharacter
00399                                  << " instead, please contact developer");
00400         result << CharacterInfo(eNoChange, startIdx+pos,
00401                                 unknownCharacter,
00402                                 eTextStyle, eNoModifier);
00403 #else
00404         RELLOG(subInput.mid(0,2) << "is unknown sequence, used unmodified, please contact developer");
00405         result << CharacterInfo(eNoChange, startIdx+pos, subInput.mid(0,2), eTextStyle, eNoModifier);
00406 #endif
00407 
00408         pos += 2; // '\' + next character
00409         continue;
00410     }
00411 
00412     for (; pos<input.length(); ++pos)
00413     {
00414         QChar ch = input[pos];        
00415         if (!whitespaceRegex.exactMatch(ch))
00416         {
00417             result << CharacterInfo(eNoChange, startIdx+pos, QString(ch), fontSize, modifier);
00418             if (readOneCharacter){ startIdx += ++pos; return result; }
00419         }
00420     }
00421 
00422     startIdx += pos;
00423     
00424     DBGLOG_SP(DBGPAR(result));
00425     return result;
00426 }
00427 
00428 QStringList StringProcessor::parseSymbols(const TCharacterList &characterList)
00429 {
00430     initialize();
00431     
00432     QStringList symbols;
00433     foreach(const CharacterInfo &c, characterList)
00434     {
00435         symbols << c.character;
00436     }
00437     
00438     return symbols;
00439 }
00440 
00441 QStringList StringProcessor::parseSymbols(const QString &input)
00442 {
00443     initialize();    
00444     
00445     TCharacterList characterList = computeCharacterList(input);
00446     return parseSymbols(characterList);
00447 }
00448 
00449 QStringList StringProcessor::getCharacters() const
00450 {
00451     return parseSymbols(m_characterList);
00452 }
00453 
00454 StringProcessor::TCharacterList StringProcessor::getCharacterList() const
00455 {
00456     return m_characterList;
00457 }
00458 
00459 StringProcessor::StringProcessor(const QString &text, int fontSize)
00460 : m_text(text), m_fontSize(fontSize)
00461 {    
00462     initialize();
00463 
00464     fillFontLists();
00465     bool ok = true;
00466     try
00467     {
00468         m_characterList = computeCharacterList(m_text);
00469     }
00470     catch(const StringProcessorException &e)
00471     {
00472         Q_ASSERT(0);
00473         RELLOG("StringProcessorException: " << e.what());
00474         m_text = "";
00475         ok = false;
00476     }
00477     
00478     if(!ok)
00479     {
00480         try
00481         {
00482             m_characterList = computeCharacterList(m_text); // should never throw exception for empty input!
00483         }
00484         catch(const StringProcessorException &e)
00485         {
00486             Q_ASSERT(0);
00487             RELLOG("StringProcessorException: " << e.what());
00488             qFatal("Unexpected exception!");
00489         }
00490     }
00491     
00492     computeMetrics();
00493 }
00494 
00495 void StringProcessor::fillFontLists()
00496 {
00497     m_fontList.clear();
00498     m_metricsList.clear();
00499     
00500     Q_ASSERT(fontFamilyList.size() >= 2);
00501     
00502     // fonts in latex are italic, but in editor it does not seem good
00503     m_fontList << QFont(fontFamilyList[0], m_fontSize, QFont::Normal, false)    // Arial
00504                << QFont(fontFamilyList[1], m_fontSize, QFont::Normal, false);   // Symbol
00505 
00506     // due to printing to EPS file by printer in PrinterResolution mode
00507     m_fontList[0].setPixelSize(QFontInfo(m_fontList[0]).pixelSize());
00508     m_fontList[1].setPixelSize(QFontInfo(m_fontList[1]).pixelSize());
00509 
00510     m_metricsList << QFontMetrics(m_fontList[0])
00511                   << QFontMetrics(m_fontList[1]);
00512 }
00513 
00514 void StringProcessor::computeMetrics()
00515 {                 
00516     int width = 0;
00517     int height = 0;
00518     int ascent = 0;
00519     int descent = 0;
00520     
00521     m_height = height;
00522     m_ascent = ascent;
00523     m_descent = descent;
00524     
00525     TCharPair tmpPair;
00526     QFont font;    
00527     QFontMetrics metrics(font);
00528 
00529     for(TCharacterList::ConstIterator charIt = m_characterList.begin();
00530         charIt != m_characterList.end();
00531         ++charIt)
00532     {
00533         switch((*charIt).changeType)
00534         {
00535             case eNoChange:
00536                 font = m_fontList[eNormalFont];
00537                 updateFont(font, *charIt);
00538                 metrics = QFontMetrics(font);
00539                 width += metrics.width((*charIt).character);                
00540                 break;
00541             case eStringToChar:
00542                 tmpPair = string2CharMap[(*charIt).character];
00543                 font = m_fontList[tmpPair.second];
00544                 updateFont(font, *charIt);
00545                 metrics = QFontMetrics(font);
00546                 width += metrics.width(tmpPair.first);
00547                 break;            
00548             default:
00549                 Q_ASSERT(0 && "unexpected value");
00550                 break;
00551         }
00552         // find max values
00553         if ((height = metrics.height()) > m_height) m_height = height;
00554         if ((ascent = metrics.ascent()) > m_ascent) m_ascent = ascent;
00555         if ((descent = metrics.descent()) > m_descent) m_descent = descent;
00556     }   
00557 
00558     m_width = width;
00559 }
00560 
00561 int StringProcessor::getHeight() const
00562 {
00563     return m_height;   
00564 }
00565 
00566 int StringProcessor::getDescent() const
00567 {
00568     return m_descent;
00569 }
00570 
00571 int StringProcessor::getAscent() const
00572 {
00573     return m_ascent;
00574 }
00575 
00576 bool StringProcessor::setText(const QString &text)
00577 {    
00578     try
00579     {
00580         m_characterList = computeCharacterList(text);   
00581     }
00582     catch(const StringProcessorException &e)
00583     {
00584         RELLOG("StringProcessorException: " << e.what());
00585         RELLOG("Change wasn't applied!");
00586         return false;
00587     }
00588         
00589     m_text = text;
00590     computeMetrics();
00591     return true;
00592 }
00593 
00594 void StringProcessor::setFontSize(int fontSize)
00595 {    
00596     m_fontSize = fontSize;
00597     fillFontLists();
00598     computeMetrics();
00599 }
00600 
00601 bool StringProcessor::updateFont(QFont &font, const CharacterInfo &c) const
00602 {
00603     bool chFS = true;
00604     switch(c.fontSize)
00605     {
00606         case eScriptStyle:
00607             font.setPixelSize(font.pixelSize()*SCRIPT_STYLE_MULT);          break;
00608         case eScriptScriptStyle:
00609             font.setPixelSize(font.pixelSize()*SCRIPT_SCRIPT_STYLE_MULT);   break;
00610         default:
00611             chFS = false;
00612             break;
00613     }
00614 
00615     bool chM = true;
00616     switch(c.modifier)
00617     {
00618         case eBar:         
00619             font.setOverline(true);                                         break;
00620         case eUnderline:
00621             font.setUnderline(true);                                        break;
00622         case eOverline:
00623             font.setOverline(true);                                         break;
00624         default:
00625             chM = false;
00626             break;
00627     }
00628     
00629     if (chM || chFS)
00630         return true;
00631         
00632     return false;
00633 }
00634 
00635 void StringProcessor::drawText(QPainter *painter, QPointF& point) const
00636 {        
00637     TCharPair   tmpPair;
00638     QFont font;    
00639     QFontMetrics metrics(font);
00640     
00641     for(TCharacterList::ConstIterator charIt = m_characterList.begin();
00642         charIt != m_characterList.end();
00643         ++charIt)
00644     {
00645         switch((*charIt).changeType)
00646         {
00647             case eNoChange:                    
00648                 DBGLOG_SP_DRAW((*charIt).character);
00649                 
00650                 font = m_fontList[eNormalFont];
00651                 updateFont(font, (*charIt));
00652                 metrics = QFontMetrics(font);
00653                 painter->setFont(font);
00654                 
00655                 painter->drawText(point, (*charIt).character);
00656                 point.setX(point.x() + metrics.width((*charIt).character));
00657                 break;
00658             case eStringToChar:
00659                 Q_ASSERT(string2CharMap.contains((*charIt).character));
00660                 DBGLOG_SP_DRAW("character:" << (*charIt).character);
00661                 tmpPair = string2CharMap[(*charIt).character];                
00662                 DBGLOG_SP_DRAW(tmpPair.first);
00663 
00664                 font = m_fontList[tmpPair.second];
00665                 updateFont(font, (*charIt));
00666                 metrics = QFontMetrics(font);
00667                 painter->setFont(font);
00668                 
00669                 painter->drawText(point, tmpPair.first);
00670                 point.setX(point.x() + metrics.width(tmpPair.first));
00671                 break;
00672             default:
00673                 Q_ASSERT(0 && "unexpected value");
00674                 break;
00675         }
00676     }
00677 }
00678 
00679 #ifdef TESTING_STRING_PROCESSOR
00680 QDebug operator<<(QDebug dbg, const StringProcessor::CharacterInfo &c)
00681 {
00682     QString tmp;
00683     switch(c.changeType)
00684     {
00685         case StringProcessor::eStringToChar:        tmp = QString("eStringToChar(%1)").arg(c.changeType);   break;        
00686         default:                                    tmp = QString("eNoChange(%1)").arg(c.changeType);       break;
00687     }
00688     dbg.nospace() << endl << tmp << "," << c.textIdx << "," << c.character << ",";
00689     switch(c.fontSize)
00690     {
00691         case StringProcessor::eScriptStyle:         tmp = QString("eScriptStyle(%1)").arg(c.fontSize);      break;
00692         case StringProcessor::eScriptScriptStyle:   tmp = QString("eScriptScriptStyle(%1)").arg(c.fontSize);break;
00693         default:                                    tmp = QString("eTextStyle(%1)").arg(c.fontSize);        break;
00694     }
00695     dbg.nospace() << tmp;
00696     switch(c.modifier)
00697     {
00698         case StringProcessor::eBar:                 tmp = QString("eBar(%1)").arg(c.modifier);              break;
00699         default:                                    tmp = QString("eNoModifier(%1)").arg(c.modifier);       break;
00700     }
00701     dbg.nospace() << tmp;
00702 
00703     return dbg.nospace();
00704 }
00705 #endif
00706 
00707 //--------------------------------------------------- StringProcessor -->
00708 
00709 
00710 
00711 #ifdef STRING_PROCESSOR_TEST
00712 
00713 #include "label.h"
00714 #include "labelSyntaxChecker.h"
00715 #include "dialogs.h"
00716 
00717 #include <QLineEdit>
00718 #include <QPushButton>
00719 #include <QBoxLayout>
00720 #include <QGraphicsView>
00721 #include <QTimer>
00722 #include <QCheckBox>
00723 
00724 ITransition::TCharSet g_alphabet = 
00725     QSet<QString>::fromList((QStringList() 
00726     << "a" << "b" << "c" << "d" << "e"
00727     << "\\alpha" << "\\beta" << "\\gamma" << "\\delta"));
00728 
00729 StringProcessorTestDialog::StringProcessorTestDialog(QWidget *parent)
00730 : QDialog(parent), m_idx(0), m_syntaxChecker(new LabelSyntaxChecker(g_alphabet, "A", "\\varepsilon"))
00731 {
00732     m_timer = new QTimer(this);
00733     m_timer->setInterval(1000);
00734     connect(m_timer, SIGNAL(timeout()), this, SLOT(timerEvent()));
00735 
00736     m_edtText = new QLineEdit(tr("\\alpha"), this);
00737     QPushButton *btnApply = new QPushButton(tr("&Apply"), this);
00738     connect(btnApply, SIGNAL(clicked()), this, SLOT(changeText()));
00739     m_checkTimer = new QCheckBox("alpha", this);
00740     connect(m_checkTimer, SIGNAL(stateChanged(int)), this, SLOT(timerChange(int)));
00741 
00742     m_checkSyntax = new QCheckBox("checkSyntax", this);
00743 
00744     QWidget *editHBox = new QWidget(this);
00745     QHBoxLayout *editHBoxLayout = new QHBoxLayout;
00746     editHBoxLayout->addWidget(m_edtText);
00747     editHBoxLayout->addWidget(btnApply);
00748     editHBoxLayout->addWidget(m_checkSyntax);
00749     editHBoxLayout->addWidget(m_checkTimer);
00750     editHBox->setLayout(editHBoxLayout);
00751 
00752     m_view = new QGraphicsView(this);
00753     m_view->setScene(new QGraphicsScene(m_view));    
00754     m_label = new LabelX(0, "\\alpha", true, 20);
00755     m_label->setPos(QPointF(10, 10));    
00756     m_view->scene()->addItem(m_label);
00757 
00758     QPushButton *btnClose = new QPushButton(tr("&Close"), this);
00759     connect(btnClose, SIGNAL(clicked()), this, SLOT(close()));
00760     
00761     QVBoxLayout *vBoxLayout = new QVBoxLayout;
00762     vBoxLayout->addWidget(editHBox);
00763     vBoxLayout->addWidget(m_view);
00764     vBoxLayout->addWidget(btnClose, Qt::AlignHCenter);
00765     vBoxLayout->setSpacing(10);
00766     
00767     this->setLayout(vBoxLayout);
00768 
00769     m_greekList << "alpha" << "beta" << "gamma" << "delta" << "varepsilon" << "epsilon" << "zeta" << "eta"
00770                 << "vartheta" << "theta" << "iota" << "kappa" << "lambda" << "mu" << "nu" << "xi" << "omicron"
00771                 << "varpi" << "pi" << "rho" << "varsigma" << "sigma" << "tau" << "upsilon"
00772                 << "varphi" << "phi" << "chi" << "psi" << "omega";
00773 
00774     m_greekList << "Alpha" << "Beta" << "Gamma" << "Delta" << "Epsilon" << "Zeta" << "Eta"
00775                 << "Theta" << "Iota" << "Kappa" << "Lambda" << "Mu" << "Nu" << "Xi" << "Omicron"
00776                 << "Pi" << "Rho" << "Sigma" << "Tau" << "Upsilon" << "Phi" << "Chi" << "Psi" << "Omega";
00777 }
00778 
00779 StringProcessorTestDialog::~StringProcessorTestDialog()
00780 {
00781         delete m_syntaxChecker;
00782 }
00783 
00784 void StringProcessorTestDialog::changeText()
00785 {
00786     bool change = true;
00787     if (m_checkSyntax->isChecked())
00788     {        
00789         try
00790         {
00791             StringProcessor::TCharacterList charList = StringProcessor::computeCharacterList(m_edtText->text());
00792             change &= m_syntaxChecker->checkSyntax(charList);
00793         }
00794         catch(const StringProcessorException &e)
00795         {
00796             DBGLOG("StringProcessorException: " << e.what());
00797             return;
00798         }
00799         
00800         DBGLOG_SP(DBGPAR(m_syntaxChecker->getCharacters()));
00801         DBGLOG_SP(DBGPAR(m_syntaxChecker->getPattern()));
00802         
00803         if (!change)
00804         {
00805             ReportDialog rd(m_syntaxChecker->getReport(), this);
00806             rd.exec();
00807             return;
00808         }
00809     }    
00810     
00811     m_label->setText(m_edtText->text());
00812     m_view->scene()->update();   
00813 }
00814 
00815 void StringProcessorTestDialog::timerChange(int state)
00816 {
00817     if (state == Qt::Checked)
00818         m_timer->start();
00819     else
00820         m_timer->stop();
00821 }
00822 
00823 void StringProcessorTestDialog::timerEvent()
00824 {    
00825     if (m_idx == m_greekList.size()) m_idx = 0;    
00826     m_label->setText("\\" + m_greekList[m_idx]);
00827     m_view->scene()->update();
00828     m_checkTimer->setText(m_greekList[m_idx]);
00829     ++m_idx;
00830 }
00831 
00832 void StringProcessor::runTest()
00833 {
00834     StringProcessorTestDialog sptd;
00835     sptd.exec();
00836 }
00837 
00838 #endif

Generated on Tue Jan 4 2011 03:03:24 for Autoamata editor by  doxygen 1.7.0