File indexing completed on 2024-04-21 05:43:03

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