File indexing completed on 2024-04-14 05:44:26

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 "repeatwidget.h"
0008 
0009 #include <QButtonGroup>
0010 #include <QGroupBox>
0011 #include <QLabel>
0012 #include <QPainter>
0013 #include <QRadioButton>
0014 #include <QSpinBox>
0015 #include <QVBoxLayout>
0016 
0017 #include <KLocalizedString>
0018 #include <QDialog>
0019 #include <QDialogButtonBox>
0020 #include <QPushButton>
0021 
0022 #include "concwidget.h"
0023 #include "kwidgetstreamer.h"
0024 #include "repeatregexp.h"
0025 
0026 RepeatWidget::RepeatWidget(RegExpEditorWindow *editorWindow, QWidget *parent)
0027     : SingleContainerWidget(editorWindow, parent)
0028 {
0029     _child = new ConcWidget(editorWindow, this);
0030     init();
0031 }
0032 
0033 RepeatWidget::RepeatWidget(RepeatRegExp *regexp, RegExpEditorWindow *editorWindow, QWidget *parent)
0034     : SingleContainerWidget(editorWindow, parent)
0035 {
0036     init();
0037     RegExpWidget *child = WidgetFactory::createWidget(regexp->child(), editorWindow, this);
0038     if (!(_child = dynamic_cast<ConcWidget *>(child))) {
0039         _child = new ConcWidget(editorWindow, child, this);
0040     }
0041 
0042     if (regexp->max() == -1) {
0043         if (regexp->min() == 0) {
0044             _content->set(RepeatRangeWindow::ANY, regexp->min(), regexp->max());
0045         } else {
0046             _content->set(RepeatRangeWindow::ATLEAST, regexp->min(), regexp->max()); // krazy:exclude=spelling
0047         }
0048     } else {
0049         if (regexp->min() == 0) {
0050             _content->set(RepeatRangeWindow::ATMOST, regexp->min(), regexp->max());
0051         } else if (regexp->min() == regexp->max()) {
0052             _content->set(RepeatRangeWindow::EXACTLY, regexp->min(), regexp->max());
0053         } else {
0054             _content->set(RepeatRangeWindow::MINMAX, regexp->min(), regexp->max());
0055         }
0056     }
0057 }
0058 
0059 void RepeatWidget::init()
0060 {
0061     _configWindow = new QDialog(this);
0062     _configWindow->setWindowTitle(i18n("Number of Times to Repeat Content"));
0063     QVBoxLayout *mainLayout = new QVBoxLayout;
0064     _configWindow->setLayout(mainLayout);
0065 
0066     _content = new RepeatRangeWindow(_configWindow);
0067     connect(_configWindow, &QDialog::rejected, this, &RepeatWidget::slotConfigCanceled);
0068     connect(_configWindow, &QDialog::finished, this, &RepeatWidget::slotConfigWindowClosed);
0069     mainLayout->addWidget(_content);
0070 
0071     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
0072     QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0073     okButton->setDefault(true);
0074     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0075     mainLayout->addWidget(buttonBox);
0076     _configWindow->connect(buttonBox, &QDialogButtonBox::accepted, _configWindow, &QDialog::accept);
0077     _configWindow->connect(buttonBox, &QDialogButtonBox::rejected, _configWindow, &QDialog::reject);
0078 }
0079 
0080 QSize RepeatWidget::sizeHint() const
0081 {
0082     // TODO: Merge with LookAheadWidget::sizeHint
0083     QFontMetrics metrics = fontMetrics();
0084     _textSize = metrics.size(0, _content->text());
0085 
0086     _childSize = _child->sizeHint();
0087 
0088     int height = _textSize.height() + bdSize + _childSize.height() + bdSize + 2 * pw;
0089     int width = 2 * pw + qMax(_childSize.width(), 4 * bdSize + _textSize.width());
0090     return QSize(width, height);
0091 }
0092 
0093 void RepeatWidget::paintEvent(QPaintEvent *e)
0094 {
0095     // TODO: Merge with LookAheadWidget::paintEvent
0096     QSize mySize = sizeHint();
0097     QPainter painter(this);
0098 
0099     drawPossibleSelection(painter, mySize);
0100 
0101     // move the child to its position and resize it.
0102     _child->move(pw, _textSize.height() + bdSize);
0103     QSize curChildSize = _child->size();
0104     QSize newChildSize = QSize(mySize.width() - 2 * pw, _childSize.height());
0105     if (curChildSize != newChildSize) {
0106         _child->resize(newChildSize);
0107         // I resized the child, so give it a chance to relect thus.
0108         _child->update();
0109     }
0110 
0111     // Draw the border and the text.
0112     int startY = _textSize.height() / 2;
0113 
0114     // Top lines and text
0115     painter.drawLine(pw, startY, bdSize, startY);
0116     painter.drawText(pw + 2 * bdSize, 0, _textSize.width(), _textSize.height(), 0, _content->text());
0117     int offset = pw + 3 * bdSize + _textSize.width();
0118     painter.drawLine(offset, startY, mySize.width() - pw, startY);
0119 
0120     // horizontal lines
0121     painter.drawLine(0, startY, 0, mySize.height() - pw);
0122     painter.drawLine(mySize.width() - pw, startY, mySize.width() - pw, mySize.height() - pw);
0123 
0124     // buttom line
0125     painter.drawLine(0, mySize.height() - pw, mySize.width() - pw, mySize.height() - pw);
0126 
0127     SingleContainerWidget::paintEvent(e);
0128 }
0129 
0130 RegExp *RepeatWidget::regExp() const
0131 {
0132     return new RepeatRegExp(isSelected(), _content->min(), _content->max(), _child->regExp());
0133 }
0134 
0135 void RepeatWidget::slotConfigWindowClosed()
0136 {
0137     _editorWindow->updateContent(nullptr);
0138     update();
0139 }
0140 
0141 void RepeatWidget::slotConfigCanceled()
0142 {
0143     QDataStream stream(&_backup, QIODevice::ReadOnly);
0144 
0145     stream.setVersion(QDataStream::Qt_3_1);
0146     KWidgetStreamer streamer;
0147     streamer.fromStream(stream, _content);
0148     repaint();
0149 }
0150 
0151 int RepeatWidget::edit()
0152 {
0153     _configWindow->move(QCursor::pos() - QPoint(_configWindow->sizeHint().width() / 2, _configWindow->sizeHint().height() / 2));
0154     QDataStream stream(&_backup, QIODevice::WriteOnly);
0155 
0156     stream.setVersion(QDataStream::Qt_3_1);
0157     KWidgetStreamer streamer;
0158     streamer.toStream(_content, stream);
0159 
0160     return _configWindow->exec();
0161 }
0162 
0163 //--------------------------------------------------------------------------------
0164 RepeatRangeWindow::RepeatRangeWindow(QWidget *parent)
0165     : QWidget(parent)
0166 {
0167     QVBoxLayout *mainLayout = new QVBoxLayout(this);
0168     mainLayout->setContentsMargins(0, 0, 0, 0);
0169 
0170     _groupWidget = new QGroupBox(i18n("Times to Match"));
0171     mainLayout->addWidget(_groupWidget);
0172     _group = new QButtonGroup(this);
0173 
0174     QGridLayout *groupLayout = new QGridLayout(_groupWidget);
0175 
0176     // Any number of times
0177     QRadioButton *radioBut = new QRadioButton(i18n("Any number of times (including zero times)"));
0178     radioBut->setObjectName(QStringLiteral("RepeatRangeWindow::choice any times"));
0179 
0180     groupLayout->addWidget(radioBut, 0, 0, 1, 3);
0181     _group->addButton(radioBut, ANY);
0182     radioBut->click();
0183 
0184     createLine(groupLayout, i18n("At least"), &_leastTimes, ATLEAST); // krazy:exclude=spelling
0185     createLine(groupLayout, i18n("At most"), &_mostTimes, ATMOST);
0186     createLine(groupLayout, i18n("Exactly"), &_exactlyTimes, EXACTLY);
0187 
0188     // from ___ to ___ times
0189     radioBut = new QRadioButton(i18n("From"));
0190     radioBut->setObjectName(QStringLiteral("RepeatRangeWindow::from"));
0191     groupLayout->addWidget(radioBut, 4, 0);
0192     _group->addButton(radioBut, MINMAX);
0193 
0194     _rangeFrom = new QSpinBox();
0195     _rangeFrom->setRange(1, 999);
0196     _rangeFrom->setSingleStep(1);
0197     groupLayout->addWidget(_rangeFrom, 4, 1);
0198 
0199     QHBoxLayout *layout = new QHBoxLayout();
0200 
0201     QLabel *label = new QLabel(i18n("to"));
0202     layout->addWidget(label);
0203 
0204     _rangeTo = new QSpinBox();
0205     _rangeTo->setRange(1, 999);
0206     _rangeTo->setSingleStep(1);
0207     layout->addWidget(_rangeTo);
0208 
0209     label = new QLabel(i18n("time(s)"));
0210     layout->addWidget(label);
0211 
0212     groupLayout->addLayout(layout, 4, 2);
0213 
0214     connect(_rangeFrom, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateMaxVal(int)));
0215     connect(_rangeTo, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateMinVal(int)));
0216 
0217     connect(_group, &QButtonGroup::idClicked, this, &RepeatRangeWindow::slotItemChange);
0218 
0219     _group->button(ANY)->click();
0220 }
0221 
0222 void RepeatRangeWindow::createLine(QGridLayout *layout, const QString &text, QSpinBox **spin, REPEATTYPE tp)
0223 {
0224     int row = layout->rowCount();
0225 
0226     QRadioButton *radioBut = new QRadioButton(text);
0227     layout->addWidget(radioBut, row, 0);
0228 
0229     *spin = new QSpinBox();
0230     (*spin)->setRange(1, 999);
0231     (*spin)->setSingleStep(1);
0232     (*spin)->setValue(1);
0233     layout->addWidget(*spin, row, 1);
0234 
0235     QLabel *label = new QLabel(i18n("time(s)"));
0236     layout->addWidget(label, row, 2, 1, 2);
0237     _group->addButton(radioBut, tp);
0238 }
0239 
0240 void RepeatRangeWindow::slotItemChange(int which)
0241 {
0242     _leastTimes->setEnabled(false);
0243     _mostTimes->setEnabled(false);
0244     _exactlyTimes->setEnabled(false);
0245     _rangeFrom->setEnabled(false);
0246     _rangeTo->setEnabled(false);
0247 
0248     switch (which) {
0249     case ANY:
0250         break;
0251     case ATLEAST:
0252         _leastTimes->setEnabled(true);
0253         break; // krazy:exclude=spelling
0254     case ATMOST:
0255         _mostTimes->setEnabled(true);
0256         break;
0257     case EXACTLY:
0258         _exactlyTimes->setEnabled(true);
0259         break;
0260     case MINMAX:
0261         _rangeFrom->setEnabled(true);
0262         _rangeTo->setEnabled(true);
0263         break;
0264     }
0265 }
0266 
0267 void RepeatRangeWindow::slotUpdateMinVal(int maxVal)
0268 {
0269     if (_rangeFrom->value() > maxVal) {
0270         _rangeFrom->setValue(maxVal);
0271     }
0272 }
0273 
0274 void RepeatRangeWindow::slotUpdateMaxVal(int minVal)
0275 {
0276     if (_rangeTo->value() < minVal) {
0277         _rangeTo->setValue(minVal);
0278     }
0279 }
0280 
0281 QString RepeatRangeWindow::text()
0282 {
0283     switch (_group->checkedId()) {
0284     case ANY:
0285         return i18n("Repeated Any Number of Times");
0286     case ATLEAST:
0287         return i18np("Repeated at Least 1 Time", "Repeated at Least %1 Times", _leastTimes->value()); // krazy:exclude=spelling
0288     case ATMOST:
0289         return i18np("Repeated at Most 1 Time", "Repeated at Most %1 Times", _mostTimes->value());
0290     case EXACTLY:
0291         return i18np("Repeated Exactly 1 Time", "Repeated Exactly %1 Times", _exactlyTimes->value());
0292     case MINMAX:
0293         return i18n("Repeated From %1 to %2 Times", _rangeFrom->value(), _rangeTo->value());
0294     }
0295 
0296     qFatal("Fall through!");
0297     return QString();
0298 }
0299 
0300 int RepeatRangeWindow::min()
0301 {
0302     switch (_group->checkedId()) {
0303     case ANY:
0304         return 0;
0305     case ATLEAST:
0306         return _leastTimes->value(); // krazy:exclude=spelling
0307     case ATMOST:
0308         return 0;
0309     case EXACTLY:
0310         return _exactlyTimes->value();
0311     case MINMAX:
0312         return _rangeFrom->value();
0313     }
0314     qFatal("Fall through!");
0315     return -1;
0316 }
0317 
0318 int RepeatRangeWindow::max()
0319 {
0320     switch (_group->checkedId()) {
0321     case ANY:
0322         return -1;
0323     case ATLEAST:
0324         return -1; // krazy:exclude=spelling
0325     case ATMOST:
0326         return _mostTimes->value();
0327     case EXACTLY:
0328         return _exactlyTimes->value();
0329     case MINMAX:
0330         return _rangeTo->value();
0331     }
0332     qFatal("Fall through!");
0333     return -1;
0334 }
0335 
0336 void RepeatRangeWindow::set(REPEATTYPE tp, int min, int max)
0337 {
0338     _group->button(tp)->click();
0339     switch (tp) {
0340     case ANY:
0341         break;
0342     case ATLEAST: // krazy:exclude=spelling
0343         _leastTimes->setValue(min);
0344         break;
0345     case ATMOST:
0346         _mostTimes->setValue(max);
0347         break;
0348     case EXACTLY:
0349         _exactlyTimes->setValue(min);
0350         break;
0351     case MINMAX:
0352         _rangeFrom->setValue(min);
0353         _rangeTo->setValue(max);
0354         break;
0355     }
0356 }
0357 
0358 #include "moc_repeatwidget.cpp"