diff options
Diffstat (limited to 'chalk/ui/kis_doc.cpp')
-rw-r--r-- | chalk/ui/kis_doc.cpp | 1171 |
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" + |