File indexing completed on 2024-05-19 09:39:42

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 ITEMDOCUMENT_H
0012 #define ITEMDOCUMENT_H
0013 
0014 #include "canvasitems.h"
0015 #include <canvas.h>
0016 #include <document.h>
0017 #include <set>
0018 
0019 #include <QMap>
0020 #include <QStack>
0021 // #include <q3valuevector.h>
0022 
0023 class Canvas;
0024 class CanvasTip;
0025 class Connector;
0026 class CMManager;
0027 class ECNode;
0028 class Item;
0029 class ItemDocumentData;
0030 class ItemGroup;
0031 class KTechlab;
0032 class Operation;
0033 
0034 class KActionMenu;
0035 class KtlQCanvasItem;
0036 
0037 typedef QStack<ItemDocumentData *> IDDStack;
0038 typedef QPointer<Item> GuardedItem;
0039 typedef QMap<int, GuardedItem> IntItemMap;
0040 typedef QMap<QString, Item *> ItemMap;
0041 typedef QList<GuardedItem> ItemList;
0042 typedef QList<QPoint> QPointList;
0043 
0044 /**
0045 @author David Saxton
0046 */
0047 class ItemDocument : public Document
0048 {
0049     Q_OBJECT
0050 
0051     friend class KtlTestsAppFixture;
0052 
0053 public:
0054     ItemDocument(const QString &caption);
0055     ~ItemDocument() override;
0056 
0057     class Z
0058     {
0059     public:
0060         enum {
0061             Select = 10000000,
0062             Connector = 20000000,
0063             Item = 30000000,
0064             RaisedItem = 40000000,
0065             ResizeHandle = 50000000,
0066             Tip = 60000000,
0067             ConnectorCreateLine = 70000000,
0068 
0069             // How much "Z" separates items stacked on each other
0070             DeltaItem = 10000
0071         };
0072     };
0073 
0074     /**
0075      * Some things (such as the canvas getting resized, connectors being
0076      * invalidated, need to be done after editing operations have finished,
0077      * etc, and they also need to be done in the order given in the
0078      * enumeration below.
0079      */
0080     class ItemDocumentEvent
0081     {
0082     public:
0083         enum type { ResizeCanvasToItems = 1 << 0, UpdateNodeGroups = 1 << 1, RerouteInvalidatedConnectors = 1 << 2, UpdateZOrdering = 1 << 3 };
0084     };
0085 
0086     void fileSave() override;
0087     void fileSaveAs() override;
0088     void print() override;
0089     bool openURL(const QUrl &url) override;
0090     /**
0091      * Attempt to register the item, returning true iff successful
0092      */
0093     virtual bool registerItem(KtlQCanvasItem *qcanvasItem);
0094     /**
0095      * Will attempt to create an item with the given id at position p. Some item
0096      * (such as PIC/START) have restrictions, and can only have one instance of
0097      * themselves on the canvas, and adds the operation to the undo list
0098      */
0099     virtual Item *addItem(const QString &id, const QPoint &p, bool newItem) = 0;
0100     /**
0101      * @returns A pointer to the canvas
0102      */
0103     Canvas *canvas() const
0104     {
0105         return m_canvas;
0106     }
0107     /**
0108      * Attemtps to register a unique id for the canvas view of an item on the
0109      * canvas. If the id does not already exist, will return true; otherwise
0110      * the function will return false.
0111      */
0112     bool registerUID(const QString &uid);
0113     /**
0114      * Generates a unique id based on a possibly unique component name.
0115      */
0116     QString generateUID(QString name);
0117     /**
0118      * Unlists the given id as one that is used.
0119      * @see registerUID
0120      */
0121     virtual void unregisterUID(const QString &uid);
0122     /**
0123      * @return Whether or not the item is valid; i.e. is appropriate to the
0124      * document being edited, and does not have other special restrictions
0125      * on it (such as only allowing one instance of the Start part in
0126      * FlowCode).
0127      */
0128     virtual bool isValidItem(Item *item) = 0;
0129     /**
0130      * @return Whether or not the item is valid; i.e. is appropriate to the
0131      * document being edited, and does not have other special restrictions
0132      * on it (such as only allowing one instance of the Start part in
0133      * FlowCode).
0134      */
0135     virtual bool isValidItem(const QString &itemId) = 0;
0136     /**
0137      * Increases the "height" of the given list of items by "one".
0138      */
0139     void raiseZ(const ItemList &itemList);
0140     /**
0141      * Decreases the "height" of the given list of items by "one".
0142      */
0143     void lowerZ(const ItemList &itemList);
0144     /**
0145      * @return ItemGroup that is used as the select list for this document.
0146      */
0147     virtual ItemGroup *selectList() const = 0;
0148     /**
0149      * Deselects any currently selected items
0150      */
0151     void unselectAll();
0152     /**
0153      * Select a list of KtlQCanvasItem's
0154      */
0155     void select(const KtlQCanvasItemList &list);
0156     /**
0157      * Select a KtlQCanvasItem
0158      */
0159     void select(KtlQCanvasItem *item);
0160     /**
0161      * Unselects the item
0162      */
0163     void unselect(KtlQCanvasItem *qcanvasItem);
0164     /**
0165      * Deletes anything waiting to be deleted.
0166      */
0167     virtual void flushDeleteList() = 0;
0168     /**
0169      * Returns a rubber-band rectangle that contains all of the items on the
0170      * canvas, padded out by a small border.
0171      */
0172     QRect canvasBoundingRect() const;
0173     /**
0174      * Returns a pointer to a Item on the canvas with the given id,
0175      * or nullptr if no such Item exists.
0176      */
0177     Item *itemWithID(const QString &);
0178     /**
0179      * Returns true if the user can perform an undo action
0180      * (i.e. the undo stack is not empty)
0181      */
0182     bool isUndoAvailable() const override;
0183     /**
0184      * Returns true if the user can perform an redo action
0185      * (i.e. the redo stack is not empty)
0186      */
0187     bool isRedoAvailable() const override;
0188     /**
0189      * Returns the top item at point (x, y), or nullptr if there is no item there
0190      */
0191     KtlQCanvasItem *itemAtTop(const QPoint &pos) const;
0192     /**
0193      * Called when the canvas is clicked on with the right mouse button.
0194      * Popups up a menu for editing operations
0195      */
0196     virtual void canvasRightClick(const QPoint &pos, KtlQCanvasItem *item);
0197     /**
0198      * List of items in the ItemDocument
0199      */
0200     ItemList itemList() const;
0201     /**
0202      * Set the given KtlQCanvasItem (which will attempt to be casted to known
0203      * items to be deleted.
0204      */
0205     virtual void appendDeleteList(KtlQCanvasItem *) = 0;
0206     /**
0207      * Save the current state of the document to the undo/redo history.
0208      * @param actionTicket if this is non-negative, and the last state save
0209      * also had the same actionTicket, then the next state save will
0210      * overwrite the previous state save.
0211      * @see getActionTicket
0212      */
0213     void requestStateSave(int actionTicket = -1);
0214 
0215     /**
0216      * Clears the undo / redo history
0217      */
0218     void clearHistory();
0219     /**
0220      * Requests an event to be done after other stuff (editing, etc) is finished.
0221      */
0222     void requestEvent(ItemDocumentEvent::type type);
0223     /**
0224      * Called from Canvas (when KtlQCanvas::advance is called).
0225      */
0226     virtual void update();
0227 
0228     /**
0229      * Returns a unique id, for use in requestStateSave
0230      */
0231     int getActionTicket() const
0232     {
0233         return m_nextActionTicket++;
0234     }
0235 
0236 public slots:
0237     void undo() override;
0238     void redo() override;
0239     void cut() override;
0240     void paste() override;
0241     /**
0242      * Ask the canvas to be resized to the current items on the canvas.
0243      */
0244     void requestCanvasResize();
0245     /**
0246      * Selects everything in the view.
0247      */
0248     void selectAll() override = 0;
0249     /**
0250      * Increases the "height" of the selected items.
0251      */
0252     void raiseZ();
0253     /**
0254      * Decreases the "height" of the selected items.
0255      */
0256     void lowerZ();
0257     /**
0258      * Brings up a file dialog requesting the location of the file to export
0259      * to, and then exports an image of the canvas.
0260      */
0261     void exportToImage();
0262 
0263 protected:
0264     void exportToImageDraw(const QRect &saveArea, QPaintDevice &pDev);
0265 public slots:
0266     /**
0267      * Deletes whatever is selected.
0268      */
0269     virtual void deleteSelection() {};
0270     /**
0271      * Called when the user presses Escape (or similar)
0272      */
0273     void cancelCurrentOperation();
0274     /**
0275      * Sets the y-positions of the selected items to the average of the
0276      * initial y-positions.
0277      */
0278 
0279     // TODO: decide whether these should be moved to ICNdocument...
0280     void alignHorizontally();
0281     /**
0282      * Sets the x-positions of the selected items to the average of the
0283      * initial x-positions.
0284      */
0285     void alignVertically();
0286     /**
0287      * Averages out the horizontal spacing between the selected items.
0288      */
0289     void distributeHorizontally();
0290     /**
0291      * Averages out the vertical spacing between the selected items.
0292      */
0293     void distributeVertically();
0294     /**
0295      * Adds an items not in the Z ordering to the ordering, and removes any
0296      * items from the Z ordering if they have parents. Then, calls all items
0297      * found in the ordering to tell them their Z position.
0298      */
0299     // ##################
0300 
0301     void slotUpdateZOrdering();
0302     /**
0303      * Call this with ItemDocument::DrawAction to start drawing the given thing
0304      */
0305     void slotSetDrawAction(QAction *selected);
0306     /**
0307      * Sets the editing mode to repeatedly creating a CNItem
0308      * with the given id. Usually called when the user double-clicks on
0309      * the component box.
0310      */
0311     void slotSetRepeatedItemId(const QString &id);
0312     /**
0313      * Unsets the editing mode from repeatedly creating a CNItem
0314      */
0315     void slotUnsetRepeatedItemId();
0316     /**
0317      * Called when the user changes the configuration.
0318      * This, for example, will tell the CNItems on the canvas to update
0319      * their configuration.
0320      */
0321     void slotUpdateConfiguration() override;
0322     /**
0323      * Enables / disables / selects various actions depending on
0324      * what is selected or not.
0325      */
0326     virtual void slotInitItemActions();
0327     /**
0328      * Process queued events (see ItemDocument::ItemDocumentEvent).
0329      */
0330     void processItemDocumentEvents();
0331 
0332 signals:
0333     /**
0334      * Emitted when the selection changes.
0335      */
0336     void selectionChanged();
0337 
0338 protected slots:
0339     /**
0340      * Called after the canvas is resized to set the scrollbars of the
0341      * ItemViews to either always show or always hidden.
0342      */
0343     void updateItemViewScrollbars();
0344 
0345 protected:
0346     /**
0347      * Called from registerItem when a new item is added.
0348      */
0349     virtual void itemAdded(Item *item);
0350     void handleNewView(View *view) override;
0351     /**
0352      * Set to true to remove buttons and grid and so on from the canvas, set false to put them back
0353      */
0354     void setSVGExport(bool svgExport);
0355     void writeFile();
0356     /**
0357      * Reinherit this if you want to add any options to the right-click context
0358      */
0359     virtual void fillContextMenu(const QPoint &pos);
0360     /**
0361      * Reads the background settings (grid-colour, underlying colour) from the Config settings,
0362      * and generates the background pixmap from those settings
0363      */
0364     void updateBackground();
0365     /**
0366      * Sets the canvas size to both (a) containing all items present on the
0367      * canvas, and (b) no smaller than the smallest view of the canvas. This
0368      * function should only be called by processItemDocumentEvents - a resize
0369      * request must be made with requestEvent.
0370      */
0371     void resizeCanvasToItems();
0372 
0373     Canvas *m_canvas;
0374 
0375     CMManager *m_cmManager;
0376     CanvasTip *m_canvasTip;
0377 
0378     ItemList m_itemDeleteList;
0379     ItemMap m_itemList;
0380 
0381     QString m_fileExtensionInfo; // For displaying in the save file dialog
0382     QString m_fileExtensionValue; // saving files enforces this file extension
0383 
0384 private:
0385     /**
0386      * This clears a given stack and deletes all pointers, but the one to m_currentState.
0387      */
0388     void cleanClearStack(IDDStack &stack);
0389 
0390     static int m_nextActionTicket;
0391 
0392     unsigned m_queuedEvents; // OR'ed together list of ItemDocumentEvent::type
0393     unsigned m_nextIdNum;
0394     int m_currentActionTicket;
0395     bool m_bIsLoading;
0396 
0397     ItemDocumentData *m_currentState;
0398     ItemDocumentData *m_savedState; // Pointer to the document data that holds the state when it saved
0399 
0400     KActionMenu *m_pAlignmentAction;
0401 
0402     IntItemMap m_zOrder;
0403 
0404     std::set<QString> m_idList; // used to ensure unique IDs to try to make sure save files are valid.
0405 
0406     QTimer *m_pEventTimer;
0407     QTimer *m_pUpdateItemViewScrollbarsTimer;
0408 
0409     IDDStack m_undoStack;
0410     IDDStack m_redoStack;
0411 
0412     friend class ICNView;
0413     friend class ItemView;
0414 };
0415 
0416 /**
0417 @author David Saxton
0418 */
0419 class Canvas : public KtlQCanvas
0420 {
0421     Q_OBJECT
0422 public:
0423     Canvas(ItemDocument *itemDocument);
0424 
0425     /**
0426      * Sets a message to be displayed on the canvas for a brief period of
0427      * time. If this is called with an empty message, then any existing
0428      * message will be removed.
0429      */
0430     void setMessage(const QString &message);
0431     void update() override;
0432     void resize(const QRect &size) override;
0433 
0434 signals:
0435     /**
0436      * Emitted when the canvas rectangle-size changes.
0437      */
0438     void resized(const QRect &oldSize, const QRect &newSize);
0439 
0440 public slots:
0441     void slotSetAllChanged()
0442     {
0443         setAllChanged();
0444     }
0445 
0446 protected:
0447     void drawBackground(QPainter &painter, const QRect &clip) override;
0448     void drawForeground(QPainter &painter, const QRect &clip) override;
0449 
0450     ItemDocument *p_itemDocument;
0451 
0452     QString m_message;
0453     QTimer *m_pMessageTimeout;
0454 };
0455 
0456 /**
0457 @author David Saxton
0458 */
0459 class CanvasTip : public KtlQCanvasRectangle
0460 {
0461 public:
0462     CanvasTip(ItemDocument *itemDocument, KtlQCanvas *qcanvas);
0463     ~CanvasTip() override;
0464 
0465     void displayVI(ECNode *node, const QPoint &pos);
0466     void displayVI(Connector *connector, const QPoint &pos);
0467 
0468 protected:
0469     void draw(QPainter &p) override;
0470     void setText(const QString &text);
0471     bool updateVI();
0472     void display(const QPoint &pos);
0473     QString displayText(unsigned num) const;
0474 
0475     QVector<double> m_v;
0476     QVector<double> m_i;
0477     ItemDocument *p_itemDocument;
0478     QString m_text;
0479 };
0480 
0481 #endif