From 7ab6c38496079ad403ee8b3398b54a5dd576f76d Mon Sep 17 00:00:00 2001 From: dnk-88 Date: Wed, 3 Aug 2011 18:45:14 +0300 Subject: [PATCH] Changed: #1302 Redesigned the primitives database and added undo\redo commands for database. --HG-- branch : gsoc2011-worldeditorqt --- .../plugins/world_editor/primitive_item.cpp | 196 ++++++--- .../src/plugins/world_editor/primitive_item.h | 131 ++++-- .../plugins/world_editor/primitives_model.cpp | 277 ++++++------- .../plugins/world_editor/primitives_model.h | 46 ++- .../plugins/world_editor/primitives_view.cpp | 372 +++++++++++++----- .../plugins/world_editor/primitives_view.h | 34 +- .../world_editor/world_editor_actions.cpp | 191 ++++++++- .../world_editor/world_editor_actions.h | 100 ++++- .../world_editor/world_editor_window.cpp | 78 ++-- .../world_editor/world_editor_window.h | 8 +- .../world_editor/world_editor_window.ui | 12 +- 11 files changed, 1070 insertions(+), 375 deletions(-) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.cpp index 300a30631..e948f8b0f 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.cpp @@ -17,6 +17,9 @@ // Project includes #include "primitive_item.h" #include "world_editor_misc.h" +#include "world_editor_constants.h" + +#include "../landscape_editor/landscape_editor_constants.h" // NeL includes #include @@ -28,87 +31,160 @@ namespace WorldEditor { -BaseTreeItem::BaseTreeItem(BaseTreeItem *parent) +Node::Node() + : m_parent(0) { - m_parentItem = parent; - m_itemData << QIcon() << "" << "" << ""; } -BaseTreeItem::BaseTreeItem(const QList &data, BaseTreeItem *parent) +Node::~Node() { - m_parentItem = parent; - m_itemData = data; + if (m_parent) + m_parent->removeChildNode(this); + + qDeleteAll(m_children); + nlassert(m_children.isEmpty()); + m_data.clear(); } -BaseTreeItem::~BaseTreeItem() +void Node::prependChildNode(Node *node) { - qDeleteAll(m_childItems); + // Node is already a child + nlassert(!m_children.contains(node)); + + // Node already has a parent + nlassert(!m_children.contains(node)); + + m_children.prepend(node); + node->m_parent = this; } -void BaseTreeItem::appendChild(BaseTreeItem *item) +void Node::appendChildNode(Node *node) { - m_childItems.append(item); + // Node is already a child + nlassert(!m_children.contains(node)); + + // Node already has a parent + nlassert(!m_children.contains(node)); + + m_children.append(node); + node->m_parent = this; } -void BaseTreeItem::deleteChild(int row) +void Node::insertChildNodeBefore(Node *node, Node *before) { - delete m_childItems.takeAt(row); + // Node is already a child + nlassert(!m_children.contains(node)); + + // Node already has a parent + nlassert(!m_children.contains(node)); + + int idx = before ? m_children.indexOf(before) : -1; + if (idx == -1) + m_children.append(node); + else + m_children.insert(idx, node); + node->m_parent = this; } -BaseTreeItem *BaseTreeItem::child(int row) +void Node::insertChildNodeAfter(Node *node, Node *after) { - return m_childItems.value(row); + // Node is already a child + nlassert(!m_children.contains(node)); + + // Node already has a parent + nlassert(!m_children.contains(node)); + + int idx = after ? m_children.indexOf(after) : -1; + if (idx == -1) + m_children.append(node); + else + m_children.insert(idx + 1, node); + node->m_parent = this; } -int BaseTreeItem::childCount() const +void Node::removeChildNode(Node *node) { - return m_childItems.count(); + nlassert(m_children.contains(node)); + nlassert(node->parent() == this); + + m_children.removeOne(node); + + node->m_parent = 0; } -int BaseTreeItem::columnCount() const +Node *Node::child(int row) { - return m_itemData.count(); + return m_children.at(row); } -QVariant BaseTreeItem::data(int column) const +int Node::childCount() const { - return m_itemData.value(column); + return m_children.count(); } -void BaseTreeItem::setData(int column, const QVariant &data) +QVariant Node::data(int key) const { - m_itemData[column] = data; + return m_data[key]; } -BaseTreeItem *BaseTreeItem::parent() +void Node::setData(int key, const QVariant &data) { - return m_parentItem; + m_data[key] = data; } -int BaseTreeItem::row() const +Node *Node::parent() { - if (m_parentItem) - return m_parentItem->m_childItems.indexOf(const_cast(this)); + return m_parent; +} + +int Node::row() const +{ + if (m_parent) + return m_parent->m_children.indexOf(const_cast(this)); return 0; } -void BaseTreeItem::setModified(bool value) +Node::NodeType Node::type() const { - m_modified = value; + return BasicNodeType; } -bool BaseTreeItem::isModified() const +WorldEditNode::WorldEditNode(const QString &name) { - return m_modified; + setData(Qt::DisplayRole, name); + setData(Qt::DecorationRole, QIcon(Constants::ICON_WORLD_EDITOR)); } -PrimitiveItem::PrimitiveItem(NLLIGO::IPrimitive *primitive, BaseTreeItem *parent) - : BaseTreeItem(parent), - m_primitive(primitive) +WorldEditNode::~WorldEditNode() { - setData(1, QString(m_primitive->getName().c_str())); - setData(2, QString(m_primitive->getClassName().c_str())); +} + +Node::NodeType WorldEditNode::type() const +{ + return WorldEditNodeType; +} + +LandscapeNode::LandscapeNode(const QString &name) +{ + setData(Qt::DisplayRole, name); + setData(Qt::DecorationRole, QIcon(LandscapeEditor::Constants::ICON_ZONE_ITEM)); +} + +LandscapeNode::~LandscapeNode() +{ +} + +Node::NodeType LandscapeNode::type() const +{ + return LandscapeNodeType; +} + +PrimitiveNode::PrimitiveNode(NLLIGO::IPrimitive *primitive) + : m_primitive(primitive) +{ + setData(Qt::DisplayRole, QString(m_primitive->getName().c_str())); + setData(Qt::ToolTipRole, QString(m_primitive->getClassName().c_str())); std::string className; m_primitive->getPropertyByName("class", className); @@ -125,43 +201,57 @@ PrimitiveItem::PrimitiveItem(NLLIGO::IPrimitive *primitive, BaseTreeItem *parent else icon = QIcon("./old_ico/folder_h.ico"); } - setData(0, icon); + setData(Qt::DecorationRole, icon); - setData(3, QString(className.c_str())); + //setData(3, QString(className.c_str())); } -/* -PrimitiveItem::PrimitiveItem(const PrimitiveItem &other) -{ -} -*/ -PrimitiveItem::~PrimitiveItem() + +PrimitiveNode::~PrimitiveNode() { } -NLLIGO::IPrimitive *PrimitiveItem::primitive() const +NLLIGO::IPrimitive *PrimitiveNode::primitive() const { return m_primitive; } -const NLLIGO::CPrimitiveClass *PrimitiveItem::primitiveClass() const +const NLLIGO::CPrimitiveClass *PrimitiveNode::primitiveClass() const { return NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig->getPrimitiveClass(*m_primitive); } +RootPrimitiveNode *PrimitiveNode::rootPrimitiveNode() +{ + Node *node = this; + while (node && (node->type() != Node::RootPrimitiveNodeType)) + node = node->parent(); + return (RootPrimitiveNode *)node; +} -RootPrimitiveItem::RootPrimitiveItem(const QString &name, NLLIGO::CPrimitives *primitives, BaseTreeItem *parent) - : PrimitiveItem(primitives->RootNode, parent), +Node::NodeType PrimitiveNode::type() const +{ + return PrimitiveNodeType; +} + +RootPrimitiveNode::RootPrimitiveNode(const QString &name, NLLIGO::CPrimitives *primitives) + : PrimitiveNode(primitives->RootNode), m_primitives(primitives) { - setData(1, name); + setData(Qt::DisplayRole, name); } -/* -RootPrimitiveItem::RootPrimitiveItem(const RootPrimitiveItem &other) + +RootPrimitiveNode::~RootPrimitiveNode() { } -*/ -RootPrimitiveItem::~RootPrimitiveItem() + +NLLIGO::CPrimitives *RootPrimitiveNode::primitives() const { + return m_primitives; +} + +Node::NodeType RootPrimitiveNode::type() const +{ + return RootPrimitiveNodeType; } } /* namespace WorldEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.h index 5d00e6c92..01c63962c 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitive_item.h @@ -31,69 +31,144 @@ namespace WorldEditor { +class WorldEditNode; +class RootPrimitiveNode; +class LandscapeNode; +class PrimitiveNode; + /* -@class BaseTreeItem +@class Node @brief @details */ -class BaseTreeItem +class Node { public: - BaseTreeItem(BaseTreeItem *parent = 0); - BaseTreeItem(const QList &data, BaseTreeItem *parent = 0); - virtual ~BaseTreeItem(); - void appendChild(BaseTreeItem *child); - void deleteChild(int row); + enum NodeType + { + BasicNodeType, + WorldEditNodeType, + RootPrimitiveNodeType, + LandscapeNodeType, + PrimitiveNodeType, + UserNodeType = 1024 + }; - BaseTreeItem *child(int row); + Node(); + virtual ~Node(); + + /// Remove child node from the child list. + void removeChildNode(Node *node); + + /// Insert node at the beginning of the list. + void prependChildNode(Node *node); + + /// Insert node at the end of the list. + void appendChildNode(Node *node); + + /// Insert node in front of the node pointed to by the pointer before. + void insertChildNodeBefore(Node *node, Node *before); + + /// Insert node in back of the node pointed to by the pointer after. + void insertChildNodeAfter(Node *node, Node *after); + + /// Return the node at index position row in the child list. + Node *child(int row); + + /// Return the number of nodes in the list. int childCount() const; - int columnCount() const; - QVariant data(int column) const; - void setData(int column, const QVariant &data); + + /// Return a row index this node. int row() const; - BaseTreeItem *parent(); - void setModified(bool value); - bool isModified() const; + + /// Return a pointer to this node's parent item. If this node does not have a parent, 0 is returned. + Node *parent(); + + /// Set this node's custom data for the key key to value. + void setData(int key, const QVariant &data); + + /// Return this node's custom data for the key key as a QVariant. + QVariant data(int key) const; + + /// Return a type this node. + virtual NodeType type() const; private: + Q_DISABLE_COPY(Node) - bool m_modified; - QList m_childItems; - QList m_itemData; - BaseTreeItem *m_parentItem; + Node *m_parent; + QList m_children; + QHash m_data; }; /* -@class PrimitiveItem +@class WorldEditNode @brief @details */ -class PrimitiveItem: public BaseTreeItem +class WorldEditNode: public Node { public: - PrimitiveItem(NLLIGO::IPrimitive *primitive, BaseTreeItem *parent); - PrimitiveItem(const PrimitiveItem &other); - virtual ~PrimitiveItem(); + WorldEditNode(const QString &name); + virtual ~WorldEditNode(); + + virtual NodeType type() const; + +private: +}; + +/* +@class LandscapeNode +@brief +@details +*/ +class LandscapeNode: public Node +{ +public: + LandscapeNode(const QString &name); + virtual ~LandscapeNode(); + + virtual NodeType type() const; + +private: +}; + +/* +@class PrimitiveNode +@brief +@details +*/ +class PrimitiveNode: public Node +{ +public: + PrimitiveNode(NLLIGO::IPrimitive *primitive); + virtual ~PrimitiveNode(); NLLIGO::IPrimitive *primitive() const; const NLLIGO::CPrimitiveClass *primitiveClass() const; + RootPrimitiveNode *rootPrimitiveNode(); + + virtual NodeType type() const; private: NLLIGO::IPrimitive *m_primitive; }; /* -@class PrimitivesItem +@class RootPrimitiveNode @brief @details */ -class RootPrimitiveItem: public PrimitiveItem +class RootPrimitiveNode: public PrimitiveNode { public: - RootPrimitiveItem(const QString &name, NLLIGO::CPrimitives *primitives, BaseTreeItem *parent); - RootPrimitiveItem(const RootPrimitiveItem &other); - virtual ~RootPrimitiveItem(); + RootPrimitiveNode(const QString &name, NLLIGO::CPrimitives *primitives); + virtual ~RootPrimitiveNode(); + + NLLIGO::CPrimitives *primitives() const; + + virtual NodeType type() const; private: NLLIGO::CPrimitives *m_primitives; diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.cpp index 7a41822ab..bc8925175 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.cpp @@ -31,24 +31,26 @@ namespace WorldEditor { PrimitivesTreeModel::PrimitivesTreeModel(QObject *parent) - : QAbstractItemModel(parent) + : QAbstractItemModel(parent), + m_worldEditNode(0) { - QList rootData; - rootData << "Name" << "Class" << "Class"; - m_rootItem = new BaseTreeItem(rootData); + m_rootNode = new Node(); + m_rootNode->setData(Qt::DisplayRole, "Name"); } PrimitivesTreeModel::~PrimitivesTreeModel() { - delete m_rootItem; + delete m_rootNode; } int PrimitivesTreeModel::columnCount(const QModelIndex &parent) const { - if (parent.isValid()) - return static_cast(parent.internalPointer())->columnCount(); - else - return m_rootItem->columnCount(); + /* if (parent.isValid()) + return static_cast(parent.internalPointer())->columnCount(); + else + return m_rootItem->columnCount(); + */ + return 1; } QVariant PrimitivesTreeModel::data(const QModelIndex &index, int role) const @@ -56,20 +58,15 @@ QVariant PrimitivesTreeModel::data(const QModelIndex &index, int role) const if (!index.isValid()) return QVariant(); - BaseTreeItem *item = static_cast(index.internalPointer()); + Node *item = static_cast(index.internalPointer()); switch (role) { // case Qt::TextAlignmentRole: // return int(Qt::AlignLeft | Qt::AlignVCenter); case Qt::DisplayRole: - return item->data(index.column() + 1); + return item->data(Qt::DisplayRole); case Qt::DecorationRole: - { - if (index.column() == 0) - return qVariantFromValue(item->data(0)); - else - return QVariant(); - } + return item->data(Qt::DecorationRole); default: return QVariant(); } @@ -83,31 +80,30 @@ Qt::ItemFlags PrimitivesTreeModel::flags(const QModelIndex &index) const return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } -QVariant PrimitivesTreeModel::headerData(int section, Qt::Orientation orientation, - int role) const +QVariant PrimitivesTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) - return m_rootItem->data(section); +// return m_rootNode->data(section); + return m_rootNode->data(Qt::DisplayRole); return QVariant(); } -QModelIndex PrimitivesTreeModel::index(int row, int column, const QModelIndex &parent) -const +QModelIndex PrimitivesTreeModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); - BaseTreeItem *parentItem; + Node *parentNode; if (!parent.isValid()) - parentItem = m_rootItem; + parentNode = m_rootNode; else - parentItem = static_cast(parent.internalPointer()); + parentNode = static_cast(parent.internalPointer()); - BaseTreeItem *childItem = parentItem->child(row); - if (childItem) - return createIndex(row, column, childItem); + Node *childNode = parentNode->child(row); + if (childNode) + return createIndex(row, column, childNode); else return QModelIndex(); } @@ -117,161 +113,166 @@ QModelIndex PrimitivesTreeModel::parent(const QModelIndex &index) const if (!index.isValid()) return QModelIndex(); - BaseTreeItem *childItem = static_cast(index.internalPointer()); - BaseTreeItem *parentItem = childItem->parent(); + Node *childNode = static_cast(index.internalPointer()); + Node *parentNode = childNode->parent(); - if (parentItem == m_rootItem) + if (parentNode == m_rootNode) return QModelIndex(); - return createIndex(parentItem->row(), 0, parentItem); + return createIndex(parentNode->row(), 0, parentNode); } int PrimitivesTreeModel::rowCount(const QModelIndex &parent) const { - BaseTreeItem *parentItem; + Node *parentNode; if (parent.column() > 0) return 0; if (!parent.isValid()) - parentItem = m_rootItem; + parentNode = m_rootNode; else - parentItem = static_cast(parent.internalPointer()); + parentNode = static_cast(parent.internalPointer()); - return parentItem->childCount(); + return parentNode->childCount(); } -NLLIGO::IPrimitive *PrimitivesTreeModel::primitive(const QModelIndex &index) +Path PrimitivesTreeModel::pathFromIndex(const QModelIndex &index) { - NLLIGO::IPrimitive *prim = 0; - if (index.isValid()) + QModelIndex iter = index; + Path path; + while(iter.isValid()) { - PrimitiveItem *item = static_cast(index.internalPointer()); - prim = item->primitive(); + path.prepend(PathItem(iter.row(), iter.column())); + iter = iter.parent(); } - return prim; + return path; } -const NLLIGO::CPrimitiveClass *PrimitivesTreeModel::primitiveClass(const QModelIndex &index) +QModelIndex PrimitivesTreeModel::pathToIndex(const Path &path) { - if (index.isValid()) + QModelIndex iter; + for(int i = 0; i < path.size(); i++) { - NLLIGO::IPrimitive *prim = primitive(index); - return ligoConfig()->getPrimitiveClass(*prim); + iter = index(path[i].first, path[i].second, iter); } - return 0; + return iter; } -void PrimitivesTreeModel::loadPrimitive(const QString &fileName) -{ - NLLIGO::CPrimitives *primitives = new NLLIGO::CPrimitives(); - - // set the primitive context - NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = primitives; - - NLLIGO::loadXmlPrimitiveFile(*primitives, fileName.toStdString(), *NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig); - - // unset the context - NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; - - addRootPrimitive(fileName, primitives); -} - -void PrimitivesTreeModel::newPrimitiveWithoutUndo(const QString &className, uint id, const QModelIndex &parent) -{ - const NLLIGO::CPrimitiveClass *primClass = primitiveClass(parent); - float delta = 10; - - // TODO: Set the context - //CPrimitiveContext::instance().CurrentPrimitive = &_DataHierarchy[locator._LocateStack[0]].Primitives; - - NLLIGO::IPrimitive *newPrimitive = createPrimitive(className.toStdString().c_str(), className.toStdString().c_str() - , NLMISC::CVector(), delta, primClass->DynamicChildren[id].Parameters, primitive(parent)); - - // unset the context - //CPrimitiveContext::instance().CurrentPrimitive = NULL; - - if (newPrimitive != 0) - { - scanPrimitive(newPrimitive, parent); - } -} - -void PrimitivesTreeModel::deletePrimitiveWithoutUndo(const QModelIndex &index) -{ - deletePrimitive(primitive(index)); - removeRows(index.row(), index.parent()); -} - -void PrimitivesTreeModel::addRootPrimitive(const QString &name, NLLIGO::CPrimitives *primitives) +void PrimitivesTreeModel::createWorldEditNode(const QString &fileName) { beginResetModel(); + m_worldEditNode = new WorldEditNode(fileName); + m_rootNode->appendChildNode(m_worldEditNode); + endResetModel(); +} - // Create root primitive - RootPrimitiveItem *newPrimitives = new RootPrimitiveItem(name, primitives, m_rootItem); - m_rootItem->appendChild(newPrimitives); - - // Scan childs items and add in tree model - for (uint i = 0; i < primitives->RootNode->getNumChildren(); ++i) +void PrimitivesTreeModel::deleteWorldEditNode() +{ + beginResetModel(); + if (m_worldEditNode != 0) { - NLLIGO::IPrimitive *childPrim; - primitives->RootNode->getChild(childPrim, i); - scanPrimitive(childPrim, newPrimitives); + delete m_worldEditNode; + m_worldEditNode = 0; } endResetModel(); } -void PrimitivesTreeModel::scanPrimitive(NLLIGO::IPrimitive *prim, const QModelIndex &parentIndex) +Path PrimitivesTreeModel::createLandscapeNode(const QString &fileName) { - PrimitiveItem *parent = static_cast(parentIndex.internalPointer()); + if (m_worldEditNode == 0) + createWorldEditNode("NewWorldEdit"); - // Add in tree model - beginInsertRows(parentIndex, parent->childCount(), parent->childCount()); - PrimitiveItem *newItem = new PrimitiveItem(prim, parent); - parent->appendChild(newItem); + QModelIndex parentIndex = index(0, 0, QModelIndex()); + beginInsertRows(parentIndex, 0, 0); + LandscapeNode *newNode = new LandscapeNode(fileName); + m_worldEditNode->prependChildNode(newNode); + endInsertRows(); + return pathFromIndex(index(0, 0, index(0, 0, QModelIndex()))); +} + + +Path PrimitivesTreeModel::createRootPrimitiveNode(const QString &fileName, NLLIGO::CPrimitives *primitives) +{ + if (m_worldEditNode == 0) + createWorldEditNode("NewWorldEdit"); + + // Get position + int pos = m_worldEditNode->childCount(); + + QModelIndex parentIndex = index(0, 0, QModelIndex()); + + // Add root node in tree model + beginInsertRows(parentIndex, pos, pos); + RootPrimitiveNode *newNode = new RootPrimitiveNode(fileName, primitives); + m_worldEditNode->appendChildNode(newNode); endInsertRows(); - // Scan childs items and add in tree model - QModelIndex childIndex = index(parent->childCount() - 1, 0, parentIndex); - for (uint i = 0; i < prim->getNumChildren(); ++i) + QModelIndex rootPrimIndex = index(pos, 0, parentIndex); + + // Scan childs items and add in the tree model + for (uint i = 0; i < primitives->RootNode->getNumChildren(); ++i) { NLLIGO::IPrimitive *childPrim; - prim->getChild(childPrim, i); - scanPrimitive(childPrim, childIndex); + primitives->RootNode->getChild(childPrim, i); + createChildNodes(childPrim, rootPrimIndex); + } + + return pathFromIndex(rootPrimIndex); +} + +Path PrimitivesTreeModel::createPrimitiveNode(NLLIGO::IPrimitive *primitive, const Path &parent) +{ + QModelIndex parentIndex = pathToIndex(parent); + Node *parentNode = static_cast(parentIndex.internalPointer()); + int pos = parentNode->childCount(); + + createChildNodes(primitive, parentIndex); + + return pathFromIndex(index(pos, 0, parentIndex)); +} + +void PrimitivesTreeModel::deleteNode(const Path &path) +{ + QModelIndex nodeIndex = pathToIndex(path); + QModelIndex parentIndex = nodeIndex.parent(); + Node *node = static_cast(nodeIndex.internalPointer()); + + // Scan childs items and delete from the tree model + removeChildNodes(node, parentIndex); +} + +void PrimitivesTreeModel::createChildNodes(NLLIGO::IPrimitive *primitive, const QModelIndex &parent) +{ + Node *parentNode = static_cast(parent.internalPointer()); + + int pos = parentNode->childCount(); + + // Add node in the tree model + beginInsertRows(parent, pos, pos); + PrimitiveNode *newNode = new PrimitiveNode(primitive); + parentNode->appendChildNode(newNode); + endInsertRows(); + + // Scan childs items and add in the tree model + QModelIndex childIndex = index(pos, 0, parent); + for (uint i = 0; i < primitive->getNumChildren(); ++i) + { + NLLIGO::IPrimitive *childPrim; + primitive->getChild(childPrim, i); + createChildNodes(childPrim, childIndex); } } -void PrimitivesTreeModel::scanPrimitive(NLLIGO::IPrimitive *prim, BaseTreeItem *parent) +void PrimitivesTreeModel::removeChildNodes(Node *node, const QModelIndex &parent) { - // Add in tree model - PrimitiveItem *newItem = new PrimitiveItem(prim, parent); - parent->appendChild(newItem); + // Delete all child nodes from the tree model + while (node->childCount() != 0) + removeChildNodes(node->child(node->childCount() - 1), parent.child(node->row(), 0)); - // Scan childs items and add in tree model - for (uint i = 0; i < prim->getNumChildren(); ++i) - { - NLLIGO::IPrimitive *childPrim; - prim->getChild(childPrim, i); - scanPrimitive(childPrim, newItem); - } -} - -void PrimitivesTreeModel::removeRows(int position, const QModelIndex &parent) -{ - BaseTreeItem *item = static_cast(parent.internalPointer())->child(position); - - // Delete all child items from tree model - while (item->childCount() != 0) - removeRows(0, parent.child(position, 0)); - - // Delete item - beginRemoveRows(parent, position, position); - static_cast(parent.internalPointer())->deleteChild(position); + // Delete node from the tree model + beginRemoveRows(parent, node->row(), node->row()); + delete node; endRemoveRows(); } -NLLIGO::CLigoConfig *PrimitivesTreeModel::ligoConfig() const -{ - return NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig; -} - } /* namespace WorldEditor */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.h index ab4581a30..d2b6509ad 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_model.h @@ -31,9 +31,15 @@ namespace WorldEditor { +class Node; +class WorldEditNode; -class BaseTreeItem; -class PrimitiveItem; +typedef QPair PathItem; +/* +@typedef Path +@brief It store a list of row and column numbers which have to walk through from the root index of the model to reach the need item +*/ +typedef QList Path; /** @class PrimitivesTreeModel @@ -58,32 +64,34 @@ public: int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; - // Get primitive - NLLIGO::IPrimitive *primitive(const QModelIndex &index); + /// Convert QModelIndex to the persistent index - @Path. + /// @Path is a list of [row,column] pairs showing us the way through the model. + Path pathFromIndex(const QModelIndex &index); - // Get primitive class - const NLLIGO::CPrimitiveClass *primitiveClass(const QModelIndex &index); + QModelIndex pathToIndex(const Path &path); - // Load primitive from file - void loadPrimitive(const QString &fileName); + void createWorldEditNode(const QString &fileName); + void deleteWorldEditNode(); - // Create new primitive and add in tree model - void newPrimitiveWithoutUndo(const QString &className, uint id, const QModelIndex &parent); + /// Add new landscape node in tree model. + Path createLandscapeNode(const QString &fileName); - void deletePrimitiveWithoutUndo(const QModelIndex &index); + /// Add new root primitive node and all sub-primitives in the tree model. + Path createRootPrimitiveNode(const QString &fileName, NLLIGO::CPrimitives *primitives); - NLLIGO::CLigoConfig *ligoConfig() const; + /// Add new primitive node and all sub-primitives in the tree model. + Path createPrimitiveNode(NLLIGO::IPrimitive *primitive, const Path &parent); + + /// Delete node and all child nodes from the tree model + void deleteNode(const Path &path); private: - // Add root primitive in tree model and add all its sub-items. - void addRootPrimitive(const QString &name, NLLIGO::CPrimitives *primitives); + void createChildNodes(NLLIGO::IPrimitive *primitive, const QModelIndex &parent); - void scanPrimitive(NLLIGO::IPrimitive *prim, const QModelIndex &parentIndex); - void scanPrimitive(NLLIGO::IPrimitive *prim, BaseTreeItem *parent = 0); + void removeChildNodes(Node *node, const QModelIndex &parent); - void removeRows(int position, const QModelIndex &parent); - - BaseTreeItem *m_rootItem; + Node *m_rootNode; + WorldEditNode *m_worldEditNode; }; } /* namespace WorldEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.cpp index 0cc4e5e52..517dcee43 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.cpp @@ -16,8 +16,13 @@ // Project includes #include "primitives_view.h" -//#include "primitive_item.h" +#include "primitive_item.h" #include "primitives_model.h" +#include "world_editor_actions.h" + +#include "../core/core_constants.h" +#include "../landscape_editor/landscape_editor_constants.h" +#include "../landscape_editor/builder_zone_base.h" // NeL includes #include @@ -27,22 +32,56 @@ // Qt includes #include #include +#include namespace WorldEditor { PrimitivesView::PrimitivesView(QWidget *parent) : QTreeView(parent), + m_undoStack(0), + m_zoneBuilder(0), m_primitivesTreeModel(0) { setContextMenuPolicy(Qt::DefaultContextMenu); - m_deleteAction = new QAction("Delete", this); - m_selectChildrenAction = new QAction("Select children", this); - m_helpAction = new QAction("Help", this); - m_showAction = new QAction("Show", this); - m_hideAction = new QAction("Hide", this); + m_unloadAction = new QAction("Unload", this); + m_unloadAction->setEnabled(false); + m_saveAction = new QAction("Save", this); + m_saveAction->setEnabled(false); + m_saveAction->setIcon(QIcon(Core::Constants::ICON_SAVE)); + + m_saveAsAction = new QAction("Save As...", this); + m_saveAsAction->setIcon(QIcon(Core::Constants::ICON_SAVE_AS)); + m_saveAsAction->setEnabled(false); + + m_loadLandAction = new QAction("Load landscape file", this); + m_loadLandAction->setIcon(QIcon(LandscapeEditor::Constants::ICON_ZONE_ITEM)); + + m_loadPrimitiveAction = new QAction("Load primitive file", this); + m_loadPrimitiveAction->setIcon(QIcon("./old_ico/root.ico")); + + m_newPrimitiveAction = new QAction("New primitive", this); + + m_deleteAction = new QAction("Delete", this); + m_deleteAction->setEnabled(false); + + m_selectChildrenAction = new QAction("Select children", this); + + m_helpAction = new QAction("Help", this); + m_helpAction->setEnabled(false); + + m_showAction = new QAction("Show", this); + m_showAction->setEnabled(false); + + m_hideAction = new QAction("Hide", this); + m_hideAction->setEnabled(false); + + connect(m_loadLandAction, SIGNAL(triggered()), this, SLOT(loadLandscape())); + connect(m_loadPrimitiveAction, SIGNAL(triggered()), this, SLOT(loadRootPrimitive())); + connect(m_newPrimitiveAction, SIGNAL(triggered()), this, SLOT(createRootPrimitive())); + connect(m_selectChildrenAction, SIGNAL(triggered()), this, SLOT(selectChildren())); connect(m_deleteAction, SIGNAL(triggered()), this, SLOT(deletePrimitives())); #ifdef Q_OS_DARWIN @@ -54,30 +93,116 @@ PrimitivesView::~PrimitivesView() { } +void PrimitivesView::setUndoStack(QUndoStack *undoStack) +{ + m_undoStack = undoStack; +} + +void PrimitivesView::setZoneBuilder(LandscapeEditor::ZoneBuilderBase *zoneBuilder) +{ + m_zoneBuilder = zoneBuilder; +} + void PrimitivesView::setModel(PrimitivesTreeModel *model) { QTreeView::setModel(model); m_primitivesTreeModel = model; } -void PrimitivesView::deletePrimitives() +void PrimitivesView::loadRootPrimitive() { - QModelIndexList indexList = selectionModel()->selectedRows(); + nlassert(m_undoStack); + nlassert(m_primitivesTreeModel); - // TODO: use QPersistentModelIndex for deleting several items - m_primitivesTreeModel->deletePrimitiveWithoutUndo(indexList.first()); + QStringList fileNames = QFileDialog::getOpenFileNames(this, + tr("Open NeL Ligo primitive file"), m_lastDir, + tr("All NeL Ligo primitive files (*.primitive)")); + + setCursor(Qt::WaitCursor); + if (!fileNames.isEmpty()) + { + if (fileNames.count() > 1) + m_undoStack->beginMacro("Load primitive files"); + + Q_FOREACH(QString fileName, fileNames) + { + m_lastDir = QFileInfo(fileName).absolutePath(); + m_undoStack->push(new LoadRootPrimitiveCommand(fileName, m_primitivesTreeModel)); + } + + if (fileNames.count() > 1) + m_undoStack->endMacro(); + } + setCursor(Qt::ArrowCursor); } -void PrimitivesView::addNewPrimitive(int value) +void PrimitivesView::loadLandscape() +{ + nlassert(m_undoStack); + nlassert(m_zoneBuilder); + nlassert(m_primitivesTreeModel); + + QStringList fileNames = QFileDialog::getOpenFileNames(this, + tr("Open NeL Ligo land file"), m_lastDir, + tr("All NeL Ligo land files (*.land)")); + + setCursor(Qt::WaitCursor); + if (!fileNames.isEmpty()) + { + if (fileNames.count() > 1) + m_undoStack->beginMacro("Load land files"); + + Q_FOREACH(QString fileName, fileNames) + { + m_lastDir = QFileInfo(fileName).absolutePath(); + m_undoStack->push(new LoadLandscapeCommand(fileName, m_primitivesTreeModel, m_zoneBuilder)); + } + + if (fileNames.count() > 1) + m_undoStack->endMacro(); + } + setCursor(Qt::ArrowCursor); +} + +void PrimitivesView::createRootPrimitive() +{ + nlassert(m_undoStack); + nlassert(m_primitivesTreeModel); + + m_undoStack->push(new CreateRootPrimitiveCommand("NewPrimitive", m_primitivesTreeModel)); +} + +void PrimitivesView::selectChildren() { QModelIndexList indexList = selectionModel()->selectedRows(); + QModelIndex parentIndex = indexList.first(); - const NLLIGO::CPrimitiveClass *primClass = m_primitivesTreeModel->primitiveClass(indexList.first()); + selectionModel()->clearSelection(); + selectChildren(parentIndex); +} + +void PrimitivesView::deletePrimitives() +{ + nlassert(m_undoStack); + nlassert(m_primitivesTreeModel); + + QModelIndexList indexList = selectionModel()->selectedRows(); +} + +void PrimitivesView::addNewPrimitiveByClass(int value) +{ + nlassert(m_undoStack); + nlassert(m_primitivesTreeModel); + + QModelIndexList indexList = selectionModel()->selectedRows(); + + PrimitiveNode *node = static_cast(indexList.first().internalPointer()); // Get class name - QString className = primClass->DynamicChildren[value].ClassName.c_str(); + QString className = node->primitiveClass()->DynamicChildren[value].ClassName.c_str(); - m_primitivesTreeModel->newPrimitiveWithoutUndo(className, value, indexList.first()); + m_undoStack->push(new AddPrimitiveByClassCommand(className, m_primitivesTreeModel->pathFromIndex(indexList.first()), + m_primitivesTreeModel)); } void PrimitivesView::generatePrimitives(int value) @@ -96,96 +221,153 @@ void PrimitivesView::contextMenuEvent(QContextMenuEvent *event) return; QMenu *popurMenu = new QMenu(this); - popurMenu->addAction(m_deleteAction); - popurMenu->addAction(m_selectChildrenAction); - popurMenu->addAction(m_helpAction); - popurMenu->addSeparator(); - popurMenu->addAction(m_showAction); - popurMenu->addAction(m_hideAction); - popurMenu->addSeparator(); - - QSignalMapper *addSignalMapper = new QSignalMapper(this); - QSignalMapper *generateSignalMapper = new QSignalMapper(this); - QSignalMapper *openSignalMapper = new QSignalMapper(this); - connect(addSignalMapper, SIGNAL(mapped(int)), this, SLOT(addNewPrimitive(int))); - connect(generateSignalMapper, SIGNAL(mapped(int)), this, SLOT(generatePrimitives(int))); - //connect(openSignalMapper, SIGNAL(mapped(int)), this, SLOT(openItem(int))); if (indexList.size() == 1) { - const NLLIGO::CPrimitiveClass *primClass = m_primitivesTreeModel->primitiveClass(indexList.first()); - - // What class is it ? - if (primClass && primClass->DynamicChildren.size()) + Node *node = static_cast(indexList.first().internalPointer()); + switch (node->type()) { - popurMenu->addSeparator(); - - // For each child, add a create method - for (size_t i = 0; i < primClass->DynamicChildren.size(); i++) - { - // Get class name - QString className = primClass->DynamicChildren[i].ClassName.c_str(); - - // Get icon - QIcon icon(QString("./old_ico/%1.ico").arg(className)); - - // Create and add action in popur menu - QAction *action = popurMenu->addAction(icon, QString("Add %1").arg(className)); - addSignalMapper->setMapping(action, i); - connect(action, SIGNAL(triggered()), addSignalMapper, SLOT(map())); - } - } - - // What class is it ? - if (primClass && primClass->GeneratedChildren.size()) - { - popurMenu->addSeparator(); - - // For each child, add a create method - for (size_t i = 0; i < primClass->GeneratedChildren.size(); i++) - { - // Get class name - QString childName = primClass->GeneratedChildren[i].ClassName.c_str(); - - // Create and add action in popur menu - QAction *action = popurMenu->addAction(QString("Generate %1").arg(childName)); - generateSignalMapper->setMapping(action, i); - connect(generateSignalMapper, SIGNAL(triggered()), addSignalMapper, SLOT(map())); - } - } - /* - // What class is it ? - if (primClass) - { - // Look for files - std::vector filenames; - - // Filenames - buildFilenameVector (*Selection.front (), filenames); - - // File names ? - if (!filenames.empty ()) - { - // Add separator - popurMenu->addSeparator(); - - // Found ? - for (uint i = 0; i < filenames.size(); i++) - { - // Add a menu entry - pMenu->AppendMenu (MF_STRING, ID_EDIT_OPEN_FILE_BEGIN+i, ("Open "+NLMISC::CFile::getFilename (filenames[i])).c_str ()); - } - } - } - */ + case Node::WorldEditNodeType: + fillMenu_WorldEdit(popurMenu); + break; + case Node::RootPrimitiveNodeType: + fillMenu_RootPrimitive(popurMenu, indexList.first()); + break; + case Node::LandscapeNodeType: + fillMenu_Landscape(popurMenu); + break; + case Node::PrimitiveNodeType: + fillMenu_Primitive(popurMenu, indexList.first()); + break; + }; } popurMenu->exec(event->globalPos()); delete popurMenu; - delete addSignalMapper; - delete generateSignalMapper; - delete openSignalMapper; event->accept(); } +void PrimitivesView::selectChildren(const QModelIndex &parent) +{ + const int rowCount = model()->rowCount(parent); + + for (int i = 0; i < rowCount; ++i) + { + QModelIndex childIndex = parent.child(i, 0); + selectionModel()->select(childIndex, QItemSelectionModel::Select); + selectChildren(childIndex); + } +} + +void PrimitivesView::fillMenu_WorldEdit(QMenu *menu) +{ + menu->addAction(m_unloadAction); + menu->addAction(m_saveAction); + menu->addAction(m_saveAsAction); + menu->addSeparator(); + menu->addAction(m_loadLandAction); + menu->addAction(m_loadPrimitiveAction); + menu->addAction(m_newPrimitiveAction); + menu->addSeparator(); + menu->addAction(m_helpAction); +} + +void PrimitivesView::fillMenu_Landscape(QMenu *menu) +{ + menu->addAction(m_deleteAction); + menu->addSeparator(); + menu->addAction(m_showAction); + menu->addAction(m_hideAction); +} + +void PrimitivesView::fillMenu_RootPrimitive(QMenu *menu, const QModelIndex &index) +{ + menu->addAction(m_saveAction); + menu->addAction(m_saveAsAction); + fillMenu_Primitive(menu, index); +} + +void PrimitivesView::fillMenu_Primitive(QMenu *menu, const QModelIndex &index) +{ + menu->addAction(m_deleteAction); + menu->addAction(m_selectChildrenAction); + menu->addAction(m_helpAction); + menu->addSeparator(); + menu->addAction(m_showAction); + menu->addAction(m_hideAction); + + QSignalMapper *addSignalMapper = new QSignalMapper(menu); + QSignalMapper *generateSignalMapper = new QSignalMapper(menu); + QSignalMapper *openSignalMapper = new QSignalMapper(menu); + connect(addSignalMapper, SIGNAL(mapped(int)), this, SLOT(addNewPrimitiveByClass(int))); + connect(generateSignalMapper, SIGNAL(mapped(int)), this, SLOT(generatePrimitives(int))); + //connect(openSignalMapper, SIGNAL(mapped(int)), this, SLOT(openItem(int))); + + PrimitiveNode *node = static_cast(index.internalPointer()); + const NLLIGO::CPrimitiveClass *primClass = node->primitiveClass(); + + // What class is it ? + if (primClass && primClass->DynamicChildren.size()) + { + menu->addSeparator(); + + // For each child, add a create method + for (size_t i = 0; i < primClass->DynamicChildren.size(); i++) + { + // Get class name + QString className = primClass->DynamicChildren[i].ClassName.c_str(); + + // Get icon + QIcon icon(QString("./old_ico/%1.ico").arg(className)); + + // Create and add action in popur menu + QAction *action = menu->addAction(icon, QString("Add %1").arg(className)); + addSignalMapper->setMapping(action, i); + connect(action, SIGNAL(triggered()), addSignalMapper, SLOT(map())); + } + } + + // What class is it ? + if (primClass && primClass->GeneratedChildren.size()) + { + menu->addSeparator(); + + // For each child, add a create method + for (size_t i = 0; i < primClass->GeneratedChildren.size(); i++) + { + // Get class name + QString childName = primClass->GeneratedChildren[i].ClassName.c_str(); + + // Create and add action in popur menu + QAction *action = menu->addAction(QString("Generate %1").arg(childName)); + generateSignalMapper->setMapping(action, i); + connect(generateSignalMapper, SIGNAL(triggered()), addSignalMapper, SLOT(map())); + } + } + /* + // What class is it ? + if (primClass) + { + // Look for files + std::vector filenames; + + // Filenames + buildFilenameVector (*Selection.front (), filenames); + + // File names ? + if (!filenames.empty ()) + { + // Add separator + popurMenu->addSeparator(); + + // Found ? + for (uint i = 0; i < filenames.size(); i++) + { + // Add a menu entry + pMenu->AppendMenu (MF_STRING, ID_EDIT_OPEN_FILE_BEGIN+i, ("Open "+NLMISC::CFile::getFilename (filenames[i])).c_str ()); + } + } + */ +} + } /* namespace WorldEditor */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.h index b0381b5bf..67c3ffba0 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/primitives_view.h @@ -28,11 +28,15 @@ #include #include #include +#include + +namespace LandscapeEditor +{ +class ZoneBuilderBase; +} namespace WorldEditor { - -class BaseTreeItem; class PrimitivesTreeModel; /** @@ -48,23 +52,47 @@ public: PrimitivesView(QWidget *parent = 0); ~PrimitivesView(); + void setUndoStack(QUndoStack *undoStack); + void setZoneBuilder(LandscapeEditor::ZoneBuilderBase *zoneBuilder); virtual void setModel(PrimitivesTreeModel *model); private Q_SLOTS: + void loadLandscape(); + void loadRootPrimitive(); + void createRootPrimitive(); + void selectChildren(); + void deletePrimitives(); - void addNewPrimitive(int value); + void addNewPrimitiveByClass(int value); void generatePrimitives(int value); void openItem(int value); protected: void contextMenuEvent(QContextMenuEvent *event); +private: + void selectChildren(const QModelIndex &parent); + void fillMenu_WorldEdit(QMenu *menu); + void fillMenu_Landscape(QMenu *menu); + void fillMenu_RootPrimitive(QMenu *menu, const QModelIndex &index); + void fillMenu_Primitive(QMenu *menu, const QModelIndex &index); + + QString m_lastDir; + + QAction *m_unloadAction; + QAction *m_saveAction; + QAction *m_saveAsAction; + QAction *m_loadLandAction; + QAction *m_loadPrimitiveAction; + QAction *m_newPrimitiveAction; QAction *m_deleteAction; QAction *m_selectChildrenAction; QAction *m_helpAction; QAction *m_showAction; QAction *m_hideAction; + QUndoStack *m_undoStack; + LandscapeEditor::ZoneBuilderBase *m_zoneBuilder; PrimitivesTreeModel *m_primitivesTreeModel; }; diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.cpp index cae402d27..fb8299c23 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.cpp @@ -1,5 +1,4 @@ // Object Viewer Qt - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited // Copyright (C) 2011 Dzmitry Kamiahin // // This program is free software: you can redistribute it and/or modify @@ -17,31 +16,211 @@ // Project includes #include "world_editor_actions.h" +#include "world_editor_misc.h" +#include "primitive_item.h" + +// Lanscape Editor plugin +#include "../landscape_editor/builder_zone_base.h" + +// STL includes +#include // NeL includes #include +#include +#include +#include +#include // Qt includes +#include namespace WorldEditor { -OpenLandscapeCommand::OpenLandscapeCommand(const QString &fileName, QUndoCommand *parent) +CreateWorldCommand::CreateWorldCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent) : QUndoCommand(parent), - m_fileName(fileName) + m_fileName(fileName), + m_model(model) +{ + setText("Create new world"); +} + +CreateWorldCommand::~CreateWorldCommand() { } -OpenLandscapeCommand::~OpenLandscapeCommand() +void CreateWorldCommand::undo() +{ + m_model->deleteWorldEditNode(); +} + +void CreateWorldCommand::redo() +{ + m_model->createWorldEditNode(m_fileName); +} + +LoadLandscapeCommand::LoadLandscapeCommand(const QString &fileName, PrimitivesTreeModel *model, + LandscapeEditor::ZoneBuilderBase *zoneBuilder, QUndoCommand *parent) + : QUndoCommand(parent), + m_id(-1), + m_fileName(fileName), + m_model(model), + m_zoneBuilder(zoneBuilder) +{ + setText("Load land file"); +} + +LoadLandscapeCommand::~LoadLandscapeCommand() { } -void OpenLandscapeCommand::undo() +void LoadLandscapeCommand::undo() +{ + m_zoneBuilder->deleteZoneRegion(m_id); + m_model->deleteNode(landIndex); +} + +void LoadLandscapeCommand::redo() +{ + if (m_id == -1) + m_id = m_zoneBuilder->loadZoneRegion(m_fileName); + else + m_zoneBuilder->loadZoneRegion(m_fileName, m_id); + + landIndex = m_model->createLandscapeNode(m_fileName); +} + +CreateRootPrimitiveCommand::CreateRootPrimitiveCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent) + : QUndoCommand(parent), + m_fileName(fileName), + m_model(model) +{ + setText("Create new primitive"); +} + +CreateRootPrimitiveCommand::~CreateRootPrimitiveCommand() { } -void OpenLandscapeCommand::redo() +void CreateRootPrimitiveCommand::undo() { + QModelIndex index = m_model->pathToIndex(m_rootPrimIndex); + + RootPrimitiveNode *node = static_cast(index.internalPointer()); + + delete node->primitives(); + + m_model->deleteNode(m_rootPrimIndex); +} + +void CreateRootPrimitiveCommand::redo() +{ + NLLIGO::CPrimitives *newRootPrim = new NLLIGO::CPrimitives(); + m_rootPrimIndex = m_model->createRootPrimitiveNode(m_fileName, newRootPrim); +} + + +LoadRootPrimitiveCommand::LoadRootPrimitiveCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent) + : QUndoCommand(parent), + m_fileName(fileName), + m_model(model) +{ + setText("Load primitive file"); +} + +LoadRootPrimitiveCommand::~LoadRootPrimitiveCommand() +{ +} + +void LoadRootPrimitiveCommand::undo() +{ + QModelIndex index = m_model->pathToIndex(m_rootPrimIndex); + + RootPrimitiveNode *node = static_cast(index.internalPointer()); + + delete node->primitives(); + + m_model->deleteNode(m_rootPrimIndex); +} + +void LoadRootPrimitiveCommand::redo() +{ + NLLIGO::CPrimitives *primitives = new NLLIGO::CPrimitives(); + + // set the primitive context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = primitives; + + NLLIGO::loadXmlPrimitiveFile(*primitives, m_fileName.toStdString(), *NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig); + + // unset the context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; + + + // Initialize default values + Utils::recursiveUpdateDefaultValues(primitives->RootNode); + + // Check property types + if (Utils::recursiveUpdateDefaultValues(primitives->RootNode)) + { + nlwarning("In file (%s) : Some primitives have been modified to initialise their default values\nor to change their properties type.", m_fileName.toStdString().c_str()); + } + + m_rootPrimIndex = m_model->createRootPrimitiveNode(m_fileName, primitives); +} + +AddPrimitiveByClassCommand::AddPrimitiveByClassCommand(const QString &className, const Path &parentIndex, + PrimitivesTreeModel *model, QUndoCommand *parent) + : QUndoCommand(parent), + m_className(className), + m_parentIndex(parentIndex), + m_model(model) +{ + setText(QString("Add %1").arg(m_className)); +} + +AddPrimitiveByClassCommand::~AddPrimitiveByClassCommand() +{ +} + +void AddPrimitiveByClassCommand::undo() +{ + QModelIndex index = m_model->pathToIndex(m_newPrimIndex); + PrimitiveNode *node = static_cast(index.internalPointer()); + + // set the primitive context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = node->rootPrimitiveNode()->primitives(); + + Utils::deletePrimitive(node->primitive()); + + // unset the context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; + + m_model->deleteNode(m_newPrimIndex); +} + +void AddPrimitiveByClassCommand::redo() +{ + QModelIndex parentIndex = m_model->pathToIndex(m_parentIndex); + PrimitiveNode *parentNode = static_cast(parentIndex.internalPointer()); + const NLLIGO::CPrimitiveClass *primClass = parentNode->primitiveClass(); + + float delta = 10; + int id = 0; + while (primClass->DynamicChildren[id].ClassName != m_className.toStdString()) + ++id; + + // set the primitive context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = parentNode->rootPrimitiveNode()->primitives(); + + QString namePrimititve = QString("%1_%2").arg(m_className).arg(parentNode->childCount()); + NLLIGO::IPrimitive *newPrimitive = Utils::createPrimitive(m_className.toStdString().c_str(), namePrimititve.toStdString().c_str(), + NLMISC::CVector(), delta, primClass->DynamicChildren[id].Parameters, parentNode->primitive()); + + // unset the context + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; + + m_newPrimIndex = m_model->createPrimitiveNode(newPrimitive, m_parentIndex); } } /* namespace WorldEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.h index 5a1c1ea49..00951dd9e 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_actions.h @@ -1,5 +1,4 @@ // Object Viewer Qt - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited // Copyright (C) 2011 Dzmitry Kamiahin // // This program is free software: you can redistribute it and/or modify @@ -19,6 +18,7 @@ #define WORLD_EDITOR_ACTIONS_H // Project includes +#include "primitives_model.h" // NeL includes @@ -27,20 +27,110 @@ #include #include +namespace LandscapeEditor +{ +class ZoneBuilderBase; +} + namespace WorldEditor { -class OpenLandscapeCommand: public QUndoCommand +/** +@class CreateWorldCommand +@brief +@details +*/ +class CreateWorldCommand: public QUndoCommand { public: - OpenLandscapeCommand(const QString &fileName, QUndoCommand *parent = 0); - virtual ~OpenLandscapeCommand(); + CreateWorldCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent = 0); + virtual ~CreateWorldCommand(); virtual void undo(); virtual void redo(); private: - QString m_fileName; + const QString m_fileName; + PrimitivesTreeModel *const m_model; +}; + +/** +@class LoadLandscapeCommand +@brief +@details +*/ +class LoadLandscapeCommand: public QUndoCommand +{ +public: + LoadLandscapeCommand(const QString &fileName, PrimitivesTreeModel *model, + LandscapeEditor::ZoneBuilderBase *zoneBuilder, QUndoCommand *parent = 0); + virtual ~LoadLandscapeCommand(); + + virtual void undo(); + virtual void redo(); +private: + + Path landIndex; + int m_id; + const QString m_fileName; + PrimitivesTreeModel *const m_model; + LandscapeEditor::ZoneBuilderBase *const m_zoneBuilder; +}; + +class CreateRootPrimitiveCommand: public QUndoCommand +{ +public: + CreateRootPrimitiveCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent = 0); + virtual ~CreateRootPrimitiveCommand(); + + virtual void undo(); + virtual void redo(); +private: + + const QString m_fileName; + Path m_rootPrimIndex; + PrimitivesTreeModel *const m_model; +}; + +/** +@class LoadPrimitiveCommand +@brief +@details +*/ +class LoadRootPrimitiveCommand: public QUndoCommand +{ +public: + LoadRootPrimitiveCommand(const QString &fileName, PrimitivesTreeModel *model, QUndoCommand *parent = 0); + virtual ~LoadRootPrimitiveCommand(); + + virtual void undo(); + virtual void redo(); +private: + + Path m_rootPrimIndex; + const QString m_fileName; + PrimitivesTreeModel *const m_model; +}; + +/** +@class AddPrimitiveCommand +@brief +@details +*/ +class AddPrimitiveByClassCommand: public QUndoCommand +{ +public: + AddPrimitiveByClassCommand(const QString &className, const Path &parentIndex, + PrimitivesTreeModel *model, QUndoCommand *parent = 0); + virtual ~AddPrimitiveByClassCommand(); + + virtual void undo(); + virtual void redo(); +private: + + const QString m_className; + Path m_parentIndex, m_newPrimIndex; + PrimitivesTreeModel *m_model; }; } /* namespace WorldEditor */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.cpp index fd9f9c755..132b52b70 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.cpp @@ -1,5 +1,4 @@ // Object Viewer Qt - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited // Copyright (C) 2011 Dzmitry Kamiahin // // This program is free software: you can redistribute it and/or modify @@ -20,6 +19,8 @@ #include "world_editor_constants.h" #include "primitives_model.h" #include "world_editor_scene.h" +#include "world_editor_misc.h" +#include "world_editor_actions.h" // Core #include "../core/icore.h" @@ -28,17 +29,12 @@ // Lanscape Editor plugin #include "../landscape_editor/builder_zone_base.h" -//#include "../landscape_editor/project_settings_dialog.h" // NeL includes #include #include #include - -#include -#include -#include -#include +#include // Qt includes #include @@ -47,7 +43,6 @@ namespace WorldEditor { -QString _lastDir; WorldEditorWindow::WorldEditorWindow(QWidget *parent) : QMainWindow(parent), @@ -57,9 +52,9 @@ WorldEditorWindow::WorldEditorWindow(QWidget *parent) m_ui.setupUi(this); m_undoStack = new QUndoStack(this); - m_worldEditorScene = new WorldEditorScene(160, this); + m_worldEditorScene = new WorldEditorScene(NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig->CellSize, this); m_zoneBuilderBase = new LandscapeEditor::ZoneBuilderBase(m_worldEditorScene); - + m_worldEditorScene->setZoneBuilder(m_zoneBuilderBase); m_ui.graphicsView->setScene(m_worldEditorScene); @@ -78,12 +73,16 @@ WorldEditorWindow::WorldEditorWindow(QWidget *parent) m_primitivesModel = new PrimitivesTreeModel(); m_ui.treePrimitivesView->setModel(m_primitivesModel); + // TODO: ? + m_ui.treePrimitivesView->setUndoStack(m_undoStack); + m_ui.treePrimitivesView->setZoneBuilder(m_zoneBuilderBase); + createMenus(); createToolBars(); readSettings(); connect(m_ui.newWorldEditAction, SIGNAL(triggered()), this, SLOT(newWorldEditFile())); - connect(m_ui.saveWorldEditAction, SIGNAL(triggered()), this, SLOT(saveAllWorldEditFiles())); + connect(m_ui.saveWorldEditAction, SIGNAL(triggered()), this, SLOT(saveWorldEditFile())); } @@ -101,33 +100,64 @@ QUndoStack *WorldEditorWindow::undoStack() const void WorldEditorWindow::open() { - QStringList fileNames = QFileDialog::getOpenFileNames(this, - tr("Open NeL Ligo primitive file"), _lastDir, - tr("All NeL Ligo primitive files (*.primitive)")); + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open NeL World Edit file"), m_lastDir, + tr("All NeL World Editor file (*.worldedit)")); setCursor(Qt::WaitCursor); - if (!fileNames.isEmpty()) + if (!fileName.isEmpty()) { - QStringList list = fileNames; - _lastDir = QFileInfo(list.front()).absolutePath(); - Q_FOREACH(QString fileName, fileNames) - { - loadPrimitive(fileName); - } + m_lastDir = QFileInfo(fileName).absolutePath(); + loadWorldEditFile(fileName); } setCursor(Qt::ArrowCursor); } -void WorldEditorWindow::loadPrimitive(const QString &fileName) +void WorldEditorWindow::loadWorldEditFile(const QString &fileName) +{ + Utils::WorldEditList worldEditList; + if (!Utils::loadWorldEditFile(fileName.toStdString(), worldEditList)) + { + return; + } + + m_undoStack->beginMacro(QString("Load %1").arg(fileName)); + + checkCurrentWorld(); + + m_undoStack->push(new CreateWorldCommand(fileName, m_primitivesModel)); + for (size_t i = 0; i < worldEditList.size(); ++i) + { + switch (worldEditList[i].first) + { + case Utils::DataDirectoryType: + m_zoneBuilderBase->init(QString(worldEditList[i].second.c_str()), true); + break; + case Utils::ContextType: + break; + case Utils::LandscapeType: + m_undoStack->push(new LoadLandscapeCommand(QString(worldEditList[i].second.c_str()), m_primitivesModel, m_zoneBuilderBase)); + break; + case Utils::PrimitiveType: + m_undoStack->push(new LoadRootPrimitiveCommand(QString(worldEditList[i].second.c_str()), m_primitivesModel)); + break; + }; + } + m_undoStack->endMacro(); +} + +void WorldEditorWindow::checkCurrentWorld() { - m_primitivesModel->loadPrimitive(fileName); } void WorldEditorWindow::newWorldEditFile() { + checkCurrentWorld(); + + m_undoStack->push(new CreateWorldCommand("NewWorldEdit", m_primitivesModel)); } -void WorldEditorWindow::saveAllWorldEditFiles() +void WorldEditorWindow::saveWorldEditFile() { } diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.h index 99768736b..2536bcc1c 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.h @@ -1,5 +1,4 @@ // Object Viewer Qt - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited // Copyright (C) 2011 Dzmitry Kamiahin // // This program is free software: you can redistribute it and/or modify @@ -50,7 +49,7 @@ public Q_SLOTS: private Q_SLOTS: void newWorldEditFile(); - void saveAllWorldEditFiles(); + void saveWorldEditFile(); void openProjectSettings(); private: @@ -59,7 +58,10 @@ private: void readSettings(); void writeSettings(); - void loadPrimitive(const QString &fileName); + void loadWorldEditFile(const QString &fileName); + void checkCurrentWorld(); + + QString m_lastDir; PrimitivesTreeModel *m_primitivesModel; QUndoStack *m_undoStack; diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.ui index 331dc34ff..80e4e5ace 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.ui +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/world_editor/world_editor_window.ui @@ -20,7 +20,17 @@ - + + + QGraphicsView::RubberBandDrag + + + QGraphicsView::AnchorUnderMouse + + + QGraphicsView::AnchorUnderMouse + +