Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

kis_doc.cc 35.1 KB
Newer Older
1 2 3 4
/*
 *  Copyright (c) 1999 Matthias Elter  <me@kde.org>
 *  Copyright (c) 2000 John Califf  <jcaliff@compuzone.net>
 *  Copyright (c) 2001 Toshitaka Fujioka  <fujioka@kde.org>
5
 *  Copyright (c) 2002, 2003 Patrick Julien <freak@codepimps.org>
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 *  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
Dirk Mueller's avatar
Dirk Mueller committed
19
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
 */
Patrick Julien's avatar
Patrick Julien committed
21 22 23 24

// Qt
#include <qapplication.h>
#include <qclipboard.h>
25 26 27
#include <qdom.h>
#include <qimage.h>
#include <qpainter.h>
Patrick Julien's avatar
Patrick Julien committed
28 29
#include <qtl.h>
#include <qstringlist.h>
30
#include <qwidget.h>
31
#include <qpaintdevicemetrics.h>
32

Patrick Julien's avatar
Patrick Julien committed
33
// KDE
Patrick Julien's avatar
Patrick Julien committed
34
#include <dcopobject.h>
35
#include <kapplication.h>
36 37
#include <kcommand.h>
#include <kdebug.h>
Patrick Julien's avatar
Patrick Julien committed
38
#include <kimageio.h>
39
#include <kfiledialog.h>
Patrick Julien's avatar
Patrick Julien committed
40
#include <kglobal.h>
41
#include <kmessagebox.h>
Patrick Julien's avatar
Patrick Julien committed
42
#include <kmimetype.h>
43
#include <knotifyclient.h>
Patrick Julien's avatar
Patrick Julien committed
44
#include <klocale.h>
45

Patrick Julien's avatar
Patrick Julien committed
46
// KOffice
47 48 49 50 51
#include <koFilterManager.h>
#include <koMainWindow.h>
#include <koQueryTrader.h>
#include <koStore.h>
#include <koStoreDevice.h>
Patrick Julien's avatar
Patrick Julien committed
52
#include <koTemplateChooseDia.h>
David Faure's avatar
David Faure committed
53
#include <koApplication.h>
Laurent Montel's avatar
Laurent Montel committed
54
#include <kocommandhistory.h>
55

Patrick Julien's avatar
Patrick Julien committed
56
// Local
Patrick Julien's avatar
Patrick Julien committed
57
#include "kis_types.h"
Patrick Julien's avatar
Patrick Julien committed
58
#include "kis_config.h"
59
#include "kis_dlg_builder_progress.h"
Patrick Julien's avatar
Patrick Julien committed
60
#include "kis_global.h"
61
#include "kis_channel.h"
Patrick Julien's avatar
Patrick Julien committed
62
#include "kis_dlg_create_img.h"
63
#include "kis_doc.h"
64
#include "kis_factory.h"
65 66
#include "kis_image.h"
#include "kis_layer.h"
Patrick Julien's avatar
Patrick Julien committed
67
#include "kis_nameserver.h"
Patrick Julien's avatar
Patrick Julien committed
68
#include "kis_painter.h"
Patrick Julien's avatar
Patrick Julien committed
69
#include "kis_mask.h"
70
#include "kis_floatingselection.h"
Patrick Julien's avatar
Patrick Julien committed
71
#include "kis_command.h"
72
#include "kis_view.h"
73 74 75
#include "builder/kis_builder_subject.h"
#include "builder/kis_builder_monitor.h"
#include "builder/kis_image_magick_converter.h"
76 77
#include "kis_strategy_colorspace.h"
#include "kis_colorspace_registry.h"
78
#include "tiles/kistilemgr.h"
79

Laurent Montel's avatar
Laurent Montel committed
80 81
#include "KIsDocIface.h"

82
static const char *CURRENT_DTD_VERSION = "1.3";
83

Patrick Julien's avatar
Patrick Julien committed
84 85 86
namespace {
	class KisCommandImageAdd : public KisCommand {
		typedef KisCommand super;
87

Patrick Julien's avatar
Patrick Julien committed
88
	public:
89
		KisCommandImageAdd(KisDoc *doc,
90
			KisUndoAdapter *adapter,
91
			KisImageSP img) : super(i18n("Add Image"), adapter)
Patrick Julien's avatar
Patrick Julien committed
92 93 94 95
		{
			m_doc = doc;
			m_img = img;
		}
96

Patrick Julien's avatar
Patrick Julien committed
97 98 99
		virtual ~KisCommandImageAdd()
		{
		}
100

Patrick Julien's avatar
Patrick Julien committed
101 102
		virtual void execute()
		{
103
			adapter() -> setUndo(false);
Patrick Julien's avatar
Patrick Julien committed
104
			m_doc -> addImage(m_img);
105
			adapter() -> setUndo(true);
Patrick Julien's avatar
Patrick Julien committed
106
		}
107

Patrick Julien's avatar
Patrick Julien committed
108 109
		virtual void unexecute()
		{
110
			adapter() -> setUndo(false);
Patrick Julien's avatar
Patrick Julien committed
111
			m_doc -> removeImage(m_img);
112
			adapter() -> setUndo(true);
Patrick Julien's avatar
Patrick Julien committed
113
		}
114

Patrick Julien's avatar
Patrick Julien committed
115 116 117 118
	private:
		KisDoc *m_doc;
		KisImageSP m_img;
	};
119

Patrick Julien's avatar
Patrick Julien committed
120 121
	class KisCommandImageMv : public KisCommand {
		typedef KisCommand super;
122

Patrick Julien's avatar
Patrick Julien committed
123
	public:
124 125 126
		KisCommandImageMv(KisDoc *doc,
				KisUndoAdapter *adapter,
				const QString& name,
127
				const QString& oldName) : super(i18n("Rename Image"), adapter)
Patrick Julien's avatar
Patrick Julien committed
128 129 130 131 132
		{
			m_doc = doc;
			m_name = name;
			m_oldName = oldName;
		}
133

Patrick Julien's avatar
Patrick Julien committed
134 135 136
		virtual ~KisCommandImageMv()
		{
		}
137

Patrick Julien's avatar
Patrick Julien committed
138 139
		virtual void execute()
		{
140
			adapter() -> setUndo(false);
Patrick Julien's avatar
Patrick Julien committed
141
			m_doc -> renameImage(m_oldName, m_name);
142
			adapter() -> setUndo(true);
Patrick Julien's avatar
Patrick Julien committed
143
		}
144

Patrick Julien's avatar
Patrick Julien committed
145 146
		virtual void unexecute()
		{
147
			adapter() -> setUndo(false);
Patrick Julien's avatar
Patrick Julien committed
148
			m_doc -> renameImage(m_name, m_oldName);
149
			adapter() -> setUndo(true);
Patrick Julien's avatar
Patrick Julien committed
150
		}
151

Patrick Julien's avatar
Patrick Julien committed
152 153 154 155 156
	private:
		KisDoc *m_doc;
		QString m_name;
		QString m_oldName;
	};
157

Patrick Julien's avatar
Patrick Julien committed
158 159
	class KisCommandImageRm : public KisCommand {
		typedef KisCommand super;
160

Patrick Julien's avatar
Patrick Julien committed
161
	public:
162
		KisCommandImageRm(KisDoc *doc,
163 164
				KisUndoAdapter *adapter,
				KisImageSP img) : super(i18n("Remove Image"), adapter)
Patrick Julien's avatar
Patrick Julien committed
165 166 167 168
		{
			m_doc = doc;
			m_img = img;
		}
169

Patrick Julien's avatar
Patrick Julien committed
170 171 172
		virtual ~KisCommandImageRm()
		{
		}
173

Patrick Julien's avatar
Patrick Julien committed
174 175
		virtual void execute()
		{
176
			adapter() -> setUndo(false);
Patrick Julien's avatar
Patrick Julien committed
177
			m_doc -> removeImage(m_img);
178
			adapter() -> setUndo(true);
Patrick Julien's avatar
Patrick Julien committed
179
		}
180

Patrick Julien's avatar
Patrick Julien committed
181 182
		virtual void unexecute()
		{
183
			adapter() -> setUndo(false);
Patrick Julien's avatar
Patrick Julien committed
184
			m_doc -> addImage(m_img);
185
			adapter() -> setUndo(true);
Patrick Julien's avatar
Patrick Julien committed
186
		}
187

Patrick Julien's avatar
Patrick Julien committed
188 189 190 191
	private:
		KisDoc *m_doc;
		KisImageSP m_img;
	};
192 193 194 195 196

	class LayerAddCmd : public KisCommand {
		typedef KisCommand super;

	public:
197 198 199
		LayerAddCmd(KisDoc *doc,
				KisUndoAdapter *adapter,
				KisImageSP img,
200
				KisLayerSP layer) : super(i18n("Add Layer"), adapter)
201 202 203 204 205 206 207 208 209 210 211 212 213
		{
			m_doc = doc;
			m_img = img;
			m_layer = layer;
			m_index = img -> index(layer);
		}

		virtual ~LayerAddCmd()
		{
		}

		virtual void execute()
		{
214
			adapter() -> setUndo(false);
215
			m_doc -> layerAdd(m_img, m_layer, m_index);
216
			adapter() -> setUndo(true);
217 218 219 220
		}

		virtual void unexecute()
		{
221
			adapter() -> setUndo(false);
222
			m_doc -> layerRemove(m_img, m_layer);
223
			adapter() -> setUndo(true);
224 225 226 227 228 229 230 231
		}

	private:
		KisDoc *m_doc;
		KisImageSP m_img;
		KisLayerSP m_layer;
		Q_INT32 m_index;
	};
Patrick Julien's avatar
Patrick Julien committed
232 233 234 235 236

	class LayerRmCmd : public KNamedCommand {
		typedef KNamedCommand super;

	public:
237 238 239
		LayerRmCmd(KisDoc *doc,
				KisUndoAdapter *adapter,
				KisImageSP img,
240
				KisLayerSP layer) : super(i18n("Remove Layer"))
Patrick Julien's avatar
Patrick Julien committed
241 242
		{
			m_doc = doc;
243
			m_adapter = adapter;
Patrick Julien's avatar
Patrick Julien committed
244 245 246 247 248 249 250 251 252 253 254
			m_img = img;
			m_layer = layer;
			m_index = img -> index(layer);
		}

		virtual ~LayerRmCmd()
		{
		}

		virtual void execute()
		{
255
			m_adapter -> setUndo(false);
Patrick Julien's avatar
Patrick Julien committed
256
			m_doc -> layerRemove(m_img, m_layer);
257
			m_adapter -> setUndo(true);
Patrick Julien's avatar
Patrick Julien committed
258 259 260 261
		}

		virtual void unexecute()
		{
262
			m_adapter -> setUndo(false);
Patrick Julien's avatar
Patrick Julien committed
263
			m_doc -> layerAdd(m_img, m_layer, m_index);
264
			m_adapter -> setUndo(true);
Patrick Julien's avatar
Patrick Julien committed
265 266 267 268
		}

	private:
		KisDoc *m_doc;
269
		KisUndoAdapter *m_adapter;
Patrick Julien's avatar
Patrick Julien committed
270 271 272 273
		KisImageSP m_img;
		KisLayerSP m_layer;
		Q_INT32 m_index;
	};
Patrick Julien's avatar
Patrick Julien committed
274 275 276 277 278

	class LayerPropsCmd : public KNamedCommand {
		typedef KNamedCommand super;

	public:
279
		LayerPropsCmd(KisLayerSP layer,
280 281 282 283 284 285
			      KisImageSP img,
			      KisDoc *doc,
			      KisUndoAdapter *adapter,
			      const QString& name,
			      Q_INT32 opacity,
			      CompositeOp compositeOp) : super(i18n("Layer Property Changes"))
Patrick Julien's avatar
Patrick Julien committed
286 287 288 289
		{
			m_layer = layer;
			m_img = img;
			m_doc = doc;
290
			m_adapter = adapter;
Patrick Julien's avatar
Patrick Julien committed
291 292
			m_name = name;
			m_opacity = opacity;
293
			m_compositeOp = compositeOp;
Patrick Julien's avatar
Patrick Julien committed
294 295 296 297 298 299 300 301 302 303 304
		}

		virtual ~LayerPropsCmd()
		{
		}

	public:
		virtual void execute()
		{
			QString name = m_layer -> name();
			Q_INT32 opacity = m_layer -> opacity();
305
			CompositeOp compositeOp = m_layer -> compositeOp();
Patrick Julien's avatar
Patrick Julien committed
306

307
			m_adapter -> setUndo(false);
Laurent Montel's avatar
Laurent Montel committed
308
			m_doc -> setLayerProperties(m_img,
309
						    m_layer,
Laurent Montel's avatar
Laurent Montel committed
310
						    m_opacity,
311 312
						    m_compositeOp,
						    m_name);
313
			m_adapter -> setUndo(true);
Patrick Julien's avatar
Patrick Julien committed
314 315
			m_name = name;
			m_opacity = opacity;
316
			m_compositeOp = compositeOp;
Patrick Julien's avatar
Patrick Julien committed
317 318 319 320 321 322 323 324 325
			m_img -> notify();
		}

		virtual void unexecute()
		{
			execute();
		}

	private:
326
		KisUndoAdapter *m_adapter;
327 328 329 330
		KisLayerSP m_layer;
		KisImageSP m_img;
		KisDoc *m_doc;
		QString m_name;
Patrick Julien's avatar
Patrick Julien committed
331
		Q_INT32 m_opacity;
332
		CompositeOp m_compositeOp;
Patrick Julien's avatar
Patrick Julien committed
333
	};
334
}
335

336
KisDoc::KisDoc(QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name, bool singleViewMode) :
Patrick Julien's avatar
Patrick Julien committed
337
	super(parentWidget, widgetName, parent, name, singleViewMode)
338
{
339 340
	kdDebug() << "KisDoc created for " << widgetName << "\n";

Patrick Julien's avatar
Patrick Julien committed
341 342
	m_undo = false;
	m_dcop = 0;
Boudewijn Rempt's avatar
Oops  
Boudewijn Rempt committed
343
	setInstance(KisFactory::global(), false);
Patrick Julien's avatar
Patrick Julien committed
344 345
	m_cmdHistory = 0;
	m_nserver = 0;
Patrick Julien's avatar
Patrick Julien committed
346
	m_pushedClipboard = false;
Patrick Julien's avatar
Patrick Julien committed
347
	m_currentMacro = 0;
348

Patrick Julien's avatar
Patrick Julien committed
349 350
	if (name)
		dcopObject();
351
}
352

353 354
KisDoc::~KisDoc()
{
355
	delete m_cmdHistory;
Patrick Julien's avatar
Patrick Julien committed
356
        delete m_dcop;
Patrick Julien's avatar
Patrick Julien committed
357
	delete m_nserver;
358 359
}

Patrick Julien's avatar
Patrick Julien committed
360
QCString KisDoc::mimeType() const
361
{
Patrick Julien's avatar
Patrick Julien committed
362 363
	return APP_MIMETYPE;
}
364

Patrick Julien's avatar
Patrick Julien committed
365 366 367 368 369 370
DCOPObject *KisDoc::dcopObject()
{
	if (!m_dcop)
		m_dcop = new KIsDocIface(this);

	return m_dcop;
371 372
}

373 374
bool KisDoc::initDoc()
{
375
	kdDebug() << "KisDoc::initDoc\n";
376 377 378
	if (!init())
		return false;

379
	bool ok = false;
380
	QString file;
381
	KoTemplateChooseDia::DialogType dlgtype;
382

383
	if (initDocFlags() != KoDocument::InitDocFileNew)
384 385 386
		dlgtype = KoTemplateChooseDia::Everything;
	else
		dlgtype = KoTemplateChooseDia::OnlyTemplates;
387

388 389
	KoTemplateChooseDia::ReturnType ret =
	    KoTemplateChooseDia::choose(KisFactory::global(), file, APP_MIMETYPE,
390 391
					"*.kra", i18n("Krita"),
					dlgtype, "krita_template");
392 393

	if (ret == KoTemplateChooseDia::Template) {
394
		kdDebug() << "Eek: template is hard-coded rgba" << endl;
Patrick Julien's avatar
Patrick Julien committed
395
		KisConfig cfg;
Patrick Julien's avatar
Patrick Julien committed
396
		QString name = nextImageName();
397
		KisImageSP img = new KisImage(this, cfg.defImgWidth(), cfg.defImgHeight(), KisColorSpaceRegistry::singleton()->colorSpace("RGBA"), name);
398
		img -> setResolution(100, 100); // XXX
Patrick Julien's avatar
Patrick Julien committed
399
		KisLayerSP layer = new KisLayer(img, cfg.defLayerWidth(), cfg.defLayerHeight(), img -> nextLayerName(), OPACITY_OPAQUE);
400

401
		layer -> setVisible(true);
Patrick Julien's avatar
Patrick Julien committed
402
		addImage(img);
403
		ok = true;
Patrick Julien's avatar
Patrick Julien committed
404
	} else if (ret == KoTemplateChooseDia::File) {
405
		KURL url( file );
Patrick Julien's avatar
Patrick Julien committed
406 407 408
		ok = openURL(url);
	} else if (ret == KoTemplateChooseDia::Empty) {
		if ((ok = slotNewImage()))
409 410 411
			emit imageListUpdated();
	}

412
	setModified(false);
413 414 415
	return ok;
}

416
bool KisDoc::init()
417
{
418
	kdDebug() << "KisDoc::init\n";
419 420 421
	if (m_cmdHistory) {
		delete m_cmdHistory;
		m_cmdHistory = 0;
422
	}
423

424 425 426 427 428
	if (m_nserver) {
		delete m_nserver;
		m_nserver = 0;
	}

Laurent Montel's avatar
Laurent Montel committed
429
	m_cmdHistory = new KoCommandHistory(actionCollection(), true);
430 431 432
	connect(m_cmdHistory, SIGNAL(documentRestored()), this, SLOT(slotDocumentRestored()));
	connect(m_cmdHistory, SIGNAL(commandExecuted()), this, SLOT(slotCommandExecuted()));
	m_undo = true;
433
	m_nserver = new KisNameServer(i18n("Image %1"), 1);
434
	return true;
435
}
436

437
QDomDocument KisDoc::saveXML()
438
{
439 440
	QDomDocument doc = createDomDocument("DOC", CURRENT_DTD_VERSION);
	QDomElement root = doc.documentElement();
441

442 443 444
	root.setAttribute("editor", "Krita");
	root.setAttribute("depth", sizeof(QUANTUM));
	root.setAttribute("syntaxVersion", "1");
445

446 447 448 449
	for (vKisImageSP_it it = m_images.begin(); it != m_images.end(); it++)
		root.appendChild(saveImage(doc, *it));

	return doc;
450 451
}

452
bool KisDoc::loadOasis( const QDomDocument&, KoOasisStyles&, const QDomDocument&, KoStore* )
Laurent Montel's avatar
Laurent Montel committed
453
{
454
	//XXX: todo (and that includes defining an OASIS format for layered 2D raster data!)
David Faure's avatar
David Faure committed
455 456 457 458 459 460
	return false;
}


bool KisDoc::saveOasis( KoStore*, KoXmlWriter* )
{
461
	//XXX: todo (and that includes defining an OASIS format for layered 2D raster data!)
David Faure's avatar
David Faure committed
462
	return false;
Laurent Montel's avatar
Laurent Montel committed
463 464
}

465
bool KisDoc::loadXML(QIODevice *, const QDomDocument& doc)
466
{
467 468 469 470
	QDomElement root;
	QString attr;
	QDomNode node;
	KisImageSP img;
471

472 473
	if (!init())
		return false;
474

475 476
	if (doc.doctype().name() != "DOC")
		return false;
477

478 479
	root = doc.documentElement();
	attr = root.attribute("syntaxVersion");
480

481 482
	if (attr.toInt() > 1)
		return false;
483

484 485 486 487 488 489
	if ((attr = root.attribute("depth")) == QString::null)
		return false;

	m_conversionDepth = attr.toInt();

	for (node = root.firstChild(); !node.isNull(); node = node.nextSibling()) {
490
		if (node.isElement()) {
491 492 493 494 495
			if (node.nodeName() == "IMAGE") {
				QDomElement elem = node.toElement();

				if (!(img = loadImage(elem)))
					return false;
496

497 498 499 500 501 502 503 504 505
				m_images.push_back(img);
			} else {
				kdDebug(DBG_AREA_CORE) << "KisDoc::loadXML nodeName == " << node.nodeName() << endl;
				return false;
			}
		}
	}

	return true;
506 507
}

508
QDomElement KisDoc::saveImage(QDomDocument& doc, KisImageSP img)
509
{
510 511 512 513 514 515 516 517 518
	QDomElement image = doc.createElement("IMAGE");
	vKisLayerSP layers;
	vKisChannelSP channels;

	Q_ASSERT(img);
	image.setAttribute("name", img -> name());
	image.setAttribute("mime", "application/x-kra");
	image.setAttribute("width", img -> width());
	image.setAttribute("height", img -> height());
519
	image.setAttribute("colorspacename", img -> colorStrategy() -> name());
520
	layers = img -> layers();
521

522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
	if (layers.size() > 0) {
		QDomElement elem = doc.createElement("LAYERS");

		image.appendChild(elem);

		for (vKisLayerSP_it it = layers.begin(); it != layers.end(); it++)
			elem.appendChild(saveLayer(doc, *it));
	}

	channels = img -> channels();

	if (channels.size() > 0) {
		QDomElement elem = doc.createElement("CHANNELS");

		image.appendChild(elem);

		for (vKisChannelSP_it it = channels.begin(); it != channels.end(); it++)
			elem.appendChild(saveChannel(doc, *it));
	}

	// TODO Image colormap if any
	return image;
544 545
}

546
KisImageSP KisDoc::loadImage(const QDomElement& element)
547
{
548 549 550 551 552 553 554 555
	KisConfig cfg;
	QString attr;
	QDomNode node;
	QDomNode child;
	KisImageSP img;
	QString name;
	Q_INT32 width;
	Q_INT32 height;
556 557
	QString colorspacename;
	Q_INT32 colorspace_int; // used to keep compatibility with old document
558

559 560 561
	if ((attr = element.attribute("mime")) == NATIVE_MIMETYPE) {
		if ((name = element.attribute("name")) == QString::null)
			return 0;
562

563 564
		if (namePresent(name))
			name = nextImageName();
565

566 567
		if ((attr = element.attribute("width")) == QString::null)
			return 0;
568

569 570
		if ((width = attr.toInt()) < 0 || width > cfg.maxImgWidth())
			return 0;
571

572 573
		if ((attr = element.attribute("height")) == QString::null)
			return 0;
574

575 576
		if ((height = attr.toInt()) < 0 || height > cfg.maxImgHeight())
			return 0;
577

578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
		if ((colorspacename = element.attribute("colorspacename")) == QString::null)
		{
			// TODO: This code is used for compatibility with old files,
			// it should be removed before alpha
			if ((attr = element.attribute("colorspace")) == QString::null)
				return 0;
			colorspace_int = attr.toInt();
			kdDebug() << "colorspace_int = " << colorspace_int << endl;
			if( colorspace_int <= IMAGE_TYPE_UNKNOWN || colorspace_int > IMAGE_TYPE_YUVA)
				return 0;
			switch(colorspace_int)
			{
					case IMAGE_TYPE_GREYA:
					case IMAGE_TYPE_GREY:
						colorspacename = "Grayscale + Alpha";
						break;
					case IMAGE_TYPE_RGB:
					case IMAGE_TYPE_RGBA:
						colorspacename = "RGBA";
						break;
					case IMAGE_TYPE_CMYK:
					case IMAGE_TYPE_CMYKA:
						colorspacename = "CMYKA";
						break;
					default:
						return 0;
			}
		}
606
		img = new KisImage(this, width, height, KisColorSpaceRegistry::singleton()->colorSpace(colorspacename), name);
607

608
		for (node = element.firstChild(); !node.isNull(); node = node.nextSibling()) {
609
			if (node.isElement()) {
610 611 612
				if (node.nodeName() == "LAYERS") {
					for (child = node.firstChild(); !child.isNull(); child = child.nextSibling()) {
						KisLayerSP layer = loadLayer(child.toElement(), img);
613

614
						if (!layer)
Patrick Julien's avatar
Patrick Julien committed
615
							return 0;
616

617 618
						img -> add(layer, -1);
					}
619 620 621 622

					if (img -> nlayers()) {
						img -> activateLayer(0);
					}
623 624 625
				} else if (node.nodeName() == "CHANNELS") {
					for (child = node.firstChild(); !child.isNull(); child = child.nextSibling()) {
						KisChannelSP channel = loadChannel(child.toElement(), img);
626

627
						if (!channel)
Patrick Julien's avatar
Patrick Julien committed
628
							return 0;
629

630 631 632 633 634 635 636
						img -> add(channel, -1);
					}
				} else if (node.nodeName() == "COLORMAP") {
					// TODO
				} else {
					kdDebug(DBG_AREA_CORE) << "KisDoc::loadImage nodeName == " << node.nodeName() << endl;
				}
637 638
			}
		}
639 640
	} else {
		// TODO Try to import it
641
	}
642

643
	return img;
644
}
645

646 647 648
QDomElement KisDoc::saveLayer(QDomDocument& doc, KisLayerSP layer)
{
	QDomElement layerElement = doc.createElement("layer");
649

650 651 652 653 654 655 656 657 658 659 660 661 662
	layerElement.setAttribute("name", layer -> name());
	layerElement.setAttribute("x", layer -> x());
	layerElement.setAttribute("y", layer -> y());
	layerElement.setAttribute("width", layer -> width());
	layerElement.setAttribute("height", layer -> height());
	layerElement.setAttribute("opacity", layer -> opacity());
	layerElement.setAttribute("visible", layer -> visible());
	layerElement.setAttribute("linked", layer -> linked());
	// TODO : Layer mask
	return layerElement;
}

KisLayerSP KisDoc::loadLayer(const QDomElement& element, KisImageSP img)
663
{
664 665 666 667 668 669 670 671 672 673 674 675 676
	KisConfig cfg;
	QString attr;
	QDomNode node;
	QDomNode child;
	QString name;
	Q_INT32 x;
	Q_INT32 y;
	Q_INT32 width;
	Q_INT32 height;
	Q_INT32 opacity;
	bool visible;
	bool linked;
	KisLayerSP layer;
677

678 679
	if ((name = element.attribute("name")) == QString::null)
		return 0;
680

681 682
	if ((attr = element.attribute("x")) == QString::null)
		return 0;
683

684
	x = attr.toInt();
685

686 687
	if ((attr = element.attribute("y")) == QString::null)
		return 0;
688

689
	y = attr.toInt();
690

691 692
	if ((attr = element.attribute("width")) == QString::null)
		return 0;
693

694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
	if ((width = attr.toInt()) < 0 || x + width > cfg.maxImgWidth())
		return 0;

	if ((attr = element.attribute("height")) == QString::null)
		return 0;

	if ((height = attr.toInt()) < 0 || y + height > cfg.maxImgHeight())
		return 0;

	if ((attr = element.attribute("opacity")) == QString::null)
		return 0;

	if ((opacity = attr.toInt()) < 0 || opacity > QUANTUM_MAX)
		return 0;

	if ((attr = element.attribute("visible")) == QString::null)
		return 0;

	visible = attr == "0" ? false : true;
713

714 715 716 717 718
	if ((attr = element.attribute("linked")) == QString::null)
		return 0;

	linked = attr == "0" ? false : true;
	layer = new KisLayer(img, width, height, name, opacity);
719 720
	layer -> setLinked(linked);
	layer -> setVisible(visible);
721 722
	layer -> move(x, y);
	return layer;
723 724
}

725
QDomElement KisDoc::saveChannel(QDomDocument& doc, KisChannelSP channel)
726
{
727
	QDomElement channelElement = doc.createElement("CHANNEL");
728

729 730 731 732 733 734 735 736
	channelElement.setAttribute("name", channel -> name());
	channelElement.setAttribute("x", channel -> x());
	channelElement.setAttribute("y", channel -> y());
	channelElement.setAttribute("width", channel -> width());
	channelElement.setAttribute("height", channel -> height());
	channelElement.setAttribute("opacity", channel -> opacity());
	return channelElement;
}
737

738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
KisChannelSP KisDoc::loadChannel(const QDomElement& element, KisImageSP img)
{
	KisConfig cfg;
	QString attr;
	QDomNode node;
	QDomNode child;
	QString name;
	Q_INT32 x;
	Q_INT32 y;
	Q_INT32 width;
	Q_INT32 height;
	Q_INT32 opacity;
	KisChannelSP channel;

	if ((name = element.attribute("name")) == QString::null)
		return 0;
754

755 756
	if ((attr = element.attribute("x")) == QString::null)
		return 0;
757

758
	x = attr.toInt();
759

760 761
	if ((attr = element.attribute("y")) == QString::null)
		return 0;
762

763
	y = attr.toInt();
Patrick Julien's avatar
Patrick Julien committed
764

765 766
	if ((attr = element.attribute("width")) == QString::null)
		return 0;
767

768 769
	if ((width = attr.toInt()) < 0 || x + width > cfg.maxImgWidth())
		return 0;
770

771 772
	if ((attr = element.attribute("height")) == QString::null)
		return 0;
773

774 775
	if ((height = attr.toInt()) < 0 || y + height > cfg.maxImgHeight())
		return 0;
776

777 778
	if ((attr = element.attribute("opacity")) == QString::null)
		return 0;
779

780 781
	if ((opacity = attr.toInt()) < 0 || opacity > QUANTUM_MAX)
		return 0;
782

783 784 785 786
	channel = new KisChannel(img, width, height, name, KoColor::black());
	channel -> opacity(opacity);
	channel -> move(x, y);
	return channel;
787 788
}

789
bool KisDoc::completeSaving(KoStore *store)
790
{
791 792 793 794
	QString uri = url().url();
	QString location;
	bool external = isStoredExtern();
	Q_INT32 totalSteps = 0;
795 796
	vKisImageSP images;
	KisImageSP img;
797

798
	for (vKisImageSP_it it = m_images.begin(); it != m_images.end(); it++) {
799
		totalSteps += (*it) -> nlayers() + (*it) -> nchannels();
800 801 802 803
		img = new KisImage(**it);
		img -> setName((*it) -> name());
		images.push_back(img);
	}
804

805
	emit ioSteps(totalSteps);
806

807
	for (vKisImageSP_it it = images.begin(); it != images.end(); it++) {
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
		vKisLayerSP layers = (*it) -> layers();
		vKisChannelSP channels = (*it) -> channels();

		for (vKisLayerSP_it it2 = layers.begin(); it2 != layers.end(); it2++) {
			connect(*it2, SIGNAL(ioProgress(Q_INT8)), this, SLOT(slotIOProgress(Q_INT8)));
			location = external ? QString::null : uri;
			location += (*it) -> name() + "/layers/" + (*it2) -> name();

			if (store -> open(location)) {
				if (!(*it2) -> write(store)) {
					(*it2) -> disconnect();
					store -> close();
					emit ioDone();
					return false;
				}
823

824 825
				store -> close();
			}
826

827 828 829 830
			// TODO Mask
			emit ioCompletedStep();
			(*it2) -> disconnect();
		}
831

832 833 834 835 836 837 838 839 840 841 842 843
		for (vKisChannelSP_it it2 = channels.begin(); it2 != channels.end(); it2++) {
			connect(*it2, SIGNAL(ioProgress(Q_INT8)), this, SLOT(slotIOProgress(Q_INT8)));
			location = external ? QString::null : uri;
			location += (*it) -> name() + "/channels/" + (*it2) -> name();

			if (store -> open(location)) {
				if (!(*it2) -> write(store)) {
					(*it2) -> disconnect();
					store -> close();
					emit ioDone();
					return false;
				}
844

845
				store -> close();
846
			}
847 848 849

			emit ioCompletedStep();
			(*it2) -> disconnect();
850 851 852
		}
	}

853 854
	emit ioDone();
	return true;
855 856
}

857
bool KisDoc::completeLoading(KoStore *store)
858
{
859 860 861 862
	QString uri = url().url();
	QString location;
	bool external = isStoredExtern();
	Q_INT32 totalSteps = 0;
863

864 865
	for (vKisImageSP_it it = m_images.begin(); it != m_images.end(); it++)
		totalSteps += (*it) -> nlayers() + (*it) -> nchannels();
866

867
	emit ioSteps(totalSteps);
868

869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884
	for (vKisImageSP_it it = m_images.begin(); it != m_images.end(); it++) {
		vKisLayerSP layers = (*it) -> layers();
		vKisChannelSP channels = (*it) -> channels();

		for (vKisLayerSP_it it2 = layers.begin(); it2 != layers.end(); it2++) {
			connect(*it2, SIGNAL(ioProgress(Q_INT8)), this, SLOT(slotIOProgress(Q_INT8)));
			location = external ? QString::null : uri;
			location += (*it) -> name() + "/layers/" + (*it2) -> name();

			if (store -> open(location)) {
				if (!(*it2) -> read(store)) {
					(*it2) -> disconnect();
					store -> close();
					emit ioDone();
					return false;
				}
885

886 887
				store -> close();
			}
888

889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905
			// TODO Mask
			emit ioCompletedStep();
			(*it2) -> disconnect();
		}

		for (vKisChannelSP_it it2 = channels.begin(); it2 != channels.end(); it2++) {
			connect(*it2, SIGNAL(ioProgress(Q_INT8)), this, SLOT(slotIOProgress(Q_INT8)));
			location = external ? QString::null : uri;
			location += (*it) -> name() + "/channels/" + (*it2) -> name();

			if (store -> open(location)) {
				if (!(*it2) -> read(store)) {
					(*it2) -> disconnect();
					store -> close();
					emit ioDone();
					return false;
				}
906

907 908 909
				store -> close();
			}

910 911
			emit ioCompletedStep();
			(*it2) -> disconnect();
912 913 914
		}
	}

915
	emit ioDone();
916
	return true;
917 918
}

919
bool KisDoc::namePresent(const QString& name) const
920
{
921
	for (vKisImageSP_cit it = m_images.begin(); it != m_images.end(); it++)
922 923 924 925 926 927
		if ((*it) -> name() == name)
			return true;

	return false;
}

928 929
void KisDoc::renameImage(const QString& oldName, const QString& newName)
{
Patrick Julien's avatar
Patrick Julien committed
930
	for (vKisImageSP_it it = m_images.begin(); it != m_images.end(); it++) {
931 932
		if ((*it) -> name() == oldName) {
			(*it) -> setName(newName);
Patrick Julien's avatar
Patrick Julien committed
933 934

			if (m_undo)
935
				addCommand(new KisCommandImageMv(this, this, newName, oldName));
Patrick Julien's avatar
Patrick Julien committed
936 937

			emit imageListUpdated();
Patrick Julien's avatar
Patrick Julien committed
938
			break;
939 940
		}
	}
941 942 943 944
}

QStringList KisDoc::images()
{
945
	QStringList lst;
946

Patrick Julien's avatar
Patrick Julien committed
947
	for (vKisImageSP_it it = m_images.begin(); it != m_images.end(); it++)
948
		lst.append((*it) -> name());
949

950
	return lst;
951 952 953 954
}

bool KisDoc::isEmpty() const
{
Patrick Julien's avatar
Patrick Julien committed
955
	return m_images.size() == 0;
956 957
}

958 959 960 961 962 963 964 965 966 967
Q_INT32 KisDoc::imageIndex(KisImageSP img) const
{
	for (vKisImageSP_cit it = m_images.begin(); it != m_images.end(); it++) {
		if (*it == img)
			return it - m_images.begin();
	}

	return -1;
}

968
KisImageSP KisDoc::imageNum(unsigned int num) const
969
{
970 971
	if (m_images.empty() || num > m_images.size())
		return 0;
972

973
	return m_images[num];
974 975
}

976 977 978 979 980
Q_INT32 KisDoc::nimages() const
{
	return m_images.size();
}

981
KisImageSP KisDoc::findImage(const QString& name) const
Patrick Julien's avatar
Patrick Julien committed
982
{
983
	for (vKisImageSP_cit it = m_images.begin(); it != m_images.end(); it++) {
984 985 986 987
		if ((*it) -> name() == name) {
			return *it;
		}
	}
Patrick Julien's avatar
Patrick Julien committed
988

989
	return 0;
Patrick Julien's avatar
Patrick Julien committed
990
}
991

992
bool KisDoc::contains(KisImageSP img) const
993
{
994
	return qFind(m_images.begin(), m_images.end(), img) != m_images.end();
995 996
}

997
KisImageSP KisDoc::newImage(const QString& name, Q_INT32 width, Q_INT32 height, KisStrategyColorSpaceSP colorstrategy)
998
{
999
	KisImageSP img = new KisImage(this, width, height, colorstrategy, name);
1000

1001
	m_images.push_back(img);
1002

Patrick Julien's avatar
Patrick Julien committed
1003
	if (m_undo)
1004
		addCommand(new KisCommandImageAdd(this, this, img));
1005

1006
	return img;
1007 1008
}