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 ITEMDOCUMENT_H 12 #define ITEMDOCUMENT_H 13 14 #include <set> 15 #include <document.h> 16 #include <canvas.h> 17 #include "canvasitems.h" 18 19 #include <QMap> 20 #include <QStack> 21 // #include <q3valuevector.h> 22 23 class Canvas; 24 class CanvasTip; 25 class Connector; 26 class CMManager; 27 class ECNode; 28 class Item; 29 class ItemDocumentData; 30 class ItemGroup; 31 class KTechlab; 32 class Operation; 33 34 class KActionMenu; 35 class KtlQCanvasItem; 36 37 typedef QStack<ItemDocumentData*> IDDStack; 38 typedef QPointer<Item> GuardedItem; 39 typedef QMap< int, GuardedItem > IntItemMap; 40 typedef QMap< QString, Item* > ItemMap; 41 typedef QList<GuardedItem> ItemList; 42 typedef QList<QPoint> QPointList; 43 44 /** 45 @author David Saxton 46 */ 47 class ItemDocument : public Document 48 { 49 Q_OBJECT 50 51 friend class KtlTestsAppFixture; 52 53 public: 54 ItemDocument( const QString &caption, const char *name = nullptr ); 55 ~ItemDocument() override; 56 57 class Z 58 { 59 public: 60 enum 61 { 62 Select = 10000000, 63 Connector = 20000000, 64 Item = 30000000, 65 RaisedItem = 40000000, 66 ResizeHandle = 50000000, 67 Tip = 60000000, 68 ConnectorCreateLine = 70000000, 69 70 // How much "Z" separates items stacked on each other 71 DeltaItem = 10000 72 }; 73 }; 74 75 /** 76 * Some things (such as the canvas getting resized, connectors being 77 * invalidated, need to be done after editing operations have finished, 78 * etc, and they also need to be done in the order given in the 79 * enumeration below. 80 */ 81 class ItemDocumentEvent 82 { 83 public: enum type 84 { 85 ResizeCanvasToItems = 1 << 0, 86 UpdateNodeGroups = 1 << 1, 87 RerouteInvalidatedConnectors = 1 << 2, 88 UpdateZOrdering = 1 << 3 89 }; 90 }; 91 92 void fileSave() override; 93 void fileSaveAs() override; 94 void print() override; 95 bool openURL( const QUrl &url ) override; 96 /** 97 * Attempt to register the item, returning true iff successful 98 */ 99 virtual bool registerItem( KtlQCanvasItem *qcanvasItem ); 100 /** 101 * Will attempt to create an item with the given id at position p. Some item 102 * (such as PIC/START) have restrictions, and can only have one instance of 103 * themselves on the canvas, and adds the operation to the undo list 104 */ 105 virtual Item* addItem( const QString &id, const QPoint &p, bool newItem ) = 0; 106 /** 107 * @returns A pointer to the canvas 108 */ canvas()109 Canvas *canvas() const { return m_canvas; } 110 /** 111 * Attemtps to register a unique id for the canvas view of an item on the 112 * canvas. If the id does not already exist, will return true; otherwise 113 * the function will return false. 114 */ 115 bool registerUID( const QString & uid ); 116 /** 117 * Generates a unique id based on a possibly unique component name. 118 */ 119 QString generateUID( QString name ); 120 /** 121 * Unlists the given id as one that is used. 122 * @see registerUID 123 */ 124 virtual void unregisterUID( const QString & uid ); 125 /** 126 * @return Whether or not the item is valid; i.e. is appropriate to the 127 * document being edited, and does not have other special restrictions 128 * on it (such as only allowing one instance of the Start part in 129 * FlowCode). 130 */ 131 virtual bool isValidItem( Item *item ) = 0; 132 /** 133 * @return Whether or not the item is valid; i.e. is appropriate to the 134 * document being edited, and does not have other special restrictions 135 * on it (such as only allowing one instance of the Start part in 136 * FlowCode). 137 */ 138 virtual bool isValidItem( const QString &itemId ) = 0; 139 /** 140 * Increases the "height" of the given list of items by "one". 141 */ 142 void raiseZ( const ItemList & itemList ); 143 /** 144 * Decreases the "height" of the given list of items by "one". 145 */ 146 void lowerZ( const ItemList & itemList ); 147 /** 148 * @return ItemGroup that is used as the select list for this document. 149 */ 150 virtual ItemGroup *selectList() const = 0; 151 /** 152 * Deselects any currently selected items 153 */ 154 void unselectAll(); 155 /** 156 * Select a list of KtlQCanvasItem's 157 */ 158 void select( const KtlQCanvasItemList & list ); 159 /** 160 * Select a KtlQCanvasItem 161 */ 162 void select( KtlQCanvasItem * item ); 163 /** 164 * Unselects the item 165 */ 166 void unselect( KtlQCanvasItem *qcanvasItem ); 167 /** 168 * Deletes anything waiting to be deleted. 169 */ 170 virtual void flushDeleteList() = 0; 171 /** 172 * Returns a rubber-band rectangle that contains all of the items on the 173 * canvas, padded out by a small border. 174 */ 175 QRect canvasBoundingRect() const; 176 /** 177 * Returns a pointer to a Item on the canvas with the given id, 178 * or nullptr if no such Item exists. 179 */ 180 Item* itemWithID( const QString & ); 181 /** 182 * Returns true if the user can perform an undo action 183 * (i.e. the undo stack is not empty) 184 */ 185 bool isUndoAvailable() const override; 186 /** 187 * Returns true if the user can perform an redo action 188 * (i.e. the redo stack is not empty) 189 */ 190 bool isRedoAvailable() const override; 191 /** 192 * Returns the top item at point (x, y), or nullptr if there is no item there 193 */ 194 KtlQCanvasItem* itemAtTop( const QPoint &pos ) const ; 195 /** 196 * Called when the canvas is clicked on with the right mouse button. 197 * Popups up a menu for editing operations 198 */ 199 virtual void canvasRightClick( const QPoint &pos, KtlQCanvasItem* item ); 200 /** 201 * List of items in the ItemDocument 202 */ 203 ItemList itemList() const; 204 /** 205 * Set the given KtlQCanvasItem (which will attempt to be casted to known 206 * items to be deleted. 207 */ 208 virtual void appendDeleteList( KtlQCanvasItem * ) = 0; 209 /** 210 * Save the current state of the document to the undo/redo history. 211 * @param actionTicket if this is non-negative, and the last state save 212 * also had the same actionTicket, then the next state save will 213 * overwrite the previous state save. 214 * @see getActionTicket 215 */ 216 void requestStateSave( int actionTicket = -1 ); 217 218 /** 219 * Clears the undo / redo history 220 */ 221 void clearHistory(); 222 /** 223 * Requests an event to be done after other stuff (editing, etc) is finished. 224 */ 225 void requestEvent( ItemDocumentEvent::type type ); 226 /** 227 * Called from Canvas (when KtlQCanvas::advance is called). 228 */ 229 virtual void update(); 230 231 /** 232 * Returns a unique id, for use in requestStateSave 233 */ getActionTicket()234 int getActionTicket() const { return m_nextActionTicket++; } 235 236 public slots: 237 void undo() override; 238 void redo() override; 239 void cut() override; 240 void paste() override; 241 /** 242 * Ask the canvas to be resized to the current items on the canvas. 243 */ 244 void requestCanvasResize(); 245 /** 246 * Selects everything in the view. 247 */ 248 void selectAll() override = 0; 249 /** 250 * Increases the "height" of the selected items. 251 */ 252 void raiseZ(); 253 /** 254 * Decreases the "height" of the selected items. 255 */ 256 void lowerZ(); 257 /** 258 * Brings up a file dialog requesting the location of the file to export 259 * to, and then exports an image of the canvas. 260 */ 261 void exportToImage(); 262 protected: 263 void exportToImageDraw( const QRect & saveArea, QPaintDevice &pDev); 264 public slots: 265 /** 266 * Deletes whatever is selected. 267 */ deleteSelection()268 virtual void deleteSelection() {}; 269 /** 270 * Called when the user presses Escape (or similar) 271 */ 272 void cancelCurrentOperation(); 273 /** 274 * Sets the y-positions of the selected items to the average of the 275 * initial y-positions. 276 */ 277 278 // TODO: decide whether these should be moved to ICNdocument... 279 void alignHorizontally(); 280 /** 281 * Sets the x-positions of the selected items to the average of the 282 * initial x-positions. 283 */ 284 void alignVertically(); 285 /** 286 * Averages out the horizontal spacing between the selected items. 287 */ 288 void distributeHorizontally(); 289 /** 290 * Averages out the vertical spacing between the selected items. 291 */ 292 void distributeVertically(); 293 /** 294 * Adds an items not in the Z ordering to the ordering, and removes any 295 * items from the Z ordering if they have parents. Then, calls all items 296 * found in the ordering to tell them their Z position. 297 */ 298 // ################## 299 300 301 void slotUpdateZOrdering(); 302 /** 303 * Call this with ItemDocument::DrawAction to start drawing the given thing 304 */ 305 void slotSetDrawAction( QAction *selected ); 306 /** 307 * Sets the editing mode to repeatedly creating a CNItem 308 * with the given id. Usually called when the user double-clicks on 309 * the component box. 310 */ 311 void slotSetRepeatedItemId( const QString &id ); 312 /** 313 * Unsets the editing mode from repeatedly creating a CNItem 314 */ 315 void slotUnsetRepeatedItemId(); 316 /** 317 * Called when the user changes the configuration. 318 * This, for example, will tell the CNItems on the canvas to update 319 * their configuration. 320 */ 321 void slotUpdateConfiguration() override; 322 /** 323 * Enables / disables / selects various actions depending on 324 * what is selected or not. 325 */ 326 virtual void slotInitItemActions(); 327 /** 328 * Process queued events (see ItemDocument::ItemDocumentEvent). 329 */ 330 void processItemDocumentEvents(); 331 332 signals: 333 /** 334 * Emitted when the selection changes. 335 */ 336 void selectionChanged(); 337 338 protected slots: 339 /** 340 * Called after the canvas is resized to set the scrollbars of the 341 * ItemViews to either always show or always hidden. 342 */ 343 void updateItemViewScrollbars(); 344 345 protected: 346 /** 347 * Called from registerItem when a new item is added. 348 */ 349 virtual void itemAdded( Item * item ); 350 void handleNewView( View *view ) override; 351 /** 352 * Set to true to remove buttons and grid and so on from the canvas, set false to put them back 353 */ 354 void setSVGExport( bool svgExport ); 355 void writeFile(); 356 /** 357 * Reinherit this if you want to add any options to the right-click context 358 */ 359 virtual void fillContextMenu( const QPoint & pos ); 360 /** 361 * Reads the background settings (grid-colour, underlying colour) from the Config settings, 362 * and generates the background pixmap from those settings 363 */ 364 void updateBackground(); 365 /** 366 * Sets the canvas size to both (a) containing all items present on the 367 * canvas, and (b) no smaller than the smallest view of the canvas. This 368 * function should only be called by processItemDocumentEvents - a resize 369 * request must be made with requestEvent. 370 */ 371 void resizeCanvasToItems(); 372 373 Canvas *m_canvas; 374 375 CMManager *m_cmManager; 376 CanvasTip *m_canvasTip; 377 378 ItemList m_itemDeleteList; 379 ItemMap m_itemList; 380 381 QString m_fileExtensionInfo; // For displaying in the save file dialog 382 383 384 385 private: 386 /** 387 * This clears a given stack and deletes all pointers, but the one to m_currentState. 388 */ 389 void cleanClearStack( IDDStack &stack ); 390 391 static int m_nextActionTicket; 392 393 unsigned m_queuedEvents; // OR'ed together list of ItemDocumentEvent::type 394 unsigned m_nextIdNum; 395 int m_currentActionTicket; 396 bool m_bIsLoading; 397 398 ItemDocumentData *m_currentState; 399 ItemDocumentData *m_savedState; // Pointer to the document data that holds the state when it saved 400 401 KActionMenu *m_pAlignmentAction; 402 403 IntItemMap m_zOrder; 404 405 std::set<QString> m_idList; // used to ensure unique IDs to try to make sure save files are valid. 406 407 QTimer *m_pEventTimer; 408 QTimer *m_pUpdateItemViewScrollbarsTimer; 409 410 IDDStack m_undoStack; 411 IDDStack m_redoStack; 412 413 friend class ICNView; 414 friend class ItemView; 415 }; 416 417 418 /** 419 @author David Saxton 420 */ 421 class Canvas : public KtlQCanvas 422 { 423 Q_OBJECT 424 public: 425 Canvas( ItemDocument *itemDocument, const char * name = nullptr ); 426 427 /** 428 * Sets a message to be displayed on the canvas for a brief period of 429 * time. If this is called with an empty message, then any existing 430 * message will be removed. 431 */ 432 void setMessage( const QString & message ); 433 void update() override; 434 void resize( const QRect & size ) override; 435 436 signals: 437 /** 438 * Emitted when the canvas rectangle-size changes. 439 */ 440 void resized( const QRect & oldSize, const QRect & newSize ); 441 442 public slots: slotSetAllChanged()443 void slotSetAllChanged() { setAllChanged(); } 444 445 protected: 446 void drawBackground ( QPainter & painter, const QRect & clip ) override; 447 void drawForeground ( QPainter & painter, const QRect & clip ) override; 448 449 ItemDocument *p_itemDocument; 450 451 QString m_message; 452 QTimer * m_pMessageTimeout; 453 }; 454 455 456 /** 457 @author David Saxton 458 */ 459 class CanvasTip : public KtlQCanvasRectangle 460 { 461 public: 462 CanvasTip( ItemDocument *itemDocument, KtlQCanvas *qcanvas ); 463 ~CanvasTip() override; 464 465 void displayVI( ECNode *node, const QPoint &pos ); 466 void displayVI( Connector *connector, const QPoint &pos ); 467 468 protected: 469 void draw( QPainter &p ) override; 470 void setText( const QString & text ); 471 bool updateVI(); 472 void display( const QPoint &pos ); 473 QString displayText( unsigned num ) const; 474 475 QVector<double> m_v; 476 QVector<double> m_i; 477 ItemDocument *p_itemDocument; 478 QString m_text; 479 }; 480 481 482 #endif 483