File indexing completed on 2024-12-08 08:10:40

0001 /***************************************************************************
0002  *   Copyright (C) 2005 by David Saxton                                    *
0003  *   david@bluehaze.org                                                    *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  ***************************************************************************/
0010 
0011 #ifndef ICNDOCUMENT_H
0012 #define ICNDOCUMENT_H
0013 
0014 #include "itemdocument.h"
0015 
0016 #include <QMap>
0017 
0018 class Cells;
0019 class CNItem;
0020 class CNItemGroup;
0021 class Connector;
0022 class ECNode;
0023 class FlowContainer;
0024 class Node;
0025 class NodeGroup;
0026 
0027 typedef QMap<QString, Node *> NodeMap;
0028 typedef QList<QPointer<Connector>> ConnectorList;
0029 typedef QList<QPointer<Node>> NodeList;
0030 typedef QList<NodeGroup *> NodeGroupList;
0031 typedef QList<QPointer<NodeGroup>> GuardedNodeGroupList;
0032 
0033 /**
0034 @author David Saxton
0035 */
0036 class ICNDocument : public ItemDocument
0037 {
0038     Q_OBJECT
0039 public:
0040     ICNDocument(const QString &caption);
0041 
0042     ~ICNDocument() override;
0043 
0044     enum hit_score { hs_none = 0, hs_connector = 4, hs_item = 1000 };
0045 
0046     View *createView(ViewContainer *viewContainer, uint viewAreaId) override;
0047 
0048     /**
0049      * Will attempt to create an item with the given id at position p. Some item
0050      * (such as PIC/START) have restrictions, and can only have one instance of
0051      * themselves on the canvas, and adds the operation to the undo list
0052      */
0053     Item *addItem(const QString &id, const QPoint &p, bool newItem) override;
0054 
0055     /**
0056      * short for casting whatever itemWithID(id) returns
0057      */
0058     CNItem *cnItemWithID(const QString &id);
0059     /**
0060      * Returns a pointer to a node on the canvas with the given id,
0061      * or nullptr if no such node exists
0062      */
0063     virtual Node *nodeWithID(const QString &id) = 0;
0064     /**
0065      * Returns a pointer to a Connector on the canvas with the given id,
0066      * or nullptr if no such Connector exists
0067      */
0068     Connector *connectorWithID(const QString &id);
0069     /**
0070      * Adds a KtlQCanvasItem to the delete list to be deleted,
0071      * when flushDeleteList() is called
0072      */
0073     void appendDeleteList(KtlQCanvasItem *qcanvasItem) override;
0074     /**
0075      * Permantly deletes all items that have been added to the delete list with
0076      * the appendDeleteList( KtlQCanvasItem *qcanvasItem ) function.
0077      */
0078     void flushDeleteList() override = 0;
0079     /**
0080      * Reinherit this function to perform special checks on whether the two
0081      * given QCanvasItems (either nodes or connectors or both) can be
0082      * connected together.
0083      */
0084     virtual bool canConnect(KtlQCanvasItem *qcanvasItem1, KtlQCanvasItem *qcanvasItem2) const;
0085     /**
0086      *        copies the selected items to the clipboard, in an XML text form
0087      */
0088     void copy() override;
0089     /**
0090      *        selects everything in the current document
0091      */
0092     void selectAll() override;
0093 
0094     /**
0095      * registers (adds to the document) an item (a connector or a node)
0096      * @param qcanvasItem the item to be registered
0097      * @return true if succeeded, false if it didn't
0098      */
0099     bool registerItem(KtlQCanvasItem *qcanvasItem) override;
0100     /**
0101      * Returns a pointer to the 2-dimension array of ICNDocument cells.
0102      */
0103     Cells *cells() const
0104     {
0105         return m_cells;
0106     }
0107     /**
0108      * Adds score to the cells at the given cell referece
0109      */
0110     void addCPenalty(int x, int y, int score);
0111     /**
0112      * If there are two connectors joined to a node, then they can be merged
0113      * into one connector. The node will not be removed.
0114      * @param node The node between the two connectors
0115      * @param noCreate If true, no new connectors will be created
0116      * @returns true if it was successful in merging the connectors
0117      */
0118     // bool joinConnectors( Node *node );
0119     /**
0120      * Snaps a coordinate in the document to the grid
0121      * @param pos The coordinate
0122      * @return The snapped to grid coordinate
0123      */
0124     static int gridSnap(int pos); /// Returns 'pos' when snapped to grid
0125     /**
0126      * Snaps a point to the grid
0127      * @param pos The point
0128      * @return The adjusted coordinate
0129      */
0130     static QPoint gridSnap(const QPoint &pos);
0131     /**
0132      * Returns true if the CNItem is valid - e.g. will return true for a
0133      * component in a circuit, but not in a pic program
0134      */
0135     bool isValidItem(Item *item) override = 0;
0136     bool isValidItem(const QString &itemId) override = 0;
0137 
0138     // TODO to document
0139     virtual ConnectorList getCommonConnectors(const ItemList &list);
0140     virtual NodeList getCommonNodes(const ItemList &list);
0141 
0142     /**
0143      * returns all the nodes contained by the document. Note that this function is inefficient,
0144      * so don't use it in loops
0145      * @return all the nodes contained by the document
0146      */
0147     virtual NodeList nodeList() const = 0;
0148 
0149     /**
0150      * @return all the connectors from the document
0151      */
0152     const ConnectorList &connectorList() const
0153     {
0154         return m_connectorList;
0155     }
0156 
0157     /**
0158      * @return all the nodegroups from the document
0159      */
0160     const GuardedNodeGroupList &nodeGroupList() const
0161     {
0162         return m_nodeGroupList;
0163     }
0164 
0165     /**
0166      * @return the selected items from the document
0167      */
0168     ItemGroup *selectList() const override;
0169 
0170     /**
0171      * Creates a connector between two nodes, and returns a pointer to it
0172      * and adds the operation to the undo list
0173      */
0174     virtual Connector *createConnector(const QString &startNodeId, const QString &endNodeId, QPointList *pointList = nullptr) = 0;
0175     /**
0176      * Creates a connector from node1 to node2. If pointList is non-null, then the
0177      * connector will be assigned those points
0178      */
0179     // virtual
0180 
0181     Connector *createConnector(Node *node1, Node *node2, QPointList *pointList = nullptr);
0182     /**
0183      * Splits Connector con into two connectors at point pos2, and creates a connector from the node
0184      * to the intersection of the two new connectors. If pointList is non-null, then the new connector
0185      * from the node will be assigned those points
0186      */
0187     virtual Connector *createConnector(Node *node, Connector *con, const QPoint &pos2, QPointList *pointList = nullptr) = 0;
0188     /**
0189      * Splits con1 and con2 into two new connectors each at points pos1 and pos2, and creates a new connector
0190      * between the two points of intersection given by pos1 and pos2. If pointList is non-null, then the new
0191      * connector between the two points will be assigned those points
0192      */
0193     virtual Connector *createConnector(Connector *con1, Connector *con2, const QPoint &pos1, const QPoint &pos2, QPointList *pointList = nullptr) = 0;
0194     /**
0195      * Returns the flowcontainer at the given position at the highest level that
0196      * is not in the current select list, or nullptr if there isn't one
0197      */
0198     FlowContainer *flowContainer(const QPoint &pos);
0199     /**
0200      * Sets the drag (e.g. horizontal arrow) cursor for resizing a CNItem, depending on the corner clicked on
0201      */
0202     void setItemResizeCursor(int cornerType);
0203 
0204     void getTranslatable(const ItemList &itemList, ConnectorList *fixedConnectors = nullptr, ConnectorList *translatableConnectors = nullptr, NodeGroupList *translatableNodeGroups = nullptr);
0205 
0206     /**
0207      * Reroutes invalidated directors. You shouldn't call this function
0208      * directly - instead use ItemDocument::requestEvent.
0209      */
0210     void rerouteInvalidatedConnectors();
0211     /**
0212      * Assigns the orphan nodes into NodeGroups. You shouldn't call this
0213      * function directly - instead use ItemDocument::requestEvent.
0214      */
0215     virtual void slotAssignNodeGroups();
0216 
0217     void unregisterUID(const QString &uid) override;
0218 
0219 public slots:
0220     /**
0221      * Deletes all items in the selected item list, along with associated
0222      * connectors, etc, and adds the operation to the undo list
0223      */
0224     void deleteSelection() override;
0225     /**
0226      * This function looks at all the connectors and the nodes, determines
0227      * which ones need rerouting, and then reroutes them
0228      */
0229     void requestRerouteInvalidatedConnectors();
0230     /**
0231      * Remaps the 2-dimension array of ICNDocument cells, and the various
0232      * hitscores / etc associated with them. This is used for connector
0233      * routing, and should be called after e.g. items have been moved
0234      */
0235     void createCellMap();
0236     /**
0237      * Call this to request NodeGroup reassignment.
0238      */
0239     void slotRequestAssignNG();
0240 
0241 signals:
0242     /**
0243      * Emitted when a Connector is added
0244      */
0245     void connectorAdded(Connector *connector);
0246     /**
0247      * Emitted when a Node is added
0248      */
0249     void nodeAdded(Node *node);
0250 
0251 protected:
0252     /**
0253      * Adds all connector points from the items (used in connector routing).
0254      * This only needs to be called when connector(s) need routing.
0255      */
0256     void addAllItemConnectorPoints();
0257 
0258     void fillContextMenu(const QPoint &pos) override;
0259     /**
0260      * Creates a new NodeGroup to control the node, if there does not already
0261      * exist a NodeGroup containing the given node. The associated nodes will
0262      * also be added to the NodeGroup.
0263      * @returns a pointer to the NodeGroup if one was created, or a pointer to the existing one containing that node
0264      */
0265     NodeGroup *createNodeGroup(Node *node);
0266     /**
0267      * Finds (and deletes if found) the NodeGroup containing the given node.
0268      * @returns true if the NodeGroup was found and deleted
0269      */
0270     bool deleteNodeGroup(Node *node);
0271 
0272     friend class CanvasEditor;
0273 
0274     /**
0275      *        deletes all the elements containde in the nodeList. Should be overridden.
0276      */
0277     virtual void deleteAllNodes() = 0;
0278 
0279     /**
0280      *        Selects all nodes on the document. Should be overridden.
0281      */
0282     virtual void selectAllNodes() = 0;
0283 
0284     // this should be overridden in {Flow|Circuit}ICNDocument
0285     ConnectorList m_connectorList;
0286     CNItemGroup *m_selectList; // Selected objects
0287 
0288     // OVERLOADED
0289     KtlQCanvasItemList m_itemDeleteList; // List of canvas items to be deleted
0290 
0291 private:
0292     Cells *m_cells;
0293     GuardedNodeGroupList m_nodeGroupList;
0294 };
0295 
0296 /**
0297 @author David Saxton
0298 */
0299 class DirCursor
0300 {
0301 public:
0302     static DirCursor *self();
0303     ~DirCursor();
0304 
0305     static QPixmap leftArrow()
0306     {
0307         return self()->m_leftArrow;
0308     }
0309 
0310     static QPixmap rightArrow()
0311     {
0312         return self()->m_rightArrow;
0313     }
0314 
0315     static QPixmap upArrow()
0316     {
0317         return self()->m_upArrow;
0318     }
0319 
0320     static QPixmap downArrow()
0321     {
0322         return self()->m_downArrow;
0323     }
0324 
0325 protected:
0326     DirCursor();
0327     void initCursors();
0328 
0329     static DirCursor *m_self;
0330     QPixmap m_leftArrow;
0331     QPixmap m_rightArrow;
0332     QPixmap m_upArrow;
0333     QPixmap m_downArrow;
0334 };
0335 
0336 #endif