| 1 | #include <CommitChangesWidget.h> |
| 2 | #include <ui_CommitChangesWidget.h> |
| 3 | |
| 4 | #include <ClickableFrame.h> |
| 5 | #include <CommitInfo.h> |
| 6 | #include <FileWidget.h> |
| 7 | #include <GitBase.h> |
| 8 | #include <GitCache.h> |
| 9 | #include <GitLocal.h> |
| 10 | #include <GitQlientSettings.h> |
| 11 | #include <GitQlientStyles.h> |
| 12 | #include <GitRepoLoader.h> |
| 13 | #include <GitWip.h> |
| 14 | #include <RevisionFiles.h> |
| 15 | #include <UnstagedMenu.h> |
| 16 | |
| 17 | #include <QDir> |
| 18 | #include <QItemDelegate> |
| 19 | #include <QKeyEvent> |
| 20 | #include <QListWidgetItem> |
| 21 | #include <QMenu> |
| 22 | #include <QMessageBox> |
| 23 | #include <QPainter> |
| 24 | #include <QProcess> |
| 25 | #include <QRegExp> |
| 26 | #include <QScrollBar> |
| 27 | #include <QTextCodec> |
| 28 | #include <QTextStream> |
| 29 | #include <QToolTip> |
| 30 | |
| 31 | #include <QLogger.h> |
| 32 | |
| 33 | using namespace QLogger; |
| 34 | |
| 35 | QString CommitChangesWidget::lastMsgBeforeError; |
| 36 | |
| 37 | enum GitQlientRole |
| 38 | { |
| 39 | U_ListRole = Qt::UserRole, |
| 40 | U_IsConflict, |
| 41 | U_IsUntracked, |
| 42 | U_FullPath |
| 43 | }; |
| 44 | |
| 45 | CommitChangesWidget::CommitChangesWidget(const QSharedPointer<GitCache> &cache, const QSharedPointer<GitBase> &git, |
| 46 | QWidget *parent) |
| 47 | : QWidget(parent) |
| 48 | , ui(new Ui::CommitChangesWidget) |
| 49 | , mCache(cache) |
| 50 | , mGit(git) |
| 51 | { |
| 52 | ui->setupUi(this); |
| 53 | setAttribute(Qt::WA_DeleteOnClose); |
| 54 | |
| 55 | ui->amendFrame->setVisible(false); |
| 56 | |
| 57 | mTitleMaxLength = GitQlientSettings().globalValue("commitTitleMaxLength" , mTitleMaxLength).toInt(); |
| 58 | |
| 59 | ui->lCounter->setText(QString::number(mTitleMaxLength)); |
| 60 | ui->leCommitTitle->setMaxLength(mTitleMaxLength); |
| 61 | ui->teDescription->setMaximumHeight(100); |
| 62 | |
| 63 | connect(ui->leCommitTitle, &QLineEdit::textChanged, this, &CommitChangesWidget::updateCounter); |
| 64 | connect(ui->leCommitTitle, &QLineEdit::returnPressed, this, &CommitChangesWidget::commitChanges); |
| 65 | connect(ui->applyActionBtn, &QPushButton::clicked, this, &CommitChangesWidget::commitChanges); |
| 66 | connect(ui->warningButton, &QPushButton::clicked, this, [this]() { emit signalCancelAmend(mCurrentSha); }); |
| 67 | connect(ui->stagedFilesList, &StagedFilesList::signalResetFile, this, &CommitChangesWidget::resetFile); |
| 68 | connect(ui->stagedFilesList, &StagedFilesList::signalShowDiff, this, |
| 69 | [this](const QString &fileName) { requestDiff(mGit->getWorkingDir() + "/" + fileName); }); |
| 70 | connect(ui->unstagedFilesList, &QListWidget::customContextMenuRequested, this, |
| 71 | &CommitChangesWidget::showUnstagedMenu); |
| 72 | connect(ui->unstagedFilesList, &QListWidget::itemDoubleClicked, this, |
| 73 | [this](QListWidgetItem *item) { requestDiff(mGit->getWorkingDir() + "/" + item->toolTip()); }); |
| 74 | |
| 75 | ui->warningButton->setVisible(false); |
| 76 | ui->applyActionBtn->setText(tr("Commit" )); |
| 77 | } |
| 78 | |
| 79 | CommitChangesWidget::~CommitChangesWidget() |
| 80 | { |
| 81 | delete ui; |
| 82 | } |
| 83 | |
| 84 | void CommitChangesWidget::reload() |
| 85 | { |
| 86 | configure(mCurrentSha); |
| 87 | } |
| 88 | |
| 89 | void CommitChangesWidget::resetFile(QListWidgetItem *item) |
| 90 | { |
| 91 | QScopedPointer<GitLocal> git(new GitLocal(mGit)); |
| 92 | const auto ret = git->resetFile(item->toolTip()); |
| 93 | const auto revInfo = mCache->commitInfo(mCurrentSha); |
| 94 | const auto files = mCache->revisionFile(mCurrentSha, revInfo.firstParent()); |
| 95 | |
| 96 | for (auto i = 0; i < files->count(); ++i) |
| 97 | { |
| 98 | auto fileName = files->getFile(i); |
| 99 | |
| 100 | if (fileName == item->toolTip()) |
| 101 | { |
| 102 | const auto isUnknown = files->statusCmp(i, RevisionFiles::UNKNOWN); |
| 103 | const auto isInIndex = files->statusCmp(i, RevisionFiles::IN_INDEX); |
| 104 | const auto untrackedFile = !isInIndex && isUnknown; |
| 105 | const auto row = ui->stagedFilesList->row(item); |
| 106 | const auto iconPath = QString(":/icons/add" ); |
| 107 | const auto fileWidget = qobject_cast<FileWidget *>(ui->stagedFilesList->itemWidget(item)); |
| 108 | |
| 109 | QFontMetrics metrix(item->font()); |
| 110 | const auto clippedText = metrix.elidedText(item->toolTip(), Qt::ElideMiddle, width() - 10); |
| 111 | |
| 112 | if (isInIndex || untrackedFile) |
| 113 | { |
| 114 | item->setData(GitQlientRole::U_ListRole, QVariant::fromValue(ui->unstagedFilesList)); |
| 115 | |
| 116 | ui->stagedFilesList->takeItem(row); |
| 117 | ui->unstagedFilesList->addItem(item); |
| 118 | |
| 119 | const auto newFileWidget = new FileWidget(iconPath, clippedText, this); |
| 120 | newFileWidget->setTextColor(fileWidget->getTextColor()); |
| 121 | newFileWidget->setToolTip(fileName); |
| 122 | |
| 123 | connect(newFileWidget, &FileWidget::clicked, this, [this, item]() { addFileToCommitList(item); }); |
| 124 | ui->unstagedFilesList->setItemWidget(item, newFileWidget); |
| 125 | |
| 126 | delete fileWidget; |
| 127 | } |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | if (ret.success) |
| 132 | emit signalUpdateWip(); |
| 133 | } |
| 134 | |
| 135 | QColor CommitChangesWidget::getColorForFile(const RevisionFiles &files, int index) const |
| 136 | { |
| 137 | const auto isUnknown = files.statusCmp(index, RevisionFiles::UNKNOWN); |
| 138 | const auto isInIndex = files.statusCmp(index, RevisionFiles::IN_INDEX); |
| 139 | const auto isConflict = files.statusCmp(index, RevisionFiles::CONFLICT); |
| 140 | const auto untrackedFile = !isInIndex && isUnknown; |
| 141 | const auto isPartiallyCached = files.statusCmp(index, RevisionFiles::PARTIALLY_CACHED); |
| 142 | |
| 143 | QColor myColor; |
| 144 | const auto isDeleted = files.statusCmp(index, RevisionFiles::DELETED); |
| 145 | |
| 146 | if (isConflict) |
| 147 | myColor = GitQlientStyles::getBlue(); |
| 148 | else if (isDeleted) |
| 149 | myColor = GitQlientStyles::getRed(); |
| 150 | else if (untrackedFile) |
| 151 | myColor = GitQlientStyles::getOrange(); |
| 152 | else if (files.statusCmp(index, RevisionFiles::NEW) || isUnknown || isInIndex || isPartiallyCached) |
| 153 | myColor = GitQlientStyles::getGreen(); |
| 154 | else |
| 155 | myColor = GitQlientStyles::getTextColor(); |
| 156 | |
| 157 | return myColor; |
| 158 | } |
| 159 | |
| 160 | void CommitChangesWidget::deleteUntrackedFiles() |
| 161 | { |
| 162 | for (auto i = 0; i < ui->unstagedFilesList->count(); ++i) |
| 163 | { |
| 164 | const auto item = ui->unstagedFilesList->item(i); |
| 165 | |
| 166 | if (item->data(GitQlientRole::U_IsUntracked).toBool()) |
| 167 | { |
| 168 | const auto path = QString("%1" ).arg(item->data(GitQlientRole::U_FullPath).toString()); |
| 169 | |
| 170 | QLog_Info("UI" , "Removing path: " + path); |
| 171 | |
| 172 | QProcess p; |
| 173 | p.setWorkingDirectory(mGit->getWorkingDir()); |
| 174 | p.start("rm" , { "-rf" , path }); |
| 175 | |
| 176 | p.waitForFinished(); |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | emit signalCheckoutPerformed(); |
| 181 | } |
| 182 | |
| 183 | void CommitChangesWidget::prepareCache() |
| 184 | { |
| 185 | for (auto it = mInternalCache.begin(); it != mInternalCache.end(); ++it) |
| 186 | it.value().keep = false; |
| 187 | } |
| 188 | |
| 189 | void CommitChangesWidget::clearCache() |
| 190 | { |
| 191 | |
| 192 | for (auto it = mInternalCache.begin(); it != mInternalCache.end();) |
| 193 | { |
| 194 | if (!it.value().keep) |
| 195 | { |
| 196 | if (it.value().item) |
| 197 | delete it.value().item; |
| 198 | |
| 199 | it = mInternalCache.erase(it); |
| 200 | } |
| 201 | else |
| 202 | ++it; |
| 203 | } |
| 204 | } |
| 205 | |
| 206 | void CommitChangesWidget::insertFiles(const RevisionFiles &files, QListWidget *fileList) |
| 207 | { |
| 208 | for (auto &cachedItem : mInternalCache) // Move to prepareCache |
| 209 | cachedItem.keep = false; |
| 210 | |
| 211 | for (auto i = 0; i < files.count(); ++i) |
| 212 | { |
| 213 | const auto fileName = files.getFile(i); |
| 214 | const auto isUnknown = files.statusCmp(i, RevisionFiles::UNKNOWN); |
| 215 | const auto isInIndex = files.statusCmp(i, RevisionFiles::IN_INDEX); |
| 216 | const auto isConflict = files.statusCmp(i, RevisionFiles::CONFLICT); |
| 217 | const auto isPartiallyCached = files.statusCmp(i, RevisionFiles::PARTIALLY_CACHED); |
| 218 | const auto staged = isInIndex && !isUnknown && !isConflict; |
| 219 | const auto untrackedFile = !isInIndex && isUnknown; |
| 220 | auto wip = QString("%1-%2" ).arg(fileName, ui->stagedFilesList->objectName()); |
| 221 | |
| 222 | if (staged || isPartiallyCached) |
| 223 | { |
| 224 | if (!mInternalCache.contains(wip)) |
| 225 | { |
| 226 | const auto color = getColorForFile(files, i); |
| 227 | const auto itemPair = fillFileItemInfo(fileName, isConflict, untrackedFile, QString(":/icons/remove" ), |
| 228 | color, ui->stagedFilesList); |
| 229 | connect(itemPair.second, &FileWidget::clicked, this, [this, item = itemPair.first]() { resetFile(item); }); |
| 230 | |
| 231 | ui->stagedFilesList->setItemWidget(itemPair.first, itemPair.second); |
| 232 | itemPair.first->setSizeHint(itemPair.second->sizeHint()); |
| 233 | } |
| 234 | else |
| 235 | mInternalCache[wip].keep = true; |
| 236 | } |
| 237 | |
| 238 | if (!staged) |
| 239 | { |
| 240 | wip = QString("%1-%2" ).arg(fileName, fileList->objectName()); |
| 241 | if (!mInternalCache.contains(wip)) |
| 242 | { |
| 243 | // Item configuration |
| 244 | auto color = getColorForFile(files, i); |
| 245 | |
| 246 | // If the item is not new but the color is green this is not correct. |
| 247 | // It means that the file was partially staged so the color backs to default. |
| 248 | if (!files.statusCmp(i, RevisionFiles::NEW) && color == GitQlientStyles::getGreen()) |
| 249 | color = GitQlientStyles::getTextColor(); |
| 250 | |
| 251 | const auto itemPair |
| 252 | = fillFileItemInfo(fileName, isConflict, untrackedFile, QString(":/icons/add" ), color, fileList); |
| 253 | |
| 254 | connect(itemPair.second, &FileWidget::clicked, this, |
| 255 | [this, item = itemPair.first]() { addFileToCommitList(item); }); |
| 256 | |
| 257 | fileList->setItemWidget(itemPair.first, itemPair.second); |
| 258 | itemPair.first->setSizeHint(itemPair.second->sizeHint()); |
| 259 | } |
| 260 | else |
| 261 | mInternalCache[wip].keep = true; |
| 262 | } |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | QPair<QListWidgetItem *, FileWidget *> CommitChangesWidget::fillFileItemInfo(const QString &file, bool isConflict, |
| 267 | bool isUntracked, const QString &icon, |
| 268 | const QColor &color, QListWidget *parent) |
| 269 | { |
| 270 | auto modName = file; |
| 271 | auto item = new QListWidgetItem(parent); |
| 272 | |
| 273 | item->setData(GitQlientRole::U_FullPath, file); |
| 274 | |
| 275 | if (isConflict) |
| 276 | { |
| 277 | modName = QString(file + " (conflicts)" ); |
| 278 | |
| 279 | item->setData(GitQlientRole::U_IsConflict, isConflict); |
| 280 | } |
| 281 | |
| 282 | item->setData(GitQlientRole::U_ListRole, QVariant::fromValue(parent)); |
| 283 | item->setData(GitQlientRole::U_IsUntracked, isUntracked); |
| 284 | item->setToolTip(modName); |
| 285 | |
| 286 | QFontMetrics metrix(item->font()); |
| 287 | const auto clippedText = metrix.elidedText(modName, Qt::ElideMiddle, width() - 10); |
| 288 | |
| 289 | const auto fileWidget = new FileWidget(icon, clippedText, this); |
| 290 | fileWidget->setTextColor(color); |
| 291 | fileWidget->setToolTip(modName); |
| 292 | |
| 293 | mInternalCache.insert(QString("%1-%2" ).arg(file, parent->objectName()), { true, item }); |
| 294 | |
| 295 | return qMakePair(item, fileWidget); |
| 296 | } |
| 297 | |
| 298 | void CommitChangesWidget::addAllFilesToCommitList() |
| 299 | { |
| 300 | QStringList files; |
| 301 | |
| 302 | for (auto i = ui->unstagedFilesList->count() - 1; i >= 0; --i) |
| 303 | files += addFileToCommitList(ui->unstagedFilesList->item(i), false); |
| 304 | |
| 305 | const auto git = QScopedPointer<GitLocal>(new GitLocal(mGit)); |
| 306 | |
| 307 | if (const auto ret = git->markFilesAsResolved(files); ret.success) |
| 308 | { |
| 309 | QScopedPointer<GitWip> git(new GitWip(mGit, mCache)); |
| 310 | git->updateWip(); |
| 311 | } |
| 312 | |
| 313 | ui->applyActionBtn->setEnabled(ui->stagedFilesList->count() > 0); |
| 314 | } |
| 315 | |
| 316 | void CommitChangesWidget::requestDiff(const QString &fileName) |
| 317 | { |
| 318 | const auto isCached = qobject_cast<StagedFilesList *>(sender()) == ui->stagedFilesList; |
| 319 | emit signalShowDiff(CommitInfo::ZERO_SHA, mCache->commitInfo(CommitInfo::ZERO_SHA).firstParent(), fileName, |
| 320 | isCached); |
| 321 | } |
| 322 | |
| 323 | QString CommitChangesWidget::addFileToCommitList(QListWidgetItem *item, bool updateGit) |
| 324 | { |
| 325 | const auto fileList = qvariant_cast<QListWidget *>(item->data(GitQlientRole::U_ListRole)); |
| 326 | const auto fileWidget = qobject_cast<FileWidget *>(fileList->itemWidget(item)); |
| 327 | const auto fileName = fileWidget->toolTip().remove(tr("(conflicts)" )).trimmed(); |
| 328 | |
| 329 | if (updateGit) |
| 330 | { |
| 331 | const auto git = QScopedPointer<GitLocal>(new GitLocal(mGit)); |
| 332 | |
| 333 | if (const auto ret = git->stageFile(fileName); ret.success) |
| 334 | { |
| 335 | QScopedPointer<GitWip> git(new GitWip(mGit, mCache)); |
| 336 | git->updateWip(); |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | const auto row = fileList->row(item); |
| 341 | fileList->removeItemWidget(item); |
| 342 | fileList->takeItem(row); |
| 343 | |
| 344 | const auto newKey = QString("%1-%2" ).arg(fileName, ui->stagedFilesList->objectName()); |
| 345 | |
| 346 | if (!mInternalCache.contains(newKey)) |
| 347 | { |
| 348 | const auto wip = mInternalCache.take(QString("%1-%2" ).arg(fileName, fileList->objectName())); |
| 349 | mInternalCache.insert(newKey, wip); |
| 350 | |
| 351 | QFontMetrics metrix(item->font()); |
| 352 | const auto clippedText = metrix.elidedText(fileName, Qt::ElideMiddle, width() - 10); |
| 353 | |
| 354 | const auto newFileWidget = new FileWidget(":/icons/remove" , clippedText, this); |
| 355 | newFileWidget->setTextColor(fileWidget->getTextColor()); |
| 356 | newFileWidget->setToolTip(fileName); |
| 357 | |
| 358 | connect(newFileWidget, &FileWidget::clicked, this, [this, item]() { removeFileFromCommitList(item); }); |
| 359 | |
| 360 | ui->stagedFilesList->addItem(item); |
| 361 | ui->stagedFilesList->setItemWidget(item, newFileWidget); |
| 362 | |
| 363 | if (item->data(GitQlientRole::U_IsConflict).toBool()) |
| 364 | { |
| 365 | newFileWidget->setText(fileName); |
| 366 | } |
| 367 | } |
| 368 | |
| 369 | delete fileWidget; |
| 370 | |
| 371 | ui->applyActionBtn->setEnabled(true); |
| 372 | |
| 373 | return fileName; |
| 374 | } |
| 375 | |
| 376 | void CommitChangesWidget::revertAllChanges() |
| 377 | { |
| 378 | auto needsUpdate = false; |
| 379 | |
| 380 | for (auto i = ui->unstagedFilesList->count() - 1; i >= 0; --i) |
| 381 | { |
| 382 | QScopedPointer<GitLocal> git(new GitLocal(mGit)); |
| 383 | needsUpdate |= git->checkoutFile(ui->unstagedFilesList->takeItem(i)->toolTip()); |
| 384 | } |
| 385 | |
| 386 | if (needsUpdate) |
| 387 | emit signalCheckoutPerformed(); |
| 388 | } |
| 389 | |
| 390 | void CommitChangesWidget::removeFileFromCommitList(QListWidgetItem *item) |
| 391 | { |
| 392 | if (item->flags() & Qt::ItemIsSelectable) |
| 393 | { |
| 394 | const auto itemOriginalList = qvariant_cast<QListWidget *>(item->data(GitQlientRole::U_ListRole)); |
| 395 | const auto row = ui->stagedFilesList->row(item); |
| 396 | const auto fileWidget = qobject_cast<FileWidget *>(ui->stagedFilesList->itemWidget(item)); |
| 397 | const auto fileName = fileWidget->toolTip(); |
| 398 | |
| 399 | const auto wip = mInternalCache.take(QString("%1-%2" ).arg(fileName, ui->stagedFilesList->objectName())); |
| 400 | mInternalCache.insert(QString("%1-%2" ).arg(fileName, itemOriginalList->objectName()), wip); |
| 401 | |
| 402 | QFontMetrics metrix(item->font()); |
| 403 | const auto clippedText = metrix.elidedText(fileName, Qt::ElideMiddle, width() - 10); |
| 404 | |
| 405 | const auto newFileWidget = new FileWidget(":/icons/add" , clippedText, this); |
| 406 | newFileWidget->setTextColor(fileWidget->getTextColor()); |
| 407 | newFileWidget->setToolTip(fileName); |
| 408 | |
| 409 | connect(newFileWidget, &FileWidget::clicked, this, [this, item]() { addFileToCommitList(item); }); |
| 410 | |
| 411 | QScopedPointer<GitLocal> git = QScopedPointer<GitLocal>(new GitLocal(mGit)); |
| 412 | git->resetFile(fileName); |
| 413 | |
| 414 | if (item->data(GitQlientRole::U_IsConflict).toBool()) |
| 415 | { |
| 416 | newFileWidget->setText(fileName + tr(" (conflicts)" )); |
| 417 | } |
| 418 | |
| 419 | delete fileWidget; |
| 420 | |
| 421 | ui->stagedFilesList->removeItemWidget(item); |
| 422 | const auto item = ui->stagedFilesList->takeItem(row); |
| 423 | |
| 424 | itemOriginalList->addItem(item); |
| 425 | itemOriginalList->setItemWidget(item, newFileWidget); |
| 426 | |
| 427 | ui->applyActionBtn->setDisabled(ui->stagedFilesList->count() == 0); |
| 428 | } |
| 429 | } |
| 430 | |
| 431 | QStringList CommitChangesWidget::getFiles() |
| 432 | { |
| 433 | QStringList selFiles; |
| 434 | const auto totalItems = ui->stagedFilesList->count(); |
| 435 | |
| 436 | for (auto i = 0; i < totalItems; ++i) |
| 437 | { |
| 438 | const auto fileWidget = static_cast<FileWidget *>(ui->stagedFilesList->itemWidget(ui->stagedFilesList->item(i))); |
| 439 | selFiles.append(fileWidget->toolTip()); |
| 440 | } |
| 441 | |
| 442 | return selFiles; |
| 443 | } |
| 444 | |
| 445 | bool CommitChangesWidget::checkMsg(QString &msg) |
| 446 | { |
| 447 | const auto title = ui->leCommitTitle->text(); |
| 448 | |
| 449 | if (title.isEmpty()) |
| 450 | QMessageBox::warning(this, "Commit changes" , "Please, add a title." ); |
| 451 | |
| 452 | msg = title; |
| 453 | |
| 454 | if (!ui->teDescription->toPlainText().isEmpty()) |
| 455 | { |
| 456 | auto description = QString("\n\n%1" ).arg(ui->teDescription->toPlainText()); |
| 457 | description.remove(QRegExp("(^|\\n)\\s*#[^\\n]*" )); // strip comments |
| 458 | msg += description; |
| 459 | } |
| 460 | |
| 461 | msg.replace(QRegExp("[ \\t\\r\\f\\v]+\\n" ), "\n" ); // strip line trailing cruft |
| 462 | msg = msg.trimmed(); |
| 463 | |
| 464 | if (msg.isEmpty()) |
| 465 | { |
| 466 | QMessageBox::warning(this, "Commit changes" , "Please, add a title." ); |
| 467 | return false; |
| 468 | } |
| 469 | |
| 470 | msg = QString("%1\n%2\n" ) |
| 471 | .arg(msg.section('\n', 0, 0, QString::SectionIncludeTrailingSep), msg.section('\n', 1).trimmed()); |
| 472 | |
| 473 | return true; |
| 474 | } |
| 475 | |
| 476 | void CommitChangesWidget::updateCounter(const QString &text) |
| 477 | { |
| 478 | ui->lCounter->setText(QString::number(mTitleMaxLength - text.count())); |
| 479 | } |
| 480 | |
| 481 | bool CommitChangesWidget::hasConflicts() |
| 482 | { |
| 483 | for (const auto &iter : qAsConst(mInternalCache)) |
| 484 | if (iter.item->data(GitQlientRole::U_IsConflict).toBool()) |
| 485 | return true; |
| 486 | |
| 487 | return false; |
| 488 | } |
| 489 | |
| 490 | void CommitChangesWidget::clear() |
| 491 | { |
| 492 | ui->unstagedFilesList->clear(); |
| 493 | ui->stagedFilesList->clear(); |
| 494 | mInternalCache.clear(); |
| 495 | ui->leCommitTitle->clear(); |
| 496 | ui->teDescription->clear(); |
| 497 | ui->applyActionBtn->setEnabled(false); |
| 498 | } |
| 499 | |
| 500 | void CommitChangesWidget::clearStaged() |
| 501 | { |
| 502 | ui->stagedFilesList->clear(); |
| 503 | |
| 504 | const auto end = mInternalCache.end(); |
| 505 | for (auto it = mInternalCache.begin(); it != end;) |
| 506 | { |
| 507 | if (it.key().contains(QString("-%1" ).arg(ui->stagedFilesList->objectName()))) |
| 508 | it = mInternalCache.erase(it); |
| 509 | else |
| 510 | ++it; |
| 511 | } |
| 512 | |
| 513 | ui->applyActionBtn->setEnabled(false); |
| 514 | } |
| 515 | |
| 516 | void CommitChangesWidget::setCommitTitleMaxLength() |
| 517 | { |
| 518 | mTitleMaxLength = GitQlientSettings().globalValue("commitTitleMaxLength" , mTitleMaxLength).toInt(); |
| 519 | |
| 520 | ui->lCounter->setText(QString::number(mTitleMaxLength)); |
| 521 | ui->leCommitTitle->setMaxLength(mTitleMaxLength); |
| 522 | updateCounter(ui->leCommitTitle->text()); |
| 523 | } |
| 524 | |
| 525 | void CommitChangesWidget::(const QPoint &pos) |
| 526 | { |
| 527 | const auto item = ui->unstagedFilesList->itemAt(pos); |
| 528 | |
| 529 | if (item) |
| 530 | { |
| 531 | const auto fileName = item->toolTip(); |
| 532 | const auto = new UnstagedMenu(mGit, fileName, this); |
| 533 | connect(contextMenu, &UnstagedMenu::signalEditFile, this, &CommitChangesWidget::signalEditFile); |
| 534 | connect(contextMenu, &UnstagedMenu::signalShowDiff, this, &CommitChangesWidget::requestDiff); |
| 535 | connect(contextMenu, &UnstagedMenu::signalCommitAll, this, &CommitChangesWidget::addAllFilesToCommitList); |
| 536 | connect(contextMenu, &UnstagedMenu::signalRevertAll, this, &CommitChangesWidget::revertAllChanges); |
| 537 | connect(contextMenu, &UnstagedMenu::changeReverted, this, &CommitChangesWidget::changeReverted); |
| 538 | connect(contextMenu, &UnstagedMenu::signalCheckedOut, this, &CommitChangesWidget::signalCheckoutPerformed); |
| 539 | connect(contextMenu, &UnstagedMenu::signalShowFileHistory, this, &CommitChangesWidget::signalShowFileHistory); |
| 540 | connect(contextMenu, &UnstagedMenu::signalStageFile, this, [this, item] { addFileToCommitList(item); }); |
| 541 | connect(contextMenu, &UnstagedMenu::deleteUntracked, this, &CommitChangesWidget::deleteUntrackedFiles); |
| 542 | |
| 543 | const auto parentPos = ui->unstagedFilesList->mapToParent(pos); |
| 544 | contextMenu->popup(mapToGlobal(parentPos)); |
| 545 | } |
| 546 | } |
| 547 | |