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

0001 /*
0002  *  SPDX-FileCopyrightText: 2002-2003 Jesper K. Pedersen <blackie@kde.org>
0003  *  SPDX-FileCopyrightText: 2011 Morten A. B. Sjøgren <m_abs@mabs.dk>
0004  *
0005  *  SPDX-License-Identifier: LGPL-2.0-only
0006  **/
0007 
0008 #include "multicontainerwidget.h"
0009 
0010 #include "dragaccepter.h"
0011 
0012 MultiContainerWidget::MultiContainerWidget(RegExpEditorWindow *editorWindow, QWidget *parent)
0013     : RegExpWidget(editorWindow, parent)
0014 {
0015 }
0016 
0017 void MultiContainerWidget::append(RegExpWidget *child)
0018 {
0019     child->setParent(this);
0020     _children.append(child);
0021     _children.append(new DragAccepter(_editorWindow, this));
0022 }
0023 
0024 bool MultiContainerWidget::hasSelection() const
0025 {
0026     if (_isSelected) {
0027         return true;
0028     }
0029 
0030     QList<RegExpWidget *>::const_iterator it = _children.constBegin();
0031     ++it; // Move past the first dragAccepter
0032     for (; it != _children.constEnd(); it += 2) {
0033         if ((*it)->hasSelection()) {
0034             return true;
0035         }
0036     }
0037     return false;
0038 }
0039 
0040 void MultiContainerWidget::clearSelection()
0041 {
0042     _isSelected = false;
0043     for (int i = 0; i < _children.count(); i++) {
0044         _children.at(i)->clearSelection();
0045     }
0046 }
0047 
0048 void MultiContainerWidget::deleteSelection()
0049 {
0050     // run from the back to the front (which we do since we delete items on the run)
0051     // When deleting children, delete the drag accepter to its right.
0052     for (int i = (int)_children.count() - 2; i > 0; i -= 2) {
0053         RegExpWidget *child = _children.at(i);
0054         if (child->isSelected()) {
0055             delete _children.at(i + 1);
0056             _children.removeAt(i + 1);
0057             delete child;
0058             _children.removeAt(i);
0059         } else if (child->hasSelection()) {
0060             child->deleteSelection();
0061         }
0062     }
0063     _isSelected = false;
0064     update();
0065 }
0066 
0067 void MultiContainerWidget::addNewChild(DragAccepter *accepter, RegExpWidget *child)
0068 {
0069     for (int i = 0; i < _children.count(); i += 2) {
0070         RegExpWidget *ch = _children.at(i);
0071         if (ch == accepter) {
0072             // Insert the new child
0073             _children.insert(i + 1, child);
0074 
0075             // Insert an accepter as the next element.
0076             DragAccepter *accepter = new DragAccepter(_editorWindow, this);
0077 
0078             _children.insert(i + 2, accepter);
0079 
0080             // These two show's must come here otherwise a paintevent
0081             // will be invoked, where the invariant, that a accepter is located at
0082             // every second element.
0083             child->show();
0084             accepter->show();
0085 
0086             update();
0087 
0088             return;
0089         }
0090     }
0091     qFatal("Accepter not found in list");
0092 }
0093 
0094 bool MultiContainerWidget::updateSelection(bool parentSelected)
0095 {
0096     bool changed = false;
0097     bool isSel = _isSelected;
0098     QVector<bool> oldState(_children.count());
0099     QVector<bool> newState(_children.count());
0100 
0101     for (int i = 0; i < (int)_children.count(); i++) {
0102         oldState[i] = _children.at(i)->isSelected();
0103     }
0104 
0105     RegExpWidget::updateSelection(parentSelected);
0106 
0107     int first;
0108     int last;
0109 
0110     // scan for the first selected item.
0111     for (first = 1; first < (int)_children.count(); first += 2) {
0112         RegExpWidget *child = _children.at(first);
0113         changed = child->updateSelection(_isSelected) || changed;
0114         newState[first] = child->isSelected();
0115         if (child->isSelected()) {
0116             break;
0117         }
0118     }
0119 
0120     // scan for the last selected item
0121     for (last = _children.count() - 2; last > first; last -= 2) {
0122         RegExpWidget *child = _children.at(last);
0123         changed = child->updateSelection(_isSelected) || changed;
0124         newState[last] = child->isSelected();
0125         if (child->isSelected()) {
0126             break;
0127         }
0128     }
0129 
0130     // everything between first and last must be selected.
0131     for (int j = first + 2; j < last; j += 2) {
0132         RegExpWidget *child = _children.at(j);
0133 
0134         changed = child->updateSelection(true) || changed;
0135         newState[j] = true;
0136     }
0137 
0138     // update drag accepters.
0139     for (int k = 0; k < (int)_children.count(); k += 2) {
0140         RegExpWidget *child = _children.at(k);
0141         bool select;
0142         if (k == 0 || k == (int)_children.count() - 1) {
0143             // The elements at the border is only selected if the parent is selected.
0144             select = _isSelected;
0145         } else {
0146             // Drag accepters in the middle is selected if the elements at both
0147             // sides are selected.
0148             select = newState[k - 1] && newState[k + 1];
0149         }
0150 
0151         bool isChildSel = child->isSelected();
0152         DragAccepter *accepter = dynamic_cast<DragAccepter *>(child);
0153         if (accepter) {
0154             accepter->_isSelected = select;
0155         }
0156 
0157         if (select != isChildSel) {
0158             child->repaint();
0159         }
0160     }
0161 
0162     changed = changed || isSel != _isSelected;
0163     if (changed) {
0164         repaint();
0165     }
0166 
0167     return changed;
0168 }
0169 
0170 QRect MultiContainerWidget::selectionRect() const
0171 {
0172     if (_isSelected) {
0173         return QRect(mapToGlobal(QPoint(0, 0)), size());
0174     } else {
0175         QRect res;
0176         QList<RegExpWidget *>::const_iterator it = _children.constBegin();
0177         ++it; // Move past the first dragAccepter
0178         for (; it != _children.constEnd(); it += 2) {
0179             if ((*it)->hasSelection()) {
0180                 QRect childSel = (*it)->selectionRect();
0181                 if (res.isNull()) {
0182                     res = childSel;
0183                 } else {
0184                     QRect newRes;
0185                     newRes.setLeft(qMin(res.left(), childSel.left()));
0186                     newRes.setTop(qMin(res.top(), childSel.top()));
0187                     newRes.setRight(qMax(res.right(), childSel.right()));
0188                     newRes.setBottom(qMax(res.bottom(), childSel.bottom()));
0189                     res = newRes;
0190                 }
0191             }
0192         }
0193         return res;
0194     }
0195 }
0196 
0197 RegExpWidget *MultiContainerWidget::widgetUnderPoint(QPointF globalPos, bool justVisibleWidgets)
0198 {
0199     int start, incr;
0200     if (justVisibleWidgets) {
0201         start = 1;
0202         incr = 2;
0203     } else {
0204         start = 0;
0205         incr = 1;
0206     }
0207 
0208     for (int i = start; i < _children.count(); i += incr) {
0209         RegExpWidget *wid = _children.at(i)->widgetUnderPoint(globalPos, justVisibleWidgets);
0210         if (wid) {
0211             return wid;
0212         }
0213     }
0214 
0215     if (justVisibleWidgets) {
0216         return nullptr;
0217     } else {
0218         return RegExpWidget::widgetUnderPoint(globalPos, justVisibleWidgets);
0219     }
0220 }
0221 
0222 RegExpWidget *MultiContainerWidget::findWidgetToEdit(QPointF globalPos)
0223 {
0224     for (int i = 1; i < _children.count(); i += 2) {
0225         RegExpWidget *wid = _children.at(i)->findWidgetToEdit(globalPos);
0226         if (wid) {
0227             return wid;
0228         }
0229     }
0230     return nullptr;
0231 }
0232 
0233 void MultiContainerWidget::selectWidget(bool sel)
0234 {
0235     RegExpWidget::selectWidget(sel);
0236     QList<RegExpWidget *>::const_iterator it = _children.constBegin();
0237     for (; it != _children.constEnd(); ++it) {
0238         (*it)->selectWidget(sel);
0239     }
0240     update();
0241 }
0242 
0243 void MultiContainerWidget::updateAll()
0244 {
0245     QList<RegExpWidget *>::const_iterator it = _children.constBegin();
0246     for (; it != _children.constEnd(); ++it) {
0247         (*it)->updateAll();
0248     }
0249     RegExpWidget::updateAll();
0250 }
0251 
0252 void MultiContainerWidget::updateCursorRecursively()
0253 {
0254     QList<RegExpWidget *>::const_iterator it = _children.constBegin();
0255     for (; it != _children.constEnd(); ++it) {
0256         (*it)->updateCursorRecursively();
0257     }
0258     updateCursorShape();
0259 }