StageObjectsData *StageObjectsData::clone() const
{
	StageObjectsData *data = new StageObjectsData();

	// Clone each element (the new data gets ownership)
	int i, elementsCount = m_elements.size();
	for (i = 0; i < elementsCount; ++i)
		data->m_elements.append(m_elements[i]->clone());

	// Clone each spline (the new data gets ownership)
	for (i = 0; i < m_splines.size(); ++i)
		data->m_splines.append(m_splines[i]->clone());

	// Same for internal fxs
	std::map<TFx *, TFx *> fxTable; // And trace the pairings with the originals
	std::set<TFx *>::const_iterator it;
	for (it = m_fxs.begin(); it != m_fxs.end(); ++it) {
		TFx *fxOrig = *it;
		assert(fxOrig);
		assert(fxTable.count(fxOrig) == 0);

		TFx *fx = fxOrig->clone(false);
		fx->getAttributes()->setId(fxOrig->getAttributes()->getId());
		fx->getAttributes()->passiveCacheDataIdx() = -1;
		fx->setName(fxOrig->getName());
		fx->setFxId(fxOrig->getFxId());

		fxTable[fxOrig] = fx;
		fx->addRef();
		data->m_fxs.insert(fx);
	}

	// Same with terminals
	for (it = m_terminalFxs.begin(); it != m_terminalFxs.end(); ++it) {
		TFx *fxOrig = *it;
		assert(fxOrig);

		// If the fx was not already cloned above, do it now
		TFx *fx = searchFx(fxTable, fxOrig);
		if (!fx) {
			fx = fxOrig->clone(false);
			fx->getAttributes()->setId(fxOrig->getAttributes()->getId());
			fx->getAttributes()->passiveCacheDataIdx() = -1;
			fx->setName(fxOrig->getName());
			fx->setFxId(fxOrig->getFxId());
			fxTable[fxOrig] = fx;
		}

		fx->addRef();
		data->m_terminalFxs.insert(fx);
	}

	if (!fxTable.empty())
		updateFxLinks(fxTable); // Applies the traced map pairings to every fx descendant
								// of each fx stored in the map.

	// WARNING: m_fxsTable is NOT COPIED / CLONED !!

	return data;
}
void StageObjectsData::storeFxs(const std::set<TFx *> &fxs, TXsheet *xsh, int fxFlags)
{
	bool doClone = (fxFlags & eDoClone);
	bool resetFxDagPositions = (fxFlags & eResetFxDagPositions);

	TFxSet *terminalFxs = xsh->getFxDag()->getTerminalFxs();

	// Traverse specified fxs
	std::set<TFx *>::const_iterator it;
	for (it = fxs.begin(); it != fxs.end(); ++it) {
		TFx *fxOrig = *it, *fx = fxOrig;

		if (doClone) {
			// If required, clone them
			fx = fxOrig->clone(false);

			fx->setName(fxOrig->getName());
			fx->getAttributes()->setId(fxOrig->getAttributes()->getId());
			fx->getAttributes()->passiveCacheDataIdx() = -1;

			if (resetFxDagPositions)
				fx->getAttributes()->setDagNodePos(TConst::nowhere);
		}

		// Store them (and the original/clone pairing even if not cloning)
		m_fxTable[fxOrig] = fx;
		fx->addRef();
		m_fxs.insert(fx);

		// Find out if the fx is a terminal one in the selection. If so, store it there too.
		bool isTerminal = true;
		if (!terminalFxs->containsFx(fxOrig)) // If it's terminal in the xsheet, no doubt
		{
			// Otherwise, check terminality with respect to the selection
			int i, outputConnectionsCount = fxOrig->getOutputConnectionCount();
			for (i = 0; i < outputConnectionsCount; ++i) {
				TFx *outputFx = fxOrig->getOutputConnection(i)->getOwnerFx();
				if (outputFx && fxs.count(outputFx) > 0) {
					isTerminal = false;
					break;
				}
			}
		}

		// Well, excluding true TOutputFxs...
		TOutputFx *outFx = dynamic_cast<TOutputFx *>(fx);
		if (isTerminal && !outFx) {
			fx->addRef();
			m_terminalFxs.insert(fx);
		}
	}

	// Updating terminality of the column fxs too!
	// WARNING: This requires that storeObjects() is invoked BEFORE this !
	for (it = m_originalColumnFxs.begin(); it != m_originalColumnFxs.end(); ++it) {
		TFx *fxOrig = *it;

		bool isTerminal = true;
		if (!terminalFxs->containsFx(fxOrig)) {
			int i, outputConnectionsCount = fxOrig->getOutputConnectionCount();
			for (i = 0; i < outputConnectionsCount; ++i) {
				TFx *outputFx = fxOrig->getOutputConnection(i)->getOwnerFx();
				if (outputFx && fxs.count(outputFx) > 0) {
					isTerminal = false;
					break;
				}
			}
		}

		if (isTerminal) {
			TFx *fx = m_fxTable[fxOrig];

			fx->addRef();
			m_terminalFxs.insert(fx);
		}
	}

	if (!m_fxTable.empty() && doClone)
		updateFxLinks(m_fxTable); // Apply original/clone pairings
								  // to fx relatives
}
void StageObjectsData::storeObjects(const std::vector<TStageObjectId> &ids, TXsheet *xsh, int fxFlags)
{
	assert(m_fxTable.empty()); // Should be enforced OUTSIDE. Track implicit uses.
	m_fxTable.clear();		   // TO BE REMOVED

	int i, objCount = ids.size();

	// Discriminate sensible stage object types (ie cameras and columns from the rest).
	// Store them in a map, ordered by object index.

	std::map<int, TStageObjectId> cameraIds, columnIds, pegbarIds;
	for (i = 0; i < objCount; ++i) {
		TStageObjectId id = ids[i];
		if (id.isColumn())
			columnIds[id.getIndex()] = id;
		else if (id.isPegbar())
			pegbarIds[id.getIndex()] = id;
		else if (id.isCamera())
			cameraIds[id.getIndex()] = id;
	}

	// Store a suitable object for each
	std::map<int, TStageObjectId>::iterator it;
	for (it = cameraIds.begin(); it != cameraIds.end(); ++it) {
		// Cameras
		TCameraDataElement *cameraElement = new TCameraDataElement();
		cameraElement->storeCamera(it->second, xsh);
		m_elements.append(cameraElement);
	}

	for (it = pegbarIds.begin(); it != pegbarIds.end(); ++it) {
		// Pegbars (includes curves)
		TStageObjectDataElement *objElement = new TStageObjectDataElement();
		objElement->storeObject(it->second, xsh);
		m_elements.append(objElement);
	}

	for (it = columnIds.begin(); it != columnIds.end(); ++it) {
		// Columns
		int colIndex = it->second.getIndex();

		TXshColumn *column = xsh->getColumn(colIndex);
		if (!column)
			continue;

		TColumnDataElement *columnElement = new TColumnDataElement();
		columnElement->storeColumn(xsh, colIndex, fxFlags);
		m_elements.append(columnElement);

		TXshColumn *copiedColumn = columnElement->m_column.getPointer();
		if (column->getFx() && copiedColumn->getFx()) {
			// Store column fx pairings (even if the originals are not cloned)
			m_fxTable[column->getFx()] = copiedColumn->getFx();
			m_originalColumnFxs.insert(column->getFx());
		}
	}

	// Insert terminal fxs
	set<TFx *>::iterator jt;
	for (jt = m_originalColumnFxs.begin(); jt != m_originalColumnFxs.end(); ++jt) {
		if (isColumnSelectionTerminalFx(
				*jt, xsh->getFxDag()->getTerminalFxs(), m_originalColumnFxs)) {
			TFx *fx = m_fxTable[*jt];

			fx->addRef();
			m_terminalFxs.insert(fx);
		}
	}
}