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     if ((attr = element.attribute("hasmask")).isNull())
00597         attr = "0";
00598 
00599     if (attr == "1") {
00600         // We add a mask, but we'll fill in the actual mask later in completeLoading with the visitor
00601         layer->createMask();
00602     }
00603 
00604 
00605     // Load exif info
00606     for( QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling() )
00607     {
00608         QDomElement e = node.toElement();
00609         if ( !e.isNull() && e.tagName() == "ExifInfo" )
00610         {
00611             layer->paintDevice()->exifInfo()->load(e);
00612         }
00613     }
00614     return layer.data();
00615 }
00616 
00617 KisGroupLayerSP KisDoc::loadGroupLayer(const QDomElement& element, KisImageSP img,
00618                                        QString name, Q_INT32 x, Q_INT32 y, Q_INT32 opacity, bool visible, bool locked,
00619                                        KisCompositeOp compositeOp)
00620 {
00621     QString attr;
00622     KisGroupLayerSP layer;
00623 
00624     layer = new KisGroupLayer(img, name, opacity);
00625     Q_CHECK_PTR(layer);
00626 
00627     layer->setCompositeOp(compositeOp);
00628     layer->setVisible(visible);
00629     layer->setLocked(locked);
00630     layer->setX(x);
00631     layer->setY(y);
00632 
00633     loadLayers(element, img, layer);
00634 
00635     return layer;
00636 }
00637 
00638 KisAdjustmentLayerSP KisDoc::loadAdjustmentLayer(const QDomElement& element, KisImageSP img,
00639                                              QString name, Q_INT32 x, Q_INT32 y, Q_INT32 opacity, bool visible, bool locked,
00640                                              KisCompositeOp compositeOp)
00641 {
00642     QString attr;
00643     KisAdjustmentLayerSP layer;
00644     QString filtername;
00645 
00646     if ((filtername = element.attribute("filtername")).isNull()) {
00647         // XXX: Invalid adjustmentlayer! We should warn about it!
00648         kdWarning(DBG_AREA_FILE) << "No filter in adjustment layer" << endl;
00649         return 0;
00650     }
00651 
00652     KisFilter * f = KisFilterRegistry::instance()->get(filtername);
00653     if (!f) {
00654         kdWarning(DBG_AREA_FILE) << "No filter for filtername " << filtername << "\n";
00655         return 0; // XXX: We don't have this filter. We should warn about it!
00656     }
00657 
00658     KisFilterConfiguration * kfc = f->configuration();
00659 
00660     // We'll load the configuration and the selection later.
00661     layer = new KisAdjustmentLayer(img, name, kfc, 0);
00662     Q_CHECK_PTR(layer);
00663 
00664     layer->setCompositeOp(compositeOp);
00665     layer->setVisible(visible);
00666     layer->setLocked(locked);
00667     layer->setX(x);
00668     layer->setY(y);
00669     layer->setOpacity(opacity);
00670 
00671     if ((element.attribute("filename")).isNull())
00672         m_layerFilenames[layer.data()] = name;
00673     else
00674         m_layerFilenames[layer.data()] = QString(element.attribute("filename"));
00675 
00676     return layer;
00677 }
00678 
00679 KisPartLayerSP KisDoc::loadPartLayer(const QDomElement& element, KisImageSP img,
00680                                      QString name, Q_INT32 /*x*/, Q_INT32 /*y*/, Q_INT32 opacity,
00681                                       bool visible, bool locked,
00682                                       KisCompositeOp compositeOp) {
00683     KisChildDoc* child = new KisChildDoc(this);
00684     QString filename(element.attribute("filename"));
00685     QDomElement partElement = element.namedItem("object").toElement();
00686 
00687     if (partElement.isNull()) {
00688         kdWarning() << "loadPartLayer failed with partElement isNull" << endl;
00689         return 0;
00690     }
00691 
00692     child->load(partElement);
00693     insertChild(child);
00694 
00695     KisPartLayerSP layer = new KisPartLayerImpl(img, child);
00696     Q_CHECK_PTR(layer);
00697 
00698     layer->setCompositeOp(compositeOp);
00699     layer->setVisible(visible);
00700     layer->setLocked(locked);
00701     layer->setOpacity(opacity);
00702     layer->setName(name);
00703 
00704     return layer;
00705 }
00706 
00707 bool KisDoc::completeSaving(KoStore *store)
00708 {
00709     QString uri = url().url();
00710     QString location;
00711     bool external = isStoredExtern();
00712     Q_INT32 totalSteps = 0;
00713 
00714     if (!m_currentImage) return false;
00715 
00716     totalSteps = (m_currentImage)->nlayers();
00717 
00718 
00719     setIOSteps(totalSteps + 1);
00720 
00721     // Save the layers data
00722     Q_UINT32 count=0;
00723     KisSaveVisitor visitor(m_currentImage, store, count);
00724 
00725     if(external)
00726         visitor.setExternalUri(uri);
00727 
00728     m_currentImage->rootLayer()->accept(visitor);
00729 
00730     // saving annotations
00731     // XXX this only saves EXIF and ICC info. This would probably need
00732     // a redesign of the dtd of the krita file to do this more generally correct
00733     // e.g. have <ANNOTATION> tags or so.
00734     KisAnnotationSP annotation = (m_currentImage)->annotation("exif");
00735     if (annotation) {
00736         location = external ? QString::null : uri;
00737         location += (m_currentImage)->name() + "/annotations/exif";
00738         if (store->open(location)) {
00739             store->write(annotation->annotation());
00740             store->close();
00741         }
00742     }
00743     if (m_currentImage->getProfile()) {
00744         annotation = m_currentImage->getProfile()->annotation();
00745 
00746         if (annotation) {
00747             location = external ? QString::null : uri;
00748             location += m_currentImage->name() + "/annotations/icc";
00749             if (store->open(location)) {
00750                 store->write(annotation->annotation());
00751                 store->close();
00752             }
00753         }
00754     }
00755 
00756     IODone();
00757     return true;
00758 }
00759 
00760 bool KisDoc::completeLoading(KoStore *store)
00761 {
00762     QString uri = url().url();
00763     QString location;
00764     bool external = isStoredExtern();
00765     Q_INT32 totalSteps = 0;
00766 
00767     totalSteps = (m_currentImage)->nlayers();
00768 
00769     setIOSteps(totalSteps);
00770 
00771     // Load the layers data
00772     KisLoadVisitor visitor(m_currentImage, store, m_layerFilenames);
00773 
00774     if(external)
00775         visitor.setExternalUri(uri);
00776 
00777     m_currentImage->rootLayer()->accept(visitor);
00778 
00779     // annotations
00780     // exif
00781     location = external ? QString::null : uri;
00782     location += (m_currentImage)->name() + "/annotations/exif";
00783     if (store->hasFile(location)) {
00784         QByteArray data;
00785         store->open(location);
00786         data = store->read(store->size());
00787         store->close();
00788         (m_currentImage)->addAnnotation(new KisAnnotation("exif", "", data));
00789     }
00790     // icc profile
00791     location = external ? QString::null : uri;
00792     location += (m_currentImage)->name() + "/annotations/icc";
00793     if (store->hasFile(location)) {
00794         QByteArray data;
00795         store->open(location);
00796         data = store->read(store->size());
00797         store->close();
00798         (m_currentImage)->setProfile(new KisProfile(data));
00799     }
00800 
00801     IODone();
00802 
00803     setModified( false );
00804     setUndo(true);
00805     return true;
00806 }
00807 
00808 QWidget* KisDoc::createCustomDocumentWidget(QWidget *parent)
00809 {
00810 
00811     KisConfig cfg;
00812 
00813     int w = cfg.defImgWidth();
00814     int h = cfg.defImgHeight();
00815 
00816     QSize sz = KisClipboard::instance()->clipSize();
00817     if (sz.isValid() && sz.width() != 0 && sz.height() != 0) {
00818         w = sz.width();
00819         h = sz.height();
00820     }
00821     return new KisCustomImageWidget(parent, this, w, h, cfg.defImgResolution(), cfg.workingColorSpace(),"unnamed");
00822 }
00823 
00824 
00825 KoDocument* KisDoc::hitTest(const QPoint &pos, const QWMatrix& matrix) {
00826     KoDocument* doc = super::hitTest(pos, matrix);
00827     if (doc && doc != this) {
00828         // We hit a child document. We will only acknowledge we hit it, if the hit child
00829         // is the currently active parts layer.
00830         KisPartLayerImpl* partLayer
00831                 = dynamic_cast<KisPartLayerImpl*>(currentImage()->activeLayer().data());
00832 
00833         if (!partLayer)
00834             return this;
00835 
00836         if (doc == partLayer->childDoc()->document()) {
00837             return doc;
00838         }
00839         return this;
00840     }
00841     return doc;
00842 }
00843 
00844 void KisDoc::renameImage(const QString& oldName, const QString& newName)
00845 {
00846     (m_currentImage)->setName(newName);
00847 
00848     if (undo())
00849         addCommand(new KisCommandImageMv(this, this, newName, oldName));
00850 }
00851 
00852 
00853 KisImageSP KisDoc::newImage(const QString& name, Q_INT32 width, Q_INT32 height, KisColorSpace * colorstrategy)
00854 {
00855     if (!init())
00856         return 0;
00857 
00858     setUndo(false);
00859 
00860     KisImageSP img = new KisImage(this, width, height, colorstrategy, name);
00861     Q_CHECK_PTR(img);
00862     connect( img, SIGNAL( sigImageModified() ), this, SLOT( slotImageUpdated() ));
00863 
00864     KisPaintLayer *layer = new KisPaintLayer(img, img->nextLayerName(), OPACITY_OPAQUE,colorstrategy);
00865     Q_CHECK_PTR(layer);
00866 
00867     KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8();
00868     KisFillPainter painter;
00869 
00870     painter.begin(layer->paintDevice());
00871     painter.fillRect(0, 0, width, height, KisColor(Qt::white, cs), OPACITY_OPAQUE);
00872     painter.end();
00873 
00874     img->addLayer(layer, img->rootLayer(), 0);
00875     img->activate(layer);
00876 
00877     m_currentImage = img;
00878 
00879     setUndo(true);
00880 
00881     return img;
00882 }
00883 
00884 bool KisDoc::newImage(const QString& name, Q_INT32 width, Q_INT32 height, KisColorSpace * cs, const KisColor &bgColor, const QString &imgDescription, const double imgResolution)
00885 {
00886     if (!init())
00887         return false;
00888 
00889     KisConfig cfg;
00890 
00891     Q_UINT8 opacity = OPACITY_OPAQUE;//bgColor.getAlpha();
00892     KisImageSP img;
00893     KisPaintLayer *layer;
00894 
00895     if (!cs) return false;
00896 
00897     setUndo(false);
00898 
00899     img = new KisImage(this, width, height, cs, name);
00900     Q_CHECK_PTR(img);
00901     connect( img, SIGNAL( sigImageModified() ), this, SLOT( slotImageUpdated() ));
00902     img->setResolution(imgResolution, imgResolution);
00903     img->setDescription(imgDescription);
00904     img->setProfile(cs->getProfile());
00905 
00906     layer = new KisPaintLayer(img, img->nextLayerName(), OPACITY_OPAQUE, cs);
00907     Q_CHECK_PTR(layer);
00908 
00909     KisFillPainter painter;
00910     painter.begin(layer->paintDevice());
00911     painter.fillRect(0, 0, width, height, bgColor, opacity);
00912     painter.end();
00913 
00914     QValueVector<KisPaintDeviceAction *> actions = KisMetaRegistry::instance() ->
00915                 csRegistry()->paintDeviceActionsFor(cs);
00916     for (uint i = 0; i < actions.count(); i++)
00917         actions.at(i)->act(layer->paintDevice(), img->width(), img->height());
00918 
00919     img->setBackgroundColor(bgColor);
00920     img->addLayer(layer, img->rootLayer(), 0);
00921     img->activate(layer);
00922 
00923     m_currentImage = img;
00924 
00925     cfg.defImgWidth(width);
00926     cfg.defImgHeight(height);
00927     cfg.defImgResolution(imgResolution);
00928 
00929     setUndo(true);
00930 
00931     return true;
00932 }
00933 
00934 KoView* KisDoc::createViewInstance(QWidget* parent, const char *name)
00935 {
00936     KisView * v = new KisView(this, this, parent, name);
00937     Q_CHECK_PTR(v);
00938 
00939     return v;
00940 }
00941 
00942 void KisDoc::paintContent(QPainter& painter, const QRect& rc, bool transparent, double zoomX, double zoomY)
00943 {
00944     KisConfig cfg;
00945     QString monitorProfileName = cfg.monitorProfile();
00946     KisProfile *  profile = KisMetaRegistry::instance()->csRegistry()->getProfileByName(monitorProfileName);
00947     painter.scale(zoomX, zoomY);
00948     QRect rect = rc & m_currentImage->bounds();
00949     KisImage::PaintFlags paintFlags;
00950     if (transparent) {
00951         paintFlags = KisImage::PAINT_SELECTION;
00952     } else {
00953         paintFlags = (KisImage::PaintFlags)(KisImage::PAINT_BACKGROUND|KisImage::PAINT_SELECTION);
00954     }
00955 
00956     paintFlags = (KisImage::PaintFlags)(paintFlags | KisImage::PAINT_EMBEDDED_RECT);
00957 
00958     m_currentImage->renderToPainter(rect.left(), rect.top(), rect.right(), rect.bottom(), painter, profile, paintFlags);
00959 }
00960 
00961 void KisDoc::slotImageUpdated()
00962 {
00963     emit docUpdated();
00964     setModified(true);
00965 }
00966 
00967 void KisDoc::slotImageUpdated(const QRect& rect)
00968 {
00969     emit docUpdated(rect);
00970 }
00971 
00972 void KisDoc::beginMacro(const QString& macroName)
00973 {
00974     if (m_undo) {
00975         if (m_macroNestDepth == 0) {
00976             Q_ASSERT(m_currentMacro == 0);
00977             m_currentMacro = new KMacroCommand(macroName);
00978             Q_CHECK_PTR(m_currentMacro);
00979         }
00980 
00981         m_macroNestDepth++;
00982     }
00983 }
00984 
00985 void KisDoc::endMacro()
00986 {
00987     if (m_undo) {
00988         Q_ASSERT(m_macroNestDepth > 0);
00989         if (m_macroNestDepth > 0) {
00990             m_macroNestDepth--;
00991 
00992             if (m_macroNestDepth == 0) {
00993                 Q_ASSERT(m_currentMacro != 0);
00994 
00995                 m_cmdHistory->addCommand(m_currentMacro, false);
00996                 m_currentMacro = 0;
00997                 emit sigCommandExecuted();
00998             }
00999         }
01000     }
01001 }
01002 
01003 void KisDoc::setCommandHistoryListener(const KisCommandHistoryListener * l)
01004 {
01005    // Never have more than one instance of a listener around. Qt should prove a Set class for this...
01006     m_undoListeners.removeRef(l);
01007     m_undoListeners.append(l);
01008 }
01009 
01010 void KisDoc::removeCommandHistoryListener(const KisCommandHistoryListener * l)
01011 {
01012    m_undoListeners.removeRef(l);
01013 }
01014 
01015 KCommand * KisDoc::presentCommand()
01016 {
01017     return m_cmdHistory->presentCommand();
01018 }
01019 
01020 void KisDoc::addCommand(KCommand *cmd)
01021 {
01022     Q_ASSERT(cmd);
01023 
01024     KisCommandHistoryListener* l = 0;
01025 
01026     for (l = m_undoListeners.first(); l; l = m_undoListeners.next()) {
01027         l->notifyCommandAdded(cmd);
01028     }
01029 
01030     setModified(true);
01031 
01032     if (m_undo) {
01033         if (m_currentMacro)
01034             m_currentMacro->addCommand(cmd);
01035         else {
01036             m_cmdHistory->addCommand(cmd, false);
01037             emit sigCommandExecuted();
01038         }
01039     } else {
01040         kdDebug() << "Deleting command\n";
01041         delete cmd;
01042     }
01043 }
01044 
01045 void KisDoc::setUndo(bool undo)
01046 {
01047     m_undo = undo;
01048     if (m_undo && m_cmdHistory->undoLimit() == 50 /*default*/) {
01049         KisConfig cfg;
01050         setUndoLimit( cfg.defUndoLimit() );
01051     }
01052 }
01053 
01054 Q_INT32 KisDoc::undoLimit() const
01055 {
01056     return m_cmdHistory->undoLimit();
01057 }
01058 
01059 void KisDoc::setUndoLimit(Q_INT32 limit)
01060 {
01061     m_cmdHistory->setUndoLimit(limit);
01062 }
01063 
01064 Q_INT32 KisDoc::redoLimit() const
01065 {
01066     return m_cmdHistory->redoLimit();
01067 }
01068 
01069 void KisDoc::setRedoLimit(Q_INT32 limit)
01070 {
01071     m_cmdHistory->setRedoLimit(limit);
01072 }
01073 
01074 void KisDoc::slotDocumentRestored()
01075 {
01076     setModified(false);
01077 }
01078 
01079 void KisDoc::slotCommandExecuted(KCommand *command)
01080 {
01081     setModified(true);
01082     emit sigCommandExecuted();
01083 
01084     KisCommandHistoryListener* l = 0;
01085 
01086     for (l = m_undoListeners.first(); l; l = m_undoListeners.next()) {
01087         l->notifyCommandExecuted(command);
01088     }
01089 
01090 }
01091 
01092 void KisDoc::slotUpdate(KisImageSP, Q_UINT32 x, Q_UINT32 y, Q_UINT32 w, Q_UINT32 h)
01093 {
01094     QRect rc(x, y, w, h);
01095 
01096     emit docUpdated(rc);
01097 }
01098 
01099 bool KisDoc::undo() const
01100 {
01101     return m_undo;
01102 }
01103 
01104 void KisDoc::setIOSteps(Q_INT32 nsteps)
01105 {
01106     m_ioProgressTotalSteps = nsteps * 100;
01107     m_ioProgressBase = 0;
01108     emitProgress(0);
01109 }
01110 
01111 void KisDoc::IOCompletedStep()
01112 {
01113     m_ioProgressBase += 100;
01114 }
01115 
01116 void KisDoc::IODone()
01117 {
01118     emitProgress(-1);
01119 }
01120 
01121 void KisDoc::slotIOProgress(Q_INT8 percentage)
01122 {
01123     KApplication *app = KApplication::kApplication();
01124 
01125     Q_ASSERT(app);
01126 
01127     if (app->hasPendingEvents())
01128         app->processEvents();
01129 
01130     int totalPercentage = ((m_ioProgressBase + percentage) * 100) / m_ioProgressTotalSteps;
01131 
01132     emitProgress(totalPercentage);
01133 }
01134 
01135 KisChildDoc * KisDoc::createChildDoc( const QRect & rect, KoDocument* childDoc )
01136 {
01137     KisChildDoc * ch = new KisChildDoc( this, rect, childDoc );
01138     insertChild( ch );
01139     ch->document()->setStoreInternal(true);
01140     return ch;
01141 }
01142 
01143 void KisDoc::prepareForImport()
01144 {
01145     if (m_nserver == 0)
01146         init();
01147     setUndo(false);
01148 }
01149 
01150 KisImageSP KisDoc::currentImage()
01151 {
01152     return m_currentImage;
01153 }
01154 
01155 void KisDoc::setCurrentImage(KisImageSP image)
01156 {
01157     m_currentImage = image;
01158     setUndo(true);
01159     image->notifyImageLoaded();
01160     emit loadingFinished();
01161 }
01162 
01163 void KisDoc::initEmpty()
01164 {
01165     KisConfig cfg;
01166     KisColorSpace * rgb = KisMetaRegistry::instance()->csRegistry()->getRGB8();
01167     newImage("", cfg.defImgWidth(), cfg.defImgHeight(), rgb);
01168 }
01169 
01170 #include "kis_doc.moc"
01171 
KDE Home | KDE Accessibility Home | Description of Access Keys