OSDN Git Service

It's 2011 now.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / regexp / regexpwindow.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "regexpwindow.h"
35 #include "settings.h"
36
37 #include <QtGui/QCheckBox>
38 #include <QtGui/QComboBox>
39 #include <QtGui/QLabel>
40 #include <QtGui/QLayout>
41 #include <QtGui/QLineEdit>
42 #include <QtGui/QContextMenuEvent>
43 #include <QtGui/QMenu>
44 #include <QtGui/QInputDialog>
45
46 using namespace RegExp::Internal;
47
48 RegExpWindow::RegExpWindow(QWidget *parent) :
49    QWidget(parent),
50    patternLabel(new QLabel(tr("&Pattern:"))),
51    escapedPatternLabel(new QLabel(tr("&Escaped pattern:"))),
52    syntaxLabel(new QLabel(tr("&Pattern syntax:"))),
53    textLabel(new QLabel(tr("&Text:"))),
54    patternComboBox (new QComboBox),
55    escapedPatternLineEdit(new QLineEdit),
56    textComboBox(new QComboBox),
57    caseSensitiveCheckBox(new QCheckBox(tr("Case &sensitive"))),
58    minimalCheckBox(new QCheckBox(tr("&Minimal"))),
59    syntaxComboBox(new QComboBox),
60    indexLabel(new QLabel(tr("Index of match:"))),
61    matchedLengthLabel(new QLabel(tr("Matched length:"))),
62    indexEdit(new QLineEdit),
63    matchedLengthEdit(new QLineEdit)
64 {
65     QVBoxLayout *vboxLayout = new QVBoxLayout(this);
66     QGridLayout *mainLayout = new QGridLayout;
67
68     patternComboBox->setEditable(true);
69     patternComboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
70
71     patternLabel->setBuddy(patternComboBox);
72
73     mainLayout->addWidget(patternLabel, 0, 0);
74     mainLayout->addWidget(patternComboBox, 0, 1);
75
76     escapedPatternLineEdit->setReadOnly(true);
77     QPalette palette = escapedPatternLineEdit->palette();
78     palette.setBrush(QPalette::Base, palette.brush(QPalette::Disabled, QPalette::Base));
79     escapedPatternLineEdit->setPalette(palette);
80
81     escapedPatternLabel->setBuddy(escapedPatternLineEdit);
82
83     mainLayout->addWidget(escapedPatternLabel, 1, 0);
84     mainLayout->addWidget(escapedPatternLineEdit, 1, 1);
85
86     syntaxComboBox->addItem(tr("Regular Expression v1"), QRegExp::RegExp);
87     syntaxComboBox->addItem(tr("Regular Expression v2"), QRegExp::RegExp2);
88     syntaxComboBox->addItem(tr("Wildcard"), QRegExp::Wildcard);
89     syntaxComboBox->addItem(tr("Fixed String"), QRegExp::FixedString);
90
91     syntaxLabel->setBuddy(syntaxComboBox);
92
93     mainLayout->addWidget(syntaxLabel, 2, 0);
94     mainLayout->addWidget(syntaxComboBox, 2, 1);
95
96     QHBoxLayout *checkBoxLayout = new QHBoxLayout;
97
98     caseSensitiveCheckBox->setChecked(true);
99
100     checkBoxLayout->addWidget(caseSensitiveCheckBox);
101     checkBoxLayout->addWidget(minimalCheckBox);
102     checkBoxLayout->addStretch(1);
103
104     mainLayout->addLayout(checkBoxLayout, 3, 0, 1, 2);
105
106     textComboBox->setEditable(true);
107     textComboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
108
109     textLabel->setBuddy(textComboBox);
110
111     mainLayout->addWidget(textLabel, 4, 0);
112     mainLayout->addWidget(textComboBox, 4, 1);
113
114     indexEdit->setReadOnly(true);
115
116     mainLayout->addWidget(indexLabel, 5, 0);
117     mainLayout->addWidget(indexEdit, 5, 1);
118
119     matchedLengthEdit->setReadOnly(true);
120
121     mainLayout->addWidget(matchedLengthLabel, 6, 0);
122     mainLayout->addWidget(matchedLengthEdit, 6, 1);
123
124     vboxLayout->addLayout(mainLayout);
125     vboxLayout->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
126
127     for (int i = 0; i < MaxCaptures; ++i) {
128         captureLabels[i] = new QLabel(tr("Capture %1:").arg(i));
129         captureEdits[i] = new QLineEdit;
130         captureEdits[i]->setReadOnly(true);
131     }
132     captureLabels[0]->setText(tr("Match:"));
133
134     for (int j = 0; j < MaxCaptures; ++j) {
135         mainLayout->addWidget(captureLabels[j], 7 + j, 0);
136         mainLayout->addWidget(captureEdits[j], 7 + j, 1);
137     }
138
139     connect(patternComboBox, SIGNAL(editTextChanged(const QString &)), this, SLOT(refresh()));
140     connect(textComboBox, SIGNAL(editTextChanged(const QString &)), this, SLOT(refresh()));
141     connect(caseSensitiveCheckBox, SIGNAL(toggled(bool)), this, SLOT(refresh()));
142     connect(minimalCheckBox, SIGNAL(toggled(bool)), this, SLOT(refresh()));
143     connect(syntaxComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(refresh()));
144
145     setWindowTitle(tr("Regular Expression"));
146     refresh();
147 }
148
149 static const char *escapedBackSlash = "\\\\";
150 static const char *escapedDoubleQuote = "\\\"";
151
152 static QString escapePattern(const QString &pattern)
153 {
154     QString escaped = pattern;
155     escaped.replace(QString(QLatin1Char('\\')) , QLatin1String(escapedBackSlash));
156     const QChar doubleQuote(QLatin1Char('"'));
157     escaped.replace(doubleQuote, QString(QLatin1String(escapedDoubleQuote)));
158     escaped.prepend(doubleQuote);
159     escaped.append(doubleQuote);
160     return escaped;
161 }
162
163 static QString unescapePattern(QString escaped)
164 {
165     // remove quotes
166     const QChar doubleQuote(QLatin1Char('"'));
167     if (escaped.endsWith(doubleQuote))
168         escaped.truncate(escaped.size() - 1);
169     if (escaped.startsWith(doubleQuote))
170         escaped.remove(0, 1);
171
172     const int size = escaped.size();
173     if (!size)
174         return QString();
175
176     // parse out escapes. Do not just replace.
177     QString pattern;
178     const QChar backSlash = QLatin1Char('\\');
179     bool escapeSeen = false;
180     for (int  i = 0; i < size; i++) {
181         const QChar c = escaped.at(i);
182         if (c == backSlash && !escapeSeen)
183             escapeSeen = true;
184         else {
185             pattern.push_back(c);
186             escapeSeen = false;
187         }
188     }
189     return pattern;
190 }
191
192 void RegExpWindow::refresh()
193 {
194     setUpdatesEnabled(false);
195
196     const QString pattern = patternComboBox->currentText();
197     const QString text = textComboBox->currentText();
198
199     escapedPatternLineEdit->setText(escapePattern(pattern));
200
201     QRegExp rx(pattern);
202     const Qt::CaseSensitivity cs = caseSensitiveCheckBox->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive;
203     rx.setCaseSensitivity(cs);
204     rx.setMinimal(minimalCheckBox->isChecked());
205     const QRegExp::PatternSyntax syntax = QRegExp::PatternSyntax(
206             syntaxComboBox->itemData(syntaxComboBox->currentIndex()).toInt());
207     rx.setPatternSyntax(syntax);
208
209     QPalette palette = patternComboBox->palette();
210     if (rx.isValid()) {
211         palette.setColor(QPalette::Text,
212                          textComboBox->palette().color(QPalette::Text));
213     } else {
214         palette.setColor(QPalette::Text, Qt::red);
215     }
216     patternComboBox->setPalette(palette);
217
218     indexEdit->setText(QString::number(rx.indexIn(text)));
219     matchedLengthEdit->setText(QString::number(rx.matchedLength()));
220     for (int i = 0; i < MaxCaptures; ++i) {
221         const bool enabled = i <= rx.numCaptures();
222         captureLabels[i]->setEnabled(enabled);
223         captureEdits[i]->setEnabled(enabled);
224         captureEdits[i]->setText(rx.cap(i));
225     }
226
227     setUpdatesEnabled(true);
228 }
229
230 static void saveTextCombo(const QComboBox *cb, QString &current, QStringList &items)
231 {
232     current =  cb->currentText();
233     items.clear();
234     if (const int count = cb->count())
235         for (int i = 0;i <  count; i++) {
236             const QString text = cb->itemText(i);
237             if (items.indexOf(text) == -1)
238                 items += text;
239         }
240 }
241
242 Settings RegExpWindow::settings() const
243 {
244     Settings rc;
245     rc.m_patternSyntax = static_cast<QRegExp::PatternSyntax>(syntaxComboBox->itemData(syntaxComboBox->currentIndex()).toInt());
246     rc.m_minimal = minimalCheckBox->checkState() == Qt::Checked;
247     rc.m_caseSensitive = caseSensitiveCheckBox->checkState() == Qt::Checked;
248     saveTextCombo(patternComboBox, rc.m_currentPattern, rc.m_patterns);
249     saveTextCombo(textComboBox,  rc.m_currentMatch, rc.m_matches);
250     return rc;
251 }
252
253 static void restoreTextCombo(const QString &current, const QStringList &items, QComboBox *cb)
254 {
255     cb->clear();
256     cb->addItems(items);
257     cb->lineEdit()->setText(current);
258 }
259
260 void RegExpWindow::setSettings(const Settings &s)
261 {
262     const int patternIndex = syntaxComboBox->findData(QVariant(s.m_patternSyntax));
263     syntaxComboBox->setCurrentIndex(patternIndex);
264     minimalCheckBox->setCheckState(s.m_minimal ? Qt::Checked : Qt::Unchecked);
265     caseSensitiveCheckBox->setCheckState(s.m_caseSensitive ? Qt::Checked : Qt::Unchecked);
266     restoreTextCombo(s.m_currentPattern, s.m_patterns, patternComboBox);
267     restoreTextCombo(s.m_currentMatch, s.m_matches, textComboBox);
268 }
269
270 void RegExpWindow::contextMenuEvent(QContextMenuEvent *event)
271 {
272     QMenu menu(this);
273
274     QAction *enterQuotedAction = menu.addAction(tr("Enter Pattern from Code..."));
275     connect(enterQuotedAction, SIGNAL(triggered()), this, SLOT(enterEscaped()));
276     menu.addSeparator();
277
278     QAction *clearPatternsAction = menu.addAction(tr("Clear Patterns"));
279     connect(clearPatternsAction, SIGNAL(triggered()), patternComboBox, SLOT(clear()));
280
281     QAction *clearTextsAction = menu.addAction(tr("Clear Text"));
282     connect(clearTextsAction, SIGNAL(triggered()), textComboBox, SLOT(clear()));
283
284     event->accept();
285     menu.exec(event->globalPos());
286 }
287
288 void  RegExpWindow::enterEscaped()
289 {
290     const QString escapedPattern = QInputDialog::getText (this, tr("Enter Pattern from Code"), tr("Pattern"));
291     if ( escapedPattern.isEmpty())
292         return;
293     patternComboBox->lineEdit()->setText(unescapePattern(escapedPattern));
294
295 }