summaryrefslogtreecommitdiffstats
path: root/chalk/ui/kis_doc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chalk/ui/kis_doc.cpp')
-rw-r--r--chalk/ui/kis_doc.cpp1171
1 files changed, 1171 insertions, 0 deletions
diff --git a/chalk/ui/kis_doc.cpp b/chalk/ui/kis_doc.cpp
new file mode 100644
index 00000000..60dbbfdd
--- /dev/null
+++ b/chalk/ui/kis_doc.cpp
@@ -0,0 +1,1171 @@
+/*
+ * Copyright (c) 1999 Matthias Elter <[email protected]>
+ * Copyright (c) 2000 John Califf <[email protected]>
+ * Copyright (c) 2001 Toshitaka Fujioka <[email protected]>
+ * Copyright (c) 2002, 2003 Patrick Julien <[email protected]>
+ *
+ * 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.
+ */
+
+// TQt
+#include <tqapplication.h>
+#include <tqdom.h>
+#include <tqimage.h>
+#include <tqpainter.h>
+#include <tqtl.h>
+#include <tqstringlist.h>
+#include <tqwidget.h>
+#include <tqpaintdevicemetrics.h>
+
+// KDE
+#include <dcopobject.h>
+#include <tdeapplication.h>
+#include <kcommand.h>
+#include <kdebug.h>
+#include <kimageio.h>
+#include <tdefiledialog.h>
+#include <tdeglobal.h>
+#include <kmimetype.h>
+#include <knotifyclient.h>
+#include <tdelocale.h>
+#include <tdemessagebox.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-chalk"
+
+/**
+ * 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 TQString& name,
+ const TQString& 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;
+ TQString m_name;
+ TQString m_oldName;
+ };
+
+}
+
+KisDoc::KisDoc(TQWidget *parentWidget, const char *widgetName, TQObject *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( "chalk_template" );
+
+ init();
+
+ if (name)
+ dcopObject();
+}
+
+KisDoc::~KisDoc()
+{
+ delete m_cmdHistory;
+ delete m_nserver;
+ m_undoListeners.setAutoDelete(false);
+ delete m_dcop;
+}
+
+TQCString KisDoc::mimeType() const
+{
+ return APP_MIMETYPE;
+}
+
+DCOPObject *KisDoc::dcopObject()
+{
+ if (!m_dcop) {
+ m_dcop = new KisDocIface(this);
+ TQ_CHECK_PTR(m_dcop);
+ }
+ return m_dcop;
+}
+
+bool KisDoc::initDoc(InitDocFlags flags, TQWidget* parentWidget)
+{
+ if (!init())
+ return false;
+
+ bool ok = false;
+
+ TQString file;
+ KoTemplateChooseDia::DialogType dlgtype;
+
+ if (flags != KoDocument::InitDocFileNew) {
+ dlgtype = KoTemplateChooseDia::Everything;
+ } else {
+ dlgtype = KoTemplateChooseDia::OnlyTemplates;
+ }
+
+ KoTemplateChooseDia::ReturnType ret =
+ KoTemplateChooseDia::choose(KisFactory::instance(),
+ file,
+ dlgtype,
+ "chalk_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 TQString& file)
+{
+ setUndo(false);
+
+ KoDocument::openExistingFile(file);
+
+ setUndo(true);
+}
+
+void KisDoc::openTemplate(const TQString& 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);
+ TQ_CHECK_PTR(m_cmdHistory);
+
+ connect(m_cmdHistory, TQT_SIGNAL(documentRestored()), this, TQT_SLOT(slotDocumentRestored()));
+ connect(m_cmdHistory, TQT_SIGNAL(commandExecuted(KCommand *)), this, TQT_SLOT(slotCommandExecuted(KCommand *)));
+ setUndo(true);
+
+ m_nserver = new KisNameServer(i18n("Image %1"), 1);
+ TQ_CHECK_PTR(m_nserver);
+
+ if (!KisMetaRegistry::instance()->csRegistry()->exists(KisID("RGBA",""))) {
+ KMessageBox::sorry(0, i18n("No colorspace modules loaded: cannot run Chalk"));
+ return false;
+ }
+
+ m_undoListeners.setAutoDelete(false);
+
+ return true;
+}
+
+TQDomDocument KisDoc::saveXML()
+{
+ TQDomDocument doc = createDomDocument("DOC", CURRENT_DTD_VERSION);
+ TQDomElement root = doc.documentElement();
+
+ root.setAttribute("editor", "Chalk");
+ root.setAttribute("depth", sizeof(TQ_UINT8));
+ root.setAttribute("syntaxVersion", "1");
+
+ root.appendChild(saveImage(doc, m_currentImage));
+
+ return doc;
+}
+
+bool KisDoc::loadOasis( const TQDomDocument&, KoOasisStyles&, const TQDomDocument&, 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(TQIODevice *, const TQDomDocument& doc)
+{
+ TQDomElement root;
+ TQString attr;
+ TQDomNode 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") {
+ TQDomElement elem = node.toElement();
+ if (!(img = loadImage(elem)))
+ return false;
+ m_currentImage = img;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ emit loadingFinished();
+ return true;
+}
+
+bool KisDoc::loadChildren(KoStore* store) {
+ TQPtrListIterator<KoDocumentChild> it(children());
+ for( ; it.current(); ++it ) {
+ if (!it.current()->loadDocument(store)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+TQDomElement KisDoc::saveImage(TQDomDocument& doc, KisImageSP img)
+{
+ TQDomElement 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());
+
+ TQ_UINT32 count=0;
+ KisSaveXmlVisitor visitor(doc, image, count, true);
+
+ m_currentImage->rootLayer()->accept(visitor);
+
+ return image;
+}
+
+KisImageSP KisDoc::loadImage(const TQDomElement& element)
+{
+
+ KisConfig cfg;
+ TQString attr;
+ TQDomNode node;
+ TQDomNode child;
+ KisImageSP img;
+ TQString name;
+ TQ_INT32 width;
+ TQ_INT32 height;
+ TQString description;
+ TQString profileProductName;
+ double xres;
+ double yres;
+ TQString 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.
+ // Chalk 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
+ TQ_CHECK_PTR(img);
+ connect( img, TQT_SIGNAL( sigImageModified() ), this, TQT_SLOT( slotImageUpdated() ));
+ img->setDescription(description);
+ img->setResolution(xres, yres);
+
+ loadLayers(element, img, img->rootLayer().data());
+
+ }
+
+ img->notifyImageLoaded();
+
+ return img;
+}
+
+void KisDoc::loadLayers(const TQDomElement& element, KisImageSP img, KisGroupLayerSP parent)
+{
+ TQDomNode node = element.firstChild();
+ TQDomNode 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 TQDomElement& 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.
+ TQString attr;
+ TQString name;
+ TQ_INT32 x;
+ TQ_INT32 y;
+ TQ_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 > TQ_UINT8_MAX)
+ opacity = OPACITY_OPAQUE;
+
+
+ TQString 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 TQDomElement& element, KisImageSP img,
+ TQString name, TQ_INT32 x, TQ_INT32 y,
+ TQ_INT32 opacity, bool visible, bool locked, KisCompositeOp compositeOp)
+{
+ TQString attr;
+ KisPaintLayerSP layer;
+ KisColorSpace * cs;
+
+ TQString colorspacename;
+ TQString 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);
+ TQ_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()] = TQString(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( TQDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling() )
+ {
+ TQDomElement e = node.toElement();
+ if ( !e.isNull() && e.tagName() == "ExifInfo" )
+ {
+ layer->paintDevice()->exifInfo()->load(e);
+ }
+ }
+ return layer.data();
+}
+
+KisGroupLayerSP KisDoc::loadGroupLayer(const TQDomElement& element, KisImageSP img,
+ TQString name, TQ_INT32 x, TQ_INT32 y, TQ_INT32 opacity, bool visible, bool locked,
+ KisCompositeOp compositeOp)
+{
+ TQString attr;
+ KisGroupLayerSP layer;
+
+ layer = new KisGroupLayer(img, name, opacity);
+ TQ_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 TQDomElement& element, KisImageSP img,
+ TQString name, TQ_INT32 x, TQ_INT32 y, TQ_INT32 opacity, bool visible, bool locked,
+ KisCompositeOp compositeOp)
+{
+ TQString attr;
+ KisAdjustmentLayerSP layer;
+ TQString 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);
+ TQ_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()] = TQString(element.attribute("filename"));
+
+ return layer;
+}
+
+KisPartLayerSP KisDoc::loadPartLayer(const TQDomElement& element, KisImageSP img,
+ TQString name, TQ_INT32 /*x*/, TQ_INT32 /*y*/, TQ_INT32 opacity,
+ bool visible, bool locked,
+ KisCompositeOp compositeOp) {
+ KisChildDoc* child = new KisChildDoc(this);
+ TQString filename(element.attribute("filename"));
+ TQDomElement 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);
+ TQ_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)
+{
+ TQString uri = url().url();
+ TQString location;
+ bool external = isStoredExtern();
+ TQ_INT32 totalSteps = 0;
+
+ if (!m_currentImage) return false;
+
+ totalSteps = (m_currentImage)->nlayers();
+
+
+ setIOSteps(totalSteps + 1);
+
+ // Save the layers data
+ TQ_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 chalk file to do this more generally correct
+ // e.g. have <ANNOTATION> tags or so.
+ KisAnnotationSP annotation = (m_currentImage)->annotation("exif");
+ if (annotation) {
+ location = external ? TQString() : 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 ? TQString() : 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)
+{
+ TQString uri = url().url();
+ TQString location;
+ bool external = isStoredExtern();
+ TQ_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 ? TQString() : uri;
+ location += (m_currentImage)->name() + "/annotations/exif";
+ if (store->hasFile(location)) {
+ TQByteArray data;
+ store->open(location);
+ data = store->read(store->size());
+ store->close();
+ (m_currentImage)->addAnnotation(new KisAnnotation("exif", "", data));
+ }
+ // icc profile
+ location = external ? TQString() : uri;
+ location += (m_currentImage)->name() + "/annotations/icc";
+ if (store->hasFile(location)) {
+ TQByteArray data;
+ store->open(location);
+ data = store->read(store->size());
+ store->close();
+ (m_currentImage)->setProfile(new KisProfile(data));
+ }
+
+ IODone();
+
+ setModified( false );
+ setUndo(true);
+ return true;
+}
+
+TQWidget* KisDoc::createCustomDocumentWidget(TQWidget *parent)
+{
+
+ KisConfig cfg;
+
+ int w = cfg.defImgWidth();
+ int h = cfg.defImgHeight();
+
+ TQSize 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 TQPoint &pos, const TQWMatrix& 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 TQString& oldName, const TQString& newName)
+{
+ (m_currentImage)->setName(newName);
+
+ if (undo())
+ addCommand(new KisCommandImageMv(this, this, newName, oldName));
+}
+
+
+KisImageSP KisDoc::newImage(const TQString& name, TQ_INT32 width, TQ_INT32 height, KisColorSpace * colorstrategy)
+{
+ if (!init())
+ return 0;
+
+ setUndo(false);
+
+ KisImageSP img = new KisImage(this, width, height, colorstrategy, name);
+ TQ_CHECK_PTR(img);
+ connect( img, TQT_SIGNAL( sigImageModified() ), this, TQT_SLOT( slotImageUpdated() ));
+
+ KisPaintLayer *layer = new KisPaintLayer(img, img->nextLayerName(), OPACITY_OPAQUE,colorstrategy);
+ TQ_CHECK_PTR(layer);
+
+ KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8();
+ KisFillPainter painter;
+
+ painter.begin(layer->paintDevice());
+ painter.fillRect(0, 0, width, height, KisColor(TQt::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 TQString& name, TQ_INT32 width, TQ_INT32 height, KisColorSpace * cs, const KisColor &bgColor, const TQString &imgDescription, const double imgResolution)
+{
+ if (!init())
+ return false;
+
+ KisConfig cfg;
+
+ TQ_UINT8 opacity = OPACITY_OPAQUE;//bgColor.getAlpha();
+ KisImageSP img;
+ KisPaintLayer *layer;
+
+ if (!cs) return false;
+
+ setUndo(false);
+
+ img = new KisImage(this, width, height, cs, name);
+ TQ_CHECK_PTR(img);
+ connect( img, TQT_SIGNAL( sigImageModified() ), this, TQT_SLOT( slotImageUpdated() ));
+ img->setResolution(imgResolution, imgResolution);
+ img->setDescription(imgDescription);
+ img->setProfile(cs->getProfile());
+
+ layer = new KisPaintLayer(img, img->nextLayerName(), OPACITY_OPAQUE, cs);
+ TQ_CHECK_PTR(layer);
+
+ KisFillPainter painter;
+ painter.begin(layer->paintDevice());
+ painter.fillRect(0, 0, width, height, bgColor, opacity);
+ painter.end();
+
+ TQValueVector<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(TQWidget* parent, const char *name)
+{
+ KisView * v = new KisView(this, this, parent, name);
+ TQ_CHECK_PTR(v);
+
+ return v;
+}
+
+void KisDoc::paintContent(TQPainter& painter, const TQRect& rc, bool transparent, double zoomX, double zoomY)
+{
+ KisConfig cfg;
+ TQString monitorProfileName = cfg.monitorProfile();
+ KisProfile * profile = KisMetaRegistry::instance()->csRegistry()->getProfileByName(monitorProfileName);
+ painter.scale(zoomX, zoomY);
+ TQRect 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 TQRect& rect)
+{
+ emit docUpdated(rect);
+}
+
+void KisDoc::beginMacro(const TQString& macroName)
+{
+ if (m_undo) {
+ if (m_macroNestDepth == 0) {
+ Q_ASSERT(m_currentMacro == 0);
+ m_currentMacro = new KMacroCommand(macroName);
+ TQ_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. TQt 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() );
+ }
+}
+
+TQ_INT32 KisDoc::undoLimit() const
+{
+ return m_cmdHistory->undoLimit();
+}
+
+void KisDoc::setUndoLimit(TQ_INT32 limit)
+{
+ m_cmdHistory->setUndoLimit(limit);
+}
+
+TQ_INT32 KisDoc::redoLimit() const
+{
+ return m_cmdHistory->redoLimit();
+}
+
+void KisDoc::setRedoLimit(TQ_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, TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 w, TQ_UINT32 h)
+{
+ TQRect rc(x, y, w, h);
+
+ emit docUpdated(rc);
+}
+
+bool KisDoc::undo() const
+{
+ return m_undo;
+}
+
+void KisDoc::setIOSteps(TQ_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(TQ_INT8 percentage)
+{
+ TDEApplication *app = TDEApplication::kApplication();
+
+ Q_ASSERT(app);
+
+ if (app->hasPendingEvents())
+ app->processEvents();
+
+ int totalPercentage = ((m_ioProgressBase + percentage) * 100) / m_ioProgressTotalSteps;
+
+ emitProgress(totalPercentage);
+}
+
+KisChildDoc * KisDoc::createChildDoc( const TQRect & 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"
+