00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "kis_shape_selection.h"
00020
00021
00022 #include <QPainter>
00023 #include <QTimer>
00024
00025 #include <ktemporaryfile.h>
00026
00027 #include <KoLineBorder.h>
00028 #include <KoPathShape.h>
00029 #include <KoCompositeOp.h>
00030 #include <KoColorSpaceRegistry.h>
00031 #include <KoShapeManager.h>
00032 #include <KoDocument.h>
00033 #include <KoEmbeddedDocumentSaver.h>
00034 #include <KoGenStyle.h>
00035 #include <KoOdfLoadingContext.h>
00036 #include <KoOdfReadStore.h>
00037 #include <KoOdfStylesReader.h>
00038 #include <KoOdfWriteStore.h>
00039 #include <KoXmlNS.h>
00040 #include <KoShapeRegistry.h>
00041 #include <KoShapeLoadingContext.h>
00042 #include <KoXmlWriter.h>
00043 #include <KoStore.h>
00044 #include <KoShapeSavingContext.h>
00045 #include <KoStoreDevice.h>
00046
00047
00048 #include "kis_painter.h"
00049 #include "kis_paint_device.h"
00050 #include "kis_shape_selection_model.h"
00051 #include "kis_image.h"
00052 #include "kis_selection.h"
00053 #include "kis_shape_selection_canvas.h"
00054
00055 #include <kis_debug.h>
00056
00057 KisShapeSelection::KisShapeSelection(KisImageWSP image, KisSelectionSP selection)
00058 : KoShapeLayer(new KisShapeSelectionModel(image, selection, this))
00059 , m_image(image)
00060 {
00061 Q_ASSERT(m_image);
00062 setShapeId("KisShapeSelection");
00063 setSelectable(false);
00064 m_dirty = false;
00065 m_canvas = new KisShapeSelectionCanvas();
00066 m_canvas->shapeManager()->add(this);
00067
00068 }
00069
00070 KisShapeSelection::~KisShapeSelection()
00071 {
00072 delete m_canvas;
00073 }
00074
00075 KisShapeSelection::KisShapeSelection(const KisShapeSelection& rhs)
00076 : KoShapeLayer(rhs)
00077 {
00078 m_dirty = rhs.m_dirty;
00079 m_image = rhs.m_image;
00080 m_canvas = new KisShapeSelectionCanvas();
00081 m_canvas->shapeManager()->add(this);
00082 }
00083
00084 KisSelectionComponent* KisShapeSelection::clone()
00085 {
00086 return new KisShapeSelection(*this);
00087 }
00088
00089 bool KisShapeSelection::saveSelection(KoStore * store) const
00090 {
00091 store->disallowNameExpansion();
00092 KoOdfWriteStore odfStore(store);
00093 KoXmlWriter* manifestWriter = odfStore.manifestWriter("application/vnd.oasis.opendocument.graphics");
00094 KoEmbeddedDocumentSaver embeddedSaver;
00095 KoDocument::SavingContext documentContext(odfStore, embeddedSaver);
00096
00097 if (!store->open("content.xml"))
00098 return false;
00099
00100 KoStoreDevice storeDev(store);
00101 KoXmlWriter * docWriter = KoOdfWriteStore::createOasisXmlWriter(&storeDev, "office:document-content");
00102
00103
00104 KTemporaryFile masterStyles;
00105 masterStyles.open();
00106 KoXmlWriter masterStylesTmpWriter(&masterStyles, 1);
00107
00108 KoPageLayout page;
00109 page.format = KoPageFormat::defaultFormat();
00110 QRectF rc = boundingRect();
00111 page.width = rc.width();
00112 page.height = rc.height();
00113 if (page.width > page.height) {
00114 page.orientation = KoPageFormat::Landscape;
00115 } else {
00116 page.orientation = KoPageFormat::Portrait;
00117 }
00118
00119 KoGenStyles mainStyles;
00120 KoGenStyle pageLayout = page.saveOdf();
00121 QString layoutName = mainStyles.lookup(pageLayout, "PL");
00122 KoGenStyle masterPage(KoGenStyle::StyleMaster);
00123 masterPage.addAttribute("style:page-layout-name", layoutName);
00124 mainStyles.lookup(masterPage, "Default", KoGenStyles::DontForceNumbering);
00125
00126 KTemporaryFile contentTmpFile;
00127 contentTmpFile.open();
00128 KoXmlWriter contentTmpWriter(&contentTmpFile, 1);
00129
00130 contentTmpWriter.startElement("office:body");
00131 contentTmpWriter.startElement("office:drawing");
00132
00133 KoShapeSavingContext shapeContext(contentTmpWriter, mainStyles, documentContext.embeddedSaver);
00134
00135 shapeContext.xmlWriter().startElement("draw:page");
00136 shapeContext.xmlWriter().addAttribute("draw:name", "");
00137 shapeContext.xmlWriter().addAttribute("draw:id", "page1");
00138 shapeContext.xmlWriter().addAttribute("draw:master-page-name", "Default");
00139
00140 saveOdf(shapeContext);
00141
00142 shapeContext.xmlWriter().endElement();
00143
00144 contentTmpWriter.endElement();
00145 contentTmpWriter.endElement();
00146
00147 mainStyles.saveOdfAutomaticStyles(docWriter, false);
00148
00149
00150 contentTmpFile.seek(0);
00151 docWriter->addCompleteElement(&contentTmpFile);
00152
00153 docWriter->endElement();
00154 docWriter->endDocument();
00155 delete docWriter;
00156
00157 if (!store->close())
00158 return false;
00159
00160 manifestWriter->addManifestEntry("content.xml", "text/xml");
00161
00162 if (! mainStyles.saveOdfStylesDotXml(store, manifestWriter)) {
00163 return false;
00164 }
00165
00166 manifestWriter->addManifestEntry("settings.xml", "text/xml");
00167
00168 if (! shapeContext.saveDataCenter(documentContext.odfStore.store(), documentContext.odfStore.manifestWriter()))
00169 return false;
00170
00171
00172 if (!odfStore.closeManifestWriter()) {
00173 dbgImage << "closing manifestWriter failed";
00174 return false;
00175 }
00176
00177 return true;
00178 }
00179
00180 bool KisShapeSelection::loadSelection(KoStore* store)
00181 {
00182 KoOdfReadStore odfStore(store);
00183 QString errorMessage;
00184
00185 odfStore.loadAndParse(errorMessage);
00186
00187 if (!errorMessage.isEmpty()) {
00188 qDebug() << errorMessage;
00189 return false;
00190 }
00191
00192 KoXmlElement contents = odfStore.contentDoc().documentElement();
00193
00194
00195
00196
00197
00198
00199 KoXmlElement body(KoXml::namedItemNS(contents, KoXmlNS::office, "body"));
00200
00201 if (body.isNull()) {
00202 qDebug() << "No office:body found!";
00203
00204 return false;
00205 }
00206
00207 body = KoXml::namedItemNS(body, KoXmlNS::office, "drawing");
00208 if (body.isNull()) {
00209 qDebug() << "No office:drawing found!";
00210
00211 return false;
00212 }
00213
00214 KoXmlElement page(KoXml::namedItemNS(body, KoXmlNS::draw, "page"));
00215 if (page.isNull()) {
00216 qDebug() << "No office:drawing found!";
00217
00218 return false;
00219 }
00220
00221 KoXmlElement * master = 0;
00222 if (odfStore.styles().masterPages().contains("Standard"))
00223 master = odfStore.styles().masterPages().value("Standard");
00224 else if (odfStore.styles().masterPages().contains("Default"))
00225 master = odfStore.styles().masterPages().value("Default");
00226 else if (! odfStore.styles().masterPages().empty())
00227 master = odfStore.styles().masterPages().begin().value();
00228
00229 if (master) {
00230 const KoXmlElement *style = odfStore.styles().findStyle(
00231 master->attributeNS(KoXmlNS::style, "page-layout-name", QString()));
00232 KoPageLayout pageLayout;
00233 pageLayout.loadOdf(*style);
00234 setSize(QSizeF(pageLayout.width, pageLayout.height));
00235 } else {
00236 kWarning() << "No master page found!";
00237 return false;
00238 }
00239
00240 QMap<QString, KoDataCenter*> dataCenterMap;
00241 KoOdfLoadingContext context(odfStore.styles(), odfStore.store());
00242 KoShapeLoadingContext shapeContext(context, dataCenterMap);
00243
00244
00245 KoXmlElement layerElement;
00246 forEachElement(layerElement, context.stylesReader().layerSet()) {
00247 if (!loadOdf(layerElement, shapeContext)) {
00248 kWarning() << "Could not load shape layer!";
00249 return false;
00250 }
00251 }
00252
00253 KoXmlElement child;
00254 forEachElement(child, page) {
00255 KoShape * shape = KoShapeRegistry::instance()->createShapeFromOdf(child, shapeContext);
00256 if (shape) {
00257 addChild(shape);
00258 }
00259 }
00260
00261 return true;
00262
00263 }
00264
00265
00266 void KisShapeSelection::addChild(KoShape *object)
00267 {
00268 KoShapeLayer::addChild(object);
00269 m_canvas->shapeManager()->add(object);
00270 }
00271
00272 void KisShapeSelection::removeChild(KoShape *object)
00273 {
00274 m_canvas->shapeManager()->remove(object);
00275 KoShapeLayer::removeChild(object);
00276 }
00277
00278 QPainterPath KisShapeSelection::selectionOutline()
00279 {
00280 if (m_dirty) {
00281 QList<KoShape*> shapesList = childShapes();
00282
00283 QPainterPath outline;
00284 foreach(KoShape * shape, shapesList) {
00285 QMatrix shapeMatrix = shape->absoluteTransformation(0);
00286 outline = outline.united(shapeMatrix.map(shape->outline()));
00287 }
00288 m_outline = outline;
00289 m_dirty = false;
00290 }
00291 return m_outline;
00292 }
00293
00294 void KisShapeSelection::paintComponent(QPainter& painter, const KoViewConverter& converter)
00295 {
00296 Q_UNUSED(painter);
00297 Q_UNUSED(converter);
00298 }
00299
00300 void KisShapeSelection::renderToProjection(KisSelection* projection)
00301 {
00302 Q_ASSERT(projection);
00303 Q_ASSERT(m_image);
00304 QMatrix resolutionMatrix;
00305 resolutionMatrix.scale(m_image->xRes(), m_image->yRes());
00306
00307 QRectF boundingRect = resolutionMatrix.mapRect(selectionOutline().boundingRect());
00308 renderSelection(projection, boundingRect.toAlignedRect());
00309 }
00310
00311 void KisShapeSelection::renderToProjection(KisSelection* projection, const QRect& r)
00312 {
00313 Q_ASSERT(projection);
00314 renderSelection(projection, r);
00315 }
00316
00317 void KisShapeSelection::renderSelection(KisSelection* projection, const QRect& r)
00318 {
00319 Q_ASSERT(projection);
00320 Q_ASSERT(m_image);
00321
00322 QMatrix resolutionMatrix;
00323 resolutionMatrix.scale(m_image->xRes(), m_image->yRes());
00324
00325 QTime t;
00326 t.start();
00327
00328 KisPaintDeviceSP tmpMask = new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8());
00329
00330 const qint32 MASK_IMAGE_WIDTH = 256;
00331 const qint32 MASK_IMAGE_HEIGHT = 256;
00332
00333 QImage polygonMaskImage(MASK_IMAGE_WIDTH, MASK_IMAGE_HEIGHT, QImage::Format_ARGB32);
00334 QPainter maskPainter(&polygonMaskImage);
00335 maskPainter.setRenderHint(QPainter::Antialiasing, true);
00336
00337
00338
00339 for (qint32 x = r.x(); x < r.x() + r.width(); x += MASK_IMAGE_WIDTH) {
00340 for (qint32 y = r.y(); y < r.y() + r.height(); y += MASK_IMAGE_HEIGHT) {
00341
00342 maskPainter.fillRect(polygonMaskImage.rect(), QColor(OPACITY_TRANSPARENT, OPACITY_TRANSPARENT, OPACITY_TRANSPARENT, 255));
00343 maskPainter.translate(-x, -y);
00344 maskPainter.fillPath(resolutionMatrix.map(selectionOutline()), QColor(OPACITY_OPAQUE, OPACITY_OPAQUE, OPACITY_OPAQUE, 255));
00345 maskPainter.translate(x, y);
00346
00347 qint32 rectWidth = qMin(r.x() + r.width() - x, MASK_IMAGE_WIDTH);
00348 qint32 rectHeight = qMin(r.y() + r.height() - y, MASK_IMAGE_HEIGHT);
00349
00350 KisRectIterator rectIt = tmpMask->createRectIterator(x, y, rectWidth, rectHeight);
00351
00352 while (!rectIt.isDone()) {
00353 (*rectIt.rawData()) = qRed(polygonMaskImage.pixel(rectIt.x() - x, rectIt.y() - y));
00354 ++rectIt;
00355 }
00356 }
00357 }
00358 KisPainter painter(projection);
00359 painter.bitBlt(r.x(), r.y(), tmpMask, r.x(), r.y(), r.width(), r.height());
00360 painter.end();
00361 dbgRender << "Shape selection rendering: " << t.elapsed();
00362 }
00363
00364 void KisShapeSelection::setDirty()
00365 {
00366 m_dirty = true;
00367 }
00368
00369 KoShapeManager* KisShapeSelection::shapeManager() const
00370 {
00371 return m_canvas->shapeManager();
00372 }
00373
00374 KisShapeSelectionFactory::KisShapeSelectionFactory(QObject* parent)
00375 : KoShapeFactory(parent, "KisShapeSelection", "selection shape container")
00376 {
00377 }
00378
00379 KoShape* KisShapeSelectionFactory::createDefaultShape() const
00380 {
00381 return 0;
00382 }
00383
00384 KoShape* KisShapeSelectionFactory::createShape(const KoProperties* params) const
00385 {
00386 Q_UNUSED(params);
00387 return 0;
00388 }
00389
00390 #include "kis_shape_selection.moc"