Calligra Suite is an integrated work applications suite based on Qt and KDE. It is a fork continuation of KOffice, and it’s where most of the former KOffice developers have landed. Calligra includes a text processor, a spreadsheet, a presentations application, a database, vector and image editors, etc
Two years ago I made a proposal for in-document versioning for (then) KOffice applications. It would be based on libQtGit, which I wished about yesterday, and a new library tentatively called libQVersioned, which would provide a higher-level API.
This is what I wrote back then, I have added a few clarifications:
I’m working on a more general solution towards document versioning.
First, I’m developing libQtGit, which provides a Qt-like API to use git. Unfortunately, it’s been on hold for three months because I was too busy with real work. The good news is last Monday I started hacking on it again.
Second, I intend to develop a framework (tentatively named QVersioned for now) on top of libQtGit. QVersioned will provide QVersionedDir and QVersionedFile classes (amongst others, but those two are the most important). Those classes would essentially have the same API QDir and QFile have. QVersioned would open ZIP files and store a .git directory inside. There are cases, like OpenDocument files (which are already a ZIP file) where nothing special would be needed. For other cases (for instance, a .txt file), there would be a .txtv (meaning “.txt versioned”) which would be a ZIP fiel containing the .txt + .git directory.
Now, how did I intend to implement ODF versioning, which was going to be the “this thing works” case?:
- The .git folder would store the uncompressed contents of the ODF file, i. e. XML, images, etc. This is needed to avoid duplication, allow diffs, etc
- There would be also a a checkout, which would provide a full copy of the latest version (XML, images, etc) in the ZIP file, just like any ODF-capable application not supporting QVersioned would expect (these applications would just ignore the .git directory)
- Clarification: what items 1 and 2 mean is to version an ODF file you would do something like:
- mkdir doc
- cd doc && unzip document.odt
- git init
- git add .
- git commit -a -m “<comment provided by user>”
- zip -9 document.odt .git *
- When a QVersioned-capable application opens an ODF file, it compares the XML, images, etc to the latest version in git:
- If the diff is empty, last save was by a QVersioned-capable application
- If the diff is not empty, last save was by a QVersioned-incapable application. A new “git commit -a” is performed. Yes, we probably have lost “versions” of the document in between this commit and the former one but something’s better than nothing.
By using libQtGit and QVersioned, it would also be possible to add collaboration features such as “send me an update” (i. e. send me a diff which transforms my outdated document into your latest version), collaborative editing (send diffs back and forth) and more things I cannot think of right now.
In case you are interested in the libQtGit API (remember QVersioned will offer a higher-level API), this is the signature of the method you would call:
Git::Repository::Commit* Git::Repository::commit (
const QString& message = QString(),
const Commit* c = 0,
const QString& author = QString(),
const CommitFlags cf = DefaultCommitFlags,
const CleanUpMode cum = DefaultCleanUpBehavior
);
That’s equivalent to “git commit -C commit_id -m “message” “. CommitFlags is a QFlags and CleanUpMode a QEnum:
enum CommitFlag {
DefaultCommitFlags = 0x0 /*< git commit */,
OverrideIndexCommit = 0x1 /*< git commit -a */,
SignOffCommit = 0x2 /*< git commit -s */,
AmendCommit = 0x4 /*< git commit --amend */,
AllowEmptyCommit = 0x8 /*< git commit --allow empty */,
NoVerifyCommit = 0x16 /*< git commit -n */
};
Q_DECLARE_FLAGS ( CommitFlags, CommitFlag )
enum CleanUpMode {
DefaultCleanUpBehavior = 0x0 /*< git commit */,
VerbatimClean = 0x1 /*< git commit --cleanup=verbatim */,
WhiteSpaceClean = 0x2 /*< git commit --cleanup=whitespace*/,
StripClean = 0x4 /*< git commit --cleanup=strip */,
DefaultClean = 0x8 /*< git commit --cleanup=default */
};
Q_ENUMS ( CleanUpMode )
For the “git commit -a -m “Save latest unversioned version on ODF document opening” “, we would use:
// Assuming 'repo' is a valid Git::Repository object
repo->commit (
"Save latest unversioned version on ODF document opening",
0,
"(The application would probably take the author's name from the product registration)",
Git::Repository::OverrideIndexCommit
);
So, how is libQtGit doing? Well, the API is there for X git add, commit, init, mv, rm, checkout, clone, branch, revert, reset, clean, gc, status, merge, push, fetch, pull, rebase, config, update-server-info and (partially) symbolic-ref. When I say “the API is there” I mean “all the QFlags, QEnums, methods, classes and its translation to git parameters is done”. It’s just a matter of implementing the QProcess part, parsing output, etc. Boring and time-consuming but easy.
In addition to file versioning and collaboration, there is another interesting feature (that I will wish about tomorrow) that could be achieved.