You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/krita/ui/kis_doc.cc

1172 lines
31 KiB

/*
* Copyright (c) 1999 Matthias Elter <me@kde.org>
* Copyright (c) 2000 John Califf <jcaliff@compuzone.net>
* Copyright (c) 2001 Toshitaka Fujioka <fujioka@kde.org>
* Copyright (c) 2002, 2003 Patrick Julien <freak@codepimps.org>
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// Qt
#include <qapplication.h>
#include <qdom.h>
#include <qimage.h>
#include <qpainter.h>
#include <qtl.h>
#include <qstringlist.h>
#include <qwidget.h>
#include <qpaintdevicemetrics.h>
// KDE
#include <dcopobject.h>
#include <kapplication.h>
#include <kcommand.h>
#include <kdebug.h>
#include <kimageio.h>
#include <kfiledialog.h>
#include <kglobal.h>
#include <kmimetype.h>
#include <knotifyclient.h>
#include <klocale.h>
#include <kmessagebox.h>
// KOffice
#include <KoFilterManager.h>
#include <KoMainWindow.h>
#include <KoQueryTrader.h>
#include <KoStore.h>
#include <KoStoreDevice.h>
#include <KoTemplateChooseDia.h>
#include <KoApplication.h>
#include <KoCommandHistory.h>
// Local
#include <kis_clipboard.h>
#include <kis_meta_registry.h>
#include "kis_annotation.h"
#include "kis_types.h"
#include "kis_config.h"
#include "kis_debug_areas.h"
#include "kis_doc.h"
#include "kis_factory.h"
#include "kis_image.h"
#include "kis_layer.h"
#include "kis_paint_layer.h"
#include "kis_nameserver.h"
#include "kis_painter.h"
#include "kis_selection.h"
#include "kis_fill_painter.h"
#include "kis_command.h"
#include "kis_view.h"
#include "kis_colorspace.h"
#include "kis_colorspace_factory_registry.h"
#include "kis_profile.h"
#include "kis_id.h"
#include "kis_part_layer.h"
#include "kis_doc_iface.h"
#include "kis_paint_device_action.h"
#include "kis_custom_image_widget.h"
#include "kis_load_visitor.h"
#include "kis_save_visitor.h"
#include "kis_savexml_visitor.h"
static const char *CURRENT_DTD_VERSION = "1.3";
/**
* Mime type for this app - not same as file type, but file types
* can be associated with a mime type and are opened with applications
* associated with the same mime type
*/
#define APP_MIMETYPE "application/x-krita"
/**
* Mime type for native file format
*/
#define NATIVE_MIMETYPE "application/x-kra"
namespace {
class KisCommandImageMv : public KisCommand {
typedef KisCommand super;
public:
KisCommandImageMv(KisDoc *doc,
KisUndoAdapter *adapter,
const QString& name,
const QString& oldName) : super(i18n("Rename Image"), adapter)
{
m_doc = doc;
m_name = name;
m_oldName = oldName;
}
virtual ~KisCommandImageMv()
{
}
virtual void execute()
{
adapter()->setUndo(false);
m_doc->renameImage(m_oldName, m_name);
adapter()->setUndo(true);
}
virtual void unexecute()
{
adapter()->setUndo(false);
m_doc->renameImage(m_name, m_oldName);
adapter()->setUndo(true);
}
private:
KisDoc *m_doc;
QString m_name;
QString m_oldName;
};
}
KisDoc::KisDoc(QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name, bool singleViewMode) :
super(parentWidget, widgetName, parent, name, singleViewMode)
{
m_undo = false;
m_dcop = 0;
m_cmdHistory = 0;
m_nserver = 0;
m_currentImage = 0;
m_currentMacro = 0;
m_macroNestDepth = 0;
m_ioProgressBase = 0;
m_ioProgressTotalSteps = 0;
setInstance( KisFactory::instance(), false );
setTemplateType( "krita_template" );
init();
if (name)
dcopObject();
}
KisDoc::~KisDoc()
{
delete m_cmdHistory;
delete m_nserver;
m_undoListeners.setAutoDelete(false);
delete m_dcop;
}
QCString KisDoc::mimeType() const
{
return APP_MIMETYPE;
}
DCOPObject *KisDoc::dcopObject()
{
if (!m_dcop) {
m_dcop = new KisDocIface(this);
Q_CHECK_PTR(m_dcop);
}
return m_dcop;
}
bool KisDoc::initDoc(InitDocFlags flags, QWidget* parentWidget)
{
if (!init())
return false;
bool ok = false;
QString file;
KoTemplateChooseDia::DialogType dlgtype;
if (flags != KoDocument::InitDocFileNew) {
dlgtype = KoTemplateChooseDia::Everything;
} else {
dlgtype = KoTemplateChooseDia::OnlyTemplates;
}
KoTemplateChooseDia::ReturnType ret =
KoTemplateChooseDia::choose(KisFactory::instance(),
file,
dlgtype,
"krita_template",
parentWidget);
setUndo(false);
if (ret == KoTemplateChooseDia::Template) {
resetURL();
ok = loadNativeFormat( file );
setEmpty();
ok = true;
} else if (ret == KoTemplateChooseDia::File) {
KURL url( file );
ok = openURL(url);
} else if (ret == KoTemplateChooseDia::Empty) {
setEmpty();
ok = true;
}
setModified(false);
KisConfig cfg;
setUndo(cfg.undoEnabled());
return ok;
}
void KisDoc::openExistingFile(const QString& file)
{
setUndo(false);
KoDocument::openExistingFile(file);
setUndo(true);
}
void KisDoc::openTemplate(const QString& file)
{
setUndo(false);
KoDocument::openTemplate(file);
setUndo(true);
}
bool KisDoc::init()
{
if (m_cmdHistory) {
delete m_cmdHistory;
m_cmdHistory = 0;
}
if (m_nserver) {
delete m_nserver;
m_nserver = 0;
}
m_cmdHistory = new KoCommandHistory(actionCollection(), true);
Q_CHECK_PTR(m_cmdHistory);
connect(m_cmdHistory, SIGNAL(documentRestored()), this, SLOT(slotDocumentRestored()));
connect(m_cmdHistory, SIGNAL(commandExecuted(KCommand *)), this, SLOT(slotCommandExecuted(KCommand *)));
setUndo(true);
m_nserver = new KisNameServer(i18n("Image %1"), 1);
Q_CHECK_PTR(m_nserver);
if (!KisMetaRegistry::instance()->csRegistry()->exists(KisID("RGBA",""))) {
KMessageBox::sorry(0, i18n("No colorspace modules loaded: cannot run Krita"));
return false;
}
m_undoListeners.setAutoDelete(false);
return true;
}
QDomDocument KisDoc::saveXML()
{
QDomDocument doc = createDomDocument("DOC", CURRENT_DTD_VERSION);
QDomElement root = doc.documentElement();
root.setAttribute("editor", "Krita");
root.setAttribute("depth", sizeof(Q_UINT8));
root.setAttribute("syntaxVersion", "1");
root.appendChild(saveImage(doc, m_currentImage));
return doc;
}
bool KisDoc::loadOasis( const QDomDocument&, KoOasisStyles&, const QDomDocument&, KoStore* )
{
//XXX: todo (and that includes defining an OASIS format for layered 2D raster data!)
return false;
}
bool KisDoc::saveOasis( KoStore*, KoXmlWriter* )
{
//XXX: todo (and that includes defining an OASIS format for layered 2D raster data!)
return false;
}
bool KisDoc::loadXML(QIODevice *, const QDomDocument& doc)
{
QDomElement root;
QString attr;
QDomNode node;
KisImageSP img;
if (!init())
return false;
if (doc.doctype().name() != "DOC")
return false;
root = doc.documentElement();
attr = root.attribute("syntaxVersion");
if (attr.toInt() > 1)
return false;
if ((attr = root.attribute("depth")).isNull())
return false;
m_conversionDepth = attr.toInt();
if (!root.hasChildNodes()) {
return false; // XXX used to be: return slotNewImage();
}
setUndo(false);
for (node = root.firstChild(); !node.isNull(); node = node.nextSibling()) {
if (node.isElement()) {
if (node.nodeName() == "IMAGE") {
QDomElement elem = node.toElement();
if (!(img = loadImage(elem)))
return false;
m_currentImage = img;
} else {
return false;
}
}
}
emit loadingFinished();
return true;
}
bool KisDoc::loadChildren(KoStore* store) {
QPtrListIterator<KoDocumentChild> it(children());
for( ; it.current(); ++it ) {
if (!it.current()->loadDocument(store)) {
return false;
}
}
return true;
}
QDomElement KisDoc::saveImage(QDomDocument& doc, KisImageSP img)
{
QDomElement image = doc.createElement("IMAGE");
Q_ASSERT(img);
image.setAttribute("name", img->name());
image.setAttribute("mime", "application/x-kra");
image.setAttribute("width", img->width());
image.setAttribute("height", img->height());
image.setAttribute("colorspacename", img->colorSpace()->id().id());
image.setAttribute("description", img->description());
// XXX: Save profile as blob inside the image, instead of the product name.
if (img->getProfile() && img->getProfile()-> valid())
image.setAttribute("profile", img->getProfile()->productName());
image.setAttribute("x-res", img->xRes());
image.setAttribute("y-res", img->yRes());
Q_UINT32 count=0;
KisSaveXmlVisitor visitor(doc, image, count, true);
m_currentImage->rootLayer()->accept(visitor);
return image;
}
KisImageSP KisDoc::loadImage(const QDomElement& element)
{
KisConfig cfg;
QString attr;
QDomNode node;
QDomNode child;
KisImageSP img;
QString name;
Q_INT32 width;
Q_INT32 height;
QString description;
QString profileProductName;
double xres;
double yres;
QString colorspacename;
KisColorSpace * cs;
if ((attr = element.attribute("mime")) == NATIVE_MIMETYPE) {
if ((name = element.attribute("name")).isNull())
return 0;
if ((attr = element.attribute("width")).isNull())
return 0;
width = attr.toInt();
if ((attr = element.attribute("height")).isNull())
return 0;
height = attr.toInt();
description = element.attribute("description");
if ((attr = element.attribute("x-res")).isNull())
xres = 100.0;
xres = attr.toDouble();
if ((attr = element.attribute("y-res")).isNull())
yres = 100.0;
yres = attr.toDouble();
if ((colorspacename = element.attribute("colorspacename")).isNull())
{
// An old file: take a reasonable default.
// Krita didn't support anything else in those
// days anyway.
colorspacename = "RGBA";
}
// A hack for an old colorspacename
if (colorspacename == "Grayscale + Alpha")
colorspacename = "GRAYA";
if ((profileProductName = element.attribute("profile")).isNull()) {
// no mention of profile so get default profile
cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(colorspacename,"");
}
else {
cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(colorspacename, profileProductName);
}
if (cs == 0) {
kdWarning(DBG_AREA_FILE) << "Could not open colorspace\n";
return 0;
}
img = new KisImage(this, width, height, cs, name);
img->blockSignals(true); // Don't send out signals while we're building the image
Q_CHECK_PTR(img);
connect( img, SIGNAL( sigImageModified() ), this, SLOT( slotImageUpdated() ));
img->setDescription(description);
img->setResolution(xres, yres);
loadLayers(element, img, img->rootLayer().data());
}
img->notifyImageLoaded();
return img;
}
void KisDoc::loadLayers(const QDomElement& element, KisImageSP img, KisGroupLayerSP parent)
{
QDomNode node = element.firstChild();
QDomNode child;
if(!node.isNull())
{
if (node.isElement()) {
if (node.nodeName() == "LAYERS") {
for (child = node.firstChild(); !child.isNull(); child = child.nextSibling()) {
KisLayerSP layer = loadLayer(child.toElement(), img);
if (!layer) {
kdWarning(DBG_AREA_FILE) << "Could not load layer\n";
}
else {
img->nextLayerName(); // Make sure the nameserver is current with the number of layers.
img->addLayer(layer, parent, 0);
}
}
}
}
}
}
KisLayerSP KisDoc::loadLayer(const QDomElement& element, KisImageSP img)
{
// Nota bene: If you add new properties to layers, you should
// ALWAYS define a default value in case the property is not
// present in the layer definition: this helps a LOT with backward
// compatibilty.
QString attr;
QString name;
Q_INT32 x;
Q_INT32 y;
Q_INT32 opacity;
bool visible;
bool locked;
if ((name = element.attribute("name")).isNull())
return 0;
if ((attr = element.attribute("x")).isNull())
return 0;
x = attr.toInt();
if ((attr = element.attribute("y")).isNull())
return 0;
y = attr.toInt();
if ((attr = element.attribute("opacity")).isNull())
return 0;
if ((opacity = attr.toInt()) < 0 || opacity > Q_UINT8_MAX)
opacity = OPACITY_OPAQUE;
QString compositeOpName = element.attribute("compositeop");
KisCompositeOp compositeOp;
if (compositeOpName.isNull()) {
compositeOp = COMPOSITE_OVER;
} else {
compositeOp = KisCompositeOp(compositeOpName);
}
if (!compositeOp.isValid()) {
return 0;
}
if ((attr = element.attribute("visible")).isNull())
attr = "1";
visible = attr == "0" ? false : true;
if ((attr = element.attribute("locked")).isNull())
attr = "0";
locked = attr == "0" ? false : true;
// Now find out the layer type and do specific handling
if ((attr = element.attribute("layertype")).isNull())
return loadPaintLayer(element, img, name, x, y, opacity, visible, locked, compositeOp) ;
if(attr == "paintlayer")
return loadPaintLayer(element, img, name, x, y, opacity, visible, locked, compositeOp);
if(attr == "grouplayer")
return loadGroupLayer(element, img, name, x, y, opacity, visible, locked, compositeOp).data();
if(attr == "adjustmentlayer")
return loadAdjustmentLayer(element, img, name, x, y, opacity, visible, locked, compositeOp).data();
if(attr == "partlayer")
return loadPartLayer(element, img, name, x, y, opacity, visible, locked, compositeOp).data();
kdWarning(DBG_AREA_FILE) << "Specified layertype is not recognised\n";
return 0;
}
KisLayerSP KisDoc::loadPaintLayer(const QDomElement& element, KisImageSP img,
QString name, Q_INT32 x, Q_INT32 y,
Q_INT32 opacity, bool visible, bool locked, KisCompositeOp compositeOp)
{
QString attr;
KisPaintLayerSP layer;
KisColorSpace * cs;
QString colorspacename;
QString profileProductName;
if ((colorspacename = element.attribute("colorspacename")).isNull())
cs = img->colorSpace();
else
// use default profile - it will be replaced later in completLoading
cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(colorspacename,"");
layer = new KisPaintLayer(img, name, opacity, cs);
Q_CHECK_PTR(layer);
layer->setCompositeOp(compositeOp);
layer->setVisible(visible);
layer->setLocked(locked);
layer->setX(x);
layer->setY(y);
if ((element.attribute("filename")).isNull())
m_layerFilenames[layer.data()] = name;
else
m_layerFilenames[layer.data()] = QString(element.attribute("filename"));
if ((attr = element.attribute("hasmask")).isNull())
attr = "0";
if (attr == "1") {
// We add a mask, but we'll fill in the actual mask later in completeLoading with the visitor
layer->createMask();
}
// Load exif info
for( QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling() )
{
QDomElement e = node.toElement();
if ( !e.isNull() && e.tagName() == "ExifInfo" )
{
layer->paintDevice()->exifInfo()->load(e);
}
}
return layer.data();
}
KisGroupLayerSP KisDoc::loadGroupLayer(const QDomElement& element, KisImageSP img,
QString name, Q_INT32 x, Q_INT32 y, Q_INT32 opacity, bool visible, bool locked,
KisCompositeOp compositeOp)
{
QString attr;
KisGroupLayerSP layer;
layer = new KisGroupLayer(img, name, opacity);
Q_CHECK_PTR(layer);
layer->setCompositeOp(compositeOp);
layer->setVisible(visible);
layer->setLocked(locked);
layer->setX(x);
layer->setY(y);
loadLayers(element, img, layer);
return layer;
}
KisAdjustmentLayerSP KisDoc::loadAdjustmentLayer(const QDomElement& element, KisImageSP img,
QString name, Q_INT32 x, Q_INT32 y, Q_INT32 opacity, bool visible, bool locked,
KisCompositeOp compositeOp)
{
QString attr;
KisAdjustmentLayerSP layer;
QString filtername;
if ((filtername = element.attribute("filtername")).isNull()) {
// XXX: Invalid adjustmentlayer! We should warn about it!
kdWarning(DBG_AREA_FILE) << "No filter in adjustment layer" << endl;
return 0;
}
KisFilter * f = KisFilterRegistry::instance()->get(filtername);
if (!f) {
kdWarning(DBG_AREA_FILE) << "No filter for filtername " << filtername << "\n";
return 0; // XXX: We don't have this filter. We should warn about it!
}
KisFilterConfiguration * kfc = f->configuration();
// We'll load the configuration and the selection later.
layer = new KisAdjustmentLayer(img, name, kfc, 0);
Q_CHECK_PTR(layer);
layer->setCompositeOp(compositeOp);
layer->setVisible(visible);
layer->setLocked(locked);
layer->setX(x);
layer->setY(y);
layer->setOpacity(opacity);
if ((element.attribute("filename")).isNull())
m_layerFilenames[layer.data()] = name;
else
m_layerFilenames[layer.data()] = QString(element.attribute("filename"));
return layer;
}
KisPartLayerSP KisDoc::loadPartLayer(const QDomElement& element, KisImageSP img,
QString name, Q_INT32 /*x*/, Q_INT32 /*y*/, Q_INT32 opacity,
bool visible, bool locked,
KisCompositeOp compositeOp) {
KisChildDoc* child = new KisChildDoc(this);
QString filename(element.attribute("filename"));
QDomElement partElement = element.namedItem("object").toElement();
if (partElement.isNull()) {
kdWarning() << "loadPartLayer failed with partElement isNull" << endl;
return 0;
}
child->load(partElement);
insertChild(child);
KisPartLayerSP layer = new KisPartLayerImpl(img, child);
Q_CHECK_PTR(layer);
layer->setCompositeOp(compositeOp);
layer->setVisible(visible);
layer->setLocked(locked);
layer->setOpacity(opacity);
layer->setName(name);
return layer;
}
bool KisDoc::completeSaving(KoStore *store)
{
QString uri = url().url();
QString location;
bool external = isStoredExtern();
Q_INT32 totalSteps = 0;
if (!m_currentImage) return false;
totalSteps = (m_currentImage)->nlayers();
setIOSteps(totalSteps + 1);
// Save the layers data
Q_UINT32 count=0;
KisSaveVisitor visitor(m_currentImage, store, count);
if(external)
visitor.setExternalUri(uri);
m_currentImage->rootLayer()->accept(visitor);
// saving annotations
// XXX this only saves EXIF and ICC info. This would probably need
// a redesign of the dtd of the krita file to do this more generally correct
// e.g. have <ANNOTATION> tags or so.
KisAnnotationSP annotation = (m_currentImage)->annotation("exif");
if (annotation) {
location = external ? QString::null : uri;
location += (m_currentImage)->name() + "/annotations/exif";
if (store->open(location)) {
store->write(annotation->annotation());
store->close();
}
}
if (m_currentImage->getProfile()) {
annotation = m_currentImage->getProfile()->annotation();
if (annotation) {
location = external ? QString::null : uri;
location += m_currentImage->name() + "/annotations/icc";
if (store->open(location)) {
store->write(annotation->annotation());
store->close();
}
}
}
IODone();
return true;
}
bool KisDoc::completeLoading(KoStore *store)
{
QString uri = url().url();
QString location;
bool external = isStoredExtern();
Q_INT32 totalSteps = 0;
totalSteps = (m_currentImage)->nlayers();
setIOSteps(totalSteps);
// Load the layers data
KisLoadVisitor visitor(m_currentImage, store, m_layerFilenames);
if(external)
visitor.setExternalUri(uri);
m_currentImage->rootLayer()->accept(visitor);
// annotations
// exif
location = external ? QString::null : uri;
location += (m_currentImage)->name() + "/annotations/exif";
if (store->hasFile(location)) {
QByteArray data;
store->open(location);
data = store->read(store->size());
store->close();
(m_currentImage)->addAnnotation(new KisAnnotation("exif", "", data));
}
// icc profile
location = external ? QString::null : uri;
location += (m_currentImage)->name() + "/annotations/icc";
if (store->hasFile(location)) {
QByteArray data;
store->open(location);
data = store->read(store->size());
store->close();
(m_currentImage)->setProfile(new KisProfile(data));
}
IODone();
setModified( false );
setUndo(true);
return true;
}
QWidget* KisDoc::createCustomDocumentWidget(QWidget *parent)
{
KisConfig cfg;
int w = cfg.defImgWidth();
int h = cfg.defImgHeight();
QSize sz = KisClipboard::instance()->clipSize();
if (sz.isValid() && sz.width() != 0 && sz.height() != 0) {
w = sz.width();
h = sz.height();
}
return new KisCustomImageWidget(parent, this, w, h, cfg.defImgResolution(), cfg.workingColorSpace(),"unnamed");
}
KoDocument* KisDoc::hitTest(const QPoint &pos, const QWMatrix& matrix) {
KoDocument* doc = super::hitTest(pos, matrix);
if (doc && doc != this) {
// We hit a child document. We will only acknowledge we hit it, if the hit child
// is the currently active parts layer.
KisPartLayerImpl* partLayer
= dynamic_cast<KisPartLayerImpl*>(currentImage()->activeLayer().data());
if (!partLayer)
return this;
if (doc == partLayer->childDoc()->document()) {
return doc;
}
return this;
}
return doc;
}
void KisDoc::renameImage(const QString& oldName, const QString& newName)
{
(m_currentImage)->setName(newName);
if (undo())
addCommand(new KisCommandImageMv(this, this, newName, oldName));
}
KisImageSP KisDoc::newImage(const QString& name, Q_INT32 width, Q_INT32 height, KisColorSpace * colorstrategy)
{
if (!init())
return 0;
setUndo(false);
KisImageSP img = new KisImage(this, width, height, colorstrategy, name);
Q_CHECK_PTR(img);
connect( img, SIGNAL( sigImageModified() ), this, SLOT( slotImageUpdated() ));
KisPaintLayer *layer = new KisPaintLayer(img, img->nextLayerName(), OPACITY_OPAQUE,colorstrategy);
Q_CHECK_PTR(layer);
KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8();
KisFillPainter painter;
painter.begin(layer->paintDevice());
painter.fillRect(0, 0, width, height, KisColor(Qt::white, cs), OPACITY_OPAQUE);
painter.end();
img->addLayer(layer, img->rootLayer(), 0);
img->activate(layer);
m_currentImage = img;
setUndo(true);
return img;
}
bool KisDoc::newImage(const QString& name, Q_INT32 width, Q_INT32 height, KisColorSpace * cs, const KisColor &bgColor, const QString &imgDescription, const double imgResolution)
{
if (!init())
return false;
KisConfig cfg;
Q_UINT8 opacity = OPACITY_OPAQUE;//bgColor.getAlpha();
KisImageSP img;
KisPaintLayer *layer;
if (!cs) return false;
setUndo(false);
img = new KisImage(this, width, height, cs, name);
Q_CHECK_PTR(img);
connect( img, SIGNAL( sigImageModified() ), this, SLOT( slotImageUpdated() ));
img->setResolution(imgResolution, imgResolution);
img->setDescription(imgDescription);
img->setProfile(cs->getProfile());
layer = new KisPaintLayer(img, img->nextLayerName(), OPACITY_OPAQUE, cs);
Q_CHECK_PTR(layer);
KisFillPainter painter;
painter.begin(layer->paintDevice());
painter.fillRect(0, 0, width, height, bgColor, opacity);
painter.end();
QValueVector<KisPaintDeviceAction *> actions = KisMetaRegistry::instance() ->
csRegistry()->paintDeviceActionsFor(cs);
for (uint i = 0; i < actions.count(); i++)
actions.at(i)->act(layer->paintDevice(), img->width(), img->height());
img->setBackgroundColor(bgColor);
img->addLayer(layer, img->rootLayer(), 0);
img->activate(layer);
m_currentImage = img;
cfg.defImgWidth(width);
cfg.defImgHeight(height);
cfg.defImgResolution(imgResolution);
setUndo(true);
return true;
}
KoView* KisDoc::createViewInstance(QWidget* parent, const char *name)
{
KisView * v = new KisView(this, this, parent, name);
Q_CHECK_PTR(v);
return v;
}
void KisDoc::paintContent(QPainter& painter, const QRect& rc, bool transparent, double zoomX, double zoomY)
{
KisConfig cfg;
QString monitorProfileName = cfg.monitorProfile();
KisProfile * profile = KisMetaRegistry::instance()->csRegistry()->getProfileByName(monitorProfileName);
painter.scale(zoomX, zoomY);
QRect rect = rc & m_currentImage->bounds();
KisImage::PaintFlags paintFlags;
if (transparent) {
paintFlags = KisImage::PAINT_SELECTION;
} else {
paintFlags = (KisImage::PaintFlags)(KisImage::PAINT_BACKGROUND|KisImage::PAINT_SELECTION);
}
paintFlags = (KisImage::PaintFlags)(paintFlags | KisImage::PAINT_EMBEDDED_RECT);
m_currentImage->renderToPainter(rect.left(), rect.top(), rect.right(), rect.bottom(), painter, profile, paintFlags);
}
void KisDoc::slotImageUpdated()
{
emit docUpdated();
setModified(true);
}
void KisDoc::slotImageUpdated(const QRect& rect)
{
emit docUpdated(rect);
}
void KisDoc::beginMacro(const QString& macroName)
{
if (m_undo) {
if (m_macroNestDepth == 0) {
Q_ASSERT(m_currentMacro == 0);
m_currentMacro = new KMacroCommand(macroName);
Q_CHECK_PTR(m_currentMacro);
}
m_macroNestDepth++;
}
}
void KisDoc::endMacro()
{
if (m_undo) {
Q_ASSERT(m_macroNestDepth > 0);
if (m_macroNestDepth > 0) {
m_macroNestDepth--;
if (m_macroNestDepth == 0) {
Q_ASSERT(m_currentMacro != 0);
m_cmdHistory->addCommand(m_currentMacro, false);
m_currentMacro = 0;
emit sigCommandExecuted();
}
}
}
}
void KisDoc::setCommandHistoryListener(const KisCommandHistoryListener * l)
{
// Never have more than one instance of a listener around. Qt should prove a Set class for this...
m_undoListeners.removeRef(l);
m_undoListeners.append(l);
}
void KisDoc::removeCommandHistoryListener(const KisCommandHistoryListener * l)
{
m_undoListeners.removeRef(l);
}
KCommand * KisDoc::presentCommand()
{
return m_cmdHistory->presentCommand();
}
void KisDoc::addCommand(KCommand *cmd)
{
Q_ASSERT(cmd);
KisCommandHistoryListener* l = 0;
for (l = m_undoListeners.first(); l; l = m_undoListeners.next()) {
l->notifyCommandAdded(cmd);
}
setModified(true);
if (m_undo) {
if (m_currentMacro)
m_currentMacro->addCommand(cmd);
else {
m_cmdHistory->addCommand(cmd, false);
emit sigCommandExecuted();
}
} else {
kdDebug() << "Deleting command\n";
delete cmd;
}
}
void KisDoc::setUndo(bool undo)
{
m_undo = undo;
if (m_undo && m_cmdHistory->undoLimit() == 50 /*default*/) {
KisConfig cfg;
setUndoLimit( cfg.defUndoLimit() );
}
}
Q_INT32 KisDoc::undoLimit() const
{
return m_cmdHistory->undoLimit();
}
void KisDoc::setUndoLimit(Q_INT32 limit)
{
m_cmdHistory->setUndoLimit(limit);
}
Q_INT32 KisDoc::redoLimit() const
{
return m_cmdHistory->redoLimit();
}
void KisDoc::setRedoLimit(Q_INT32 limit)
{
m_cmdHistory->setRedoLimit(limit);
}
void KisDoc::slotDocumentRestored()
{
setModified(false);
}
void KisDoc::slotCommandExecuted(KCommand *command)
{
setModified(true);
emit sigCommandExecuted();
KisCommandHistoryListener* l = 0;
for (l = m_undoListeners.first(); l; l = m_undoListeners.next()) {
l->notifyCommandExecuted(command);
}
}
void KisDoc::slotUpdate(KisImageSP, Q_UINT32 x, Q_UINT32 y, Q_UINT32 w, Q_UINT32 h)
{
QRect rc(x, y, w, h);
emit docUpdated(rc);
}
bool KisDoc::undo() const
{
return m_undo;
}
void KisDoc::setIOSteps(Q_INT32 nsteps)
{
m_ioProgressTotalSteps = nsteps * 100;
m_ioProgressBase = 0;
emitProgress(0);
}
void KisDoc::IOCompletedStep()
{
m_ioProgressBase += 100;
}
void KisDoc::IODone()
{
emitProgress(-1);
}
void KisDoc::slotIOProgress(Q_INT8 percentage)
{
KApplication *app = KApplication::kApplication();
Q_ASSERT(app);
if (app->hasPendingEvents())
app->processEvents();
int totalPercentage = ((m_ioProgressBase + percentage) * 100) / m_ioProgressTotalSteps;
emitProgress(totalPercentage);
}
KisChildDoc * KisDoc::createChildDoc( const QRect & rect, KoDocument* childDoc )
{
KisChildDoc * ch = new KisChildDoc( this, rect, childDoc );
insertChild( ch );
ch->document()->setStoreInternal(true);
return ch;
}
void KisDoc::prepareForImport()
{
if (m_nserver == 0)
init();
setUndo(false);
}
KisImageSP KisDoc::currentImage()
{
return m_currentImage;
}
void KisDoc::setCurrentImage(KisImageSP image)
{
m_currentImage = image;
setUndo(true);
image->notifyImageLoaded();
emit loadingFinished();
}
void KisDoc::initEmpty()
{
KisConfig cfg;
KisColorSpace * rgb = KisMetaRegistry::instance()->csRegistry()->getRGB8();
newImage("", cfg.defImgWidth(), cfg.defImgHeight(), rgb);
}
#include "kis_doc.moc"