Over the past few weeks I have been working on the Snapshot Docker, and now it is finished already. -))
The idea of snapshots is to make copies of the current document and allow users to return to them at a later time. This is a part of my whole Google Summer of Code project, which aims to bring Krita a better undo/redo system. When fully implemented, it will fully replace the current mechanism that stores actions with one that stores different states. That is to say, Krita will create a snapshot of the document for every undoable step.
Snapshot Docker is not only a feature requested by artists but also a experimental implementation of the clone-replace mechanism. It has the following key parts:
Cloning the document, which is provided by
KisDocument::lockAndCloneForSaving(), which is already implemented in master.
Replace the current document by another one, which is previously cloned.
Part (1) is already implemented so the work falls mainly on Part (2). My original approach is to replace the
document and image pointers in
KisCanvas, but it is not viable since other parts of the program
have signal/slot connections on the
KisImage, and directly replacing the two pointers will
not only fail to work but also cause weird crashes. After discussing with Dmitry,
we find out that it is probably better not to touch these two pointers, but to replace the content within
KisImage. It is therefore suggested that two member functions be made, namely
KisImage::copyFromImage. These functions copies data from another document/image
to the current one, avoiding the changes to the pointers inside the original instance. Eh, except for the nodes,
since we have to reset and refresh the nodes in the image.
It is also important to notify other parts of Krita about the change in the document. One important thing is
tell the layer docker about the changes in the nodes (they are completely different), which is done using the
KisImage::sigLayersChangedAsync() signal. The current activated node is also stored and restored, by using
the strategy of linearizing the layer tree using a queue, and then finding the corresponding node in the cloned
image. Note that when restoring, we are unable to find layer by uuid, since they should change when copied to
the current image (the comments in
KisImage says the only situation where we should keep the uuids is for saving).
Another interesting thing is the palettes. Krita 4.2.0 allows documents to store their own, local palettes.
The palette list is but a
QList<KoColorSet *>, meaning that only creating a new
QList of the same pointers
will not work. This is because, the palettes are controlled by canvas resource manager, which takes the responsibility
to delete them. Therefore, when taking snapshots, we had better take deep copies of the
KoColorSets. And then
another problem comes: the snapshots own their
KoColorSets because they are not controlled by the resource manager
in any way; but the
KisDocument in the view does not. So we have to set up another flag,
tell the document whether it should delete the palettes in the destructor.
And now the work has shifted to the refactoring of
kritaflake, the library that mainly handles vector layers and
shapes. I converted the whole
KoShape hierarchy to implicit sharing where possible, but some tests are broken. I
am now on Windows, where unit tests do not run. I will continue the development of flake as soon as I get access to
my Linux laptop.