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 }