File indexing completed on 2024-04-14 03:39:17
0001 0002 /************************************************************************************* 0003 * Copyright (C) 2007 by Aleix Pol <aleixpol@kde.org> * 0004 * * 0005 * This program is free software; you can redistribute it and/or * 0006 * modify it under the terms of the GNU General Public License * 0007 * as published by the Free Software Foundation; either version 2 * 0008 * of the License, or (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the Free Software * 0017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 0018 *************************************************************************************/ 0019 0020 #include "algebrahighlighter.h" 0021 #include <QGuiApplication> 0022 #include <QStack> 0023 #include <QPalette> 0024 0025 #include <analitza/expression.h> 0026 #include <analitza/analyzer.h> 0027 #include <analitza/variables.h> 0028 #include <analitza/explexer.h> 0029 #include <analitza/expressionparser.h> 0030 0031 AlgebraHighlighter::AlgebraHighlighter(QTextDocument *doc, const Analitza::Analyzer *na) 0032 : QSyntaxHighlighter(doc), m_correct(true), m_mode(Autodetect), m_pos(0), m_editingParameter(-1), m_editingBounds(-1), a(na) 0033 { 0034 bold.setFontWeight(QFont::Bold); 0035 } 0036 0037 QString removeTags(const QString& in) 0038 { 0039 bool tag=false; 0040 QString out; 0041 for(int i=0; i<in.length(); i++){ 0042 if(!tag && in[i]=='<') 0043 tag=true; 0044 else if(tag && in[i]=='>') 0045 tag=false; 0046 else if(!tag) { 0047 if(in.mid(i,4)==QLatin1String(">")){ 0048 out += '>'; 0049 i+=3; 0050 } else 0051 out += in[i]; 0052 } 0053 } 0054 return out; 0055 } 0056 0057 struct FuncItem 0058 { 0059 FuncItem() : parameter(-1), pos(-1), bounding(false) {} 0060 FuncItem(const QString& name, int p) : id(name), parameter(p), pos(-1), bounding(false) {} 0061 QString id; 0062 int parameter; 0063 int pos; 0064 bool bounding; 0065 }; 0066 0067 void AlgebraHighlighter::highlightBlock(const QString &text) 0068 { 0069 m_correct=true; 0070 if(int(m_pos)>=text.length()) 0071 m_pos=text.length(); 0072 0073 QPalette pal=qApp->palette(); 0074 QColor number(pal.color(QPalette::Active, QPalette::Link)); 0075 QColor variable(pal.color(QPalette::Active, QPalette::LinkVisited)); 0076 QColor comment(pal.color(QPalette::Active, QPalette::Window)); 0077 QColor id(150,0,50); 0078 QColor string(0xbb,0,0); 0079 QColor uncorrect(Qt::red); 0080 m_editingParameter=0; 0081 m_editingName.clear(); 0082 0083 if(Analitza::Expression::isMathML(text)) { 0084 QString lasttag; 0085 int inside=0; 0086 for(int i=0; i<text.length(); i++) { 0087 if(text[i]=='<') { //We enter in a tag 0088 lasttag.clear(); 0089 int j=i+1, k=0; 0090 for(k=i+1; k<text.length() && text[k]!='>'; ++k){ 0091 lasttag.append(text[k]); 0092 if(text[k]!=' ' && j==k-1) 0093 j=k; 0094 } 0095 j++; 0096 0097 setFormat(i, 1, bold); 0098 setFormat(j, 1, bold); 0099 if(lasttag.startsWith(QChar('/'))){ 0100 setFormat(i+1, j-i-1, QColor(100,0,0)); 0101 setFormat(i+1, 1, bold); 0102 inside--; 0103 } else if(lasttag.endsWith(QChar('/'))) { 0104 setFormat(i+1, j-i-1, id); 0105 setFormat(j+1, 2, bold); 0106 } else if(j!=k) { 0107 setFormat(i+1, j-i-1, QColor(150,0,0)); 0108 setFormat(j+1, k-j-1, QColor(150,100,0)); 0109 inside++; 0110 } else { 0111 setFormat(i+1, j-i-1, QColor(150,0,0)); 0112 inside++; 0113 } 0114 i=k; 0115 } 0116 else if(lasttag==QLatin1String("cn")) 0117 setFormat(i, 1, number); 0118 else if(lasttag==QLatin1String("ci")) 0119 setFormat(i, 1, variable); 0120 } 0121 0122 m_correct=(inside==0); 0123 } else { 0124 ExpLexer lex(text); 0125 QStack<ExpLexer::TOKEN> paren; 0126 QStack<FuncItem> parameter; 0127 0128 while(lex.lex()!=ExpressionTable::EOF_SYMBOL && lex.error().isEmpty()) { 0129 QColor f; 0130 bool isBold=false; 0131 switch(lex.current.type){ 0132 case ExpressionTable::tVal: 0133 if(lex.current.val.mid(1,2)==QLatin1String("cn")) //if it is a number 0134 f=number; 0135 else { //if it is a variable 0136 if(a && a->variables()->contains(removeTags(lex.current.val))) 0137 f=number; 0138 else 0139 f=variable; 0140 } 0141 break; 0142 case ExpressionTable::tId: 0143 f=id; 0144 m_aName=lex.current.val; 0145 break; 0146 case ExpressionTable::tString: 0147 f=string; 0148 break; 0149 case ExpressionTable::tComment: 0150 f=comment; 0151 break; 0152 case -1: 0153 m_correct = false; 0154 f=uncorrect; 0155 break; 0156 case ExpressionTable::tLpr: 0157 case ExpressionTable::tLcb: 0158 paren.push(lex.current); 0159 if(m_pos>lex.current.pos) 0160 parameter.push(FuncItem(m_aName, 0)); 0161 isBold=true; 0162 setFormat(lex.current.pos, lex.current.len, bold); 0163 break; 0164 case ExpressionTable::tRpr: 0165 case ExpressionTable::tRcb: { 0166 isBold=true; 0167 setFormat(lex.current.pos, lex.current.len, bold); 0168 0169 bool corr=!paren.isEmpty(); 0170 if(corr) { 0171 if(lex.current.type==ExpressionTable::tRpr && paren.top().type!=ExpressionTable::tLpr) 0172 corr=false; 0173 0174 if(m_pos==lex.current.pos || m_pos==paren.top().pos) { 0175 QTextCharFormat bg=bold; 0176 bg.setBackground(Qt::yellow); 0177 0178 setFormat(lex.current.pos, lex.current.len, bg); 0179 setFormat(paren.top().pos, paren.top().len, bg); 0180 } 0181 0182 paren.pop(); 0183 if(m_pos>lex.current.pos) 0184 parameter.pop(); 0185 } 0186 0187 if(!corr) 0188 setFormat(lex.current.pos, lex.current.len, uncorrect); // error 0189 } break; 0190 default: 0191 if(m_pos>lex.current.pos && !parameter.isEmpty() 0192 && lex.current.type==ExpressionTable::tComa) { 0193 parameter.top().parameter++; 0194 parameter.top().pos=lex.current.pos; 0195 } 0196 0197 0198 0199 if(m_pos>lex.current.pos && !parameter.isEmpty() 0200 && lex.current.type==ExpressionTable::tColon) { 0201 parameter.top().bounding=true; 0202 parameter.top().pos=lex.current.pos; 0203 } 0204 0205 isBold=true; 0206 setFormat(lex.current.pos, lex.current.len, bold); 0207 break; 0208 } 0209 if(!isBold) 0210 setFormat(lex.current.pos, lex.current.len, f); 0211 } 0212 0213 if(!lex.error().isEmpty()) 0214 { 0215 setFormat(lex.current.pos, text.size()-lex.current.pos, uncorrect); 0216 } 0217 0218 if(!parameter.isEmpty()) { 0219 m_editingName=parameter.top().id; 0220 m_editingParameter=parameter.top().parameter; 0221 m_editingBounds=parameter.top().bounding; 0222 0223 if(m_editingParameter!=0 || m_editingBounds) { 0224 QTextCharFormat currentComa=bold; 0225 currentComa.setBackground(Qt::yellow); 0226 setFormat(parameter.top().pos, 1, currentComa); 0227 } 0228 } 0229 } 0230 } 0231 0232 QString AlgebraHighlighter::editingName() const 0233 { 0234 return m_editingName; 0235 } 0236 0237 int AlgebraHighlighter::editingParameter() const 0238 { 0239 return m_editingParameter; 0240 } 0241 0242 bool AlgebraHighlighter::editingBounds() const 0243 { 0244 return m_editingBounds; 0245 }