1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3 #include "RegexExplorer.h"
4
RegexExplorer(QWidget * p)5 RegexExplorer::RegexExplorer(QWidget* p)
6 : QDialog(p)
7 , m_matched(false)
8 {
9 this->setupUi(this);
10
11 for (int i = 1; i < cmsys::RegularExpressionMatch::NSUBEXP; ++i) {
12 matchNumber->addItem(QString("Match %1").arg(QString::number(i)),
13 QVariant(i));
14 }
15 matchNumber->setCurrentIndex(0);
16 }
17
setStatusColor(QWidget * widget,bool successful)18 void RegexExplorer::setStatusColor(QWidget* widget, bool successful)
19 {
20 QColor color = successful ? QColor(0, 127, 0) : Qt::red;
21
22 QPalette palette = widget->palette();
23 palette.setColor(QPalette::WindowText, color);
24 widget->setPalette(palette);
25 }
26
on_regularExpression_textChanged(const QString & text)27 void RegexExplorer::on_regularExpression_textChanged(const QString& text)
28 {
29 #ifdef QT_NO_STL
30 m_regex = text.toAscii().constData();
31 #else
32 m_regex = text.toStdString();
33 #endif
34
35 bool validExpression =
36 stripEscapes(m_regex) && m_regexParser.compile(m_regex);
37 if (!validExpression) {
38 m_regexParser.set_invalid();
39 }
40
41 setStatusColor(labelRegexValid, validExpression);
42
43 on_inputText_textChanged();
44 }
45
on_inputText_textChanged()46 void RegexExplorer::on_inputText_textChanged()
47 {
48 if (m_regexParser.is_valid()) {
49 QString plainText = inputText->toPlainText();
50 #ifdef QT_NO_STL
51 m_text = plainText.toAscii().constData();
52 #else
53 m_text = plainText.toStdString();
54 #endif
55 m_matched = m_regexParser.find(m_text);
56 } else {
57 m_matched = false;
58 }
59
60 setStatusColor(labelRegexMatch, m_matched);
61
62 if (!m_matched) {
63 clearMatch();
64 return;
65 }
66
67 std::string matchingText;
68
69 if (matchAll->isChecked()) {
70 const char* p = m_text.c_str();
71 while (m_regexParser.find(p)) {
72 std::string::size_type l = m_regexParser.start();
73 std::string::size_type r = m_regexParser.end();
74 if (r - l == 0) {
75 // matched empty string
76 clearMatch();
77 return;
78 }
79 if (!matchingText.empty()) {
80 matchingText += ";";
81 }
82 matchingText += std::string(p + l, r - l);
83 p += r;
84 }
85 } else {
86 matchingText = m_regexParser.match(0);
87 }
88
89 #ifdef QT_NO_STL
90 QString matchText = matchingText.c_str();
91 #else
92 QString matchText = QString::fromStdString(matchingText);
93 #endif
94 match0->setPlainText(matchText);
95
96 on_matchNumber_currentIndexChanged(matchNumber->currentIndex());
97 }
98
on_matchNumber_currentIndexChanged(int index)99 void RegexExplorer::on_matchNumber_currentIndexChanged(int index)
100 {
101 if (!m_matched) {
102 return;
103 }
104
105 QVariant itemData = matchNumber->itemData(index);
106 int idx = itemData.toInt();
107
108 if (idx < 1 || idx >= cmsys::RegularExpressionMatch::NSUBEXP) {
109 return;
110 }
111
112 #ifdef QT_NO_STL
113 QString match = m_regexParser.match(idx).c_str();
114 #else
115 QString match = QString::fromStdString(m_regexParser.match(idx));
116 #endif
117 matchN->setPlainText(match);
118 }
119
on_matchAll_toggled(bool checked)120 void RegexExplorer::on_matchAll_toggled(bool checked)
121 {
122 Q_UNUSED(checked);
123
124 on_inputText_textChanged();
125 }
126
clearMatch()127 void RegexExplorer::clearMatch()
128 {
129 m_matched = false;
130 match0->clear();
131 matchN->clear();
132 }
133
stripEscapes(std::string & source)134 bool RegexExplorer::stripEscapes(std::string& source)
135 {
136 const char* in = source.c_str();
137
138 std::string result;
139 result.reserve(source.size());
140
141 for (char inc = *in; inc != '\0'; inc = *++in) {
142 if (inc == '\\') {
143 char nextc = in[1];
144 if (nextc == 't') {
145 result.append(1, '\t');
146 in++;
147 } else if (nextc == 'n') {
148 result.append(1, '\n');
149 in++;
150 } else if (isalnum(nextc) || nextc == '\0') {
151 return false;
152 } else {
153 result.append(1, nextc);
154 in++;
155 }
156 } else {
157 result.append(1, inc);
158 }
159 }
160
161 source = result;
162 return true;
163 }
164