changeset 296:d40294e164da status_outside_tabs

Merge from the default branch
author Chris Cannam
date Tue, 22 Feb 2011 13:03:03 +0000
parents 3fbafca196e4 (current diff) 01a471e9cbe3 (diff)
children e4284fab6962
files easyhg.pro hgtabwidget.cpp hgtabwidget.h mainwindow.cpp mainwindow.h
diffstat 17 files changed, 378 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/changesetitem.cpp	Mon Feb 21 11:07:21 2011 +0000
+++ b/changesetitem.cpp	Tue Feb 22 13:03:03 2011 +0000
@@ -108,6 +108,7 @@
 ChangesetItem::activateMenu()
 {
     m_parentDiffActions.clear();
+    m_summaryActions.clear();
 
     QMenu *menu = new QMenu;
     QLabel *label = new QLabel(tr("<qt><b>&nbsp;Revision: </b>%1</qt>")
@@ -120,16 +121,18 @@
     QAction *copyId = menu->addAction(tr("Copy identifier to clipboard"));
     connect(copyId, SIGNAL(triggered()), this, SLOT(copyIdActivated()));
 
+    QAction *stat = menu->addAction(tr("Summarise changes"));
+    connect(stat, SIGNAL(triggered()), this, SLOT(showSummaryActivated()));
+
     menu->addSeparator();
 
     QStringList parents = m_changeset->parents();
 
+    QString leftId, rightId;
+    bool havePositions = false;
+
     if (parents.size() > 1) {
-
-        QString leftId, rightId;
         ChangesetScene *cs = dynamic_cast<ChangesetScene *>(scene());
-        bool havePositions = false;
-
         if (cs && parents.size() == 2) {
             ChangesetItem *i0 = cs->getItemById(parents[0]);
             ChangesetItem *i1 = cs->getItemById(parents[1]);
@@ -144,37 +147,33 @@
                 havePositions = true;
             }
         }
+    }
 
+    if (parents.size() > 1) {
         if (havePositions) {
             
-            QAction *diffParent = menu->addAction(tr("Diff to left parent"));
-            connect(diffParent, SIGNAL(triggered()),
-                    this, SLOT(diffToParentActivated()));
-            m_parentDiffActions[diffParent] = leftId;
+            QAction *diff = menu->addAction(tr("Diff to left parent"));
+            connect(diff, SIGNAL(triggered()), this, SLOT(diffToParentActivated()));
+            m_parentDiffActions[diff] = leftId;
             
-            diffParent = menu->addAction(tr("Diff to right parent"));
-            connect(diffParent, SIGNAL(triggered()),
-                    this, SLOT(diffToParentActivated()));
-            m_parentDiffActions[diffParent] = rightId;
+            diff = menu->addAction(tr("Diff to right parent"));
+            connect(diff, SIGNAL(triggered()), this, SLOT(diffToParentActivated()));
+            m_parentDiffActions[diff] = rightId;
 
         } else {
 
             foreach (QString parentId, parents) {
-                QString text = tr("Diff to parent %1")
-                    .arg(Changeset::hashOf(parentId));
-                QAction *diffParent = menu->addAction(text);
-                connect(diffParent, SIGNAL(triggered()),
-                        this, SLOT(diffToParentActivated()));
-                m_parentDiffActions[diffParent] = parentId;
+                QString text = tr("Diff to parent %1").arg(Changeset::hashOf(parentId));
+                QAction *diff = menu->addAction(text);
+                connect(diff, SIGNAL(triggered()), this, SLOT(diffToParentActivated()));
+                m_parentDiffActions[diff] = parentId;
             }
         }
 
     } else {
 
-        QAction *diffParent =
-            menu->addAction(tr("Diff to parent"));
-        connect(diffParent, SIGNAL(triggered()),
-                this, SLOT(diffToParentActivated()));
+        QAction *diff = menu->addAction(tr("Diff to parent"));
+        connect(diff, SIGNAL(triggered()), this, SLOT(diffToParentActivated()));
     }
 
     QAction *diffCurrent = menu->addAction(tr("Diff to current working folder"));
@@ -223,14 +222,18 @@
     emit diffToParent(getId(), parentId);
 }
 
+void ChangesetItem::showSummaryActivated()
+{
+    emit showSummary(m_changeset);
+}
+
 void ChangesetItem::updateActivated() { emit updateTo(getId()); }
 void ChangesetItem::diffToCurrentActivated() { emit diffToCurrent(getId()); }
 void ChangesetItem::mergeActivated() { emit mergeFrom(getId()); }
 void ChangesetItem::tagActivated() { emit tag(getId()); }
 
 void
-ChangesetItem::paint(QPainter *paint, const QStyleOptionGraphicsItem *option,
-                     QWidget *w)
+ChangesetItem::paint(QPainter *paint, const QStyleOptionGraphicsItem *, QWidget *)
 {
     paint->save();
     
--- a/changesetitem.h	Mon Feb 21 11:07:21 2011 +0000
+++ b/changesetitem.h	Tue Feb 22 13:03:03 2011 +0000
@@ -63,6 +63,7 @@
     void updateTo(QString);
     void diffToCurrent(QString);
     void diffToParent(QString child, QString parent);
+    void showSummary(Changeset *);
     void mergeFrom(QString);
     void tag(QString);
 
@@ -74,6 +75,7 @@
     void copyIdActivated();
     void updateActivated();
     void diffToParentActivated();
+    void showSummaryActivated();
     void diffToCurrentActivated();
     void mergeActivated();
     void tagActivated();
@@ -95,6 +97,7 @@
     bool m_new;
 
     QMap<QAction *, QString> m_parentDiffActions;
+    QMap<QAction *, QString> m_summaryActions;
 };
 
 #endif // CHANGESETITEM_H
--- a/changesetscene.cpp	Mon Feb 21 11:07:21 2011 +0000
+++ b/changesetscene.cpp	Tue Feb 22 13:03:03 2011 +0000
@@ -45,6 +45,9 @@
     connect(item, SIGNAL(diffToParent(QString, QString)),
             this, SIGNAL(diffToParent(QString, QString)));
 
+    connect(item, SIGNAL(showSummary(Changeset *)),
+            this, SIGNAL(showSummary(Changeset *)));
+
     connect(item, SIGNAL(mergeFrom(QString)),
             this, SIGNAL(mergeFrom(QString)));
 
@@ -115,6 +118,7 @@
         ChangesetItem *csit = dynamic_cast<ChangesetItem *>(it);
         if (csit && csit->getId() == id) return csit;
     }
+    return 0;
 }
 
 
--- a/changesetscene.h	Mon Feb 21 11:07:21 2011 +0000
+++ b/changesetscene.h	Tue Feb 22 13:03:03 2011 +0000
@@ -21,6 +21,7 @@
 #include <QGraphicsScene>
 
 class ChangesetItem;
+class Changeset;
 class UncommittedItem;
 class DateItem;
 
@@ -46,6 +47,7 @@
 
     void updateTo(QString id);
     void diffToParent(QString id, QString parent);
+    void showSummary(Changeset *);
     void diffToCurrent(QString id);
     void mergeFrom(QString id);
     void tag(QString id);
--- a/confirmcommentdialog.cpp	Mon Feb 21 11:07:21 2011 +0000
+++ b/confirmcommentdialog.cpp	Tue Feb 22 13:03:03 2011 +0000
@@ -51,8 +51,10 @@
                                                   QDialogButtonBox::Cancel);
     layout->addWidget(bbox, 2, 0);
     m_ok = bbox->button(QDialogButtonBox::Ok);
+    m_ok->setDefault(true);
     m_ok->setEnabled(initialComment != "");
     m_ok->setText(okButtonText);
+    bbox->button(QDialogButtonBox::Cancel)->setAutoDefault(false);
 
     connect(bbox, SIGNAL(accepted()), this, SLOT(accept()));
     connect(bbox, SIGNAL(rejected()), this, SLOT(reject()));
@@ -93,6 +95,7 @@
 
     QPushButton *ok = box.addButton(QMessageBox::Ok);
     ok->setText(okButtonText);
+    box.setDefaultButton(QMessageBox::Ok);
     if (box.exec() == -1) return false;
     return box.standardButton(box.clickedButton()) == QMessageBox::Ok;
 }
@@ -110,6 +113,7 @@
 
     QPushButton *ok = box.addButton(QMessageBox::Ok);
     ok->setText(okButtonText);
+    box.setDefaultButton(QMessageBox::Cancel);
     if (box.exec() == -1) return false;
     return box.standardButton(box.clickedButton()) == QMessageBox::Ok;
 }
--- a/easyhg-extdiff.sh	Mon Feb 21 11:07:21 2011 +0000
+++ b/easyhg-extdiff.sh	Tue Feb 22 13:03:03 2011 +0000
@@ -26,5 +26,5 @@
 	"$od" "$1" "$2" | cat
     fi
 fi
-[ -z "$found" ]
+[ -n "$found" ]
 
--- a/easyhg-merge.sh	Mon Feb 21 11:07:21 2011 +0000
+++ b/easyhg-merge.sh	Tue Feb 22 13:03:03 2011 +0000
@@ -27,7 +27,8 @@
 if [ -z "$found" ]; then
     fm=/Developer/Applications/Utilities/FileMerge.app/Contents/MacOS/FileMerge
     if [ -x "$fm" ]; then
+	found=true
 	"$fm" -left "$left" -merge "$out" -ancestor "$ancestor" -right "$right"
     fi
 fi
-[ -z "$found" ]
+[ -n "$found" ]
--- a/easyhg.pro	Mon Feb 21 11:07:21 2011 +0000
+++ b/easyhg.pro	Tue Feb 22 13:03:03 2011 +0000
@@ -50,7 +50,8 @@
     uncommitteditem.h \
     settingsdialog.h \
     clickablelabel.h \
-    workstatuswidget.h
+    workstatuswidget.h \
+    moreinformationdialog.h
 SOURCES = main.cpp \
     mainwindow.cpp \
     hgtabwidget.cpp \
@@ -81,7 +82,8 @@
     incomingdialog.cpp \
     uncommitteditem.cpp \
     settingsdialog.cpp \
-    workstatuswidget.cpp
+    workstatuswidget.cpp \
+    moreinformationdialog.cpp
 
 macx-* {
     SOURCES += common_osx.mm
--- a/hgaction.h	Mon Feb 21 11:07:21 2011 +0000
+++ b/hgaction.h	Tue Feb 22 13:03:03 2011 +0000
@@ -43,6 +43,7 @@
     ACT_INIT,
     ACT_COMMIT,
     ACT_ANNOTATE,
+    ACT_UNCOMMITTED_SUMMARY,
     ACT_DIFF_SUMMARY,
     ACT_FOLDERDIFF,
     ACT_CHGSETDIFF,
@@ -62,15 +63,20 @@
     QString workingDir;
     QStringList params;
     QString executable; // empty for normal Hg, but gets filled in by hgrunner
+    void *extraData;
 
     HgAction() : action(ACT_NONE) { }
 
     HgAction(HGACTIONS _action, QString _wd, QStringList _params) :
-        action(_action), workingDir(_wd), params(_params) { }
+        action(_action), workingDir(_wd), params(_params), extraData(0) { }
+
+    HgAction(HGACTIONS _action, QString _wd, QStringList _params, void *_d) :
+        action(_action), workingDir(_wd), params(_params), extraData(_d) { }
 
     bool operator==(const HgAction &a) {
         return (a.action == action && a.workingDir == workingDir &&
-                a.params == params && a.executable == executable);
+                a.params == params && a.executable == executable &&
+                a.extraData == extraData);
     }
 
     bool shouldBeFast() const {
--- a/hgtabwidget.cpp	Mon Feb 21 11:07:21 2011 +0000
+++ b/hgtabwidget.cpp	Tue Feb 22 13:03:03 2011 +0000
@@ -67,6 +67,9 @@
     connect(m_historyWidget, SIGNAL(diffToParent(QString, QString)),
             this, SIGNAL(diffToParent(QString, QString)));
 
+    connect(m_historyWidget, SIGNAL(showSummary(Changeset *)),
+            this, SIGNAL(showSummary(Changeset *)));
+
     connect(m_historyWidget, SIGNAL(mergeFrom(QString)),
             this, SIGNAL(mergeFrom(QString)));
 
--- a/hgtabwidget.h	Mon Feb 21 11:07:21 2011 +0000
+++ b/hgtabwidget.h	Tue Feb 22 13:03:03 2011 +0000
@@ -90,6 +90,7 @@
 
     void updateTo(QString id);
     void diffToParent(QString id, QString parent);
+    void showSummary(Changeset *);
     void diffToCurrent(QString id);
     void mergeFrom(QString id);
     void tag(QString id);
--- a/historywidget.cpp	Mon Feb 21 11:07:21 2011 +0000
+++ b/historywidget.cpp	Tue Feb 22 13:03:03 2011 +0000
@@ -277,6 +277,9 @@
     connect(scene, SIGNAL(diffToParent(QString, QString)),
             this, SIGNAL(diffToParent(QString, QString)));
 
+    connect(scene, SIGNAL(showSummary(Changeset *)),
+            this, SIGNAL(showSummary(Changeset *)));
+
     connect(scene, SIGNAL(mergeFrom(QString)),
             this, SIGNAL(mergeFrom(QString)));
 
--- a/historywidget.h	Mon Feb 21 11:07:21 2011 +0000
+++ b/historywidget.h	Tue Feb 22 13:03:03 2011 +0000
@@ -54,6 +54,7 @@
 
     void updateTo(QString id);
     void diffToParent(QString id, QString parent);
+    void showSummary(Changeset *);
     void diffToCurrent(QString id);
     void mergeFrom(QString id);
     void tag(QString id);
--- a/mainwindow.cpp	Mon Feb 21 11:07:21 2011 +0000
+++ b/mainwindow.cpp	Tue Feb 22 13:03:03 2011 +0000
@@ -43,6 +43,7 @@
 #include "confirmcommentdialog.h"
 #include "incomingdialog.h"
 #include "settingsdialog.h"
+#include "moreinformationdialog.h"
 #include "version.h"
 #include "workstatuswidget.h"
 
@@ -547,7 +548,7 @@
     
     params << "diff" << "--stat";
 
-    m_runner->requestAction(HgAction(ACT_DIFF_SUMMARY, m_workFolderPath, params));
+    m_runner->requestAction(HgAction(ACT_UNCOMMITTED_SUMMARY, m_workFolderPath, params));
 }
 
 void MainWindow::hgFolderDiff()
@@ -603,6 +604,20 @@
 }
 
 
+void MainWindow::hgShowSummaryFor(Changeset *cs)
+{
+    QStringList params;
+
+    // This will pick a default parent if there is more than one
+    // (whereas with diff we need to supply one).  But it does need a
+    // bit more parsing
+    params << "log" << "--stat" << "--rev" << Changeset::hashOf(cs->id());
+
+    m_runner->requestAction(HgAction(ACT_DIFF_SUMMARY, m_workFolderPath,
+                                     params, cs));
+}
+
+
 void MainWindow::hgUpdate()
 {
     QStringList params;
@@ -847,7 +862,7 @@
 {
     if (ConfirmCommentDialog::confirm
         (this, tr("Confirm pull"),
-         format3(tr("Confirm pull from remote repository"),
+         format3(tr("Pull from remote repository?"),
                  tr("You are about to pull changes from the following remote repository:"),
                  m_remoteRepoPath),
          tr("Pull"))) {
@@ -862,7 +877,7 @@
 {
     if (ConfirmCommentDialog::confirm
         (this, tr("Confirm push"),
-         format3(tr("Confirm push to remote repository"),
+         format3(tr("Push to remote repository?"),
                  tr("You are about to push your changes to the following remote repository:"),
                  m_remoteRepoPath),
          tr("Push"))) {
@@ -1531,6 +1546,11 @@
     }
 }
 
+QString MainWindow::format1(QString head)
+{
+    return QString("<qt><h3>%1</h3></qt>").arg(head);
+}    
+
 QString MainWindow::format3(QString head, QString intro, QString code)
 {
     code = xmlEncode(code).replace("\n", "<br>")
@@ -1573,37 +1593,44 @@
 
 void MainWindow::showPushResult(QString output)
 {
+    QString head;
     QString report;
     int n = extractChangeCount(output);
     if (n > 0) {
-        report = tr("Pushed %n changeset(s)", "", n);
+        head = tr("Pushed %n changeset(s)", "", n);
     } else if (n == 0) {
-        report = tr("No changes to push");
+        head = tr("No changes to push");
+        report = tr("The remote repository already contains all changes that have been committed locally.");
+        if (m_hgTabs->canCommit()) {
+            report = tr("%1<p>You do have some uncommitted changes. If you wish to push those to the remote repository, commit them locally first.").arg(report);
+        }            
     } else {
-        report = tr("Push complete");
+        head = tr("Push complete");
     }
-    report = format3(report, tr("The push command output was:"), output);
     m_runner->hide();
-    QMessageBox::information(this, "Push complete", report);
+
+    MoreInformationDialog::information(this, tr("Push complete"),
+                                       head, report, output);
 }
 
 void MainWindow::showPullResult(QString output)
 {
+    QString head;
     QString report;
     int n = extractChangeCount(output);
     if (n > 0) {
-        report = tr("Pulled %n changeset(s)", "", n);
+        head = tr("Pulled %n changeset(s)", "", n);
+        report = tr("New changes will be highlighted in the history. Update to bring these changes into your working copy.");
     } else if (n == 0) {
-        report = tr("No changes to pull");
+        head = tr("No changes to pull");
+        report = tr("Your local repository already contains all changes found in the remote repository.");
     } else {
-        report = tr("Pull complete");
+        head = tr("Pull complete");
     }
-    report = format3(report, tr("The pull command output was:"), output);
     m_runner->hide();
 
-    //!!! and something about updating
-
-    QMessageBox::information(this, "Pull complete", report);
+    MoreInformationDialog::information(this, tr("Pull complete"),
+                                       head, report, output);
 }
 
 void MainWindow::reportNewRemoteHeads(QString output)
@@ -1628,17 +1655,19 @@
     }
 
     if (headsAreLocal) {
-        QMessageBox::warning
-            (this, tr("Push failed"),
-             format3(tr("Push failed"),
-                     tr("Your local repository could not be pushed to the remote repository.<br><br>You may need to merge the changes locally first.<br><br>The output of the push command was:"),
-                     output));
+        MoreInformationDialog::warning
+            (this,
+             tr("Push failed"),
+             tr("Push failed"),
+             tr("Your local repository could not be pushed to the remote repository.<br><br>You may need to merge the changes locally first."),
+             output);
     } else {
-        QMessageBox::warning
-            (this, tr("Push failed"),
-             format3(tr("Push failed"),
-                     tr("Your local repository could not be pushed to the remote repository.<br><br>The remote repository may have been changed by someone else since you last pushed. Try pulling and merging their changes into your local repository first.<br><br>The output of the push command was:"),
-                     output));
+        MoreInformationDialog::warning
+            (this,
+             tr("Push failed"),
+             tr("Push failed"),
+             tr("Your local repository could not be pushed to the remote repository.<br><br>The remote repository may have been changed by someone else since you last pushed. Try pulling and merging their changes into your local repository first."),
+             output);
     }
 }
 
@@ -1674,19 +1703,21 @@
         // uh huh
         return;
     case ACT_TEST_HG:
-        QMessageBox::warning
-            (this, tr("Failed to run Mercurial"),
-             format3(tr("Failed to run Mercurial"),
-                     tr("The Mercurial program either could not be found or failed to run.<br>Check that the Mercurial program path is correct in %1.<br><br>%2").arg(setstr).arg(output == "" ? QString("") : tr("The test command said:")),
-                     output));
+        MoreInformationDialog::warning
+            (this,
+             tr("Failed to run Mercurial"),
+             tr("Failed to run Mercurial"),
+             tr("The Mercurial program either could not be found or failed to run.<br>Check that the Mercurial program path is correct in %1.").arg(setstr),
+             output);
         settings();
         return;
     case ACT_TEST_HG_EXT:
         QMessageBox::warning
-            (this, tr("Failed to run Mercurial"),
-             format3(tr("Failed to run Mercurial with extension enabled"),
-                     tr("The Mercurial program failed to run with the EasyMercurial interaction extension enabled.<br>This may indicate an installation problem with EasyMercurial.<br><br>You may be able to continue working if you switch off &ldquo;Use EasyHg Mercurial Extension&rdquo; in %1.  Note that remote repositories that require authentication may not work if you do this.<br><br>%2").arg(setstr).arg(output == "" ? QString("") : tr("The test command said:")),
-                     output));
+            (this,
+             tr("Failed to run Mercurial"),
+             tr("Failed to run Mercurial with extension enabled"),
+             tr("The Mercurial program failed to run with the EasyMercurial interaction extension enabled.<br>This may indicate an installation problem with EasyMercurial.<br><br>You may be able to continue working if you switch off &ldquo;Use EasyHg Mercurial Extension&rdquo; in %1.  Note that remote repositories that require authentication may not work if you do this.").arg(setstr),
+             output);
         settings();
         return;
     case ACT_CLONEFROMREMOTE:
@@ -1732,6 +1763,8 @@
         command += " " + arg;
     }
 
+    //!!!
+
     QString message = tr("<qt><h3>Command failed</h3>"
                          "<p>The following command failed:</p>"
                          "<code>%1</code>"
@@ -1840,7 +1873,12 @@
         MultiChoiceDialog::addRecentArgument("local", m_workFolderPath);
         MultiChoiceDialog::addRecentArgument("remote", m_remoteRepoPath);
         MultiChoiceDialog::addRecentArgument("remote", m_workFolderPath, true);
-        QMessageBox::information(this, tr("Clone"), tr("<qt><h3>Clone successful</h3><pre>%1</pre>").arg(xmlEncode(output)));
+        MoreInformationDialog::information
+            (this,
+             tr("Clone"),
+             tr("Clone successful"),
+             tr("The remote repository was successfully cloned to the local folder <code>%1</code>.").arg(xmlEncode(m_workFolderPath)),
+             output);
         enableDisableActions();
         m_shouldHgStat = true;
         break;
@@ -1899,13 +1937,42 @@
         m_shouldHgStat = true;
         break;
 
-    case ACT_DIFF_SUMMARY:
+    case ACT_UNCOMMITTED_SUMMARY:
         QMessageBox::information(this, tr("Change summary"),
                                  format3(tr("Summary of uncommitted changes"),
                                          "",
                                          output));
         break;
 
+    case ACT_DIFF_SUMMARY:
+    {
+        // Output has log info first, diff following after a blank line
+        output.replace("\r\n", "\n");
+        QStringList olist = output.split("\n\n", QString::SkipEmptyParts);
+        if (olist.size() > 1) output = olist[1];
+
+        Changeset *cs = (Changeset *)completedAction.extraData;
+        if (cs) {
+            QMessageBox::information
+                (this, tr("Change summary"),
+                 format3(tr("Summary of changes"),
+                         cs->formatHtml(),
+                         output));
+        } else if (output == "") {
+            // Can happen, for a merge commit (depending on parent)
+            QMessageBox::information(this, tr("Change summary"),
+                                     format3(tr("Summary of changes"),
+                                             tr("No changes"),
+                                             output));
+        } else {
+            QMessageBox::information(this, tr("Change summary"),
+                                     format3(tr("Summary of changes"),
+                                             "",
+                                             output));
+        }            
+        break;
+    }
+
     case ACT_FOLDERDIFF:
     case ACT_CHGSETDIFF:
     case ACT_SERVE:
@@ -1919,8 +1986,10 @@
         break;
         
     case ACT_MERGE:
-        //!!! use format3?
-        QMessageBox::information(this, tr("Merge"), tr("<qt><h3>Merge successful</h3><pre>%1</pre>").arg(xmlEncode(output)));
+        MoreInformationDialog::information
+            (this, tr("Merge"), tr("Merge successful"),
+             tr("The merge succeeded.  Remember to commit the result!"),
+             output);
         m_shouldHgStat = true;
         m_justMerged = true;
         break;
@@ -2081,6 +2150,9 @@
     connect(m_hgTabs, SIGNAL(diffToParent(QString, QString)),
             this, SLOT(hgDiffToParent(QString, QString)));
 
+    connect(m_hgTabs, SIGNAL(showSummary(Changeset *)),
+            this, SLOT(hgShowSummaryFor(Changeset *)));
+
     connect(m_hgTabs, SIGNAL(mergeFrom(QString)),
             this, SLOT(hgMergeFrom(QString)));
 
--- a/mainwindow.h	Mon Feb 21 11:07:21 2011 +0000
+++ b/mainwindow.h	Tue Feb 22 13:03:03 2011 +0000
@@ -71,6 +71,7 @@
     void hgAdd();
     void hgCommit();
     void hgShowSummary();
+    void hgShowSummaryFor(Changeset *);
     void hgFolderDiff();
     void hgDiffToCurrent(QString);
     void hgDiffToParent(QString, QString);
@@ -143,6 +144,7 @@
     void showPullResult(QString);
     void showPushResult(QString);
     int extractChangeCount(QString);
+    QString format1(QString);
     QString format3(QString, QString, QString);
 
     void clearState();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/moreinformationdialog.cpp	Tue Feb 22 13:03:03 2011 +0000
@@ -0,0 +1,140 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    EasyMercurial
+
+    Based on hgExplorer by Jari Korhonen
+    Copyright (c) 2010 Jari Korhonen
+    Copyright (c) 2011 Chris Cannam
+    Copyright (c) 2011 Queen Mary, University of London
+
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#include "moreinformationdialog.h"
+
+#include <QMessageBox>
+#include <QLabel>
+#include <QGridLayout>
+#include <QTextEdit>
+#include <QDialogButtonBox>
+#include <QPushButton>
+#include <QApplication>
+#include <QStyle>
+
+MoreInformationDialog::MoreInformationDialog(QString title,
+                                             QString head,
+                                             QString text,
+                                             QString more,
+                                             QWidget *parent) :
+    QDialog(parent)
+{
+    setWindowTitle(title);
+
+    QGridLayout *layout = new QGridLayout;
+    layout->setSpacing(10);
+    setLayout(layout);
+
+    m_iconLabel = new QLabel;
+    layout->addWidget(m_iconLabel, 0, 0, 2, 1, Qt::AlignTop);
+
+    QLabel *headLabel = new QLabel(QString("<qt><h3>%1</h3></qt>").arg(head));
+    layout->addWidget(headLabel, 0, 1);
+
+    QLabel *textLabel = new QLabel(text);
+    textLabel->setTextFormat(Qt::RichText);
+    textLabel->setWordWrap(true);
+    layout->addWidget(textLabel, 1, 1, Qt::AlignTop);
+
+    QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok);
+    connect(bb, SIGNAL(accepted()), this, SLOT(accept()));
+    layout->addWidget(bb, 2, 0, 1, 2);
+
+    m_moreButton = bb->addButton(tr("More Details..."),
+                                 QDialogButtonBox::ActionRole);
+    m_moreButton->setDefault(false);
+
+    connect(m_moreButton, SIGNAL(clicked()), this, SLOT(moreClicked()));
+
+    bb->button(QDialogButtonBox::Ok)->setDefault(true);
+
+    m_moreText = new QTextEdit();
+    m_moreText->setAcceptRichText(false);
+    m_moreText->document()->setPlainText(more);
+    m_moreText->setMinimumWidth(360);
+    m_moreText->setReadOnly(true);
+    m_moreText->setLineWrapMode(QTextEdit::NoWrap);
+
+    QFont font("Monospace");
+    font.setStyleHint(QFont::TypeWriter);
+    m_moreText->setFont(font);
+
+    layout->addWidget(m_moreText, 3, 0, 1, 2);
+
+    m_moreText->hide();
+    if (more == "") m_moreButton->hide();
+
+    layout->setRowStretch(1, 20);
+    layout->setColumnStretch(1, 20);
+    setMinimumWidth(400);
+}
+
+MoreInformationDialog::~MoreInformationDialog()
+{
+}
+
+void
+MoreInformationDialog::moreClicked()
+{
+    if (m_moreText->isVisible()) {
+        m_moreText->hide();
+        m_moreButton->setText(tr("Show Details..."));
+    } else {
+        m_moreText->show();
+        m_moreButton->setText(tr("Hide Details..."));
+    }
+    adjustSize();
+}        
+
+void
+MoreInformationDialog::setIcon(QIcon icon)
+{
+    QStyle *style = qApp->style();
+    int iconSize = style->pixelMetric(QStyle::PM_MessageBoxIconSize, 0, this);
+    m_iconLabel->setPixmap(icon.pixmap(iconSize, iconSize));
+}
+
+void
+MoreInformationDialog::critical(QWidget *parent, QString title, QString head,
+				QString text, QString more)
+{
+    MoreInformationDialog d(title, head, text, more, parent);
+    QStyle *style = qApp->style();
+    d.setIcon(style->standardIcon(QStyle::SP_MessageBoxCritical, 0, &d));
+    d.exec();
+}
+
+void
+MoreInformationDialog::information(QWidget *parent, QString title, QString head,
+                                   QString text, QString more)
+{
+    MoreInformationDialog d(title, head, text, more, parent);
+    QStyle *style = qApp->style();
+    d.setIcon(style->standardIcon(QStyle::SP_MessageBoxInformation, 0, &d));
+    d.exec();
+}
+
+void
+MoreInformationDialog::warning(QWidget *parent, QString title, QString head,
+                               QString text, QString more)
+{
+    MoreInformationDialog d(title, head, text, more, parent);
+    QStyle *style = qApp->style();
+    d.setIcon(style->standardIcon(QStyle::SP_MessageBoxWarning, 0, &d));
+    d.exec();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/moreinformationdialog.h	Tue Feb 22 13:03:03 2011 +0000
@@ -0,0 +1,63 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    EasyMercurial
+
+    Based on hgExplorer by Jari Korhonen
+    Copyright (c) 2010 Jari Korhonen
+    Copyright (c) 2011 Chris Cannam
+    Copyright (c) 2011 Queen Mary, University of London
+
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef MORE_INFORMATION_DIALOG_H
+#define MORE_INFORMATION_DIALOG_H
+
+#include <QString>
+#include <QDialog>
+
+class QLabel;
+class QTextEdit;
+class QPushButton;
+
+/**
+ * Provide methods like the QMessageBox static methods, to call up
+ * dialogs with "More information" buttons in them.  QMessageBox does
+ * have an optional additional-details field, but it doesn't behave
+ * quite as we'd like with regard to layout
+ */
+
+class MoreInformationDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    MoreInformationDialog(QString title,
+                          QString head,
+                          QString text,
+                          QString more,
+                          QWidget *parent = 0);
+
+    ~MoreInformationDialog();
+
+    void setIcon(QIcon);
+
+    static void critical(QWidget *parent, QString title, QString head, QString text, QString more);
+    static void information(QWidget *parent, QString title, QString head, QString text, QString more);
+    static void warning(QWidget *parent, QString title, QString head, QString text, QString more);
+
+private slots:
+    void moreClicked();
+
+private:
+    QLabel *m_iconLabel;
+    QPushButton *m_moreButton;
+    QTextEdit *m_moreText;
+};
+
+#endif