File indexing completed on 2025-05-04 05:17:22

0001 /*
0002 SPDX-FileCopyrightText: 2021 Hamed Masafi <hamed.masfi@gmail.com>
0003 
0004 SPDX-License-Identifier: GPL-3.0-or-later
0005 */
0006 
0007 #include "diffwindow.h"
0008 
0009 #include <KActionCollection>
0010 #include <KLocalizedString>
0011 
0012 #include <QDebug>
0013 #include <QDockWidget>
0014 #include <QTreeView>
0015 
0016 #include <core/editactionsmapper.h>
0017 #include <dialogs/diffopendialog.h>
0018 #include <entities/branch.h>
0019 #include <entities/tag.h>
0020 #include <entities/tree.h>
0021 #include <gitmanager.h>
0022 #include <models/difftreemodel.h>
0023 #include <models/filesmodel.h>
0024 #include <widgets/difftreeview.h>
0025 #include <widgets/diffwidget.h>
0026 
0027 DiffWindow::DiffWindow()
0028     : AppMainWindow()
0029 {
0030     init(true);
0031 }
0032 
0033 DiffWindow::DiffWindow(Git::Manager *git)
0034     : AppMainWindow()
0035     , mGit(git)
0036 {
0037     init(true);
0038 
0039     mOldBranch = git->currentBranch();
0040     const auto diffs = git->diffBranch(mOldBranch);
0041 
0042     for (const auto &f : diffs) {
0043         mDiffModel->addFile(f);
0044         mFilesModel->append(f.name());
0045     }
0046 
0047     mLeftStorage.setGitManager(git);
0048     mRightStorage.setPath(git->path());
0049     mDiffModel->sortItems();
0050 }
0051 
0052 DiffWindow::DiffWindow(QSharedPointer<Git::File> oldFile, QSharedPointer<Git::File> newFile)
0053     : AppMainWindow()
0054     , mOldFile(oldFile)
0055     , mNewFile(newFile)
0056 {
0057     init(false);
0058 
0059     mDiffWidget->setOldFile(oldFile);
0060     mDiffWidget->setNewFile(newFile);
0061     mDiffWidget->compare();
0062 }
0063 
0064 DiffWindow::DiffWindow(Git::Manager *git, const QString &oldBranch, const QString &newBranch)
0065     : AppMainWindow()
0066     , mGit(git)
0067     , mOldBranch(oldBranch)
0068     , mNewBranch(newBranch)
0069 {
0070     init(true);
0071 
0072     const auto diffs = git->diffBranches(oldBranch, newBranch);
0073 
0074     for (auto &f : diffs) {
0075         mDiffModel->addFile(f);
0076         //        qCDebug(KOMMIT_LOG) << f.name() << f.status();
0077         mFilesModel->append(f.name());
0078     }
0079     // mLeftStorage.set = mRightStorage = Git;
0080     mDiffModel->sortItems();
0081 }
0082 
0083 DiffWindow::DiffWindow(Git::Manager *git, QSharedPointer<Git::Tag> tag)
0084     : AppMainWindow()
0085     , mOldBranch(tag->name())
0086     , mNewBranch("Working dir")
0087 {
0088     init(true);
0089 
0090     auto tree = tag->commit()->tree();
0091     const auto diffs = git->diff(tree);
0092 
0093     for (auto &f : diffs) {
0094         mDiffModel->addFile(f);
0095         //        qCDebug(KOMMIT_LOG) << f.name() << f.status();
0096         mFilesModel->append(f.newFile());
0097     }
0098     mLeftStorage.setTree(tree);
0099     mRightStorage.setPath(git->path());
0100     mDiffModel->sortItems();
0101 }
0102 
0103 DiffWindow::DiffWindow(Git::Branch *oldBranch, Git::Branch *newBranch)
0104 {
0105     mLeftStorage.setTree(oldBranch->tree());
0106     mRightStorage.setTree(newBranch->tree());
0107 }
0108 
0109 DiffWindow::DiffWindow(Git::Manager *git, QSharedPointer<Git::Tree> leftTree)
0110 {
0111     init(true);
0112     mLeftStorage.setTree(leftTree);
0113     mRightStorage.setPath(git->path());
0114 
0115     const auto diffs = git->diff(leftTree);
0116 
0117     for (auto &f : diffs) {
0118         mDiffModel->addFile(f);
0119         //        qCDebug(KOMMIT_LOG) << f.name() << f.status();
0120         mFilesModel->append(f.newFile());
0121     }
0122 
0123     mDiffModel->sortItems();
0124 }
0125 
0126 DiffWindow::DiffWindow(const QString &oldDir, const QString &newDir)
0127 {
0128     init(true);
0129 
0130     mLeftDir = oldDir;
0131     mRightDir = newDir;
0132     compareDirs();
0133 
0134     mLeftStorage.setPath(oldDir);
0135     mRightStorage.setPath(newDir);
0136 }
0137 
0138 void DiffWindow::init(bool showSideBar)
0139 {
0140     auto mapper = new EditActionsMapper(this);
0141     mDiffWidget = new DiffWidget(this);
0142     mDiffWidget->showSameSize(true);
0143 
0144     mapper->init(actionCollection());
0145 
0146     setCentralWidget(mDiffWidget);
0147 
0148     mapper->addTextEdit(mDiffWidget->oldCodeEditor());
0149     mapper->addTextEdit(mDiffWidget->newCodeEditor());
0150     setWindowTitle(i18nc("@title:window", "Kommit Diff[*]"));
0151 
0152     mDock = new QDockWidget(this);
0153     mDock->setWindowTitle(i18nc("@title:window", "Tree"));
0154     mDock->setObjectName(QStringLiteral("treeViewDock"));
0155 
0156     mTreeView = new DiffTreeView(this);
0157     connect(mTreeView, &DiffTreeView::fileSelected, this, &DiffWindow::slotTreeViewFileSelected);
0158     mDock->setWidget(mTreeView);
0159     mDock->setAllowedAreas(Qt::AllDockWidgetAreas);
0160     addDockWidget(Qt::LeftDockWidgetArea, mDock);
0161 
0162     mFilesModel = new FilesModel(this);
0163     mDiffModel = new DiffTreeModel(this);
0164     mDiffModel->setShowRoot(true);
0165     //_treeView->setDiffModel(_diffModel, _filesModel);
0166 
0167     initActions();
0168     setupGUI(StandardWindowOption::Default, QStringLiteral("kommitdiffui.rc"));
0169 
0170     mDock->setVisible(showSideBar);
0171 
0172     mTreeView->setModels(mDiffModel, mFilesModel);
0173 }
0174 
0175 void DiffWindow::initActions()
0176 {
0177     auto actionCollection = this->actionCollection();
0178 
0179     auto viewHiddenCharsAction = actionCollection->addAction(QStringLiteral("view_hidden_chars"));
0180     viewHiddenCharsAction->setText(i18n("View hidden chars..."));
0181     viewHiddenCharsAction->setCheckable(true);
0182     connect(viewHiddenCharsAction, &QAction::triggered, mDiffWidget, &DiffWidget::showHiddenChars);
0183 
0184     auto viewSameSizeBlocksAction = actionCollection->addAction(QStringLiteral("view_same_size_blocks"), mDiffWidget, &DiffWidget::showSameSize);
0185     viewSameSizeBlocksAction->setText(i18n("Same size blocks"));
0186     viewSameSizeBlocksAction->setCheckable(true);
0187     viewSameSizeBlocksAction->setChecked(true);
0188 
0189     auto viewFilesInfo = actionCollection->addAction(QStringLiteral("view_files_info"), mDiffWidget, &DiffWidget::showFilesInfo);
0190     viewFilesInfo->setText(i18n("Show files names"));
0191     viewFilesInfo->setCheckable(true);
0192     viewFilesInfo->setChecked(true);
0193 
0194     auto showTreeDockAction = mDock->toggleViewAction();
0195     actionCollection->addAction(QStringLiteral("show_tree_dock"), showTreeDockAction);
0196     showTreeDockAction->setText(i18n("Show Tree"));
0197 
0198     auto reloadAction = actionCollection->addAction(QStringLiteral("file_reload"), mDiffWidget, &DiffWidget::compare);
0199     reloadAction->setText(i18n("Reload"));
0200 
0201     KStandardAction::quit(this, &QWidget::close, actionCollection);
0202     KStandardAction::open(this, &DiffWindow::fileOpen, actionCollection);
0203 
0204 #ifdef UNDEF
0205     auto settingsManager = new SettingsManager(mGit, this);
0206     KStandardAction::preferences(settingsManager, &SettingsManager::show, actionCollection);
0207 #endif
0208 }
0209 
0210 void DiffWindow::fileOpen()
0211 {
0212     DiffOpenDialog d(this);
0213     if (d.exec() != QDialog::Accepted)
0214         return;
0215 
0216     if (d.mode() == DiffOpenDialog::Dirs) {
0217         mLeftStorage.setPath(d.oldDir());
0218         mRightStorage.setPath(d.newDir());
0219         compareDirs();
0220     } else {
0221         mDiffWidget->setOldFile(QSharedPointer<Git::File>{new Git::File{d.oldFile()}});
0222         mDiffWidget->setNewFile(QSharedPointer<Git::File>{new Git::File{d.newFile()}});
0223         mDiffWidget->compare();
0224     }
0225 }
0226 
0227 void DiffWindow::slotTreeViewFileSelected(const QString &file)
0228 {
0229     // switch (mLeftStorage) {
0230     // case FileSystem:
0231     //     mDiffWidget->setOldFile(Git::File{mLeftDir + QLatin1Char('/') + file});
0232     //     break;
0233     // case Git:
0234     //     mDiffWidget->setOldFile({mGit, mOldBranch, file});
0235     //     break;
0236     // case NoStorage:
0237     //     return;
0238     // }
0239     // switch (mRightStorage) {
0240     // case FileSystem:
0241     //     mDiffWidget->setNewFile(Git::File{mRightDir + QLatin1Char('/') + file});
0242     //     break;
0243     // case Git:
0244     //     mDiffWidget->setNewFile({mGit, mNewBranch, file});
0245     //     break;
0246     // case NoStorage:
0247     //     return;
0248     // }
0249 
0250     mDiffWidget->setOldFile(mLeftStorage.file(file));
0251     mDiffWidget->setNewFile(mRightStorage.file(file));
0252 
0253     mDiffWidget->compare();
0254 }
0255 
0256 QString diffTypeText(const Diff::DiffType type)
0257 {
0258     switch (type) {
0259     case Diff::DiffType::Unchanged:
0260         return i18n("Unchanged");
0261     case Diff::DiffType::Added:
0262         return i18n("Added");
0263     case Diff::DiffType::Removed:
0264         return i18n("Removed");
0265     case Diff::DiffType::Modified:
0266         return i18n("Modified");
0267     }
0268     return {};
0269 }
0270 
0271 void DiffWindow::compareDirs()
0272 {
0273     auto map = Diff::diffDirs(mLeftDir, mRightDir);
0274     for (auto i = map.begin(); i != map.end(); ++i) {
0275         mDiffModel->addFile(i.key(), i.value());
0276     }
0277     mDiffModel->sortItems();
0278 
0279     mDock->show();
0280 }
0281 
0282 QSharedPointer<Git::File> DiffWindow::Storage::file(const QString &path) const
0283 {
0284     switch (mMode) {
0285     case Mode::NoStorage:
0286         break;
0287     case Mode::FileSystem:
0288         return QSharedPointer<Git::File>{new Git::File{mPath + path}};
0289     case Mode::Git:
0290         return QSharedPointer<Git::File>{new Git::File{mManager, "mNewBranch", path}};
0291     case Mode::Tree:
0292         return mTree->file(path);
0293     }
0294 
0295     return {};
0296 }
0297 
0298 void DiffWindow::Storage::setGitManager(Git::Manager *manager)
0299 {
0300     mMode = Mode::Git;
0301     mManager = manager;
0302 }
0303 
0304 void DiffWindow::Storage::setPath(const QString &path)
0305 {
0306     mPath = path;
0307     if (!mPath.endsWith("/"))
0308         mPath += "/";
0309     mMode = Mode::FileSystem;
0310 }
0311 
0312 void DiffWindow::Storage::setTree(QSharedPointer<Git::Tree> tree)
0313 {
0314     mTree = tree;
0315     mMode = Mode::Tree;
0316 }
0317 #include "moc_diffwindow.cpp"