File indexing completed on 2024-05-19 05:42:20

0001 // ct_lvtqtc_lakosentity.h                                          -*-C++-*-
0002 
0003 /*
0004 // Copyright 2023 Codethink Ltd <codethink@codethink.co.uk>
0005 // SPDX-License-Identifier: Apache-2.0
0006 //
0007 // Licensed under the Apache License, Version 2.0 (the "License");
0008 // you may not use this file except in compliance with the License.
0009 // You may obtain a copy of the License at
0010 //
0011 //     http://www.apache.org/licenses/LICENSE-2.0
0012 //
0013 // Unless required by applicable law or agreed to in writing, software
0014 // distributed under the License is distributed on an "AS IS" BASIS,
0015 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0016 // See the License for the specific language governing permissions and
0017 // limitations under the License.
0018 */
0019 
0020 #ifndef INCLUDED_CT_LVTGRPS_LAKOSENTITY
0021 #define INCLUDED_CT_LVTGRPS_LAKOSENTITY
0022 
0023 #include <lvtqtc_export.h>
0024 
0025 #include <ct_lvtclr_colormanagement.h>
0026 
0027 #include <ct_lvtshr_graphenums.h>
0028 #include <ct_lvtshr_loaderinfo.h>
0029 #include <ct_lvtshr_uniqueid.h>
0030 
0031 #include <ct_lvtplg_pluginmanager.h>
0032 #include <ct_lvtqtc_edgecollection.h>
0033 #include <ct_lvtqtc_ellipsistextitem.h>
0034 #include <ct_lvtqtc_graphicsrectitem.h>
0035 #include <ct_lvtqtc_util.h>
0036 
0037 #include <QColor>
0038 #include <QFont>
0039 #include <QJsonObject>
0040 #include <QPointF>
0041 #include <QRectF>
0042 
0043 #include <memory>
0044 #include <unordered_map>
0045 
0046 class QAction;
0047 class QUndoCommand;
0048 
0049 namespace Codethink::lvtldr {
0050 class LakosianNode;
0051 }
0052 namespace Codethink::lvtqtc {
0053 struct EdgeCollection;
0054 class LakosRelation;
0055 
0056 /*! \class LakosEntity lakos_entity.cpp lakos_entity.h
0057  *  \brief Represents and draws a Lakos Entity
0058  *
0059  * %LakosEntity draws a Lakos Entity, and handles tool tips
0060  * and mouse clicks
0061  */
0062 class LVTQTC_EXPORT LakosEntity : public GraphicsRectItem {
0063     Q_OBJECT
0064 
0065   public:
0066     enum PresentationFlags { NoFlag = 0x00, Highlighted = 0x01 };
0067 
0068     enum class RelayoutBehavior : short { e_DoNotRelayout, e_RequestRelayout };
0069 
0070     enum class ToggleContentBehavior : short {
0071         Single, // only shows or hides this container.
0072         Recursive // recurse into children calling showContent on them.
0073     };
0074 
0075     enum class LevelizationLayoutType { Horizontal, Vertical };
0076 
0077     enum { Type = QtcUtil::LAKOSENTITY_TYPE };
0078     // for qgraphicsitem_cast magic
0079 
0080     LakosEntity(const std::string& uniqueId, lvtldr::LakosianNode *node, lvtshr::LoaderInfo info);
0081     ~LakosEntity() override;
0082 
0083     [[nodiscard]] const std::string& uniqueIdStr() const;
0084     /*! \brief Unique identifier string
0085      *
0086      * This string uniquely identifies a particular vertex
0087      * corresponding to a row in a database table, such
0088      * as the 'class_declaration' table. It consists of
0089      * the name of the table, followed by '#' and the
0090      * value of the id.
0091      *
0092      * Example: 'class_declaration#1234'.
0093      */
0094 
0095     [[nodiscard]] lvtldr::LakosianNode *internalNode() const;
0096 
0097     [[nodiscard]] lvtshr::UniqueId uniqueId() const;
0098 
0099     [[nodiscard]] std::string name() const;
0100     // returns the name of this node
0101 
0102     void setName(const std::string& name);
0103     // sets the name of this node.
0104     // The name is used to identify the node on screen, but there's
0105     // also `setText` that does the same.
0106     // TODO: simplify the API.
0107 
0108     void setPresentationFlags(PresentationFlags flags, bool value);
0109 
0110     void updateZLevel();
0111     // updates the z level based on selection state.
0112 
0113     void setQualifiedName(const std::string& qname);
0114 
0115     void setFont(const QFont& f);
0116     // sets the font of the current entity
0117 
0118     [[nodiscard]] long long shortId() const;
0119     // This is only guaranteed to be unique within the same instance type.
0120     // You almost certainly want to use uniqueId() instead
0121 
0122     [[nodiscard]] std::string tooltipString() const;
0123     // returns the tooltip for the node, excluding the qualifiedName variant
0124     // that is used when the tooltip string is empty. if you call
0125     // the Qt tooltip() method, this could return the qualified name.
0126 
0127     [[nodiscard]] std::string coverTextString() const;
0128 
0129     void setTooltipString(const std::string& tt);
0130     // set's the tooltip string to tt. if not set, the qualifiedName is used.
0131 
0132     virtual void updateTooltip() = 0;
0133 
0134     [[nodiscard]] std::string qualifiedName() const;
0135     // returns the qualified name of this node
0136 
0137     void setNotes(const std::string& notes);
0138     // set the notes for this entity.
0139 
0140     void setColorId(const std::string& colorId);
0141     // Sets the color id of this element.
0142     // The color id is used to
0143     // fetch a specific color from the ColorManagement.
0144 
0145     [[nodiscard]] std::string colorId() const;
0146     // returns the color id of this node.
0147     // The color id is used to
0148     // fetch a specific color from the ColorManagement.
0149 
0150     [[nodiscard]] QColor color() const;
0151     // returns the current color of this node.
0152     // TODO: Change this, the color is not important, but the brush is.
0153     // That's because the brush can hold more things than just a color,
0154     // and if we change the color of a brush that has a gradient, nothing
0155     // will change on the painted item.
0156 
0157     void setMainEntity();
0158     // Draws a different background to highlight that this is the main node.
0159     // TODO: rename to setAsMainEntity(). setMainEntity means that we are
0160     // setting a mainEntity inside of this element.
0161 
0162     [[nodiscard]] bool isMainEntity() const;
0163     // returns if this is the main node or not.
0164 
0165     LakosEntity *getTopLevelParent();
0166     // Get the top-most LakosEntity in the parent/child hierarchy
0167 
0168     virtual void updateBackground();
0169     // recalculates the background.
0170 
0171     [[nodiscard]] bool highlighted() const;
0172     // \brief Indicates if the entity is highlighted
0173 
0174     void setColorManagement(lvtclr::ColorManagement *colorManagement);
0175     // Sets color management of the entity
0176 
0177     [[nodiscard]] QList<LakosEntity *> lakosEntities() const;
0178     // TODO: pick one, std::vector or QList, don't mix them.
0179 
0180     [[nodiscard]] std::vector<std::shared_ptr<EdgeCollection>>& edgesCollection() const;
0181     // The edges that have this node as source.
0182 
0183     [[nodiscard]] std::vector<std::shared_ptr<EdgeCollection>>& targetCollection() const;
0184     // The edges that have this node as a Target.
0185 
0186     [[nodiscard]] const std::vector<std::shared_ptr<EdgeCollection>>& redundantRelationshipsCollection() const;
0187     // edges (that are also on the edgesCollection) that are redundant.
0188 
0189     void setRelationshipVisibility(QtcUtil::VisibilityMode mode);
0190 
0191     void removeEdge(LakosRelation *relation);
0192     // removes a relation from this node, and removes the edgesCollection
0193     // that hold that relation, if there are no more relations on it.
0194 
0195     void addTargetCollection(const std::shared_ptr<EdgeCollection>& collection);
0196     // add edges that have this node as target.
0197 
0198     void setRelationRedundant(const std::shared_ptr<EdgeCollection>& edgeCollection);
0199     // Mark a relation as redundant (via transitive reduction)
0200 
0201     void resetRedundantRelations();
0202 
0203     bool hasRelationshipWith(LakosEntity *entity) const;
0204     // returns true if we have a lakosConnection to this entity.
0205 
0206     std::shared_ptr<EdgeCollection> getRelationshipWith(LakosEntity *entity) const;
0207 
0208     void recursiveEdgeRelayout();
0209     // recalculate all the edges, that belongs to this entity and the
0210     // children.
0211 
0212     void recursiveEdgeHighlight(bool highlight);
0213 
0214     virtual void setText(const std::string& text);
0215     // Set the text label, this overrides the visible strings of the
0216     // element, where `name` is currently shown.
0217     // could be userful to merge those usecases.
0218 
0219     void setTextPos(qreal x, qreal y);
0220     // Set's the position of the text, in item coordinates.
0221 
0222     [[nodiscard]] QPointF getTextPos() const;
0223     // returns the position of the text
0224 
0225     void layoutAllRelations();
0226     // Call layoutRelations() on all edges
0227 
0228     [[nodiscard]] const lvtshr::LoaderInfo& loaderInfo() const;
0229 
0230     std::unique_ptr<QDialog> createNotesDialog();
0231     void showNotesDialog();
0232 
0233     void showRedundantRelations(bool show);
0234     // Control whether we should show redundant relations
0235 
0236     void populateMenu(QMenu& menu, QMenu *debugMenu, QPointF scenePosition);
0237 
0238     void showToggleExpansionButton(bool show);
0239     void toggleExpansion(QtcUtil::CreateUndoAction CreateUndoAction,
0240                          std::optional<QPointF> moveToPosition = std::nullopt,
0241                          RelayoutBehavior relayoutBehavior = RelayoutBehavior::e_DoNotRelayout);
0242 
0243     [[nodiscard]] bool isBlockingEvents() const;
0244     // returns true if we are ignoring events on this node.
0245     // We ignore events if the node is covered / hiding content.
0246 
0247     void recalculateRectangle();
0248     // recalculate the rectangle based on the child items,
0249     // but excluding the items specifically set to ignore.
0250     // Only appropriate for an expanded container.
0251 
0252     [[nodiscard]] bool isExpanded() const;
0253     // returns true if we are expanded, false if we are collapsed.
0254     // TODO: create a enum `VisibilityMode` to remove boolean traps.
0255 
0256     void toggleCover(ToggleContentBehavior behavior, QtcUtil::CreateUndoAction create);
0257     // calls hideContent or showContent based on the current status.
0258 
0259     void hideContent(ToggleContentBehavior behavior, QtcUtil::CreateUndoAction create);
0260     // show all edges that leaves this LakosEntity, and add a semitranslucent cover.
0261 
0262     void showContent(ToggleContentBehavior behavior, QtcUtil::CreateUndoAction create);
0263     // hides the semitranslucent cover and hides all the edges.
0264 
0265     [[nodiscard]] bool isCovered() const;
0266     // Child items are hidden behind a semi-translucent cover, events are
0267     // not propagated - besides move, click and menu.
0268 
0269     void calculateEdgeVisibility(const std::shared_ptr<EdgeCollection>& ec);
0270     void calculateEdgeVisibility();
0271     // calculates the visibility of all edges that leaves this node
0272     // and all edges that arrive on this node, and set the appropriate
0273     // value for it, recursively.
0274 
0275     [[nodiscard]] bool isCoveredByParent() const;
0276     // returns true if any parent of this LakosEntity is covered.
0277 
0278     [[nodiscard]] bool isParentCollapsed() const;
0279     // returns true if any parent of this LakosEntity is collapsed.
0280 
0281     bool childrenHasVisibleRelationshipWith(LakosEntity *otherEntity) const;
0282     // Do we have a visible relationship with the entity, from one of the
0283     // childrens?
0284 
0285     [[nodiscard]] std::string legendText() const;
0286     // Returns a string which summarises what this thing is
0287 
0288     virtual QList<QAction *> actionsForMenu(QPointF scenePosition);
0289     // returns a list of QActions that should be inserted on the
0290     // right click menu.
0291 
0292     virtual void enableLayoutUpdates();
0293     // When a LakosEntity is first constructed, we don't update layouts,
0294     // edges, etc with each move so that we don't spend time on that while
0295     // laying out a whole scene. Once the scene is set up we do want to
0296     // carefully update these things as we go along. On construction this
0297     // disabled.
0298 
0299     virtual void showChildRedundantRelations(bool show);
0300     // call showRedundnatRelations on all children
0301 
0302     virtual void setHighlighted(bool highlighted);
0303     // Set whether or not the entity is highlighted
0304 
0305     [[nodiscard]] virtual std::string colorIdText() const;
0306     // returns what the colorId means for this node, used on
0307     // tooltips and information texts.
0308 
0309     [[nodiscard]] virtual lvtshr::DiagramType instanceType() const = 0;
0310     // returns a specific type of the instance, for loading and storing into the database.
0311 
0312     [[nodiscard]] int type() const override;
0313     // see QGraphicsItem documentation.
0314 
0315     QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant& value) override;
0316     // see QGraphicsItem documentation.
0317 
0318     [[nodiscard]] QList<LakosEntity *> parentHierarchy() const;
0319     // a list of parents from this item.
0320     // the outermost is the one directly on the scene
0321     // the innermost the direct parent of this item
0322     // empty hierarchy means that this item is directly on the scene
0323 
0324     void expand(QtcUtil::CreateUndoAction CreateUndoAction,
0325                 std::optional<QPointF> moveToPosition = std::nullopt,
0326                 RelayoutBehavior behavior = RelayoutBehavior::e_DoNotRelayout);
0327     // Expands this node.
0328 
0329     void shrink(QtcUtil::CreateUndoAction CreateUndoAction,
0330                 std::optional<QPointF> moveToPosition = std::nullopt,
0331                 RelayoutBehavior behavior = RelayoutBehavior::e_DoNotRelayout);
0332     // Shrinks this node.
0333 
0334     [[nodiscard]] std::unordered_map<LakosEntity *, int> childrenLevels() const;
0335 
0336     void levelizationLayout(LevelizationLayoutType type,
0337                             int direction,
0338                             std::optional<QPointF> moveToPosition = std::nullopt);
0339 
0340     QJsonObject toJson() const;
0341     void fromJson(const QJsonObject& thisObj);
0342 
0343     void setColor(const QColor& color);
0344 
0345     void setPluginManager(Codethink::lvtplg::PluginManager& pm);
0346 
0347     void startDrag(QPointF startPosition);
0348     void doDrag(QPointF movePosition);
0349     void endDrag(QPointF endPosition);
0350 
0351   Q_SIGNALS:
0352     Q_SIGNAL void navigateRequested();
0353     // We want to load this node as the main node
0354 
0355     Q_SIGNAL void loadChildren();
0356     // Request that the children of this entity are loaded
0357 
0358     Q_SIGNAL void loadClients(bool onlyLocal = false);
0359     // load entities that are clients for this entity.
0360     // If `onlyLocal` is true, only load clients from the same package.
0361 
0362     Q_SIGNAL void loadProviders(bool onlyLocal = false);
0363     // Load entities that are providers for this entity.
0364     // If `onlyLocal` is true, only load clients from the same package.
0365 
0366     Q_SIGNAL void unloadThis();
0367     Q_SIGNAL void unloadChildren();
0368     // Request that the children of this entity are not loaded
0369 
0370     Q_SIGNAL void neverLoadEdges();
0371     // Request that the edges for this entity are not loaded
0372 
0373     Q_SIGNAL void formFactorChanged();
0374     // Expanded / shrunk / rect changed.
0375 
0376     Q_SIGNAL void coverChanged();
0377     // covered / uncovered the contents.
0378 
0379     Q_SIGNAL void dragStarted();
0380     // A drag operation started. child classes must implement to handle complex behavior.
0381 
0382     Q_SIGNAL void dragFinished();
0383     // a drag operation finished, this item potentially is moved.
0384 
0385     Q_SIGNAL void moving();
0386     // The user is manually dragging this LakosEntity
0387 
0388     Q_SIGNAL void graphUpdate();
0389     // The user manually changed something and we should save the graph
0390 
0391     Q_SIGNAL void undoGroupRequested(const QString& groupName);
0392     // start to merge undo actions here.
0393 
0394     Q_SIGNAL void undoCommandCreated(QUndoCommand *command);
0395     // A new undo command is created for his node.
0396 
0397     Q_SIGNAL void entityRenameRequest(const lvtshr::UniqueId& uid, const std::string& newName);
0398 
0399     Q_SIGNAL void requestRemoval();
0400     // asks the scene to safely remove this element.
0401 
0402     Q_SIGNAL void requestRelayout();
0403     // asks the scene to relayout the nodes internal to this entity.
0404 
0405     Q_SIGNAL void requestGraphRelayout();
0406     // asks the scene to relayout the entire graph
0407     // this can be the case when we expand or shrink the nodes covering up
0408     // other nodes.
0409 
0410     Q_SIGNAL void toggleSelection();
0411     // Toggle selection.
0412 
0413     Q_SIGNAL void createReportActionClicked(std::string const& title, std::string const& htmlContents);
0414 
0415     Q_SIGNAL void requestNewTab(const QSet<QString> qualifiedNames);
0416 
0417   protected:
0418     [[nodiscard]] bool layoutUpdatesEnabled() const;
0419     // See enableLayoutUpdates()
0420 
0421     void makeToolTip(const std::string& noColorStr);
0422     // changes the item tooltip. this should be a smaller version of the
0423     // information panel.
0424 
0425     void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *ev) override;
0426     // see QGraphicsItem documentation.
0427 
0428     void mousePressEvent(QGraphicsSceneMouseEvent *ev) override;
0429     // see QGraphicsItem documentation.
0430 
0431     void mouseMoveEvent(QGraphicsSceneMouseEvent *ev) override;
0432     // see QGraphicsItem documentation
0433 
0434     void mouseReleaseEvent(QGraphicsSceneMouseEvent *ev) override;
0435     // see QGraphicsItem documentation.
0436 
0437     void hoverEnterEvent(QGraphicsSceneHoverEvent *ev) override;
0438     // see QGraphicsItem documentation.
0439 
0440     void hoverLeaveEvent(QGraphicsSceneHoverEvent *ev) override;
0441     // see QGraphicsItem documentation.
0442 
0443     void truncateTitle(EllipsisTextItem::Truncate v);
0444 
0445     void forceHideLevelNumbers();
0446 
0447   private:
0448     void layoutIgnoredItems();
0449     // special handling to position items that are ignored
0450     // from the original layout algorithm
0451 
0452     void layoutEdges(LakosEntity *child);
0453     // Layout the edges of the specified child.
0454 
0455     void layoutEdges(LakosEntity *child, EdgeCollection::PointFrom pointFrom, EdgeCollection::PointTo pointTo);
0456     // Layout the edges of the specified child.
0457 
0458     void setTopMargins(qreal topMargins);
0459     // adds the top margins as extra spacing.
0460 
0461     void ignoreItemOnLayout(QGraphicsItem *item);
0462     // adds the item to the list of items that will be ignored on
0463     // the recalculation of the rectangle.
0464 
0465     void updateChildrenLoadedInfo();
0466     // show / hide the information about missing children elements.
0467     // this can happen when we partially load the item.
0468 
0469     // for the *ItemChange methods:
0470     void reactChildRemoved(QGraphicsItem *child);
0471     void reactChildAdded(QGraphicsItem *child);
0472 
0473     struct Private;
0474     std::unique_ptr<Private> d;
0475 };
0476 
0477 } // end namespace Codethink::lvtqtc
0478 
0479 #endif