File indexing completed on 2024-05-05 10:04:25
0001 // clang-format off 0002 /* 0003 * This file is part of KDiff3. 0004 * 0005 * SPDX-FileCopyrightText: 2002-2011 Joachim Eibl, joachim.eibl at gmx.de 0006 * SPDX-FileCopyrightText: 2018-2020 Michael Reeves reeves.87@gmail.com 0007 * SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 // clang-format on 0010 0011 #include "compat.h" 0012 #include "defmac.h" 0013 #include "difftextwindow.h" 0014 #include "DirectoryInfo.h" 0015 #include "directorymergewindow.h" 0016 #include "fileaccess.h" 0017 #include "kdiff3.h" 0018 #include "kdiff3_shell.h" 0019 #include "Logging.h" 0020 #include "optiondialog.h" 0021 #include "progress.h" 0022 #include "Utils.h" 0023 0024 #include "mergeresultwindow.h" 0025 #include "smalldialogs.h" 0026 0027 #include <algorithm> 0028 #include <cstdio> 0029 #include <list> 0030 #include <typeinfo> 0031 0032 #include <QCheckBox> 0033 #include <QClipboard> 0034 #include <QComboBox> 0035 #include <QDialog> 0036 #include <QDir> 0037 #include <QDockWidget> 0038 #include <QEvent> // QKeyEvent, QDropEvent, QInputEvent 0039 #include <QFile> 0040 #include <QLayout> 0041 #include <QLineEdit> 0042 #include <QMimeData> 0043 #include <QPointer> 0044 #include <QProcess> 0045 #include <QScrollBar> 0046 #include <QSplitter> 0047 #include <QStatusBar> 0048 #include <QStringList> 0049 #include <QUrl> 0050 0051 #include <KLocalizedString> 0052 #include <KMessageBox> 0053 #include <KShortcutsDialog> 0054 0055 void KDiff3App::mainInit(TotalDiffStatus* pTotalDiffStatus, const InitFlags inFlags) 0056 { 0057 ProgressScope pp; 0058 mErrors.clear(); 0059 bool bLoadFiles = inFlags & InitFlag::loadFiles; 0060 bool bUseCurrentEncoding = inFlags & InitFlag::useCurrentEncoding; 0061 bool bAutoSolve = inFlags & InitFlag::autoSolve; 0062 0063 bool bGUI = (inFlags & InitFlag::initGUI); 0064 0065 IgnoreFlags eIgnoreFlags = IgnoreFlag::none; 0066 if(gOptions->ignoreComments()) 0067 eIgnoreFlags |= IgnoreFlag::ignoreComments; 0068 0069 if(gOptions->whiteSpaceIsEqual()) 0070 eIgnoreFlags |= IgnoreFlag::ignoreWhiteSpace; 0071 0072 assert(pTotalDiffStatus != nullptr); 0073 0074 bool bVisibleMergeResultWindow = !m_outputFilename.isEmpty(); 0075 0076 //Easier to do here then have all eleven of our call points do the check. 0077 if(m_sd1->isEmpty() && m_sd2->isEmpty() && m_sd3->isEmpty()) 0078 bLoadFiles = false; 0079 0080 if(bGUI) 0081 { 0082 if(bVisibleMergeResultWindow && !gOptions->m_PreProcessorCmd.isEmpty()) 0083 { 0084 QString msg = "- " + i18n("PreprocessorCmd: ") + gOptions->m_PreProcessorCmd + '\n'; 0085 KMessageBox::ButtonCode result = Compat::warningTwoActions(this, 0086 i18n("The following option(s) you selected might change data:\n") + msg + 0087 i18n("\nMost likely this is not wanted during a merge.\n" 0088 "Do you want to disable these settings or continue with these settings active?"), 0089 i18n("Option Unsafe for Merging"), 0090 KGuiItem(i18n("Use These Options During Merge")), 0091 KGuiItem(i18n("Disable Unsafe Options"))); 0092 0093 if(result == Compat::SecondaryAction) 0094 { 0095 gOptions->m_PreProcessorCmd = ""; 0096 } 0097 } 0098 0099 // Because of the progress dialog paint events can occur, but data is invalid, 0100 // so painting must be suppressed 0101 setLockPainting(true); 0102 } 0103 0104 //insure merge result window never has stale iterators/pointers. 0105 if(m_pMergeResultWindow) m_pMergeResultWindow->reset(); 0106 //Clear stale pointers in DiffTextWindow. 0107 if(m_pDiffTextWindow1) m_pDiffTextWindow1->reset(); 0108 if(m_pDiffTextWindow2) m_pDiffTextWindow2->reset(); 0109 if(m_pDiffTextWindow3) m_pDiffTextWindow3->reset(); 0110 m_diff3LineList.clear(); 0111 mDiff3LineVector.clear(); 0112 0113 if(bLoadFiles) 0114 { 0115 m_manualDiffHelpList.clear(); 0116 0117 if(m_sd3->isEmpty()) 0118 ProgressProxy::setMaxNofSteps(4); // Read 2 files, 1 comparison, 1 finediff 0119 else 0120 ProgressProxy::setMaxNofSteps(9); // Read 3 files, 3 comparisons, 3 finediffs 0121 0122 // First get all input data. 0123 ProgressProxy::setInformation(i18nc("Status message", "Loading A: %1", m_sd1->getFilename())); 0124 qCInfo(kdiffMain) << "Loading A: " << m_sd1->getFilename(); 0125 0126 if(bUseCurrentEncoding) 0127 m_sd1->readAndPreprocess(m_sd1->getEncoding(), false); 0128 else 0129 m_sd1->readAndPreprocess(gOptions->mEncodingA, gOptions->mAutoDetectA); 0130 0131 ProgressProxy::step(); 0132 0133 ProgressProxy::setInformation(i18nc("Status message", "Loading B: %1", m_sd2->getFilename())); 0134 qCInfo(kdiffMain) << "Loading B: " << m_sd2->getFilename(); 0135 0136 if(bUseCurrentEncoding) 0137 m_sd2->readAndPreprocess(m_sd2->getEncoding(), false); 0138 else 0139 m_sd2->readAndPreprocess(gOptions->mEncodingB, gOptions->mAutoDetectB); 0140 0141 ProgressProxy::step(); 0142 mErrors.append(m_sd1->getErrors()); 0143 mErrors.append(m_sd2->getErrors()); 0144 } 0145 else 0146 { 0147 if(m_sd3->isEmpty()) 0148 ProgressProxy::setMaxNofSteps(2); // 1 comparison, 1 finediff 0149 else 0150 ProgressProxy::setMaxNofSteps(6); // 3 comparisons, 3 finediffs 0151 } 0152 0153 pTotalDiffStatus->reset(); 0154 0155 if(mErrors.isEmpty()) 0156 { 0157 try 0158 { 0159 // Run the diff. 0160 if(m_sd3->isEmpty()) 0161 { 0162 pTotalDiffStatus->setBinaryEqualAB(m_sd1->isBinaryEqualWith(m_sd2)); 0163 0164 if(m_sd1->isText() && m_sd2->isText()) 0165 { 0166 ProgressProxy::setInformation(i18nc("Status message", "Diff: A <-> B")); 0167 qCInfo(kdiffMain) << "Diff: A <-> B"; 0168 m_manualDiffHelpList.runDiff(m_sd1->getLineDataForDiff(), m_sd1->getSizeLines(), m_sd2->getLineDataForDiff(), m_sd2->getSizeLines(), m_diffList12, e_SrcSelector::A, e_SrcSelector::B); 0169 0170 ProgressProxy::step(); 0171 0172 ProgressProxy::setInformation(i18nc("Status message", "Linediff: A <-> B")); 0173 qCInfo(kdiffMain) << "Linediff: A <-> B"; 0174 m_diff3LineList.calcDiff3LineListUsingAB(&m_diffList12); 0175 0176 pTotalDiffStatus->setTextEqualAB(m_diff3LineList.fineDiff(e_SrcSelector::A, m_sd1->getLineDataForDisplay(), m_sd2->getLineDataForDisplay(), eIgnoreFlags)); 0177 if(m_sd1->getSizeBytes() == 0) pTotalDiffStatus->setTextEqualAB(false); 0178 0179 ProgressProxy::step(); 0180 } 0181 else 0182 { 0183 ProgressProxy::step(); 0184 ProgressProxy::step(); 0185 } 0186 } 0187 else 0188 { 0189 if(bLoadFiles) 0190 { 0191 ProgressProxy::setInformation(i18nc("Status message", "Loading C: %1", m_sd3->getFilename())); 0192 qCInfo(kdiffMain) << "Loading C: " << m_sd3->getFilename(); 0193 0194 if(bUseCurrentEncoding) 0195 m_sd3->readAndPreprocess(m_sd3->getEncoding(), false); 0196 else 0197 m_sd3->readAndPreprocess(gOptions->mEncodingC, gOptions->mAutoDetectC); 0198 0199 ProgressProxy::step(); 0200 } 0201 0202 pTotalDiffStatus->setBinaryEqualAB(m_sd1->isBinaryEqualWith(m_sd2)); 0203 pTotalDiffStatus->setBinaryEqualAC(m_sd1->isBinaryEqualWith(m_sd3)); 0204 pTotalDiffStatus->setBinaryEqualBC(m_sd3->isBinaryEqualWith(m_sd2)); 0205 0206 ProgressProxy::setInformation(i18nc("Status message", "Diff: A <-> B")); 0207 qCInfo(kdiffMain) << "Diff: A <-> B"; 0208 0209 if(m_sd1->isText() && m_sd2->isText()) 0210 { 0211 m_manualDiffHelpList.runDiff(m_sd1->getLineDataForDiff(), m_sd1->getSizeLines(), m_sd2->getLineDataForDiff(), m_sd2->getSizeLines(), m_diffList12, e_SrcSelector::A, e_SrcSelector::B); 0212 0213 m_diff3LineList.calcDiff3LineListUsingAB(&m_diffList12); 0214 } 0215 ProgressProxy::step(); 0216 0217 ProgressProxy::setInformation(i18nc("Status message", "Diff: A <-> C")); 0218 qCInfo(kdiffMain) << "Diff: A <-> C"; 0219 0220 if(m_sd1->isText() && m_sd3->isText()) 0221 { 0222 m_manualDiffHelpList.runDiff(m_sd1->getLineDataForDiff(), m_sd1->getSizeLines(), m_sd3->getLineDataForDiff(), m_sd3->getSizeLines(), m_diffList13, e_SrcSelector::A, e_SrcSelector::C); 0223 0224 m_diff3LineList.calcDiff3LineListUsingAC(&m_diffList13); 0225 m_diff3LineList.correctManualDiffAlignment(&m_manualDiffHelpList); 0226 m_diff3LineList.calcDiff3LineListTrim(m_sd1->getLineDataForDiff(), m_sd2->getLineDataForDiff(), m_sd3->getLineDataForDiff(), &m_manualDiffHelpList); 0227 } 0228 ProgressProxy::step(); 0229 0230 ProgressProxy::setInformation(i18nc("Status message", "Diff: B <-> C")); 0231 qCInfo(kdiffMain) << "Diff: B <-> C"; 0232 0233 if(m_sd2->isText() && m_sd3->isText()) 0234 { 0235 m_manualDiffHelpList.runDiff(m_sd2->getLineDataForDiff(), m_sd2->getSizeLines(), m_sd3->getLineDataForDiff(), m_sd3->getSizeLines(), m_diffList23, e_SrcSelector::B, e_SrcSelector::C); 0236 if(gOptions->m_bDiff3AlignBC) 0237 { 0238 m_diff3LineList.calcDiff3LineListUsingBC(&m_diffList23); 0239 m_diff3LineList.correctManualDiffAlignment(&m_manualDiffHelpList); 0240 m_diff3LineList.calcDiff3LineListTrim(m_sd1->getLineDataForDiff(), m_sd2->getLineDataForDiff(), m_sd3->getLineDataForDiff(), &m_manualDiffHelpList); 0241 } 0242 } 0243 ProgressProxy::step(); 0244 0245 if(!gOptions->m_bDiff3AlignBC) 0246 { 0247 m_diff3LineList.debugLineCheck(m_sd1->getSizeLines(), e_SrcSelector::A); 0248 m_diff3LineList.debugLineCheck(m_sd2->getSizeLines(), e_SrcSelector::B); 0249 m_diff3LineList.debugLineCheck(m_sd3->getSizeLines(), e_SrcSelector::C); 0250 } 0251 0252 ProgressProxy::setInformation(i18nc("Status message", "Linediff: A <-> B")); 0253 qCInfo(kdiffMain) << "Linediff: A <-> B"; 0254 if(m_sd1->hasData() && m_sd2->hasData() && m_sd1->isText() && m_sd2->isText()) 0255 pTotalDiffStatus->setTextEqualAB(m_diff3LineList.fineDiff(e_SrcSelector::A, m_sd1->getLineDataForDisplay(), m_sd2->getLineDataForDisplay(), eIgnoreFlags)); 0256 ProgressProxy::step(); 0257 0258 ProgressProxy::setInformation(i18nc("Status message", "Linediff: B <-> C")); 0259 qCInfo(kdiffMain) << "Linediff: B <-> C"; 0260 if(m_sd2->hasData() && m_sd3->hasData() && m_sd2->isText() && m_sd3->isText()) 0261 pTotalDiffStatus->setTextEqualBC(m_diff3LineList.fineDiff(e_SrcSelector::B, m_sd2->getLineDataForDisplay(), m_sd3->getLineDataForDisplay(), eIgnoreFlags)); 0262 ProgressProxy::step(); 0263 0264 ProgressProxy::setInformation(i18nc("Status message", "Linediff: A <-> C")); 0265 qCInfo(kdiffMain) << "Linediff: A <-> C"; 0266 if(m_sd1->hasData() && m_sd3->hasData() && m_sd1->isText() && m_sd3->isText()) 0267 pTotalDiffStatus->setTextEqualAC(m_diff3LineList.fineDiff(e_SrcSelector::C, m_sd3->getLineDataForDisplay(), m_sd1->getLineDataForDisplay(), eIgnoreFlags)); 0268 0269 if(!gOptions->m_bDiff3AlignBC) 0270 { 0271 m_diff3LineList.debugLineCheck(m_sd2->getSizeLines(), e_SrcSelector::B); 0272 m_diff3LineList.debugLineCheck(m_sd3->getSizeLines(), e_SrcSelector::C); 0273 } 0274 0275 ProgressProxy::setInformation(i18nc("Status message", "Linediff: A <-> B")); 0276 if(m_sd1->hasData() && m_sd2->hasData() && m_sd1->isText() && m_sd2->isText()) 0277 pTotalDiffStatus->setTextEqualAB(m_diff3LineList.fineDiff(e_SrcSelector::A, m_sd1->getLineDataForDisplay(), m_sd2->getLineDataForDisplay(), eIgnoreFlags)); 0278 ProgressProxy::step(); 0279 0280 ProgressProxy::setInformation(i18nc("Status message", "Linediff: B <-> C")); 0281 if(m_sd3->hasData() && m_sd2->hasData() && m_sd3->isText() && m_sd2->isText()) 0282 pTotalDiffStatus->setTextEqualBC(m_diff3LineList.fineDiff(e_SrcSelector::B, m_sd2->getLineDataForDisplay(), m_sd3->getLineDataForDisplay(), eIgnoreFlags)); 0283 ProgressProxy::step(); 0284 0285 ProgressProxy::setInformation(i18nc("Status message", "Linediff: A <-> C")); 0286 if(m_sd1->hasData() && m_sd3->hasData() && m_sd1->isText() && m_sd3->isText()) 0287 pTotalDiffStatus->setTextEqualAC(m_diff3LineList.fineDiff(e_SrcSelector::C, m_sd3->getLineDataForDisplay(), m_sd1->getLineDataForDisplay(), eIgnoreFlags)); 0288 ProgressProxy::step(); 0289 if(m_sd1->getSizeBytes() == 0) 0290 { 0291 pTotalDiffStatus->setTextEqualAB(false); 0292 pTotalDiffStatus->setTextEqualAC(false); 0293 } 0294 if(m_sd2->getSizeBytes() == 0) 0295 { 0296 pTotalDiffStatus->setTextEqualAB(false); 0297 pTotalDiffStatus->setTextEqualBC(false); 0298 } 0299 0300 mErrors.append(m_sd3->getErrors()); 0301 } 0302 } 0303 catch(const std::bad_alloc&) 0304 { 0305 m_manualDiffHelpList.clear(); 0306 m_diff3LineList.clear(); 0307 mDiff3LineVector.clear(); 0308 m_sd1->reset(); 0309 m_sd2->reset(); 0310 m_sd3->reset(); 0311 mErrors.append(i18nc("Error message", "Not enough memory to complete request.")); 0312 ProgressProxy::clear(); 0313 } 0314 catch(const std::exception& e) 0315 { 0316 qCCritical(kdiffMain) << "An internal error occurred:" << e.what(); 0317 0318 mErrors.append(i18n("An internal error occurred: %1", QString::fromStdString(e.what()))); 0319 ProgressProxy::clear(); 0320 } 0321 } 0322 else 0323 { 0324 ProgressProxy::clear(); 0325 } 0326 0327 if(mErrors.isEmpty() && m_sd1->isText() && m_sd2->isText()) 0328 { 0329 Diff3Line::m_pDiffBufferInfo->init(&m_diff3LineList, 0330 m_sd1->getLineDataForDiff(), 0331 m_sd2->getLineDataForDiff(), 0332 m_sd3->getLineDataForDiff()); 0333 0334 m_diff3LineList.calcWhiteDiff3Lines(m_sd1->getLineDataForDiff(), m_sd2->getLineDataForDiff(), m_sd3->getLineDataForDiff(), gOptions->ignoreComments()); 0335 m_diff3LineList.calcDiff3LineVector(mDiff3LineVector); 0336 } 0337 0338 // Calc needed lines for display 0339 try 0340 { 0341 m_neededLines = SafeInt<LineType>(m_diff3LineList.size()); 0342 } 0343 catch(std::exception&) 0344 { 0345 mErrors.append(i18n("Too many lines in diff. Skipping file.")); 0346 } 0347 0348 m_pMergeResultWindow->connectActions(); 0349 0350 m_pMainWidget->setVisible(bGUI); //sets off multiple resize events internally. 0351 0352 m_bTripleDiff = !m_sd3->isEmpty(); 0353 0354 m_pMergeResultWindowTitle->setEncodings(m_sd1->getEncoding(), m_sd2->getEncoding(), m_sd3->getEncoding()); 0355 if(!gOptions->m_bAutoSelectOutEncoding) 0356 m_pMergeResultWindowTitle->setEncoding(gOptions->mEncodingOut); 0357 0358 m_pMergeResultWindowTitle->setLineEndStyles(m_sd1->getLineEndStyle(), m_sd2->getLineEndStyle(), m_sd3->getLineEndStyle()); 0359 0360 if(bGUI) 0361 { 0362 const ManualDiffHelpList* pMDHL = &m_manualDiffHelpList; 0363 m_pDiffTextWindow1->init(m_sd1->getAliasName(), m_sd1->getEncoding(), m_sd1->getLineEndStyle(), 0364 m_sd1->getLineDataForDisplay(), m_sd1->getSizeLines(), &mDiff3LineVector, pMDHL); 0365 m_pDiffTextWindowFrame1->init(); 0366 0367 m_pDiffTextWindow2->init(m_sd2->getAliasName(), m_sd2->getEncoding(), m_sd2->getLineEndStyle(), 0368 m_sd2->getLineDataForDisplay(), m_sd2->getSizeLines(), &mDiff3LineVector, pMDHL); 0369 m_pDiffTextWindowFrame2->init(); 0370 0371 m_pDiffTextWindow3->init(m_sd3->getAliasName(), m_sd3->getEncoding(), m_sd3->getLineEndStyle(), 0372 m_sd3->getLineDataForDisplay(), m_sd3->getSizeLines(), &mDiff3LineVector, pMDHL); 0373 m_pDiffTextWindowFrame3->init(); 0374 0375 m_pDiffTextWindowFrame3->setVisible(m_bTripleDiff); 0376 } 0377 0378 m_bOutputModified = bVisibleMergeResultWindow; 0379 0380 m_pMergeResultWindow->init( 0381 m_sd1->getLineDataForDisplay(), m_sd1->getSizeLines(), 0382 m_sd2->getLineDataForDisplay(), m_sd2->getSizeLines(), 0383 m_bTripleDiff ? m_sd3->getLineDataForDisplay() : nullptr, m_sd3->getSizeLines(), 0384 &m_diff3LineList, 0385 pTotalDiffStatus, bAutoSolve); 0386 m_pMergeResultWindowTitle->setFileName(m_outputFilename.isEmpty() ? QString("unnamed.txt") : m_outputFilename); 0387 0388 if(bGUI) 0389 { 0390 m_pOverview->init(&m_diff3LineList); 0391 DiffTextWindow::mVScrollBar->setValue(0); 0392 m_pHScrollBar->setValue(0); 0393 MergeResultWindow::mVScrollBar->setValue(0); 0394 setLockPainting(false); 0395 0396 if(!bVisibleMergeResultWindow) 0397 m_pMergeWindowFrame->hide(); 0398 else 0399 m_pMergeWindowFrame->show(); 0400 0401 // Try to create a meaningful but not too long caption 0402 if(mErrors.isEmpty()) 0403 { 0404 createCaption(); 0405 } 0406 m_bFinishMainInit = true; // call slotFinishMainInit after finishing the word wrap 0407 m_bLoadFiles = bLoadFiles; 0408 postRecalcWordWrap(); 0409 } 0410 } 0411 0412 void KDiff3App::setLockPainting(bool bLock) 0413 { 0414 if(m_pDiffTextWindow1) m_pDiffTextWindow1->setPaintingAllowed(!bLock); 0415 if(m_pDiffTextWindow2) m_pDiffTextWindow2->setPaintingAllowed(!bLock); 0416 if(m_pDiffTextWindow3) m_pDiffTextWindow3->setPaintingAllowed(!bLock); 0417 if(m_pOverview) m_pOverview->setPaintingAllowed(!bLock); 0418 if(m_pMergeResultWindow) m_pMergeResultWindow->setPaintingAllowed(!bLock); 0419 } 0420 0421 void KDiff3App::createCaption() 0422 { 0423 // Try to create a meaningful but not too long caption 0424 // 1. If the filenames are equal then show only one filename 0425 QString caption; 0426 QString f1 = m_sd1->getAliasName(); 0427 QString f2 = m_sd2->getAliasName(); 0428 QString f3 = m_sd3->getAliasName(); 0429 QtSizeType p; 0430 0431 if((p = f1.lastIndexOf('/')) >= 0 || (p = f1.lastIndexOf('\\')) >= 0) 0432 f1 = f1.mid(p + 1); 0433 if((p = f2.lastIndexOf('/')) >= 0 || (p = f2.lastIndexOf('\\')) >= 0) 0434 f2 = f2.mid(p + 1); 0435 if((p = f3.lastIndexOf('/')) >= 0 || (p = f3.lastIndexOf('\\')) >= 0) 0436 f3 = f3.mid(p + 1); 0437 0438 if(!f1.isEmpty()) 0439 { 0440 if((f2.isEmpty() && f3.isEmpty()) || 0441 (f2.isEmpty() && f1 == f3) || (f3.isEmpty() && f1 == f2) || (f1 == f2 && f1 == f3)) 0442 caption = f1; 0443 } 0444 else if(!f2.isEmpty()) 0445 { 0446 if(f3.isEmpty() || f2 == f3) 0447 caption = f2; 0448 } 0449 else if(!f3.isEmpty()) 0450 caption = f3; 0451 0452 // 2. If the files don't have the same name then show all names 0453 if(caption.isEmpty() && (!f1.isEmpty() || !f2.isEmpty() || !f3.isEmpty())) 0454 { 0455 caption = (f1.isEmpty() ? QString("") : f1); 0456 caption += QLatin1String(caption.isEmpty() || f2.isEmpty() ? "" : " <-> ") + (f2.isEmpty() ? QString("") : f2); 0457 caption += QLatin1String(caption.isEmpty() || f3.isEmpty() ? "" : " <-> ") + (f3.isEmpty() ? QString("") : f3); 0458 } 0459 0460 m_pKDiff3Shell->setWindowTitle(caption.isEmpty() ? QString("KDiff3") : caption + QString(" - KDiff3")); 0461 } 0462 0463 void KDiff3App::setHScrollBarRange() 0464 { 0465 qint32 w1 = m_pDiffTextWindow1 != nullptr && m_pDiffTextWindow1->isVisible() ? m_pDiffTextWindow1->getMaxTextWidth() : 0; 0466 qint32 w2 = m_pDiffTextWindow2 != nullptr && m_pDiffTextWindow2->isVisible() ? m_pDiffTextWindow2->getMaxTextWidth() : 0; 0467 qint32 w3 = m_pDiffTextWindow3 != nullptr && m_pDiffTextWindow3->isVisible() ? m_pDiffTextWindow3->getMaxTextWidth() : 0; 0468 0469 qint32 wm = m_pMergeResultWindow != nullptr && m_pMergeResultWindow->isVisible() ? m_pMergeResultWindow->getMaxTextWidth() : 0; 0470 0471 qint32 v1 = m_pDiffTextWindow1 != nullptr && m_pDiffTextWindow1->isVisible() ? m_pDiffTextWindow1->getVisibleTextAreaWidth() : 0; 0472 qint32 v2 = m_pDiffTextWindow2 != nullptr && m_pDiffTextWindow2->isVisible() ? m_pDiffTextWindow2->getVisibleTextAreaWidth() : 0; 0473 qint32 v3 = m_pDiffTextWindow3 != nullptr && m_pDiffTextWindow3->isVisible() ? m_pDiffTextWindow3->getVisibleTextAreaWidth() : 0; 0474 qint32 vm = m_pMergeResultWindow != nullptr && m_pMergeResultWindow->isVisible() ? m_pMergeResultWindow->getVisibleTextAreaWidth() : 0; 0475 0476 // Find the minimum, but don't consider 0. 0477 qint32 pageStep = v1; 0478 0479 if((pageStep == 0 || pageStep > v2) && v2 > 0) 0480 pageStep = v2; 0481 if((pageStep == 0 || pageStep > v3) && v3 > 0) 0482 pageStep = v3; 0483 if((pageStep == 0 || pageStep > vm) && vm > 0) 0484 pageStep = vm; 0485 0486 qint32 rangeMax = 0; 0487 if(w1 > v1 && w1 - v1 > rangeMax && v1 > 0) 0488 rangeMax = w1 - v1; 0489 if(w2 > v2 && w2 - v2 > rangeMax && v2 > 0) 0490 rangeMax = w2 - v2; 0491 if(w3 > v3 && w3 - v3 > rangeMax && v3 > 0) 0492 rangeMax = w3 - v3; 0493 if(wm > vm && wm - vm > rangeMax && vm > 0) 0494 rangeMax = wm - vm; 0495 0496 m_pHScrollBar->setRange(0, rangeMax); 0497 m_pHScrollBar->setSingleStep(fontMetrics().horizontalAdvance('0') * 10); 0498 m_pHScrollBar->setPageStep(pageStep); 0499 } 0500 0501 void KDiff3App::resizeDiffTextWindowHeight(qint32 newHeight) 0502 { 0503 m_DTWHeight = newHeight; 0504 0505 DiffTextWindow::mVScrollBar->setRange(0, std::max(0, m_neededLines + 1 - newHeight)); 0506 DiffTextWindow::mVScrollBar->setPageStep(newHeight); 0507 m_pOverview->setRange(DiffTextWindow::mVScrollBar->value(), DiffTextWindow::mVScrollBar->pageStep()); 0508 0509 setHScrollBarRange(); 0510 } 0511 0512 void KDiff3App::scrollDiffTextWindow(qint32 deltaX, qint32 deltaY) 0513 { 0514 if(deltaY != 0 && DiffTextWindow::mVScrollBar != nullptr) 0515 { 0516 DiffTextWindow::mVScrollBar->setValue(DiffTextWindow::mVScrollBar->value() + deltaY); 0517 } 0518 if(deltaX != 0 && m_pHScrollBar != nullptr) 0519 m_pHScrollBar->QScrollBar::setValue(m_pHScrollBar->value() + deltaX); 0520 } 0521 0522 void KDiff3App::scrollMergeResultWindow(qint32 deltaX, qint32 deltaY) 0523 { 0524 if(deltaY != 0) 0525 MergeResultWindow::mVScrollBar->setValue(MergeResultWindow::mVScrollBar->value() + deltaY); 0526 if(deltaX != 0) 0527 m_pHScrollBar->setValue(m_pHScrollBar->value() + deltaX); 0528 } 0529 0530 void KDiff3App::sourceMask(qint32 srcMask, qint32 enabledMask) 0531 { 0532 chooseA->blockSignals(true); 0533 chooseB->blockSignals(true); 0534 chooseC->blockSignals(true); 0535 chooseA->setChecked((srcMask & 1) != 0); 0536 chooseB->setChecked((srcMask & 2) != 0); 0537 chooseC->setChecked((srcMask & 4) != 0); 0538 chooseA->blockSignals(false); 0539 chooseB->blockSignals(false); 0540 chooseC->blockSignals(false); 0541 chooseA->setEnabled((enabledMask & 1) != 0); 0542 chooseB->setEnabled((enabledMask & 2) != 0); 0543 chooseC->setEnabled((enabledMask & 4) != 0); 0544 } 0545 0546 void KDiff3App::initView() 0547 { 0548 // set the main widget here 0549 if(mInitCalled) 0550 { 0551 return; 0552 } 0553 0554 mInitCalled = true; 0555 //m_pMainWidget // Contains vertical splitter and horiz scrollbar 0556 QVBoxLayout* pVLayout = new QVBoxLayout(m_pMainWidget); 0557 pVLayout->setContentsMargins(0, 0, 0, 0); 0558 pVLayout->setSpacing(0); 0559 0560 QSplitter* pVSplitter = new QSplitter(); 0561 pVSplitter->setObjectName("VSplitter"); 0562 pVSplitter->setOpaqueResize(false); 0563 pVSplitter->setOrientation(Qt::Vertical); 0564 pVLayout->addWidget(pVSplitter); 0565 0566 QWidget* pDiffWindowFrame = new QWidget(); // Contains diff windows, overview and vert scrollbar 0567 pDiffWindowFrame->setObjectName("DiffWindowFrame"); 0568 QHBoxLayout* pDiffHLayout = new QHBoxLayout(pDiffWindowFrame); 0569 pDiffHLayout->setContentsMargins(0, 0, 0, 0); 0570 pDiffHLayout->setSpacing(0); 0571 pVSplitter->addWidget(pDiffWindowFrame); 0572 0573 m_pDiffWindowSplitter = new QSplitter(); 0574 m_pDiffWindowSplitter->setObjectName("DiffWindowSplitter"); 0575 m_pDiffWindowSplitter->setOpaqueResize(false); 0576 0577 m_pDiffWindowSplitter->setOrientation(gOptions->m_bHorizDiffWindowSplitting ? Qt::Horizontal : Qt::Vertical); 0578 pDiffHLayout->addWidget(m_pDiffWindowSplitter); 0579 0580 m_pOverview = new Overview(); 0581 m_pOverview->setObjectName("Overview"); 0582 pDiffHLayout->addWidget(m_pOverview); 0583 0584 DiffTextWindow::mVScrollBar = new QScrollBar(Qt::Vertical, pDiffWindowFrame); 0585 pDiffHLayout->addWidget(DiffTextWindow::mVScrollBar); 0586 0587 chk_connect_a(m_pOverview, &Overview::setLine, DiffTextWindow::mVScrollBar, &QScrollBar::setValue); 0588 chk_connect_a(this, &KDiff3App::showWhiteSpaceToggled, m_pOverview, &Overview::slotRedraw); 0589 chk_connect_a(this, &KDiff3App::changeOverViewMode, m_pOverview, &Overview::setOverviewMode); 0590 0591 m_pDiffTextWindowFrame1 = new DiffTextWindowFrame(m_pDiffWindowSplitter, e_SrcSelector::A, m_sd1, *this); 0592 m_pDiffWindowSplitter->addWidget(m_pDiffTextWindowFrame1); 0593 m_pDiffTextWindowFrame2 = new DiffTextWindowFrame(m_pDiffWindowSplitter, e_SrcSelector::B, m_sd2, *this); 0594 m_pDiffWindowSplitter->addWidget(m_pDiffTextWindowFrame2); 0595 m_pDiffTextWindowFrame3 = new DiffTextWindowFrame(m_pDiffWindowSplitter, e_SrcSelector::C, m_sd3, *this); 0596 m_pDiffWindowSplitter->addWidget(m_pDiffTextWindowFrame3); 0597 m_pDiffTextWindow1 = m_pDiffTextWindowFrame1->getDiffTextWindow(); 0598 m_pDiffTextWindow2 = m_pDiffTextWindowFrame2->getDiffTextWindow(); 0599 m_pDiffTextWindow3 = m_pDiffTextWindowFrame3->getDiffTextWindow(); 0600 0601 m_pDiffTextWindowFrame1->setupConnections(this); 0602 m_pDiffTextWindowFrame2->setupConnections(this); 0603 m_pDiffTextWindowFrame3->setupConnections(this); 0604 0605 // Merge window 0606 m_pMergeWindowFrame = new QWidget(pVSplitter); 0607 m_pMergeWindowFrame->setObjectName("MergeWindowFrame"); 0608 pVSplitter->addWidget(m_pMergeWindowFrame); 0609 QHBoxLayout* pMergeHLayout = new QHBoxLayout(m_pMergeWindowFrame); 0610 pMergeHLayout->setContentsMargins(0, 0, 0, 0); 0611 pMergeHLayout->setSpacing(0); 0612 QVBoxLayout* pMergeVLayout = new QVBoxLayout(); 0613 pMergeHLayout->addLayout(pMergeVLayout, 1); 0614 0615 m_pMergeResultWindowTitle = new WindowTitleWidget(); 0616 pMergeVLayout->addWidget(m_pMergeResultWindowTitle); 0617 0618 m_pMergeResultWindow = new MergeResultWindow(m_pMergeWindowFrame, statusBar()); 0619 pMergeVLayout->addWidget(m_pMergeResultWindow, 1); 0620 0621 MergeResultWindow::mVScrollBar = new QScrollBar(Qt::Vertical, m_pMergeWindowFrame); 0622 pMergeHLayout->addWidget(MergeResultWindow::mVScrollBar); 0623 0624 autoAdvance->setEnabled(true); 0625 0626 QList<qint32> sizes = pVSplitter->sizes(); 0627 qint32 total = sizes[0] + sizes[1]; 0628 if(total < 10) 0629 total = 100; 0630 sizes[0] = total / 2; 0631 sizes[1] = total / 2; 0632 pVSplitter->setSizes(sizes); 0633 0634 QList<qint32> hSizes = {1, 1, 1}; 0635 0636 m_pDiffWindowSplitter->setSizes(hSizes); 0637 0638 m_pMergeResultWindow->installEventFilter(m_pMergeResultWindowTitle); // for focus tracking 0639 0640 QHBoxLayout* pHScrollBarLayout = new QHBoxLayout(); 0641 pVLayout->addLayout(pHScrollBarLayout); 0642 m_pHScrollBar = new ReversibleScrollBar(Qt::Horizontal, &gOptions->m_bRightToLeftLanguage); 0643 pHScrollBarLayout->addWidget(m_pHScrollBar); 0644 m_pCornerWidget = new QWidget(m_pMainWidget); 0645 pHScrollBarLayout->addWidget(m_pCornerWidget); 0646 0647 chk_connect_a(DiffTextWindow::mVScrollBar, &QScrollBar::valueChanged, m_pOverview, &Overview::setFirstLine); 0648 chk_connect_a(DiffTextWindow::mVScrollBar, &QScrollBar::valueChanged, m_pDiffTextWindow1, &DiffTextWindow::setFirstLine); 0649 chk_connect_a(m_pHScrollBar, &ReversibleScrollBar::valueChanged2, m_pDiffTextWindow1, &DiffTextWindow::setHorizScrollOffset); 0650 m_pDiffTextWindow1->setupConnections(this); 0651 0652 chk_connect_a(DiffTextWindow::mVScrollBar, &QScrollBar::valueChanged, m_pDiffTextWindow2, &DiffTextWindow::setFirstLine); 0653 chk_connect_a(m_pHScrollBar, &ReversibleScrollBar::valueChanged2, m_pDiffTextWindow2, &DiffTextWindow::setHorizScrollOffset); 0654 m_pDiffTextWindow2->setupConnections(this); 0655 0656 chk_connect_a(DiffTextWindow::mVScrollBar, &QScrollBar::valueChanged, m_pDiffTextWindow3, &DiffTextWindow::setFirstLine); 0657 chk_connect_a(m_pHScrollBar, &ReversibleScrollBar::valueChanged2, m_pDiffTextWindow3, &DiffTextWindow::setHorizScrollOffset); 0658 m_pDiffTextWindow3->setupConnections(this); 0659 0660 MergeResultWindow* p = m_pMergeResultWindow; 0661 chk_connect_a(MergeResultWindow::mVScrollBar, &QScrollBar::valueChanged, p, &MergeResultWindow::setFirstLine); 0662 0663 chk_connect_a(m_pHScrollBar, &ReversibleScrollBar::valueChanged2, p, &MergeResultWindow::setHorizScrollOffset); 0664 chk_connect_a(p, &MergeResultWindow::modifiedChanged, m_pMergeResultWindowTitle, &WindowTitleWidget::slotSetModified); 0665 p->setupConnections(this); 0666 sourceMask(0, 0); 0667 0668 chk_connect_a(p, &MergeResultWindow::setFastSelectorRange, m_pDiffTextWindow1, &DiffTextWindow::setFastSelectorRange); 0669 chk_connect_a(p, &MergeResultWindow::setFastSelectorRange, m_pDiffTextWindow2, &DiffTextWindow::setFastSelectorRange); 0670 chk_connect_a(p, &MergeResultWindow::setFastSelectorRange, m_pDiffTextWindow3, &DiffTextWindow::setFastSelectorRange); 0671 chk_connect_a(m_pDiffTextWindow1, &DiffTextWindow::setFastSelectorLine, p, &MergeResultWindow::slotSetFastSelectorLine); 0672 chk_connect_a(m_pDiffTextWindow2, &DiffTextWindow::setFastSelectorLine, p, &MergeResultWindow::slotSetFastSelectorLine); 0673 chk_connect_a(m_pDiffTextWindow3, &DiffTextWindow::setFastSelectorLine, p, &MergeResultWindow::slotSetFastSelectorLine); 0674 chk_connect_a(m_pDiffTextWindow1, &DiffTextWindow::gotFocus, p, &MergeResultWindow::updateSourceMask); 0675 chk_connect_a(m_pDiffTextWindow2, &DiffTextWindow::gotFocus, p, &MergeResultWindow::updateSourceMask); 0676 chk_connect_a(m_pDiffTextWindow3, &DiffTextWindow::gotFocus, p, &MergeResultWindow::updateSourceMask); 0677 chk_connect_a(m_pDirectoryMergeInfo, &DirectoryMergeInfo::gotFocus, p, &MergeResultWindow::updateSourceMask); 0678 0679 chk_connect_a(m_pDiffTextWindow1, &DiffTextWindow::resizeHeightChangedSignal, this, &KDiff3App::resizeDiffTextWindowHeight); 0680 // The following connects cause the wordwrap to be recalced thrice, just to make sure. Better than forgetting one. 0681 chk_connect_a(m_pDiffTextWindow1, &DiffTextWindow::resizeWidthChangedSignal, this, &KDiff3App::postRecalcWordWrap); 0682 chk_connect_a(m_pDiffTextWindow2, &DiffTextWindow::resizeWidthChangedSignal, this, &KDiff3App::postRecalcWordWrap); 0683 chk_connect_a(m_pDiffTextWindow3, &DiffTextWindow::resizeWidthChangedSignal, this, &KDiff3App::postRecalcWordWrap); 0684 0685 m_pDiffTextWindow1->setFocus(); 0686 m_pMainWidget->setMinimumSize(50, 50); 0687 m_pCornerWidget->setFixedSize(DiffTextWindow::mVScrollBar->width(), m_pHScrollBar->height()); 0688 showWindowA->setChecked(true); 0689 showWindowB->setChecked(true); 0690 showWindowC->setChecked(true); 0691 } 0692 0693 // called after word wrap is complete 0694 void KDiff3App::slotFinishMainInit() 0695 { 0696 assert(m_pDiffTextWindow1 != nullptr && DiffTextWindow::mVScrollBar != nullptr && m_pOverview != nullptr); 0697 0698 setHScrollBarRange(); 0699 0700 qint32 newHeight = m_pDiffTextWindow1->getNofVisibleLines(); 0701 /*qint32 newWidth = m_pDiffTextWindow1->getNofVisibleColumns();*/ 0702 m_DTWHeight = newHeight; 0703 0704 DiffTextWindow::mVScrollBar->setRange(0, std::max(0, m_neededLines + 1 - newHeight)); 0705 DiffTextWindow::mVScrollBar->setPageStep(newHeight); 0706 m_pOverview->setRange(DiffTextWindow::mVScrollBar->value(), DiffTextWindow::mVScrollBar->pageStep()); 0707 0708 qint32 d3l = -1; 0709 if(!m_manualDiffHelpList.empty()) 0710 d3l = m_manualDiffHelpList.front().calcManualDiffFirstDiff3LineIdx(mDiff3LineVector); 0711 0712 setUpdatesEnabled(true); 0713 0714 if(d3l >= 0) 0715 { 0716 qint32 line = m_pDiffTextWindow1->convertDiff3LineIdxToLine(d3l); 0717 DiffTextWindow::mVScrollBar->setValue(std::max(0, line - 1)); 0718 } 0719 else 0720 { 0721 m_pMergeResultWindow->slotGoTop(); 0722 if(!m_outputFilename.isEmpty() && !m_pMergeResultWindow->isUnsolvedConflictAtCurrent()) 0723 m_pMergeResultWindow->slotGoNextUnsolvedConflict(); 0724 } 0725 0726 if(m_pCornerWidget) 0727 m_pCornerWidget->setFixedSize(DiffTextWindow::mVScrollBar->width(), m_pHScrollBar->height()); 0728 0729 Q_EMIT updateAvailabilities(); 0730 bool bVisibleMergeResultWindow = !m_outputFilename.isEmpty(); 0731 0732 if(m_bLoadFiles) 0733 { 0734 if(bVisibleMergeResultWindow) 0735 m_pMergeResultWindow->showNumberOfConflicts(!m_bAutoFlag); 0736 else if( 0737 // Avoid showing this message during startup without parameters. 0738 !(m_sd1->getAliasName().isEmpty() && m_sd2->getAliasName().isEmpty() && m_sd3->getAliasName().isEmpty()) && 0739 (m_sd1->isValid() && m_sd2->isValid() && m_sd3->isValid())) 0740 { 0741 QString totalInfo; 0742 if(m_totalDiffStatus->isBinaryEqualAB() && m_totalDiffStatus->isBinaryEqualAC()) 0743 totalInfo += i18n("All input files are binary equal."); 0744 else if(m_totalDiffStatus->isTextEqualAB() && m_totalDiffStatus->isTextEqualAC()) 0745 totalInfo += i18n("All input files contain the same text, but are not binary equal."); 0746 else 0747 { 0748 if(m_totalDiffStatus->isBinaryEqualAB()) 0749 totalInfo += i18n("Files %1 and %2 are binary equal.\n", QStringLiteral("A"), QStringLiteral("B")); 0750 else if(m_totalDiffStatus->isTextEqualAB()) 0751 totalInfo += i18n("Files %1 and %2 have equal text, but are not binary equal. \n", QStringLiteral("A"), QStringLiteral("B")); 0752 if(m_totalDiffStatus->isBinaryEqualAC()) 0753 totalInfo += i18n("Files %1 and %2 are binary equal.\n", QStringLiteral("A"), QStringLiteral("C")); 0754 else if(m_totalDiffStatus->isTextEqualAC()) 0755 totalInfo += i18n("Files %1 and %2 have equal text, but are not binary equal. \n", QStringLiteral("A"), QStringLiteral("C")); 0756 if(m_totalDiffStatus->isBinaryEqualBC()) 0757 totalInfo += i18n("Files %1 and %2 are binary equal.\n", QStringLiteral("B"), QStringLiteral("C")); 0758 else if(m_totalDiffStatus->isTextEqualBC()) 0759 totalInfo += i18n("Files %1 and %2 have equal text, but are not binary equal. \n", QStringLiteral("B"), QStringLiteral("C")); 0760 } 0761 0762 if(!totalInfo.isEmpty()) 0763 KMessageBox::information(this, totalInfo); 0764 } 0765 0766 if(bVisibleMergeResultWindow && (!m_sd1->isText() || !m_sd2->isText() || !m_sd3->isText())) 0767 { 0768 KMessageBox::information(this, i18n( 0769 "Some input files do not seem to be pure text files.\n" 0770 "Note that the KDiff3 merge was not meant for binary data.\n" 0771 "Continue at your own risk.")); 0772 } 0773 if(m_sd1->isIncompleteConversion() || m_sd2->isIncompleteConversion() || m_sd3->isIncompleteConversion()) 0774 { 0775 QString files; 0776 if(m_sd1->isIncompleteConversion()) 0777 files += QStringLiteral("A"); 0778 if(m_sd2->isIncompleteConversion()) 0779 files += files.isEmpty() ? QStringLiteral("B") : i18n(", B"); 0780 if(m_sd3->isIncompleteConversion()) 0781 files += files.isEmpty() ? QStringLiteral("C") : i18n(", C"); 0782 0783 KMessageBox::information(this, i18n("Some input characters could not be converted to valid unicode.\n" 0784 "You might be using the wrong codec. (e.g. UTF-8 for non UTF-8 files).\n" 0785 "Do not save the result if unsure. Continue at your own risk.\n" 0786 "Affected input files are in %1.", 0787 files)); 0788 } 0789 } 0790 0791 if(bVisibleMergeResultWindow && m_pMergeResultWindow) 0792 { 0793 m_pMergeResultWindow->setFocus(); 0794 } 0795 else if(m_pDiffTextWindow1) 0796 { 0797 m_pDiffTextWindow1->setFocus(); 0798 } 0799 } 0800 0801 void KDiff3App::resizeEvent(QResizeEvent* e) 0802 { 0803 QMainWindow::resizeEvent(e); 0804 if(m_pCornerWidget) 0805 m_pCornerWidget->setFixedSize(DiffTextWindow::mVScrollBar->width(), m_pHScrollBar->height()); 0806 } 0807 0808 void KDiff3App::wheelEvent(QWheelEvent* pWheelEvent) 0809 { 0810 pWheelEvent->accept(); 0811 QPoint delta = pWheelEvent->angleDelta(); 0812 0813 //Block diagonal scrolling easily generated unintentionally with track pads. 0814 if(delta.x() != 0 && abs(delta.y()) < abs(delta.x()) && m_pHScrollBar != nullptr) 0815 QCoreApplication::sendEvent(m_pHScrollBar, pWheelEvent); 0816 } 0817 0818 void KDiff3App::keyPressEvent(QKeyEvent* keyEvent) 0819 { 0820 bool bCtrl = (keyEvent->modifiers() & Qt::ControlModifier) != 0; 0821 0822 switch(keyEvent->key()) 0823 { 0824 case Qt::Key_Down: 0825 case Qt::Key_Up: 0826 case Qt::Key_PageDown: 0827 case Qt::Key_PageUp: 0828 if(DiffTextWindow::mVScrollBar != nullptr) 0829 QCoreApplication::sendEvent(DiffTextWindow::mVScrollBar, keyEvent); 0830 return; 0831 case Qt::Key_Left: 0832 case Qt::Key_Right: 0833 if(m_pHScrollBar != nullptr) 0834 QCoreApplication::sendEvent(m_pHScrollBar, keyEvent); 0835 return; 0836 case Qt::Key_End: 0837 case Qt::Key_Home: 0838 if(bCtrl) 0839 { 0840 if(DiffTextWindow::mVScrollBar != nullptr) 0841 QCoreApplication::sendEvent(DiffTextWindow::mVScrollBar, keyEvent); 0842 } 0843 else 0844 { 0845 if(m_pHScrollBar != nullptr) 0846 QCoreApplication::sendEvent(m_pHScrollBar, keyEvent); 0847 } 0848 return; 0849 } 0850 0851 QMainWindow::keyPressEvent(keyEvent); 0852 } 0853 0854 void KDiff3App::slotFinishDrop() 0855 { 0856 raise(); 0857 mainInit(m_totalDiffStatus); 0858 } 0859 0860 void KDiff3App::slotFileOpen() 0861 { 0862 if(!canContinue()) return; 0863 0864 if(m_pDirectoryMergeWindow->isDirectoryMergeInProgress()) 0865 { 0866 qint32 result = Compat::warningTwoActions(this, 0867 i18n("You are currently doing a folder merge. Are you sure, you want to abort?"), 0868 i18nc("Error dialog title", "Warning"), 0869 KGuiItem(i18n("Abort")), 0870 KGuiItem(i18n("Continue Merging"))); 0871 if(result != Compat::PrimaryAction) 0872 return; 0873 } 0874 0875 slotStatusMsg(i18n("Opening files...")); 0876 0877 for(;;) 0878 { 0879 QPointer<OpenDialog> d = QPointer<OpenDialog>(new OpenDialog(this, 0880 QDir::toNativeSeparators(m_bDirCompare ? gDirInfo->dirA().prettyAbsPath() : m_sd1->isFromBuffer() ? QString("") : 0881 m_sd1->getAliasName()), 0882 QDir::toNativeSeparators(m_bDirCompare ? gDirInfo->dirB().prettyAbsPath() : m_sd2->isFromBuffer() ? QString("") : 0883 m_sd2->getAliasName()), 0884 QDir::toNativeSeparators(m_bDirCompare ? gDirInfo->dirC().prettyAbsPath() : m_sd3->isFromBuffer() ? QString("") : 0885 m_sd3->getAliasName()), 0886 m_bDirCompare ? !gDirInfo->destDir().prettyAbsPath().isEmpty() : !m_outputFilename.isEmpty(), 0887 QDir::toNativeSeparators(m_bDefaultFilename ? QString("") : m_outputFilename))); 0888 0889 qint32 status = d->exec(); 0890 if(status == QDialog::Accepted) 0891 { 0892 m_sd1->setFilename(d->getFileA()); 0893 m_sd2->setFilename(d->getFileB()); 0894 m_sd3->setFilename(d->getFileC()); 0895 0896 if(d->merge()) 0897 { 0898 if(d->getOutputFile().isEmpty()) 0899 { 0900 m_outputFilename = "unnamed.txt"; 0901 m_bDefaultFilename = true; 0902 } 0903 else 0904 { 0905 m_outputFilename = d->getOutputFile(); 0906 m_bDefaultFilename = false; 0907 } 0908 } 0909 else 0910 m_outputFilename = ""; 0911 0912 m_bDirCompare = m_sd1->isDir(); 0913 0914 if(m_bDirCompare) 0915 { 0916 bool bSuccess = doDirectoryCompare(false); 0917 if(bSuccess) 0918 { 0919 m_pDirectoryMergeDock->show(); 0920 m_pDirectoryMergeInfoDock->show(); 0921 m_pMainWidget->hide(); 0922 break; 0923 } 0924 } 0925 else 0926 { 0927 doFileCompare(); 0928 0929 if((!m_sd1->getErrors().isEmpty()) || 0930 (!m_sd2->getErrors().isEmpty()) || 0931 (!m_sd3->getErrors().isEmpty())) 0932 { 0933 QString text(i18n("Opening of these files failed:")); 0934 text += "\n\n"; 0935 if(!m_sd1->getErrors().isEmpty()) 0936 text += " - " + m_sd1->getAliasName() + '\n' + m_sd1->getErrors().join('\n') + '\n'; 0937 if(!m_sd2->getErrors().isEmpty()) 0938 text += " - " + m_sd2->getAliasName() + '\n' + m_sd2->getErrors().join('\n') + '\n'; 0939 if(!m_sd3->getErrors().isEmpty()) 0940 text += " - " + m_sd3->getAliasName() + '\n' + m_sd3->getErrors().join('\n') + '\n'; 0941 0942 KMessageBox::error(this, text, i18n("File open error")); 0943 0944 continue; 0945 } 0946 } 0947 } 0948 break; 0949 } 0950 0951 Q_EMIT updateAvailabilities(); 0952 slotStatusMsg(i18n("Ready.")); 0953 } 0954 0955 void KDiff3App::slotFileOpen2(QStringList& errors, const QString& fn1, const QString& fn2, const QString& fn3, const QString& ofn, 0956 const QString& an1, const QString& an2, const QString& an3, TotalDiffStatus* pTotalDiffStatus) 0957 { 0958 if(!canContinue()) return; 0959 0960 if(fn1.isEmpty() && fn2.isEmpty() && fn3.isEmpty() && ofn.isEmpty()) 0961 { 0962 m_pMainWidget->hide(); 0963 return; 0964 } 0965 0966 slotStatusMsg(i18n("Opening files...")); 0967 m_sd1->reset(); 0968 m_sd2->reset(); 0969 m_sd3->reset(); 0970 0971 m_sd1->setFilename(fn1); 0972 m_sd2->setFilename(fn2); 0973 m_sd3->setFilename(fn3); 0974 0975 m_sd1->setAliasName(an1); 0976 m_sd2->setAliasName(an2); 0977 m_sd3->setAliasName(an3); 0978 0979 if(!ofn.isEmpty()) 0980 { 0981 m_outputFilename = ofn; 0982 m_bDefaultFilename = false; 0983 } 0984 else 0985 { 0986 m_outputFilename = ""; 0987 m_bDefaultFilename = true; 0988 } 0989 0990 if(!m_sd1->isDir()) 0991 { 0992 improveFilenames(); 0993 //KDiff3App::slotFileOpen2 needs to handle both GUI and non-GUI diffs. 0994 if(pTotalDiffStatus == nullptr) 0995 mainInit(m_totalDiffStatus); 0996 else 0997 mainInit(pTotalDiffStatus, InitFlag::loadFiles | InitFlag::autoSolve); 0998 0999 errors.append(mErrors); 1000 1001 if(m_bDirCompare) 1002 { 1003 errors.append(m_sd1->getErrors()); 1004 errors.append(m_sd2->getErrors()); 1005 errors.append(m_sd3->getErrors()); 1006 1007 return; 1008 } 1009 1010 if(m_sd1->isValid() && m_sd2->isValid() && m_sd3->isValid()) 1011 { 1012 if(m_pDirectoryMergeWindow != nullptr && m_pDirectoryMergeWindow->isVisible() && !dirShowBoth->isChecked()) 1013 { 1014 slotDirViewToggle(); 1015 } 1016 } 1017 } 1018 else 1019 doDirectoryCompare(true); // Create new window for KDiff3 for directory comparison. 1020 1021 slotStatusMsg(i18n("Ready.")); 1022 } 1023 1024 void KDiff3App::slotFileNameChanged(const QString& fileName, e_SrcSelector winIdx) 1025 { 1026 QStringList errors; 1027 QString fn1 = m_sd1->getFilename(); 1028 QString an1 = m_sd1->getAliasName(); 1029 QString fn2 = m_sd2->getFilename(); 1030 QString an2 = m_sd2->getAliasName(); 1031 QString fn3 = m_sd3->getFilename(); 1032 QString an3 = m_sd3->getAliasName(); 1033 1034 if(winIdx == e_SrcSelector::A) 1035 { 1036 fn1 = fileName; 1037 an1 = ""; 1038 } 1039 else if(winIdx == e_SrcSelector::B) 1040 { 1041 fn2 = fileName; 1042 an2 = ""; 1043 } 1044 else if(winIdx == e_SrcSelector::C) 1045 { 1046 fn3 = fileName; 1047 an3 = ""; 1048 } 1049 1050 slotFileOpen2(errors, fn1, fn2, fn3, m_outputFilename, an1, an2, an3, nullptr); 1051 } 1052 1053 void KDiff3App::slotEditCut() 1054 { 1055 slotStatusMsg(i18n("Cutting selection...")); 1056 Q_EMIT cut(); 1057 slotStatusMsg(i18n("Ready.")); 1058 } 1059 1060 void KDiff3App::slotEditCopy() 1061 { 1062 slotStatusMsg(i18n("Copying selection to clipboard...")); 1063 1064 Q_EMIT copy(); 1065 1066 slotStatusMsg(i18n("Ready.")); 1067 } 1068 1069 void KDiff3App::slotEditPaste() 1070 { 1071 slotStatusMsg(i18n("Inserting clipboard contents...")); 1072 1073 if(m_pMergeResultWindow != nullptr && m_pMergeResultWindow->isVisible()) 1074 { 1075 m_pMergeResultWindow->pasteClipboard(false); 1076 } 1077 else 1078 { 1079 if(canContinue()) 1080 { 1081 QString error; 1082 bool do_init = false; 1083 1084 if(m_pDiffTextWindow1->hasFocus()) 1085 { 1086 m_sd1->setData(QApplication::clipboard()->text(QClipboard::Clipboard)); 1087 const QStringList& errors = m_sd1->getErrors(); 1088 if(!errors.isEmpty()) 1089 error = m_sd1->getErrors()[0]; 1090 1091 do_init = true; 1092 } 1093 else if(m_pDiffTextWindow2->hasFocus()) 1094 { 1095 m_sd2->setData(QApplication::clipboard()->text(QClipboard::Clipboard)); 1096 const QStringList& errors = m_sd2->getErrors(); 1097 if(!errors.isEmpty()) 1098 error = m_sd2->getErrors()[0]; 1099 1100 do_init = true; 1101 } 1102 else if(m_pDiffTextWindow3->hasFocus()) 1103 { 1104 m_sd3->setData(QApplication::clipboard()->text(QClipboard::Clipboard)); 1105 const QStringList& errors = m_sd3->getErrors(); 1106 if(!errors.isEmpty()) 1107 error = m_sd3->getErrors()[0]; 1108 1109 do_init = true; 1110 } 1111 1112 if(!error.isEmpty()) 1113 { 1114 KMessageBox::error(m_pOptionDialog, error); 1115 } 1116 1117 if(do_init) 1118 { 1119 mainInit(m_totalDiffStatus); 1120 } 1121 } 1122 } 1123 1124 slotStatusMsg(i18n("Ready.")); 1125 } 1126 1127 void KDiff3App::slotEditSelectAll() 1128 { 1129 1130 Q_EMIT selectAll(); 1131 1132 slotStatusMsg(i18n("Ready.")); 1133 } 1134 1135 void KDiff3App::slotGoCurrent() 1136 { 1137 Q_EMIT goCurrent(); 1138 } 1139 1140 void KDiff3App::slotGoTop() 1141 { 1142 Q_EMIT goTop(); 1143 } 1144 1145 void KDiff3App::slotGoBottom() 1146 { 1147 Q_EMIT goBottom(); 1148 } 1149 1150 void KDiff3App::slotGoPrevUnsolvedConflict() 1151 { 1152 Q_EMIT goPrevUnsolvedConflict(); 1153 } 1154 1155 void KDiff3App::slotGoNextUnsolvedConflict() 1156 { 1157 m_bTimerBlock = false; 1158 Q_EMIT goNextUnsolvedConflict(); 1159 } 1160 1161 void KDiff3App::slotGoPrevConflict() 1162 { 1163 Q_EMIT goPrevConflict(); 1164 } 1165 1166 void KDiff3App::slotGoNextConflict() 1167 { 1168 m_bTimerBlock = false; 1169 Q_EMIT goNextConflict(); 1170 } 1171 1172 void KDiff3App::slotGoPrevDelta() 1173 { 1174 Q_EMIT goPrevDelta(); 1175 } 1176 1177 void KDiff3App::slotGoNextDelta() 1178 { 1179 Q_EMIT goNextDelta(); 1180 } 1181 1182 void KDiff3App::slotGoToLine() 1183 { 1184 QDialog pDialog; 1185 QVBoxLayout* l = new QVBoxLayout(&pDialog); 1186 1187 QLineEdit* pLineNumEdit = new QLineEdit(); 1188 //Limit input to valid 1 based line numbers 1189 pLineNumEdit->setValidator(new QIntValidator(1, DiffTextWindow::mVScrollBar->maximum(), pLineNumEdit)); 1190 1191 QPushButton* pOkButton = new QPushButton(i18n("Ok")); 1192 l->addWidget(pLineNumEdit); 1193 l->addWidget(pOkButton); 1194 1195 chk_connect(pOkButton, &QPushButton::clicked, &pDialog, 1196 ([&pDialog, pLineNumEdit]() { 1197 if(pLineNumEdit->text() != "") 1198 { 1199 qint32 lineNum = pLineNumEdit->text().toInt(); 1200 lineNum = qMax(lineNum - 2, 0); 1201 //No need for anything else here setValue triggers a valueChanged signal internally. 1202 DiffTextWindow::mVScrollBar->setValue(lineNum); 1203 } 1204 pDialog.close(); 1205 })); 1206 1207 pDialog.setWindowTitle(i18n("Go to Line")); 1208 pDialog.setWindowFlag(Qt::WindowContextHelpButtonHint, false); 1209 pDialog.setFixedSize(260, 110); 1210 pDialog.exec(); 1211 } 1212 1213 void KDiff3App::choose(e_SrcSelector choice) 1214 { 1215 if(!m_bTimerBlock) 1216 { 1217 if(m_pDirectoryMergeWindow && m_pDirectoryMergeWindow->hasFocus()) 1218 { 1219 if(choice == e_SrcSelector::A) m_pDirectoryMergeWindow->slotCurrentChooseA(); 1220 if(choice == e_SrcSelector::B) m_pDirectoryMergeWindow->slotCurrentChooseB(); 1221 if(choice == e_SrcSelector::C) m_pDirectoryMergeWindow->slotCurrentChooseC(); 1222 1223 chooseA->setChecked(false); 1224 chooseB->setChecked(false); 1225 chooseC->setChecked(false); 1226 } 1227 else if(m_pMergeResultWindow) 1228 { 1229 m_pMergeResultWindow->choose(choice); 1230 if(autoAdvance->isChecked()) 1231 { 1232 m_bTimerBlock = true; 1233 QTimer::singleShot(gOptions->m_autoAdvanceDelay, this, &KDiff3App::slotGoNextUnsolvedConflict); 1234 } 1235 } 1236 } 1237 } 1238 1239 void KDiff3App::slotChooseA() 1240 { 1241 choose(e_SrcSelector::A); 1242 } 1243 void KDiff3App::slotChooseB() 1244 { 1245 choose(e_SrcSelector::B); 1246 } 1247 void KDiff3App::slotChooseC() 1248 { 1249 choose(e_SrcSelector::C); 1250 } 1251 1252 void KDiff3App::slotAutoSolve() 1253 { 1254 Q_EMIT autoSolve(); 1255 1256 Q_EMIT updateAvailabilities(); 1257 } 1258 1259 void KDiff3App::slotUnsolve() 1260 { 1261 Q_EMIT unsolve(); 1262 } 1263 1264 void KDiff3App::slotMergeHistory() 1265 { 1266 Q_EMIT mergeHistory(); 1267 } 1268 1269 void KDiff3App::slotRegExpAutoMerge() 1270 { 1271 Q_EMIT regExpAutoMerge(); 1272 } 1273 1274 void KDiff3App::slotSplitDiff() 1275 { 1276 LineRef firstLine; 1277 LineRef lastLine; 1278 QPointer<DiffTextWindow> pDTW = nullptr; 1279 if(m_pDiffTextWindow1) 1280 { 1281 pDTW = m_pDiffTextWindow1; 1282 pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); 1283 } 1284 if(!firstLine.isValid() && m_pDiffTextWindow2) 1285 { 1286 pDTW = m_pDiffTextWindow2; 1287 pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); 1288 } 1289 if(!firstLine.isValid() && m_pDiffTextWindow3) 1290 { 1291 pDTW = m_pDiffTextWindow3; 1292 pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); 1293 } 1294 if(pDTW && firstLine.isValid() && m_pMergeResultWindow) 1295 { 1296 pDTW->resetSelection(); 1297 1298 m_pMergeResultWindow->slotSplitDiff(firstLine, lastLine); 1299 } 1300 } 1301 1302 void KDiff3App::slotJoinDiffs() 1303 { 1304 LineRef firstLine; 1305 LineRef lastLine; 1306 QPointer<DiffTextWindow> pDTW = nullptr; 1307 if(m_pDiffTextWindow1) 1308 { 1309 pDTW = m_pDiffTextWindow1; 1310 pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); 1311 } 1312 if(!firstLine.isValid() && m_pDiffTextWindow2) 1313 { 1314 pDTW = m_pDiffTextWindow2; 1315 pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); 1316 } 1317 if(!firstLine.isValid() && m_pDiffTextWindow3) 1318 { 1319 pDTW = m_pDiffTextWindow3; 1320 pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); 1321 } 1322 if(pDTW && firstLine.isValid() && m_pMergeResultWindow) 1323 { 1324 pDTW->resetSelection(); 1325 1326 m_pMergeResultWindow->slotJoinDiffs(firstLine, lastLine); 1327 } 1328 } 1329 1330 void KDiff3App::slotConfigure() 1331 { 1332 m_pOptionDialog->setState(); 1333 m_pOptionDialog->setMinimumHeight(m_pOptionDialog->minimumHeight() + 40); 1334 m_pOptionDialog->exec(); 1335 mEscapeAction->setEnabled(gOptions->m_bEscapeKeyQuits); 1336 slotRefresh(); 1337 } 1338 1339 void KDiff3App::slotConfigureKeys() 1340 { 1341 KShortcutsDialog::showDialog(actionCollection(), KShortcutsEditor::LetterShortcutsDisallowed, this); 1342 } 1343 1344 void KDiff3App::slotRefresh() 1345 { 1346 QApplication::setFont(gOptions->appFont()); 1347 1348 Q_EMIT doRefresh(); 1349 1350 if(m_pHScrollBar != nullptr) 1351 { 1352 m_pHScrollBar->setAgain(); 1353 } 1354 if(m_pDiffWindowSplitter != nullptr) 1355 { 1356 m_pDiffWindowSplitter->setOrientation(gOptions->m_bHorizDiffWindowSplitting ? Qt::Horizontal : Qt::Vertical); 1357 } 1358 } 1359 1360 void KDiff3App::slotSelectionStart() 1361 { 1362 const QObject* s = sender(); 1363 if(s == nullptr) return; 1364 1365 if(s != m_pDiffTextWindow1) m_pDiffTextWindow1->resetSelection(); 1366 if(s != m_pDiffTextWindow2) m_pDiffTextWindow2->resetSelection(); 1367 if(s != m_pDiffTextWindow3) m_pDiffTextWindow3->resetSelection(); 1368 if(s != m_pMergeResultWindow) m_pMergeResultWindow->resetSelection(); 1369 } 1370 1371 void KDiff3App::slotSelectionEnd() 1372 { 1373 if(gOptions->m_bAutoCopySelection) 1374 { 1375 slotEditCopy(); 1376 } 1377 else 1378 { 1379 QClipboard* clipBoard = QApplication::clipboard(); 1380 1381 if(clipBoard->supportsSelection()) 1382 { 1383 QString sCurSelection = getSelection(); 1384 1385 if(!sCurSelection.isEmpty()) 1386 { 1387 clipBoard->setText(sCurSelection, QClipboard::Selection); 1388 } 1389 } 1390 } 1391 1392 Q_EMIT updateAvailabilities(); 1393 } 1394 1395 void KDiff3App::slotClipboardChanged() 1396 { 1397 const QClipboard* clipboard = QApplication::clipboard(); 1398 const QMimeData* mimeData = clipboard->mimeData(); 1399 if(mimeData && mimeData->hasText()) 1400 { 1401 QString s = clipboard->text(); 1402 editPaste->setEnabled(!s.isEmpty()); 1403 } 1404 else 1405 { 1406 editPaste->setEnabled(false); 1407 } 1408 } 1409 1410 void KDiff3App::slotOutputModified(bool bModified) 1411 { 1412 if(bModified && !m_bOutputModified) 1413 { 1414 m_bOutputModified = true; 1415 Q_EMIT updateAvailabilities(); 1416 } 1417 } 1418 1419 void KDiff3App::slotAutoAdvanceToggled() 1420 { 1421 gOptions->m_bAutoAdvance = autoAdvance->isChecked(); 1422 } 1423 1424 void KDiff3App::slotWordWrapToggled() 1425 { 1426 gOptions->setWordWrap(wordWrap->isChecked()); 1427 postRecalcWordWrap(); 1428 } 1429 1430 // Enable or disable all widgets except the status bar widget. 1431 void KDiff3App::mainWindowEnable(bool bEnable) 1432 { 1433 if(QMainWindow* pWindow = dynamic_cast<QMainWindow*>(window())) 1434 { 1435 QWidget* pStatusBarWidget = pWindow->statusBar(); 1436 pWindow->setEnabled(bEnable); 1437 pStatusBarWidget->setEnabled(true); 1438 } 1439 } 1440 1441 void KDiff3App::postRecalcWordWrap() 1442 { 1443 if(!m_bRecalcWordWrapPosted) 1444 { 1445 while(DiffTextWindow::maxThreads() > 0) {} //Clear wordwrap threads. 1446 m_bRecalcWordWrapPosted = true; 1447 m_firstD3LIdx = -1; 1448 Q_EMIT sigRecalcWordWrap(); 1449 } 1450 else 1451 { 1452 g_pProgressDialog->cancel(ProgressDialog::eResize); 1453 } 1454 } 1455 1456 void KDiff3App::slotRecalcWordWrap() 1457 { 1458 recalcWordWrap(); 1459 } 1460 1461 // visibleTextWidthForPrinting is >=0 only for printing, otherwise the really visible width is used 1462 void KDiff3App::recalcWordWrap(qint32 visibleTextWidthForPrinting) 1463 { 1464 m_bRecalcWordWrapPosted = true; 1465 mainWindowEnable(false); 1466 1467 if(m_firstD3LIdx < 0) 1468 { 1469 m_firstD3LIdx = 0; 1470 if(!m_pDiffTextWindow1) 1471 return; //Nothing that happens from here on makes any sense if we don't have a DiffTextWindow. 1472 1473 m_firstD3LIdx = m_pDiffTextWindow1->convertLineToDiff3LineIdx(m_pDiffTextWindow1->getFirstLine()); 1474 } 1475 1476 // Convert selection to D3L-coords (converting back happens in DiffTextWindow::recalcWordWrap() 1477 if(m_pDiffTextWindow1) 1478 m_pDiffTextWindow1->convertSelectionToD3LCoords(); 1479 if(m_pDiffTextWindow2) 1480 m_pDiffTextWindow2->convertSelectionToD3LCoords(); 1481 if(m_pDiffTextWindow3) 1482 m_pDiffTextWindow3->convertSelectionToD3LCoords(); 1483 1484 g_pProgressDialog->clearCancelState(); // clear cancelled state if previously set 1485 1486 if(!m_diff3LineList.empty()) 1487 { 1488 if(gOptions->wordWrapOn()) 1489 { 1490 m_diff3LineList.recalcWordWrap(true); 1491 1492 // Let every window calc how many lines will be needed. 1493 if(m_pDiffTextWindow1) 1494 { 1495 m_pDiffTextWindow1->recalcWordWrap(true, 0, visibleTextWidthForPrinting); 1496 } 1497 if(m_pDiffTextWindow2) 1498 { 1499 m_pDiffTextWindow2->recalcWordWrap(true, 0, visibleTextWidthForPrinting); 1500 } 1501 if(m_pDiffTextWindow3) 1502 { 1503 m_pDiffTextWindow3->recalcWordWrap(true, 0, visibleTextWidthForPrinting); 1504 } 1505 } 1506 else 1507 { 1508 m_neededLines = SafeInt<LineType>(m_diff3LineList.size()); 1509 if(m_pDiffTextWindow1) 1510 m_pDiffTextWindow1->recalcWordWrap(false, 0, 0); 1511 if(m_pDiffTextWindow2) 1512 m_pDiffTextWindow2->recalcWordWrap(false, 0, 0); 1513 if(m_pDiffTextWindow3) 1514 m_pDiffTextWindow3->recalcWordWrap(false, 0, 0); 1515 } 1516 mRunnablesStarted = DiffTextWindow::startRunnables(); 1517 if(!mRunnablesStarted) 1518 slotFinishRecalcWordWrap(visibleTextWidthForPrinting); 1519 else 1520 { 1521 g_pProgressDialog->setInformation(gOptions->wordWrapOn() ? i18n("Word wrap (Cancel disables word wrap)") : i18n("Calculating max width for horizontal scrollbar"), 1522 false); 1523 } 1524 } 1525 else 1526 { 1527 //don't leave processing incomplete if m_diff3LineList isEmpty as when an error occurs during reading. 1528 slotFinishRecalcWordWrap(visibleTextWidthForPrinting); 1529 } 1530 } 1531 1532 void KDiff3App::slotFinishRecalcWordWrap(qint32 visibleTextWidthForPrinting) 1533 { 1534 assert(m_firstD3LIdx >= 0); 1535 1536 if(mRunnablesStarted) 1537 { 1538 ProgressProxy::endBackgroundTask(); 1539 mRunnablesStarted = false; 1540 } 1541 1542 if(gOptions->wordWrapOn() && g_pProgressDialog->wasCancelled()) 1543 { 1544 if(g_pProgressDialog->cancelReason() == ProgressDialog::eUserAbort) 1545 { 1546 wordWrap->setChecked(false); 1547 gOptions->setWordWrap(wordWrap->isChecked()); 1548 } 1549 1550 Q_EMIT sigRecalcWordWrap(); 1551 return; 1552 } 1553 else 1554 { 1555 m_bRecalcWordWrapPosted = false; 1556 } 1557 1558 g_pProgressDialog->setStayHidden(false); 1559 1560 const bool bPrinting = visibleTextWidthForPrinting >= 0; 1561 1562 if(!m_diff3LineList.empty()) 1563 { 1564 if(gOptions->wordWrapOn()) 1565 { 1566 LineType sumOfLines = m_diff3LineList.recalcWordWrap(false); 1567 1568 // Finish the word wrap 1569 if(m_pDiffTextWindow1) 1570 m_pDiffTextWindow1->recalcWordWrap(true, sumOfLines, visibleTextWidthForPrinting); 1571 if(m_pDiffTextWindow2) 1572 m_pDiffTextWindow2->recalcWordWrap(true, sumOfLines, visibleTextWidthForPrinting); 1573 if(m_pDiffTextWindow3) 1574 m_pDiffTextWindow3->recalcWordWrap(true, sumOfLines, visibleTextWidthForPrinting); 1575 1576 m_neededLines = sumOfLines; 1577 } 1578 else 1579 { 1580 if(m_pDiffTextWindow1) 1581 m_pDiffTextWindow1->recalcWordWrap(false, 1, 0); 1582 if(m_pDiffTextWindow2) 1583 m_pDiffTextWindow2->recalcWordWrap(false, 1, 0); 1584 if(m_pDiffTextWindow3) 1585 m_pDiffTextWindow3->recalcWordWrap(false, 1, 0); 1586 } 1587 slotStatusMsg(QString()); 1588 } 1589 1590 if(!bPrinting) 1591 { 1592 if(m_pOverview) 1593 m_pOverview->slotRedraw(); 1594 if(DiffTextWindow::mVScrollBar) 1595 DiffTextWindow::mVScrollBar->setRange(0, std::max<qint32>(0, SafeInt<qint32>(m_neededLines + 1 - m_DTWHeight))); 1596 if(m_pDiffTextWindow1) 1597 { 1598 if(DiffTextWindow::mVScrollBar) 1599 DiffTextWindow::mVScrollBar->setValue(m_pDiffTextWindow1->convertDiff3LineIdxToLine(m_firstD3LIdx)); 1600 1601 setHScrollBarRange(); 1602 m_pHScrollBar->setValue(0); 1603 } 1604 } 1605 mainWindowEnable(true); 1606 1607 if(m_bFinishMainInit) 1608 { 1609 m_bFinishMainInit = false; 1610 slotFinishMainInit(); 1611 } 1612 if(m_pEventLoopForPrinting) 1613 m_pEventLoopForPrinting->quit(); 1614 } 1615 1616 void KDiff3App::slotShowWhiteSpaceToggled() 1617 { 1618 gOptions->m_bShowWhiteSpaceCharacters = showWhiteSpaceCharacters->isChecked(); 1619 gOptions->m_bShowWhiteSpace = showWhiteSpace->isChecked(); 1620 1621 Q_EMIT showWhiteSpaceToggled(); 1622 } 1623 1624 void KDiff3App::slotShowLineNumbersToggled() 1625 { 1626 gOptions->m_bShowLineNumbers = showLineNumbers->isChecked(); 1627 1628 if(wordWrap->isChecked()) 1629 recalcWordWrap(); 1630 1631 Q_EMIT showLineNumbersToggled(); 1632 } 1633 1634 /// Return true for success, else false 1635 bool KDiff3App::doDirectoryCompare(const bool bCreateNewInstance) 1636 { 1637 FileAccess f1(m_sd1->getFilename()); 1638 FileAccess f2(m_sd2->getFilename()); 1639 FileAccess f3(m_sd3->getFilename()); 1640 FileAccess f4(m_outputFilename); 1641 1642 assert(f1.isDir()); 1643 1644 if(bCreateNewInstance) 1645 { 1646 Q_EMIT createNewInstance(f1.absoluteFilePath(), f2.absoluteFilePath(), f3.absoluteFilePath()); 1647 } 1648 else 1649 { 1650 //Only a debugging aid now. Used to insure m_bDirCompare is not changed 1651 [[maybe_unused]] const bool bDirCompare = m_bDirCompare; 1652 1653 FileAccess destDir; 1654 1655 if(!m_bDefaultFilename) destDir = f4; 1656 m_pDirectoryMergeDock->show(); 1657 m_pDirectoryMergeInfoDock->show(); 1658 m_pMainWidget->hide(); 1659 setUpdatesEnabled(true); 1660 1661 (*gDirInfo) = DirectoryInfo(f1, f2, f3, destDir); 1662 1663 bool bSuccess = m_pDirectoryMergeWindow->init( 1664 !m_outputFilename.isEmpty()); 1665 //This is a bug if it still happens. 1666 assert(m_bDirCompare == bDirCompare); 1667 1668 if(bSuccess) 1669 { 1670 m_sd1->reset(); 1671 if(m_pDiffTextWindow1 != nullptr) 1672 { 1673 m_pDiffTextWindow1->init(QString(""), nullptr, eLineEndStyleDos, nullptr, 0, nullptr, nullptr); 1674 m_pDiffTextWindowFrame1->init(); 1675 } 1676 m_sd2->reset(); 1677 if(m_pDiffTextWindow2 != nullptr) 1678 { 1679 m_pDiffTextWindow2->init(QString(""), nullptr, eLineEndStyleDos, nullptr, 0, nullptr, nullptr); 1680 m_pDiffTextWindowFrame2->init(); 1681 } 1682 m_sd3->reset(); 1683 if(m_pDiffTextWindow3 != nullptr) 1684 { 1685 m_pDiffTextWindow3->init(QString(""), nullptr, eLineEndStyleDos, nullptr, 0, nullptr, nullptr); 1686 m_pDiffTextWindowFrame3->init(); 1687 } 1688 } 1689 Q_EMIT updateAvailabilities(); 1690 return bSuccess; 1691 } 1692 1693 return true; 1694 } 1695 /* 1696 If A is targetted to an existing file and the paths point to directories attempt to find that file in the corresponding 1697 directory. If it exists then the filename from A will be appended to the path. 1698 */ 1699 void KDiff3App::improveFilenames() 1700 { 1701 FileAccess f1(m_sd1->getFilename()); 1702 FileAccess f2(m_sd2->getFilename()); 1703 FileAccess f3(m_sd3->getFilename()); 1704 FileAccess f4(m_outputFilename); 1705 1706 if(f1.isFile() && f1.exists()) 1707 { 1708 if(f2.isDir()) 1709 { 1710 f2.addPath(f1.fileName()); 1711 if(f2.isFile() && f2.exists()) 1712 m_sd2->setFileAccess(f2); 1713 } 1714 if(f3.isDir()) 1715 { 1716 f3.addPath(f1.fileName()); 1717 if(f3.isFile() && f3.exists()) 1718 m_sd3->setFileAccess(f3); 1719 } 1720 if(f4.isDir()) 1721 { 1722 f4.addPath(f1.fileName()); 1723 if(f4.isFile() && f4.exists()) 1724 m_outputFilename = f4.absoluteFilePath(); 1725 } 1726 } 1727 } 1728 1729 void KDiff3App::slotReload() 1730 { 1731 if(!canContinue()) return; 1732 1733 mainInit(m_totalDiffStatus); 1734 } 1735 1736 bool KDiff3App::canContinue() 1737 { 1738 // First test if anything must be saved. 1739 if(m_bOutputModified) 1740 { 1741 qint32 result = Compat::warningTwoActionsCancel(this, 1742 i18n("The merge result has not been saved."), 1743 i18nc("Error dialog title", "Warning"), 1744 KGuiItem(i18n("Save && Continue")), 1745 KGuiItem(i18n("Continue Without Saving"))); 1746 if(result == KMessageBox::Cancel) 1747 return false; 1748 else if(result == Compat::PrimaryAction) 1749 { 1750 slotFileSave(); 1751 if(m_bOutputModified) 1752 { 1753 KMessageBox::error(this, i18n("Saving the merge result failed."), i18nc("Error dialog title", "Warning")); 1754 return false; 1755 } 1756 } 1757 } 1758 1759 m_bOutputModified = false; 1760 return true; 1761 } 1762 1763 void KDiff3App::slotDirShowBoth() 1764 { 1765 if(dirShowBoth->isChecked()) 1766 { 1767 if(m_pDirectoryMergeDock) 1768 m_pDirectoryMergeDock->setVisible(m_bDirCompare); 1769 if(m_pDirectoryMergeInfoDock) 1770 m_pDirectoryMergeInfoDock->setVisible(m_bDirCompare); 1771 1772 m_pMainWidget->show(); 1773 } 1774 else 1775 { 1776 bool bTextDataAvailable = (m_sd1->hasData() || m_sd2->hasData() || m_sd3->hasData()); 1777 if(bTextDataAvailable) 1778 { 1779 m_pMainWidget->show(); 1780 m_pDirectoryMergeDock->hide(); 1781 m_pDirectoryMergeInfoDock->hide(); 1782 } 1783 else if(m_bDirCompare) 1784 { 1785 m_pDirectoryMergeDock->show(); 1786 m_pDirectoryMergeInfoDock->show(); 1787 } 1788 } 1789 1790 Q_EMIT updateAvailabilities(); 1791 } 1792 1793 void KDiff3App::slotDirViewToggle() 1794 { 1795 if(m_bDirCompare) 1796 { 1797 if(!m_pDirectoryMergeDock->isVisible()) 1798 { 1799 m_pDirectoryMergeDock->show(); 1800 m_pDirectoryMergeInfoDock->show(); 1801 m_pMainWidget->hide(); 1802 } 1803 else 1804 { 1805 m_pDirectoryMergeDock->hide(); 1806 m_pDirectoryMergeInfoDock->hide(); 1807 m_pMainWidget->show(); 1808 } 1809 } 1810 Q_EMIT updateAvailabilities(); 1811 } 1812 1813 void KDiff3App::slotShowWindowAToggled() 1814 { 1815 if(m_pDiffTextWindow1 != nullptr) 1816 { 1817 m_pDiffTextWindowFrame1->setVisible(showWindowA->isChecked()); 1818 Q_EMIT updateAvailabilities(); 1819 } 1820 } 1821 1822 void KDiff3App::slotShowWindowBToggled() 1823 { 1824 if(m_pDiffTextWindow2 != nullptr) 1825 { 1826 m_pDiffTextWindowFrame2->setVisible(showWindowB->isChecked()); 1827 Q_EMIT updateAvailabilities(); 1828 } 1829 } 1830 1831 void KDiff3App::slotShowWindowCToggled() 1832 { 1833 if(m_pDiffTextWindow3 != nullptr) 1834 { 1835 m_pDiffTextWindowFrame3->setVisible(showWindowC->isChecked()); 1836 Q_EMIT updateAvailabilities(); 1837 } 1838 } 1839 1840 void KDiff3App::slotEditFind() 1841 { 1842 m_pFindDialog->restartFind(); 1843 1844 // Use currently selected text: 1845 QString sCurSelection = getSelection(); 1846 1847 if(!sCurSelection.isEmpty() && !sCurSelection.contains('\n')) 1848 { 1849 m_pFindDialog->m_pSearchString->setText(sCurSelection); 1850 } 1851 1852 if(QDialog::Accepted == m_pFindDialog->exec()) 1853 { 1854 slotEditFindNext(); 1855 } 1856 } 1857 1858 void KDiff3App::slotEditFindNext() 1859 { 1860 QString s = m_pFindDialog->m_pSearchString->text(); 1861 if(s.isEmpty()) 1862 { 1863 slotEditFind(); 1864 return; 1865 } 1866 1867 bool bDirDown = true; 1868 bool bCaseSensitive = m_pFindDialog->m_pCaseSensitive->isChecked(); 1869 1870 LineRef d3vLine = m_pFindDialog->currentLine; 1871 QtSizeType posInLine = m_pFindDialog->currentPos; 1872 LineRef l; 1873 QtSizeType p = 0; 1874 if(m_pFindDialog->getCurrentWindow() == eWindowIndex::A) 1875 { 1876 if(m_pFindDialog->m_pSearchInA->isChecked() && m_pDiffTextWindow1 != nullptr && 1877 m_pDiffTextWindow1->findString(s, d3vLine, posInLine, bDirDown, bCaseSensitive)) 1878 { 1879 m_pDiffTextWindow1->setSelection(d3vLine, posInLine, d3vLine, posInLine + s.length(), l, p); 1880 DiffTextWindow::mVScrollBar->setValue(l - DiffTextWindow::mVScrollBar->pageStep() / 2); 1881 m_pHScrollBar->setValue(std::max<SafeInt<qint32>>(0, p + s.length() - m_pHScrollBar->pageStep())); 1882 m_pFindDialog->currentLine = d3vLine; 1883 m_pFindDialog->currentPos = posInLine + 1; 1884 return; 1885 } 1886 m_pFindDialog->nextWindow(); 1887 } 1888 1889 d3vLine = m_pFindDialog->currentLine; 1890 posInLine = m_pFindDialog->currentPos; 1891 if(m_pFindDialog->getCurrentWindow() == eWindowIndex::B) 1892 { 1893 if(m_pFindDialog->m_pSearchInB->isChecked() && m_pDiffTextWindow2 != nullptr && 1894 m_pDiffTextWindow2->findString(s, d3vLine, posInLine, bDirDown, bCaseSensitive)) 1895 { 1896 m_pDiffTextWindow2->setSelection(d3vLine, posInLine, d3vLine, posInLine + s.length(), l, p); 1897 DiffTextWindow::mVScrollBar->setValue(l - DiffTextWindow::mVScrollBar->pageStep() / 2); 1898 m_pHScrollBar->setValue(std::max<SafeInt<qint32>>(0, p + s.length() - m_pHScrollBar->pageStep())); 1899 m_pFindDialog->currentLine = d3vLine; 1900 m_pFindDialog->currentPos = posInLine + 1; 1901 return; 1902 } 1903 1904 m_pFindDialog->nextWindow(); 1905 } 1906 1907 d3vLine = m_pFindDialog->currentLine; 1908 posInLine = m_pFindDialog->currentPos; 1909 if(m_pFindDialog->getCurrentWindow() == eWindowIndex::C) 1910 { 1911 if(m_pFindDialog->m_pSearchInC->isChecked() && m_pDiffTextWindow3 != nullptr && 1912 m_pDiffTextWindow3->findString(s, d3vLine, posInLine, bDirDown, bCaseSensitive)) 1913 { 1914 m_pDiffTextWindow3->setSelection(d3vLine, posInLine, d3vLine, posInLine + s.length(), l, p); 1915 DiffTextWindow::mVScrollBar->setValue(l - DiffTextWindow::mVScrollBar->pageStep() / 2); 1916 m_pHScrollBar->setValue(std::max<SafeInt<qint32>>(0, p + s.length() - m_pHScrollBar->pageStep())); 1917 m_pFindDialog->currentLine = d3vLine; 1918 m_pFindDialog->currentPos = posInLine + 1; 1919 return; 1920 } 1921 1922 m_pFindDialog->nextWindow(); 1923 } 1924 1925 d3vLine = m_pFindDialog->currentLine; 1926 posInLine = m_pFindDialog->currentPos; 1927 if(m_pFindDialog->getCurrentWindow() == eWindowIndex::Output) 1928 { 1929 if(m_pFindDialog->m_pSearchInOutput->isChecked() && m_pMergeResultWindow != nullptr && m_pMergeResultWindow->isVisible() && 1930 m_pMergeResultWindow->findString(s, d3vLine, posInLine, bDirDown, bCaseSensitive)) 1931 { 1932 m_pMergeResultWindow->setSelection(d3vLine, posInLine, d3vLine, posInLine + s.length()); 1933 MergeResultWindow::mVScrollBar->setValue(d3vLine - MergeResultWindow::mVScrollBar->pageStep() / 2); 1934 m_pHScrollBar->setValue(std::max<SafeInt<qint32>>(0, posInLine + s.length() - m_pHScrollBar->pageStep())); 1935 m_pFindDialog->currentLine = d3vLine; 1936 m_pFindDialog->currentPos = posInLine + 1; 1937 return; 1938 } 1939 1940 m_pFindDialog->nextWindow(); 1941 } 1942 1943 KMessageBox::information(this, i18n("Search complete."), i18n("Search Complete")); 1944 m_pFindDialog->restartFind(); 1945 } 1946 1947 void KDiff3App::slotMergeCurrentFile() 1948 { 1949 if(m_bDirCompare && m_pDirectoryMergeWindow->isVisible() && m_pDirectoryMergeWindow->isFileSelected()) 1950 { 1951 m_pDirectoryMergeWindow->mergeCurrentFile(); 1952 } 1953 else if(m_pMainWidget->isVisible()) 1954 { 1955 if(!canContinue()) return; 1956 1957 if(m_outputFilename.isEmpty()) 1958 { 1959 if(!m_sd3->isEmpty() && !m_sd3->isFromBuffer()) 1960 { 1961 m_outputFilename = m_sd3->getFilename(); 1962 } 1963 else if(!m_sd2->isEmpty() && !m_sd2->isFromBuffer()) 1964 { 1965 m_outputFilename = m_sd2->getFilename(); 1966 } 1967 else if(!m_sd1->isEmpty() && !m_sd1->isFromBuffer()) 1968 { 1969 m_outputFilename = m_sd1->getFilename(); 1970 } 1971 else 1972 { 1973 m_outputFilename = "unnamed.txt"; 1974 m_bDefaultFilename = true; 1975 } 1976 } 1977 mainInit(m_totalDiffStatus); 1978 } 1979 } 1980 1981 void KDiff3App::slotWinFocusNext() 1982 { 1983 QWidget* focus = qApp->focusWidget(); 1984 if(focus == m_pDirectoryMergeWindow && m_pDirectoryMergeWindow->isVisible() && !dirShowBoth->isChecked()) 1985 { 1986 slotDirViewToggle(); 1987 } 1988 1989 std::list<QWidget*> visibleWidgetList; 1990 if(m_pDiffTextWindow1 && m_pDiffTextWindow1->isVisible()) visibleWidgetList.push_back(m_pDiffTextWindow1); 1991 if(m_pDiffTextWindow2 && m_pDiffTextWindow2->isVisible()) visibleWidgetList.push_back(m_pDiffTextWindow2); 1992 if(m_pDiffTextWindow3 && m_pDiffTextWindow3->isVisible()) visibleWidgetList.push_back(m_pDiffTextWindow3); 1993 if(m_pMergeResultWindow && m_pMergeResultWindow->isVisible()) visibleWidgetList.push_back(m_pMergeResultWindow); 1994 if(m_bDirCompare /*m_pDirectoryMergeWindow->isVisible()*/) visibleWidgetList.push_back(m_pDirectoryMergeWindow); 1995 //if ( m_pDirectoryMergeInfo->isVisible() ) visibleWidgetList.push_back(m_pDirectoryMergeInfo->getInfoList()); 1996 if(visibleWidgetList.empty()) 1997 return; 1998 1999 std::list<QWidget*>::iterator i = std::find(visibleWidgetList.begin(), visibleWidgetList.end(), focus); 2000 ++i; 2001 if(i == visibleWidgetList.end()) 2002 i = visibleWidgetList.begin(); 2003 2004 if(*i == m_pDirectoryMergeWindow && !dirShowBoth->isChecked()) 2005 { 2006 slotDirViewToggle(); 2007 } 2008 (*i)->setFocus(); 2009 } 2010 2011 void KDiff3App::slotWinFocusPrev() 2012 { 2013 QWidget* focus = qApp->focusWidget(); 2014 if(focus == m_pDirectoryMergeWindow && m_pDirectoryMergeWindow->isVisible() && !dirShowBoth->isChecked()) 2015 { 2016 slotDirViewToggle(); 2017 } 2018 2019 std::list<QWidget*> visibleWidgetList; 2020 if(m_pDiffTextWindow1 && m_pDiffTextWindow1->isVisible()) visibleWidgetList.push_back(m_pDiffTextWindow1); 2021 if(m_pDiffTextWindow2 && m_pDiffTextWindow2->isVisible()) visibleWidgetList.push_back(m_pDiffTextWindow2); 2022 if(m_pDiffTextWindow3 && m_pDiffTextWindow3->isVisible()) visibleWidgetList.push_back(m_pDiffTextWindow3); 2023 if(m_pMergeResultWindow && m_pMergeResultWindow->isVisible()) visibleWidgetList.push_back(m_pMergeResultWindow); 2024 if(m_bDirCompare /* m_pDirectoryMergeWindow->isVisible() */) visibleWidgetList.push_back(m_pDirectoryMergeWindow); 2025 //if ( m_pDirectoryMergeInfo->isVisible() ) visibleWidgetList.push_back(m_pDirectoryMergeInfo->getInfoList()); 2026 if(visibleWidgetList.empty()) 2027 return; 2028 2029 std::list<QWidget*>::iterator i = std::find(visibleWidgetList.begin(), visibleWidgetList.end(), focus); 2030 if(i == visibleWidgetList.begin()) 2031 i = visibleWidgetList.end(); 2032 --i; 2033 //i will never be 2034 if(*i == m_pDirectoryMergeWindow && !dirShowBoth->isChecked()) 2035 { 2036 slotDirViewToggle(); 2037 } 2038 (*i)->setFocus(); 2039 } 2040 2041 void KDiff3App::slotWinToggleSplitterOrientation() 2042 { 2043 if(m_pDiffWindowSplitter != nullptr) 2044 { 2045 m_pDiffWindowSplitter->setOrientation( 2046 m_pDiffWindowSplitter->orientation() == Qt::Vertical ? Qt::Horizontal : Qt::Vertical); 2047 2048 gOptions->m_bHorizDiffWindowSplitting = m_pDiffWindowSplitter->orientation() == Qt::Horizontal; 2049 } 2050 } 2051 2052 void KDiff3App::slotOverviewNormal() 2053 { 2054 Q_EMIT changeOverViewMode(e_OverviewMode::eOMNormal); 2055 2056 Q_EMIT updateAvailabilities(); 2057 } 2058 2059 void KDiff3App::slotOverviewAB() 2060 { 2061 Q_EMIT changeOverViewMode(e_OverviewMode::eOMAvsB); 2062 2063 Q_EMIT updateAvailabilities(); 2064 } 2065 2066 void KDiff3App::slotOverviewAC() 2067 { 2068 Q_EMIT changeOverViewMode(e_OverviewMode::eOMAvsC); 2069 2070 Q_EMIT updateAvailabilities(); 2071 } 2072 2073 void KDiff3App::slotOverviewBC() 2074 { 2075 Q_EMIT changeOverViewMode(e_OverviewMode::eOMBvsC); 2076 2077 Q_EMIT updateAvailabilities(); 2078 } 2079 2080 void KDiff3App::slotNoRelevantChangesDetected() 2081 { 2082 if(m_bTripleDiff && !m_outputFilename.isEmpty()) 2083 { 2084 //KMessageBox::information( this, "No relevant changes detected", "KDiff3" ); 2085 if(!gOptions->m_IrrelevantMergeCmd.isEmpty()) 2086 { 2087 /* 2088 QProcess doesn't check for single quotes and uses non-standard escaping syntax for double quotes. 2089 The distinction between single and double quotes is purely a command shell issue. So 2090 we split the command string ourselves. 2091 */ 2092 QStringList args; 2093 QString program; 2094 Utils::getArguments(gOptions->m_IrrelevantMergeCmd, program, args); 2095 QProcess process; 2096 process.start(program, args); 2097 process.waitForFinished(-1); 2098 } 2099 } 2100 } 2101 2102 void KDiff3App::slotAddManualDiffHelp() 2103 { 2104 LineRef firstLine; 2105 LineRef lastLine; 2106 e_SrcSelector winIdx = e_SrcSelector::Invalid; 2107 if(m_pDiffTextWindow1) 2108 { 2109 m_pDiffTextWindow1->getSelectionRange(&firstLine, &lastLine, eFileCoords); 2110 winIdx = e_SrcSelector::A; 2111 } 2112 if(!firstLine.isValid() && m_pDiffTextWindow2) 2113 { 2114 m_pDiffTextWindow2->getSelectionRange(&firstLine, &lastLine, eFileCoords); 2115 winIdx = e_SrcSelector::B; 2116 } 2117 if(!firstLine.isValid() && m_pDiffTextWindow3) 2118 { 2119 m_pDiffTextWindow3->getSelectionRange(&firstLine, &lastLine, eFileCoords); 2120 winIdx = e_SrcSelector::C; 2121 } 2122 2123 if(!firstLine.isValid() || !lastLine.isValid() || lastLine < firstLine) 2124 KMessageBox::information(this, i18n("Nothing is selected in either diff input window."), i18n("Error while adding manual diff range")); 2125 else 2126 { 2127 m_manualDiffHelpList.insertEntry(winIdx, firstLine, lastLine); 2128 2129 mainInit(m_totalDiffStatus, InitFlag::autoSolve | InitFlag::initGUI); // Init without reload 2130 slotRefresh(); 2131 } 2132 } 2133 2134 void KDiff3App::slotClearManualDiffHelpList() 2135 { 2136 m_manualDiffHelpList.clear(); 2137 mainInit(m_totalDiffStatus, InitFlag::autoSolve | InitFlag::initGUI); // Init without reload 2138 slotRefresh(); 2139 } 2140 2141 void KDiff3App::slotEncodingChanged(const QByteArray&) 2142 { 2143 mainInit(m_totalDiffStatus, InitFlag::loadFiles | InitFlag::useCurrentEncoding | InitFlag::autoSolve); // Init with reload 2144 slotRefresh(); 2145 } 2146 2147 void KDiff3App::slotUpdateAvailabilities() 2148 { 2149 if(m_pDiffTextWindow2 == nullptr || m_pDiffTextWindow1 == nullptr || m_pDiffTextWindow3 == nullptr) 2150 return; 2151 2152 bool bTextDataAvailable = (m_sd1->hasData() || m_sd2->hasData() || m_sd3->hasData()); 2153 2154 if(dirShowBoth->isChecked()) 2155 { 2156 if(m_pDirectoryMergeDock != nullptr) 2157 m_pDirectoryMergeDock->setVisible(m_bDirCompare); 2158 if(m_pDirectoryMergeInfoDock != nullptr) 2159 m_pDirectoryMergeInfoDock->setVisible(m_bDirCompare); 2160 2161 if(!m_pMainWidget->isVisible() && 2162 bTextDataAvailable && !m_pDirectoryMergeWindow->isScanning()) 2163 m_pMainWidget->show(); 2164 } 2165 2166 bool bDiffWindowVisible = m_pMainWidget->isVisible(); 2167 bool bMergeEditorVisible = m_pMergeWindowFrame != nullptr && m_pMergeWindowFrame->isVisible() && m_pMergeResultWindow != nullptr; 2168 2169 m_pDirectoryMergeWindow->updateAvailabilities(bMergeEditorVisible, m_bDirCompare, bDiffWindowVisible, chooseA, chooseB, chooseC); 2170 2171 dirShowBoth->setEnabled(m_bDirCompare); 2172 dirViewToggle->setEnabled( 2173 m_bDirCompare && 2174 (m_pDirectoryMergeDock != nullptr && m_pDirectoryMergeInfoDock != nullptr && 2175 ((!m_pDirectoryMergeDock->isVisible() && m_pMainWidget->isVisible()) || 2176 (m_pDirectoryMergeDock->isVisible() && !m_pMainWidget->isVisible() && bTextDataAvailable)))); 2177 2178 showWhiteSpaceCharacters->setEnabled(bDiffWindowVisible); 2179 autoAdvance->setEnabled(bMergeEditorVisible); 2180 mAutoSolve->setEnabled(bMergeEditorVisible && m_bTripleDiff); 2181 mUnsolve->setEnabled(bMergeEditorVisible); 2182 2183 editUndo->setEnabled(false); //Not yet implemented but planned. 2184 editCut->setEnabled(allowCut()); 2185 editCopy->setEnabled(allowCopy()); 2186 2187 mMergeHistory->setEnabled(bMergeEditorVisible); 2188 mergeRegExp->setEnabled(bMergeEditorVisible); 2189 showWindowA->setEnabled(bDiffWindowVisible && (m_pDiffTextWindow2->isVisible() || m_pDiffTextWindow3->isVisible())); 2190 showWindowB->setEnabled(bDiffWindowVisible && (m_pDiffTextWindow1->isVisible() || m_pDiffTextWindow3->isVisible())); 2191 showWindowC->setEnabled(bDiffWindowVisible && m_bTripleDiff && (m_pDiffTextWindow1->isVisible() || m_pDiffTextWindow2->isVisible())); 2192 editFind->setEnabled(bDiffWindowVisible); 2193 editFindNext->setEnabled(bDiffWindowVisible); 2194 m_pFindDialog->m_pSearchInC->setEnabled(m_bTripleDiff); 2195 m_pFindDialog->m_pSearchInOutput->setEnabled(bMergeEditorVisible); 2196 2197 bool bSavable = bMergeEditorVisible && m_pMergeResultWindow->getNumberOfUnsolvedConflicts() == 0; 2198 fileSave->setEnabled(m_bOutputModified && bSavable); 2199 fileSaveAs->setEnabled(bSavable); 2200 2201 mGoTop->setEnabled(bDiffWindowVisible && m_pMergeResultWindow != nullptr && m_pMergeResultWindow->isDeltaAboveCurrent()); 2202 mGoBottom->setEnabled(bDiffWindowVisible && m_pMergeResultWindow != nullptr && m_pMergeResultWindow->isDeltaBelowCurrent()); 2203 mGoCurrent->setEnabled(bDiffWindowVisible); 2204 mGoPrevUnsolvedConflict->setEnabled(bMergeEditorVisible && m_pMergeResultWindow->isUnsolvedConflictAboveCurrent()); 2205 mGoNextUnsolvedConflict->setEnabled(bMergeEditorVisible && m_pMergeResultWindow->isUnsolvedConflictBelowCurrent()); 2206 mGoPrevConflict->setEnabled(bDiffWindowVisible && bMergeEditorVisible && m_pMergeResultWindow->isConflictAboveCurrent()); 2207 mGoNextConflict->setEnabled(bDiffWindowVisible && bMergeEditorVisible && m_pMergeResultWindow->isConflictBelowCurrent()); 2208 mGoPrevDelta->setEnabled(bDiffWindowVisible && m_pMergeResultWindow != nullptr && m_pMergeResultWindow->isDeltaAboveCurrent()); 2209 mGoNextDelta->setEnabled(bDiffWindowVisible && m_pMergeResultWindow != nullptr && m_pMergeResultWindow->isDeltaBelowCurrent()); 2210 2211 overviewModeNormal->setEnabled(m_bTripleDiff && bDiffWindowVisible); 2212 overviewModeAB->setEnabled(m_bTripleDiff && bDiffWindowVisible); 2213 overviewModeAC->setEnabled(m_bTripleDiff && bDiffWindowVisible); 2214 overviewModeBC->setEnabled(m_bTripleDiff && bDiffWindowVisible); 2215 e_OverviewMode overviewMode = m_pOverview == nullptr ? e_OverviewMode::eOMNormal : m_pOverview->getOverviewMode(); 2216 overviewModeNormal->setChecked(overviewMode == e_OverviewMode::eOMNormal); 2217 overviewModeAB->setChecked(overviewMode == e_OverviewMode::eOMAvsB); 2218 overviewModeAC->setChecked(overviewMode == e_OverviewMode::eOMAvsC); 2219 overviewModeBC->setChecked(overviewMode == e_OverviewMode::eOMBvsC); 2220 2221 winToggleSplitOrientation->setEnabled(bDiffWindowVisible && m_pDiffWindowSplitter != nullptr); 2222 }