File indexing completed on 2024-05-19 04:26:55

0001 /*
0002  *  SPDX-FileCopyrightText: 2016 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 #include "Document.h"
0007 #include <QPointer>
0008 #include <QUrl>
0009 #include <QDomDocument>
0010 
0011 #include <KoColorSpaceConstants.h>
0012 #include <KisDocument.h>
0013 #include <kis_image.h>
0014 #include <KisPart.h>
0015 #include <kis_paint_device.h>
0016 #include <KisMainWindow.h>
0017 #include <kis_node_manager.h>
0018 #include <kis_node_selection_adapter.h>
0019 #include <KisViewManager.h>
0020 #include <kis_file_layer.h>
0021 #include <kis_adjustment_layer.h>
0022 #include <kis_mask.h>
0023 #include <kis_clone_layer.h>
0024 #include <kis_group_layer.h>
0025 #include <kis_filter_mask.h>
0026 #include <kis_transform_mask.h>
0027 #include <kis_transparency_mask.h>
0028 #include <kis_selection_mask.h>
0029 #include <lazybrush/kis_colorize_mask.h>
0030 #include <kis_effect_mask.h>
0031 #include <kis_paint_layer.h>
0032 #include <kis_generator_layer.h>
0033 #include <kis_generator_registry.h>
0034 #include <kis_shape_layer.h>
0035 #include <kis_filter_configuration.h>
0036 #include <kis_filter_registry.h>
0037 #include <kis_selection.h>
0038 #include <KisMimeDatabase.h>
0039 #include <kis_filter_strategy.h>
0040 #include <kis_guides_config.h>
0041 #include <kis_coordinates_converter.h>
0042 #include <kis_time_span.h>
0043 #include <KisImportExportErrorCode.h>
0044 #include <kis_types.h>
0045 #include <kis_annotation.h>
0046 
0047 #include <KoColor.h>
0048 #include <KoColorSpace.h>
0049 #include <KoColorProfile.h>
0050 #include <KoColorSpaceRegistry.h>
0051 #include <KoColorConversionTransformation.h>
0052 #include <KoDocumentInfo.h>
0053 #include <KisGlobalResourcesInterface.h>
0054 
0055 #include <InfoObject.h>
0056 #include <Node.h>
0057 #include <Selection.h>
0058 #include <LibKisUtils.h>
0059 
0060 #include "kis_animation_importer.h"
0061 #include <kis_canvas2.h>
0062 #include <KoUpdater.h>
0063 #include <QMessageBox>
0064 
0065 #include <kis_image_animation_interface.h>
0066 #include <kis_layer_utils.h>
0067 #include <kis_undo_adapter.h>
0068 #include <commands/kis_set_global_selection_command.h>
0069 
0070 struct Document::Private {
0071     Private() {}
0072     QPointer<KisDocument> document;
0073     bool ownsDocument {false};
0074 };
0075 
0076 Document::Document(KisDocument *document, bool ownsDocument, QObject *parent)
0077     : QObject(parent)
0078     , d(new Private)
0079 {
0080     d->document = document;
0081     d->ownsDocument = ownsDocument;
0082 }
0083 
0084 Document::~Document()
0085 {
0086     if (d->ownsDocument && d->document) {
0087         KisPart::instance()->removeDocument(d->document);
0088         delete d->document;
0089     }
0090     delete d;
0091 }
0092 
0093 bool Document::operator==(const Document &other) const
0094 {
0095     return (d->document == other.d->document);
0096 }
0097 
0098 bool Document::operator!=(const Document &other) const
0099 {
0100     return !(operator==(other));
0101 }
0102 
0103 bool Document::batchmode() const
0104 {
0105     if (!d->document) return false;
0106     return d->document->fileBatchMode();
0107 }
0108 
0109 void Document::setBatchmode(bool value)
0110 {
0111     if (!d->document) return;
0112     d->document->setFileBatchMode(value);
0113 }
0114 
0115 Node *Document::activeNode() const
0116 {
0117     QList<KisNodeSP> activeNodes;
0118     Q_FOREACH(QPointer<KisView> view, KisPart::instance()->views()) {
0119         if (view && view->document() == d->document) {
0120             activeNodes << view->currentNode();
0121 
0122         }
0123     }
0124     if (activeNodes.size() > 0) {
0125         QList<Node*> nodes = LibKisUtils::createNodeList(activeNodes, d->document->image());
0126         return nodes.first();
0127     }
0128 
0129     return 0;
0130 }
0131 
0132 void Document::setActiveNode(Node* value)
0133 {
0134     if (!value) return;
0135     if (!value->node()) return;
0136     KisMainWindow *mainWin = KisPart::instance()->currentMainwindow();
0137     if (!mainWin) return;
0138     KisViewManager *viewManager = mainWin->viewManager();
0139     if (!viewManager) return;
0140     if (viewManager->document() != d->document) return;
0141     KisNodeManager *nodeManager = viewManager->nodeManager();
0142     if (!nodeManager) return;
0143     KisNodeSelectionAdapter *selectionAdapter = nodeManager->nodeSelectionAdapter();
0144     if (!selectionAdapter) return;
0145     selectionAdapter->setActiveNode(value->node());
0146 
0147 }
0148 
0149 QList<Node *> Document::topLevelNodes() const
0150 {
0151     if (!d->document) return QList<Node *>();
0152     Node n(d->document->image(), d->document->image()->rootLayer());
0153     return n.childNodes();
0154 }
0155 
0156 
0157 Node *Document::nodeByName(const QString &name) const
0158 {
0159     if (!d->document) return 0;
0160     KisNodeSP node = KisLayerUtils::findNodeByName(d->document->image()->rootLayer(),name);
0161 
0162     if (node.isNull()) return 0;
0163 
0164     return Node::createNode(d->document->image(), node);
0165 }
0166 
0167 Node *Document::nodeByUniqueID(const QUuid &id) const
0168 {
0169     if (!d->document) return 0;
0170 
0171     KisNodeSP node = KisLayerUtils::findNodeByUuid(d->document->image()->rootLayer(), id);
0172 
0173     if (node.isNull()) return 0;
0174     return Node::createNode(d->document->image(), node);
0175 }
0176 
0177 
0178 QString Document::colorDepth() const
0179 {
0180     if (!d->document) return "";
0181     return d->document->image()->colorSpace()->colorDepthId().id();
0182 }
0183 
0184 QString Document::colorModel() const
0185 {
0186     if (!d->document) return "";
0187     return d->document->image()->colorSpace()->colorModelId().id();
0188 }
0189 
0190 QString Document::colorProfile() const
0191 {
0192     if (!d->document) return "";
0193     return d->document->image()->colorSpace()->profile()->name();
0194 }
0195 
0196 bool Document::setColorProfile(const QString &value)
0197 {
0198     if (!d->document) return false;
0199     if (!d->document->image()) return false;
0200     const KoColorProfile *profile = KoColorSpaceRegistry::instance()->profileByName(value);
0201     if (!profile) return false;
0202     bool retval = d->document->image()->assignImageProfile(profile);
0203     d->document->image()->waitForDone();
0204     return retval;
0205 }
0206 
0207 bool Document::setColorSpace(const QString &colorModel, const QString &colorDepth, const QString &colorProfile)
0208 {
0209     if (!d->document) return false;
0210     if (!d->document->image()) return false;
0211     const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorModel, colorDepth, colorProfile);
0212     if (!colorSpace) return false;
0213 
0214     d->document->image()->convertImageColorSpace(colorSpace,
0215                                                  KoColorConversionTransformation::IntentPerceptual,
0216                                                  KoColorConversionTransformation::HighQuality | KoColorConversionTransformation::NoOptimization);
0217 
0218     d->document->image()->waitForDone();
0219     return true;
0220 }
0221 
0222 QColor Document::backgroundColor()
0223 {
0224     if (!d->document) return QColor();
0225     if (!d->document->image()) return QColor();
0226 
0227     const KoColor color = d->document->image()->defaultProjectionColor();
0228     return color.toQColor();
0229 }
0230 
0231 bool Document::setBackgroundColor(const QColor &color)
0232 {
0233     if (!d->document) return false;
0234     if (!d->document->image()) return false;
0235 
0236     KoColor background = KoColor(color, d->document->image()->colorSpace());
0237     d->document->image()->setDefaultProjectionColor(background);
0238 
0239     d->document->image()->setModifiedWithoutUndo();
0240     d->document->image()->initialRefreshGraph();
0241 
0242     return true;
0243 }
0244 
0245 QString Document::documentInfo() const
0246 {
0247     QDomDocument doc = KisDocument::createDomDocument("document-info"
0248                                                       /*DTD name*/, "document-info" /*tag name*/, "1.1");
0249     doc = d->document->documentInfo()->save(doc);
0250     return doc.toString();
0251 }
0252 
0253 void Document::setDocumentInfo(const QString &document)
0254 {
0255     QDomDocument doc;
0256     QString errorMsg;
0257     int errorLine, errorColumn;
0258     doc.setContent(document, &errorMsg, &errorLine, &errorColumn);
0259     d->document->documentInfo()->load(doc);
0260 }
0261 
0262 
0263 QString Document::fileName() const
0264 {
0265     if (!d->document) return QString();
0266     return d->document->path();
0267 }
0268 
0269 void Document::setFileName(QString value)
0270 {
0271     if (!d->document) return;
0272     QString mimeType = KisMimeDatabase::mimeTypeForFile(value, false);
0273     d->document->setMimeType(mimeType.toLatin1());
0274     d->document->setPath(value);
0275 }
0276 
0277 int Document::height() const
0278 {
0279     if (!d->document) return 0;
0280     KisImageSP image = d->document->image();
0281     if (!image) return 0;
0282     return image->height();
0283 }
0284 
0285 void Document::setHeight(int value)
0286 {
0287     if (!d->document) return;
0288     if (!d->document->image()) return;
0289     resizeImage(d->document->image()->bounds().x(),
0290                 d->document->image()->bounds().y(),
0291                 d->document->image()->width(),
0292                 value);
0293 }
0294 
0295 
0296 QString Document::name() const
0297 {
0298     if (!d->document) return "";
0299     return d->document->documentInfo()->aboutInfo("title");
0300 }
0301 
0302 void Document::setName(QString value)
0303 {
0304     if (!d->document) return;
0305     d->document->documentInfo()->setAboutInfo("title", value);
0306 }
0307 
0308 
0309 int Document::resolution() const
0310 {
0311     if (!d->document) return 0;
0312     KisImageSP image = d->document->image();
0313     if (!image) return 0;
0314 
0315     return qRound(d->document->image()->xRes() * 72);
0316 }
0317 
0318 void Document::setResolution(int value)
0319 {
0320     if (!d->document) return;
0321     KisImageSP image = d->document->image();
0322     if (!image) return;
0323 
0324     KisFilterStrategy *strategy = KisFilterStrategyRegistry::instance()->get("Bicubic");
0325     KIS_SAFE_ASSERT_RECOVER_RETURN(strategy);
0326 
0327     image->scaleImage(image->size(), value / 72.0, value / 72.0, strategy);
0328     image->waitForDone();
0329 }
0330 
0331 
0332 Node *Document::rootNode() const
0333 {
0334     if (!d->document) return 0;
0335     KisImageSP image = d->document->image();
0336     if (!image) return 0;
0337 
0338     return Node::createNode(image, image->root());
0339 }
0340 
0341 Selection *Document::selection() const
0342 {
0343     if (!d->document) return 0;
0344     if (!d->document->image()) return 0;
0345     if (!d->document->image()->globalSelection()) return 0;
0346     return new Selection(d->document->image()->globalSelection());
0347 }
0348 
0349 void Document::setSelection(Selection* value)
0350 {
0351     if (!d->document) return;
0352     if (!d->document->image()) return;
0353     if (value) {
0354         d->document->image()->undoAdapter()->addCommand(new KisSetGlobalSelectionCommand(d->document->image(), value->selection()));
0355     }
0356     else {
0357         d->document->image()->undoAdapter()->addCommand(new KisSetGlobalSelectionCommand(d->document->image(), nullptr));
0358     }
0359 }
0360 
0361 
0362 int Document::width() const
0363 {
0364     if (!d->document) return 0;
0365     KisImageSP image = d->document->image();
0366     if (!image) return 0;
0367     return image->width();
0368 }
0369 
0370 void Document::setWidth(int value)
0371 {
0372     if (!d->document) return;
0373     if (!d->document->image()) return;
0374     resizeImage(d->document->image()->bounds().x(),
0375                 d->document->image()->bounds().y(),
0376                 value,
0377                 d->document->image()->height());
0378 }
0379 
0380 
0381 int Document::xOffset() const
0382 {
0383     if (!d->document) return 0;
0384     KisImageSP image = d->document->image();
0385     if (!image) return 0;
0386     return image->bounds().x();
0387 }
0388 
0389 void Document::setXOffset(int x)
0390 {
0391     if (!d->document) return;
0392     if (!d->document->image()) return;
0393     resizeImage(x,
0394                 d->document->image()->bounds().y(),
0395                 d->document->image()->width(),
0396                 d->document->image()->height());
0397 }
0398 
0399 
0400 int Document::yOffset() const
0401 {
0402     if (!d->document) return 0;
0403     KisImageSP image = d->document->image();
0404     if (!image) return 0;
0405     return image->bounds().y();
0406 }
0407 
0408 void Document::setYOffset(int y)
0409 {
0410     if (!d->document) return;
0411     if (!d->document->image()) return;
0412     resizeImage(d->document->image()->bounds().x(),
0413                 y,
0414                 d->document->image()->width(),
0415                 d->document->image()->height());
0416 }
0417 
0418 
0419 double Document::xRes() const
0420 {
0421     if (!d->document) return 0.0;
0422     if (!d->document->image()) return 0.0;
0423     return d->document->image()->xRes()*72.0;
0424 }
0425 
0426 void Document::setXRes(double xRes) const
0427 {
0428     if (!d->document) return;
0429     KisImageSP image = d->document->image();
0430     if (!image) return;
0431 
0432     KisFilterStrategy *strategy = KisFilterStrategyRegistry::instance()->get("Bicubic");
0433     KIS_SAFE_ASSERT_RECOVER_RETURN(strategy);
0434 
0435     image->scaleImage(image->size(), xRes / 72.0, image->yRes(), strategy);
0436     image->waitForDone();
0437 }
0438 
0439 double Document::yRes() const
0440 {
0441     if (!d->document) return 0.0;
0442     if (!d->document->image()) return 0.0;
0443     return d->document->image()->yRes()*72.0;
0444 }
0445 
0446 void Document::setYRes(double yRes) const
0447 {
0448     if (!d->document) return;
0449     KisImageSP image = d->document->image();
0450     if (!image) return;
0451 
0452     KisFilterStrategy *strategy = KisFilterStrategyRegistry::instance()->get("Bicubic");
0453     KIS_SAFE_ASSERT_RECOVER_RETURN(strategy);
0454 
0455     image->scaleImage(image->size(), image->xRes(), yRes / 72.0, strategy);
0456     image->waitForDone();
0457 }
0458 
0459 
0460 QByteArray Document::pixelData(int x, int y, int w, int h) const
0461 {
0462     QByteArray ba;
0463 
0464     if (!d->document) return ba;
0465     KisImageSP image = d->document->image();
0466     if (!image) return ba;
0467 
0468     KisPaintDeviceSP dev = image->projection();
0469     ba.resize(w * h * dev->pixelSize());
0470     dev->readBytes(reinterpret_cast<quint8*>(ba.data()), x, y, w, h);
0471     return ba;
0472 }
0473 
0474 bool Document::close()
0475 {
0476     bool retval = d->document->closePath(false);
0477 
0478     Q_FOREACH(KisView *view, KisPart::instance()->views()) {
0479         if (view->document() == d->document) {
0480             view->close();
0481             view->closeView();
0482             view->deleteLater();
0483         }
0484     }
0485 
0486     KisPart::instance()->removeDocument(d->document, !d->ownsDocument);
0487 
0488     if (d->ownsDocument) {
0489 
0490         delete d->document;
0491     }
0492 
0493     d->document = 0;
0494     return retval;
0495 }
0496 
0497 void Document::crop(int x, int y, int w, int h)
0498 {
0499     if (!d->document) return;
0500     KisImageSP image = d->document->image();
0501     if (!image) return;
0502     QRect rc(x, y, w, h);
0503     image->cropImage(rc);
0504     image->waitForDone();
0505 }
0506 
0507 bool Document::exportImage(const QString &filename, const InfoObject &exportConfiguration)
0508 {
0509     if (!d->document) return false;
0510 
0511     const QString outputFormatString = KisMimeDatabase::mimeTypeForFile(filename, false);
0512     const QByteArray outputFormat = outputFormatString.toLatin1();
0513 
0514     return d->document->exportDocumentSync(filename, outputFormat, exportConfiguration.configuration());
0515 }
0516 
0517 void Document::flatten()
0518 {
0519     if (!d->document) return;
0520     if (!d->document->image()) return;
0521     d->document->image()->flatten(0);
0522     d->document->image()->waitForDone();
0523 }
0524 
0525 void Document::resizeImage(int x, int y, int w, int h)
0526 {
0527     if (!d->document) return;
0528     KisImageSP image = d->document->image();
0529     if (!image) return;
0530     QRect rc;
0531     rc.setX(x);
0532     rc.setY(y);
0533     rc.setWidth(w);
0534     rc.setHeight(h);
0535 
0536     image->resizeImage(rc);
0537     image->waitForDone();
0538 }
0539 
0540 void Document::scaleImage(int w, int h, int xres, int yres, QString strategy)
0541 {
0542     if (!d->document) return;
0543     KisImageSP image = d->document->image();
0544     if (!image) return;
0545     QRect rc = image->bounds();
0546     rc.setWidth(w);
0547     rc.setHeight(h);
0548 
0549     KisFilterStrategy *actualStrategy = KisFilterStrategyRegistry::instance()->get(strategy);
0550     if (!actualStrategy) actualStrategy = KisFilterStrategyRegistry::instance()->get("Bicubic");
0551 
0552     image->scaleImage(rc.size(), xres / 72.0, yres / 72.0, actualStrategy);
0553     image->waitForDone();
0554 }
0555 
0556 void Document::rotateImage(double radians)
0557 {
0558     if (!d->document) return;
0559     KisImageSP image = d->document->image();
0560     if (!image) return;
0561     image->rotateImage(radians);
0562     image->waitForDone();
0563 }
0564 
0565 void Document::shearImage(double angleX, double angleY)
0566 {
0567     if (!d->document) return;
0568     KisImageSP image = d->document->image();
0569     if (!image) return;
0570     image->shear(angleX, angleY);
0571     image->waitForDone();
0572 }
0573 
0574 bool Document::save()
0575 {
0576     if (!d->document) return false;
0577     if (d->document->path().isEmpty()) return false;
0578 
0579     bool retval = d->document->save(true, 0);
0580     d->document->waitForSavingToComplete();
0581 
0582     return retval;
0583 }
0584 
0585 bool Document::saveAs(const QString &filename)
0586 {
0587     if (!d->document) return false;
0588 
0589     setFileName(filename);
0590     const QString outputFormatString = KisMimeDatabase::mimeTypeForFile(filename, false);
0591     const QByteArray outputFormat = outputFormatString.toLatin1();
0592     QString oldPath = d->document->path();
0593     d->document->setPath(filename);
0594     bool retval = d->document->saveAs(filename, outputFormat, true);
0595     d->document->waitForSavingToComplete();
0596     d->document->setPath(oldPath);
0597 
0598     return retval;
0599 }
0600 
0601 Node* Document::createNode(const QString &name, const QString &nodeType)
0602 {
0603     if (!d->document) return 0;
0604     if (!d->document->image()) return 0;
0605     KisImageSP image = d->document->image();
0606 
0607     Node *node = 0;
0608 
0609     if (nodeType.toLower()== "paintlayer") {
0610         node = new Node(image, new KisPaintLayer(image, name, OPACITY_OPAQUE_U8));
0611     }
0612     else if (nodeType.toLower()  == "grouplayer") {
0613         node = new Node(image, new KisGroupLayer(image, name, OPACITY_OPAQUE_U8));
0614     }
0615     else if (nodeType.toLower()  == "filelayer") {
0616         node = new Node(image, new KisFileLayer(image, name, OPACITY_OPAQUE_U8));
0617     }
0618     else if (nodeType.toLower()  == "filterlayer") {
0619         node = new Node(image, new KisAdjustmentLayer(image, name, 0, 0));
0620     }
0621     else if (nodeType.toLower()  == "filllayer") {
0622         node = new Node(image, new KisGeneratorLayer(image, name, 0, 0));
0623     }
0624     else if (nodeType.toLower()  == "clonelayer") {
0625         node = new Node(image, new KisCloneLayer(0, image, name, OPACITY_OPAQUE_U8));
0626     }
0627     else if (nodeType.toLower()  == "vectorlayer") {
0628         node = new Node(image, new KisShapeLayer(d->document->shapeController(), image, name, OPACITY_OPAQUE_U8));
0629     }
0630     else if (nodeType.toLower()  == "transparencymask") {
0631         node = new Node(image, new KisTransparencyMask(image, name));
0632     }
0633     else if (nodeType.toLower()  == "filtermask") {
0634         node = new Node(image, new KisFilterMask(image, name));
0635     }
0636     else if (nodeType.toLower()  == "transformmask") {
0637         node = new Node(image, new KisTransformMask(image, name));
0638     }
0639     else if (nodeType.toLower()  == "selectionmask") {
0640         node = new Node(image, new KisSelectionMask(image, name));
0641     }
0642     else if (nodeType.toLower()  == "colorizemask") {
0643         node = new Node(image, new KisColorizeMask(image, name));
0644     }
0645 
0646     return node;
0647 }
0648 
0649 GroupLayer *Document::createGroupLayer(const QString &name)
0650 {
0651     if (!d->document) return 0;
0652     if (!d->document->image()) return 0;
0653     KisImageSP image = d->document->image();
0654 
0655     return new GroupLayer(image, name);
0656 }
0657 
0658 FileLayer *Document::createFileLayer(const QString &name, const QString fileName, const QString scalingMethod, const QString scalingFilter)
0659 {
0660     if (!d->document) return 0;
0661     if (!d->document->image()) return 0;
0662     KisImageSP image = d->document->image();
0663 
0664     return new FileLayer(image, name, this->fileName(), fileName, scalingMethod, scalingFilter);
0665 }
0666 
0667 FilterLayer *Document::createFilterLayer(const QString &name, Filter &filter, Selection &selection)
0668 {
0669     if (!d->document) return 0;
0670     if (!d->document->image()) return 0;
0671     KisImageSP image = d->document->image();
0672 
0673     return new FilterLayer(image, name, filter, selection);
0674 }
0675 
0676 FillLayer *Document::createFillLayer(const QString &name, const QString generatorName, InfoObject &configuration, Selection &selection)
0677 {
0678     if (!d->document) return 0;
0679     if (!d->document->image()) return 0;
0680     KisImageSP image = d->document->image();
0681 
0682     KisGeneratorSP generator = KisGeneratorRegistry::instance()->value(generatorName);
0683     if (generator) {
0684 
0685         KisFilterConfigurationSP config = generator->factoryConfiguration(KisGlobalResourcesInterface::instance());
0686         Q_FOREACH(const QString property, configuration.properties().keys()) {
0687             config->setProperty(property, configuration.property(property));
0688         }
0689 
0690         return new FillLayer(image, name, config, selection);
0691     }
0692     return 0;
0693 }
0694 
0695 CloneLayer *Document::createCloneLayer(const QString &name, const Node *source)
0696 {
0697     if (!d->document) return 0;
0698     if (!d->document->image()) return 0;
0699     KisImageSP image = d->document->image();
0700     KisLayerSP layer = qobject_cast<KisLayer*>(source->node().data());
0701 
0702     return new CloneLayer(image, name, layer);
0703 }
0704 
0705 VectorLayer *Document::createVectorLayer(const QString &name)
0706 {
0707     if (!d->document) return 0;
0708     if (!d->document->image()) return 0;
0709     KisImageSP image = d->document->image();
0710 
0711     return new VectorLayer(d->document->shapeController(), image, name);
0712 }
0713 
0714 FilterMask *Document::createFilterMask(const QString &name, Filter &filter, const Node *selection_source)
0715 {
0716     if (!d->document)
0717         return 0;
0718 
0719     if (!d->document->image())
0720         return 0;
0721 
0722     if(!selection_source)
0723         return 0;
0724 
0725     KisLayerSP layer = qobject_cast<KisLayer*>(selection_source->node().data());
0726     if(layer.isNull())
0727         return 0;
0728 
0729     KisImageSP image = d->document->image();
0730     FilterMask* mask = new FilterMask(image, name, filter);
0731     qobject_cast<KisMask*>(mask->node().data())->initSelection(layer);
0732 
0733     return mask;
0734 }
0735 
0736 FilterMask *Document::createFilterMask(const QString &name, Filter &filter, Selection &selection)
0737 {
0738     if (!d->document)
0739         return 0;
0740 
0741     if (!d->document->image())
0742         return 0;
0743 
0744     KisImageSP image = d->document->image();
0745     FilterMask* mask = new FilterMask(image, name, filter);
0746     qobject_cast<KisMask*>(mask->node().data())->setSelection(selection.selection());
0747 
0748     return mask;
0749 }
0750 
0751 SelectionMask *Document::createSelectionMask(const QString &name)
0752 {
0753     if (!d->document) return 0;
0754     if (!d->document->image()) return 0;
0755     KisImageSP image = d->document->image();
0756 
0757     return new SelectionMask(image, name);
0758 }
0759 
0760 TransparencyMask *Document::createTransparencyMask(const QString &name)
0761 {
0762     if (!d->document) return 0;
0763     if (!d->document->image()) return 0;
0764     KisImageSP image = d->document->image();
0765 
0766     return new TransparencyMask(image, name);
0767 }
0768 
0769 TransformMask *Document::createTransformMask(const QString &name)
0770 {
0771     if (!d->document) return 0;
0772     if (!d->document->image()) return 0;
0773     KisImageSP image = d->document->image();
0774 
0775     return new TransformMask(image, name);
0776 }
0777 
0778 ColorizeMask *Document::createColorizeMask(const QString &name)
0779 {
0780     if (!d->document) return 0;
0781     if (!d->document->image()) return 0;
0782     KisImageSP image = d->document->image();
0783 
0784     return new ColorizeMask(image, name);
0785 }
0786 
0787 QImage Document::projection(int x, int y, int w, int h) const
0788 {
0789     if (!d->document || !d->document->image()) return QImage();
0790     return d->document->image()->convertToQImage(x, y, w, h, 0);
0791 }
0792 
0793 QImage Document::thumbnail(int w, int h) const
0794 {
0795     if (!d->document || !d->document->image()) return QImage();
0796     return d->document->generatePreview(QSize(w, h)).toImage();
0797 }
0798 
0799 
0800 void Document::lock()
0801 {
0802     if (!d->document || !d->document->image()) return;
0803     d->document->image()->barrierLock();
0804 }
0805 
0806 void Document::unlock()
0807 {
0808     if (!d->document || !d->document->image()) return;
0809     d->document->image()->unlock();
0810 }
0811 
0812 void Document::waitForDone()
0813 {
0814     if (!d->document || !d->document->image()) return;
0815     d->document->image()->waitForDone();
0816 }
0817 
0818 bool Document::tryBarrierLock()
0819 {
0820     if (!d->document || !d->document->image()) return false;
0821     return d->document->image()->tryBarrierLock();
0822 }
0823 
0824 void Document::refreshProjection()
0825 {
0826     if (!d->document || !d->document->image()) return;
0827     d->document->image()->refreshGraph();
0828 }
0829 
0830 QList<qreal> Document::horizontalGuides() const
0831 {
0832     QList<qreal> lines;
0833     if (!d->document || !d->document->image()) return lines;
0834     KisCoordinatesConverter converter;
0835     converter.setImage(d->document->image());
0836     QTransform transform = converter.imageToDocumentTransform().inverted();
0837     QList<qreal> untransformedLines = d->document->guidesConfig().horizontalGuideLines();
0838     for (int i = 0; i< untransformedLines.size(); i++) {
0839         qreal line = untransformedLines[i];
0840         lines.append(transform.map(QPointF(line, line)).x());
0841     }
0842     return lines;
0843 }
0844 
0845 QList<qreal> Document::verticalGuides() const
0846 {
0847     QList<qreal> lines;
0848     if (!d->document || !d->document->image()) return lines;
0849     KisCoordinatesConverter converter;
0850     converter.setImage(d->document->image());
0851     QTransform transform = converter.imageToDocumentTransform().inverted();
0852     QList<qreal> untransformedLines = d->document->guidesConfig().verticalGuideLines();
0853     for (int i = 0; i< untransformedLines.size(); i++) {
0854         qreal line = untransformedLines[i];
0855         lines.append(transform.map(QPointF(line, line)).y());
0856     }
0857     return lines;
0858 }
0859 
0860 bool Document::guidesVisible() const
0861 {
0862     return d->document->guidesConfig().showGuides();
0863 }
0864 
0865 bool Document::guidesLocked() const
0866 {
0867     return d->document->guidesConfig().lockGuides();
0868 }
0869 
0870 Document *Document::clone() const
0871 {
0872     if (!d->document) return 0;
0873     QPointer<KisDocument> clone = d->document->clone();
0874 
0875     /// We set ownsDocument to true, it will be reset
0876     /// automatically as soon as we create the first
0877     /// view for the document
0878     Document * newDocument = new Document(clone, true);
0879     return newDocument;
0880 }
0881 
0882 void Document::setHorizontalGuides(const QList<qreal> &lines)
0883 {
0884     if (!d->document) return;
0885     KisGuidesConfig config = d->document->guidesConfig();
0886     KisCoordinatesConverter converter;
0887     converter.setImage(d->document->image());
0888     QTransform transform = converter.imageToDocumentTransform();
0889     QList<qreal> transformedLines;
0890     for (int i = 0; i< lines.size(); i++) {
0891         qreal line = lines[i];
0892         transformedLines.append(transform.map(QPointF(line, line)).x());
0893     }
0894     config.setHorizontalGuideLines(transformedLines);
0895     d->document->setGuidesConfig(config);
0896 }
0897 
0898 void Document::setVerticalGuides(const QList<qreal> &lines)
0899 {
0900     if (!d->document) return;
0901     KisGuidesConfig config = d->document->guidesConfig();
0902     KisCoordinatesConverter converter;
0903     converter.setImage(d->document->image());
0904     QTransform transform = converter.imageToDocumentTransform();
0905     QList<qreal> transformedLines;
0906     for (int i = 0; i< lines.size(); i++) {
0907         qreal line = lines[i];
0908         transformedLines.append(transform.map(QPointF(line, line)).y());
0909     }
0910     config.setVerticalGuideLines(transformedLines);
0911     d->document->setGuidesConfig(config);
0912 }
0913 
0914 void Document::setGuidesVisible(bool visible)
0915 {
0916     if (!d->document) return;
0917     KisGuidesConfig config = d->document->guidesConfig();
0918     config.setShowGuides(visible);
0919     d->document->setGuidesConfig(config);
0920 }
0921 
0922 void Document::setGuidesLocked(bool locked)
0923 {
0924     if (!d->document) return;
0925     KisGuidesConfig config = d->document->guidesConfig();
0926     config.setLockGuides(locked);
0927     d->document->setGuidesConfig(config);
0928 }
0929 
0930 bool Document::modified() const
0931 {
0932     if (!d->document) return false;
0933     return d->document->isModified();
0934 }
0935 
0936 void Document::setModified(bool modified)
0937 {
0938     if (!d->document) return;
0939     d->document->setModified(modified);
0940 }
0941 
0942 QRect Document::bounds() const
0943 {
0944     if (!d->document) return QRect();
0945     return d->document->image()->bounds();
0946 }
0947 
0948 QPointer<KisDocument> Document::document() const
0949 {
0950     return d->document;
0951 }
0952 
0953 void Document::setOwnsDocument(bool ownsDocument)
0954 {
0955     d->ownsDocument = ownsDocument;
0956 }
0957 
0958 /* Animation related function */
0959 
0960 bool Document::importAnimation(const QList<QString> &files, int firstFrame, int step)
0961 {
0962     KisView *activeView = KisPart::instance()->currentMainwindow()->activeView();
0963 
0964     KoUpdaterPtr updater = 0;
0965     if (activeView && d->document->fileBatchMode()) {
0966          updater = activeView->viewManager()->createUnthreadedUpdater(i18n("Import frames"));
0967     }
0968 
0969     KisAnimationImporter importer(d->document->image(), updater);
0970     KisImportExportErrorCode status = importer.import(files, firstFrame, step);
0971 
0972     return status.isOk();
0973 }
0974 
0975 int Document::framesPerSecond()
0976 {
0977     if (!d->document) return false;
0978     if (!d->document->image()) return false;
0979 
0980     return d->document->image()->animationInterface()->framerate();
0981 }
0982 
0983 void Document::setFramesPerSecond(int fps)
0984 {
0985     if (!d->document) return;
0986     if (!d->document->image()) return;
0987 
0988     d->document->image()->animationInterface()->setFramerate(fps);
0989 }
0990 
0991 void Document::setFullClipRangeStartTime(int startTime)
0992 {
0993     if (!d->document) return;
0994     if (!d->document->image()) return;
0995 
0996     d->document->image()->animationInterface()->setDocumentRangeStartFrame(startTime);
0997 }
0998 
0999 
1000 int Document::fullClipRangeStartTime()
1001 {
1002     if (!d->document) return false;
1003     if (!d->document->image()) return false;
1004 
1005     return d->document->image()->animationInterface()->documentPlaybackRange().start();
1006 }
1007 
1008 
1009 void Document::setFullClipRangeEndTime(int endTime)
1010 {
1011     if (!d->document) return;
1012     if (!d->document->image()) return;
1013 
1014     d->document->image()->animationInterface()->setDocumentRangeEndFrame(endTime);
1015 }
1016 
1017 
1018 int Document::fullClipRangeEndTime()
1019 {
1020     if (!d->document) return false;
1021     if (!d->document->image()) return false;
1022 
1023     return d->document->image()->animationInterface()->documentPlaybackRange().end();
1024 }
1025 
1026 int Document::animationLength()
1027 {
1028     if (!d->document) return false;
1029     if (!d->document->image()) return false;
1030 
1031     return d->document->image()->animationInterface()->totalLength();
1032 }
1033 
1034 void Document::setPlayBackRange(int start, int stop)
1035 {
1036     if (!d->document) return;
1037     if (!d->document->image()) return;
1038 
1039     const KisTimeSpan newTimeRange = KisTimeSpan::fromTimeWithDuration(start, (stop-start));
1040     d->document->image()->animationInterface()->setActivePlaybackRange(newTimeRange);
1041 }
1042 
1043 int Document::playBackStartTime()
1044 {
1045     if (!d->document) return false;
1046     if (!d->document->image()) return false;
1047 
1048     return d->document->image()->animationInterface()->activePlaybackRange().start();
1049 }
1050 
1051 int Document::playBackEndTime()
1052 {
1053     if (!d->document) return false;
1054     if (!d->document->image()) return false;
1055 
1056     return d->document->image()->animationInterface()->activePlaybackRange().end();
1057 }
1058 
1059 int Document::currentTime()
1060 {
1061     if (!d->document) return false;
1062     if (!d->document->image()) return false;
1063 
1064     return d->document->image()->animationInterface()->currentTime();
1065 }
1066 
1067 void Document::setCurrentTime(int time)
1068 {
1069     if (!d->document) return;
1070     if (!d->document->image()) return;
1071 
1072     return d->document->image()->animationInterface()->requestTimeSwitchWithUndo(time);
1073 }
1074 
1075 QStringList Document::annotationTypes() const
1076 {
1077     if (!d->document) return QStringList();
1078 
1079     QStringList types;
1080 
1081     KisImageSP image = d->document->image().toStrongRef();
1082 
1083     if (!image) return QStringList();
1084 
1085     vKisAnnotationSP_it beginIt = image->beginAnnotations();
1086     vKisAnnotationSP_it endIt = image->endAnnotations();
1087 
1088     vKisAnnotationSP_it it = beginIt;
1089     while (it != endIt) {
1090         if (!(*it) || (*it)->type().isEmpty()) {
1091             qWarning() << "Warning: empty annotation";
1092             it++;
1093             continue;
1094         }
1095         types << (*it)->type();
1096 
1097         it++;
1098     }
1099     return types;
1100 }
1101 
1102 QString Document::annotationDescription(const QString &type) const
1103 {
1104     KisImageSP image = d->document->image().toStrongRef();
1105     KisAnnotationSP annotation = image->annotation(type);
1106     return annotation->description();
1107 }
1108 
1109 QByteArray Document::annotation(const QString &type)
1110 {
1111     KisImageSP image = d->document->image().toStrongRef();
1112     KisAnnotationSP annotation = image->annotation(type);
1113     if (annotation) {
1114         return annotation->annotation();
1115     }
1116     else {
1117         return QByteArray();
1118     }
1119 }
1120 
1121 void Document::setAnnotation(const QString &key, const QString &description, const QByteArray &annotation)
1122 {
1123     KisAnnotation *a = new KisAnnotation(key, description, annotation);
1124     KisImageSP image = d->document->image().toStrongRef();
1125     image->addAnnotation(a);
1126 
1127 }
1128 
1129 void Document::removeAnnotation(const QString &type)
1130 {
1131     KisImageSP image = d->document->image().toStrongRef();
1132     image->removeAnnotation(type);
1133 }