File indexing completed on 2024-04-28 15:14:03
0001 /*************************************************************************** 0002 File : EquationHighlighter.h 0003 Project : LabPlot 0004 -------------------------------------------------------------------- 0005 Copyright : (C) 2014 Alexander Semke (alexander.semke@web.de) 0006 Copyright : (C) 2006 David Saxton <david@bluehaze.org> 0007 Description : syntax highligher for mathematical equations 0008 0009 ***************************************************************************/ 0010 0011 /*************************************************************************** 0012 * * 0013 * This program is free software; you can redistribute it and/or modify * 0014 * it under the terms of the GNU General Public License as published by * 0015 * the Free Software Foundation; either version 2 of the License, or * 0016 * (at your option) any later version. * 0017 * * 0018 * This program is distributed in the hope that it will be useful, * 0019 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0021 * GNU General Public License for more details. * 0022 * * 0023 * You should have received a copy of the GNU General Public License * 0024 * along with this program; if not, write to the Free Software * 0025 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0026 * Boston, MA 02110-1301 USA * 0027 * * 0028 ***************************************************************************/ 0029 0030 #include "EquationHighlighter.h" 0031 #include "backend/gsl/ExpressionParser.h" 0032 0033 #include <QPalette> 0034 #include <KTextEdit> 0035 0036 EquationHighlighter::EquationHighlighter(KTextEdit* parent) 0037 : QSyntaxHighlighter(parent), 0038 m_parent(parent) 0039 // m_errorPosition = -1 0040 {} 0041 0042 void EquationHighlighter::setVariables(const QStringList& variables) { 0043 m_variables = variables; 0044 rehighlight(); 0045 } 0046 0047 void EquationHighlighter::highlightBlock(const QString& text) { 0048 //TODO: m_parent->checkTextValidity(); 0049 0050 if (text.isEmpty()) 0051 return; 0052 0053 QTextCharFormat number; 0054 QTextCharFormat function; 0055 QTextCharFormat variable; 0056 QTextCharFormat constant; 0057 QTextCharFormat matchedParenthesis; 0058 0059 QPalette palette; 0060 if (qGray(palette.color(QPalette::Base).rgb()) > 160) { 0061 number.setForeground(QColor(0, 0, 127)); 0062 function.setForeground(QColor(85, 0, 0)); 0063 function.setFontWeight(QFont::Bold); 0064 variable.setForeground(QColor(0, 85, 0)); 0065 constant.setForeground(QColor(85, 0, 0)); 0066 matchedParenthesis.setBackground(QColor(255, 255, 183)); 0067 } else { 0068 number.setForeground(QColor(160, 160, 255)); 0069 function.setForeground(QColor(255, 160, 160)); 0070 function.setFontWeight(QFont::Bold); 0071 variable.setForeground(QColor(160, 255, 160)); 0072 constant.setForeground(QColor(255, 160, 160)); 0073 matchedParenthesis.setBackground(QColor(85, 85, 0)); 0074 } 0075 0076 QTextCharFormat other; 0077 0078 static const QStringList& functions = ExpressionParser::getInstance()->functions(); 0079 static const QStringList& constants = ExpressionParser::getInstance()->constants(); 0080 0081 for (int i = 0; i < text.length(); ++i) { 0082 QString remaining = text.right(text.length() - i); 0083 bool found = false; 0084 0085 //variables 0086 for (const QString& var: m_variables) { 0087 if (remaining.startsWith(var)) { 0088 QString nextChar = remaining.mid(var.length(), 1); 0089 if (nextChar == " " || nextChar == ")" || nextChar == "+" || nextChar == "-" 0090 || nextChar == "*" || nextChar == "/" || nextChar == "^") { 0091 setFormat(i, var.length(), variable); 0092 i += var.length() - 1; 0093 found = true; 0094 break; 0095 } 0096 } 0097 } 0098 if (found) 0099 continue; 0100 0101 //functions 0102 for (const QString& f: functions) { 0103 if (remaining.startsWith(f)) { 0104 setFormat(i, f.length(), function); 0105 i += f.length() - 1; 0106 found = true; 0107 break; 0108 } 0109 } 0110 if (found) 0111 continue; 0112 0113 //constants 0114 for (const QString& f: constants) { 0115 if (remaining.startsWith(f)) { 0116 setFormat(i, f.length(), function); 0117 i += f.length() - 1; 0118 found = true; 0119 break; 0120 } 0121 } 0122 if (found) 0123 continue; 0124 0125 //TODO 0126 /* 0127 ushort u = text[i].unicode(); 0128 bool isFraction = (u >= 0xbc && u <= 0xbe) || (u >= 0x2153 && u <= 0x215e); 0129 bool isPower = (u >= 0xb2 && u <= 0xb3) || (u == 0x2070) || (u >= 0x2074 && u <= 0x2079); 0130 bool isDigit = text[i].isDigit(); 0131 SET_NUMBER_LOCALE 0132 bool isDecimalPoint = text[i] == numberLocale.decimalPoint(); 0133 0134 if (isFraction || isPower || isDigit || isDecimalPoint) 0135 setFormat(i, 1, number); 0136 else 0137 setFormat(i, 1, other); 0138 */ 0139 } 0140 0141 //highlight matched brackets 0142 int cursorPos = m_parent->textCursor().position(); 0143 if (cursorPos < 0) 0144 cursorPos = 0; 0145 0146 // Adjust cursorpos to allow for a bracket before the cursor position 0147 if (cursorPos >= text.size()) 0148 cursorPos = text.size() - 1; 0149 else if (cursorPos > 0 && (text[cursorPos-1] == '(' || text[cursorPos-1] == ')')) 0150 cursorPos--; 0151 0152 bool haveOpen = text[cursorPos] == '('; 0153 bool haveClose = text[cursorPos] == ')'; 0154 0155 if ((haveOpen || haveClose) && m_parent->hasFocus()) { 0156 // Search for the other bracket 0157 0158 int inc = haveOpen ? 1 : -1; // which direction to search in 0159 0160 int level = 0; 0161 for (int i = cursorPos; i >= 0 && i < text.size(); i += inc) { 0162 if (text[i] == ')') 0163 level--; 0164 else if (text[i] == '(') 0165 level++; 0166 0167 if (level == 0) { 0168 // Matched! 0169 setFormat(cursorPos, 1, matchedParenthesis); 0170 setFormat(i, 1, matchedParenthesis); 0171 break; 0172 } 0173 } 0174 } 0175 0176 //TODO: highlight the position of the error 0177 // if (m_errorPosition != -1) { 0178 // QTextCharFormat error; 0179 // error.setForeground(Qt::red); 0180 // 0181 // setFormat(m_errorPosition, 1, error); 0182 // } 0183 } 0184 0185 void EquationHighlighter::rehighlight() { 0186 setDocument(nullptr); 0187 setDocument(m_parent->document()); 0188 } 0189 0190 /** 0191 * This is used to indicate the position where the error occurred. 0192 * If \p position is negative, then no error will be shown. 0193 */ 0194 // void EquationHighlighter::setErrorPosition(int position) { 0195 // m_errorPosition = position; 0196 // }