File indexing completed on 2024-04-14 05:44:22
0001 /* 0002 * SPDX-FileCopyrightText: 2002-2003 Jesper K. Pedersen <blackie@kde.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-only 0005 **/ 0006 0007 #include "characterswidget.h" 0008 0009 #include <QApplication> 0010 #include <QCheckBox> 0011 #include <QDialogButtonBox> 0012 #include <QGroupBox> 0013 #include <QLabel> 0014 #include <QPainter> 0015 #include <QPushButton> 0016 #include <QVBoxLayout> 0017 0018 #include "charselector.h" 0019 #include "myfontmetrics.h" 0020 #include "regexpconverter.h" 0021 #include "textrangeregexp.h" 0022 0023 CharacterEdits *CharactersWidget::_configWindow = nullptr; 0024 0025 CharactersWidget::CharactersWidget(RegExpEditorWindow *editorWindow, QWidget *parent) 0026 : RegExpWidget(editorWindow, parent) 0027 { 0028 _regexp = new TextRangeRegExp(false /* not used */); 0029 } 0030 0031 CharactersWidget::CharactersWidget(TextRangeRegExp *regexp, RegExpEditorWindow *editorWindow, QWidget *parent) 0032 : RegExpWidget(editorWindow, parent) 0033 { 0034 _regexp = dynamic_cast<TextRangeRegExp *>(regexp->clone()); 0035 Q_ASSERT(_regexp); 0036 } 0037 0038 CharactersWidget::~CharactersWidget() 0039 { 0040 delete _regexp; 0041 } 0042 0043 QSize CharactersWidget::sizeHint() const 0044 { 0045 QFontMetrics metrics = fontMetrics(); 0046 _textSize = HackCalculateFontSize(metrics, title()); 0047 // _textSize = metrics.size(0, title()); 0048 0049 QSize headerSize(_textSize.width() + 4 * bdSize, _textSize.height()); 0050 0051 _contentSize = HackCalculateFontSize(metrics, text()); 0052 // _contentSize = metrics.size(0, text()); 0053 0054 return QSize(qMax(headerSize.width(), bdSize + _contentSize.width() + bdSize + 2 * pw), 0055 headerSize.height() + bdSize + _contentSize.height() + bdSize + 2 * pw); 0056 } 0057 0058 void CharactersWidget::paintEvent(QPaintEvent *e) 0059 { 0060 QSize mySize = sizeHint(); 0061 0062 QPainter painter(this); 0063 drawPossibleSelection(painter, mySize); 0064 0065 int center = _textSize.height() / 2; 0066 int offset = 0; 0067 0068 // draw the horizontal line and the label 0069 painter.drawLine(pw, center, bdSize, center); 0070 offset += pw + 2 * bdSize; 0071 0072 painter.drawText(offset, 0, _textSize.width(), _textSize.height(), 0, title()); 0073 offset += _textSize.width() + bdSize; 0074 0075 painter.drawLine(offset, center, mySize.width(), center); 0076 0077 // Draw the rest of the lines 0078 int y = mySize.width() - pw; 0079 int x = mySize.height() - pw; 0080 painter.drawLine(0, center, 0, mySize.height()); 0081 painter.drawLine(y, center, y, mySize.height()); 0082 painter.drawLine(0, x, y, x); 0083 0084 // Draw the text 0085 painter.drawText(bdSize, bdSize + _textSize.height(), _contentSize.width(), _contentSize.height(), 0, text()); 0086 0087 RegExpWidget::paintEvent(e); 0088 } 0089 0090 RegExp *CharactersWidget::regExp() const 0091 { 0092 RegExp *r = _regexp->clone(); 0093 r->setSelected(isSelected()); 0094 return r; 0095 } 0096 0097 QString CharactersWidget::text() const 0098 { 0099 QString res = QString(); 0100 0101 if (_regexp->wordChar()) { 0102 res += i18n("- A word character\n"); 0103 } 0104 0105 if (_regexp->nonWordChar()) { 0106 res += i18n("- A non-word character\n"); 0107 } 0108 0109 if (_regexp->digit()) { 0110 res += i18n("- A digit character\n"); 0111 } 0112 0113 if (_regexp->nonDigit()) { 0114 res += i18n("- A non-digit character\n"); 0115 } 0116 0117 if (_regexp->space()) { 0118 res += i18n("- A space character\n"); 0119 } 0120 0121 if (_regexp->nonSpace()) { 0122 res += i18n("- A non-space character\n"); 0123 } 0124 0125 // Single characters 0126 QStringList chars = _regexp->chars(); 0127 if (!chars.isEmpty()) { 0128 QString str = chars.join(QStringLiteral(", ")); 0129 res += QStringLiteral("- ") + str + QStringLiteral("\n"); 0130 } 0131 0132 // Ranges characters 0133 for (const StringPair &elm : _regexp->range()) { 0134 QString fromText = elm.first; 0135 QString toText = elm.second; 0136 0137 res += i18nc("a range of characters", "- from %1 to %2\n", fromText, toText); 0138 } 0139 return res.left(res.length() - 1); 0140 } 0141 0142 QString CharactersWidget::title() const 0143 { 0144 if (_regexp->negate()) { 0145 return i18n("Any Character Except"); 0146 } else { 0147 return i18n("One of Following Characters"); 0148 } 0149 } 0150 0151 RegExpWidget *CharactersWidget::findWidgetToEdit(QPointF globalPos) 0152 { 0153 if (QRectF(mapToGlobal(QPointF(0, 0)), size()).contains(globalPos)) { 0154 return this; 0155 } else { 0156 return nullptr; 0157 } 0158 } 0159 0160 int CharactersWidget::edit() 0161 { 0162 if (_configWindow == nullptr) { 0163 QApplication::setOverrideCursor(Qt::WaitCursor); 0164 // No parent here, as this window should continue to exists. 0165 _configWindow = new CharacterEdits(nullptr); 0166 _configWindow->setObjectName(QStringLiteral("CharactersWidget::_configWindow")); 0167 QApplication::restoreOverrideCursor(); 0168 } 0169 0170 _configWindow->move(QCursor::pos() - QPoint(_configWindow->sizeHint().width() / 2, _configWindow->sizeHint().height() / 2)); 0171 _configWindow->setRegexp(_regexp); 0172 int ret = _configWindow->exec(); 0173 if (ret == QDialog::Accepted) { 0174 _editorWindow->updateContent(nullptr); 0175 update(); 0176 } 0177 return ret; 0178 } 0179 0180 void CharacterEdits::addCharacter(const QString &txt) 0181 { 0182 const KMultiFormListBoxEntryList list = _single->elements(); 0183 for (KMultiFormListBoxEntry *e : list) { 0184 SingleEntry *entry = dynamic_cast<SingleEntry *>(e); 0185 if (entry && entry->isEmpty()) { 0186 entry->setText(txt); 0187 return; 0188 } 0189 } 0190 0191 SingleEntry *entry = new SingleEntry(_single); 0192 entry->setText(txt); 0193 _single->append(entry); 0194 } 0195 0196 void CharacterEdits::addRange(const QString &from, const QString &to) 0197 { 0198 const KMultiFormListBoxEntryList list = _range->elements(); 0199 for (KMultiFormListBoxEntry *e : list) { 0200 RangeEntry *entry = dynamic_cast<RangeEntry *>(e); 0201 if (entry && entry->isEmpty()) { 0202 entry->setFrom(from); 0203 entry->setTo(to); 0204 return; 0205 } 0206 } 0207 0208 RangeEntry *entry = new RangeEntry(_range); 0209 entry->setFrom(from); 0210 entry->setTo(to); 0211 _range->append(entry); 0212 } 0213 0214 void CharacterEdits::setRegexp(TextRangeRegExp *regexp) 0215 { 0216 _regexp = regexp; 0217 negate->setChecked(regexp->negate()); 0218 digit->setChecked(regexp->digit()); 0219 _nonDigit->setChecked(regexp->nonDigit()); 0220 space->setChecked(regexp->space()); 0221 _nonSpace->setChecked(regexp->nonSpace()); 0222 wordChar->setChecked(regexp->wordChar()); 0223 _nonWordChar->setChecked(regexp->nonWordChar()); 0224 0225 bool enabled = (RegExpConverter::current()->features() & RegExpConverter::CharacterRangeNonItems); 0226 _nonWordChar->setEnabled(enabled); 0227 _nonDigit->setEnabled(enabled); 0228 _nonSpace->setEnabled(enabled); 0229 0230 // Characters 0231 0232 const KMultiFormListBoxEntryList list1 = _single->elements(); 0233 for (KMultiFormListBoxEntry *e : list1) { 0234 SingleEntry *entry = dynamic_cast<SingleEntry *>(e); 0235 if (entry) { 0236 entry->setText(QString()); 0237 } 0238 } 0239 QStringList list2 = regexp->chars(); 0240 for (QStringList::Iterator it2(list2.begin()); it2 != list2.end(); ++it2) { 0241 addCharacter(*it2); 0242 } 0243 0244 // Ranges 0245 KMultiFormListBoxEntryList list3 = _range->elements(); 0246 for (KMultiFormListBoxEntry *e : list3) { 0247 RangeEntry *entry = dynamic_cast<RangeEntry *>(e); 0248 if (entry) { 0249 entry->setFrom(QString()); 0250 entry->setTo(QString()); 0251 } 0252 } 0253 0254 const auto range = _regexp->range(); 0255 for (const StringPair &elm : range) { 0256 QString from = elm.first; 0257 QString to = elm.second; 0258 addRange(from, to); 0259 } 0260 } 0261 0262 CharacterEdits::CharacterEdits(QWidget *parent) 0263 : QDialog(parent) 0264 { 0265 setWindowTitle(i18n("Specify Characters")); 0266 QVBoxLayout *mainLayout = new QVBoxLayout; 0267 setLayout(mainLayout); 0268 0269 setObjectName(QStringLiteral("CharacterEdits")); 0270 QWidget *top = new QWidget(this); 0271 QVBoxLayout *topLayout = new QVBoxLayout(top); 0272 topLayout->setContentsMargins(0, 0, 0, 0); 0273 mainLayout->addWidget(top); 0274 0275 negate = new QCheckBox(i18n("Do not match the characters specified here")); 0276 topLayout->addWidget(negate); 0277 0278 // The predefined box 0279 QGroupBox *predefined = new QGroupBox(i18n("Predefined Character Ranges")); 0280 topLayout->addWidget(predefined); 0281 QGridLayout *predefinedLayout = new QGridLayout(predefined); 0282 0283 wordChar = new QCheckBox(i18n("A word character")); 0284 predefinedLayout->addWidget(wordChar, 0, 0); 0285 digit = new QCheckBox(i18n("A digit character")); 0286 predefinedLayout->addWidget(digit, 0, 1); 0287 space = new QCheckBox(i18n("A space character")); 0288 predefinedLayout->addWidget(space, 0, 2); 0289 0290 _nonWordChar = new QCheckBox(i18n("A non-word character")); 0291 predefinedLayout->addWidget(_nonWordChar, 1, 0); 0292 _nonDigit = new QCheckBox(i18n("A non-digit character")); 0293 predefinedLayout->addWidget(_nonDigit, 1, 1); 0294 _nonSpace = new QCheckBox(i18n("A non-space character")); 0295 predefinedLayout->addWidget(_nonSpace, 1, 2); 0296 0297 // Single characters 0298 QGroupBox *singleBox = new QGroupBox(i18n("Single Characters")); 0299 QVBoxLayout *groupLayout = new QVBoxLayout(singleBox); 0300 topLayout->addWidget(singleBox); 0301 _single = new KMultiFormListBox(new SingleFactory(), KMultiFormListBox::MultiVisible); 0302 groupLayout->addWidget(_single); 0303 _single->addElement(); 0304 _single->addElement(); 0305 _single->addElement(); 0306 0307 QWidget *moreW = new QWidget(); 0308 groupLayout->addWidget(moreW); 0309 QHBoxLayout *moreLay = new QHBoxLayout(moreW); 0310 QPushButton *more = new QPushButton(i18n("More Entries")); 0311 moreLay->addWidget(more); 0312 moreLay->addStretch(1); 0313 moreLay->setContentsMargins(0, 0, 0, 0); 0314 0315 connect(more, &QAbstractButton::clicked, _single, &KMultiFormListBox::addElement); 0316 0317 // Ranges 0318 QGroupBox *rangeBox = new QGroupBox(i18n("Character Ranges")); 0319 groupLayout = new QVBoxLayout(rangeBox); 0320 topLayout->addWidget(rangeBox); 0321 0322 _range = new KMultiFormListBox(new RangeFactory(), KMultiFormListBox::MultiVisible); 0323 groupLayout->addWidget(_range); 0324 _range->addElement(); 0325 _range->addElement(); 0326 _range->addElement(); 0327 0328 moreW = new QWidget(); 0329 groupLayout->addWidget(moreW); 0330 moreLay = new QHBoxLayout(moreW); 0331 more = new QPushButton(i18n("More Entries")); 0332 moreLay->addWidget(more); 0333 moreLay->addStretch(1); 0334 moreLay->setContentsMargins(0, 0, 0, 0); 0335 connect(more, &QAbstractButton::clicked, _range, &KMultiFormListBox::addElement); 0336 0337 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); 0338 QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); 0339 okButton->setDefault(true); 0340 okButton->setShortcut(Qt::CTRL | Qt::Key_Return); 0341 connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); 0342 connect(okButton, &QAbstractButton::clicked, this, &CharacterEdits::slotOK); 0343 mainLayout->addWidget(buttonBox); 0344 } 0345 0346 void CharacterEdits::slotOK() 0347 { 0348 _regexp->setNegate(negate->isChecked()); 0349 0350 _regexp->setWordChar(wordChar->isChecked()); 0351 _regexp->setNonWordChar(_nonWordChar->isChecked()); 0352 0353 _regexp->setDigit(digit->isChecked()); 0354 _regexp->setNonDigit(_nonDigit->isChecked()); 0355 0356 _regexp->setSpace(space->isChecked()); 0357 _regexp->setNonSpace(_nonSpace->isChecked()); 0358 0359 // single characters 0360 _regexp->clearChars(); 0361 const KMultiFormListBoxEntryList list = _single->elements(); 0362 for (KMultiFormListBoxEntry *e : list) { 0363 SingleEntry *entry = dynamic_cast<SingleEntry *>(e); 0364 if (entry && !entry->isEmpty()) { 0365 _regexp->addCharacter(entry->text()); 0366 } 0367 } 0368 0369 // Ranges 0370 _regexp->clearRange(); 0371 const auto elements = _range->elements(); 0372 for (KMultiFormListBoxEntry *e : elements) { 0373 RangeEntry *entry = dynamic_cast<RangeEntry *>(e); 0374 if (entry && !entry->isEmpty()) { 0375 _regexp->addRange(entry->fromText(), entry->toText()); 0376 } 0377 } 0378 accept(); 0379 } 0380 0381 SingleEntry::SingleEntry(QWidget *parent) 0382 : KMultiFormListBoxEntry(parent) 0383 { 0384 QHBoxLayout *layout = new QHBoxLayout(this); 0385 layout->setContentsMargins(0, 0, 0, 0); 0386 _selector = new CharSelector(this); 0387 layout->addWidget(_selector); 0388 layout->addStretch(1); 0389 } 0390 0391 QString SingleEntry::text() const 0392 { 0393 return _selector->text(); 0394 } 0395 0396 void SingleEntry::setText(const QString &text) 0397 { 0398 _selector->setText(text); 0399 } 0400 0401 bool SingleEntry::isEmpty() const 0402 { 0403 return _selector->isEmpty(); 0404 } 0405 0406 RangeEntry::RangeEntry(QWidget *parent) 0407 : KMultiFormListBoxEntry(parent) 0408 { 0409 QHBoxLayout *layout = new QHBoxLayout(this); 0410 layout->setContentsMargins(0, 0, 0, 0); 0411 0412 QLabel *label = new QLabel(i18n("From:"), this); 0413 _from = new CharSelector(this); 0414 layout->addWidget(label); 0415 layout->addWidget(_from); 0416 0417 layout->addStretch(1); 0418 0419 label = new QLabel(i18nc("end of range", "To:"), this); 0420 _to = new CharSelector(this); 0421 layout->addWidget(label); 0422 layout->addWidget(_to); 0423 } 0424 0425 QString RangeEntry::fromText() const 0426 { 0427 return _from->text(); 0428 } 0429 0430 QString RangeEntry::toText() const 0431 { 0432 return _to->text(); 0433 } 0434 0435 void RangeEntry::setFrom(const QString &text) 0436 { 0437 _from->setText(text); 0438 } 0439 0440 void RangeEntry::setTo(const QString &text) 0441 { 0442 _to->setText(text); 0443 } 0444 0445 bool RangeEntry::isEmpty() const 0446 { 0447 return _from->isEmpty() || _to->isEmpty(); 0448 } 0449 0450 #include "moc_characterswidget.cpp"