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