kis_node.cpp 16.7 KB
Newer Older
1
/*
Boudewijn Rempt's avatar
Boudewijn Rempt committed
2
 * Copyright (c) 2007 Boudewijn Rempt <boud@valdyas.org>
3
 *
Boudewijn Rempt's avatar
Boudewijn Rempt committed
4 5 6 7
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
8
 *
Boudewijn Rempt's avatar
Boudewijn Rempt committed
9 10 11 12
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
13
 *
Boudewijn Rempt's avatar
Boudewijn Rempt committed
14 15 16
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
 */
Boudewijn Rempt's avatar
Boudewijn Rempt committed
18

19
#include "kis_node.h"
20

21
#include <QList>
22 23 24
#include <QReadWriteLock>
#include <QReadLocker>
#include <QWriteLocker>
25
#include <QPainterPath>
26
#include <QRect>
27

28 29
#include <KoProperties.h>

30
#include "kis_global.h"
31
#include "kis_node_graph_listener.h"
Boudewijn Rempt's avatar
Boudewijn Rempt committed
32
#include "kis_node_visitor.h"
33
#include "kis_processing_visitor.h"
34
#include "kis_node_progress_proxy.h"
35
#include "kis_busy_progress_indicator.h"
36

37 38
#include "kis_clone_layer.h"

39 40 41
#include "kis_safe_read_list.h"
typedef KisSafeReadList<KisNodeSP> KisSafeReadNodeList;

42
#include "kis_abstract_projection_plane.h"
43
#include "kis_projection_leaf.h"
44
#include "kis_undo_adapter.h"
45

Jouni Pentikäinen's avatar
Jouni Pentikäinen committed
46
#include "kis_keyframe_channel.h"
47
#include "kis_time_range.h"
48 49

/**
Boudewijn Rempt's avatar
Boudewijn Rempt committed
50 51 52
 *The link between KisProjection ans KisImageUpdater
 *uses queued signals with an argument of KisNodeSP type,
 *so we should register it beforehand
53 54 55 56 57 58 59 60 61
 */
struct KisNodeSPStaticRegistrar {
    KisNodeSPStaticRegistrar() {
        qRegisterMetaType<KisNodeSP>("KisNodeSP");
    }
};
static KisNodeSPStaticRegistrar __registrar;


62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
/**
 * Note about "thread safety" of KisNode
 *
 * 1) One can *read* any information about node and node graph in any
 *    number of threads concurrently. This operation is safe because
 *    of the usage of KisSafeReadNodeList and will run concurrently
 *    (lock-free).
 *
 * 2) One can *write* any information into the node or node graph in a
 *    single thread only! Changing the graph concurrently is *not*
 *    sane and therefore not supported.
 *
 * 3) One can *read and write* information about the node graph
 *    concurrently, given that there is only *one* writer thread and
 *    any number of reader threads. Please note that in this case the
 *    node's code is just guaranteed *not to crash*, which is ensured
 *    by nodeSubgraphLock. You need to ensure the sanity of the data
 *    read by the reader threads yourself!
 */

82
struct Q_DECL_HIDDEN KisNode::Private
83 84
{
public:
85
    Private(KisNode *node)
Boudewijn Rempt's avatar
Boudewijn Rempt committed
86
            : graphListener(0)
87
            , nodeProgressProxy(0)
88
            , busyProgressIndicator(0)
89
            , animated(false)
90
            , useInTimeline(false)
Dmitry Kazakov's avatar
Dmitry Kazakov committed
91
            , projectionLeaf(new KisProjectionLeaf(node))
92
    {
93 94
    }

95
    KisNodeWSP parent;
Boudewijn Rempt's avatar
Boudewijn Rempt committed
96
    KisNodeGraphListener *graphListener;
97
    KisSafeReadNodeList nodes;
Boudewijn Rempt's avatar
Boudewijn Rempt committed
98
    KisNodeProgressProxy *nodeProgressProxy;
99
    KisBusyProgressIndicator *busyProgressIndicator;
100
    QReadWriteLock nodeSubgraphLock;
101
    QMap<QString, KisKeyframeChannel*> keyframeChannels;
102
    bool animated;
103
    bool useInTimeline;
104

105 106
    KisProjectionLeafSP projectionLeaf;

107 108 109 110 111 112
    const KisNode* findSymmetricClone(const KisNode *srcRoot,
                                      const KisNode *dstRoot,
                                      const KisNode *srcTarget);
    void processDuplicatedClones(const KisNode *srcDuplicationRoot,
                                 const KisNode *dstDuplicationRoot,
                                 KisNode *node);
113
};
114

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
/**
 * Finds the layer in \p dstRoot subtree, which has the same path as
 * \p srcTarget has in \p srcRoot
 */
const KisNode* KisNode::Private::findSymmetricClone(const KisNode *srcRoot,
                                                    const KisNode *dstRoot,
                                                    const KisNode *srcTarget)
{
    if (srcRoot == srcTarget) return dstRoot;

    KisSafeReadNodeList::const_iterator srcIter = srcRoot->m_d->nodes.constBegin();
    KisSafeReadNodeList::const_iterator dstIter = dstRoot->m_d->nodes.constBegin();

    for (; srcIter != srcRoot->m_d->nodes.constEnd(); srcIter++, dstIter++) {

        KIS_ASSERT_RECOVER_RETURN_VALUE((srcIter != srcRoot->m_d->nodes.constEnd()) ==
                                        (dstIter != dstRoot->m_d->nodes.constEnd()), 0);

        const KisNode *node = findSymmetricClone(srcIter->data(), dstIter->data(), srcTarget);
        if (node) return node;

    }

    return 0;
}

/**
 * This function walks through a subtrees of old and new layers and
 * searches for clone layers. For each clone layer it checks whether
 * its copyFrom() lays inside the old subtree, and if it is so resets
 * it to the corresponding layer in the new subtree.
 *
 * That is needed when the user duplicates a group layer with all its
 * layer subtree. In such a case all the "internal" clones must stay
 * "internal" and not point to the layers of the older group.
 */
void KisNode::Private::processDuplicatedClones(const KisNode *srcDuplicationRoot,
                                               const KisNode *dstDuplicationRoot,
                                               KisNode *node)
{
    if (KisCloneLayer *clone = dynamic_cast<KisCloneLayer*>(node)) {
        KIS_ASSERT_RECOVER_RETURN(clone->copyFrom());
        const KisNode *newCopyFrom = findSymmetricClone(srcDuplicationRoot,
                                                        dstDuplicationRoot,
                                                        clone->copyFrom());

        if (newCopyFrom) {
            KisLayer *newCopyFromLayer = dynamic_cast<KisLayer*>(const_cast<KisNode*>(newCopyFrom));
            KIS_ASSERT_RECOVER_RETURN(newCopyFromLayer);

            clone->setCopyFrom(newCopyFromLayer);
        }
    }

    KisSafeReadNodeList::const_iterator iter;
    FOREACH_SAFE(iter, node->m_d->nodes) {
        KisNode *child = const_cast<KisNode*>((*iter).data());
        processDuplicatedClones(srcDuplicationRoot, dstDuplicationRoot, child);
    }
}

176
KisNode::KisNode()
177
        : m_d(new Private(this))
178
{
179 180
    m_d->parent = 0;
    m_d->graphListener = 0;
181 182
}

Boudewijn Rempt's avatar
Boudewijn Rempt committed
183 184
KisNode::KisNode(const KisNode & rhs)
        : KisBaseNode(rhs)
185
        , m_d(new Private(this))
186
{
187
    m_d->parent = 0;
188
    m_d->graphListener = 0;
189

190 191 192
    // NOTE: the nodes are not supposed to be added/removed while
    // creation of another node, so we do *no* locking here!

193 194
    KisSafeReadNodeList::const_iterator iter;
    FOREACH_SAFE(iter, rhs.m_d->nodes) {
195 196 197 198
        KisNodeSP child = (*iter)->clone();
        child->createNodeProgressProxy();
        m_d->nodes.append(child);
        child->setParent(this);
Boudewijn Rempt's avatar
Boudewijn Rempt committed
199
    }
200 201

    m_d->processDuplicatedClones(&rhs, this, this);
202 203 204 205
}

KisNode::~KisNode()
{
206 207 208 209 210
    if (m_d->busyProgressIndicator) {
        m_d->busyProgressIndicator->deleteLater();
    }

    if (m_d->nodeProgressProxy) {
211
        m_d->nodeProgressProxy->deleteLater();
212
    }
213 214 215 216 217 218

    {
        QWriteLocker l(&m_d->nodeSubgraphLock);
        m_d->nodes.clear();
    }

219
    delete m_d;
220 221
}

222
QRect KisNode::needRect(const QRect &rect, PositionToFilthy pos) const
223
{
224
    Q_UNUSED(pos);
225 226 227
    return rect;
}

228
QRect KisNode::changeRect(const QRect &rect, PositionToFilthy pos) const
229
{
230
    Q_UNUSED(pos);
231 232 233
    return rect;
}

234 235 236 237 238 239
QRect KisNode::accessRect(const QRect &rect, PositionToFilthy pos) const
{
    Q_UNUSED(pos);
    return rect;
}

240
KisAbstractProjectionPlaneSP KisNode::projectionPlane() const
241 242
{
    KIS_ASSERT_RECOVER_NOOP(0 && "KisNode::projectionPlane() is not defined!");
243
    static KisAbstractProjectionPlaneSP plane =
244
        toQShared(new KisDumbProjectionPlane());
245

246
    return plane;
247 248
}

249 250 251 252 253
QList<KisKeyframeChannel*> KisNode::keyframeChannels() const
{
    return m_d->keyframeChannels.values();
}

254
KisKeyframeChannel * KisNode::getKeyframeChannel(const QString &id) const
255 256 257 258 259 260
{
    QMap<QString, KisKeyframeChannel*>::iterator i = m_d->keyframeChannels.find(id);
    if (i == m_d->keyframeChannels.end()) return 0;
    return i.value();
}

261 262 263 264 265 266 267 268
bool KisNode::isAnimated() const
{
    return m_d->animated;
}

void KisNode::enableAnimation()
{
    m_d->animated = true;
269
    baseNodeChangedCallback();
270 271 272 273 274 275 276 277 278 279 280 281 282
}

bool KisNode::useInTimeline() const
{
    return m_d->useInTimeline;
}

void KisNode::setUseInTimeline(bool value)
{
    if (value == m_d->useInTimeline) return;

    m_d->useInTimeline = value;
    baseNodeChangedCallback();
283 284
}

285 286 287 288 289
void KisNode::addKeyframeChannel(KisKeyframeChannel *channel)
{
    m_d->keyframeChannels.insert(channel->id(), channel);
}

290 291 292 293 294
KisProjectionLeafSP KisNode::projectionLeaf() const
{
    return m_d->projectionLeaf;
}

Boudewijn Rempt's avatar
Boudewijn Rempt committed
295 296
bool KisNode::accept(KisNodeVisitor &v)
{
Boudewijn Rempt's avatar
Boudewijn Rempt committed
297
    return v.visit(this);
298 299
}

300 301 302 303 304
void KisNode::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter)
{
    return visitor.visit(this, undoAdapter);
}

305 306 307 308 309
int KisNode::graphSequenceNumber() const
{
    return m_d->graphListener ? m_d->graphListener->graphSequenceNumber() : -1;
}

Boudewijn Rempt's avatar
Boudewijn Rempt committed
310
KisNodeGraphListener *KisNode::graphListener() const
311
{
312
    return m_d->graphListener;
313 314
}

Boudewijn Rempt's avatar
Boudewijn Rempt committed
315
void KisNode::setGraphListener(KisNodeGraphListener *graphListener)
316
{
317
    m_d->graphListener = graphListener;
318

319
    QReadLocker l(&m_d->nodeSubgraphLock);
320 321 322 323 324
    KisSafeReadNodeList::const_iterator iter;
    FOREACH_SAFE(iter, m_d->nodes) {
        KisNodeSP child = (*iter);
        child->setGraphListener(graphListener);
    }
325 326
}

327 328 329 330 331 332
void KisNode::setParent(KisNodeWSP parent)
{
    QWriteLocker l(&m_d->nodeSubgraphLock);
    m_d->parent = parent;
}

333
KisNodeSP KisNode::parent() const
334
{
335 336
    QReadLocker l(&m_d->nodeSubgraphLock);
    return m_d->parent.isValid() ? KisNodeSP(m_d->parent) : 0;
337 338
}

339 340 341 342 343
KisBaseNodeSP KisNode::parentCallback() const
{
    return parent();
}

344 345
void KisNode::notifyParentVisibilityChanged(bool value)
{
346 347
    QReadLocker l(&m_d->nodeSubgraphLock);

348 349 350 351 352 353 354
    KisSafeReadNodeList::const_iterator iter;
    FOREACH_SAFE(iter, m_d->nodes) {
        KisNodeSP child = (*iter);
        child->notifyParentVisibilityChanged(value);
    }
}

355 356 357 358 359 360 361
void KisNode::baseNodeChangedCallback()
{
    if(m_d->graphListener) {
        m_d->graphListener->nodeChanged(this);
    }
}

362 363 364 365 366 367 368
void KisNode::baseNodeInvalidateAllFramesCallback()
{
    if(m_d->graphListener) {
        m_d->graphListener->invalidateAllFrames();
    }
}

369
KisNodeSP KisNode::firstChild() const
370
{
371 372
    QReadLocker l(&m_d->nodeSubgraphLock);
    return !m_d->nodes.isEmpty() ? m_d->nodes.first() : 0;
373 374
}

375
KisNodeSP KisNode::lastChild() const
376
{
377 378
    QReadLocker l(&m_d->nodeSubgraphLock);
    return !m_d->nodes.isEmpty() ? m_d->nodes.last() : 0;
379 380
}

381
KisNodeSP KisNode::prevChildImpl(KisNodeSP child)
382
{
383 384 385 386 387 388 389 390 391
    /**
     * Warning: mind locking policy!
     *
     * The graph locks must be *always* taken in descending
     * order. That is if you want to (or it implicitly happens that
     * you) take a lock of a parent and a chil, you must first take
     * the lock of a parent, and only after that ask a child to do the
     * same.  Otherwise you'll get a deadlock.
     */
392

393
    QReadLocker l(&m_d->nodeSubgraphLock);
394

395 396
    int i = m_d->nodes.indexOf(child) - 1;
    return i >= 0 ? m_d->nodes.at(i) : 0;
397 398
}

399
KisNodeSP KisNode::nextChildImpl(KisNodeSP child)
400
{
401 402 403
    /**
     * See a comment in KisNode::prevChildImpl()
     */
404 405
    QReadLocker l(&m_d->nodeSubgraphLock);

406 407 408 409 410 411
    int i = m_d->nodes.indexOf(child) + 1;
    return i > 0 && i < m_d->nodes.size() ? m_d->nodes.at(i) : 0;
}

KisNodeSP KisNode::prevSibling() const
{
412
    KisNodeSP parentNode = parent();
413 414
    return parentNode ? parentNode->prevChildImpl(const_cast<KisNode*>(this)) : 0;
}
415

416 417 418 419
KisNodeSP KisNode::nextSibling() const
{
    KisNodeSP parentNode = parent();
    return parentNode ? parentNode->nextChildImpl(const_cast<KisNode*>(this)) : 0;
420 421
}

422
quint32 KisNode::childCount() const
423
{
424
    QReadLocker l(&m_d->nodeSubgraphLock);
425
    return m_d->nodes.size();
426 427
}

428

Boudewijn Rempt's avatar
Boudewijn Rempt committed
429
KisNodeSP KisNode::at(quint32 index) const
430
{
431 432
    QReadLocker l(&m_d->nodeSubgraphLock);

Boudewijn Rempt's avatar
Boudewijn Rempt committed
433 434
    if (!m_d->nodes.isEmpty() && index < (quint32)m_d->nodes.size()) {
        return m_d->nodes.at(index);
435 436
    }

437 438 439
    return 0;
}

Boudewijn Rempt's avatar
Boudewijn Rempt committed
440
int KisNode::index(const KisNodeSP node) const
441
{
442 443
    QReadLocker l(&m_d->nodeSubgraphLock);

444
    return m_d->nodes.indexOf(node);
445 446
}

Boudewijn Rempt's avatar
Boudewijn Rempt committed
447
QList<KisNodeSP> KisNode::childNodes(const QStringList & nodeTypes, const KoProperties & properties) const
Boudewijn Rempt's avatar
Boudewijn Rempt committed
448
{
449 450
    QReadLocker l(&m_d->nodeSubgraphLock);

Boudewijn Rempt's avatar
Boudewijn Rempt committed
451 452
    QList<KisNodeSP> nodes;

453 454
    KisSafeReadNodeList::const_iterator iter;
    FOREACH_SAFE(iter, m_d->nodes) {
455 456 457 458 459 460 461 462 463 464 465
        if (*iter) {
            if (properties.isEmpty() || (*iter)->check(properties)) {
                bool rightType = true;

                if(!nodeTypes.isEmpty()) {
                    rightType = false;
                    foreach(const QString &nodeType,  nodeTypes) {
                        if ((*iter)->inherits(nodeType.toLatin1())) {
                            rightType = true;
                            break;
                        }
466
                    }
Boudewijn Rempt's avatar
Boudewijn Rempt committed
467
                }
Boudewijn Rempt's avatar
Boudewijn Rempt committed
468
                if (rightType) {
469 470
                    nodes.append(*iter);
                }
471 472
            }
        }
Boudewijn Rempt's avatar
Boudewijn Rempt committed
473
    }
Boudewijn Rempt's avatar
Boudewijn Rempt committed
474 475 476
    return nodes;
}

Boudewijn Rempt's avatar
Boudewijn Rempt committed
477
bool KisNode::add(KisNodeSP newNode, KisNodeSP aboveThis)
478
{
Boudewijn Rempt's avatar
Boudewijn Rempt committed
479
    Q_ASSERT(newNode);
480

Boudewijn Rempt's avatar
Boudewijn Rempt committed
481
    if (!newNode) return false;
482
    if (aboveThis && aboveThis->parent().data() != this) return false;
Boudewijn Rempt's avatar
Boudewijn Rempt committed
483 484
    if (!allowAsChild(newNode)) return false;
    if (newNode->parent()) return false;
485
    if (index(newNode) >= 0) return false;
486

487
    int idx = aboveThis ? this->index(aboveThis) + 1 : 0;
488

489 490 491 492
    // threoretical race condition may happen here ('idx' may become
    // deprecated until the write lock will be held). But we ignore
    // it, because it is not supported to add/remove nodes from two
    // concurrent threads simultaneously
493

494 495 496
    if (m_d->graphListener) {
        m_d->graphListener->aboutToAddANode(this, idx);
    }
497

498 499
    {
        QWriteLocker l(&m_d->nodeSubgraphLock);
500

501
        newNode->createNodeProgressProxy();
502

Boudewijn Rempt's avatar
Boudewijn Rempt committed
503
        m_d->nodes.insert(idx, newNode);
504

505 506
        newNode->setParent(this);
        newNode->setGraphListener(m_d->graphListener);
507
    }
508

509
    if (m_d->graphListener) {
510
        m_d->graphListener->nodeHasBeenAdded(this, idx);
511
    }
512

513

514
    return true;
515 516
}

Boudewijn Rempt's avatar
Boudewijn Rempt committed
517
bool KisNode::remove(quint32 index)
518
{
Boudewijn Rempt's avatar
Boudewijn Rempt committed
519
    if (index < childCount()) {
520 521
        KisNodeSP removedNode = at(index);

522
        if (m_d->graphListener) {
Boudewijn Rempt's avatar
Boudewijn Rempt committed
523
            m_d->graphListener->aboutToRemoveANode(this, index);
524
        }
525

526 527
        {
            QWriteLocker l(&m_d->nodeSubgraphLock);
528

529
            removedNode->setGraphListener(0);
530

531 532 533 534 535 536 537 538
            removedNode->setParent(0);   // after calling aboutToRemoveANode or then the model get broken according to TT's modeltest

            m_d->nodes.removeAt(index);
        }

        if (m_d->graphListener) {
            m_d->graphListener->nodeHasBeenRemoved(this, index);
        }
539 540 541 542

        return true;
    }
    return false;
543 544
}

Boudewijn Rempt's avatar
Boudewijn Rempt committed
545
bool KisNode::remove(KisNodeSP node)
546
{
547
    return node->parent().data() == this ? remove(index(node)) : false;
548 549
}

550
KisNodeProgressProxy* KisNode::nodeProgressProxy() const
551
{
Boudewijn Rempt's avatar
Boudewijn Rempt committed
552
    if (m_d->nodeProgressProxy) {
553
        return m_d->nodeProgressProxy;
Boudewijn Rempt's avatar
Boudewijn Rempt committed
554
    } else if (parent()) {
555 556 557 558 559
        return parent()->nodeProgressProxy();
    }
    return 0;
}

560 561 562 563 564 565 566 567 568 569
KisBusyProgressIndicator* KisNode::busyProgressIndicator() const
{
    if (m_d->busyProgressIndicator) {
        return m_d->busyProgressIndicator;
    } else if (parent()) {
        return parent()->busyProgressIndicator();
    }
    return 0;
}

Boudewijn Rempt's avatar
Boudewijn Rempt committed
570
void KisNode::createNodeProgressProxy()
571
{
Boudewijn Rempt's avatar
Boudewijn Rempt committed
572 573
    if (!m_d->nodeProgressProxy) {
        m_d->nodeProgressProxy = new KisNodeProgressProxy(this);
574
        m_d->busyProgressIndicator = new KisBusyProgressIndicator(m_d->nodeProgressProxy);
575 576 577
    }
}

578 579 580 581 582
void KisNode::setDirty()
{
    setDirty(extent());
}

583 584 585 586 587 588 589
void KisNode::setDirty(const QVector<QRect> &rects)
{
    foreach(const QRect &rc, rects) {
        setDirty(rc);
    }
}

590
void KisNode::setDirty(const QRegion &region)
591
{
592
    setDirty(region.rects());
593
}
594

595 596 597 598 599 600 601
void KisNode::setDirty(const QRect & rect)
{
    if(m_d->graphListener) {
        m_d->graphListener->requestProjectionUpdate(this, rect);
    }
}

602 603 604 605 606 607 608
void KisNode::invalidateFrames(const KisTimeRange &range, const QRect &rect)
{
    if(m_d->graphListener) {
        m_d->graphListener->invalidateFrames(range, rect);
    }
}

Dmitry Kazakov's avatar
Dmitry Kazakov committed
609
void KisNode::requestTimeSwitch(int time)
610 611
{
    if(m_d->graphListener) {
Dmitry Kazakov's avatar
Dmitry Kazakov committed
612
        m_d->graphListener->requestTimeSwitch(time);
613 614 615
    }
}

616 617 618 619 620 621 622
void KisNode::syncLodCache()
{
    KisPaintDeviceSP device = paintDevice();
    if (device) {
        QRegion dirtyRegion = device->syncLodCache(device->defaultBounds()->currentLevelOfDetail());
        Q_UNUSED(dirtyRegion);
    }
623 624 625 626 627 628 629 630

    KisPaintDeviceSP originalDevice = original();
    if (originalDevice && originalDevice != device) {
        QRegion dirtyRegion = originalDevice->syncLodCache(originalDevice->defaultBounds()->currentLevelOfDetail());
        Q_UNUSED(dirtyRegion);
    }

    projectionPlane()->syncLodCache();
631
}