Mercurial > hg > easyhg
diff mainwindow.cpp @ 163:5c262ac73948
* First cut of work on merge/resolve logic
author | Chris Cannam |
---|---|
date | Fri, 03 Dec 2010 19:35:04 +0000 |
parents | 910c2c5d1873 |
children | de39da2f9f4d |
line wrap: on
line diff
--- a/mainwindow.cpp Fri Dec 03 14:43:32 2010 +0000 +++ b/mainwindow.cpp Fri Dec 03 19:35:04 2010 +0000 @@ -47,6 +47,7 @@ fsWatcher = 0; commitsSincePush = 0; + shouldHgStat = true; createActions(); createMenus(); @@ -85,6 +86,7 @@ } findDiffBinaryName(); + findMergeBinaryName(); ColourSet *cs = ColourSet::instance(); cs->clearDefaultNames(); @@ -161,6 +163,8 @@ QStringList params; params << "stat" << "-ardum"; + lastStatOutput = ""; + // annoyingly, hg stat actually modifies the working directory -- // it creates files called hg-checklink and hg-checkexec to test // properties of the filesystem @@ -240,19 +244,6 @@ } } -void MainWindow::hgResolveMark() -{ - QStringList params; - QString currentFile;//!!! = hgTabs -> getCurrentFileListLine(); - - if (!currentFile.isEmpty()) - { - params << "resolve" << "--mark" << "--" << currentFile.mid(2); //Jump over status marker characters (e.g "M ") - - runner->requestAction(HgAction(ACT_RESOLVE_MARK, workFolderPath, params)); - } -} - void MainWindow::hgResolveList() { QStringList params; @@ -331,8 +322,6 @@ runner->requestAction(HgAction(ACT_COMMIT, workFolderPath, params)); } - - justMerged = false; } QString MainWindow::filterTag(QString tag) @@ -424,6 +413,30 @@ diffBinaryName = diff; } +void MainWindow::findMergeBinaryName() +{ + QSettings settings; + QString merge = settings.value("mergebinary", "").toString(); + if (merge == "") { + QStringList bases; + bases << "fmdiff3" << "kdiff3" << "meld" << "diffuse"; + bool found = false; + foreach (QString base, bases) { + merge = findExecutable(base); + if (merge != base) { + found = true; + break; + } + } + if (found) { + settings.setValue("mergebinary", merge); + } else { + merge = ""; + } + } + mergeBinaryName = merge; +} + void MainWindow::hgFolderDiff() { if (diffBinaryName == "") return; @@ -443,6 +456,8 @@ void MainWindow::hgDiffToCurrent(QString id) { + if (diffBinaryName == "") return; + QStringList params; // Diff given revision against working folder @@ -457,6 +472,8 @@ void MainWindow::hgDiffToParent(QString child, QString parent) { + if (diffBinaryName == "") return; + QStringList params; // Diff given revision against working folder @@ -508,32 +525,92 @@ tr("<h3>%1</h3><p>%2").arg(rf) .arg(tr("You are about to <b>revert</b> %n file(s).<br><br>This will <b>throw away any changes</b> that you have made to these files but have not committed.", "", files.size())), files)) { + + lastRevertedFiles = files; if (files.empty()) { params << "revert" << "--no-backup"; } else { params << "revert" << "--no-backup" << "--" << files; } + + //!!! This is problematic. If you've got an uncommitted + //!!! merge, you can't revert it without declaring which + //!!! parent of the merge you want to revert to (reasonably + //!!! enough). We're OK if we just did the merge in easyhg a + //!!! moment ago, because we have a record of which parent was + //!!! the target -- but if you exit and restart, we've lost + //!!! that record and it doesn't appear to be possible to get + //!!! it back from Hg. Even if you just switched from one + //!!! repo to another, the record is lost. What to do? + + if (justMerged && mergeTargetRevision != "") { + params << "--rev" << mergeTargetRevision; + } runner->requestAction(HgAction(ACT_REVERT, workFolderPath, params)); } } + +void MainWindow::hgMarkResolved(QStringList files) +{ + QStringList params; + + params << "resolve" << "--mark"; + + if (files.empty()) { + params << "--all"; + } else { + params << files; + } + + runner->requestAction(HgAction(ACT_RESOLVE_MARK, workFolderPath, params)); +} + + void MainWindow::hgRetryMerge() { QStringList params; - params << "resolve" << "--all"; + params << "resolve"; + + if (mergeBinaryName != "") { + params << "--tool" << mergeBinaryName; + } + + QStringList files = hgTabs->getSelectedUnresolvedFiles(); + if (files.empty()) { + params << "--all"; + } else { + params << files; + } + runner->requestAction(HgAction(ACT_RETRY_MERGE, workFolderPath, params)); + + mergeCommitComment = tr("Merge"); } void MainWindow::hgMerge() { + if (hgTabs->canResolve()) { + hgRetryMerge(); + return; + } + QStringList params; params << "merge"; - + + if (mergeBinaryName != "") { + params << "--tool" << mergeBinaryName; + } + + if (currentParents.size() == 1) { + mergeTargetRevision = currentParents[0]->id(); + } + runner->requestAction(HgAction(ACT_MERGE, workFolderPath, params)); mergeCommitComment = tr("Merge"); @@ -546,6 +623,10 @@ params << "merge"; params << "--rev" << Changeset::hashOf(id); + + if (mergeBinaryName != "") { + params << "--tool" << mergeBinaryName; + } runner->requestAction(HgAction(ACT_MERGE, workFolderPath, params)); @@ -673,6 +754,10 @@ foreach (Changeset *cs, currentHeads) delete cs; currentHeads.clear(); currentBranch = ""; + lastStatOutput = ""; + lastRevertedFiles.clear(); + mergeTargetRevision = ""; + mergeCommitComment = ""; needNewLog = true; } @@ -1198,25 +1283,6 @@ : ""); QMessageBox::warning(this, tr("Command failed"), message); - -/* todo: -if ((runningAction == ACT_MERGE) && (exitCode != 0)) - { - // If we had a failed merge, offer to retry - if (QMessageBox::Ok == QMessageBox::information(this, tr("Retry merge ?"), tr("Merge attempt failed. retry ?"), QMessageBox::Ok | QMessageBox::Cancel)) - { - runningAction = ACT_NONE; - hgRetryMerge(); - } - else - { - runningAction = ACT_NONE; - hgStat(); - } - } - else - { -*/ } void MainWindow::commandCompleted(HgAction completedAction, QString output) @@ -1225,7 +1291,6 @@ if (action == ACT_NONE) return; - bool shouldHgStat = false; bool headsChanged = false; QStringList oldHeadIds; @@ -1253,17 +1318,35 @@ case ACT_STAT: if (fsWatcher) fsWatcher->blockSignals(false); - hgTabs->updateWorkFolderFileList(output); + lastStatOutput = output; updateFileSystemWatcher(); break; + + case ACT_RESOLVE_LIST: + if (output != "") { + // Remove lines beginning with R (they are resolved, + // and the file stat parser treats R as removed) + QStringList outList = output.split('\n'); + QStringList winnowed; + foreach (QString line, outList) { + if (!line.startsWith("R ")) winnowed.push_back(line); + } + output = winnowed.join("\n"); + } + DEBUG << "lastStatOutput = " << lastStatOutput << endl; + DEBUG << "output = " << output << endl; + hgTabs->updateWorkFolderFileList(lastStatOutput + output); + break; + + case ACT_RESOLVE_MARK: + shouldHgStat = true; + break; case ACT_INCOMING: showIncoming(output); break; case ACT_ANNOTATE: - case ACT_RESOLVE_LIST: - case ACT_RESOLVE_MARK: presentLongStdoutToUser(output); shouldHgStat = true; break; @@ -1327,12 +1410,17 @@ case ACT_COMMIT: hgTabs->clearSelections(); + justMerged = false; shouldHgStat = true; break; + + case ACT_REVERT: + hgMarkResolved(lastRevertedFiles); + justMerged = false; + break; case ACT_REMOVE: case ACT_ADD: - case ACT_REVERT: hgTabs->clearSelections(); shouldHgStat = true; break; @@ -1357,8 +1445,8 @@ break; case ACT_RETRY_MERGE: - QMessageBox::information(this, tr("Merge retry"), - tr("Merge retry successful.")); + QMessageBox::information(this, tr("Resolved"), + tr("<qt><h3>Merge resolved</h3><p>Merge resolved successfully.</p>")); shouldHgStat = true; justMerged = true; break; @@ -1368,11 +1456,11 @@ } // Sequence when no full log required: - // paths -> branch -> stat -> heads -> + // paths -> branch -> stat -> resolve-list -> heads -> // incremental-log (only if heads changed) -> parents // // Sequence when full log required: - // paths -> branch -> stat -> heads -> parents -> log + // paths -> branch -> stat -> resolve-list -> heads -> parents -> log // // Note we want to call enableDisableActions only once, at the end // of whichever sequence is in use. @@ -1390,6 +1478,10 @@ break; case ACT_STAT: + hgResolveList(); + break; + + case ACT_RESOLVE_LIST: hgQueryHeads(); break; @@ -1420,6 +1512,7 @@ default: if (shouldHgStat) { + shouldHgStat = false; hgQueryPaths(); } else { noMore = true; @@ -1448,7 +1541,6 @@ connect(hgUpdateAct, SIGNAL(triggered()), this, SLOT(hgUpdate())); connect(hgRevertAct, SIGNAL(triggered()), this, SLOT(hgRevert())); connect(hgMergeAct, SIGNAL(triggered()), this, SLOT(hgMerge())); - connect(hgRetryMergeAct, SIGNAL(triggered()), this, SLOT(hgRetryMerge())); connect(hgTagAct, SIGNAL(triggered()), this, SLOT(hgTag())); connect(hgIgnoreAct, SIGNAL(triggered()), this, SLOT(hgIgnore())); @@ -1465,8 +1557,6 @@ // connect(hgUpdateToRevAct, SIGNAL(triggered()), this, SLOT(hgUpdateToRev())); connect(hgAnnotateAct, SIGNAL(triggered()), this, SLOT(hgAnnotate())); - connect(hgResolveListAct, SIGNAL(triggered()), this, SLOT(hgResolveList())); - connect(hgResolveMarkAct, SIGNAL(triggered()), this, SLOT(hgResolveMark())); connect(hgServeAct, SIGNAL(triggered()), this, SLOT(hgServe())); connect(clearSelectionsAct, SIGNAL(triggered()), this, SLOT(clearSelections())); } @@ -1562,9 +1652,6 @@ hgUpdateAct -> setEnabled(localRepoActionsEnabled); hgCommitAct -> setEnabled(localRepoActionsEnabled); hgMergeAct -> setEnabled(localRepoActionsEnabled); - hgRetryMergeAct -> setEnabled(localRepoActionsEnabled); - hgResolveListAct -> setEnabled(localRepoActionsEnabled); - hgResolveMarkAct -> setEnabled(localRepoActionsEnabled); hgAnnotateAct -> setEnabled(localRepoActionsEnabled); hgServeAct -> setEnabled(localRepoActionsEnabled); hgTagAct -> setEnabled(localRepoActionsEnabled); @@ -1579,8 +1666,8 @@ hgAddAct->setEnabled(localRepoActionsEnabled && hgTabs->canAdd()); hgRemoveAct->setEnabled(localRepoActionsEnabled && hgTabs->canRemove()); hgCommitAct->setEnabled(localRepoActionsEnabled && hgTabs->canCommit()); - hgRevertAct->setEnabled(localRepoActionsEnabled && hgTabs->canCommit()); - hgFolderDiffAct->setEnabled(localRepoActionsEnabled && hgTabs->canDoDiff()); + hgRevertAct->setEnabled(localRepoActionsEnabled && hgTabs->canRevert()); + hgFolderDiffAct->setEnabled(localRepoActionsEnabled && hgTabs->canDiff()); // A default merge makes sense if: // * there is only one parent (if there are two, we have an uncommitted merge) and @@ -1624,10 +1711,13 @@ emptyRepo = true; } else { haveMerge = true; + justMerged = true; } - hgMergeAct->setEnabled(localRepoActionsEnabled && canMerge); - hgUpdateAct->setEnabled(localRepoActionsEnabled && canUpdate); + hgMergeAct->setEnabled(localRepoActionsEnabled && + (canMerge || hgTabs->canResolve())); + hgUpdateAct->setEnabled(localRepoActionsEnabled && + (canUpdate && !hgTabs->canRevert())); // Set the state field on the file status widget @@ -1644,10 +1734,18 @@ hgTabs->setState(tr("Nothing committed to this repository yet")); } else if (canMerge) { hgTabs->setState(tr("<b>Awaiting merge</b> on %1").arg(branchText)); + } else if (!hgTabs->getAllUnresolvedFiles().empty()) { + hgTabs->setState(tr("Have unresolved files following merge on %1").arg(branchText)); } else if (haveMerge) { hgTabs->setState(tr("Have merged but not yet committed on %1").arg(branchText)); } else if (canUpdate) { - hgTabs->setState(tr("On %1. Not at the head of the branch: consider updating").arg(branchText)); + if (hgTabs->canRevert()) { + // have uncommitted changes + hgTabs->setState(tr("On %1. Not at the head of the branch").arg(branchText)); + } else { + // no uncommitted changes + hgTabs->setState(tr("On %1. Not at the head of the branch: consider updating").arg(branchText)); + } } else if (currentBranchHeads > 1) { hgTabs->setState(tr("At one of %n heads of %1", "", currentBranchHeads).arg(branchText)); } else { @@ -1722,15 +1820,6 @@ hgAnnotateAct = new QAction(tr("Annotate"), this); hgAnnotateAct -> setStatusTip(tr("Show line-by-line version information for selected file")); - hgResolveListAct = new QAction(tr("Resolve (list)"), this); - hgResolveListAct -> setStatusTip(tr("Resolve (list): Show list of files needing merge")); - - hgResolveMarkAct = new QAction(tr("Resolve (mark)"), this); - hgResolveMarkAct -> setStatusTip(tr("Resolve (mark): Mark selected file status as resolved")); - - hgRetryMergeAct = new QAction(tr("Retry merge"), this); - hgRetryMergeAct -> setStatusTip(tr("Retry merge after failed merge attempt.")); - hgTagAct = new QAction(tr("Tag revision"), this); hgTagAct -> setStatusTip(tr("Give decsriptive name (tag) to current workfolder parent revision."));