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"