File indexing completed on 2024-04-21 05:51:35

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 "altnwidget.h"
0008 
0009 #include <QPaintEvent>
0010 #include <QPainter>
0011 
0012 #include <KLocalizedString>
0013 #include <KMessageBox>
0014 
0015 #include "altnregexp.h"
0016 #include "concwidget.h"
0017 #include "dragaccepter.h"
0018 
0019 AltnWidget::AltnWidget(RegExpEditorWindow *editorWindow, QWidget *parent)
0020     : MultiContainerWidget(editorWindow, parent)
0021 {
0022     DragAccepter *accepter = new DragAccepter(editorWindow, this);
0023     accepter->resize(0, 0); // See note (1) in Comments
0024     _children.append(accepter);
0025     _text = i18n("Alternatives");
0026 }
0027 
0028 AltnWidget::AltnWidget(AltnRegExp *regexp, RegExpEditorWindow *editorWindow, QWidget *parent)
0029     : MultiContainerWidget(editorWindow, parent)
0030 {
0031     DragAccepter *accepter = new DragAccepter(editorWindow, this);
0032     accepter->resize(0, 0); // See note (1) in Comments
0033     _children.append(accepter);
0034     _text = i18n("Alternatives");
0035 
0036     const RegExpList list = regexp->children();
0037     for (RegExp *r : list) {
0038         RegExpWidget *child = WidgetFactory::createWidget(r, editorWindow, this);
0039         ConcWidget *conc;
0040         if (!(conc = dynamic_cast<ConcWidget *>(child))) {
0041             conc = new ConcWidget(editorWindow, child, parent);
0042         }
0043         append(conc);
0044     }
0045     updateDrawLineInfo();
0046 }
0047 
0048 void AltnWidget::addNewChild(DragAccepter *accepter, RegExpWidget *child)
0049 {
0050     ConcWidget *conc = new ConcWidget(_editorWindow, child, this);
0051     MultiContainerWidget::addNewChild(accepter, conc);
0052     updateDrawLineInfo();
0053     repaint();
0054 }
0055 
0056 void AltnWidget::setConcChild(ConcWidget *child)
0057 {
0058     addNewConcChild(dynamic_cast<DragAccepter *>(_children.at(0)), child);
0059 }
0060 
0061 void AltnWidget::addNewConcChild(DragAccepter *accepter, ConcWidget *child)
0062 {
0063     child->setParent(this);
0064     MultiContainerWidget::addNewChild(accepter, child);
0065     updateDrawLineInfo();
0066 }
0067 
0068 QSize AltnWidget::sizeHint() const
0069 {
0070     QList<RegExpWidget *>::const_iterator it = _children.constBegin();
0071     // Skip the first child, as we only need half of the size of the first and the
0072     // last drag accepter. Does, however, not apply when there only is onw child.
0073     if (_children.count() != 1) {
0074         ++it;
0075     }
0076 
0077     _childrenWidth = 0;
0078     _childrenHeight = 0;
0079 
0080     for (; it != _children.constEnd(); ++it) {
0081         QSize thisChildSize = (*it)->sizeHint();
0082         _childrenWidth = qMax(_childrenWidth, thisChildSize.width());
0083         _childrenHeight += thisChildSize.height();
0084     }
0085 
0086     // Now add the size of the header
0087     QFontMetrics metrics = fontMetrics();
0088     _textSize = metrics.size(0, _text);
0089 
0090     int headerWidth = _textSize.width() + 2 * bdSize + 2;
0091 
0092     _childrenWidth = qMax(_childrenWidth, headerWidth);
0093 
0094     return QSize(_childrenWidth + 2 * pw, _childrenHeight + _textSize.height() + 1 * pw);
0095 }
0096 
0097 void AltnWidget::paintEvent(QPaintEvent *e)
0098 {
0099     Q_ASSERT(dynamic_cast<DragAccepter *>(_children.at(0)));
0100     // if this fails, then I should check the location of the show()
0101     Q_ASSERT(_children.count() == 1 || (_children.count() >= 3 && dynamic_cast<DragAccepter *>(_children.at(_children.count() - 1))));
0102 
0103     int offset = 0;
0104     QSize mySize = sizeHint();
0105 
0106     QPainter painter(this);
0107     drawPossibleSelection(painter, mySize);
0108 
0109     //-------------------------------------- First draw the border and text
0110     int startY = _textSize.height() / 2;
0111 
0112     painter.drawLine(0, startY, bdSize, startY);
0113     int xOffset = bdSize + 1;
0114 
0115     painter.drawText(xOffset, 0, _textSize.width(), _textSize.height(), 0, _text);
0116     xOffset += _textSize.width() + 1;
0117     painter.drawLine(xOffset, startY, mySize.width(), startY);
0118     painter.drawLine(0, startY, 0, mySize.height());
0119     painter.drawLine(mySize.width() - pw, startY, mySize.width() - pw, mySize.height());
0120     painter.drawLine(0, mySize.height() - pw, mySize.width() - pw, mySize.height() - pw);
0121 
0122     //---- Run through all the children and place them at the correct location.
0123     offset = _textSize.height();
0124     xOffset = pw;
0125 
0126     for (int i = 0; i < _children.count(); i++) {
0127         RegExpWidget *child = _children.at(i);
0128 
0129         QSize childSize = child->sizeHint();
0130         QSize curChildSize = child->size();
0131 
0132         //-------------------------------------- place the child
0133         int x = xOffset;
0134         int y = offset;
0135         int h = childSize.height();
0136         if ((_children.count() != 1) && (i == 0 || i == _children.count() - 1)) {
0137             // first and last DragAccepter should only be half size.
0138             h /= 2;
0139         }
0140 
0141         int w = _childrenWidth;
0142         child->setGeometry(x, y, w, h);
0143         if (w != curChildSize.width() || h != curChildSize.height()) {
0144             // I resized the child, so give it a chance to relect thus.
0145             child->update();
0146         }
0147 
0148         offset += h;
0149     }
0150     MultiContainerWidget::paintEvent(e);
0151 }
0152 
0153 RegExp *AltnWidget::regExp() const
0154 {
0155     AltnRegExp *regexp = new AltnRegExp(isSelected());
0156 
0157     QList<RegExpWidget *>::const_iterator it = _children.constBegin();
0158     ++it; // start with the second element
0159     for (; it != _children.constEnd(); it += 2) {
0160         regexp->addRegExp((*it)->regExp());
0161     }
0162 
0163     return regexp;
0164 }
0165 
0166 void AltnWidget::applyRegExpToSelection(RegExpType type)
0167 {
0168     for (int i = 1; i < _children.count(); i += 2) {
0169         RegExpWidget *child = _children.at(i);
0170         if (child->hasSelection()) {
0171             child->applyRegExpToSelection(type);
0172         }
0173     }
0174 }
0175 
0176 RegExp *AltnWidget::selection() const
0177 {
0178     if (isSelected()) {
0179         return regExp();
0180     } else {
0181         QList<RegExpWidget *>::const_iterator it = _children.constBegin();
0182         ++it; // Skip past DragAccepter
0183         for (; *it; it += 2) {
0184             if ((*it)->hasSelection()) {
0185                 return (*it)->selection();
0186             }
0187         }
0188     }
0189     qFatal("Selection not found");
0190     return nullptr; // compiler shut up.
0191 }
0192 
0193 bool AltnWidget::validateSelection() const
0194 {
0195     if (_isSelected) {
0196         return true;
0197     }
0198 
0199     bool foundASelection = false;
0200     QList<RegExpWidget *>::const_iterator it = _children.constBegin();
0201     ++it; // Skip past DragAccepter
0202     for (; it != _children.constEnd(); it += 2) {
0203         if ((*it)->hasSelection()) {
0204             if (foundASelection) {
0205                 KMessageBox::information(const_cast<AltnWidget *>(this),
0206                                          i18n("Selecting several alternatives is "
0207                                               "currently not supported."),
0208                                          i18n("Selection Invalid"));
0209                 _editorWindow->clearSelection(true);
0210                 return false;
0211             } else {
0212                 foundASelection = true;
0213             }
0214         }
0215     }
0216     return true;
0217 }
0218 
0219 void AltnWidget::updateDrawLineInfo()
0220 {
0221     for (int i = 0; i < _children.count(); i += 2) {
0222         bool line = (i != 0 && i != _children.count() - 1);
0223         DragAccepter *accepter = dynamic_cast<DragAccepter *>(_children.at(i));
0224         if (accepter) {
0225             accepter->setDrawLine(line);
0226         }
0227     }
0228 }
0229 
0230 void AltnWidget::deleteSelection()
0231 {
0232     MultiContainerWidget::deleteSelection();
0233     updateDrawLineInfo();
0234 }