krita

kis_doc.cc

00001 /*
00002  *  Copyright (c) 1999 Matthias Elter  <me@kde.org>
00003  *  Copyright (c) 2000 John Califf  <jcaliff@compuzone.net>
00004  *  Copyright (c) 2001 Toshitaka Fujioka  <fujioka@kde.org>
00005  *  Copyright (c) 2002, 2003 Patrick Julien <freak@codepimps.org>
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program; if not, write to the Free Software
00019  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  */
00021 
00022 // Qt
00023 #include <qapplication.h>
00024 #include <qdom.h>
00025 #include <qimage.h>
00026 #include <qpainter.h>
00027 #include <qtl.h>
00028 #include <qstringlist.h>
00029 #include <qwidget.h>
00030 #include <qpaintdevicemetrics.h>
00031 
00032 // KDE
00033 #include <dcopobject.h>
00034 #include <kapplication.h>
00035 #include <kcommand.h>
00036 #include <kdebug.h>
00037 #include <kimageio.h>
00038 #include <kfiledialog.h>
00039 #include <kglobal.h>
00040 #include <kmimetype.h>
00041 #include <knotifyclient.h>
00042 #include <klocale.h>
00043 #include <kmessagebox.h>
00044 
00045 // KOffice
00046 #include <KoFilterManager.h>
00047 #include <KoMainWindow.h>
00048 #include <KoQueryTrader.h>
00049 #include <KoStore.h>
00050 #include <KoStoreDevice.h>
00051 #include <KoTemplateChooseDia.h>
00052 #include <KoApplication.h>
00053 #include <KoCommandHistory.h>
00054 
00055 // Local
00056 #include <kis_clipboard.h>
00057 #include <kis_meta_registry.h>
00058 #include "kis_annotation.h"
00059 #include "kis_types.h"
00060 #include "kis_config.h"
00061 #include "kis_debug_areas.h"
00062 #include "kis_doc.h"
00063 #include "kis_factory.h"
00064 #include "kis_image.h"
00065 #include "kis_layer.h"
00066 #include "kis_paint_layer.h"
00067 #include "kis_nameserver.h"
00068 #include "kis_painter.h"
00069 #include "kis_selection.h"
00070 #include "kis_fill_painter.h"
00071 #include "kis_command.h"
00072 #include "kis_view.h"
00073 #include "kis_colorspace.h"
00074 #include "kis_colorspace_factory_registry.h"
00075 #include "kis_profile.h"
00076 #include "kis_id.h"
00077 #include "kis_part_layer.h"
00078 #include "kis_doc_iface.h"
00079 #include "kis_paint_device_action.h"
00080 #include "kis_custom_image_widget.h"
00081 #include "kis_load_visitor.h"
00082 #include "kis_save_visitor.h"
00083 #include "kis_savexml_visitor.h"
00084 
00085 static const char *CURRENT_DTD_VERSION = "1.3";
00086 
00092 #define APP_MIMETYPE "application/x-krita"
00093 
00097 #define NATIVE_MIMETYPE "application/x-kra"
00098 
00099 namespace {
00100     class KisCommandImageMv : public KisCommand {
00101         typedef KisCommand super;
00102 
00103     public:
00104         KisCommandImageMv(KisDoc *doc,
00105                   KisUndoAdapter *adapter,
00106                   const QString& name,
00107                   const QString& oldName) : super(i18n("Rename Image"), adapter)
00108             {
00109                 m_doc = doc;
00110                 m_name = name;
00111                 m_oldName = oldName;
00112             }
00113 
00114         virtual ~KisCommandImageMv()
00115             {
00116             }
00117 
00118         virtual void execute()
00119             {
00120                 adapter()->setUndo(false);
00121                 m_doc->renameImage(m_oldName, m_name);
00122                 adapter()->setUndo(true);
00123             }
00124 
00125         virtual void unexecute()
00126             {
00127                 adapter()->setUndo(false);
00128                 m_doc->renameImage(m_name, m_oldName);
00129                 adapter()->setUndo(true);
00130             }
00131 
00132     private:
00133         KisDoc *m_doc;
00134         QString m_name;
00135         QString m_oldName;
00136     };
00137 
00138 }
00139 
00140 KisDoc::KisDoc(QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name, bool singleViewMode) :
00141     super(parentWidget, widgetName, parent, name, singleViewMode)
00142 {
00143 
00144     m_undo = false;
00145     m_dcop = 0;
00146     m_cmdHistory = 0;
00147     m_nserver = 0;
00148     m_currentImage = 0;
00149     m_currentMacro = 0;
00150     m_macroNestDepth = 0;
00151     m_ioProgressBase = 0;
00152     m_ioProgressTotalSteps = 0;
00153 
00154     setInstance( KisFactory::instance(), false );
00155     setTemplateType( "krita_template" );
00156 
00157     init();
00158 
00159     if (name)
00160         dcopObject();
00161 }
00162 
00163 KisDoc::~KisDoc()
00164 {
00165     delete m_cmdHistory;
00166     delete m_nserver;
00167     m_undoListeners.setAutoDelete(false);
00168     delete m_dcop;
00169 }
00170 
00171 QCString KisDoc::mimeType() const
00172 {
00173     return APP_MIMETYPE;
00174 }
00175 
00176 DCOPObject *KisDoc::dcopObject()
00177 {
00178     if (!m_dcop) {
00179         m_dcop = new KisDocIface(this);
00180         Q_CHECK_PTR(m_dcop);
00181     }
00182     return m_dcop;
00183 }
00184 
00185 bool KisDoc::initDoc(InitDocFlags flags, QWidget* parentWidget)
00186 {
00187     if (!init())
00188         return false;
00189 
00190     bool ok = false;
00191 
00192     QString file;
00193     KoTemplateChooseDia::DialogType dlgtype;
00194 
00195      if (flags != KoDocument::InitDocFileNew) {
00196         dlgtype = KoTemplateChooseDia::Everything;
00197     } else {
00198          dlgtype = KoTemplateChooseDia::OnlyTemplates;
00199     }
00200 
00201     KoTemplateChooseDia::ReturnType ret =
00202         KoTemplateChooseDia::choose(KisFactory::instance(),
00203                         file,
00204                         dlgtype,
00205                         "krita_template",
00206                         parentWidget);
00207     setUndo(false);
00208 
00209     if (ret == KoTemplateChooseDia::Template) {
00210         resetURL();
00211         ok = loadNativeFormat( file );
00212         setEmpty();
00213         ok = true;
00214 
00215     } else if (ret == KoTemplateChooseDia::File) {
00216         KURL url( file );
00217         ok = openURL(url);
00218     } else if (ret == KoTemplateChooseDia::Empty) {
00219         setEmpty();
00220         ok = true;
00221     }
00222 
00223     setModified(false);
00224     KisConfig cfg;
00225     setUndo(cfg.undoEnabled());
00226 
00227     return ok;
00228 }
00229 
00230 void KisDoc::openExistingFile(const QString& file)
00231 {
00232   setUndo(false);
00233 
00234   KoDocument::openExistingFile(file);
00235 
00236   setUndo(true);
00237 }
00238 
00239 void KisDoc::openTemplate(const QString& file)
00240 {
00241   setUndo(false);
00242 
00243   KoDocument::openTemplate(file);
00244 
00245   setUndo(true);
00246 }
00247 
00248 bool KisDoc::init()
00249 {
00250     if (m_cmdHistory) {
00251         delete m_cmdHistory;
00252         m_cmdHistory = 0;
00253     }
00254 
00255     if (m_nserver) {
00256         delete m_nserver;
00257         m_nserver = 0;
00258     }
00259 
00260     m_cmdHistory = new KoCommandHistory(actionCollection(), true);
00261     Q_CHECK_PTR(m_cmdHistory);
00262 
00263     connect(m_cmdHistory, SIGNAL(documentRestored()), this, SLOT(slotDocumentRestored()));
00264     connect(m_cmdHistory, SIGNAL(commandExecuted(KCommand *)), this, SLOT(slotCommandExecuted(KCommand *)));
00265     setUndo(true);
00266 
00267     m_nserver = new KisNameServer(i18n("Image %1"), 1);
00268     Q_CHECK_PTR(m_nserver);
00269 
00270     if (!KisMetaRegistry::instance()->csRegistry()->exists(KisID("RGBA",""))) {
00271         KMessageBox::sorry(0, i18n("No colorspace modules loaded: cannot run Krita"));
00272         return false;
00273     }
00274 
00275     m_undoListeners.setAutoDelete(false);
00276 
00277     return true;
00278 }
00279 
00280 QDomDocument KisDoc::saveXML()
00281 {
00282     QDomDocument doc = createDomDocument("DOC", CURRENT_DTD_VERSION);
00283     QDomElement root = doc.documentElement();
00284 
00285     root.setAttribute("editor", "Krita");
00286     root.setAttribute("depth", sizeof(Q_UINT8));
00287     root.setAttribute("syntaxVersion", "1");
00288 
00289     root.appendChild(saveImage(doc, m_currentImage));
00290 
00291     return doc;
00292 }
00293 
00294 bool KisDoc::loadOasis( const QDomDocument&, KoOasisStyles&, const QDomDocument&, KoStore* )
00295 {
00296     //XXX: todo (and that includes defining an OASIS format for layered 2D raster data!)
00297     return false;
00298 }
00299 
00300 
00301 bool KisDoc::saveOasis( KoStore*, KoXmlWriter* )
00302 {
00303     //XXX: todo (and that includes defining an OASIS format for layered 2D raster data!)
00304     return false;
00305 }
00306 
00307 bool KisDoc::loadXML(QIODevice *, const QDomDocument& doc)
00308 {
00309     QDomElement root;
00310     QString attr;
00311     QDomNode node;
00312     KisImageSP img;
00313 
00314     if (!init())
00315         return false;
00316     if (doc.doctype().name() != "DOC")
00317         return false;
00318     root = doc.documentElement();
00319     attr = root.attribute("syntaxVersion");
00320      if (attr.toInt() > 1)
00321          return false;
00322     if ((attr = root.attribute("depth")).isNull())
00323         return false;
00324     m_conversionDepth = attr.toInt();
00325 
00326     if (!root.hasChildNodes()) {
00327         return false; // XXX used to be: return slotNewImage();
00328     }
00329 
00330     setUndo(false);
00331 
00332     for (node = root.firstChild(); !node.isNull(); node = node.nextSibling()) {
00333         if (node.isElement()) {
00334             if (node.nodeName() == "IMAGE") {
00335                 QDomElement elem = node.toElement();
00336                 if (!(img = loadImage(elem)))
00337                     return false;
00338                 m_currentImage = img;
00339             } else {
00340                 return false;
00341             }
00342         }
00343     }
00344 
00345     emit loadingFinished();
00346     return true;
00347 }
00348 
00349 bool KisDoc::loadChildren(KoStore* store) {
00350     QPtrListIterator<KoDocumentChild> it(children());
00351     for( ; it.current(); ++it ) {
00352         if (!it.current()->loadDocument(store)) {
00353             return false;
00354         }
00355     }
00356     return true;
00357 }
00358 
00359 QDomElement KisDoc::saveImage(QDomDocument& doc, KisImageSP img)
00360 {
00361     QDomElement image = doc.createElement("IMAGE");
00362 
00363     Q_ASSERT(img);
00364     image.setAttribute("name", img->name());
00365     image.setAttribute("mime", "application/x-kra");
00366     image.setAttribute("width", img->width());
00367     image.setAttribute("height", img->height());
00368     image.setAttribute("colorspacename", img->colorSpace()->id().id());
00369     image.setAttribute("description", img->description());
00370     // XXX: Save profile as blob inside the image, instead of the product name.
00371     if (img->getProfile() && img->getProfile()-> valid())
00372         image.setAttribute("profile", img->getProfile()->productName());
00373     image.setAttribute("x-res", img->xRes());
00374     image.setAttribute("y-res", img->yRes());
00375 
00376     Q_UINT32 count=0;
00377     KisSaveXmlVisitor visitor(doc, image, count, true);
00378 
00379     m_currentImage->rootLayer()->accept(visitor);
00380 
00381     return image;
00382 }
00383 
00384 KisImageSP KisDoc::loadImage(const QDomElement& element)
00385 {
00386 
00387     KisConfig cfg;
00388     QString attr;
00389     QDomNode node;
00390     QDomNode child;
00391     KisImageSP img;
00392     QString name;
00393     Q_INT32 width;
00394     Q_INT32 height;
00395     QString description;
00396     QString profileProductName;
00397     double xres;
00398     double yres;
00399     QString colorspacename;
00400     KisColorSpace * cs;
00401 
00402     if ((attr = element.attribute("mime")) == NATIVE_MIMETYPE) {
00403         if ((name = element.attribute("name")).isNull())
00404             return 0;
00405         if ((attr = element.attribute("width")).isNull())
00406             return 0;
00407         width = attr.toInt();
00408         if ((attr = element.attribute("height")).isNull())
00409             return 0;
00410         height = attr.toInt();
00411 
00412         description = element.attribute("description");
00413 
00414         if ((attr = element.attribute("x-res")).isNull())
00415             xres = 100.0;
00416         xres = attr.toDouble();
00417 
00418         if ((attr = element.attribute("y-res")).isNull())
00419             yres = 100.0;
00420         yres = attr.toDouble();
00421 
00422         if ((colorspacename = element.attribute("colorspacename")).isNull())
00423         {
00424             // An old file: take a reasonable default.
00425             // Krita didn't support anything else in those
00426             // days anyway.
00427             colorspacename = "RGBA";
00428         }
00429 
00430         // A hack for an old colorspacename
00431         if (colorspacename  == "Grayscale + Alpha")
00432             colorspacename  = "GRAYA";
00433 
00434         if ((profileProductName = element.attribute("profile")).isNull()) {
00435             // no mention of profile so get default profile
00436             cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(colorspacename,"");
00437         }
00438         else {
00439             cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(colorspacename, profileProductName);
00440         }
00441 
00442         if (cs == 0) {
00443             kdWarning(DBG_AREA_FILE) << "Could not open colorspace\n";
00444             return 0;
00445         }
00446 
00447         img = new KisImage(this, width, height, cs, name);
00448         img->blockSignals(true); // Don't send out signals while we're building the image
00449         Q_CHECK_PTR(img);
00450         connect( img, SIGNAL( sigImageModified() ), this, SLOT( slotImageUpdated() ));
00451         img->setDescription(description);
00452         img->setResolution(xres, yres);
00453 
00454         loadLayers(element, img, img->rootLayer().data());
00455 
00456     }
00457 
00458     img->notifyImageLoaded();
00459 
00460     return img;
00461 }
00462 
00463 void KisDoc::loadLayers(const QDomElement& element, KisImageSP img, KisGroupLayerSP parent)
00464 {
00465     QDomNode node = element.firstChild();
00466     QDomNode child;
00467 
00468     if(!node.isNull())
00469     {
00470         if (node.isElement()) {
00471             if (node.nodeName() == "LAYERS") {
00472                 for (child = node.firstChild(); !child.isNull(); child = child.nextSibling()) {
00473                     KisLayerSP layer = loadLayer(child.toElement(), img);
00474 
00475                     if (!layer) {
00476                         kdWarning(DBG_AREA_FILE) << "Could not load layer\n";
00477                     }
00478                     else {
00479                         img->nextLayerName(); // Make sure the nameserver is current with the number of layers.
00480                         img->addLayer(layer, parent, 0);
00481                     }
00482                 }
00483             }
00484         }
00485     }
00486 }
00487 
00488 KisLayerSP KisDoc::loadLayer(const QDomElement& element, KisImageSP img)
00489 {
00490     // Nota bene: If you add new properties to layers, you should
00491     // ALWAYS define a default value in case the property is not
00492     // present in the layer definition: this helps a LOT with backward
00493     // compatibilty.
00494     QString attr;
00495     QString name;
00496     Q_INT32 x;
00497     Q_INT32 y;
00498     Q_INT32 opacity;
00499     bool visible;
00500     bool locked;
00501 
00502     if ((name = element.attribute("name")).isNull())
00503         return 0;
00504 
00505     if ((attr = element.attribute("x")).isNull())
00506         return 0;
00507     x = attr.toInt();
00508 
00509     if ((attr = element.attribute("y")).isNull())
00510         return 0;
00511 
00512     y = attr.toInt();
00513 
00514     if ((attr = element.attribute("opacity")).isNull())
00515         return 0;
00516 
00517     if ((opacity = attr.toInt()) < 0 || opacity > Q_UINT8_MAX)
00518         opacity = OPACITY_OPAQUE;
00519 
00520 
00521     QString compositeOpName = element.attribute("compositeop");
00522     KisCompositeOp compositeOp;
00523 
00524     if (compositeOpName.isNull()) {
00525         compositeOp = COMPOSITE_OVER;
00526     } else {
00527         compositeOp = KisCompositeOp(compositeOpName);
00528     }
00529 
00530     if (!compositeOp.isValid()) {
00531         return 0;
00532     }
00533 
00534     if ((attr = element.attribute("visible")).isNull())
00535         attr = "1";
00536 
00537     visible = attr == "0" ? false : true;
00538 
00539     if ((attr = element.attribute("locked")).isNull())
00540         attr = "0";
00541 
00542     locked = attr == "0" ? false : true;
00543 
00544     // Now find out the layer type and do specific handling
00545     if ((attr = element.attribute("layertype")).isNull())
00546         return loadPaintLayer(element, img, name, x, y, opacity, visible, locked, compositeOp) ;
00547 
00548     if(attr == "paintlayer")
00549         return loadPaintLayer(element, img, name, x, y, opacity, visible, locked, compositeOp);
00550 
00551     if(attr == "grouplayer")
00552         return loadGroupLayer(element, img, name, x, y, opacity, visible, locked, compositeOp).data();
00553 
00554     if(attr == "adjustmentlayer")
00555         return loadAdjustmentLayer(element, img, name, x, y, opacity, visible, locked, compositeOp).data();
00556 
00557     if(attr == "partlayer")
00558         return loadPartLayer(element, img, name, x, y, opacity, visible, locked, compositeOp).data();
00559 
00560     kdWarning(DBG_AREA_FILE) << "Specified layertype is not recognised\n";
00561     return 0;
00562 }
00563 
00564 
00565 KisLayerSP KisDoc::loadPaintLayer(const QDomElement& element, KisImageSP img,
00566                                   QString name, Q_INT32 x, Q_INT32 y,
00567                                   Q_INT32 opacity, bool visible, bool locked, KisCompositeOp compositeOp)
00568 {
00569     QString attr;
00570     KisPaintLayerSP layer;
00571     KisColorSpace * cs;
00572 
00573     QString colorspacename;
00574     QString profileProductName;
00575 
00576     if ((colorspacename = element.attribute("colorspacename")).isNull())
00577         cs = img->colorSpace();
00578     else
00579         // use default profile - it will be replaced later in completLoading
00580         cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(colorspacename,"");
00581 
00582     layer = new KisPaintLayer(img, name, opacity, cs);
00583     Q_CHECK_PTR(layer);
00584 
00585     layer->setCompositeOp(compositeOp);
00586     layer->setVisible(visible);
00587     layer->setLocked(locked);
00588     layer->setX(x);
00589     layer->setY(y);
00590 
00591     if ((element.attribute("filename")).isNull())
00592         m_layerFilenames[layer.data()] = name;
00593     else
00594         m_layerFilenames[layer.data()] = QString(element.attribute("filename"));
00595 
00596     // Load exif info
00597     for( QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling() )
00598     {
00599         QDomElement e = node.toElement();
00600         if ( !e.isNull() && e.tagName() == "ExifInfo" )
00601         {
00602             layer->paintDevice()->exifInfo()->load(e);
00603         }
00604     }
00605     return layer.data();
00606 }
00607 
00608 KisGroupLayerSP KisDoc::loadGroupLayer(const QDomElement& element, KisImageSP img,
00609                                        QString name, Q_INT32 x, Q_INT32 y, Q_INT32 opacity, bool visible, bool locked,
00610                                        KisCompositeOp compositeOp)
00611 {
00612     QString attr;
00613     KisGroupLayerSP layer;
00614 
00615     layer = new KisGroupLayer(img, name, opacity);
00616     Q_CHECK_PTR(layer);
00617 
00618     layer->setCompositeOp(compositeOp);
00619     layer->setVisible(visible);
00620     layer->setLocked(locked);
00621     layer->setX(x);
00622     layer->setY(y);
00623 
00624     loadLayers(element, img, layer);
00625 
00626     return layer;
00627 }
00628 
00629 KisAdjustmentLayerSP KisDoc::loadAdjustmentLayer(const QDomElement& element, KisImageSP img,
00630                                              QString name, Q_INT32 x, Q_INT32 y, Q_INT32 opacity, bool visible, bool locked,
00631                                              KisCompositeOp compositeOp)
00632 {
00633     QString attr;
00634     KisAdjustmentLayerSP layer;
00635     QString filtername;
00636 
00637     if ((filtername = element.attribute("filtername")).isNull()) {
00638         // XXX: Invalid adjustmentlayer! We should warn about it!
00639         kdWarning(DBG_AREA_FILE) << "No filter in adjustment layer" << endl;
00640         return 0;
00641     }
00642 
00643     KisFilter * f = KisFilterRegistry::instance()->get(filtername);
00644     if (!f) {
00645         kdWarning(DBG_AREA_FILE) << "No filter for filtername " << filtername << "\n";
00646         return 0; // XXX: We don't have this filter. We should warn about it!
00647     }
00648 
00649     KisFilterConfiguration * kfc = f->configuration();
00650 
00651     // We'll load the configuration and the selection later.
00652     layer = new KisAdjustmentLayer(img, name, kfc, 0);
00653     Q_CHECK_PTR(layer);
00654 
00655     layer->setCompositeOp(compositeOp);
00656     layer->setVisible(visible);
00657     layer->setLocked(locked);
00658     layer->setX(x);
00659     layer->setY(y);
00660     layer->setOpacity(opacity);
00661 
00662     if ((element.attribute("filename")).isNull())
00663         m_layerFilenames[layer.data()] = name;
00664     else
00665         m_layerFilenames[layer.data()] = QString(element.attribute("filename"));
00666 
00667     return layer;
00668 }
00669 
00670 KisPartLayerSP KisDoc::loadPartLayer(const QDomElement& element, KisImageSP img,
00671                                      QString name, Q_INT32 /*x*/, Q_INT32 /*y*/, Q_INT32 opacity,
00672                                       bool visible, bool locked,
00673                                       KisCompositeOp compositeOp) {
00674     KisChildDoc* child = new KisChildDoc(this);
00675     QString filename(element.attribute("filename"));
00676     QDomElement partElement = element.namedItem("object").toElement();
00677 
00678     if (partElement.isNull()) {
00679         kdWarning() << "loadPartLayer failed with partElement isNull" << endl;
00680         return 0;
00681     }
00682 
00683     child->load(partElement);
00684     insertChild(child);
00685 
00686     KisPartLayerSP layer = new KisPartLayerImpl(img, child);
00687     Q_CHECK_PTR(layer);
00688 
00689     layer->setCompositeOp(compositeOp);
00690     layer->setVisible(visible);
00691     layer->setLocked(locked);
00692     layer->setOpacity(opacity);
00693     layer->setName(name);
00694 
00695     return layer;
00696 }
00697 
00698 bool KisDoc::completeSaving(KoStore *store)
00699 {
00700     QString uri = url().url();
00701     QString location;
00702     bool external = isStoredExtern();
00703     Q_INT32 totalSteps = 0;
00704 
00705     if (!m_currentImage) return false;
00706 
00707     totalSteps = (m_currentImage)->nlayers();
00708 
00709 
00710     setIOSteps(totalSteps + 1);
00711 
00712     // Save the layers data
00713     Q_UINT32 count=0;
00714     KisSaveVisitor visitor(m_currentImage, store, count);
00715 
00716     if(external)
00717         visitor.setExternalUri(uri);
00718 
00719     m_currentImage->rootLayer()->accept(visitor);
00720 
00721     // saving annotations
00722     // XXX this only saves EXIF and ICC info. This would probably need
00723     // a redesign of the dtd of the krita file to do this more generally correct
00724     // e.g. have <ANNOTATION> tags or so.
00725     KisAnnotationSP annotation = (m_currentImage)->annotation("exif");
00726     if (annotation) {
00727         location = external ? QString::null : uri;
00728         location += (m_currentImage)->name() + "/annotations/exif";
00729         if (store->open(location)) {
00730             store->write(annotation->annotation());
00731             store->close();
00732         }
00733     }
00734     if (m_currentImage->getProfile()) {
00735         annotation = m_currentImage->getProfile()->annotation();
00736 
00737         if (annotation) {
00738             location = external ? QString::null : uri;
00739             location += m_currentImage->name() + "/annotations/icc";
00740             if (store->open(location)) {
00741                 store->write(annotation->annotation());
00742                 store->close();
00743             }
00744         }
00745     }
00746 
00747     IODone();
00748     return true;
00749 }
00750 
00751 bool KisDoc::completeLoading(KoStore *store)
00752 {
00753     QString uri = url().url();
00754     QString location;
00755     bool external = isStoredExtern();
00756     Q_INT32 totalSteps = 0;
00757 
00758     totalSteps = (m_currentImage)->nlayers();
00759 
00760     setIOSteps(totalSteps);
00761 
00762     // Load the layers data
00763     KisLoadVisitor visitor(m_currentImage, store, m_layerFilenames);
00764 
00765     if(external)
00766         visitor.setExternalUri(uri);
00767 
00768     m_currentImage->rootLayer()->accept(visitor);
00769 
00770     // annotations
00771     // exif
00772     location = external ? QString::null : uri;
00773     location += (m_currentImage)->name() + "/annotations/exif";
00774     if (store->hasFile(location)) {
00775         QByteArray data;
00776         store->open(location);
00777         data = store->read(store->size());
00778         store->close();
00779         (m_currentImage)->addAnnotation(new KisAnnotation("exif", "", data));
00780     }
00781     // icc profile
00782     location = external ? QString::null : uri;
00783     location += (m_currentImage)->name() + "/annotations/icc";
00784     if (store->hasFile(location)) {
00785         QByteArray data;
00786         store->open(location);
00787         data = store->read(store->size());
00788         store->close();
00789         (m_currentImage)->setProfile(new KisProfile(data));
00790     }
00791 
00792     IODone();
00793 
00794     setModified( false );
00795     setUndo(true);
00796     return true;
00797 }
00798 
00799 QWidget* KisDoc::createCustomDocumentWidget(QWidget *parent)
00800 {
00801 
00802     KisConfig cfg;
00803 
00804     int w = cfg.defImgWidth();
00805     int h = cfg.defImgHeight();
00806 
00807     QSize sz = KisClipboard::instance()->clipSize();
00808     if (sz.isValid() && sz.width() != 0 && sz.height() != 0) {
00809         w = sz.width();
00810         h = sz.height();
00811     }
00812     return new KisCustomImageWidget(parent, this, w, h, cfg.defImgResolution(), cfg.workingColorSpace(),"unnamed");
00813 }
00814 
00815 
00816 KoDocument* KisDoc::hitTest(const QPoint &pos, const QWMatrix& matrix) {
00817     KoDocument* doc = super::hitTest(pos, matrix);
00818     if (doc && doc != this) {
00819         // We hit a child document. We will only acknowledge we hit it, if the hit child
00820         // is the currently active parts layer.
00821         KisPartLayerImpl* partLayer
00822                 = dynamic_cast<KisPartLayerImpl*>(currentImage()->activeLayer().data());
00823 
00824         if (!partLayer)
00825             return this;
00826 
00827         if (doc == partLayer->childDoc()->document()) {
00828             return doc;
00829         }
00830         return this;
00831     }
00832     return doc;
00833 }
00834 
00835 void KisDoc::renameImage(const QString& oldName, const QString& newName)
00836 {
00837     (m_currentImage)->setName(newName);
00838 
00839     if (undo())
00840         addCommand(new KisCommandImageMv(this, this, newName, oldName));
00841 }
00842 
00843 
00844 KisImageSP KisDoc::newImage(const QString& name, Q_INT32 width, Q_INT32 height, KisColorSpace * colorstrategy)
00845 {
00846     if (!init())
00847         return 0;
00848 
00849     setUndo(false);
00850 
00851     KisImageSP img = new KisImage(this, width, height, colorstrategy, name);
00852     Q_CHECK_PTR(img);
00853     connect( img, SIGNAL( sigImageModified() ), this, SLOT( slotImageUpdated() ));
00854 
00855     KisPaintLayer *layer = new KisPaintLayer(img, img->nextLayerName(), OPACITY_OPAQUE,colorstrategy);
00856     Q_CHECK_PTR(layer);
00857 
00858     KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8();
00859     KisFillPainter painter;
00860 
00861     painter.begin(layer->paintDevice());
00862     painter.fillRect(0, 0, width, height, KisColor(Qt::white, cs), OPACITY_OPAQUE);
00863     painter.end();
00864 
00865     img->addLayer(layer, img->rootLayer(), 0);
00866     img->activate(layer);
00867 
00868     m_currentImage = img;
00869 
00870     setUndo(true);
00871 
00872     return img;
00873 }
00874 
00875 bool KisDoc::newImage(const QString& name, Q_INT32 width, Q_INT32 height, KisColorSpace * cs, const KisColor &bgColor, const QString &imgDescription, const double imgResolution)
00876 {
00877     if (!init())
00878         return false;
00879 
00880     KisConfig cfg;
00881 
00882     Q_UINT8 opacity = OPACITY_OPAQUE;//bgColor.getAlpha();
00883     KisImageSP img;
00884     KisPaintLayer *layer;
00885 
00886     if (!cs) return false;
00887 
00888     setUndo(false);
00889 
00890     img = new KisImage(this, width, height, cs, name);
00891     Q_CHECK_PTR(img);
00892     connect( img, SIGNAL( sigImageModified() ), this, SLOT( slotImageUpdated() ));
00893     img->setResolution(imgResolution, imgResolution);
00894     img->setDescription(imgDescription);
00895     img->setProfile(cs->getProfile());
00896 
00897     layer = new KisPaintLayer(img, img->nextLayerName(), OPACITY_OPAQUE, cs);
00898     Q_CHECK_PTR(layer);
00899 
00900     KisFillPainter painter;
00901     painter.begin(layer->paintDevice());
00902     painter.fillRect(0, 0, width, height, bgColor, opacity);
00903     painter.end();
00904 
00905     QValueVector<KisPaintDeviceAction *> actions = KisMetaRegistry::instance() ->
00906                 csRegistry()->paintDeviceActionsFor(cs);
00907     for (uint i = 0; i < actions.count(); i++)
00908         actions.at(i)->act(layer->paintDevice(), img->width(), img->height());
00909 
00910     img->setBackgroundColor(bgColor);
00911     img->addLayer(layer, img->rootLayer(), 0);
00912     img->activate(layer);
00913 
00914     m_currentImage = img;
00915 
00916     cfg.defImgWidth(width);
00917     cfg.defImgHeight(height);
00918     cfg.defImgResolution(imgResolution);
00919 
00920     setUndo(true);
00921 
00922     return true;
00923 }
00924 
00925 KoView* KisDoc::createViewInstance(QWidget* parent, const char *name)
00926 {
00927     KisView * v = new KisView(this, this, parent, name);
00928     Q_CHECK_PTR(v);
00929 
00930     return v;
00931 }
00932 
00933 void KisDoc::paintContent(QPainter& painter, const QRect& rc, bool transparent, double zoomX, double zoomY)
00934 {
00935     KisConfig cfg;
00936     QString monitorProfileName = cfg.monitorProfile();
00937     KisProfile *  profile = KisMetaRegistry::instance()->csRegistry()->getProfileByName(monitorProfileName);
00938     painter.scale(zoomX, zoomY);
00939     QRect rect = rc & m_currentImage->bounds();
00940     KisImage::PaintFlags paintFlags;
00941     if (transparent) {
00942         paintFlags = KisImage::PAINT_SELECTION;
00943     } else {
00944         paintFlags = (KisImage::PaintFlags)(KisImage::PAINT_BACKGROUND|KisImage::PAINT_SELECTION);
00945     }
00946 
00947     paintFlags = (KisImage::PaintFlags)(paintFlags | KisImage::PAINT_EMBEDDED_RECT);
00948 
00949     m_currentImage->renderToPainter(rect.left(), rect.top(), rect.right(), rect.bottom(), painter, profile, paintFlags);
00950 }
00951 
00952 void KisDoc::slotImageUpdated()
00953 {
00954     emit docUpdated();
00955     setModified(true);
00956 }
00957 
00958 void KisDoc::slotImageUpdated(const QRect& rect)
00959 {
00960     emit docUpdated(rect);
00961 }
00962 
00963 void KisDoc::beginMacro(const QString& macroName)
00964 {
00965     if (m_undo) {
00966         if (m_macroNestDepth == 0) {
00967             Q_ASSERT(m_currentMacro == 0);
00968             m_currentMacro = new KMacroCommand(macroName);
00969             Q_CHECK_PTR(m_currentMacro);
00970         }
00971 
00972         m_macroNestDepth++;
00973     }
00974 }
00975 
00976 void KisDoc::endMacro()
00977 {
00978     if (m_undo) {
00979         Q_ASSERT(m_macroNestDepth > 0);
00980         if (m_macroNestDepth > 0) {
00981             m_macroNestDepth--;
00982 
00983             if (m_macroNestDepth == 0) {
00984                 Q_ASSERT(m_currentMacro != 0);
00985 
00986                 m_cmdHistory->addCommand(m_currentMacro, false);
00987                 m_currentMacro = 0;
00988                 emit sigCommandExecuted();
00989             }
00990         }
00991     }
00992 }
00993 
00994 void KisDoc::setCommandHistoryListener(const KisCommandHistoryListener * l)
00995 {
00996    // Never have more than one instance of a listener around. Qt should prove a Set class for this...
00997     m_undoListeners.removeRef(l);
00998     m_undoListeners.append(l);
00999 }
01000 
01001 void KisDoc::removeCommandHistoryListener(const KisCommandHistoryListener * l)
01002 {
01003    m_undoListeners.removeRef(l);
01004 }
01005 
01006 KCommand * KisDoc::presentCommand()
01007 {
01008     return m_cmdHistory->presentCommand();
01009 }
01010 
01011 void KisDoc::addCommand(KCommand *cmd)
01012 {
01013     Q_ASSERT(cmd);
01014 
01015     KisCommandHistoryListener* l = 0;
01016 
01017     for (l = m_undoListeners.first(); l; l = m_undoListeners.next()) {
01018         l->notifyCommandAdded(cmd);
01019     }
01020 
01021     setModified(true);
01022 
01023     if (m_undo) {
01024         if (m_currentMacro)
01025             m_currentMacro->addCommand(cmd);
01026         else {
01027             m_cmdHistory->addCommand(cmd, false);
01028             emit sigCommandExecuted();
01029         }
01030     } else {
01031         kdDebug() << "Deleting command\n";
01032         delete cmd;
01033     }
01034 }
01035 
01036 void KisDoc::setUndo(bool undo)
01037 {
01038     m_undo = undo;
01039     if (m_undo && m_cmdHistory->undoLimit() == 50 /*default*/) {
01040         KisConfig cfg;
01041         setUndoLimit( cfg.defUndoLimit() );
01042     }
01043 }
01044 
01045 Q_INT32 KisDoc::undoLimit() const
01046 {
01047     return m_cmdHistory->undoLimit();
01048 }
01049 
01050 void KisDoc::setUndoLimit(Q_INT32 limit)
01051 {
01052     m_cmdHistory->setUndoLimit(limit);
01053 }
01054 
01055 Q_INT32 KisDoc::redoLimit() const
01056 {
01057     return m_cmdHistory->redoLimit();
01058 }
01059 
01060 void KisDoc::setRedoLimit(Q_INT32 limit)
01061 {
01062     m_cmdHistory->setRedoLimit(limit);
01063 }
01064 
01065 void KisDoc::slotDocumentRestored()
01066 {
01067     setModified(false);
01068 }
01069 
01070 void KisDoc::slotCommandExecuted(KCommand *command)
01071 {
01072     setModified(true);
01073     emit sigCommandExecuted();
01074 
01075     KisCommandHistoryListener* l = 0;
01076 
01077     for (l = m_undoListeners.first(); l; l = m_undoListeners.next()) {
01078         l->notifyCommandExecuted(command);
01079     }
01080 
01081 }
01082 
01083 void KisDoc::slotUpdate(KisImageSP, Q_UINT32 x, Q_UINT32 y, Q_UINT32 w, Q_UINT32 h)
01084 {
01085     QRect rc(x, y, w, h);
01086 
01087     emit docUpdated(rc);
01088 }
01089 
01090 bool KisDoc::undo() const
01091 {
01092     return m_undo;
01093 }
01094 
01095 void KisDoc::setIOSteps(Q_INT32 nsteps)
01096 {
01097     m_ioProgressTotalSteps = nsteps * 100;
01098     m_ioProgressBase = 0;
01099     emitProgress(0);
01100 }
01101 
01102 void KisDoc::IOCompletedStep()
01103 {
01104     m_ioProgressBase += 100;
01105 }
01106 
01107 void KisDoc::IODone()
01108 {
01109     emitProgress(-1);
01110 }
01111 
01112 void KisDoc::slotIOProgress(Q_INT8 percentage)
01113 {
01114     KApplication *app = KApplication::kApplication();
01115 
01116     Q_ASSERT(app);
01117 
01118     if (app->hasPendingEvents())
01119         app->processEvents();
01120 
01121     int totalPercentage = ((m_ioProgressBase + percentage) * 100) / m_ioProgressTotalSteps;
01122 
01123     emitProgress(totalPercentage);
01124 }
01125 
01126 KisChildDoc * KisDoc::createChildDoc( const QRect & rect, KoDocument* childDoc )
01127 {
01128     KisChildDoc * ch = new KisChildDoc( this, rect, childDoc );
01129     insertChild( ch );
01130     ch->document()->setStoreInternal(true);
01131     return ch;
01132 }
01133 
01134 void KisDoc::prepareForImport()
01135 {
01136     if (m_nserver == 0)
01137         init();
01138     setUndo(false);
01139 }
01140 
01141 KisImageSP KisDoc::currentImage()
01142 {
01143     return m_currentImage;
01144 }
01145 
01146 void KisDoc::setCurrentImage(KisImageSP image)
01147 {
01148     m_currentImage = image;
01149     setUndo(true);
01150     image->notifyImageLoaded();
01151     emit loadingFinished();
01152 }
01153 
01154 void KisDoc::initEmpty()
01155 {
01156     KisConfig cfg;
01157     KisColorSpace * rgb = KisMetaRegistry::instance()->csRegistry()->getRGB8();
01158     newImage("", cfg.defImgWidth(), cfg.defImgHeight(), rgb);
01159 }
01160 
01161 #include "kis_doc.moc"
01162 
KDE Home | KDE Accessibility Home | Description of Access Keys