File indexing completed on 2024-05-05 10:04:51
0001 /* 0002 SPDX-FileCopyrightText: 2001-2005, 2009 Otto Bruggeman <bruggie@gmail.com> 0003 SPDX-FileCopyrightText: 2001-2003 John Firebaugh <jfirebaugh@kde.org> 0004 SPDX-FileCopyrightText: 2007-2011 Kevin Kofler <kevin.kofler@chello.at> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "komparenavtreepart.h" 0010 0011 #include <QDebug> 0012 #include <QTreeWidgetItemIterator> 0013 0014 #include <KLocalizedString> 0015 #include <KPluginMetaData> 0016 #include <KPluginFactory> 0017 0018 #include <KompareDiff2/Difference> 0019 #include <KompareDiff2/DiffModel> 0020 #include <KompareDiff2/DiffModelList> 0021 #include <KompareDiff2/KompareModelList> 0022 0023 #include <komparenavviewdebug.h> 0024 0025 #define COL_SOURCE 0 0026 #define COL_DESTINATION 1 0027 #define COL_DIFFERENCE 2 0028 0029 using namespace Diff2; 0030 0031 KompareNavTreePart::KompareNavTreePart(QWidget* parentWidget, QObject* parent, 0032 const KPluginMetaData& metaData, const QVariantList&) 0033 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0034 : KParts::ReadOnlyPart(parent, metaData), 0035 #else 0036 : KParts::ReadOnlyPart(parent), 0037 #endif 0038 m_splitter(nullptr), 0039 m_modelList(nullptr), 0040 m_srcDirTree(nullptr), 0041 m_destDirTree(nullptr), 0042 m_fileList(nullptr), 0043 m_changesList(nullptr), 0044 m_srcRootItem(nullptr), 0045 m_destRootItem(nullptr), 0046 m_selectedModel(nullptr), 0047 m_selectedDifference(nullptr), 0048 m_source(), 0049 m_destination(), 0050 m_info(nullptr) 0051 { 0052 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0053 setMetaData(metaData); 0054 #endif 0055 0056 m_splitter = new QSplitter(Qt::Horizontal, parentWidget); 0057 0058 setWidget(m_splitter); 0059 0060 m_srcDirTree = new QTreeWidget(m_splitter); 0061 m_srcDirTree->setHeaderLabel(i18nc("@title:column", "Source Folder")); 0062 m_srcDirTree->setRootIsDecorated(false); 0063 m_srcDirTree->setSortingEnabled(true); 0064 m_srcDirTree->sortByColumn(0, Qt::AscendingOrder); 0065 0066 m_destDirTree = new QTreeWidget(m_splitter); 0067 m_destDirTree->setHeaderLabel(i18nc("@title:column", "Destination Folder")); 0068 m_destDirTree->setRootIsDecorated(false); 0069 m_destDirTree->setSortingEnabled(true); 0070 m_destDirTree->sortByColumn(0, Qt::AscendingOrder); 0071 0072 m_fileList = new QTreeWidget(m_splitter); 0073 m_fileList->setHeaderLabels(QStringList { 0074 i18nc("@title:column", "Source File"), 0075 i18nc("@title:column", "Destination File") 0076 } ); 0077 m_fileList->setAllColumnsShowFocus(true); 0078 m_fileList->setRootIsDecorated(false); 0079 m_fileList->setSortingEnabled(true); 0080 m_fileList->sortByColumn(0, Qt::AscendingOrder); 0081 0082 m_changesList = new QTreeWidget(m_splitter); 0083 m_changesList->setHeaderLabels(QStringList { 0084 i18nc("@title:column", "Source Line"), 0085 i18nc("@title:column", "Destination Line"), 0086 i18nc("@title:column", "Difference"), 0087 } ); 0088 m_changesList->setAllColumnsShowFocus(true); 0089 m_changesList->setRootIsDecorated(false); 0090 m_changesList->setSortingEnabled(true); 0091 m_changesList->sortByColumn(0, Qt::AscendingOrder); 0092 0093 connect(m_srcDirTree, &QTreeWidget::currentItemChanged, 0094 this, &KompareNavTreePart::slotSrcDirTreeSelectionChanged); 0095 connect(m_destDirTree, &QTreeWidget::currentItemChanged, 0096 this, &KompareNavTreePart::slotDestDirTreeSelectionChanged); 0097 connect(m_fileList, &QTreeWidget::currentItemChanged, 0098 this, &KompareNavTreePart::slotFileListSelectionChanged); 0099 connect(m_changesList, &QTreeWidget::currentItemChanged, 0100 this, &KompareNavTreePart::slotChangesListSelectionChanged); 0101 } 0102 0103 KompareNavTreePart::~KompareNavTreePart() 0104 { 0105 m_modelList = nullptr; 0106 m_selectedModel = nullptr; 0107 m_selectedDifference = nullptr; 0108 } 0109 0110 void KompareNavTreePart::slotKompareInfo(struct Kompare::Info* info) 0111 { 0112 m_info = info; 0113 } 0114 0115 void KompareNavTreePart::slotModelsChanged(const DiffModelList* modelList) 0116 { 0117 qCDebug(KOMPARENAVVIEW) << "Models (" << modelList << ") have changed... scanning the models... " ; 0118 0119 if (modelList) 0120 { 0121 m_modelList = modelList; 0122 m_srcDirTree->clear(); 0123 m_destDirTree->clear(); 0124 m_fileList->clear(); 0125 m_changesList->clear(); 0126 buildTreeInMemory(); 0127 } 0128 else 0129 { 0130 m_modelList = modelList; 0131 m_srcDirTree->clear(); 0132 m_destDirTree->clear(); 0133 m_fileList->clear(); 0134 m_changesList->clear(); 0135 } 0136 } 0137 0138 void KompareNavTreePart::buildTreeInMemory() 0139 { 0140 qCDebug(KOMPARENAVVIEW) << "BuildTreeInMemory called" ; 0141 0142 if (m_modelList->count() == 0) 0143 { 0144 qCDebug(KOMPARENAVVIEW) << "No models... weird shit..." ; 0145 return; // avoids a crash on clear() 0146 } 0147 0148 if (!m_info) 0149 { 0150 qCDebug(KOMPARENAVVIEW) << "No Info... weird shit..." ; 0151 return; 0152 } 0153 0154 QString srcBase; 0155 QString destBase; 0156 0157 DiffModel* model; 0158 model = m_modelList->first(); 0159 m_selectedModel = nullptr; 0160 0161 switch (m_info->mode) 0162 { 0163 case Kompare::ShowingDiff: 0164 // BUG: 107489 No common root because it is a multi directory relative path diff 0165 // We need to detect this and create a different rootitem / or so or should we always add this? 0166 // Trouble we run into is that the directories do not start with a / 0167 // so we have an unknown top root dir 0168 // Thinking some more about it i guess it is best to use "" as base and simply show some string 0169 // like Unknown filesystem path as root text but only in the case of dirs starting without a / 0170 srcBase = model->sourcePath(); 0171 destBase = model->destinationPath(); 0172 // FIXME: these tests will not work on windows, we need something else 0173 if (srcBase[0] != QLatin1Char('/')) 0174 srcBase.clear(); 0175 if (destBase[0] != QLatin1Char('/')) 0176 destBase.clear(); 0177 break; 0178 case Kompare::ComparingFiles: 0179 srcBase = model->sourcePath(); 0180 destBase = model->destinationPath(); 0181 break; 0182 case Kompare::ComparingDirs: 0183 srcBase = m_info->localSource; 0184 if (!srcBase.endsWith(QLatin1Char('/'))) 0185 srcBase += QLatin1Char('/'); 0186 destBase = m_info->localDestination; 0187 if (!destBase.endsWith(QLatin1Char('/'))) 0188 destBase += QLatin1Char('/'); 0189 break; 0190 case Kompare::BlendingFile: 0191 case Kompare::BlendingDir: 0192 default: 0193 qCDebug(KOMPARENAVVIEW) << "Oops needs to implement this..." ; 0194 } 0195 0196 // qCDebug(KOMPARENAVVIEW) << "srcBase = " << srcBase ; 0197 // qCDebug(KOMPARENAVVIEW) << "destBase = " << destBase ; 0198 0199 m_srcRootItem = new KDirLVI(m_srcDirTree, srcBase); 0200 m_destRootItem = new KDirLVI(m_destDirTree, destBase); 0201 0202 QString srcPath; 0203 QString destPath; 0204 0205 // Create the tree from the models 0206 DiffModelListConstIterator modelIt = m_modelList->begin(); 0207 DiffModelListConstIterator mEnd = m_modelList->end(); 0208 0209 for (; modelIt != mEnd; ++modelIt) 0210 { 0211 model = *modelIt; 0212 srcPath = model->sourcePath(); 0213 destPath = model->destinationPath(); 0214 0215 qCDebug(KOMPARENAVVIEW) << "srcPath = " << srcPath ; 0216 qCDebug(KOMPARENAVVIEW) << "destPath = " << destPath ; 0217 m_srcRootItem->addModel(srcPath, model, &m_modelToSrcDirItemDict); 0218 m_destRootItem->addModel(destPath, model, &m_modelToDestDirItemDict); 0219 } 0220 // m_srcDirTree->setSelected( m_srcDirTree->firstChild(), true ); 0221 } 0222 0223 void KompareNavTreePart::buildDirectoryTree() 0224 { 0225 // FIXME: afaict this can be deleted 0226 // qCDebug(KOMPARENAVVIEW) << "BuildDirTree called" ; 0227 } 0228 0229 QString KompareNavTreePart::compareFromEndAndReturnSame( 0230 const QString& string1, 0231 const QString& string2) 0232 { 0233 QString result; 0234 0235 int srcLen = string1.length(); 0236 int destLen = string2.length(); 0237 0238 while (srcLen != 0 && destLen != 0) 0239 { 0240 if (string1[--srcLen] == string2[--destLen]) 0241 result.prepend(string1[srcLen]); 0242 else 0243 break; 0244 } 0245 0246 if (srcLen != 0 && destLen != 0 && result.startsWith(QLatin1Char('/'))) 0247 result = result.remove(0, 1); // strip leading /, we need it later 0248 0249 return result; 0250 } 0251 0252 void KompareNavTreePart::slotSetSelection(const DiffModel* model, const Difference* diff) 0253 { 0254 qCDebug(KOMPARENAVVIEW) << "KompareNavTreePart::slotSetSelection model = " << model << ", diff = " << diff ; 0255 if (model == m_selectedModel) 0256 { 0257 // model is the same, so no need to update that... 0258 if (diff != m_selectedDifference) 0259 { 0260 m_selectedDifference = diff; 0261 setSelectedDifference(diff); 0262 } 0263 return; 0264 } 0265 0266 // model is different so we need to find the right dirs, file and changeitems to select 0267 // if m_selectedModel == NULL then everything needs to be done as well 0268 if (!m_selectedModel || model->sourcePath() != m_selectedModel->sourcePath()) 0269 { // dirs are different, so we need to update the dirviews as well 0270 m_selectedModel = model; 0271 m_selectedDifference = diff; 0272 0273 setSelectedDir(model); 0274 setSelectedFile(model); 0275 setSelectedDifference(diff); 0276 return; 0277 } 0278 0279 if (!m_selectedModel || model->sourceFile() != m_selectedModel->sourceFile()) 0280 { 0281 m_selectedModel = model; 0282 setSelectedFile(model); 0283 0284 m_selectedDifference = diff; 0285 setSelectedDifference(diff); 0286 } 0287 } 0288 0289 void KompareNavTreePart::setSelectedDir(const DiffModel* model) 0290 { 0291 KDirLVI* currentDir; 0292 currentDir = m_modelToSrcDirItemDict[ model ]; 0293 qCDebug(KOMPARENAVVIEW) << "Manually setting selection in srcdirtree with currentDir = " << currentDir ; 0294 m_srcDirTree->blockSignals(true); 0295 m_srcDirTree->setCurrentItem(currentDir); 0296 m_srcDirTree->scrollToItem(currentDir); 0297 m_srcDirTree->blockSignals(false); 0298 0299 currentDir = m_modelToDestDirItemDict[ model ]; 0300 qCDebug(KOMPARENAVVIEW) << "Manually setting selection in destdirtree with currentDir = " << currentDir ; 0301 m_destDirTree->blockSignals(true); 0302 m_destDirTree->setCurrentItem(currentDir); 0303 m_destDirTree->scrollToItem(currentDir); 0304 m_destDirTree->blockSignals(false); 0305 0306 m_fileList->blockSignals(true); 0307 currentDir->fillFileList(m_fileList, &m_modelToFileItemDict); 0308 m_fileList->blockSignals(false); 0309 } 0310 0311 void KompareNavTreePart::setSelectedFile(const DiffModel* model) 0312 { 0313 KFileLVI* currentFile; 0314 currentFile = m_modelToFileItemDict[ model ]; 0315 qCDebug(KOMPARENAVVIEW) << "Manually setting selection in filelist" ; 0316 m_fileList->blockSignals(true); 0317 m_fileList->setCurrentItem(currentFile); 0318 m_fileList->scrollToItem(currentFile); 0319 m_fileList->blockSignals(false); 0320 0321 m_changesList->blockSignals(true); 0322 currentFile->fillChangesList(m_changesList, &m_diffToChangeItemDict); 0323 m_changesList->blockSignals(false); 0324 } 0325 0326 void KompareNavTreePart::setSelectedDifference(const Difference* diff) 0327 { 0328 KChangeLVI* currentDiff; 0329 currentDiff = m_diffToChangeItemDict[ diff ]; 0330 qCDebug(KOMPARENAVVIEW) << "Manually setting selection in changeslist to " << currentDiff ; 0331 m_changesList->blockSignals(true); 0332 m_changesList->setCurrentItem(currentDiff); 0333 m_changesList->scrollToItem(currentDiff); 0334 m_changesList->blockSignals(false); 0335 } 0336 0337 void KompareNavTreePart::slotSetSelection(const Difference* diff) 0338 { 0339 // qCDebug(KOMPARENAVVIEW) << "Scotty i need more power !!" ; 0340 if (m_selectedDifference != diff) 0341 { 0342 // qCDebug(KOMPARENAVVIEW) << "But sir, i am giving you all she's got" ; 0343 m_selectedDifference = diff; 0344 setSelectedDifference(diff); 0345 } 0346 } 0347 0348 void KompareNavTreePart::slotSrcDirTreeSelectionChanged(QTreeWidgetItem* item) 0349 { 0350 if (!item) 0351 return; 0352 0353 qCDebug(KOMPARENAVVIEW) << "Sent by the sourceDirectoryTree with item = " << item ; 0354 m_srcDirTree->scrollToItem(item); 0355 KDirLVI* dir = static_cast<KDirLVI*>(item); 0356 // order the dest tree view to set its selected item to the same as here 0357 QString path; 0358 // We start with an empty path and after the call path contains the full path 0359 path = dir->fullPath(path); 0360 KDirLVI* selItem = m_destRootItem->setSelected(path); 0361 m_destDirTree->blockSignals(true); 0362 m_destDirTree->setCurrentItem(selItem); 0363 m_destDirTree->scrollToItem(selItem); 0364 m_destDirTree->blockSignals(false); 0365 // fill the changes list 0366 dir->fillFileList(m_fileList, &m_modelToFileItemDict); 0367 } 0368 0369 void KompareNavTreePart::slotDestDirTreeSelectionChanged(QTreeWidgetItem* item) 0370 { 0371 if (!item) 0372 return; 0373 0374 qCDebug(KOMPARENAVVIEW) << "Sent by the destinationDirectoryTree with item = " << item ; 0375 m_destDirTree->scrollToItem(item); 0376 KDirLVI* dir = static_cast<KDirLVI*>(item); 0377 // order the src tree view to set its selected item to the same as here 0378 QString path; 0379 // We start with an empty path and after the call path contains the full path 0380 path = dir->fullPath(path); 0381 KDirLVI* selItem = m_srcRootItem->setSelected(path); 0382 m_srcDirTree->blockSignals(true); 0383 m_srcDirTree->setCurrentItem(selItem); 0384 m_srcDirTree->scrollToItem(selItem); 0385 m_srcDirTree->blockSignals(false); 0386 // fill the changes list 0387 dir->fillFileList(m_fileList, &m_modelToFileItemDict); 0388 } 0389 0390 void KompareNavTreePart::slotFileListSelectionChanged(QTreeWidgetItem* item) 0391 { 0392 if (!item) 0393 return; 0394 0395 qCDebug(KOMPARENAVVIEW) << "Sent by the fileList with item = " << item ; 0396 0397 KFileLVI* file = static_cast<KFileLVI*>(item); 0398 m_selectedModel = file->model(); 0399 m_changesList->blockSignals(true); 0400 file->fillChangesList(m_changesList, &m_diffToChangeItemDict); 0401 m_changesList->blockSignals(false); 0402 0403 if (m_changesList->currentItem()) 0404 { 0405 // FIXME: This is ugly... 0406 m_selectedDifference = (static_cast<KChangeLVI*>(m_changesList->currentItem()))->difference(); 0407 } 0408 0409 Q_EMIT selectionChanged(m_selectedModel, m_selectedDifference); 0410 } 0411 0412 void KompareNavTreePart::slotChangesListSelectionChanged(QTreeWidgetItem* item) 0413 { 0414 if (!item) 0415 return; 0416 0417 qCDebug(KOMPARENAVVIEW) << "Sent by the changesList" ; 0418 0419 KChangeLVI* change = static_cast<KChangeLVI*>(item); 0420 m_selectedDifference = change->difference(); 0421 0422 Q_EMIT selectionChanged(m_selectedDifference); 0423 } 0424 0425 void KompareNavTreePart::slotApplyDifference(bool /*apply*/) 0426 { 0427 KChangeLVI* clvi = m_diffToChangeItemDict[m_selectedDifference]; 0428 if (clvi) 0429 clvi->setDifferenceText(); 0430 } 0431 0432 void KompareNavTreePart::slotApplyAllDifferences(bool /*apply*/) 0433 { 0434 QHash<const Diff2::Difference*, KChangeLVI*>::ConstIterator it = m_diffToChangeItemDict.constBegin(); 0435 QHash<const Diff2::Difference*, KChangeLVI*>::ConstIterator end = m_diffToChangeItemDict.constEnd(); 0436 0437 qCDebug(KOMPARENAVVIEW) << "m_diffToChangeItemDict.count() = " << m_diffToChangeItemDict.count() ; 0438 0439 for (; it != end ; ++it) 0440 { 0441 it.value()->setDifferenceText(); 0442 } 0443 } 0444 0445 void KompareNavTreePart::slotApplyDifference(const Difference* diff, bool /*apply*/) 0446 { 0447 // this applies to the currently selected difference 0448 KChangeLVI* clvi = m_diffToChangeItemDict[diff]; 0449 if (clvi) 0450 clvi->setDifferenceText(); 0451 } 0452 0453 void KChangeLVI::setDifferenceText() 0454 { 0455 QString text; 0456 switch (m_difference->type()) { 0457 case Difference::Change: 0458 // Shouldn't this simply be diff->sourceLineCount() ? 0459 // because you change the _number of lines_ lines in source, not in dest 0460 if (m_difference->applied()) 0461 text = i18np("Applied: Changes made to %1 line undone", "Applied: Changes made to %1 lines undone", 0462 m_difference->sourceLineCount()); 0463 else 0464 text = i18np("Changed %1 line", "Changed %1 lines", 0465 m_difference->sourceLineCount()); 0466 break; 0467 case Difference::Insert: 0468 if (m_difference->applied()) 0469 text = i18np("Applied: Insertion of %1 line undone", "Applied: Insertion of %1 lines undone", 0470 m_difference->destinationLineCount()); 0471 else 0472 text = i18np("Inserted %1 line", "Inserted %1 lines", 0473 m_difference->destinationLineCount()); 0474 break; 0475 case Difference::Delete: 0476 if (m_difference->applied()) 0477 text = i18np("Applied: Deletion of %1 line undone", "Applied: Deletion of %1 lines undone", 0478 m_difference->sourceLineCount()); 0479 else 0480 text = i18np("Deleted %1 line", "Deleted %1 lines", 0481 m_difference->sourceLineCount()); 0482 break; 0483 default: 0484 qCDebug(KOMPARENAVVIEW) << "Unknown or Unchanged enum value when checking for diff->type() in KChangeLVI's constructor" ; 0485 text.clear(); 0486 } 0487 0488 setText(2, text); 0489 } 0490 0491 KChangeLVI::KChangeLVI(QTreeWidget* parent, Difference* diff) : QTreeWidgetItem(parent) 0492 { 0493 m_difference = diff; 0494 0495 setText(0, QString::number(diff->sourceLineNumber())); 0496 setText(1, QString::number(diff->destinationLineNumber())); 0497 0498 setDifferenceText(); 0499 } 0500 0501 bool KChangeLVI::operator<(const QTreeWidgetItem& item) const 0502 { 0503 int column = treeWidget()->sortColumn(); 0504 QString text1 = text(column); 0505 QString text2 = item.text(column); 0506 0507 // Compare the numbers. 0508 if (column < 2 && text1.length() != text2.length()) 0509 return text1.length() < text2.length(); 0510 return text1 < text2; 0511 } 0512 0513 KChangeLVI::~KChangeLVI() 0514 { 0515 } 0516 0517 KFileLVI::KFileLVI(QTreeWidget* parent, DiffModel* model) : QTreeWidgetItem(parent) 0518 { 0519 m_model = model; 0520 0521 QString src = model->sourceFile(); 0522 QString dst = model->destinationFile(); 0523 0524 setText(0, src); 0525 setText(1, dst); 0526 setIcon(0, QIcon::fromTheme(getIcon(src))); 0527 setIcon(1, QIcon::fromTheme(getIcon(dst))); 0528 } 0529 0530 bool KFileLVI::hasExtension(const QString& extensions, const QString& fileName) 0531 { 0532 const QStringList extList = extensions.split(QLatin1Char(' ')); 0533 for (const QString& ext : extList) { 0534 if (fileName.endsWith(ext, Qt::CaseInsensitive)) { 0535 return true; 0536 } 0537 } 0538 return false; 0539 } 0540 0541 const QString KFileLVI::getIcon(const QString& fileName) 0542 { 0543 // C++, C 0544 if (hasExtension(QStringLiteral(".h .hpp"), fileName)) { 0545 return QStringLiteral("text-x-c++hdr"); 0546 } 0547 if (hasExtension(QStringLiteral(".cpp"), fileName)) { 0548 return QStringLiteral("text-x-c++src"); 0549 } 0550 if (hasExtension(QStringLiteral(".c"), fileName)) { 0551 return QStringLiteral("text-x-csrc"); 0552 } 0553 // Python 0554 if (hasExtension(QStringLiteral(".py .pyw"), fileName)) { 0555 return QStringLiteral("text-x-python"); 0556 } 0557 // C# 0558 if (hasExtension(QStringLiteral(".cs"), fileName)) { 0559 return QStringLiteral("text-x-csharp"); 0560 } 0561 // Objective-C 0562 if (hasExtension(QStringLiteral(".m"), fileName)) { 0563 return QStringLiteral("text-x-objcsrc"); 0564 } 0565 // Java 0566 if (hasExtension(QStringLiteral(".java"), fileName)) { 0567 return QStringLiteral("text-x-java"); 0568 } 0569 // Script 0570 if (hasExtension(QStringLiteral(".sh"), fileName)) { 0571 return QStringLiteral("text-x-script"); 0572 } 0573 // Makefile 0574 if (hasExtension(QStringLiteral(".cmake Makefile"), fileName)) { 0575 return QStringLiteral("text-x-makefile"); 0576 } 0577 // Ada 0578 if (hasExtension(QStringLiteral(".ada .ads .adb"), fileName)) { 0579 return QStringLiteral("text-x-adasrc"); 0580 } 0581 // Pascal 0582 if (hasExtension(QStringLiteral(".pas"), fileName)) { 0583 return QStringLiteral("text-x-pascal"); 0584 } 0585 // Patch 0586 if (hasExtension(QStringLiteral(".diff"), fileName)) { 0587 return QStringLiteral("text-x-patch"); 0588 } 0589 // Tcl 0590 if (hasExtension(QStringLiteral(".tcl"), fileName)) { 0591 return QStringLiteral("text-x-tcl"); 0592 } 0593 // Text 0594 if (hasExtension(QStringLiteral(".txt"), fileName)) { 0595 return QStringLiteral("text-plain"); 0596 } 0597 // Xml 0598 if (hasExtension(QStringLiteral(".xml"), fileName)) { 0599 return QStringLiteral("text-xml"); 0600 } 0601 // unknown or no file extension 0602 return QStringLiteral("text-plain"); 0603 } 0604 0605 void KFileLVI::fillChangesList(QTreeWidget* changesList, QHash<const Diff2::Difference*, KChangeLVI*>* diffToChangeItemDict) 0606 { 0607 changesList->clear(); 0608 diffToChangeItemDict->clear(); 0609 0610 DifferenceListConstIterator diffIt = m_model->differences()->constBegin(); 0611 DifferenceListConstIterator dEnd = m_model->differences()->constEnd(); 0612 0613 for (; diffIt != dEnd; ++diffIt) 0614 { 0615 KChangeLVI* change = new KChangeLVI(changesList, *diffIt); 0616 diffToChangeItemDict->insert(*diffIt, change); 0617 } 0618 0619 changesList->setCurrentItem(changesList->topLevelItem(0)); 0620 } 0621 0622 KFileLVI::~KFileLVI() 0623 { 0624 } 0625 0626 KDirLVI::KDirLVI(QTreeWidget* parent, const QString& dir) : QTreeWidgetItem(parent) 0627 { 0628 // qCDebug(KOMPARENAVVIEW) << "KDirLVI (QTreeWidget) constructor called with dir = " << dir ; 0629 m_rootItem = true; 0630 m_dirName = dir; 0631 setIcon(0, QIcon::fromTheme(QStringLiteral("folder"))); 0632 setExpanded(true); 0633 if (m_dirName.isEmpty()) 0634 setText(0, i18nc("@item directory name not known", "Unknown")); 0635 else 0636 setText(0, m_dirName); 0637 } 0638 0639 KDirLVI::KDirLVI(KDirLVI* parent, const QString& dir) : QTreeWidgetItem(parent) 0640 { 0641 // qCDebug(KOMPARENAVVIEW) << "KDirLVI (KDirLVI) constructor called with dir = " << dir ; 0642 m_rootItem = false; 0643 m_dirName = dir; 0644 setIcon(0, QIcon::fromTheme(QStringLiteral("folder"))); 0645 setExpanded(true); 0646 setText(0, m_dirName); 0647 } 0648 0649 // addModel always removes it own path from the beginning 0650 void KDirLVI::addModel(QString& path, DiffModel* model, QHash<const Diff2::DiffModel*, KDirLVI*>* modelToDirItemDict) 0651 { 0652 // qCDebug(KOMPARENAVVIEW) << "KDirLVI::addModel called with path = " << path << " from KDirLVI with m_dirName = " << m_dirName ; 0653 0654 if (!m_dirName.isEmpty()) 0655 { 0656 if (path.indexOf(m_dirName) > -1) 0657 path = path.remove(path.indexOf(m_dirName), m_dirName.length()); 0658 } 0659 0660 // qCDebug(KOMPARENAVVIEW) << "Path after removal of own dir (\"" << m_dirName << "\") = " << path ; 0661 0662 if (path.isEmpty()) { 0663 m_modelList.append(model); 0664 modelToDirItemDict->insert(model, this); 0665 return; 0666 } 0667 0668 KDirLVI* child; 0669 0670 QString dir = path.mid(0, path.indexOf(QLatin1Char('/'), 0) + 1); 0671 child = findChild(dir); 0672 if (!child) 0673 { 0674 // does not exist yet so make it 0675 // qCDebug(KOMPARENAVVIEW) << "KDirLVI::addModel creating new KDirLVI because not found" ; 0676 child = new KDirLVI(this, dir); 0677 } 0678 0679 child->addModel(path, model, modelToDirItemDict); 0680 } 0681 0682 KDirLVI* KDirLVI::findChild(const QString& dir) 0683 { 0684 // qCDebug(KOMPARENAVVIEW) << "KDirLVI::findChild called with dir = " << dir ; 0685 KDirLVI* child; 0686 if ((child = static_cast<KDirLVI*>(this->child(0))) != nullptr) 0687 { // has children, check if dir already exists, if so addModel 0688 QTreeWidgetItemIterator it(child); 0689 while (*it) { 0690 child = static_cast<KDirLVI*>(*it); 0691 0692 if (dir == child->dirName()) 0693 return child; 0694 ++it; 0695 } 0696 } 0697 0698 return nullptr; 0699 } 0700 0701 void KDirLVI::fillFileList(QTreeWidget* fileList, QHash<const Diff2::DiffModel*, KFileLVI*>* modelToFileItemDict) 0702 { 0703 fileList->clear(); 0704 0705 DiffModelListIterator modelIt = m_modelList.begin(); 0706 DiffModelListIterator mEnd = m_modelList.end(); 0707 for (; modelIt != mEnd; ++modelIt) 0708 { 0709 KFileLVI* file = new KFileLVI(fileList, *modelIt); 0710 modelToFileItemDict->insert(*modelIt, file); 0711 } 0712 0713 fileList->setCurrentItem(fileList->topLevelItem(0)); 0714 } 0715 0716 QString KDirLVI::fullPath(QString& path) 0717 { 0718 // if (!path.isEmpty()) 0719 // qCDebug(KOMPARENAVVIEW) << "KDirLVI::fullPath called with path = " << path ; 0720 // else 0721 // qCDebug(KOMPARENAVVIEW) << "KDirLVI::fullPath called with empty path..." ; 0722 0723 if (m_rootItem) // don't bother adding rootItem's dir... 0724 return path; 0725 0726 path = path.prepend(m_dirName); 0727 0728 KDirLVI* lviParent = dynamic_cast<KDirLVI*>(parent()); 0729 if (lviParent) 0730 { 0731 path = lviParent->fullPath(path); 0732 } 0733 0734 return path; 0735 } 0736 0737 KDirLVI* KDirLVI::setSelected(const QString& _dir) 0738 { 0739 QString dir(_dir); 0740 // qCDebug(KOMPARENAVVIEW) << "KDirLVI::setSelected called with dir = " << dir ; 0741 0742 // root item's dirName is never taken into account... remember that 0743 if (!m_rootItem) 0744 { 0745 dir = dir.remove(0, m_dirName.length()); 0746 } 0747 0748 if (dir.isEmpty()) 0749 { 0750 return this; 0751 } 0752 KDirLVI* child = static_cast<KDirLVI*>(this->child(0)); 0753 if (!child) 0754 return nullptr; 0755 0756 QTreeWidgetItemIterator it(child); 0757 while (*it) { 0758 child = static_cast<KDirLVI*>(*it); 0759 0760 if (dir.startsWith(child->dirName())) 0761 return child->setSelected(dir); 0762 ++it; 0763 } 0764 0765 return nullptr; 0766 } 0767 0768 KDirLVI::~KDirLVI() 0769 { 0770 m_modelList.clear(); 0771 } 0772 0773 K_PLUGIN_FACTORY_WITH_JSON(KompareNavTreePartFactory, "komparenavtreepart.json", 0774 registerPlugin<KompareNavTreePart>();) 0775 0776 #include "komparenavtreepart.moc" 0777 #include "moc_komparenavtreepart.cpp"