File indexing completed on 2024-05-05 05:45:47
0001 /* 0002 SPDX-FileCopyrightText: 2004-2005 Jeff Snyder <jeff-webcvsspam@caffeinated.me.uk> 0003 SPDX-FileCopyrightText: 2007-2011 Kevin Kofler <kevin.kofler@chello.at> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 // associated header 0009 #include "komparesplitter.h" 0010 0011 // qt 0012 #include <QStyle> 0013 #include <QString> 0014 #include <QTimer> 0015 #include <QScrollBar> 0016 #include <QMap> 0017 #include <QSplitter> 0018 #include <QApplication> 0019 #include <QPainter> 0020 #include <QPixmap> 0021 #include <QKeyEvent> 0022 #include <QGridLayout> 0023 #include <QResizeEvent> 0024 #include <QChildEvent> 0025 #include <QEvent> 0026 #include <QWheelEvent> 0027 0028 // kde 0029 0030 // kompare 0031 #include "komparelistview.h" 0032 #include "viewsettings.h" 0033 #include "kompareconnectwidget.h" 0034 #include <KompareDiff2/DiffModel> 0035 #include <KompareDiff2/Difference> 0036 0037 using namespace KompareDiff2; 0038 0039 KompareSplitter::KompareSplitter(ViewSettings* settings, QWidget* parent) : 0040 QSplitter(Qt::Horizontal, parent), 0041 m_settings(settings) 0042 { 0043 QFrame* scrollFrame = static_cast<QFrame*>(parent); 0044 0045 // Set up the scrollFrame 0046 scrollFrame->setFrameStyle(QFrame::NoFrame | QFrame::Plain); 0047 scrollFrame->setLineWidth(scrollFrame->style()->pixelMetric(QStyle::PM_DefaultFrameWidth)); 0048 QGridLayout* pairlayout = new QGridLayout(scrollFrame); 0049 pairlayout->setSpacing(0); 0050 pairlayout->setContentsMargins(0, 0, 0, 0); 0051 m_vScroll = new QScrollBar(Qt::Vertical, scrollFrame); 0052 pairlayout->addWidget(m_vScroll, 0, 1); 0053 m_hScroll = new QScrollBar(Qt::Horizontal, scrollFrame); 0054 pairlayout->addWidget(m_hScroll, 1, 0); 0055 0056 new KompareListViewFrame(true, m_settings, this, "source"); 0057 new KompareListViewFrame(false, m_settings, this, "destination"); 0058 pairlayout->addWidget(this, 0, 0); 0059 0060 // set up our looks 0061 setLineWidth(style()->pixelMetric(QStyle::PM_DefaultFrameWidth)); 0062 0063 setHandleWidth(50); 0064 setChildrenCollapsible(false); 0065 setFrameStyle(QFrame::NoFrame); 0066 setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored)); 0067 setOpaqueResize(true); 0068 setFocusPolicy(Qt::WheelFocus); 0069 0070 connect(this, &KompareSplitter::configChanged, this, &KompareSplitter::slotConfigChanged); 0071 connect(this, &KompareSplitter::configChanged, this, &KompareSplitter::slotDelayedRepaintHandles); 0072 connect(this, &KompareSplitter::configChanged, this, &KompareSplitter::slotDelayedUpdateScrollBars); 0073 0074 // scrolling 0075 connect(m_vScroll, &QScrollBar::valueChanged, this, &KompareSplitter::slotScrollToId); 0076 connect(m_vScroll, &QScrollBar::sliderMoved, this, &KompareSplitter::slotScrollToId); 0077 connect(m_hScroll, &QScrollBar::valueChanged, this, &KompareSplitter::setXOffset); 0078 connect(m_hScroll, &QScrollBar::sliderMoved, this, &KompareSplitter::setXOffset); 0079 0080 m_scrollTimer = new QTimer(this); 0081 m_restartTimer = false; 0082 connect(m_scrollTimer, &QTimer::timeout, this, &KompareSplitter::timerTimeout); 0083 0084 // we need to receive childEvents now so that d->list is ready for when 0085 // slotSetSelection(...) arrives 0086 qApp->sendPostedEvents(this, QEvent::ChildAdded); 0087 0088 // init stuff 0089 slotUpdateScrollBars(); 0090 } 0091 0092 KompareSplitter::~KompareSplitter() 0093 { 0094 } 0095 0096 QSplitterHandle* KompareSplitter::createHandle() 0097 { 0098 return new KompareConnectWidgetFrame(m_settings, this); 0099 } 0100 0101 void KompareSplitter::slotDelayedRepaintHandles() 0102 { 0103 QTimer::singleShot(0, this, &KompareSplitter::slotRepaintHandles); 0104 } 0105 0106 void KompareSplitter::slotRepaintHandles() 0107 { 0108 const int end = count(); 0109 for (int i = 1; i < end; ++i) 0110 handle(i)->update(); 0111 } 0112 0113 void KompareSplitter::timerTimeout() 0114 { 0115 if (m_restartTimer) 0116 m_restartTimer = false; 0117 else 0118 m_scrollTimer->stop(); 0119 0120 slotDelayedRepaintHandles(); 0121 0122 Q_EMIT scrollViewsToId(m_scrollTo); 0123 slotRepaintHandles(); 0124 m_vScroll->setValue(m_scrollTo); 0125 } 0126 0127 void KompareSplitter::slotScrollToId(int id) 0128 { 0129 m_scrollTo = id; 0130 0131 if (m_restartTimer) 0132 return; 0133 0134 if (m_scrollTimer->isActive()) 0135 { 0136 m_restartTimer = true; 0137 } 0138 else 0139 { 0140 Q_EMIT scrollViewsToId(id); 0141 slotRepaintHandles(); 0142 m_vScroll->setValue(id); 0143 m_scrollTimer->start(30); 0144 } 0145 } 0146 0147 void KompareSplitter::slotDelayedUpdateScrollBars() 0148 { 0149 QTimer::singleShot(0, this, &KompareSplitter::slotUpdateScrollBars); 0150 } 0151 0152 void KompareSplitter::slotUpdateScrollBars() 0153 { 0154 const int end = count(); 0155 for (int i = 0; i < end; ++i) { 0156 KompareListView* lv = listView(i); 0157 int minHScroll = minHScrollId(); 0158 if (lv->contentsX() < minHScroll) { 0159 lv->setXOffset(minHScroll); 0160 } 0161 } 0162 0163 int m_scrollDistance = m_settings->m_scrollNoOfLines * lineHeight(); 0164 int m_pageSize = pageSize(); 0165 0166 if (needVScrollBar()) 0167 { 0168 m_vScroll->show(); 0169 0170 m_vScroll->blockSignals(true); 0171 m_vScroll->setRange(minVScrollId(), 0172 maxVScrollId()); 0173 m_vScroll->setValue(scrollId()); 0174 m_vScroll->setSingleStep(m_scrollDistance); 0175 m_vScroll->setPageStep(m_pageSize); 0176 m_vScroll->blockSignals(false); 0177 } 0178 else 0179 { 0180 m_vScroll->hide(); 0181 } 0182 0183 if (needHScrollBar()) 0184 { 0185 m_hScroll->show(); 0186 m_hScroll->blockSignals(true); 0187 m_hScroll->setRange(minHScrollId(), maxHScrollId()); 0188 m_hScroll->setValue(maxContentsX()); 0189 m_hScroll->setSingleStep(10); 0190 m_hScroll->setPageStep(minVisibleWidth() - 10); 0191 m_hScroll->blockSignals(false); 0192 } 0193 else 0194 { 0195 m_hScroll->hide(); 0196 } 0197 } 0198 0199 void KompareSplitter::slotDelayedUpdateVScrollValue() 0200 { 0201 QTimer::singleShot(0, this, &KompareSplitter::slotUpdateVScrollValue); 0202 } 0203 0204 void KompareSplitter::slotUpdateVScrollValue() 0205 { 0206 m_vScroll->setValue(scrollId()); 0207 } 0208 0209 void KompareSplitter::keyPressEvent(QKeyEvent* e) 0210 { 0211 //keyboard scrolling 0212 switch (e->key()) { 0213 case Qt::Key_Right: 0214 case Qt::Key_L: 0215 m_hScroll->triggerAction(QAbstractSlider::SliderSingleStepAdd); 0216 break; 0217 case Qt::Key_Left: 0218 case Qt::Key_H: 0219 m_hScroll->triggerAction(QAbstractSlider::SliderSingleStepSub); 0220 break; 0221 case Qt::Key_Up: 0222 case Qt::Key_K: 0223 m_vScroll->triggerAction(QAbstractSlider::SliderSingleStepSub); 0224 break; 0225 case Qt::Key_Down: 0226 case Qt::Key_J: 0227 m_vScroll->triggerAction(QAbstractSlider::SliderSingleStepAdd); 0228 break; 0229 case Qt::Key_PageDown: 0230 m_vScroll->triggerAction(QAbstractSlider::SliderPageStepAdd); 0231 break; 0232 case Qt::Key_PageUp: 0233 m_vScroll->triggerAction(QAbstractSlider::SliderPageStepSub); 0234 break; 0235 } 0236 e->accept(); 0237 slotRepaintHandles(); 0238 } 0239 0240 void KompareSplitter::wheelEvent(QWheelEvent* e) 0241 { 0242 if (e->angleDelta().y() != 0) 0243 { 0244 if (e->modifiers() & Qt::ControlModifier) { 0245 if (e->angleDelta().y() < 0) // scroll down one page 0246 m_vScroll->triggerAction(QAbstractSlider::SliderPageStepAdd); 0247 else // scroll up one page 0248 m_vScroll->triggerAction(QAbstractSlider::SliderPageStepSub); 0249 } else { 0250 if (e->angleDelta().y() < 0) // scroll down 0251 m_vScroll->triggerAction(QAbstractSlider::SliderSingleStepAdd); 0252 else // scroll up 0253 m_vScroll->triggerAction(QAbstractSlider::SliderSingleStepSub); 0254 } 0255 } 0256 else 0257 { 0258 if (e->modifiers() & Qt::ControlModifier) { 0259 if (e->angleDelta().y() < 0) // scroll right one page 0260 m_hScroll->triggerAction(QAbstractSlider::SliderPageStepAdd); 0261 else // scroll left one page 0262 m_hScroll->triggerAction(QAbstractSlider::SliderPageStepSub); 0263 } else { 0264 if (e->angleDelta().y() < 0) // scroll to the right 0265 m_hScroll->triggerAction(QAbstractSlider::SliderSingleStepAdd); 0266 else // scroll to the left 0267 m_hScroll->triggerAction(QAbstractSlider::SliderSingleStepSub); 0268 } 0269 } 0270 e->accept(); 0271 slotDelayedRepaintHandles(); 0272 } 0273 0274 /* FIXME: this should return/the scrollId() from the listview containing the 0275 * /base/ of the diff. but there's bigger issues with that atm. 0276 */ 0277 0278 int KompareSplitter::scrollId() 0279 { 0280 if (widget(0)) 0281 return listView(0)->scrollId(); 0282 return minVScrollId(); 0283 } 0284 0285 int KompareSplitter::lineHeight() 0286 { 0287 if (widget(0)) 0288 return listView(0)->fontMetrics().height(); 0289 return 1; 0290 } 0291 0292 int KompareSplitter::pageSize() 0293 { 0294 if (widget(0)) { 0295 KompareListView* view = listView(0); 0296 return view->visibleHeight() - view->style()->pixelMetric(QStyle::PM_ScrollBarExtent); 0297 } 0298 return 1; 0299 } 0300 0301 bool KompareSplitter::needVScrollBar() 0302 { 0303 int pagesize = pageSize(); 0304 const int end = count(); 0305 for (int i = 0; i < end; ++i) { 0306 KompareListView* view = listView(i); 0307 if (view ->contentsHeight() > pagesize) 0308 return true; 0309 } 0310 return false; 0311 } 0312 0313 int KompareSplitter::minVScrollId() 0314 { 0315 0316 int min = -1; 0317 int mSId; 0318 const int end = count(); 0319 for (int i = 0; i < end; ++i) { 0320 mSId = listView(i)->minScrollId(); 0321 if (mSId < min || min == -1) 0322 min = mSId; 0323 } 0324 return (min == -1) ? 0 : min; 0325 } 0326 0327 int KompareSplitter::maxVScrollId() 0328 { 0329 int max = 0; 0330 int mSId; 0331 const int end = count(); 0332 for (int i = 0; i < end; ++i) { 0333 mSId = listView(i)->maxScrollId(); 0334 if (mSId > max) 0335 max = mSId; 0336 } 0337 return max; 0338 } 0339 0340 bool KompareSplitter::needHScrollBar() 0341 { 0342 const int end = count(); 0343 for (int i = 0; i < end; ++i) { 0344 KompareListView* view = listView(i); 0345 if (view->contentsWidth() > view->visibleWidth()) 0346 return true; 0347 } 0348 return false; 0349 } 0350 0351 int KompareSplitter::minHScrollId() 0352 { 0353 // hardcode an offset to hide the tree controls 0354 return 6; 0355 } 0356 0357 int KompareSplitter::maxHScrollId() 0358 { 0359 int max = 0; 0360 int mHSId; 0361 const int end = count(); 0362 for (int i = 0; i < end; ++i) { 0363 KompareListView* view = listView(i); 0364 mHSId = view->contentsWidth() - view->visibleWidth(); 0365 if (mHSId > max) 0366 max = mHSId; 0367 } 0368 return max; 0369 } 0370 0371 int KompareSplitter::maxContentsX() 0372 { 0373 int max = 0; 0374 int mCX; 0375 const int end = count(); 0376 for (int i = 0; i < end; ++i) { 0377 mCX = listView(i)->contentsX(); 0378 if (mCX > max) 0379 max = mCX; 0380 } 0381 return max; 0382 } 0383 0384 int KompareSplitter::minVisibleWidth() 0385 { 0386 // Why the hell do we want to know this? 0387 // ah yes, it is because we use it to set the "page size" for horiz. scrolling. 0388 // despite the fact that *none* has a pgright and pgleft key :P 0389 // But we do have mousewheels with horizontal scrolling functionality, 0390 // pressing shift and scrolling then goes left and right one page at the time 0391 int min = -1; 0392 int vW; 0393 const int end = count(); 0394 for (int i = 0; i < end; ++i) { 0395 vW = listView(i)->visibleWidth(); 0396 if (vW < min || min == -1) 0397 min = vW; 0398 } 0399 return (min == -1) ? 0 : min; 0400 } 0401 0402 KompareListView* KompareSplitter::listView(int index) 0403 { 0404 return static_cast<KompareListViewFrame*>(widget(index))->view(); 0405 } 0406 0407 KompareConnectWidget* KompareSplitter::connectWidget(int index) 0408 { 0409 return static_cast<KompareConnectWidgetFrame*>(handle(index))->wid(); 0410 } 0411 0412 void KompareSplitter::slotSetSelection(const DiffModel* model, const Difference* diff) 0413 { 0414 const int end = count(); 0415 for (int i = 0; i < end; ++i) { 0416 connectWidget(i)->slotSetSelection(model, diff); 0417 listView(i)->slotSetSelection(model, diff); 0418 static_cast<KompareListViewFrame*>(widget(i))->slotSetModel(model); 0419 } 0420 0421 slotDelayedRepaintHandles(); 0422 slotDelayedUpdateScrollBars(); 0423 } 0424 0425 void KompareSplitter::slotSetSelection(const Difference* diff) 0426 { 0427 const int end = count(); 0428 for (int i = 0; i < end; ++i) { 0429 connectWidget(i)->slotSetSelection(diff); 0430 listView(i)->slotSetSelection(diff); 0431 } 0432 0433 slotDelayedRepaintHandles(); 0434 slotDelayedUpdateScrollBars(); 0435 } 0436 0437 void KompareSplitter::slotApplyDifference(bool apply) 0438 { 0439 const int end = count(); 0440 for (int i = 0; i < end; ++i) 0441 listView(i)->slotApplyDifference(apply); 0442 slotDelayedRepaintHandles(); 0443 } 0444 0445 void KompareSplitter::slotApplyAllDifferences(bool apply) 0446 { 0447 const int end = count(); 0448 for (int i = 0; i < end; ++i) 0449 listView(i)->slotApplyAllDifferences(apply); 0450 slotDelayedRepaintHandles(); 0451 slotScrollToId(m_scrollTo); // FIXME! 0452 } 0453 0454 void KompareSplitter::slotApplyDifference(const Difference* diff, bool apply) 0455 { 0456 const int end = count(); 0457 for (int i = 0; i < end; ++i) 0458 listView(i)->slotApplyDifference(diff, apply); 0459 slotDelayedRepaintHandles(); 0460 } 0461 0462 void KompareSplitter::slotDifferenceClicked(const Difference* diff) 0463 { 0464 const int end = count(); 0465 for (int i = 0; i < end; ++i) 0466 listView(i)->setSelectedDifference(diff, false); 0467 Q_EMIT selectionChanged(diff); 0468 } 0469 0470 void KompareSplitter::slotConfigChanged() 0471 { 0472 const int end = count(); 0473 for (int i = 0; i < end; ++i) { 0474 KompareListView* view = listView(i); 0475 view->setFont(m_settings->m_font); 0476 view->update(); 0477 } 0478 } 0479 0480 #include "moc_komparesplitter.cpp"