File indexing completed on 2024-06-23 05:16:25
0001 /* 0002 SPDX-FileCopyrightText: 2010 Casey Link <unnamedrambler@gmail.com> 0003 SPDX-FileCopyrightText: 2009-2010 Klaralvdalens Datakonsult AB, a KDAB Group company <info@kdab.net> 0004 0005 Refactored from earlier code by: 0006 SPDX-FileCopyrightText: 2010 Volker Krause <vkrause@kde.org> 0007 SPDX-FileCopyrightText: 2004 Cornelius Schumacher <schumacher@kde.org> 0008 0009 SPDX-License-Identifier: LGPL-2.0-or-later 0010 */ 0011 #include "multiplyinglineview_p.h" 0012 0013 #include "libkdepim_debug.h" 0014 #include <KLocalizedString> 0015 #include <KMessageBox> 0016 0017 #include <QResizeEvent> 0018 #include <QScrollBar> 0019 #include <QTimer> 0020 #include <QVBoxLayout> 0021 0022 using namespace KPIM; 0023 0024 MultiplyingLineView::MultiplyingLineView(MultiplyingLineFactory *factory, MultiplyingLineEditor *parent) 0025 : QScrollArea(parent) 0026 , mPage(new QWidget(this)) 0027 , mTopLayout(new QVBoxLayout(this)) 0028 , mMultiplyingLineFactory(factory) 0029 { 0030 setWidgetResizable(true); 0031 setFrameStyle(QFrame::NoFrame); 0032 0033 mPage->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); 0034 setWidget(mPage); 0035 0036 mTopLayout->setContentsMargins(0, 0, 0, 0); 0037 mTopLayout->setSpacing(0); 0038 mPage->setLayout(mTopLayout); 0039 } 0040 0041 MultiplyingLine *MultiplyingLineView::activeLine() const 0042 { 0043 return mLines.last(); 0044 } 0045 0046 MultiplyingLine *MultiplyingLineView::emptyLine() const 0047 { 0048 for (MultiplyingLine *line : std::as_const(mLines)) { 0049 if (line->isEmpty()) { 0050 return line; 0051 } 0052 } 0053 return nullptr; 0054 } 0055 0056 MultiplyingLine *MultiplyingLineView::addLine(bool showDialogBox) 0057 { 0058 const int maximumRecipients = mMultiplyingLineFactory->maximumRecipients(); 0059 if (maximumRecipients != -1) { 0060 int numberOfLine = mLines.count(); 0061 if (numberOfLine++ >= maximumRecipients) { 0062 if (showDialogBox) { 0063 KMessageBox::error(this, i18n("We can not add more recipients. We have reached maximum recipients")); 0064 } 0065 0066 return nullptr; 0067 } 0068 } 0069 MultiplyingLine *line = mMultiplyingLineFactory->newLine(widget()); 0070 0071 mTopLayout->addWidget(line); 0072 line->setCompletionMode(mCompletionMode); 0073 line->show(); 0074 connect(line, &MultiplyingLine::returnPressed, this, &MultiplyingLineView::slotReturnPressed); 0075 connect(line, &MultiplyingLine::upPressed, this, &MultiplyingLineView::slotUpPressed); 0076 connect(line, &MultiplyingLine::downPressed, this, &MultiplyingLineView::slotDownPressed); 0077 connect(line, &MultiplyingLine::rightPressed, this, &MultiplyingLineView::focusRight); 0078 connect(line, &MultiplyingLine::deleteLine, this, &MultiplyingLineView::slotDecideLineDeletion); 0079 connect(line, &MultiplyingLine::completionModeChanged, this, &MultiplyingLineView::setCompletionMode); 0080 0081 if (!mLines.isEmpty()) { 0082 line->fixTabOrder(mLines.last()->tabOut()); 0083 } 0084 mLines.append(line); 0085 mFirstColumnWidth = line->setColumnWidth(mFirstColumnWidth); 0086 mLineHeight = line->minimumSizeHint().height(); 0087 line->resize(viewport()->width(), mLineHeight); 0088 resizeView(); 0089 ensureVisible(0, mLines.count() * mLineHeight, 0, 0); 0090 0091 QTimer::singleShot(0, this, &MultiplyingLineView::moveScrollBarToEnd); 0092 0093 Q_EMIT lineAdded(line); 0094 return line; 0095 } 0096 0097 void MultiplyingLineView::moveScrollBarToEnd() 0098 { 0099 // scroll to bottom 0100 verticalScrollBar()->triggerAction(QAbstractSlider::SliderToMaximum); 0101 } 0102 0103 void MultiplyingLineView::slotReturnPressed(MultiplyingLine *line) 0104 { 0105 if (!line->data()->isEmpty()) { 0106 MultiplyingLine *empty = emptyLine(); 0107 if (!empty) { 0108 empty = addLine(true); 0109 } 0110 if (!empty) { 0111 return; 0112 } 0113 activateLine(empty); 0114 } 0115 } 0116 0117 void MultiplyingLineView::slotDownPressed(MultiplyingLine *line) 0118 { 0119 const int pos = mLines.indexOf(line); 0120 if (pos >= (mLines.count() - 1)) { 0121 Q_EMIT focusDown(); 0122 } else if (pos >= 0) { 0123 activateLine(mLines.at(pos + 1)); 0124 } 0125 } 0126 0127 void MultiplyingLineView::slotUpPressed(MultiplyingLine *line) 0128 { 0129 const int pos = mLines.indexOf(line); 0130 if (pos > 0) { 0131 activateLine(mLines.at(pos - 1)); 0132 } else { 0133 Q_EMIT focusUp(); 0134 } 0135 } 0136 0137 void MultiplyingLineView::slotDecideLineDeletion(MultiplyingLine *line) 0138 { 0139 if (!line->isEmpty()) { 0140 mModified = true; 0141 } 0142 if (mLines.count() == 1) { 0143 line->clear(); 0144 } else if (!line->canDeleteLineEdit()) { 0145 line->clear(); 0146 } else if (mLines.indexOf(line) != mLines.count() - 1) { 0147 mCurDelLine = line; 0148 slotDeleteLine(); 0149 } 0150 } 0151 0152 void MultiplyingLineView::slotDeleteLine() 0153 { 0154 if (!mCurDelLine) { 0155 return; 0156 } 0157 0158 MultiplyingLine *line = mCurDelLine; 0159 line->aboutToBeDeleted(); 0160 const int pos = mLines.indexOf(line); 0161 0162 if (mCurDelLine->isActive()) { 0163 int newPos; 0164 if (pos == 0) { 0165 newPos = pos + 1; 0166 } else { 0167 newPos = pos - 1; 0168 } 0169 0170 // if there is something left to activate, do so 0171 if (mLines.at(newPos)) { 0172 mLines.at(newPos)->activate(); 0173 } 0174 } 0175 0176 mLines.removeAll(line); 0177 line->hide(); 0178 line->setParent(nullptr); 0179 line->deleteLater(); 0180 0181 if (pos > 0) { 0182 Q_EMIT lineDeleted(pos); 0183 } 0184 0185 resizeView(); 0186 } 0187 0188 void MultiplyingLineView::resizeView() 0189 { 0190 if (mDynamicSizeHint) { 0191 if (!mAutoResize) { 0192 if (mLines.count() < 6) { 0193 setMinimumHeight(mLineHeight * mLines.count()); 0194 } else { 0195 setMinimumHeight(mLineHeight * 5); 0196 setMaximumHeight(mLineHeight * mLines.count()); 0197 } 0198 } else { 0199 setMinimumHeight(mLineHeight * mLines.count()); 0200 } 0201 } 0202 0203 parentWidget()->layout()->activate(); 0204 Q_EMIT sizeHintChanged(); 0205 } 0206 0207 void MultiplyingLineView::activateLine(MultiplyingLine *line) 0208 { 0209 line->activate(); 0210 ensureWidgetVisible(line); 0211 } 0212 0213 void MultiplyingLineView::resizeEvent(QResizeEvent *ev) 0214 { 0215 QScrollArea::resizeEvent(ev); 0216 const int numberLine(mLines.count()); 0217 for (int i = 0; i < numberLine; ++i) { 0218 mLines.at(i)->resize(ev->size().width(), mLineHeight); 0219 } 0220 ensureVisible(0, numberLine * mLineHeight, 0, 0); 0221 } 0222 0223 QSize MultiplyingLineView::sizeHint() const 0224 { 0225 if (mDynamicSizeHint) { 0226 return {200, mLineHeight * static_cast<int>(mLines.count())}; 0227 } else { 0228 return QScrollArea::sizeHint(); 0229 } 0230 } 0231 0232 QSize MultiplyingLineView::minimumSizeHint() const 0233 { 0234 if (mDynamicSizeHint) { 0235 int height; 0236 int numLines = 5; 0237 if (mLines.count() < numLines) { 0238 height = mLineHeight * mLines.count(); 0239 } else { 0240 height = mLineHeight * numLines; 0241 } 0242 return {200, height}; 0243 } else { 0244 return QScrollArea::minimumSizeHint(); 0245 } 0246 } 0247 0248 QList<MultiplyingLineData::Ptr> MultiplyingLineView::allData() const 0249 { 0250 QList<MultiplyingLineData::Ptr> data; 0251 0252 QListIterator<MultiplyingLine *> it(mLines); 0253 while (it.hasNext()) { 0254 MultiplyingLine *line = it.next(); 0255 if (!line->data()->isEmpty()) { 0256 data.append(line->data()); 0257 } 0258 } 0259 0260 return data; 0261 } 0262 0263 void MultiplyingLineView::setCompletionMode(KCompletion::CompletionMode mode) 0264 { 0265 if (mCompletionMode == mode) { 0266 return; 0267 } 0268 mCompletionMode = mode; 0269 0270 QListIterator<MultiplyingLine *> it(mLines); 0271 while (it.hasNext()) { 0272 MultiplyingLine *line = it.next(); 0273 line->blockSignals(true); 0274 line->setCompletionMode(mode); 0275 line->blockSignals(false); 0276 } 0277 Q_EMIT completionModeChanged(mode); // report change to MultiplyingLineEditor 0278 } 0279 0280 void MultiplyingLineView::removeData(const MultiplyingLineData::Ptr &data) 0281 { 0282 // search a line which matches recipient and type 0283 QListIterator<MultiplyingLine *> it(mLines); 0284 MultiplyingLine *line = nullptr; 0285 while (it.hasNext()) { 0286 line = it.next(); 0287 if (line->data() == data) { 0288 break; 0289 } 0290 } 0291 if (line) { 0292 line->slotPropagateDeletion(); 0293 } 0294 } 0295 0296 bool MultiplyingLineView::isModified() const 0297 { 0298 if (mModified) { 0299 return true; 0300 } 0301 0302 QListIterator<MultiplyingLine *> it(mLines); 0303 MultiplyingLine *line = nullptr; 0304 while (it.hasNext()) { 0305 line = it.next(); 0306 if (line->isModified()) { 0307 return true; 0308 } 0309 } 0310 0311 return false; 0312 } 0313 0314 void MultiplyingLineView::clearModified() 0315 { 0316 mModified = false; 0317 0318 QListIterator<MultiplyingLine *> it(mLines); 0319 while (it.hasNext()) { 0320 MultiplyingLine *line = it.next(); 0321 line->clearModified(); 0322 } 0323 } 0324 0325 void MultiplyingLineView::setFocus() 0326 { 0327 if (!mLines.empty() && mLines.constLast()->isActive()) { 0328 setFocusBottom(); 0329 } else { 0330 setFocusTop(); 0331 } 0332 } 0333 0334 void MultiplyingLineView::setFocusTop() 0335 { 0336 if (!mLines.empty()) { 0337 MultiplyingLine *line = mLines.constFirst(); 0338 if (line) { 0339 line->activate(); 0340 } else { 0341 qCWarning(LIBKDEPIM_LOG) << "No first"; 0342 } 0343 } else { 0344 qCWarning(LIBKDEPIM_LOG) << "No first"; 0345 } 0346 } 0347 0348 void MultiplyingLineView::setFocusBottom() 0349 { 0350 if (!mLines.empty()) { 0351 MultiplyingLine *line = mLines.constLast(); 0352 if (line) { 0353 ensureWidgetVisible(line); 0354 line->activate(); 0355 } else { 0356 qCWarning(LIBKDEPIM_LOG) << "No last"; 0357 } 0358 } 0359 } 0360 0361 int MultiplyingLineView::setFirstColumnWidth(int w) 0362 { 0363 mFirstColumnWidth = w; 0364 0365 QListIterator<MultiplyingLine *> it(mLines); 0366 while (it.hasNext()) { 0367 MultiplyingLine *line = it.next(); 0368 mFirstColumnWidth = line->setColumnWidth(mFirstColumnWidth); 0369 } 0370 0371 resizeView(); 0372 return mFirstColumnWidth; 0373 } 0374 0375 QList<MultiplyingLine *> MultiplyingLineView::lines() const 0376 { 0377 return mLines; 0378 } 0379 0380 void MultiplyingLineView::setAutoResize(bool resize) 0381 { 0382 mAutoResize = resize; 0383 0384 if (mAutoResize) { 0385 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0386 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0387 setMaximumHeight(QWIDGETSIZE_MAX); 0388 } else { 0389 setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); 0390 setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); 0391 } 0392 } 0393 0394 bool MultiplyingLineView::autoResize() const 0395 { 0396 return mAutoResize; 0397 } 0398 0399 void MultiplyingLineView::setDynamicSizeHint(bool dynamic) 0400 { 0401 mDynamicSizeHint = dynamic; 0402 } 0403 0404 bool MultiplyingLineView::dynamicSizeHint() const 0405 { 0406 return mDynamicSizeHint; 0407 } 0408 0409 #include "moc_multiplyinglineview_p.cpp"