1 /***************************************************************************
2  *   Copyright (C) 2005 by David Saxton                                    *
3  *   david@bluehaze.org                                                    *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  ***************************************************************************/
10 
11 #ifndef ICNDOCUMENT_H
12 #define ICNDOCUMENT_H
13 
14 #include "itemdocument.h"
15 
16 #include <QMap>
17 
18 class Cells;
19 class CNItem;
20 class CNItemGroup;
21 class Connector;
22 class ECNode;
23 class FlowContainer;
24 class Node;
25 class NodeGroup;
26 
27 typedef QMap< QString, Node* > NodeMap;
28 typedef QList<QPointer<Connector> > ConnectorList;
29 typedef QList<QPointer<Node> > NodeList;
30 typedef QList<NodeGroup*> NodeGroupList;
31 typedef QList<QPointer<NodeGroup> > GuardedNodeGroupList;
32 
33 /**
34 @author David Saxton
35 */
36 class ICNDocument : public ItemDocument
37 {
38 Q_OBJECT
39 public:
40 	ICNDocument( const QString &caption, const char *name );
41 
42 	~ICNDocument() override;
43 
44 	enum hit_score
45 	{
46 		hs_none = 0,
47 		hs_connector = 4,
48 		hs_item = 1000
49 	};
50 
51 	View *createView( ViewContainer *viewContainer, uint viewAreaId, const char *name = nullptr ) override;
52 
53 	/**
54 	 * Will attempt to create an item with the given id at position p. Some item
55 	 * (such as PIC/START) have restrictions, and can only have one instance of
56 	 * themselves on the canvas, and adds the operation to the undo list
57 	 */
58 	Item* addItem( const QString &id, const QPoint &p, bool newItem ) override;
59 
60 	/**
61 	 * short for casting whatever itemWithID(id) returns
62 	 */
63 	CNItem* cnItemWithID( const QString &id );
64 	/**
65 	 * Returns a pointer to a node on the canvas with the given id,
66 	 * or nullptr if no such node exists
67 	 */
68 	virtual Node* nodeWithID( const QString &id ) = 0;
69 	/**
70 	 * Returns a pointer to a Connector on the canvas with the given id,
71 	 * or nullptr if no such Connector exists
72 	 */
73 	Connector* connectorWithID( const QString &id );
74 	/**
75 	 * Adds a KtlQCanvasItem to the delete list to be deleted,
76 	 * when flushDeleteList() is called
77 	 */
78 	void appendDeleteList( KtlQCanvasItem *qcanvasItem ) override;
79 	/**
80 	 * Permantly deletes all items that have been added to the delete list with
81 	 * the appendDeleteList( KtlQCanvasItem *qcanvasItem ) function.
82 	 */
83 	void flushDeleteList() override = 0;
84 	/**
85 	 * Reinherit this function to perform special checks on whether the two
86 	 * given QCanvasItems (either nodes or connectors or both) can be
87 	 * connected together.
88 	 */
89 	virtual bool canConnect( KtlQCanvasItem *qcanvasItem1, KtlQCanvasItem *qcanvasItem2 ) const;
90 	/**
91 	 *        copies the selected items to the clipboard, in an XML text form
92 	 */
93 	void copy() override;
94 	/**
95 	 *        selects everything in the current document
96 	 */
97 	void selectAll() override;
98 
99 	/**
100 	 * registers (adds to the document) an item (a connector or a node)
101 	 * @param qcanvasItem the item to be registered
102 	 * @return true if succeeded, false if it didn't
103 	 */
104 	bool registerItem( KtlQCanvasItem *qcanvasItem ) override;
105 	/**
106 	 * Returns a pointer to the 2-dimension array of ICNDocument cells.
107 	 */
cells()108 	Cells *cells() const { return m_cells; }
109 	/**
110 	 * Adds score to the cells at the given cell referece
111 	 */
112 	void addCPenalty( int x, int y, int score );
113 	/**
114 	 * If there are two connectors joined to a node, then they can be merged
115 	 * into one connector. The node will not be removed.
116 	 * @param node The node between the two connectors
117 	 * @param noCreate If true, no new connectors will be created
118 	 * @returns true if it was successful in merging the connectors
119 	 */
120 	// bool joinConnectors( Node *node );
121 	/**
122 	 * Snaps a coordinate in the document to the grid
123 	 * @param pos The coordinate
124 	 * @return The snapped to grid coordinate
125 	 */
126 	static int gridSnap( int pos ); /// Returns 'pos' when snapped to grid
127 	/**
128 	 * Snaps a point to the grid
129 	 * @param pos The point
130 	 * @return The adjusted coordinate
131 	 */
132 	static QPoint gridSnap( const QPoint &pos );
133 	/**
134 	 * Returns true if the CNItem is valid - e.g. will return true for a
135 	 * component in a circuit, but not in a pic program
136 	 */
137 	bool isValidItem( Item *item ) override = 0;
138 	bool isValidItem( const QString &itemId ) override = 0;
139 
140 	// TODO to document
141 	virtual ConnectorList getCommonConnectors( const ItemList &list );
142 	virtual NodeList getCommonNodes( const ItemList &list );
143 
144 	/**
145 	 * returns all the nodes contained by the document. Note that this function is inefficient,
146 	 * so don't use it in loops
147 	 * @return all the nodes contained by the document
148 	 */
149 	virtual NodeList nodeList() const = 0;
150 
151 	/**
152 	 * @return all the connectors from the document
153 	 */
connectorList()154 	const ConnectorList & connectorList() const { return m_connectorList; }
155 
156 	/**
157 	 * @return all the nodegroups from the document
158 	 */
nodeGroupList()159 	const GuardedNodeGroupList & nodeGroupList() const { return m_nodeGroupList; }
160 
161 	/**
162 	 * @return the selected items from the document
163 	 */
164 	ItemGroup *selectList() const override;
165 
166 	/**
167 	 * Creates a connector between two nodes, and returns a pointer to it
168 	 * and adds the operation to the undo list
169 	 */
170 	virtual Connector* createConnector( const QString &startNodeId, const QString &endNodeId, QPointList *pointList = nullptr ) = 0;
171 	/**
172 	 * Creates a connector from node1 to node2. If pointList is non-null, then the
173 	 * connector will be assigned those points
174 	 */
175 	//virtual
176 
177 	Connector *createConnector( Node *node1, Node *node2, QPointList *pointList = nullptr);
178 	/**
179 	 * Splits Connector con into two connectors at point pos2, and creates a connector from the node
180 	 * to the intersection of the two new connectors. If pointList is non-null, then the new connector
181 	 * from the node will be assigned those points
182 	 */
183 	virtual Connector * createConnector( Node *node, Connector *con, const QPoint &pos2, QPointList *pointList = nullptr ) = 0;
184 	/**
185 	 * Splits con1 and con2 into two new connectors each at points pos1 and pos2, and creates a new connector
186 	 * between the two points of intersection given by pos1 and pos2. If pointList is non-null, then the new
187 	 * connector between the two points will be assigned those points
188 	 */
189 	virtual Connector * createConnector( Connector *con1, Connector *con2, const QPoint &pos1, const QPoint &pos2, QPointList *pointList = nullptr ) = 0;
190 	/**
191 	 * Returns the flowcontainer at the given position at the highest level that
192 	 * is not in the current select list, or nullptr if there isn't one
193 	 */
194 	FlowContainer *flowContainer( const QPoint &pos );
195 	/**
196 	 * Sets the drag (e.g. horizontal arrow) cursor for resizing a CNItem, depending on the corner clicked on
197 	 */
198 	void setItemResizeCursor( int cornerType );
199 
200 	void getTranslatable( const ItemList & itemList, ConnectorList * fixedConnectors = nullptr, ConnectorList * translatableConnectors = nullptr, NodeGroupList * translatableNodeGroups = nullptr );
201 
202 	/**
203 	 * Reroutes invalidated directors. You shouldn't call this function
204 	 * directly - instead use ItemDocument::requestEvent.
205 	 */
206 	void rerouteInvalidatedConnectors();
207 	/**
208 	 * Assigns the orphan nodes into NodeGroups. You shouldn't call this
209 	 * function directly - instead use ItemDocument::requestEvent.
210 	 */
211 	virtual void slotAssignNodeGroups();
212 
213 	void unregisterUID( const QString & uid ) override;
214 
215 public slots:
216 	/**
217 	 * Deletes all items in the selected item list, along with associated
218 	 * connectors, etc, and adds the operation to the undo list
219 	 */
220 	void deleteSelection() override;
221 	/**
222 	 * This function looks at all the connectors and the nodes, determines
223 	 * which ones need rerouting, and then reroutes them
224 	 */
225 	void requestRerouteInvalidatedConnectors();
226 	/**
227 	 * Remaps the 2-dimension array of ICNDocument cells, and the various
228 	 * hitscores / etc associated with them. This is used for connector
229 	 * routing, and should be called after e.g. items have been moved
230 	 */
231 	void createCellMap();
232 	/**
233 	 * Call this to request NodeGroup reassignment.
234 	 */
235 	void slotRequestAssignNG();
236 
237 signals:
238 	/**
239 	 * Emitted when a Connector is added
240 	 */
241 	void connectorAdded( Connector *connector );
242 	/**
243 	 * Emitted when a Node is added
244 	 */
245 	void nodeAdded( Node *node );
246 
247 protected:
248 	/**
249 	 * Adds all connector points from the items (used in connector routing).
250 	 * This only needs to be called when connector(s) need routing.
251 	 */
252 	void addAllItemConnectorPoints();
253 
254 	void fillContextMenu( const QPoint &pos ) override;
255 	/**
256 	 * Creates a new NodeGroup to control the node, if there does not already
257 	 * exist a NodeGroup containing the given node. The associated nodes will
258 	 * also be added to the NodeGroup.
259 	 * @returns a pointer to the NodeGroup if one was created, or a pointer to the existing one containing that node
260 	 */
261 	NodeGroup* createNodeGroup( Node *node );
262 	/**
263 	 * Finds (and deletes if found) the NodeGroup containing the given node.
264 	 * @returns true if the NodeGroup was found and deleted
265 	 */
266 	bool deleteNodeGroup( Node *node );
267 
268 	friend class CanvasEditor;
269 
270 	/**
271 	 *        deletes all the elements containde in the nodeList. Should be overridden.
272 	 */
273 	virtual void deleteAllNodes() = 0;
274 
275 	/**
276 	 *        Selects all nodes on the document. Should be overridden.
277 	 */
278 	virtual void selectAllNodes() = 0;
279 
280 	// this should be overridden in {Flow|Circuit}ICNDocument
281 	ConnectorList m_connectorList;
282 	CNItemGroup *m_selectList; // Selected objects
283 
284 	// OVERLOADED
285 	KtlQCanvasItemList m_itemDeleteList; // List of canvas items to be deleted
286 
287 private:
288 	Cells *m_cells;
289 	GuardedNodeGroupList m_nodeGroupList;
290 
291 };
292 
293 /**
294 @author David Saxton
295 */
296 class DirCursor
297 {
298 public:
299 	static DirCursor* self();
300 	~DirCursor();
301 
leftArrow()302 	static QPixmap leftArrow()
303 	{
304 		return self()->m_leftArrow;
305 	}
306 
rightArrow()307 	static QPixmap rightArrow()
308 	{
309 		return self()->m_rightArrow;
310 	}
311 
upArrow()312 	static QPixmap upArrow()
313 	{
314 		return self()->m_upArrow;
315 	}
316 
downArrow()317 	static QPixmap downArrow()
318 	{
319 		return self()->m_downArrow;
320 	}
321 
322 protected:
323 	DirCursor();
324 	void initCursors();
325 
326 	static DirCursor *m_self;
327 	QPixmap m_leftArrow;
328 	QPixmap m_rightArrow;
329 	QPixmap m_upArrow;
330 	QPixmap m_downArrow;
331 };
332 
333 
334 #endif
335