#
#
# add_file "guitone/res/dialogs/revision_diff.ui"
# content [c2d6932f4262a673b95c1588db61492d082e8b17]
#
# add_file "guitone/src/view/dialogs/RevisionDiff.cpp"
# content [8e5f7cfdc82f4ea811c72387596b40711d45ac57]
#
# add_file "guitone/src/view/dialogs/RevisionDiff.h"
# content [30a57d9b293fa8ea65371907ef3d5ff0a5996e44]
#
# patch "guitone/guitone.pro"
# from [94af3d787686a8f7727a0491e459a01ba1c451a6]
# to [dfe02e6f1114d8de5b82ffa4bb285480489b58bb]
#
# patch "guitone/src/model/ContentDiff.cpp"
# from [bdaf1d319eaa667501b6321534535a990e61d011]
# to [01b29d9366d9187f3f4b06f920eef473a109f44d]
#
# patch "guitone/src/model/ContentDiff.h"
# from [7b893384b27150e421956e5834087d7fe454c041]
# to [db6aed4aa7fa672a4dcfb29f160d45cea1f5228f]
#
# patch "guitone/src/view/InventoryView.cpp"
# from [64145819868bf2bc34916de61f252985eb0838e0]
# to [a9729726a253d1b035732e56347949c2c0434b2e]
#
# patch "guitone/src/view/InventoryView.h"
# from [e27d8be7c798a13d350783fdaf5b38bc85b6e6bc]
# to [4be916c896d8a6131f74b44eef8b4fb1a78cfdde]
#
============================================================
--- guitone/res/dialogs/revision_diff.ui c2d6932f4262a673b95c1588db61492d082e8b17
+++ guitone/res/dialogs/revision_diff.ui c2d6932f4262a673b95c1588db61492d082e8b17
@@ -0,0 +1,93 @@
+
+ RevisionDiffDialog
+
+
+
+ 0
+ 0
+ 444
+ 432
+
+
+
+ Differences in %1 between %2 and %3
+
+
+
+ 9
+
+
+ 6
+
+ -
+
+
+ 0
+
+
+ 6
+
+
-
+
+
+ -
+
+
+ 0
+
+
+ 6
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Close
+
+
+
+
+
+
+
+
+
+
+
+ DiffView
+ QTreeView
+
+
+
+
+
+
+ closeButton
+ clicked()
+ RevisionDiffDialog
+ accept()
+
+
+ 214
+ 225
+
+
+ 199
+ 149
+
+
+
+
+
============================================================
--- guitone/src/view/dialogs/RevisionDiff.cpp 8e5f7cfdc82f4ea811c72387596b40711d45ac57
+++ guitone/src/view/dialogs/RevisionDiff.cpp 8e5f7cfdc82f4ea811c72387596b40711d45ac57
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Thomas Keller *
+ * address@hidden *
+ * *
+ * 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. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include "RevisionDiff.h"
+#include "../../monotone/Monotone.h"
+
+#include
+
+RevisionDiff::RevisionDiff(QWidget* parent)
+ : QDialog(parent)
+{
+ setupUi(this);
+ diffView->setItemsExpandable(true);
+ diffView->setRootIsDecorated(true);
+ // arrow width is approx. 10px
+ diffView->setIndentation(10);
+}
+
+void RevisionDiff::init(QString path, QString leftRevision, QString rightRevision)
+{
+ QString title = windowTitle();
+ QString left = tr("base revision");
+ QString right = tr("workspace revision");
+
+ if (leftRevision.size() > 0)
+ {
+ left = leftRevision.left(8).append("...");
+ }
+
+ if (rightRevision.size() > 0)
+ {
+ right = rightRevision.left(8).append("...");
+ }
+
+ setWindowTitle(title.arg(path).arg(left).arg(right));
+
+ diffModel = new ContentDiff(this);
+ diffView->setModel(diffModel);
+
+ // FIXME: proper error handling here
+ if (!diffModel->readDiff(path, leftRevision, rightRevision))
+ {
+ qDebug("RevisionDiff::init: couldn't execute readDiff");
+ done(1);
+ }
+}
+
+RevisionDiff::~RevisionDiff() {}
+
============================================================
--- guitone/src/view/dialogs/RevisionDiff.h 30a57d9b293fa8ea65371907ef3d5ff0a5996e44
+++ guitone/src/view/dialogs/RevisionDiff.h 30a57d9b293fa8ea65371907ef3d5ff0a5996e44
@@ -0,0 +1,41 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Thomas Keller *
+ * address@hidden *
+ * *
+ * 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. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef REVISION_DIFF_H
+#define REVISION_DIFF_H
+
+#include "ui_revision_diff.h"
+#include "../../model/ContentDiff.h"
+
+class RevisionDiff : public QDialog, private Ui::RevisionDiffDialog
+{
+ Q_OBJECT
+
+public:
+ RevisionDiff(QWidget*);
+ void init(QString, QString, QString);
+
+ ~RevisionDiff();
+
+private:
+ ContentDiff * diffModel;
+};
+
+#endif
============================================================
--- guitone/guitone.pro 94af3d787686a8f7727a0491e459a01ba1c451a6
+++ guitone/guitone.pro dfe02e6f1114d8de5b82ffa4bb285480489b58bb
@@ -16,6 +16,7 @@ HEADERS += src/view/Guitone.h \
src/view/dialogs/Preferences.h \
src/view/dialogs/AncestryGraph.h \
src/view/dialogs/FileDiff.h \
+ src/view/dialogs/RevisionDiff.h \
src/view/dialogs/KeyManagement.h \
src/view/dialogs/GenerateKeypair.h \
src/view/dialogs/About.h \
@@ -51,6 +52,7 @@ SOURCES += src/view/Guitone.cpp \
src/view/dialogs/Preferences.cpp \
src/view/dialogs/AncestryGraph.cpp \
src/view/dialogs/FileDiff.cpp \
+ src/view/dialogs/RevisionDiff.cpp \
src/view/dialogs/KeyManagement.cpp \
src/view/dialogs/GenerateKeypair.cpp \
src/view/dialogs/About.cpp \
@@ -80,6 +82,7 @@ FORMS += res/dialogs/switch_workspace.
res/dialogs/preferences.ui \
res/dialogs/ancestry_graph.ui \
res/dialogs/file_diff.ui \
+ res/dialogs/revision_diff.ui \
res/dialogs/key_management.ui \
res/dialogs/generate_keypair.ui \
res/dialogs/about.ui
============================================================
--- guitone/src/model/ContentDiff.cpp bdaf1d319eaa667501b6321534535a990e61d011
+++ guitone/src/model/ContentDiff.cpp 01b29d9366d9187f3f4b06f920eef473a109f44d
@@ -21,7 +21,8 @@
#include "ContentDiff.h"
#include "../monotone/Monotone.h"
-#include
+#include
+#include
ContentDiff::ContentDiff(QObject *parent)
: AutomateCommand(parent)
@@ -35,21 +36,7 @@ bool ContentDiff::readDiff(QString fileN
bool ContentDiff::readDiff(QString fileName)
{
- Monotone * mtn = Monotone::singleton();
-
- QStringList cmd;
- cmd << "get_base_revision_id";
- int retCode;
-
- if (!mtn->executeCommand(cmd, retCode) || retCode != 0)
- {
- qWarning("ContentDiff::readDiff: could not execute get_base_revision_id");
- return false;
- }
-
- QString rev = mtn->getOutput();
- rev.chop(1);
- return readDiff(fileName, rev);
+ return readDiff(fileName, QString(), QString());
}
bool ContentDiff::readDiff(QString fileName, QString leftRevision)
@@ -64,10 +51,28 @@ bool ContentDiff::readDiff(
// reset the view
reset();
+ Monotone *mtn = Monotone::singleton();
+
QStringList cmd;
cmd << "content_diff" << fileName;
QStringList opts;
+
+ if (leftRevision.length() == 0)
+ {
+ int retCode;
+
+ if (!mtn->executeCommand(QStringList() << "get_base_revision_id", retCode)
+ || retCode != 0)
+ {
+ qWarning("ContentDiff::readDiff: could not execute get_base_revision_id");
+ return false;
+ }
+
+ leftRevision = mtn->getOutput();
+ leftRevision.chop(1);
+ }
+
opts << "r" << leftRevision;
if (rightRevision.length() > 0)
@@ -75,8 +80,6 @@ bool ContentDiff::readDiff(
opts << "r" << rightRevision;
}
- Monotone *mtn = Monotone::singleton();
-
return mtn->triggerCommand(this, cmd, opts);
}
@@ -87,43 +90,171 @@ void ContentDiff::parseOutput(AutomateCo
diffParser = new DiffParser(AutomateCommand::data);
+ // flatten the data for the current view
+ FileDiffs fileDiffs = diffParser->getAllDiffs();
+
+ QMapIterator i(fileDiffs);
+ while (i.hasNext())
+ {
+ i.next();
+ ListLine * fileLine = new ListLine(ListLine::FileLine);
+ lines.append(fileLine);
+
+ Diff * diff = (Diff*)i.value();
+
+ if (diff->is_binary)
+ {
+ fileLine->secondColumn = tr("%1 (binary)").arg(i.key());
+ continue;
+ }
+
+ fileLine->secondColumn =
+ tr("%1 (%2 hunks)").arg(i.key()).arg(diff->hunks.size());
+
+ for (int j=0, k=diff->hunks.size(); jhunks.at(j);
+ for (int m=0, n=hunk->lines.size(); mlines.at(m);
+ ListLine * hunkLine = new ListLine(ListLine::HunkLine);
+ fileLine->addChild(hunkLine);
+
+ if (line->state == DiffLine::Unchanged)
+ {
+ hunkLine->firstColumn = QString::number(hunk->leftStart + m);
+ }
+ else if (line->state == DiffLine::Added)
+ {
+ hunkLine->firstColumn = QString("+");
+ }
+ else
+ {
+ hunkLine->firstColumn = QString("-");
+ }
+ hunkLine->secondColumn = line->content;
+ }
+
+ if (j < k-1)
+ {
+ ListLine * sep = new ListLine(ListLine::HunkSep);
+ fileLine->addChild(sep);
+ }
+ }
+ }
+
+ reset();
+
emit diffRead();
}
-//
-// dummy implementations, eventually these will get its own view sometime
-//
int ContentDiff::columnCount(const QModelIndex &parent) const
{
- return 0;
+ return 2;
}
QVariant ContentDiff::data(const QModelIndex &index, int role) const
{
- return QVariant();
+ if (!index.isValid()) return QVariant();
+
+ int col = index.column();
+ ListLine * line = static_cast(index.internalPointer());
+
+ if (role == Qt::DisplayRole)
+ {
+ switch (col)
+ {
+ case 0: return QVariant(line->firstColumn);
+ case 1: return QVariant(line->secondColumn);
+ }
+
+ Q_ASSERT(false);
+ }
+
+ if (role == Qt::FontRole && col == 1)
+ {
+ QFont font;
+
+ if (line->type == ListLine::FileLine)
+ {
+ font.setBold(true);
+ }
+
+ if (line->type == ListLine::HunkLine)
+ {
+ font.setStyleHint(QFont::Courier);
+ font.setFamily("Courier");
+ }
+
+ return QVariant(font);
+ }
+
+ if (role == Qt::TextAlignmentRole && col == 0)
+ {
+ return QVariant(Qt::AlignRight);
+ }
+
+ if (role == Qt::BackgroundRole)
+ {
+ if (line->type != ListLine::HunkLine) return QVariant();
+
+ if (line->firstColumn.compare("-") == 0)
+ {
+ return QVariant(QBrush(Qt::red));
+ }
+
+ if (line->firstColumn.compare("+") == 0)
+ {
+ return QVariant(QBrush(Qt::green));
+ }
+
+ // unchanged lines
+ return QVariant();
+ }
+
+ return QVariant();
}
Qt::ItemFlags ContentDiff::flags(const QModelIndex &index) const
{
- return 0;
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QVariant ContentDiff::headerData(int section, Qt::Orientation orientation, int role) const
{
- return QVariant();
+ if (role != Qt::DisplayRole || orientation != Qt::Horizontal)
+ return QVariant();
+ if (section == 0) return QVariant(tr("Line"));
+ return QVariant(tr("File/Content"));
}
int ContentDiff::rowCount(const QModelIndex& parent) const
{
- return 0;
+ if (!parent.isValid()) return lines.size();
+ ListLine * line = static_cast(parent.internalPointer());
+ return line->lines.size();
}
QModelIndex ContentDiff::index(int row, int column, const QModelIndex& parent) const
{
- return QModelIndex();
+ if (!parent.isValid())
+ {
+ if (row >= lines.size()) return QModelIndex();
+ ListLine * line = lines.at(row);
+ return createIndex(row, column, line);
+ }
+
+ ListLine * parentLine = static_cast(parent.internalPointer());
+ if (row >= parentLine->lines.size()) return QModelIndex();
+ ListLine * line = parentLine->lines.at(row);
+ return createIndex(row, column, line);
}
QModelIndex ContentDiff::parent(const QModelIndex& index) const
{
- return QModelIndex();
+ if (!index.isValid()) return QModelIndex();
+ ListLine * line = static_cast(index.internalPointer());
+ if (!line->parent) return QModelIndex();
+ return createIndex(lines.indexOf(line->parent) , 0, line->parent);
}
+
============================================================
--- guitone/src/model/ContentDiff.h 7b893384b27150e421956e5834087d7fe454c041
+++ guitone/src/model/ContentDiff.h db6aed4aa7fa672a4dcfb29f160d45cea1f5228f
@@ -26,6 +26,28 @@
#include "AutomateCommand.h"
#include "../util/DiffParser.h"
+#include
+
+struct ListLine
+{
+ enum Type { FileLine, HunkSep, HunkLine };
+
+ Type type;
+ QString firstColumn;
+ QString secondColumn;
+ ListLine * parent;
+ QList lines;
+
+ ListLine() : type(HunkLine), parent(0) {}
+ ListLine(Type t) : type(t), parent(0)
+ {
+ if (type == HunkSep) firstColumn = "...";
+ }
+ void addChild(ListLine * l) { lines.append(l); l->parent = this; }
+};
+
+typedef QList ListLines;
+
class ContentDiff : public AutomateCommand
{
Q_OBJECT
@@ -56,6 +78,7 @@ private:
private:
void parseOutput(AutomateCommand*);
DiffParser * diffParser;
+ ListLines lines;
};
#endif
============================================================
--- guitone/src/view/InventoryView.cpp 64145819868bf2bc34916de61f252985eb0838e0
+++ guitone/src/view/InventoryView.cpp a9729726a253d1b035732e56347949c2c0434b2e
@@ -24,6 +24,7 @@
#include "../model/InventoryItem.h"
#include "../monotone/Monotone.h"
#include "dialogs/FileDiff.h"
+#include "dialogs/RevisionDiff.h"
#include
#include
@@ -134,6 +135,7 @@ void InventoryView::contextMenuEvent(QCo
if (item->hasChangedRecursive())
{
menu.addAction(actCommit);
+ menu.addAction(actRevisionDiff);
}
if (item->hasNotStatus(InventoryItem::Ignored) &&
@@ -147,12 +149,11 @@ void InventoryView::contextMenuEvent(QCo
{
menu.addAction(actRevert);
- // added files and directories can't be diffed
if (item->hasNotStatus(InventoryItem::Added) &&
!item->isDirectory())
{
- menu.addAction(actDiff);
- }
+ menu.addAction(actFileDiff);
+ }
}
}
@@ -174,12 +175,12 @@ void InventoryView::contextMenuEvent(QCo
if (item->hasStatus(InventoryItem::Patched) &&
item->hasNotStatus(InventoryItem::Added))
{
- actDiff->setFont(activeFont);
+ actFileDiff->setFont(activeFont);
actOpen->setFont(normalFont);
}
else
{
- actDiff->setFont(normalFont);
+ actFileDiff->setFont(normalFont);
actOpen->setFont(activeFont);
}
}
@@ -249,9 +250,13 @@ void InventoryView::createAndConnectCont
actRevert->setStatusTip(tr("Revert uncommitted changes"));
connect(actRevert, SIGNAL(triggered()), this, SLOT(slotRevert()));
- actDiff = new QAction(tr("D&iff"), this);
- actDiff->setStatusTip(tr("Diff against base revision"));
- connect(actDiff, SIGNAL(triggered()), this, SLOT(slotDiff()));
+ actFileDiff = new QAction(tr("D&iff"), this);
+ actFileDiff->setStatusTip(tr("Diff against base revision"));
+ connect(actFileDiff, SIGNAL(triggered()), this, SLOT(slotFileDiff()));
+
+ actRevisionDiff = new QAction(tr("D&iff all"), this);
+ actRevisionDiff->setStatusTip(tr("Show all differences"));
+ connect(actRevisionDiff, SIGNAL(triggered()), this, SLOT(slotRevisionDiff()));
actRename = new QAction(tr("Rena&me"), this);
actRename->setStatusTip(tr("Rename file"));
@@ -374,7 +379,7 @@ void InventoryView::slotUnignore(void)
qDebug("InventoryView::slotUnignore!!!");
}
-void InventoryView::slotDiff(void)
+void InventoryView::slotFileDiff(void)
{
QModelIndex index(getSingleSelection());
if (!index.isValid()) return;
@@ -383,7 +388,7 @@ void InventoryView::slotDiff(void)
if (item->isDirectory() || !item->hasStatus(InventoryItem::Patched))
{
- qDebug("InventoryView::slotDiff: File is a directory or not patched/unknown.");
+ qDebug("InventoryView::slotFileDiff: File is a directory or not patched/unknown.");
return;
}
@@ -393,6 +398,20 @@ void InventoryView::slotDiff(void)
clearSelection();
}
+void InventoryView::slotRevisionDiff(void)
+{
+ QModelIndex index(getSingleSelection());
+ if (!index.isValid()) return;
+
+ InventoryItem * item = static_cast(index.internalPointer());
+
+ RevisionDiff dlg(this);
+ dlg.init(item->getPath(), QString(), QString());
+ dlg.exec();
+
+ clearSelection();
+}
+
QModelIndex InventoryView::getSingleSelection()
{
QItemSelectionModel *selectionModel = this->selectionModel();
@@ -432,7 +451,7 @@ void InventoryView::itemClicked(const QM
if (item->hasStatus(InventoryItem::Patched) &&
item->hasNotStatus(InventoryItem::Added))
{
- slotDiff();
+ slotFileDiff();
return;
}
============================================================
--- guitone/src/view/InventoryView.h e27d8be7c798a13d350783fdaf5b38bc85b6e6bc
+++ guitone/src/view/InventoryView.h 4be916c896d8a6131f74b44eef8b4fb1a78cfdde
@@ -58,7 +58,8 @@ private:
QAction *actUnignore;
QAction *actRevert;
QAction *actRename;
- QAction *actDiff;
+ QAction *actFileDiff;
+ QAction *actRevisionDiff;
Type type;
@@ -75,7 +76,8 @@ private slots:
void slotUnignore(void);
void slotRevert(void);
void slotRename(void);
- void slotDiff(void);
+ void slotFileDiff(void);
+ void slotRevisionDiff(void);
};
#endif